scout-ai 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a95a3c664d483df9e6c5d968822ac358e74215770e7387186f5de12ac72cedeb
4
- data.tar.gz: 55e9c02ef0d7794ba797c4fe9c1fdc023c0b08d32178386d53eabcdcb317a0b9
3
+ metadata.gz: 456939ec51f2ea2c9be5a7fa5eb7992161e893dcfb6618b85eac7e7317af25fa
4
+ data.tar.gz: 67d22d1cd09f74c73843f143897d543993df4f5d68b9649ab1751a19a944e8fd
5
5
  SHA512:
6
- metadata.gz: 5252115360b664c8353c05f417b62992bc2970fd04cf1c77281c6eb0ebb185d58ce8b4f3909729b00b7d8b205bf09eb2ccf6ee530044393cf5139b0b44e54f16
7
- data.tar.gz: 59358958fdae5ed1aac9edcffde28ffc21bd348ffd589d467be59a005b4dd2c2e942981399f412c710eec630e748a9a2438273cb2a569aa09c17388bc2e25927
6
+ metadata.gz: 501bf9ff434058cb2ebad6b084a7ffbccf8a392b1a735c9e6e5726afcc23c7331ef471fc4c675130e49920def430332dd01b647b5f9a473c038b8ef0609d55e1
7
+ data.tar.gz: a267f504d6342a15fe1c0b7f180a47e3b7cd532b71fbd4a5fd3868b4fb7337f3a5c4f5d1ce0aa53276eb268e64ec035806d262b7713dba23d65bb50af2d6c3ab
data/.vimproject CHANGED
@@ -48,6 +48,8 @@ scout-ai=$PWD filter="*.rb *.rake Rakefile *.rdoc *.R *.sh *.js *.haml *.sass *.
48
48
  test_log_resonse
49
49
 
50
50
  test_prompt.rb
51
+
52
+ openclaw
51
53
  }
