2024-05-07 10:02:16 -03:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module DiscourseAi
|
|
|
|
module Completions
|
|
|
|
module Dialects
|
|
|
|
class XmlTools
|
|
|
|
def initialize(tools)
|
|
|
|
@raw_tools = tools
|
|
|
|
end
|
|
|
|
|
|
|
|
def translated_tools
|
2025-05-15 17:32:39 +10:00
|
|
|
result = +""
|
|
|
|
|
|
|
|
raw_tools.each do |tool|
|
2024-05-07 10:02:16 -03:00
|
|
|
parameters = +""
|
2025-05-15 17:32:39 +10:00
|
|
|
if tool.parameters.present?
|
|
|
|
tool.parameters.each do |parameter|
|
2024-05-07 10:02:16 -03:00
|
|
|
parameters << <<~PARAMETER
|
|
|
|
<parameter>
|
2025-05-15 17:32:39 +10:00
|
|
|
<name>#{parameter.name}</name>
|
|
|
|
<type>#{parameter.type}</type>
|
|
|
|
<description>#{parameter.description}</description>
|
|
|
|
<required>#{parameter.required}</required>
|
2024-05-07 10:02:16 -03:00
|
|
|
PARAMETER
|
2025-05-15 17:32:39 +10:00
|
|
|
if parameter.item_type
|
|
|
|
parameters << "<array_item_type>#{parameter.item_type}</array_item_type>\n"
|
2024-05-07 10:02:16 -03:00
|
|
|
end
|
2025-05-15 17:32:39 +10:00
|
|
|
parameters << "<options>#{parameter.enum.join(",")}</options>\n" if parameter.enum
|
2024-05-07 10:02:16 -03:00
|
|
|
parameters << "</parameter>\n"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-05-15 17:32:39 +10:00
|
|
|
result << <<~TOOLS
|
2024-05-07 10:02:16 -03:00
|
|
|
<tool_description>
|
2025-05-15 17:32:39 +10:00
|
|
|
<tool_name>#{tool.name}</tool_name>
|
|
|
|
<description>#{tool.description}</description>
|
2024-05-07 10:02:16 -03:00
|
|
|
<parameters>
|
|
|
|
#{parameters}</parameters>
|
|
|
|
</tool_description>
|
|
|
|
TOOLS
|
|
|
|
end
|
2025-05-15 17:32:39 +10:00
|
|
|
result
|
2024-05-07 10:02:16 -03:00
|
|
|
end
|
|
|
|
|
|
|
|
def instructions
|
|
|
|
return "" if raw_tools.blank?
|
|
|
|
|
2024-06-07 23:52:01 +10:00
|
|
|
@instructions ||=
|
|
|
|
begin
|
2025-05-15 17:32:39 +10:00
|
|
|
has_arrays = raw_tools.any? { |tool| tool.parameters&.any? { |p| p.type == "array" } }
|
2024-05-07 10:02:16 -03:00
|
|
|
|
2024-06-07 23:52:01 +10:00
|
|
|
(<<~TEXT).strip
|
|
|
|
#{tool_preamble(include_array_tip: has_arrays)}
|
|
|
|
<tools>
|
|
|
|
#{translated_tools}</tools>
|
|
|
|
TEXT
|
|
|
|
end
|
2024-05-07 10:02:16 -03:00
|
|
|
end
|
|
|
|
|
2025-03-25 08:06:43 +11:00
|
|
|
DONE_MESSAGE =
|
|
|
|
"Regardless of what you think, REPLY IMMEDIATELY, WITHOUT MAKING ANY FURTHER TOOL CALLS, YOU ARE OUT OF TOOL CALL QUOTA!"
|
|
|
|
|
2024-05-07 10:02:16 -03:00
|
|
|
def from_raw_tool(raw_message)
|
2025-03-25 08:06:43 +11:00
|
|
|
result = (<<~TEXT).strip
|
2024-05-07 10:02:16 -03:00
|
|
|
<function_results>
|
|
|
|
<result>
|
|
|
|
<tool_name>#{raw_message[:name] || raw_message[:id]}</tool_name>
|
|
|
|
<json>
|
|
|
|
#{raw_message[:content]}
|
|
|
|
</json>
|
|
|
|
</result>
|
|
|
|
</function_results>
|
|
|
|
TEXT
|
2025-03-25 08:06:43 +11:00
|
|
|
|
|
|
|
if @injecting_done
|
|
|
|
"#{result}\n\n#{DONE_MESSAGE}"
|
|
|
|
else
|
|
|
|
result
|
|
|
|
end
|
2024-05-07 10:02:16 -03:00
|
|
|
end
|
|
|
|
|
|
|
|
def from_raw_tool_call(raw_message)
|
|
|
|
parsed = JSON.parse(raw_message[:content], symbolize_names: true)
|
|
|
|
parameters = +""
|
|
|
|
|
|
|
|
if parsed[:arguments]
|
|
|
|
parameters << "<parameters>\n"
|
|
|
|
parsed[:arguments].each { |k, v| parameters << "<#{k}>#{v}</#{k}>\n" }
|
|
|
|
parameters << "</parameters>\n"
|
|
|
|
end
|
|
|
|
|
|
|
|
(<<~TEXT).strip
|
|
|
|
<function_calls>
|
|
|
|
<invoke>
|
|
|
|
<tool_name>#{raw_message[:name] || parsed[:name]}</tool_name>
|
|
|
|
#{parameters}</invoke>
|
|
|
|
</function_calls>
|
|
|
|
TEXT
|
|
|
|
end
|
|
|
|
|
2025-03-25 08:06:43 +11:00
|
|
|
def inject_done(&blk)
|
|
|
|
@injecting_done = true
|
|
|
|
blk.call
|
|
|
|
ensure
|
|
|
|
@injecting_done = false
|
|
|
|
end
|
|
|
|
|
2024-05-07 10:02:16 -03:00
|
|
|
private
|
|
|
|
|
|
|
|
attr_reader :raw_tools
|
|
|
|
|
|
|
|
def tool_preamble(include_array_tip: true)
|
|
|
|
array_tip =
|
|
|
|
if include_array_tip
|
|
|
|
<<~TEXT
|
|
|
|
If a parameter type is an array, return an array of values. For example:
|
|
|
|
<$PARAMETER_NAME>["one","two","three"]</$PARAMETER_NAME>
|
|
|
|
TEXT
|
|
|
|
else
|
|
|
|
""
|
|
|
|
end
|
|
|
|
|
|
|
|
<<~TEXT
|
|
|
|
In this environment you have access to a set of tools you can use to answer the user's question.
|
|
|
|
You may call them like this.
|
|
|
|
|
|
|
|
<function_calls>
|
|
|
|
<invoke>
|
|
|
|
<tool_name>$TOOL_NAME</tool_name>
|
|
|
|
<parameters>
|
|
|
|
<$PARAMETER_NAME>$PARAMETER_VALUE</$PARAMETER_NAME>
|
|
|
|
...
|
|
|
|
</parameters>
|
|
|
|
</invoke>
|
|
|
|
</function_calls>
|
|
|
|
#{array_tip}
|
|
|
|
If you wish to call multiple function in one reply, wrap multiple <invoke>
|
|
|
|
block in a single <function_calls> block.
|
|
|
|
|
2024-11-19 09:22:39 +11:00
|
|
|
- Always prefer to lead with tool calls, if you need to execute any.
|
|
|
|
- Avoid all niceties prior to tool calls, Eg: "Let me look this up for you.." etc.
|
|
|
|
- DO NOT encode HTML entities in tool calls. You may use <![CDATA[...]]> for encoding if required.
|
2024-05-07 10:02:16 -03:00
|
|
|
Here are the complete list of tools available:
|
|
|
|
TEXT
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|