Context
When an agent fails in production, a developer needs to look up the right Chronicle trace from product context (user, session, message, feedback). Today Chronicle records a Trace as an ordered set of Envelopes with linear parent_envelope_id linkage and runtime-only ChronicleSession — there is no first-class product attribution surface for filtering, multi-turn message→trace mapping, or true nested agent/waterfall stitching.
Whiteboard framing (growth/design session):
- Indexing for filtering: how does a user look up traces?
- Trace 1:N Envelope; both need dimensions (
Map<string,string>)
- Multi-turn: Session → Messages → each Message drives one agent graph run → one Chronicle
TraceID
- Session→Message mapping is not Chronicle’s job; MessageID→TraceID (and SessionID-only for S2S) is
- Nested agents: child runs (e.g. Researcher) must attribute under the parent tool call / span (Orchestrator), not a flat chain
Problem
-
Lookup / filtering — No stable, queryable dimension taxonomy on Trace (and optionally Envelope). ContextMetadata.extra exists but is unstructured and not an indexing contract. Stores index mainly by trace_id / sequence.
-
Product ID ↔ Chronicle ID — No mandated way to attach:
session_id (mandatory for product correlation)
message_id (optional; multi-turn)
caller_id / caller_type (optional; S2S / cross-agent)
Feedback / “thumbs down at time X” needs MessageID (or SessionID) → TraceID without Chronicle owning the session store.
-
Nested attribution — record_envelope parents to _last_envelope_id (linear chain). _envelope_stack / current_parent_id() exist but are unused for nesting. Parallel / nested tool→sub-agent graphs cannot rebuild a waterfall (TRACE > SPAN > RUN).
Goals
- Define where dimensions live (Trace-level vs Envelope-level) and a minimal schema for product correlation.
- Define the attribution contract:
- Multi-turn:
session_id + message_id → one trace_id per message turn
- S2S / single-shot:
session_id (and optional caller fields) alone
- Stitch child envelopes to true parents so nested agent runs attribute under the invoking tool/LLM boundary (waterfall-ready graph).
- Keep Chronicle a record/replay library — not a full tracing UI — but make production lookup and OTel/export nesting sound.
Non-goals
- Owning Session↔Message storage or chat history
- Building a full observability dashboard
- Changing Layer-2 judge rubrics / feedback semantics
Proposed direction (open for debate)
-
Dimensions
- Trace-level:
session_id (required when set by caller), optional message_id, caller_id, caller_type, plus free-form dimensions
- Envelope-level: optional override/tags for filtering within a run
- Pass via
record() / session begin args (and/or first envelope), not inferred from chat state
-
Parent stitching
- Use nest stack (
_push_envelope / _pop_envelope) so parent_envelope_id = current_parent_id() instead of last-written
- Document parallel-tool semantics (multiple children under one parent)
-
Lookup POC
- Store/API: filter traces by
session_id and/or message_id (+ dimensions)
- Document “tightly coupled feedback → resolve MessageID → TraceID”
Acceptance criteria
Related
Context
When an agent fails in production, a developer needs to look up the right Chronicle trace from product context (user, session, message, feedback). Today Chronicle records a Trace as an ordered set of Envelopes with linear
parent_envelope_idlinkage and runtime-onlyChronicleSession— there is no first-class product attribution surface for filtering, multi-turn message→trace mapping, or true nested agent/waterfall stitching.Whiteboard framing (growth/design session):
Map<string,string>)TraceIDProblem
Lookup / filtering — No stable, queryable dimension taxonomy on Trace (and optionally Envelope).
ContextMetadata.extraexists but is unstructured and not an indexing contract. Stores index mainly bytrace_id/sequence.Product ID ↔ Chronicle ID — No mandated way to attach:
session_id(mandatory for product correlation)message_id(optional; multi-turn)caller_id/caller_type(optional; S2S / cross-agent)Feedback / “thumbs down at time X” needs MessageID (or SessionID) → TraceID without Chronicle owning the session store.
Nested attribution —
record_envelopeparents to_last_envelope_id(linear chain)._envelope_stack/current_parent_id()exist but are unused for nesting. Parallel / nested tool→sub-agent graphs cannot rebuild a waterfall (TRACE > SPAN > RUN).Goals
session_id+message_id→ onetrace_idper message turnsession_id(and optional caller fields) aloneNon-goals
Proposed direction (open for debate)
Dimensions
session_id(required when set by caller), optionalmessage_id,caller_id,caller_type, plus free-formdimensionsrecord()/ session begin args (and/or first envelope), not inferred from chat stateParent stitching
_push_envelope/_pop_envelope) soparent_envelope_id = current_parent_id()instead of last-writtenLookup POC
session_idand/ormessage_id(+ dimensions)Acceptance criteria
session_id/message_idat record time; query by themRelated
chronicle/session.py(_last_envelope_idvs unused_envelope_stack)chronicle/envelope/schema.py(ContextMetadata,parent_envelope_id)chronicle/execution_graph.py,chronicle/otel.py