cloudbase-agent-observability 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.
- cloudbase_agent/observability/__init__.py +104 -0
- cloudbase_agent/observability/api.py +302 -0
- cloudbase_agent/observability/attributes.py +336 -0
- cloudbase_agent/observability/constants.py +78 -0
- cloudbase_agent/observability/coze/__init__.py +10 -0
- cloudbase_agent/observability/coze/event_handler.py +565 -0
- cloudbase_agent/observability/crewai/__init__.py +42 -0
- cloudbase_agent/observability/crewai/callback_handler.py +414 -0
- cloudbase_agent/observability/langchain/__init__.py +10 -0
- cloudbase_agent/observability/langchain/callback_handler.py +1158 -0
- cloudbase_agent/observability/server/__init__.py +31 -0
- cloudbase_agent/observability/server/config.py +101 -0
- cloudbase_agent/observability/server/setup.py +412 -0
- cloudbase_agent/observability/span_wrapper.py +374 -0
- cloudbase_agent/observability/tracer.py +116 -0
- cloudbase_agent/observability/types.py +152 -0
- cloudbase_agent_observability-0.1.0.data/data/share/doc/cloudbase_agent_py_observability/README.md +247 -0
- cloudbase_agent_observability-0.1.0.dist-info/METADATA +263 -0
- cloudbase_agent_observability-0.1.0.dist-info/RECORD +20 -0
- cloudbase_agent_observability-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cloudbase Agent Observability - OpenTelemetry-based tracing with OpenInference semantic conventions.
|
|
3
|
+
|
|
4
|
+
This package provides observability capabilities for Cloudbase Agent agents using OpenTelemetry
|
|
5
|
+
and OpenInference semantic conventions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from cloudbase_agent.observability.span_wrapper import (
|
|
9
|
+
Observation,
|
|
10
|
+
ObservationAgent,
|
|
11
|
+
ObservationChain,
|
|
12
|
+
ObservationEmbedding,
|
|
13
|
+
ObservationLLM,
|
|
14
|
+
ObservationRetriever,
|
|
15
|
+
ObservationReranker,
|
|
16
|
+
ObservationSpan,
|
|
17
|
+
ObservationTool,
|
|
18
|
+
)
|
|
19
|
+
from cloudbase_agent.observability.tracer import get_tracer, set_tracer_provider
|
|
20
|
+
from cloudbase_agent.observability.attributes import (
|
|
21
|
+
create_observation_attributes,
|
|
22
|
+
create_trace_attributes,
|
|
23
|
+
)
|
|
24
|
+
from cloudbase_agent.observability.types import (
|
|
25
|
+
ObservationLevel,
|
|
26
|
+
ObservationType,
|
|
27
|
+
)
|
|
28
|
+
from cloudbase_agent.observability.api import (
|
|
29
|
+
start_observation,
|
|
30
|
+
update_active_trace,
|
|
31
|
+
get_active_trace_id,
|
|
32
|
+
get_active_span_id,
|
|
33
|
+
)
|
|
34
|
+
from cloudbase_agent.observability.constants import (
|
|
35
|
+
OpenInferenceAttributes,
|
|
36
|
+
OpenInferenceSpanKind,
|
|
37
|
+
OtelSpanAttributes,
|
|
38
|
+
OBSERVABILITY_TRACER_NAME,
|
|
39
|
+
OBSERVABILITY_SDK_NAME,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Server utilities (optional import - requires opentelemetry-sdk)
|
|
43
|
+
try:
|
|
44
|
+
from cloudbase_agent.observability.server import (
|
|
45
|
+
setup_observability,
|
|
46
|
+
setup_observability_async,
|
|
47
|
+
BatchConfig,
|
|
48
|
+
ConsoleTraceConfig,
|
|
49
|
+
OTLPTraceConfig,
|
|
50
|
+
CustomTraceConfig,
|
|
51
|
+
ObservabilityConfig,
|
|
52
|
+
)
|
|
53
|
+
SERVER_AVAILABLE = True
|
|
54
|
+
except ImportError:
|
|
55
|
+
SERVER_AVAILABLE = False
|
|
56
|
+
|
|
57
|
+
__all__ = [
|
|
58
|
+
# Span wrapper classes
|
|
59
|
+
"Observation",
|
|
60
|
+
"ObservationSpan",
|
|
61
|
+
"ObservationLLM",
|
|
62
|
+
"ObservationEmbedding",
|
|
63
|
+
"ObservationAgent",
|
|
64
|
+
"ObservationTool",
|
|
65
|
+
"ObservationChain",
|
|
66
|
+
"ObservationRetriever",
|
|
67
|
+
"ObservationReranker",
|
|
68
|
+
# Tracer functions
|
|
69
|
+
"get_tracer",
|
|
70
|
+
"set_tracer_provider",
|
|
71
|
+
# Attribute functions
|
|
72
|
+
"create_observation_attributes",
|
|
73
|
+
"create_trace_attributes",
|
|
74
|
+
# Types
|
|
75
|
+
"ObservationType",
|
|
76
|
+
"ObservationLevel",
|
|
77
|
+
# API functions
|
|
78
|
+
"start_observation",
|
|
79
|
+
"update_active_trace",
|
|
80
|
+
"get_active_trace_id",
|
|
81
|
+
"get_active_span_id",
|
|
82
|
+
# Constants
|
|
83
|
+
"OpenInferenceAttributes",
|
|
84
|
+
"OpenInferenceSpanKind",
|
|
85
|
+
"OtelSpanAttributes",
|
|
86
|
+
"OBSERVABILITY_TRACER_NAME",
|
|
87
|
+
"OBSERVABILITY_SDK_NAME",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# Server exports (available only when opentelemetry-sdk is installed)
|
|
91
|
+
if SERVER_AVAILABLE:
|
|
92
|
+
__all__.extend([
|
|
93
|
+
# Server setup API
|
|
94
|
+
"setup_observability",
|
|
95
|
+
"setup_observability_async",
|
|
96
|
+
# Server configuration types
|
|
97
|
+
"BatchConfig",
|
|
98
|
+
"ConsoleTraceConfig",
|
|
99
|
+
"OTLPTraceConfig",
|
|
100
|
+
"CustomTraceConfig",
|
|
101
|
+
"ObservabilityConfig",
|
|
102
|
+
])
|
|
103
|
+
|
|
104
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Public API for Cloudbase Agent observability.
|
|
3
|
+
|
|
4
|
+
Provides convenient functions for creating and managing observations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Any, Dict, Optional, Union, overload
|
|
9
|
+
|
|
10
|
+
from opentelemetry import context, trace
|
|
11
|
+
from opentelemetry.trace import SpanContext, Status, StatusCode
|
|
12
|
+
from opentelemetry.util.types import AttributeValue
|
|
13
|
+
|
|
14
|
+
from cloudbase_agent.observability.types import (
|
|
15
|
+
ObservationType,
|
|
16
|
+
BaseSpanAttributes,
|
|
17
|
+
LLMAttributes,
|
|
18
|
+
EmbeddingAttributes,
|
|
19
|
+
AgentAttributes,
|
|
20
|
+
ToolAttributes,
|
|
21
|
+
ChainAttributes,
|
|
22
|
+
RetrieverAttributes,
|
|
23
|
+
RerankerAttributes,
|
|
24
|
+
EvaluatorAttributes,
|
|
25
|
+
GuardrailAttributes,
|
|
26
|
+
ObservationAttributes,
|
|
27
|
+
TraceAttributes,
|
|
28
|
+
)
|
|
29
|
+
from cloudbase_agent.observability.span_wrapper import (
|
|
30
|
+
Observation,
|
|
31
|
+
ObservationSpan,
|
|
32
|
+
ObservationLLM,
|
|
33
|
+
ObservationEmbedding,
|
|
34
|
+
ObservationAgent,
|
|
35
|
+
ObservationTool,
|
|
36
|
+
ObservationChain,
|
|
37
|
+
ObservationRetriever,
|
|
38
|
+
ObservationReranker,
|
|
39
|
+
ObservationEvaluator,
|
|
40
|
+
ObservationGuardrail,
|
|
41
|
+
)
|
|
42
|
+
from cloudbase_agent.observability.tracer import get_tracer
|
|
43
|
+
from cloudbase_agent.observability.attributes import (
|
|
44
|
+
update_active_trace as _update_active_trace,
|
|
45
|
+
get_active_trace_id as _get_active_trace_id,
|
|
46
|
+
get_active_span_id as _get_active_span_id,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _create_parent_context(
|
|
51
|
+
parent_span_context: Optional[SpanContext],
|
|
52
|
+
) -> context.Context:
|
|
53
|
+
"""Create a parent context from a span context.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
parent_span_context: The span context to use as parent.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
The created context (returns current context if no parent).
|
|
60
|
+
"""
|
|
61
|
+
# Create a NonRecordingSpan with the parent context
|
|
62
|
+
from opentelemetry.trace import NonRecordingSpan
|
|
63
|
+
parent_span = NonRecordingSpan(parent_span_context)
|
|
64
|
+
|
|
65
|
+
# Use the parent context to set the span in context
|
|
66
|
+
return trace.set_span_in_context(parent_span)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@overload
|
|
70
|
+
def start_observation(
|
|
71
|
+
name: str,
|
|
72
|
+
attributes: LLMAttributes,
|
|
73
|
+
*,
|
|
74
|
+
as_type: "Literal['llm']",
|
|
75
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
76
|
+
start_time: Optional[datetime] = None,
|
|
77
|
+
) -> ObservationLLM:
|
|
78
|
+
...
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@overload
|
|
82
|
+
def start_observation(
|
|
83
|
+
name: str,
|
|
84
|
+
attributes: EmbeddingAttributes,
|
|
85
|
+
*,
|
|
86
|
+
as_type: "Literal['embedding']",
|
|
87
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
88
|
+
start_time: Optional[datetime] = None,
|
|
89
|
+
) -> ObservationEmbedding:
|
|
90
|
+
...
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@overload
|
|
94
|
+
def start_observation(
|
|
95
|
+
name: str,
|
|
96
|
+
attributes: AgentAttributes,
|
|
97
|
+
*,
|
|
98
|
+
as_type: "Literal['agent']",
|
|
99
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
100
|
+
start_time: Optional[datetime] = None,
|
|
101
|
+
) -> ObservationAgent:
|
|
102
|
+
...
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@overload
|
|
106
|
+
def start_observation(
|
|
107
|
+
name: str,
|
|
108
|
+
attributes: ToolAttributes,
|
|
109
|
+
*,
|
|
110
|
+
as_type: "Literal['tool']",
|
|
111
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
112
|
+
start_time: Optional[datetime] = None,
|
|
113
|
+
) -> ObservationTool:
|
|
114
|
+
...
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@overload
|
|
118
|
+
def start_observation(
|
|
119
|
+
name: str,
|
|
120
|
+
attributes: ChainAttributes,
|
|
121
|
+
*,
|
|
122
|
+
as_type: "Literal['chain']",
|
|
123
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
124
|
+
start_time: Optional[datetime] = None,
|
|
125
|
+
) -> ObservationChain:
|
|
126
|
+
...
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@overload
|
|
130
|
+
def start_observation(
|
|
131
|
+
name: str,
|
|
132
|
+
attributes: RetrieverAttributes,
|
|
133
|
+
*,
|
|
134
|
+
as_type: "Literal['retriever']",
|
|
135
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
136
|
+
start_time: Optional[datetime] = None,
|
|
137
|
+
) -> ObservationRetriever:
|
|
138
|
+
...
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@overload
|
|
142
|
+
def start_observation(
|
|
143
|
+
name: str,
|
|
144
|
+
attributes: RerankerAttributes,
|
|
145
|
+
*,
|
|
146
|
+
as_type: "Literal['reranker']",
|
|
147
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
148
|
+
start_time: Optional[datetime] = None,
|
|
149
|
+
) -> ObservationReranker:
|
|
150
|
+
...
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@overload
|
|
154
|
+
def start_observation(
|
|
155
|
+
name: str,
|
|
156
|
+
attributes: EvaluatorAttributes,
|
|
157
|
+
*,
|
|
158
|
+
as_type: "Literal['evaluator']",
|
|
159
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
160
|
+
start_time: Optional[datetime] = None,
|
|
161
|
+
) -> ObservationEvaluator:
|
|
162
|
+
...
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@overload
|
|
166
|
+
def start_observation(
|
|
167
|
+
name: str,
|
|
168
|
+
attributes: GuardrailAttributes,
|
|
169
|
+
*,
|
|
170
|
+
as_type: "Literal['guardrail']",
|
|
171
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
172
|
+
start_time: Optional[datetime] = None,
|
|
173
|
+
) -> ObservationGuardrail:
|
|
174
|
+
...
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@overload
|
|
178
|
+
def start_observation(
|
|
179
|
+
name: str,
|
|
180
|
+
attributes: Optional[BaseSpanAttributes] = None,
|
|
181
|
+
*,
|
|
182
|
+
as_type: "Literal['span']" = "span",
|
|
183
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
184
|
+
start_time: Optional[datetime] = None,
|
|
185
|
+
) -> ObservationSpan:
|
|
186
|
+
...
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def start_observation(
|
|
190
|
+
name: str,
|
|
191
|
+
attributes: Optional[ObservationAttributes] = None,
|
|
192
|
+
*,
|
|
193
|
+
as_type: ObservationType = "span",
|
|
194
|
+
parent_span_context: Optional[SpanContext] = None,
|
|
195
|
+
start_time: Optional[datetime] = None,
|
|
196
|
+
) -> Observation:
|
|
197
|
+
"""Create and start a new Cloudbase Agent observation.
|
|
198
|
+
|
|
199
|
+
Supports multiple observation types with full type safety:
|
|
200
|
+
- **span**: General-purpose operations (default)
|
|
201
|
+
- **llm**: LLM calls and AI model interactions
|
|
202
|
+
- **embedding**: Text embedding and vector operations
|
|
203
|
+
- **agent**: AI agent workflows
|
|
204
|
+
- **tool**: Individual tool calls
|
|
205
|
+
- **chain**: Multi-step processes
|
|
206
|
+
- **retriever**: Document retrieval
|
|
207
|
+
- **reranker**: Result reranking
|
|
208
|
+
- **evaluator**: Quality assessment
|
|
209
|
+
- **guardrail**: Safety checks
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
name: Descriptive name for the observation.
|
|
213
|
+
attributes: Type-specific attributes.
|
|
214
|
+
as_type: Type of observation to create. Defaults to 'span'.
|
|
215
|
+
parent_span_context: Optional parent span context for linking.
|
|
216
|
+
start_time: Optional custom start time.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Strongly-typed observation object.
|
|
220
|
+
|
|
221
|
+
Examples:
|
|
222
|
+
LLM observation:
|
|
223
|
+
>>> llm = start_observation('openai-gpt-4', {
|
|
224
|
+
... 'input': [{'role': 'user', 'content': 'Hello'}],
|
|
225
|
+
... 'model': 'gpt-4',
|
|
226
|
+
... 'model_parameters': {'temperature': 0.7}
|
|
227
|
+
... }, as_type='llm')
|
|
228
|
+
|
|
229
|
+
Tool observation:
|
|
230
|
+
>>> tool = start_observation('weather-api', {
|
|
231
|
+
... 'input': {'location': 'SF'}
|
|
232
|
+
... }, as_type='tool')
|
|
233
|
+
"""
|
|
234
|
+
tracer = get_tracer()
|
|
235
|
+
|
|
236
|
+
# Start the OTEL span with optional parent context
|
|
237
|
+
if parent_span_context:
|
|
238
|
+
# Use start_as_current_span with parent context for proper context propagation
|
|
239
|
+
from opentelemetry.trace import NonRecordingSpan
|
|
240
|
+
parent_span = NonRecordingSpan(parent_span_context)
|
|
241
|
+
parent_ctx = trace.set_span_in_context(parent_span)
|
|
242
|
+
|
|
243
|
+
# Use context manager to properly attach/detach
|
|
244
|
+
token = context.attach(parent_ctx)
|
|
245
|
+
otel_span = tracer.start_span(name, start_time=start_time)
|
|
246
|
+
# Keep context attached - the span wrapper will manage it
|
|
247
|
+
else:
|
|
248
|
+
token = None
|
|
249
|
+
otel_span = tracer.start_span(name, start_time=start_time)
|
|
250
|
+
|
|
251
|
+
# Store token in span for cleanup when span ends
|
|
252
|
+
if token:
|
|
253
|
+
otel_span._agkit_context_token = token
|
|
254
|
+
|
|
255
|
+
# Create the appropriate observation wrapper
|
|
256
|
+
if as_type == "llm":
|
|
257
|
+
return ObservationLLM(otel_span, attributes)
|
|
258
|
+
elif as_type == "embedding":
|
|
259
|
+
return ObservationEmbedding(otel_span, attributes)
|
|
260
|
+
elif as_type == "agent":
|
|
261
|
+
return ObservationAgent(otel_span, attributes)
|
|
262
|
+
elif as_type == "tool":
|
|
263
|
+
return ObservationTool(otel_span, attributes)
|
|
264
|
+
elif as_type == "chain":
|
|
265
|
+
return ObservationChain(otel_span, attributes)
|
|
266
|
+
elif as_type == "retriever":
|
|
267
|
+
return ObservationRetriever(otel_span, attributes)
|
|
268
|
+
elif as_type == "reranker":
|
|
269
|
+
return ObservationReranker(otel_span, attributes)
|
|
270
|
+
elif as_type == "evaluator":
|
|
271
|
+
return ObservationEvaluator(otel_span, attributes)
|
|
272
|
+
elif as_type == "guardrail":
|
|
273
|
+
return ObservationGuardrail(otel_span, attributes)
|
|
274
|
+
else:
|
|
275
|
+
return ObservationSpan(otel_span, attributes)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def update_active_trace(attributes: TraceAttributes) -> None:
|
|
279
|
+
"""Update the currently active trace with new attributes.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
attributes: Trace attributes to set.
|
|
283
|
+
"""
|
|
284
|
+
_update_active_trace(attributes)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def get_active_trace_id() -> Optional[str]:
|
|
288
|
+
"""Get the current active trace ID.
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
The trace ID as a hex string, or None if no active span.
|
|
292
|
+
"""
|
|
293
|
+
return _get_active_trace_id()
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def get_active_span_id() -> Optional[str]:
|
|
297
|
+
"""Get the current active observation ID.
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
The span ID as a hex string, or None if no active span.
|
|
301
|
+
"""
|
|
302
|
+
return _get_active_span_id()
|