meshagent-agents 0.0.37__py3-none-any.whl → 0.0.39__py3-none-any.whl
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.
Potentially problematic release.
This version of meshagent-agents might be problematic. Click here for more details.
- meshagent/agents/__init__.py +27 -2
- meshagent/agents/adapter.py +18 -9
- meshagent/agents/agent.py +317 -214
- meshagent/agents/chat.py +392 -267
- meshagent/agents/context.py +58 -30
- meshagent/agents/development.py +11 -13
- meshagent/agents/hosting.py +109 -46
- meshagent/agents/indexer.py +241 -224
- meshagent/agents/listener.py +55 -52
- meshagent/agents/mail.py +145 -109
- meshagent/agents/planning.py +294 -199
- meshagent/agents/prompt.py +14 -12
- meshagent/agents/pydantic.py +98 -61
- meshagent/agents/schemas/__init__.py +11 -0
- meshagent/agents/schemas/document.py +32 -21
- meshagent/agents/schemas/gallery.py +23 -14
- meshagent/agents/schemas/presentation.py +33 -17
- meshagent/agents/schemas/schema.py +99 -45
- meshagent/agents/schemas/super_editor_document.py +52 -46
- meshagent/agents/single_shot_writer.py +37 -31
- meshagent/agents/thread_schema.py +74 -32
- meshagent/agents/utils.py +20 -12
- meshagent/agents/version.py +1 -1
- meshagent/agents/worker.py +48 -28
- meshagent/agents/writer.py +36 -23
- meshagent_agents-0.0.39.dist-info/METADATA +64 -0
- meshagent_agents-0.0.39.dist-info/RECORD +30 -0
- meshagent_agents-0.0.37.dist-info/METADATA +0 -36
- meshagent_agents-0.0.37.dist-info/RECORD +0 -30
- {meshagent_agents-0.0.37.dist-info → meshagent_agents-0.0.39.dist-info}/WHEEL +0 -0
- {meshagent_agents-0.0.37.dist-info → meshagent_agents-0.0.39.dist-info}/licenses/LICENSE +0 -0
- {meshagent_agents-0.0.37.dist-info → meshagent_agents-0.0.39.dist-info}/top_level.txt +0 -0
meshagent/agents/planning.py
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
from meshagent.agents.agent import AgentCallContext,
|
|
2
|
-
from meshagent.api import
|
|
3
|
-
from meshagent.api.
|
|
4
|
-
from meshagent.
|
|
5
|
-
from meshagent.tools.toolkit import Toolkit, TextResponse, Tool, ToolContext
|
|
1
|
+
from meshagent.agents.agent import AgentCallContext, AgentException
|
|
2
|
+
from meshagent.api import Requirement
|
|
3
|
+
from meshagent.api.messaging import TextResponse
|
|
4
|
+
from meshagent.tools.toolkit import Toolkit, Tool, ToolContext
|
|
6
5
|
from meshagent.api.schema import MeshSchema
|
|
7
6
|
from meshagent.agents.writer import Writer, WriterContext
|
|
8
7
|
from meshagent.agents.adapter import LLMAdapter, ToolResponseAdapter
|
|
9
|
-
from meshagent.api.schema import
|
|
8
|
+
from meshagent.api.schema import ElementType, ChildProperty, ValueProperty
|
|
10
9
|
from meshagent.api.schema_util import merge
|
|
11
10
|
from meshagent.tools.document_tools import build_tools, DocumentAuthoringToolkit
|
|
12
11
|
from meshagent.agents import TaskRunner
|
|
13
12
|
from copy import deepcopy
|
|
14
13
|
from typing import Optional
|
|
15
14
|
|
|
15
|
+
from meshagent.api.schema_util import prompt_schema
|
|
16
|
+
import logging
|
|
17
|
+
|
|
16
18
|
reasoning_rules = [
|
|
17
19
|
"If an ask_user tool call is available, plans should include a series of questions to ask the user to help refine.",
|
|
18
20
|
"If an ask_user tool call is available, ask a maximum of one question per step",
|
|
@@ -21,32 +23,32 @@ reasoning_rules = [
|
|
|
21
23
|
"Do not use tool calls to write estimates of progress or plans",
|
|
22
24
|
"You are a document generation service",
|
|
23
25
|
"The user is asking for a document to be created",
|
|
24
|
-
"You must use tool calls must to generate the answer to the user's question as document"
|
|
26
|
+
"You must use tool calls must to generate the answer to the user's question as document",
|
|
25
27
|
]
|
|
26
28
|
|
|
27
29
|
goto_next_step_message = """
|
|
28
30
|
execute the next step, and provide the result of the step.
|
|
29
31
|
"""
|
|
30
32
|
|
|
33
|
+
|
|
31
34
|
def is_reasoning_done(*, context: AgentCallContext, response: dict) -> bool:
|
|
32
35
|
parsed = response["response"]["data"][0]
|
|
33
36
|
if "abort" in parsed:
|
|
34
37
|
abort = parsed["abort"]
|
|
35
38
|
reason = abort["reason"]
|
|
36
39
|
raise AgentException(reason)
|
|
37
|
-
|
|
40
|
+
|
|
38
41
|
elif "progress" in parsed:
|
|
39
42
|
result = parsed["progress"]
|
|
40
|
-
|
|
43
|
+
|
|
41
44
|
if "done" not in result or result["done"]:
|
|
42
45
|
logger.info("Done generating response %s", result)
|
|
43
46
|
return True
|
|
44
47
|
else:
|
|
45
48
|
context.chat.append_user_message(goto_next_step_message)
|
|
46
49
|
return False
|
|
47
|
-
|
|
50
|
+
|
|
48
51
|
elif "plan" in parsed:
|
|
49
|
-
plan = parsed["plan"]
|
|
50
52
|
context.chat.append_user_message(goto_next_step_message)
|
|
51
53
|
return False
|
|
52
54
|
else:
|
|
@@ -54,29 +56,57 @@ def is_reasoning_done(*, context: AgentCallContext, response: dict) -> bool:
|
|
|
54
56
|
context.chat.append_user_message("this response did not conform to the schema")
|
|
55
57
|
return False
|
|
56
58
|
|
|
57
|
-
def reasoning_schema(*, description: str, elements: Optional[list[ElementType]] = None, has_done_property: bool = True, has_abort: bool = True) -> MeshSchema:
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
def reasoning_schema(
|
|
61
|
+
*,
|
|
62
|
+
description: str,
|
|
63
|
+
elements: Optional[list[ElementType]] = None,
|
|
64
|
+
has_done_property: bool = True,
|
|
65
|
+
has_abort: bool = True,
|
|
66
|
+
) -> MeshSchema:
|
|
67
|
+
if elements is None:
|
|
60
68
|
elements = []
|
|
61
69
|
|
|
62
70
|
progress_properties = [
|
|
63
|
-
ValueProperty(
|
|
64
|
-
|
|
71
|
+
ValueProperty(
|
|
72
|
+
name="percentage",
|
|
73
|
+
description="an estimate for how complete the task is so far",
|
|
74
|
+
type="string",
|
|
75
|
+
),
|
|
76
|
+
ValueProperty(
|
|
77
|
+
name="next",
|
|
78
|
+
description="a very short description of the next step",
|
|
79
|
+
type="string",
|
|
80
|
+
),
|
|
65
81
|
]
|
|
66
82
|
|
|
67
83
|
if has_done_property:
|
|
68
|
-
progress_properties.append(
|
|
84
|
+
progress_properties.append(
|
|
85
|
+
ValueProperty(
|
|
86
|
+
name="done",
|
|
87
|
+
description="whether there is more work to do. the program will continue will continue to send messages to the LLM to refine the answer until done is set to true.",
|
|
88
|
+
type="boolean",
|
|
89
|
+
)
|
|
90
|
+
)
|
|
69
91
|
|
|
70
92
|
elements = elements.copy()
|
|
71
93
|
|
|
72
94
|
if has_abort:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
95
|
+
(
|
|
96
|
+
elements.append(
|
|
97
|
+
ElementType(
|
|
98
|
+
tag_name="abort",
|
|
99
|
+
description="return if the task cannot completed because the user cancelled a request or errors could not be resolved",
|
|
100
|
+
properties=[
|
|
101
|
+
ValueProperty(
|
|
102
|
+
name="reason",
|
|
103
|
+
description="the reason the task was aborted",
|
|
104
|
+
type="string",
|
|
105
|
+
)
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
),
|
|
109
|
+
)
|
|
80
110
|
|
|
81
111
|
return MeshSchema(
|
|
82
112
|
root_tag_name="response",
|
|
@@ -85,88 +115,109 @@ def reasoning_schema(*, description: str, elements: Optional[list[ElementType]]
|
|
|
85
115
|
tag_name="response",
|
|
86
116
|
description="a response for a task",
|
|
87
117
|
properties=[
|
|
88
|
-
ChildProperty(
|
|
89
|
-
"
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
118
|
+
ChildProperty(
|
|
119
|
+
name="data",
|
|
120
|
+
description="the response for a task, should contain a single item",
|
|
121
|
+
child_tag_names=[
|
|
122
|
+
"plan",
|
|
123
|
+
"progress",
|
|
124
|
+
*map(lambda x: x.tag_name, elements),
|
|
125
|
+
],
|
|
126
|
+
)
|
|
127
|
+
],
|
|
93
128
|
),
|
|
94
129
|
ElementType(
|
|
95
130
|
tag_name="plan",
|
|
96
131
|
description="a plan will be output for each task to describe the work that will be done, the work will be performed using tool calls.",
|
|
97
132
|
properties=[
|
|
98
|
-
ChildProperty(
|
|
99
|
-
|
|
133
|
+
ChildProperty(
|
|
134
|
+
name="steps",
|
|
135
|
+
description="the steps for the plan",
|
|
136
|
+
child_tag_names=["step"],
|
|
137
|
+
)
|
|
138
|
+
],
|
|
100
139
|
),
|
|
101
140
|
ElementType(
|
|
102
141
|
tag_name="step",
|
|
103
142
|
description="a step in the plan",
|
|
104
143
|
properties=[
|
|
105
|
-
ValueProperty(
|
|
144
|
+
ValueProperty(
|
|
145
|
+
name="description",
|
|
146
|
+
description="a short sentence description description of the work that will be performed to complete the user's request.",
|
|
147
|
+
type="string",
|
|
148
|
+
)
|
|
106
149
|
],
|
|
107
150
|
),
|
|
108
151
|
ElementType(
|
|
109
152
|
tag_name="progress",
|
|
110
153
|
description="the progress of the task",
|
|
111
|
-
properties=progress_properties
|
|
154
|
+
properties=progress_properties,
|
|
112
155
|
),
|
|
113
156
|
ElementType(
|
|
114
157
|
tag_name="thinking",
|
|
115
158
|
description="use to log information that will not be included in the final answer",
|
|
116
159
|
properties=[
|
|
117
|
-
ValueProperty(
|
|
160
|
+
ValueProperty(
|
|
161
|
+
name="text",
|
|
162
|
+
description="used to log thoughts or progress",
|
|
163
|
+
type="string",
|
|
164
|
+
),
|
|
118
165
|
],
|
|
119
166
|
),
|
|
120
|
-
*elements
|
|
121
|
-
]
|
|
167
|
+
*elements,
|
|
168
|
+
],
|
|
169
|
+
)
|
|
122
170
|
|
|
123
|
-
from meshagent.api.schema_util import prompt_schema
|
|
124
|
-
import logging
|
|
125
171
|
|
|
126
172
|
logger = logging.getLogger("planning_agent")
|
|
127
173
|
|
|
128
174
|
|
|
129
|
-
|
|
130
175
|
class PlanningWriter(Writer):
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
176
|
+
def __init__(
|
|
177
|
+
self,
|
|
178
|
+
*,
|
|
179
|
+
name: str,
|
|
180
|
+
llm_adapter: LLMAdapter,
|
|
181
|
+
tool_adapter: Optional[ToolResponseAdapter] = None,
|
|
182
|
+
max_iterations: int = 100,
|
|
183
|
+
toolkits: Optional[list[Tool]] = None,
|
|
184
|
+
title: Optional[str] = None,
|
|
185
|
+
description: Optional[str] = None,
|
|
186
|
+
rules: Optional[list[str]] | None = None,
|
|
187
|
+
requires: Optional[list[Requirement]] = None,
|
|
188
|
+
supports_tools: Optional[bool] = None,
|
|
189
|
+
):
|
|
134
190
|
super().__init__(
|
|
135
191
|
name=name,
|
|
136
192
|
description=description,
|
|
137
193
|
title=title,
|
|
138
194
|
input_schema=merge(
|
|
139
|
-
schema=prompt_schema(description="use a prompt to generate content"),
|
|
140
|
-
additional_properties={
|
|
141
|
-
|
|
142
|
-
}),
|
|
195
|
+
schema=prompt_schema(description="use a prompt to generate content"),
|
|
196
|
+
additional_properties={"path": {"type": "string"}},
|
|
197
|
+
),
|
|
143
198
|
output_schema={
|
|
144
|
-
"type"
|
|
145
|
-
"additionalProperties"
|
|
146
|
-
"required"
|
|
147
|
-
"properties"
|
|
148
|
-
}
|
|
199
|
+
"type": "object",
|
|
200
|
+
"additionalProperties": False,
|
|
201
|
+
"required": [],
|
|
202
|
+
"properties": {},
|
|
149
203
|
},
|
|
150
|
-
requires
|
|
151
|
-
supports_tools
|
|
204
|
+
requires=requires,
|
|
205
|
+
supports_tools=supports_tools,
|
|
152
206
|
)
|
|
153
207
|
|
|
154
|
-
if rules
|
|
208
|
+
if rules is None:
|
|
155
209
|
rules = []
|
|
156
210
|
|
|
157
211
|
self._rules = rules
|
|
158
212
|
|
|
159
213
|
self._llm_adapter = llm_adapter
|
|
160
|
-
self._tool_adapter = tool_adapter
|
|
214
|
+
self._tool_adapter = tool_adapter
|
|
161
215
|
self._max_iterations = max_iterations
|
|
162
|
-
if toolkits
|
|
216
|
+
if toolkits is None:
|
|
163
217
|
toolkits = []
|
|
164
218
|
self.toolkits = toolkits
|
|
165
219
|
|
|
166
|
-
self._planning_rules
|
|
167
|
-
*reasoning_rules,
|
|
168
|
-
*rules
|
|
169
|
-
]
|
|
220
|
+
self._planning_rules: list[str] = [*reasoning_rules, *rules]
|
|
170
221
|
|
|
171
222
|
async def init_chat_context(self):
|
|
172
223
|
chat = await super().init_chat_context()
|
|
@@ -174,20 +225,17 @@ class PlanningWriter(Writer):
|
|
|
174
225
|
all_rules = self._planning_rules.copy()
|
|
175
226
|
chat.append_rules(rules=all_rules)
|
|
176
227
|
return chat
|
|
177
|
-
|
|
178
|
-
async def write(self, writer_context: WriterContext, arguments: dict):
|
|
179
228
|
|
|
180
|
-
|
|
229
|
+
async def write(self, writer_context: WriterContext, arguments: dict):
|
|
230
|
+
writer_context.call_context.chat.append_rules(
|
|
231
|
+
f"your are writing to the document at the path {writer_context.path}"
|
|
232
|
+
)
|
|
181
233
|
|
|
182
234
|
arguments = arguments.copy()
|
|
183
235
|
self.pop_path(arguments=arguments)
|
|
184
|
-
|
|
236
|
+
|
|
185
237
|
execute = goto_next_step_message
|
|
186
238
|
|
|
187
|
-
react = """
|
|
188
|
-
based on what you know know, either execute the next task or formulate a new plan. If you have sufficient information to complete the task, return a final answer.
|
|
189
|
-
"""
|
|
190
|
-
|
|
191
239
|
prompt = arguments["prompt"]
|
|
192
240
|
|
|
193
241
|
writer_context.call_context.chat.append_user_message(message=prompt)
|
|
@@ -197,41 +245,51 @@ class PlanningWriter(Writer):
|
|
|
197
245
|
i = 0
|
|
198
246
|
while i < self._max_iterations:
|
|
199
247
|
i += 1
|
|
200
|
-
|
|
248
|
+
|
|
201
249
|
try:
|
|
202
250
|
logger.info("COMPLETION STARTING: Step %s", i)
|
|
203
|
-
|
|
251
|
+
|
|
204
252
|
base_args = arguments.copy()
|
|
205
253
|
base_args.pop("path")
|
|
206
|
-
|
|
254
|
+
|
|
207
255
|
toolkits = [
|
|
208
256
|
DocumentAuthoringToolkit(),
|
|
209
257
|
Toolkit(
|
|
210
258
|
name="meshagent.planning-writer.tools",
|
|
211
|
-
tools=build_tools(
|
|
259
|
+
tools=build_tools(
|
|
260
|
+
document_type="document",
|
|
261
|
+
schema=writer_context.document.schema,
|
|
262
|
+
documents={writer_context.path: writer_context.document},
|
|
263
|
+
),
|
|
264
|
+
),
|
|
212
265
|
*self.toolkits,
|
|
213
|
-
*writer_context.call_context.toolkits
|
|
266
|
+
*writer_context.call_context.toolkits,
|
|
214
267
|
]
|
|
215
268
|
|
|
216
|
-
responses = await self._llm_adapter.next(
|
|
269
|
+
responses = await self._llm_adapter.next(
|
|
270
|
+
context=writer_context.call_context.chat,
|
|
271
|
+
room=writer_context.room,
|
|
272
|
+
toolkits=toolkits,
|
|
273
|
+
tool_adapter=self._tool_adapter,
|
|
274
|
+
output_schema=rs,
|
|
275
|
+
)
|
|
217
276
|
|
|
218
277
|
logger.info("COMPLETION RESPONSE %s", responses)
|
|
219
|
-
|
|
278
|
+
|
|
220
279
|
except Exception as e:
|
|
221
280
|
logger.error("Unable to execute reasoning completion task", exc_info=e)
|
|
222
281
|
# retry
|
|
223
|
-
raise(e)
|
|
224
|
-
|
|
282
|
+
raise (e)
|
|
283
|
+
|
|
225
284
|
parsed = responses["response"]["data"][0]
|
|
226
285
|
if "abort" in parsed:
|
|
227
286
|
abort = parsed["abort"]
|
|
228
287
|
reason = abort["reason"]
|
|
229
288
|
raise AgentException(reason)
|
|
230
|
-
|
|
289
|
+
|
|
231
290
|
elif "progress" in parsed:
|
|
232
291
|
result = parsed["progress"]
|
|
233
292
|
|
|
234
|
-
|
|
235
293
|
if "done" not in result or result["done"]:
|
|
236
294
|
logger.info("Done generating response %s", result)
|
|
237
295
|
return {}
|
|
@@ -239,36 +297,52 @@ class PlanningWriter(Writer):
|
|
|
239
297
|
writer_context.call_context.chat.append_user_message(execute)
|
|
240
298
|
continue
|
|
241
299
|
elif "plan" in parsed:
|
|
242
|
-
plan = parsed["plan"]
|
|
243
300
|
writer_context.call_context.chat.append_user_message(execute)
|
|
244
301
|
continue
|
|
245
302
|
else:
|
|
246
303
|
logger.info("recieved invalid response, %s", parsed)
|
|
247
|
-
writer_context.call_context.chat.append_user_message(
|
|
304
|
+
writer_context.call_context.chat.append_user_message(
|
|
305
|
+
"this response did not conform to the schema"
|
|
306
|
+
)
|
|
248
307
|
continue
|
|
249
308
|
|
|
250
|
-
|
|
251
|
-
class PlanningResponder(TaskRunner):
|
|
252
309
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
310
|
+
class PlanningResponder(TaskRunner):
|
|
311
|
+
def __init__(
|
|
312
|
+
self,
|
|
313
|
+
*,
|
|
314
|
+
name: str,
|
|
315
|
+
llm_adapter: LLMAdapter,
|
|
316
|
+
tool_adapter: Optional[ToolResponseAdapter] = None,
|
|
317
|
+
output_schema: dict,
|
|
318
|
+
max_iterations: int = 100,
|
|
319
|
+
toolkits: Optional[list[Toolkit]] = None,
|
|
320
|
+
title: Optional[str] = None,
|
|
321
|
+
description: Optional[str] = None,
|
|
322
|
+
requires: Optional[list[Requirement]] = None,
|
|
323
|
+
supports_tools: bool = True,
|
|
324
|
+
input_prompt: bool = True,
|
|
325
|
+
rules: Optional[list[str]] = None,
|
|
326
|
+
labels: Optional[list[str]] = None,
|
|
327
|
+
):
|
|
328
|
+
if not isinstance(output_schema, dict):
|
|
329
|
+
raise Exception(
|
|
330
|
+
"schema must be a dict, got: {type}".format(type=type(output_schema))
|
|
331
|
+
)
|
|
256
332
|
|
|
257
333
|
self._input_prompt = input_prompt
|
|
258
334
|
|
|
259
|
-
if rules
|
|
335
|
+
if rules is None:
|
|
260
336
|
rules = []
|
|
261
337
|
|
|
262
|
-
|
|
263
338
|
if input_prompt:
|
|
264
339
|
input_schema = prompt_schema(description="use a prompt to generate content")
|
|
265
340
|
else:
|
|
266
341
|
input_schema = {
|
|
267
|
-
"type"
|
|
268
|
-
"additionalProperties"
|
|
269
|
-
"required"
|
|
270
|
-
"properties"
|
|
271
|
-
}
|
|
342
|
+
"type": "object",
|
|
343
|
+
"additionalProperties": False,
|
|
344
|
+
"required": [],
|
|
345
|
+
"properties": {},
|
|
272
346
|
}
|
|
273
347
|
|
|
274
348
|
super().__init__(
|
|
@@ -280,20 +354,17 @@ class PlanningResponder(TaskRunner):
|
|
|
280
354
|
requires=requires,
|
|
281
355
|
supports_tools=supports_tools,
|
|
282
356
|
labels=labels,
|
|
283
|
-
toolkits=toolkits
|
|
357
|
+
toolkits=toolkits,
|
|
284
358
|
)
|
|
285
|
-
|
|
359
|
+
|
|
286
360
|
self._max_iterations = max_iterations
|
|
287
361
|
|
|
288
|
-
self._planning_rules
|
|
289
|
-
*rules,
|
|
290
|
-
*reasoning_rules
|
|
291
|
-
]
|
|
362
|
+
self._planning_rules: list[str] = [*rules, *reasoning_rules]
|
|
292
363
|
|
|
293
364
|
self._responses = dict()
|
|
294
365
|
|
|
295
366
|
self._llm_adapter = llm_adapter
|
|
296
|
-
self._tool_adapter = tool_adapter
|
|
367
|
+
self._tool_adapter = tool_adapter
|
|
297
368
|
|
|
298
369
|
async def init_chat_context(self):
|
|
299
370
|
chat = self._llm_adapter.create_chat_context()
|
|
@@ -302,48 +373,56 @@ class PlanningResponder(TaskRunner):
|
|
|
302
373
|
chat.append_rules(rules=all_rules)
|
|
303
374
|
return chat
|
|
304
375
|
|
|
305
|
-
|
|
306
376
|
async def ask(self, context: AgentCallContext, arguments: dict):
|
|
307
|
-
|
|
308
377
|
class ResponseTool(Tool):
|
|
309
|
-
def __init__(
|
|
378
|
+
def __init__(
|
|
379
|
+
self,
|
|
380
|
+
output_schema: dict,
|
|
381
|
+
context: AgentCallContext,
|
|
382
|
+
parent: PlanningResponder,
|
|
383
|
+
):
|
|
310
384
|
super().__init__(
|
|
311
385
|
name="respond",
|
|
312
|
-
title="respond",
|
|
313
|
-
description="send the response to the user",
|
|
314
|
-
input_schema=output_schema
|
|
386
|
+
title="respond",
|
|
387
|
+
description="send the response to the user",
|
|
388
|
+
input_schema=output_schema,
|
|
315
389
|
)
|
|
316
390
|
self.parent = parent
|
|
317
|
-
self.context = context
|
|
391
|
+
self.context = context
|
|
318
392
|
|
|
319
393
|
async def execute(self, *, context: ToolContext, **kwargs):
|
|
320
394
|
self.parent._responses[self.context] = kwargs
|
|
321
395
|
return TextResponse(text="the response was sent")
|
|
322
|
-
|
|
396
|
+
|
|
323
397
|
class ResponseToolkit(Toolkit):
|
|
324
398
|
def __init__(self, output_schema, context, parent):
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
399
|
+
tools = [
|
|
400
|
+
ResponseTool(
|
|
401
|
+
output_schema=output_schema, context=context, parent=parent
|
|
402
|
+
)
|
|
328
403
|
]
|
|
329
404
|
|
|
330
405
|
super().__init__(
|
|
331
406
|
name="meshagent.responder",
|
|
332
407
|
title="responder",
|
|
333
408
|
description="tools for responding",
|
|
334
|
-
tools=tools
|
|
409
|
+
tools=tools,
|
|
335
410
|
)
|
|
336
|
-
|
|
337
411
|
|
|
338
|
-
context.toolkits.append(
|
|
339
|
-
|
|
412
|
+
context.toolkits.append(
|
|
413
|
+
ResponseToolkit(
|
|
414
|
+
output_schema=self.output_schema, context=context, parent=self
|
|
415
|
+
)
|
|
416
|
+
)
|
|
417
|
+
|
|
340
418
|
execute = goto_next_step_message
|
|
341
419
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
420
|
+
rs = reasoning_schema(
|
|
421
|
+
description="uses tools",
|
|
422
|
+
elements=[],
|
|
423
|
+
has_done_property=True,
|
|
424
|
+
has_abort=True,
|
|
425
|
+
).to_json()
|
|
347
426
|
|
|
348
427
|
if self._input_prompt:
|
|
349
428
|
prompt = arguments["prompt"]
|
|
@@ -353,122 +432,135 @@ class PlanningResponder(TaskRunner):
|
|
|
353
432
|
i = 0
|
|
354
433
|
while i < self._max_iterations:
|
|
355
434
|
i += 1
|
|
356
|
-
|
|
435
|
+
|
|
357
436
|
try:
|
|
358
437
|
logger.info("COMPLETION STARTING: Step %s", i)
|
|
359
|
-
|
|
360
|
-
responses = await self._llm_adapter.next(
|
|
438
|
+
|
|
439
|
+
responses = await self._llm_adapter.next(
|
|
440
|
+
context=context.chat,
|
|
441
|
+
room=room,
|
|
442
|
+
toolkits=context.toolkits,
|
|
443
|
+
tool_adapter=self._tool_adapter,
|
|
444
|
+
output_schema=rs,
|
|
445
|
+
)
|
|
361
446
|
|
|
362
447
|
logger.info("COMPLETION RESPONSE %s", responses)
|
|
363
|
-
|
|
448
|
+
|
|
364
449
|
except Exception as e:
|
|
365
450
|
logger.error("Unable to execute reasoning completion task", exc_info=e)
|
|
366
451
|
# retry
|
|
367
|
-
raise(e)
|
|
368
|
-
|
|
452
|
+
raise (e)
|
|
453
|
+
|
|
369
454
|
parsed = responses["response"]["data"][0]
|
|
370
455
|
|
|
371
456
|
if "abort" in parsed:
|
|
372
457
|
abort = parsed["abort"]
|
|
373
458
|
reason = abort["reason"]
|
|
374
459
|
raise AgentException(reason)
|
|
375
|
-
|
|
460
|
+
|
|
376
461
|
elif "progress" in parsed:
|
|
377
462
|
result = parsed["progress"]
|
|
378
463
|
|
|
379
|
-
if "done" in result and result["done"]:
|
|
464
|
+
if "done" in result and result["done"]:
|
|
380
465
|
if context not in self._responses:
|
|
381
|
-
context.chat.append_user_message(
|
|
466
|
+
context.chat.append_user_message(
|
|
467
|
+
"you must call the respond tool"
|
|
468
|
+
)
|
|
382
469
|
continue
|
|
383
|
-
|
|
470
|
+
|
|
384
471
|
final_answer = self._responses.pop(context)
|
|
385
472
|
logger.info("Done generating response %s", final_answer)
|
|
386
473
|
return final_answer
|
|
387
|
-
|
|
474
|
+
|
|
388
475
|
else:
|
|
389
476
|
context.chat.append_user_message(execute)
|
|
390
477
|
continue
|
|
391
478
|
elif "plan" in parsed:
|
|
392
|
-
plan = parsed["plan"]
|
|
393
479
|
context.chat.append_user_message(execute)
|
|
394
480
|
continue
|
|
395
481
|
else:
|
|
396
482
|
logger.info("recieved invalid response, %s", parsed)
|
|
397
|
-
context.chat.append_user_message(
|
|
483
|
+
context.chat.append_user_message(
|
|
484
|
+
"this response did not conform to the schema"
|
|
485
|
+
)
|
|
398
486
|
continue
|
|
399
487
|
|
|
400
|
-
|
|
401
488
|
return {}
|
|
402
489
|
|
|
403
|
-
class DynamicPlanningResponder(TaskRunner):
|
|
404
490
|
|
|
405
|
-
|
|
406
|
-
|
|
491
|
+
class DynamicPlanningResponder(TaskRunner):
|
|
492
|
+
def __init__(
|
|
493
|
+
self,
|
|
494
|
+
*,
|
|
495
|
+
name: str,
|
|
496
|
+
llm_adapter: LLMAdapter,
|
|
497
|
+
tool_adapter: Optional[ToolResponseAdapter] = None,
|
|
498
|
+
max_iterations: int = 100,
|
|
499
|
+
toolkits: Optional[list[Toolkit]] = None,
|
|
500
|
+
title: Optional[str] = None,
|
|
501
|
+
description: Optional[str] = None,
|
|
502
|
+
):
|
|
407
503
|
super().__init__(
|
|
408
504
|
name=name,
|
|
409
505
|
title=title,
|
|
410
506
|
description=description,
|
|
411
507
|
input_schema=merge(
|
|
412
|
-
schema=prompt_schema(
|
|
413
|
-
|
|
414
|
-
additional_properties={
|
|
415
|
-
"output_schema" : { "type" : "object" }
|
|
416
|
-
}
|
|
508
|
+
schema=prompt_schema(description="use a prompt to generate content"),
|
|
509
|
+
additional_properties={"output_schema": {"type": "object"}},
|
|
417
510
|
),
|
|
418
|
-
output_schema=None
|
|
419
|
-
|
|
511
|
+
output_schema=None,
|
|
512
|
+
)
|
|
513
|
+
|
|
420
514
|
self._max_iterations = max_iterations
|
|
421
515
|
|
|
422
|
-
self._planning_rules
|
|
423
|
-
*reasoning_rules
|
|
424
|
-
]
|
|
516
|
+
self._planning_rules: list[str] = [*reasoning_rules]
|
|
425
517
|
|
|
426
518
|
self._responses = dict()
|
|
427
519
|
|
|
428
520
|
self._llm_adapter = llm_adapter
|
|
429
|
-
self._tool_adapter = tool_adapter
|
|
521
|
+
self._tool_adapter = tool_adapter
|
|
430
522
|
|
|
431
|
-
if toolkits
|
|
523
|
+
if toolkits is None:
|
|
432
524
|
toolkits = []
|
|
433
|
-
|
|
525
|
+
|
|
434
526
|
self.toolkits = toolkits
|
|
435
|
-
|
|
436
527
|
|
|
437
528
|
async def init_chat_context(self):
|
|
438
|
-
chat
|
|
529
|
+
chat = self._llm_adapter.create_chat_context()
|
|
439
530
|
|
|
440
531
|
all_rules = self._planning_rules.copy()
|
|
441
532
|
chat.append_rules(rules=all_rules)
|
|
442
533
|
return chat
|
|
443
534
|
|
|
444
|
-
|
|
445
535
|
async def ask(self, context: AgentCallContext, arguments: dict):
|
|
446
|
-
|
|
447
536
|
dynamic_schema = arguments["output_schema"]
|
|
448
537
|
|
|
449
|
-
|
|
450
538
|
class ResponseTool(Tool):
|
|
451
|
-
def __init__(
|
|
452
|
-
|
|
539
|
+
def __init__(
|
|
540
|
+
self,
|
|
541
|
+
output_schema: dict,
|
|
542
|
+
context: AgentCallContext,
|
|
543
|
+
parent: PlanningResponder,
|
|
544
|
+
):
|
|
453
545
|
output_schema = deepcopy(output_schema)
|
|
454
|
-
|
|
546
|
+
|
|
455
547
|
schema = {
|
|
456
|
-
"type"
|
|
457
|
-
"additionalProperties"
|
|
458
|
-
"required"
|
|
459
|
-
"properties"
|
|
460
|
-
"summary"
|
|
461
|
-
"type"
|
|
462
|
-
"description"
|
|
548
|
+
"type": "object",
|
|
549
|
+
"additionalProperties": False,
|
|
550
|
+
"required": ["summary", "data"],
|
|
551
|
+
"properties": {
|
|
552
|
+
"summary": {
|
|
553
|
+
"type": "string",
|
|
554
|
+
"description": "a summary of the data structure",
|
|
463
555
|
},
|
|
464
|
-
"data": output_schema
|
|
465
|
-
}
|
|
556
|
+
"data": output_schema,
|
|
557
|
+
},
|
|
466
558
|
}
|
|
467
559
|
|
|
468
560
|
if "$defs" in output_schema:
|
|
469
561
|
schema["$defs"] = output_schema["$defs"]
|
|
470
562
|
del output_schema["$defs"]
|
|
471
|
-
|
|
563
|
+
|
|
472
564
|
super().__init__(
|
|
473
565
|
name="respond",
|
|
474
566
|
title="respond",
|
|
@@ -476,7 +568,7 @@ class DynamicPlanningResponder(TaskRunner):
|
|
|
476
568
|
description="send the response to the user",
|
|
477
569
|
)
|
|
478
570
|
self.parent = parent
|
|
479
|
-
self.context = context
|
|
571
|
+
self.context = context
|
|
480
572
|
|
|
481
573
|
async def execute(self, *, context: ToolContext, **kwargs):
|
|
482
574
|
self.parent._responses[self.context] = kwargs
|
|
@@ -486,79 +578,82 @@ class DynamicPlanningResponder(TaskRunner):
|
|
|
486
578
|
def __init__(self, output_schema, context, parent):
|
|
487
579
|
super().__init__(
|
|
488
580
|
name="meshagent.dynamic_response",
|
|
489
|
-
tools=[
|
|
490
|
-
ResponseTool(
|
|
491
|
-
|
|
581
|
+
tools=[
|
|
582
|
+
ResponseTool(
|
|
583
|
+
output_schema=output_schema, context=context, parent=parent
|
|
584
|
+
)
|
|
585
|
+
],
|
|
492
586
|
)
|
|
493
587
|
|
|
494
|
-
context.toolkits.append(
|
|
495
|
-
|
|
588
|
+
context.toolkits.append(
|
|
589
|
+
ResponseToolkit(output_schema=dynamic_schema, context=context, parent=self)
|
|
590
|
+
)
|
|
591
|
+
|
|
496
592
|
execute = goto_next_step_message
|
|
497
593
|
|
|
498
|
-
react = """
|
|
499
|
-
based on what you know know, either execute the next task or formulate a new plan. If you have sufficient information to complete the task, return a final answer.
|
|
500
|
-
"""
|
|
501
|
-
|
|
502
594
|
rs = reasoning_schema(description="uses tools", elements=[]).to_json()
|
|
503
595
|
|
|
504
596
|
prompt = arguments["prompt"]
|
|
505
597
|
|
|
506
598
|
context.chat.append_user_message(message=prompt)
|
|
507
|
-
|
|
599
|
+
|
|
508
600
|
room = context.room
|
|
509
|
-
|
|
601
|
+
|
|
510
602
|
i = 0
|
|
511
603
|
while i < self._max_iterations:
|
|
512
604
|
i += 1
|
|
513
|
-
|
|
605
|
+
|
|
514
606
|
try:
|
|
515
607
|
logger.info("COMPLETION STARTING: Step %s", i)
|
|
516
|
-
|
|
517
|
-
toolkits = [
|
|
518
|
-
*self.toolkits,
|
|
519
|
-
*context.toolkits
|
|
520
|
-
]
|
|
521
608
|
|
|
522
|
-
|
|
609
|
+
toolkits = [*self.toolkits, *context.toolkits]
|
|
523
610
|
|
|
611
|
+
responses = await self._llm_adapter.next(
|
|
612
|
+
context=context.chat,
|
|
613
|
+
room=room,
|
|
614
|
+
toolkits=toolkits,
|
|
615
|
+
tool_adapter=self._tool_adapter,
|
|
616
|
+
output_schema=rs,
|
|
617
|
+
)
|
|
524
618
|
|
|
525
619
|
logger.info("COMPLETION RESPONSE %s", responses)
|
|
526
|
-
|
|
620
|
+
|
|
527
621
|
except Exception as e:
|
|
528
622
|
logger.error("Unable to execute reasoning completion task", exc_info=e)
|
|
529
623
|
# retry
|
|
530
|
-
raise(e)
|
|
531
|
-
|
|
624
|
+
raise (e)
|
|
625
|
+
|
|
532
626
|
parsed = responses["response"]["data"][0]
|
|
533
627
|
|
|
534
628
|
if "abort" in parsed:
|
|
535
629
|
abort = parsed["abort"]
|
|
536
630
|
reason = abort["reason"]
|
|
537
631
|
raise AgentException(reason)
|
|
538
|
-
|
|
632
|
+
|
|
539
633
|
elif "progress" in parsed:
|
|
540
634
|
result = parsed["progress"]
|
|
541
635
|
|
|
542
|
-
if "done" not in result or result["done"]:
|
|
636
|
+
if "done" not in result or result["done"]:
|
|
543
637
|
if context not in self._responses:
|
|
544
|
-
context.chat.append_user_message(
|
|
638
|
+
context.chat.append_user_message(
|
|
639
|
+
"you must call the respond tool"
|
|
640
|
+
)
|
|
545
641
|
continue
|
|
546
|
-
|
|
642
|
+
|
|
547
643
|
final_answer = self._responses.pop(context)
|
|
548
|
-
|
|
644
|
+
|
|
549
645
|
logger.info("Done generating response %s", final_answer)
|
|
550
646
|
return final_answer["data"]
|
|
551
|
-
|
|
647
|
+
|
|
552
648
|
else:
|
|
553
649
|
context.chat.append_user_message(execute)
|
|
554
650
|
continue
|
|
555
651
|
elif "plan" in parsed:
|
|
556
|
-
plan = parsed["plan"]
|
|
557
652
|
context.chat.append_user_message(execute)
|
|
558
653
|
continue
|
|
559
654
|
else:
|
|
560
655
|
logger.info("recieved invalid response, %s", parsed)
|
|
561
|
-
context.chat.append_user_message(
|
|
656
|
+
context.chat.append_user_message(
|
|
657
|
+
"this response did not conform to the schema"
|
|
658
|
+
)
|
|
562
659
|
continue
|
|
563
|
-
|
|
564
|
-
|