agenta 0.68.0__py3-none-any.whl → 0.72.4__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.
@@ -166,24 +166,27 @@ def litellm_handler():
166
166
  namespace="metrics.unit.costs",
167
167
  )
168
168
 
169
+ # Handle both dict and object attribute access for usage, and safely handle None
170
+ usage = getattr(response_obj, "usage", None)
171
+ if isinstance(usage, dict):
172
+ prompt_tokens = usage.get("prompt_tokens")
173
+ completion_tokens = usage.get("completion_tokens")
174
+ total_tokens = usage.get("total_tokens")
175
+ elif usage is not None:
176
+ prompt_tokens = getattr(usage, "prompt_tokens", None)
177
+ completion_tokens = getattr(usage, "completion_tokens", None)
178
+ total_tokens = getattr(usage, "total_tokens", None)
179
+ else:
180
+ prompt_tokens = completion_tokens = total_tokens = None
181
+
169
182
  span.set_attributes(
170
183
  attributes=(
171
184
  {
172
- "prompt": (
173
- float(response_obj.usage.prompt_tokens)
174
- if response_obj.usage.prompt_tokens
175
- else None
176
- ),
177
- "completion": (
178
- float(response_obj.usage.completion_tokens)
179
- if response_obj.usage.completion_tokens
180
- else None
181
- ),
182
- "total": (
183
- float(response_obj.usage.total_tokens)
184
- if response_obj.usage.total_tokens
185
- else None
186
- ),
185
+ "prompt": float(prompt_tokens) if prompt_tokens else None,
186
+ "completion": float(completion_tokens)
187
+ if completion_tokens
188
+ else None,
189
+ "total": float(total_tokens) if total_tokens else None,
187
190
  }
188
191
  ),
189
192
  namespace="metrics.unit.tokens",
@@ -300,24 +303,29 @@ def litellm_handler():
300
303
  namespace="metrics.unit.costs",
301
304
  )
302
305
 
306
+ # Handle both dict and object attribute access for usage
307
+ usage = getattr(response_obj, "usage", None)
308
+ if usage is None:
309
+ prompt_tokens = None
310
+ completion_tokens = None
311
+ total_tokens = None
312
+ elif isinstance(usage, dict):
313
+ prompt_tokens = usage.get("prompt_tokens")
314
+ completion_tokens = usage.get("completion_tokens")
315
+ total_tokens = usage.get("total_tokens")
316
+ else:
317
+ prompt_tokens = getattr(usage, "prompt_tokens", None)
318
+ completion_tokens = getattr(usage, "completion_tokens", None)
319
+ total_tokens = getattr(usage, "total_tokens", None)
320
+
303
321
  span.set_attributes(
304
322
  attributes=(
305
323
  {
306
- "prompt": (
307
- float(response_obj.usage.prompt_tokens)
308
- if response_obj.usage.prompt_tokens
309
- else None
310
- ),
311
- "completion": (
312
- float(response_obj.usage.completion_tokens)
313
- if response_obj.usage.completion_tokens
314
- else None
315
- ),
316
- "total": (
317
- float(response_obj.usage.total_tokens)
318
- if response_obj.usage.total_tokens
319
- else None
320
- ),
324
+ "prompt": float(prompt_tokens) if prompt_tokens else None,
325
+ "completion": float(completion_tokens)
326
+ if completion_tokens
327
+ else None,
328
+ "total": float(total_tokens) if total_tokens else None,
321
329
  }
322
330
  ),
323
331
  namespace="metrics.unit.tokens",
@@ -17,14 +17,12 @@ import agenta as ag
17
17
 
18
18
  log = get_module_logger(__name__)
19
19
 
20
- AGENTA_RUNTIME_PREFIX = getenv("AGENTA_RUNTIME_PREFIX", "")
21
-
22
20
 
23
21
  _CACHE_ENABLED = (
24
22
  getenv("AGENTA_SERVICE_MIDDLEWARE_CACHE_ENABLED", "true").lower() in TRUTHY
25
23
  )
26
24
 
27
- _ALWAYS_ALLOW_LIST = [f"{AGENTA_RUNTIME_PREFIX}/health"]
25
+ _ALWAYS_ALLOW_LIST = ["/health"]
28
26
 
29
27
  _cache = TTLLRUCache()
30
28
 
@@ -64,7 +62,7 @@ class AuthHTTPMiddleware(BaseHTTPMiddleware):
64
62
 
65
63
  async def dispatch(self, request: Request, call_next: Callable):
66
64
  try:
67
- if request.url.path in _ALWAYS_ALLOW_LIST:
65
+ if _strip_service_prefix(request.url.path) in _ALWAYS_ALLOW_LIST:
68
66
  request.state.auth = {}
69
67
 
70
68
  else:
@@ -253,3 +251,20 @@ class AuthHTTPMiddleware(BaseHTTPMiddleware):
253
251
  status_code=500,
254
252
  content=f"Could not verify credentials: unexpected error - {str(exc)}. Please try again later or contact support if the issue persists.",
255
253
  ) from exc
254
+
255
+
256
+ def _strip_service_prefix(path: str) -> str:
257
+ if not path.startswith("/services/"):
258
+ return path
259
+
260
+ parts = path.split("/", 3)
261
+ if len(parts) < 4:
262
+ return "/"
263
+
264
+ service_name = parts[2]
265
+ remainder = parts[3]
266
+
267
+ if not service_name or not remainder or remainder.startswith("/"):
268
+ return path
269
+
270
+ return f"/{remainder}"
@@ -224,6 +224,7 @@ class ConfigMiddleware(BaseHTTPMiddleware):
224
224
  baggage.get("ag.refs.variant.slug")
225
225
  # ALTERNATIVE
226
226
  or request.query_params.get("variant_slug")
227
+ or body.get("variant_slug")
227
228
  # LEGACY
228
229
  or baggage.get("variant_slug")
229
230
  or request.query_params.get("config")
@@ -234,6 +235,7 @@ class ConfigMiddleware(BaseHTTPMiddleware):
234
235
  baggage.get("ag.refs.variant.version")
235
236
  # ALTERNATIVE
236
237
  or request.query_params.get("variant_version")
238
+ or body.get("variant_version")
237
239
  # LEGACY
238
240
  or baggage.get("variant_version")
239
241
  )
@@ -244,7 +246,7 @@ class ConfigMiddleware(BaseHTTPMiddleware):
244
246
  return Reference(
245
247
  id=variant_id,
246
248
  slug=variant_slug,
247
- version=variant_version,
249
+ version=str(variant_version) if variant_version is not None else None,
248
250
  )
249
251
 
250
252
  async def _parse_environment_ref(
@@ -3,13 +3,12 @@ from typing import Callable
3
3
  from starlette.middleware.base import BaseHTTPMiddleware
4
4
  from fastapi import Request, FastAPI
5
5
 
6
- from opentelemetry.baggage.propagation import W3CBaggagePropagator
7
- from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
8
-
9
6
  from agenta.sdk.utils.exceptions import suppress
10
7
  from agenta.sdk.tracing.propagation import extract
11
-
8
+ from agenta.sdk.utils.exceptions import suppress
12
9
  from agenta.sdk.utils.logging import get_module_logger
10
+ from fastapi import FastAPI, Request
11
+ from starlette.middleware.base import BaseHTTPMiddleware
13
12
 
14
13
  log = get_module_logger(__name__)
15
14
 
@@ -21,11 +21,9 @@ import agenta as ag
21
21
  log = get_module_logger(__name__)
22
22
 
23
23
 
24
- AGENTA_RUNTIME_PREFIX = getenv("AGENTA_RUNTIME_PREFIX", "")
25
-
26
24
  _ALWAYS_ALLOW_LIST = [
27
- f"{AGENTA_RUNTIME_PREFIX}/health",
28
- f"{AGENTA_RUNTIME_PREFIX}/openapi.json",
25
+ "/health",
26
+ "/openapi.json",
29
27
  ]
30
28
 
31
29
  _PROVIDER_KINDS = [
@@ -116,7 +114,7 @@ class VaultMiddleware(BaseHTTPMiddleware):
116
114
  allow_secrets = True
117
115
 
118
116
  try:
119
- if not request.url.path in _ALWAYS_ALLOW_LIST:
117
+ if _strip_service_prefix(request.url.path) not in _ALWAYS_ALLOW_LIST:
120
118
  await self._allow_local_secrets(credentials)
121
119
 
122
120
  for provider_kind in _PROVIDER_KINDS:
@@ -331,3 +329,20 @@ class VaultMiddleware(BaseHTTPMiddleware):
331
329
  status_code=500,
332
330
  content=f"Could not verify credentials: unexpected error - {str(exc)}. Please try again later or contact support if the issue persists.",
333
331
  ) from exc
332
+
333
+
334
+ def _strip_service_prefix(path: str) -> str:
335
+ if not path.startswith("/services/"):
336
+ return path
337
+
338
+ parts = path.split("/", 3)
339
+ if len(parts) < 4:
340
+ return "/"
341
+
342
+ service_name = parts[2]
343
+ remainder = parts[3]
344
+
345
+ if not service_name or not remainder or remainder.startswith("/"):
346
+ return path
347
+
348
+ return f"/{remainder}"
@@ -6,7 +6,7 @@ from fastapi import Request
6
6
 
7
7
  from agenta.sdk.utils.logging import get_module_logger
8
8
  from agenta.sdk.utils.exceptions import suppress
9
- from agenta.sdk.engines.tracing.propagation import extract
9
+ from agenta.sdk.tracing.propagation import extract
10
10
 
11
11
 
12
12
  log = get_module_logger(__name__)
@@ -127,7 +127,7 @@ class VaultMiddleware:
127
127
  request: WorkflowServiceRequest,
128
128
  call_next: Callable[[WorkflowServiceRequest], Any],
129
129
  ):
