fix(ai): show the question in askUserQuestion tool-call labels (#10153)

This commit is contained in:
Guilhem
2026-07-16 15:48:24 +02:00
committed by GitHub
parent 7d5009e392
commit fa03984a14
7 changed files with 22 additions and 13 deletions
@@ -1312,7 +1312,7 @@ export class AIChatManager {
if (message.role === 'tool' && message.tool_call_id === toolId && message.userQuestion) {
return {
...message,
content: `User answered question: ${answerSummary}`,
content: `Asked: ${message.userQuestion.question} ${answerSummary}`,
isLoading: false,
userQuestion: {
...message.userQuestion,
@@ -2996,7 +2996,11 @@ export class AIChatManager {
return {
...message,
isLoading: false,
content: messageText,
// A question's card disappears once canceled, so keep the question
// itself readable in the collapsed header.
content: message.userQuestion
? `Asked: ${message.userQuestion.question}${messageText}`
: messageText,
error: messageText,
userQuestion: message.userQuestion
? { ...message.userQuestion, canceled: true }
@@ -143,7 +143,7 @@ export async function parseAnthropicCompletion(
callbacks.setToolStatus(toolId, {
isLoading: true,
content: `Calling ${toolName}...`,
content: tool?.streamingLabel ?? `Calling ${toolName}...`,
toolName,
isStreamingArguments: shouldStream,
showFade: tool?.showFade,
@@ -3250,7 +3250,7 @@ describe('global AI tools', () => {
expect(callbacks.setToolStatus).toHaveBeenLastCalledWith(
'test-askUserQuestion',
expect.objectContaining({
content: 'User answered question: python3',
content: 'Asked: Which script language should be used? — python3',
isLoading: false,
result: 'python3',
userQuestion: expect.objectContaining({ selectedChoices: ['python3'] })
@@ -3288,7 +3288,7 @@ describe('global AI tools', () => {
expect(callbacks.setToolStatus).toHaveBeenLastCalledWith(
'test-askUserQuestion',
expect.objectContaining({
content: 'User answered question: bun, go',
content: 'Asked: Which languages should be supported? — bun, go',
isLoading: false,
result: '- bun\n- go',
userQuestion: expect.objectContaining({ selectedChoices: ['bun', 'go'] })
@@ -3362,7 +3362,7 @@ describe('global AI tools', () => {
expect(callbacks.setToolStatus).toHaveBeenLastCalledWith(
'test-askUserQuestion',
expect.objectContaining({
content: 'User answered question: use deno instead',
content: 'Asked: Which script language should be used? — use deno instead',
result: 'use deno instead',
userQuestion: expect.objectContaining({ selectedChoices: ['use deno instead'] })
})
@@ -2133,6 +2133,7 @@ export const globalTools: Tool<{}>[] = [
'askUserQuestion',
'Ask the user a question with proposed answers and wait for their selected or custom answer before continuing.'
),
streamingLabel: 'Asking the user a question...',
fn: async ({ args, toolId, toolCallbacks }) => {
const parsed = askUserQuestionSchema.parse(args)
const userQuestion = {
@@ -2142,7 +2143,7 @@ export const globalTools: Tool<{}>[] = [
}
toolCallbacks.setToolStatus(toolId, {
content: parsed.question,
content: `Asking user: ${parsed.question}`,
userQuestion,
isLoading: true
})
@@ -2162,7 +2163,7 @@ export const globalTools: Tool<{}>[] = [
if (!selected?.length) {
const message = 'Question cancelled by user'
toolCallbacks.setToolStatus(toolId, {
content: message,
content: `Asked: ${parsed.question} — cancelled by user`,
userQuestion: { ...userQuestion, canceled: true },
isLoading: false,
error: message
@@ -2176,12 +2177,13 @@ export const globalTools: Tool<{}>[] = [
// ("Yes, immediately") stays unambiguous to the model reading it back.
const answerText =
selected.length === 1 ? selected[0] : selected.map((c) => `- ${c}`).join('\n')
// The collapsed tool-header is a human glance, not model input, so the picks
// read as a compact comma list there instead of a stacked bullet list.
// The collapsed tool-header is a human glance, not model input, so it carries
// the question plus the picks as a compact comma list (not a bullet list) —
// it is the only place the exchange stays readable in the transcript.
const answerSummary = selected.join(', ')
toolCallbacks.setToolStatus(toolId, {
content: `User answered question: ${answerSummary}`,
content: `Asked: ${parsed.question} ${answerSummary}`,
userQuestion: {
...userQuestion,
selectedChoices: selected
@@ -337,7 +337,7 @@ export async function parseOpenAIResponsesCompletion(
callbacks.onMessageEnd()
callbacks.setToolStatus(`${item.id}`, {
isLoading: true,
content: `Calling ${item.name}...`,
content: tool?.streamingLabel ?? `Calling ${item.name}...`,
toolName: item.name,
isStreamingArguments: shouldStream,
showFade: tool?.showFade,
@@ -820,6 +820,9 @@ export interface Tool<T> {
autoCollapseDetails?: boolean
streamArguments?: boolean
showFade?: boolean
/** Header shown while the model is still streaming this call's arguments,
* before `fn` runs and sets a real status. Defaults to "Calling <name>...". */
streamingLabel?: string
}
/** Status of a job the chat started and tracks in the jobs tray. Mirrors the
+1 -1
View File
@@ -1176,7 +1176,7 @@ export async function parseOpenAICompletion(
// Display tool call with streaming parameters if enabled
callbacks.setToolStatus(toolCallId, {
isLoading: true,
content: `Calling ${funcName}...`,
content: tool?.streamingLabel ?? `Calling ${funcName}...`,
toolName: funcName,
isStreamingArguments: shouldStream,
showFade: tool?.showFade,