runtime-labs-sdk 0.1.0__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.
- runtime_labs_sdk-0.1.0/.gitignore +22 -0
- runtime_labs_sdk-0.1.0/PKG-INFO +382 -0
- runtime_labs_sdk-0.1.0/README.md +361 -0
- runtime_labs_sdk-0.1.0/pyproject.toml +33 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/__init__.py +6 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/binding.py +204 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/bootstrap.py +60 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/config.py +42 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/correlation.py +64 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/export.py +109 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/hooks.py +263 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/payloads.py +147 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/propagation.py +47 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/sdk.py +235 -0
- runtime_labs_sdk-0.1.0/src/runtime_labs/semconv.py +64 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*.egg-info/
|
|
10
|
+
dist/
|
|
11
|
+
*.jsonl
|
|
12
|
+
.scanner-recordings/
|
|
13
|
+
.scanner-cache/
|
|
14
|
+
.scanner-checkpoints/
|
|
15
|
+
.scanner-runs/
|
|
16
|
+
|
|
17
|
+
# Local app state and frontend build artifacts
|
|
18
|
+
.runtime-labs/
|
|
19
|
+
node_modules/
|
|
20
|
+
*.tsbuildinfo
|
|
21
|
+
playwright-report/
|
|
22
|
+
test-results/
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: runtime-labs-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenTelemetry tracing with eval payloads and verified source identities
|
|
5
|
+
Project-URL: Repository, https://github.com/arpandesai0/runtime-labs
|
|
6
|
+
Project-URL: Documentation, https://github.com/arpandesai0/runtime-labs/blob/main/packages/sdk/README.md
|
|
7
|
+
Requires-Python: <3.14,>=3.11
|
|
8
|
+
Requires-Dist: httpx<1,>=0.28
|
|
9
|
+
Requires-Dist: opentelemetry-api==1.45.1
|
|
10
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.45.1
|
|
11
|
+
Requires-Dist: opentelemetry-sdk==1.45.1
|
|
12
|
+
Requires-Dist: python-dotenv<2,>=1.1
|
|
13
|
+
Requires-Dist: runtime-labs-contracts
|
|
14
|
+
Provides-Extra: google
|
|
15
|
+
Requires-Dist: google-genai==2.27.0; extra == 'google'
|
|
16
|
+
Provides-Extra: langgraph
|
|
17
|
+
Requires-Dist: langgraph==1.2.18; extra == 'langgraph'
|
|
18
|
+
Provides-Extra: otlp
|
|
19
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.45.1; extra == 'otlp'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# Runtime Labs local Python SDK
|
|
23
|
+
|
|
24
|
+
The SDK emits OpenTelemetry spans with full eval payloads for LangGraph execution
|
|
25
|
+
and Google Gen AI non-streaming model calls. The scanner's strict `DeploymentManifest`
|
|
26
|
+
adds `runtime_labs.node_id` when source proof succeeds. Tracing also works with
|
|
27
|
+
missing or stale manifests: those operations remain unattributed and the handle
|
|
28
|
+
reports fixed diagnostic codes.
|
|
29
|
+
|
|
30
|
+
## Install and initialize
|
|
31
|
+
|
|
32
|
+
From this workspace:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv sync
|
|
36
|
+
uv run python examples/sdk_offline/demo.py
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For an application with its own environment, install both local distributions
|
|
40
|
+
(substitute the checkout directory):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv pip install /path/to/runtime-labs/packages/contracts \
|
|
44
|
+
'/path/to/runtime-labs/packages/sdk[google,langgraph]'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`runtime-labs-sdk` is independently packaged and has no scanner dependency. The
|
|
48
|
+
Google and LangGraph adapters are optional and loaded at initialization; importing
|
|
49
|
+
`runtime_labs` does not import either integration. Unsupported dependency versions
|
|
50
|
+
are diagnosed and their adapters are skipped.
|
|
51
|
+
|
|
52
|
+
Connect and scan the application checkout in the web UI first. Run the application
|
|
53
|
+
inside its Git checkout with an `origin` remote. No manifest file is downloaded or
|
|
54
|
+
configured by the customer. The SDK reads that remote and asks the backend for the
|
|
55
|
+
successful scan's manifest at startup. SSH and HTTPS remotes normalize to the same
|
|
56
|
+
host/owner/repository identity.
|
|
57
|
+
|
|
58
|
+
Optional application `.env` (the default is shown):
|
|
59
|
+
|
|
60
|
+
```dotenv
|
|
61
|
+
RUNTIME_LABS_API_URL=http://127.0.0.1:8000
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
At startup, before constructing provider clients or building/executing graphs:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import runtime_labs
|
|
68
|
+
|
|
69
|
+
sdk = runtime_labs.init(api_key="runtime-labs-local-dev-key")
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
# Normal application startup and execution.
|
|
73
|
+
...
|
|
74
|
+
finally:
|
|
75
|
+
sdk.flush()
|
|
76
|
+
sdk.shutdown()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The API key is sent to the backend as an Authorization bearer header for manifest
|
|
80
|
+
lookup and automatic telemetry delivery. Authentication and workspace lookup are
|
|
81
|
+
currently deferred: the backend uses the default tenant/workspace. The key is
|
|
82
|
+
hidden from configuration representations and is never included in span payloads
|
|
83
|
+
or provider credentials.
|
|
84
|
+
|
|
85
|
+
Configuration rules:
|
|
86
|
+
|
|
87
|
+
- `api_url=` overrides process `RUNTIME_LABS_API_URL`, then the nearest `.env` value,
|
|
88
|
+
then the local default above. SDK settings are read without interpolation or
|
|
89
|
+
mutating the application's environment.
|
|
90
|
+
- By default the SDK resolves the checkout's `origin` and HEAD, requests
|
|
91
|
+
`POST /api/sdk/manifest`, validates the strict deployment manifest, and holds it
|
|
92
|
+
in memory. No manifest cache file or customer download step is required.
|
|
93
|
+
- The backend resolves the complete canonical Git identity, reads the successful
|
|
94
|
+
scan's saved artifact, and returns the manifest and repository ingestion route.
|
|
95
|
+
Duplicate matching checkouts, unavailable artifacts, and revision mismatches
|
|
96
|
+
are rejected rather than guessed.
|
|
97
|
+
- Existing source-path, source-digest, and loaded-code proofs still apply.
|
|
98
|
+
- For explicit offline/test use only, `RUNTIME_LABS_MANIFEST_PATH` remains a legacy
|
|
99
|
+
override. Paths retain their existing `~` and nearest-`.env` resolution rules.
|
|
100
|
+
An empty override enables normal runtime fetching instead of disabling attribution.
|
|
101
|
+
- A failed lookup never breaks application execution. Inspect `sdk.diagnostics`
|
|
102
|
+
for `repository_identity_unavailable`, `manifest_fetch_failed`, or
|
|
103
|
+
`manifest_revision_mismatch`. Unsupported or unverified spans stay unattributed.
|
|
104
|
+
- Deployed environments must retain Git metadata for automatic remote discovery.
|
|
105
|
+
Initialization fetches once with a five-second HTTP timeout; retry after fixing
|
|
106
|
+
backend/scan availability by shutting down and initializing again.
|
|
107
|
+
|
|
108
|
+
## Public API and local output
|
|
109
|
+
|
|
110
|
+
`init(*, api_key, exporter=None, tracer_provider=None, capture_payloads=True, api_url=None)`
|
|
111
|
+
returns an SDK handle with:
|
|
112
|
+
|
|
113
|
+
- `diagnostics`: a sorted tuple of sanitized, deduplicated diagnostic codes.
|
|
114
|
+
- `sources.manifest`: a detached strict-contract snapshot; editing it cannot change
|
|
115
|
+
the immutable attribution indexes. Repository/revision metadata stay here.
|
|
116
|
+
- `flush(timeout_millis=30000) -> bool`: flush only this SDK's exporter.
|
|
117
|
+
- `shutdown()`: flush, disable instrumentation, restore owned hooks, and release
|
|
118
|
+
SDK-owned resources. It is safe to call repeatedly.
|
|
119
|
+
|
|
120
|
+
Identical initialization returns the same handle. A different key, resolved path,
|
|
121
|
+
exporter, explicit provider or payload setting returns that handle with
|
|
122
|
+
`initialization_conflict`,
|
|
123
|
+
without installing more hooks. Shut down and initialize again to change settings;
|
|
124
|
+
construct new graphs after reinitialization. Shutdown should follow completion or
|
|
125
|
+
cancellation of application work; it does not await running requests.
|
|
126
|
+
|
|
127
|
+
After successful runtime bootstrap, the SDK automatically exports OTLP/HTTP spans
|
|
128
|
+
to the repository route supplied by the backend. The OTLP exporter is included in
|
|
129
|
+
the base SDK dependency set. Explicit exporters and standard `OTEL_*` settings
|
|
130
|
+
remain supported; `OTEL_TRACES_EXPORTER=none` disables delivery. Offline manifest
|
|
131
|
+
mode retains the console default. Console records contain trace/span/parent IDs,
|
|
132
|
+
start/end timestamps, duration, status, and allowed attributes including application
|
|
133
|
+
payloads. HTTP authentication, environment dumps, and source bodies are not captured.
|
|
134
|
+
Errors use only `error.type` values `cancelled`, `timeout` or `_OTHER`; automatic
|
|
135
|
+
exception events and status descriptions are disabled. Application code and other
|
|
136
|
+
instrumentation retain their own logging/export policies.
|
|
137
|
+
|
|
138
|
+
## Payloads for evals
|
|
139
|
+
|
|
140
|
+
Full payload capture is enabled by default. The MVP performs **no redaction or SDK
|
|
141
|
+
size limiting**. Each payload attribute is a JSON string, supported by standard
|
|
142
|
+
OTel exporters. Decode it with `json.loads(span.attributes[attribute_name])`.
|
|
143
|
+
|
|
144
|
+
| Span | Payload attributes |
|
|
145
|
+
| --- | --- |
|
|
146
|
+
| Workflow / agent | `runtime_labs.input`, `runtime_labs.output`: input state and returned value |
|
|
147
|
+
| Google model call | `runtime_labs.request`: original model, contents and supplied generation config; `runtime_labs.response`: returned response body, candidates, usage, parsed output and automatic tool-calling history |
|
|
148
|
+
| Google model call | `gen_ai.input.messages`, `gen_ai.output.messages`: standard message/part representation; `gen_ai.system_instructions` when supplied |
|
|
149
|
+
| Tool execution | `gen_ai.tool.call.arguments`, `gen_ai.tool.call.result`: bound arguments and returned value |
|
|
150
|
+
|
|
151
|
+
The `runtime_labs.*` payload attributes carry application data, not additional
|
|
152
|
+
source identity fields. `runtime_labs.node_id` remains the only custom source ID.
|
|
153
|
+
Prompts, completions, all returned candidates and tool payloads are stored in full.
|
|
154
|
+
Raw provider request/response attributes retain provider-specific body fields;
|
|
155
|
+
HTTP options and `sdk_http_response` transport envelopes are not body payloads.
|
|
156
|
+
The SDK does not inspect client credentials or automatically export its API key.
|
|
157
|
+
|
|
158
|
+
Request/input snapshots are taken before execution, so in-place application or
|
|
159
|
+
Google automatic function-calling mutations cannot rewrite the original input.
|
|
160
|
+
The returned automatic function-calling history retains its intermediate tool
|
|
161
|
+
calls/results. Workflow outputs contain the final graph state, including the
|
|
162
|
+
application's answer, enabling complete input/output evaluation examples. Runtime
|
|
163
|
+
trace and span IDs join these payloads to the manifest's source node IDs.
|
|
164
|
+
|
|
165
|
+
JSON-compatible values, Pydantic models, dataclasses, enums, dates and bytes are
|
|
166
|
+
supported; bytes are encoded as base64. Callable tool definitions store callable
|
|
167
|
+
names and qualified names rather than executable code. Unsupported or cyclic
|
|
168
|
+
values produce `payload_capture_failed` and omit that payload attribute while
|
|
169
|
+
preserving application results/exceptions and other span data. A failed or
|
|
170
|
+
cancelled operation keeps its input; it does not invent a response.
|
|
171
|
+
|
|
172
|
+
To select metadata-only output explicitly:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
sdk = runtime_labs.init(api_key="runtime-labs-local-dev-key", capture_payloads=False)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
OTel/application processors and downstream collectors can have their own limits;
|
|
179
|
+
the Runtime Labs SDK does not introduce payload truncation. Local JSON and OTLP
|
|
180
|
+
export receive the same payload attributes. Evaluation execution/dataset storage
|
|
181
|
+
are separate later components; this change supplies their runtime examples.
|
|
182
|
+
|
|
183
|
+
For assertions, supply the standard OTel in-memory exporter:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from runtime_labs.export import InMemorySpanExporter
|
|
187
|
+
|
|
188
|
+
exporter = InMemorySpanExporter()
|
|
189
|
+
sdk = runtime_labs.init(api_key="runtime-labs-local-dev-key", exporter=exporter)
|
|
190
|
+
# Execute work; then inspect exporter.get_finished_spans().
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The explicitly selected in-memory exporter retains spans until `clear()` or
|
|
194
|
+
`shutdown()`; applications should bound its use. Custom exporters use the standard
|
|
195
|
+
OTel `SpanExporter` interface. Export/flush/shutdown exceptions become diagnostic
|
|
196
|
+
codes and do not replace application results or exceptions. Local export is
|
|
197
|
+
synchronous, so exporter work contributes latency.
|
|
198
|
+
|
|
199
|
+
An application-owned global `TracerProvider` is respected. An optional explicit
|
|
200
|
+
`tracer_provider` also works. The SDK adds one reusable processor scoped to
|
|
201
|
+
`runtime_labs`, never shuts down an application provider, and does not export its
|
|
202
|
+
other instrumentation scopes through the local exporter. If no application provider
|
|
203
|
+
exists, the SDK creates a private OTel provider without taking the global slot.
|
|
204
|
+
Active OTel context still establishes parentage across both providers. Application
|
|
205
|
+
processors on a shared provider can also observe SDK spans.
|
|
206
|
+
|
|
207
|
+
Remote OTLP/HTTP export requires **both** explicit standard settings:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
uv pip install '/path/to/runtime-labs/packages/sdk[otlp]'
|
|
211
|
+
export OTEL_TRACES_EXPORTER=otlp
|
|
212
|
+
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
|
|
213
|
+
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`OTEL_EXPORTER_OTLP_ENDPOINT`, generic protocol/timeout/header settings and the
|
|
217
|
+
trace-specific settings are handled by the standard exporter. HTTP/protobuf is the
|
|
218
|
+
supported protocol. An endpoint alone never enables remote export; missing extras,
|
|
219
|
+
missing endpoint or unsupported protocol produce diagnostics and local fallback.
|
|
220
|
+
The pinned exporter's per-instance transport logger is silenced so server reasons
|
|
221
|
+
and transport exceptions cannot echo private text; failures use sanitized SDK
|
|
222
|
+
diagnostics. Its optional internal metrics use a no-op provider.
|
|
223
|
+
`OTEL_TRACES_EXPORTER=none` discards SDK output. No collector/server is included.
|
|
224
|
+
|
|
225
|
+
## Correlation identifiers and trace context
|
|
226
|
+
|
|
227
|
+
The SDK records the identifiers a framework uses to tie runs together, verbatim,
|
|
228
|
+
and never decides what they mean. On every LangGraph `invoke`/`ainvoke` it copies
|
|
229
|
+
allowlisted keys from the run config onto the workflow span as
|
|
230
|
+
`runtime_labs.ctx.<framework>.<key>`, for example
|
|
231
|
+
`runtime_labs.ctx.langgraph.thread_id`. The defaults are LangGraph's `thread_id`,
|
|
232
|
+
`checkpoint_id`, `checkpoint_ns` and `run_id`. Only allowlisted keys leave the
|
|
233
|
+
process, because applications often keep user IDs and secrets in the same config;
|
|
234
|
+
only non-empty strings, integers and UUIDs are copied, truncated to 256 characters.
|
|
235
|
+
|
|
236
|
+
Extend the allowlist without code changes:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
export RUNTIME_LABS_CORRELATION_KEYS=langgraph.tenant,langgraph.session
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
or with `runtime_labs.init(api_key=..., correlation_keys={"langgraph": ["tenant"]})`.
|
|
243
|
+
Runtime Labs pipelines map these raw identifiers to concepts such as conversations
|
|
244
|
+
with rules that are data, so new frameworks need a rule, not an SDK release.
|
|
245
|
+
|
|
246
|
+
Within one process, span parents follow OpenTelemetry context, which LangGraph and
|
|
247
|
+
asyncio carry into their own threads and tasks. Work that crosses a process or
|
|
248
|
+
service boundary (an HTTP call, a queue message, an outbox row) must carry the
|
|
249
|
+
context itself, as a standard W3C `traceparent`:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
headers = runtime_labs.inject_context() # producer
|
|
253
|
+
with runtime_labs.continue_trace(headers): # consumer
|
|
254
|
+
handle(message)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Code that starts raw threads should run work with
|
|
258
|
+
`contextvars.copy_context().run(...)` to keep the parent.
|
|
259
|
+
|
|
260
|
+
## Supported interfaces and conventions
|
|
261
|
+
|
|
262
|
+
| Component | Pinned/tested version | Coverage |
|
|
263
|
+
| --- | --- | --- |
|
|
264
|
+
| CPython | 3.11–3.13 | Code identity and UTF-8 call positions |
|
|
265
|
+
| Google Gen AI | 2.27.0 | `Models.generate_content`, `AsyncModels.generate_content` |
|
|
266
|
+
| LangGraph | 1.2.18 | `StateGraph` construction, `add_node`, `compile`; compiled `invoke`/`ainvoke` |
|
|
267
|
+
| LangChain Core | 1.7.0 (workspace lock) | LangGraph callback signature and context propagation |
|
|
268
|
+
| OTel API/SDK | 1.45.1 | Context, tracing, processors and standard exporters |
|
|
269
|
+
| OTel OTLP/HTTP exporter | 1.45.1 (optional) | Explicit HTTP/protobuf export |
|
|
270
|
+
| OTel Python semantic-conventions package | 0.66b1 (SDK dependency) | SDK resource conventions |
|
|
271
|
+
| GenAI conventions | `51a0f580f8a6ad804ca4de5e033683c6fbbe5906` | Development conventions, mapping in `semconv.py` |
|
|
272
|
+
|
|
273
|
+
Verified official references: [OTel Python instrumentation](https://opentelemetry.io/docs/languages/python/instrumentation/),
|
|
274
|
+
[GenAI inference conventions](https://github.com/open-telemetry/semantic-conventions-genai/blob/51a0f580f8a6ad804ca4de5e033683c6fbbe5906/docs/gen-ai/client-inference.md),
|
|
275
|
+
[agent/workflow/tool conventions](https://github.com/open-telemetry/semantic-conventions-genai/blob/51a0f580f8a6ad804ca4de5e033683c6fbbe5906/docs/gen-ai/gen-ai-agent-spans.md),
|
|
276
|
+
[Google SDK](https://github.com/googleapis/python-genai/tree/v2.27.0),
|
|
277
|
+
[LangGraph](https://docs.langchain.com/oss/python/langgraph/overview), and
|
|
278
|
+
[streaming boundaries](https://docs.langchain.com/oss/python/langgraph/streaming).
|
|
279
|
+
GenAI conventions remain in development; their revision is explicit rather than
|
|
280
|
+
silently adopting future changes.
|
|
281
|
+
|
|
282
|
+
Provider spans use `generate_content`, `CLIENT`, and `gcp.vertex_ai`, `gcp.gemini`
|
|
283
|
+
or `gcp.gen_ai` according to runtime backend metadata. Request/response models come
|
|
284
|
+
from actual request/response metadata. Tokens come only from provider usage:
|
|
285
|
+
input = prompt count, output = candidate count plus reasoning count when reported;
|
|
286
|
+
reasoning and cache-read counts are separately reported when available. Missing
|
|
287
|
+
counts remain absent. For automatic function calling, the final SDK response's
|
|
288
|
+
reported usage is recorded; counts from hidden HTTP rounds are not estimated or
|
|
289
|
+
aggregated. One span covers the whole public logical call, including these rounds.
|
|
290
|
+
Return identity, arguments, exceptions and async cancellation are preserved.
|
|
291
|
+
|
|
292
|
+
Workflow, agent and tool spans use `INTERNAL` and standard `invoke_workflow`,
|
|
293
|
+
`invoke_agent` and `execute_tool` operations and names. The only custom source
|
|
294
|
+
attribute is `runtime_labs.node_id`. No extra source IDs or static parent IDs are
|
|
295
|
+
attached. The Google adapter honors and sets standard OTel instrumentation
|
|
296
|
+
suppression, and deduplicates reentry. Uncooperative third-party instrumentors that
|
|
297
|
+
ignore suppression cannot be deduplicated reliably.
|
|
298
|
+
|
|
299
|
+
## Source-binding policy
|
|
300
|
+
|
|
301
|
+
The SDK consumes `DeploymentManifest` directly and validates all references using
|
|
302
|
+
the shared strict contract. It neither scans nor executes repository source, calls
|
|
303
|
+
an LLM, generates IDs, or imports modules selected by manifest data.
|
|
304
|
+
|
|
305
|
+
Attribution requires a unique kind and qualified symbol match, normalized for
|
|
306
|
+
Python `<locals>` names, the complete canonical manifest-relative path suffix of
|
|
307
|
+
the actual module/frame file, the verified full-file SHA-256, and agreement between
|
|
308
|
+
the executing code and code compiled from those bytes. Compilation is never
|
|
309
|
+
execution. Checkout filenames alone are normalized out of the code comparison;
|
|
310
|
+
bytecode, constants, nested code, closure layout, flags and position tables remain.
|
|
311
|
+
Different absolute checkout directories therefore work without scanner paths or
|
|
312
|
+
basename-only guessing.
|
|
313
|
+
Direct scripts use their module spec or a canonical module name derived from the
|
|
314
|
+
manifest path; source proof is still required. Verification suppresses compiler
|
|
315
|
+
warnings because those warnings can otherwise echo source lines.
|
|
316
|
+
|
|
317
|
+
For model calls, the executed CALL instruction must match the exact manifest
|
|
318
|
+
range, including UTF-8 byte columns; same-line sync/async calls remain distinct.
|
|
319
|
+
Workflow construction must fall within its unique verified constructor range.
|
|
320
|
+
Registered callback objects identify nested agents. Known module-level Python
|
|
321
|
+
tools and their already-loaded aliases receive wrappers; registration by itself
|
|
322
|
+
never emits a tool span. Ordinary functions such as `finalize_response` receive
|
|
323
|
+
no span. Stale, missing, ambiguous or unprovable code produces generic spans and
|
|
324
|
+
diagnostics, with no guessed source identity.
|
|
325
|
+
|
|
326
|
+
Files are checked again at each attribution, including after construction or a
|
|
327
|
+
previous successful match. Preloaded code is accepted only if its executable code
|
|
328
|
+
and positions agree with the current verified file. This rejects a matching disk
|
|
329
|
+
file paired with different loaded bytecode/constants. It does **not** reconstruct
|
|
330
|
+
historical import-time bytes: comment-only changes with identical code/positions,
|
|
331
|
+
changes outside the executing code unit, mutable globals/closures, or deliberate
|
|
332
|
+
code-object forgery are not a deployment attestation. The current whole-file digest
|
|
333
|
+
must still match the manifest. IDs alone do not validate a deployed revision or
|
|
334
|
+
promise identity reconciliation across commits.
|
|
335
|
+
|
|
336
|
+
Runtime parents always come from OTel context. A direct shared-tool call is under
|
|
337
|
+
the executing agent. A Google automatic tool call is under that logical provider
|
|
338
|
+
span, itself under the executing agent. Static registration/containment edges do
|
|
339
|
+
not override these parents. LangGraph's public runtime events primarily describe
|
|
340
|
+
streaming and do not expose this example's exact Python callback identities, so
|
|
341
|
+
this adapter uses narrowly tested construction/registration/execution wrappers
|
|
342
|
+
without callback arguments or customer decorators.
|
|
343
|
+
|
|
344
|
+
## Offline acceptance harness
|
|
345
|
+
|
|
346
|
+
`examples/sdk_offline` contains an unchanged source copy of the sibling simple
|
|
347
|
+
example and its saved verified manifest. The sibling application's source and
|
|
348
|
+
configuration are untouched. The demo denies socket connections and uses real
|
|
349
|
+
pinned clients/graphs with HTTPX mock transports and fake Vertex credentials.
|
|
350
|
+
|
|
351
|
+
Each of billing, technical and general, through both sync and async graph entry
|
|
352
|
+
points, asserts this six-span tree (the selected agent varies):
|
|
353
|
+
|
|
354
|
+
```text
|
|
355
|
+
invoke_workflow build_workflow
|
|
356
|
+
invoke_agent triage_agent
|
|
357
|
+
generate_content offline-request-model
|
|
358
|
+
invoke_agent billing_agent | technical_agent | general_agent
|
|
359
|
+
execute_tool lookup_policy
|
|
360
|
+
generate_content offline-request-model
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
All six spans in each run must have IDs in the loaded manifest. Across the three
|
|
364
|
+
branches, the harness observes all ten distinct nodes, including all four model
|
|
365
|
+
sites. It checks the actual tool parent on every run and prints node IDs with the
|
|
366
|
+
tree. This is an observation of the offline runs, not a source coverage estimate.
|
|
367
|
+
Tests additionally exercise true async callbacks/provider calls using a newly
|
|
368
|
+
compiled scanner manifest, automatic tool execution, parallel requests, stale
|
|
369
|
+
loaded code and failure/privacy/lifecycle cases. Tests deny network globally.
|
|
370
|
+
|
|
371
|
+
## Limitations
|
|
372
|
+
|
|
373
|
+
Streaming graph execution has no workflow-lifetime adapter; registered callbacks
|
|
374
|
+
may still emit leaf spans. Google streaming, chats and embeddings are not adapted.
|
|
375
|
+
Provider-driven tools are covered when they are already-loaded, manifest-matched
|
|
376
|
+
Python functions passed to Google; arbitrary callable objects, local tool closures,
|
|
377
|
+
cached pre-init callable references, decorators with replaced code, packaged/zip or
|
|
378
|
+
unavailable source, and other framework/provider versions are not guaranteed.
|
|
379
|
+
Graphs must be constructed after initialization. No whole-program tracing or
|
|
380
|
+
instrumentation of ordinary application functions is performed. Hosted lookup,
|
|
381
|
+
authentication, collectors, other providers, evaluation execution and cross-commit
|
|
382
|
+
reconciliation are outside this milestone.
|