refactor: rename pod crate to worker
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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).
|
||||
///
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:?}"),
|
||||
|
||||
@@ -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")],
|
||||
|
||||
Reference in New Issue
Block a user