mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-21 22:55:16 +00:00
fix(cli): persist skipped duplicate tool results
This commit is contained in:
parent
a20a724ec0
commit
71f23b79c7
2 changed files with 62 additions and 6 deletions
|
|
@ -28500,7 +28500,7 @@ describe('Session', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('drops repeated duplicate provider functionCall ids after the first synthetic response', async () => {
|
||||
it('records repeated duplicate provider calls without returning results', async () => {
|
||||
const execute = vi.fn().mockResolvedValue({
|
||||
llmContent: 'should not run',
|
||||
returnDisplay: 'should not run',
|
||||
|
|
@ -28529,6 +28529,7 @@ describe('Session', () => {
|
|||
],
|
||||
]),
|
||||
);
|
||||
const usedIds = new Set(['shell_1']);
|
||||
const [duplicatePart] = core.normalizeModelToolCallIds(
|
||||
[
|
||||
{
|
||||
|
|
@ -28539,7 +28540,7 @@ describe('Session', () => {
|
|||
},
|
||||
},
|
||||
],
|
||||
new Set(['shell_1']),
|
||||
usedIds,
|
||||
new Set<string>(),
|
||||
);
|
||||
const duplicateCall = duplicatePart.functionCall!;
|
||||
|
|
@ -28549,6 +28550,19 @@ describe('Session', () => {
|
|||
).runToolCalls(new AbortController().signal, 'prompt-history-dup', [
|
||||
duplicateCall,
|
||||
]);
|
||||
const [repeatedPart] = core.normalizeModelToolCallIds(
|
||||
[
|
||||
{
|
||||
functionCall: {
|
||||
id: 'shell_1',
|
||||
name: 'read_file',
|
||||
args: { file_path: 'b.ts' },
|
||||
},
|
||||
},
|
||||
],
|
||||
usedIds,
|
||||
new Set<string>(),
|
||||
);
|
||||
const toolLoopState: DaemonToolLoopState = {
|
||||
totalToolCalls: 0,
|
||||
invalidToolParamErrors: new Map<string, number>(),
|
||||
|
|
@ -28558,13 +28572,14 @@ describe('Session', () => {
|
|||
repeatedToolFailureMode: 'off',
|
||||
repeatedToolFailureState: createRepeatedToolFailureGuardState(),
|
||||
};
|
||||
expect(repeatedPart.functionCall?.id).toBe('shell_1__qwen_dup_3');
|
||||
const secondResult = await (
|
||||
session as unknown as ToolCallInternals
|
||||
).runToolCalls(
|
||||
new AbortController().signal,
|
||||
'prompt-history-dup',
|
||||
[
|
||||
duplicateCall,
|
||||
repeatedPart.functionCall!,
|
||||
{ id: 'fresh_shell', name: 'read_file', args: { file_path: 'c.ts' } },
|
||||
],
|
||||
toolLoopState,
|
||||
|
|
@ -28589,9 +28604,39 @@ describe('Session', () => {
|
|||
core.LoopType.GLOBAL_TOOL_CALL_DUPLICATE,
|
||||
);
|
||||
expect(mockChatRecordingService.recordToolResult).toHaveBeenCalledTimes(
|
||||
1,
|
||||
3,
|
||||
);
|
||||
expect(mockClient.sessionUpdate).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
mockChatRecordingService.recordToolResult.mock.calls
|
||||
.slice(1)
|
||||
.map(([parts, metadata]) => ({
|
||||
callId: metadata.callId,
|
||||
responseId: parts[0]?.functionResponse?.id,
|
||||
error: parts[0]?.functionResponse?.response?.['error'],
|
||||
status: metadata.status,
|
||||
executionStatus: metadata.executionStatus,
|
||||
})),
|
||||
).toEqual([
|
||||
{
|
||||
callId: 'shell_1__qwen_dup_3',
|
||||
responseId: 'shell_1__qwen_dup_3',
|
||||
error: expect.stringContaining(
|
||||
'loop detection stopped the current turn',
|
||||
),
|
||||
status: 'error',
|
||||
executionStatus: 'not_started',
|
||||
},
|
||||
{
|
||||
callId: 'fresh_shell',
|
||||
responseId: 'fresh_shell',
|
||||
error: expect.stringContaining(
|
||||
'loop detection stopped the current turn',
|
||||
),
|
||||
status: 'error',
|
||||
executionStatus: 'not_started',
|
||||
},
|
||||
]);
|
||||
expect(mockClient.sessionUpdate).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('suppresses duplicate TodoWrite calls without emitting plan updates', async () => {
|
||||
|
|
|
|||
|
|
@ -9055,11 +9055,22 @@ export class Session implements SessionContext {
|
|||
} else {
|
||||
debugLogger.warn(message);
|
||||
}
|
||||
return await finalizeRunToolResult({
|
||||
await Promise.all(
|
||||
dedupedFunctionCalls.map((fc) =>
|
||||
recordSkippedToolCall(
|
||||
fc,
|
||||
LOOP_DETECTED_SKIP_MESSAGE,
|
||||
false,
|
||||
ToolErrorType.UNKNOWN,
|
||||
),
|
||||
),
|
||||
);
|
||||
const result = await finalizeRunToolResult({
|
||||
parts: [],
|
||||
stopAfterPermissionCancel: false,
|
||||
loopDetected: true,
|
||||
});
|
||||
return { ...result, parts: [] };
|
||||
}
|
||||
|
||||
const pushDuplicateBatch = (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue