mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 13:22:35 -07:00
fix(core): throw explicit error on dropped tool responses (#26668)
This commit is contained in:
@@ -2227,6 +2227,69 @@ describe('LocalAgentExecutor', () => {
|
||||
// Agent should terminate with ABORTED status
|
||||
expect(output.terminate_reason).toBe(AgentTerminateMode.ABORTED);
|
||||
});
|
||||
|
||||
it('should throw a critical error when a tool response is dropped by the scheduler', async () => {
|
||||
const definition = createTestDefinition([LS_TOOL_NAME]);
|
||||
const executor = await LocalAgentExecutor.create(
|
||||
definition,
|
||||
mockConfig,
|
||||
onActivity,
|
||||
);
|
||||
|
||||
// Turn 1: Model calls two tools
|
||||
mockModelResponse([
|
||||
{ name: LS_TOOL_NAME, args: { path: 'dir1' }, id: 'call1' },
|
||||
{ name: LS_TOOL_NAME, args: { path: 'dir2' }, id: 'call2' },
|
||||
]);
|
||||
|
||||
// Simulate scheduler returning only ONE result for TWO calls (dropped response)
|
||||
mockScheduleAgentTools.mockResolvedValueOnce([
|
||||
{
|
||||
status: 'success',
|
||||
request: { callId: 'call1', name: LS_TOOL_NAME },
|
||||
response: {
|
||||
responseParts: [
|
||||
{
|
||||
functionResponse: {
|
||||
name: LS_TOOL_NAME,
|
||||
id: 'call1',
|
||||
response: { ok: true },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(
|
||||
executor.run({ goal: 'Protocol test' }, signal),
|
||||
).rejects.toThrow(
|
||||
'Critical System Failure: Tool execution result was lost/dropped by the scheduler',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw a critical error when all scheduler results are missing/dropped', async () => {
|
||||
const definition = createTestDefinition([LS_TOOL_NAME]);
|
||||
const executor = await LocalAgentExecutor.create(
|
||||
definition,
|
||||
mockConfig,
|
||||
onActivity,
|
||||
);
|
||||
|
||||
// Turn 1: Model calls one tool
|
||||
mockModelResponse([
|
||||
{ name: LS_TOOL_NAME, args: { path: 'dir1' }, id: 'call1' },
|
||||
]);
|
||||
|
||||
// Simulate scheduler returning NO results (dropped response)
|
||||
mockScheduleAgentTools.mockResolvedValueOnce([]);
|
||||
|
||||
await expect(
|
||||
executor.run({ goal: 'Protocol test 2' }, signal),
|
||||
).rejects.toThrow(
|
||||
'Critical System Failure: Tool execution result was lost/dropped by the scheduler',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model Routing', () => {
|
||||
@@ -2334,7 +2397,15 @@ describe('LocalAgentExecutor', () => {
|
||||
},
|
||||
response: {
|
||||
resultDisplay: 'ls result',
|
||||
responseParts: [],
|
||||
responseParts: [
|
||||
{
|
||||
functionResponse: {
|
||||
name: LS_TOOL_NAME,
|
||||
id: 'call1',
|
||||
response: { ok: true },
|
||||
},
|
||||
},
|
||||
],
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1287,25 +1287,29 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
}
|
||||
}
|
||||
|
||||
// Reconstruct toolResponseParts in the original order
|
||||
// Ensure exactly one response per function call to satisfy the Gemini API protocol.
|
||||
const toolResponseParts: Part[] = [];
|
||||
for (const [index, functionCall] of functionCalls.entries()) {
|
||||
const callId = functionCall.id ?? `${promptId}-${index}`;
|
||||
const part = syncResults.get(callId);
|
||||
|
||||
if (part) {
|
||||
toolResponseParts.push(part);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If all authorized tool calls failed (and task isn't complete), provide a generic error.
|
||||
if (
|
||||
functionCalls.length > 0 &&
|
||||
toolResponseParts.length === 0 &&
|
||||
!taskCompleted
|
||||
) {
|
||||
toolResponseParts.push({
|
||||
text: 'All tool calls failed or were unauthorized. Please analyze the errors and try an alternative approach.',
|
||||
});
|
||||
const isAborted = signal.aborted;
|
||||
const isTaskComplete =
|
||||
functionCall.name === COMPLETE_TASK_TOOL_NAME && taskCompleted;
|
||||
|
||||
// Safely skip missing responses if the run was interrupted or the turn won't be sent back.
|
||||
if (isAborted || isTaskComplete) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`[LocalAgentExecutor] Critical System Failure: Tool execution result was lost/dropped by the scheduler for callId ${callId} (${functionCall.name}). This indicates an internal race condition or scheduler bug.`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user