meshagent-agents 0.0.1__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 +5 -0
- meshagent/agents/adapter.py +39 -0
- meshagent/agents/agent.py +427 -0
- meshagent/agents/chat.py +316 -0
- meshagent/agents/context.py +90 -0
- meshagent/agents/development.py +32 -0
- meshagent/agents/hosting.py +117 -0
- meshagent/agents/indexer.py +593 -0
- meshagent/agents/listener.py +155 -0
- meshagent/agents/planning.py +603 -0
- meshagent/agents/prompt.py +49 -0
- meshagent/agents/pydantic.py +137 -0
- meshagent/agents/schema.py +50 -0
- meshagent/agents/single_shot_writer.py +92 -0
- meshagent/agents/version.py +1 -0
- meshagent/agents/worker.py +126 -0
- meshagent/agents/writer.py +82 -0
- meshagent_agents-0.0.1.dist-info/LICENSE +201 -0
- meshagent_agents-0.0.1.dist-info/METADATA +29 -0
- meshagent_agents-0.0.1.dist-info/RECORD +22 -0
- meshagent_agents-0.0.1.dist-info/WHEEL +5 -0
- meshagent_agents-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
from .agent import Agent, AgentCallContext, AgentChatContext, RequiredToolkit, TaskRunner, SingleRoomAgent
|
|
2
|
+
from .development import connect_development_agent
|
|
3
|
+
from .listener import Listener, ListenerContext
|
|
4
|
+
from .hosting import RemoteTaskRunnerServer
|
|
5
|
+
from .adapter import ToolResponseAdapter, LLMAdapter
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from .agent import AgentChatContext
|
|
3
|
+
from jsonschema import validate
|
|
4
|
+
from meshagent.tools.toolkit import Response, Toolkit
|
|
5
|
+
from meshagent.api import RoomClient
|
|
6
|
+
from typing import Any, Optional
|
|
7
|
+
|
|
8
|
+
class ToolResponseAdapter(ABC):
|
|
9
|
+
def __init__(self):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
async def to_plain_text(self, *, room: RoomClient, response: Response):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
async def append_messages(self, *, context: AgentChatContext, tool_call: Any, room: RoomClient, response: Response):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LLMAdapter(ABC):
|
|
22
|
+
|
|
23
|
+
def create_chat_context(self) -> AgentChatContext:
|
|
24
|
+
return AgentChatContext()
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def next(self,
|
|
28
|
+
*,
|
|
29
|
+
context: AgentChatContext,
|
|
30
|
+
room: RoomClient,
|
|
31
|
+
toolkits: Toolkit,
|
|
32
|
+
tool_adapter: Optional[ToolResponseAdapter] = None,
|
|
33
|
+
output_schema: Optional[dict] = None,
|
|
34
|
+
) -> Any:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
def validate(response: dict, output_schema: dict):
|
|
38
|
+
validate(response, output_schema)
|
|
39
|
+
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from meshagent.api.room_server_client import RoomException, RequiredToolkit, Requirement, RequiredSchema
|
|
7
|
+
from meshagent.api import WebSocketClientProtocol, ToolDescription, ToolkitDescription, Participant, RemoteParticipant, meshagent_base_url, StorageEntry
|
|
8
|
+
from meshagent.api.protocol import Protocol
|
|
9
|
+
from meshagent.tools.toolkit import Toolkit, Tool, ToolContext
|
|
10
|
+
from meshagent.api.room_server_client import RoomClient, RoomException
|
|
11
|
+
from meshagent.api.schema_document import Document
|
|
12
|
+
from jsonschema import validate
|
|
13
|
+
from typing import Callable, Awaitable
|
|
14
|
+
from .context import AgentCallContext, AgentChatContext
|
|
15
|
+
from .schema import no_arguments_schema
|
|
16
|
+
import logging
|
|
17
|
+
import asyncio
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger("agent")
|
|
21
|
+
logger.setLevel(logging.INFO)
|
|
22
|
+
|
|
23
|
+
class AgentException(RoomException):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RoomTool(Tool):
|
|
28
|
+
def __init__(self, *, toolkit_name: str, name, input_schema, title = None, description = None, rules = None, thumbnail_url = None, participant_id: Optional[str] = None, on_behalf_of_id: Optional[str] = None, defs: Optional[dict] = None):
|
|
29
|
+
self._toolkit_name = toolkit_name
|
|
30
|
+
self._participant_id = participant_id
|
|
31
|
+
self._on_behalf_of_id = on_behalf_of_id
|
|
32
|
+
|
|
33
|
+
super().__init__(name=name, input_schema=input_schema, title=title, description=description, rules=rules, thumbnail_url=thumbnail_url, defs=defs)
|
|
34
|
+
|
|
35
|
+
async def execute(self, context, **kwargs):
|
|
36
|
+
return await context.room.agents.invoke_tool(
|
|
37
|
+
toolkit=self._toolkit_name,
|
|
38
|
+
tool=self.name,
|
|
39
|
+
participant_id=self._participant_id,
|
|
40
|
+
on_behalf_of_id=self._on_behalf_of_id,
|
|
41
|
+
arguments=kwargs,
|
|
42
|
+
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
class Agent:
|
|
46
|
+
|
|
47
|
+
def __init__(self, *, name: str, title: Optional[str] = None, description: Optional[str] = None, requires: Optional[list[Requirement]] = None, labels: Optional[list[str]] = None):
|
|
48
|
+
self._name = name
|
|
49
|
+
if title == None:
|
|
50
|
+
title = name
|
|
51
|
+
self._title = title
|
|
52
|
+
if description == None:
|
|
53
|
+
description = ""
|
|
54
|
+
|
|
55
|
+
self._description = description
|
|
56
|
+
if requires == None:
|
|
57
|
+
requires = []
|
|
58
|
+
self._requires = requires
|
|
59
|
+
|
|
60
|
+
if labels == None:
|
|
61
|
+
labels = []
|
|
62
|
+
|
|
63
|
+
self._labels = labels
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def name(self):
|
|
67
|
+
return self._name
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def description(self):
|
|
71
|
+
return self._description
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def title(self):
|
|
75
|
+
return self._title
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def requires(self):
|
|
79
|
+
return self._requires
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def labels(self):
|
|
83
|
+
return self._labels
|
|
84
|
+
|
|
85
|
+
async def init_chat_context(self) -> AgentChatContext:
|
|
86
|
+
return AgentChatContext()
|
|
87
|
+
|
|
88
|
+
def to_json(self) -> dict:
|
|
89
|
+
return {
|
|
90
|
+
"name" : self.name,
|
|
91
|
+
"title" : self.title,
|
|
92
|
+
"description" : self.description,
|
|
93
|
+
"requires" : list(map(lambda x: x.to_json(), self.requires)),
|
|
94
|
+
"labels" : self.labels
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
class SingleRoomAgent(Agent):
|
|
98
|
+
|
|
99
|
+
def __init__(self, *, name, title = None, description = None, requires = None, labels: Optional[list[str]] = None):
|
|
100
|
+
super().__init__(name=name, title=title, description=description, requires=requires, labels=labels)
|
|
101
|
+
self._room = None
|
|
102
|
+
|
|
103
|
+
async def start(self, *, room: RoomClient) -> None:
|
|
104
|
+
|
|
105
|
+
if self._room != None:
|
|
106
|
+
raise RoomException("room is already started")
|
|
107
|
+
|
|
108
|
+
self._room = room
|
|
109
|
+
|
|
110
|
+
async def stop(self) -> None:
|
|
111
|
+
self._room = None
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def room(self):
|
|
116
|
+
return self._room
|
|
117
|
+
|
|
118
|
+
async def install_requirements(self, participant_id: Optional[str] = None):
|
|
119
|
+
|
|
120
|
+
schemas_by_name = dict[str, StorageEntry]()
|
|
121
|
+
|
|
122
|
+
schemas = await self._room.storage.list(path=".schemas")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
for schema in schemas:
|
|
126
|
+
schemas_by_name[schema.name] = schema
|
|
127
|
+
|
|
128
|
+
toolkits_by_name = dict[str, ToolkitDescription]()
|
|
129
|
+
|
|
130
|
+
visible_tools = await self._room.agents.list_toolkits(participant_id=participant_id)
|
|
131
|
+
|
|
132
|
+
for toolkit_description in visible_tools:
|
|
133
|
+
toolkits_by_name[toolkit_description.name] = toolkit_description
|
|
134
|
+
|
|
135
|
+
installed = False
|
|
136
|
+
|
|
137
|
+
for requirement in self.requires:
|
|
138
|
+
|
|
139
|
+
if isinstance(requirement, RequiredToolkit):
|
|
140
|
+
if requirement.name not in toolkits_by_name:
|
|
141
|
+
|
|
142
|
+
installed = True
|
|
143
|
+
|
|
144
|
+
logger.info(f"Installing required tool {requirement.name}")
|
|
145
|
+
|
|
146
|
+
if requirement.name.startswith("https://"):
|
|
147
|
+
url = requirement.name
|
|
148
|
+
else:
|
|
149
|
+
url = f"{meshagent_base_url()}/toolkits/{requirement.name}"
|
|
150
|
+
|
|
151
|
+
await self._room.agents.make_call(url=url, name=requirement.name, arguments={})
|
|
152
|
+
|
|
153
|
+
elif isinstance(requirement, RequiredSchema):
|
|
154
|
+
|
|
155
|
+
if requirement.name not in schemas_by_name:
|
|
156
|
+
|
|
157
|
+
installed = True
|
|
158
|
+
|
|
159
|
+
logger.info(f"Installing required tool {requirement.name}")
|
|
160
|
+
|
|
161
|
+
if requirement.name.startswith("https://"):
|
|
162
|
+
url = requirement.name
|
|
163
|
+
else:
|
|
164
|
+
url = f"{meshagent_base_url()}/schemas/{requirement.name}"
|
|
165
|
+
|
|
166
|
+
await self._room.agents.make_call(url=url, name=requirement.name, arguments={})
|
|
167
|
+
|
|
168
|
+
else:
|
|
169
|
+
raise RoomException("unsupported requirement")
|
|
170
|
+
|
|
171
|
+
if installed:
|
|
172
|
+
await asyncio.sleep(5)
|
|
173
|
+
|
|
174
|
+
async def get_required_tools(self, participant_id: str) -> list[Toolkit]:
|
|
175
|
+
|
|
176
|
+
toolkits_by_name = dict[str, ToolkitDescription]()
|
|
177
|
+
|
|
178
|
+
toolkits = list[Toolkit]()
|
|
179
|
+
|
|
180
|
+
visible_tools = await self._room.agents.list_toolkits(participant_id=participant_id)
|
|
181
|
+
|
|
182
|
+
for toolkit_description in visible_tools:
|
|
183
|
+
toolkits_by_name[toolkit_description.name] = toolkit_description
|
|
184
|
+
|
|
185
|
+
for required_toolkit in self.requires:
|
|
186
|
+
|
|
187
|
+
if isinstance(required_toolkit, RequiredToolkit):
|
|
188
|
+
|
|
189
|
+
toolkit = toolkits_by_name.get(required_toolkit.name, None)
|
|
190
|
+
if toolkit == None:
|
|
191
|
+
raise RoomException(f"unable to locate required toolkit {required_toolkit.name}")
|
|
192
|
+
|
|
193
|
+
room_tools = list[RoomTool]()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
if required_toolkit.tools == None:
|
|
197
|
+
|
|
198
|
+
for tool_description in toolkit.tools:
|
|
199
|
+
tool = RoomTool(
|
|
200
|
+
on_behalf_of_id=participant_id,
|
|
201
|
+
toolkit_name=toolkit.name,
|
|
202
|
+
name=tool_description.name,
|
|
203
|
+
description=tool_description.description,
|
|
204
|
+
input_schema=tool_description.input_schema,
|
|
205
|
+
title=tool_description.title,
|
|
206
|
+
thumbnail_url=tool_description.thumbnail_url,
|
|
207
|
+
participant_id=participant_id,
|
|
208
|
+
defs = tool_description.defs
|
|
209
|
+
)
|
|
210
|
+
room_tools.append(tool)
|
|
211
|
+
|
|
212
|
+
else:
|
|
213
|
+
tools_by_name = dict[str, ToolDescription]()
|
|
214
|
+
for tool_description in toolkit.tools:
|
|
215
|
+
tools_by_name[tool_description.name] = tool_description
|
|
216
|
+
|
|
217
|
+
for required_tool in required_toolkit.tools:
|
|
218
|
+
|
|
219
|
+
tool_description = tools_by_name.get(required_tool, None)
|
|
220
|
+
if tool_description == None:
|
|
221
|
+
raise RoomException(f"unable to locate required tool {required_tool}")
|
|
222
|
+
|
|
223
|
+
tool = RoomTool(
|
|
224
|
+
on_behalf_of_id=participant_id,
|
|
225
|
+
toolkit_name=toolkit.name,
|
|
226
|
+
name=tool_description.name,
|
|
227
|
+
description=tool_description.description,
|
|
228
|
+
input_schema=tool_description.input_schema,
|
|
229
|
+
title=tool_description.title,
|
|
230
|
+
thumbnail_url=tool_description.thumbnail_url,
|
|
231
|
+
participant_id=participant_id,
|
|
232
|
+
defs = tool_description.defs
|
|
233
|
+
)
|
|
234
|
+
room_tools.append(tool)
|
|
235
|
+
|
|
236
|
+
toolkits.append(Toolkit(
|
|
237
|
+
name = toolkit.name,
|
|
238
|
+
title = toolkit.title,
|
|
239
|
+
description = toolkit.description,
|
|
240
|
+
thumbnail_url = toolkit.thumbnail_url,
|
|
241
|
+
tools = room_tools,
|
|
242
|
+
))
|
|
243
|
+
|
|
244
|
+
return toolkits
|
|
245
|
+
|
|
246
|
+
class TaskRunner(SingleRoomAgent):
|
|
247
|
+
|
|
248
|
+
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):
|
|
249
|
+
super().__init__(name=name, title=title, description=description, requires=requires, labels=labels)
|
|
250
|
+
|
|
251
|
+
self._registration_id = None
|
|
252
|
+
|
|
253
|
+
if input_schema == None:
|
|
254
|
+
input_schema = no_arguments_schema(
|
|
255
|
+
description="execute the agent",
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
if supports_tools == None:
|
|
259
|
+
supports_tools = False
|
|
260
|
+
|
|
261
|
+
self._supports_tools = supports_tools
|
|
262
|
+
self._input_schema = input_schema
|
|
263
|
+
self._output_schema = output_schema
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
async def validate_arguments(self, arguments: dict):
|
|
268
|
+
validate(arguments, self.input_schema)
|
|
269
|
+
|
|
270
|
+
async def validate_response(self, response: dict):
|
|
271
|
+
if self.output_schema != None:
|
|
272
|
+
validate(response, self.output_schema)
|
|
273
|
+
|
|
274
|
+
async def ask(self, *, context: AgentCallContext, arguments: dict) -> dict:
|
|
275
|
+
raise Exception("Not implemented")
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def supports_tools(self):
|
|
279
|
+
return self._supports_tools
|
|
280
|
+
|
|
281
|
+
@property
|
|
282
|
+
def input_schema(self):
|
|
283
|
+
return self._input_schema
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def output_schema(self):
|
|
287
|
+
return self._output_schema
|
|
288
|
+
|
|
289
|
+
def to_json(self) -> dict:
|
|
290
|
+
return {
|
|
291
|
+
"name" : self.name,
|
|
292
|
+
"title" : self.title,
|
|
293
|
+
"description" : self.description,
|
|
294
|
+
"input_schema" : self.input_schema,
|
|
295
|
+
"output_schema" : self.output_schema,
|
|
296
|
+
"requires" : list(map(lambda x: x.to_json(), self.requires)),
|
|
297
|
+
"supports_tools" : self.supports_tools,
|
|
298
|
+
"labels" : self.labels
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async def _register(self):
|
|
302
|
+
self._registration_id = (await self._room.send_request("agent.register_agent", {
|
|
303
|
+
"name": self.name,
|
|
304
|
+
"title" : self.title,
|
|
305
|
+
"description" : self.description,
|
|
306
|
+
"input_schema" : self.input_schema,
|
|
307
|
+
"output_schema" : self.output_schema,
|
|
308
|
+
"requires" : list(map(lambda x : x.to_json(), self.requires)),
|
|
309
|
+
"supports_tools" : self.supports_tools,
|
|
310
|
+
"labels" : self.labels
|
|
311
|
+
}))["id"]
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
async def _unregister(self):
|
|
315
|
+
await self._room.send_request("agent.unregister_agent", {
|
|
316
|
+
"id": self._registration_id
|
|
317
|
+
})
|
|
318
|
+
self._registration_id = None
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
async def start(self, *, room: RoomClient):
|
|
322
|
+
|
|
323
|
+
await super().start(room=room)
|
|
324
|
+
|
|
325
|
+
self._room.protocol.register_handler("agent.ask", self._ask)
|
|
326
|
+
await self._register()
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
async def stop(self):
|
|
330
|
+
if self.room.protocol.is_open:
|
|
331
|
+
await self._unregister()
|
|
332
|
+
else:
|
|
333
|
+
logger.info(f"disconnected '{self.name}' from room, this will automatically happen when all the users leave the room. agents will not keep the room open")
|
|
334
|
+
|
|
335
|
+
self._room.protocol.unregister_handler("agent.ask", self._ask)
|
|
336
|
+
|
|
337
|
+
await super().stop()
|
|
338
|
+
|
|
339
|
+
async def _ask(self, protocol:Protocol, message_id:int, msg_type:str, data:bytes):
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
async def worker():
|
|
343
|
+
# Decode and parse the message
|
|
344
|
+
message = json.loads(data.decode('utf-8'))
|
|
345
|
+
logger.info("got message %s", message)
|
|
346
|
+
args = message["arguments"]
|
|
347
|
+
task_id = message["task_id"]
|
|
348
|
+
context_json = message["context"]
|
|
349
|
+
toolkits_json = message["toolkits"]
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
#context_json = message["context"]
|
|
353
|
+
|
|
354
|
+
try:
|
|
355
|
+
chat_context = await self.init_chat_context()
|
|
356
|
+
|
|
357
|
+
caller : Participant | None = None
|
|
358
|
+
|
|
359
|
+
for participant in self._room.messaging.get_participants():
|
|
360
|
+
if message["caller_id"] == participant.id:
|
|
361
|
+
caller = participant
|
|
362
|
+
break
|
|
363
|
+
|
|
364
|
+
if caller == None:
|
|
365
|
+
caller = RemoteParticipant(
|
|
366
|
+
id=message["caller_id"],
|
|
367
|
+
role="user",
|
|
368
|
+
attributes={}
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
await self.install_requirements(participant_id=caller.id)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
context = AgentCallContext(chat=chat_context, room=self.room, caller=caller)
|
|
376
|
+
|
|
377
|
+
for toolkit_json in toolkits_json:
|
|
378
|
+
tools = []
|
|
379
|
+
for tool_json in toolkit_json["tools"]:
|
|
380
|
+
tools.append(RoomTool(
|
|
381
|
+
on_behalf_of_id=message["caller_id"],
|
|
382
|
+
participant_id=message["caller_id"],
|
|
383
|
+
toolkit_name=toolkit_json["name"],
|
|
384
|
+
name=tool_json["name"],
|
|
385
|
+
title=tool_json["title"],
|
|
386
|
+
description=tool_json["description"],
|
|
387
|
+
input_schema=tool_json["input_schema"],
|
|
388
|
+
thumbnail_url=toolkit_json["thumbnail_url"],
|
|
389
|
+
defs=tool_json.get("defs", None)
|
|
390
|
+
))
|
|
391
|
+
|
|
392
|
+
context.toolkits.append(Toolkit(
|
|
393
|
+
name=toolkit_json["name"],
|
|
394
|
+
title=toolkit_json["title"],
|
|
395
|
+
description=toolkit_json["description"],
|
|
396
|
+
thumbnail_url=toolkit_json["thumbnail_url"],
|
|
397
|
+
tools=tools,
|
|
398
|
+
))
|
|
399
|
+
|
|
400
|
+
response = await self.ask(context=context, arguments=args)
|
|
401
|
+
|
|
402
|
+
await protocol.send(type="agent.ask_response", data=json.dumps({
|
|
403
|
+
"task_id" : task_id,
|
|
404
|
+
"response" : response,
|
|
405
|
+
}))
|
|
406
|
+
|
|
407
|
+
except Exception as e:
|
|
408
|
+
logger.error("Task runner failed to complete task", exc_info=e)
|
|
409
|
+
await protocol.send(type="agent.ask_response", data=json.dumps({
|
|
410
|
+
"task_id" : task_id,
|
|
411
|
+
"error" : str(e),
|
|
412
|
+
}))
|
|
413
|
+
|
|
414
|
+
def on_done(task: asyncio.Task):
|
|
415
|
+
task.result()
|
|
416
|
+
|
|
417
|
+
task = asyncio.create_task(worker())
|
|
418
|
+
task.add_done_callback(on_done)
|
|
419
|
+
|
|
420
|
+
class RunTaskTool(Tool):
|
|
421
|
+
def __init__(self, *, agent_name: str, input_schema: dict, rules = None, thumbnail_url = None):
|
|
422
|
+
super().__init__(name=agent_name, input_schema=input_schema, rules=rules, thumbnail_url=thumbnail_url)
|
|
423
|
+
|
|
424
|
+
self._agent_name = agent_name
|
|
425
|
+
|
|
426
|
+
async def execute(self, context: ToolContext, **kwargs):
|
|
427
|
+
return await context.room.agents.ask(agent=self._agent_name, arguments=kwargs)
|