meshagent-agents 0.0.36__py3-none-any.whl → 0.0.38__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 +390 -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.38.dist-info/METADATA +64 -0
- meshagent_agents-0.0.38.dist-info/RECORD +30 -0
- meshagent_agents-0.0.36.dist-info/METADATA +0 -36
- meshagent_agents-0.0.36.dist-info/RECORD +0 -30
- {meshagent_agents-0.0.36.dist-info → meshagent_agents-0.0.38.dist-info}/WHEEL +0 -0
- {meshagent_agents-0.0.36.dist-info → meshagent_agents-0.0.38.dist-info}/licenses/LICENSE +0 -0
- {meshagent_agents-0.0.36.dist-info → meshagent_agents-0.0.38.dist-info}/top_level.txt +0 -0
meshagent/agents/agent.py
CHANGED
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from copy import deepcopy
|
|
3
|
-
|
|
4
1
|
from typing import Optional
|
|
5
2
|
|
|
6
3
|
from meshagent.api.messaging import unpack_message, pack_message
|
|
7
|
-
from meshagent.api.room_server_client import
|
|
8
|
-
|
|
4
|
+
from meshagent.api.room_server_client import (
|
|
5
|
+
RoomException,
|
|
6
|
+
RequiredToolkit,
|
|
7
|
+
Requirement,
|
|
8
|
+
RequiredSchema,
|
|
9
|
+
)
|
|
10
|
+
from meshagent.api import (
|
|
11
|
+
ToolDescription,
|
|
12
|
+
ToolkitDescription,
|
|
13
|
+
Participant,
|
|
14
|
+
RemoteParticipant,
|
|
15
|
+
meshagent_base_url,
|
|
16
|
+
StorageEntry,
|
|
17
|
+
)
|
|
9
18
|
from meshagent.api.protocol import Protocol
|
|
10
|
-
from meshagent.tools.toolkit import
|
|
11
|
-
|
|
19
|
+
from meshagent.tools.toolkit import (
|
|
20
|
+
Toolkit,
|
|
21
|
+
Tool,
|
|
22
|
+
ToolContext,
|
|
23
|
+
toolkit_factory,
|
|
24
|
+
register_toolkit_factory,
|
|
25
|
+
)
|
|
26
|
+
from meshagent.api.room_server_client import RoomClient
|
|
12
27
|
from jsonschema import validate
|
|
13
28
|
from .context import AgentCallContext, AgentChatContext
|
|
14
29
|
from meshagent.api.schema_util import no_arguments_schema
|
|
15
|
-
from meshagent.api import MeshSchema
|
|
16
30
|
import logging
|
|
17
31
|
import asyncio
|
|
18
|
-
from typing import Optional, Dict, Callable, Coroutine
|
|
19
32
|
|
|
20
33
|
logger = logging.getLogger("agent")
|
|
21
34
|
|
|
@@ -25,97 +38,135 @@ class AgentException(RoomException):
|
|
|
25
38
|
|
|
26
39
|
|
|
27
40
|
class RoomTool(Tool):
|
|
28
|
-
def __init__(
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
toolkit_name: str,
|
|
45
|
+
name,
|
|
46
|
+
input_schema,
|
|
47
|
+
title=None,
|
|
48
|
+
description=None,
|
|
49
|
+
rules=None,
|
|
50
|
+
thumbnail_url=None,
|
|
51
|
+
participant_id: Optional[str] = None,
|
|
52
|
+
on_behalf_of_id: Optional[str] = None,
|
|
53
|
+
defs: Optional[dict] = None,
|
|
54
|
+
):
|
|
29
55
|
self._toolkit_name = toolkit_name
|
|
30
56
|
self._participant_id = participant_id
|
|
31
57
|
self._on_behalf_of_id = on_behalf_of_id
|
|
32
58
|
|
|
33
|
-
super().__init__(
|
|
59
|
+
super().__init__(
|
|
60
|
+
name=name,
|
|
61
|
+
input_schema=input_schema,
|
|
62
|
+
title=title,
|
|
63
|
+
description=description,
|
|
64
|
+
rules=rules,
|
|
65
|
+
thumbnail_url=thumbnail_url,
|
|
66
|
+
defs=defs,
|
|
67
|
+
)
|
|
34
68
|
|
|
35
69
|
async def execute(self, context, **kwargs):
|
|
36
|
-
|
|
70
|
+
return await context.room.agents.invoke_tool(
|
|
37
71
|
toolkit=self._toolkit_name,
|
|
38
72
|
tool=self.name,
|
|
39
73
|
participant_id=self._participant_id,
|
|
40
74
|
on_behalf_of_id=self._on_behalf_of_id,
|
|
41
75
|
arguments=kwargs,
|
|
42
|
-
|
|
43
76
|
)
|
|
44
|
-
|
|
45
|
-
class Agent:
|
|
46
77
|
|
|
47
|
-
|
|
48
|
-
|
|
78
|
+
|
|
79
|
+
class Agent:
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
*,
|
|
83
|
+
name: str,
|
|
84
|
+
title: Optional[str] = None,
|
|
85
|
+
description: Optional[str] = None,
|
|
86
|
+
requires: Optional[list[Requirement]] = None,
|
|
87
|
+
labels: Optional[list[str]] = None,
|
|
88
|
+
):
|
|
49
89
|
self._name = name
|
|
50
|
-
if title
|
|
90
|
+
if title is None:
|
|
51
91
|
title = name
|
|
52
92
|
self._title = title
|
|
53
|
-
if description
|
|
93
|
+
if description is None:
|
|
54
94
|
description = ""
|
|
55
95
|
|
|
56
96
|
self._description = description
|
|
57
|
-
if requires
|
|
97
|
+
if requires is None:
|
|
58
98
|
requires = []
|
|
59
99
|
|
|
60
100
|
self.init_requirements(requires)
|
|
61
101
|
self._requires = requires
|
|
62
|
-
|
|
63
|
-
if labels
|
|
102
|
+
|
|
103
|
+
if labels is None:
|
|
64
104
|
labels = []
|
|
65
|
-
|
|
105
|
+
|
|
66
106
|
self._labels = labels
|
|
67
107
|
|
|
68
108
|
@property
|
|
69
109
|
def name(self):
|
|
70
110
|
return self._name
|
|
71
|
-
|
|
111
|
+
|
|
72
112
|
@property
|
|
73
113
|
def description(self):
|
|
74
114
|
return self._description
|
|
75
|
-
|
|
115
|
+
|
|
76
116
|
@property
|
|
77
117
|
def title(self):
|
|
78
118
|
return self._title
|
|
79
|
-
|
|
119
|
+
|
|
80
120
|
@property
|
|
81
121
|
def requires(self):
|
|
82
122
|
return self._requires
|
|
83
|
-
|
|
123
|
+
|
|
84
124
|
@property
|
|
85
125
|
def labels(self):
|
|
86
126
|
return self._labels
|
|
87
|
-
|
|
127
|
+
|
|
88
128
|
def init_requirements(self, requires): ...
|
|
89
|
-
|
|
129
|
+
|
|
90
130
|
async def init_chat_context(self) -> AgentChatContext:
|
|
91
|
-
return AgentChatContext()
|
|
131
|
+
return AgentChatContext()
|
|
92
132
|
|
|
93
133
|
def to_json(self) -> dict:
|
|
94
134
|
return {
|
|
95
|
-
"name"
|
|
96
|
-
"title"
|
|
97
|
-
"description"
|
|
98
|
-
"requires"
|
|
99
|
-
"labels"
|
|
135
|
+
"name": self.name,
|
|
136
|
+
"title": self.title,
|
|
137
|
+
"description": self.description,
|
|
138
|
+
"requires": list(map(lambda x: x.to_json(), self.requires)),
|
|
139
|
+
"labels": self.labels,
|
|
100
140
|
}
|
|
101
141
|
|
|
102
|
-
class SingleRoomAgent(Agent):
|
|
103
142
|
|
|
104
|
-
|
|
105
|
-
|
|
143
|
+
class SingleRoomAgent(Agent):
|
|
144
|
+
def __init__(
|
|
145
|
+
self,
|
|
146
|
+
*,
|
|
147
|
+
name,
|
|
148
|
+
title=None,
|
|
149
|
+
description=None,
|
|
150
|
+
requires=None,
|
|
151
|
+
labels: Optional[list[str]] = None,
|
|
152
|
+
):
|
|
153
|
+
super().__init__(
|
|
154
|
+
name=name,
|
|
155
|
+
title=title,
|
|
156
|
+
description=description,
|
|
157
|
+
requires=requires,
|
|
158
|
+
labels=labels,
|
|
159
|
+
)
|
|
106
160
|
self._room = None
|
|
107
161
|
|
|
108
|
-
|
|
109
162
|
async def start(self, *, room: RoomClient) -> None:
|
|
110
|
-
|
|
111
|
-
if self._room != None:
|
|
163
|
+
if self._room is not None:
|
|
112
164
|
raise RoomException("room is already started")
|
|
113
|
-
|
|
165
|
+
|
|
114
166
|
self._room = room
|
|
115
167
|
|
|
116
168
|
await self.install_requirements()
|
|
117
169
|
|
|
118
|
-
|
|
119
170
|
async def stop(self) -> None:
|
|
120
171
|
self._room = None
|
|
121
172
|
pass
|
|
@@ -123,70 +174,70 @@ class SingleRoomAgent(Agent):
|
|
|
123
174
|
@property
|
|
124
175
|
def room(self):
|
|
125
176
|
return self._room
|
|
126
|
-
|
|
177
|
+
|
|
127
178
|
async def install_requirements(self, participant_id: Optional[str] = None):
|
|
128
|
-
|
|
129
179
|
schemas_by_name = dict[str, StorageEntry]()
|
|
130
180
|
|
|
131
181
|
schemas = await self._room.storage.list(path=".schemas")
|
|
132
|
-
|
|
182
|
+
|
|
133
183
|
for schema in schemas:
|
|
134
184
|
schemas_by_name[schema.name] = schema
|
|
135
185
|
|
|
136
186
|
toolkits_by_name = dict[str, ToolkitDescription]()
|
|
137
187
|
|
|
138
|
-
visible_tools = await self._room.agents.list_toolkits(
|
|
139
|
-
|
|
188
|
+
visible_tools = await self._room.agents.list_toolkits(
|
|
189
|
+
participant_id=participant_id
|
|
190
|
+
)
|
|
191
|
+
|
|
140
192
|
for toolkit_description in visible_tools:
|
|
141
193
|
toolkits_by_name[toolkit_description.name] = toolkit_description
|
|
142
194
|
|
|
143
195
|
installed = False
|
|
144
196
|
|
|
145
197
|
for requirement in self.requires:
|
|
146
|
-
|
|
147
198
|
if isinstance(requirement, RequiredToolkit):
|
|
148
|
-
|
|
149
|
-
if toolkit_factory(requirement.name) != None:
|
|
199
|
+
if toolkit_factory(requirement.name) is not None:
|
|
150
200
|
# no need to install something we can create from a factory
|
|
151
201
|
continue
|
|
152
202
|
|
|
153
203
|
if requirement.name == "ui":
|
|
154
204
|
# TODO: maybe requirements can be marked as non installable?
|
|
155
205
|
continue
|
|
156
|
-
|
|
206
|
+
|
|
157
207
|
if requirement.name not in toolkits_by_name:
|
|
158
|
-
|
|
159
208
|
installed = True
|
|
160
209
|
|
|
161
210
|
logger.info(f"Installing required tool {requirement.name}")
|
|
162
|
-
|
|
211
|
+
|
|
163
212
|
if requirement.name.startswith("https://"):
|
|
164
213
|
url = requirement.name
|
|
165
214
|
else:
|
|
166
215
|
url = f"{meshagent_base_url()}/toolkits/{requirement.name}"
|
|
167
216
|
|
|
168
|
-
await self._room.agents.make_call(
|
|
169
|
-
|
|
170
|
-
|
|
217
|
+
await self._room.agents.make_call(
|
|
218
|
+
url=url, name=requirement.name, arguments={}
|
|
219
|
+
)
|
|
171
220
|
|
|
221
|
+
elif isinstance(requirement, RequiredSchema):
|
|
172
222
|
if requirement.name not in schemas_by_name:
|
|
173
|
-
|
|
174
223
|
installed = True
|
|
175
224
|
|
|
176
225
|
schema_path = f".schemas/{requirement.name}.json"
|
|
177
|
-
|
|
226
|
+
|
|
178
227
|
if await self._room.storage.exists(path=schema_path):
|
|
179
228
|
# Schema is already in the room
|
|
180
229
|
pass
|
|
181
230
|
else:
|
|
182
231
|
logger.info(f"Installing required tool {requirement.name}")
|
|
183
|
-
|
|
232
|
+
|
|
184
233
|
if requirement.name.startswith("https://"):
|
|
185
234
|
url = requirement.name
|
|
186
235
|
else:
|
|
187
236
|
url = f"{meshagent_base_url()}/schemas/{requirement.name}"
|
|
188
|
-
|
|
189
|
-
await self._room.agents.make_call(
|
|
237
|
+
|
|
238
|
+
await self._room.agents.make_call(
|
|
239
|
+
url=url, name=requirement.name, arguments={}
|
|
240
|
+
)
|
|
190
241
|
|
|
191
242
|
else:
|
|
192
243
|
raise RoomException("unsupported requirement")
|
|
@@ -195,43 +246,39 @@ class SingleRoomAgent(Agent):
|
|
|
195
246
|
await asyncio.sleep(5)
|
|
196
247
|
|
|
197
248
|
async def get_required_toolkits(self, context: ToolContext) -> list[Toolkit]:
|
|
198
|
-
|
|
199
|
-
|
|
200
249
|
tool_target = context.caller
|
|
201
|
-
if context.on_behalf_of
|
|
250
|
+
if context.on_behalf_of is not None:
|
|
202
251
|
tool_target = context.on_behalf_of
|
|
203
252
|
|
|
204
253
|
toolkits_by_name = dict[str, ToolkitDescription]()
|
|
205
254
|
|
|
206
255
|
toolkits = list[Toolkit]()
|
|
207
256
|
|
|
208
|
-
visible_tools = await self._room.agents.list_toolkits(
|
|
257
|
+
visible_tools = await self._room.agents.list_toolkits(
|
|
258
|
+
participant_id=tool_target.id
|
|
259
|
+
)
|
|
209
260
|
|
|
210
261
|
for toolkit_description in visible_tools:
|
|
211
262
|
toolkits_by_name[toolkit_description.name] = toolkit_description
|
|
212
263
|
|
|
213
|
-
|
|
214
264
|
for required_toolkit in self.requires:
|
|
215
|
-
|
|
216
265
|
if isinstance(required_toolkit, RequiredToolkit):
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
toolkit = await toolkit_factory(required_toolkit.name)(context, required_toolkit)
|
|
266
|
+
if toolkit_factory(required_toolkit.name) is not None:
|
|
267
|
+
toolkit = await toolkit_factory(required_toolkit.name)(
|
|
268
|
+
context, required_toolkit
|
|
269
|
+
)
|
|
222
270
|
toolkits.append(toolkit)
|
|
223
271
|
continue
|
|
224
272
|
|
|
225
|
-
|
|
226
273
|
toolkit = toolkits_by_name.get(required_toolkit.name, None)
|
|
227
|
-
if toolkit
|
|
228
|
-
raise RoomException(
|
|
274
|
+
if toolkit is None:
|
|
275
|
+
raise RoomException(
|
|
276
|
+
f"unable to locate required toolkit {required_toolkit.name}"
|
|
277
|
+
)
|
|
229
278
|
|
|
230
279
|
room_tools = list[RoomTool]()
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if required_toolkit.tools == None:
|
|
234
280
|
|
|
281
|
+
if required_toolkit.tools is None:
|
|
235
282
|
for tool_description in toolkit.tools:
|
|
236
283
|
tool = RoomTool(
|
|
237
284
|
on_behalf_of_id=tool_target.id,
|
|
@@ -242,7 +289,7 @@ class SingleRoomAgent(Agent):
|
|
|
242
289
|
title=tool_description.title,
|
|
243
290
|
thumbnail_url=tool_description.thumbnail_url,
|
|
244
291
|
participant_id=tool_target.id,
|
|
245
|
-
defs
|
|
292
|
+
defs=tool_description.defs,
|
|
246
293
|
)
|
|
247
294
|
room_tools.append(tool)
|
|
248
295
|
|
|
@@ -252,10 +299,11 @@ class SingleRoomAgent(Agent):
|
|
|
252
299
|
tools_by_name[tool_description.name] = tool_description
|
|
253
300
|
|
|
254
301
|
for required_tool in required_toolkit.tools:
|
|
255
|
-
|
|
256
302
|
tool_description = tools_by_name.get(required_tool, None)
|
|
257
|
-
if tool_description
|
|
258
|
-
raise RoomException(
|
|
303
|
+
if tool_description is None:
|
|
304
|
+
raise RoomException(
|
|
305
|
+
f"unable to locate required tool {required_tool}"
|
|
306
|
+
)
|
|
259
307
|
|
|
260
308
|
tool = RoomTool(
|
|
261
309
|
on_behalf_of_id=tool_target.id,
|
|
@@ -266,60 +314,78 @@ class SingleRoomAgent(Agent):
|
|
|
266
314
|
title=tool_description.title,
|
|
267
315
|
thumbnail_url=tool_description.thumbnail_url,
|
|
268
316
|
participant_id=tool_target.id,
|
|
269
|
-
defs
|
|
317
|
+
defs=tool_description.defs,
|
|
270
318
|
)
|
|
271
319
|
room_tools.append(tool)
|
|
272
320
|
|
|
273
|
-
toolkits.append(
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
321
|
+
toolkits.append(
|
|
322
|
+
Toolkit(
|
|
323
|
+
name=toolkit.name,
|
|
324
|
+
title=toolkit.title,
|
|
325
|
+
description=toolkit.description,
|
|
326
|
+
thumbnail_url=toolkit.thumbnail_url,
|
|
327
|
+
tools=room_tools,
|
|
328
|
+
)
|
|
329
|
+
)
|
|
280
330
|
|
|
281
331
|
return toolkits
|
|
282
|
-
|
|
283
|
-
class TaskRunner(SingleRoomAgent):
|
|
284
332
|
|
|
285
|
-
def __init__(self, *, name, title = None, description = None, requires = None, supports_tools : Optional[bool] = None, input_schema: dict, output_schema: dict, labels: Optional[list[str]] = None, toolkits: Optional[list[Toolkit]] = None):
|
|
286
|
-
super().__init__(name=name, title=title, description=description, requires=requires, labels=labels)
|
|
287
333
|
|
|
288
|
-
|
|
334
|
+
class TaskRunner(SingleRoomAgent):
|
|
335
|
+
def __init__(
|
|
336
|
+
self,
|
|
337
|
+
*,
|
|
338
|
+
name,
|
|
339
|
+
title=None,
|
|
340
|
+
description=None,
|
|
341
|
+
requires=None,
|
|
342
|
+
supports_tools: Optional[bool] = None,
|
|
343
|
+
input_schema: dict,
|
|
344
|
+
output_schema: dict,
|
|
345
|
+
labels: Optional[list[str]] = None,
|
|
346
|
+
toolkits: Optional[list[Toolkit]] = None,
|
|
347
|
+
):
|
|
348
|
+
super().__init__(
|
|
349
|
+
name=name,
|
|
350
|
+
title=title,
|
|
351
|
+
description=description,
|
|
352
|
+
requires=requires,
|
|
353
|
+
labels=labels,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
if toolkits is None:
|
|
289
357
|
toolkits = []
|
|
290
358
|
|
|
291
359
|
self._toolkits = toolkits
|
|
292
360
|
|
|
293
|
-
self._registration_id = None
|
|
361
|
+
self._registration_id = None
|
|
294
362
|
|
|
295
|
-
if input_schema
|
|
363
|
+
if input_schema is None:
|
|
296
364
|
input_schema = no_arguments_schema(
|
|
297
365
|
description="execute the agent",
|
|
298
366
|
)
|
|
299
367
|
|
|
300
|
-
if supports_tools
|
|
368
|
+
if supports_tools is None:
|
|
301
369
|
supports_tools = False
|
|
302
|
-
|
|
370
|
+
|
|
303
371
|
self._supports_tools = supports_tools
|
|
304
372
|
self._input_schema = input_schema
|
|
305
373
|
self._output_schema = output_schema
|
|
306
|
-
|
|
307
374
|
|
|
308
|
-
|
|
309
375
|
async def validate_arguments(self, arguments: dict):
|
|
310
376
|
validate(arguments, self.input_schema)
|
|
311
377
|
|
|
312
378
|
async def validate_response(self, response: dict):
|
|
313
|
-
if self.output_schema
|
|
379
|
+
if self.output_schema is not None:
|
|
314
380
|
validate(response, self.output_schema)
|
|
315
381
|
|
|
316
382
|
async def ask(self, *, context: AgentCallContext, arguments: dict) -> dict:
|
|
317
383
|
raise Exception("Not implemented")
|
|
318
|
-
|
|
384
|
+
|
|
319
385
|
@property
|
|
320
386
|
def supports_tools(self):
|
|
321
387
|
return self._supports_tools
|
|
322
|
-
|
|
388
|
+
|
|
323
389
|
@property
|
|
324
390
|
def input_schema(self):
|
|
325
391
|
return self._input_schema
|
|
@@ -330,203 +396,240 @@ class TaskRunner(SingleRoomAgent):
|
|
|
330
396
|
|
|
331
397
|
def to_json(self) -> dict:
|
|
332
398
|
return {
|
|
333
|
-
"name"
|
|
334
|
-
"title"
|
|
335
|
-
"description"
|
|
336
|
-
"input_schema"
|
|
337
|
-
"output_schema"
|
|
338
|
-
"requires"
|
|
339
|
-
"supports_tools"
|
|
340
|
-
"labels"
|
|
399
|
+
"name": self.name,
|
|
400
|
+
"title": self.title,
|
|
401
|
+
"description": self.description,
|
|
402
|
+
"input_schema": self.input_schema,
|
|
403
|
+
"output_schema": self.output_schema,
|
|
404
|
+
"requires": list(map(lambda x: x.to_json(), self.requires)),
|
|
405
|
+
"supports_tools": self.supports_tools,
|
|
406
|
+
"labels": self.labels,
|
|
341
407
|
}
|
|
342
|
-
|
|
408
|
+
|
|
343
409
|
async def _register(self):
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
410
|
+
self._registration_id = (
|
|
411
|
+
await self._room.send_request(
|
|
412
|
+
"agent.register_agent",
|
|
413
|
+
{
|
|
414
|
+
"name": self.name,
|
|
415
|
+
"title": self.title,
|
|
416
|
+
"description": self.description,
|
|
417
|
+
"input_schema": self.input_schema,
|
|
418
|
+
"output_schema": self.output_schema,
|
|
419
|
+
"requires": list(map(lambda x: x.to_json(), self.requires)),
|
|
420
|
+
"supports_tools": self.supports_tools,
|
|
421
|
+
"labels": self.labels,
|
|
422
|
+
},
|
|
423
|
+
)
|
|
424
|
+
)["id"]
|
|
355
425
|
|
|
356
426
|
async def _unregister(self):
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
427
|
+
await self._room.send_request(
|
|
428
|
+
"agent.unregister_agent", {"id": self._registration_id}
|
|
429
|
+
)
|
|
430
|
+
self._registration_id = None
|
|
362
431
|
|
|
363
432
|
async def start(self, *, room: RoomClient):
|
|
364
|
-
|
|
365
433
|
await super().start(room=room)
|
|
366
434
|
|
|
367
435
|
self._room.protocol.register_handler("agent.ask", self._ask)
|
|
368
436
|
await self._register()
|
|
369
|
-
|
|
370
437
|
|
|
371
|
-
async def stop(self):
|
|
438
|
+
async def stop(self):
|
|
372
439
|
if self.room.protocol.is_open:
|
|
373
440
|
await self._unregister()
|
|
374
441
|
else:
|
|
375
|
-
logger.info(
|
|
442
|
+
logger.info(
|
|
443
|
+
f"disconnected '{self.name}' from room, this will automatically happen when all the users leave the room. agents will not keep the room open"
|
|
444
|
+
)
|
|
376
445
|
|
|
377
446
|
self._room.protocol.unregister_handler("agent.ask", self._ask)
|
|
378
447
|
|
|
379
448
|
await super().stop()
|
|
380
449
|
|
|
381
|
-
async def _ask(
|
|
382
|
-
|
|
383
|
-
|
|
450
|
+
async def _ask(
|
|
451
|
+
self, protocol: Protocol, message_id: int, msg_type: str, data: bytes
|
|
452
|
+
):
|
|
384
453
|
async def worker():
|
|
385
454
|
# Decode and parse the message
|
|
386
455
|
message, _ = unpack_message(data)
|
|
387
456
|
logger.info("agent got message %s", message)
|
|
388
457
|
args = message["arguments"]
|
|
389
|
-
task_id = message["task_id"]
|
|
390
|
-
context_json = message["context"]
|
|
458
|
+
task_id = message["task_id"]
|
|
391
459
|
toolkits_json = message["toolkits"]
|
|
392
|
-
|
|
393
|
-
#context_json = message["context"]
|
|
460
|
+
|
|
461
|
+
# context_json = message["context"]
|
|
394
462
|
|
|
395
463
|
chat_context = None
|
|
396
464
|
|
|
397
465
|
try:
|
|
398
466
|
chat_context = await self.init_chat_context()
|
|
399
467
|
|
|
400
|
-
caller
|
|
401
|
-
on_behalf_of
|
|
402
|
-
on_behalf_of_id = message.get("on_behalf_of_id", None)
|
|
403
|
-
|
|
468
|
+
caller: Participant | None = None
|
|
469
|
+
on_behalf_of: Participant | None = None
|
|
470
|
+
on_behalf_of_id = message.get("on_behalf_of_id", None)
|
|
471
|
+
|
|
404
472
|
for participant in self._room.messaging.get_participants():
|
|
405
473
|
if message["caller_id"] == participant.id:
|
|
406
474
|
caller = participant
|
|
407
475
|
break
|
|
408
|
-
|
|
476
|
+
|
|
409
477
|
if on_behalf_of_id == participant.id:
|
|
410
478
|
on_behalf_of = participant
|
|
411
479
|
break
|
|
412
480
|
|
|
413
|
-
if caller
|
|
481
|
+
if caller is None:
|
|
414
482
|
caller = RemoteParticipant(
|
|
415
|
-
id=message["caller_id"],
|
|
416
|
-
role="user",
|
|
417
|
-
attributes={}
|
|
483
|
+
id=message["caller_id"], role="user", attributes={}
|
|
418
484
|
)
|
|
419
485
|
|
|
420
|
-
if on_behalf_of_id
|
|
486
|
+
if on_behalf_of_id is not None and on_behalf_of is None:
|
|
421
487
|
on_behalf_of = RemoteParticipant(
|
|
422
|
-
id=message["on_behalf_of_id"],
|
|
423
|
-
role="user",
|
|
424
|
-
attributes={}
|
|
488
|
+
id=message["on_behalf_of_id"], role="user", attributes={}
|
|
425
489
|
)
|
|
426
|
-
|
|
490
|
+
|
|
427
491
|
tool_target = caller
|
|
428
|
-
if on_behalf_of
|
|
492
|
+
if on_behalf_of is not None:
|
|
429
493
|
tool_target = on_behalf_of
|
|
430
494
|
|
|
431
|
-
|
|
432
495
|
toolkits = [
|
|
433
496
|
*self._toolkits,
|
|
434
|
-
*await self.get_required_toolkits(
|
|
497
|
+
*await self.get_required_toolkits(
|
|
498
|
+
context=ToolContext(
|
|
499
|
+
room=self.room,
|
|
500
|
+
caller=caller,
|
|
501
|
+
on_behalf_of=on_behalf_of,
|
|
502
|
+
caller_context={"chat": chat_context.to_json()},
|
|
503
|
+
)
|
|
504
|
+
),
|
|
435
505
|
]
|
|
436
506
|
|
|
437
|
-
context = AgentCallContext(
|
|
438
|
-
|
|
507
|
+
context = AgentCallContext(
|
|
508
|
+
chat=chat_context,
|
|
509
|
+
room=self.room,
|
|
510
|
+
caller=caller,
|
|
511
|
+
on_behalf_of=on_behalf_of,
|
|
512
|
+
toolkits=toolkits,
|
|
513
|
+
)
|
|
514
|
+
|
|
439
515
|
for toolkit_json in toolkits_json:
|
|
440
516
|
tools = []
|
|
441
517
|
for tool_json in toolkit_json["tools"]:
|
|
442
|
-
tools.append(
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
name=toolkit_json["name"],
|
|
456
|
-
title=toolkit_json["title"],
|
|
457
|
-
description=toolkit_json["description"],
|
|
458
|
-
thumbnail_url=toolkit_json["thumbnail_url"],
|
|
459
|
-
tools=tools,
|
|
460
|
-
))
|
|
518
|
+
tools.append(
|
|
519
|
+
RoomTool(
|
|
520
|
+
on_behalf_of_id=on_behalf_of_id,
|
|
521
|
+
participant_id=tool_target.id,
|
|
522
|
+
toolkit_name=toolkit_json["name"],
|
|
523
|
+
name=tool_json["name"],
|
|
524
|
+
title=tool_json["title"],
|
|
525
|
+
description=tool_json["description"],
|
|
526
|
+
input_schema=tool_json["input_schema"],
|
|
527
|
+
thumbnail_url=toolkit_json["thumbnail_url"],
|
|
528
|
+
defs=tool_json.get("defs", None),
|
|
529
|
+
)
|
|
530
|
+
)
|
|
461
531
|
|
|
532
|
+
context.toolkits.append(
|
|
533
|
+
Toolkit(
|
|
534
|
+
name=toolkit_json["name"],
|
|
535
|
+
title=toolkit_json["title"],
|
|
536
|
+
description=toolkit_json["description"],
|
|
537
|
+
thumbnail_url=toolkit_json["thumbnail_url"],
|
|
538
|
+
tools=tools,
|
|
539
|
+
)
|
|
540
|
+
)
|
|
462
541
|
|
|
463
|
-
|
|
464
542
|
response = await self.ask(context=context, arguments=args)
|
|
465
|
-
|
|
466
|
-
await protocol.send(
|
|
467
|
-
"
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
543
|
+
|
|
544
|
+
await protocol.send(
|
|
545
|
+
type="agent.ask_response",
|
|
546
|
+
data=pack_message(
|
|
547
|
+
{
|
|
548
|
+
"task_id": task_id,
|
|
549
|
+
"answer": response,
|
|
550
|
+
"caller_context": {"chat": chat_context.to_json()},
|
|
551
|
+
}
|
|
552
|
+
),
|
|
553
|
+
)
|
|
473
554
|
|
|
474
555
|
except Exception as e:
|
|
475
556
|
logger.error("Task runner failed to complete task", exc_info=e)
|
|
476
|
-
if chat_context
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
557
|
+
if chat_context is not None:
|
|
558
|
+
await protocol.send(
|
|
559
|
+
type="agent.ask_response",
|
|
560
|
+
data=pack_message(
|
|
561
|
+
{
|
|
562
|
+
"task_id": task_id,
|
|
563
|
+
"error": str(e),
|
|
564
|
+
"caller_context": {"chat": chat_context.to_json()},
|
|
565
|
+
}
|
|
566
|
+
),
|
|
567
|
+
)
|
|
485
568
|
else:
|
|
486
|
-
await protocol.send(
|
|
487
|
-
"
|
|
488
|
-
|
|
489
|
-
|
|
569
|
+
await protocol.send(
|
|
570
|
+
type="agent.ask_response",
|
|
571
|
+
data=pack_message(
|
|
572
|
+
{
|
|
573
|
+
"task_id": task_id,
|
|
574
|
+
"error": str(e),
|
|
575
|
+
}
|
|
576
|
+
),
|
|
577
|
+
)
|
|
490
578
|
|
|
491
579
|
def on_done(task: asyncio.Task):
|
|
492
580
|
task.result()
|
|
493
581
|
|
|
494
582
|
task = asyncio.create_task(worker())
|
|
495
|
-
task.add_done_callback(on_done)
|
|
583
|
+
task.add_done_callback(on_done)
|
|
496
584
|
|
|
497
585
|
|
|
498
586
|
class RunTaskTool(Tool):
|
|
499
|
-
def __init__(
|
|
500
|
-
|
|
587
|
+
def __init__(
|
|
588
|
+
self,
|
|
589
|
+
*,
|
|
590
|
+
name: str,
|
|
591
|
+
agent_name: str,
|
|
592
|
+
input_schema: dict,
|
|
593
|
+
rules=None,
|
|
594
|
+
thumbnail_url=None,
|
|
595
|
+
title: Optional[str] = None,
|
|
596
|
+
description: Optional[str] = None,
|
|
597
|
+
):
|
|
598
|
+
super().__init__(
|
|
599
|
+
name=name,
|
|
600
|
+
input_schema=input_schema,
|
|
601
|
+
rules=rules,
|
|
602
|
+
thumbnail_url=thumbnail_url,
|
|
603
|
+
title=title,
|
|
604
|
+
description=description,
|
|
605
|
+
)
|
|
501
606
|
|
|
502
607
|
self._agent_name = agent_name
|
|
503
608
|
|
|
504
609
|
async def execute(self, context: ToolContext, **kwargs):
|
|
505
610
|
return await context.room.agents.ask(agent=self._agent_name, arguments=kwargs)
|
|
506
|
-
|
|
507
611
|
|
|
508
|
-
async def make_run_task_tool(context: ToolContext, toolkit: RequiredToolkit):
|
|
509
612
|
|
|
613
|
+
async def make_run_task_tool(context: ToolContext, toolkit: RequiredToolkit):
|
|
510
614
|
agents = await context.room.agents.list_agents()
|
|
511
615
|
tools = []
|
|
512
616
|
for agent_name in toolkit.tools:
|
|
513
617
|
agent = next((x for x in agents if x.name == agent_name), None)
|
|
514
618
|
|
|
515
|
-
if agent
|
|
619
|
+
if agent is None:
|
|
516
620
|
raise RoomException(f"agent was not found in the room {agent_name}")
|
|
517
|
-
|
|
621
|
+
|
|
518
622
|
tools.append(
|
|
519
623
|
RunTaskTool(
|
|
520
624
|
agent_name=agent_name,
|
|
521
625
|
name=f"run_{agent_name}",
|
|
522
626
|
input_schema=agent.input_schema,
|
|
523
627
|
title=agent.title,
|
|
524
|
-
description=agent.description
|
|
525
|
-
)
|
|
628
|
+
description=agent.description,
|
|
629
|
+
)
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
return Toolkit(name="agents", tools=tools)
|
|
526
633
|
|
|
527
|
-
return Toolkit(
|
|
528
|
-
name="agents",
|
|
529
|
-
tools=tools
|
|
530
|
-
)
|
|
531
634
|
|
|
532
635
|
register_toolkit_factory("agents", make_run_task_tool)
|