Skip to content

Commit 52a7dd2

Browse files
FEATURE: optional tool detail blocks (#662)
This is a rather huge refactor with 1 new feature (tool details can be suppressed) Previously we use the name "Command" to describe "Tools", this unifies all the internal language and simplifies the code. We also amended the persona UI to use less DToggles which aligns with our design guidelines. Co-authored-by: Martin Brennan <martin@discourse.org>
1 parent 875bb04 commit 52a7dd2

File tree

85 files changed

+492
-571
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+492
-571
lines changed

app/controllers/discourse_ai/admin/ai_personas_controller.rb

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def index
2323
DiscourseAi::Configuration::LlmEnumerator.values.map do |hash|
2424
{ id: hash[:value], name: hash[:name] }
2525
end
26-
render json: { ai_personas: ai_personas, meta: { commands: tools, llms: llms } }
26+
render json: { ai_personas: ai_personas, meta: { tools: tools, llms: llms } }
2727
end
2828

2929
def show
@@ -126,28 +126,29 @@ def ai_persona_params
126126
:rag_conversation_chunks,
127127
:question_consolidator_llm,
128128
:allow_chat,
129+
:tool_details,
129130
allowed_group_ids: [],
130131
rag_uploads: [:id],
131132
)
132133

133-
if commands = params.dig(:ai_persona, :commands)
134-
permitted[:commands] = permit_commands(commands)
134+
if tools = params.dig(:ai_persona, :tools)
135+
permitted[:tools] = permit_tools(tools)
135136
end
136137

137138
permitted
138139
end
139140

140-
def permit_commands(commands)
141-
return [] if !commands.is_a?(Array)
141+
def permit_tools(tools)
142+
return [] if !tools.is_a?(Array)
142143

143-
commands.filter_map do |command, options|
144-
break nil if !command.is_a?(String)
144+
tools.filter_map do |tool, options|
145+
break nil if !tool.is_a?(String)
145146
options&.permit! if options && options.is_a?(ActionController::Parameters)
146147

147148
if options
148-
[command, options]
149+
[tool, options]
149150
else
150-
command
151+
tool
151152
end
152153
end
153154
end

app/models/ai_persona.rb

Lines changed: 49 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# frozen_string_literal: true
22

33
class AiPersona < ActiveRecord::Base
4+
# TODO remove this line 01-11-2024
5+
self.ignored_columns = [:commands]
6+
47
# places a hard limit, so per site we cache a maximum of 500 classes
58
MAX_PERSONAS_PER_SITE = 500
69

@@ -102,204 +105,78 @@ def bump_cache
102105
end
103106

104107
def class_instance
105-
allowed_group_ids = self.allowed_group_ids
106-
id = self.id
107-
system = self.system
108-
user_id = self.user_id
109-
mentionable = self.mentionable
110-
default_llm = self.default_llm
111-
max_context_posts = self.max_context_posts
112-
vision_enabled = self.vision_enabled
113-
vision_max_pixels = self.vision_max_pixels
114-
rag_conversation_chunks = self.rag_conversation_chunks
115-
question_consolidator_llm = self.question_consolidator_llm
116-
allow_chat = self.allow_chat
108+
attributes = %i[
109+
id
110+
user_id
111+
system
112+
mentionable
113+
default_llm
114+
max_context_posts
115+
vision_enabled
116+
vision_max_pixels
117+
rag_conversation_chunks
118+
question_consolidator_llm
119+
allow_chat
120+
name
121+
description
122+
allowed_group_ids
123+
tool_details
124+
]
117125

118126
persona_class = DiscourseAi::AiBot::Personas::Persona.system_personas_by_id[self.id]
119-
if persona_class
120-
persona_class.define_singleton_method :allowed_group_ids do
121-
allowed_group_ids
122-
end
123-
124-
persona_class.define_singleton_method :id do
125-
id
126-
end
127-
128-
persona_class.define_singleton_method :system do
129-
system
130-
end
131-
132-
persona_class.define_singleton_method :user_id do
133-
user_id
134-
end
135-
136-
persona_class.define_singleton_method :allow_chat do
137-
allow_chat
138-
end
139-
140-
persona_class.define_singleton_method :mentionable do
141-
mentionable
142-
end
143-
144-
persona_class.define_singleton_method :default_llm do
145-
default_llm
146-
end
147127