130
- api_url = f"{ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.host}/api"
130
+ api_url = ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.api_url
131
131
 
132
132
  with suppress():
133
133
  ctx = RunningContext.get()
@@ -88,7 +88,7 @@ class Slug(BaseModel):
88
88
  def check_url_safety(cls, v):
89
89
  if v is not None:
90
90
  if not match(r"^[a-zA-Z0-9_-]+$", v):
91
- raise ValueError("slug must be URL-safe.")
91
+ raise ValueError("'slug' must be URL-safe.")
92
92
  return v
93
93
 
94
94
 
@@ -122,6 +122,7 @@ class OTLPExporter(OTLPSpanExporter):
122
122
  # "[SPAN] [EXPORT]",
123
123
  # trace_id=UUID(int=trace_id).hex,
124
124
  # span_id=UUID(int=span_id).hex[-16:],
125
+ # span_attributes=_span.attributes,
125
126
  # )
126
127
 
127
128
  serialized_spans.append(super().export(_spans))
@@ -1,21 +1,21 @@
1
- from typing import Optional, Dict, List
2
1
  from threading import Lock
3
- from json import dumps
4
- from uuid import UUID
2
+ from typing import Dict, List, Optional
5
3
 
4
+
5
+ from agenta.sdk.contexts.tracing import TracingContext
6
+ from agenta.sdk.utils.logging import get_module_logger
6
7
  from opentelemetry.baggage import get_all as get_baggage
7
8
  from opentelemetry.context import Context
8
9
  from opentelemetry.sdk.trace import Span, SpanProcessor
9
10
  from opentelemetry.sdk.trace.export import (
10
- SpanExporter,
11
- ReadableSpan,
12
11
  BatchSpanProcessor,
12
+ ReadableSpan,
13
+ SpanExporter,
13
14
  )
14
15
  from opentelemetry.trace import SpanContext
15
16
 
16
17
  from agenta.sdk.utils.logging import get_module_logger
17
- from agenta.sdk.tracing.conventions import Reference
18
-
18
+ from agenta.sdk.models.tracing import BaseModel
19
19
  from agenta.sdk.contexts.tracing import TracingContext
20
20
 
21
21
  log = get_module_logger(__name__)
@@ -65,15 +65,38 @@ class TraceProcessor(SpanProcessor):
65
65
  # )
66
66
 
67
67
  for key in self.references.keys():
68
- span.set_attribute(f"ag.refs.{key}", self.references[key])
68
+ ref = self.references[key]
69
+ if isinstance(ref, BaseModel):
70
+ try:
71
+ ref = ref.model_dump(mode="json", exclude_none=True)
72
+ except Exception: # pylint: disable=bare-except
73
+ pass
74
+ if isinstance(ref, dict):
75
+ for field, value in ref.items():
76
+ span.set_attribute(f"ag.refs.{key}.{field}", str(value))
69
77
 
70
78
  baggage = get_baggage(parent_context)
71
79
 
72
80
  for key in baggage.keys():
73
- if key.startswith("ag.refs."):
74
- _key = key.replace("ag.refs.", "")
75
- if _key in [_.value for _ in Reference.__members__.values()]:
76
- span.set_attribute(key, baggage[key])
81
+ if key.startswith("ag."):
82
+ value = baggage[key]
83
+
84
+ if key.startswith("ag.refs."):
85
+ ref = value
86
+ if isinstance(value, BaseModel):
87
+ try:
88
+ ref = value.model_dump(mode="json", exclude_none=True) # type: ignore
89
+ except Exception: # pylint: disable=bare-except
90
+ pass
91
+ if isinstance(ref, dict):
92
+ for field, val in ref.items():
93
+ span.set_attribute(f"{key}.{field}", str(val))
94
+ elif isinstance(ref, (str, bool, int, float, bytes)):
95
+ span.set_attribute(key, ref)
96
+ else:
97
+ # Not a reference - only set if it's a valid attribute type
98
+ if isinstance(value, (str, bool, int, float, bytes)):
99
+ span.set_attribute(key, value)
77
100
 
78
101
  context = TracingContext.get()
79
102
 
@@ -105,10 +128,11 @@ class TraceProcessor(SpanProcessor):
105
128
  if not self.inline:
106
129
  if context.links:
107
130
  for key, link in context.links.items():
108
- try:
109
- link = link.model_dump(mode="json", exclude_none=True)
110
- except: # pylint: disable=bare-except
111
- pass
131
+ if isinstance(link, BaseModel):
132
+ try:
133
+ link = link.model_dump(mode="json", exclude_none=True)
134
+ except Exception:
135
+ pass
112
136
  if not isinstance(link, dict):
113
137
  continue
114
138
  if not link.get("trace_id") or not link.get("span_id"):
@@ -127,30 +151,14 @@ class TraceProcessor(SpanProcessor):
127
151
 
128
152
  if context.references:
129
153
  for key, ref in context.references.items():
130
- try:
131
- ref = ref.model_dump(mode="json", exclude_none=True)
132
- except: # pylint: disable=bare-except
133
- pass
134
- if not isinstance(ref, dict):
135
- continue
136
- if not ref.get("id") and not ref.get("slug") and not ref.get("version"):
137
- continue
138
-
139
- if ref.get("id"):
140
- span.set_attribute(
141
- f"ag.refs.{key}.id",
142
- str(ref.get("id")),
143
- )
144
- if ref.get("slug"):
145
- span.set_attribute(
146
- f"ag.refs.{key}.slug",
147
- str(ref.get("slug")),
148
- )
149
- if ref.get("version"):
150
- span.set_attribute(
151
- f"ag.refs.{key}.version",
152
- str(ref.get("version")),
153
- )
154
+ if isinstance(ref, BaseModel):
155
+ try:
156
+ ref = ref.model_dump(mode="json", exclude_none=True)
157
+ except Exception:
158
+ pass
159
+ if isinstance(ref, dict):
160
+ for field, value in ref.items():
161
+ span.set_attribute(f"ag.refs.{key}.{field}", str(value))
154
162
 
155
163
  trace_id = span.context.trace_id
156
164
  span_id = span.context.span_id
@@ -1,14 +1,10 @@
1
- from typing import Tuple, Optional, Dict, Any
1
+ from typing import Any, Dict, Optional, Tuple
2
2
 
3
- from opentelemetry.trace import Span, set_span_in_context, get_current_span
4
- from opentelemetry.baggage.propagation import W3CBaggagePropagator
5
- from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
3
+ from agenta.sdk.contexts.tracing import TracingContext
6
4
  from opentelemetry.baggage import set_baggage
5
+ from opentelemetry.baggage.propagation import W3CBaggagePropagator
7
6
  from opentelemetry.context import get_current
8
-
9
- from agenta.sdk.contexts.tracing import TracingContext
10
-
11
- import agenta as ag
7
+ from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
12
8
 
13
9
 
14
10
  def extract(
@@ -47,11 +43,12 @@ def extract(
47
43
  baggage = {}
48
44
 
49
45
  try:
50
- _carrier = {
51
- "baggage": headers.get("Baggage") # Uppercase
46
+ raw_baggage = (
47
+ headers.get("Baggage") # Uppercase
52
48
  or headers.get("baggage") # Lowercase
53
- or "",
54
- }
49
+ or ""
50
+ )
51
+ _carrier = {"baggage": raw_baggage}
55
52
 
56
53
  _context = W3CBaggagePropagator().extract(_carrier)
57
54
 
@@ -31,6 +31,7 @@ from agenta.sdk.tracing.conventions import Reference, is_valid_attribute_key
31
31
  from agenta.sdk.tracing.propagation import extract, inject
32
32
  from agenta.sdk.utils.cache import TTLLRUCache
33
33
 
34
+ import agenta as ag
34
35
 
35
36
  log = get_module_logger(__name__)
36
37
 
@@ -215,6 +216,42 @@ class Tracing(metaclass=Singleton):
215
216
  namespace="metrics",
216
217
  )
217
218
 
219
+ def store_session(
220
+ self,
221
+ session_id: Optional[str] = None,
222
+ span: Optional[Span] = None,
223
+ ):
224
+ """Set session attributes on the current span.
225
+
226
+ Args:
227
+ session_id: Unique identifier for the session
228
+ span: Optional span to set attributes on (defaults to current span)
229
+ """
230
+ with suppress():
231
+ if span is None:
232
+ span = self.get_current_span()
233
+
234
+ if session_id:
235
+ span.set_attribute("id", session_id, namespace="session")
236
+
237
+ def store_user(
238
+ self,
239
+ user_id: Optional[str] = None,
240
+ span: Optional[Span] = None,
241
+ ):
242
+ """Set user attributes on the current span.
243
+
244
+ Args:
245
+ user_id: Unique identifier for the user
246
+ span: Optional span to set attributes on (defaults to current span)
247
+ """
248
+ with suppress():
249
+ if span is None:
250
+ span = self.get_current_span()
251
+
252
+ if user_id:
253
+ span.set_attribute("id", user_id, namespace="user")
254
+
218
255
  def is_inline_trace_ready(
219
256
  self,
220
257
  trace_id: Optional[int] = None,
@@ -314,6 +351,58 @@ class Tracing(metaclass=Singleton):
314
351
 
315
352
  return None
316
353
 
354
+ def get_trace_url(
355
+ self,
356
+ trace_id: Optional[str] = None,
357
+ ) -> str:
358
+ """
359
+ Build a URL to view a trace in the Agenta UI.
360
+
361
+ Automatically extracts the trace ID from the current tracing context
362
+ if not explicitly provided.
363
+
364
+ Args:
365
+ trace_id: Optional trace ID (hex string format). If not provided,
366
+ it will be automatically extracted from the current trace context.
367
+
368
+ Returns:
369
+ The full URL to view the trace in the observability dashboard
370
+
371
+ Raises:
372
+ RuntimeError: If the SDK is not initialized, no active trace context exists,
373
+ or scope info cannot be fetched
374
+ """
375
+ if trace_id is None:
376
+ span_ctx = self.get_span_context()
377
+ if span_ctx is None or not span_ctx.is_valid:
378
+ raise RuntimeError(
379
+ "No active trace context found. "
380
+ "Make sure you call this within an instrumented function or span."
381
+ )
382
+
383
+ trace_id = f"{span_ctx.trace_id:032x}"
384
+
385
+ if not ag or not ag.DEFAULT_AGENTA_SINGLETON_INSTANCE:
386
+ raise RuntimeError(
387
+ "Agenta SDK is not initialized. Please call ag.init() first."
388
+ )
389
+
390
+ api_url = ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.api_url
391
+ web_url = api_url.replace("/api", "") if api_url else None
392
+
393
+ (organization_id, workspace_id, project_id) = (
394
+ ag.DEFAULT_AGENTA_SINGLETON_INSTANCE.resolve_scopes()
395
+ )
396
+
397
+ if not web_url or not workspace_id or not project_id:
398
+ raise RuntimeError(
399
+ "Could not determine workspace/project context. Please call ag.init() first."
400
+ )
401
+
402
+ return (
403
+ f"{web_url}/w/{workspace_id}/p/{project_id}/observability?trace={trace_id}"
404
+ )
405
+
317
406
 
318
407
  def get_tracer(
319
408
  tracing: Tracing,
agenta/sdk/types.py CHANGED
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field, model_validator, AliasChoices
8
8
  from starlette.responses import StreamingResponse
9
9
 
10
10
 
11
- from agenta.sdk.assets import supported_llm_models
11
+ from agenta.sdk.assets import supported_llm_models, model_metadata
12
12
  from agenta.client.backend.types import AgentaNodesResponse, AgentaNodeDto
13
13
 
14
14
 
@@ -23,7 +23,11 @@ def MCField( # pylint: disable=invalid-name
23
23
  ) -> Field:
24
24
  # Pydantic 2.12+ no longer allows post-creation mutation of field properties
25
25
  if isinstance(choices, dict):
26
- json_extra = {"choices": choices, "x-parameter": "grouped_choice"}
26
+ json_extra = {
27
+ "choices": choices,
28
+ "x-parameter": "grouped_choice",
29
+ "x-model-metadata": model_metadata,
30
+ }
27
31
  elif isinstance(choices, list):
28
32
  json_extra = {"choices": choices, "x-parameter": "choice"}
29
33
  else:
@@ -88,7 +88,6 @@ class DaytonaRunner(CodeRunner):
88
88
  target=target,
89
89
  )
90
90
  self.daytona = Daytona(config)
91
- # log.debug("Daytona client initialized")
92
91
 
93
92
  except Exception as e:
94
93
  raise RuntimeError(f"Failed to initialize Daytona client: {e}")
@@ -107,8 +106,6 @@ class DaytonaRunner(CodeRunner):
107
106
  "Set it to the Daytona sandbox ID or snapshot name you want to use."
108
107
  )
109
108
 
110
- # log.debug(f"Creating sandbox from snapshot: {snapshot_id}")
111
-
112
109
  from daytona import CreateSandboxFromSnapshotParams
113
110
 
114
111
  sandbox = self.daytona.create(
@@ -118,9 +115,6 @@ class DaytonaRunner(CodeRunner):
118
115
  )
119
116
  )
120
117
 
121
- # log.debug(
122
- # f"Sandbox created: {sandbox.id if hasattr(sandbox, 'id') else sandbox}"
123
- # )
124
118
  return sandbox
125
119
 
126
120
  except Exception as e:
@@ -1,7 +1,17 @@
1
1
  import os
2
+ from typing import TYPE_CHECKING
3
+
2
4
  from agenta.sdk.workflows.runners.base import CodeRunner
3
5
  from agenta.sdk.workflows.runners.local import LocalRunner
4
- from agenta.sdk.workflows.runners.daytona import DaytonaRunner
6
+
7
+ if TYPE_CHECKING:
8
+ from agenta.sdk.workflows.runners.daytona import DaytonaRunner
9
+
10
+
11
+ def _get_daytona_runner() -> "DaytonaRunner":
12
+ from agenta.sdk.workflows.runners.daytona import DaytonaRunner
13
+
14
+ return DaytonaRunner()
5
15
 
6
16
 
7
17
  def get_runner() -> CodeRunner:
@@ -21,7 +31,14 @@ def get_runner() -> CodeRunner:
21
31
  runner_type = os.getenv("AGENTA_SERVICES_SANDBOX_RUNNER", "local").lower()
22
32
 
23
33
  if runner_type == "daytona":
24
- return DaytonaRunner()
34
+ try:
35
+ return _get_daytona_runner()
36
+ except ImportError as exc:
37
+ raise ValueError(
38
+ "Daytona runner requires the 'daytona' package. "
39
+ "Install optional dependencies or set "
40
+ "AGENTA_SERVICES_SANDBOX_RUNNER=local."
41
+ ) from exc
25
42
  elif runner_type == "local":
26
43
  return LocalRunner()
27
44
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenta
3
- Version: 0.68.0
3
+ Version: 0.72.4
4
4
  Summary: The SDK for agenta is an open-source LLMOps platform.
5
5
  Keywords: LLMOps,LLM,evaluation,prompt engineering
6
6
  Author: Mahmoud Mabrouk
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.14
16
16
  Classifier: Programming Language :: Python :: 3.9
17
17
  Classifier: Topic :: Software Development :: Libraries
18
18
  Requires-Dist: daytona (>=0.121.0,<0.122.0)
19
- Requires-Dist: fastapi (>=0.122,<0.123)
19
+ Requires-Dist: fastapi (>=0.125)
20
20
  Requires-Dist: httpx (>=0.28,<0.29)
21
21
  Requires-Dist: importlib-metadata (>=8,<9)
22
22
  Requires-Dist: jinja2 (>=3,<4)
@@ -26,6 +26,7 @@ Requires-Dist: opentelemetry-api (>=1,<2)
26
26
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1,<2)
27
27
  Requires-Dist: opentelemetry-instrumentation (>=0.59b0,<0.60)
28
28
  Requires-Dist: opentelemetry-sdk (>=1,<2)
29
+ Requires-Dist: orjson (>=3,<4)
29
30
  Requires-Dist: pydantic (>=2,<3)
30
31
  Requires-Dist: python-dotenv (>=1,<2)
31
32
  Requires-Dist: python-jsonpath (>=2,<3)