mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
Fix confirmations.
- This fixes what it means to get confirmations in GC. Prior to this they had just been accidentally unwired as part of all of the refactorings to turns + to server/core. - The key piece of this is that we wrap the onConfirm in the gemini stream hook in order to resubmit function responses. This isn't 100% ideal but gets the job done for now. - Fixed history not updating properly with confirmations. Fixes https://b.corp.google.com/issues/412323656
This commit is contained in:
committed by
N. Taylor Mullen
parent
618f8a43cf
commit
738c2692fb
@@ -130,83 +130,78 @@ export class Turn {
|
||||
yield event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute pending tool calls
|
||||
const toolPromises = this.pendingToolCalls.map(
|
||||
async (pendingToolCall): Promise<ServerToolExecutionOutcome> => {
|
||||
const tool = this.availableTools.get(pendingToolCall.name);
|
||||
if (!tool) {
|
||||
return {
|
||||
...pendingToolCall,
|
||||
error: new Error(
|
||||
`Tool "${pendingToolCall.name}" not found or not provided to Turn.`,
|
||||
),
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const confirmationDetails = await tool.shouldConfirmExecute(
|
||||
pendingToolCall.args,
|
||||
);
|
||||
if (confirmationDetails) {
|
||||
return { ...pendingToolCall, confirmationDetails };
|
||||
} else {
|
||||
const result = await tool.execute(pendingToolCall.args);
|
||||
return {
|
||||
...pendingToolCall,
|
||||
result,
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
}
|
||||
} catch (execError: unknown) {
|
||||
return {
|
||||
...pendingToolCall,
|
||||
error: new Error(
|
||||
`Tool execution failed: ${execError instanceof Error ? execError.message : String(execError)}`,
|
||||
),
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
const outcomes = await Promise.all(toolPromises);
|
||||
|
||||
// Process outcomes and prepare function responses
|
||||
this.pendingToolCalls = []; // Clear pending calls for this turn
|
||||
|
||||
for (let i = 0; i < outcomes.length; i++) {
|
||||
const outcome = outcomes[i];
|
||||
if (outcome.confirmationDetails) {
|
||||
this.confirmationDetails.push(outcome.confirmationDetails);
|
||||
const serverConfirmationetails: ServerToolCallConfirmationDetails = {
|
||||
request: {
|
||||
callId: outcome.callId,
|
||||
name: outcome.name,
|
||||
args: outcome.args,
|
||||
},
|
||||
details: outcome.confirmationDetails,
|
||||
// Execute pending tool calls
|
||||
const toolPromises = this.pendingToolCalls.map(
|
||||
async (pendingToolCall): Promise<ServerToolExecutionOutcome> => {
|
||||
const tool = this.availableTools.get(pendingToolCall.name);
|
||||
if (!tool) {
|
||||
return {
|
||||
...pendingToolCall,
|
||||
error: new Error(
|
||||
`Tool "${pendingToolCall.name}" not found or not provided to Turn.`,
|
||||
),
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
yield {
|
||||
type: GeminiEventType.ToolCallConfirmation,
|
||||
value: serverConfirmationetails,
|
||||
};
|
||||
} else {
|
||||
const responsePart = this.buildFunctionResponse(outcome);
|
||||
this.fnResponses.push(responsePart);
|
||||
const responseInfo: ToolCallResponseInfo = {
|
||||
callId: outcome.callId,
|
||||
responsePart,
|
||||
resultDisplay: outcome.result?.returnDisplay,
|
||||
error: outcome.error,
|
||||
};
|
||||
yield { type: GeminiEventType.ToolCallResponse, value: responseInfo };
|
||||
}
|
||||
}
|
||||
|
||||
// If there were function responses, the caller (GeminiService) will loop
|
||||
// and call run() again with these responses.
|
||||
// If no function responses, the turn ends here.
|
||||
try {
|
||||
const confirmationDetails = await tool.shouldConfirmExecute(
|
||||
pendingToolCall.args,
|
||||
);
|
||||
if (confirmationDetails) {
|
||||
return { ...pendingToolCall, confirmationDetails };
|
||||
} else {
|
||||
const result = await tool.execute(pendingToolCall.args);
|
||||
return {
|
||||
...pendingToolCall,
|
||||
result,
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
}
|
||||
} catch (execError: unknown) {
|
||||
return {
|
||||
...pendingToolCall,
|
||||
error: new Error(
|
||||
`Tool execution failed: ${execError instanceof Error ? execError.message : String(execError)}`,
|
||||
),
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
const outcomes = await Promise.all(toolPromises);
|
||||
|
||||
// Process outcomes and prepare function responses
|
||||
this.pendingToolCalls = []; // Clear pending calls for this turn
|
||||
|
||||
for (const outcome of outcomes) {
|
||||
if (outcome.confirmationDetails) {
|
||||
this.confirmationDetails.push(outcome.confirmationDetails);
|
||||
const serverConfirmationetails: ServerToolCallConfirmationDetails = {
|
||||
request: {
|
||||
callId: outcome.callId,
|
||||
name: outcome.name,
|
||||
args: outcome.args,
|
||||
},
|
||||
details: outcome.confirmationDetails,
|
||||
};
|
||||
yield {
|
||||
type: GeminiEventType.ToolCallConfirmation,
|
||||
value: serverConfirmationetails,
|
||||
};
|
||||
} else {
|
||||
const responsePart = this.buildFunctionResponse(outcome);
|
||||
this.fnResponses.push(responsePart);
|
||||
const responseInfo: ToolCallResponseInfo = {
|
||||
callId: outcome.callId,
|
||||
responsePart,
|
||||
resultDisplay: outcome.result?.returnDisplay,
|
||||
error: outcome.error,
|
||||
};
|
||||
yield { type: GeminiEventType.ToolCallResponse, value: responseInfo };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user