148-
persona_class.define_singleton_method :max_context_posts do
149-
max_context_posts
150-
end
151-
152-
persona_class.define_singleton_method :vision_enabled do
153-
vision_enabled
154-
end
155-
156-
persona_class.define_singleton_method :vision_max_pixels do
157-
vision_max_pixels
158-
end
159-
160-
persona_class.define_singleton_method :question_consolidator_llm do
161-
question_consolidator_llm
162-
end
128+
instance_attributes = {}
129+
attributes.each do |attr|
130+
value = self.read_attribute(attr)
131+
instance_attributes[attr] = value
132+
end
163133

164-
persona_class.define_singleton_method :rag_conversation_chunks do
165-
rag_conversation_chunks
134+
if persona_class
135+
instance_attributes.each do |key, value|
136+
# description/name are localized
137+
persona_class.define_singleton_method(key) { value } if key != :description && key != :name
166138
end
167-
168139
return persona_class
169140
end
170141

171-
name = self.name
172-
description = self.description
173-
ai_persona_id = self.id
174-
175142
options = {}
176-
177-
tools = self.respond_to?(:commands) ? self.commands : self.tools
178-
179143
tools =
180-
tools.filter_map do |element|
181-
inner_name = element
182-
current_options = nil
183-
184-
if element.is_a?(Array)
185-
inner_name = element[0]
186-
current_options = element[1]
187-
end
188-
189-
# Won't migrate data yet. Let's rewrite to the tool name.
190-
inner_name = inner_name.gsub("Command", "")
144+
self.tools.filter_map do |element|
145+
inner_name, current_options = element.is_a?(Array) ? element : [element, nil]
146+
inner_name = inner_name.gsub("Tool", "")
191147
inner_name = "List#{inner_name}" if %w[Categories Tags].include?(inner_name)
192148

193149
begin
194-
klass = ("DiscourseAi::AiBot::Tools::#{inner_name}").constantize
150+
klass = "DiscourseAi::AiBot::Tools::#{inner_name}".constantize
195151
options[klass] = current_options if current_options
196152
klass
197153
rescue StandardError
198154
nil
199155
end
200156
end
201157

202-
Class.new(DiscourseAi::AiBot::Personas::Persona) do
203-
define_singleton_method :id do
204-
id
205-
end
206-
207-
define_singleton_method :name do
208-
name
209-
end
210-
211-
define_singleton_method :user_id do
212-
user_id
213-
end
214-
215-
define_singleton_method :description do
216-
description
217-
end
218-
219-
define_singleton_method :system do
220-
system
221-
end
222-
223-
define_singleton_method :allowed_group_ids do
224-
allowed_group_ids
225-
end
226-
227-
define_singleton_method :user_id do
228-
user_id
229-
end
230-
231-
define_singleton_method :mentionable do
232-
mentionable
233-
end
234-
235-
define_singleton_method :default_llm do
236-
default_llm
237-
end
238-
239-
define_singleton_method :max_context_posts do
240-
max_context_posts
241-
end
242-
243-
define_singleton_method :vision_enabled do
244-
vision_enabled
245-
end
246-
247-
define_singleton_method :vision_max_pixels do
248-
vision_max_pixels
249-
end
250-
251-
define_singleton_method :rag_conversation_chunks do
252-
rag_conversation_chunks
253-
end
254-
255-
define_singleton_method :question_consolidator_llm do
256-
question_consolidator_llm
257-
end
158+
ai_persona_id = self.id
258159

259-
define_singleton_method :allow_chat do
260-
allow_chat
261-
end
160+
Class.new(DiscourseAi::AiBot::Personas::Persona) do
161+
instance_attributes.each { |key, value| define_singleton_method(key) { value } }
262162

