fix(tool-sieve): allow mixed prose + tool json interception

This commit is contained in:
CJACK.
2026-03-20 01:15:32 +08:00
parent 2d5103997b
commit 145501d4a5
2 changed files with 9 additions and 29 deletions

View File

@@ -259,28 +259,28 @@ test('sieve emits final tool_calls for split arguments payload without increment
assert.deepEqual(finalCalls[0].input, { path: 'README.MD', mode: 'head' });
});
test('sieve keeps tool json as text when leading prose exists (strict mode)', () => {
test('sieve still emits tool_calls when leading prose exists before tool json', () => {
const events = runSieve(
['我将调用工具。', '{"tool_calls":[{"name":"read_file","input":{"path":"README.MD"}}]}'],
['read_file'],
);
const hasTool = events.some((evt) => (evt.type === 'tool_calls' && evt.calls?.length > 0) || (evt.type === 'tool_call_deltas' && evt.deltas?.length > 0));
const leakedText = collectText(events);
assert.equal(hasTool, false);
assert.equal(hasTool, true);
assert.equal(leakedText.includes('我将调用工具。'), true);
assert.equal(leakedText.toLowerCase().includes('tool_calls'), true);
assert.equal(leakedText.toLowerCase().includes('tool_calls'), false);
});
test('sieve keeps same-chunk trailing prose payload as text in strict mode', () => {
test('sieve emits tool_calls and keeps trailing prose when payload and prose share a chunk', () => {
const events = runSieve(
['{"tool_calls":[{"name":"read_file","input":{"path":"README.MD"}}]}然后继续解释。'],
['read_file'],
);
const hasTool = events.some((evt) => (evt.type === 'tool_calls' && evt.calls?.length > 0) || (evt.type === 'tool_call_deltas' && evt.deltas?.length > 0));
const leakedText = collectText(events);
assert.equal(hasTool, false);
assert.equal(hasTool, true);
assert.equal(leakedText.includes('然后继续解释。'), true);
assert.equal(leakedText.toLowerCase().includes('tool_calls'), true);
assert.equal(leakedText.toLowerCase().includes('tool_calls'), false);
});
test('formatOpenAIStreamToolCalls reuses ids with the same idStore', () => {