From bb5c50f9ab0318dc118ce9c3099b7559e0d0e512 Mon Sep 17 00:00:00 2001 From: Hare Date: Tue, 20 Oct 2026 02:44:28 +0900 Subject: [PATCH] feat: persist System input policies through public consumers --- crates/protocol/src/lib.rs | 14 ++ crates/session-store/src/fs_store.rs | 4 + crates/session-store/src/history.rs | 192 +++++++++++++++ .../session-store/src/legacy_session_log.rs | 1 + .../src/legacy_session_log/tests.rs | 1 + crates/session-store/src/public_index.rs | 2 + crates/session-store/src/public_material.rs | 119 +++++++-- .../src/public_material/tests.rs | 164 +++++++++++++ crates/session-store/src/public_snapshot.rs | 55 ++++- .../src/public_snapshot/run_stats.rs | 1 + crates/session-store/src/segment_log.rs | 18 ++ crates/session-store/src/store.rs | 3 + crates/session-store/src/system_input.rs | 21 ++ crates/session-store/src/system_item.rs | 11 +- .../session-store/src/worker_session_store.rs | 5 + crates/session-store/tests/fs_store_test.rs | 176 ++++++++++++++ crates/session-store/tests/session_test.rs | 1 + .../standalone/src/subjektiv/journal/tests.rs | 1 + crates/standalone/src/subjektiv_sessions.rs | 1 + crates/tui/src/app.rs | 2 + .../tests/session_material_tests.rs | 1 + crates/worker-runtime/src/retention.rs | 2 + crates/worker-runtime/src/runtime.rs | 1 + crates/worker-runtime/src/session_public.rs | 1 + crates/worker-runtime/src/worker_backend.rs | 1 + .../src/feature/builtin/session_explore.rs | 2 +- .../src/feature/builtin/worker_observation.rs | 1 + crates/worker/src/internal_worker.rs | 1 + crates/worker/src/ipc/protocol_session.rs | 3 +- crates/worker/src/session_capture.rs | 227 +++++++++++++++--- crates/worker/src/session_history.rs | 4 + crates/worker/src/spawn/comm_tools.rs | 1 + crates/worker/src/spawn/registry.rs | 1 + crates/worker/src/wip.rs | 1 + crates/worker/tests/compact_events_test.rs | 1 + crates/workspace-server/src/server.rs | 2 + .../server/tests/subjektiv_journal_tests.rs | 2 + .../tests/subjektiv_memory_journal_tests.rs | 1 + .../src/lib/generated/protocol-validator.ts | 2 +- web/workspace/src/lib/generated/protocol.ts | 2 +- 40 files changed, 988 insertions(+), 61 deletions(-) diff --git a/crates/protocol/src/lib.rs b/crates/protocol/src/lib.rs index 8055193d5..8be8c3d9a 100644 --- a/crates/protocol/src/lib.rs +++ b/crates/protocol/src/lib.rs @@ -982,6 +982,17 @@ pub enum SessionEntryProvenance { LegacyUnknown, } +/// Public use decisions contain no Feature identity or private payload. Absence +/// denotes the older projection contract, not permission to expose System input. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] +#[serde(deny_unknown_fields)] +pub struct SessionEntryUsePolicy { + pub observation_readable: bool, + pub memory_evidence: bool, +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[cfg_attr(feature = "typescript", derive(ts_rs::TS))] #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] @@ -994,6 +1005,8 @@ pub struct SessionSnapshotEntry { pub provenance: SessionEntryProvenance, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub derived_from: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub use_policy: Option, #[serde(flatten)] pub data: SessionSnapshotEntryData, } @@ -2619,6 +2632,7 @@ mod tests { session: SessionSnapshot { pending_submissions: PendingSubmissionsSnapshot::default(), entries: vec![SessionSnapshotEntry { + use_policy: None, entry_id: "entry-1".into(), timestamp: 1, provenance: SessionEntryProvenance::HumanInput, diff --git a/crates/session-store/src/fs_store.rs b/crates/session-store/src/fs_store.rs index b6cade6b5..aa9988e8f 100644 --- a/crates/session-store/src/fs_store.rs +++ b/crates/session-store/src/fs_store.rs @@ -361,6 +361,7 @@ impl Store for FsStore { segment_id: SegmentId, entry: &LogEntry, ) -> Result<(), StoreError> { + entry.validate_system_inputs()?; let _retention = self.retention().lock_live(session_id)?; let line = serde_json::to_string(entry)?; self.append_line(&self.log_path(session_id, segment_id), &line) @@ -448,6 +449,9 @@ impl Store for FsStore { segment_id: SegmentId, entries: &[LogEntry], ) -> Result<(), StoreError> { + for entry in entries { + entry.validate_system_inputs()?; + } let _retention = self.retention().lock_live(session_id)?; let path = self.log_path(session_id, segment_id); if let Some(parent) = path.parent() { diff --git a/crates/session-store/src/history.rs b/crates/session-store/src/history.rs index 4997a3b83..f25617b1d 100644 --- a/crates/session-store/src/history.rs +++ b/crates/session-store/src/history.rs @@ -67,6 +67,10 @@ pub enum LoggedSessionHistoryOrigin { ToolOutput { worker: LoggedWorkerSubject, }, + /// Descriptive producer identity; use policies live in separate metadata. + Provided { + producer: String, + }, /// Host-produced opening context summary; not auto-read or TaskStore material. CompactionSummary, /// Frozen Host Journal reference, never independent observation evidence. @@ -86,14 +90,26 @@ pub struct LoggedSessionHistoryMetadata { pub origin: LoggedSessionHistoryOrigin, #[serde(default, skip_serializing_if = "Option::is_none")] pub derivation: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub system_input: Option, } impl LoggedSessionHistoryMetadata { + fn validate_system_input(&self) -> Result<(), crate::SystemInputError> { + if matches!(self.origin, LoggedSessionHistoryOrigin::Provided { .. }) + && self.system_input.is_none() + { + return Err(crate::SystemInputError::MissingMetadata); + } + Ok(()) + } + pub fn legacy_unknown() -> Self { Self { entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, + system_input: None, } } } @@ -101,20 +117,140 @@ impl LoggedSessionHistoryMetadata { /// Persisted item and metadata are one value so transforms cannot reorder or /// truncate one without the other. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(try_from = "HistoryEntryWire")] pub struct LoggedHistoryEntry { pub item: LoggedItem, pub metadata: LoggedSessionHistoryMetadata, } +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct HistoryEntryWire { + item: LoggedItem, + metadata: LoggedSessionHistoryMetadata, +} + +impl TryFrom for LoggedHistoryEntry { + type Error = crate::SystemInputError; + + fn try_from(wire: HistoryEntryWire) -> Result { + let entry = Self { + item: wire.item, + metadata: wire.metadata, + }; + entry.validate_system_input()?; + Ok(entry) + } +} + +impl LoggedHistoryEntry { + pub fn validate_system_input(&self) -> Result<(), crate::SystemInputError> { + self.metadata.validate_system_input()?; + if self.metadata.system_input.is_some() { + let LoggedItem::Message { + role: crate::LoggedRole::System, + content, + } = &self.item + else { + return Err(crate::SystemInputError::InconsistentRecord); + }; + let [crate::LoggedContentPart::Text { text }] = content.as_slice() else { + return Err(crate::SystemInputError::InconsistentRecord); + }; + if text.len() > crate::system_input::MAX_SYSTEM_INPUT_BYTES { + return Err(crate::SystemInputError::ResourceLimit); + } + } + Ok(()) + } +} + /// Typed system-item history record. The typed system event remains available /// to client replay while its model-visible projection carries the same stable /// metadata used by live history. #[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(try_from = "SystemEntryWire")] pub struct LoggedSystemHistoryEntry { pub item: crate::SystemItem, pub metadata: LoggedSessionHistoryMetadata, } +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct SystemEntryWire { + item: crate::SystemItem, + metadata: LoggedSessionHistoryMetadata, +} + +impl TryFrom for LoggedSystemHistoryEntry { + type Error = crate::SystemInputError; + + fn try_from(wire: SystemEntryWire) -> Result { + let entry = Self { + item: wire.item, + metadata: wire.metadata, + }; + entry.validate_system_input()?; + Ok(entry) + } +} + +impl LoggedSystemHistoryEntry { + pub fn from_input( + origin: LoggedSessionHistoryOrigin, + derivation: Option, + input: crate::SystemInputEnvelope, + ) -> Self { + let (body, system_input) = input.into_parts(); + Self { + item: crate::SystemItem::Input { body }, + metadata: LoggedSessionHistoryMetadata { + entry_id: LoggedSessionHistoryEntryId::new(), + origin, + derivation, + system_input: Some(system_input), + }, + } + } + + pub fn validate_system_input(&self) -> Result<(), crate::SystemInputError> { + self.metadata.validate_system_input()?; + match (&self.item, &self.metadata.system_input) { + (crate::SystemItem::Input { body }, Some(_)) => { + if body.len() > crate::system_input::MAX_SYSTEM_INPUT_BYTES { + return Err(crate::SystemInputError::ResourceLimit); + } + } + (crate::SystemItem::Input { .. }, None) => { + return Err(crate::SystemInputError::MissingMetadata); + } + (_, Some(_)) => return Err(crate::SystemInputError::InconsistentRecord), + (_, None) => {} + } + Ok(()) + } + + pub fn to_history_entry(&self) -> LoggedHistoryEntry { + LoggedHistoryEntry { + item: self.item.to_history_item().into(), + metadata: self.metadata.clone(), + } + } + + pub fn public_item(&self) -> crate::PublicSystemItem { + if matches!(self.item, crate::SystemItem::Input { .. }) { + return self + .metadata + .system_input + .as_ref() + .and_then(crate::SystemInputMetadata::public_item) + .cloned() + .unwrap_or_else(|| self.item.public_item()); + } + self.item.public_item() + } +} + #[cfg(test)] mod tests { use super::*; @@ -132,6 +268,7 @@ mod tests { }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::HumanInput { account_id: "account-1".into(), @@ -150,6 +287,61 @@ mod tests { ); } + #[test] + fn external_system_records_reject_missing_policy_role_mismatch_and_overlimit_body() { + let valid = serde_json::json!({ + "item": { "kind": "input", "body": "context" }, + "metadata": { + "entry_id": "stable-entry", "origin": { "kind": "provided", "producer": "owner" }, + "system_input": { "usage": { + "recording_material": "exclude", "memory_evidence": "exclude", + "observation": "hidden", "compaction": "reference_input" + } } + } + }); + let restored: LoggedSystemHistoryEntry = serde_json::from_value(valid.clone()).unwrap(); + let flat = serde_json::to_value(restored.to_history_entry()).unwrap(); + assert!(serde_json::from_value::(flat.clone()).is_ok()); + for generic in [true, false] { + let wire = if generic { &valid } else { &flat }; + let decode = |wire| { + if generic { + serde_json::from_value::(wire).is_err() + } else { + serde_json::from_value::(wire).is_err() + } + }; + let mut missing = wire.clone(); + missing["metadata"] + .as_object_mut() + .unwrap() + .remove("system_input"); + assert!(decode(missing)); + let mut absent_policy = wire.clone(); + absent_policy["metadata"]["system_input"] + .as_object_mut() + .unwrap() + .remove("usage"); + assert!(decode(absent_policy)); + let mut invalid_role = wire.clone(); + invalid_role["item"] = + serde_json::to_value(LoggedItem::from(agen::Item::user_message("not system"))) + .unwrap(); + assert!(decode(invalid_role)); + let mut oversized = wire.clone(); + if generic { + oversized["item"]["body"] = "x" + .repeat(crate::system_input::MAX_SYSTEM_INPUT_BYTES + 1) + .into(); + } else { + oversized["item"]["content"][0]["text"] = "x" + .repeat(crate::system_input::MAX_SYSTEM_INPUT_BYTES + 1) + .into(); + } + assert!(decode(oversized)); + } + } + #[test] fn annotated_segment_start_is_restore_visible_without_projecting_metadata() { let session_id = uuid::Uuid::now_v7(); diff --git a/crates/session-store/src/legacy_session_log.rs b/crates/session-store/src/legacy_session_log.rs index 5c465d0b9..987a53984 100644 --- a/crates/session-store/src/legacy_session_log.rs +++ b/crates/session-store/src/legacy_session_log.rs @@ -167,6 +167,7 @@ fn legacy_metadata( identity.extend_from_slice(&(line_index as u64).to_be_bytes()); identity.extend_from_slice(&(item_index as u64).to_be_bytes()); LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(format!( "l-{}", base64::Engine::encode(&base64::engine::general_purpose::URL_SAFE_NO_PAD, identity) diff --git a/crates/session-store/src/legacy_session_log/tests.rs b/crates/session-store/src/legacy_session_log/tests.rs index 3c72462c5..314ee6d5f 100644 --- a/crates/session-store/src/legacy_session_log/tests.rs +++ b/crates/session-store/src/legacy_session_log/tests.rs @@ -22,6 +22,7 @@ fn seed( content: vec![crate::LoggedContentPart::Text { text: text.into() }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId("summary".into()), origin, derivation: Some(crate::LoggedHistoryDerivation { diff --git a/crates/session-store/src/public_index.rs b/crates/session-store/src/public_index.rs index 24932e397..cba29bc87 100644 --- a/crates/session-store/src/public_index.rs +++ b/crates/session-store/src/public_index.rs @@ -1296,6 +1296,7 @@ mod tests { LoggedHistoryEntry { item, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(id.to_owned()), origin, derivation: None, @@ -1537,6 +1538,7 @@ mod tests { prompt_provenance: None, }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId("system-item".into()), origin: LoggedSessionHistoryOrigin::BackendInstruction { operation_id: None, diff --git a/crates/session-store/src/public_material.rs b/crates/session-store/src/public_material.rs index 6487bdade..f27795928 100644 --- a/crates/session-store/src/public_material.rs +++ b/crates/session-store/src/public_material.rs @@ -148,15 +148,24 @@ struct SegmentHeader { file_len: u64, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PublicMaterialUse { + Recording, + MemoryEvidence, +} + /// A fixed material catalog. Opening a new catalog observes newly appended /// records; reading a body through this catalog verifies its saved digest and /// byte length again. Missing/corrected/deleted sources are explicit failures. +/// Explicit evidence permission applies to model text, not the private payload; +/// Web display and observation instead use the producer's public projection. pub struct SessionPublicMaterialReader { session_id: SessionId, active_segment_id: SegmentId, layout: Layout, limits: PublicMaterialLimits, materials: Vec, + purpose: PublicMaterialUse, retention: Option, } @@ -180,7 +189,13 @@ impl SessionPublicMaterialReader { active_segment_id: SegmentId, limits: PublicMaterialLimits, ) -> Result { - Self::open_worker_guarded(session_root, active_segment_id, limits, None) + Self::open_worker_guarded( + session_root, + active_segment_id, + limits, + None, + PublicMaterialUse::Recording, + ) } /// Uses the Host's aggregate-external control root for the whole scan and every body read. @@ -191,7 +206,30 @@ impl SessionPublicMaterialReader { limits: PublicMaterialLimits, retention: crate::retention::SessionRetentionStore, ) -> Result { - Self::open_worker_guarded(session_root, active_segment_id, limits, Some(retention)) + Self::open_worker_for_use( + session_root, + active_segment_id, + limits, + retention, + PublicMaterialUse::Recording, + ) + } + + /// Selects the evidence purpose independently of public display and observation. + pub fn open_worker_for_use( + session_root: &Path, + active_segment_id: SegmentId, + limits: PublicMaterialLimits, + retention: crate::retention::SessionRetentionStore, + purpose: PublicMaterialUse, + ) -> Result { + Self::open_worker_guarded( + session_root, + active_segment_id, + limits, + Some(retention), + purpose, + ) } fn open_worker_guarded( @@ -199,6 +237,7 @@ impl SessionPublicMaterialReader { active_segment_id: SegmentId, limits: PublicMaterialLimits, retention: Option, + purpose: PublicMaterialUse, ) -> Result { let store = WorkerSessionStore::open_read_only(session_root) .map_err(|_| PublicMaterialError::Unavailable)?; @@ -212,6 +251,7 @@ impl SessionPublicMaterialReader { Layout::Worker(session_root.into()), limits, retention, + purpose, ) } @@ -237,6 +277,25 @@ impl SessionPublicMaterialReader { active_segment_id: SegmentId, limits: PublicMaterialLimits, retention: crate::retention::SessionRetentionStore, + ) -> Result { + Self::open_fs_for_use( + sessions_root, + session_id, + active_segment_id, + limits, + retention, + PublicMaterialUse::Recording, + ) + } + + /// Uses retained originals with the independently selected evidence policy. + pub fn open_fs_for_use( + sessions_root: &Path, + session_id: SessionId, + active_segment_id: SegmentId, + limits: PublicMaterialLimits, + retention: crate::retention::SessionRetentionStore, + purpose: PublicMaterialUse, ) -> Result { Self::open( session_id, @@ -244,6 +303,7 @@ impl SessionPublicMaterialReader { Layout::Fs(sessions_root.join(session_id.to_string())), limits, Some(retention), + purpose, ) } @@ -263,6 +323,7 @@ impl SessionPublicMaterialReader { layout: Layout, limits: PublicMaterialLimits, retention: Option, + purpose: PublicMaterialUse, ) -> Result { let _guard = retention .as_ref() @@ -435,23 +496,19 @@ impl SessionPublicMaterialReader { } => turn = *total_turn_count, _ => {} } + let system_history; let entries: &[LoggedHistoryEntry] = match &record { LogEntry::AnnotatedSegmentStart { history, .. } | LogEntry::AnnotatedUserInput { history, .. } => history, LogEntry::AnnotatedAssistantItem { entry, .. } | LogEntry::AnnotatedToolResult { entry, .. } | LogEntry::ToolResultCorrected { entry, .. } => std::slice::from_ref(entry), + LogEntry::AnnotatedSystemItem { entry, .. } => { + system_history = entry.to_history_entry(); + std::slice::from_ref(&system_history) + } _ => &[], }; - if let LogEntry::AnnotatedSystemItem { entry, .. } = &record { - charge(&mut examined, limits.max_entries)?; - if entry.metadata.entry_id.0.is_empty() - || !history_seen.insert(entry.metadata.entry_id.0.clone()) - { - return Err(PublicMaterialError::Inconsistent); - } - history_ids.push(entry.metadata.entry_id.0.clone()); - } for (history_index, entry) in entries.iter().enumerate() { charge(&mut examined, limits.max_entries)?; let id = &entry.metadata.entry_id.0; @@ -468,7 +525,7 @@ impl SessionPublicMaterialReader { if in_run && ai_materialized(&entry.item) { safe = true; } - let Some((sha256, total_bytes)) = canonical_metadata(entry)? else { + let Some((sha256, total_bytes)) = canonical_metadata(entry, purpose)? else { continue; }; let location = Location { @@ -621,6 +678,7 @@ impl SessionPublicMaterialReader { layout, limits, materials, + purpose, retention: retention.clone(), }) } @@ -660,6 +718,7 @@ impl SessionPublicMaterialReader { let Some((_, record)) = reader.next()? else { return Err(PublicMaterialError::Missing); }; + let system_history; let (body, origin) = if let Some(boundary) = run_boundary(&record) { if boundary_reference( &record, @@ -683,12 +742,16 @@ impl SessionPublicMaterialReader { LogEntry::AnnotatedAssistantItem { entry, .. } | LogEntry::AnnotatedToolResult { entry, .. } | LogEntry::ToolResultCorrected { entry, .. } => Some(entry), + LogEntry::AnnotatedSystemItem { entry, .. } => { + system_history = entry.to_history_entry(); + Some(&system_history) + } _ => None, } .filter(|e| format!("E{}", e.metadata.entry_id.0) == descriptor.identity.entry_ref) .ok_or(PublicMaterialError::Changed)?; ( - canonical_body(entry).ok_or(PublicMaterialError::Changed)?, + canonical_body(entry, self.purpose).ok_or(PublicMaterialError::Changed)?, PublicMaterialOrigin::History { origin: entry.metadata.origin.clone(), }, @@ -828,7 +891,32 @@ fn boundary_reference( .unwrap_or_else(|| format!("El-run-{session}-{segment}-{offset}")) } -fn canonical_body(entry: &LoggedHistoryEntry) -> Option> { +fn canonical_body( + entry: &LoggedHistoryEntry, + purpose: PublicMaterialUse, +) -> Option> { + if let Some(input) = &entry.metadata.system_input { + let usage = input.usage(); + let allowed = match purpose { + PublicMaterialUse::Recording => usage.recording_material, + PublicMaterialUse::MemoryEvidence => usage.memory_evidence, + }; + if allowed == crate::InputEvidenceUse::Exclude { + return None; + } + if let LoggedItem::Message { + role: LoggedRole::System, + content, + } = &entry.item + { + return Some(CanonicalBody::Message { + origin: &entry.metadata.origin, + role: LoggedRole::System, + content, + }); + } + return None; + } if matches!( entry.metadata.origin, LoggedSessionHistoryOrigin::DerivedSummary @@ -880,8 +968,9 @@ fn canonical_body(entry: &LoggedHistoryEntry) -> Option> { fn canonical_metadata( entry: &LoggedHistoryEntry, + purpose: PublicMaterialUse, ) -> Result, PublicMaterialError> { - let Some(body) = canonical_body(entry) else { + let Some(body) = canonical_body(entry, purpose) else { return Ok(None); }; let mut sink = BodySink::new(0, 0); diff --git a/crates/session-store/src/public_material/tests.rs b/crates/session-store/src/public_material/tests.rs index b77642840..0376af0bc 100644 --- a/crates/session-store/src/public_material/tests.rs +++ b/crates/session-store/src/public_material/tests.rs @@ -9,6 +9,7 @@ fn entry(id: &str, item: LoggedItem) -> LoggedHistoryEntry { LoggedHistoryEntry { item, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(id.into()), origin: LoggedSessionHistoryOrigin::LocalHumanInput, derivation: None, @@ -591,6 +592,7 @@ fn reasoning_proves_rollback_safety_but_private_and_derived_items_are_not_materi }, }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId("startup-journal".into()), origin: LoggedSessionHistoryOrigin::DerivedSummary, derivation: None, @@ -1243,3 +1245,165 @@ fn compaction_without_exact_derivation_or_with_invalid_turn_is_rejected() { )); } } + +#[test] +fn generic_system_material_uses_explicit_evidence_purpose_not_producer_or_body() { + use crate::{ + FeatureInputPayload, InputCompactionUse, InputEvidenceUse, InputObservationUse, + LoggedSystemHistoryEntry, SystemInputEnvelope, SystemInputMetadata, SystemInputUsePolicy, + }; + for worker_layout in [false, true] { + let temp = tempfile::tempdir().unwrap(); + let session = crate::new_session_id(); + let segment = crate::new_segment_id(); + let fork = crate::new_segment_id(); + let make = |producer: &str, recording_material, memory_evidence, body: &str| { + LoggedSystemHistoryEntry::from_input( + LoggedSessionHistoryOrigin::Provided { + producer: producer.into(), + }, + None, + SystemInputEnvelope::new( + body, + SystemInputMetadata::new( + SystemInputUsePolicy { + recording_material, + memory_evidence, + observation: InputObservationUse::Hidden, + compaction: InputCompactionUse::Retain, + }, + Some( + FeatureInputPayload::encode( + "unknown:future", + 99, + &serde_json::json!({"private": "not-public"}), + ) + .unwrap(), + ), + None, + ) + .unwrap(), + ) + .unwrap(), + ) + }; + let inputs = [ + make( + "same-owner", + InputEvidenceUse::Include, + InputEvidenceUse::Exclude, + "do not extract this; original material", + ), + make( + "same-owner", + InputEvidenceUse::Exclude, + InputEvidenceUse::Include, + "memory-only original", + ), + make( + "renamed-owner", + InputEvidenceUse::Exclude, + InputEvidenceUse::Exclude, + "reference without warning text", + ), + ]; + let root = if worker_layout { + temp.path().join("worker") + } else { + temp.path().join(session.to_string()) + }; + let store: Box = if worker_layout { + Box::new(WorkerSessionStore::new(&root).unwrap()) + } else { + Box::new(FsStore::new(temp.path()).unwrap()) + }; + store + .create_segment(session, segment, &[seed(session, vec![])]) + .unwrap(); + for entry in &inputs { + store + .append( + session, + segment, + &LogEntry::AnnotatedSystemItem { + ts: 2, + entry: entry.clone(), + extensions: vec![], + }, + ) + .unwrap(); + } + store + .append( + session, + segment, + &LogEntry::TurnEnd { + ts: 3, + turn_count: 1, + }, + ) + .unwrap(); + let mut fork_seed = seed( + session, + inputs + .iter() + .map(LoggedSystemHistoryEntry::to_history_entry) + .collect(), + ); + if let LogEntry::AnnotatedSegmentStart { forked_from, .. } = &mut fork_seed { + *forked_from = Some(crate::SegmentOrigin { + segment_id: segment, + at_turn_index: 1, + }); + } + store.create_segment(session, fork, &[fork_seed]).unwrap(); + let open = |active, purpose| { + if worker_layout { + SessionPublicMaterialReader::open_worker_for_use( + &root, + active, + Default::default(), + crate::retention::fs_retention(temp.path()), + purpose, + ) + .unwrap() + } else { + SessionPublicMaterialReader::open_fs_for_use( + temp.path(), + session, + active, + Default::default(), + crate::retention::fs_retention(temp.path()), + purpose, + ) + .unwrap() + } + }; + for (purpose, selected, expected_text) in [ + ( + PublicMaterialUse::Recording, + 0, + "do not extract this; original material", + ), + (PublicMaterialUse::MemoryEvidence, 1, "memory-only original"), + ] { + let original = open(segment, purpose); + let inherited = open(fork, purpose); + assert_eq!( + ids(&original), + vec![format!("E{}", inputs[selected].metadata.entry_id.0)] + ); + assert_eq!(ids(&inherited), ids(&original)); + let descriptor = inherited.descriptors().next().unwrap(); + let body = inherited + .read_content(descriptor, 0, 16 * 1024) + .unwrap() + .content; + let value: serde_json::Value = serde_json::from_str(&body).unwrap(); + assert_eq!(value["role"], "system"); + assert_eq!(value["content"][0]["text"], expected_text); + assert!(!body.contains("not-public")); + assert!(!body.contains("unknown:future")); + } + } +} diff --git a/crates/session-store/src/public_snapshot.rs b/crates/session-store/src/public_snapshot.rs index 6a1d94b0e..1baa121c8 100644 --- a/crates/session-store/src/public_snapshot.rs +++ b/crates/session-store/src/public_snapshot.rs @@ -27,7 +27,7 @@ use thiserror::Error; use crate::{ LogEntry, LoggedContentPart, LoggedHistoryEntry, LoggedItem, LoggedRole, - LoggedSessionHistoryOrigin, SegmentId, SegmentOrigin, SessionId, StoreError, SystemItem, + LoggedSessionHistoryOrigin, SegmentId, SegmentOrigin, SessionId, StoreError, WorkerAggregateStore, WorkerSessionStore, WorkerStoreError, }; @@ -1165,7 +1165,7 @@ fn capture_tool_correction( let LogEntry::ToolResultCorrected { entry, .. } = record else { return false; }; - if let Some(data) = project_item(&entry.metadata.entry_id.0, &entry.item) { + if let Some(data) = project_history_item(entry) { // We read backwards: the first correction seen is the latest one. corrections .entry(entry.metadata.entry_id.0.clone()) @@ -1600,12 +1600,12 @@ pub(crate) fn project_session_snapshot_for_segment( } => extend_history(&mut entries, history, Some(segments), *ts), LogEntry::AnnotatedAssistantItem { ts, entry } | LogEntry::AnnotatedToolResult { ts, entry } => { - if let Some(data) = project_item(&entry.metadata.entry_id.0, &entry.item) { + if let Some(data) = project_history_item(entry) { entries.push(history_entry(entry, *ts, data)); } } LogEntry::ToolResultCorrected { ts, entry } => { - if let Some(data) = project_item(&entry.metadata.entry_id.0, &entry.item) { + if let Some(data) = project_history_item(entry) { if let Some(existing) = entries .iter_mut() .find(|existing| existing.entry_id == entry.metadata.entry_id.0) @@ -1618,11 +1618,16 @@ pub(crate) fn project_session_snapshot_for_segment( } } LogEntry::AnnotatedSystemItem { ts, entry, .. } => entries.push(system_entry( - &entry.item, + &entry.public_item(), entry.metadata.entry_id.0.clone(), *ts, provenance(&entry.metadata.origin), derivation_ids(entry), + entry + .metadata + .system_input + .as_ref() + .map(crate::SystemInputMetadata::public_use_policy), )), LogEntry::RunYielded { ts, @@ -1775,7 +1780,7 @@ fn extend_history( segments: input_segments.cloned().unwrap_or_default(), } } else { - let Some(data) = project_item(&entry.metadata.entry_id.0, &entry.item) else { + let Some(data) = project_history_item(entry) else { continue; }; data @@ -1790,6 +1795,11 @@ fn history_entry( data: SessionSnapshotEntryData, ) -> SessionSnapshotEntry { SessionSnapshotEntry { + use_policy: entry + .metadata + .system_input + .as_ref() + .map(crate::SystemInputMetadata::public_use_policy), entry_id: entry.metadata.entry_id.0.clone(), timestamp, provenance: provenance(&entry.metadata.origin), @@ -1833,6 +1843,7 @@ fn run_transition_entry( data: SessionSnapshotEntryData, ) -> SessionSnapshotEntry { SessionSnapshotEntry { + use_policy: None, entry_id: persisted_entry_id .map(|entry_id| entry_id.0.clone()) .unwrap_or_else(|| legacy_entry_id(session_key, segment_id, log_index, 0)), @@ -1852,6 +1863,7 @@ fn legacy_entry( data: SessionSnapshotEntryData, ) -> SessionSnapshotEntry { SessionSnapshotEntry { + use_policy: None, entry_id: legacy_entry_id(session_key, segment_id, log_index, item_index), timestamp, provenance: SessionEntryProvenance::LegacyUnknown, @@ -1884,9 +1896,8 @@ fn provenance(origin: &LoggedSessionHistoryOrigin) -> SessionEntryProvenance { LoggedSessionHistoryOrigin::FlowInstruction { .. } => { SessionEntryProvenance::FlowInstruction } - LoggedSessionHistoryOrigin::BackendInstruction { .. } => { - SessionEntryProvenance::BackendInstruction - } + LoggedSessionHistoryOrigin::BackendInstruction { .. } + | LoggedSessionHistoryOrigin::Provided { .. } => SessionEntryProvenance::BackendInstruction, LoggedSessionHistoryOrigin::ModelOutput { .. } => SessionEntryProvenance::ModelOutput, LoggedSessionHistoryOrigin::ToolOutput { .. } => SessionEntryProvenance::ToolOutput, LoggedSessionHistoryOrigin::CompactionSummary @@ -1914,6 +1925,18 @@ pub fn session_tool_attachment_id( URL_SAFE_NO_PAD.encode(hash.finalize()) } +fn project_history_item(entry: &LoggedHistoryEntry) -> Option { + if let Some(input) = &entry.metadata.system_input { + let public = input.public_projection(); + return Some(SessionSnapshotEntryData::SystemItem { + item_kind: public.kind.clone(), + content: public.body.clone(), + data: Some(serde_json::to_value(public).expect("public system input is serializable")), + }); + } + project_item(&entry.metadata.entry_id.0, &entry.item) +} + fn project_item(entry_id: &str, item: &LoggedItem) -> Option { match item { LoggedItem::Message { role, content } => { @@ -1986,17 +2009,19 @@ fn project_item(entry_id: &str, item: &LoggedItem) -> Option, + use_policy: Option, ) -> SessionSnapshotEntry { - let public = item.public_item(); + let public = item.clone(); let data = Some(serde_json::to_value(&public).expect("public system input is serializable")); let item_kind = public.kind; let content = public.body; SessionSnapshotEntry { + use_policy, entry_id, timestamp, provenance, @@ -2285,6 +2310,7 @@ mod tests { content: vec![LoggedContentPart::Text { text: text.into() }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(entry_id.into()), origin, derivation: None, @@ -3583,6 +3609,7 @@ mod tests { .map(|item| LoggedHistoryEntry { item, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, @@ -3637,6 +3664,7 @@ mod tests { }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: user_entry_id, origin: LoggedSessionHistoryOrigin::HumanInput { account_id: "account-1".into(), @@ -3706,6 +3734,7 @@ mod tests { }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::FlowInstruction { selector: "builtin:coder-review".into(), @@ -3725,6 +3754,7 @@ mod tests { }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: user_entry_id.clone(), origin: origin.clone(), derivation: Some(LoggedHistoryDerivation { @@ -3755,6 +3785,7 @@ mod tests { fn annotated_projection_preserves_identity_and_provenance() { let session_id = crate::new_session_id(); let metadata = LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::ModelOutput { worker: LoggedWorkerSubject { @@ -4317,6 +4348,7 @@ mod tests { is_error: false, }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId("ancestor-image".into()), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, @@ -4411,6 +4443,7 @@ mod tests { is_error: false, }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId("tool-images".into()), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/session-store/src/public_snapshot/run_stats.rs b/crates/session-store/src/public_snapshot/run_stats.rs index 2d5b49902..4806e1da2 100644 --- a/crates/session-store/src/public_snapshot/run_stats.rs +++ b/crates/session-store/src/public_snapshot/run_stats.rs @@ -103,6 +103,7 @@ fn finish( stats.insert( anchor.clone(), SessionSnapshotEntry { + use_policy: None, entry_id: format!("run-stats:{anchor}"), timestamp: ended_at, provenance: SessionEntryProvenance::LegacyUnknown, diff --git a/crates/session-store/src/segment_log.rs b/crates/session-store/src/segment_log.rs index 97f347dad..f76ea783c 100644 --- a/crates/session-store/src/segment_log.rs +++ b/crates/session-store/src/segment_log.rs @@ -254,6 +254,23 @@ pub struct SegmentOrigin { } impl LogEntry { + /// Validate generic System records before a Store publishes any bytes. + pub fn validate_system_inputs(&self) -> Result<(), crate::SystemInputError> { + match self { + Self::AnnotatedSegmentStart { history, .. } + | Self::AnnotatedUserInput { history, .. } => { + for entry in history { + entry.validate_system_input()?; + } + } + Self::AnnotatedAssistantItem { entry, .. } + | Self::AnnotatedToolResult { entry, .. } + | Self::ToolResultCorrected { entry, .. } => entry.validate_system_input()?, + Self::AnnotatedSystemItem { entry, .. } => entry.validate_system_input()?, + _ => {} + } + Ok(()) + } /// Allocate the durable public identity for a newly committed Run /// transition. Calling this repeatedly is idempotent so the exact value /// written to storage is also the value published to live subscribers. @@ -537,6 +554,7 @@ mod tests { LoggedHistoryEntry { item: LoggedItem::from(item), metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/session-store/src/store.rs b/crates/session-store/src/store.rs index a876b7429..bf29ccb63 100644 --- a/crates/session-store/src/store.rs +++ b/crates/session-store/src/store.rs @@ -27,6 +27,9 @@ pub enum StoreError { #[error("serialization error: {0}")] Serde(#[from] serde_json::Error), + #[error("invalid system input: {0}")] + InvalidSystemInput(#[from] crate::SystemInputError), + #[error("segment not found: {0}")] NotFound(SegmentId), diff --git a/crates/session-store/src/system_input.rs b/crates/session-store/src/system_input.rs index fc9613941..3595c7bdb 100644 --- a/crates/session-store/src/system_input.rs +++ b/crates/session-store/src/system_input.rs @@ -36,6 +36,10 @@ pub enum SystemInputError { UnsupportedPayload, #[error("system input payload does not match the owner's typed contract")] InvalidTypedPayload, + #[error("generic system input is missing explicit metadata")] + MissingMetadata, + #[error("system input metadata does not match its logical record")] + InconsistentRecord, } /// One private payload owned by a Feature's versioned typed decoder. @@ -229,6 +233,23 @@ impl SystemInputMetadata { pub fn public_item(&self) -> Option<&PublicSystemItem> { self.public.as_ref() } + + pub fn public_use_policy(&self) -> protocol::SessionEntryUsePolicy { + let has_public = self.public.is_some(); + protocol::SessionEntryUsePolicy { + observation_readable: has_public + && self.usage.observation == InputObservationUse::Readable, + memory_evidence: has_public && self.usage.memory_evidence == InputEvidenceUse::Include, + } + } + + pub fn public_projection(&self) -> PublicSystemItem { + self.public.clone().unwrap_or_else(|| PublicSystemItem { + kind: "input".into(), + body: String::new(), + presentation: crate::PublicSystemPresentation::Ignored, + }) + } } /// System role is invariant; provenance and use policies are attached data. diff --git a/crates/session-store/src/system_item.rs b/crates/session-store/src/system_item.rs index 376a3cd8f..6d3d6ce43 100644 --- a/crates/session-store/src/system_item.rs +++ b/crates/session-store/src/system_item.rs @@ -92,6 +92,9 @@ pub struct PromptRenderProvenance { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "snake_case")] pub enum SystemItem { + /// Generic System body; private metadata and public presentation are supplied + /// independently by the producer in the same annotated history record. + Input { body: String }, /// One-time derived Journal reference context. The bounded Host snapshot is /// retained as JSON independently of its rendered body and prompt projection. JournalStartup { @@ -227,9 +230,9 @@ impl SystemItem { event: event.clone(), }, Self::TaskReminder { .. } => PublicSystemPresentation::TaskReminder, - Self::LegacyKnowledgeIgnored { .. } | Self::LegacyIgnored { .. } => { - PublicSystemPresentation::Ignored - } + Self::Input { .. } + | Self::LegacyKnowledgeIgnored { .. } + | Self::LegacyIgnored { .. } => PublicSystemPresentation::Ignored, Self::JournalStartup { .. } | Self::ResidentSummaryRefresh { .. } | Self::SubjectBehaviorRefresh { .. } @@ -253,6 +256,7 @@ impl SystemItem { /// for this item. Returns the variant's stored `body` verbatim. pub fn history_text(&self) -> String { match self { + SystemItem::Input { body } => body.clone(), SystemItem::JournalStartup { body, .. } => body.clone(), SystemItem::Notification { body, .. } => body.clone(), SystemItem::WorkerEvent { body, .. } => body.clone(), @@ -280,6 +284,7 @@ impl SystemItem { /// wire — keep flexible. pub fn kind_label(&self) -> &'static str { match self { + SystemItem::Input { .. } => "input", SystemItem::JournalStartup { .. } => "journal_startup", SystemItem::Notification { .. } => "notification", SystemItem::WorkerEvent { .. } => "worker_event", diff --git a/crates/session-store/src/worker_session_store.rs b/crates/session-store/src/worker_session_store.rs index b19180b3f..bb6ffe34f 100644 --- a/crates/session-store/src/worker_session_store.rs +++ b/crates/session-store/src/worker_session_store.rs @@ -742,6 +742,7 @@ impl Store for WorkerSessionStore { segment_id: SegmentId, entry: &LogEntry, ) -> Result<(), StoreError> { + entry.validate_system_inputs()?; let _retention = self.lock_publication(session_id)?; self.ensure_session(session_id, true)?; self.append_log_entry(&self.log_path(segment_id), entry) @@ -800,6 +801,9 @@ impl Store for WorkerSessionStore { segment_id: SegmentId, entries: &[LogEntry], ) -> Result<(), StoreError> { + for entry in entries { + entry.validate_system_inputs()?; + } let _retention = self.lock_publication(session_id)?; self.ensure_session(session_id, true)?; let mut content = Vec::new(); @@ -1430,6 +1434,7 @@ mod tests { LoggedHistoryEntry { item: LoggedItem::from(item), metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/session-store/tests/fs_store_test.rs b/crates/session-store/tests/fs_store_test.rs index 1ecb81d01..af4e940ec 100644 --- a/crates/session-store/tests/fs_store_test.rs +++ b/crates/session-store/tests/fs_store_test.rs @@ -11,6 +11,7 @@ fn annotated(item: Item) -> LoggedHistoryEntry { LoggedHistoryEntry { item: LoggedItem::from(item), metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, @@ -421,3 +422,178 @@ fn lookup_session_of_finds_owning_session() { assert_eq!(store.lookup_session_of(segid).unwrap(), Some(sid)); } + +// Storage/projection component test: both production layouts, temporary originals, +// no Feature, model, runtime or Host authority is substituted into this boundary. +#[test] +fn generic_system_append_and_fork_preserve_metadata_without_public_payload_leak() { + use session_store::{ + FeatureInputPayload, InputCompactionUse, InputEvidenceUse, InputObservationUse, + LoggedHistoryDerivation, LoggedSystemHistoryEntry, PublicSystemItem, + PublicSystemPresentation, SystemInputEnvelope, SystemInputMetadata, SystemInputUsePolicy, + WorkerSessionStore, + }; + for worker_layout in [false, true] { + let dir = tempfile::tempdir().unwrap(); + let sid = new_session_id(); + let segment = new_segment_id(); + let fork = new_segment_id(); + let store: Box = if worker_layout { + Box::new(WorkerSessionStore::new(dir.path()).unwrap()) + } else { + Box::new(FsStore::new(dir.path()).unwrap()) + }; + store + .create_segment(sid, segment, &[nil_session_start(1, sid)]) + .unwrap(); + let entry = LoggedSystemHistoryEntry::from_input( + LoggedSessionHistoryOrigin::Provided { + producer: "new-feature".into(), + }, + Some(LoggedHistoryDerivation { + sources: vec![LoggedSessionHistoryEntryId("source-entry".into())], + }), + SystemInputEnvelope::new( + "private model body", + SystemInputMetadata::new( + SystemInputUsePolicy { + recording_material: InputEvidenceUse::Exclude, + memory_evidence: InputEvidenceUse::Exclude, + observation: InputObservationUse::Hidden, + compaction: InputCompactionUse::ReferenceInput, + }, + Some( + FeatureInputPayload::encode( + "new-feature:context", + 101, + &serde_json::json!({"private": "secret-detail"}), + ) + .unwrap(), + ), + Some(PublicSystemItem { + kind: "context".into(), + body: "explicit public body".into(), + presentation: PublicSystemPresentation::Context, + }), + ) + .unwrap(), + ) + .unwrap(), + ); + store + .append( + sid, + segment, + &LogEntry::AnnotatedSystemItem { + ts: 2, + entry: entry.clone(), + extensions: vec![], + }, + ) + .unwrap(); + let saved = store.read_all(sid, segment).unwrap(); + let LogEntry::AnnotatedSystemItem { + entry: restored, .. + } = &saved[1] + else { + panic!("missing system input") + }; + assert_eq!(restored.to_history_entry(), entry.to_history_entry()); + assert_eq!( + collect_state(&saved).history[0].as_text(), + Some("private model body") + ); + let mut fork_seed = nil_session_start(3, sid); + if let LogEntry::AnnotatedSegmentStart { + history, + forked_from, + .. + } = &mut fork_seed + { + history.push(restored.to_history_entry()); + *forked_from = Some(session_store::SegmentOrigin { + segment_id: segment, + at_turn_index: 0, + }); + } + store.create_segment(sid, fork, &[fork_seed]).unwrap(); + let fork_saved = store.read_all(sid, fork).unwrap(); + let LogEntry::AnnotatedSegmentStart { history, .. } = &fork_saved[0] else { + unreachable!() + }; + assert_eq!(history, &[entry.to_history_entry()]); + let original = session_store::public_snapshot::project_session_snapshot(sid, &saved); + let inherited = session_store::public_snapshot::project_session_snapshot(sid, &fork_saved); + let public = serde_json::to_string(&original.entries).unwrap(); + assert!(public.contains("explicit public body")); + for private in ["private model body", "secret-detail", "new-feature:context"] { + assert!(!public.contains(private), "private field leaked: {private}"); + } + assert_eq!(original.entries.len(), 1); + assert_eq!(inherited.entries.len(), 1); + assert_eq!(original.entries[0].entry_id, inherited.entries[0].entry_id); + assert_eq!( + original.entries[0].derived_from, + inherited.entries[0].derived_from + ); + assert_eq!( + original.entries[0].provenance, + inherited.entries[0].provenance + ); + assert_eq!( + serde_json::to_value(&original.entries[0].data).unwrap(), + serde_json::to_value(&inherited.entries[0].data).unwrap() + ); + } +} + +#[test] +fn invalid_generic_system_input_rejects_append_create_and_external_json_without_changing_originals() +{ + use session_store::{StoreError, SystemItem, WorkerSessionStore}; + for worker_layout in [false, true] { + let dir = tempfile::tempdir().unwrap(); + let sid = new_session_id(); + let segment = new_segment_id(); + let store: Box = if worker_layout { + Box::new(WorkerSessionStore::new(dir.path()).unwrap()) + } else { + Box::new(FsStore::new(dir.path()).unwrap()) + }; + let seed = nil_session_start(1, sid); + store + .create_segment(sid, segment, std::slice::from_ref(&seed)) + .unwrap(); + let path = if worker_layout { + dir.path().join("segments").join(format!("{segment}.jsonl")) + } else { + dir.path() + .join(sid.to_string()) + .join(format!("{segment}.jsonl")) + }; + let before = std::fs::read(&path).unwrap(); + let invalid = LogEntry::AnnotatedSystemItem { + ts: 2, + extensions: vec![], + entry: session_store::LoggedSystemHistoryEntry { + item: SystemItem::Input { + body: "no policy".into(), + }, + metadata: LoggedSessionHistoryMetadata::legacy_unknown(), + }, + }; + assert!(matches!( + store.append(sid, segment, &invalid), + Err(StoreError::InvalidSystemInput(_)) + )); + assert!(matches!( + store.create_segment(sid, segment, &[seed, invalid.clone()]), + Err(StoreError::InvalidSystemInput(_)) + )); + assert!( + serde_json::from_value::(serde_json::to_value(invalid).unwrap()).is_err() + ); + assert_eq!(std::fs::read(path).unwrap(), before); + assert_eq!(store.read_all(sid, segment).unwrap().len(), 1); + } +} diff --git a/crates/session-store/tests/session_test.rs b/crates/session-store/tests/session_test.rs index 901c0578f..e12d3ff29 100644 --- a/crates/session-store/tests/session_test.rs +++ b/crates/session-store/tests/session_test.rs @@ -24,6 +24,7 @@ fn annotated(items: &[Item]) -> Vec { .map(|item| session_store::LoggedHistoryEntry { item: session_store::LoggedItem::from(item), metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId::new(), origin: session_store::LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/standalone/src/subjektiv/journal/tests.rs b/crates/standalone/src/subjektiv/journal/tests.rs index 3eacfeeb0..bd24ef67d 100644 --- a/crates/standalone/src/subjektiv/journal/tests.rs +++ b/crates/standalone/src/subjektiv/journal/tests.rs @@ -212,6 +212,7 @@ fn message(id: &str, text: &str) -> session_store::LoggedHistoryEntry { content: vec![session_store::LoggedContentPart::Text { text: text.into() }], }, metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId(id.into()), origin: session_store::LoggedSessionHistoryOrigin::LocalHumanInput, derivation: None, diff --git a/crates/standalone/src/subjektiv_sessions.rs b/crates/standalone/src/subjektiv_sessions.rs index 36a75df06..71dc48631 100644 --- a/crates/standalone/src/subjektiv_sessions.rs +++ b/crates/standalone/src/subjektiv_sessions.rs @@ -1621,6 +1621,7 @@ allow = [] let history = |id: &str, item: LoggedItem| LoggedHistoryEntry { item, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(id.into()), origin: LoggedSessionHistoryOrigin::BackendInstruction { operation_id: None }, derivation: None, diff --git a/crates/tui/src/app.rs b/crates/tui/src/app.rs index 306368070..e537c5385 100644 --- a/crates/tui/src/app.rs +++ b/crates/tui/src/app.rs @@ -3567,6 +3567,7 @@ mod completion_flow_tests { session_store::LoggedHistoryEntry { item: session_store::LoggedItem::from(item), metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId::new(), origin: session_store::LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, @@ -4324,6 +4325,7 @@ mod completion_flow_tests { })); app.handle_worker_event(Event::SessionEntryCommitted { entry: protocol::SessionSnapshotEntry { + use_policy: None, entry_id: "run-failure".into(), timestamp: 2, provenance: protocol::SessionEntryProvenance::LegacyUnknown, diff --git a/crates/worker-runtime/src/http_server/tests/session_material_tests.rs b/crates/worker-runtime/src/http_server/tests/session_material_tests.rs index 33f8555dc..9c0e5f9e2 100644 --- a/crates/worker-runtime/src/http_server/tests/session_material_tests.rs +++ b/crates/worker-runtime/src/http_server/tests/session_material_tests.rs @@ -35,6 +35,7 @@ fn message(id: &str, role: LoggedRole, text: &str) -> LoggedHistoryEntry { content: vec![LoggedContentPart::Text { text: text.into() }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(id.into()), origin: LoggedSessionHistoryOrigin::LocalHumanInput, derivation: None, diff --git a/crates/worker-runtime/src/retention.rs b/crates/worker-runtime/src/retention.rs index bc7994de9..9777e7390 100644 --- a/crates/worker-runtime/src/retention.rs +++ b/crates/worker-runtime/src/retention.rs @@ -1831,6 +1831,7 @@ mod tests { }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId("original".into()), origin: LoggedSessionHistoryOrigin::LocalHumanInput, derivation: None, @@ -1844,6 +1845,7 @@ mod tests { }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId("summary".into()), origin: LoggedSessionHistoryOrigin::DerivedSummary, derivation: Some(session_store::LoggedHistoryDerivation { diff --git a/crates/worker-runtime/src/runtime.rs b/crates/worker-runtime/src/runtime.rs index 2b671c6e5..c9307a5dc 100644 --- a/crates/worker-runtime/src/runtime.rs +++ b/crates/worker-runtime/src/runtime.rs @@ -12422,6 +12422,7 @@ mod tests { session: protocol::SessionSnapshot { pending_submissions: protocol::PendingSubmissionsSnapshot::default(), entries: vec![protocol::SessionSnapshotEntry { + use_policy: None, entry_id: "restored-log-entry".to_owned(), timestamp: 1, provenance: protocol::SessionEntryProvenance::LegacyUnknown, diff --git a/crates/worker-runtime/src/session_public.rs b/crates/worker-runtime/src/session_public.rs index dac5d21f0..93f337f6d 100644 --- a/crates/worker-runtime/src/session_public.rs +++ b/crates/worker-runtime/src/session_public.rs @@ -398,6 +398,7 @@ mod tests { content: vec![LoggedContentPart::Text { text: text.into() }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(id.to_string()), origin: LoggedSessionHistoryOrigin::HumanInput { account_id: "account-1".to_string(), diff --git a/crates/worker-runtime/src/worker_backend.rs b/crates/worker-runtime/src/worker_backend.rs index 74044cde9..ca598cd80 100644 --- a/crates/worker-runtime/src/worker_backend.rs +++ b/crates/worker-runtime/src/worker_backend.rs @@ -5033,6 +5033,7 @@ mod tests { }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id, origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/worker/src/feature/builtin/session_explore.rs b/crates/worker/src/feature/builtin/session_explore.rs index 69d4ced54..aacc16081 100644 --- a/crates/worker/src/feature/builtin/session_explore.rs +++ b/crates/worker/src/feature/builtin/session_explore.rs @@ -371,7 +371,7 @@ fn parse_entry_ref(value: &str) -> Result { fn parse_kind(value: &str) -> Result { ReferenceKind::parse(value).ok_or_else(|| { ToolError::InvalidArgument(format!( - "invalid kind {value:?}; expected user, assistant, or tool" + "invalid kind {value:?}; expected user, assistant, system, or tool" )) }) } diff --git a/crates/worker/src/feature/builtin/worker_observation.rs b/crates/worker/src/feature/builtin/worker_observation.rs index 325f89615..9b6d5488c 100644 --- a/crates/worker/src/feature/builtin/worker_observation.rs +++ b/crates/worker/src/feature/builtin/worker_observation.rs @@ -813,6 +813,7 @@ mod tests { _ => return None, }; Some(protocol::SessionSnapshotEntry { + use_policy: None, entry_id: format!("fake-{index:08}"), timestamp: index as u64, provenance: protocol::SessionEntryProvenance::LegacyUnknown, diff --git a/crates/worker/src/internal_worker.rs b/crates/worker/src/internal_worker.rs index 7ffc44b42..46400d52d 100644 --- a/crates/worker/src/internal_worker.rs +++ b/crates/worker/src/internal_worker.rs @@ -1499,6 +1499,7 @@ permission = "write" is_error: false, }, metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId(entry_id.into()), origin: session_store::LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/worker/src/ipc/protocol_session.rs b/crates/worker/src/ipc/protocol_session.rs index 759c9c411..038770284 100644 --- a/crates/worker/src/ipc/protocol_session.rs +++ b/crates/worker/src/ipc/protocol_session.rs @@ -90,7 +90,7 @@ pub fn live_log_entry_event(entry: LogEntry) -> Option { } LogEntry::AnnotatedSystemItem { entry, .. } => { let entry_id = Some(entry.metadata.entry_id.0.clone()); - let value = serde_json::to_value(entry.item.public_item()) + let value = serde_json::to_value(entry.public_item()) .expect("public system input is serializable"); Some(Event::SystemItem { entry_id, @@ -348,6 +348,7 @@ mod tests { prompt_provenance: None, }, metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: entry_id.clone(), origin: session_store::LoggedSessionHistoryOrigin::BackendInstruction { operation_id: None, diff --git a/crates/worker/src/session_capture.rs b/crates/worker/src/session_capture.rs index c89570146..7e78a12fc 100644 --- a/crates/worker/src/session_capture.rs +++ b/crates/worker/src/session_capture.rs @@ -74,6 +74,7 @@ impl std::fmt::Display for SessionEntryRef { pub(crate) enum ReferenceKind { User, Assistant, + System, Tool, } @@ -82,6 +83,7 @@ impl ReferenceKind { match self { Self::User => "user", Self::Assistant => "assistant", + Self::System => "system", Self::Tool => "tool", } } @@ -90,6 +92,7 @@ impl ReferenceKind { match value { "user" => Some(Self::User), "assistant" | "agent" => Some(Self::Assistant), + "system" => Some(Self::System), "tool" => Some(Self::Tool), _ => None, } @@ -131,6 +134,7 @@ pub(crate) struct OverviewItem { #[derive(Debug, Clone)] pub(crate) struct ReferenceEntry { + use_policy: Option, pub id: SessionEntryRef, pub origin: SessionEntryProvenance, pub entry_range: [u64; 2], @@ -242,6 +246,7 @@ pub(crate) struct SessionEntryEvidence { #[derive(Debug, Clone)] struct CapturedHistoryEntry { + use_policy: Option, item: Item, entry_id: session_store::LoggedSessionHistoryEntryId, origin: SessionEntryProvenance, @@ -302,10 +307,12 @@ impl SessionCapture { is_error, attachments: _, } => Item::tool_result_item(call_id, summary, content, is_error), - // Observation deliberately excludes system items and - // controller errors from model-visible session evidence. - SessionSnapshotEntryData::SystemItem { .. } - | SessionSnapshotEntryData::Invoke { .. } + SessionSnapshotEntryData::SystemItem { content, .. } => { + entry.use_policy?; + Item::system_message(content) + } + // Controller errors are not model-visible evidence. + SessionSnapshotEntryData::Invoke { .. } | SessionSnapshotEntryData::Usage { .. } | SessionSnapshotEntryData::RunStats { .. } | SessionSnapshotEntryData::RunYielded { .. } @@ -314,6 +321,7 @@ impl SessionCapture { | SessionSnapshotEntryData::RunError { .. } => return None, }; Some(CapturedHistoryEntry { + use_policy: entry.use_policy, item, entry_id: session_store::LoggedSessionHistoryEntryId(entry.entry_id), origin: entry.provenance, @@ -328,6 +336,7 @@ impl SessionCapture { .into_iter() .enumerate() .map(|(index, item)| CapturedHistoryEntry { + use_policy: None, item, entry_id: session_store::LoggedSessionHistoryEntryId(format!("{index:08}")), origin: SessionEntryProvenance::LegacyUnknown, @@ -342,10 +351,21 @@ impl SessionCapture { ) -> Self { let entries = entries .into_iter() - .map(|entry| CapturedHistoryEntry { - item: entry.item, - entry_id: entry.annotation.entry_id, - origin: public_provenance(&entry.annotation.origin), + .map(|entry| { + let (item, use_policy) = if let Some(input) = &entry.annotation.system_input { + ( + Item::system_message(input.public_projection().body), + Some(input.public_use_policy()), + ) + } else { + (entry.item, None) + }; + CapturedHistoryEntry { + item, + use_policy, + entry_id: entry.annotation.entry_id, + origin: public_provenance(&entry.annotation.origin), + } }) .collect(); Self::from_captured_entries(segment_id, entries) @@ -364,7 +384,8 @@ impl SessionCapture { let entry_range = [idx as u64, idx as u64]; match item { Item::Message { role, content, .. } => { - let Some(kind) = message_reference_kind(&entry.origin, role) else { + let Some(kind) = message_reference_kind(&entry.origin, role, entry.use_policy) + else { continue; }; let text = content @@ -376,6 +397,7 @@ impl SessionCapture { let summary = truncate_chars(&text, 240); let id = SessionEntryRef::from_history_entry_id(&entry.entry_id); index.push(ReferenceEntry { + use_policy: entry.use_policy, id: id.clone(), origin: entry.origin.clone(), entry_range, @@ -386,7 +408,9 @@ impl SessionCapture { summary: summary.clone(), search_text: text.clone(), }); - if matches!(kind, ReferenceKind::User | ReferenceKind::Assistant) { + if entry.use_policy.is_none_or(|p| p.observation_readable) + && matches!(kind, ReferenceKind::User | ReferenceKind::Assistant) + { overview.push(OverviewItem { id: id.clone(), origin: entry.origin.clone(), @@ -403,6 +427,7 @@ impl SessionCapture { } => { let text = format!("{name}\n{arguments}"); index.push(ReferenceEntry { + use_policy: entry.use_policy, id: SessionEntryRef::from_history_entry_id(&entry.entry_id), origin: entry.origin.clone(), entry_range, @@ -430,6 +455,7 @@ impl SessionCapture { content.as_deref().unwrap_or_default(), ); index.push(ReferenceEntry { + use_policy: entry.use_policy, id: SessionEntryRef::from_history_entry_id(&entry.entry_id), origin: entry.origin.clone(), entry_range, @@ -510,6 +536,9 @@ impl SessionCapture { let mut hits = Vec::new(); for entry in &self.index { + if entry.use_policy.is_some_and(|p| !p.observation_readable) { + continue; + } if entry.entry_range[0] < min_entry_index || entry.entry_range[0] > max_entry_index { continue; } @@ -581,6 +610,9 @@ impl SessionCapture { }; for entry in selected { + if entry.use_policy.is_some_and(|p| !p.observation_readable) { + continue; + } if entries.len() >= max_items { truncated = true; break; @@ -695,21 +727,11 @@ impl SessionCapture { pub(crate) fn evidence_for(&self, id: &str) -> Option { let entry = self.index.iter().find(|entry| entry.id.as_str() == id)?; - let excerpt = self - .read( - ReadSelector::Id(id), - ReadOptions { - include_tools: true, - tool_part: ToolPart::Both, - detail: ReadDetail::Compact, - max_items: 1, - max_bytes: 2 * 1024, - }, - ) - .entries - .first() - .map(|entry| entry.text.clone()) - .unwrap_or_else(|| entry.summary.clone()); + if entry.use_policy.is_some_and(|p| !p.memory_evidence) { + return None; + } + let item = &self.entries.get(entry.entry_range[0] as usize)?.item; + let excerpt = render_item(item, entry, ReadDetail::Compact, 2 * 1024); Some(SessionEntryEvidence { segment_id: self.segment_id.clone(), entry_ref: entry.id.clone(), @@ -731,9 +753,8 @@ fn public_provenance(origin: &WorkerHistoryProvenance) -> SessionEntryProvenance } WorkerHistoryProvenance::WorkerInput { .. } => SessionEntryProvenance::WorkerInput, WorkerHistoryProvenance::FlowInstruction { .. } => SessionEntryProvenance::FlowInstruction, - WorkerHistoryProvenance::BackendInstruction { .. } => { - SessionEntryProvenance::BackendInstruction - } + WorkerHistoryProvenance::BackendInstruction { .. } + | WorkerHistoryProvenance::Provided { .. } => SessionEntryProvenance::BackendInstruction, WorkerHistoryProvenance::ModelOutput { .. } => SessionEntryProvenance::ModelOutput, WorkerHistoryProvenance::ToolOutput { .. } => SessionEntryProvenance::ToolOutput, WorkerHistoryProvenance::CompactionSummary @@ -746,7 +767,15 @@ fn public_provenance(origin: &WorkerHistoryProvenance) -> SessionEntryProvenance fn message_reference_kind( origin: &SessionEntryProvenance, provider_role: &Role, + use_policy: Option, ) -> Option { + if use_policy.is_some() { + return match provider_role { + Role::System => Some(ReferenceKind::System), + Role::User => Some(ReferenceKind::User), + Role::Assistant => Some(ReferenceKind::Assistant), + }; + } match origin { SessionEntryProvenance::HumanInput | SessionEntryProvenance::WorkerInput => { Some(ReferenceKind::User) @@ -950,6 +979,148 @@ mod tests { } } + #[test] + fn generic_public_input_observation_and_memory_policies_survive_store_restore_independently() { + use session_store::{ + FeatureInputPayload, FsStore, InputCompactionUse, InputEvidenceUse, + InputObservationUse, LogEntry, LoggedSystemHistoryEntry, PublicSystemItem, + PublicSystemPresentation, Store, SystemInputEnvelope, SystemInputMetadata, + SystemInputUsePolicy, + }; + let root = tempfile::tempdir().unwrap(); + let store = FsStore::new(root.path()).unwrap(); + let session = session_store::new_session_id(); + let segment = session_store::new_segment_id(); + store + .create_segment( + session, + segment, + &[LogEntry::AnnotatedSegmentStart { + ts: 1, + session_id: session, + system_prompt: None, + config: Default::default(), + history: vec![], + forked_from: None, + compacted_from: None, + }], + ) + .unwrap(); + let mut inputs = Vec::new(); + for (producer, observation, memory_evidence, public) in [ + ( + "same", + InputObservationUse::Readable, + InputEvidenceUse::Exclude, + true, + ), + ( + "same", + InputObservationUse::Hidden, + InputEvidenceUse::Include, + true, + ), + ( + "renamed", + InputObservationUse::Readable, + InputEvidenceUse::Include, + true, + ), + ( + "renamed", + InputObservationUse::Hidden, + InputEvidenceUse::Exclude, + true, + ), + ( + "private", + InputObservationUse::Readable, + InputEvidenceUse::Include, + false, + ), + ] { + let entry = LoggedSystemHistoryEntry::from_input( + WorkerHistoryProvenance::Provided { + producer: producer.into(), + }, + None, + SystemInputEnvelope::new( + "private model text", + SystemInputMetadata::new( + SystemInputUsePolicy { + recording_material: InputEvidenceUse::Exclude, + memory_evidence, + observation, + compaction: InputCompactionUse::ReferenceInput, + }, + Some( + FeatureInputPayload::encode( + "future:owner", + 99, + &serde_json::json!({ "secret": "private metadata" }), + ) + .unwrap(), + ), + public.then(|| PublicSystemItem { + kind: "supplied-context".into(), + body: "public context: do not extract this".into(), + presentation: PublicSystemPresentation::Context, + }), + ) + .unwrap(), + ) + .unwrap(), + ); + store + .append( + session, + segment, + &LogEntry::AnnotatedSystemItem { + ts: 2, + entry: entry.clone(), + extensions: vec![], + }, + ) + .unwrap(); + inputs.push(entry); + } + let saved = store.read_all(session, segment).unwrap(); + let restored = + crate::session_history::restore_history_entries(session, segment, &saved).unwrap(); + let snapshot = session_store::public_snapshot::project_session_snapshot(session, &saved); + let snapshot: SessionSnapshot = + serde_json::from_value(serde_json::to_value(snapshot).unwrap()).unwrap(); + for capture in [ + SessionCapture::from_history_entries(segment.to_string(), restored), + SessionCapture::from_session_snapshot(segment.to_string(), snapshot), + ] { + let hits = capture.search(&SearchOptions { + kind: Some(ReferenceKind::System), + ..Default::default() + }); + assert_eq!(hits.len(), 2); + for (index, input) in inputs.iter().enumerate() { + let reference = SessionEntryRef::from_history_entry_id(&input.metadata.entry_id); + let read = + capture.read(ReadSelector::Id(reference.as_str()), ReadOptions::default()); + assert_eq!(!read.entries.is_empty(), matches!(index, 0 | 2)); + let evidence = capture.evidence_for(reference.as_str()); + assert_eq!(evidence.is_some(), matches!(index, 1 | 2)); + for text in read + .entries + .iter() + .map(|entry| entry.text.as_str()) + .chain(evidence.iter().map(|entry| entry.excerpt.as_str())) + { + assert!(text.contains("public context: do not extract this")); + assert!(!text.contains("private model text")); + assert!(!text.contains("private metadata")); + assert!(!text.contains("future:owner")); + } + } + } + } + #[test] fn overview_contains_user_and_assistant_only() { let view = SessionCapture::new( diff --git a/crates/worker/src/session_history.rs b/crates/worker/src/session_history.rs index d416ccef1..232a8c92d 100644 --- a/crates/worker/src/session_history.rs +++ b/crates/worker/src/session_history.rs @@ -24,6 +24,7 @@ pub(crate) fn test_logged_history_entry(item: impl Into) -> LoggedHistoryE LoggedHistoryEntry { item: session_store::LoggedItem::from(item.into()), metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, @@ -38,6 +39,7 @@ pub(crate) fn test_logged_system_entry( session_store::LoggedSystemHistoryEntry { item, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId::new(), origin: LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, @@ -58,6 +60,7 @@ pub(crate) fn metadata( derivation: Option, ) -> SessionHistoryMetadata { SessionHistoryMetadata { + system_input: None, entry_id: SessionHistoryEntryId::new(), origin, derivation, @@ -80,6 +83,7 @@ pub(crate) fn history_entry_with_id( HistoryEntry::new( item, SessionHistoryMetadata { + system_input: None, entry_id, origin, derivation: None, diff --git a/crates/worker/src/spawn/comm_tools.rs b/crates/worker/src/spawn/comm_tools.rs index 9fca770de..59ca3c167 100644 --- a/crates/worker/src/spawn/comm_tools.rs +++ b/crates/worker/src/spawn/comm_tools.rs @@ -77,6 +77,7 @@ mod tests { .into_iter() .enumerate() .map(|(index, value)| protocol::SessionSnapshotEntry { + use_policy: None, entry_id: format!("test-{index}"), timestamp: index as u64, provenance: protocol::SessionEntryProvenance::LegacyUnknown, diff --git a/crates/worker/src/spawn/registry.rs b/crates/worker/src/spawn/registry.rs index 05317f491..1d5b7dfb3 100644 --- a/crates/worker/src/spawn/registry.rs +++ b/crates/worker/src/spawn/registry.rs @@ -1338,6 +1338,7 @@ mod tests { is_error: false, }, metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId(entry_id.into()), origin: session_store::LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/worker/src/wip.rs b/crates/worker/src/wip.rs index 8c4a0849e..1f12478d3 100644 --- a/crates/worker/src/wip.rs +++ b/crates/worker/src/wip.rs @@ -5502,6 +5502,7 @@ mod tests { entry: session_store::LoggedHistoryEntry { item: session_store::LoggedItem::from(saved), metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId::new(), origin: session_store::LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/worker/tests/compact_events_test.rs b/crates/worker/tests/compact_events_test.rs index 2aeb8f521..d72150e71 100644 --- a/crates/worker/tests/compact_events_test.rs +++ b/crates/worker/tests/compact_events_test.rs @@ -119,6 +119,7 @@ fn annotated(item: Item) -> session_store::LoggedHistoryEntry { session_store::LoggedHistoryEntry { item: session_store::LoggedItem::from(item), metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId::new(), origin: session_store::LoggedSessionHistoryOrigin::LegacyUnknown, derivation: None, diff --git a/crates/workspace-server/src/server.rs b/crates/workspace-server/src/server.rs index dd256fea9..4bdf8a7f6 100644 --- a/crates/workspace-server/src/server.rs +++ b/crates/workspace-server/src/server.rs @@ -44108,6 +44108,7 @@ mod tests { content: vec![LoggedContentPart::Text { text: text.into() }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(id.to_string()), origin: LoggedSessionHistoryOrigin::HumanInput { account_id: "account-1".to_string(), @@ -44297,6 +44298,7 @@ mod tests { content: vec![LoggedContentPart::Text { text: text.into() }], }, metadata: LoggedSessionHistoryMetadata { + system_input: None, entry_id: LoggedSessionHistoryEntryId(id.to_string()), origin: LoggedSessionHistoryOrigin::HumanInput { account_id: "account-1".to_string(), diff --git a/crates/workspace-server/src/server/tests/subjektiv_journal_tests.rs b/crates/workspace-server/src/server/tests/subjektiv_journal_tests.rs index 8f83a29e0..fd0c89fea 100644 --- a/crates/workspace-server/src/server/tests/subjektiv_journal_tests.rs +++ b/crates/workspace-server/src/server/tests/subjektiv_journal_tests.rs @@ -479,6 +479,7 @@ fn seed_session( vec![session_store::LoggedHistoryEntry { item, metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId("read-source-original".into()), origin, derivation: None, @@ -1706,6 +1707,7 @@ impl SubjectRemovalFixture { .map(|text| session_store::LoggedHistoryEntry { item: message(text), metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId(text.into()), origin: session_store::LoggedSessionHistoryOrigin::LocalHumanInput, derivation: None, diff --git a/crates/workspace-server/src/server/tests/subjektiv_memory_journal_tests.rs b/crates/workspace-server/src/server/tests/subjektiv_memory_journal_tests.rs index abcc72632..efe44156f 100644 --- a/crates/workspace-server/src/server/tests/subjektiv_memory_journal_tests.rs +++ b/crates/workspace-server/src/server/tests/subjektiv_memory_journal_tests.rs @@ -67,6 +67,7 @@ impl Fixture { content: vec![session_store::LoggedContentPart::Text { text: text.into() }], }, metadata: session_store::LoggedSessionHistoryMetadata { + system_input: None, entry_id: session_store::LoggedSessionHistoryEntryId(format!("original-{index}")), origin: session_store::LoggedSessionHistoryOrigin::LocalHumanInput, derivation: None, diff --git a/web/workspace/src/lib/generated/protocol-validator.ts b/web/workspace/src/lib/generated/protocol-validator.ts index 2a2da1ea5..7b58a3b4b 100644 --- a/web/workspace/src/lib/generated/protocol-validator.ts +++ b/web/workspace/src/lib/generated/protocol-validator.ts @@ -21,7 +21,7 @@ const MAX_CORRELATION_ID_BYTES = 128; const MAX_RESOURCE_ID_BYTES = 256; const MAX_WORKER_IDS_PER_SELECTOR = 256; const MAX_REJECTION_MESSAGE_BYTES = 1024; -const subscriptionFrameSchema: unknown = {"$defs":{"Alert":{"additionalProperties":false,"description":"User-facing alert emitted from the Worker layer.\n\nThis is a separate channel from `tracing` (developer logs): entries\nhere are assembled explicitly by the Worker when a condition should be\nsurfaced to the person driving the client. Keep messages short and\nhuman-readable.","properties":{"id":{"description":"Stable only within the emitting live Worker; not durable alert history.","type":["string","null"]},"level":{"$ref":"#/$defs/AlertLevel"},"message":{"type":"string"},"position":{"anyOf":[{"$ref":"#/$defs/AlertPosition"},{"type":"null"}]},"source":{"$ref":"#/$defs/AlertSource"},"timestamp_ms":{"description":"Milliseconds since the Unix epoch.","format":"int64","maximum":9007199254740991.0,"minimum":-9007199254740991.0,"type":"integer"}},"required":["level","source","message","timestamp_ms"],"type":"object"},"AlertLevel":{"enum":["warn","error"],"type":"string"},"AlertPosition":{"description":"Display anchor captured at emission, resolved when pending text is committed.","oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"start","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"entry_id":{"type":"string"},"kind":{"const":"after_entry","type":"string"}},"required":["kind","entry_id"],"type":"object"},{"additionalProperties":false,"properties":{"call_id":{"type":"string"},"kind":{"const":"after_tool_call","type":"string"}},"required":["kind","call_id"],"type":"object"},{"additionalProperties":false,"properties":{"block_id":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"kind":{"const":"after_in_flight","type":"string"}},"required":["kind","block_id"],"type":"object"}]},"AlertSource":{"enum":["worker","engine","compactor","agents_md"],"type":"string"},"CommandEvent":{"oneOf":[{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"kind":{"const":"started","type":"string"},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"tool_call_id":{"type":["string","null"]}},"required":["kind","command_id","observed_at_ms"],"type":"object"},{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"content":{"type":"string"},"end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"kind":{"const":"output","type":"string"},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"start_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"stream":{"$ref":"#/$defs/CommandStream"}},"required":["kind","command_id","stream","start_offset","end_offset","content","observed_at_ms"],"type":"object"},{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"exit_code":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":["integer","null"]},"kind":{"const":"terminal","type":"string"},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"status":{"$ref":"#/$defs/CommandStatus"},"stderr_end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"stdout_end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","command_id","status","stdout_end_offset","stderr_end_offset","observed_at_ms"],"type":"object"}]},"CommandSnapshot":{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"exit_code":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":["integer","null"]},"last_output_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"started_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"status":{"$ref":"#/$defs/CommandStatus"},"stderr":{"$ref":"#/$defs/CommandStreamSlice"},"stdout":{"$ref":"#/$defs/CommandStreamSlice"},"tool_call_id":{"type":["string","null"]}},"required":["command_id","status","started_at_ms","observed_at_ms","stdout","stderr"],"type":"object"},"CommandStatus":{"description":"Live provider-owned command status. These values are operational Console\nstate only and are never appended to Worker history.","enum":["running","completed","failed","timed_out","cancelled"],"type":"string"},"CommandStream":{"enum":["stdout","stderr"],"type":"string"},"CommandStreamSlice":{"additionalProperties":false,"properties":{"content":{"type":"string"},"end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"start_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"truncated":{"type":"boolean"}},"required":["start_offset","end_offset","content","truncated"],"type":"object"},"CompactionLifecycle":{"additionalProperties":false,"description":"Stable parent-owned lifecycle for one compaction run.","properties":{"compaction_id":{"type":"string"},"ended_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"error":{"type":["string","null"]},"internal_worker":{"anyOf":[{"$ref":"#/$defs/InternalWorkerRef"},{"type":"null"}]},"new_segment_id":{"type":["string","null"]},"schema_version":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"started_at_ms":{"description":"Milliseconds since the Unix epoch.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"state":{"$ref":"#/$defs/CompactionLifecycleState"},"summary":{"type":["string","null"]}},"required":["schema_version","compaction_id","state","started_at_ms"],"type":"object"},"CompactionLifecycleState":{"enum":["running","done","failed","interrupted"],"type":"string"},"CompactionPhase":{"enum":["preparing","summarizing","committing"],"type":"string"},"CompactionTrigger":{"enum":["manual","pre_run","request_threshold"],"type":"string"},"CompletionContext":{"additionalProperties":false,"properties":{"argument":{"type":["string","null"]},"invocation":{"$ref":"#/$defs/FeatureInvocationIdentity"}},"required":["invocation"],"type":"object"},"CompletionEntry":{"additionalProperties":false,"description":"One completion candidate for a prefix query.","properties":{"description":{"type":["string","null"]},"invocation":{"anyOf":[{"$ref":"#/$defs/FeatureInvocationDescriptor"},{"type":"null"}]},"is_dir":{"default":false,"type":"boolean"},"usage":{"type":["string","null"]},"value":{"type":"string"}},"required":["value","is_dir"],"type":"object"},"CompletionKind":{"description":"Kind of completion requested by `Method::ListCompletions`.\n\n`File` is the existing `@` path lane. `Feature` lists installed chat\ninvocations. `FeatureArgument` resolves a declared argument using the\nsource-qualified [`CompletionContext`].","enum":["file","feature","feature_argument"],"type":"string"},"ContextTokenSource":{"description":"Provenance of the current-context token count in a [`Greeting`].","oneOf":[{"const":"measured","description":"Provider-reported input occupancy from the most recent LLM request.","type":"string"},{"const":"estimated","description":"Current history projected from the Worker's token accounting records.","type":"string"}]},"ContextUsage":{"additionalProperties":false,"description":"Current prompt-context occupancy, distinct from cumulative run traffic.","properties":{"source":{"$ref":"#/$defs/ContextTokenSource"},"tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["tokens","source"],"type":"object"},"ErrorCode":{"enum":["already_running","not_running","not_paused","provider_error","tool_error","invalid_request","internal"],"type":"string"},"Event":{"oneOf":[{"additionalProperties":false,"description":"Durable Submit acceptance. A `Queued` receipt follows the durable FIFO\ncheckpoint. A `Started` receipt follows the pending activation checkpoint;\nthe corresponding [`Event::UserMessage`] marks the later history commit.\nRepeating the same request id and exact payload returns the same receipt\nwithout appending or activating twice.","properties":{"data":{"additionalProperties":false,"properties":{"disposition":{"$ref":"#/$defs/SubmissionDisposition"},"submission_id":{"type":"string"},"submission_request_id":{"type":"string"}},"required":["submission_request_id","submission_id","disposition"],"type":"object"},"event":{"const":"submission_accepted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Correlated rejection before durable acceptance.","properties":{"data":{"additionalProperties":false,"properties":{"message":{"type":"string"},"submission_request_id":{"type":"string"}},"required":["submission_request_id","message"],"type":"object"},"event":{"const":"submission_rejected","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Durable notification acceptance. The request identity is persisted with\nthe notification receipt before this event is emitted. Repeating the\nsame request id and exact payload returns the same acknowledgement\nwithout appending the notification twice.","properties":{"data":{"additionalProperties":false,"properties":{"notification_request_id":{"type":"string"}},"required":["notification_request_id"],"type":"object"},"event":{"const":"notification_accepted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Correlated notification rejection before durable acceptance.","properties":{"data":{"additionalProperties":false,"properties":{"message":{"type":"string"},"notification_request_id":{"type":"string"}},"required":["notification_request_id","message"],"type":"object"},"event":{"const":"notification_rejected","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Complete FIFO replacement following enqueue, activation, cancel, or clear.\nClients replace their pending view in stream order; reconnect uses the snapshot.","properties":{"data":{"additionalProperties":false,"properties":{"pending":{"$ref":"#/$defs/PendingSubmissionsSnapshot"}},"required":["pending"],"type":"object"},"event":{"const":"pending_submissions_changed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A user input message persisted as `LogEntry::AnnotatedUserInput` and\nactivated for a turn. Broadcast to every subscribed client so TUI / GUI\ninstances show the same user line that reconnect snapshots replay.","properties":{"data":{"additionalProperties":false,"properties":{"entry_id":{"description":"Stable durable history identity. Older mixed-version producers omit it.","type":["string","null"]},"segments":{"items":{"$ref":"#/$defs/Segment"},"type":"array"}},"required":["segments"],"type":"object"},"event":{"const":"user_message","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A canonical assistant/tool entry has committed to durable history.\nStreaming events remain the in-flight authority; this event supplies the\nstable identity used to reconcile that live block with paged history.","properties":{"data":{"additionalProperties":false,"properties":{"entry":{"$ref":"#/$defs/SessionSnapshotEntry"}},"required":["entry"],"type":"object"},"event":{"const":"session_entry_committed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"One agent-injected system item committed to history.\n\nCarries the allowlisted JSON form of `session_store::PublicSystemItem`,\nnot the storage record. Its descriptive `kind` is independent from the\ntyped `presentation` used for notification, reminder, or context rendering.\nPrivate Feature payloads and prompt provenance are never event data.\n\nOne event per `LogEntry::AnnotatedSystemItem` commit. Disk-side and\nwire-side are 1:1.","properties":{"data":{"additionalProperties":false,"properties":{"entry_id":{"description":"Stable durable history identity. Synthetic compatibility events omit it.","type":["string","null"]},"item":true},"required":["item"],"type":"object"},"event":{"const":"system_item","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A new self-driving cycle has begun (IDLE → active transition).\n\nMarker event for the start of an Invoke range; the range extends\nimplicitly until the next `InvokeStart`. Fires for every accepted\n`Method::Submit` (kind=`UserSend`), `Method::Notify` (kind=`Notify`),\n`Method::WorkerEvent` re-injection (kind=`WorkerEvent`), and any other\nIDLE-breaking trigger. Mid-run interrupts (e.g. hook output,\ntyped system reminder insertion that doesn't break IDLE) do not\nemit `InvokeStart` — they appear as `SystemItem` only.\n\nCarries `kind` only; the payload (user text / notify message /\nworker event body) is delivered separately via the immediately\nfollowing `UserMessage` / `SystemItem` event.","properties":{"data":{"additionalProperties":false,"properties":{"kind":{"$ref":"#/$defs/InvokeKind"},"timestamp_ms":{"description":"Timestamp of the persisted Invoke, not the client's attach time.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]}},"required":["kind"],"type":"object"},"event":{"const":"invoke_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"One AgentTurn boundary opened. An AgentTurn is a maximal run of\nLLM generation calls whose input messages are identical (i.e.\nretries from network errors / 5xx / stream disconnects collapse\ninto the same AgentTurn). When the input changes (a new tool\nresult lands, a user interrupts, etc.), the next LLM call belongs\nto a new AgentTurn.\n\n`turn` is the AgentTurn index from `Engine::turn_count`.\n\nCurrently retry is not yet implemented (`agen-stream-continuation`)\nso AgentTurn and `LlmCall` fire 1:1, but the contract here is\nthe AgentTurn boundary; consumers that want per-LLM-call signals\nmust subscribe to `LlmCallStart` / `LlmCallEnd` instead.","properties":{"data":{"additionalProperties":false,"properties":{"turn":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["turn"],"type":"object"},"event":{"const":"turn_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"AgentTurn closed.","properties":{"data":{"additionalProperties":false,"properties":{"result":{"$ref":"#/$defs/TurnResult"},"turn":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["turn","result"],"type":"object"},"event":{"const":"turn_end","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"One LLM generation call started (1 request → 1 generation, retry\nincluded). Multiple `LlmCall*` pairs may fire inside a single\n`TurnStart` / `TurnEnd` pair when a request is retried; today\nthey fire 1:1 because retry is not implemented.\n\n`llm_call` is the worker-wide running counter from\n`Engine::llm_call_count`.","properties":{"data":{"additionalProperties":false,"properties":{"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["llm_call"],"type":"object"},"event":{"const":"llm_call_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"LLM generation call ended.","properties":{"data":{"additionalProperties":false,"properties":{"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["llm_call"],"type":"object"},"event":{"const":"llm_call_end","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A transport-level LLM request retry has been scheduled.\n\nThis is operational state for clients to render while the worker is\nwaiting in backoff. It is not part of conversation history.","properties":{"data":{"additionalProperties":false,"properties":{"elapsed_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"error":{"type":"string"},"failed_attempt":{"description":"The attempt that just failed. 1 origin.","format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"max_attempts":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"status":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":["integer","null"]},"wait_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["llm_call","failed_attempt","max_attempts","wait_ms","elapsed_ms","error"],"type":"object"},"event":{"const":"llm_retry","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Stream generation was interrupted after events had begun and the worker\nis continuing with a follow-up LLM request.","properties":{"data":{"additionalProperties":false,"properties":{"attempt":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"max_attempts":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"reason":{"type":"string"}},"required":["llm_call","attempt","max_attempts","reason"],"type":"object"},"event":{"const":"llm_continuation","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"text_delta","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"text_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A reasoning / thinking block has started.\n\nAlways paired with a `ThinkingDone`. `ThinkingDelta` is optional:\nsome providers (or some configurations) emit thinking metadata\nwithout plaintext, in which case Start → Done arrive with no\ndeltas in between. Multiple thinking blocks per turn are allowed.","properties":{"event":{"const":"thinking_start","type":"string"}},"required":["event"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"thinking_delta","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Thinking block completed. `text` is the full accumulated body\n(empty string when the provider didn't emit plaintext).","properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"thinking_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"event":{"const":"tool_call_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"id":{"type":"string"},"json":{"type":"string"}},"required":["id","json"],"type":"object"},"event":{"const":"tool_call_args_delta","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","arguments"],"type":"object"},"event":{"const":"tool_call_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"disposition":{"anyOf":[{"$ref":"#/$defs/ToolResultDisposition"},{"type":"null"}]},"id":{"type":"string"},"is_error":{"default":false,"type":"boolean"},"output":{"description":"Full tool output. Absent when the tool chose to return\nsummary-only, or when the result was pruned.","type":["string","null"]},"summary":{"description":"Short human-readable summary. Always present; used by clients\nthat only want a 1-line rendering (e.g. collapsed views).","type":"string"}},"required":["id","summary","is_error"],"type":"object"},"event":{"const":"tool_result","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Token accounting for one LLM request.\n\n`input_tokens` is the prompt prefix occupancy (cache reads /\ncache writes included), as normalised by the worker layer.\n`cache_read_input_tokens` is the cache-hit subset of that\noccupancy; subtracting it yields the \"net upload\" the client\nactually paid full price to send on this request, which is what\nthe TUI status line accumulates per turn.","properties":{"data":{"additionalProperties":false,"properties":{"cache_read_input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"output_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"timestamp_ms":{"description":"Present for usage delivered from the committed session-log lane.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]}},"type":"object"},"event":{"const":"usage","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Authoritative current-context occupancy after a non-request boundary.\n\nUnlike [`Event::Usage`], this is not cumulative request traffic. It lets\nconnected clients converge with reconnect snapshots after run completion,\ncompaction, rewind, and other history rewrites. `None` explicitly means\nthe current value is unavailable and stale occupancy must be cleared.","properties":{"data":{"additionalProperties":false,"properties":{"usage":{"anyOf":[{"$ref":"#/$defs/ContextUsage"},{"type":"null"}]}},"type":"object"},"event":{"const":"context_usage","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"result":{"$ref":"#/$defs/RunResult"}},"required":["result"],"type":"object"},"event":{"const":"run_end","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"code":{"$ref":"#/$defs/ErrorCode"},"message":{"type":"string"}},"required":["code","message"],"type":"object"},"event":{"const":"error","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Sent exactly once at the start of every client connection.\n\n`entries` is the session-log mirror at subscribe time, serialised\nas the JSON form of `session_store::LogEntry`. This is the\nbulk-reconstruction lane: clients walk the entries to seed their\nderived view.\n\n`greeting` and `status` accompany the snapshot so clients render\nworker identity and current controller state without an extra round\ntrip.\n\nLive updates after the snapshot arrive through the streaming\nevents (`TextDelta` / `ToolCall*` / `ToolResult` / etc.) plus\nrole-specific entry events (`SegmentRotated` / `SystemItem`) —\nthere is no generic \"every committed entry\" broadcast.","properties":{"data":{"additionalProperties":false,"properties":{"greeting":{"$ref":"#/$defs/Greeting"},"in_flight":{"$ref":"#/$defs/InFlightSnapshot","description":"Unfinished model output that has already streamed in the current\nrun but is not yet represented by committed snapshot entries."},"internal_workers":{"description":"Parent-owned Internal Worker sessions visible to this client.\nService-private Internal Workers are deliberately excluded.","items":{"$ref":"#/$defs/InternalWorkerSnapshot"},"type":"array"},"session":{"$ref":"#/$defs/SessionSnapshot"},"state":{"$ref":"#/$defs/WorkerStateSnapshot","description":"Full live execution state. `Stopped` remains Runtime\ncatalog authority and is deliberately not represented here."}},"required":["session","greeting","state"],"type":"object"},"event":{"const":"snapshot","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A live event from a parent-owned Internal Worker. The payload reuses the\nnormal Worker event vocabulary while the wrapper carries stable origin\nidentity. Apply in arrival order on the parent's serialized stream; a\nreconnect snapshot replaces the projection before live events resume.","properties":{"data":{"additionalProperties":false,"properties":{"event":{"$ref":"#/$defs/Event"},"worker":{"$ref":"#/$defs/InternalWorkerRef"}},"required":["worker","event"],"type":"object"},"event":{"const":"internal_worker","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Terminal removal fence for one parent-owned Internal Worker session.\n\nClients discard the matching child and descendants, then ignore later\nnested events for this identity until an authoritative snapshot replaces\nthe projection.","properties":{"data":{"additionalProperties":false,"properties":{"worker":{"$ref":"#/$defs/InternalWorkerRef"}},"required":["worker"],"type":"object"},"event":{"const":"internal_worker_removed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Server-side segment log rotated to a fresh `SegmentStart`.\n\nFires on compaction and on auto-fork when the store head drifts\nA compaction/fork has replaced the authoritative segment. Clients drop\ntheir derived view and reseed from the canonical committed snapshot.","properties":{"data":{"additionalProperties":false,"properties":{"session":{"$ref":"#/$defs/SessionSnapshot"}},"required":["session"],"type":"object"},"event":{"const":"segment_rotated","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Current Worker controller status. Broadcast on every controller-level\ntransition and included in `History` snapshots for late attach.","properties":{"data":{"additionalProperties":false,"properties":{"snapshot":{"$ref":"#/$defs/WorkerStateSnapshot"}},"required":["snapshot"],"type":"object"},"event":{"const":"worker_state","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"acknowledgement":{"$ref":"#/$defs/WorkerCommandAcknowledgement"}},"required":["acknowledgement"],"type":"object"},"event":{"const":"command_acknowledged","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Bounded, provider-owned command telemetry for the live Console. This is\nintentionally not a history entry and is reconstructed from\n`Snapshot.in_flight.commands` after reconnect.","properties":{"data":{"additionalProperties":false,"properties":{"event":{"$ref":"#/$defs/CommandEvent"}},"required":["event"],"type":"object"},"event":{"const":"command","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::ListCompletions`. Delivered only to the\nrequesting socket (not broadcast). `entries` is empty when no\ncandidates match or when the requested kind has no resolver\nwired up.","properties":{"data":{"additionalProperties":false,"properties":{"context":{"anyOf":[{"$ref":"#/$defs/CompletionContext"},{"type":"null"}]},"entries":{"items":{"$ref":"#/$defs/CompletionEntry"},"type":"array"},"kind":{"$ref":"#/$defs/CompletionKind"},"prefix":{"default":"","type":"string"},"request_id":{"type":["string","null"]}},"required":["kind","entries","prefix"],"type":"object"},"event":{"const":"completions","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A rewind has truncated the authoritative session. `session` is the\nretained canonical snapshot clients should use to reseed display state.","properties":{"data":{"additionalProperties":false,"properties":{"input":{"items":{"$ref":"#/$defs/Segment"},"type":"array"},"session":{"$ref":"#/$defs/SessionSnapshot"},"summary":{"$ref":"#/$defs/RewindSummary"}},"required":["session","input","summary"],"type":"object"},"event":{"const":"rewind_applied","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::ListWorkers`. Payload is a stable JSON value so the Worker\ncrate can evolve discovery fields without introducing a protocol\ndependency on session-store.","properties":{"data":{"additionalProperties":false,"properties":{"workers":true},"required":["workers"],"type":"object"},"event":{"const":"workers_listed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::RestoreWorker`.","properties":{"data":{"additionalProperties":false,"properties":{"result":true},"required":["result"],"type":"object"},"event":{"const":"worker_restored","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::RegisterPeer`.","properties":{"data":{"additionalProperties":false,"properties":{"result":true},"required":["result"],"type":"object"},"event":{"const":"peer_registered","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"$ref":"#/$defs/Alert"},"event":{"const":"alert","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Latest memory extract/consolidation lifecycle event for UI observability.\n\nThis is not part of LLM history or prompt context; clients may display it\nbriefly as operational status.","properties":{"data":{"$ref":"#/$defs/MemoryWorkerEvent"},"event":{"const":"memory_worker","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Runtime-only compaction progress. `None` clears the current status.\nThis never enters Session history and carries no operation or Segment identity.","properties":{"data":{"additionalProperties":false,"properties":{"compaction":{"anyOf":[{"$ref":"#/$defs/InFlightCompaction"},{"type":"null"}]}},"type":"object"},"event":{"const":"compaction_progress","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Legacy compaction lifecycle event retained for wire read compatibility.","properties":{"data":{"additionalProperties":false,"properties":{"lifecycle":{"$ref":"#/$defs/CompactionLifecycle"}},"required":["lifecycle"],"type":"object"},"event":{"const":"compact_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Compaction completed and the session was rotated.","properties":{"data":{"additionalProperties":false,"properties":{"lifecycle":{"$ref":"#/$defs/CompactionLifecycle"}},"required":["lifecycle"],"type":"object"},"event":{"const":"compact_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Compaction failed or was cancelled. The session is unchanged.","properties":{"data":{"additionalProperties":false,"properties":{"lifecycle":{"$ref":"#/$defs/CompactionLifecycle"}},"required":["lifecycle"],"type":"object"},"event":{"const":"compact_failed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"event":{"const":"shutdown","type":"string"}},"required":["event"],"type":"object"}]},"EventSubscriptionSelector":{"oneOf":[{"additionalProperties":false,"properties":{"topic":{"const":"runtime_workers","type":"string"}},"required":["topic"],"type":"object"},{"additionalProperties":false,"properties":{"topic":{"const":"worker_lifecycle","type":"string"},"worker_ids":{"$ref":"#/$defs/SubscriptionWorkerIds"}},"required":["topic","worker_ids"],"type":"object"},{"additionalProperties":false,"properties":{"runtime_id":{"type":["string","null"]},"topic":{"const":"worker_protocol","type":"string"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["topic","worker_id"],"type":"object"},{"additionalProperties":false,"description":"Server-derived Workspace projection. Workspace identity comes from the\nauthenticated connection and is deliberately absent from this selector.","properties":{"topic":{"const":"workspace_workers","type":"string"}},"required":["topic"],"type":"object"},{"additionalProperties":false,"description":"Typed extension point for the later Workdir subscription slice.","properties":{"topic":{"const":"workspace_workdirs","type":"string"}},"required":["topic"],"type":"object"}]},"FeatureInvocation":{"additionalProperties":false,"properties":{"arguments":{"items":{"$ref":"#/$defs/InvocationArgumentValue"},"type":"array"},"identity":{"$ref":"#/$defs/FeatureInvocationIdentity"},"invocation_id":{"description":"Stable client-generated id retained across queueing and transport retry.","type":"string"},"name":{"description":"Selected public name, retained for exact draft/history restoration. Host\nresolution is always by `identity`.","type":"string"}},"required":["invocation_id","identity","name","arguments"],"type":"object"},"FeatureInvocationDescriptor":{"additionalProperties":false,"properties":{"aliases":{"default":[],"items":{"type":"string"},"type":"array"},"arguments":{"default":[],"items":{"$ref":"#/$defs/InvocationArgumentDescriptor"},"type":"array"},"client_adapter":{"anyOf":[{"$ref":"#/$defs/InvocationClientAdapter"},{"type":"null"}]},"description":{"type":"string"},"display_name":{"type":"string"},"identity":{"$ref":"#/$defs/FeatureInvocationIdentity"},"name":{"type":"string"},"syntax":{"$ref":"#/$defs/FeatureInvocationSyntax"}},"required":["identity","name","display_name","description","syntax","aliases","arguments"],"type":"object"},"FeatureInvocationIdentity":{"description":"Source-qualified identity of one invocation contribution, for example\n`builtin:attachments/attach`. Display names and aliases are never authority.","type":"string"},"FeatureInvocationSyntax":{"oneOf":[{"const":"parenthesized","description":"`/name(value, key=value)` with JSON-style quoted strings and `)` as the\nexplicit boundary before following natural language.","type":"string"}]},"Greeting":{"additionalProperties":false,"description":"Worker self-description rendered by clients when a session starts empty.\n\nSnapshot metadata contains only resolved public execution information so\nclients do not need their own copy of the manifest.","properties":{"context_tokens":{"default":0,"description":"Legacy numeric mirror retained for mixed-version clients.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"context_usage":{"anyOf":[{"$ref":"#/$defs/ContextUsage"},{"type":"null"}],"description":"Typed current-context value. Older snapshots omit it; clients may fall\nback to `context_tokens` only when `context_window` is known."},"context_window":{"default":0,"description":"Resolved effective model context window in tokens. Legacy producers use\nzero when this is unavailable; clients must treat that as unknown.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"cwd":{"type":"string"},"model":{"type":"string"},"provider":{"type":"string"},"reasoning":{"anyOf":[{"$ref":"#/$defs/ReasoningConfig"},{"type":"null"}],"description":"Effective reasoning control. Absent means unspecified or unavailable."},"scope_summary":{"type":"string"},"tools":{"items":{"type":"string"},"type":"array"},"worker_name":{"type":"string"}},"required":["worker_name","cwd","provider","model","scope_summary","tools","context_tokens","context_window"],"type":"object"},"InFlightBlock":{"oneOf":[{"additionalProperties":false,"properties":{"finished":{"type":"boolean"},"kind":{"const":"text","type":"string"},"text":{"type":"string"}},"required":["kind","text"],"type":"object"},{"additionalProperties":false,"properties":{"finished":{"type":"boolean"},"kind":{"const":"thinking","type":"string"},"text":{"type":"string"}},"required":["kind","text"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"type":"string"},"id":{"type":"string"},"kind":{"const":"tool_call","type":"string"},"name":{"type":"string"},"state":{"$ref":"#/$defs/InFlightToolCallState"}},"required":["kind","id","name","args"],"type":"object"}]},"InFlightCompaction":{"additionalProperties":false,"properties":{"phase":{"$ref":"#/$defs/CompactionPhase"},"started_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"trigger":{"$ref":"#/$defs/CompactionTrigger"}},"required":["phase","started_at_ms","trigger"],"type":"object"},"InFlightSnapshot":{"additionalProperties":false,"description":"Unfinished model output and active command state included in\n`Event::Snapshot` for clients that attach while work is still streaming.\n\nThese blocks are presentation state only: they are reconstructed from the\nactive Worker controller and must not be treated as committed assistant\nhistory. Finalized assistant items continue to come from ordinary snapshot\nentries.","properties":{"block_ids":{"description":"Live-Worker identities parallel to the blocks actually included below.","items":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"type":"array"},"blocks":{"items":{"$ref":"#/$defs/InFlightBlock"},"type":"array"},"commands":{"items":{"$ref":"#/$defs/CommandSnapshot"},"type":"array"},"compaction":{"anyOf":[{"$ref":"#/$defs/InFlightCompaction"},{"type":"null"}],"description":"The currently running compaction, if any.\n\nThis is lifecycle progress only. Candidate history and the staged\nSegment remain private until the Segment is activated atomically."}},"type":"object"},"InFlightToolCallState":{"enum":["pending","streaming_args","done"],"type":"string"},"InternalWorkerKind":{"description":"Presentation category for an Internal Worker exposed through its parent's\nprotocol stream. Internal Workers never become independently addressable\nprotocol subjects.","oneOf":[{"enum":["sub_worker"],"type":"string"},{"additionalProperties":false,"properties":{"service":{"additionalProperties":false,"properties":{"kind":{"type":"string"}},"required":["kind"],"type":"object"}},"required":["service"],"type":"object"}]},"InternalWorkerRef":{"additionalProperties":false,"description":"Stable presentation identity for one parent-owned Internal Worker session.\n`name` is display-only; `session_id` is the identity used by clients.","properties":{"kind":{"$ref":"#/$defs/InternalWorkerKind"},"name":{"type":"string"},"parent_session_id":{"type":["string","null"]},"session_id":{"type":"string"}},"required":["session_id","name","kind"],"type":"object"},"InternalWorkerSnapshot":{"additionalProperties":false,"description":"Reconnect state for one visible Internal Worker. The parent serializes\nsnapshot publication and subsequent live events on the same ordered stream.","properties":{"error":{"type":["string","null"]},"greeting":{"anyOf":[{"$ref":"#/$defs/Greeting"},{"type":"null"}],"description":"Public execution metadata for this child. Older snapshots and service\nworkers may omit it; clients must never substitute the parent's values."},"in_flight":{"$ref":"#/$defs/InFlightSnapshot"},"internal_workers":{"items":{"$ref":"#/$defs/InternalWorkerSnapshot"},"type":"array"},"session":{"$ref":"#/$defs/SessionSnapshot"},"status":{"$ref":"#/$defs/WorkerStatus","default":"idle"},"worker":{"$ref":"#/$defs/InternalWorkerRef"}},"required":["worker","session","status"],"type":"object"},"InvocationArgumentDescriptor":{"additionalProperties":false,"properties":{"completion":{"$ref":"#/$defs/InvocationCompletion","default":{"kind":"none"}},"description":{"type":["string","null"]},"name":{"type":"string"},"position":{"description":"Zero-based positional index. `None` means named-only. A positional\nargument may also be supplied by name; this makes chip editing stable.","format":"uint16","maximum":65535.0,"minimum":0.0,"type":["integer","null"]},"required":{"default":false,"type":"boolean"},"value_type":{"$ref":"#/$defs/InvocationArgumentType"}},"required":["name","value_type","completion","required"],"type":"object"},"InvocationArgumentType":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"string","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"integer","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"boolean","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"enum","type":"string"},"values":{"items":{"type":"string"},"type":"array"}},"required":["kind","values"],"type":"object"},{"additionalProperties":false,"description":"A Worker-readable path. This does not grant filesystem authority.","properties":{"kind":{"const":"worker_file","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"description":"A resource selected and staged by the client. It must never be resolved\nas a path on the Worker host.","properties":{"kind":{"const":"client_file","type":"string"}},"required":["kind"],"type":"object"}]},"InvocationArgumentValue":{"additionalProperties":false,"properties":{"name":{"type":"string"},"value":{"$ref":"#/$defs/InvocationValue"}},"required":["name","value"],"type":"object"},"InvocationClientAdapter":{"oneOf":[{"const":"attachment","description":"The client stages a local file and replaces the draft invocation with an\n`UploadedFile` chip. Local paths are not sent to or persisted by Worker.","type":"string"}]},"InvocationCompletion":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"none","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"static","type":"string"},"values":{"items":{"type":"string"},"type":"array"}},"required":["kind","values"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"worker_file","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"client_file","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"description":"Host-owned provider selected by source-qualified id. Metadata lookup is\nside-effect free; implementations never cross this wire boundary.","properties":{"kind":{"const":"provider","type":"string"},"provider":{"type":"string"}},"required":["kind","provider"],"type":"object"}]},"InvocationValue":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"string","type":"string"},"value":{"type":"string"}},"required":["kind","value"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"integer","type":"string"},"value":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":"integer"}},"required":["kind","value"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"boolean","type":"string"},"value":{"type":"boolean"}},"required":["kind","value"],"type":"object"}]},"InvokeKind":{"description":"Kind of trigger that opened a new Invoke (IDLE → active) range.\n\nOne Invoke groups all entries from this trigger up to the next\n`Invoke` marker. The kind is the only payload — content (user text,\nnotify message, worker event body) is delivered by the immediately\nfollowing Turn entry, not by the marker itself.","oneOf":[{"const":"user_send","description":"`Method::Submit` — a user submission.","type":"string"},{"const":"notify","description":"`Method::Notify` — free-text notification injected into history.","type":"string"},{"const":"worker_event","description":"`Method::WorkerEvent` — typed lifecycle report from a child Worker.","type":"string"},{"const":"system_reminder","description":"A typed system reminder that crosses an IDLE boundary (mid-run\nreminders that don't break IDLE are SystemItem-only and do not\nopen a new Invoke).","type":"string"},{"const":"wakeup","description":"Cron / RemoteTrigger style scheduled wake-up. Reserved; no\nproducer is wired today but the variant is part of the initial\nset so future schedulers don't have to amend the wire enum.","type":"string"}]},"MemoryWorkerEvent":{"additionalProperties":false,"properties":{"message":{"description":"Human-readable compact form for actionbar rendering.","type":"string"},"reason":{"type":"string"},"run_id":{"type":"string"},"status":{"type":"string"},"timestamp_ms":{"description":"Milliseconds since the Unix epoch.","format":"int64","maximum":9007199254740991.0,"minimum":-9007199254740991.0,"type":"integer"},"trigger":{"type":"string"},"worker":{"type":"string"}},"required":["worker","status","run_id","trigger","reason","message","timestamp_ms"],"type":"object"},"Method":{"oneOf":[{"additionalProperties":false,"description":"Durably accept typed input for immediate activation or the session FIFO.\nRunning or Paused Workers queue Submit for a later turn; use Notify for\nadvisory information to incorporate into work already in progress.\n\n`submission_request_id` is generated by the authenticated caller and is\nused only for idempotent retry. Worker allocates the durable\n`submission_id` returned by [`Event::SubmissionAccepted`].","properties":{"method":{"const":"submit","type":"string"},"params":{"additionalProperties":false,"properties":{"input":{"items":{"$ref":"#/$defs/Segment"},"type":"array"},"submission_request_id":{"type":"string"}},"required":["submission_request_id","input"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Human-readable text injected into the target Worker's LLM context as a\nnon-blocking system message. Accepted notifications are delivered at the\nnext between-turn boundary, or start a coalesced notification run while\nthe Worker is idle. No side effects beyond LLM context; use\n`WorkerEvent` for typed lifecycle reports.","properties":{"method":{"const":"notify","type":"string"},"params":{"additionalProperties":false,"properties":{"message":{"type":"string"},"notification_request_id":{"type":"string"}},"required":["notification_request_id","message"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Typed lifecycle report from a child Worker to its direct parent.","properties":{"method":{"const":"worker_event","type":"string"},"params":{"$ref":"#/$defs/WorkerEvent"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Return the authoritative FIFO summary without exposing queued payloads.","properties":{"method":{"const":"list_pending_submissions","type":"string"}},"required":["method"],"type":"object"},{"additionalProperties":false,"description":"Remove one queued submission. Running or already activated submissions\nare immutable and therefore cannot be cancelled here.","properties":{"method":{"const":"cancel_pending_submission","type":"string"},"params":{"additionalProperties":false,"properties":{"submission_id":{"type":"string"}},"required":["submission_id"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Remove exactly the observed ordered set of submissions, preserving the\nactive run. Reject if the FIFO content changed before admission.","properties":{"method":{"const":"clear_pending_submissions","type":"string"},"params":{"additionalProperties":false,"properties":{"expected_submission_ids":{"items":{"type":"string"},"type":"array"}},"required":["expected_submission_ids"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Activate the next queued submission while the Worker is idle. This is an\nexplicit recovery operation and never resumes a paused run implicitly.","properties":{"method":{"const":"continue_pending","type":"string"},"params":{"additionalProperties":false,"properties":{"expected_head_id":{"type":"string"}},"required":["expected_head_id"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"resume","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"cancel","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Stop the in-flight turn and transition to `Paused`.\n\nUnlike `Cancel` (which discards and returns to `Idle`), a paused\nWorker can resume the interrupted work via `Resume`, or accept a\nfresh `Submit` (orphan `tool_use` items are closed with a\nsynthetic tool result before the new user message is appended).","properties":{"method":{"const":"pause","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Request an explicit compaction while the Worker is otherwise idle.\n\nThis is a typed control method: clients must not send `compact` as a\n`Method::Submit` user message.","properties":{"method":{"const":"compact","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Rewind to just before a user input identified by its public Session entry ID.\nValidate the target against the current segment at execution time.\nLater appended history is discarded too; tool side effects are not undone.","properties":{"method":{"const":"rewind_to","type":"string"},"params":{"additionalProperties":false,"properties":{"entry_id":{"type":"string"}},"required":["entry_id"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"shutdown","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Request a list of completion candidates from the Worker.\n\nReply is sent on the same socket as `Event::Completions` (not\nbroadcast). The IPC server handles this directly and writes\nthe response straight back to the requesting socket.","properties":{"method":{"const":"list_completions","type":"string"},"params":{"additionalProperties":false,"properties":{"context":{"anyOf":[{"$ref":"#/$defs/CompletionContext"},{"type":"null"}]},"kind":{"$ref":"#/$defs/CompletionKind"},"prefix":{"type":"string"},"request_id":{"description":"Client query identity. Echoed verbatim so identical-prefix ABA\nresponses cannot cross edits, target switches, or permission changes.","type":["string","null"]}},"required":["kind","prefix"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"List Workers visible to this Worker from durable Worker state and the spawned-child\nregistry. This is not a host-wide Worker universe query.","properties":{"method":{"const":"list_workers","type":"string"}},"required":["method"],"type":"object"},{"additionalProperties":false,"description":"Restore a visible stopped/restorable Worker, or report that it is already\nlive. Missing state and not-visible state are distinct errors.","properties":{"method":{"const":"restore_worker","type":"string"},"params":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Register another existing Worker as a reciprocal peer of this Worker.\n\nThis is metadata/control state only: it does not ask the target's live\ncontroller for consent, and it must not grant delegated scope,\nspawned-child ownership, output cursors, or child lifecycle authority.","properties":{"method":{"const":"register_peer","type":"string"},"params":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}},"required":["method","params"],"type":"object"}]},"PasteArtifactAvailability":{"enum":["available","unavailable","integrity_failed"],"type":"string"},"PasteArtifactMediaType":{"description":"One typed piece of a user submission.\n\n`Method::Submit` and `Event::UserMessage` carry `Vec`. Dumb\nclients (CLI piping, scripts) only need to produce a single\n`Segment::Text`; richer clients (TUI / GUI) construct typed atoms\n(paste chips, file refs) and\nsend them through directly so the Worker side never has to re-parse a\nflattened string.\n\nForward compat: payloads with unknown `kind` deserialize to\n`Segment::Unknown`. Worker treats this the same as known-but-unresolved\nvariants — emits an alert and inserts a `[unknown input segment]`\nplaceholder into the LLM context so neither user nor LLM is blind to\nthe dropped intent.","enum":["text_plain_utf8"],"type":"string"},"PasteArtifactRef":{"additionalProperties":false,"description":"Session-owned reference to a large pasted-input artifact.\n\nThe reference contains only bounded integrity and provenance metadata. The\nartifact body remains in session storage and is available to the model only\nthrough the scoped paste-artifact tools installed by Worker.","properties":{"artifact_id":{"type":"string"},"availability":{"$ref":"#/$defs/PasteArtifactAvailability","description":"Availability observed when this immutable reference was committed.\nReads revalidate storage and integrity rather than trusting this field."},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"char_count":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"created_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"line_count":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"media_type":{"$ref":"#/$defs/PasteArtifactMediaType"},"sha256":{"type":"string"},"source_entry_id":{"type":"string"}},"required":["artifact_id","created_at_ms","media_type","availability","byte_len","char_count","line_count","sha256","source_entry_id"],"type":"object"},"PendingSubmissionSummary":{"additionalProperties":false,"description":"Bounded public projection of one pending submission. Only a short display\npreview is exposed; full payload segments and provenance remain in the log.","properties":{"accepted_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"preview":{"description":"Single-line display text, at most 240 Unicode scalars plus an ellipsis.\nAbsent on older runtimes. Never used to reconstruct the submitted input.","type":["string","null"]},"segment_count":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"submission_id":{"type":"string"}},"required":["submission_id","accepted_at_ms","segment_count","byte_len"],"type":"object"},"PendingSubmissionsSnapshot":{"additionalProperties":false,"description":"Session-owned FIFO content projection used by snapshots and live events.","properties":{"head_id":{"default":null,"type":["string","null"]},"notification_count":{"default":0,"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"notification_previews":{"description":"Ordered display-only previews of waiting notifications, each bounded like\nPendingSubmissionSummary::preview. Older runtimes omit this field.","items":{"type":"string"},"type":"array"},"submissions":{"default":[],"items":{"$ref":"#/$defs/PendingSubmissionSummary"},"type":"array"}},"required":["head_id","notification_count","submissions"],"type":"object"},"Permission":{"description":"Permission lattice used by [`ScopeRule`].\n\nThe derived `Ord` instance follows declaration order, so\n`Read < Write`. Allow rules grant the stated level (and by extension\neverything below); deny rules cap the effective level **strictly\nbelow** the stated level.","enum":["read","write"],"type":"string"},"ReasoningConfig":{"description":"Public reasoning configuration resolved for the model client.\n\nThis deliberately exposes only the effective provider control, not the\nWorker manifest or provider credentials. The tagged shape prevents token\nbudgets from being presented as effort labels.","oneOf":[{"additionalProperties":false,"properties":{"effort":{"type":"string"},"kind":{"const":"effort","type":"string"}},"required":["kind","effort"],"type":"object"},{"additionalProperties":false,"properties":{"budget_tokens":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":"integer"},"kind":{"const":"budget_tokens","type":"string"}},"required":["kind","budget_tokens"],"type":"object"}]},"RewindSummary":{"additionalProperties":false,"properties":{"discarded_entries":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"tool_side_effect_warning":{"type":"boolean"},"truncated_to_entries":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["truncated_to_entries","discarded_entries","tool_side_effect_warning"],"type":"object"},"RunFailureKind":{"enum":["engine","compaction"],"type":"string"},"RunResult":{"oneOf":[{"enum":["finished","paused","limit_reached"],"type":"string"},{"const":"cancelled","description":"The logical Run ended because the user intentionally cancelled it after\nobservable work. Unlike `RolledBack`, committed history is retained.","type":"string"},{"const":"rolled_back","description":"The accepted Method::Submit produced no assistant/tool output before\nuser interruption, so the Worker rolled the submit-time turn state back\nto its pre-submit snapshot. Clients should treat the Worker as Idle and\nrestore the just-submitted input into the editable composer if desired.","type":"string"}]},"RunResumeSource":{"enum":["compaction","pause"],"type":"string"},"RunYieldReason":{"enum":["compaction"],"type":"string"},"ScopeRule":{"additionalProperties":false,"description":"A single allow or deny rule inside a scope configuration.","properties":{"permission":{"$ref":"#/$defs/Permission","description":"Permission level this rule grants (allow) or caps strictly below\n(deny)."},"recursive":{"default":true,"description":"When `false`, the rule only matches the target itself and its\ndirect children. Defaults to `true`.","type":"boolean"},"symlink_policy":{"$ref":"#/$defs/SymlinkPolicy","default":"resolved","description":"Which path identity an allow rule uses when symbolic links are\nencountered. Deny rules always inspect both identities."},"target":{"description":"Target path. Must be absolute by the time a `Scope` is built from\nthis rule — relative paths are resolved per-layer against the\nmanifest file's directory (cwd for overlay layers) before cascade\nmerge.","type":"string"}},"required":["target","permission","recursive","symlink_policy"],"type":"object"},"Segment":{"oneOf":[{"additionalProperties":false,"description":"Free-form text. The fallback every client can produce.","properties":{"content":{"type":"string"},"kind":{"const":"text","type":"string"}},"required":["kind","content"],"type":"object"},{"additionalProperties":false,"description":"Bracketed-paste capture from a TUI-style client. `id`, `chars`\nand `lines` carry the metadata needed to re-render a\n`[Clipboard #N | X chars, Y lines]` chip in `Event::UserMessage`\nre-broadcast.","properties":{"chars":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"content":{"type":"string"},"id":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"kind":{"const":"paste","type":"string"},"lines":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"}},"required":["kind","id","chars","lines","content"],"type":"object"},{"additionalProperties":false,"description":"Internal reference produced when Worker stores a large `Paste` before\ncommitting input. Clients may receive this in history/event projections;\nthe body is intentionally absent.","properties":{"artifact":{"$ref":"#/$defs/PasteArtifactRef"},"kind":{"const":"paste_artifact","type":"string"}},"required":["kind","artifact"],"type":"object"},{"additionalProperties":false,"description":"Client-local file uploaded into the owning Worker session before submit.\nThe Session Log stores only this immutable reference, never file bytes or\nthe client's local path.","properties":{"file":{"$ref":"#/$defs/UploadedFileRef"},"kind":{"const":"uploaded_file","type":"string"}},"required":["kind","file"],"type":"object"},{"additionalProperties":false,"description":"`@` file-system reference. Worker resolves readable files to\n`[File: ]` attachments and readable normal directories to shallow\n`[Dir: ]` listings; the flattened user text keeps the literal\n`@` placeholder either way.","properties":{"kind":{"const":"file_ref","type":"string"},"path":{"type":"string"}},"required":["kind","path"],"type":"object"},{"additionalProperties":false,"description":"Explicitly selected, source-qualified Feature invocation. The host never\npromotes free text to this variant and validates it against the installed\ndeclaration before execution.","properties":{"invocation":{"$ref":"#/$defs/FeatureInvocation"},"kind":{"const":"feature_invoke","type":"string"}},"required":["kind","invocation"],"type":"object"},{"additionalProperties":false,"description":"Source-qualified request for the host to start a Flow before committing\nthis user input. Runtime resolves it through Workspace authority and\nreplaces it with the entered state's instructions before Worker-side\ninput resolution.","properties":{"kind":{"const":"flow","type":"string"},"selector":{"type":"string"}},"required":["kind","selector"],"type":"object"},{"additionalProperties":false,"description":"Unknown variant from a newer client. Worker treats this as an\nunresolved input — surfaces an alert and inserts a placeholder.\nRound-trip is lossy: re-serializing yields `{\"kind\":\"unknown\"}`.","properties":{"kind":{"const":"unknown","type":"string"}},"required":["kind"],"type":"object"}]},"SessionContentPart":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"text","type":"string"},"text":{"type":"string"}},"required":["kind","text"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"refusal","type":"string"},"refusal":{"type":"string"}},"required":["kind","refusal"],"type":"object"}]},"SessionEntryProvenance":{"enum":["human_input","worker_input","flow_instruction","backend_instruction","model_output","tool_output","derived_summary","legacy_unknown"],"type":"string"},"SessionMessageRole":{"enum":["user","assistant"],"type":"string"},"SessionSnapshot":{"additionalProperties":false,"description":"Canonical, storage-independent projection of committed session history.\n\nWorker protocols expose this DTO instead of append-log records. New\nstorage variants can therefore be added without teaching every client how\nto replay the durable log format.","properties":{"entries":{"items":{"$ref":"#/$defs/SessionSnapshotEntry"},"type":"array"},"pending_submissions":{"$ref":"#/$defs/PendingSubmissionsSnapshot","default":{"head_id":null,"notification_count":0,"submissions":[]}}},"required":["entries","pending_submissions"],"type":"object"},"SessionSnapshotEntry":{"oneOf":[{"additionalProperties":false,"properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"user_input","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"segments":{"items":{"$ref":"#/$defs/Segment"},"type":"array"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","segments","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"content":{"items":{"$ref":"#/$defs/SessionContentPart"},"type":"array"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"message","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"role":{"$ref":"#/$defs/SessionMessageRole"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","role","content","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"arguments":{"type":"string"},"call_id":{"type":"string"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"tool_call","type":"string"},"name":{"type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","call_id","name","arguments","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"attachments":{"items":{"$ref":"#/$defs/SessionToolAttachment"},"type":"array"},"call_id":{"type":"string"},"content":{"type":["string","null"]},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"is_error":{"type":"boolean"},"kind":{"const":"tool_result","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"summary":{"type":"string"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","call_id","summary","is_error","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"content":{"type":"string"},"data":true,"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"item_kind":{"type":"string"},"kind":{"const":"system_item","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","item_kind","content","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Durable, non-terminal control return from one logical Run. This is not a\ncompleted run and must not be used to infer the current Worker state.","properties":{"active_run_turn_count":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_yielded","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"reason":{"$ref":"#/$defs/RunYieldReason"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","reason","active_run_turn_count","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Durable boundary immediately before Engine execution resumes. The source\ndistinguishes automatic compaction continuation from an intentional\nuser-pause resume; it does not prove that later model output occurred.","properties":{"active_run_turn_count":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_resumed","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"source":{"$ref":"#/$defs/RunResumeSource"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","source","active_run_turn_count","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Snapshot-only replay of persisted invocation/usage records. These are\naccounting metadata, never model context or conversation rows.","properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"invoke","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"trigger":{"$ref":"#/$defs/InvokeKind"}},"required":["kind","trigger","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"cache_read_input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"kind":{"const":"usage","type":"string"},"output_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","input_tokens","cache_read_input_tokens","output_tokens","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Display-only accounting reconstructed from persisted run/usage records.","properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"elapsed_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_stats","type":"string"},"output_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"requests":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"upload_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","elapsed_ms","requests","upload_tokens","output_tokens","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Durable terminal for an intentional cancellation. Consumers must not\npresent this lifecycle result as an execution failure.","properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_cancelled","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"failure":{"anyOf":[{"$ref":"#/$defs/RunFailureKind"},{"type":"null"}]},"kind":{"const":"run_error","type":"string"},"message":{"type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","message","entry_id","timestamp","provenance"],"type":"object"}]},"SessionToolAttachment":{"additionalProperties":false,"properties":{"attachment_id":{"description":"Stable, bounded identity derived from the owning Session entry, attachment\nposition, and immutable image bytes. It is a locator, not a bearer secret.","type":"string"},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"media_type":{"type":"string"}},"required":["attachment_id","media_type","byte_len"],"type":"object"},"SubmissionDisposition":{"description":"Durable acceptance result for one idempotent Submit request.","oneOf":[{"enum":["started"],"type":"string"},{"const":"queued","description":"Input is durably held in the session FIFO until eligible for activation.","type":"string"}]},"SubscriptionEvent":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"payload":{"$ref":"#/$defs/SubscriptionEventPayload"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["subscription_id","payload"],"type":"object"},"event":{"const":"event","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"code":{"$ref":"#/$defs/SubscriptionTerminationCode"},"message":{"type":"string"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["subscription_id","code","message"],"type":"object"},"event":{"const":"subscription_closed","type":"string"}},"required":["event","data"],"type":"object"}]},"SubscriptionEventPayload":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"worker":{"$ref":"#/$defs/SubscriptionWorker"}},"required":["worker"],"type":"object"},"event":{"const":"worker_upserted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"runtime_id":{"type":["string","null"]},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["worker_id"],"type":"object"},"event":{"const":"worker_removed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"event":{"$ref":"#/$defs/Event"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["worker_id","event"],"type":"object"},"event":{"const":"worker_protocol","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"workdir":{"$ref":"#/$defs/WorkspaceSubscriptionWorkdir"}},"required":["workdir"],"type":"object"},"event":{"const":"workdir_upserted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"working_directory_id":{"$ref":"#/$defs/SubscriptionWorkdirId"}},"required":["working_directory_id"],"type":"object"},"event":{"const":"workdir_removed","type":"string"}},"required":["event","data"],"type":"object"}]},"SubscriptionId":{"type":"string"},"SubscriptionRejectionCode":{"enum":["invalid_request","unsupported_protocol_version","unsupported_selector","unauthorized","resource_not_found","capacity_exceeded","internal"],"type":"string"},"SubscriptionRequest":{"oneOf":[{"additionalProperties":false,"properties":{"method":{"const":"subscribe_events","type":"string"},"params":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"selector":{"$ref":"#/$defs/EventSubscriptionSelector"}},"required":["request_id","selector"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"unsubscribe_events","type":"string"},"params":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["request_id","subscription_id"],"type":"object"}},"required":["method","params"],"type":"object"}]},"SubscriptionRequestId":{"type":"string"},"SubscriptionResponse":{"oneOf":[{"additionalProperties":false,"properties":{"payload":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"selector":{"$ref":"#/$defs/EventSubscriptionSelector"},"snapshot":{"$ref":"#/$defs/SubscriptionSnapshot"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["request_id","subscription_id","selector","snapshot"],"type":"object"},"result":{"const":"subscribed","type":"string"}},"required":["result","payload"],"type":"object"},{"additionalProperties":false,"properties":{"payload":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["request_id","subscription_id"],"type":"object"},"result":{"const":"unsubscribed","type":"string"}},"required":["result","payload"],"type":"object"},{"additionalProperties":false,"properties":{"payload":{"additionalProperties":false,"properties":{"code":{"$ref":"#/$defs/SubscriptionRejectionCode"},"message":{"type":"string"},"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"subscription_id":{"anyOf":[{"$ref":"#/$defs/SubscriptionId"},{"type":"null"}]}},"required":["request_id","code","message"],"type":"object"},"result":{"const":"subscription_rejected","type":"string"}},"required":["result","payload"],"type":"object"}]},"SubscriptionSnapshot":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"workers":{"items":{"$ref":"#/$defs/SubscriptionWorker"},"type":"array"}},"required":["workers"],"type":"object"},"topic":{"const":"workers","type":"string"}},"required":["topic","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"events":{"items":{"$ref":"#/$defs/Event"},"type":"array"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["worker_id","events"],"type":"object"},"topic":{"const":"worker_protocol","type":"string"}},"required":["topic","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"workdirs":{"items":{"$ref":"#/$defs/WorkspaceSubscriptionWorkdir"},"type":"array"}},"required":["workdirs"],"type":"object"},"topic":{"const":"workspace_workdirs","type":"string"}},"required":["topic","data"],"type":"object"}]},"SubscriptionTerminationCode":{"enum":["lagged","resource_gone","unauthorized","server_shutdown"],"type":"string"},"SubscriptionWorkdirId":{"type":"string"},"SubscriptionWorker":{"additionalProperties":false,"properties":{"availability":{"$ref":"#/$defs/SubscriptionWorkerAvailability","default":"observed","description":"Freshness of the Runtime-backed observation carried by this projection.\n`Unavailable` preserves catalog membership without claiming that execution stopped."},"display_name":{"type":["string","null"]},"has_running_internal_workers":{"default":false,"type":"boolean"},"job":{"anyOf":[{"$ref":"#/$defs/SubscriptionWorkerJob"},{"type":"null"}],"description":"Backend-owned Job binding. Runtime producers leave this unset; the\nWorkspace projection enriches both snapshots and live updates."},"profile":{"type":["string","null"]},"resource_key":{"description":"Workspace-scoped canonical resource key. Runtime producers leave this unset;\nWorkspace-facing projections must populate it before publishing the Worker.","type":["string","null"]},"restore_observation_token":{"description":"Opaque Runtime-owned Restore observation identity, never a display-state hash.","type":["string","null"]},"runtime_id":{"description":"Set by the Workspace Server when projecting a Runtime-owned Worker to clients.\nRuntime producers leave this unset because the connection identifies the Runtime.","type":["string","null"]},"state":{"$ref":"#/$defs/SubscriptionWorkerState","description":"Runtime catalog lifecycle compatibility projection; not foreground-state authority."},"workdir_attachments":{"items":{"$ref":"#/$defs/SubscriptionWorkerWorkdirAttachment"},"type":"array"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"},"worker_state":{"anyOf":[{"$ref":"#/$defs/WorkerStateSnapshot"},{"type":"null"}],"description":"Latest foreground state observed from the Worker. This remains\nabsent until an authoritative Worker snapshot/event has been applied."},"workspace_id":{"type":["string","null"]}},"required":["worker_id","state","availability","has_running_internal_workers"],"type":"object"},"SubscriptionWorkerAvailability":{"description":"Whether the Workspace Server has a current Runtime observation for a Worker.\n\n`Unavailable` deliberately does not imply `Stopped`: it means the last observed\nlifecycle state is retained while the Runtime observation source is unavailable.","enum":["observed","unavailable"],"type":"string"},"SubscriptionWorkerId":{"type":"string"},"SubscriptionWorkerIds":{"description":"A bounded, canonical worker-id set. Ordering on the wire and in equality/hash\nsemantics is lexical, so equivalent selectors aggregate to one upstream key.","items":{"$ref":"#/$defs/SubscriptionWorkerId"},"type":"array"},"SubscriptionWorkerJob":{"additionalProperties":false,"properties":{"attempt_id":{"type":"string"},"job_id":{"type":"string"},"purpose":{"type":"string"}},"required":["job_id","attempt_id","purpose"],"type":"object"},"SubscriptionWorkerProtocolMethod":{"additionalProperties":false,"properties":{"method":{"$ref":"#/$defs/Method"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["subscription_id","method"],"type":"object"},"SubscriptionWorkerState":{"enum":["idle","running","paused","stopped"],"type":"string"},"SubscriptionWorkerWorkdirAttachment":{"additionalProperties":false,"properties":{"alias":{"description":"Stable Worker-local routing alias.","type":"string"},"repository_key":{"type":["string","null"]},"working_directory_id":{"$ref":"#/$defs/SubscriptionWorkdirId"}},"required":["alias","working_directory_id"],"type":"object"},"SymlinkPolicy":{"description":"Symbolic-link identity used by one filesystem allow rule.\n\n`Resolved` is the least authority and the default: access is matched\nagainst the provider-resolved target. `Logical` intentionally grants the\npath as presented through the Workdir, even when it aliases another target.","enum":["resolved","logical"],"type":"string"},"ToolResultDisposition":{"enum":["success","error","interrupted","cancelled","outcome_unknown"],"type":"string"},"TurnResult":{"enum":["finished","paused"],"type":"string"},"UploadedFileAvailability":{"description":"Availability recorded for an uploaded client-local file.","enum":["available","unavailable","integrity_failed"],"type":"string"},"UploadedFileRef":{"additionalProperties":false,"description":"Session-owned immutable reference to a client-local uploaded file.\n\nUpload transports return an unbound reference. Worker fills\n`source_entry_id` immediately before the containing user input is committed;\ncommitted Session Log and public snapshot records therefore always retain\nthe durable source-entry identity without storing the file body.","properties":{"artifact_id":{"type":"string"},"availability":{"$ref":"#/$defs/UploadedFileAvailability"},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"created_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"file_name":{"type":"string"},"media_type":{"type":"string"},"sha256":{"type":"string"},"source_entry_id":{"type":["string","null"]}},"required":["artifact_id","file_name","media_type","created_at_ms","availability","byte_len","sha256"],"type":"object"},"WorkerBusyState":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"run","type":"string"},"state":{"$ref":"#/$defs/WorkerRunState"}},"required":["kind","state"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"maintenance","type":"string"},"state":{"$ref":"#/$defs/WorkerMaintenanceState"}},"required":["kind","state"],"type":"object"}]},"WorkerCommandAcknowledgement":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandKind"},"command_id":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"disposition":{"$ref":"#/$defs/WorkerCommandDisposition"},"state":{"$ref":"#/$defs/WorkerStateSnapshot","description":"The complete authoritative state observed after command admission."}},"required":["command_id","command","disposition","state"],"type":"object"},"WorkerCommandDisposition":{"enum":["accepted","stale_command_id","conflict","invalid_state"],"type":"string"},"WorkerCommandEnvelope":{"additionalProperties":false,"description":"Caller-owned identity for one state-changing Worker command.\n\nCommands operate on the controller state at admission time, not a caller's\npreviously observed Run. A controller accepts command ids in strictly\nincreasing order; retrying an accepted id cannot apply it to a later Run.\nExact retries must retain the same command kind. Removed preconditions are\nrejected at the wire boundary rather than treated as arrival-time commands.","properties":{"command_id":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["command_id"],"type":"object"},"WorkerCommandKind":{"enum":["resume","cancel","pause","compact","shutdown"],"type":"string"},"WorkerEvent":{"description":"Typed lifecycle events sent from a child Worker to its parent.\n\nDelivered as `Method::WorkerEvent` over the parent's Unix socket. The\nparent Controller always applies variant-specific side effects\n(registry / worker-allocation updates). Agent-visible variants are also\nqueued into the notification buffer; control-plane-only variants are\nnot injected into the parent's LLM context.\n\nTransport is fire-and-forget; receivers must tolerate out-of-order\ndelivery (e.g. `TurnEnded` arriving after `ShutDown` for the same\nchild Worker).","oneOf":[{"additionalProperties":false,"description":"Child finished one turn and is back to IDLE.","properties":{"kind":{"const":"turn_ended","type":"string"},"worker_name":{"type":"string"}},"required":["kind","worker_name"],"type":"object"},{"additionalProperties":false,"description":"Engine execution error occurred inside the child's turn.\n\nLimited to worker runtime failures (provider / tool errors) —\ndoes not include transient method-rejection responses such as\n`AlreadyRunning`.","properties":{"kind":{"const":"errored","type":"string"},"message":{"type":"string"},"worker_name":{"type":"string"}},"required":["kind","worker_name","message"],"type":"object"},{"additionalProperties":false,"description":"Child has stopped (controller loop is exiting).","properties":{"kind":{"const":"shut_down","type":"string"},"worker_name":{"type":"string"}},"required":["kind","worker_name"],"type":"object"},{"additionalProperties":false,"description":"Child SubWorker sub-delegated scope to a grandchild SubWorker via `SubWorkerSpawn`.\n\nControl-plane only: receivers apply registry side effects and\npropagate upward, but do not expose this as an agent notification.\n\nThe parent uses this to add the grandchild to its own\n`spawned_workers.json` so it can manage the grandchild directly\neven if the intermediate child dies. The parent then re-fires\nthis event upward (if it has a parent of its own) to maintain\nthe chain to root.","properties":{"kind":{"const":"scope_sub_delegated","type":"string"},"parent_worker":{"description":"Sub-delegating Worker (= the sender itself).","type":"string"},"scope":{"description":"Scope delegated to the grandchild.","items":{"$ref":"#/$defs/ScopeRule"},"type":"array"},"sub_socket":{"description":"Unix-socket path where the grandchild is reachable.","type":"string"},"sub_worker":{"description":"Name of the grandchild Worker.","type":"string"}},"required":["kind","parent_worker","sub_worker","sub_socket","scope"],"type":"object"}]},"WorkerMaintenanceState":{"enum":["compacting"],"type":"string"},"WorkerRunState":{"enum":["running","pausing","paused","cancelling"],"type":"string"},"WorkerState":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"idle","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"busy","type":"string"},"state":{"$ref":"#/$defs/WorkerBusyState"}},"required":["kind","state"],"type":"object"}]},"WorkerStateSnapshot":{"additionalProperties":false,"properties":{"last_command_id":{"description":"Highest lifecycle command id observed by this controller instance.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"last_finished_submission_request_id":{"description":"Most recent Submit request whose controller Run has returned and whose\npost-Run state transition has been published. This is a teardown fence,\nnot a successful-result claim; cancelled and failed Runs may also finish.","type":["string","null"]},"state":{"$ref":"#/$defs/WorkerState"}},"required":["last_command_id","state"],"type":"object"},"WorkerStatus":{"enum":["idle","running","paused","stopped"],"type":"string"},"WorkspaceSubscriptionWorkdir":{"additionalProperties":false,"description":"Workspace-facing Workdir summary. Backend-generated Repository UUIDs never\nenter this DTO; Workspace Server must resolve the required Repository key.","properties":{"repository_key":{"type":"string"},"state":{"type":"string"},"working_directory_id":{"$ref":"#/$defs/SubscriptionWorkdirId"}},"required":["working_directory_id","repository_key","state"],"type":"object"}},"$schema":"https://json-schema.org/draft/2020-12/schema","description":"Direction is explicit at the outer envelope, while concrete message kinds\nremain typed within each lane.","oneOf":[{"additionalProperties":false,"properties":{"frame":{"const":"request","type":"string"},"message":{"$ref":"#/$defs/SubscriptionRequest"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"},{"additionalProperties":false,"properties":{"frame":{"const":"response","type":"string"},"message":{"$ref":"#/$defs/SubscriptionResponse"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"},{"additionalProperties":false,"properties":{"frame":{"const":"event","type":"string"},"message":{"$ref":"#/$defs/SubscriptionEvent"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"},{"additionalProperties":false,"properties":{"frame":{"const":"worker_protocol","type":"string"},"message":{"$ref":"#/$defs/SubscriptionWorkerProtocolMethod"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"}],"title":"SubscriptionFrame"}; +const subscriptionFrameSchema: unknown = {"$defs":{"Alert":{"additionalProperties":false,"description":"User-facing alert emitted from the Worker layer.\n\nThis is a separate channel from `tracing` (developer logs): entries\nhere are assembled explicitly by the Worker when a condition should be\nsurfaced to the person driving the client. Keep messages short and\nhuman-readable.","properties":{"id":{"description":"Stable only within the emitting live Worker; not durable alert history.","type":["string","null"]},"level":{"$ref":"#/$defs/AlertLevel"},"message":{"type":"string"},"position":{"anyOf":[{"$ref":"#/$defs/AlertPosition"},{"type":"null"}]},"source":{"$ref":"#/$defs/AlertSource"},"timestamp_ms":{"description":"Milliseconds since the Unix epoch.","format":"int64","maximum":9007199254740991.0,"minimum":-9007199254740991.0,"type":"integer"}},"required":["level","source","message","timestamp_ms"],"type":"object"},"AlertLevel":{"enum":["warn","error"],"type":"string"},"AlertPosition":{"description":"Display anchor captured at emission, resolved when pending text is committed.","oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"start","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"entry_id":{"type":"string"},"kind":{"const":"after_entry","type":"string"}},"required":["kind","entry_id"],"type":"object"},{"additionalProperties":false,"properties":{"call_id":{"type":"string"},"kind":{"const":"after_tool_call","type":"string"}},"required":["kind","call_id"],"type":"object"},{"additionalProperties":false,"properties":{"block_id":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"kind":{"const":"after_in_flight","type":"string"}},"required":["kind","block_id"],"type":"object"}]},"AlertSource":{"enum":["worker","engine","compactor","agents_md"],"type":"string"},"CommandEvent":{"oneOf":[{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"kind":{"const":"started","type":"string"},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"tool_call_id":{"type":["string","null"]}},"required":["kind","command_id","observed_at_ms"],"type":"object"},{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"content":{"type":"string"},"end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"kind":{"const":"output","type":"string"},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"start_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"stream":{"$ref":"#/$defs/CommandStream"}},"required":["kind","command_id","stream","start_offset","end_offset","content","observed_at_ms"],"type":"object"},{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"exit_code":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":["integer","null"]},"kind":{"const":"terminal","type":"string"},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"status":{"$ref":"#/$defs/CommandStatus"},"stderr_end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"stdout_end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["kind","command_id","status","stdout_end_offset","stderr_end_offset","observed_at_ms"],"type":"object"}]},"CommandSnapshot":{"additionalProperties":false,"properties":{"command_id":{"type":"string"},"exit_code":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":["integer","null"]},"last_output_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"observed_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"started_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"status":{"$ref":"#/$defs/CommandStatus"},"stderr":{"$ref":"#/$defs/CommandStreamSlice"},"stdout":{"$ref":"#/$defs/CommandStreamSlice"},"tool_call_id":{"type":["string","null"]}},"required":["command_id","status","started_at_ms","observed_at_ms","stdout","stderr"],"type":"object"},"CommandStatus":{"description":"Live provider-owned command status. These values are operational Console\nstate only and are never appended to Worker history.","enum":["running","completed","failed","timed_out","cancelled"],"type":"string"},"CommandStream":{"enum":["stdout","stderr"],"type":"string"},"CommandStreamSlice":{"additionalProperties":false,"properties":{"content":{"type":"string"},"end_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"start_offset":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"truncated":{"type":"boolean"}},"required":["start_offset","end_offset","content","truncated"],"type":"object"},"CompactionLifecycle":{"additionalProperties":false,"description":"Stable parent-owned lifecycle for one compaction run.","properties":{"compaction_id":{"type":"string"},"ended_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"error":{"type":["string","null"]},"internal_worker":{"anyOf":[{"$ref":"#/$defs/InternalWorkerRef"},{"type":"null"}]},"new_segment_id":{"type":["string","null"]},"schema_version":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"started_at_ms":{"description":"Milliseconds since the Unix epoch.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"state":{"$ref":"#/$defs/CompactionLifecycleState"},"summary":{"type":["string","null"]}},"required":["schema_version","compaction_id","state","started_at_ms"],"type":"object"},"CompactionLifecycleState":{"enum":["running","done","failed","interrupted"],"type":"string"},"CompactionPhase":{"enum":["preparing","summarizing","committing"],"type":"string"},"CompactionTrigger":{"enum":["manual","pre_run","request_threshold"],"type":"string"},"CompletionContext":{"additionalProperties":false,"properties":{"argument":{"type":["string","null"]},"invocation":{"$ref":"#/$defs/FeatureInvocationIdentity"}},"required":["invocation"],"type":"object"},"CompletionEntry":{"additionalProperties":false,"description":"One completion candidate for a prefix query.","properties":{"description":{"type":["string","null"]},"invocation":{"anyOf":[{"$ref":"#/$defs/FeatureInvocationDescriptor"},{"type":"null"}]},"is_dir":{"default":false,"type":"boolean"},"usage":{"type":["string","null"]},"value":{"type":"string"}},"required":["value","is_dir"],"type":"object"},"CompletionKind":{"description":"Kind of completion requested by `Method::ListCompletions`.\n\n`File` is the existing `@` path lane. `Feature` lists installed chat\ninvocations. `FeatureArgument` resolves a declared argument using the\nsource-qualified [`CompletionContext`].","enum":["file","feature","feature_argument"],"type":"string"},"ContextTokenSource":{"description":"Provenance of the current-context token count in a [`Greeting`].","oneOf":[{"const":"measured","description":"Provider-reported input occupancy from the most recent LLM request.","type":"string"},{"const":"estimated","description":"Current history projected from the Worker's token accounting records.","type":"string"}]},"ContextUsage":{"additionalProperties":false,"description":"Current prompt-context occupancy, distinct from cumulative run traffic.","properties":{"source":{"$ref":"#/$defs/ContextTokenSource"},"tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["tokens","source"],"type":"object"},"ErrorCode":{"enum":["already_running","not_running","not_paused","provider_error","tool_error","invalid_request","internal"],"type":"string"},"Event":{"oneOf":[{"additionalProperties":false,"description":"Durable Submit acceptance. A `Queued` receipt follows the durable FIFO\ncheckpoint. A `Started` receipt follows the pending activation checkpoint;\nthe corresponding [`Event::UserMessage`] marks the later history commit.\nRepeating the same request id and exact payload returns the same receipt\nwithout appending or activating twice.","properties":{"data":{"additionalProperties":false,"properties":{"disposition":{"$ref":"#/$defs/SubmissionDisposition"},"submission_id":{"type":"string"},"submission_request_id":{"type":"string"}},"required":["submission_request_id","submission_id","disposition"],"type":"object"},"event":{"const":"submission_accepted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Correlated rejection before durable acceptance.","properties":{"data":{"additionalProperties":false,"properties":{"message":{"type":"string"},"submission_request_id":{"type":"string"}},"required":["submission_request_id","message"],"type":"object"},"event":{"const":"submission_rejected","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Durable notification acceptance. The request identity is persisted with\nthe notification receipt before this event is emitted. Repeating the\nsame request id and exact payload returns the same acknowledgement\nwithout appending the notification twice.","properties":{"data":{"additionalProperties":false,"properties":{"notification_request_id":{"type":"string"}},"required":["notification_request_id"],"type":"object"},"event":{"const":"notification_accepted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Correlated notification rejection before durable acceptance.","properties":{"data":{"additionalProperties":false,"properties":{"message":{"type":"string"},"notification_request_id":{"type":"string"}},"required":["notification_request_id","message"],"type":"object"},"event":{"const":"notification_rejected","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Complete FIFO replacement following enqueue, activation, cancel, or clear.\nClients replace their pending view in stream order; reconnect uses the snapshot.","properties":{"data":{"additionalProperties":false,"properties":{"pending":{"$ref":"#/$defs/PendingSubmissionsSnapshot"}},"required":["pending"],"type":"object"},"event":{"const":"pending_submissions_changed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A user input message persisted as `LogEntry::AnnotatedUserInput` and\nactivated for a turn. Broadcast to every subscribed client so TUI / GUI\ninstances show the same user line that reconnect snapshots replay.","properties":{"data":{"additionalProperties":false,"properties":{"entry_id":{"description":"Stable durable history identity. Older mixed-version producers omit it.","type":["string","null"]},"segments":{"items":{"$ref":"#/$defs/Segment"},"type":"array"}},"required":["segments"],"type":"object"},"event":{"const":"user_message","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A canonical assistant/tool entry has committed to durable history.\nStreaming events remain the in-flight authority; this event supplies the\nstable identity used to reconcile that live block with paged history.","properties":{"data":{"additionalProperties":false,"properties":{"entry":{"$ref":"#/$defs/SessionSnapshotEntry"}},"required":["entry"],"type":"object"},"event":{"const":"session_entry_committed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"One agent-injected system item committed to history.\n\nCarries the allowlisted JSON form of `session_store::PublicSystemItem`,\nnot the storage record. Its descriptive `kind` is independent from the\ntyped `presentation` used for notification, reminder, or context rendering.\nPrivate Feature payloads and prompt provenance are never event data.\n\nOne event per `LogEntry::AnnotatedSystemItem` commit. Disk-side and\nwire-side are 1:1.","properties":{"data":{"additionalProperties":false,"properties":{"entry_id":{"description":"Stable durable history identity. Synthetic compatibility events omit it.","type":["string","null"]},"item":true},"required":["item"],"type":"object"},"event":{"const":"system_item","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A new self-driving cycle has begun (IDLE → active transition).\n\nMarker event for the start of an Invoke range; the range extends\nimplicitly until the next `InvokeStart`. Fires for every accepted\n`Method::Submit` (kind=`UserSend`), `Method::Notify` (kind=`Notify`),\n`Method::WorkerEvent` re-injection (kind=`WorkerEvent`), and any other\nIDLE-breaking trigger. Mid-run interrupts (e.g. hook output,\ntyped system reminder insertion that doesn't break IDLE) do not\nemit `InvokeStart` — they appear as `SystemItem` only.\n\nCarries `kind` only; the payload (user text / notify message /\nworker event body) is delivered separately via the immediately\nfollowing `UserMessage` / `SystemItem` event.","properties":{"data":{"additionalProperties":false,"properties":{"kind":{"$ref":"#/$defs/InvokeKind"},"timestamp_ms":{"description":"Timestamp of the persisted Invoke, not the client's attach time.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]}},"required":["kind"],"type":"object"},"event":{"const":"invoke_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"One AgentTurn boundary opened. An AgentTurn is a maximal run of\nLLM generation calls whose input messages are identical (i.e.\nretries from network errors / 5xx / stream disconnects collapse\ninto the same AgentTurn). When the input changes (a new tool\nresult lands, a user interrupts, etc.), the next LLM call belongs\nto a new AgentTurn.\n\n`turn` is the AgentTurn index from `Engine::turn_count`.\n\nCurrently retry is not yet implemented (`agen-stream-continuation`)\nso AgentTurn and `LlmCall` fire 1:1, but the contract here is\nthe AgentTurn boundary; consumers that want per-LLM-call signals\nmust subscribe to `LlmCallStart` / `LlmCallEnd` instead.","properties":{"data":{"additionalProperties":false,"properties":{"turn":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["turn"],"type":"object"},"event":{"const":"turn_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"AgentTurn closed.","properties":{"data":{"additionalProperties":false,"properties":{"result":{"$ref":"#/$defs/TurnResult"},"turn":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["turn","result"],"type":"object"},"event":{"const":"turn_end","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"One LLM generation call started (1 request → 1 generation, retry\nincluded). Multiple `LlmCall*` pairs may fire inside a single\n`TurnStart` / `TurnEnd` pair when a request is retried; today\nthey fire 1:1 because retry is not implemented.\n\n`llm_call` is the worker-wide running counter from\n`Engine::llm_call_count`.","properties":{"data":{"additionalProperties":false,"properties":{"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["llm_call"],"type":"object"},"event":{"const":"llm_call_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"LLM generation call ended.","properties":{"data":{"additionalProperties":false,"properties":{"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["llm_call"],"type":"object"},"event":{"const":"llm_call_end","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A transport-level LLM request retry has been scheduled.\n\nThis is operational state for clients to render while the worker is\nwaiting in backoff. It is not part of conversation history.","properties":{"data":{"additionalProperties":false,"properties":{"elapsed_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"error":{"type":"string"},"failed_attempt":{"description":"The attempt that just failed. 1 origin.","format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"max_attempts":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"status":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":["integer","null"]},"wait_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["llm_call","failed_attempt","max_attempts","wait_ms","elapsed_ms","error"],"type":"object"},"event":{"const":"llm_retry","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Stream generation was interrupted after events had begun and the worker\nis continuing with a follow-up LLM request.","properties":{"data":{"additionalProperties":false,"properties":{"attempt":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"llm_call":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"max_attempts":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"reason":{"type":"string"}},"required":["llm_call","attempt","max_attempts","reason"],"type":"object"},"event":{"const":"llm_continuation","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"text_delta","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"text_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A reasoning / thinking block has started.\n\nAlways paired with a `ThinkingDone`. `ThinkingDelta` is optional:\nsome providers (or some configurations) emit thinking metadata\nwithout plaintext, in which case Start → Done arrive with no\ndeltas in between. Multiple thinking blocks per turn are allowed.","properties":{"event":{"const":"thinking_start","type":"string"}},"required":["event"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"thinking_delta","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Thinking block completed. `text` is the full accumulated body\n(empty string when the provider didn't emit plaintext).","properties":{"data":{"additionalProperties":false,"properties":{"text":{"type":"string"}},"required":["text"],"type":"object"},"event":{"const":"thinking_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"event":{"const":"tool_call_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"id":{"type":"string"},"json":{"type":"string"}},"required":["id","json"],"type":"object"},"event":{"const":"tool_call_args_delta","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","arguments"],"type":"object"},"event":{"const":"tool_call_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"disposition":{"anyOf":[{"$ref":"#/$defs/ToolResultDisposition"},{"type":"null"}]},"id":{"type":"string"},"is_error":{"default":false,"type":"boolean"},"output":{"description":"Full tool output. Absent when the tool chose to return\nsummary-only, or when the result was pruned.","type":["string","null"]},"summary":{"description":"Short human-readable summary. Always present; used by clients\nthat only want a 1-line rendering (e.g. collapsed views).","type":"string"}},"required":["id","summary","is_error"],"type":"object"},"event":{"const":"tool_result","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Token accounting for one LLM request.\n\n`input_tokens` is the prompt prefix occupancy (cache reads /\ncache writes included), as normalised by the worker layer.\n`cache_read_input_tokens` is the cache-hit subset of that\noccupancy; subtracting it yields the \"net upload\" the client\nactually paid full price to send on this request, which is what\nthe TUI status line accumulates per turn.","properties":{"data":{"additionalProperties":false,"properties":{"cache_read_input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"output_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]},"timestamp_ms":{"description":"Present for usage delivered from the committed session-log lane.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":["integer","null"]}},"type":"object"},"event":{"const":"usage","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Authoritative current-context occupancy after a non-request boundary.\n\nUnlike [`Event::Usage`], this is not cumulative request traffic. It lets\nconnected clients converge with reconnect snapshots after run completion,\ncompaction, rewind, and other history rewrites. `None` explicitly means\nthe current value is unavailable and stale occupancy must be cleared.","properties":{"data":{"additionalProperties":false,"properties":{"usage":{"anyOf":[{"$ref":"#/$defs/ContextUsage"},{"type":"null"}]}},"type":"object"},"event":{"const":"context_usage","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"result":{"$ref":"#/$defs/RunResult"}},"required":["result"],"type":"object"},"event":{"const":"run_end","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"code":{"$ref":"#/$defs/ErrorCode"},"message":{"type":"string"}},"required":["code","message"],"type":"object"},"event":{"const":"error","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Sent exactly once at the start of every client connection.\n\n`entries` is the session-log mirror at subscribe time, serialised\nas the JSON form of `session_store::LogEntry`. This is the\nbulk-reconstruction lane: clients walk the entries to seed their\nderived view.\n\n`greeting` and `status` accompany the snapshot so clients render\nworker identity and current controller state without an extra round\ntrip.\n\nLive updates after the snapshot arrive through the streaming\nevents (`TextDelta` / `ToolCall*` / `ToolResult` / etc.) plus\nrole-specific entry events (`SegmentRotated` / `SystemItem`) —\nthere is no generic \"every committed entry\" broadcast.","properties":{"data":{"additionalProperties":false,"properties":{"greeting":{"$ref":"#/$defs/Greeting"},"in_flight":{"$ref":"#/$defs/InFlightSnapshot","description":"Unfinished model output that has already streamed in the current\nrun but is not yet represented by committed snapshot entries."},"internal_workers":{"description":"Parent-owned Internal Worker sessions visible to this client.\nService-private Internal Workers are deliberately excluded.","items":{"$ref":"#/$defs/InternalWorkerSnapshot"},"type":"array"},"session":{"$ref":"#/$defs/SessionSnapshot"},"state":{"$ref":"#/$defs/WorkerStateSnapshot","description":"Full live execution state. `Stopped` remains Runtime\ncatalog authority and is deliberately not represented here."}},"required":["session","greeting","state"],"type":"object"},"event":{"const":"snapshot","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A live event from a parent-owned Internal Worker. The payload reuses the\nnormal Worker event vocabulary while the wrapper carries stable origin\nidentity. Apply in arrival order on the parent's serialized stream; a\nreconnect snapshot replaces the projection before live events resume.","properties":{"data":{"additionalProperties":false,"properties":{"event":{"$ref":"#/$defs/Event"},"worker":{"$ref":"#/$defs/InternalWorkerRef"}},"required":["worker","event"],"type":"object"},"event":{"const":"internal_worker","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Terminal removal fence for one parent-owned Internal Worker session.\n\nClients discard the matching child and descendants, then ignore later\nnested events for this identity until an authoritative snapshot replaces\nthe projection.","properties":{"data":{"additionalProperties":false,"properties":{"worker":{"$ref":"#/$defs/InternalWorkerRef"}},"required":["worker"],"type":"object"},"event":{"const":"internal_worker_removed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Server-side segment log rotated to a fresh `SegmentStart`.\n\nFires on compaction and on auto-fork when the store head drifts\nA compaction/fork has replaced the authoritative segment. Clients drop\ntheir derived view and reseed from the canonical committed snapshot.","properties":{"data":{"additionalProperties":false,"properties":{"session":{"$ref":"#/$defs/SessionSnapshot"}},"required":["session"],"type":"object"},"event":{"const":"segment_rotated","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Current Worker controller status. Broadcast on every controller-level\ntransition and included in `History` snapshots for late attach.","properties":{"data":{"additionalProperties":false,"properties":{"snapshot":{"$ref":"#/$defs/WorkerStateSnapshot"}},"required":["snapshot"],"type":"object"},"event":{"const":"worker_state","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"acknowledgement":{"$ref":"#/$defs/WorkerCommandAcknowledgement"}},"required":["acknowledgement"],"type":"object"},"event":{"const":"command_acknowledged","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Bounded, provider-owned command telemetry for the live Console. This is\nintentionally not a history entry and is reconstructed from\n`Snapshot.in_flight.commands` after reconnect.","properties":{"data":{"additionalProperties":false,"properties":{"event":{"$ref":"#/$defs/CommandEvent"}},"required":["event"],"type":"object"},"event":{"const":"command","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::ListCompletions`. Delivered only to the\nrequesting socket (not broadcast). `entries` is empty when no\ncandidates match or when the requested kind has no resolver\nwired up.","properties":{"data":{"additionalProperties":false,"properties":{"context":{"anyOf":[{"$ref":"#/$defs/CompletionContext"},{"type":"null"}]},"entries":{"items":{"$ref":"#/$defs/CompletionEntry"},"type":"array"},"kind":{"$ref":"#/$defs/CompletionKind"},"prefix":{"default":"","type":"string"},"request_id":{"type":["string","null"]}},"required":["kind","entries","prefix"],"type":"object"},"event":{"const":"completions","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"A rewind has truncated the authoritative session. `session` is the\nretained canonical snapshot clients should use to reseed display state.","properties":{"data":{"additionalProperties":false,"properties":{"input":{"items":{"$ref":"#/$defs/Segment"},"type":"array"},"session":{"$ref":"#/$defs/SessionSnapshot"},"summary":{"$ref":"#/$defs/RewindSummary"}},"required":["session","input","summary"],"type":"object"},"event":{"const":"rewind_applied","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::ListWorkers`. Payload is a stable JSON value so the Worker\ncrate can evolve discovery fields without introducing a protocol\ndependency on session-store.","properties":{"data":{"additionalProperties":false,"properties":{"workers":true},"required":["workers"],"type":"object"},"event":{"const":"workers_listed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::RestoreWorker`.","properties":{"data":{"additionalProperties":false,"properties":{"result":true},"required":["result"],"type":"object"},"event":{"const":"worker_restored","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Reply to `Method::RegisterPeer`.","properties":{"data":{"additionalProperties":false,"properties":{"result":true},"required":["result"],"type":"object"},"event":{"const":"peer_registered","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"$ref":"#/$defs/Alert"},"event":{"const":"alert","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Latest memory extract/consolidation lifecycle event for UI observability.\n\nThis is not part of LLM history or prompt context; clients may display it\nbriefly as operational status.","properties":{"data":{"$ref":"#/$defs/MemoryWorkerEvent"},"event":{"const":"memory_worker","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Runtime-only compaction progress. `None` clears the current status.\nThis never enters Session history and carries no operation or Segment identity.","properties":{"data":{"additionalProperties":false,"properties":{"compaction":{"anyOf":[{"$ref":"#/$defs/InFlightCompaction"},{"type":"null"}]}},"type":"object"},"event":{"const":"compaction_progress","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Legacy compaction lifecycle event retained for wire read compatibility.","properties":{"data":{"additionalProperties":false,"properties":{"lifecycle":{"$ref":"#/$defs/CompactionLifecycle"}},"required":["lifecycle"],"type":"object"},"event":{"const":"compact_start","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Compaction completed and the session was rotated.","properties":{"data":{"additionalProperties":false,"properties":{"lifecycle":{"$ref":"#/$defs/CompactionLifecycle"}},"required":["lifecycle"],"type":"object"},"event":{"const":"compact_done","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"description":"Compaction failed or was cancelled. The session is unchanged.","properties":{"data":{"additionalProperties":false,"properties":{"lifecycle":{"$ref":"#/$defs/CompactionLifecycle"}},"required":["lifecycle"],"type":"object"},"event":{"const":"compact_failed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"event":{"const":"shutdown","type":"string"}},"required":["event"],"type":"object"}]},"EventSubscriptionSelector":{"oneOf":[{"additionalProperties":false,"properties":{"topic":{"const":"runtime_workers","type":"string"}},"required":["topic"],"type":"object"},{"additionalProperties":false,"properties":{"topic":{"const":"worker_lifecycle","type":"string"},"worker_ids":{"$ref":"#/$defs/SubscriptionWorkerIds"}},"required":["topic","worker_ids"],"type":"object"},{"additionalProperties":false,"properties":{"runtime_id":{"type":["string","null"]},"topic":{"const":"worker_protocol","type":"string"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["topic","worker_id"],"type":"object"},{"additionalProperties":false,"description":"Server-derived Workspace projection. Workspace identity comes from the\nauthenticated connection and is deliberately absent from this selector.","properties":{"topic":{"const":"workspace_workers","type":"string"}},"required":["topic"],"type":"object"},{"additionalProperties":false,"description":"Typed extension point for the later Workdir subscription slice.","properties":{"topic":{"const":"workspace_workdirs","type":"string"}},"required":["topic"],"type":"object"}]},"FeatureInvocation":{"additionalProperties":false,"properties":{"arguments":{"items":{"$ref":"#/$defs/InvocationArgumentValue"},"type":"array"},"identity":{"$ref":"#/$defs/FeatureInvocationIdentity"},"invocation_id":{"description":"Stable client-generated id retained across queueing and transport retry.","type":"string"},"name":{"description":"Selected public name, retained for exact draft/history restoration. Host\nresolution is always by `identity`.","type":"string"}},"required":["invocation_id","identity","name","arguments"],"type":"object"},"FeatureInvocationDescriptor":{"additionalProperties":false,"properties":{"aliases":{"default":[],"items":{"type":"string"},"type":"array"},"arguments":{"default":[],"items":{"$ref":"#/$defs/InvocationArgumentDescriptor"},"type":"array"},"client_adapter":{"anyOf":[{"$ref":"#/$defs/InvocationClientAdapter"},{"type":"null"}]},"description":{"type":"string"},"display_name":{"type":"string"},"identity":{"$ref":"#/$defs/FeatureInvocationIdentity"},"name":{"type":"string"},"syntax":{"$ref":"#/$defs/FeatureInvocationSyntax"}},"required":["identity","name","display_name","description","syntax","aliases","arguments"],"type":"object"},"FeatureInvocationIdentity":{"description":"Source-qualified identity of one invocation contribution, for example\n`builtin:attachments/attach`. Display names and aliases are never authority.","type":"string"},"FeatureInvocationSyntax":{"oneOf":[{"const":"parenthesized","description":"`/name(value, key=value)` with JSON-style quoted strings and `)` as the\nexplicit boundary before following natural language.","type":"string"}]},"Greeting":{"additionalProperties":false,"description":"Worker self-description rendered by clients when a session starts empty.\n\nSnapshot metadata contains only resolved public execution information so\nclients do not need their own copy of the manifest.","properties":{"context_tokens":{"default":0,"description":"Legacy numeric mirror retained for mixed-version clients.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"context_usage":{"anyOf":[{"$ref":"#/$defs/ContextUsage"},{"type":"null"}],"description":"Typed current-context value. Older snapshots omit it; clients may fall\nback to `context_tokens` only when `context_window` is known."},"context_window":{"default":0,"description":"Resolved effective model context window in tokens. Legacy producers use\nzero when this is unavailable; clients must treat that as unknown.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"cwd":{"type":"string"},"model":{"type":"string"},"provider":{"type":"string"},"reasoning":{"anyOf":[{"$ref":"#/$defs/ReasoningConfig"},{"type":"null"}],"description":"Effective reasoning control. Absent means unspecified or unavailable."},"scope_summary":{"type":"string"},"tools":{"items":{"type":"string"},"type":"array"},"worker_name":{"type":"string"}},"required":["worker_name","cwd","provider","model","scope_summary","tools","context_tokens","context_window"],"type":"object"},"InFlightBlock":{"oneOf":[{"additionalProperties":false,"properties":{"finished":{"type":"boolean"},"kind":{"const":"text","type":"string"},"text":{"type":"string"}},"required":["kind","text"],"type":"object"},{"additionalProperties":false,"properties":{"finished":{"type":"boolean"},"kind":{"const":"thinking","type":"string"},"text":{"type":"string"}},"required":["kind","text"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"type":"string"},"id":{"type":"string"},"kind":{"const":"tool_call","type":"string"},"name":{"type":"string"},"state":{"$ref":"#/$defs/InFlightToolCallState"}},"required":["kind","id","name","args"],"type":"object"}]},"InFlightCompaction":{"additionalProperties":false,"properties":{"phase":{"$ref":"#/$defs/CompactionPhase"},"started_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"trigger":{"$ref":"#/$defs/CompactionTrigger"}},"required":["phase","started_at_ms","trigger"],"type":"object"},"InFlightSnapshot":{"additionalProperties":false,"description":"Unfinished model output and active command state included in\n`Event::Snapshot` for clients that attach while work is still streaming.\n\nThese blocks are presentation state only: they are reconstructed from the\nactive Worker controller and must not be treated as committed assistant\nhistory. Finalized assistant items continue to come from ordinary snapshot\nentries.","properties":{"block_ids":{"description":"Live-Worker identities parallel to the blocks actually included below.","items":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"type":"array"},"blocks":{"items":{"$ref":"#/$defs/InFlightBlock"},"type":"array"},"commands":{"items":{"$ref":"#/$defs/CommandSnapshot"},"type":"array"},"compaction":{"anyOf":[{"$ref":"#/$defs/InFlightCompaction"},{"type":"null"}],"description":"The currently running compaction, if any.\n\nThis is lifecycle progress only. Candidate history and the staged\nSegment remain private until the Segment is activated atomically."}},"type":"object"},"InFlightToolCallState":{"enum":["pending","streaming_args","done"],"type":"string"},"InternalWorkerKind":{"description":"Presentation category for an Internal Worker exposed through its parent's\nprotocol stream. Internal Workers never become independently addressable\nprotocol subjects.","oneOf":[{"enum":["sub_worker"],"type":"string"},{"additionalProperties":false,"properties":{"service":{"additionalProperties":false,"properties":{"kind":{"type":"string"}},"required":["kind"],"type":"object"}},"required":["service"],"type":"object"}]},"InternalWorkerRef":{"additionalProperties":false,"description":"Stable presentation identity for one parent-owned Internal Worker session.\n`name` is display-only; `session_id` is the identity used by clients.","properties":{"kind":{"$ref":"#/$defs/InternalWorkerKind"},"name":{"type":"string"},"parent_session_id":{"type":["string","null"]},"session_id":{"type":"string"}},"required":["session_id","name","kind"],"type":"object"},"InternalWorkerSnapshot":{"additionalProperties":false,"description":"Reconnect state for one visible Internal Worker. The parent serializes\nsnapshot publication and subsequent live events on the same ordered stream.","properties":{"error":{"type":["string","null"]},"greeting":{"anyOf":[{"$ref":"#/$defs/Greeting"},{"type":"null"}],"description":"Public execution metadata for this child. Older snapshots and service\nworkers may omit it; clients must never substitute the parent's values."},"in_flight":{"$ref":"#/$defs/InFlightSnapshot"},"internal_workers":{"items":{"$ref":"#/$defs/InternalWorkerSnapshot"},"type":"array"},"session":{"$ref":"#/$defs/SessionSnapshot"},"status":{"$ref":"#/$defs/WorkerStatus","default":"idle"},"worker":{"$ref":"#/$defs/InternalWorkerRef"}},"required":["worker","session","status"],"type":"object"},"InvocationArgumentDescriptor":{"additionalProperties":false,"properties":{"completion":{"$ref":"#/$defs/InvocationCompletion","default":{"kind":"none"}},"description":{"type":["string","null"]},"name":{"type":"string"},"position":{"description":"Zero-based positional index. `None` means named-only. A positional\nargument may also be supplied by name; this makes chip editing stable.","format":"uint16","maximum":65535.0,"minimum":0.0,"type":["integer","null"]},"required":{"default":false,"type":"boolean"},"value_type":{"$ref":"#/$defs/InvocationArgumentType"}},"required":["name","value_type","completion","required"],"type":"object"},"InvocationArgumentType":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"string","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"integer","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"boolean","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"enum","type":"string"},"values":{"items":{"type":"string"},"type":"array"}},"required":["kind","values"],"type":"object"},{"additionalProperties":false,"description":"A Worker-readable path. This does not grant filesystem authority.","properties":{"kind":{"const":"worker_file","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"description":"A resource selected and staged by the client. It must never be resolved\nas a path on the Worker host.","properties":{"kind":{"const":"client_file","type":"string"}},"required":["kind"],"type":"object"}]},"InvocationArgumentValue":{"additionalProperties":false,"properties":{"name":{"type":"string"},"value":{"$ref":"#/$defs/InvocationValue"}},"required":["name","value"],"type":"object"},"InvocationClientAdapter":{"oneOf":[{"const":"attachment","description":"The client stages a local file and replaces the draft invocation with an\n`UploadedFile` chip. Local paths are not sent to or persisted by Worker.","type":"string"}]},"InvocationCompletion":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"none","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"static","type":"string"},"values":{"items":{"type":"string"},"type":"array"}},"required":["kind","values"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"worker_file","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"client_file","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"description":"Host-owned provider selected by source-qualified id. Metadata lookup is\nside-effect free; implementations never cross this wire boundary.","properties":{"kind":{"const":"provider","type":"string"},"provider":{"type":"string"}},"required":["kind","provider"],"type":"object"}]},"InvocationValue":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"string","type":"string"},"value":{"type":"string"}},"required":["kind","value"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"integer","type":"string"},"value":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":"integer"}},"required":["kind","value"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"boolean","type":"string"},"value":{"type":"boolean"}},"required":["kind","value"],"type":"object"}]},"InvokeKind":{"description":"Kind of trigger that opened a new Invoke (IDLE → active) range.\n\nOne Invoke groups all entries from this trigger up to the next\n`Invoke` marker. The kind is the only payload — content (user text,\nnotify message, worker event body) is delivered by the immediately\nfollowing Turn entry, not by the marker itself.","oneOf":[{"const":"user_send","description":"`Method::Submit` — a user submission.","type":"string"},{"const":"notify","description":"`Method::Notify` — free-text notification injected into history.","type":"string"},{"const":"worker_event","description":"`Method::WorkerEvent` — typed lifecycle report from a child Worker.","type":"string"},{"const":"system_reminder","description":"A typed system reminder that crosses an IDLE boundary (mid-run\nreminders that don't break IDLE are SystemItem-only and do not\nopen a new Invoke).","type":"string"},{"const":"wakeup","description":"Cron / RemoteTrigger style scheduled wake-up. Reserved; no\nproducer is wired today but the variant is part of the initial\nset so future schedulers don't have to amend the wire enum.","type":"string"}]},"MemoryWorkerEvent":{"additionalProperties":false,"properties":{"message":{"description":"Human-readable compact form for actionbar rendering.","type":"string"},"reason":{"type":"string"},"run_id":{"type":"string"},"status":{"type":"string"},"timestamp_ms":{"description":"Milliseconds since the Unix epoch.","format":"int64","maximum":9007199254740991.0,"minimum":-9007199254740991.0,"type":"integer"},"trigger":{"type":"string"},"worker":{"type":"string"}},"required":["worker","status","run_id","trigger","reason","message","timestamp_ms"],"type":"object"},"Method":{"oneOf":[{"additionalProperties":false,"description":"Durably accept typed input for immediate activation or the session FIFO.\nRunning or Paused Workers queue Submit for a later turn; use Notify for\nadvisory information to incorporate into work already in progress.\n\n`submission_request_id` is generated by the authenticated caller and is\nused only for idempotent retry. Worker allocates the durable\n`submission_id` returned by [`Event::SubmissionAccepted`].","properties":{"method":{"const":"submit","type":"string"},"params":{"additionalProperties":false,"properties":{"input":{"items":{"$ref":"#/$defs/Segment"},"type":"array"},"submission_request_id":{"type":"string"}},"required":["submission_request_id","input"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Human-readable text injected into the target Worker's LLM context as a\nnon-blocking system message. Accepted notifications are delivered at the\nnext between-turn boundary, or start a coalesced notification run while\nthe Worker is idle. No side effects beyond LLM context; use\n`WorkerEvent` for typed lifecycle reports.","properties":{"method":{"const":"notify","type":"string"},"params":{"additionalProperties":false,"properties":{"message":{"type":"string"},"notification_request_id":{"type":"string"}},"required":["notification_request_id","message"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Typed lifecycle report from a child Worker to its direct parent.","properties":{"method":{"const":"worker_event","type":"string"},"params":{"$ref":"#/$defs/WorkerEvent"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Return the authoritative FIFO summary without exposing queued payloads.","properties":{"method":{"const":"list_pending_submissions","type":"string"}},"required":["method"],"type":"object"},{"additionalProperties":false,"description":"Remove one queued submission. Running or already activated submissions\nare immutable and therefore cannot be cancelled here.","properties":{"method":{"const":"cancel_pending_submission","type":"string"},"params":{"additionalProperties":false,"properties":{"submission_id":{"type":"string"}},"required":["submission_id"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Remove exactly the observed ordered set of submissions, preserving the\nactive run. Reject if the FIFO content changed before admission.","properties":{"method":{"const":"clear_pending_submissions","type":"string"},"params":{"additionalProperties":false,"properties":{"expected_submission_ids":{"items":{"type":"string"},"type":"array"}},"required":["expected_submission_ids"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Activate the next queued submission while the Worker is idle. This is an\nexplicit recovery operation and never resumes a paused run implicitly.","properties":{"method":{"const":"continue_pending","type":"string"},"params":{"additionalProperties":false,"properties":{"expected_head_id":{"type":"string"}},"required":["expected_head_id"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"resume","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"cancel","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Stop the in-flight turn and transition to `Paused`.\n\nUnlike `Cancel` (which discards and returns to `Idle`), a paused\nWorker can resume the interrupted work via `Resume`, or accept a\nfresh `Submit` (orphan `tool_use` items are closed with a\nsynthetic tool result before the new user message is appended).","properties":{"method":{"const":"pause","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Request an explicit compaction while the Worker is otherwise idle.\n\nThis is a typed control method: clients must not send `compact` as a\n`Method::Submit` user message.","properties":{"method":{"const":"compact","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Rewind to just before a user input identified by its public Session entry ID.\nValidate the target against the current segment at execution time.\nLater appended history is discarded too; tool side effects are not undone.","properties":{"method":{"const":"rewind_to","type":"string"},"params":{"additionalProperties":false,"properties":{"entry_id":{"type":"string"}},"required":["entry_id"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"shutdown","type":"string"},"params":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandEnvelope"}},"required":["command"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Request a list of completion candidates from the Worker.\n\nReply is sent on the same socket as `Event::Completions` (not\nbroadcast). The IPC server handles this directly and writes\nthe response straight back to the requesting socket.","properties":{"method":{"const":"list_completions","type":"string"},"params":{"additionalProperties":false,"properties":{"context":{"anyOf":[{"$ref":"#/$defs/CompletionContext"},{"type":"null"}]},"kind":{"$ref":"#/$defs/CompletionKind"},"prefix":{"type":"string"},"request_id":{"description":"Client query identity. Echoed verbatim so identical-prefix ABA\nresponses cannot cross edits, target switches, or permission changes.","type":["string","null"]}},"required":["kind","prefix"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"List Workers visible to this Worker from durable Worker state and the spawned-child\nregistry. This is not a host-wide Worker universe query.","properties":{"method":{"const":"list_workers","type":"string"}},"required":["method"],"type":"object"},{"additionalProperties":false,"description":"Restore a visible stopped/restorable Worker, or report that it is already\nlive. Missing state and not-visible state are distinct errors.","properties":{"method":{"const":"restore_worker","type":"string"},"params":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"description":"Register another existing Worker as a reciprocal peer of this Worker.\n\nThis is metadata/control state only: it does not ask the target's live\ncontroller for consent, and it must not grant delegated scope,\nspawned-child ownership, output cursors, or child lifecycle authority.","properties":{"method":{"const":"register_peer","type":"string"},"params":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}},"required":["method","params"],"type":"object"}]},"PasteArtifactAvailability":{"enum":["available","unavailable","integrity_failed"],"type":"string"},"PasteArtifactMediaType":{"description":"One typed piece of a user submission.\n\n`Method::Submit` and `Event::UserMessage` carry `Vec`. Dumb\nclients (CLI piping, scripts) only need to produce a single\n`Segment::Text`; richer clients (TUI / GUI) construct typed atoms\n(paste chips, file refs) and\nsend them through directly so the Worker side never has to re-parse a\nflattened string.\n\nForward compat: payloads with unknown `kind` deserialize to\n`Segment::Unknown`. Worker treats this the same as known-but-unresolved\nvariants — emits an alert and inserts a `[unknown input segment]`\nplaceholder into the LLM context so neither user nor LLM is blind to\nthe dropped intent.","enum":["text_plain_utf8"],"type":"string"},"PasteArtifactRef":{"additionalProperties":false,"description":"Session-owned reference to a large pasted-input artifact.\n\nThe reference contains only bounded integrity and provenance metadata. The\nartifact body remains in session storage and is available to the model only\nthrough the scoped paste-artifact tools installed by Worker.","properties":{"artifact_id":{"type":"string"},"availability":{"$ref":"#/$defs/PasteArtifactAvailability","description":"Availability observed when this immutable reference was committed.\nReads revalidate storage and integrity rather than trusting this field."},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"char_count":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"created_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"line_count":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"media_type":{"$ref":"#/$defs/PasteArtifactMediaType"},"sha256":{"type":"string"},"source_entry_id":{"type":"string"}},"required":["artifact_id","created_at_ms","media_type","availability","byte_len","char_count","line_count","sha256","source_entry_id"],"type":"object"},"PendingSubmissionSummary":{"additionalProperties":false,"description":"Bounded public projection of one pending submission. Only a short display\npreview is exposed; full payload segments and provenance remain in the log.","properties":{"accepted_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"preview":{"description":"Single-line display text, at most 240 Unicode scalars plus an ellipsis.\nAbsent on older runtimes. Never used to reconstruct the submitted input.","type":["string","null"]},"segment_count":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"submission_id":{"type":"string"}},"required":["submission_id","accepted_at_ms","segment_count","byte_len"],"type":"object"},"PendingSubmissionsSnapshot":{"additionalProperties":false,"description":"Session-owned FIFO content projection used by snapshots and live events.","properties":{"head_id":{"default":null,"type":["string","null"]},"notification_count":{"default":0,"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"notification_previews":{"description":"Ordered display-only previews of waiting notifications, each bounded like\nPendingSubmissionSummary::preview. Older runtimes omit this field.","items":{"type":"string"},"type":"array"},"submissions":{"default":[],"items":{"$ref":"#/$defs/PendingSubmissionSummary"},"type":"array"}},"required":["head_id","notification_count","submissions"],"type":"object"},"Permission":{"description":"Permission lattice used by [`ScopeRule`].\n\nThe derived `Ord` instance follows declaration order, so\n`Read < Write`. Allow rules grant the stated level (and by extension\neverything below); deny rules cap the effective level **strictly\nbelow** the stated level.","enum":["read","write"],"type":"string"},"ReasoningConfig":{"description":"Public reasoning configuration resolved for the model client.\n\nThis deliberately exposes only the effective provider control, not the\nWorker manifest or provider credentials. The tagged shape prevents token\nbudgets from being presented as effort labels.","oneOf":[{"additionalProperties":false,"properties":{"effort":{"type":"string"},"kind":{"const":"effort","type":"string"}},"required":["kind","effort"],"type":"object"},{"additionalProperties":false,"properties":{"budget_tokens":{"format":"int32","maximum":2147483647.0,"minimum":-2147483648.0,"type":"integer"},"kind":{"const":"budget_tokens","type":"string"}},"required":["kind","budget_tokens"],"type":"object"}]},"RewindSummary":{"additionalProperties":false,"properties":{"discarded_entries":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"tool_side_effect_warning":{"type":"boolean"},"truncated_to_entries":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["truncated_to_entries","discarded_entries","tool_side_effect_warning"],"type":"object"},"RunFailureKind":{"enum":["engine","compaction"],"type":"string"},"RunResult":{"oneOf":[{"enum":["finished","paused","limit_reached"],"type":"string"},{"const":"cancelled","description":"The logical Run ended because the user intentionally cancelled it after\nobservable work. Unlike `RolledBack`, committed history is retained.","type":"string"},{"const":"rolled_back","description":"The accepted Method::Submit produced no assistant/tool output before\nuser interruption, so the Worker rolled the submit-time turn state back\nto its pre-submit snapshot. Clients should treat the Worker as Idle and\nrestore the just-submitted input into the editable composer if desired.","type":"string"}]},"RunResumeSource":{"enum":["compaction","pause"],"type":"string"},"RunYieldReason":{"enum":["compaction"],"type":"string"},"ScopeRule":{"additionalProperties":false,"description":"A single allow or deny rule inside a scope configuration.","properties":{"permission":{"$ref":"#/$defs/Permission","description":"Permission level this rule grants (allow) or caps strictly below\n(deny)."},"recursive":{"default":true,"description":"When `false`, the rule only matches the target itself and its\ndirect children. Defaults to `true`.","type":"boolean"},"symlink_policy":{"$ref":"#/$defs/SymlinkPolicy","default":"resolved","description":"Which path identity an allow rule uses when symbolic links are\nencountered. Deny rules always inspect both identities."},"target":{"description":"Target path. Must be absolute by the time a `Scope` is built from\nthis rule — relative paths are resolved per-layer against the\nmanifest file's directory (cwd for overlay layers) before cascade\nmerge.","type":"string"}},"required":["target","permission","recursive","symlink_policy"],"type":"object"},"Segment":{"oneOf":[{"additionalProperties":false,"description":"Free-form text. The fallback every client can produce.","properties":{"content":{"type":"string"},"kind":{"const":"text","type":"string"}},"required":["kind","content"],"type":"object"},{"additionalProperties":false,"description":"Bracketed-paste capture from a TUI-style client. `id`, `chars`\nand `lines` carry the metadata needed to re-render a\n`[Clipboard #N | X chars, Y lines]` chip in `Event::UserMessage`\nre-broadcast.","properties":{"chars":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"content":{"type":"string"},"id":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"},"kind":{"const":"paste","type":"string"},"lines":{"format":"uint32","maximum":4294967295.0,"minimum":0.0,"type":"integer"}},"required":["kind","id","chars","lines","content"],"type":"object"},{"additionalProperties":false,"description":"Internal reference produced when Worker stores a large `Paste` before\ncommitting input. Clients may receive this in history/event projections;\nthe body is intentionally absent.","properties":{"artifact":{"$ref":"#/$defs/PasteArtifactRef"},"kind":{"const":"paste_artifact","type":"string"}},"required":["kind","artifact"],"type":"object"},{"additionalProperties":false,"description":"Client-local file uploaded into the owning Worker session before submit.\nThe Session Log stores only this immutable reference, never file bytes or\nthe client's local path.","properties":{"file":{"$ref":"#/$defs/UploadedFileRef"},"kind":{"const":"uploaded_file","type":"string"}},"required":["kind","file"],"type":"object"},{"additionalProperties":false,"description":"`@` file-system reference. Worker resolves readable files to\n`[File: ]` attachments and readable normal directories to shallow\n`[Dir: ]` listings; the flattened user text keeps the literal\n`@` placeholder either way.","properties":{"kind":{"const":"file_ref","type":"string"},"path":{"type":"string"}},"required":["kind","path"],"type":"object"},{"additionalProperties":false,"description":"Explicitly selected, source-qualified Feature invocation. The host never\npromotes free text to this variant and validates it against the installed\ndeclaration before execution.","properties":{"invocation":{"$ref":"#/$defs/FeatureInvocation"},"kind":{"const":"feature_invoke","type":"string"}},"required":["kind","invocation"],"type":"object"},{"additionalProperties":false,"description":"Source-qualified request for the host to start a Flow before committing\nthis user input. Runtime resolves it through Workspace authority and\nreplaces it with the entered state's instructions before Worker-side\ninput resolution.","properties":{"kind":{"const":"flow","type":"string"},"selector":{"type":"string"}},"required":["kind","selector"],"type":"object"},{"additionalProperties":false,"description":"Unknown variant from a newer client. Worker treats this as an\nunresolved input — surfaces an alert and inserts a placeholder.\nRound-trip is lossy: re-serializing yields `{\"kind\":\"unknown\"}`.","properties":{"kind":{"const":"unknown","type":"string"}},"required":["kind"],"type":"object"}]},"SessionContentPart":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"text","type":"string"},"text":{"type":"string"}},"required":["kind","text"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"refusal","type":"string"},"refusal":{"type":"string"}},"required":["kind","refusal"],"type":"object"}]},"SessionEntryProvenance":{"enum":["human_input","worker_input","flow_instruction","backend_instruction","model_output","tool_output","derived_summary","legacy_unknown"],"type":"string"},"SessionEntryUsePolicy":{"additionalProperties":false,"description":"Public use decisions contain no Feature identity or private payload. Absence\ndenotes the older projection contract, not permission to expose System input.","properties":{"memory_evidence":{"type":"boolean"},"observation_readable":{"type":"boolean"}},"required":["observation_readable","memory_evidence"],"type":"object"},"SessionMessageRole":{"enum":["user","assistant"],"type":"string"},"SessionSnapshot":{"additionalProperties":false,"description":"Canonical, storage-independent projection of committed session history.\n\nWorker protocols expose this DTO instead of append-log records. New\nstorage variants can therefore be added without teaching every client how\nto replay the durable log format.","properties":{"entries":{"items":{"$ref":"#/$defs/SessionSnapshotEntry"},"type":"array"},"pending_submissions":{"$ref":"#/$defs/PendingSubmissionsSnapshot","default":{"head_id":null,"notification_count":0,"submissions":[]}}},"required":["entries","pending_submissions"],"type":"object"},"SessionSnapshotEntry":{"oneOf":[{"additionalProperties":false,"properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"user_input","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"segments":{"items":{"$ref":"#/$defs/Segment"},"type":"array"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","segments","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"content":{"items":{"$ref":"#/$defs/SessionContentPart"},"type":"array"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"message","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"role":{"$ref":"#/$defs/SessionMessageRole"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","role","content","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"arguments":{"type":"string"},"call_id":{"type":"string"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"tool_call","type":"string"},"name":{"type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","call_id","name","arguments","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"attachments":{"items":{"$ref":"#/$defs/SessionToolAttachment"},"type":"array"},"call_id":{"type":"string"},"content":{"type":["string","null"]},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"is_error":{"type":"boolean"},"kind":{"const":"tool_result","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"summary":{"type":"string"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","call_id","summary","is_error","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"content":{"type":"string"},"data":true,"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"item_kind":{"type":"string"},"kind":{"const":"system_item","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","item_kind","content","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Durable, non-terminal control return from one logical Run. This is not a\ncompleted run and must not be used to infer the current Worker state.","properties":{"active_run_turn_count":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_yielded","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"reason":{"$ref":"#/$defs/RunYieldReason"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","reason","active_run_turn_count","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Durable boundary immediately before Engine execution resumes. The source\ndistinguishes automatic compaction continuation from an intentional\nuser-pause resume; it does not prove that later model output occurred.","properties":{"active_run_turn_count":{"format":"uint","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_resumed","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"source":{"$ref":"#/$defs/RunResumeSource"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","source","active_run_turn_count","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Snapshot-only replay of persisted invocation/usage records. These are\naccounting metadata, never model context or conversation rows.","properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"invoke","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"trigger":{"$ref":"#/$defs/InvokeKind"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","trigger","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"cache_read_input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"input_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"kind":{"const":"usage","type":"string"},"output_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","input_tokens","cache_read_input_tokens","output_tokens","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Display-only accounting reconstructed from persisted run/usage records.","properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"elapsed_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_stats","type":"string"},"output_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"requests":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"upload_tokens":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","elapsed_ms","requests","upload_tokens","output_tokens","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"description":"Durable terminal for an intentional cancellation. Consumers must not\npresent this lifecycle result as an execution failure.","properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"kind":{"const":"run_cancelled","type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","entry_id","timestamp","provenance"],"type":"object"},{"additionalProperties":false,"properties":{"derived_from":{"items":{"type":"string"},"type":"array"},"entry_id":{"description":"Stable identity from durable history metadata, or a deterministic\nidentity derived from the legacy segment and log position.","type":"string"},"failure":{"anyOf":[{"$ref":"#/$defs/RunFailureKind"},{"type":"null"}]},"kind":{"const":"run_error","type":"string"},"message":{"type":"string"},"provenance":{"$ref":"#/$defs/SessionEntryProvenance"},"timestamp":{"description":"Timestamp copied from the durable log record that commits this entry.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"use_policy":{"anyOf":[{"$ref":"#/$defs/SessionEntryUsePolicy"},{"type":"null"}]}},"required":["kind","message","entry_id","timestamp","provenance"],"type":"object"}]},"SessionToolAttachment":{"additionalProperties":false,"properties":{"attachment_id":{"description":"Stable, bounded identity derived from the owning Session entry, attachment\nposition, and immutable image bytes. It is a locator, not a bearer secret.","type":"string"},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"media_type":{"type":"string"}},"required":["attachment_id","media_type","byte_len"],"type":"object"},"SubmissionDisposition":{"description":"Durable acceptance result for one idempotent Submit request.","oneOf":[{"enum":["started"],"type":"string"},{"const":"queued","description":"Input is durably held in the session FIFO until eligible for activation.","type":"string"}]},"SubscriptionEvent":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"payload":{"$ref":"#/$defs/SubscriptionEventPayload"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["subscription_id","payload"],"type":"object"},"event":{"const":"event","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"code":{"$ref":"#/$defs/SubscriptionTerminationCode"},"message":{"type":"string"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["subscription_id","code","message"],"type":"object"},"event":{"const":"subscription_closed","type":"string"}},"required":["event","data"],"type":"object"}]},"SubscriptionEventPayload":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"worker":{"$ref":"#/$defs/SubscriptionWorker"}},"required":["worker"],"type":"object"},"event":{"const":"worker_upserted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"runtime_id":{"type":["string","null"]},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["worker_id"],"type":"object"},"event":{"const":"worker_removed","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"event":{"$ref":"#/$defs/Event"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["worker_id","event"],"type":"object"},"event":{"const":"worker_protocol","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"workdir":{"$ref":"#/$defs/WorkspaceSubscriptionWorkdir"}},"required":["workdir"],"type":"object"},"event":{"const":"workdir_upserted","type":"string"}},"required":["event","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"working_directory_id":{"$ref":"#/$defs/SubscriptionWorkdirId"}},"required":["working_directory_id"],"type":"object"},"event":{"const":"workdir_removed","type":"string"}},"required":["event","data"],"type":"object"}]},"SubscriptionId":{"type":"string"},"SubscriptionRejectionCode":{"enum":["invalid_request","unsupported_protocol_version","unsupported_selector","unauthorized","resource_not_found","capacity_exceeded","internal"],"type":"string"},"SubscriptionRequest":{"oneOf":[{"additionalProperties":false,"properties":{"method":{"const":"subscribe_events","type":"string"},"params":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"selector":{"$ref":"#/$defs/EventSubscriptionSelector"}},"required":["request_id","selector"],"type":"object"}},"required":["method","params"],"type":"object"},{"additionalProperties":false,"properties":{"method":{"const":"unsubscribe_events","type":"string"},"params":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["request_id","subscription_id"],"type":"object"}},"required":["method","params"],"type":"object"}]},"SubscriptionRequestId":{"type":"string"},"SubscriptionResponse":{"oneOf":[{"additionalProperties":false,"properties":{"payload":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"selector":{"$ref":"#/$defs/EventSubscriptionSelector"},"snapshot":{"$ref":"#/$defs/SubscriptionSnapshot"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["request_id","subscription_id","selector","snapshot"],"type":"object"},"result":{"const":"subscribed","type":"string"}},"required":["result","payload"],"type":"object"},{"additionalProperties":false,"properties":{"payload":{"additionalProperties":false,"properties":{"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["request_id","subscription_id"],"type":"object"},"result":{"const":"unsubscribed","type":"string"}},"required":["result","payload"],"type":"object"},{"additionalProperties":false,"properties":{"payload":{"additionalProperties":false,"properties":{"code":{"$ref":"#/$defs/SubscriptionRejectionCode"},"message":{"type":"string"},"request_id":{"$ref":"#/$defs/SubscriptionRequestId"},"subscription_id":{"anyOf":[{"$ref":"#/$defs/SubscriptionId"},{"type":"null"}]}},"required":["request_id","code","message"],"type":"object"},"result":{"const":"subscription_rejected","type":"string"}},"required":["result","payload"],"type":"object"}]},"SubscriptionSnapshot":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"workers":{"items":{"$ref":"#/$defs/SubscriptionWorker"},"type":"array"}},"required":["workers"],"type":"object"},"topic":{"const":"workers","type":"string"}},"required":["topic","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"events":{"items":{"$ref":"#/$defs/Event"},"type":"array"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"}},"required":["worker_id","events"],"type":"object"},"topic":{"const":"worker_protocol","type":"string"}},"required":["topic","data"],"type":"object"},{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"workdirs":{"items":{"$ref":"#/$defs/WorkspaceSubscriptionWorkdir"},"type":"array"}},"required":["workdirs"],"type":"object"},"topic":{"const":"workspace_workdirs","type":"string"}},"required":["topic","data"],"type":"object"}]},"SubscriptionTerminationCode":{"enum":["lagged","resource_gone","unauthorized","server_shutdown"],"type":"string"},"SubscriptionWorkdirId":{"type":"string"},"SubscriptionWorker":{"additionalProperties":false,"properties":{"availability":{"$ref":"#/$defs/SubscriptionWorkerAvailability","default":"observed","description":"Freshness of the Runtime-backed observation carried by this projection.\n`Unavailable` preserves catalog membership without claiming that execution stopped."},"display_name":{"type":["string","null"]},"has_running_internal_workers":{"default":false,"type":"boolean"},"job":{"anyOf":[{"$ref":"#/$defs/SubscriptionWorkerJob"},{"type":"null"}],"description":"Backend-owned Job binding. Runtime producers leave this unset; the\nWorkspace projection enriches both snapshots and live updates."},"profile":{"type":["string","null"]},"resource_key":{"description":"Workspace-scoped canonical resource key. Runtime producers leave this unset;\nWorkspace-facing projections must populate it before publishing the Worker.","type":["string","null"]},"restore_observation_token":{"description":"Opaque Runtime-owned Restore observation identity, never a display-state hash.","type":["string","null"]},"runtime_id":{"description":"Set by the Workspace Server when projecting a Runtime-owned Worker to clients.\nRuntime producers leave this unset because the connection identifies the Runtime.","type":["string","null"]},"state":{"$ref":"#/$defs/SubscriptionWorkerState","description":"Runtime catalog lifecycle compatibility projection; not foreground-state authority."},"workdir_attachments":{"items":{"$ref":"#/$defs/SubscriptionWorkerWorkdirAttachment"},"type":"array"},"worker_id":{"$ref":"#/$defs/SubscriptionWorkerId"},"worker_state":{"anyOf":[{"$ref":"#/$defs/WorkerStateSnapshot"},{"type":"null"}],"description":"Latest foreground state observed from the Worker. This remains\nabsent until an authoritative Worker snapshot/event has been applied."},"workspace_id":{"type":["string","null"]}},"required":["worker_id","state","availability","has_running_internal_workers"],"type":"object"},"SubscriptionWorkerAvailability":{"description":"Whether the Workspace Server has a current Runtime observation for a Worker.\n\n`Unavailable` deliberately does not imply `Stopped`: it means the last observed\nlifecycle state is retained while the Runtime observation source is unavailable.","enum":["observed","unavailable"],"type":"string"},"SubscriptionWorkerId":{"type":"string"},"SubscriptionWorkerIds":{"description":"A bounded, canonical worker-id set. Ordering on the wire and in equality/hash\nsemantics is lexical, so equivalent selectors aggregate to one upstream key.","items":{"$ref":"#/$defs/SubscriptionWorkerId"},"type":"array"},"SubscriptionWorkerJob":{"additionalProperties":false,"properties":{"attempt_id":{"type":"string"},"job_id":{"type":"string"},"purpose":{"type":"string"}},"required":["job_id","attempt_id","purpose"],"type":"object"},"SubscriptionWorkerProtocolMethod":{"additionalProperties":false,"properties":{"method":{"$ref":"#/$defs/Method"},"subscription_id":{"$ref":"#/$defs/SubscriptionId"}},"required":["subscription_id","method"],"type":"object"},"SubscriptionWorkerState":{"enum":["idle","running","paused","stopped"],"type":"string"},"SubscriptionWorkerWorkdirAttachment":{"additionalProperties":false,"properties":{"alias":{"description":"Stable Worker-local routing alias.","type":"string"},"repository_key":{"type":["string","null"]},"working_directory_id":{"$ref":"#/$defs/SubscriptionWorkdirId"}},"required":["alias","working_directory_id"],"type":"object"},"SymlinkPolicy":{"description":"Symbolic-link identity used by one filesystem allow rule.\n\n`Resolved` is the least authority and the default: access is matched\nagainst the provider-resolved target. `Logical` intentionally grants the\npath as presented through the Workdir, even when it aliases another target.","enum":["resolved","logical"],"type":"string"},"ToolResultDisposition":{"enum":["success","error","interrupted","cancelled","outcome_unknown"],"type":"string"},"TurnResult":{"enum":["finished","paused"],"type":"string"},"UploadedFileAvailability":{"description":"Availability recorded for an uploaded client-local file.","enum":["available","unavailable","integrity_failed"],"type":"string"},"UploadedFileRef":{"additionalProperties":false,"description":"Session-owned immutable reference to a client-local uploaded file.\n\nUpload transports return an unbound reference. Worker fills\n`source_entry_id` immediately before the containing user input is committed;\ncommitted Session Log and public snapshot records therefore always retain\nthe durable source-entry identity without storing the file body.","properties":{"artifact_id":{"type":"string"},"availability":{"$ref":"#/$defs/UploadedFileAvailability"},"byte_len":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"created_at_ms":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"file_name":{"type":"string"},"media_type":{"type":"string"},"sha256":{"type":"string"},"source_entry_id":{"type":["string","null"]}},"required":["artifact_id","file_name","media_type","created_at_ms","availability","byte_len","sha256"],"type":"object"},"WorkerBusyState":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"run","type":"string"},"state":{"$ref":"#/$defs/WorkerRunState"}},"required":["kind","state"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"maintenance","type":"string"},"state":{"$ref":"#/$defs/WorkerMaintenanceState"}},"required":["kind","state"],"type":"object"}]},"WorkerCommandAcknowledgement":{"additionalProperties":false,"properties":{"command":{"$ref":"#/$defs/WorkerCommandKind"},"command_id":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"disposition":{"$ref":"#/$defs/WorkerCommandDisposition"},"state":{"$ref":"#/$defs/WorkerStateSnapshot","description":"The complete authoritative state observed after command admission."}},"required":["command_id","command","disposition","state"],"type":"object"},"WorkerCommandDisposition":{"enum":["accepted","stale_command_id","conflict","invalid_state"],"type":"string"},"WorkerCommandEnvelope":{"additionalProperties":false,"description":"Caller-owned identity for one state-changing Worker command.\n\nCommands operate on the controller state at admission time, not a caller's\npreviously observed Run. A controller accepts command ids in strictly\nincreasing order; retrying an accepted id cannot apply it to a later Run.\nExact retries must retain the same command kind. Removed preconditions are\nrejected at the wire boundary rather than treated as arrival-time commands.","properties":{"command_id":{"format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"}},"required":["command_id"],"type":"object"},"WorkerCommandKind":{"enum":["resume","cancel","pause","compact","shutdown"],"type":"string"},"WorkerEvent":{"description":"Typed lifecycle events sent from a child Worker to its parent.\n\nDelivered as `Method::WorkerEvent` over the parent's Unix socket. The\nparent Controller always applies variant-specific side effects\n(registry / worker-allocation updates). Agent-visible variants are also\nqueued into the notification buffer; control-plane-only variants are\nnot injected into the parent's LLM context.\n\nTransport is fire-and-forget; receivers must tolerate out-of-order\ndelivery (e.g. `TurnEnded` arriving after `ShutDown` for the same\nchild Worker).","oneOf":[{"additionalProperties":false,"description":"Child finished one turn and is back to IDLE.","properties":{"kind":{"const":"turn_ended","type":"string"},"worker_name":{"type":"string"}},"required":["kind","worker_name"],"type":"object"},{"additionalProperties":false,"description":"Engine execution error occurred inside the child's turn.\n\nLimited to worker runtime failures (provider / tool errors) —\ndoes not include transient method-rejection responses such as\n`AlreadyRunning`.","properties":{"kind":{"const":"errored","type":"string"},"message":{"type":"string"},"worker_name":{"type":"string"}},"required":["kind","worker_name","message"],"type":"object"},{"additionalProperties":false,"description":"Child has stopped (controller loop is exiting).","properties":{"kind":{"const":"shut_down","type":"string"},"worker_name":{"type":"string"}},"required":["kind","worker_name"],"type":"object"},{"additionalProperties":false,"description":"Child SubWorker sub-delegated scope to a grandchild SubWorker via `SubWorkerSpawn`.\n\nControl-plane only: receivers apply registry side effects and\npropagate upward, but do not expose this as an agent notification.\n\nThe parent uses this to add the grandchild to its own\n`spawned_workers.json` so it can manage the grandchild directly\neven if the intermediate child dies. The parent then re-fires\nthis event upward (if it has a parent of its own) to maintain\nthe chain to root.","properties":{"kind":{"const":"scope_sub_delegated","type":"string"},"parent_worker":{"description":"Sub-delegating Worker (= the sender itself).","type":"string"},"scope":{"description":"Scope delegated to the grandchild.","items":{"$ref":"#/$defs/ScopeRule"},"type":"array"},"sub_socket":{"description":"Unix-socket path where the grandchild is reachable.","type":"string"},"sub_worker":{"description":"Name of the grandchild Worker.","type":"string"}},"required":["kind","parent_worker","sub_worker","sub_socket","scope"],"type":"object"}]},"WorkerMaintenanceState":{"enum":["compacting"],"type":"string"},"WorkerRunState":{"enum":["running","pausing","paused","cancelling"],"type":"string"},"WorkerState":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"idle","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"busy","type":"string"},"state":{"$ref":"#/$defs/WorkerBusyState"}},"required":["kind","state"],"type":"object"}]},"WorkerStateSnapshot":{"additionalProperties":false,"properties":{"last_command_id":{"description":"Highest lifecycle command id observed by this controller instance.","format":"uint64","maximum":9007199254740991.0,"minimum":0.0,"type":"integer"},"last_finished_submission_request_id":{"description":"Most recent Submit request whose controller Run has returned and whose\npost-Run state transition has been published. This is a teardown fence,\nnot a successful-result claim; cancelled and failed Runs may also finish.","type":["string","null"]},"state":{"$ref":"#/$defs/WorkerState"}},"required":["last_command_id","state"],"type":"object"},"WorkerStatus":{"enum":["idle","running","paused","stopped"],"type":"string"},"WorkspaceSubscriptionWorkdir":{"additionalProperties":false,"description":"Workspace-facing Workdir summary. Backend-generated Repository UUIDs never\nenter this DTO; Workspace Server must resolve the required Repository key.","properties":{"repository_key":{"type":"string"},"state":{"type":"string"},"working_directory_id":{"$ref":"#/$defs/SubscriptionWorkdirId"}},"required":["working_directory_id","repository_key","state"],"type":"object"}},"$schema":"https://json-schema.org/draft/2020-12/schema","description":"Direction is explicit at the outer envelope, while concrete message kinds\nremain typed within each lane.","oneOf":[{"additionalProperties":false,"properties":{"frame":{"const":"request","type":"string"},"message":{"$ref":"#/$defs/SubscriptionRequest"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"},{"additionalProperties":false,"properties":{"frame":{"const":"response","type":"string"},"message":{"$ref":"#/$defs/SubscriptionResponse"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"},{"additionalProperties":false,"properties":{"frame":{"const":"event","type":"string"},"message":{"$ref":"#/$defs/SubscriptionEvent"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"},{"additionalProperties":false,"properties":{"frame":{"const":"worker_protocol","type":"string"},"message":{"$ref":"#/$defs/SubscriptionWorkerProtocolMethod"},"protocol_version":{"format":"uint16","maximum":65535.0,"minimum":0.0,"type":"integer"}},"required":["frame","message","protocol_version"],"type":"object"}],"title":"SubscriptionFrame"}; export const RUST_SERIALIZED_SUBSCRIPTION_FRAME_FIXTURES: readonly unknown[] = [{"protocol_version":2,"frame":"response","message":{"result":"subscribed","payload":{"request_id":"fixture-request","subscription_id":"fixture-subscription","selector":{"topic":"workspace_workers"},"snapshot":{"topic":"workers","data":{"workers":[{"restore_observation_token":"fixture-restore-observation","worker_id":"fixture-worker","runtime_id":"fixture-runtime","resource_key":"fixture-worker-resource","availability":"observed","state":"idle","has_running_internal_workers":false,"workspace_id":"fixture-workspace","workdir_attachments":[{"alias":"external","working_directory_id":"fixture-external-workdir"}]}]}}}}},{"protocol_version":2,"frame":"event","message":{"event":"event","data":{"subscription_id":"fixture-subscription","payload":{"event":"worker_protocol","data":{"worker_id":"fixture-worker","event":{"event":"pending_submissions_changed","data":{"pending":{"notification_count":0,"head_id":null,"submissions":[]}}}}}}}},{"protocol_version":2,"frame":"event","message":{"event":"event","data":{"subscription_id":"fixture-subscription","payload":{"event":"worker_protocol","data":{"worker_id":"fixture-worker","event":{"event":"snapshot","data":{"session":{"pending_submissions":{"notification_count":0,"head_id":null,"submissions":[]},"entries":[]},"greeting":{"worker_name":"fixture-worker","cwd":"/fixture","provider":"openai_responses","model":"gpt-6-astra","reasoning":{"kind":"effort","effort":"high"},"scope_summary":"fixture scope","tools":["Read"],"context_window":272000,"context_tokens":142000,"context_usage":{"tokens":142000,"source":"measured"}},"state":{"last_command_id":0,"state":{"kind":"idle"}},"internal_workers":[{"worker":{"session_id":"fixture-child-session","name":"fixture-child","parent_session_id":"fixture-parent-session","kind":"sub_worker"},"session":{"pending_submissions":{"notification_count":0,"head_id":null,"submissions":[]},"entries":[]},"greeting":{"worker_name":"fixture-worker","cwd":"/fixture","provider":"openai_responses","model":"gpt-6-astra","reasoning":{"kind":"effort","effort":"high"},"scope_summary":"fixture scope","tools":["Read"],"context_window":272000,"context_tokens":142000,"context_usage":{"tokens":142000,"source":"measured"}},"status":"idle"}]}}}}}}}]; const utf8 = new TextEncoder(); diff --git a/web/workspace/src/lib/generated/protocol.ts b/web/workspace/src/lib/generated/protocol.ts index 8b6870f39..8223baf07 100644 --- a/web/workspace/src/lib/generated/protocol.ts +++ b/web/workspace/src/lib/generated/protocol.ts @@ -206,7 +206,7 @@ entry_id: string, /** * Timestamp copied from the durable log record that commits this entry. */ -timestamp: number, provenance: SessionEntryProvenance, derived_from?: Array, } & ({ "kind": "user_input", segments: Array, } | { "kind": "message", role: SessionMessageRole, content: Array, } | { "kind": "tool_call", call_id: string, name: string, arguments: string, } | { "kind": "tool_result", call_id: string, summary: string, content?: string | null, is_error: boolean, attachments?: Array, } | { "kind": "system_item", item_kind: string, content: string, data?: unknown, } | { "kind": "run_yielded", reason: RunYieldReason, active_run_turn_count: number, } | { "kind": "run_resumed", source: RunResumeSource, active_run_turn_count: number, } | { "kind": "invoke", trigger: InvokeKind, } | { "kind": "usage", input_tokens: number, cache_read_input_tokens: number, output_tokens: number, } | { "kind": "run_stats", elapsed_ms: number, requests: number, upload_tokens: number, output_tokens: number, } | { "kind": "run_cancelled" } | { "kind": "run_error", message: string, failure?: RunFailureKind | null, }); +timestamp: number, provenance: SessionEntryProvenance, derived_from?: Array, use_policy?: SessionEntryUsePolicy | null, } & ({ "kind": "user_input", segments: Array, } | { "kind": "message", role: SessionMessageRole, content: Array, } | { "kind": "tool_call", call_id: string, name: string, arguments: string, } | { "kind": "tool_result", call_id: string, summary: string, content?: string | null, is_error: boolean, attachments?: Array, } | { "kind": "system_item", item_kind: string, content: string, data?: unknown, } | { "kind": "run_yielded", reason: RunYieldReason, active_run_turn_count: number, } | { "kind": "run_resumed", source: RunResumeSource, active_run_turn_count: number, } | { "kind": "invoke", trigger: InvokeKind, } | { "kind": "usage", input_tokens: number, cache_read_input_tokens: number, output_tokens: number, } | { "kind": "run_stats", elapsed_ms: number, requests: number, upload_tokens: number, output_tokens: number, } | { "kind": "run_cancelled" } | { "kind": "run_error", message: string, failure?: RunFailureKind | null, }); export type SessionConversationTurn = { turn_id: string, entries: Array, };