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.
Files changed (48) hide show
  1. quraite/__init__.py +3 -3
  2. quraite/adapters/__init__.py +134 -134
  3. quraite/adapters/agno_adapter.py +159 -159
  4. quraite/adapters/base.py +123 -123
  5. quraite/adapters/bedrock_agents_adapter.py +343 -343
  6. quraite/adapters/flowise_adapter.py +275 -275
  7. quraite/adapters/google_adk_adapter.py +209 -209
  8. quraite/adapters/http_adapter.py +239 -239
  9. quraite/adapters/langflow_adapter.py +192 -192
  10. quraite/adapters/langgraph_adapter.py +304 -304
  11. quraite/adapters/langgraph_server_adapter.py +252 -252
  12. quraite/adapters/n8n_adapter.py +220 -220
  13. quraite/adapters/openai_agents_adapter.py +269 -269
  14. quraite/adapters/pydantic_ai_adapter.py +312 -312
  15. quraite/adapters/smolagents_adapter.py +152 -152
  16. quraite/logger.py +61 -62
  17. quraite/schema/message.py +91 -54
  18. quraite/schema/response.py +16 -16
  19. quraite/serve/__init__.py +1 -1
  20. quraite/serve/cloudflared.py +210 -210
  21. quraite/serve/local_agent.py +360 -360
  22. quraite/tracing/__init__.py +24 -24
  23. quraite/tracing/constants.py +16 -16
  24. quraite/tracing/span_exporter.py +115 -115
  25. quraite/tracing/span_processor.py +49 -49
  26. quraite/tracing/tool_extractors.py +290 -290
  27. quraite/tracing/trace.py +564 -494
  28. quraite/tracing/types.py +179 -179
  29. quraite/tracing/utils.py +170 -170
  30. quraite/utils/json_utils.py +269 -269
  31. {quraite-0.0.1.dist-info → quraite-0.1.0.dist-info}/METADATA +9 -9
  32. quraite-0.1.0.dist-info/RECORD +35 -0
  33. {quraite-0.0.1.dist-info → quraite-0.1.0.dist-info}/WHEEL +1 -1
  34. quraite/traces/traces_adk_openinference.json +0 -379
  35. quraite/traces/traces_agno_multi_agent.json +0 -669
  36. quraite/traces/traces_agno_openinference.json +0 -321
  37. quraite/traces/traces_crewai_openinference.json +0 -155
  38. quraite/traces/traces_langgraph_openinference.json +0 -349
  39. quraite/traces/traces_langgraph_openinference_multi_agent.json +0 -2705
  40. quraite/traces/traces_langgraph_traceloop.json +0 -510
  41. quraite/traces/traces_openai_agents_multi_agent_1.json +0 -402
  42. quraite/traces/traces_openai_agents_openinference.json +0 -341
  43. quraite/traces/traces_pydantic_openinference.json +0 -286
  44. quraite/traces/traces_pydantic_openinference_multi_agent_1.json +0 -399
  45. quraite/traces/traces_pydantic_openinference_multi_agent_2.json +0 -398
  46. quraite/traces/traces_smol_agents_openinference.json +0 -397
  47. quraite/traces/traces_smol_agents_tool_calling_openinference.json +0 -704
  48. quraite-0.0.1.dist-info/RECORD +0 -49
