Module: Chat
- Extended by:
- Annotation
- Defined in:
- lib/scout/llm/chat/parse.rb,
lib/scout/llm/chat/process.rb,
lib/scout/llm/chat/annotation.rb,
lib/scout/llm/chat/process/meta.rb,
lib/scout/llm/chat/process/clear.rb,
lib/scout/llm/chat/process/files.rb,
lib/scout/llm/chat/process/tools.rb,
lib/scout/llm/chat/process/options.rb
Class Method Summary collapse
- .associations(messages, kb = nil) ⇒ Object
- .clean(messages, role = ['skip', 'previous_response_id']) ⇒ Object
- .clear(messages, role = 'clear') ⇒ Object
- .content_tokens(message) ⇒ Object
- .files(messages, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) ⇒ Object
- .find_file(file, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) ⇒ Object
- .follow(intro, coda) ⇒ Object
- .imports(messages, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) ⇒ Object
- .indiferent(messages) ⇒ Object
- .jobs(messages, original = nil) ⇒ Object
- .load_workflow(workflow) ⇒ Object
- .meta(messages) ⇒ Object
- .options(chat) ⇒ Object
- .parse(text, role = nil) ⇒ Object
- .parse_meta(str) ⇒ Object
- .print(chat) ⇒ Object
- .print_brief(chat, expand = []) ⇒ Object
- .pull(chat, role = :previous_response_id) ⇒ Object
- .purge(chat, role = :previous_response_id) ⇒ Object
- .serialize_meta(meta) ⇒ Object
- .tag(tag, content, name = nil) ⇒ Object
- .tasks(messages, original = nil) ⇒ Object
- .tools(messages) ⇒ Object
Instance Method Summary collapse
- #answer ⇒ Object
- #append(coda) ⇒ Object
- #ask(options = {}) ⇒ Object
- #assistant(content) ⇒ Object
- #association(name, path, options = {}) ⇒ Object
- #branch ⇒ Object
- #chat(options = {}) ⇒ Object
- #continue(file) ⇒ Object
-
#create_image(file) ⇒ Object
Image.
- #directory(directory) ⇒ Object
- #endpoint(value) ⇒ Object
- #file(file) ⇒ Object
- #final ⇒ Object
- #follow(coda) ⇒ Object
- #format(format) ⇒ Object
- #image(file) ⇒ Object
- #import(file) ⇒ Object
- #import_last(file) ⇒ Object
- #inline_job(step) ⇒ Object
- #inline_task(workflow, task_name, inputs = {}) ⇒ Object
- #introduce(workflow) ⇒ Object
- #job(step) ⇒ Object
- #json ⇒ Object
- #json_format(format) ⇒ Object
- #message(role, content) ⇒ Object
- #meta ⇒ Object
- #model(value) ⇒ Object
- #option(name, value) ⇒ Object
- #pdf(file) ⇒ Object
- #prepend(intro) ⇒ Object
-
#print ⇒ Object
Reporting.
- #purge ⇒ Object
- #remove_role(role = :clear) ⇒ Object
-
#save(path, force = true) ⇒ Object
Write and save.
- #shed ⇒ Object
- #system(content) ⇒ Object
- #tag(content, name = nil, tag = :file, role = :user) ⇒ Object
- #task(workflow, task_name, inputs = {}) ⇒ Object
- #tool(*parts) ⇒ Object
- #user(content) ⇒ Object
- #write(path, force = true) ⇒ Object
- #write_answer(path, force = true) ⇒ Object
Class Method Details
.associations(messages, kb = nil) ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/scout/llm/chat/process/tools.rb', line 201 def self.associations(, kb = nil) tool_definitions = {} new = .collect do || role = [:role] if role == 'association' name, path, *_ = content_tokens() kb ||= KnowledgeBase.new Scout.var.Agent.Chat.knowledge_base = IndiferentHash.([:content]) [:fields] = [:fields].split(/,\s*/) if String === [:fields] [:type] = [:type].to_sym if String === [:type] kb.register name, Path.setup(path), tool_definitions.merge!(LLM.knowledge_base_tool_definition( kb, [name])) next elsif role == 'clear_associations' tool_definitions = {} else end end.compact.flatten .replace new tool_definitions end |
.clean(messages, role = ['skip', 'previous_response_id']) ⇒ Object
16 17 18 19 20 21 22 23 24 |
# File 'lib/scout/llm/chat/process/clear.rb', line 16 def self.clean(, role = ['skip', 'previous_response_id']) .reject do || ((String === [:content]) && [:content].empty?) || if Array === role else [:role].to_s == role.to_s end end end |
.clear(messages, role = 'clear') ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 |
# File 'lib/scout/llm/chat/process/clear.rb', line 2 def self.clear(, role = 'clear') new = [] .reverse.each do || if [:role].to_s == role.to_s break else new << end end Chat.setup new.reverse end |
.content_tokens(message) ⇒ Object
10 11 12 |
# File 'lib/scout/llm/chat/process.rb', line 10 def self.content_tokens() Shellwords.split([:content].strip) end |
.files(messages, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/scout/llm/chat/process/files.rb', line 62 def self.files(, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) .collect do || if [:role] == 'file' || [:role] == 'directory' file = [:content].to_s.strip found_file = find_file(file, original, caller_lib_dir) raise "File not found: #{file}" if found_file.nil? target = found_file if [:role] == 'directory' Path.setup target target.glob('**/*'). reject{|file| Open.directory?(file) }.collect{|file| files([{role: 'file', content: file}]) } else new = Chat.tag :file, Open.read(target), file {role: 'user', content: new} end elsif [:role] == 'pdf' || [:role] == 'image' file = [:content].to_s.strip found_file = find_file(file, original, caller_lib_dir) raise "File not found: #{file}" if found_file.nil? [:content] = found_file else end end.flatten end |
.find_file(file, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/scout/llm/chat/process/files.rb', line 17 def self.find_file(file, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) path = Scout.chats[file] original = original.find if Path === original if original relative = File.join(File.dirname(original), file) relative_lib = File.join(caller_lib_dir, file) if caller_lib_dir end if relative && Open.exist?(relative) relative elsif relative_lib && Open.exist?(relative_lib) relative_lib elsif Open.exist?(file) file elsif Open.remote?(file) file elsif path.exists? path end end |
.follow(intro, coda) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/scout/llm/chat/annotation.rb', line 106 def self.follow(intro, coda) = Chat.(coda.dup) previous_response_id = [:previous_response_id] if if previous_response_id new = intro + Chat.clear(coda, :previous_response_id) new.unshift({role: :previous_response_id, content: previous_response_id}) else new = intro + coda end Chat.setup new end |
.imports(messages, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/scout/llm/chat/process/files.rb', line 38 def self.imports(, original = nil, caller_lib_dir = Path.caller_lib_dir(nil, 'chats')) .collect do || if [:role] == 'import' || [:role] == 'continue' || [:role] == 'last' file = [:content].to_s.strip found_file = find_file(file, original, caller_lib_dir) raise "Import not found: #{file}" if found_file.nil? new = LLM. Open.read(found_file) new = if [:role] == 'continue' [new.reject{|msg| msg[:content].nil? || msg[:content].strip.empty? }.last] elsif [:role] == 'last' [LLM.purge(new).reject{|msg| msg[:content].empty?}.last] else LLM.purge(new) end LLM.chat new, found_file else end end.flatten end |
.indiferent(messages) ⇒ Object
14 15 16 |
# File 'lib/scout/llm/chat/process.rb', line 14 def self.indiferent() .collect{|msg| IndiferentHash.setup msg } end |
.jobs(messages, original = nil) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/scout/llm/chat/process/tools.rb', line 56 def self.jobs(, original = nil) .collect do || if [:role] == 'job' || [:role] == 'inline_job' file = [:content].strip step = Step.load file id = step.short_path[0..39] id = id.gsub('/','-') if [:role] == 'inline_job' path = step.path path = path.find if Path === path {role: 'file', content: step.path} else function_name = step.full_task_name.sub('#', '-') function_name = step.task_name tool_call = { function: { name: function_name, arguments: step.provided_inputs }, id: id, } content = if step.done? Open.read(step.path) elsif step.error? Log.warn "Error in job #{step.path}" e = step.exception if ENV['SCOUT_CHAT_JOB_EXCEPTION'] == 'true' {exception: e., stack: e.backtrace }.to_json else raise e end end tool_output = { id: id, content: content } [ {role: 'function_call', content: tool_call.to_json}, {role: 'function_call_output', content: tool_output.to_json}, ] end else end end.flatten end |
.load_workflow(workflow) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 |
# File 'lib/scout/llm/chat/process/tools.rb', line 3 def self.load_workflow(workflow) workflow = begin Kernel.const_get workflow rescue if Scout.chats.Agent[workflow]['workflow.rb'].exists? Workflow.require_workflow_file Scout.chats.Agent[workflow]['workflow.rb'].find Workflow.main || Workflow.workflows.last else Workflow.require_workflow(workflow) end end end |
.meta(messages) ⇒ Object
43 44 45 46 47 |
# File 'lib/scout/llm/chat/process/meta.rb', line 43 def self.() = pull(, :meta) return nil if .nil? [:content] end |
.options(chat) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/scout/llm/chat/process/options.rb', line 2 def self.(chat) = IndiferentHash.setup({}) = IndiferentHash.setup({}) new = [] # Most options reset after an assistant reply, but not previous_response_id chat.each do |info| if Hash === info role = info[:role].to_s if %w(endpoint model backend agent).include? role.to_s [role] = info[:content] next elsif %w(persist).include? role.to_s [role] = info[:content] next elsif %w(previous_response_id).include? role.to_s [role] = info[:content] elsif %w(format).include? role.to_s format = info[:content] if Path.is_filename?(format) file = find_file(format) if file format = Open.json(file) end end [role] = format next end if role.to_s == 'option' key, _, value = info[:content].partition(" ") [key] = value next end if role.to_s == 'sticky_option' key, _, value = info[:content].partition(" ") [key] = value next end if role == 'assistant' .clear end end new << info end chat.replace new .merge end |
.parse(text, role = nil) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/scout/llm/chat/parse.rb', line 2 def self.parse(text, role = nil) default_role = "user" = [] current_role = role || default_role current_content = "" in_protected_block = false protected_block_type = nil protected_stack = [] role = default_role if role.nil? file_lines = text.split("\n") file_lines.each do |line| stripped = line.strip # Detect protected blocks if stripped.start_with?("```") if in_protected_block if protected_block_type == :ticks in_protected_block = false protected_block_type = nil current_content << "\n" << line unless line.strip.empty? end else in_protected_block = true protected_block_type = :ticks current_content << "\n" << line unless line.strip.empty? end next elsif stripped.end_with?("]]") && in_protected_block && protected_block_type == :square in_protected_block = false protected_block_type = nil line = line.sub("]]", "") current_content << "\n" << line unless line.strip.empty? next elsif stripped.start_with?("[[") in_protected_block = true protected_block_type = :square line = line.sub("[[", "") current_content << "\n" << line unless line.strip.empty? next elsif stripped.end_with?("]]") && in_protected_block && protected_block_type == :square in_protected_block = false protected_block_type = nil line = line.sub("]]", "") current_content << "\n" << line unless line.strip.empty? next elsif stripped.match(/^[^\s]*:-- .* {{{/) in_protected_block = true protected_block_type = :square line = line.sub(/^[^\s]*:-- (.*) {{{.*/, '<cmd_output cmd="\1">') current_content << "\n" << line unless line.strip.empty? next elsif stripped.match(/^.*:--.* }}}/) && in_protected_block && protected_block_type == :square in_protected_block = false protected_block_type = nil line = line.sub(/^.*:-- .* }}}.*/, "</cmd_output>") current_content << "\n" << line unless line.strip.empty? next elsif in_protected_block if protected_block_type == :xml if stripped =~ %r{</(\w+)>} closing_tag = $1 if protected_stack.last == closing_tag protected_stack.pop end if protected_stack.empty? in_protected_block = false protected_block_type = nil end end end current_content << "\n" << line next end # XML-style tag handling (protected content) if stripped =~ /^<(\w+)(\s+[^>]*)?>/ && (tag = $1) && text =~ %r{</#{$1}>} protected_stack.push(tag) in_protected_block = true protected_block_type = :xml next end # Match a new message header if line =~ /^([a-z0-9_]+):(.*)$/ role = $1 inline_content = $2.strip current_content = current_content.strip if current_content # Save current message if any << { role: current_role, content: current_content } if current_content && ! current_content.empty? if inline_content.empty? # Block message current_role = role current_content = "" else # Inline message + next block is default role << { role: role, content: inline_content } if inline_content && ! inline_content.empty? current_role = 'user' if role == 'previous_response_id' current_role = 'user' if role == 'agent' current_content = "" end else if current_content.nil? current_content = line else current_content += "\n" + line end end end # Final message << { role: current_role || default_role, content: current_content.strip } if current_content && ! current_content.empty? end |
.parse_meta(str) ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/scout/llm/chat/process/meta.rb', line 13 def self.(str) parts = str.split('=') = {} key = parts.shift while next_part = parts.shift if parts.any? rnext_part = next_part.reverse rkey,_, rvalue = rnext_part.partition(/\s+/) next_key = rkey.reverse value = rvalue.reverse else value = next_part end case value when /^-?\d+$/ [key] = value.to_i when /^-?\d+\.\d+$/ [key] = value.to_f else [key] = value end key = next_key end end |
.print(chat) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/scout/llm/chat/parse.rb', line 124 def self.print(chat) return chat if String === chat "\n" + chat.collect do || IndiferentHash.setup case [:content] when Hash, Array [:role].to_s + ":\n\n" + [:content].to_json when nil, '' [:role].to_s + ":" else if %w(option previous_response_id function_call function_call_output meta).include? [:role].to_s [:role].to_s + ": " + [:content].to_s else [:role].to_s + ":\n\n" + [:content].to_s end end end * "\n\n" end |
.print_brief(chat, expand = []) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/scout/llm/chat/parse.rb', line 143 def self.print_brief(chat, = []) return chat if String === chat = .collect{|role| role.to_s } "\n" + chat.collect do || = IndiferentHash.setup role, content = .values_at :role, :content role = role.to_s str = case [:content] when Hash, Array [:content].to_json when nil, '' '' else [:content].to_s end next role, "\n\n" + str if .include?(role) [role, Log.fingerprint(str)[1..-2]] end.compact.collect do |role,str| "#{role}: #{str}" end * "\n\n" end |
.pull(chat, role = :previous_response_id) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/scout/llm/chat/process/clear.rb', line 34 def self.pull(chat, role = :previous_response_id) last = nil chat.reject! do |msg| msg = IndiferentHash.setup msg.dup match = msg[:role].to_s == role.to_s last = msg if match match end return nil if last.nil? IndiferentHash.setup last.dup end |
.purge(chat, role = :previous_response_id) ⇒ Object
26 27 28 29 30 31 32 |
# File 'lib/scout/llm/chat/process/clear.rb', line 26 def self.purge(chat, role = :previous_response_id) chat.reject do |msg| msg = IndiferentHash.setup msg.dup msg[:role].to_s == role.to_s end end |
.serialize_meta(meta) ⇒ Object
2 3 4 5 6 7 8 9 10 11 |
# File 'lib/scout/llm/chat/process/meta.rb', line 2 def self.() keys = .keys keys = keys.sort_by do |k| v = [k] String === v ? v.length : 0 end keys.collect{|k| [k,[k]] * "="} * " " end |
.tag(tag, content, name = nil) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/scout/llm/chat/process/files.rb', line 2 def self.tag(tag, content, name = nil) if name <<-EOF.strip <#{tag} name="#{name}"> #{content} </#{tag}> EOF else <<-EOF.strip <#{tag}> #{content} </#{tag}> EOF end end |
.tasks(messages, original = nil) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/scout/llm/chat/process/tools.rb', line 16 def self.tasks(, original = nil) jobs = [] new = .collect do || if [:role] == 'task' || [:role] == 'inline_task' || [:role] == 'exec_task' info = [:content].strip workflow, task = info.split(" ").values_at 0, 1 = IndiferentHash. info jobname = .delete :jobname if String === workflow workflow = Chat.load_workflow workflow end job = workflow.job(task, jobname, ) jobs << job unless [:role] == 'exec_task' if [:role] == 'exec_task' begin {role: 'user', content: job.exec} rescue {role: 'exec_job', content: $!} end elsif [:role] == 'inline_task' {role: 'inline_job', content: job.path.find} else {role: 'job', content: job.path.find} end else end end.flatten Workflow.produce(jobs) if jobs.any? new end |
.tools(messages) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/scout/llm/chat/process/tools.rb', line 110 def self.tools() tool_definitions = IndiferentHash.setup({}) introduced_workflows = [] new = .collect do || role = [:role] if role == 'mcp' url, *tools = content_tokens() if url == 'stdio' command = tools.shift mcp_tool_definitions = LLM.mcp_tools(url, command: command, url: nil, type: :stdio) else mcp_tool_definitions = LLM.mcp_tools(url) end if tools.any? tools.each do |tool| tool_definitions[tool] = mcp_tool_definitions[tool] end else tool_definitions.merge!(mcp_tool_definitions) end next elsif role == 'tool' workflow_name, task_name, *inputs = content_tokens() inputs = nil if inputs.empty? inputs = [] if inputs == ['none'] || inputs == ['noinputs'] if Open.remote? workflow_name require 'rbbt' require 'scout/offsite/ssh' require 'rbbt/workflow/remote_workflow' workflow = RemoteWorkflow.new workflow_name else workflow = Chat.load_workflow workflow_name end if task_name definition = LLM.task_tool_definition workflow, task_name, inputs tool_definitions[task_name] = [workflow, definition] else tool_definitions.merge!(LLM.workflow_tools(workflow)) end next elsif role == 'introduce' workflow_name = [:content] next if introduced_workflows.include? workflow_name introduced_workflows << workflow_name workflow = begin Kernel.const_get workflow_name rescue end if Open.remote? workflow_name require 'rbbt' require 'scout/offsite/ssh' require 'rbbt/workflow/remote_workflow' workflow = RemoteWorkflow.new workflow_name else workflow = Workflow.require_workflow workflow_name end unless workflow raise "Workflow not found #{workflow_name}" if workflow.nil? next unless workflow.documentation.empty? content = <<-EOF You have access to tools from workflow '#{workflow.name}'. Below is the documentation of the workflow: # #{workflow.documentation[:title]} #{workflow.documentation[:description]} EOF {role: :user, content: content} elsif role == 'kb' knowledge_base_name, *databases = content_tokens() databases = nil if databases.empty? knowledge_base = KnowledgeBase.load knowledge_base_name knowledge_base_definition = LLM.knowledge_base_tool_definition(knowledge_base, databases) tool_definitions.merge!(knowledge_base_definition) next elsif role == 'clear_tools' tool_definitions = {} else end end.compact.flatten .replace new tool_definitions end |
Instance Method Details
#answer ⇒ Object
203 204 205 |
# File 'lib/scout/llm/chat/annotation.rb', line 203 def answer final[:content] end |
#append(coda) ⇒ Object
120 121 122 123 124 |
# File 'lib/scout/llm/chat/annotation.rb', line 120 def append(coda) coda = [coda] if Hash === coda new = Chat.follow(self.dup, coda) self.replace new end |
#ask(options = {}) ⇒ Object
91 92 93 |
# File 'lib/scout/llm/chat/annotation.rb', line 91 def ask( = {}) LLM.ask(LLM.chat(self), ) end |
#assistant(content) ⇒ Object
17 18 19 |
# File 'lib/scout/llm/chat/annotation.rb', line 17 def assistant(content) (:assistant, content) end |
#association(name, path, options = {}) ⇒ Object
80 81 82 83 84 |
# File 'lib/scout/llm/chat/annotation.rb', line 80 def association(name, path, = {}) = IndiferentHash. content = [name, path, ]*" " (:association, name) end |
#branch ⇒ Object
165 166 167 |
# File 'lib/scout/llm/chat/annotation.rb', line 165 def branch self.annotate self.dup end |
#chat(options = {}) ⇒ Object
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/scout/llm/chat/annotation.rb', line 95 def chat( = {}) response = ask(.merge(return_messages: true)) if Array === response self.concat(response) final else self.push({role: :assistant, content: response}) response end end |
#continue(file) ⇒ Object
46 47 48 |
# File 'lib/scout/llm/chat/annotation.rb', line 46 def continue(file) (:continue, file) end |
#create_image(file) ⇒ Object
Image
237 238 239 240 |
# File 'lib/scout/llm/chat/annotation.rb', line 237 def create_image(file, ...) base64_image = LLM.image(LLM.chat(self), ...) Open.write(file, Base64.decode(file_content), mode: 'wb') end |
#directory(directory) ⇒ Object
42 43 44 |
# File 'lib/scout/llm/chat/annotation.rb', line 42 def directory(directory) (:directory, directory) end |
#endpoint(value) ⇒ Object
173 174 175 |
# File 'lib/scout/llm/chat/annotation.rb', line 173 def endpoint(value) option :endpoint, value end |
#file(file) ⇒ Object
29 30 31 |
# File 'lib/scout/llm/chat/annotation.rb', line 29 def file(file) (:file, file) end |
#final ⇒ Object
191 192 193 |
# File 'lib/scout/llm/chat/annotation.rb', line 191 def final LLM.purge(self).last end |
#follow(coda) ⇒ Object
126 127 128 129 |
# File 'lib/scout/llm/chat/annotation.rb', line 126 def follow(coda) new = Chat.follow(self.dup, coda) self.replace new end |
#format(format) ⇒ Object
50 51 52 |
# File 'lib/scout/llm/chat/annotation.rb', line 50 def format(format) (:format, format) end |
#image(file) ⇒ Object
181 182 183 |
# File 'lib/scout/llm/chat/annotation.rb', line 181 def image(file) self. :image, file end |
#import(file) ⇒ Object
21 22 23 |
# File 'lib/scout/llm/chat/annotation.rb', line 21 def import(file) (:import, file) end |
#import_last(file) ⇒ Object
25 26 27 |
# File 'lib/scout/llm/chat/annotation.rb', line 25 def import_last(file) (:last, file) end |
#inline_job(step) ⇒ Object
75 76 77 |
# File 'lib/scout/llm/chat/annotation.rb', line 75 def inline_job(step) (:inline_job, step.path) end |
#inline_task(workflow, task_name, inputs = {}) ⇒ Object
65 66 67 68 69 |
# File 'lib/scout/llm/chat/annotation.rb', line 65 def inline_task(workflow, task_name, inputs = {}) input_str = IndiferentHash. inputs content = [workflow, task_name, input_str]*" " (:inline_task, content) end |
#introduce(workflow) ⇒ Object
33 34 35 |
# File 'lib/scout/llm/chat/annotation.rb', line 33 def introduce(workflow) (:introduce, workflow) end |
#job(step) ⇒ Object
71 72 73 |
# File 'lib/scout/llm/chat/annotation.rb', line 71 def job(step) (:job, step.path) end |
#json ⇒ Object
143 144 145 146 147 148 149 150 151 152 |
# File 'lib/scout/llm/chat/annotation.rb', line 143 def json(...) self.format :json output = ask(...) obj = JSON.parse output if (Hash === obj) and obj.keys == ['content'] obj['content'] else obj end end |
#json_format(format) ⇒ Object
154 155 156 157 158 159 160 161 162 163 |
# File 'lib/scout/llm/chat/annotation.rb', line 154 def json_format(format, ...) self.format format output = ask(...) obj = JSON.parse output if (Hash === obj) and obj.keys == ['content'] obj['content'] else obj end end |
#message(role, content) ⇒ Object
5 6 7 |
# File 'lib/scout/llm/chat/annotation.rb', line 5 def (role, content) self.append({role: role.to_s, content: content}) end |
#meta ⇒ Object
242 243 244 245 246 |
# File 'lib/scout/llm/chat/annotation.rb', line 242 def () = self.select{|info| info[:role].to_s == "meta" }.last return {} if .nil? Chat. [:content] end |
#model(value) ⇒ Object
177 178 179 |
# File 'lib/scout/llm/chat/annotation.rb', line 177 def model(value) option :model, value end |
#option(name, value) ⇒ Object
169 170 171 |
# File 'lib/scout/llm/chat/annotation.rb', line 169 def option(name, value) self. 'option', [name, value] * " " end |
#pdf(file) ⇒ Object
37 38 39 |
# File 'lib/scout/llm/chat/annotation.rb', line 37 def pdf(file) (:pdf, file) end |
#prepend(intro) ⇒ Object
131 132 133 134 135 |
# File 'lib/scout/llm/chat/annotation.rb', line 131 def prepend(intro) into = [intro] if Hash === intro new = Chat.follow(intro, self.dup) self.replace new end |
#print ⇒ Object
Reporting
187 188 189 |
# File 'lib/scout/llm/chat/annotation.rb', line 187 def print LLM.print LLM.chat(self) end |
#purge ⇒ Object
195 196 197 |
# File 'lib/scout/llm/chat/annotation.rb', line 195 def purge Chat.setup(LLM.purge(self)) end |
#remove_role(role = :clear) ⇒ Object
137 138 139 140 141 |
# File 'lib/scout/llm/chat/annotation.rb', line 137 def remove_role(role=:clear) = self.select{|m| m[:role].to_s == role.to_s } self.reject!{|m| m[:role].to_s == role.to_s } end |
#save(path, force = true) ⇒ Object
Write and save
209 210 211 212 213 214 215 216 |
# File 'lib/scout/llm/chat/annotation.rb', line 209 def save(path, force = true) path = path.to_s if Symbol === path if not (Open.exists?(path) || Path === path || Path.located?(path)) path = Scout.chats.find[path] end return if Open.exists?(path) && ! force Open.write path, LLM.print(self) end |
#shed ⇒ Object
199 200 201 |
# File 'lib/scout/llm/chat/annotation.rb', line 199 def shed self.annotate [final] end |
#system(content) ⇒ Object
13 14 15 |
# File 'lib/scout/llm/chat/annotation.rb', line 13 def system(content) (:system, content) end |
#tag(content, name = nil, tag = :file, role = :user) ⇒ Object
86 87 88 |
# File 'lib/scout/llm/chat/annotation.rb', line 86 def tag(content, name=nil, tag=:file, role=:user) self. role, LLM.tag(tag, content, name) end |
#task(workflow, task_name, inputs = {}) ⇒ Object
59 60 61 62 63 |
# File 'lib/scout/llm/chat/annotation.rb', line 59 def task(workflow, task_name, inputs = {}) input_str = IndiferentHash. inputs content = [workflow, task_name, input_str]*" " (:task, content) end |
#tool(*parts) ⇒ Object
54 55 56 57 |
# File 'lib/scout/llm/chat/annotation.rb', line 54 def tool(*parts) content = parts * "\n" (:tool, content) end |
#user(content) ⇒ Object
9 10 11 |
# File 'lib/scout/llm/chat/annotation.rb', line 9 def user(content) (:user, content) end |
#write(path, force = true) ⇒ Object
218 219 220 221 222 223 224 225 |
# File 'lib/scout/llm/chat/annotation.rb', line 218 def write(path, force = true) path = path.to_s if Symbol === path if not (Open.exists?(path) || Path === path || Path.located?(path)) path = Scout.chats.find[path] end return if Open.exists?(path) && ! force Open.write path, self.print end |
#write_answer(path, force = true) ⇒ Object
227 228 229 230 231 232 233 234 |
# File 'lib/scout/llm/chat/annotation.rb', line 227 def write_answer(path, force = true) path = path.to_s if Symbol === path if not (Open.exists?(path) || Path === path || Path.located?(path)) path = Scout.chats.find[path] end return if Open.exists?(path) && ! force Open.write path, self.answer end |