Keep a record of each run's tool calls so bots can't claim work they never did

The wrap-up turn now gets the run's actual tool calls, each bot message
keeps them as bot_messages.tool_log, and history follows recorded bot
messages with an [App record] line. The coordinator also gets update_bot
in workspaces, so it can fill a bot's core prompt from there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-25 11:32:56 +01:00
co-authored by Claude Opus 5.5
parent 93896646c7
commit d7f88d8dd3
22 changed files with 293 additions and 19 deletions
+7 -3
View File
@@ -89,8 +89,9 @@ type Params = {
* computers, and which name, role and core instructions each crew member
* gets, and what goes) and the install's skills, MCP servers and custom
* tools (`grabCoordinatorExtensionTools`) or, in a workspace,
* set_bot_workspace_instructions, plus set_bot_type to make a worker a
* workspace's admin. A workspace admin, in the workspace it leads, gets
* set_bot_workspace_instructions and update_bot for the workspace's crew
* (a bot's core prompt is asked for from wherever the user is), plus
* set_bot_type to make a worker a workspace's admin. A workspace admin, in the workspace it leads, gets
* `grabWorkspaceAdminTools`. Every gate reads the bot's types (`powers`),
* never `bots.kind`. Anything else on a computer goes through a task,
* never mid-reply.
@@ -182,7 +183,10 @@ export default async function grabBotChatTools({
requester_name: bot.name || "The coordinator",
workers,
}));
tools.push(setWorkspaceInstructionsTool({ user_id, workspace_id, workers }));
tools.push(
setWorkspaceInstructionsTool({ user_id, workspace_id, workers }),
updateBotTool({ user_id, workers }),
);
if (powers.can("set_bot_types")) {
tools.push(setBotTypeTool({ user_id, bot_id, workers, workspaces, workspace_id }));