diff --git a/frontend/src/lib/components/copilot/chat/AIChatDisplay.svelte b/frontend/src/lib/components/copilot/chat/AIChatDisplay.svelte index 9a7afb766e..7bfb8b27c6 100644 --- a/frontend/src/lib/components/copilot/chat/AIChatDisplay.svelte +++ b/frontend/src/lib/components/copilot/chat/AIChatDisplay.svelte @@ -562,7 +562,7 @@ const yoloBypassedTools = $derived.by(() => { return aiChatManager.tools - .filter((tool) => tool.requiresConfirmation === true) + .filter((tool) => tool.requiresConfirmation === true || tool.bypassedByAutoAccept === true) .map((tool) => ({ name: tool.def.function.name, // confirmationMessage may be a function of the call args, which we don't diff --git a/frontend/src/lib/components/copilot/chat/global/core.ts b/frontend/src/lib/components/copilot/chat/global/core.ts index f50dad77bd..076ffe1a0a 100644 --- a/frontend/src/lib/components/copilot/chat/global/core.ts +++ b/frontend/src/lib/components/copilot/chat/global/core.ts @@ -3667,6 +3667,9 @@ export const globalTools: Tool<{}>[] = [ }, // No requiresConfirmation: like run_script, the argument form is the confirmation — // but this one is auto-acceptable, so YOLO answers it and the model keeps iterating. + // Which is a decision made for the user, so the posture's own list has to name it. + bypassedByAutoAccept: true, + confirmationMessage: 'Run a test of a script', streamingLabel: 'Preparing the test form...', queuedLabel: (args) => `Test ${args?.path ?? 'the script'}`, showDetails: true, diff --git a/frontend/src/lib/components/copilot/chat/shared.ts b/frontend/src/lib/components/copilot/chat/shared.ts index 1d0d97e885..3e12789119 100644 --- a/frontend/src/lib/components/copilot/chat/shared.ts +++ b/frontend/src/lib/components/copilot/chat/shared.ts @@ -1147,6 +1147,10 @@ export interface Tool { * is true. */ refuseInPlanMode?: (p: { args: any; helpers: T }) => ToolRejection | undefined requiresConfirmation?: boolean + /** The tool's own argument form is its confirmation, and the bypass posture answers that + * form — so no card is waited on, yet a decision is still being made for the user. The + * list of what the posture bypasses is built from both this and `requiresConfirmation`. */ + bypassedByAutoAccept?: boolean /** Header shown on the confirmation card before the tool runs. Pass a function * to derive it from the parsed arguments (e.g. name the script being tested). */ confirmationMessage?: string | ((args: any) => string)