refactor: rename pod crate to worker

This commit is contained in:
2026-06-26 00:05:57 +09:00
parent 4c677640f4
commit 6c59fe927b
194 changed files with 6637 additions and 6146 deletions
+3 -3
View File
@@ -15,18 +15,18 @@ Owns:
Does not own:
- current Pod-name metadata (`pod-store`)
- current Worker-name metadata (`pod-store`)
- live process/socket discovery (`pod-registry`, `client`)
- UI state (`tui`)
- generated memory summaries (`memory`)
## Design notes
A session log records what happened. It is not the current Pod registry and should not be queried as the only source of "what does Pod X mean now?"
A session log records what happened. It is not the current Worker registry and should not be queried as the only source of "what does Worker X mean now?"
Prefer explicit current log variants over broad legacy compatibility when schema changes; hidden compatibility can make future replay bugs silent.
## See also
- [`../../docs/design/pod-session-state.md`](../../docs/design/pod-session-state.md)
- [`../../docs/design/worker-session-state.md`](../../docs/design/worker-session-state.md)
- [`../../docs/design/context-history.md`](../../docs/design/context-history.md)
+2 -2
View File
@@ -11,7 +11,7 @@
//! the same Session.
//!
//! This crate provides free functions for persistence operations.
//! The caller (typically Pod) holds the Engine directly and calls these
//! The caller (typically Worker) holds the Engine directly and calls these
//! functions after state-mutating operations.
//!
//! Debug-mode [`TraceEntry`] records capture raw stream events in a separate
@@ -51,7 +51,7 @@ pub use segment::{
};
pub use segment_log::{LogEntry, RestoredState, SegmentOrigin, collect_state};
pub use store::{Store, StoreError};
pub use system_item::{SystemItem, SystemReminder, SystemReminderSource, render_pod_event};
pub use system_item::{SystemItem, SystemReminder, SystemReminderSource, render_worker_event};
/// Session identifier — the fork-tree root. UUID v7 (time-ordered).
///
+5 -5
View File
@@ -1,7 +1,7 @@
//! Free functions for segment persistence operations.
//!
//! These functions record and restore segment state without owning a Engine.
//! The caller (typically Pod) holds the Engine directly and calls these
//! The caller (typically Worker) holds the Engine directly and calls these
//! functions after state-mutating operations.
use crate::logged_item::{LoggedItem, to_logged};
@@ -36,7 +36,7 @@ pub fn create_segment(
/// Write a fresh `SegmentStart` entry using pre-generated IDs.
///
/// Used by callers that need to reserve `(session_id, segment_id)`
/// synchronously but defer the initial log append (e.g. Pod, which
/// synchronously but defer the initial log append (e.g. Worker, which
/// resolves a templated system prompt only at first turn).
pub fn create_segment_with_ids(
store: &impl Store,
@@ -102,7 +102,7 @@ pub fn restore(
/// Restore segment state when only the segment ID is known. Uses
/// [`Store::lookup_session_of`] to resolve the parent Session.
///
/// Shim for legacy entry points (`pod-cli --session <UUID>` etc.) that
/// Shim for legacy entry points (`worker-cli --session <UUID>` etc.) that
/// receive a Segment ID without a Session ID.
pub fn restore_by_segment(
store: &impl Store,
@@ -174,7 +174,7 @@ pub fn ensure_head_or_fork(
/// Log a `UserInput` entry from the original typed `Vec<Segment>`.
///
/// Submit-time entry. Pod calls this at the head of a `Run` turn before
/// Submit-time entry. Worker calls this at the head of a `Run` turn before
/// the worker pushes its flattened user message into history; replay
/// derives the worker `Item::user_message` from these segments via
/// [`Segment::flatten_to_text`].
@@ -250,7 +250,7 @@ pub fn classify_history_item(item: &Item, ts: u64) -> LogEntry {
}
/// Append a single typed system item as `LogEntry::SystemItem`. Helper
/// for the Pod-side interceptor commit path; mirrors the per-item
/// for the Worker-side interceptor commit path; mirrors the per-item
/// commit shape used for assistant / tool result entries.
pub fn append_system_item(
store: &impl Store,
+4 -4
View File
@@ -58,10 +58,10 @@ pub enum LogEntry {
/// IDLE → active marker. Records the start of a new self-driving
/// cycle (Invoke range). The range extends implicitly until the
/// next `Invoke` entry; this entry carries the trigger only — the
/// actual payload (user text / notify message / pod event body) is
/// actual payload (user text / notify message / worker event body) is
/// in the immediately following Turn entry (`UserInput` / `SystemItem`).
///
/// Used by `pod-session-fork` style operations: the fork-point seq
/// Used by `worker-session-fork` style operations: the fork-point seq
/// (`at_turn_index` in persistence-semantics) points at one of these
/// `Invoke` entries so "back to N-th send" maps cleanly to the
/// IDLE-break boundary the user sees.
@@ -87,7 +87,7 @@ pub enum LogEntry {
/// One tool-execution result appended to history.
ToolResult { ts: u64, item: LoggedItem },
/// One typed agent-injected system item: notification, child-Pod
/// One typed agent-injected system item: notification, child-Worker
/// lifecycle event, `@<path>` / `#<slug>` / `/<slug>` resolution
/// payload. Each `SystemItem` carries kind metadata that the LLM
/// itself never sees (the LLM gets `Item::system_message` with the
@@ -117,7 +117,7 @@ pub enum LogEntry {
/// A paused interrupted turn was explicitly abandoned without calling
/// `run()` or `resume()` again. Replay clears the interrupted marker so
/// the restored Pod is idle and future user input starts a normal new turn.
/// the restored Worker is idle and future user input starts a normal new turn.
PausedTurnAbandoned { ts: u64 },
/// `RequestConfig` changed.
+3 -3
View File
@@ -8,8 +8,8 @@
//! `< 1 KiB` line on local fs and completes well below a millisecond. Going
//! through `tokio::fs` would force every caller — including `Engine`'s sync
//! `on_history_append` callback — to bridge sync → async via a channel +
//! drain task. Keeping the store sync lets the worker callback, Pod commit
//! paths, and `PodInterceptor` all share one direct `append_entry` call.
//! drain task. Keeping the store sync lets the worker callback, Worker commit
//! paths, and `WorkerInterceptor` all share one direct `append_entry` call.
use crate::event_trace::TraceEntry;
use crate::segment_log::LogEntry;
@@ -81,7 +81,7 @@ pub trait Store: Send + Sync {
/// Truncate a segment log to `entries_len` entries.
///
/// Used by Pod's submit-time empty-turn rollback after it has proven
/// Used by Worker's submit-time empty-turn rollback after it has proven
/// that no LLM output from the accepted turn was materialized. The
/// default implementation rewrites the retained prefix through
/// `create_segment`, matching the append-only logical model while still
+35 -32
View File
@@ -1,8 +1,8 @@
//! Typed system-message items injected by the agent system.
//!
//! Items in worker history with `role:system` are never produced by the
//! LLM — they are always inserted by the Pod itself (notifications,
//! file/knowledge/workflow ref resolutions, child-pod lifecycle events,
//! LLM — they are always inserted by the Worker itself (notifications,
//! file/knowledge/workflow ref resolutions, child-worker lifecycle events,
//! future `<system-reminder>` tags, …). [`SystemItem`] carries the
//! typed shape of each such injection so clients can dispatch on
//! `kind` instead of parsing text prefixes like `[Notification] …` or
@@ -19,7 +19,7 @@
//! system-message text.
use llm_engine::llm_client::types::Item;
use protocol::PodEvent;
use protocol::WorkerEvent;
use serde::{Deserialize, Serialize};
const SYSTEM_REMINDER_OPEN: &str = "<system-reminder>";
@@ -105,7 +105,7 @@ fn render_system_reminder(body: &str) -> String {
/// One agent-injected system item, tagged by origin.
///
/// Each variant carries the kind-specific raw data clients use for
/// typed rendering (`Notification.message`, `PodEvent.event`, file
/// typed rendering (`Notification.message`, `WorkerEvent.event`, file
/// path / knowledge slug / workflow slug / etc.), plus a pre-rendered
/// `body` (where applicable) that is the exact `role:system` text the
/// LLM actually saw at commit time. `body` is denormalised so that
@@ -122,15 +122,15 @@ fn render_system_reminder(body: &str) -> String {
pub enum SystemItem {
/// Free-form notification sent in by an external caller via
/// `Method::Notify`. `message` is the raw caller-supplied text;
/// `body` is the wrapped LLM-context form (Pod renders it via
/// `body` is the wrapped LLM-context form (Worker renders it via
/// `notify_wrapper` at commit time).
Notification { message: String, body: String },
/// Lifecycle event reported by a child Pod via `Method::PodEvent`.
/// Lifecycle event reported by a child Worker via `Method::WorkerEvent`.
/// `event` is the typed payload (so the TUI can render per-child
/// banners without re-parsing); `body` is the wrapped LLM-context
/// form (same `notify_wrapper` path as `Notification`).
PodEvent { event: PodEvent, body: String },
WorkerEvent { event: WorkerEvent, body: String },
/// `@<path>` file reference resolution. `body` is the rendered
/// LLM-context text (`[File: <path>]\n…` for regular files,
@@ -140,7 +140,7 @@ pub enum SystemItem {
FileAttachment { path: String, body: String },
/// `#<slug>` Knowledge reference resolution. `body` is the
/// rendered text the LLM saw (Pod composes the `[Knowledge: …]`
/// rendered text the LLM saw (Worker composes the `[Knowledge: …]`
/// header + body).
Knowledge { slug: String, body: String },
@@ -169,7 +169,7 @@ impl SystemItem {
pub fn history_text(&self) -> String {
match self {
SystemItem::Notification { body, .. } => body.clone(),
SystemItem::PodEvent { body, .. } => body.clone(),
SystemItem::WorkerEvent { body, .. } => body.clone(),
SystemItem::FileAttachment { body, .. } => body.clone(),
SystemItem::Knowledge { body, .. } => body.clone(),
SystemItem::Workflow { body, .. } => body.clone(),
@@ -189,7 +189,7 @@ impl SystemItem {
pub fn kind_label(&self) -> &'static str {
match self {
SystemItem::Notification { .. } => "notification",
SystemItem::PodEvent { .. } => "pod_event",
SystemItem::WorkerEvent { .. } => "worker_event",
SystemItem::FileAttachment { .. } => "file_attachment",
SystemItem::Knowledge { .. } => "knowledge",
SystemItem::Workflow { .. } => "workflow",
@@ -199,22 +199,25 @@ impl SystemItem {
}
}
/// Render a `PodEvent` as the one-line notification text the agent
/// Render a `WorkerEvent` as the one-line notification text the agent
/// sees. Centralised here (rather than at the controller's render
/// site) so persistence and broadcast share the same rendering.
pub fn render_pod_event(event: &PodEvent) -> String {
pub fn render_worker_event(event: &WorkerEvent) -> String {
match event {
PodEvent::TurnEnded { pod_name } => format!("pod `{pod_name}` finished a turn"),
PodEvent::Errored { pod_name, message } => {
format!("pod `{pod_name}` errored: {message}")
WorkerEvent::TurnEnded { worker_name } => format!("worker `{worker_name}` finished a turn"),
WorkerEvent::Errored {
worker_name,
message,
} => {
format!("worker `{worker_name}` errored: {message}")
}
PodEvent::ShutDown { pod_name } => format!("pod `{pod_name}` shut down"),
PodEvent::ScopeSubDelegated {
parent_pod,
sub_pod,
WorkerEvent::ShutDown { worker_name } => format!("worker `{worker_name}` shut down"),
WorkerEvent::ScopeSubDelegated {
parent_worker,
sub_worker,
..
} => {
format!("pod `{parent_pod}` sub-delegated scope to `{sub_pod}`")
format!("worker `{parent_worker}` sub-delegated scope to `{sub_worker}`")
}
}
}
@@ -236,10 +239,10 @@ mod tests {
}
#[test]
fn pod_event_history_text_returns_stored_body() {
let item = SystemItem::PodEvent {
event: PodEvent::TurnEnded {
pod_name: "child".into(),
fn worker_event_history_text_returns_stored_body() {
let item = SystemItem::WorkerEvent {
event: WorkerEvent::TurnEnded {
worker_name: "child".into(),
},
body: "[Notification]\npod `child` finished a turn\n\n(non-blocking hint…)".into(),
};
@@ -321,21 +324,21 @@ mod tests {
}
#[test]
fn round_trip_pod_event() {
let item = SystemItem::PodEvent {
event: PodEvent::TurnEnded {
pod_name: "child".into(),
fn round_trip_worker_event() {
let item = SystemItem::WorkerEvent {
event: WorkerEvent::TurnEnded {
worker_name: "child".into(),
},
body: "[Notification] pod `child` finished a turn".into(),
body: "[Notification] worker `child` finished a turn".into(),
};
let json = serde_json::to_string(&item).unwrap();
let parsed: SystemItem = serde_json::from_str(&json).unwrap();
match parsed {
SystemItem::PodEvent {
event: PodEvent::TurnEnded { pod_name },
SystemItem::WorkerEvent {
event: WorkerEvent::TurnEnded { worker_name },
body,
} => {
assert_eq!(pod_name, "child");
assert_eq!(worker_name, "child");
assert!(body.contains("`child`"));
}
other => panic!("unexpected: {other:?}"),
+2 -2
View File
@@ -103,7 +103,7 @@ async fn run_and_persist(
segment_id: session_store::SegmentId,
input: &str,
) -> (Engine<MockLlmClient>, llm_engine::EngineResult) {
// Mirror Pod's run-entry contract: log the user input as segments
// Mirror Worker's run-entry contract: log the user input as segments
// before the worker pushes its flattened user_message; save_delta
// skips the resulting user_message item to avoid double-write.
session_store::save_user_input(
@@ -450,7 +450,7 @@ async fn session_auto_forks_on_conflict() {
// Writer tracked: just the SegmentStart we wrote.
let mut entries_written: usize = 1;
// Simulate another Pod writing to the same segment behind our back.
// Simulate another Worker writing to the same segment behind our back.
let extra_entry = LogEntry::UserInput {
ts: 9999,
segments: vec![protocol::Segment::text("Interloper")],