From c63cc64d403ab8ca4c2c7e228955a5a5eac620fb Mon Sep 17 00:00:00 2001 From: Merge Sim Date: Sun, 30 Aug 2026 17:17:30 -0700 Subject: [PATCH] fix(agents): restore OMP approval forwarding after merge --- .../providers/pi-family-events.ts | 28 +++++++----- .../providers/pi-family-tool-fields.ts | 45 +++++++++++++++++-- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/shared/agent-hook-listener/providers/pi-family-events.ts b/src/shared/agent-hook-listener/providers/pi-family-events.ts index 5f0aeaf42c5..b3d66ee1d77 100644 --- a/src/shared/agent-hook-listener/providers/pi-family-events.ts +++ b/src/shared/agent-hook-listener/providers/pi-family-events.ts @@ -28,19 +28,23 @@ export function normalizePiCompatibleEvent( ((agentType === 'pi' && isAskUserQuestionTool(toolName)) || (agentType === 'omp' && toolName === 'ask')) && (eventName === 'tool_call' || eventName === 'tool_execution_start') + const isOmpApprovalRequest = agentType === 'omp' && eventName === 'tool_approval_requested' + const isOmpApprovalResolution = agentType === 'omp' && eventName === 'tool_approval_resolved' - const stateName = isPiCompatibleAsk - ? 'blocked' - : eventName === 'before_agent_start' || - eventName === 'agent_start' || - eventName === 'tool_call' || - eventName === 'tool_execution_start' || - eventName === 'tool_execution_end' || - eventName === 'message_end' - ? 'working' - : eventName === 'agent_end' - ? 'done' - : null + const stateName = + isPiCompatibleAsk || isOmpApprovalRequest + ? 'blocked' + : isOmpApprovalResolution || + eventName === 'before_agent_start' || + eventName === 'agent_start' || + eventName === 'tool_call' || + eventName === 'tool_execution_start' || + eventName === 'tool_execution_end' || + eventName === 'message_end' + ? 'working' + : eventName === 'agent_end' + ? 'done' + : null if (!stateName) { return null diff --git a/src/shared/agent-hook-listener/providers/pi-family-tool-fields.ts b/src/shared/agent-hook-listener/providers/pi-family-tool-fields.ts index 21648548036..bb3e3251655 100644 --- a/src/shared/agent-hook-listener/providers/pi-family-tool-fields.ts +++ b/src/shared/agent-hook-listener/providers/pi-family-tool-fields.ts @@ -1,7 +1,29 @@ import type { ToolSnapshot } from '../listener-event' +import { isAskUserQuestionTool } from '../../agent-question-answered-intent' import { deriveToolInputPreview, hasOwnField, readString, toolUpdate } from '../tool-input-preview' import { deriveInteractivePrompt } from '../interactive-tool' +/** OMP's `ask` carries the same questions/options payload as Pi's question tool. */ +function serializeQuestionPrompt(toolInput: unknown): string | undefined { + if (toolInput === undefined || toolInput === null) { + return undefined + } + try { + return JSON.stringify(toolInput) + } catch { + return undefined + } +} + +function isPiCompatibleAskTool( + agentKind: 'pi' | 'omp' | 'prime-agent', + toolName: string | undefined +): boolean { + return agentKind === 'omp' + ? toolName === 'ask' + : agentKind === 'pi' && isAskUserQuestionTool(toolName) +} + export function extractPiToolFields( eventName: unknown, hookPayload: Record, @@ -15,16 +37,33 @@ export function extractPiToolFields( const toolName = readString(hookPayload, 'tool_name') const rawToolInput = hookPayload.tool_input const toolInput = deriveToolInputPreview(toolName, rawToolInput) - // Why: OMP shares this extractor; only derive interactivePrompt for Pi so OMP ask_user_question metadata stays unchanged. + // Why: OMP's `ask` uses the same questions/options shape as Pi's question tool. const interactivePrompt = - agentKind === 'pi' && (eventName === 'tool_call' || eventName === 'tool_execution_start') - ? deriveInteractivePrompt(toolName, rawToolInput, eventName) + isPiCompatibleAskTool(agentKind, toolName) && + (eventName === 'tool_call' || eventName === 'tool_execution_start') + ? agentKind === 'omp' + ? serializeQuestionPrompt(rawToolInput) + : deriveInteractivePrompt(toolName, rawToolInput, eventName) : undefined return toolUpdate( { toolName, toolInput, interactivePrompt }, { hasToolInputField: hasOwnField(hookPayload, 'tool_input') } ) } + if ( + agentKind === 'omp' && + (eventName === 'tool_approval_requested' || eventName === 'tool_approval_resolved') + ) { + return toolUpdate( + { + toolName: readString(hookPayload, 'tool_name'), + toolInput: + eventName === 'tool_approval_requested' ? readString(hookPayload, 'reason') : undefined, + interactivePrompt: undefined + }, + { hasToolInputField: true } + ) + } if (eventName === 'message_end' && hookPayload.role === 'assistant') { const text = readString(hookPayload, 'text') if (text) {