quraite 0.1.2__tar.gz → 0.1.4__tar.gz
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-0.1.2 → quraite-0.1.4}/PKG-INFO +54 -62
- {quraite-0.1.2 → quraite-0.1.4}/README.md +53 -61
- {quraite-0.1.2 → quraite-0.1.4}/pyproject.toml +25 -4
- quraite-0.1.4/quraite/__init__.py +7 -0
- quraite-0.1.4/quraite/adapters/agno_adapter.py +115 -0
- quraite-0.1.4/quraite/adapters/base.py +73 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/bedrock_agents_adapter.py +23 -76
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/flowise_adapter.py +31 -72
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/google_adk_adapter.py +28 -94
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/http_adapter.py +28 -44
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/langchain_adapter.py +51 -118
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/langchain_server_adapter.py +37 -89
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/langflow_adapter.py +15 -60
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/n8n_adapter.py +19 -63
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/openai_agents_adapter.py +35 -59
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/pydantic_ai_adapter.py +27 -97
- quraite-0.1.4/quraite/adapters/smolagents_adapter.py +87 -0
- quraite-0.1.2/quraite/tracing/constants.py → quraite-0.1.4/quraite/constants/framework.py +1 -2
- quraite-0.1.4/quraite/schema/__init__.py +4 -0
- quraite-0.1.4/quraite/schema/invoke.py +46 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/schema/message.py +20 -21
- quraite-0.1.4/quraite/serve/__init__.py +5 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/serve/cloudflared.py +3 -2
- quraite-0.1.4/quraite/serve/server.py +305 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/tracing/__init__.py +8 -5
- quraite-0.1.4/quraite/tracing/constants.py +1 -0
- quraite-0.1.4/quraite/tracing/setup.py +129 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/tracing/span_exporter.py +6 -6
- {quraite-0.1.2 → quraite-0.1.4}/quraite/tracing/span_processor.py +6 -7
- {quraite-0.1.2 → quraite-0.1.4}/quraite/tracing/tool_extractors.py +1 -1
- {quraite-0.1.2 → quraite-0.1.4}/quraite/tracing/trace.py +36 -24
- {quraite-0.1.2 → quraite-0.1.4}/quraite/utils/json_utils.py +2 -2
- quraite-0.1.2/quraite/__init__.py +0 -3
- quraite-0.1.2/quraite/adapters/agno_adapter.py +0 -157
- quraite-0.1.2/quraite/adapters/base.py +0 -123
- quraite-0.1.2/quraite/adapters/smolagents_adapter.py +0 -148
- quraite-0.1.2/quraite/schema/response.py +0 -16
- quraite-0.1.2/quraite/serve/__init__.py +0 -1
- quraite-0.1.2/quraite/serve/local_agent.py +0 -360
- quraite-0.1.2/quraite/traces/traces_adk_openinference.json +0 -379
- quraite-0.1.2/quraite/traces/traces_agno_multi_agent.json +0 -669
- quraite-0.1.2/quraite/traces/traces_agno_openinference.json +0 -321
- quraite-0.1.2/quraite/traces/traces_crewai_openinference.json +0 -155
- quraite-0.1.2/quraite/traces/traces_langgraph_openinference.json +0 -349
- quraite-0.1.2/quraite/traces/traces_langgraph_openinference_multi_agent.json +0 -2705
- quraite-0.1.2/quraite/traces/traces_langgraph_traceloop.json +0 -510
- quraite-0.1.2/quraite/traces/traces_openai_agents_multi_agent_1.json +0 -402
- quraite-0.1.2/quraite/traces/traces_openai_agents_openinference.json +0 -341
- quraite-0.1.2/quraite/traces/traces_pydantic_openinference.json +0 -286
- quraite-0.1.2/quraite/traces/traces_pydantic_openinference_multi_agent_1.json +0 -399
- quraite-0.1.2/quraite/traces/traces_pydantic_openinference_multi_agent_2.json +0 -398
- quraite-0.1.2/quraite/traces/traces_smol_agents_openinference.json +0 -397
- quraite-0.1.2/quraite/traces/traces_smol_agents_tool_calling_openinference.json +0 -704
- quraite-0.1.2/quraite/utils/__init__.py +0 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/adapters/__init__.py +1 -1
- {quraite-0.1.2 → quraite-0.1.4}/quraite/logger.py +0 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/tracing/types.py +0 -0
- {quraite-0.1.2 → quraite-0.1.4}/quraite/tracing/utils.py +0 -0
- {quraite-0.1.2/quraite/schema → quraite-0.1.4/quraite/utils}/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: quraite
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: This project provides adaptors and methods to integrate with the Quraite platform
|
|
5
5
|
Author: Shiv Mohith
|
|
6
6
|
Author-email: Shiv Mohith <shivmohith8@gmail.com>
|
|
@@ -92,55 +92,43 @@ pip install 'quraite[langchain,pydantic-ai,agno]'
|
|
|
92
92
|
Pass your compiled LangChain agent to the adapter and expose it as an HTTP API:
|
|
93
93
|
|
|
94
94
|
```python
|
|
95
|
-
import asyncio
|
|
96
|
-
import uvicorn
|
|
97
95
|
from dotenv import load_dotenv
|
|
98
|
-
from openinference.instrumentation import TracerProvider
|
|
99
|
-
from openinference.instrumentation.langchain import LangChainInstrumentor
|
|
100
96
|
|
|
101
|
-
from quraite
|
|
102
|
-
from quraite.
|
|
103
|
-
from quraite.tracing
|
|
104
|
-
from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
|
|
97
|
+
from quraite import run_agent
|
|
98
|
+
from quraite.adapters import LangchainAdapter
|
|
99
|
+
from quraite.tracing import Framework, setup_tracing
|
|
105
100
|
|
|
106
101
|
load_dotenv()
|
|
107
102
|
|
|
108
|
-
# Set up tracing
|
|
109
|
-
# Use Quraite's in-memory span exporter to capture the agent trajectory
|
|
110
|
-
# and use it for evaluation.
|
|
111
|
-
tracer_provider = TracerProvider()
|
|
112
|
-
quraite_span_exporter = QuraiteInMemorySpanExporter()
|
|
113
|
-
quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
|
|
114
|
-
tracer_provider.add_span_processor(quraite_span_processor)
|
|
115
|
-
LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
|
|
116
|
-
|
|
117
103
|
# Your compiled LangChain agent (created elsewhere)
|
|
118
104
|
# agent = create_agent(...)
|
|
119
105
|
|
|
120
|
-
#
|
|
121
|
-
|
|
106
|
+
# Setup tracing once
|
|
107
|
+
tracer_provider = setup_tracing([Framework.LANGCHAIN])
|
|
108
|
+
|
|
109
|
+
# Create adapter with tracer provider
|
|
110
|
+
adapter = LangchainAdapter(
|
|
122
111
|
agent_graph=agent, # Pass your compiled LangChain agent here
|
|
123
112
|
tracer_provider=tracer_provider,
|
|
124
113
|
)
|
|
125
114
|
|
|
126
|
-
#
|
|
127
|
-
|
|
128
|
-
|
|
115
|
+
# Option 1: Use run_agent to start the server (simplest)
|
|
116
|
+
run_agent(
|
|
117
|
+
adapter,
|
|
129
118
|
agent_id="your-agent-id", # Optional: for Quraite platform integration
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
app = server.create_app(
|
|
133
119
|
port=8080,
|
|
134
120
|
host="0.0.0.0",
|
|
135
121
|
tunnel="cloudflare", # Options: "cloudflare", "ngrok", or "none"
|
|
136
122
|
)
|
|
137
123
|
|
|
138
|
-
# Option
|
|
139
|
-
|
|
124
|
+
# Option 2: Use create_app for more control (e.g., with uvicorn reload)
|
|
125
|
+
from quraite import create_app
|
|
126
|
+
import uvicorn
|
|
127
|
+
|
|
128
|
+
app = create_app(adapter, agent_id="your-agent-id")
|
|
140
129
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
# uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
|
|
144
132
|
```
|
|
145
133
|
|
|
146
134
|
The server exposes:
|
|
@@ -191,20 +179,14 @@ Most agent frameworks return agent steps, but lack critical observability data.
|
|
|
191
179
|
To enable tracing:
|
|
192
180
|
|
|
193
181
|
```python
|
|
194
|
-
from
|
|
195
|
-
from quraite.tracing.span_exporter import QuraiteInMemorySpanExporter
|
|
196
|
-
from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
|
|
197
|
-
|
|
198
|
-
tracer_provider = TracerProvider()
|
|
182
|
+
from quraite.tracing import Framework, setup_tracing
|
|
199
183
|
|
|
200
|
-
#
|
|
201
|
-
|
|
202
|
-
quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
|
|
203
|
-
tracer_provider.add_span_processor(quraite_span_processor)
|
|
184
|
+
# Setup tracing once at app startup
|
|
185
|
+
tracer_provider = setup_tracing([Framework.LANGCHAIN])
|
|
204
186
|
|
|
205
|
-
#
|
|
206
|
-
from
|
|
207
|
-
|
|
187
|
+
# Pass to adapter
|
|
188
|
+
from quraite.adapters import LangchainAdapter
|
|
189
|
+
adapter = LangchainAdapter(agent_graph=agent, tracer_provider=tracer_provider)
|
|
208
190
|
```
|
|
209
191
|
|
|
210
192
|
### Message Schema
|
|
@@ -245,16 +227,18 @@ tool_msg = ToolMessage(
|
|
|
245
227
|
)
|
|
246
228
|
```
|
|
247
229
|
|
|
248
|
-
###
|
|
230
|
+
### Invoke Input and Output
|
|
249
231
|
|
|
250
|
-
Agent invocations
|
|
232
|
+
Agent invocations use structured `InvokeInput` and return `InvokeOutput`:
|
|
251
233
|
|
|
252
234
|
```python
|
|
253
|
-
from quraite.schema.
|
|
235
|
+
from quraite.schema.invoke import InvokeInput, InvokeOutput
|
|
254
236
|
|
|
255
|
-
response:
|
|
256
|
-
input=
|
|
257
|
-
|
|
237
|
+
response: InvokeOutput = await adapter.ainvoke(
|
|
238
|
+
input=InvokeInput(
|
|
239
|
+
user_message=user_msg,
|
|
240
|
+
session_id="session-123"
|
|
241
|
+
)
|
|
258
242
|
)
|
|
259
243
|
|
|
260
244
|
# Access trajectory (list of messages)
|
|
@@ -292,37 +276,45 @@ All adapters inherit from `BaseAdapter`:
|
|
|
292
276
|
|
|
293
277
|
```python
|
|
294
278
|
from quraite.adapters.base import BaseAdapter
|
|
279
|
+
from quraite.schema.invoke import InvokeInput, InvokeOutput
|
|
295
280
|
|
|
296
281
|
class MyAdapter(BaseAdapter):
|
|
297
282
|
async def ainvoke(
|
|
298
283
|
self,
|
|
299
|
-
input:
|
|
300
|
-
|
|
301
|
-
) -> AgentInvocationResponse:
|
|
284
|
+
input: InvokeInput,
|
|
285
|
+
) -> InvokeOutput:
|
|
302
286
|
# Implementation
|
|
287
|
+
# Access user_message: input.user_message
|
|
288
|
+
# Access session_id: input.session_id
|
|
303
289
|
pass
|
|
304
290
|
```
|
|
305
291
|
|
|
306
|
-
###
|
|
292
|
+
### Running Your Agent
|
|
307
293
|
|
|
308
|
-
|
|
294
|
+
Use `run_agent` or `create_app` to start a local HTTP server for your agent:
|
|
309
295
|
|
|
310
296
|
```python
|
|
311
|
-
import
|
|
312
|
-
from quraite.serve.local_agent import LocalAgentServer
|
|
297
|
+
from quraite import run_agent, create_app
|
|
313
298
|
|
|
314
|
-
|
|
315
|
-
|
|
299
|
+
# Simple approach: run_agent handles everything
|
|
300
|
+
run_agent(
|
|
301
|
+
adapter,
|
|
316
302
|
agent_id="optional-agent-id",
|
|
317
|
-
)
|
|
318
|
-
|
|
319
|
-
app = server.create_app(
|
|
320
303
|
port=8080,
|
|
321
304
|
host="0.0.0.0",
|
|
322
305
|
tunnel="cloudflare", # or "ngrok" or "none"
|
|
323
306
|
)
|
|
324
307
|
|
|
325
|
-
|
|
308
|
+
# Advanced approach: create_app for more control (e.g., uvicorn reload)
|
|
309
|
+
import uvicorn
|
|
310
|
+
|
|
311
|
+
app = create_app(
|
|
312
|
+
adapter,
|
|
313
|
+
agent_id="optional-agent-id",
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
if __name__ == "__main__":
|
|
317
|
+
uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
|
|
326
318
|
```
|
|
327
319
|
|
|
328
320
|
## Development
|
|
@@ -57,55 +57,43 @@ pip install 'quraite[langchain,pydantic-ai,agno]'
|
|
|
57
57
|
Pass your compiled LangChain agent to the adapter and expose it as an HTTP API:
|
|
58
58
|
|
|
59
59
|
```python
|
|
60
|
-
import asyncio
|
|
61
|
-
import uvicorn
|
|
62
60
|
from dotenv import load_dotenv
|
|
63
|
-
from openinference.instrumentation import TracerProvider
|
|
64
|
-
from openinference.instrumentation.langchain import LangChainInstrumentor
|
|
65
61
|
|
|
66
|
-
from quraite
|
|
67
|
-
from quraite.
|
|
68
|
-
from quraite.tracing
|
|
69
|
-
from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
|
|
62
|
+
from quraite import run_agent
|
|
63
|
+
from quraite.adapters import LangchainAdapter
|
|
64
|
+
from quraite.tracing import Framework, setup_tracing
|
|
70
65
|
|
|
71
66
|
load_dotenv()
|
|
72
67
|
|
|
73
|
-
# Set up tracing
|
|
74
|
-
# Use Quraite's in-memory span exporter to capture the agent trajectory
|
|
75
|
-
# and use it for evaluation.
|
|
76
|
-
tracer_provider = TracerProvider()
|
|
77
|
-
quraite_span_exporter = QuraiteInMemorySpanExporter()
|
|
78
|
-
quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
|
|
79
|
-
tracer_provider.add_span_processor(quraite_span_processor)
|
|
80
|
-
LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
|
|
81
|
-
|
|
82
68
|
# Your compiled LangChain agent (created elsewhere)
|
|
83
69
|
# agent = create_agent(...)
|
|
84
70
|
|
|
85
|
-
#
|
|
86
|
-
|
|
71
|
+
# Setup tracing once
|
|
72
|
+
tracer_provider = setup_tracing([Framework.LANGCHAIN])
|
|
73
|
+
|
|
74
|
+
# Create adapter with tracer provider
|
|
75
|
+
adapter = LangchainAdapter(
|
|
87
76
|
agent_graph=agent, # Pass your compiled LangChain agent here
|
|
88
77
|
tracer_provider=tracer_provider,
|
|
89
78
|
)
|
|
90
79
|
|
|
91
|
-
#
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
# Option 1: Use run_agent to start the server (simplest)
|
|
81
|
+
run_agent(
|
|
82
|
+
adapter,
|
|
94
83
|
agent_id="your-agent-id", # Optional: for Quraite platform integration
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
app = server.create_app(
|
|
98
84
|
port=8080,
|
|
99
85
|
host="0.0.0.0",
|
|
100
86
|
tunnel="cloudflare", # Options: "cloudflare", "ngrok", or "none"
|
|
101
87
|
)
|
|
102
88
|
|
|
103
|
-
# Option
|
|
104
|
-
|
|
89
|
+
# Option 2: Use create_app for more control (e.g., with uvicorn reload)
|
|
90
|
+
from quraite import create_app
|
|
91
|
+
import uvicorn
|
|
92
|
+
|
|
93
|
+
app = create_app(adapter, agent_id="your-agent-id")
|
|
105
94
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
# uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
|
|
109
97
|
```
|
|
110
98
|
|
|
111
99
|
The server exposes:
|
|
@@ -156,20 +144,14 @@ Most agent frameworks return agent steps, but lack critical observability data.
|
|
|
156
144
|
To enable tracing:
|
|
157
145
|
|
|
158
146
|
```python
|
|
159
|
-
from
|
|
160
|
-
from quraite.tracing.span_exporter import QuraiteInMemorySpanExporter
|
|
161
|
-
from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
|
|
162
|
-
|
|
163
|
-
tracer_provider = TracerProvider()
|
|
147
|
+
from quraite.tracing import Framework, setup_tracing
|
|
164
148
|
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
|
|
168
|
-
tracer_provider.add_span_processor(quraite_span_processor)
|
|
149
|
+
# Setup tracing once at app startup
|
|
150
|
+
tracer_provider = setup_tracing([Framework.LANGCHAIN])
|
|
169
151
|
|
|
170
|
-
#
|
|
171
|
-
from
|
|
172
|
-
|
|
152
|
+
# Pass to adapter
|
|
153
|
+
from quraite.adapters import LangchainAdapter
|
|
154
|
+
adapter = LangchainAdapter(agent_graph=agent, tracer_provider=tracer_provider)
|
|
173
155
|
```
|
|
174
156
|
|
|
175
157
|
### Message Schema
|
|
@@ -210,16 +192,18 @@ tool_msg = ToolMessage(
|
|
|
210
192
|
)
|
|
211
193
|
```
|
|
212
194
|
|
|
213
|
-
###
|
|
195
|
+
### Invoke Input and Output
|
|
214
196
|
|
|
215
|
-
Agent invocations
|
|
197
|
+
Agent invocations use structured `InvokeInput` and return `InvokeOutput`:
|
|
216
198
|
|
|
217
199
|
```python
|
|
218
|
-
from quraite.schema.
|
|
200
|
+
from quraite.schema.invoke import InvokeInput, InvokeOutput
|
|
219
201
|
|
|
220
|
-
response:
|
|
221
|
-
input=
|
|
222
|
-
|
|
202
|
+
response: InvokeOutput = await adapter.ainvoke(
|
|
203
|
+
input=InvokeInput(
|
|
204
|
+
user_message=user_msg,
|
|
205
|
+
session_id="session-123"
|
|
206
|
+
)
|
|
223
207
|
)
|
|
224
208
|
|
|
225
209
|
# Access trajectory (list of messages)
|
|
@@ -257,37 +241,45 @@ All adapters inherit from `BaseAdapter`:
|
|
|
257
241
|
|
|
258
242
|
```python
|
|
259
243
|
from quraite.adapters.base import BaseAdapter
|
|
244
|
+
from quraite.schema.invoke import InvokeInput, InvokeOutput
|
|
260
245
|
|
|
261
246
|
class MyAdapter(BaseAdapter):
|
|
262
247
|
async def ainvoke(
|
|
263
248
|
self,
|
|
264
|
-
input:
|
|
265
|
-
|
|
266
|
-
) -> AgentInvocationResponse:
|
|
249
|
+
input: InvokeInput,
|
|
250
|
+
) -> InvokeOutput:
|
|
267
251
|
# Implementation
|
|
252
|
+
# Access user_message: input.user_message
|
|
253
|
+
# Access session_id: input.session_id
|
|
268
254
|
pass
|
|
269
255
|
```
|
|
270
256
|
|
|
271
|
-
###
|
|
257
|
+
### Running Your Agent
|
|
272
258
|
|
|
273
|
-
|
|
259
|
+
Use `run_agent` or `create_app` to start a local HTTP server for your agent:
|
|
274
260
|
|
|
275
261
|
```python
|
|
276
|
-
import
|
|
277
|
-
from quraite.serve.local_agent import LocalAgentServer
|
|
262
|
+
from quraite import run_agent, create_app
|
|
278
263
|
|
|
279
|
-
|
|
280
|
-
|
|
264
|
+
# Simple approach: run_agent handles everything
|
|
265
|
+
run_agent(
|
|
266
|
+
adapter,
|
|
281
267
|
agent_id="optional-agent-id",
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
app = server.create_app(
|
|
285
268
|
port=8080,
|
|
286
269
|
host="0.0.0.0",
|
|
287
270
|
tunnel="cloudflare", # or "ngrok" or "none"
|
|
288
271
|
)
|
|
289
272
|
|
|
290
|
-
|
|
273
|
+
# Advanced approach: create_app for more control (e.g., uvicorn reload)
|
|
274
|
+
import uvicorn
|
|
275
|
+
|
|
276
|
+
app = create_app(
|
|
277
|
+
adapter,
|
|
278
|
+
agent_id="optional-agent-id",
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
if __name__ == "__main__":
|
|
282
|
+
uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
|
|
291
283
|
```
|
|
292
284
|
|
|
293
285
|
## Development
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "quraite"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.4"
|
|
4
4
|
description = "This project provides adaptors and methods to integrate with the Quraite platform"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -49,10 +49,12 @@ module-root = ""
|
|
|
49
49
|
|
|
50
50
|
[dependency-groups]
|
|
51
51
|
dev = [
|
|
52
|
-
"autoflake>=2.3.1",
|
|
53
|
-
"black>=25.9.0",
|
|
54
52
|
"ipykernel>=7.1.0",
|
|
55
|
-
"
|
|
53
|
+
"mypy>=1.14.1",
|
|
54
|
+
"ruff>=0.9.4",
|
|
55
|
+
]
|
|
56
|
+
temp = [
|
|
57
|
+
"arize-phoenix-otel>=0.14.0",
|
|
56
58
|
]
|
|
57
59
|
test = [
|
|
58
60
|
"numpy>=2.2.6",
|
|
@@ -72,3 +74,22 @@ test = [
|
|
|
72
74
|
"pytest-env>=1.2.0",
|
|
73
75
|
"pytest-dotenv>=0.5.2",
|
|
74
76
|
]
|
|
77
|
+
|
|
78
|
+
[tool.ruff]
|
|
79
|
+
line-length = 88
|
|
80
|
+
target-version = "py310"
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint]
|
|
83
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
84
|
+
ignore = []
|
|
85
|
+
|
|
86
|
+
[tool.ruff.lint.isort]
|
|
87
|
+
known-first-party = ["quraite"]
|
|
88
|
+
|
|
89
|
+
[tool.mypy]
|
|
90
|
+
python_version = "3.10"
|
|
91
|
+
warn_return_any = true
|
|
92
|
+
warn_unused_configs = true
|
|
93
|
+
disallow_untyped_defs = false
|
|
94
|
+
ignore_missing_imports = true
|
|
95
|
+
explicit_package_bases = true
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
3
|
+
from agno.agent import Agent
|
|
4
|
+
from agno.team import Team
|
|
5
|
+
from openinference.instrumentation.agno.utils import _AGNO_PARENT_NODE_CONTEXT_KEY
|
|
6
|
+
from opentelemetry import context as context_api
|
|
7
|
+
from opentelemetry.trace import TracerProvider
|
|
8
|
+
|
|
9
|
+
from quraite.adapters.base import BaseAdapter
|
|
10
|
+
from quraite.constants.framework import Framework
|
|
11
|
+
from quraite.logger import get_logger
|
|
12
|
+
from quraite.schema.invoke import InvokeInput, InvokeOutput
|
|
13
|
+
from quraite.tracing.trace import AgentSpan, AgentTrace
|
|
14
|
+
|
|
15
|
+
logger = get_logger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AgnoAdapter(BaseAdapter):
|
|
19
|
+
"""Agno adapter for Agent and Team (requires tracing)."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
agent: Agent | Team,
|
|
24
|
+
*,
|
|
25
|
+
tracer_provider: TracerProvider | None = None,
|
|
26
|
+
agent_name: str = "Agno Agent",
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Initialize Agno adapter.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
agent: Agno Agent or Team instance
|
|
33
|
+
tracer_provider: TracerProvider from setup_tracing() (required)
|
|
34
|
+
agent_name: Agent name for metadata
|
|
35
|
+
"""
|
|
36
|
+
if tracer_provider is None:
|
|
37
|
+
raise ValueError(
|
|
38
|
+
"Agno adapter requires tracing. Use setup_tracing([Framework.AGNO]) first."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
self.agent: Agent | Team = agent
|
|
42
|
+
self.agent_name = agent_name
|
|
43
|
+
self._init_tracer(tracer_provider)
|
|
44
|
+
logger.info("AgnoAdapter initialized")
|
|
45
|
+
|
|
46
|
+
async def ainvoke(self, input: InvokeInput) -> InvokeOutput:
|
|
47
|
+
"""Invoke Agno agent and return response with trace."""
|
|
48
|
+
logger.info("ainvoke called (session_id=%s)", input.session_id)
|
|
49
|
+
session_id = input.session_id or str(uuid.uuid4())
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
return await self._ainvoke_with_tracing(
|
|
53
|
+
input.user_message_str(), session_id
|
|
54
|
+
)
|
|
55
|
+
except Exception as e:
|
|
56
|
+
logger.exception("Error invoking Agno agent")
|
|
57
|
+
raise RuntimeError(f"Error invoking Agno agent: {e}") from e
|
|
58
|
+
|
|
59
|
+
async def _ainvoke_with_tracing(
|
|
60
|
+
self,
|
|
61
|
+
user_message: str,
|
|
62
|
+
session_id: str,
|
|
63
|
+
) -> InvokeOutput:
|
|
64
|
+
"""Execute ainvoke with tracing enabled."""
|
|
65
|
+
with self.tracer.start_as_current_span("agno_invocation") as span:
|
|
66
|
+
# Workaround: openinference-instrumentation-agno>=0.1.25 forces a new root
|
|
67
|
+
# trace for Team instances unless _AGNO_PARENT_NODE_CONTEXT_KEY is set.
|
|
68
|
+
# This ensures child spans inherit our trace_id.
|
|
69
|
+
# See: https://github.com/Arize-ai/openinference/pull/2533
|
|
70
|
+
#
|
|
71
|
+
# Context API notes:
|
|
72
|
+
# - set_value() creates a new Context with the key-value pair (doesn't activate it)
|
|
73
|
+
# - attach() makes the context active and returns a token (restore point)
|
|
74
|
+
# - detach(token) restores the previous context (cleanup)
|
|
75
|
+
ctx = context_api.set_value(
|
|
76
|
+
_AGNO_PARENT_NODE_CONTEXT_KEY,
|
|
77
|
+
format(span.get_span_context().span_id, '016x')
|
|
78
|
+
)
|
|
79
|
+
token = context_api.attach(ctx)
|
|
80
|
+
trace_id = span.get_span_context().trace_id
|
|
81
|
+
|
|
82
|
+
logger.debug(
|
|
83
|
+
"Starting traced invocation (session_id=%s) with trace_id=%s",
|
|
84
|
+
session_id,
|
|
85
|
+
trace_id,
|
|
86
|
+
)
|
|
87
|
+
try:
|
|
88
|
+
await self.agent.arun(user_message, session_id=session_id)
|
|
89
|
+
finally:
|
|
90
|
+
context_api.detach(token)
|
|
91
|
+
|
|
92
|
+
# Get trace spans
|
|
93
|
+
trace_readable_spans = self.quraite_span_exporter.get_spans_by_trace_id(
|
|
94
|
+
trace_id
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if trace_readable_spans:
|
|
98
|
+
logger.info(
|
|
99
|
+
"Retrieved %d spans for trace_id=%s",
|
|
100
|
+
len(trace_readable_spans),
|
|
101
|
+
trace_id,
|
|
102
|
+
)
|
|
103
|
+
agent_trace = AgentTrace(
|
|
104
|
+
spans=[
|
|
105
|
+
AgentSpan.from_readable_oi_span(span)
|
|
106
|
+
for span in trace_readable_spans
|
|
107
|
+
],
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
logger.warning("No spans found for trace_id=%s", trace_id)
|
|
111
|
+
|
|
112
|
+
return InvokeOutput(
|
|
113
|
+
agent_trace=agent_trace,
|
|
114
|
+
agent_trajectory=agent_trace.to_agent_trajectory(framework=Framework.AGNO),
|
|
115
|
+
)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from opentelemetry.sdk.trace import TracerProvider as SDKTracerProvider
|
|
4
|
+
from opentelemetry.trace import Tracer, TracerProvider
|
|
5
|
+
|
|
6
|
+
from quraite.logger import get_logger
|
|
7
|
+
from quraite.schema.invoke import InvokeInput, InvokeOutput
|
|
8
|
+
from quraite.schema.message import AssistantMessage, MessageContentText
|
|
9
|
+
from quraite.tracing.constants import QURAITE_TRACER_NAME
|
|
10
|
+
from quraite.tracing.span_exporter import QuraiteSpanExporter
|
|
11
|
+
from quraite.tracing.span_processor import QuraiteSpanProcessor
|
|
12
|
+
|
|
13
|
+
logger = get_logger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BaseAdapter(ABC):
|
|
17
|
+
"""Base adapter for all framework adapters."""
|
|
18
|
+
|
|
19
|
+
tracer_provider: TracerProvider | None = None
|
|
20
|
+
tracer: Tracer | None = None
|
|
21
|
+
quraite_span_exporter: QuraiteSpanExporter = QuraiteSpanExporter()
|
|
22
|
+
|
|
23
|
+
def _init_tracer(self, tracer_provider: SDKTracerProvider | None) -> None:
|
|
24
|
+
"""Initialize tracer components from TracerProvider."""
|
|
25
|
+
if tracer_provider is None:
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
self.tracer_provider = tracer_provider
|
|
29
|
+
self.tracer = tracer_provider.get_tracer(QURAITE_TRACER_NAME)
|
|
30
|
+
|
|
31
|
+
# Find Quraite span exporter
|
|
32
|
+
quraite_span_exporter = next(
|
|
33
|
+
(
|
|
34
|
+
processor.span_exporter
|
|
35
|
+
for processor in tracer_provider._active_span_processor._span_processors
|
|
36
|
+
if isinstance(processor, QuraiteSpanProcessor)
|
|
37
|
+
),
|
|
38
|
+
None,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if quraite_span_exporter is None:
|
|
42
|
+
raise ValueError(
|
|
43
|
+
"Quraite span exporter not found. "
|
|
44
|
+
"Use setup_tracing() to configure tracing properly."
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
self.quraite_span_exporter = quraite_span_exporter
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
async def ainvoke(
|
|
51
|
+
self,
|
|
52
|
+
input: InvokeInput,
|
|
53
|
+
) -> InvokeOutput:
|
|
54
|
+
"""Invoke agent with input and return response."""
|
|
55
|
+
raise NotImplementedError("Not implemented")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class DummyAdapter(BaseAdapter):
|
|
59
|
+
"""Dummy adapter for testing."""
|
|
60
|
+
|
|
61
|
+
async def ainvoke(
|
|
62
|
+
self,
|
|
63
|
+
input: InvokeInput,
|
|
64
|
+
) -> InvokeOutput:
|
|
65
|
+
"""Returns dummy response."""
|
|
66
|
+
return InvokeOutput(
|
|
67
|
+
agent_trajectory=[
|
|
68
|
+
input.user_message,
|
|
69
|
+
AssistantMessage(
|
|
70
|
+
content=[MessageContentText(text="Dummy response")],
|
|
71
|
+
),
|
|
72
|
+
]
|
|
73
|
+
)
|