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:
@@ -86,12 +86,7 @@ pub(crate) async fn run(
|
||||
// ToolCtx extensions: host extensions + the event sink + the turn's tool
|
||||
// set, so shipped tools (ask_user, activate_tools, delegate) reach what
|
||||
// they need.
|
||||
let tool_extensions = || {
|
||||
let mut ext = params.extensions.clone();
|
||||
ext.insert(Arc::new(events.clone()));
|
||||
ext.insert(Arc::new(crate::tool::SharedToolSet(params.tools.clone())));
|
||||
ext
|
||||
};
|
||||
let tool_extensions = || tool_extensions(¶ms, &events);
|
||||
|
||||
events.emit(frame, parent, LoopEvent::TurnStarted);
|
||||
|
||||
@@ -289,6 +284,20 @@ pub(crate) async fn run(
|
||||
finish(TurnOutcome::Exhausted, &deps, &hook_ctx(), &events, frame, parent).await
|
||||
}
|
||||
|
||||
/// What a tool call sees: the host's extensions plus the event sink and the
|
||||
/// turn's tool set (shipped tools — ask_user, activate_tools, delegate — reach
|
||||
/// what they need through them). Shared with [`crate::recovery`], which
|
||||
/// re-executes a call outside a round and must hand it the same context.
|
||||
pub(crate) fn tool_extensions(
|
||||
params: &LoopParams,
|
||||
events: &EventSink,
|
||||
) -> crate::tool::Extensions {
|
||||
let mut ext = params.extensions.clone();
|
||||
ext.insert(Arc::new(events.clone()));
|
||||
ext.insert(Arc::new(crate::tool::SharedToolSet(params.tools.clone())));
|
||||
ext
|
||||
}
|
||||
|
||||
/// Terminal helper: hooks.on_turn_end (+ Cancelled event) then return.
|
||||
async fn finish(
|
||||
outcome: TurnOutcome,
|
||||
@@ -510,7 +519,7 @@ async fn record_call(
|
||||
})
|
||||
}
|
||||
|
||||
enum PreExecution {
|
||||
pub(crate) enum PreExecution {
|
||||
Run(Arc<dyn crate::tool::Tool>),
|
||||
Resolved(CallOutcome),
|
||||
TurnCancelled,
|
||||
@@ -519,8 +528,9 @@ enum PreExecution {
|
||||
Suspended,
|
||||
}
|
||||
|
||||
/// Gate + hooks.pre + tool lookup — shared by sequential and fan-out paths.
|
||||
async fn pre_execution(
|
||||
/// Gate + hooks.pre + tool lookup — shared by the sequential path, the
|
||||
/// fan-out and [`crate::recovery`]'s re-execution of an interrupted call.
|
||||
pub(crate) async fn pre_execution(
|
||||
deps: &Arc<KernelDeps>,
|
||||
params: &LoopParams,
|
||||
events: &EventSink,
|
||||
@@ -572,8 +582,8 @@ async fn pre_execution(
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase-3 shared by both paths: hooks.post → resolve → emit.
|
||||
async fn record_outcome(
|
||||
/// Phase-3 shared by both paths (and by recovery): hooks.post → resolve → emit.
|
||||
pub(crate) async fn record_outcome(
|
||||
deps: &Arc<KernelDeps>,
|
||||
params: &LoopParams,
|
||||
events: &EventSink,
|
||||
|
||||
Reference in New Issue
Block a user