263-
define_singleton_method :to_s do
264-
"#<DiscourseAi::AiBot::Personas::Persona::Custom @name=#{self.name} @allowed_group_ids=#{self.allowed_group_ids.join(",")}>"
163+
define_singleton_method(:to_s) do
164+
"#<#{self.class.name} @name=#{name} @allowed_group_ids=#{allowed_group_ids.join(",")}>"
265165
end
266166

267-
define_singleton_method :inspect do
268-
"#<DiscourseAi::AiBot::Personas::Persona::Custom @name=#{self.name} @allowed_group_ids=#{self.allowed_group_ids.join(",")}>"
269-
end
167+
define_singleton_method(:inspect) { to_s }
270168

271-
define_method :initialize do |*args, **kwargs|
169+
define_method(:initialize) do |*args, **kwargs|
272170
@ai_persona = AiPersona.find_by(id: ai_persona_id)
273171
super(*args, **kwargs)
274172
end
275173

276-
define_method :persona_id do
277-
@ai_persona&.id
278-
end
279-
280-
define_method :tools do
281-
tools
282-
end
283-
284-
define_method :options do
285-
options
286-
end
287-
288-
define_method :temperature do
289-
@ai_persona&.temperature
290-
end
291-
292-
define_method :top_p do
293-
@ai_persona&.top_p
294-
end
295-
296-
define_method :system_prompt do
297-
@ai_persona&.system_prompt || "You are a helpful bot."
298-
end
299-
300-
define_method :uploads do
301-
@ai_persona&.uploads
302-
end
174+
define_method(:tools) { tools }
175+
define_method(:options) { options }
176+
define_method(:temperature) { @ai_persona&.temperature }
177+
define_method(:top_p) { @ai_persona&.top_p }
178+
define_method(:system_prompt) { @ai_persona&.system_prompt || "You are a helpful bot." }
179+
define_method(:uploads) { @ai_persona&.uploads }
303180
end
304181
end
305182

@@ -357,7 +234,7 @@ def chat_preconditions
357234
end
358235

359236
def system_persona_unchangeable
360-
if top_p_changed? || temperature_changed? || system_prompt_changed? || commands_changed? ||
237+
if top_p_changed? || temperature_changed? || system_prompt_changed? || tools_changed? ||
361238
name_changed? || description_changed?
362239
errors.add(:base, I18n.t("discourse_ai.ai_bot.personas.cannot_edit_system_persona"))
363240
end
@@ -378,7 +255,7 @@ def ensure_not_system
378255
# id :bigint not null, primary key
379256
# name :string(100) not null
380257
# description :string(2000) not null
381-
# commands :json not null
258+
# tools :json not null
382259
# system_prompt :string(10000000) not null
383260
# allowed_group_ids :integer default([]), not null, is an Array
384261
# created_by_id :integer
@@ -408,6 +285,7 @@ def ensure_not_system
408285
# role_max_responses_per_hour :integer default(50), not null
409286
# question_consolidator_llm :text
410287
# allow_chat :boolean default(FALSE), not null
288+
# tool_details :boolean default(TRUE), not null
411289
#
412290
# Indexes
413291
#

app/serializers/localized_ai_persona_serializer.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class LocalizedAiPersonaSerializer < ApplicationSerializer
99
:enabled,
1010
:system,
1111
:priority,
12-
:commands,
12+
:tools,
1313
:system_prompt,
1414
:allowed_group_ids,
1515
:temperature,
@@ -24,7 +24,8 @@ class LocalizedAiPersonaSerializer < ApplicationSerializer
2424
:rag_chunk_overlap_tokens,
2525
:rag_conversation_chunks,
2626
:question_consolidator_llm,
27-
:allow_chat
27+
:allow_chat,
28+
:tool_details
2829

2930
has_one :user, serializer: BasicUserSerializer, embed: :object
3031
has_many :rag_uploads, serializer: UploadSerializer, embed: :object

0 commit comments

Comments
 (0)