1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//! Live capture hook for recording LLM I/O for later replay (ADR-048).
use crate;
use Arc;
/// Sink the run loop calls once per successful LLM call so a recorder can build
/// a replayable capture. Without a sink the hook is skipped and a run records no
/// LLM I/O — today's behaviour.
///
/// Contract: invoked only on the success path, after post-LLM guardrails pass
/// and before tool dispatch; never on the error path. Implementations must not
/// fail or block the run — buffer in memory and drain after the run completes.
/// Future methods (e.g. tool-call capture) will carry default impls so existing
/// implementors keep compiling.
/// Hands out one [`CaptureSink`] per run.
///
/// A sink buffers calls with no run attribution of its own —
/// `record_llm_call` receives a request and a response, and nothing else — so a
/// sink shared by two runs produces one interleaved buffer that cannot be split
/// again. Whoever drains it then pairs one run's log with another run's calls.
///
/// That is not hypothetical. Sharing one sink across a fan-out shipped in 3.13.0
/// (`AgentContext::child` cloned the parent's sink handle), and the umbrella's
/// own `App` still documents attaching a single App-wide sink to each agent it
/// runs. A provider is the shape that cannot be misused this way: the runtime
/// asks for the sink belonging to a `RunId`, so a child run gets its own by
/// construction.
///
/// Install via [`crate::agent::AgentContextBuilder::capture_sinks`]; every
/// descendant context inherits the provider and mints its own sink from it.