mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-22 14:30:53 +08:00
fix(server): handle tool denial interruption #1070
This commit is contained in:
parent
6b725a0b6f
commit
7d272e0f96
26
src/utils/queryHelpers.test.ts
Normal file
26
src/utils/queryHelpers.test.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { describe, expect, test } from 'bun:test'
|
||||||
|
import {
|
||||||
|
createUserInterruptionMessage,
|
||||||
|
INTERRUPT_MESSAGE_FOR_TOOL_USE,
|
||||||
|
} from './messages.js'
|
||||||
|
import { isResultSuccessful } from './queryHelpers.js'
|
||||||
|
|
||||||
|
describe('isResultSuccessful', () => {
|
||||||
|
test('treats user interruption during tool use as a normal terminal result', () => {
|
||||||
|
const interruption = createUserInterruptionMessage({ toolUse: true })
|
||||||
|
|
||||||
|
expect(isResultSuccessful(interruption, 'tool_use')).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('does not treat an ordinary user prompt as successful after tool_use', () => {
|
||||||
|
const ordinaryPrompt = createUserInterruptionMessage({ toolUse: true })
|
||||||
|
ordinaryPrompt.message.content = [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: `${INTERRUPT_MESSAGE_FOR_TOOL_USE} keep going`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(isResultSuccessful(ordinaryPrompt, 'tool_use')).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -27,7 +27,12 @@ import {
|
|||||||
createFileStateCacheWithSizeLimit,
|
createFileStateCacheWithSizeLimit,
|
||||||
type FileStateCache,
|
type FileStateCache,
|
||||||
} from './fileStateCache.js'
|
} from './fileStateCache.js'
|
||||||
import { isNotEmptyMessage, normalizeMessages } from './messages.js'
|
import {
|
||||||
|
INTERRUPT_MESSAGE,
|
||||||
|
INTERRUPT_MESSAGE_FOR_TOOL_USE,
|
||||||
|
isNotEmptyMessage,
|
||||||
|
normalizeMessages,
|
||||||
|
} from './messages.js'
|
||||||
import { expandPath } from './path.js'
|
import { expandPath } from './path.js'
|
||||||
import type {
|
import type {
|
||||||
inputSchema as permissionToolInputSchema,
|
inputSchema as permissionToolInputSchema,
|
||||||
@ -50,6 +55,7 @@ const ASK_READ_FILE_STATE_CACHE_SIZE = 10
|
|||||||
* Returns true if:
|
* Returns true if:
|
||||||
* - Last message is assistant with text/thinking content
|
* - Last message is assistant with text/thinking content
|
||||||
* - Last message is user with only tool_result blocks
|
* - Last message is user with only tool_result blocks
|
||||||
|
* - Last message is a synthetic user interruption
|
||||||
* - Last message is the user prompt but the API completed with end_turn
|
* - Last message is the user prompt but the API completed with end_turn
|
||||||
* (model chose to emit no content blocks)
|
* (model chose to emit no content blocks)
|
||||||
*/
|
*/
|
||||||
@ -78,6 +84,16 @@ export function isResultSuccessful(
|
|||||||
) {
|
) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onlyBlock = Array.isArray(content) ? content[0] : undefined
|
||||||
|
if (
|
||||||
|
content.length === 1 &&
|
||||||
|
onlyBlock?.type === 'text' &&
|
||||||
|
(onlyBlock.text === INTERRUPT_MESSAGE ||
|
||||||
|
onlyBlock.text === INTERRUPT_MESSAGE_FOR_TOOL_USE)
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carve-out: API completed (message_delta set stop_reason) but yielded
|
// Carve-out: API completed (message_delta set stop_reason) but yielded
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user