prismtrace-sdk 0.3.2__tar.gz
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.
- prismtrace_sdk-0.3.2/PKG-INFO +11 -0
- prismtrace_sdk-0.3.2/README.md +337 -0
- prismtrace_sdk-0.3.2/prismtrace/__init__.py +34 -0
- prismtrace_sdk-0.3.2/prismtrace/claude_tracer.py +363 -0
- prismtrace_sdk-0.3.2/prismtrace/client.py +265 -0
- prismtrace_sdk-0.3.2/prismtrace/elevenlabs_voice.py +223 -0
- prismtrace_sdk-0.3.2/prismtrace/google_adk.py +789 -0
- prismtrace_sdk-0.3.2/prismtrace/langchain_handler.py +411 -0
- prismtrace_sdk-0.3.2/prismtrace/langgraph_helper.py +120 -0
- prismtrace_sdk-0.3.2/prismtrace/litellm_callback.py +257 -0
- prismtrace_sdk-0.3.2/prismtrace/openai_agents.py +291 -0
- prismtrace_sdk-0.3.2/prismtrace/otel.py +145 -0
- prismtrace_sdk-0.3.2/prismtrace/verify.py +168 -0
- prismtrace_sdk-0.3.2/prismtrace_sdk.egg-info/PKG-INFO +11 -0
- prismtrace_sdk-0.3.2/prismtrace_sdk.egg-info/SOURCES.txt +21 -0
- prismtrace_sdk-0.3.2/prismtrace_sdk.egg-info/dependency_links.txt +1 -0
- prismtrace_sdk-0.3.2/prismtrace_sdk.egg-info/requires.txt +1 -0
- prismtrace_sdk-0.3.2/prismtrace_sdk.egg-info/top_level.txt +1 -0
- prismtrace_sdk-0.3.2/setup.cfg +4 -0
- prismtrace_sdk-0.3.2/setup.py +11 -0
- prismtrace_sdk-0.3.2/tests/test_google_adk.py +313 -0
- prismtrace_sdk-0.3.2/tests/test_langchain_handler.py +93 -0
- prismtrace_sdk-0.3.2/tests/test_langchain_live.py +153 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prismtrace-sdk
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: PRISMtrace SDK — AI Observability by Block Convey
|
|
5
|
+
Author: Block Convey
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Requires-Dist: httpx>=0.24.0
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: requires-dist
|
|
10
|
+
Dynamic: requires-python
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# PRISMtrace Python SDK
|
|
2
|
+
|
|
3
|
+
AI Chat Observability by Block Convey. Supports Langchain, OpenTelemetry, Claude tool use tracing, **Trajectory evaluation**, and **Knowledge Base** management.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install prismtrace-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Until the package is on PyPI, install from the repo (or set
|
|
12
|
+
`PRISMTRACE_SDK_INSTALL` in the PRISMtrace backend to the same command):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install "git+https://github.com/Block-Convey/prismtrace.git#subdirectory=sdk/python"
|
|
16
|
+
# or, from a local checkout:
|
|
17
|
+
pip install -e ./sdk/python
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quickstart — Manual Trace
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from prismtrace import PRISMtrace
|
|
24
|
+
|
|
25
|
+
pt = PRISMtrace(
|
|
26
|
+
api_key="pt-sk-your-key",
|
|
27
|
+
host="https://prismtrace-production.up.railway.app",
|
|
28
|
+
project_id="your-project-id",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
pt.trace_llm(
|
|
32
|
+
model="claude-sonnet-4-5-20250514",
|
|
33
|
+
input_messages=[{"role": "user", "content": "Hello"}],
|
|
34
|
+
output="Hi there!",
|
|
35
|
+
latency_ms=320,
|
|
36
|
+
token_count_input=10,
|
|
37
|
+
token_count_output=5,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Decorator
|
|
41
|
+
@pt.trace()
|
|
42
|
+
def ask_bot(question):
|
|
43
|
+
# your LLM call here
|
|
44
|
+
return "answer"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Trajectory Evaluation
|
|
48
|
+
|
|
49
|
+
Submit agent trajectories (ordered step lists) for automated PRISM evaluation — goal adherence, tool compliance, efficiency, and safety scores.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
result = pt.submit_trajectory(
|
|
53
|
+
agent_name="finance-agent",
|
|
54
|
+
model="claude-sonnet-4-5-20250514",
|
|
55
|
+
steps=[
|
|
56
|
+
{
|
|
57
|
+
"step_type": "reasoning",
|
|
58
|
+
"label": "Analyze user query",
|
|
59
|
+
"input_summary": "User asked about Q3 revenue",
|
|
60
|
+
"output_summary": "Need to query knowledge base for financials",
|
|
61
|
+
"duration_ms": 200,
|
|
62
|
+
"token_count": 150,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"step_type": "tool_call",
|
|
66
|
+
"label": "knowledge_base_search",
|
|
67
|
+
"tool_name": "knowledge_base_search",
|
|
68
|
+
"input_summary": "Q3 revenue figures",
|
|
69
|
+
"output_summary": "Found 3 matching documents",
|
|
70
|
+
"duration_ms": 80,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"step_type": "final_answer",
|
|
74
|
+
"label": "Provide answer",
|
|
75
|
+
"output_summary": "Q3 revenue was $4.2M, up 12% YoY",
|
|
76
|
+
"duration_ms": 300,
|
|
77
|
+
"token_count": 200,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
print(f"Trajectory ID: {result['id']}")
|
|
83
|
+
|
|
84
|
+
# Check evaluation results (runs async after submission)
|
|
85
|
+
evaluation = pt.get_trajectory_evaluation(result["id"])
|
|
86
|
+
print(evaluation)
|
|
87
|
+
|
|
88
|
+
# Re-trigger evaluation if config changed
|
|
89
|
+
pt.retrigger_evaluation(result["id"])
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Knowledge Base
|
|
93
|
+
|
|
94
|
+
Upload documents and search your project's knowledge base directly from the SDK.
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
# Upload a document
|
|
98
|
+
doc = pt.kb_upload(
|
|
99
|
+
filename="company-policy.md",
|
|
100
|
+
content="# Return Policy\nAll items may be returned within 30 days...",
|
|
101
|
+
description="Customer-facing return policy v2",
|
|
102
|
+
content_type="text/markdown",
|
|
103
|
+
)
|
|
104
|
+
print(f"Document ID: {doc['id']}, Chunks: {doc['chunk_count']}")
|
|
105
|
+
|
|
106
|
+
# Search the knowledge base
|
|
107
|
+
results = pt.kb_search("return policy for electronics", limit=3)
|
|
108
|
+
for chunk in results:
|
|
109
|
+
print(f" Score: {chunk['score']:.2f} — {chunk['content'][:80]}...")
|
|
110
|
+
|
|
111
|
+
# List all documents
|
|
112
|
+
docs = pt.kb_list_documents()
|
|
113
|
+
|
|
114
|
+
# Delete a document
|
|
115
|
+
pt.kb_delete_document(doc["id"])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## LangChain Integration
|
|
119
|
+
|
|
120
|
+
Uses `X-PRISMtrace-Key`. Env vars `PRISMTRACE_API_KEY`, `PRISMTRACE_PROJECT_ID`,
|
|
121
|
+
and `PRISMTRACE_HOST` are read when constructor args are omitted.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from prismtrace import PRISMtraceCallbackHandler
|
|
125
|
+
from langchain.chains import LLMChain
|
|
126
|
+
from langchain_anthropic import ChatAnthropic
|
|
127
|
+
|
|
128
|
+
handler = PRISMtraceCallbackHandler(
|
|
129
|
+
api_key="pt-sk-...",
|
|
130
|
+
project_id="your-project-id",
|
|
131
|
+
host="https://prismtrace-production.up.railway.app",
|
|
132
|
+
session_id="conversation-1", # groups steps into a trajectory
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
llm = ChatAnthropic(model="claude-sonnet-4-5-20250514")
|
|
136
|
+
chain = LLMChain(llm=llm, prompt=prompt, callbacks=[handler])
|
|
137
|
+
result = chain.run("What is the credit risk for this customer?")
|
|
138
|
+
handler.flush() # safe to call; also runs on process exit
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## LangGraph Integration
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from prismtrace import PRISMtraceLangGraphHandler, wrap_langgraph
|
|
145
|
+
|
|
146
|
+
handler = PRISMtraceLangGraphHandler(
|
|
147
|
+
api_key="pt-sk-...",
|
|
148
|
+
project_id="your-project-id",
|
|
149
|
+
host="https://prismtrace-production.up.railway.app",
|
|
150
|
+
agent_name="support-graph",
|
|
151
|
+
)
|
|
152
|
+
graph = wrap_langgraph(compiled_graph, handler)
|
|
153
|
+
graph.invoke({"messages": [("user", "hello")]})
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Verify connection
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
export PRISMTRACE_HOST=https://your-host
|
|
160
|
+
export PRISMTRACE_PROJECT_ID=...
|
|
161
|
+
export PRISMTRACE_API_KEY=pt-sk-...
|
|
162
|
+
python -m prismtrace.verify
|
|
163
|
+
# Prints CREDENTIAL OK|FAIL and LIVE CONNECTED|WAITING FOR LIVE
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Google ADK Integration (Beta)
|
|
167
|
+
|
|
168
|
+
Capture Google Agent Development Kit workflows by passing the adapter's
|
|
169
|
+
hooks to an `LlmAgent`:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from prismtrace import PRISMtraceADKAdapter
|
|
173
|
+
from google.adk.agents import LlmAgent
|
|
174
|
+
|
|
175
|
+
adapter = PRISMtraceADKAdapter(
|
|
176
|
+
api_key="pt-sk-...",
|
|
177
|
+
project_id="your-project-id",
|
|
178
|
+
agent_name="my-adk-agent",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
agent = LlmAgent(
|
|
182
|
+
name="loan_assistant",
|
|
183
|
+
model="gemini-2.0-flash",
|
|
184
|
+
instruction="You help users understand loan products.",
|
|
185
|
+
tools=[lookup_rate],
|
|
186
|
+
before_model_callback=adapter.before_model,
|
|
187
|
+
after_model_callback=adapter.after_model,
|
|
188
|
+
before_tool_callback=adapter.before_tool,
|
|
189
|
+
after_tool_callback=adapter.after_tool,
|
|
190
|
+
before_agent_callback=adapter.before_agent,
|
|
191
|
+
after_agent_callback=adapter.after_agent,
|
|
192
|
+
)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Wiring `before_tool_callback=adapter.before_tool` enables real tool
|
|
196
|
+
latency on `after_tool` traces; without it the trace stamps
|
|
197
|
+
`latency_ms=0` and `tool_latency_unavailable=True` in metadata.
|
|
198
|
+
|
|
199
|
+
### Error capture
|
|
200
|
+
|
|
201
|
+
ADK does not currently surface model/tool errors through a callback.
|
|
202
|
+
Emit explicit error traces from `try / except` blocks instead:
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
try:
|
|
206
|
+
response = await llm.generate_content_async(...)
|
|
207
|
+
except Exception as exc:
|
|
208
|
+
adapter.record_model_error(exc, callback_context=ctx)
|
|
209
|
+
raise
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
result = run_tool(args)
|
|
213
|
+
except Exception as exc:
|
|
214
|
+
adapter.record_tool_error(exc, callback_context=ctx,
|
|
215
|
+
tool_name="lookup_rate",
|
|
216
|
+
tool=tool, tool_context=ctx)
|
|
217
|
+
raise
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
await Runner.run_async(...)
|
|
221
|
+
except Exception as exc:
|
|
222
|
+
adapter.record_runner_error(exc)
|
|
223
|
+
raise
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Each emits a trace with `status=error` in metadata. Error messages are
|
|
227
|
+
scrubbed for `pt-sk-…`, `sk-…`, `sk-ant-…`, `AIza…` and other known
|
|
228
|
+
secret patterns before they're posted.
|
|
229
|
+
|
|
230
|
+
Runnable demo: [`examples/google_adk_demo.py`](examples/google_adk_demo.py).
|
|
231
|
+
Full validation notes (what's captured, Beta gaps, known issues):
|
|
232
|
+
[`docs/GOOGLE_ADK_INTEGRATION.md`](../../docs/GOOGLE_ADK_INTEGRATION.md).
|
|
233
|
+
|
|
234
|
+
## OpenTelemetry Integration
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from prismtrace.otel import PRISMtraceInstrumentor
|
|
238
|
+
|
|
239
|
+
instrumentor = PRISMtraceInstrumentor()
|
|
240
|
+
instrumentor.instrument(
|
|
241
|
+
api_key="pt-sk-...",
|
|
242
|
+
project_id="your-project-id",
|
|
243
|
+
endpoint="https://prismtrace-production.up.railway.app",
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
tracer = instrumentor.get_tracer("my-service")
|
|
247
|
+
with tracer.start_as_current_span("process_request") as span:
|
|
248
|
+
span.set_attribute("prismtrace.span_type", "chain")
|
|
249
|
+
span.set_attribute("prismtrace.input", "user query")
|
|
250
|
+
# ... your code ...
|
|
251
|
+
span.set_attribute("prismtrace.output", "response")
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Requires: `pip install opentelemetry-sdk opentelemetry-api`
|
|
255
|
+
|
|
256
|
+
## Claude Tool Use Tracing (with auto-trajectory)
|
|
257
|
+
|
|
258
|
+
The `ClaudeAgentTracer` now automatically emits both **spans** (for trace detail) and a **trajectory** (for PRISM evaluation) after each agentic run.
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
import anthropic
|
|
262
|
+
from prismtrace.claude_tracer import ClaudeAgentTracer
|
|
263
|
+
|
|
264
|
+
client = anthropic.Anthropic()
|
|
265
|
+
|
|
266
|
+
tracer = ClaudeAgentTracer(
|
|
267
|
+
anthropic_client=client,
|
|
268
|
+
api_key="pt-sk-...",
|
|
269
|
+
project_id="your-project-id",
|
|
270
|
+
endpoint="https://prismtrace-production.up.railway.app",
|
|
271
|
+
agent_name="weather-agent", # shows up in trajectory analytics
|
|
272
|
+
emit_trajectory=True, # default: auto-submit trajectory
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
tools = [
|
|
276
|
+
{
|
|
277
|
+
"name": "get_weather",
|
|
278
|
+
"description": "Get the weather for a location",
|
|
279
|
+
"input_schema": {
|
|
280
|
+
"type": "object",
|
|
281
|
+
"properties": {"location": {"type": "string"}},
|
|
282
|
+
"required": ["location"],
|
|
283
|
+
},
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
def execute_tool(name: str, input_data: dict) -> str:
|
|
288
|
+
if name == "get_weather":
|
|
289
|
+
return f"72F and sunny in {input_data['location']}"
|
|
290
|
+
return "Unknown tool"
|
|
291
|
+
|
|
292
|
+
result = tracer.run(
|
|
293
|
+
messages=[{"role": "user", "content": "What's the weather in SF?"}],
|
|
294
|
+
tools=tools,
|
|
295
|
+
system="You are a helpful assistant.",
|
|
296
|
+
tool_executor=execute_tool,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
print(f"Trace ID: {result['trace_id']}")
|
|
300
|
+
print(f"Trajectory ID: {result['trajectory_id']}")
|
|
301
|
+
print(f"Iterations: {result['iterations']}")
|
|
302
|
+
print(f"Traj. steps: {result['trajectory_steps']}")
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Auto-instrument all Claude calls
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
tracer.instrument_client()
|
|
309
|
+
|
|
310
|
+
# Now every client.messages.create() call is automatically traced
|
|
311
|
+
response = client.messages.create(
|
|
312
|
+
model="claude-sonnet-4-5-20250514",
|
|
313
|
+
max_tokens=1024,
|
|
314
|
+
messages=[{"role": "user", "content": "Hello"}],
|
|
315
|
+
)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Zero-code Proxy
|
|
319
|
+
|
|
320
|
+
If you route LLM calls through the PRISMtrace proxy (`/proxy/anthropic/v1/messages`), trajectories are **automatically created** whenever the response contains tool-use blocks. No SDK changes needed — just point your Anthropic base URL at the proxy.
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
import anthropic
|
|
324
|
+
|
|
325
|
+
client = anthropic.Anthropic(
|
|
326
|
+
base_url="https://prismtrace-production.up.railway.app/proxy/anthropic/v1",
|
|
327
|
+
default_headers={"X-PRISMtrace-Key": "pt-sk-your-key"},
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# Every tool-use response automatically gets a trajectory + PRISM evaluation
|
|
331
|
+
response = client.messages.create(
|
|
332
|
+
model="claude-sonnet-4-5-20250514",
|
|
333
|
+
max_tokens=1024,
|
|
334
|
+
messages=[{"role": "user", "content": "What's the weather?"}],
|
|
335
|
+
tools=[...],
|
|
336
|
+
)
|
|
337
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from .client import PRISMtrace
|
|
2
|
+
from .langchain_handler import PRISMtraceCallbackHandler
|
|
3
|
+
from .claude_tracer import ClaudeAgentTracer
|
|
4
|
+
from .langgraph_helper import PRISMtraceLangGraphHandler, wrap_graph as wrap_langgraph
|
|
5
|
+
from .google_adk import PRISMtraceADKAdapter
|
|
6
|
+
from .litellm_callback import install as install_litellm
|
|
7
|
+
from .openai_agents import PRISMtraceTracingProcessor, install as install_openai_agents
|
|
8
|
+
from .elevenlabs_voice import (
|
|
9
|
+
PRISMtraceVoiceTracer,
|
|
10
|
+
install as install_elevenlabs_voice,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__version__ = "0.3.2"
|
|
14
|
+
__all__ = [
|
|
15
|
+
# Core
|
|
16
|
+
"PRISMtrace",
|
|
17
|
+
# LangChain (Supported)
|
|
18
|
+
"PRISMtraceCallbackHandler",
|
|
19
|
+
# Anthropic direct (Supported)
|
|
20
|
+
"ClaudeAgentTracer",
|
|
21
|
+
# LangGraph (Supported)
|
|
22
|
+
"PRISMtraceLangGraphHandler",
|
|
23
|
+
"wrap_langgraph",
|
|
24
|
+
# Google ADK (Beta)
|
|
25
|
+
"PRISMtraceADKAdapter",
|
|
26
|
+
# LiteLLM (Universal Gateway, Supported)
|
|
27
|
+
"install_litellm",
|
|
28
|
+
# OpenAI Agents SDK (Preview)
|
|
29
|
+
"PRISMtraceTracingProcessor",
|
|
30
|
+
"install_openai_agents",
|
|
31
|
+
# ElevenLabs Agents — voice (Supported)
|
|
32
|
+
"PRISMtraceVoiceTracer",
|
|
33
|
+
"install_elevenlabs_voice",
|
|
34
|
+
]
|