From 84fc1c54b878aad3140819310c74fe776448a75e Mon Sep 17 00:00:00 2001 From: AstroHan Date: Wed, 15 Jul 2026 08:28:34 +0800 Subject: [PATCH] fix(runtime): project user question requests --- .../runtime-event-read-model.test.ts | 56 +++++++++++++++++++ .../runtime/src/runtime-event-read-model.ts | 6 ++ 2 files changed, 62 insertions(+) diff --git a/packages/runtime/src/__tests__/runtime-event-read-model.test.ts b/packages/runtime/src/__tests__/runtime-event-read-model.test.ts index b188d91ced..3176c95878 100644 --- a/packages/runtime/src/__tests__/runtime-event-read-model.test.ts +++ b/packages/runtime/src/__tests__/runtime-event-read-model.test.ts @@ -288,6 +288,62 @@ describe('projectRuntimeEventsToStoredMessages', () => { expect(out.diagnostics.map((diag) => diag.code)).toEqual(['context_remaining_unsupported']); }); + test('projects an AskUserQuestion round trip without a legacy row for the live request', () => { + const out = projectRuntimeEventsToStoredMessages([ + ev({ + id: 'evt-question-call', + ts: ts + 1, + role: 'model', + author: 'agent', + content: { + kind: 'function_call', + id: 'question-tool-1', + name: 'AskUserQuestion', + args: { questions: [{ question: 'Choose', options: [{ label: 'Extend' }] }] }, + }, + refs: { toolCallId: 'question-tool-1' }, + }), + ev({ + id: 'evt-question-request', + ts: ts + 2, + actions: { + userQuestionRequest: { + requestId: 'question-1', + toolUseId: 'question-tool-1', + questions: [{ question: 'Choose', options: [{ label: 'Extend' }] }], + }, + }, + refs: { toolCallId: 'question-tool-1' }, + }), + ev({ + id: 'evt-question-result', + ts: ts + 3, + role: 'tool', + author: 'tool', + content: { + kind: 'function_response', + id: 'question-tool-1', + name: 'AskUserQuestion', + result: { kind: 'json', value: { answers: ['Extend'] } }, + }, + refs: { toolCallId: 'question-tool-1' }, + }), + ev({ + id: 'evt-question-complete', + ts: ts + 4, + status: 'completed', + actions: { endInvocation: true }, + }), + ], { runHeaders: [header] }); + + expect(out.messages.map((message) => message.type)).toEqual([ + 'tool_call', + 'tool_result', + 'turn_state', + ]); + expect(out.diagnostics).toEqual([]); + }); + test('normalizes an exact legacy terminal result at RuntimeEvent restore', () => { const out = projectRuntimeEventsToStoredMessages([ ev({ diff --git a/packages/runtime/src/runtime-event-read-model.ts b/packages/runtime/src/runtime-event-read-model.ts index fc4cfcf7c2..31e152bd0f 100644 --- a/packages/runtime/src/runtime-event-read-model.ts +++ b/packages/runtime/src/runtime-event-read-model.ts @@ -156,6 +156,12 @@ export function projectRuntimeEventsToStoredMessages( projected = true; } + if (event.actions?.userQuestionRequest) { + // The matching function_call/function_response own the legacy rows; + // this request is live interaction state only. + projected = true; + } + if (event.actions?.permissionDecision) { projected = projectPermissionDecision(event, state, messages) || projected; }