feat(ingest): add Weights & Biases Weave adapter - #121
Conversation
Greptile SummaryThis PR adds
Confidence Score: 5/5Safe to merge — the adapter correctly maps Weave Calls to SpanRecords, the parallel tool-call fix matches the posthog.py reference pattern, and all 11 tests are green and offline. The core logic (op-name classification, JSON/JSONL loading, wrapper unwrapping, error detection, and live pull) is sound and closely mirrors the established posthog.py pattern. The parallel tool-call strategy is correct: returning an empty span list from the LLM Call and letting each child Call produce its own self-contained Step avoids the pairing mismatch documented in the prior review round. The only findings are a speculative 'data' wrapper key with no documented Weave source and no test, and the corresponding missing 'results' wrapper test — neither affects runtime behavior. wmh/ingest/weave.py and wmh/ingest/weave_test.py for the minor wrapper-shape coverage gap noted above. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant F as File or Weave API
participant WA as WeaveAdapter
participant WS as _weave_spans
participant N as normalize
F->>WA: from_file / from_vendor
WA->>WA: _load_payloads (JSON or JSONL)
loop each payload
WA->>WA: "spans_from_payload -> _extract_calls"
loop each Weave Call
WA->>WS: _weave_spans(call, ordinal)
alt tool call
WS-->>WA: execute_tool SpanRecord
else LLM no tool calls
WS-->>WA: chat SpanRecord with completion
else LLM single tool call
WS-->>WA: chat SpanRecord with action
else LLM parallel tool calls
WS-->>WA: empty list, child Calls emit own tool spans
end
end
end
WA->>N: spans_to_traces(all_spans)
N->>N: group by trace_id, sort by start_nano
N->>N: pair LLM spans to following tool spans
N-->>WA: list of Trace
WA-->>F: list of Trace
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant F as File or Weave API
participant WA as WeaveAdapter
participant WS as _weave_spans
participant N as normalize
F->>WA: from_file / from_vendor
WA->>WA: _load_payloads (JSON or JSONL)
loop each payload
WA->>WA: "spans_from_payload -> _extract_calls"
loop each Weave Call
WA->>WS: _weave_spans(call, ordinal)
alt tool call
WS-->>WA: execute_tool SpanRecord
else LLM no tool calls
WS-->>WA: chat SpanRecord with completion
else LLM single tool call
WS-->>WA: chat SpanRecord with action
else LLM parallel tool calls
WS-->>WA: empty list, child Calls emit own tool spans
end
end
end
WA->>N: spans_to_traces(all_spans)
N->>N: group by trace_id, sort by start_nano
N->>N: pair LLM spans to following tool spans
N-->>WA: list of Trace
WA-->>F: list of Trace
Reviews (2): Last reviewed commit: "feat(ingest): add Weights & Biases Weave..." | Re-trigger Greptile |
Add a new ingestion adapter for W&B Weave trace exports. Weave records agent executions as 'Calls' (not OTLP spans), so the adapter maps Call fields (op_name, inputs, output, trace_id) into SpanRecords with OTel GenAI attribute keys for the shared normalizer. - wmh/ingest/weave.py: WeaveAdapter with op-name heuristic classification, JSON/JSONL file loading, and live vendor pull via /calls/stream_query - wmh/ingest/weave_test.py: 11 tests covering parsing, error handling, wrapper shapes, and adapter registration - wmh/ingest/__init__.py: register weave adapter on package import - examples/ingest/weave_to_wmh.sh: usage example script
35cac35 to
0e4c92b
Compare
|
Excellent addition, Weave coverage closes a real gap. Most production agent teams I know are on Weave for tracing, and until now they had to re-export to OTLP or hand-roll a converter. This keeps the ingest surface consistent with the other six adapters. What lands well
area | why it works
-- | --
Op-name heuristic | Weave has no span.kind, so classifying by chat, complete, openai, anthropic in the op name mirrors what we do in posthog.py and avoids a hard dependency on Weave SDK
URI parsing | stripping weave:///entity/project/op/func:hash to human name keeps traces readable in wmh UI
Error detection | checking exception string plus status in ["error","failed"] matches Weave's actual export schema, not OTel status codes
Parallel tool calls | returning empty span list for the LLM Call and letting each child Call emit its own execute_tool Step avoids the action/observation mismatch we hit in PR #116 review. This is the correct pattern
Tests look solid: 11 offline tests covering op-name extraction, LLM heuristics, JSON and JSONL round-trips, error propagation, plain completions, Two small nits before merge
Python
Python Nice-to-have for follow-up
Usage is clean: Bash Safe to merge as-is, confidence 5/5 from Greptile matches my read. This plus PostHog and Langfuse means we now cover ∼90% of the observability stacks I see in the wild. |
Summary
Adds a new ingestion adapter for Weights & Biases Weave trace exports, extending the harness's observability platform coverage alongside the existing Braintrust, Phoenix, Langfuse, LangSmith, Mastra, and PostHog adapters.
Motivation
Weave is a widely adopted LLM observability and evaluation platform. Teams using Weave to trace their agent runs currently have no way to feed those traces into
wmhfor world-model building. This adapter closes that gap — a Weave user can now export their Calls (JSON/JSONL) and runwmh ingest run --source weave --file <export>to build a world model from their production data.Design
Weave records agent executions as Calls (not OTLP spans). Each Call carries an
op_name,inputs,output,trace_id,id,parent_id, and timestamps. Since this is a custom schema (not OpenTelemetry), the adapter follows the same pattern asposthog.py— it overridesspans_from_payloadand emitsSpanRecords using OTel GenAI attribute keys so the shared normalizer handles pairing and state extraction.Key decisions
span.kindtag. Calls are classified as LLM vs tool by checking if the op name contains markers likechat,complete,openai,anthropic, etc. Everything else is treated as a tool execution.weave:///entity/project/op/func_name:hash). The adapter strips the prefix and hash suffix to extract the human-readable function name.exceptionfieldexceptionstring field (not a status code). The adapter checks for a non-emptyexceptionor astatusof"error"/"failed"./calls/stream_queryendpoint (JSONL response). RequiresWANDB_API_KEYand a--project entity/projectargument.Changes
wmh/ingest/weave.pyWeaveAdapter— Call parsing, op-name classification, JSON/JSONL file loading, and live vendor pull via/calls/stream_querywmh/ingest/weave_test.pywmh/ingest/__init__.pyweaveadapter on package importexamples/ingest/weave_to_wmh.shTesting
All tests are offline (file fixtures, no network). The adapter is SDK-free — it parses exported JSON directly and uses
httpxfor vendor pulls (same as PostHog, Langfuse).Usage