refactor: rename llm worker crate to engine
This commit is contained in:
@@ -6,7 +6,7 @@ edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
llm-worker = { workspace = true }
|
||||
llm-engine = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
uuid = { workspace = true, features = ["v7", "serde"] }
|
||||
|
||||
@@ -10,7 +10,7 @@ Owns:
|
||||
|
||||
- session identifiers and segment lineage
|
||||
- JSONL log entries for replayable conversation/runtime history
|
||||
- restoring Worker/session state from committed records
|
||||
- restoring Engine/session state from committed records
|
||||
- schema surfaces that should make drift compile-visible
|
||||
|
||||
Does not own:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! Disabled by default. Enable via `SessionConfig::record_event_trace`.
|
||||
|
||||
use llm_worker::llm_client::event::Event;
|
||||
use llm_engine::llm_client::event::Event;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
//! belonging to the same logical conversation. Each Segment is recorded
|
||||
//! as a sequence of [`LogEntry`] values, one per line in a `.jsonl`
|
||||
//! file. Reading a segment log and collecting entries reconstructs the
|
||||
//! Worker state at that segment — no separate snapshots or checkpoints
|
||||
//! Engine state at that segment — no separate snapshots or checkpoints
|
||||
//! needed. Compaction and fork operations mint a fresh Segment within
|
||||
//! the same Session.
|
||||
//!
|
||||
//! This crate provides free functions for persistence operations.
|
||||
//! The caller (typically Pod) holds the Worker directly and calls these
|
||||
//! The caller (typically Pod) holds the Engine directly and calls these
|
||||
//! functions after state-mutating operations.
|
||||
//!
|
||||
//! Debug-mode [`TraceEntry`] records capture raw stream events in a separate
|
||||
@@ -40,8 +40,8 @@ pub mod system_item;
|
||||
|
||||
pub use event_trace::{TraceEntry, TracePayload};
|
||||
pub use fs_store::FsStore;
|
||||
pub use llm_worker::UsageRecord;
|
||||
pub use llm_worker::llm_client::types::{ContentPart, Item, Role};
|
||||
pub use llm_engine::UsageRecord;
|
||||
pub use llm_engine::llm_client::types::{ContentPart, Item, Role};
|
||||
pub use logged_item::{LoggedContentPart, LoggedItem, LoggedRole, from_logged, to_logged};
|
||||
pub use segment::{
|
||||
SegmentStartState, append_entry, append_system_item, classify_history_item,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Persistence-stable mirror of `llm_worker::Item`.
|
||||
//! Persistence-stable mirror of `llm_engine::Item`.
|
||||
//!
|
||||
//! `LogEntry` does not embed `Item` directly because that couples the on-disk
|
||||
//! schema to the LLM worker's internal type — a field rename or addition there
|
||||
@@ -12,7 +12,7 @@
|
||||
//! `Reasoning::encrypted_content` is preserved because OpenAI Responses ZDR
|
||||
//! requires it on stateless re-send.
|
||||
|
||||
use llm_worker::llm_client::types::{ContentPart, Item, Role};
|
||||
use llm_engine::llm_client::types::{ContentPart, Item, Role};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn is_false(value: &bool) -> bool {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Free functions for segment persistence operations.
|
||||
//!
|
||||
//! These functions record and restore segment state without owning a Worker.
|
||||
//! The caller (typically Pod) holds the Worker directly and calls these
|
||||
//! These functions record and restore segment state without owning a Engine.
|
||||
//! The caller (typically Pod) holds the Engine directly and calls these
|
||||
//! functions after state-mutating operations.
|
||||
|
||||
use crate::logged_item::{LoggedItem, to_logged};
|
||||
@@ -9,9 +9,9 @@ use crate::segment_log::{self, LogEntry, SegmentOrigin};
|
||||
use crate::store::{Store, StoreError};
|
||||
use crate::system_item::SystemItem;
|
||||
use crate::{SegmentId, SessionId};
|
||||
use llm_worker::WorkerResult;
|
||||
use llm_worker::llm_client::RequestConfig;
|
||||
use llm_worker::llm_client::types::Item;
|
||||
use llm_engine::EngineResult;
|
||||
use llm_engine::llm_client::RequestConfig;
|
||||
use llm_engine::llm_client::types::Item;
|
||||
use protocol::Segment;
|
||||
|
||||
/// State snapshot for creating a SegmentStart entry.
|
||||
@@ -89,7 +89,7 @@ pub fn create_compacted_segment(
|
||||
/// Restore segment state from a stored log.
|
||||
///
|
||||
/// Returns the reconstructed state. The caller is responsible for
|
||||
/// applying it to a Worker.
|
||||
/// applying it to a Engine.
|
||||
pub fn restore(
|
||||
store: &impl Store,
|
||||
session_id: SessionId,
|
||||
@@ -287,12 +287,12 @@ pub fn save_turn_end(
|
||||
)
|
||||
}
|
||||
|
||||
/// Log a `RunCompleted` entry — `run()` / `resume()` returned `Ok(WorkerResult)`.
|
||||
/// Log a `RunCompleted` entry — `run()` / `resume()` returned `Ok(EngineResult)`.
|
||||
pub fn save_run_completed(
|
||||
store: &impl Store,
|
||||
session_id: SessionId,
|
||||
segment_id: SegmentId,
|
||||
result: WorkerResult,
|
||||
result: EngineResult,
|
||||
interrupted: bool,
|
||||
) -> Result<(), StoreError> {
|
||||
append_entry(
|
||||
@@ -307,9 +307,9 @@ pub fn save_run_completed(
|
||||
)
|
||||
}
|
||||
|
||||
/// Log a `RunErrored` entry — `run()` / `resume()` returned `Err(WorkerError)`.
|
||||
/// Log a `RunErrored` entry — `run()` / `resume()` returned `Err(EngineError)`.
|
||||
///
|
||||
/// `WorkerError` is not `Serialize`, so the caller passes a lossy
|
||||
/// `EngineError` is not `Serialize`, so the caller passes a lossy
|
||||
/// `to_string()` rendering as `message`.
|
||||
pub fn save_run_errored(
|
||||
store: &impl Store,
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
//! Each [`LogEntry`] represents a single state transition within one
|
||||
//! segment, serialized as one line in a `.jsonl` file. Reading all
|
||||
//! entries and collecting them via [`collect_state`] reconstructs the
|
||||
//! full [`Worker`] state at that segment.
|
||||
//! full [`Engine`] state at that segment.
|
||||
//!
|
||||
//! The on-disk format is one `LogEntry` per line — entries are positionally
|
||||
//! ordered. Fork lineage references between segments use turn-number indices
|
||||
//! (`SegmentOrigin.at_turn_index`) rather than per-entry hashes.
|
||||
|
||||
use llm_worker::llm_client::types::{Item, RequestConfig};
|
||||
use llm_worker::{UsageRecord, WorkerResult};
|
||||
use llm_engine::llm_client::types::{Item, RequestConfig};
|
||||
use llm_engine::{EngineResult, UsageRecord};
|
||||
use protocol::{InvokeKind, Segment};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -19,7 +19,7 @@ use crate::system_item::SystemItem;
|
||||
|
||||
/// A single segment log entry, serialized as one JSONL line.
|
||||
///
|
||||
/// Variants correspond to specific mutation points in `Worker`:
|
||||
/// Variants correspond to specific mutation points in `Engine`:
|
||||
/// - `SegmentStart` — always the first entry; captures initial state
|
||||
/// - `Invoke` — IDLE → active marker (start of a new self-driving cycle)
|
||||
/// - `UserInput` / `AssistantItem` / `ToolResult` / `SystemItem` — history appends
|
||||
@@ -98,16 +98,16 @@ pub enum LogEntry {
|
||||
/// Turn boundary. Records the turn count after increment.
|
||||
TurnEnd { ts: u64, turn_count: usize },
|
||||
|
||||
/// `run()` / `resume()` が `WorkerResult` で正常終了した。
|
||||
/// `run()` / `resume()` が `EngineResult` で正常終了した。
|
||||
/// Audit-only metadata: replay は `interrupted` のみ反映する。
|
||||
RunCompleted {
|
||||
ts: u64,
|
||||
interrupted: bool,
|
||||
result: WorkerResult,
|
||||
result: EngineResult,
|
||||
},
|
||||
|
||||
/// `run()` / `resume()` が `WorkerError` で終了した。
|
||||
/// `WorkerError` は `Serialize` 不可なので `message` のみ lossy 保持する。
|
||||
/// `run()` / `resume()` が `EngineError` で終了した。
|
||||
/// `EngineError` は `Serialize` 不可なので `message` のみ lossy 保持する。
|
||||
/// Audit-only metadata: replay は `interrupted` のみ反映する。
|
||||
RunErrored {
|
||||
ts: u64,
|
||||
@@ -360,7 +360,7 @@ mod tests {
|
||||
LogEntry::RunCompleted {
|
||||
ts: 3200,
|
||||
interrupted: false,
|
||||
result: WorkerResult::Finished,
|
||||
result: EngineResult::Finished,
|
||||
},
|
||||
]);
|
||||
assert_eq!(state.history.len(), 2);
|
||||
@@ -593,7 +593,7 @@ mod tests {
|
||||
LogEntry::RunCompleted {
|
||||
ts: 100,
|
||||
interrupted: true,
|
||||
result: WorkerResult::Paused,
|
||||
result: EngineResult::Paused,
|
||||
},
|
||||
LogEntry::PausedTurnAbandoned { ts: 200 },
|
||||
]);
|
||||
@@ -711,14 +711,14 @@ mod tests {
|
||||
},
|
||||
parsed,
|
||||
]);
|
||||
// Worker history gets a flattened user_message item.
|
||||
// Engine history gets a flattened user_message item.
|
||||
assert_eq!(state.history.len(), 1);
|
||||
match &state.history[0] {
|
||||
Item::Message { role, content, .. } => {
|
||||
assert!(matches!(role, llm_worker::Role::User));
|
||||
assert!(matches!(role, llm_engine::Role::User));
|
||||
assert_eq!(content.len(), 1);
|
||||
match &content[0] {
|
||||
llm_worker::ContentPart::Text { text } => {
|
||||
llm_engine::ContentPart::Text { text } => {
|
||||
assert_eq!(text, "see line1\nline2@src/main.rs");
|
||||
}
|
||||
other => panic!("unexpected content: {other:?}"),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//!
|
||||
//! Sync (rather than async) is intentional: a segment log append is a single
|
||||
//! `< 1 KiB` line on local fs and completes well below a millisecond. Going
|
||||
//! through `tokio::fs` would force every caller — including `Worker`'s sync
|
||||
//! 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.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//! preserved only on the log/wire side; the LLM still sees plain
|
||||
//! system-message text.
|
||||
|
||||
use llm_worker::llm_client::types::Item;
|
||||
use llm_engine::llm_client::types::Item;
|
||||
use protocol::PodEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use llm_worker::llm_client::event::Event;
|
||||
use llm_worker::llm_client::{ClientError, LlmClient, Request};
|
||||
use llm_engine::llm_client::event::Event;
|
||||
use llm_engine::llm_client::{ClientError, LlmClient, Request};
|
||||
|
||||
/// A mock LLM client that replays pre-defined event sequences.
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use llm_worker::WorkerResult;
|
||||
use llm_worker::llm_client::types::{Item, RequestConfig};
|
||||
use llm_engine::EngineResult;
|
||||
use llm_engine::llm_client::types::{Item, RequestConfig};
|
||||
use session_store::{
|
||||
FsStore, LogEntry, Store, TraceEntry, collect_state, new_segment_id, new_session_id,
|
||||
};
|
||||
@@ -48,7 +48,7 @@ fn round_trip_write_and_read() {
|
||||
LogEntry::RunCompleted {
|
||||
ts: 3200,
|
||||
interrupted: false,
|
||||
result: WorkerResult::Finished,
|
||||
result: EngineResult::Finished,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -175,8 +175,8 @@ fn trace_entries_in_separate_file() {
|
||||
turn: 0,
|
||||
llm_call: Some(0),
|
||||
payload: session_store::TracePayload::StreamEvent {
|
||||
event: llm_worker::llm_client::event::Event::Ping(
|
||||
llm_worker::llm_client::event::PingEvent { timestamp: None },
|
||||
event: llm_engine::llm_client::event::Event::Ping(
|
||||
llm_engine::llm_client::event::PingEvent { timestamp: None },
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,11 +4,11 @@ use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use common::MockLlmClient;
|
||||
use llm_worker::Worker;
|
||||
use llm_worker::interceptor::{Interceptor, TurnEndAction};
|
||||
use llm_worker::llm_client::event::{Event, ResponseStatus, StatusEvent};
|
||||
use llm_worker::llm_client::types::{Item, RequestConfig};
|
||||
use llm_worker::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
|
||||
use llm_engine::Engine;
|
||||
use llm_engine::interceptor::{Interceptor, TurnEndAction};
|
||||
use llm_engine::llm_client::event::{Event, ResponseStatus, StatusEvent};
|
||||
use llm_engine::llm_client::types::{Item, RequestConfig};
|
||||
use llm_engine::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
|
||||
use session_store::{FsStore, LogEntry, SegmentStartState, Store, collect_state};
|
||||
|
||||
// =============================================================================
|
||||
@@ -57,7 +57,7 @@ impl Tool for MockWeatherTool {
|
||||
async fn execute(
|
||||
&self,
|
||||
_input_json: &str,
|
||||
_ctx: llm_worker::tool::ToolExecutionContext,
|
||||
_ctx: llm_engine::tool::ToolExecutionContext,
|
||||
) -> Result<ToolOutput, ToolError> {
|
||||
Ok("Sunny, 25C".to_string().into())
|
||||
}
|
||||
@@ -97,12 +97,12 @@ fn make_store() -> (tempfile::TempDir, FsStore) {
|
||||
/// Run a worker turn and persist via session-store functions.
|
||||
/// Takes ownership of the worker (needed for lock/unlock) and returns it.
|
||||
async fn run_and_persist(
|
||||
worker: Worker<MockLlmClient>,
|
||||
worker: Engine<MockLlmClient>,
|
||||
store: &FsStore,
|
||||
session_id: session_store::SessionId,
|
||||
segment_id: session_store::SegmentId,
|
||||
input: &str,
|
||||
) -> (Worker<MockLlmClient>, llm_worker::WorkerResult) {
|
||||
) -> (Engine<MockLlmClient>, llm_engine::EngineResult) {
|
||||
// Mirror Pod'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.
|
||||
@@ -159,7 +159,7 @@ async fn run_and_persist(
|
||||
async fn session_run_logs_entries() {
|
||||
let (_dir, store) = make_store();
|
||||
let client = MockLlmClient::new(simple_text_events());
|
||||
let worker = Worker::new(client);
|
||||
let worker = Engine::new(client);
|
||||
|
||||
let (sid, segid) = session_store::create_segment(
|
||||
&store,
|
||||
@@ -191,7 +191,7 @@ async fn session_run_logs_entries() {
|
||||
matches!(
|
||||
e,
|
||||
LogEntry::RunCompleted {
|
||||
result: llm_worker::WorkerResult::Finished,
|
||||
result: llm_engine::EngineResult::Finished,
|
||||
..
|
||||
}
|
||||
)
|
||||
@@ -203,7 +203,7 @@ async fn session_run_logs_entries() {
|
||||
async fn session_restore_round_trip() {
|
||||
let (_dir, store) = make_store();
|
||||
let client = MockLlmClient::new(simple_text_events());
|
||||
let mut worker = Worker::new(client);
|
||||
let mut worker = Engine::new(client);
|
||||
worker.set_system_prompt("You are helpful.");
|
||||
|
||||
let (sid, segid) = session_store::create_segment(
|
||||
@@ -242,7 +242,7 @@ async fn session_restore_round_trip() {
|
||||
async fn session_run_with_tool_call() {
|
||||
let (_dir, store) = make_store();
|
||||
let client = MockLlmClient::with_responses(tool_call_events());
|
||||
let mut worker = Worker::new(client);
|
||||
let mut worker = Engine::new(client);
|
||||
worker.register_tool(weather_tool_definition());
|
||||
|
||||
let (sid, segid) = session_store::create_segment(
|
||||
@@ -276,7 +276,7 @@ async fn session_resume_after_pause() {
|
||||
|
||||
// First run: tool call with pause policy → Paused
|
||||
let client = MockLlmClient::with_responses(tool_call_events());
|
||||
let mut worker = Worker::new(client);
|
||||
let mut worker = Engine::new(client);
|
||||
worker.register_tool(weather_tool_definition());
|
||||
worker.set_interceptor(PausePolicy);
|
||||
|
||||
@@ -291,7 +291,7 @@ async fn session_resume_after_pause() {
|
||||
.unwrap();
|
||||
|
||||
let (_worker, result) = run_and_persist(worker, &store, sid, segid, "Weather?").await;
|
||||
assert!(matches!(result, llm_worker::WorkerResult::Paused));
|
||||
assert!(matches!(result, llm_engine::EngineResult::Paused));
|
||||
|
||||
// Check RunCompleted is Paused
|
||||
let entries = store.read_all(sid, segid).unwrap();
|
||||
@@ -299,7 +299,7 @@ async fn session_resume_after_pause() {
|
||||
matches!(
|
||||
e,
|
||||
LogEntry::RunCompleted {
|
||||
result: llm_worker::WorkerResult::Paused,
|
||||
result: llm_engine::EngineResult::Paused,
|
||||
..
|
||||
}
|
||||
)
|
||||
@@ -315,7 +315,7 @@ async fn session_resume_after_pause() {
|
||||
async fn session_fork_creates_new_session() {
|
||||
let (_dir, store) = make_store();
|
||||
let client = MockLlmClient::new(simple_text_events());
|
||||
let mut worker = Worker::new(client);
|
||||
let mut worker = Engine::new(client);
|
||||
worker.set_system_prompt("System prompt");
|
||||
|
||||
let (sid, segid) = session_store::create_segment(
|
||||
@@ -357,7 +357,7 @@ async fn session_fork_creates_new_session() {
|
||||
async fn session_fork_at_truncates_within_session() {
|
||||
let (_dir, store) = make_store();
|
||||
let client = MockLlmClient::new(simple_text_events());
|
||||
let worker = Worker::new(client);
|
||||
let worker = Engine::new(client);
|
||||
|
||||
let (sid, segid) = session_store::create_segment(
|
||||
&store,
|
||||
@@ -402,7 +402,7 @@ async fn session_fork_at_truncates_within_session() {
|
||||
async fn session_config_changed_logged() {
|
||||
let (_dir, store) = make_store();
|
||||
let client = MockLlmClient::new(vec![]);
|
||||
let mut worker = Worker::new(client);
|
||||
let mut worker = Engine::new(client);
|
||||
|
||||
let (sid, segid) = session_store::create_segment(
|
||||
&store,
|
||||
@@ -435,7 +435,7 @@ async fn session_auto_forks_on_conflict() {
|
||||
|
||||
// Create a segment
|
||||
let client_a = MockLlmClient::new(simple_text_events());
|
||||
let worker_a = Worker::new(client_a);
|
||||
let worker_a = Engine::new(client_a);
|
||||
|
||||
let (sid, original_segid) = session_store::create_segment(
|
||||
&store,
|
||||
@@ -519,7 +519,7 @@ async fn session_auto_forks_on_conflict() {
|
||||
async fn nested_past_fork_leaves_ancestors_immutable() {
|
||||
let (_dir, store) = make_store();
|
||||
let client = MockLlmClient::new(simple_text_events());
|
||||
let worker = Worker::new(client);
|
||||
let worker = Engine::new(client);
|
||||
|
||||
let (sid, root_segid) = session_store::create_segment(
|
||||
&store,
|
||||
|
||||
Reference in New Issue
Block a user