fix(server): interrupt turns after tool denial (#1051)

This commit is contained in:
程序员阿江(Relakkes) 2026-07-17 18:33:32 +08:00
parent e2c57cde2c
commit a6ebcfb00c
2 changed files with 58 additions and 2 deletions

View File

@ -272,7 +272,13 @@ describe('ConversationService', () => {
pendingOutbound: [],
stderrLines: [],
sdkMessages: [],
pendingPermissionRequests: new Map(),
pendingPermissionRequests: new Map([
['req-1', {
toolName: 'ExitPlanMode',
input: {},
permissionSuggestions: [],
}],
]),
})
const result = svc.respondToPermission(
@ -294,6 +300,48 @@ describe('ConversationService', () => {
},
},
})
expect((sent[0] as any).response.response.interrupt).toBeUndefined()
})
it('should interrupt the active turn when desktop denies a tool permission', () => {
const svc = new ConversationService()
const sent: unknown[] = []
;(svc as any).sessions.set('session-1', {
proc: null,
outputCallbacks: [],
workDir: process.cwd(),
sdkToken: 'token',
sdkSocket: {
send(data: string) {
sent.push(JSON.parse(data))
},
},
pendingOutbound: [],
stderrLines: [],
sdkMessages: [],
pendingPermissionRequests: new Map([
['req-1', {
toolName: 'Bash',
input: { command: 'rm temp.txt' },
permissionSuggestions: [],
}],
]),
})
const result = svc.respondToPermission('session-1', 'req-1', false)
expect(result).toBe(true)
expect(sent[0]).toMatchObject({
type: 'control_response',
response: {
response: {
behavior: 'deny',
message: 'User denied via UI',
interrupt: true,
},
},
})
})
it('should resolve a permission mode request only after the CLI confirms the change', async () => {

View File

@ -622,7 +622,15 @@ export class ConversationService {
}
: {}),
}
: { behavior: 'deny', message: denyMessage || 'User denied via UI' },
: {
behavior: 'deny',
message: denyMessage || 'User denied via UI',
// Rejecting ExitPlanMode means "keep planning"; other desktop
// denials stop the current agent turn and wait for user input.
...(pendingRequest?.toolName !== 'ExitPlanMode'
? { interrupt: true }
: {}),
},
},
})
}