agenta 0.26.0a0__py3-none-any.whl → 0.27.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.
Potentially problematic release.
This version of agenta might be problematic. Click here for more details.
- agenta/__init__.py +29 -10
- agenta/cli/helper.py +5 -1
- agenta/client/backend/__init__.py +14 -0
- agenta/client/backend/apps/client.py +28 -20
- agenta/client/backend/client.py +47 -16
- agenta/client/backend/containers/client.py +5 -1
- agenta/client/backend/core/__init__.py +2 -1
- agenta/client/backend/core/client_wrapper.py +6 -6
- agenta/client/backend/core/file.py +33 -11
- agenta/client/backend/core/http_client.py +45 -31
- agenta/client/backend/core/pydantic_utilities.py +144 -29
- agenta/client/backend/core/request_options.py +3 -0
- agenta/client/backend/core/serialization.py +139 -42
- agenta/client/backend/evaluations/client.py +7 -2
- agenta/client/backend/evaluators/client.py +349 -1
- agenta/client/backend/observability/client.py +11 -2
- agenta/client/backend/testsets/client.py +10 -10
- agenta/client/backend/types/__init__.py +14 -0
- agenta/client/backend/types/app.py +1 -0
- agenta/client/backend/types/app_variant_response.py +3 -1
- agenta/client/backend/types/config_dto.py +32 -0
- agenta/client/backend/types/config_response_model.py +32 -0
- agenta/client/backend/types/create_span.py +3 -2
- agenta/client/backend/types/environment_output.py +1 -0
- agenta/client/backend/types/environment_output_extended.py +1 -0
- agenta/client/backend/types/evaluation.py +1 -2
- agenta/client/backend/types/evaluator.py +2 -0
- agenta/client/backend/types/evaluator_config.py +1 -0
- agenta/client/backend/types/evaluator_mapping_output_interface.py +21 -0
- agenta/client/backend/types/evaluator_output_interface.py +21 -0
- agenta/client/backend/types/human_evaluation.py +1 -2
- agenta/client/backend/types/lifecycle_dto.py +24 -0
- agenta/client/backend/types/llm_tokens.py +2 -2
- agenta/client/backend/types/reference_dto.py +23 -0
- agenta/client/backend/types/reference_request_model.py +23 -0
- agenta/client/backend/types/span.py +1 -0
- agenta/client/backend/types/span_detail.py +7 -1
- agenta/client/backend/types/test_set_output_response.py +5 -2
- agenta/client/backend/types/trace_detail.py +7 -1
- agenta/client/backend/types/with_pagination.py +4 -2
- agenta/client/backend/variants/client.py +1565 -272
- agenta/docker/docker-assets/Dockerfile.cloud.template +1 -1
- agenta/sdk/__init__.py +44 -7
- agenta/sdk/agenta_init.py +85 -33
- agenta/sdk/context/__init__.py +0 -0
- agenta/sdk/context/routing.py +26 -0
- agenta/sdk/context/tracing.py +3 -0
- agenta/sdk/decorators/__init__.py +0 -0
- agenta/sdk/decorators/{llm_entrypoint.py → routing.py} +216 -191
- agenta/sdk/decorators/tracing.py +218 -99
- agenta/sdk/litellm/__init__.py +1 -0
- agenta/sdk/litellm/litellm.py +288 -0
- agenta/sdk/managers/__init__.py +6 -0
- agenta/sdk/managers/config.py +318 -0
- agenta/sdk/managers/deployment.py +45 -0
- agenta/sdk/managers/shared.py +639 -0
- agenta/sdk/managers/variant.py +182 -0
- agenta/sdk/router.py +0 -7
- agenta/sdk/tracing/__init__.py +1 -0
- agenta/sdk/tracing/attributes.py +141 -0
- agenta/sdk/tracing/context.py +24 -0
- agenta/sdk/tracing/conventions.py +49 -0
- agenta/sdk/tracing/exporters.py +65 -0
- agenta/sdk/tracing/inline.py +1252 -0
- agenta/sdk/tracing/processors.py +117 -0
- agenta/sdk/tracing/spans.py +136 -0
- agenta/sdk/tracing/tracing.py +233 -0
- agenta/sdk/types.py +49 -2
- agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
- agenta/sdk/utils/debug.py +5 -5
- agenta/sdk/utils/exceptions.py +52 -0
- agenta/sdk/utils/globals.py +3 -5
- agenta/sdk/{tracing/logger.py → utils/logging.py} +3 -5
- agenta/sdk/utils/singleton.py +13 -0
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/METADATA +5 -1
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/RECORD +78 -57
- agenta/sdk/config_manager.py +0 -205
- agenta/sdk/context.py +0 -41
- agenta/sdk/decorators/base.py +0 -10
- agenta/sdk/tracing/callbacks.py +0 -187
- agenta/sdk/tracing/llm_tracing.py +0 -617
- agenta/sdk/tracing/tasks_manager.py +0 -129
- agenta/sdk/tracing/tracing_context.py +0 -27
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/WHEEL +0 -0
- {agenta-0.26.0a0.dist-info → agenta-0.27.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from typing import Optional, Dict, List
|
|
2
|
+
|
|
3
|
+
from opentelemetry.context import Context
|
|
4
|
+
from opentelemetry.sdk.trace import Span
|
|
5
|
+
from opentelemetry.sdk.trace.export import (
|
|
6
|
+
SpanExporter,
|
|
7
|
+
ReadableSpan,
|
|
8
|
+
BatchSpanProcessor,
|
|
9
|
+
_DEFAULT_MAX_QUEUE_SIZE,
|
|
10
|
+
_DEFAULT_MAX_EXPORT_BATCH_SIZE,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from agenta.sdk.utils.logging import log
|
|
14
|
+
|
|
15
|
+
# LOAD CONTEXT, HERE
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TraceProcessor(BatchSpanProcessor):
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
span_exporter: SpanExporter,
|
|
22
|
+
references: Dict[str, str] = None,
|
|
23
|
+
max_queue_size: int = None,
|
|
24
|
+
schedule_delay_millis: float = None,
|
|
25
|
+
max_export_batch_size: int = None,
|
|
26
|
+
export_timeout_millis: float = None,
|
|
27
|
+
):
|
|
28
|
+
super().__init__(
|
|
29
|
+
span_exporter,
|
|
30
|
+
_DEFAULT_MAX_QUEUE_SIZE,
|
|
31
|
+
12 * 60 * 60 * 1000, # 12 hours
|
|
32
|
+
_DEFAULT_MAX_EXPORT_BATCH_SIZE,
|
|
33
|
+
500, # < 1 second (0.5 seconds)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
self._registry = dict()
|
|
37
|
+
self._exporter = span_exporter
|
|
38
|
+
self.references = references or dict()
|
|
39
|
+
self.spans: Dict[int, List[ReadableSpan]] = dict()
|
|
40
|
+
|
|
41
|
+
def on_start(
|
|
42
|
+
self,
|
|
43
|
+
span: Span,
|
|
44
|
+
parent_context: Optional[Context] = None,
|
|
45
|
+
) -> None:
|
|
46
|
+
# ADD LINKS FROM CONTEXT, HERE
|
|
47
|
+
|
|
48
|
+
for key in self.references.keys():
|
|
49
|
+
span.set_attribute(f"ag.refs.{key}", self.references[key])
|
|
50
|
+
|
|
51
|
+
if span.context.trace_id not in self._registry:
|
|
52
|
+
self._registry[span.context.trace_id] = dict()
|
|
53
|
+
|
|
54
|
+
self._registry[span.context.trace_id][span.context.span_id] = True
|
|
55
|
+
|
|
56
|
+
def on_end(
|
|
57
|
+
self,
|
|
58
|
+
span: ReadableSpan,
|
|
59
|
+
):
|
|
60
|
+
if self.done:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
if span.context.trace_id not in self.spans:
|
|
64
|
+
self.spans[span.context.trace_id] = list()
|
|
65
|
+
|
|
66
|
+
self.spans[span.context.trace_id].append(span)
|
|
67
|
+
|
|
68
|
+
del self._registry[span.context.trace_id][span.context.span_id]
|
|
69
|
+
|
|
70
|
+
if len(self._registry[span.context.trace_id]) == 0:
|
|
71
|
+
self.export(span.context.trace_id)
|
|
72
|
+
|
|
73
|
+
def export(
|
|
74
|
+
self,
|
|
75
|
+
trace_id: int,
|
|
76
|
+
):
|
|
77
|
+
spans = self.spans[trace_id]
|
|
78
|
+
|
|
79
|
+
for span in spans:
|
|
80
|
+
self.queue.appendleft(span)
|
|
81
|
+
|
|
82
|
+
with self.condition:
|
|
83
|
+
self.condition.notify()
|
|
84
|
+
|
|
85
|
+
del self.spans[trace_id]
|
|
86
|
+
|
|
87
|
+
def force_flush(
|
|
88
|
+
self,
|
|
89
|
+
timeout_millis: int = None,
|
|
90
|
+
) -> bool:
|
|
91
|
+
ret = super().force_flush(timeout_millis)
|
|
92
|
+
|
|
93
|
+
if not ret:
|
|
94
|
+
log.error("--------------------------------------------")
|
|
95
|
+
log.error("Agenta SDK - skipping export due to timeout.")
|
|
96
|
+
log.error("--------------------------------------------")
|
|
97
|
+
|
|
98
|
+
def is_ready(
|
|
99
|
+
self,
|
|
100
|
+
trace_id: Optional[int] = None,
|
|
101
|
+
) -> bool:
|
|
102
|
+
is_ready = True
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
is_ready = self._exporter.is_ready(trace_id)
|
|
106
|
+
except: # pylint: disable=bare-except
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
return is_ready
|
|
110
|
+
|
|
111
|
+
def fetch(
|
|
112
|
+
self,
|
|
113
|
+
trace_id: Optional[int] = None,
|
|
114
|
+
) -> Dict[str, ReadableSpan]:
|
|
115
|
+
trace = self._exporter.fetch(trace_id) # type: ignore
|
|
116
|
+
|
|
117
|
+
return trace
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from typing import Optional, Union, Any, Dict
|
|
2
|
+
|
|
3
|
+
from opentelemetry.trace import SpanContext
|
|
4
|
+
from opentelemetry.trace.status import Status, StatusCode
|
|
5
|
+
from opentelemetry.sdk.trace import Span
|
|
6
|
+
|
|
7
|
+
from agenta.sdk.tracing.attributes import serialize
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
span: Span,
|
|
14
|
+
) -> None:
|
|
15
|
+
super().__init__( # INHERITANCE FOR TYPING ONLY
|
|
16
|
+
name=span.name,
|
|
17
|
+
context=span.context,
|
|
18
|
+
parent=span.parent,
|
|
19
|
+
sampler=span._sampler,
|
|
20
|
+
trace_config=span._trace_config,
|
|
21
|
+
resource=span.resource,
|
|
22
|
+
attributes=span.attributes,
|
|
23
|
+
events=span.events,
|
|
24
|
+
links=span.links,
|
|
25
|
+
kind=span.kind,
|
|
26
|
+
span_processor=span._span_processor,
|
|
27
|
+
instrumentation_info=span.instrumentation_info,
|
|
28
|
+
record_exception=span._record_exception,
|
|
29
|
+
set_status_on_exception=span._set_status_on_exception,
|
|
30
|
+
limits=span._limits,
|
|
31
|
+
instrumentation_scope=span.instrumentation_scope,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
self._span = span
|
|
35
|
+
|
|
36
|
+
## --- PROXY METHODS --- ##
|
|
37
|
+
|
|
38
|
+
def get_span_context(self):
|
|
39
|
+
return self._span.get_span_context()
|
|
40
|
+
|
|
41
|
+
def is_recording(self) -> bool:
|
|
42
|
+
return self._span.is_recording()
|
|
43
|
+
|
|
44
|
+
def update_name(
|
|
45
|
+
self,
|
|
46
|
+
name: str,
|
|
47
|
+
) -> None:
|
|
48
|
+
self._span.update_name(name)
|
|
49
|
+
|
|
50
|
+
def set_status(
|
|
51
|
+
self,
|
|
52
|
+
status: Union[Status, StatusCode],
|
|
53
|
+
description: Optional[str] = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
self._span.set_status(
|
|
56
|
+
status=status,
|
|
57
|
+
description=description,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def end(self) -> None:
|
|
61
|
+
self._span.end()
|
|
62
|
+
|
|
63
|
+
## --- CUSTOM METHODS W/ ATTRIBUTES SERALIZATION --- ##
|
|
64
|
+
|
|
65
|
+
def set_attributes(
|
|
66
|
+
self,
|
|
67
|
+
attributes: Dict[str, Any],
|
|
68
|
+
namespace: Optional[str] = None,
|
|
69
|
+
max_depth: Optional[int] = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
self._span.set_attributes(
|
|
72
|
+
attributes=serialize(
|
|
73
|
+
namespace=namespace,
|
|
74
|
+
attributes=attributes,
|
|
75
|
+
max_depth=max_depth,
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def set_attribute(
|
|
80
|
+
self,
|
|
81
|
+
key: str,
|
|
82
|
+
value: Any,
|
|
83
|
+
namespace: Optional[str] = None,
|
|
84
|
+
) -> None:
|
|
85
|
+
self.set_attributes(
|
|
86
|
+
attributes={key: value},
|
|
87
|
+
namespace=namespace,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def add_event(
|
|
91
|
+
self,
|
|
92
|
+
name: str,
|
|
93
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
94
|
+
timestamp: Optional[int] = None,
|
|
95
|
+
namespace: Optional[str] = None,
|
|
96
|
+
) -> None:
|
|
97
|
+
self._span.add_event(
|
|
98
|
+
name=name,
|
|
99
|
+
attributes=serialize(
|
|
100
|
+
namespace=namespace,
|
|
101
|
+
attributes=attributes,
|
|
102
|
+
),
|
|
103
|
+
timestamp=timestamp,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def add_link(
|
|
107
|
+
self,
|
|
108
|
+
context: SpanContext,
|
|
109
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
110
|
+
namespace: Optional[str] = None,
|
|
111
|
+
) -> None:
|
|
112
|
+
self._span.add_link(
|
|
113
|
+
context=context,
|
|
114
|
+
attributes=serialize(
|
|
115
|
+
namespace=namespace,
|
|
116
|
+
attributes=attributes,
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def record_exception(
|
|
121
|
+
self,
|
|
122
|
+
exception: BaseException,
|
|
123
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
124
|
+
timestamp: Optional[int] = None,
|
|
125
|
+
escaped: bool = False,
|
|
126
|
+
namespace: Optional[str] = None,
|
|
127
|
+
) -> None:
|
|
128
|
+
self._span.record_exception(
|
|
129
|
+
exception=exception,
|
|
130
|
+
attributes=serialize(
|
|
131
|
+
namespace=namespace,
|
|
132
|
+
attributes=attributes,
|
|
133
|
+
),
|
|
134
|
+
timestamp=timestamp,
|
|
135
|
+
escaped=escaped,
|
|
136
|
+
)
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
from typing import Optional, Any, Dict
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from httpx import get as check
|
|
5
|
+
|
|
6
|
+
from opentelemetry.trace import (
|
|
7
|
+
get_current_span,
|
|
8
|
+
set_tracer_provider,
|
|
9
|
+
get_tracer_provider,
|
|
10
|
+
Status,
|
|
11
|
+
StatusCode,
|
|
12
|
+
)
|
|
13
|
+
from opentelemetry.sdk.trace import Span, Tracer, TracerProvider
|
|
14
|
+
from opentelemetry.sdk.resources import Resource
|
|
15
|
+
|
|
16
|
+
from agenta.sdk.utils.singleton import Singleton
|
|
17
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
18
|
+
from agenta.sdk.utils.logging import log
|
|
19
|
+
from agenta.sdk.tracing.processors import TraceProcessor
|
|
20
|
+
from agenta.sdk.tracing.exporters import InlineExporter, OTLPExporter
|
|
21
|
+
from agenta.sdk.tracing.spans import CustomSpan
|
|
22
|
+
from agenta.sdk.tracing.inline import parse_inline_trace
|
|
23
|
+
from agenta.sdk.tracing.conventions import Reference, is_valid_attribute_key
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Tracing(metaclass=Singleton):
|
|
27
|
+
VERSION = "0.1.0"
|
|
28
|
+
|
|
29
|
+
Status = Status
|
|
30
|
+
StatusCode = StatusCode
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
url: str,
|
|
35
|
+
) -> None:
|
|
36
|
+
# ENDPOINT (OTLP)
|
|
37
|
+
self.otlp_url = url
|
|
38
|
+
# HEADERS (OTLP)
|
|
39
|
+
self.headers: Dict[str, str] = dict()
|
|
40
|
+
# REFERENCES
|
|
41
|
+
self.references: Dict[str, str] = dict()
|
|
42
|
+
|
|
43
|
+
# TRACER PROVIDER
|
|
44
|
+
self.tracer_provider: Optional[TracerProvider] = None
|
|
45
|
+
# TRACE PROCESSORS -- INLINE
|
|
46
|
+
self.inline: Optional[TraceProcessor] = None
|
|
47
|
+
# TRACER
|
|
48
|
+
self.tracer: Optional[Tracer] = None
|
|
49
|
+
# INLINE SPANS for INLINE TRACES (INLINE PROCESSOR)
|
|
50
|
+
self.inline_spans: Dict[str, Any] = dict()
|
|
51
|
+
|
|
52
|
+
# PUBLIC
|
|
53
|
+
|
|
54
|
+
def configure(
|
|
55
|
+
self,
|
|
56
|
+
api_key: Optional[str] = None,
|
|
57
|
+
# DEPRECATING
|
|
58
|
+
app_id: Optional[str] = None,
|
|
59
|
+
):
|
|
60
|
+
# HEADERS (OTLP)
|
|
61
|
+
if api_key:
|
|
62
|
+
self.headers["Authorization"] = api_key
|
|
63
|
+
# REFERENCES
|
|
64
|
+
if app_id:
|
|
65
|
+
self.references["application.id"] = app_id
|
|
66
|
+
|
|
67
|
+
# TRACER PROVIDER
|
|
68
|
+
self.tracer_provider = TracerProvider(
|
|
69
|
+
resource=Resource(attributes={"service.name": "agenta-sdk"})
|
|
70
|
+
)
|
|
71
|
+
# TRACE PROCESSORS -- INLINE
|
|
72
|
+
self.inline = TraceProcessor(
|
|
73
|
+
InlineExporter(
|
|
74
|
+
registry=self.inline_spans,
|
|
75
|
+
),
|
|
76
|
+
references=self.references,
|
|
77
|
+
)
|
|
78
|
+
self.tracer_provider.add_span_processor(self.inline)
|
|
79
|
+
# TRACE PROCESSORS -- OTLP
|
|
80
|
+
try:
|
|
81
|
+
log.info("--------------------------------------------")
|
|
82
|
+
log.info(
|
|
83
|
+
"Agenta SDK - connecting to otlp receiver at: %s",
|
|
84
|
+
self.otlp_url,
|
|
85
|
+
)
|
|
86
|
+
log.info("--------------------------------------------")
|
|
87
|
+
|
|
88
|
+
check(
|
|
89
|
+
self.otlp_url,
|
|
90
|
+
headers=self.headers,
|
|
91
|
+
timeout=1,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
_otlp = TraceProcessor(
|
|
95
|
+
OTLPExporter(
|
|
96
|
+
endpoint=self.otlp_url,
|
|
97
|
+
headers=self.headers,
|
|
98
|
+
),
|
|
99
|
+
references=self.references,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
self.tracer_provider.add_span_processor(_otlp)
|
|
103
|
+
|
|
104
|
+
log.info("Success: traces will be exported.")
|
|
105
|
+
log.info("--------------------------------------------")
|
|
106
|
+
|
|
107
|
+
except: # pylint: disable=bare-except
|
|
108
|
+
log.warning("Failure: traces will not be exported.")
|
|
109
|
+
log.warning("--------------------------------------------")
|
|
110
|
+
|
|
111
|
+
# GLOBAL TRACER PROVIDER -- INSTRUMENTATION LIBRARIES
|
|
112
|
+
set_tracer_provider(self.tracer_provider)
|
|
113
|
+
# TRACER
|
|
114
|
+
self.tracer: Tracer = self.tracer_provider.get_tracer("agenta.tracer")
|
|
115
|
+
|
|
116
|
+
def get_current_span(self):
|
|
117
|
+
_span = None
|
|
118
|
+
|
|
119
|
+
with suppress():
|
|
120
|
+
_span = get_current_span()
|
|
121
|
+
|
|
122
|
+
if _span.is_recording():
|
|
123
|
+
return CustomSpan(_span)
|
|
124
|
+
|
|
125
|
+
return _span
|
|
126
|
+
|
|
127
|
+
def store_internals(
|
|
128
|
+
self,
|
|
129
|
+
attributes: Dict[str, Any],
|
|
130
|
+
span: Optional[Span] = None,
|
|
131
|
+
):
|
|
132
|
+
with suppress():
|
|
133
|
+
if span is None:
|
|
134
|
+
span = self.get_current_span()
|
|
135
|
+
|
|
136
|
+
span.set_attributes(
|
|
137
|
+
attributes={"internals": attributes},
|
|
138
|
+
namespace="data",
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def store_refs(
|
|
142
|
+
self,
|
|
143
|
+
refs: Dict[str, str],
|
|
144
|
+
span: Optional[Span] = None,
|
|
145
|
+
):
|
|
146
|
+
with suppress():
|
|
147
|
+
if span is None:
|
|
148
|
+
span = self.get_current_span()
|
|
149
|
+
|
|
150
|
+
for key in refs.keys():
|
|
151
|
+
if key in [_.value for _ in Reference.__members__.values()]:
|
|
152
|
+
# ADD REFERENCE TO THIS SPAN
|
|
153
|
+
span.set_attribute(
|
|
154
|
+
key.value if isinstance(key, Enum) else key,
|
|
155
|
+
refs[key],
|
|
156
|
+
namespace="refs",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# AND TO ALL SPANS CREATED AFTER THIS ONE
|
|
160
|
+
self.references[key] = refs[key]
|
|
161
|
+
# TODO: THIS SHOULD BE REPLACED BY A TRACE CONTEXT !!!
|
|
162
|
+
|
|
163
|
+
def store_meta(
|
|
164
|
+
self,
|
|
165
|
+
meta: Dict[str, Any],
|
|
166
|
+
span: Optional[Span] = None,
|
|
167
|
+
):
|
|
168
|
+
with suppress():
|
|
169
|
+
if span is None:
|
|
170
|
+
span = self.get_current_span()
|
|
171
|
+
|
|
172
|
+
for key in meta.keys():
|
|
173
|
+
if is_valid_attribute_key(key):
|
|
174
|
+
span.set_attribute(
|
|
175
|
+
key,
|
|
176
|
+
meta[key],
|
|
177
|
+
namespace="meta",
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def store_metrics(
|
|
181
|
+
self,
|
|
182
|
+
metrics: Dict[str, Any],
|
|
183
|
+
span: Optional[Span] = None,
|
|
184
|
+
):
|
|
185
|
+
with suppress():
|
|
186
|
+
if span is None:
|
|
187
|
+
span = self.get_current_span()
|
|
188
|
+
|
|
189
|
+
for key in metrics.keys():
|
|
190
|
+
if is_valid_attribute_key(key):
|
|
191
|
+
span.set_attribute(
|
|
192
|
+
key,
|
|
193
|
+
metrics[key],
|
|
194
|
+
namespace="metrics",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def is_inline_trace_ready(
|
|
198
|
+
self,
|
|
199
|
+
trace_id: Optional[int] = None,
|
|
200
|
+
) -> bool:
|
|
201
|
+
is_ready = True
|
|
202
|
+
|
|
203
|
+
with suppress():
|
|
204
|
+
if trace_id is not None:
|
|
205
|
+
is_ready = self.inline.is_ready(trace_id)
|
|
206
|
+
|
|
207
|
+
return is_ready
|
|
208
|
+
|
|
209
|
+
def get_inline_trace(
|
|
210
|
+
self,
|
|
211
|
+
trace_id: Optional[int] = None,
|
|
212
|
+
) -> Dict[str, Any]:
|
|
213
|
+
_inline_trace = {}
|
|
214
|
+
|
|
215
|
+
with suppress():
|
|
216
|
+
is_ready = self.inline.is_ready(trace_id)
|
|
217
|
+
|
|
218
|
+
if is_ready is True:
|
|
219
|
+
otel_spans = self.inline.fetch(trace_id)
|
|
220
|
+
|
|
221
|
+
if otel_spans:
|
|
222
|
+
_inline_trace = parse_inline_trace(otel_spans)
|
|
223
|
+
|
|
224
|
+
return _inline_trace
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def get_tracer(
|
|
228
|
+
tracing: Tracing,
|
|
229
|
+
) -> Tracer:
|
|
230
|
+
if tracing is None or tracing.tracer is None or tracing.tracer_provider is None:
|
|
231
|
+
return get_tracer_provider().get_tracer("default.tracer")
|
|
232
|
+
|
|
233
|
+
return tracing.tracer
|
agenta/sdk/types.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from dataclasses import dataclass
|
|
2
3
|
from typing import Dict, List, Optional, Any, Union
|
|
3
4
|
|
|
4
5
|
from pydantic import ConfigDict, BaseModel, HttpUrl
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
from typing import Union
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
@dataclass
|
|
@@ -198,3 +197,51 @@ class Context(BaseModel):
|
|
|
198
197
|
def from_json(cls, json_str: str):
|
|
199
198
|
data = json.loads(json_str)
|
|
200
199
|
return cls(**data)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class ReferencesResponse(BaseModel):
|
|
203
|
+
app_id: Optional[str] = None
|
|
204
|
+
app_slug: Optional[str] = None
|
|
205
|
+
variant_id: Optional[str] = None
|
|
206
|
+
variant_slug: Optional[str] = None
|
|
207
|
+
variant_version: Optional[int] = None
|
|
208
|
+
environment_id: Optional[str] = None
|
|
209
|
+
environment_slug: Optional[str] = None
|
|
210
|
+
environment_version: Optional[int] = None
|
|
211
|
+
|
|
212
|
+
def __str__(self):
|
|
213
|
+
return str(self.model_dump(exclude_none=True))
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class LifecyclesResponse(ReferencesResponse):
|
|
217
|
+
committed_at: Optional[str] = None
|
|
218
|
+
committed_by: Optional[str] = None
|
|
219
|
+
committed_by_id: Optional[str] = None
|
|
220
|
+
deployed_at: Optional[str] = None
|
|
221
|
+
deployed_by: Optional[str] = None
|
|
222
|
+
deployed_by_id: Optional[str] = None
|
|
223
|
+
|
|
224
|
+
def __str__(self):
|
|
225
|
+
return self.model_dump_json(indent=4)
|
|
226
|
+
|
|
227
|
+
def __repr__(self):
|
|
228
|
+
return self.__str__()
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class ConfigurationResponse(LifecyclesResponse):
|
|
232
|
+
params: Dict[str, Any]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class DeploymentResponse(LifecyclesResponse):
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class Prompt(BaseModel):
|
|
240
|
+
temperature: float
|
|
241
|
+
model: str
|
|
242
|
+
max_tokens: int
|
|
243
|
+
prompt_system: str
|
|
244
|
+
prompt_user: str
|
|
245
|
+
top_p: float
|
|
246
|
+
frequency_penalty: float
|
|
247
|
+
presence_penalty: float
|
|
@@ -49,6 +49,9 @@ MODEL_COST_PER_1K_TOKENS = {
|
|
|
49
49
|
"gpt-35-turbo-16k-completion": 0.004,
|
|
50
50
|
"gpt-35-turbo-16k-0613-completion": 0.004,
|
|
51
51
|
# Others
|
|
52
|
+
"text-embedding-ada-002": 0.1,
|
|
53
|
+
"text-ada-002": 0.1,
|
|
54
|
+
"adav2": 0.1,
|
|
52
55
|
"text-ada-001": 0.0004,
|
|
53
56
|
"ada": 0.0004,
|
|
54
57
|
"text-babbage-001": 0.0005,
|
agenta/sdk/utils/debug.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from inspect import iscoroutinefunction
|
|
2
2
|
from functools import wraps
|
|
3
3
|
|
|
4
|
-
from agenta.sdk.
|
|
4
|
+
from agenta.sdk.utils.logging import log
|
|
5
5
|
|
|
6
6
|
DEBUG = False
|
|
7
7
|
SHIFT = 7
|
|
@@ -14,7 +14,7 @@ def debug(shift=1, req=False, res=False, chars=[">", "<"]):
|
|
|
14
14
|
@wraps(f)
|
|
15
15
|
async def async_log_wrapper(*args, **kwargs):
|
|
16
16
|
if DEBUG:
|
|
17
|
-
|
|
17
|
+
log.debug(
|
|
18
18
|
" ".join(
|
|
19
19
|
[
|
|
20
20
|
chars[0] * shift + " " * (SHIFT - shift),
|
|
@@ -26,7 +26,7 @@ def debug(shift=1, req=False, res=False, chars=[">", "<"]):
|
|
|
26
26
|
)
|
|
27
27
|
result = await f(*args, **kwargs)
|
|
28
28
|
if DEBUG:
|
|
29
|
-
|
|
29
|
+
log.debug(
|
|
30
30
|
" ".join(
|
|
31
31
|
[
|
|
32
32
|
chars[1] * shift + " " * (SHIFT - shift),
|
|
@@ -40,7 +40,7 @@ def debug(shift=1, req=False, res=False, chars=[">", "<"]):
|
|
|
40
40
|
@wraps(f)
|
|
41
41
|
def log_wrapper(*args, **kwargs):
|
|
42
42
|
if DEBUG:
|
|
43
|
-
|
|
43
|
+
log.debug(
|
|
44
44
|
" ".join(
|
|
45
45
|
[
|
|
46
46
|
chars[0] * shift + " " * (SHIFT - shift),
|
|
@@ -52,7 +52,7 @@ def debug(shift=1, req=False, res=False, chars=[">", "<"]):
|
|
|
52
52
|
)
|
|
53
53
|
result = f(*args, **kwargs)
|
|
54
54
|
if DEBUG:
|
|
55
|
-
|
|
55
|
+
log.debug(
|
|
56
56
|
" ".join(
|
|
57
57
|
[
|
|
58
58
|
chars[1] * shift + " " * (SHIFT - shift),
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from contextlib import AbstractContextManager
|
|
2
|
+
from traceback import format_exc
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from inspect import iscoroutinefunction
|
|
5
|
+
|
|
6
|
+
from agenta.sdk.utils.logging import log
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class suppress(AbstractContextManager): # pylint: disable=invalid-name
|
|
10
|
+
def __init__(self):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
def __enter__(self):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
17
|
+
if exc_type is None:
|
|
18
|
+
return True
|
|
19
|
+
else:
|
|
20
|
+
log.error("-------------------------------------------------")
|
|
21
|
+
log.error("Agenta SDK - suppressing tracing exception below:")
|
|
22
|
+
log.error("-------------------------------------------------")
|
|
23
|
+
log.error(format_exc().strip("\n"))
|
|
24
|
+
log.error("-------------------------------------------------")
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def handle_exceptions():
|
|
29
|
+
def decorator(func):
|
|
30
|
+
is_coroutine_function = iscoroutinefunction(func)
|
|
31
|
+
|
|
32
|
+
@wraps(func)
|
|
33
|
+
async def async_wrapper(*args, **kwargs):
|
|
34
|
+
try:
|
|
35
|
+
return await func(*args, **kwargs)
|
|
36
|
+
except Exception as e:
|
|
37
|
+
log.error("--- HANDLING EXCEPTION ---")
|
|
38
|
+
log.error("--------------------------")
|
|
39
|
+
raise e
|
|
40
|
+
|
|
41
|
+
@wraps(func)
|
|
42
|
+
def sync_wrapper(*args, **kwargs):
|
|
43
|
+
try:
|
|
44
|
+
return func(*args, **kwargs)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
log.error("--- HANDLING EXCEPTION ---")
|
|
47
|
+
log.error("--------------------------")
|
|
48
|
+
raise e
|
|
49
|
+
|
|
50
|
+
return async_wrapper if is_coroutine_function else sync_wrapper
|
|
51
|
+
|
|
52
|
+
return decorator
|
agenta/sdk/utils/globals.py
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import agenta
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
def set_global(
|
|
5
|
-
"""Allows usage of agenta.config and agenta.
|
|
4
|
+
def set_global(config=None, tracing=None):
|
|
5
|
+
"""Allows usage of agenta.config and agenta.tracing in the user's code.
|
|
6
6
|
|
|
7
7
|
Args:
|
|
8
|
-
setup: _description_. Defaults to None.
|
|
9
8
|
config: _description_. Defaults to None.
|
|
9
|
+
tracing: _description_. Defaults to None.
|
|
10
10
|
"""
|
|
11
|
-
if setup is not None:
|
|
12
|
-
agenta.setup = setup
|
|
13
11
|
if config is not None:
|
|
14
12
|
agenta.config = config
|
|
15
13
|
if tracing is not None:
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
5
|
-
def __init__(self, name="
|
|
4
|
+
class Logger:
|
|
5
|
+
def __init__(self, name="agenta.logger", level=logging.DEBUG):
|
|
6
6
|
self.logger = logging.getLogger(name)
|
|
7
7
|
self.logger.setLevel(level)
|
|
8
8
|
|
|
9
|
-
# Add a stream logger to view the logs in the console
|
|
10
9
|
console_handler = logging.StreamHandler()
|
|
11
10
|
self.logger.addHandler(console_handler)
|
|
12
11
|
|
|
@@ -15,5 +14,4 @@ class LLMLogger:
|
|
|
15
14
|
return self.logger
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
llm_logger = LLMLogger().log
|
|
17
|
+
log = Logger().log
|