agent-loop: projection, recovery, compaction into the crate (phase 3)
Nightly Build / build (push) Successful in 6m49s
Nightly Build / build (push) Successful in 6m49s
The session handler is now a thin shell: three entry points in kernel_turn.rs (run_kernel_turn / recover_turn / resolve_pending_call) and the ChatSessionHandler. Everything that shaped a Value — projection, recovery, compaction mechanics, the LLM loop, message building — lives in agent-loop or behind a loop_adapters trait. agent-loop: - projection/ (mod + media): stored history -> wire messages, the one place provider divergence lives; well-formedness contract, DTL injections (append-only), media parts. LinearAssembler is now a Projection + ProjectionHooks config, not its own implementation - recovery.rs: reap interrupted batches -> resolve the deepest frame's non-terminal calls (Running by policy + RestartHint, AwaitingHuman re-asked) -> un-wedge finished children -> cascade up, every frame on its own agent (B3) - compaction.rs: split point (never assistant+tool group), transcript, SUMMARY_PREFIX/preamble/template, the no-tools model call, summary row - manager: resolve_pending (gate skipped, real ToolContext, then continue incl. sub-agent); start_loop used by recovery; LiveInput - delegate: AsyncExecutor + StoreSink for mode:async (durable cron row, result delivered back into the parent conversation) - kernel/context/store: support the above (TurnScope via Extensions, frame lookups, aligned result-text semantics) skald-core: - loop_adapters: UserLoopRuntime (D12 - one LoopManager per user), TurnScope (per-turn state in the Extensions type-map; no scope is denied), projection_cfg/media_source/tool_digest (Skald's projection knobs without owning projection code), async_task (CronExecutor + DurableSink) - session/handler: stripped to mod.rs + kernel_turn.rs + config.rs + interface_tools.rs + media.rs; deleted agent_dispatch, approval, dispatch, emitter, gate, llm_call, llm_loop, message_builder, messages, outcome, resume - compactor.rs: policy only (threshold, model pick, CompactionEvent); mechanics are the crate's CLAUDE.md updated (recovery, compaction, sub-agents, approval gate, projection sections now describe the crate-owned flow).
This commit is contained in:
@@ -221,6 +221,11 @@ pub struct StoredCall {
|
||||
pub provider_id: String,
|
||||
pub name: String,
|
||||
pub arguments: Value,
|
||||
/// The arguments **exactly as the model emitted them**, when the store kept
|
||||
/// the string. The projection replays this verbatim: re-serializing
|
||||
/// [`Self::arguments`] reorders object keys, which changes the bytes the
|
||||
/// model produced and breaks the prompt-cache prefix.
|
||||
pub arguments_raw: Option<String>,
|
||||
pub state: CallState,
|
||||
pub result: Option<String>,
|
||||
pub result_kind: String,
|
||||
@@ -280,6 +285,10 @@ pub trait HistoryStore: Send + Sync {
|
||||
async fn set_call_state(&self, id: ToolCallId, state: CallState) -> crate::Result<()>;
|
||||
/// One call by id (translators enriching finish events, recovery).
|
||||
async fn get_call(&self, id: ToolCallId) -> crate::Result<Option<StoredCall>>;
|
||||
/// The frame a call belongs to. Recovery walks the cascade with it, and an
|
||||
/// out-of-band resolution (an approval answered from a REST endpoint) has
|
||||
/// nothing but a call id to start from.
|
||||
async fn frame_of_call(&self, id: ToolCallId) -> crate::Result<Option<FrameRecord>>;
|
||||
/// Merge host free-form extras into a call (Skald: diff preview, media).
|
||||
/// Keys not understood by the store are ignored.
|
||||
async fn set_call_extras(&self, id: ToolCallId, extras: Value) -> crate::Result<()>;
|
||||
|
||||
Reference in New Issue
Block a user