@@ -1,239 +1,239 @@
1
- """
2
- HTTP Adapter - Connects to remote agent servers via HTTP.
3
-
4
- This module provides a BaseAdapter implementation that calls remote agent
5
- servers via HTTP endpoints, enabling distributed agent evaluation.
6
- """
7
-
8
- from typing import Any, Dict, List, Optional, Union
9
-
10
- import httpx
11
-
12
- from quraite.adapters.base import BaseAdapter
13
- from quraite.logger import get_logger
14
- from quraite.schema.message import AgentMessage
15
- from quraite.schema.response import AgentInvocationResponse
16
-
17
- logger = get_logger(__name__)
18
-
19
-
20
- class HttpAdapter(BaseAdapter):
21
- """
22
- HTTP adapter client that communicates with agent servers via HTTP.
23
-
24
- This class implements the BaseAdapter interface and forwards adapter
25
- requests to a HTTP agent server, handling serialization, network errors,
26
- and retries.
27
-
28
- Args:
29
- url: The full URL of the remote agent endpoint (e.g., "http://localhost:8000/v1/agents/completions")
30
- headers: Optional dictionary of HTTP headers to include in requests
31
- timeout: Request timeout in seconds (default: 60)
32
- max_retries: Maximum number of retry attempts (default: 3)
33
- retry_delay: Initial retry delay in seconds (default: 1)
34
-
35
- Example:
36
- ```python
37
- remote_agent = HttpAdapter(
38
- url="http://localhost:8000/v1/agents/completions",
39
- headers={"Authorization": "Bearer secret_key"}
40
- )
41
-
42
- result = remote_agent.ainvoke(
43
- input=[UserMessage(...)],
44
- session_id="conv_123"
45
- )
46
- ```
47
- """
48
-
49
- def __init__(
50
- self,
51
- url: str,
52
- headers: Optional[Dict[str, str]] = None,
53
- timeout: float = 60.0,
54
- max_retries: int = 3,
55
- retry_delay: float = 1.0,
56
- ):
57
- """Initialize the HTTP adapter client."""
58
- self.url = url.rstrip("/")
59
- self.headers = headers or {}
60
- self.timeout = timeout
61
- self.max_retries = max_retries
62
- self.retry_delay = retry_delay
63
-
64
- # Create HTTP client with user-provided headers
65
- # Always include Content-Type if not provided
66
- client_headers = {"Content-Type": "application/json"}
67
- client_headers.update(self.headers)
68
-
69
- self.async_client = httpx.AsyncClient(
70
- headers=client_headers,
71
- timeout=self.timeout,
72
- )
73
- logger.info(
74
- "HttpAdapter initialized (url=%s, timeout=%s, max_retries=%s)",
75
- self.url,
76
- self.timeout,
77
- self.max_retries,
78
- )
79
-
80
- def _serialize_request(
81
- self,
82
- input: List[AgentMessage],
83
- session_id: Union[str, None],
84
- ) -> Dict[str, Any]:
85
- """
86
- Serialize invocation request to JSON-compatible dict.
87
-
88
- Args:
89
- input: List[AgentMessage] containing user_message
90
- session_id: Optional conversation ID for maintaining context
91
-
92
- Returns:
93
- Dictionary ready for JSON serialization
94
- """
95
- logger.debug(
96
- "Serializing HTTP request (messages=%d, session_id=%s)",
97
- len(input),
98
- session_id,
99
- )
100
- return {
101
- "input": [msg.model_dump(mode="json") for msg in input],
102
- "session_id": session_id,
103
- }
104
-
105
- async def _make_request_with_retry_async(
106
- self,
107
- method: str,
108
- url: str,
109
- payload: Dict[str, Any],
110
- ) -> Dict[str, Any]:
111
- """
112
- Make HTTP request with retry logic (asynchronous).
113
-
114
- Args:
115
- method: HTTP method (POST)
116
- url: Full URL of the endpoint
117
- payload: Request payload
118
-
119
- Returns:
120
- Response data as dictionary
121
-
122
- Raises:
123
- httpx.HTTPError: If all retries fail
124
- ValueError: If response format is invalid
125
- """
126
- last_exception = None
127
-
128
- for attempt in range(self.max_retries):
129
- try:
130
- response = await self.async_client.request(
131
- method=method,
132
- url=url,
133
- json=payload,
134
- )
135
- response.raise_for_status()
136
- logger.info(
137
- "HTTP request succeeded (status=%s, attempt=%d)",
138
- response.status_code,
139
- attempt + 1,
140
- )
141
- return response.json()
142
-
143
- except httpx.HTTPStatusError as e:
144
- # Don't retry on 4xx errors (client errors)
145
- if 400 <= e.response.status_code < 500:
146
- error_detail = e.response.text
147
- logger.error(
148
- "HTTP adapter received 4xx response (status=%s, detail=%s)",
149
- e.response.status_code,
150
- error_detail,
151
- )
152
- raise ValueError(
153
- f"Agent server error ({e.response.status_code}): {error_detail}"
154
- ) from e
155
-
156
- # Retry on 5xx errors
157
- last_exception = e
158
- if attempt < self.max_retries - 1:
159
- delay = self.retry_delay * (2**attempt)
160
- logger.warning(
161
- "HTTP adapter retrying after server error (status=%s, retry_in=%.2fs)",
162
- e.response.status_code,
163
- delay,
164
- )
165
- await self._async_sleep(delay)
166
-
167
- except (httpx.ConnectError, httpx.TimeoutException) as e:
168
- # Retry on network errors
169
- last_exception = e
170
- if attempt < self.max_retries - 1:
171
- delay = self.retry_delay * (2**attempt)
172
- logger.warning(
173
- "HTTP adapter retrying after network error (retry_in=%.2fs)",
174
- delay,
175
- )
176
- await self._async_sleep(delay)
177
-
178
- # All retries failed
179
- logger.exception(
180
- "HTTP adapter failed after %d attempts (url=%s)",
181
- self.max_retries,
182
- self.url,
183
- )
184
- raise RuntimeError(
185
- f"Failed to connect to agent server at {self.url} after "
186
- f"{self.max_retries} attempts. Last error: {last_exception}"
187
- ) from last_exception
188
-
189
- @staticmethod
190
- async def _async_sleep(seconds: float):
191
- """Helper for async sleep."""
192
- import asyncio
193
-
194
- await asyncio.sleep(seconds)
195
-
196
- async def ainvoke(
197
- self,
198
- input: List[AgentMessage],
199
- session_id: Union[str, None],
200
- ) -> AgentInvocationResponse:
201
- """
202
- Asynchronously invoke the HTTP agent.
203
-
204
- Args:
205
- input: List[AgentMessage] containing user_message
206
- session_id: Optional conversation ID for maintaining context
207
-
208
- Returns:
209
- AgentInvocationResponse: Response containing agent trace, trajectory, and final response.
210
- """
211
- logger.info(
212
- "HTTP ainvoke called (session_id=%s, input_messages=%d)",
213
- session_id,
214
- len(input),
215
- )
216
- payload = self._serialize_request(input, session_id)
217
- response_data = await self._make_request_with_retry_async(
218
- method="POST", url=self.url, payload=payload
219
- )
220
- logger.debug(
221
- "HTTP adapter received response keys: %s", list(response_data.keys())
222
- )
223
-
224
- return AgentInvocationResponse.model_validate(
225
- response_data.get("agent_response", {})
226
- )
227
-
228
- async def aclose(self):
229
- """Close async HTTP client."""
230
- await self.async_client.aclose()
231
- logger.debug("HTTP adapter client closed")
232
-
233
- async def __aenter__(self):
234
- """Async context manager entry."""
235
- return self
236
-
237
- async def __aexit__(self, exc_type, exc_val, exc_tb):
238
- """Async context manager exit."""
239
- await self.aclose()
1
+ """
2
+ HTTP Adapter - Connects to remote agent servers via HTTP.
3
+
4
+ This module provides a BaseAdapter implementation that calls remote agent
5
+ servers via HTTP endpoints, enabling distributed agent evaluation.
6
+ """
7
+
8
+ from typing import Any, Dict, List, Optional, Union
9
+
10
+ import httpx
11
+
12
+ from quraite.adapters.base import BaseAdapter
13
+ from quraite.logger import get_logger
14
+ from quraite.schema.message import AgentMessage
15
+ from quraite.schema.response import AgentInvocationResponse
16
+
17
+ logger = get_logger(__name__)
18
+
19
+
20
+ class HttpAdapter(BaseAdapter):
21
+ """
22
+ HTTP adapter client that communicates with agent servers via HTTP.
23
+
24
+ This class implements the BaseAdapter interface and forwards adapter
25
+ requests to a HTTP agent server, handling serialization, network errors,
26
+ and retries.
27
+
28
+ Args:
29
+ url: The full URL of the remote agent endpoint (e.g., "http://localhost:8000/v1/agents/completions")
30
+ headers: Optional dictionary of HTTP headers to include in requests
31
+ timeout: Request timeout in seconds (default: 60)
32
+ max_retries: Maximum number of retry attempts (default: 3)
33
+ retry_delay: Initial retry delay in seconds (default: 1)
34
+
35
+ Example:
36
+ ```python
37
+ remote_agent = HttpAdapter(
38
+ url="http://localhost:8000/v1/agents/completions",
39
+ headers={"Authorization": "Bearer secret_key"}
40
+ )
41
+
42
+ result = remote_agent.ainvoke(
43
+ input=[UserMessage(...)],
44
+ session_id="conv_123"
45
+ )
46
+ ```
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ url: str,
52
+ headers: Optional[Dict[str, str]] = None,
53
+ timeout: float = 60.0,
54
+ max_retries: int = 3,
55
+ retry_delay: float = 1.0,
56
+ ):
57
+ """Initialize the HTTP adapter client."""
58
+ self.url = url.rstrip("/")
59
+ self.headers = headers or {}
60
+ self.timeout = timeout
61
+ self.max_retries = max_retries
62
+ self.retry_delay = retry_delay
63
+
64
+ # Create HTTP client with user-provided headers
65
+ # Always include Content-Type if not provided
66
+ client_headers = {"Content-Type": "application/json"}
67
+ client_headers.update(self.headers)
68
+
69
+ self.async_client = httpx.AsyncClient(
70
+ headers=client_headers,
71
+ timeout=self.timeout,
72
+ )
73
+ logger.info(
74
+ "HttpAdapter initialized (url=%s, timeout=%s, max_retries=%s)",
75
+ self.url,
76
+ self.timeout,
77
+ self.max_retries,
78
+ )
79
+
80
+ def _serialize_request(
81
+ self,
82
+ input: List[AgentMessage],
83
+ session_id: Union[str, None],
84
+ ) -> Dict[str, Any]:
85
+ """
86
+ Serialize invocation request to JSON-compatible dict.
87
+
88
+ Args:
89
+ input: List[AgentMessage] containing user_message
90
+ session_id: Optional conversation ID for maintaining context
91
+
92
+ Returns:
93
+ Dictionary ready for JSON serialization
94
+ """
95
+ logger.debug(
96
+ "Serializing HTTP request (messages=%d, session_id=%s)",
97
+ len(input),
98
+ session_id,
99
+ )
100
+ return {
101
+ "input": [msg.model_dump(mode="json") for msg in input],
102
+ "session_id": session_id,
103
+ }
104
+
105
+ async def _make_request_with_retry_async(
106
+ self,
107
+ method: str,
108
+ url: str,
109
+ payload: Dict[str, Any],
110
+ ) -> Dict[str, Any]:
111
+ """
112
+ Make HTTP request with retry logic (asynchronous).
113
+
114
+ Args:
115
+ method: HTTP method (POST)
116
+ url: Full URL of the endpoint
117
+ payload: Request payload
118
+
119
+ Returns:
120
+ Response data as dictionary
121
+
122
+ Raises:
123
+ httpx.HTTPError: If all retries fail
124
+ ValueError: If response format is invalid
125
+ """
126
+ last_exception = None
127
+
128
+ for attempt in range(self.max_retries):
129
+ try:
130
+ response = await self.async_client.request(
131
+ method=method,
132
+ url=url,
133
+ json=payload,
134
+ )
135
+ response.raise_for_status()
136
+ logger.info(
137
+ "HTTP request succeeded (status=%s, attempt=%d)",
138
+ response.status_code,
139
+ attempt + 1,
140
+ )
141
+ return response.json()
142
+
143
+ except httpx.HTTPStatusError as e:
144
+ # Don't retry on 4xx errors (client errors)
145
+ if 400 <= e.response.status_code < 500:
146
+ error_detail = e.response.text
147
+ logger.error(
148
+ "HTTP adapter received 4xx response (status=%s, detail=%s)",
149
+ e.response.status_code,
150
+ error_detail,
151
+ )
152
+ raise ValueError(
153
+ f"Agent server error ({e.response.status_code}): {error_detail}"
154
+ ) from e
155
+
156
+ # Retry on 5xx errors
157
+ last_exception = e
158
+ if attempt < self.max_retries - 1:
159
+ delay = self.retry_delay * (2**attempt)
160
+ logger.warning(
161
+ "HTTP adapter retrying after server error (status=%s, retry_in=%.2fs)",
162
+ e.response.status_code,
163
+ delay,
164
+ )
165
+ await self._async_sleep(delay)
166
+
167
+ except (httpx.ConnectError, httpx.TimeoutException) as e:
168
+ # Retry on network errors
169
+ last_exception = e
170
+ if attempt < self.max_retries - 1:
171
+ delay = self.retry_delay * (2**attempt)
172
+ logger.warning(
173
+ "HTTP adapter retrying after network error (retry_in=%.2fs)",
174
+ delay,
175
+ )
176
+ await self._async_sleep(delay)
177
+
178
+ # All retries failed
179
+ logger.exception(
180
+ "HTTP adapter failed after %d attempts (url=%s)",
181
+ self.max_retries,
182
+ self.url,
183
+ )
184
+ raise RuntimeError(
185
+ f"Failed to connect to agent server at {self.url} after "
186
+ f"{self.max_retries} attempts. Last error: {last_exception}"
187
+ ) from last_exception
188
+
189
+ @staticmethod
190
+ async def _async_sleep(seconds: float):
191
+ """Helper for async sleep."""
192
+ import asyncio
193
+
194
+ await asyncio.sleep(seconds)
195
+
196
+ async def ainvoke(
197
+ self,
198
+ input: List[AgentMessage],
199
+ session_id: Union[str, None],
200
+ ) -> AgentInvocationResponse:
201
+ """
202
+ Asynchronously invoke the HTTP agent.
203
+
204
+ Args:
205
+ input: List[AgentMessage] containing user_message
206
+ session_id: Optional conversation ID for maintaining context
207
+
208
+ Returns:
209
+ AgentInvocationResponse: Response containing agent trace, trajectory, and final response.
210
+ """
211
+ logger.info(
212
+ "HTTP ainvoke called (session_id=%s, input_messages=%d)",
213
+ session_id,
214
+ len(input),
215
+ )
216
+ payload = self._serialize_request(input, session_id)
217
+ response_data = await self._make_request_with_retry_async(
218
+ method="POST", url=self.url, payload=payload
219
+ )
220
+ logger.debug(
221
+ "HTTP adapter received response keys: %s", list(response_data.keys())
222
+ )
223
+
224
+ return AgentInvocationResponse.model_validate(
225
+ response_data.get("agent_response", {})
226
+ )
227
+
228
+ async def aclose(self):
229
+ """Close async HTTP client."""
230
+ await self.async_client.aclose()
231
+ logger.debug("HTTP adapter client closed")
232
+
233
+ async def __aenter__(self):
234
+ """Async context manager entry."""
235
+ return self
236
+
237
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
238
+ """Async context manager exit."""
239
+ await self.aclose()