quraite 0.1.1__tar.gz → 0.1.2__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.
Files changed (49) hide show
  1. {quraite-0.1.1 → quraite-0.1.2}/PKG-INFO +52 -43
  2. {quraite-0.1.1 → quraite-0.1.2}/README.md +48 -39
  3. {quraite-0.1.1 → quraite-0.1.2}/pyproject.toml +2 -2
  4. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/__init__.py +12 -12
  5. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/agno_adapter.py +12 -14
  6. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/base.py +2 -2
  7. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/google_adk_adapter.py +13 -11
  8. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/http_adapter.py +6 -2
  9. quraite-0.1.1/quraite/adapters/langgraph_adapter.py → quraite-0.1.2/quraite/adapters/langchain_adapter.py +22 -21
  10. quraite-0.1.1/quraite/adapters/langgraph_server_adapter.py → quraite-0.1.2/quraite/adapters/langchain_server_adapter.py +21 -21
  11. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/openai_agents_adapter.py +12 -14
  12. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/pydantic_ai_adapter.py +12 -17
  13. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/smolagents_adapter.py +10 -14
  14. {quraite-0.1.1 → quraite-0.1.2}/quraite/serve/local_agent.py +3 -3
  15. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/__init__.py +1 -0
  16. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/constants.py +3 -4
  17. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/span_exporter.py +5 -19
  18. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/span_processor.py +1 -3
  19. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/tool_extractors.py +30 -11
  20. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/trace.py +6 -6
  21. {quraite-0.1.1 → quraite-0.1.2}/quraite/__init__.py +0 -0
  22. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/bedrock_agents_adapter.py +0 -0
  23. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/flowise_adapter.py +0 -0
  24. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/langflow_adapter.py +0 -0
  25. {quraite-0.1.1 → quraite-0.1.2}/quraite/adapters/n8n_adapter.py +0 -0
  26. {quraite-0.1.1 → quraite-0.1.2}/quraite/logger.py +0 -0
  27. {quraite-0.1.1 → quraite-0.1.2}/quraite/schema/__init__.py +0 -0
  28. {quraite-0.1.1 → quraite-0.1.2}/quraite/schema/message.py +0 -0
  29. {quraite-0.1.1 → quraite-0.1.2}/quraite/schema/response.py +0 -0
  30. {quraite-0.1.1 → quraite-0.1.2}/quraite/serve/__init__.py +0 -0
  31. {quraite-0.1.1 → quraite-0.1.2}/quraite/serve/cloudflared.py +0 -0
  32. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_adk_openinference.json +0 -0
  33. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_agno_multi_agent.json +0 -0
  34. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_agno_openinference.json +0 -0
  35. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_crewai_openinference.json +0 -0
  36. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_langgraph_openinference.json +0 -0
  37. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_langgraph_openinference_multi_agent.json +0 -0
  38. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_langgraph_traceloop.json +0 -0
  39. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_openai_agents_multi_agent_1.json +0 -0
  40. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_openai_agents_openinference.json +0 -0
  41. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_pydantic_openinference.json +0 -0
  42. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_pydantic_openinference_multi_agent_1.json +0 -0
  43. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_pydantic_openinference_multi_agent_2.json +0 -0
  44. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_smol_agents_openinference.json +0 -0
  45. {quraite-0.1.1 → quraite-0.1.2}/quraite/traces/traces_smol_agents_tool_calling_openinference.json +0 -0
  46. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/types.py +0 -0
  47. {quraite-0.1.1 → quraite-0.1.2}/quraite/tracing/utils.py +0 -0
  48. {quraite-0.1.1 → quraite-0.1.2}/quraite/utils/__init__.py +0 -0
  49. {quraite-0.1.1 → quraite-0.1.2}/quraite/utils/json_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: quraite
3
- Version: 0.1.1
3
+ Version: 0.1.2
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>
@@ -16,8 +16,8 @@ Requires-Dist: uvicorn>=0.38.0
16
16
  Requires-Dist: agno>=2.3.4 ; extra == 'agno'
17
17
  Requires-Dist: boto3>=1.40.70 ; extra == 'bedrock'
18
18
  Requires-Dist: google-adk>=1.18.0 ; extra == 'google-adk'
19
- Requires-Dist: langchain>=1.0.5 ; extra == 'langgraph'
20
- Requires-Dist: langgraph>=1.0.3 ; extra == 'langgraph'
19
+ Requires-Dist: langchain>=1.0.5 ; extra == 'langchain'
20
+ Requires-Dist: langgraph>=1.0.3 ; extra == 'langchain'
21
21
  Requires-Dist: openai-agents>=0.5.0 ; extra == 'openai-agents'
22
22
  Requires-Dist: pydantic-ai>=1.25.0 ; extra == 'pydantic-ai'
23
23
  Requires-Dist: pyngrok>=7.5.0 ; extra == 'pyngrok'
