quraite 0.0.1__py3-none-any.whl → 0.1.0__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.
- quraite/__init__.py +3 -3
- quraite/adapters/__init__.py +134 -134
- quraite/adapters/agno_adapter.py +159 -159
- quraite/adapters/base.py +123 -123
- quraite/adapters/bedrock_agents_adapter.py +343 -343
- quraite/adapters/flowise_adapter.py +275 -275
- quraite/adapters/google_adk_adapter.py +209 -209
- quraite/adapters/http_adapter.py +239 -239
- quraite/adapters/langflow_adapter.py +192 -192
- quraite/adapters/langgraph_adapter.py +304 -304
- quraite/adapters/langgraph_server_adapter.py +252 -252
- quraite/adapters/n8n_adapter.py +220 -220
- quraite/adapters/openai_agents_adapter.py +269 -269
- quraite/adapters/pydantic_ai_adapter.py +312 -312
- quraite/adapters/smolagents_adapter.py +152 -152
- quraite/logger.py +61 -62
- quraite/schema/message.py +91 -54
- quraite/schema/response.py +16 -16
- quraite/serve/__init__.py +1 -1
- quraite/serve/cloudflared.py +210 -210
- quraite/serve/local_agent.py +360 -360
- quraite/tracing/__init__.py +24 -24
- quraite/tracing/constants.py +16 -16
- quraite/tracing/span_exporter.py +115 -115
- quraite/tracing/span_processor.py +49 -49
- quraite/tracing/tool_extractors.py +290 -290
- quraite/tracing/trace.py +564 -494
- quraite/tracing/types.py +179 -179
- quraite/tracing/utils.py +170 -170
- quraite/utils/json_utils.py +269 -269
- {quraite-0.0.1.dist-info → quraite-0.1.0.dist-info}/METADATA +9 -9
- quraite-0.1.0.dist-info/RECORD +35 -0
- {quraite-0.0.1.dist-info → quraite-0.1.0.dist-info}/WHEEL +1 -1
- quraite/traces/traces_adk_openinference.json +0 -379
- quraite/traces/traces_agno_multi_agent.json +0 -669
- quraite/traces/traces_agno_openinference.json +0 -321
- quraite/traces/traces_crewai_openinference.json +0 -155
- quraite/traces/traces_langgraph_openinference.json +0 -349
- quraite/traces/traces_langgraph_openinference_multi_agent.json +0 -2705
- quraite/traces/traces_langgraph_traceloop.json +0 -510
- quraite/traces/traces_openai_agents_multi_agent_1.json +0 -402
- quraite/traces/traces_openai_agents_openinference.json +0 -341
- quraite/traces/traces_pydantic_openinference.json +0 -286
- quraite/traces/traces_pydantic_openinference_multi_agent_1.json +0 -399
- quraite/traces/traces_pydantic_openinference_multi_agent_2.json +0 -398
- quraite/traces/traces_smol_agents_openinference.json +0 -397
- quraite/traces/traces_smol_agents_tool_calling_openinference.json +0 -704
- quraite-0.0.1.dist-info/RECORD +0 -49
|
@@ -1,269 +1,269 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import uuid
|
|
3
|
-
from typing import Dict, List, Optional, Union
|
|
4
|
-
|
|
5
|
-
from agents import (
|
|
6
|
-
Agent,
|
|
7
|
-
MessageOutputItem,
|
|
8
|
-
ReasoningItem,
|
|
9
|
-
RunItem,
|
|
10
|
-
Runner,
|
|
11
|
-
SQLiteSession,
|
|
12
|
-
ToolCallItem,
|
|
13
|
-
ToolCallOutputItem,
|
|
14
|
-
TResponseInputItem,
|
|
15
|
-
)
|
|
16
|
-
from agents.memory import Session
|
|
17
|
-
from opentelemetry.trace import TracerProvider
|
|
18
|
-
|
|
19
|
-
from quraite.adapters.base import BaseAdapter
|
|
20
|
-
from quraite.logger import get_logger
|
|
21
|
-
from quraite.schema.message import (
|
|
22
|
-
AgentMessage,
|
|
23
|
-
AssistantMessage,
|
|
24
|
-
MessageContentReasoning,
|
|
25
|
-
MessageContentText,
|
|
26
|
-
ToolCall,
|
|
27
|
-
ToolMessage,
|
|
28
|
-
)
|
|
29
|
-
from quraite.schema.response import AgentInvocationResponse
|
|
30
|
-
from quraite.tracing.constants import QURAITE_ADAPTER_TRACE_PREFIX, Framework
|
|
31
|
-
from quraite.tracing.trace import AgentSpan, AgentTrace
|
|
32
|
-
|
|
33
|
-
logger = get_logger(__name__)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class OpenaiAgentsAdapter(BaseAdapter):
|
|
37
|
-
def __init__(
|
|
38
|
-
self,
|
|
39
|
-
agent: Agent,
|
|
40
|
-
agent_name: str = "OpenAI Agents",
|
|
41
|
-
tracer_provider: Optional[TracerProvider] = None,
|
|
42
|
-
):
|
|
43
|
-
self.agent = agent
|
|
44
|
-
self.sessions: Dict[str, Session] = {}
|
|
45
|
-
self._init_tracing(tracer_provider, required=False)
|
|
46
|
-
self.agent_name = agent_name
|
|
47
|
-
logger.info(
|
|
48
|
-
"OpenaiAgentsAdapter initialized (agent_name=%s, tracing_enabled=%s)",
|
|
49
|
-
agent_name,
|
|
50
|
-
bool(tracer_provider),
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
def _convert_run_items_to_messages(
|
|
54
|
-
self, run_items: List[RunItem]
|
|
55
|
-
) -> List[AgentMessage]:
|
|
56
|
-
logger.debug("Converting %d OpenAI run items to messages", len(run_items))
|
|
57
|
-
messages: List[AgentMessage] = []
|
|
58
|
-
text_content: List[MessageContentText] = []
|
|
59
|
-
reasoning_content: List[MessageContentReasoning] = []
|
|
60
|
-
tool_calls: List[ToolCall] = []
|
|
61
|
-
|
|
62
|
-
def flush_assistant_message():
|
|
63
|
-
nonlocal text_content, reasoning_content, tool_calls
|
|
64
|
-
if text_content or reasoning_content or tool_calls:
|
|
65
|
-
content = []
|
|
66
|
-
if text_content:
|
|
67
|
-
content.extend(text_content)
|
|
68
|
-
if reasoning_content:
|
|
69
|
-
content.extend(reasoning_content)
|
|
70
|
-
messages.append(
|
|
71
|
-
AssistantMessage(
|
|
72
|
-
content=content if content else None,
|
|
73
|
-
tool_calls=tool_calls if tool_calls else None,
|
|
74
|
-
)
|
|
75
|
-
)
|
|
76
|
-
text_content = []
|
|
77
|
-
reasoning_content = []
|
|
78
|
-
tool_calls = []
|
|
79
|
-
|
|
80
|
-
for item in run_items:
|
|
81
|
-
if item.type in [
|
|
82
|
-
"handoff_call_item",
|
|
83
|
-
"handoff_output_item",
|
|
84
|
-
"mcp_list_tools_item",
|
|
85
|
-
"mcp_approval_request_item",
|
|
86
|
-
"mcp_approval_response_item",
|
|
87
|
-
]:
|
|
88
|
-
continue
|
|
89
|
-
|
|
90
|
-
if isinstance(item, MessageOutputItem):
|
|
91
|
-
text_parts = []
|
|
92
|
-
for content_item in item.raw_item.content:
|
|
93
|
-
if hasattr(content_item, "text"):
|
|
94
|
-
text_parts.append(content_item.text)
|
|
95
|
-
if text_parts:
|
|
96
|
-
text_content.append(
|
|
97
|
-
MessageContentText(type="text", text="".join(text_parts))
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
elif isinstance(item, ReasoningItem):
|
|
101
|
-
if item.raw_item.summary:
|
|
102
|
-
summary = ""
|
|
103
|
-
for summary_item in item.raw_item.summary:
|
|
104
|
-
summary += summary_item.text
|
|
105
|
-
summary += "\n"
|
|
106
|
-
reasoning_content.append(
|
|
107
|
-
MessageContentReasoning(type="reasoning", reasoning=summary)
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
elif isinstance(item, ToolCallItem):
|
|
111
|
-
raw = item.raw_item
|
|
112
|
-
arguments = None
|
|
113
|
-
if hasattr(raw, "arguments"):
|
|
114
|
-
try:
|
|
115
|
-
arguments = (
|
|
116
|
-
json.loads(raw.arguments)
|
|
117
|
-
if isinstance(raw.arguments, str)
|
|
118
|
-
else raw.arguments
|
|
119
|
-
)
|
|
120
|
-
except:
|
|
121
|
-
arguments = {"raw": str(raw.arguments)}
|
|
122
|
-
tool_calls.append(
|
|
123
|
-
ToolCall(
|
|
124
|
-
id=getattr(raw, "call_id", ""),
|
|
125
|
-
name=getattr(raw, "name", ""),
|
|
126
|
-
arguments=arguments or {},
|
|
127
|
-
)
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
elif isinstance(item, ToolCallOutputItem):
|
|
131
|
-
flush_assistant_message()
|
|
132
|
-
tool_result = json.dumps({"output": item.output})
|
|
133
|
-
messages.append(
|
|
134
|
-
ToolMessage(
|
|
135
|
-
tool_call_id=item.raw_item.get("call_id", ""),
|
|
136
|
-
content=[MessageContentText(type="text", text=tool_result)],
|
|
137
|
-
)
|
|
138
|
-
)
|
|
139
|
-
continue
|
|
140
|
-
|
|
141
|
-
flush_assistant_message()
|
|
142
|
-
logger.info("Converted OpenAI agent run into %d messages", len(messages))
|
|
143
|
-
return messages
|
|
144
|
-
|
|
145
|
-
def _prepare_input(self, input: List[AgentMessage]) -> str:
|
|
146
|
-
logger.debug("Preparing OpenAI input from %d messages", len(input))
|
|
147
|
-
if not input or input[-1].role != "user":
|
|
148
|
-
logger.error("OpenAI input missing user message")
|
|
149
|
-
raise ValueError("No user message found in the input")
|
|
150
|
-
|
|
151
|
-
last_user_message = input[-1]
|
|
152
|
-
if not last_user_message.content:
|
|
153
|
-
logger.error("OpenAI user message missing content")
|
|
154
|
-
raise ValueError("User message has no content")
|
|
155
|
-
|
|
156
|
-
text_content = None
|
|
157
|
-
for content_item in last_user_message.content:
|
|
158
|
-
if content_item.type == "text" and content_item.text:
|
|
159
|
-
text_content = content_item.text
|
|
160
|
-
break
|
|
161
|
-
|
|
162
|
-
if not text_content:
|
|
163
|
-
logger.error("OpenAI user message missing text content")
|
|
164
|
-
raise ValueError("No text content found in user message")
|
|
165
|
-
|
|
166
|
-
logger.debug("Prepared OpenAI input (text_length=%d)", len(text_content))
|
|
167
|
-
return text_content
|
|
168
|
-
|
|
169
|
-
async def ainvoke(
|
|
170
|
-
self,
|
|
171
|
-
input: List[AgentMessage],
|
|
172
|
-
session_id: Union[str, None] = None,
|
|
173
|
-
) -> AgentInvocationResponse:
|
|
174
|
-
"""Asynchronous invocation method - invokes the OpenAI Agents agent and converts to List[AgentMessage]."""
|
|
175
|
-
try:
|
|
176
|
-
logger.info(
|
|
177
|
-
"OpenAI ainvoke called (session_id=%s, input_messages=%d)",
|
|
178
|
-
session_id,
|
|
179
|
-
len(input),
|
|
180
|
-
)
|
|
181
|
-
agent_input: Union[str, List[TResponseInputItem]] = self._prepare_input(
|
|
182
|
-
input
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
if session_id not in self.sessions:
|
|
186
|
-
self.sessions[session_id] = SQLiteSession(session_id=session_id)
|
|
187
|
-
session = self.sessions[session_id]
|
|
188
|
-
|
|
189
|
-
if self.tracer_provider:
|
|
190
|
-
return await self._ainvoke_with_tracing(agent_input, session)
|
|
191
|
-
|
|
192
|
-
return await self._ainvoke_without_tracing(agent_input, session)
|
|
193
|
-
except Exception as exc:
|
|
194
|
-
logger.exception("Error invoking OpenAI agent")
|
|
195
|
-
raise Exception(f"Error invoking Openai agent: {exc}") from exc
|
|
196
|
-
|
|
197
|
-
async def _ainvoke_with_tracing(
|
|
198
|
-
self,
|
|
199
|
-
agent_input: Union[str, List[TResponseInputItem]],
|
|
200
|
-
session: Session,
|
|
201
|
-
) -> AgentInvocationResponse:
|
|
202
|
-
"""Execute ainvoke with tracing enabled."""
|
|
203
|
-
adapter_trace_id = f"{QURAITE_ADAPTER_TRACE_PREFIX}-{uuid.uuid4()}"
|
|
204
|
-
logger.debug(
|
|
205
|
-
"Starting OpenAI traced invocation (trace_id=%s, session_id=%s)",
|
|
206
|
-
adapter_trace_id,
|
|
207
|
-
session.session_id if session else None,
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
with self.tracer.start_as_current_span(name=adapter_trace_id):
|
|
211
|
-
await Runner.run(
|
|
212
|
-
self.agent,
|
|
213
|
-
input=agent_input,
|
|
214
|
-
session=session,
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
trace_readable_spans = self.quraite_span_exporter.get_trace_by_testcase(
|
|
218
|
-
adapter_trace_id
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
if trace_readable_spans:
|
|
222
|
-
agent_trace = AgentTrace(
|
|
223
|
-
spans=[
|
|
224
|
-
AgentSpan.from_readable_oi_span(span)
|
|
225
|
-
for span in trace_readable_spans
|
|
226
|
-
]
|
|
227
|
-
)
|
|
228
|
-
logger.info(
|
|
229
|
-
"OpenAI trace collected %d spans for trace_id=%s",
|
|
230
|
-
len(trace_readable_spans),
|
|
231
|
-
adapter_trace_id,
|
|
232
|
-
)
|
|
233
|
-
else:
|
|
234
|
-
logger.warning(
|
|
235
|
-
"No spans exported for OpenAI trace_id=%s",
|
|
236
|
-
adapter_trace_id,
|
|
237
|
-
)
|
|
238
|
-
|
|
239
|
-
return AgentInvocationResponse(
|
|
240
|
-
agent_trace=agent_trace,
|
|
241
|
-
agent_trajectory=agent_trace.to_agent_trajectory(
|
|
242
|
-
framework=Framework.OPENAI_AGENTS
|
|
243
|
-
),
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
async def _ainvoke_without_tracing(
|
|
247
|
-
self,
|
|
248
|
-
agent_input: Union[str, List[TResponseInputItem]],
|
|
249
|
-
session: Session,
|
|
250
|
-
) -> AgentInvocationResponse:
|
|
251
|
-
"""Execute ainvoke without tracing."""
|
|
252
|
-
result = await Runner.run(
|
|
253
|
-
self.agent,
|
|
254
|
-
input=agent_input,
|
|
255
|
-
session=session,
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
try:
|
|
259
|
-
agent_trajectory = self._convert_run_items_to_messages(result.new_items)
|
|
260
|
-
logger.info(
|
|
261
|
-
"OpenAI agent produced %d trajectory messages (no tracing)",
|
|
262
|
-
len(agent_trajectory),
|
|
263
|
-
)
|
|
264
|
-
return AgentInvocationResponse(
|
|
265
|
-
agent_trajectory=agent_trajectory,
|
|
266
|
-
)
|
|
267
|
-
except Exception as exc:
|
|
268
|
-
logger.exception("Error converting OpenAI run items to messages")
|
|
269
|
-
raise Exception(f"Error converting run items to messages: {exc}") from exc
|
|
1
|
+
import json
|
|
2
|
+
import uuid
|
|
3
|
+
from typing import Dict, List, Optional, Union
|
|
4
|
+
|
|
5
|
+
from agents import (
|
|
6
|
+
Agent,
|
|
7
|
+
MessageOutputItem,
|
|
8
|
+
ReasoningItem,
|
|
9
|
+
RunItem,
|
|
10
|
+
Runner,
|
|
11
|
+
SQLiteSession,
|
|
12
|
+
ToolCallItem,
|
|
13
|
+
ToolCallOutputItem,
|
|
14
|
+
TResponseInputItem,
|
|
15
|
+
)
|
|
16
|
+
from agents.memory import Session
|
|
17
|
+
from opentelemetry.trace import TracerProvider
|
|
18
|
+
|
|
19
|
+
from quraite.adapters.base import BaseAdapter
|
|
20
|
+
from quraite.logger import get_logger
|
|
21
|
+
from quraite.schema.message import (
|
|
22
|
+
AgentMessage,
|
|
23
|
+
AssistantMessage,
|
|
24
|
+
MessageContentReasoning,
|
|
25
|
+
MessageContentText,
|
|
26
|
+
ToolCall,
|
|
27
|
+
ToolMessage,
|
|
28
|
+
)
|
|
29
|
+
from quraite.schema.response import AgentInvocationResponse
|
|
30
|
+
from quraite.tracing.constants import QURAITE_ADAPTER_TRACE_PREFIX, Framework
|
|
31
|
+
from quraite.tracing.trace import AgentSpan, AgentTrace
|
|
32
|
+
|
|
33
|
+
logger = get_logger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OpenaiAgentsAdapter(BaseAdapter):
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
agent: Agent,
|
|
40
|
+
agent_name: str = "OpenAI Agents",
|
|
41
|
+
tracer_provider: Optional[TracerProvider] = None,
|
|
42
|
+
):
|
|
43
|
+
self.agent = agent
|
|
44
|
+
self.sessions: Dict[str, Session] = {}
|
|
45
|
+
self._init_tracing(tracer_provider, required=False)
|
|
46
|
+
self.agent_name = agent_name
|
|
47
|
+
logger.info(
|
|
48
|
+
"OpenaiAgentsAdapter initialized (agent_name=%s, tracing_enabled=%s)",
|
|
49
|
+
agent_name,
|
|
50
|
+
bool(tracer_provider),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def _convert_run_items_to_messages(
|
|
54
|
+
self, run_items: List[RunItem]
|
|
55
|
+
) -> List[AgentMessage]:
|
|
56
|
+
logger.debug("Converting %d OpenAI run items to messages", len(run_items))
|
|
57
|
+
messages: List[AgentMessage] = []
|
|
58
|
+
text_content: List[MessageContentText] = []
|
|
59
|
+
reasoning_content: List[MessageContentReasoning] = []
|
|
60
|
+
tool_calls: List[ToolCall] = []
|
|
61
|
+
|
|
62
|
+
def flush_assistant_message():
|
|
63
|
+
nonlocal text_content, reasoning_content, tool_calls
|
|
64
|
+
if text_content or reasoning_content or tool_calls:
|
|
65
|
+
content = []
|
|
66
|
+
if text_content:
|
|
67
|
+
content.extend(text_content)
|
|
68
|
+
if reasoning_content:
|
|
69
|
+
content.extend(reasoning_content)
|
|
70
|
+
messages.append(
|
|
71
|
+
AssistantMessage(
|
|
72
|
+
content=content if content else None,
|
|
73
|
+
tool_calls=tool_calls if tool_calls else None,
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
text_content = []
|
|
77
|
+
reasoning_content = []
|
|
78
|
+
tool_calls = []
|
|
79
|
+
|
|
80
|
+
for item in run_items:
|
|
81
|
+
if item.type in [
|
|
82
|
+
"handoff_call_item",
|
|
83
|
+
"handoff_output_item",
|
|
84
|
+
"mcp_list_tools_item",
|
|
85
|
+
"mcp_approval_request_item",
|
|
86
|
+
"mcp_approval_response_item",
|
|
87
|
+
]:
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
if isinstance(item, MessageOutputItem):
|
|
91
|
+
text_parts = []
|
|
92
|
+
for content_item in item.raw_item.content:
|
|
93
|
+
if hasattr(content_item, "text"):
|
|
94
|
+
text_parts.append(content_item.text)
|
|
95
|
+
if text_parts:
|
|
96
|
+
text_content.append(
|
|
97
|
+
MessageContentText(type="text", text="".join(text_parts))
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
elif isinstance(item, ReasoningItem):
|
|
101
|
+
if item.raw_item.summary:
|
|
102
|
+
summary = ""
|
|
103
|
+
for summary_item in item.raw_item.summary:
|
|
104
|
+
summary += summary_item.text
|
|
105
|
+
summary += "\n"
|
|
106
|
+
reasoning_content.append(
|
|
107
|
+
MessageContentReasoning(type="reasoning", reasoning=summary)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
elif isinstance(item, ToolCallItem):
|
|
111
|
+
raw = item.raw_item
|
|
112
|
+
arguments = None
|
|
113
|
+
if hasattr(raw, "arguments"):
|
|
114
|
+
try:
|
|
115
|
+
arguments = (
|
|
116
|
+
json.loads(raw.arguments)
|
|
117
|
+
if isinstance(raw.arguments, str)
|
|
118
|
+
else raw.arguments
|
|
119
|
+
)
|
|
120
|
+
except:
|
|
121
|
+
arguments = {"raw": str(raw.arguments)}
|
|
122
|
+
tool_calls.append(
|
|
123
|
+
ToolCall(
|
|
124
|
+
id=getattr(raw, "call_id", ""),
|
|
125
|
+
name=getattr(raw, "name", ""),
|
|
126
|
+
arguments=arguments or {},
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
elif isinstance(item, ToolCallOutputItem):
|
|
131
|
+
flush_assistant_message()
|
|
132
|
+
tool_result = json.dumps({"output": item.output})
|
|
133
|
+
messages.append(
|
|
134
|
+
ToolMessage(
|
|
135
|
+
tool_call_id=item.raw_item.get("call_id", ""),
|
|
136
|
+
content=[MessageContentText(type="text", text=tool_result)],
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
flush_assistant_message()
|
|
142
|
+
logger.info("Converted OpenAI agent run into %d messages", len(messages))
|
|
143
|
+
return messages
|
|
144
|
+
|
|
145
|
+
def _prepare_input(self, input: List[AgentMessage]) -> str:
|
|
146
|
+
logger.debug("Preparing OpenAI input from %d messages", len(input))
|
|
147
|
+
if not input or input[-1].role != "user":
|
|
148
|
+
logger.error("OpenAI input missing user message")
|
|
149
|
+
raise ValueError("No user message found in the input")
|
|
150
|
+
|
|
151
|
+
last_user_message = input[-1]
|
|
152
|
+
if not last_user_message.content:
|
|
153
|
+
logger.error("OpenAI user message missing content")
|
|
154
|
+
raise ValueError("User message has no content")
|
|
155
|
+
|
|
156
|
+
text_content = None
|
|
157
|
+
for content_item in last_user_message.content:
|
|
158
|
+
if content_item.type == "text" and content_item.text:
|
|
159
|
+
text_content = content_item.text
|
|
160
|
+
break
|
|
161
|
+
|
|
162
|
+
if not text_content:
|
|
163
|
+
logger.error("OpenAI user message missing text content")
|
|
164
|
+
raise ValueError("No text content found in user message")
|
|
165
|
+
|
|
166
|
+
logger.debug("Prepared OpenAI input (text_length=%d)", len(text_content))
|
|
167
|
+
return text_content
|
|
168
|
+
|
|
169
|
+
async def ainvoke(
|
|
170
|
+
self,
|
|
171
|
+
input: List[AgentMessage],
|
|
172
|
+
session_id: Union[str, None] = None,
|
|
173
|
+
) -> AgentInvocationResponse:
|
|
174
|
+
"""Asynchronous invocation method - invokes the OpenAI Agents agent and converts to List[AgentMessage]."""
|
|
175
|
+
try:
|
|
176
|
+
logger.info(
|
|
177
|
+
"OpenAI ainvoke called (session_id=%s, input_messages=%d)",
|
|
178
|
+
session_id,
|
|
179
|
+
len(input),
|
|
180
|
+
)
|
|
181
|
+
agent_input: Union[str, List[TResponseInputItem]] = self._prepare_input(
|
|
182
|
+
input
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
if session_id not in self.sessions:
|
|
186
|
+
self.sessions[session_id] = SQLiteSession(session_id=session_id)
|
|
187
|
+
session = self.sessions[session_id]
|
|
188
|
+
|
|
189
|
+
if self.tracer_provider:
|
|
190
|
+
return await self._ainvoke_with_tracing(agent_input, session)
|
|
191
|
+
|
|
192
|
+
return await self._ainvoke_without_tracing(agent_input, session)
|
|
193
|
+
except Exception as exc:
|
|
194
|
+
logger.exception("Error invoking OpenAI agent")
|
|
195
|
+
raise Exception(f"Error invoking Openai agent: {exc}") from exc
|
|
196
|
+
|
|
197
|
+
async def _ainvoke_with_tracing(
|
|
198
|
+
self,
|
|
199
|
+
agent_input: Union[str, List[TResponseInputItem]],
|
|
200
|
+
session: Session,
|
|
201
|
+
) -> AgentInvocationResponse:
|
|
202
|
+
"""Execute ainvoke with tracing enabled."""
|
|
203
|
+
adapter_trace_id = f"{QURAITE_ADAPTER_TRACE_PREFIX}-{uuid.uuid4()}"
|
|
204
|
+
logger.debug(
|
|
205
|
+
"Starting OpenAI traced invocation (trace_id=%s, session_id=%s)",
|
|
206
|
+
adapter_trace_id,
|
|
207
|
+
session.session_id if session else None,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
with self.tracer.start_as_current_span(name=adapter_trace_id):
|
|
211
|
+
await Runner.run(
|
|
212
|
+
self.agent,
|
|
213
|
+
input=agent_input,
|
|
214
|
+
session=session,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
trace_readable_spans = self.quraite_span_exporter.get_trace_by_testcase(
|
|
218
|
+
adapter_trace_id
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
if trace_readable_spans:
|
|
222
|
+
agent_trace = AgentTrace(
|
|
223
|
+
spans=[
|
|
224
|
+
AgentSpan.from_readable_oi_span(span)
|
|
225
|
+
for span in trace_readable_spans
|
|
226
|
+
]
|
|
227
|
+
)
|
|
228
|
+
logger.info(
|
|
229
|
+
"OpenAI trace collected %d spans for trace_id=%s",
|
|
230
|
+
len(trace_readable_spans),
|
|
231
|
+
adapter_trace_id,
|
|
232
|
+
)
|
|
233
|
+
else:
|
|
234
|
+
logger.warning(
|
|
235
|
+
"No spans exported for OpenAI trace_id=%s",
|
|
236
|
+
adapter_trace_id,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
return AgentInvocationResponse(
|
|
240
|
+
agent_trace=agent_trace,
|
|
241
|
+
agent_trajectory=agent_trace.to_agent_trajectory(
|
|
242
|
+
framework=Framework.OPENAI_AGENTS
|
|
243
|
+
),
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
async def _ainvoke_without_tracing(
|
|
247
|
+
self,
|
|
248
|
+
agent_input: Union[str, List[TResponseInputItem]],
|
|
249
|
+
session: Session,
|
|
250
|
+
) -> AgentInvocationResponse:
|
|
251
|
+
"""Execute ainvoke without tracing."""
|
|
252
|
+
result = await Runner.run(
|
|
253
|
+
self.agent,
|
|
254
|
+
input=agent_input,
|
|
255
|
+
session=session,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
agent_trajectory = self._convert_run_items_to_messages(result.new_items)
|
|
260
|
+
logger.info(
|
|
261
|
+
"OpenAI agent produced %d trajectory messages (no tracing)",
|
|
262
|
+
len(agent_trajectory),
|
|
263
|
+
)
|
|
264
|
+
return AgentInvocationResponse(
|
|
265
|
+
agent_trajectory=agent_trajectory,
|
|
266
|
+
)
|
|
267
|
+
except Exception as exc:
|
|
268
|
+
logger.exception("Error converting OpenAI run items to messages")
|
|
269
|
+
raise Exception(f"Error converting run items to messages: {exc}") from exc
|