From 1bc9d1a274737cb1c83315c24698a63ef9b3a997 Mon Sep 17 00:00:00 2001 From: likiosliu Date: Fri, 13 Mar 2026 20:37:45 +0800 Subject: [PATCH 1/2] feat: add TUI feedback prompt after deep investigation completes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show "Thanks! Rate: 1-👍 2-👎 3-❌" in the status bar after deep_search runs and investigation concludes. Keyboard input records feedback (confirmed/corrected/rejected) to the memory DB via the existing updateInvestigationFeedback API. Auto-cleans up after 60s timeout or when a new message is sent. --- src/core/agent-factory.ts | 2 +- src/core/extensions/deep-investigation.ts | 59 ++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/core/agent-factory.ts b/src/core/agent-factory.ts index eb904d3..d6ea348 100644 --- a/src/core/agent-factory.ts +++ b/src/core/agent-factory.ts @@ -457,7 +457,7 @@ export async function createSiclawSession( } return parts; }, - extensionFactories: [contextPruningExtension, (api) => memoryFlushExtension(api, memoryIndexerRef.current), deepInvestigationExtension, (api) => setupExtension(api, credentialsDir)], + extensionFactories: [contextPruningExtension, (api) => memoryFlushExtension(api, memoryIndexerRef.current), (api) => deepInvestigationExtension(api, memoryRef), (api) => setupExtension(api, credentialsDir)], additionalSkillPaths: skillsDirs, }); await loader.reload(); diff --git a/src/core/extensions/deep-investigation.ts b/src/core/extensions/deep-investigation.ts index ad27d14..598457b 100644 --- a/src/core/extensions/deep-investigation.ts +++ b/src/core/extensions/deep-investigation.ts @@ -8,6 +8,8 @@ import { createChecklist, buildActivationMessage, } from "../../tools/dp-tools.js"; +import type { MemoryRef } from "../../tools/deep-search/tool.js"; +import { FEEDBACK_SIGNALS, type FeedbackStatus } from "../../memory/types.js"; /** @@ -156,10 +158,13 @@ function formatHypothesesWidget(text: string, theme: any): string[] { // --- Extension --- -export default function deepInvestigationExtension(api: ExtensionAPI): void { +export default function deepInvestigationExtension(api: ExtensionAPI, memoryRef?: MemoryRef): void { // --- Mode state --- let checklist: DpChecklist | null = null; let pendingActivation = false; + let pendingFeedbackId: string | null = null; + let deepSearchRan = false; + let feedbackCleanup: (() => void) | null = null; // --- Progress rendering state --- let activeUI: ExtensionUIContext | null = null; @@ -209,13 +214,53 @@ export default function deepInvestigationExtension(api: ExtensionAPI): void { pendingActivation = true; } + /** Show feedback hint in status bar if deep_search ran. Can be called independently of DP mode exit. */ + function showFeedbackIfNeeded(ctx: ExtensionContext): void { + if (!deepSearchRan || !ctx.hasUI) { + deepSearchRan = false; + pendingFeedbackId = null; + return; + } + deepSearchRan = false; + const id = pendingFeedbackId; + pendingFeedbackId = null; + + const cleanup = () => { + ctx.ui.setStatus("dp-mode", undefined); + unsubInput(); + clearTimeout(timer); + feedbackCleanup = null; + }; + + const timer = setTimeout(cleanup, 60_000); + + const unsubInput = ctx.ui.onTerminalInput((data: string) => { + if (ctx.ui.getEditorText().length > 0) return undefined; + const keyMap: Record = { "1": "confirmed", "2": "corrected", "3": "rejected" }; + const status = keyMap[data]; + if (!status) return undefined; + + if (id && memoryRef?.indexer) { + memoryRef.indexer.updateInvestigationFeedback(id, FEEDBACK_SIGNALS[status], status); + } + ctx.ui.notify(`Feedback recorded: ${status}`); + cleanup(); + return { consume: true }; + }); + + feedbackCleanup = cleanup; + const hint = "Thanks! Rate: 1-\uD83D\uDC4D 2-\uD83D\uDC4E 3-\u274C"; + ctx.ui.setStatus("dp-mode", isThemeUsable(ctx) ? ctx.ui.theme.fg("muted", hint) : hint); + } + function disableDpMode(ctx: ExtensionContext): void { if (!checklist) return; checklist = null; - updateStatus(ctx); persistState(); if (ctx.hasUI) ctx.ui.notify("Deep Investigation OFF"); pendingActivation = false; + showFeedbackIfNeeded(ctx); + if (!feedbackCleanup) updateStatus(ctx); // only clear status if no feedback hint active } function toggleDpMode(ctx: ExtensionContext): void { @@ -618,9 +663,19 @@ export default function deepInvestigationExtension(api: ExtensionAPI): void { } activeUI = null; resetProgressState(); + + // Flag that deep_search ran; capture investigationId if available + deepSearchRan = true; + const details = event.details as Record | undefined; + pendingFeedbackId = (details?.investigationId as string) ?? null; } }); + // Clean up feedback hint when agent starts processing next message + api.on("agent_start", () => { + feedbackCleanup?.(); + }); + // --- context: filter UI-only custom messages --- // Custom types that are UI-only metadata — must never be sent to the LLM. From af27353a50eb8a2551e509eb973bcc2e71fb6e24 Mon Sep 17 00:00:00 2001 From: likiosliu Date: Fri, 13 Mar 2026 20:45:28 +0800 Subject: [PATCH 2/2] fix: address review feedback on TUI investigation feedback 1. Show feedback prompt for standalone deep_search (no DP mode) by triggering showFeedbackIfNeeded in tool_result when !checklist. 2. Clean up stale feedback state (timer, input listener) on session_start to prevent leaks across session restarts. --- src/core/extensions/deep-investigation.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/core/extensions/deep-investigation.ts b/src/core/extensions/deep-investigation.ts index 598457b..5cfb741 100644 --- a/src/core/extensions/deep-investigation.ts +++ b/src/core/extensions/deep-investigation.ts @@ -597,6 +597,11 @@ export default function deepInvestigationExtension(api: ExtensionAPI, memoryRef? // --- session_start: restore persisted state --- api.on("session_start", async (_event, ctx) => { + // Clean up stale feedback prompt from previous session + feedbackCleanup?.(); + deepSearchRan = false; + pendingFeedbackId = null; + // Reset state — each session starts clean (prevents bleed from previous session) checklist = null; @@ -654,7 +659,7 @@ export default function deepInvestigationExtension(api: ExtensionAPI, memoryRef? // --- tool_result: progress cleanup (no auto-mark) --- - api.on("tool_result", (event) => { + api.on("tool_result", (event, ctx) => { if (event.toolName === "deep_search") { // Progress rendering cleanup if (activeUI) { @@ -668,6 +673,12 @@ export default function deepInvestigationExtension(api: ExtensionAPI, memoryRef? deepSearchRan = true; const details = event.details as Record | undefined; pendingFeedbackId = (details?.investigationId as string) ?? null; + + // Standalone deep_search (no DP mode): show feedback immediately since + // disableDpMode() won't fire. Guard with !checklist to avoid double-prompting. + if (!checklist) { + showFeedbackIfNeeded(ctx); + } } });