From 815eed2574115ecb0f575bbb289fe1d98d90a73d Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 18 Feb 2026 20:43:47 -0500 Subject: [PATCH] Add tool confirmation UI with Accept/Decline for write operations Before executing any write tool (create/update/delete), the backend now pauses with an asyncio.Future and emits a tool_pending SSE event. The frontend displays a ToolConfirmCard with Accept and Decline buttons. Clicking Accept resolves the Future and proceeds; Decline records a declined tool_call chip and falls through to regular streaming. Typing single-word yes/no responses (e.g. "yes", "cancel") also works as confirmation. 120s timeout auto-declines if no response. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/ToolCallCard.vue | 15 +- frontend/src/components/ToolConfirmCard.vue | 108 +++++++++++++ frontend/src/stores/chat.ts | 40 +++++ frontend/src/types/chat.ts | 8 +- frontend/src/views/ChatView.vue | 7 + src/fabledassistant/routes/chat.py | 22 +++ .../services/generation_buffer.py | 3 + .../services/generation_task.py | 144 +++++++++++++----- 8 files changed, 304 insertions(+), 43 deletions(-) create mode 100644 frontend/src/components/ToolConfirmCard.vue diff --git a/frontend/src/components/ToolCallCard.vue b/frontend/src/components/ToolCallCard.vue index cccf571..742ae5e 100644 --- a/frontend/src/components/ToolCallCard.vue +++ b/frontend/src/components/ToolCallCard.vue @@ -11,6 +11,7 @@ const appliedTags = ref>(new Set()); const applyingTag = ref(null); const label = computed(() => { + if (props.toolCall.status === "declined") return "Declined"; if (!props.toolCall.result.success) return "Error"; switch (props.toolCall.result.type) { case "task": @@ -180,9 +181,12 @@ async function applyTag(tag: string) {