meshagent-openai 0.0.3__py3-none-any.whl → 0.0.5__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-openai might be problematic. Click here for more details.
- meshagent/openai/tools/completions_adapter.py +7 -6
- meshagent/openai/tools/responses_adapter.py +241 -91
- {meshagent_openai-0.0.3.dist-info → meshagent_openai-0.0.5.dist-info}/METADATA +4 -4
- meshagent_openai-0.0.5.dist-info/RECORD +9 -0
- {meshagent_openai-0.0.3.dist-info → meshagent_openai-0.0.5.dist-info}/WHEEL +1 -1
- meshagent_openai-0.0.3.dist-info/RECORD +0 -9
- {meshagent_openai-0.0.3.dist-info → meshagent_openai-0.0.5.dist-info}/LICENSE +0 -0
- {meshagent_openai-0.0.3.dist-info → meshagent_openai-0.0.5.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ from meshagent.api import WebSocketClientProtocol, RoomClient, RoomException
|
|
|
4
4
|
from meshagent.tools.blob import Blob, BlobStorage
|
|
5
5
|
from meshagent.tools import Toolkit, ToolContext, Tool
|
|
6
6
|
from meshagent.api.messaging import Response, LinkResponse, FileResponse, JsonResponse, TextResponse, EmptyResponse
|
|
7
|
-
from meshagent.
|
|
7
|
+
from meshagent.api.schema_util import prompt_schema
|
|
8
8
|
from meshagent.agents.adapter import ToolResponseAdapter, LLMAdapter
|
|
9
9
|
from uuid import uuid4
|
|
10
10
|
import json
|
|
@@ -198,7 +198,7 @@ class OpenAICompletionsToolResponseAdapter(ToolResponseAdapter):
|
|
|
198
198
|
else:
|
|
199
199
|
raise Exception("unexpected return type: {type}".format(type=type(response)))
|
|
200
200
|
|
|
201
|
-
async def
|
|
201
|
+
async def create_messages(self, *, context: AgentChatContext, tool_call: Any, room: RoomClient, response: Response) -> list:
|
|
202
202
|
|
|
203
203
|
message = {
|
|
204
204
|
"role" : "tool",
|
|
@@ -209,7 +209,7 @@ class OpenAICompletionsToolResponseAdapter(ToolResponseAdapter):
|
|
|
209
209
|
|
|
210
210
|
room.developer.log_nowait(type="llm.message", data={ "context" : context.id, "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "message" : message })
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
return [ message ]
|
|
213
213
|
|
|
214
214
|
|
|
215
215
|
|
|
@@ -330,16 +330,17 @@ class OpenAICompletionsAdapter(LLMAdapter):
|
|
|
330
330
|
)
|
|
331
331
|
tool_response = await tool_bundle.execute(context=tool_context, tool_call=tool_call)
|
|
332
332
|
logger.info(f"tool response {tool_response}")
|
|
333
|
-
await tool_adapter.
|
|
333
|
+
return await tool_adapter.create_messages(context=context, tool_call=tool_call, room=room, response=tool_response)
|
|
334
|
+
|
|
334
335
|
except Exception as e:
|
|
335
336
|
logger.error(f"unable to complete tool call {tool_call}", exc_info=e)
|
|
336
337
|
room.developer.log_nowait(type="llm.error", data={ "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "error" : f"{e}" })
|
|
337
338
|
|
|
338
|
-
return {
|
|
339
|
+
return [{
|
|
339
340
|
"role" : "tool",
|
|
340
341
|
"content" : json.dumps({"error":f"unable to complete tool call: {e}"}),
|
|
341
342
|
"tool_call_id" : tool_call.id,
|
|
342
|
-
}
|
|
343
|
+
}]
|
|
343
344
|
|
|
344
345
|
|
|
345
346
|
for tool_call in message.tool_calls:
|
|
@@ -3,8 +3,8 @@ from meshagent.agents.agent import Agent, AgentChatContext, AgentCallContext
|
|
|
3
3
|
from meshagent.api import WebSocketClientProtocol, RoomClient, RoomException
|
|
4
4
|
from meshagent.tools.blob import Blob, BlobStorage
|
|
5
5
|
from meshagent.tools import Toolkit, ToolContext, Tool
|
|
6
|
-
from meshagent.api.messaging import Response, LinkResponse, FileResponse, JsonResponse, TextResponse, EmptyResponse
|
|
7
|
-
from meshagent.
|
|
6
|
+
from meshagent.api.messaging import Response, LinkResponse, FileResponse, JsonResponse, TextResponse, EmptyResponse, RawOutputs
|
|
7
|
+
from meshagent.api.schema_util import prompt_schema
|
|
8
8
|
from meshagent.agents.adapter import ToolResponseAdapter, LLMAdapter
|
|
9
9
|
from uuid import uuid4
|
|
10
10
|
import json
|
|
@@ -12,14 +12,13 @@ from jsonschema import validate
|
|
|
12
12
|
from typing import List, Dict
|
|
13
13
|
|
|
14
14
|
from openai import AsyncOpenAI, APIStatusError, NOT_GIVEN
|
|
15
|
-
from openai.types.
|
|
16
|
-
from openai.types.responses import ResponseFunctionToolCall
|
|
15
|
+
from openai.types.responses import ResponseFunctionToolCall, ResponseStreamEvent
|
|
17
16
|
|
|
18
17
|
from copy import deepcopy
|
|
19
18
|
from abc import abstractmethod, ABC
|
|
20
19
|
import os
|
|
21
20
|
import jsonschema
|
|
22
|
-
from typing import Optional, Any
|
|
21
|
+
from typing import Optional, Any, Callable
|
|
23
22
|
|
|
24
23
|
import logging
|
|
25
24
|
import re
|
|
@@ -65,12 +64,13 @@ class ResponsesToolBundle:
|
|
|
65
64
|
self._toolkits = toolkits
|
|
66
65
|
self._executors = dict[str, Toolkit]()
|
|
67
66
|
self._safe_names = {}
|
|
67
|
+
self._tools_by_name = {}
|
|
68
68
|
|
|
69
69
|
open_ai_tools = []
|
|
70
70
|
|
|
71
71
|
for toolkit in toolkits:
|
|
72
72
|
for v in toolkit.tools:
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
k = v.name
|
|
75
75
|
|
|
76
76
|
name = safe_tool_name(k)
|
|
@@ -81,22 +81,29 @@ class ResponsesToolBundle:
|
|
|
81
81
|
self._executors[k] = toolkit
|
|
82
82
|
|
|
83
83
|
self._safe_names[name] = k
|
|
84
|
+
self._tools_by_name[name] = v
|
|
85
|
+
|
|
86
|
+
if v.name != "computer_call":
|
|
87
|
+
|
|
88
|
+
fn = {
|
|
89
|
+
"type" : "function",
|
|
90
|
+
"name" : name,
|
|
91
|
+
"description" : v.description,
|
|
92
|
+
"parameters" : {
|
|
93
|
+
**v.input_schema,
|
|
94
|
+
},
|
|
95
|
+
"strict": True,
|
|
96
|
+
}
|
|
84
97
|
|
|
85
|
-
fn = {
|
|
86
|
-
"type" : "function",
|
|
87
|
-
"name" : name,
|
|
88
|
-
"description" : v.description,
|
|
89
|
-
"parameters" : {
|
|
90
|
-
**v.input_schema,
|
|
91
|
-
},
|
|
92
|
-
"strict": True,
|
|
93
|
-
}
|
|
94
98
|
|
|
99
|
+
if v.defs != None:
|
|
100
|
+
fn["parameters"]["$defs"] = v.defs
|
|
101
|
+
|
|
102
|
+
open_ai_tools.append(fn)
|
|
95
103
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
open_ai_tools.append(fn)
|
|
104
|
+
else:
|
|
105
|
+
|
|
106
|
+
open_ai_tools.append(v.options)
|
|
100
107
|
|
|
101
108
|
if len(open_ai_tools) == 0:
|
|
102
109
|
open_ai_tools = None
|
|
@@ -127,7 +134,10 @@ class ResponsesToolBundle:
|
|
|
127
134
|
except Exception as e:
|
|
128
135
|
logger.error("failed calling %s %s", tool_call.id, name, exc_info=e)
|
|
129
136
|
raise
|
|
130
|
-
|
|
137
|
+
|
|
138
|
+
def get_tool(self, name: str) -> Tool | None:
|
|
139
|
+
return self._tools_by_name.get(name, None)
|
|
140
|
+
|
|
131
141
|
def contains(self, name: str) -> bool:
|
|
132
142
|
return name in self._open_ai_tools
|
|
133
143
|
|
|
@@ -150,7 +160,8 @@ class OpenAIResponsesToolResponseAdapter(ToolResponseAdapter):
|
|
|
150
160
|
"url" : response.url,
|
|
151
161
|
})
|
|
152
162
|
|
|
153
|
-
elif isinstance(response, JsonResponse):
|
|
163
|
+
elif isinstance(response, JsonResponse):
|
|
164
|
+
|
|
154
165
|
return json.dumps(response.json)
|
|
155
166
|
|
|
156
167
|
elif isinstance(response, TextResponse):
|
|
@@ -193,34 +204,45 @@ class OpenAIResponsesToolResponseAdapter(ToolResponseAdapter):
|
|
|
193
204
|
else:
|
|
194
205
|
raise Exception("unexpected return type: {type}".format(type=type(response)))
|
|
195
206
|
|
|
196
|
-
async def
|
|
207
|
+
async def create_messages(self, *, context: AgentChatContext, tool_call: ResponseFunctionToolCall, room: RoomClient, response: Response) -> list:
|
|
197
208
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
"type" : "function_call_output"
|
|
202
|
-
}
|
|
203
|
-
|
|
209
|
+
if isinstance(response, RawOutputs):
|
|
210
|
+
|
|
211
|
+
for output in response.outputs:
|
|
204
212
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
213
|
+
room.developer.log_nowait(type="llm.message", data={ "context" : context.id, "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "message" : output })
|
|
214
|
+
|
|
215
|
+
return response.outputs
|
|
216
|
+
else:
|
|
217
|
+
output = await self.to_plain_text(room=room, response=response)
|
|
218
|
+
|
|
219
|
+
message = {
|
|
220
|
+
"output" : output,
|
|
221
|
+
"call_id" : tool_call.call_id,
|
|
222
|
+
"type" : "function_call_output"
|
|
223
|
+
}
|
|
208
224
|
|
|
209
225
|
|
|
226
|
+
room.developer.log_nowait(type="llm.message", data={ "context" : context.id, "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "message" : message })
|
|
227
|
+
|
|
228
|
+
return [ message ]
|
|
229
|
+
|
|
230
|
+
|
|
210
231
|
|
|
211
232
|
|
|
212
|
-
class OpenAIResponsesAdapter(LLMAdapter):
|
|
233
|
+
class OpenAIResponsesAdapter(LLMAdapter[ResponsesToolBundle]):
|
|
213
234
|
def __init__(self,
|
|
214
235
|
model: str = os.getenv("OPENAI_MODEL"),
|
|
215
236
|
parallel_tool_calls : Optional[bool] = None,
|
|
216
237
|
client: Optional[AsyncOpenAI] = None,
|
|
217
238
|
reasoning_effort: Optional[str] = None,
|
|
239
|
+
retries : int = 10,
|
|
218
240
|
):
|
|
219
241
|
self._model = model
|
|
220
242
|
self._parallel_tool_calls = parallel_tool_calls
|
|
221
243
|
self._client = client
|
|
222
244
|
self._reasoning_effort = reasoning_effort
|
|
223
|
-
|
|
245
|
+
self._retries = retries
|
|
224
246
|
|
|
225
247
|
def create_chat_context(self):
|
|
226
248
|
system_role = "system"
|
|
@@ -228,6 +250,8 @@ class OpenAIResponsesAdapter(LLMAdapter):
|
|
|
228
250
|
system_role = "developer"
|
|
229
251
|
elif self._model.startswith("o3"):
|
|
230
252
|
system_role = "developer"
|
|
253
|
+
elif self._model.startswith("computer-use"):
|
|
254
|
+
system_role = "developer"
|
|
231
255
|
|
|
232
256
|
context = AgentChatContext(
|
|
233
257
|
system_role=system_role
|
|
@@ -235,6 +259,40 @@ class OpenAIResponsesAdapter(LLMAdapter):
|
|
|
235
259
|
|
|
236
260
|
return context
|
|
237
261
|
|
|
262
|
+
async def check_for_termination(self, *, context: AgentChatContext, room: RoomClient) -> bool:
|
|
263
|
+
|
|
264
|
+
if len(context.previous_messages) > 0:
|
|
265
|
+
last_message = context.previous_messages[-1]
|
|
266
|
+
logger.info(f"last_message {last_message}")
|
|
267
|
+
|
|
268
|
+
for message in context.messages:
|
|
269
|
+
|
|
270
|
+
if message.get("type", "message") != "message":
|
|
271
|
+
logger.info(f"found {message.get("type", "message")}")
|
|
272
|
+
|
|
273
|
+
return False
|
|
274
|
+
|
|
275
|
+
return True
|
|
276
|
+
|
|
277
|
+
def _get_client(self, *, room: RoomClient) -> AsyncOpenAI:
|
|
278
|
+
if self._client != None:
|
|
279
|
+
openai = self._client
|
|
280
|
+
else:
|
|
281
|
+
token : str = room.protocol.token
|
|
282
|
+
url : str = room.room_url
|
|
283
|
+
|
|
284
|
+
room_proxy_url = f"{url}/v1"
|
|
285
|
+
|
|
286
|
+
openai=AsyncOpenAI(
|
|
287
|
+
api_key=token,
|
|
288
|
+
base_url=room_proxy_url,
|
|
289
|
+
default_headers={
|
|
290
|
+
"Meshagent-Session" : room.session_id
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
return openai
|
|
295
|
+
|
|
238
296
|
# Takes the current chat context, executes a completion request and processes the response.
|
|
239
297
|
# If a tool calls are requested, invokes the tools, processes the tool calls results, and appends the tool call results to the context
|
|
240
298
|
async def next(self,
|
|
@@ -244,28 +302,14 @@ class OpenAIResponsesAdapter(LLMAdapter):
|
|
|
244
302
|
toolkits: Toolkit,
|
|
245
303
|
tool_adapter: Optional[ToolResponseAdapter] = None,
|
|
246
304
|
output_schema: Optional[dict] = None,
|
|
305
|
+
event_handler: Optional[Callable[[ResponseStreamEvent],None]] = None
|
|
247
306
|
):
|
|
248
307
|
if tool_adapter == None:
|
|
249
308
|
tool_adapter = OpenAIResponsesToolResponseAdapter()
|
|
250
309
|
|
|
251
310
|
try:
|
|
252
|
-
if self._client != None:
|
|
253
|
-
openai = self._client
|
|
254
|
-
else:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
token : str = room.protocol.token
|
|
258
|
-
url : str = room.room_url
|
|
259
|
-
|
|
260
|
-
room_proxy_url = f"{url}/v1"
|
|
261
311
|
|
|
262
|
-
|
|
263
|
-
api_key=token,
|
|
264
|
-
base_url=room_proxy_url,
|
|
265
|
-
default_headers={
|
|
266
|
-
"Meshagent-Session" : room.session_id
|
|
267
|
-
}
|
|
268
|
-
)
|
|
312
|
+
openai = self._get_client(room=room)
|
|
269
313
|
|
|
270
314
|
tool_bundle = ResponsesToolBundle(toolkits=[
|
|
271
315
|
*toolkits,
|
|
@@ -276,17 +320,23 @@ class OpenAIResponsesAdapter(LLMAdapter):
|
|
|
276
320
|
logger.info("OpenAI Tools: %s", json.dumps(open_ai_tools))
|
|
277
321
|
else:
|
|
278
322
|
logger.info("OpenAI Tools: Empty")
|
|
323
|
+
open_ai_tools = NOT_GIVEN
|
|
279
324
|
|
|
280
325
|
response_schema = output_schema
|
|
281
326
|
response_name = "response"
|
|
282
327
|
|
|
283
|
-
|
|
284
|
-
while
|
|
328
|
+
|
|
329
|
+
while True:
|
|
330
|
+
|
|
285
331
|
logger.info("model: %s, context: %s, output_schema: %s", self._model, context.messages, output_schema)
|
|
286
332
|
ptc = self._parallel_tool_calls
|
|
287
333
|
extra = {}
|
|
288
334
|
if ptc != None and self._model.startswith("o") == False:
|
|
289
335
|
extra["parallel_tool_calls"] = ptc
|
|
336
|
+
|
|
337
|
+
trunc = NOT_GIVEN
|
|
338
|
+
if self._model == "computer-use-preview":
|
|
339
|
+
trunc = "auto"
|
|
290
340
|
|
|
291
341
|
text = NOT_GIVEN
|
|
292
342
|
if output_schema != None:
|
|
@@ -305,19 +355,36 @@ class OpenAIResponsesAdapter(LLMAdapter):
|
|
|
305
355
|
"effort" : self._reasoning_effort
|
|
306
356
|
}
|
|
307
357
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
tools = open_ai_tools,
|
|
312
|
-
text = text,
|
|
313
|
-
reasoning=reasoning,
|
|
314
|
-
)
|
|
358
|
+
previous_response_id = NOT_GIVEN
|
|
359
|
+
if context.previous_response_id != None:
|
|
360
|
+
previous_response_id = context.previous_response_id
|
|
315
361
|
|
|
316
|
-
|
|
362
|
+
stream = event_handler != None
|
|
317
363
|
|
|
318
|
-
for
|
|
319
|
-
|
|
364
|
+
for i in range(self._retries + 1):
|
|
365
|
+
if range == self._retries:
|
|
366
|
+
raise RoomException("exceeded maximum attempts calling openai")
|
|
367
|
+
try:
|
|
368
|
+
response = await openai.responses.create(
|
|
369
|
+
stream=stream,
|
|
370
|
+
model = self._model,
|
|
371
|
+
input = context.messages,
|
|
372
|
+
tools = open_ai_tools,
|
|
373
|
+
text = text,
|
|
374
|
+
previous_response_id=previous_response_id,
|
|
375
|
+
reasoning=reasoning,
|
|
376
|
+
truncation=trunc
|
|
377
|
+
)
|
|
378
|
+
break
|
|
379
|
+
except Exception as e:
|
|
380
|
+
logger.error(f"error calling openai attempt: {i+1}", exc_info=e)
|
|
381
|
+
if i == self._retries:
|
|
382
|
+
raise
|
|
320
383
|
|
|
384
|
+
|
|
385
|
+
async def handle_message(message):
|
|
386
|
+
|
|
387
|
+
|
|
321
388
|
if message.type == "function_call":
|
|
322
389
|
|
|
323
390
|
tasks = []
|
|
@@ -330,56 +397,139 @@ class OpenAIResponsesAdapter(LLMAdapter):
|
|
|
330
397
|
)
|
|
331
398
|
tool_response = await tool_bundle.execute(context=tool_context, tool_call=tool_call)
|
|
332
399
|
logger.info(f"tool response {tool_response}")
|
|
333
|
-
await tool_adapter.
|
|
400
|
+
return await tool_adapter.create_messages(context=context, tool_call=tool_call, room=room, response=tool_response)
|
|
334
401
|
except Exception as e:
|
|
335
402
|
logger.error(f"unable to complete tool call {tool_call}", exc_info=e)
|
|
336
403
|
room.developer.log_nowait(type="llm.error", data={ "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "error" : f"{e}" })
|
|
337
404
|
|
|
338
|
-
return {
|
|
405
|
+
return [{
|
|
339
406
|
"output" : json.dumps({"error":f"unable to complete tool call: {e}"}),
|
|
340
407
|
"call_id" : tool_call.call_id,
|
|
341
408
|
"type" : "function_call_output"
|
|
342
|
-
}
|
|
409
|
+
}]
|
|
343
410
|
|
|
344
411
|
|
|
345
412
|
tasks.append(asyncio.create_task(do_tool_call(message)))
|
|
346
413
|
|
|
347
414
|
results = await asyncio.gather(*tasks)
|
|
348
415
|
|
|
416
|
+
all_results = []
|
|
349
417
|
for result in results:
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
elif response.output_text != None:
|
|
418
|
+
room.developer.log_nowait(type="llm.message", data={ "context" : context.id, "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "message" : result })
|
|
419
|
+
all_results.extend(result)
|
|
420
|
+
|
|
421
|
+
return all_results, False
|
|
355
422
|
|
|
356
|
-
|
|
423
|
+
elif message.type == "computer_call" and tool_bundle.get_tool("computer_call"):
|
|
424
|
+
tool_context = ToolContext(
|
|
425
|
+
room=room,
|
|
426
|
+
caller=room.local_participant,
|
|
427
|
+
)
|
|
428
|
+
outputs = (await tool_bundle.get_tool("computer_call").execute(context=tool_context, arguments=message.to_dict(mode="json"))).outputs
|
|
429
|
+
|
|
430
|
+
return outputs, False
|
|
431
|
+
|
|
432
|
+
elif message.type == "reasoning":
|
|
433
|
+
reasoning = tool_bundle.get_tool("reasoning_tool")
|
|
434
|
+
if reasoning != None:
|
|
435
|
+
await tool_bundle.get_tool("reasoning_tool").execute(context=tool_context, arguments=message.to_dict(mode="json"))
|
|
357
436
|
|
|
358
|
-
|
|
359
|
-
if response_schema == None:
|
|
360
|
-
return content
|
|
437
|
+
elif message.type == "message":
|
|
361
438
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
full_response = json.loads(
|
|
439
|
+
contents = message.content
|
|
440
|
+
if response_schema == None:
|
|
441
|
+
return [], False
|
|
442
|
+
else:
|
|
443
|
+
for content in contents:
|
|
444
|
+
# First try to parse the result
|
|
445
|
+
try:
|
|
446
|
+
full_response = json.loads(content.text)
|
|
447
|
+
# sometimes open ai packs two JSON chunks seperated by newline, check if that's why we couldn't parse
|
|
448
|
+
except json.decoder.JSONDecodeError as e:
|
|
449
|
+
for part in content.text.splitlines():
|
|
450
|
+
if len(part.strip()) > 0:
|
|
451
|
+
full_response = json.loads(part)
|
|
452
|
+
|
|
453
|
+
try:
|
|
454
|
+
self.validate(response=full_response, output_schema=response_schema)
|
|
455
|
+
except Exception as e:
|
|
456
|
+
logger.error("recieved invalid response, retrying", exc_info=e)
|
|
457
|
+
error = { "role" : "user", "content" : "encountered a validation error with the output: {error}".format(error=e)}
|
|
458
|
+
room.developer.log_nowait(type="llm.message", data={ "context" : message.id, "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "message" : error })
|
|
459
|
+
context.messages.append(error)
|
|
460
|
+
continue
|
|
370
461
|
|
|
371
|
-
|
|
372
|
-
self.validate(response=full_response, output_schema=response_schema)
|
|
373
|
-
except Exception as e:
|
|
374
|
-
logger.error("recieved invalid response, retrying", exc_info=e)
|
|
375
|
-
error = { "role" : "user", "content" : "encountered a validation error with the output: {error}".format(error=e)}
|
|
376
|
-
room.developer.log_nowait(type="llm.message", data={ "context" : context.id, "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "message" : error })
|
|
377
|
-
context.messages.append(error)
|
|
378
|
-
continue
|
|
379
|
-
|
|
380
|
-
return full_response
|
|
462
|
+
return [ full_response ], True
|
|
381
463
|
else:
|
|
382
464
|
raise RoomException("Unexpected response from OpenAI {response}".format(response=message))
|
|
465
|
+
|
|
466
|
+
return [], False
|
|
467
|
+
|
|
468
|
+
if stream == False:
|
|
469
|
+
room.developer.log_nowait(type="llm.message", data={ "context" : context.id, "participant_id" : room.local_participant.id, "participant_name" : room.local_participant.get_attribute("name"), "response" : response.to_dict() })
|
|
470
|
+
|
|
471
|
+
context.create_response(response.id)
|
|
472
|
+
|
|
473
|
+
final_outputs = []
|
|
474
|
+
|
|
475
|
+
for message in response.output:
|
|
476
|
+
outputs, done = await handle_message(message=message)
|
|
477
|
+
if done:
|
|
478
|
+
final_outputs.extend(outputs)
|
|
479
|
+
else:
|
|
480
|
+
for output in outputs:
|
|
481
|
+
context.messages.append(output)
|
|
482
|
+
|
|
483
|
+
if len(final_outputs) > 0:
|
|
484
|
+
|
|
485
|
+
return final_outputs[0]
|
|
486
|
+
|
|
487
|
+
else:
|
|
488
|
+
|
|
489
|
+
final_outputs = []
|
|
490
|
+
all_outputs = []
|
|
491
|
+
async for e in response:
|
|
492
|
+
|
|
493
|
+
event : ResponseStreamEvent = e
|
|
494
|
+
|
|
495
|
+
event_handler(event)
|
|
496
|
+
|
|
497
|
+
if event.type == "response.completed":
|
|
498
|
+
context.create_response(event.response.id)
|
|
499
|
+
|
|
500
|
+
context.messages.extend(all_outputs)
|
|
501
|
+
|
|
502
|
+
term = await self.check_for_termination(context=context, room=room)
|
|
503
|
+
if term:
|
|
504
|
+
text = ""
|
|
505
|
+
for output in event.response.output:
|
|
506
|
+
if output.type == "message":
|
|
507
|
+
for content in output.content:
|
|
508
|
+
text += content.text
|
|
509
|
+
|
|
510
|
+
return text
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
all_outputs = []
|
|
514
|
+
|
|
515
|
+
elif event.type == "response.output_item.done":
|
|
516
|
+
|
|
517
|
+
context.previous_messages.append(event.item.to_dict())
|
|
518
|
+
|
|
519
|
+
outputs, done = await handle_message(message=event.item)
|
|
520
|
+
if done:
|
|
521
|
+
final_outputs.extend(outputs)
|
|
522
|
+
else:
|
|
523
|
+
for output in outputs:
|
|
524
|
+
all_outputs.append(output)
|
|
525
|
+
|
|
526
|
+
if len(final_outputs) > 0:
|
|
527
|
+
|
|
528
|
+
return final_outputs[0]
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
383
533
|
except APIStatusError as e:
|
|
384
534
|
raise RoomException(f"Error from OpenAI: {e}")
|
|
385
535
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: meshagent-openai
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: OpenAI Building Blocks for Meshagent
|
|
5
5
|
Home-page:
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -14,9 +14,9 @@ Requires-Dist: pyjwt>=2.0.0
|
|
|
14
14
|
Requires-Dist: pytest>=8.3.4
|
|
15
15
|
Requires-Dist: pytest-asyncio>=0.24.0
|
|
16
16
|
Requires-Dist: openai>=1.66.2
|
|
17
|
-
Requires-Dist: meshagent-api>=0.0.
|
|
18
|
-
Requires-Dist: meshagent-agents>=0.0.
|
|
19
|
-
Requires-Dist: meshagent-tools>=0.0.
|
|
17
|
+
Requires-Dist: meshagent-api>=0.0.5
|
|
18
|
+
Requires-Dist: meshagent-agents>=0.0.5
|
|
19
|
+
Requires-Dist: meshagent-tools>=0.0.5
|
|
20
20
|
Dynamic: description-content-type
|
|
21
21
|
Dynamic: license
|
|
22
22
|
Dynamic: project-url
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
meshagent/openai/__init__.py,sha256=qAqthmkQBsTqmrnVbtGOeaWCz9o5N48uEUCX7irzEsg,141
|
|
2
|
+
meshagent/openai/tools/__init__.py,sha256=RBU_J4qRDuBaaUdi6jpgpuMlIbvT30QmTBrZrYLwsUU,185
|
|
3
|
+
meshagent/openai/tools/completions_adapter.py,sha256=I74OC6JMbGb_C7qCYc0lWpJPs3uwuX9TfIDyn9Jou6U,15340
|
|
4
|
+
meshagent/openai/tools/responses_adapter.py,sha256=WGUCHYXq_ZzvjjUOlD59G0lazRSntQqg6BgU7N18W5M,21766
|
|
5
|
+
meshagent_openai-0.0.5.dist-info/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
|
|
6
|
+
meshagent_openai-0.0.5.dist-info/METADATA,sha256=qPqdpUmXtQEgx01u2edIoWzjNUT85aCb_5VVTUlP9gk,752
|
|
7
|
+
meshagent_openai-0.0.5.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
8
|
+
meshagent_openai-0.0.5.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
|
|
9
|
+
meshagent_openai-0.0.5.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
meshagent/openai/__init__.py,sha256=qAqthmkQBsTqmrnVbtGOeaWCz9o5N48uEUCX7irzEsg,141
|
|
2
|
-
meshagent/openai/tools/__init__.py,sha256=RBU_J4qRDuBaaUdi6jpgpuMlIbvT30QmTBrZrYLwsUU,185
|
|
3
|
-
meshagent/openai/tools/completions_adapter.py,sha256=sotgpBusJ-pkTOLWqvavokit3bysYBj4nNBat4PFnBw,15319
|
|
4
|
-
meshagent/openai/tools/responses_adapter.py,sha256=ybvIMRpIrwDr3O1CW7m_Efma926IqFv5jPawZX-WYtQ,15609
|
|
5
|
-
meshagent_openai-0.0.3.dist-info/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
|
|
6
|
-
meshagent_openai-0.0.3.dist-info/METADATA,sha256=vgZd2DmRaQAu8cokGl9N6Jn6BFE88kqoNbHKHBC0rP4,752
|
|
7
|
-
meshagent_openai-0.0.3.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
8
|
-
meshagent_openai-0.0.3.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
|
|
9
|
-
meshagent_openai-0.0.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|