Skip to main content

tapes_client/core/models/
span.rs

1//! Span shapes: the observed units of work and their edges.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use super::ContractModel;
7
8/// One observed unit of work. Every field is a deriver output, formatting-
9/// only: the harness-taxonomy fields (call_kind, model, stop_reason,
10/// thread_id, verdict) are typed rather than bagged in a metadata map, and
11/// input/output are uniform content-block arrays for ALL kinds — the console
12/// owns per-kind rendering.
13///
14/// Models the contract's `SpanItem` schema.
15#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
16#[serde(default)]
17#[non_exhaustive]
18pub struct SpanItem {
19    /// Deriver-written taxonomy, promoted from the old metadata grab-bag.
20    pub call_kind: String,
21
22    /// The contract's `duration_ns`.
23    pub duration_ns: i64,
24
25    /// Input/Output are content-block arrays (llm.ContentBlock), uniform for
26    /// every kind (tool spans included — no unwrapping).
27    #[serde(deserialize_with = "super::null_default")]
28    pub input: Vec<Value>,
29
30    /// The contract's `kind`.
31    pub kind: String,
32
33    /// The contract's `model`.
34    pub model: String,
35
36    /// The contract's `name`.
37    pub name: String,
38
39    /// The contract's `output`.
40    #[serde(deserialize_with = "super::null_default")]
41    pub output: Vec<Value>,
42
43    /// The contract's `parent_span_id`.
44    pub parent_span_id: String,
45
46    /// Payload marks a preview-truncated span so the console drills in for
47    /// the full payload; absent in full mode.
48    pub payload: String,
49
50    /// The contract's `raw_turn_id`.
51    pub raw_turn_id: i64,
52
53    /// The span's presentation ordinal within its trace; spans arrive sorted
54    /// by it (started_at ties inside one llm call — parallel tool batches
55    /// share an instant).
56    pub seq: i64,
57
58    /// The contract's `span_id`.
59    pub span_id: String,
60
61    /// The contract's `started_at`, an RFC 3339 timestamp.
62    pub started_at: String,
63
64    /// The contract's `status`.
65    pub status: String,
66
67    /// The contract's `stop_reason`.
68    pub stop_reason: String,
69
70    /// The contract's `thread_id`.
71    pub thread_id: String,
72
73    /// The contract's `trace_id`.
74    pub trace_id: String,
75
76    /// Usage (was `metrics`) is an llm.Usage object on the wire — {}-pinned
77    /// for usage-less spans.
78    pub usage: Value,
79
80    /// The typed security-monitor disposition (null off permission-check
81    /// spans), deriver-written.
82    pub verdict: Option<Value>,
83}
84
85impl ContractModel for SpanItem {
86    const SCHEMA: &'static str = "SpanItem";
87}
88
89/// A dataflow edge. kind is a typed top-level field (rejoin / verdict /
90/// compaction-seam / emits / feeds); from/to trace ids differ on cross-trace
91/// causality.
92///
93/// Models the contract's `SpanLinkItem` schema.
94#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
95#[serde(default)]
96#[non_exhaustive]
97pub struct SpanLinkItem {
98    /// The contract's `from_io`.
99    pub from_io: String,
100
101    /// The contract's `from_span_id`.
102    pub from_span_id: String,
103
104    /// The contract's `from_trace_id`.
105    pub from_trace_id: String,
106
107    /// The contract's `kind`.
108    pub kind: String,
109
110    /// The contract's `to_io`.
111    pub to_io: String,
112
113    /// The contract's `to_span_id`.
114    pub to_span_id: String,
115
116    /// The contract's `to_trace_id`.
117    pub to_trace_id: String,
118}
119
120impl ContractModel for SpanLinkItem {
121    const SCHEMA: &'static str = "SpanLinkItem";
122}