@@ -26,7 +26,7 @@ Requires-Python: >=3.10
26
26
  Provides-Extra: agno
27
27
  Provides-Extra: bedrock
28
28
  Provides-Extra: google-adk
29
- Provides-Extra: langgraph
29
+ Provides-Extra: langchain
30
30
  Provides-Extra: openai-agents
31
31
  Provides-Extra: pydantic-ai
32
32
  Provides-Extra: pyngrok
@@ -37,16 +37,15 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
39
39
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
40
+ [![OpenTelemetry](https://img.shields.io/badge/OpenTelemetry-Compatible-blue)](https://opentelemetry.io/)
40
41
 
41
- The **Quraite Python SDK** provides adapters and methods to integrate AI agent frameworks with the [Quraite platform](https://quraite.ai). It offers a unified interface for different agent frameworks, automatic tracing and observability, and easy local server setup with tunneling capabilities.
42
+ The **Quraite Python SDK** provides adapters and methods to integrate AI agent with the [Quraite platform](https://quraite.ai) for evaluation. It offers a unified interface for different agent frameworks, automatic tracing at every turn for agent trajectory evaluation, and easy local server setup with tunneling capabilities.
42
43
 
43
44
  ## Features
44
45
 
45
- - 🔌 **Framework Adapters**: Support for multiple AI agent frameworks (LangGraph, Pydantic AI, Agno, Google ADK, OpenAI Agents, Smolagents, AWS Bedrock, Flowise, Langflow, N8n, and more)
46
- - 📊 **Automatic Tracing**: Built-in OpenTelemetry-based tracing for agent execution, tool calls, and performance metrics
47
- - 🚀 **Local Server**: Easy-to-use local server with optional tunneling (Cloudflare/ngrok) for public access
48
- - 📦 **Standardized Schema**: Unified message and response formats across all frameworks
49
- - 🔍 **Observability**: Track token usage, costs, latency, and model information for each agent invocation
46
+ - 🔌 **Framework Adapters**: Support for multiple AI agent frameworks (LangChain, Pydantic AI, Agno, Google ADK, OpenAI Agents, Smolagents, AWS Bedrock, Flowise, Langflow, N8n, and more)
47
+ - 📊 **Automatic Tracing**: Built-in OpenInference-based (OpenTelemetry-based tracing support coming soon) tracing for agent trajectory evaluation. Track token usage, costs, latency, and model information for each agent invocation
48
+ - 🚀 **Local Server**: Easy-to-use local server with optional tunneling (Cloudflare/ngrok) for public access and integration with Quraite platform
50
49
 
51
50
  ## Installation
52
51
 
@@ -61,8 +60,8 @@ pip install quraite
61
60
  Install with optional dependencies for specific frameworks:
62
61
 
63
62
  ```bash
64
- # LangGraph
65
- pip install 'quraite[langgraph]'
63
+ # LangChain
64
+ pip install 'quraite[langchain]'
66
65
 
67
66
  # Pydantic AI
68
67
  pip install 'quraite[pydantic-ai]'
@@ -83,42 +82,45 @@ pip install 'quraite[smolagents]'
83
82
  pip install 'quraite[bedrock]'
84
83
 
85
84
  # Multiple frameworks
86
- pip install 'quraite[langgraph,pydantic-ai,agno]'
85
+ pip install 'quraite[langchain,pydantic-ai,agno]'
87
86
  ```
88
87
 
89
88
  ## Quick Start
90
89
 
91
- ### Example: LangGraph Agent with Local Server
90
+ ### Example: LangChain Agent with Local Server
92
91
 
93
- Pass your compiled LangGraph agent to the adapter and expose it as an HTTP API:
92
+ Pass your compiled LangChain agent to the adapter and expose it as an HTTP API:
94
93
 
95
94
  ```python
95
+ import asyncio
96
96
  import uvicorn
97
97
  from dotenv import load_dotenv
98
98
  from openinference.instrumentation import TracerProvider
99
99
  from openinference.instrumentation.langchain import LangChainInstrumentor
100
100
 
101
- from quraite.adapters import LanggraphAdapter
101
+ from quraite.adapters import LangChainAdapter
102
102
  from quraite.serve.local_agent import LocalAgentServer
103
103
  from quraite.tracing.span_exporter import QuraiteInMemorySpanExporter
104
104
  from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
105
105
 
106
106
  load_dotenv()
107
107
 
108
- # Set up tracing (optional)
108
+ # Set up tracing
109
+ # Use Quraite's in-memory span exporter to capture the agent trajectory
110
+ # and use it for evaluation.
109
111
  tracer_provider = TracerProvider()
110
112
  quraite_span_exporter = QuraiteInMemorySpanExporter()
111
113
  quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
112
114
  tracer_provider.add_span_processor(quraite_span_processor)
113
115
  LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
114
116
 
115
- # Your compiled LangGraph agent (created elsewhere)
117
+ # Your compiled LangChain agent (created elsewhere)
116
118
  # agent = create_agent(...)
117
119
 
118
120
  # Wrap with Quraite adapter
119
- adapter = LanggraphAdapter(
120
- agent_graph=agent, # Pass your compiled LangGraph agent here
121
- tracer_provider=tracer_provider, # Optional: for tracing
121
+ adapter = LangChainAdapter(
122
+ agent_graph=agent, # Pass your compiled LangChain agent here
123
+ tracer_provider=tracer_provider,
122
124
  )
123
125
 
124
126
  # Create and start server with Cloudflare tunnel
@@ -133,14 +135,18 @@ app = server.create_app(
133
135
  tunnel="cloudflare", # Options: "cloudflare", "ngrok", or "none"
134
136
  )
135
137
 
136
- if __name__ == "__main__":
137
- uvicorn.run("local_server:app", host="0.0.0.0", port=8080)
138
+ # Option 1: Use the start method to start the server
139
+ asyncio.run(server.start(host="0.0.0.0", port=8080))
140
+
141
+ # Option 2: Use uvicorn to start the server for auto-reload
142
+ # if __name__ == "__main__":
143
+ # uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
138
144
  ```
139
145
 
140
146
  The server exposes:
141
147
 
142
148
  - `GET /` - Health check endpoint
143
- - `POST /v1/agents/completions` - Agent invocation endpoint
149
+ - `POST /v1/agents/completions` - Agent invocation endpoint. This is the endpoint that Quraite will use to invoke your agent.
144
150
 
145
151
  When using `tunnel="cloudflare"` or `tunnel="ngrok"`, your agent will be publicly accessible via the generated URL.
146
152
 
@@ -148,7 +154,7 @@ When using `tunnel="cloudflare"` or `tunnel="ngrok"`, your agent will be publicl
148
154
 
149
155
  | Framework | Adapter | Installation |
150
156
  | -------------------- | ------------------------ | -------------------------------------- |
151
- | **LangGraph** | `LanggraphAdapter` | `pip install 'quraite[langgraph]'` |
157
+ | **LangChain** | `LangChainAdapter` | `pip install 'quraite[langchain]'` |
152
158
  | **Pydantic AI** | `PydanticAIAdapter` | `pip install 'quraite[pydantic-ai]'` |
153
159
  | **Agno** | `AgnoAdapter` | `pip install 'quraite[agno]'` |
154
160
  | **Google ADK** | `GoogleADKAdapter` | `pip install 'quraite[google-adk]'` |
@@ -159,27 +165,28 @@ When using `tunnel="cloudflare"` or `tunnel="ngrok"`, your agent will be publicl
159
165
  | **Langflow** | `LangflowAdapter` | Included in base package |
160
166
  | **N8n** | `N8nAdapter` | Included in base package |
161
167
  | **HTTP** | `HttpAdapter` | Included in base package |
162
- | **LangGraph Server** | `LanggraphServerAdapter` | `pip install 'quraite[langgraph]'` |
168
+ | **LangChain Server** | `LangChainServerAdapter` | `pip install 'quraite[langchain]'` |
163
169
 
164
170
  ## Core Concepts
165
171
 
166
172
  ### Adapters
167
173
 
168
- Adapters provide a unified interface (`BaseAdapter`) for different agent frameworks. Each adapter:
174
+ Adapters provide a unified interface (`BaseAdapter`) for different agent frameworks. Each adapter converts framework-specific agent response formats to the Quraite agent message format.
175
+
176
+ If you are building your own agent framework, you can create a custom adapter by extending the `BaseAdapter` class and implementing the `ainvoke` method.
177
+
178
+ ### Tracing for Agent Trajectory Evaluation
169
179
 
170
- - Converts framework-specific agents to a standard interface
171
- - Handles message format conversion
172
- - Supports optional tracing integration
173
- - Provides async invocation via `ainvoke()`
180
+ **Capture agent trajectories without modifying your code.** Get comprehensive trace data including token usage, costs, and latency for every agent step.
174
181
 
175
- ### Tracing
182
+ Most agent frameworks return agent steps, but lack critical observability data. We solve this with **OpenInference instrumentation** (OpenTelemetry instrumentation support coming soon) that automatically captures:
176
183
 
177
- The SDK includes built-in OpenTelemetry-based tracing that captures:
184
+ - Complete agent trajectories
185
+ - Token usage and costs
186
+ - Step-by-step latency
187
+ - Full execution context
178
188
 
179
- - **Agent Trajectory**: Complete conversation flow with all messages
180
- - **Tool Calls**: Tool invocations with inputs and outputs
181
- - **Performance Metrics**: Token usage, costs, latency
182
- - **Model Information**: Model name and provider details
189
+ **Works with your existing setup.** We provide OpenInference-compatible span exporters and processors that integrate seamlessly with your current observability platform - no vendor lock-in required.
183
190
 
184
191
  To enable tracing:
185
192
 
@@ -189,11 +196,13 @@ from quraite.tracing.span_exporter import QuraiteInMemorySpanExporter
189
196
  from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
190
197
 
191
198
  tracer_provider = TracerProvider()
199
+
200
+ # Add Quraite span exporter and processor to the tracer provider
192
201
  quraite_span_exporter = QuraiteInMemorySpanExporter()
193
202
  quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
194
203
  tracer_provider.add_span_processor(quraite_span_processor)
195
204
 
196
- # Instrument your framework (example for LangChain)
205
+ # Instrument your framework with OpenInference
197
206
  from openinference.instrumentation.langchain import LangChainInstrumentor
198
207
  LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
199
208
  ```
@@ -251,18 +260,15 @@ response: AgentInvocationResponse = await adapter.ainvoke(
251
260
  # Access trajectory (list of messages)
252
261
  trajectory = response.agent_trajectory
253
262
 
254
- # Access trace (if tracing enabled)
263
+ # Access trace
255
264
  trace = response.agent_trace
256
-
257
- # Access final response text
258
- final_response = response.agent_final_response
259
265
  ```
260
266
 
261
267
  ## Examples
262
268
 
263
269
  The repository includes comprehensive examples for each supported framework:
264
270
 
265
- - [`langgraph_calculator_agent`](examples/langgraph_calculator_agent/) - LangGraph calculator agent
271
+ - [`langchain_calculator_agent`](examples/langchain_calculator_agent/) - LangChain calculator agent
266
272
  - [`pydantic_calculator_agent`](examples/pydantic_calculator_agent/) - Pydantic AI calculator agent
267
273
  - [`agno_calculator_agent`](examples/agno_calculator_agent/) - Agno calculator agent
268
274
  - [`google_adk_weather_agent`](examples/google_adk_weather_agent/) - Google ADK weather agent
@@ -302,6 +308,7 @@ class MyAdapter(BaseAdapter):
302
308
  Create a local HTTP server for your agent:
303
309
 
304
310
  ```python
311
+ import asyncio
305
312
  from quraite.serve.local_agent import LocalAgentServer
306
313
 
307
314
  server = LocalAgentServer(
@@ -314,6 +321,8 @@ app = server.create_app(
314
321
  host="0.0.0.0",
315
322
  tunnel="cloudflare", # or "ngrok" or "none"
316
323
  )
324
+
325
+ asyncio.run(server.start(host="0.0.0.0", port=8080))
317
326
  ```
318
327
 
319
328
  ## Development
@@ -2,16 +2,15 @@
2
2
 
3
3
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
4
4
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
5
+ [![OpenTelemetry](https://img.shields.io/badge/OpenTelemetry-Compatible-blue)](https://opentelemetry.io/)
5
6
 
6
- The **Quraite Python SDK** provides adapters and methods to integrate AI agent frameworks with the [Quraite platform](https://quraite.ai). It offers a unified interface for different agent frameworks, automatic tracing and observability, and easy local server setup with tunneling capabilities.
7
+ The **Quraite Python SDK** provides adapters and methods to integrate AI agent with the [Quraite platform](https://quraite.ai) for evaluation. It offers a unified interface for different agent frameworks, automatic tracing at every turn for agent trajectory evaluation, and easy local server setup with tunneling capabilities.
7
8
 
8
9
  ## Features
9
10
 
10
- - 🔌 **Framework Adapters**: Support for multiple AI agent frameworks (LangGraph, Pydantic AI, Agno, Google ADK, OpenAI Agents, Smolagents, AWS Bedrock, Flowise, Langflow, N8n, and more)
11
- - 📊 **Automatic Tracing**: Built-in OpenTelemetry-based tracing for agent execution, tool calls, and performance metrics
12
- - 🚀 **Local Server**: Easy-to-use local server with optional tunneling (Cloudflare/ngrok) for public access
13
- - 📦 **Standardized Schema**: Unified message and response formats across all frameworks
14
- - 🔍 **Observability**: Track token usage, costs, latency, and model information for each agent invocation
11
+ - 🔌 **Framework Adapters**: Support for multiple AI agent frameworks (LangChain, Pydantic AI, Agno, Google ADK, OpenAI Agents, Smolagents, AWS Bedrock, Flowise, Langflow, N8n, and more)
12
+ - 📊 **Automatic Tracing**: Built-in OpenInference-based (OpenTelemetry-based tracing support coming soon) tracing for agent trajectory evaluation. Track token usage, costs, latency, and model information for each agent invocation
13
+ - 🚀 **Local Server**: Easy-to-use local server with optional tunneling (Cloudflare/ngrok) for public access and integration with Quraite platform
15
14
 
16
15
  ## Installation
17
16
 
@@ -26,8 +25,8 @@ pip install quraite
26
25
  Install with optional dependencies for specific frameworks:
27
26
 
28
27
  ```bash
29
- # LangGraph
30
- pip install 'quraite[langgraph]'
28
+ # LangChain
29
+ pip install 'quraite[langchain]'
31
30
 
32
31
  # Pydantic AI
33
32
  pip install 'quraite[pydantic-ai]'
@@ -48,42 +47,45 @@ pip install 'quraite[smolagents]'
48
47
  pip install 'quraite[bedrock]'
49
48
 
50
49
  # Multiple frameworks
51
- pip install 'quraite[langgraph,pydantic-ai,agno]'
50
+ pip install 'quraite[langchain,pydantic-ai,agno]'
52
51
  ```
53
52
 
54
53
  ## Quick Start
55
54
 
56
- ### Example: LangGraph Agent with Local Server
55
+ ### Example: LangChain Agent with Local Server
57
56
 
58
- Pass your compiled LangGraph agent to the adapter and expose it as an HTTP API:
57
+ Pass your compiled LangChain agent to the adapter and expose it as an HTTP API:
59
58
 
60
59
  ```python
60
+ import asyncio
61
61
  import uvicorn
62
62
  from dotenv import load_dotenv
63
63
  from openinference.instrumentation import TracerProvider
64
64
  from openinference.instrumentation.langchain import LangChainInstrumentor
65
65
 
66
- from quraite.adapters import LanggraphAdapter
66
+ from quraite.adapters import LangChainAdapter
67
67
  from quraite.serve.local_agent import LocalAgentServer
68
68
  from quraite.tracing.span_exporter import QuraiteInMemorySpanExporter
69
69
  from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
70
70
 
71
71
  load_dotenv()
72
72
 
73
- # Set up tracing (optional)
73
+ # Set up tracing
74
+ # Use Quraite's in-memory span exporter to capture the agent trajectory
75
+ # and use it for evaluation.
74
76
  tracer_provider = TracerProvider()
75
77
  quraite_span_exporter = QuraiteInMemorySpanExporter()
76
78
  quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
77
79
  tracer_provider.add_span_processor(quraite_span_processor)
78
80
  LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
79
81
 
80
- # Your compiled LangGraph agent (created elsewhere)
82
+ # Your compiled LangChain agent (created elsewhere)
81
83
  # agent = create_agent(...)
82
84
 
83
85
  # Wrap with Quraite adapter
84
- adapter = LanggraphAdapter(
85
- agent_graph=agent, # Pass your compiled LangGraph agent here
86
- tracer_provider=tracer_provider, # Optional: for tracing
86
+ adapter = LangChainAdapter(
87
+ agent_graph=agent, # Pass your compiled LangChain agent here
88
+ tracer_provider=tracer_provider,
87
89
  )
88
90
 
89
91
  # Create and start server with Cloudflare tunnel
@@ -98,14 +100,18 @@ app = server.create_app(
98
100
  tunnel="cloudflare", # Options: "cloudflare", "ngrok", or "none"
99
101
  )
100
102
 
101
- if __name__ == "__main__":
102
- uvicorn.run("local_server:app", host="0.0.0.0", port=8080)
103
+ # Option 1: Use the start method to start the server
104
+ asyncio.run(server.start(host="0.0.0.0", port=8080))
105
+
106
+ # Option 2: Use uvicorn to start the server for auto-reload
107
+ # if __name__ == "__main__":
108
+ # uvicorn.run("local_server:app", host="0.0.0.0", port=8080, reload=True)
103
109
  ```
104
110
 
105
111
  The server exposes:
106
112
 
107
113
  - `GET /` - Health check endpoint
108
- - `POST /v1/agents/completions` - Agent invocation endpoint
114
+ - `POST /v1/agents/completions` - Agent invocation endpoint. This is the endpoint that Quraite will use to invoke your agent.
109
115
 
110
116
  When using `tunnel="cloudflare"` or `tunnel="ngrok"`, your agent will be publicly accessible via the generated URL.
111
117
 
@@ -113,7 +119,7 @@ When using `tunnel="cloudflare"` or `tunnel="ngrok"`, your agent will be publicl
113
119
 
114
120
  | Framework | Adapter | Installation |
115
121
  | -------------------- | ------------------------ | -------------------------------------- |
116
- | **LangGraph** | `LanggraphAdapter` | `pip install 'quraite[langgraph]'` |
122
+ | **LangChain** | `LangChainAdapter` | `pip install 'quraite[langchain]'` |
117
123
  | **Pydantic AI** | `PydanticAIAdapter` | `pip install 'quraite[pydantic-ai]'` |
118
124
  | **Agno** | `AgnoAdapter` | `pip install 'quraite[agno]'` |
119
125
  | **Google ADK** | `GoogleADKAdapter` | `pip install 'quraite[google-adk]'` |
@@ -124,27 +130,28 @@ When using `tunnel="cloudflare"` or `tunnel="ngrok"`, your agent will be publicl
124
130
  | **Langflow** | `LangflowAdapter` | Included in base package |
125
131
  | **N8n** | `N8nAdapter` | Included in base package |
126
132
  | **HTTP** | `HttpAdapter` | Included in base package |
127
- | **LangGraph Server** | `LanggraphServerAdapter` | `pip install 'quraite[langgraph]'` |
133
+ | **LangChain Server** | `LangChainServerAdapter` | `pip install 'quraite[langchain]'` |
128
134
 
129
135
  ## Core Concepts
130
136
 
131
137
  ### Adapters
132
138
 
133
- Adapters provide a unified interface (`BaseAdapter`) for different agent frameworks. Each adapter:
139
+ Adapters provide a unified interface (`BaseAdapter`) for different agent frameworks. Each adapter converts framework-specific agent response formats to the Quraite agent message format.
140
+
141
+ If you are building your own agent framework, you can create a custom adapter by extending the `BaseAdapter` class and implementing the `ainvoke` method.
142
+
143
+ ### Tracing for Agent Trajectory Evaluation
134
144
 
135
- - Converts framework-specific agents to a standard interface
136
- - Handles message format conversion
137
- - Supports optional tracing integration
138
- - Provides async invocation via `ainvoke()`
145
+ **Capture agent trajectories without modifying your code.** Get comprehensive trace data including token usage, costs, and latency for every agent step.
139
146
 
140
- ### Tracing
147
+ Most agent frameworks return agent steps, but lack critical observability data. We solve this with **OpenInference instrumentation** (OpenTelemetry instrumentation support coming soon) that automatically captures:
141
148
 
142
- The SDK includes built-in OpenTelemetry-based tracing that captures:
149
+ - Complete agent trajectories
150
+ - Token usage and costs
151
+ - Step-by-step latency
152
+ - Full execution context
143
153
 
144
- - **Agent Trajectory**: Complete conversation flow with all messages
145
- - **Tool Calls**: Tool invocations with inputs and outputs
146
- - **Performance Metrics**: Token usage, costs, latency
147
- - **Model Information**: Model name and provider details
154
+ **Works with your existing setup.** We provide OpenInference-compatible span exporters and processors that integrate seamlessly with your current observability platform - no vendor lock-in required.
148
155
 
149
156
  To enable tracing:
150
157
 
@@ -154,11 +161,13 @@ from quraite.tracing.span_exporter import QuraiteInMemorySpanExporter
154
161
  from quraite.tracing.span_processor import QuraiteSimpleSpanProcessor
155
162
 
156
163
  tracer_provider = TracerProvider()
164
+
165
+ # Add Quraite span exporter and processor to the tracer provider
157
166
  quraite_span_exporter = QuraiteInMemorySpanExporter()
158
167
  quraite_span_processor = QuraiteSimpleSpanProcessor(quraite_span_exporter)
159
168
  tracer_provider.add_span_processor(quraite_span_processor)
160
169
 
161
- # Instrument your framework (example for LangChain)
170
+ # Instrument your framework with OpenInference
162
171
  from openinference.instrumentation.langchain import LangChainInstrumentor
163
172
  LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
164
173
  ```
@@ -216,18 +225,15 @@ response: AgentInvocationResponse = await adapter.ainvoke(
216
225
  # Access trajectory (list of messages)
217
226
  trajectory = response.agent_trajectory
218
227
 
219
- # Access trace (if tracing enabled)
228
+ # Access trace
220
229
  trace = response.agent_trace
221
-
222
- # Access final response text
223
- final_response = response.agent_final_response
224
230
  ```
225
231
 
226
232
  ## Examples
227
233
 
228
234
  The repository includes comprehensive examples for each supported framework:
229
235
 
230
- - [`langgraph_calculator_agent`](examples/langgraph_calculator_agent/) - LangGraph calculator agent
236
+ - [`langchain_calculator_agent`](examples/langchain_calculator_agent/) - LangChain calculator agent
231
237
  - [`pydantic_calculator_agent`](examples/pydantic_calculator_agent/) - Pydantic AI calculator agent
232
238
  - [`agno_calculator_agent`](examples/agno_calculator_agent/) - Agno calculator agent
233
239
  - [`google_adk_weather_agent`](examples/google_adk_weather_agent/) - Google ADK weather agent
@@ -267,6 +273,7 @@ class MyAdapter(BaseAdapter):
267
273
  Create a local HTTP server for your agent:
268
274
 
269
275
  ```python
276
+ import asyncio
270
277
  from quraite.serve.local_agent import LocalAgentServer
271
278
 
272
279
  server = LocalAgentServer(
@@ -279,6 +286,8 @@ app = server.create_app(
279
286
  host="0.0.0.0",
280
287
  tunnel="cloudflare", # or "ngrok" or "none"
281
288
  )
289
+
290
+ asyncio.run(server.start(host="0.0.0.0", port=8080))
282
291
  ```
283
292
 
284
293
  ## Development
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "quraite"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  description = "This project provides adaptors and methods to integrate with the Quraite platform"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -24,7 +24,7 @@ agno = ["agno>=2.3.4"]
24
24
 
25
25
  google-adk = ["google-adk>=1.18.0"]
26
26
 
27
- langgraph = [
27
+ langchain = [
28
28
  "langchain>=1.0.5",
29
29
  "langgraph>=1.0.3"
30
30
  ]
@@ -9,8 +9,8 @@ if TYPE_CHECKING:
9
9
  from quraite.adapters.flowise_adapter import FlowiseAdapter
10
10
  from quraite.adapters.google_adk_adapter import GoogleADKAdapter
11
11
  from quraite.adapters.langflow_adapter import LangflowAdapter
12
- from quraite.adapters.langgraph_adapter import LanggraphAdapter
13
- from quraite.adapters.langgraph_server_adapter import LanggraphServerAdapter
12
+ from quraite.adapters.langchain_adapter import LangchainAdapter
13
+ from quraite.adapters.langchain_server_adapter import LangchainServerAdapter
14
14
  from quraite.adapters.n8n_adapter import N8nAdapter
15
15
  from quraite.adapters.openai_agents_adapter import OpenaiAgentsAdapter
16
16
  from quraite.adapters.pydantic_ai_adapter import PydanticAIAdapter
@@ -25,8 +25,8 @@ __all__ = [
25
25
  "FlowiseAdapter",
26
26
  "GoogleADKAdapter",
27
27
  "LangflowAdapter",
28
- "LanggraphAdapter",
29
- "LanggraphServerAdapter",
28
+ "LangchainAdapter",
29
+ "LangchainServerAdapter",
30
30
  "N8nAdapter",
31
31
  "OpenaiAgentsAdapter",
32
32
  "PydanticAIAdapter",
@@ -76,24 +76,24 @@ def __getattr__(name: str):
76
76
 
77
77
  return LangflowAdapter
78
78
 
79
- elif name == "LanggraphAdapter":
79
+ elif name == "LangchainAdapter":
80
80
  try:
81
- from quraite.adapters.langgraph_adapter import LanggraphAdapter
81
+ from quraite.adapters.langchain_adapter import LangchainAdapter
82
82
 
83
- return LanggraphAdapter
83
+ return LangchainAdapter
84
84
  except ImportError as e:
85
85
  raise ImportError(
86
- f"Failed to import {name}. Please install the 'langgraph' optional dependency: pip install 'quraite[langgraph]'"
86
+ f"Failed to import {name}. Please install the 'langchain' optional dependency: pip install 'quraite[langchain]'"
87
87
  ) from e
88
88
 
89
- elif name == "LanggraphServerAdapter":
89
+ elif name == "LangchainServerAdapter":
90
90
  try:
91
- from quraite.adapters.langgraph_server_adapter import LanggraphServerAdapter
91
+ from quraite.adapters.langchain_server_adapter import LangchainServerAdapter
92
92
 
93
- return LanggraphServerAdapter
93
+ return LangchainServerAdapter
94
94
  except ImportError as e:
95
95
  raise ImportError(
96
- f"Failed to import {name}. Please install the 'langgraph' optional dependency: pip install 'quraite[langgraph]'"
96
+ f"Failed to import {name}. Please install the 'langchain' optional dependency: pip install 'quraite[langchain]'"
97
97
  ) from e
98
98
 
99
99
  elif name == "N8nAdapter":
@@ -1,4 +1,3 @@
1
- import uuid
2
1
  from typing import List, Union
3
2
 
4
3
  from agno.agent import Agent
@@ -9,7 +8,7 @@ from quraite.adapters.base import BaseAdapter
9
8
  from quraite.logger import get_logger
10
9
  from quraite.schema.message import AgentMessage
11
10
  from quraite.schema.response import AgentInvocationResponse
12
- from quraite.tracing.constants import QURAITE_ADAPTER_TRACE_PREFIX, Framework
11
+ from quraite.tracing.constants import Framework
13
12
  from quraite.tracing.trace import AgentSpan, AgentTrace
14
13
 
15
14
  logger = get_logger(__name__)
@@ -122,27 +121,26 @@ class AgnoAdapter(BaseAdapter):
122
121
  session_id: str,
123
122
  ) -> AgentInvocationResponse:
124
123
  """Execute ainvoke with tracing enabled."""
125
- adapter_trace_id = f"{QURAITE_ADAPTER_TRACE_PREFIX}-{uuid.uuid4()}"
126
- logger.debug(
127
- "Starting traced invocation (trace_id=%s, session_id=%s)",
128
- adapter_trace_id,
129
- session_id,
130
- )
131
-
132
- with self.tracer.start_as_current_span(name=adapter_trace_id):
124
+ with self.tracer.start_as_current_span("agno_invocation") as span:
125
+ trace_id = span.get_span_context().trace_id
126
+ logger.debug(
127
+ "Starting traced invocation (session_id=%s) with trace_id=%s",
128
+ session_id,
129
+ trace_id,
130
+ )
133
131
  # Run the agent/team
134
132
  await self.agent.arun(agent_input, session_id=session_id)
135
133
 
136
134
  # Get trace spans
137
- trace_readable_spans = self.quraite_span_exporter.get_trace_by_testcase(
138
- adapter_trace_id
135
+ trace_readable_spans = self.quraite_span_exporter.get_spans_by_trace_id(
136
+ trace_id
139
137
  )
140
138
 
141
139
  if trace_readable_spans:
142
140
  logger.info(
143
141
  "Retrieved %d spans for trace_id=%s",
144
142
  len(trace_readable_spans),
145
- adapter_trace_id,
143
+ trace_id,
146
144
  )
147
145
  agent_trace = AgentTrace(
148
146
  spans=[
@@ -151,7 +149,7 @@ class AgnoAdapter(BaseAdapter):
151
149
  ],
152
150
  )
153
151
  else:
154
- logger.warning("No spans found for trace_id=%s", adapter_trace_id)
152
+ logger.warning("No spans found for trace_id=%s", trace_id)
155
153
 
156
154
  return AgentInvocationResponse(
157
155
  agent_trace=agent_trace,
@@ -1,7 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from typing import Any, List, Optional, Union
3
3
 
4
- from opentelemetry.trace import TracerProvider
4
+ from opentelemetry.trace import Tracer, TracerProvider
5
5
 
6
6
  from quraite.schema.message import AgentMessage, AssistantMessage, MessageContentText
7
7
  from quraite.schema.response import AgentInvocationResponse
@@ -22,7 +22,7 @@ class BaseAdapter(ABC):
22
22
  """
23
23
 
24
24
  tracer_provider: Optional[TracerProvider] = None
25
- tracer: Optional[Any] = None
25
+ tracer: Optional[Tracer] = None
26
26
  quraite_span_exporter: Optional[QuraiteInMemorySpanExporter] = None
27
27
 
28
28
  def _init_tracing(
@@ -13,7 +13,7 @@ from quraite.adapters.base import BaseAdapter
13
13
  from quraite.logger import get_logger
14
14
  from quraite.schema.message import AgentMessage
15
15
  from quraite.schema.response import AgentInvocationResponse
16
- from quraite.tracing.constants import QURAITE_ADAPTER_TRACE_PREFIX, Framework
16
+ from quraite.tracing.constants import Framework
17
17
  from quraite.tracing.trace import AgentSpan, AgentTrace
18
18
 
19
19
  logger = get_logger(__name__)
@@ -141,14 +141,18 @@ class GoogleADKAdapter(BaseAdapter):
141
141
  session_id: str,
142
142
  ) -> AgentInvocationResponse:
143
143
  """Execute ainvoke with tracing enabled."""
144
- adapter_trace_id = f"{QURAITE_ADAPTER_TRACE_PREFIX}-{uuid.uuid4()}"
145
144
  logger.debug(
146
- "Starting Google ADK traced invocation (trace_id=%s, session_id=%s)",
147
- adapter_trace_id,
145
+ "Starting Google ADK traced invocation (session_id=%s)",
148
146
  session_id,
149
147
  )
150
148
 
151
- with self.tracer.start_as_current_span(name=adapter_trace_id):
149
+ with self.tracer.start_as_current_span("google_adk_invocation") as span:
150
+ trace_id = span.get_span_context().trace_id
151
+ logger.debug(
152
+ "Starting Google ADK traced invocation (trace_id=%s, session_id=%s)",
153
+ trace_id,
154
+ session_id,
155
+ )
152
156
  # Create session if it doesn't exist
153
157
  try:
154
158
  await self.session_service.create_session(
@@ -180,8 +184,8 @@ class GoogleADKAdapter(BaseAdapter):
180
184
  pass # Just consume events, tracing handles capture
181
185
 
182
186
  # Get trace spans
183
- trace_readable_spans = self.quraite_span_exporter.get_trace_by_testcase(
184
- adapter_trace_id
187
+ trace_readable_spans = self.quraite_span_exporter.get_spans_by_trace_id(
188
+ trace_id
185
189
  )
186
190
 
187
191
  if trace_readable_spans:
@@ -194,12 +198,10 @@ class GoogleADKAdapter(BaseAdapter):
194
198
  logger.info(
195
199
  "Google ADK trace collected %d spans for trace_id=%s",
196
200
  len(trace_readable_spans),
197
- adapter_trace_id,
201
+ trace_id,
198
202
  )
199
203
  else:
200
- logger.warning(
201
- "No spans exported for Google ADK trace_id=%s", adapter_trace_id
202
- )
204
+ logger.warning("No spans exported for Google ADK trace_id=%s", trace_id)
203
205
 
204
206
  return AgentInvocationResponse(
205
207
  agent_trace=agent_trace,