52
54
  lib=lib {
53
55
  scout-ai.rb
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 1.2.1
@@ -1,89 +1,48 @@
1
1
  module LLM
2
2
  class Agent
3
3
 
4
- AGENTS = {}
5
-
6
- def delegate(agent, name, description, &block)
7
- @other_options[:tools] ||= {}
8
- task_name = "hand_off_to_#{name}"
9
-
10
- block ||= Proc.new do |name, parameters|
11
- message = parameters[:message]
12
- new_conversation = parameters[:new_conversation]
13
- Log.medium "Delegated to #{agent}: " + Log.fingerprint(message)
14
- if new_conversation
15
- agent.start
16
- else
17
- agent.purge
18
- end
19
- agent.user message
20
- agent.chat
21
- end
22
-
23
- properties = {
24
- message: {
25
- "type": :string,
26
- "description": "Message to pass to the agent"
27
- },
28
- new_conversation: {
29
- "type": :boolean,
30
- "description": "Erase conversation history and start a new conversation with this message",
31
- "default": false
32
- }
33
- }
34
-
35
- required_inputs = [:message]
36
-
37
- function = {
38
- name: task_name,
39
- description: description,
40
- parameters: {
41
- type: "object",
42
- properties: properties,
43
- required: required_inputs
44
- }
45
- }
46
-
47
- definition = IndiferentHash.setup function.merge(type: 'function', function: function)
4
+ attr_accessor :society, :chats
48
5
 
6
+ def load_agent(agent_name, options)
7
+ raise ParameterException,
8
+ "Agent name must be a single word optionally including a few puntuation characters" unless agent_name =~ /^[a-z_.-]*$/i
9
+ @society ||= {}
10
+ @society[agent_name] ||= LLM.load_agent agent_name, options.merge(self.other_options)
11
+ end
49
12
 
50
- @other_options[:tools][task_name] = [block, definition]
13
+ def load_chat(agent_name, options, chat)
14
+ @chats ||= {}
15
+ @chats[chat] ||= load_agent(agent_name, options).clone
51
16
  end
52
17
 
53
18
  def socialize(options = {})
54
19
  @other_options[:tools] ||= {}
20
+ @society ||= {}
55
21
 
56
- task_name = "ask"
22
+ task_name = :ask
57
23
  block ||= Proc.new do |name, parameters|
58
24
  agent_name, prompt, chat_id = IndiferentHash.process_options parameters.dup,
59
25
  :agent, :prompt, :chat,
60
26
  chat: 'current'
61
27
 
62
28
  begin
63
- raise ParameterException, "Agent name must be a single word optionally including a few puntuation characters" unless agent_name =~ /^[a-z_.-]*$/i
64
-
65
-
66
29
  options = options.dup
67
30
 
68
- #options[:endpoint] ||= Scout::Config.get(:endpoint, name, :Agent, :agent_ask, :delegate)
69
- #options[:model] ||= Scout::Config.get(:model, name, :Agent, :agent_ask, :delegate)
70
-
71
31
  res = case chat_id
72
32
  when 'current'
73
- agent = LLM.load_agent agent_name, options
33
+ agent = load_chat agent_name, options, 'current'
74
34
  chat = self.current_chat - self.start_chat
75
35
  agent.concat chat
76
36
  agent.user prompt
77
37
  agent.chat
78
38
  when 'none', nil, 'false'
79
- agent = LLM.load_agent agent_name, options
39
+ agent = load_agent agent_name, options
80
40
  agent.prompt prompt
81
41
  else
82
- agent = LLM::Agent::AGENTS[[chat_id,agent_name]] ||= LLM.load_agent agent_name, options
42
+ agent = load_chat agent_name, options, chat_id
83
43
  agent.user prompt
84
44
  agent.chat
85
45
  end
86
- iii res
87
46
  res
88
47
  rescue ScoutException
89
48
  next $!
@@ -134,4 +93,51 @@ prompt.
134
93
  @other_options[:tools][task_name] = [block, definition]
135
94
  end
136
95
  end
96
+ def delegate(agent, name, description, &block)
97
+ @other_options[:tools] ||= {}
98
+ task_name = "hand_off_to_#{name}".to_sym
99
+
100
+ block ||= Proc.new do |name, parameters|
101
+ message = parameters[:message]
102
+ new_conversation = parameters[:new_conversation]
103
+ Log.medium "Delegated to #{agent}: " + Log.fingerprint(message)
104
+ if new_conversation
105
+ agent.start
106
+ else
107
+ agent.purge
108
+ end
109
+ agent.user message
110
+ agent.chat
111
+ end
112
+
113
+ properties = {
114
+ message: {
115
+ "type": :string,
116
+ "description": "Message to pass to the agent"
117
+ },
118
+ new_conversation: {
119
+ "type": :boolean,
120
+ "description": "Erase conversation history and start a new conversation with this message",
121
+ "default": false
122
+ }
123
+ }
124
+
125
+ required_inputs = [:message]
126
+
127
+ function = {
128
+ name: task_name,
129
+ description: description,
130
+ parameters: {
131
+ type: "object",
132
+ properties: properties,
133
+ required: required_inputs
134
+ }
135
+ }
136
+
137
+ definition = IndiferentHash.setup function.merge(type: 'function', function: function)
138
+
139
+
140
+ @other_options[:tools][task_name] = [block, definition]
141
+ end
142
+
137
143
  end
data/lib/scout/llm/ask.rb CHANGED
@@ -32,7 +32,7 @@ module LLM
32
32
 
33
33
  options[:meta] = Chat.meta messages
34
34
 
35
- Log.high Log.color :green, "Asking #{endpoint || 'client'}: #{options[:previous_response_id]}\n" + LLM.print(messages)
35
+ Log.high Log.color :green, "Asking #{endpoint || 'client'}: #{options[:previous_response_id]}\n" + Chat.print_brief(messages)
36
36
  tools = options[:tools]
37
37
  Log.high "Tools: #{Log.fingerprint tools.keys}" if tools
38
38
  Log.debug "#{Log.fingerprint tools}}" if tools
@@ -71,7 +71,9 @@ module LLM
71
71
  end
72
72
  end
73
73
 
74
- Log.high Log.color :blue, "Response:\n" + LLM.print(res)
74
+ Chat.setup res if Array === res
75
+
76
+ Log.high Log.color :blue, "Response:\n" + Chat.print_brief(res, %w(meta assistant))
75
77
 
76
78
  res
77
79
  end
@@ -409,8 +409,8 @@ module LLM
409
409
  pattern = {
410
410
  'pt+': [['usage','prompt_tokens']],
411
411
  'ct+': [['usage','completion_tokens']],
412
- 't+': [['usage','total_tokens']],
413
- 'r': [['choices', 0, 'message', 'reasoning_content']],
412
+ 'tt+': [['usage','total_tokens']],
413
+ 'reas': [['choices', 0, 'message', 'reasoning_content']],
414
414
  }
415
415
 
416
416
  meta = {}
@@ -134,6 +134,12 @@ module Chat
134
134
  self.replace new
135
135
  end
136
136
 
137
+ def remove_role(role=:clear)
138
+ messages = self.select{|m| m[:role].to_s == role.to_s }
139
+ self.reject!{|m| m[:role].to_s == role.to_s }
140
+ messages
141
+ end
142
+
137
143
  def json(...)
138
144
  self.format :json
139
145
  output = ask(...)
@@ -139,4 +139,30 @@ module Chat
139
139
  end
140
140
  end * "\n\n"
141
141
  end
142
+
143
+ def self.print_brief(chat, expand = [])
144
+ return chat if String === chat
145
+ expand = expand.collect{|role| role.to_s }
146
+
147
+ "\n" + chat.collect do |message|
148
+ message = IndiferentHash.setup message
149
+ role, content = message.values_at :role, :content
150
+ role = role.to_s
151
+
152
+ str = case message[:content]
153
+ when Hash, Array
154
+ message[:content].to_json
155
+ when nil, ''
156
+ ''
157
+ else
158
+ message[:content].to_s
159
+ end
160
+
161
+ next role, "\n\n" + str if expand.include?(role)
162
+
163
+ [role, Log.fingerprint(str)[1..-2]]
164
+ end.compact.collect do |role,str|
165
+ "#{role}: #{str}"
166
+ end * "\n\n"
167
+ end
142
168
  end
@@ -1,6 +1,13 @@
1
1
  module Chat
2
2
  def self.serialize_meta(meta)
3
- meta.collect{|p| p * "="} * " "
3
+ keys = meta.keys
4
+
5
+ keys = keys.sort_by do |k|
6
+ v = meta[k]
7
+ String === v ? v.length : 0
8
+ end
9
+
10
+ keys.collect{|k| [k,meta[k]] * "="} * " "
4
11
  end
5
12
 
6
13
  def self.parse_meta(str)
@@ -29,6 +36,7 @@ module Chat
29
36
 
30
37
  key = next_key
31
38
  end
39
+
32
40
  meta
33
41
  end
34
42
 
@@ -150,6 +150,10 @@ module Chat
150
150
  next
151
151
  elsif message[:role] == 'introduce'
152
152
  workflow_name = message[:content]
153
+ workflow = begin
154
+ Kernel.const_get workflow_name
155
+ rescue
156
+ end
153
157
  if Open.remote? workflow_name
154
158
  require 'rbbt'
155
159
  require 'scout/offsite/ssh'
@@ -157,7 +161,7 @@ module Chat
157
161
  workflow = RemoteWorkflow.new workflow_name
158
162
  else
159
163
  workflow = Workflow.require_workflow workflow_name
160
- end
164
+ end unless workflow
161
165
 
162
166
  raise "Workflow not found #{workflow_name}" if workflow.nil?
163
167
 
@@ -92,6 +92,7 @@ module LLM
92
92
 
93
93
  tool_call_content.collect do |function_name,function_arguments,tool_call_id,tool_call,content|
94
94
  if Step === content
95
+ step = content
95
96
  if content.done?
96
97
  content = content.load.to_json if content.done?
97
98
  elsif content.error? && content.exception
@@ -103,10 +104,13 @@ module LLM
103
104
  content = {exception: $!.message, stack: $!.backtrace }.to_json
104
105
  end
105
106
  end
107
+ else
108
+ step = nil
106
109
  end
107
110
 
108
111
  if (String === content) && content.length > max_content_length
109
112
  exception_msg = "Function #{function_name} #{tool_call_id} (#{Log.fingerprint function_arguments}) returned #{content.length} characters, which is more than the maximum of #{max_content_length}. To protect the model context window this result was not returned."
113
+ exception_msg += " The results is made available at '#{step.path}'." if step
110
114
  Log.high exception_msg
111
115
  content = {exception: exception_msg, stack: caller}.to_json
112
116
  end
data/scout-ai.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: scout-ai 1.2.0 ruby lib
5
+ # stub: scout-ai 1.2.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "scout-ai".freeze
9
- s.version = "1.2.0".freeze
9
+ s.version = "1.2.1".freeze
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez