agenta 0.20.0a0__py3-none-any.whl → 0.20.0a1__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.

Potentially problematic release.


This version of agenta might be problematic. Click here for more details.

@@ -281,6 +281,11 @@ class entrypoint(BaseDecorator):
281
281
  For synchronous functions, it calls them directly, while for asynchronous functions,
282
282
  it awaits their execution.
283
283
  """
284
+ WAIT_FOR_SPANS = True
285
+ TIMEOUT = 10
286
+ TIMESTEP = 0.01
287
+ NOFSTEPS = TIMEOUT / TIMESTEP
288
+
284
289
  data = None
285
290
  trace = None
286
291
 
@@ -296,7 +301,15 @@ class entrypoint(BaseDecorator):
296
301
  result = func(*args, **func_params["params"])
297
302
 
298
303
  if token is not None:
304
+ if WAIT_FOR_SPANS:
305
+ remaining_steps = NOFSTEPS
306
+
307
+ while not ag.tracing.is_trace_ready() and remaining_steps > 0:
308
+ await asyncio.sleep(0.01)
309
+ remaining_steps -= 1
310
+
299
311
  trace = ag.tracing.dump_trace()
312
+ ag.tracing.flush_spans()
300
313
  tracing_context.reset(token)
301
314
 
302
315
  if isinstance(result, Context):
@@ -1,5 +1,9 @@
1
1
  import agenta as ag
2
2
 
3
+ from agenta.sdk.tracing.tracing_context import tracing_context, TracingContext
4
+
5
+ from agenta.sdk.utils.debug import debug
6
+
3
7
 
4
8
  def litellm_handler():
5
9
  try:
@@ -23,20 +27,25 @@ def litellm_handler():
23
27
  LitellmCustomLogger (object): custom logger that allows us to override the events to capture.
24
28
  """
25
29
 
30
+ def __init__(self):
31
+ self.span = None
32
+
26
33
  @property
27
34
  def _trace(self):
28
35
  return ag.tracing
29
36
 
37
+ @debug()
30
38
  def log_pre_api_call(self, model, messages, kwargs):
31
39
  call_type = kwargs.get("call_type")
32
40
  span_kind = (
33
41
  "llm" if call_type in ["completion", "acompletion"] else "embedding"
34
42
  )
35
43
 
36
- ag.tracing.start_span(
44
+ self.span = ag.tracing.open_span(
37
45
  name=f"{span_kind}_call",
38
46
  input={"messages": kwargs["messages"]},
39
47
  spankind=span_kind,
48
+ active=False,
40
49
  )
41
50
  ag.tracing.set_attributes(
42
51
  {
@@ -49,9 +58,10 @@ def litellm_handler():
49
58
  }
50
59
  )
51
60
 
61
+ @debug()
52
62
  def log_stream_event(self, kwargs, response_obj, start_time, end_time):
53
- ag.tracing.set_status(status="OK")
54
- ag.tracing.end_span(
63
+ ag.tracing.set_status(status="OK", span_id=self.span.id)
64
+ ag.tracing.store_outputs(
55
65
  outputs={
56
66
  "message": kwargs.get(
57
67
  "complete_streaming_response"
@@ -65,13 +75,16 @@ def litellm_handler():
65
75
  "response_cost"
66
76
  ), # litellm calculates response cost
67
77
  },
78
+ span_id=self.span.id,
68
79
  )
80
+ ag.tracing.close_span(span_id=self.span.id)
69
81
 
82
+ @debug()
70
83
  def log_success_event(
71
84
  self, kwargs, response_obj: ModelResponse, start_time, end_time
72
85
  ):
73
- ag.tracing.set_status(status="OK")
74
- ag.tracing.end_span(
86
+ ag.tracing.set_status(status="OK", span_id=self.span.id)
87
+ ag.tracing.store_outputs(
75
88
  outputs={
76
89
  "message": response_obj.choices[0].message.content,
77
90
  "usage": (
@@ -83,12 +96,15 @@ def litellm_handler():
83
96
  "response_cost"
84
97
  ), # litellm calculates response cost
85
98
  },
99
+ span_id=self.span.id,
86
100
  )
101
+ ag.tracing.close_span(span_id=self.span.id)
87
102
 
103
+ @debug()
88
104
  def log_failure_event(
89
105
  self, kwargs, response_obj: ModelResponse, start_time, end_time
90
106
  ):
91
- ag.tracing.set_status(status="ERROR")
107
+ ag.tracing.set_status(status="ERROR", span_id=self.span.id)
92
108
  ag.tracing.set_attributes(
93
109
  {
94
110
  "traceback_exception": repr(
@@ -98,10 +114,11 @@ def litellm_handler():
98
114
  "end_time"
99
115
  ], # datetime object of when call was completed
100
116
  },
117
+ span_id=self.span.id,
101
118
  )
102
- ag.tracing.end_span(
119
+ ag.tracing.store_outputs(
103
120
  outputs={
104
- "message": kwargs["exception"], # the Exception raised
121
+ "message": repr(kwargs["exception"]), # the Exception raised
105
122
  "usage": (
106
123
  response_obj.usage.dict()
107
124
  if hasattr(response_obj, "usage")
@@ -111,13 +128,16 @@ def litellm_handler():
111
128
  "response_cost"
112
129
  ), # litellm calculates response cost
113
130
  },
131
+ span_id=self.span.id,
114
132
  )
133
+ ag.tracing.close_span(span_id=self.span.id)
115
134
 
135
+ @debug()
116
136
  async def async_log_stream_event(
117
137
  self, kwargs, response_obj, start_time, end_time
118
138
  ):
119
- ag.tracing.set_status(status="OK")
120
- ag.tracing.end_span(
139
+ ag.tracing.set_status(status="OK", span_id=self.span.id)
140
+ ag.tracing.store_outputs(
121
141
  outputs={
122
142
  "message": kwargs.get(
123
143
  "complete_streaming_response"
@@ -131,13 +151,16 @@ def litellm_handler():
131
151
  "response_cost"
132
152
  ), # litellm calculates response cost
133
153
  },
154
+ span_id=self.span.id,
134
155
  )
156
+ ag.tracing.close_span(span_id=self.span.id)
135
157
 
158
+ @debug()
136
159
  async def async_log_success_event(
137
160
  self, kwargs, response_obj, start_time, end_time
138
161
  ):
139
- ag.tracing.set_status(status="OK")
140
- ag.tracing.end_span(
162
+ ag.tracing.set_status(status="OK", span_id=self.span.id)
163
+ ag.tracing.store_outputs(
141
164
  outputs={
142
165
  "message": response_obj.choices[0].message.content,
143
166
  "usage": (
@@ -149,12 +172,15 @@ def litellm_handler():
149
172
  "response_cost"
150
173
  ), # litellm calculates response cost
151
174
  },
175
+ span_id=self.span.id,
152
176
  )
177
+ ag.tracing.close_span(span_id=self.span.id)
153
178
 
179
+ @debug()
154
180
  async def async_log_failure_event(
155
181
  self, kwargs, response_obj, start_time, end_time
156
182
  ):
157
- ag.tracing.set_status(status="ERROR")
183
+ ag.tracing.set_status(status="ERROR", span_id=self.span.id)
158
184
  ag.tracing.set_attributes(
159
185
  {
160
186
  "traceback_exception": kwargs[
@@ -164,8 +190,9 @@ def litellm_handler():
164
190
  "end_time"
165
191
  ], # datetime object of when call was completed
166
192
  },
193
+ span_id=self.span.id,
167
194
  )
168
- ag.tracing.end_span(
195
+ ag.tracing.store_outputs(
169
196
  outputs={
170
197
  "message": repr(kwargs["exception"]), # the Exception raised
171
198
  "usage": (
@@ -177,6 +204,8 @@ def litellm_handler():
177
204
  "response_cost"
178
205
  ), # litellm calculates response cost
179
206
  },
207
+ span_id=self.span.id,
180
208
  )
209
+ ag.tracing.close_span(span_id=self.span.id)
181
210
 
182
211
  return LitellmHandler()
@@ -25,7 +25,7 @@ from bson.objectid import ObjectId
25
25
 
26
26
  VARIANT_TRACKING_FEATURE_FLAG = False
27
27
 
28
- from agenta.sdk.utils.debug import debug, DEBUG, SHIFT
28
+ from agenta.sdk.utils.debug import debug
29
29
 
30
30
 
31
31
  logging.setLevel("DEBUG")
@@ -195,6 +195,14 @@ class Tracing(metaclass=SingletonMeta):
195
195
 
196
196
  tracing.trace_tags.extend(tags)
197
197
 
198
+ @debug()
199
+ def is_trace_ready(self):
200
+ tracing = tracing_context.get()
201
+
202
+ are_spans_ready = [span.end_time is not None for span in tracing.spans.values()]
203
+
204
+ return all(are_spans_ready)
205
+
198
206
  @debug()
199
207
  def close_trace(self) -> None:
200
208
  """
@@ -234,6 +242,7 @@ class Tracing(metaclass=SingletonMeta):
234
242
  name: str,
235
243
  spankind: str,
236
244
  input: Dict[str, Any],
245
+ active: bool = True,
237
246
  config: Optional[Dict[str, Any]] = None,
238
247
  **kwargs,
239
248
  ) -> CreateSpan:
@@ -270,7 +279,14 @@ class Tracing(metaclass=SingletonMeta):
270
279
  else:
271
280
  span.parent_span_id = tracing.active_span.id # type: ignore
272
281
 
273
- tracing.push(span)
282
+ tracing.spans[span.id] = span
283
+
284
+ if active:
285
+ tracing.active_span = span
286
+ else:
287
+ # DETACHED SPAN
288
+ pass
289
+
274
290
  ### --- TO BE CLEANED --- <<<
275
291
 
276
292
  logging.info(f"Opened span {span_id} {spankind.upper()}")
@@ -279,8 +295,7 @@ class Tracing(metaclass=SingletonMeta):
279
295
 
280
296
  @debug(req=True)
281
297
  def set_attributes(
282
- self,
283
- attributes: Dict[str, Any] = {},
298
+ self, attributes: Dict[str, Any] = {}, span_id: Optional[str] = None
284
299
  ) -> None:
285
300
  """
286
301
  Set attributes for the active span.
@@ -289,41 +304,31 @@ class Tracing(metaclass=SingletonMeta):
289
304
  attributes (Dict[str, Any], optional): A dictionary of attributes to set. Defaults to {}.
290
305
  """
291
306
 
292
- tracing = tracing_context.get()
293
-
294
- if tracing.active_span is None:
295
- logging.error(f"Cannot set attributes ({set(attributes)}), no active span")
296
- return
307
+ span = self._get_target_span(span_id)
297
308
 
298
309
  logging.info(
299
- f"Setting span {tracing.active_span.id} {tracing.active_span.spankind.upper()} attributes={attributes}"
310
+ f"Setting span {span.id} {span.spankind.upper()} attributes={attributes}"
300
311
  )
301
312
 
302
313
  for key, value in attributes.items():
303
- tracing.active_span.attributes[key] = value # type: ignore
314
+ span.attributes[key] = value # type: ignore
304
315
 
305
316
  @debug()
306
- def set_status(self, status: str) -> None:
317
+ def set_status(self, status: str, span_id: Optional[str] = None) -> None:
307
318
  """
308
319
  Set status for the active span.
309
320
 
310
321
  Args:
311
322
  status: Enum ( UNSET, OK, ERROR )
312
323
  """
313
- tracing = tracing_context.get()
314
-
315
- if tracing.active_span is None:
316
- logging.error(f"Cannot set status ({status}), no active span")
317
- return
324
+ span = self._get_target_span(span_id)
318
325
 
319
- logging.info(
320
- f"Setting span {tracing.active_span.id} {tracing.active_span.spankind.upper()} status={status}"
321
- )
326
+ logging.info(f"Setting span {span.id} {span.spankind.upper()} status={status}")
322
327
 
323
- tracing.active_span.status = status
328
+ span.status = status
324
329
 
325
330
  @debug()
326
- def close_span(self) -> None:
331
+ def close_span(self, span_id: Optional[str] = None) -> None:
327
332
  """
328
333
  Ends the active span, if it is a parent span, ends the trace too.
329
334
 
@@ -340,86 +345,76 @@ class Tracing(metaclass=SingletonMeta):
340
345
  Returns:
341
346
  None
342
347
  """
348
+ span = self._get_target_span(span_id)
343
349
 
344
- tracing = tracing_context.get()
345
-
346
- if tracing.active_span is None:
347
- logging.error("Cannot close span, no active span")
348
-
349
- span_id = tracing.active_span.id
350
- spankind = tracing.active_span.spankind
350
+ spankind = span.spankind
351
351
 
352
- logging.info(f"Closing span {span_id} {spankind}")
352
+ logging.info(f"Closing span {span.id} {spankind}")
353
353
 
354
354
  ### --- TO BE CLEANED --- >>>
355
- tracing.active_span.end_time = datetime.now(timezone.utc)
355
+ span.end_time = datetime.now(timezone.utc)
356
356
 
357
357
  # TODO: Remove this whole part. Setting the cost should be done through set_span_attribute
358
- if isinstance(tracing.active_span.outputs, dict):
359
- self._update_span_cost(
360
- tracing.active_span, tracing.active_span.outputs.get("cost", None)
361
- )
362
- self._update_span_tokens(
363
- tracing.active_span, tracing.active_span.outputs.get("usage", None)
364
- )
358
+ if isinstance(span.outputs, dict):
359
+ self._update_span_cost(span, span.outputs.get("cost", None))
360
+ self._update_span_tokens(span, span.outputs.get("usage", None))
365
361
 
366
- active_span_parent_id = tracing.active_span.parent_span_id
362
+ span_parent_id = span.parent_span_id
367
363
 
368
- if active_span_parent_id is not None:
369
- parent_span = tracing.spans[active_span_parent_id]
370
- self._update_span_cost(parent_span, tracing.active_span.cost)
371
- self._update_span_tokens(parent_span, tracing.active_span.tokens)
372
- tracing.active_span = parent_span
364
+ if span_parent_id is not None:
365
+ tracing = tracing_context.get()
366
+
367
+ parent_span = tracing.spans[span_parent_id]
368
+ self._update_span_cost(parent_span, span.cost)
369
+ self._update_span_tokens(parent_span, span.tokens)
370
+
371
+ if span_id is None:
372
+ tracing.active_span = parent_span
373
373
  ### --- TO BE CLEANED --- <<<
374
374
 
375
375
  logging.info(f"Closed span {span_id} {spankind}")
376
376
 
377
377
  @debug()
378
- def store_internals(self, internals: Dict[str, Any] = {}) -> None:
378
+ def store_internals(
379
+ self, internals: Dict[str, Any] = {}, span_id: Optional[str] = None
380
+ ) -> None:
379
381
  """
380
382
  Set internals for the active span.
381
383
 
382
384
  Args:
383
385
  internals (Dict[str, Any], optional): A dictionary of local variables to set. Defaults to {}.
384
386
  """
385
-
386
- tracing = tracing_context.get()
387
-
388
- if tracing.active_span is None:
389
- logging.error(f"Cannot set internals ({set(internals)}), no active span")
390
- return
387
+ span = self._get_target_span(span_id)
391
388
 
392
389
  logging.info(
393
- f"Setting span {tracing.active_span.id} {tracing.active_span.spankind.upper()} internals={internals}"
390
+ f"Setting span {span.id} {span.spankind.upper()} internals={internals}"
394
391
  )
395
392
 
396
- if tracing.active_span.internals is None:
397
- tracing.active_span.internals = dict()
393
+ if span.internals is None:
394
+ span.internals = dict()
398
395
 
399
396
  for key, value in internals.items():
400
- tracing.active_span.internals[key] = value # type: ignore
397
+ span.internals[key] = value # type: ignore
401
398
 
402
399
  @debug()
403
- def store_outputs(self, outputs: Dict[str, Any] = {}) -> None:
400
+ def store_outputs(
401
+ self, outputs: Dict[str, Any] = {}, span_id: Optional[str] = None
402
+ ) -> None:
404
403
  """
405
404
  Set outputs for the active span.
406
405
 
407
406
  Args:
408
407
  outputs (Dict[str, Any], optional): A dictionary of output variables to set. Defaults to {}.
409
408
  """
410
-
411
- tracing = tracing_context.get()
412
-
413
- if tracing.active_span is None:
414
- logging.error(f"Cannot set outputs ({set(outputs)}), no active span")
415
- return
409
+ span = self._get_target_span(span_id)
416
410
 
417
411
  logging.info(
418
- f"Setting span {tracing.active_span.id} {tracing.active_span.spankind.upper()} outputs={outputs}"
412
+ f"Setting span {span.id} {span.spankind.upper()} outputs={outputs}"
419
413
  )
420
414
 
421
- tracing.active_span.outputs = outputs
415
+ span.outputs = outputs
422
416
 
417
+ @debug()
423
418
  def dump_trace(self):
424
419
  """
425
420
  Collects and organizes tracing information into a dictionary.
@@ -443,7 +438,10 @@ class Tracing(metaclass=SingletonMeta):
443
438
  trace["usage"] = (
444
439
  None if span.tokens is None else json.loads(span.tokens.json())
445
440
  )
446
- trace["latency"] = (span.end_time - span.start_time).total_seconds()
441
+ trace["latency"] = (
442
+ (span.end_time if span.end_time else span.start_time)
443
+ - span.start_time
444
+ ).total_seconds()
447
445
 
448
446
  spans = (
449
447
  []
@@ -526,6 +524,26 @@ class Tracing(metaclass=SingletonMeta):
526
524
  # return uuid4().hex[:16]
527
525
  return str(ObjectId())
528
526
 
527
+ def _get_target_span(self, span_id) -> CreateSpan:
528
+ tracing = tracing_context.get()
529
+
530
+ span = None
531
+
532
+ if span_id is None:
533
+ if tracing.active_span is None:
534
+ logging.error(f"Cannot set attributes, no active span")
535
+ return
536
+
537
+ span = tracing.active_span
538
+ else:
539
+ if span_id not in tracing.spans.keys():
540
+ logging.error(f"Cannot set attributes, span ({span_id}) not found")
541
+ return
542
+
543
+ span = tracing.spans[span_id]
544
+
545
+ return span
546
+
529
547
  def _process_spans(self) -> None:
530
548
  tracing = tracing_context.get()
531
549
 
@@ -23,9 +23,5 @@ class TracingContext:
23
23
  def __str__(self) -> str:
24
24
  return self.__repr__()
25
25
 
26
- def push(self, span) -> None:
27
- self.active_span = span
28
- self.spans[span.id] = span
29
-
30
26
 
31
27
  tracing_context = ContextVar(CURRENT_TRACING_CONTEXT_KEY, default=None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: agenta
3
- Version: 0.20.0a0
3
+ Version: 0.20.0a1
4
4
  Summary: The SDK for agenta is an open-source LLMOps platform.
5
5
  Home-page: https://agenta.ai
6
6
  Keywords: LLMOps,LLM,evaluation,prompt engineering
@@ -131,16 +131,16 @@ agenta/sdk/agenta_init.py,sha256=8MfDuypxohd0qRTdtGjX7L17KW-1UGmzNVdiqF15_ak,979
131
131
  agenta/sdk/client.py,sha256=trKyBOYFZRk0v5Eptxvh87yPf50Y9CqY6Qgv4Fy-VH4,2142
132
132
  agenta/sdk/context.py,sha256=q-PxL05-I84puunUAs9LGsffEXcYhDxhQxjuOz2vK90,901
133
133
  agenta/sdk/decorators/base.py,sha256=9aNdX5h8a2mFweuhdO-BQPwXGKY9ONPIdLRhSGAGMfY,217
134
- agenta/sdk/decorators/llm_entrypoint.py,sha256=cyXUHJ-cldbXmBOo3CF5XTSz_Pr2vAA5Inv5LHdigyE,26910
134
+ agenta/sdk/decorators/llm_entrypoint.py,sha256=ukdw3jyKarkXHKNaQyQmzVnJsYCntzmgoAFccvCZQnA,27343
135
135
  agenta/sdk/decorators/tracing.py,sha256=BzXa_2b2VvbO5ZNTh126OkL3LFq8dMK-QFug8BHUBKA,2687
136
136
  agenta/sdk/router.py,sha256=0sbajvn5C7t18anH6yNo7-oYxldHnYfwcbmQnIXBePw,269
137
137
  agenta/sdk/tracing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
- agenta/sdk/tracing/callbacks.py,sha256=0rqkW-PGZSaNSMp_t4bGI7R9HQRgTyIy0gxmpGVJWpE,6915
138
+ agenta/sdk/tracing/callbacks.py,sha256=xWP3RRtmj3ogXeqYI6zdj6gF5QGu70UlQ17WNwdXIx8,8063
139
139
  agenta/sdk/tracing/context_manager.py,sha256=HskDaiORoOhjeN375gm05wYnieQzh5UnoIsnSAHkAyc,252
140
- agenta/sdk/tracing/llm_tracing.py,sha256=VZskBPxa4S-0810KhsTnSy7XdrG3ovcpsKjfxQEGUx8,17167
140
+ agenta/sdk/tracing/llm_tracing.py,sha256=A7_-Xx3Rioh_nfT7OjZvDPbKUvxEqruKhYRfdGwyo4w,17312
141
141
  agenta/sdk/tracing/logger.py,sha256=GfH7V-jBHcn7h5dbdrnkDMe_ml3wkXFBeoQiqR4KVRc,474
142
142
  agenta/sdk/tracing/tasks_manager.py,sha256=FBSFOWIKBycyA4ShB2ZVMzrzYQ8pWGWWBClFX8nlZFA,3726
143
- agenta/sdk/tracing/tracing_context.py,sha256=dTbsBMbIAmSOaWIxSfhKHOB1JjrAZ0eSHAlfzZs08Z4,891
143
+ agenta/sdk/tracing/tracing_context.py,sha256=nt3ewa-TK9BRJviGIZYazsAQUiG4daWxjtsbjeaDprs,789
144
144
  agenta/sdk/types.py,sha256=1rVy8ob-rTOrIFcSSseXrt0JQtqqhlJfVgVxCB2ErCk,5754
145
145
  agenta/sdk/utils/debug.py,sha256=QyuPsSoN0425UD13x_msPxSF_VT6YwHiQunZUibI-jg,2149
146
146
  agenta/sdk/utils/globals.py,sha256=JmhJcCOSbwvjQ6GDyUc2_SYR27DZk7YcrRH80ktHHOM,435
@@ -161,7 +161,7 @@ agenta/templates/simple_prompt/app.py,sha256=kODgF6lhzsaJPdgL5b21bUki6jkvqjWZzWR
161
161
  agenta/templates/simple_prompt/env.example,sha256=g9AE5bYcGPpxawXMJ96gh8oenEPCHTabsiOnfQo3c5k,70
162
162
  agenta/templates/simple_prompt/requirements.txt,sha256=ywRglRy7pPkw8bljmMEJJ4aOOQKrt9FGKULZ-DGkoBU,23
163
163
  agenta/templates/simple_prompt/template.toml,sha256=DQBtRrF4GU8LBEXOZ-GGuINXMQDKGTEG5y37tnvIUIE,60
164
- agenta-0.20.0a0.dist-info/METADATA,sha256=xMd6YzEzMtRW5i6uO62QRRePYN0r91gLpIgaF8QrzIE,26462
165
- agenta-0.20.0a0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
166
- agenta-0.20.0a0.dist-info/entry_points.txt,sha256=PDiu8_8AsL7ibU9v4iNoOKR1S7F2rdxjlEprjM9QOgo,46
167
- agenta-0.20.0a0.dist-info/RECORD,,
164
+ agenta-0.20.0a1.dist-info/METADATA,sha256=s33kh03kzj-9YuQZipN4uhW57Tyhoj9O5g-g70w_aCY,26462
165
+ agenta-0.20.0a1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
166
+ agenta-0.20.0a1.dist-info/entry_points.txt,sha256=PDiu8_8AsL7ibU9v4iNoOKR1S7F2rdxjlEprjM9QOgo,46
167
+ agenta-0.20.0a1.dist-info/RECORD,,