fix: one tool-set recipe per session, so a tool cannot vanish between rounds
Nightly Build / build (push) Successful in 7m36s

Two "unknown tool (not in this turn's tool set)" failures, one disease: the
turn's tool set was rebuilt from a different recipe depending on which entry
point happened to drive it.

A sub-agent got `ask_user_clarification`, `execute_subtask` and `activate_tools`
and nothing else — while `agents/common/tools.md` and every reporting agent's
prompt tell it to register its output with `update_scratchpad`. The child could
see the scratchpad injected into its context but had no way to write to it. It
now gets the scratchpad and todos tools, on the parent's `scratchpad_sid`: one
blackboard per session, as the surrounding code already declared.

`show_file_to_user` was injected per message by the WS handler, while
`resume_session` and `resolve_pending_call` rebuilt the list with `execute_task`
alone. So approving a card, or reconnecting mid-turn, continued the *same*
conversation with the tool silently gone. There is now a single recipe,
`ChatHub::session_interface_tools`, used by all three paths and fed by a builder
the shell installs once through `Skald::set_interface_tools_builder`: the core
keeps owning the tool, the shell keeps owning the policy of who gets it —
Telegram still does not, since it cannot act on OpenFile.
This commit is contained in:
2026-08-04 15:03:46 +01:00
parent ff298f1aef
commit f900d803f2
8 changed files with 163 additions and 36 deletions
+5 -12
View File
@@ -404,18 +404,11 @@ async fn handle_socket(mut socket: WebSocket, skald: Arc<Skald>, source: String,
// set_selected_client, which broadcasts ClientSelected.
client_name: chat_hub.get_selected_client(&source).await,
extra_system_context: Some(WEB_FORMAT_CONTEXT.to_string()),
// SPA-only tool: lets the assistant open a file in the user's
// viewer. Injected here (not in the registry) so it exists only
// for ws.rs clients (web + mobile), never for the Telegram plugin.
interface_tools: vec![
skald_core::tools::show_file::make_tool(
Arc::clone(&chat_hub),
source.clone(),
ctx.fs.clone(),
ctx.pool.as_ref().clone(),
skald.db().as_ref().clone(),
),
],
// `show_file_to_user` used to be injected right here, per
// message — which is why it disappeared from a conversation
// the moment an approval or a reconnect resumed the turn
// through another path. It is now declared once, for every
// path, by `WebFrontend::interface_tools_builder`.
..Default::default()
};
// send_message only enqueues — the turn runs on ChatHub's per-source