From 362e5d37bdf7489814a5416b49695f32c4010e5b Mon Sep 17 00:00:00 2001 From: rcourtman Date: Mon, 11 May 2026 09:14:21 +0100 Subject: [PATCH] Add Investigate button on Patrol findings Pulse Intelligence direction named seven contextual Assistant entry points: Explain, Investigate, Prepare fix, Verify fix, Why did this happen, Remember this is expected, Create rule from this. Explain was the only first-class one. Investigate was rolled into "Discuss with Assistant" with a generic open-ended prompt. Splits Investigate off as its own action. Where Explain says "tell me what we already know," Investigate says "go find out what's true right now": - Widens PatrolAssistantFindingIntent to 'discuss' | 'explain' | 'investigate'. - buildPatrolAssistantFindingPrompt gains an investigate branch: the prompt explicitly instructs the LLM to use its Pulse tools (metrics, alerts, resource state, recent changes, correlations) to gather fresh evidence, then synthesize root cause + confidence + safe next step + whether the recommended action still holds. Any command-running step must route through governed approval, not the LLM's own judgment. - FindingsPanel adds an Investigate button between Explain and Copy summary, and a handleInvestigateFinding handler that routes through openFindingInAssistant with the new intent. - Both Explain and Investigate now set autoSendInitialPrompt: true (single condition update); Discuss stays false. Test: a new investigate-intent prompt-builder case asserts the prompt mentions active tool use, the synthesis dimensions (root cause, confidence, safe next step), and the governed- approval safety boundary, and isn't the Discuss seed. --- .../src/components/AI/FindingsPanel.tsx | 45 +++++++++++++++---- .../patrolInvestigationContextModel.test.ts | 30 +++++++++++++ .../patrol/patrolInvestigationContextModel.ts | 20 ++++++++- 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/frontend-modern/src/components/AI/FindingsPanel.tsx b/frontend-modern/src/components/AI/FindingsPanel.tsx index 574a5779bf..7970de8266 100644 --- a/frontend-modern/src/components/AI/FindingsPanel.tsx +++ b/frontend-modern/src/components/AI/FindingsPanel.tsx @@ -518,7 +518,7 @@ export const FindingsPanel: Component = (props) => { const openFindingInAssistant = async ( finding: UnifiedFinding, - intent: 'discuss' | 'explain', + intent: 'discuss' | 'explain' | 'investigate', ) => { await aiIntelligenceStore.loadPendingApprovals(); const subject = getFindingSubjectPresentation(finding).label; @@ -559,15 +559,15 @@ export const FindingsPanel: Component = (props) => { nextStepAction, intent, }); - // Explain is an action-style entry point — clicking the button is the - // operator asking "do the explaining for me," not "open chat so I can - // type a question." Auto-submit the handoff prompt so the analysis is - // already in flight when the drawer is on screen. Discuss with - // Assistant keeps the previous behaviour (pre-fill, operator drives) - // because that entry is open-ended by intent. + // Explain and Investigate are action-style entry points — clicking + // the button is the operator asking "do this for me," not "open chat + // so I can type a question." Auto-submit the handoff prompt so the + // work is already in flight when the drawer is on screen. Discuss + // with Assistant keeps the previous behaviour (pre-fill, operator + // drives) because that entry is open-ended by intent. aiChatStore.openWithPrompt(handoff.prompt, { ...handoff.context, - autoSendInitialPrompt: intent === 'explain', + autoSendInitialPrompt: intent === 'explain' || intent === 'investigate', }); }; @@ -581,6 +581,17 @@ export const FindingsPanel: Component = (props) => { await openFindingInAssistant(finding, 'explain'); }; + // Investigate is the active counterpart to Explain. Explain says "tell me + // what we already know"; Investigate says "go find out what's true right + // now." The prompt instructs the LLM to use its Pulse tools (metrics, + // alerts, state, recent changes, correlations) rather than just narrate + // the attached context, and the surface auto-sends so the work is in + // flight when the operator lands. + const handleInvestigateFinding = async (finding: UnifiedFinding, e: Event) => { + e.stopPropagation(); + await openFindingInAssistant(finding, 'investigate'); + }; + // Copy a Markdown summary of the finding to the clipboard so the operator // can paste it into a chat, ticket, or incident channel. The shape mirrors // the seven-question schema (title + impact + recommendation + trust @@ -1173,7 +1184,7 @@ export const FindingsPanel: Component = (props) => { type="button" onClick={(e) => handleExplainFinding(finding, e)} class="px-2 py-1 rounded border border-border hover:bg-surface-hover flex items-center gap-1" - title="Open Assistant with an explanation prompt" + title="Ask Pulse Assistant to explain what we know about this finding using the attached evidence" > = (props) => { Explain +