import { describe, expect, it } from 'vitest'; import { ToolCallAccumulator } from './tool-call-accumulator'; describe('ToolCallAccumulator', () => { it('assembles interleaved tool calls by index', () => { const accumulator = new ToolCallAccumulator(); accumulator.append([ { index: 1, id: 'call_2', type: 'function', function: { name: 'storage.', arguments: '{"scope":' } }, { index: 0, id: 'call_1', type: 'function', function: { name: 'runtime.', arguments: '{"deep":' } }, ]); accumulator.append([ { index: 0, function: { name: 'inspect', arguments: 'true}' } }, { index: 1, function: { name: 'estimate', arguments: '"model"}' } }, ]); expect(accumulator.finish(true)).toEqual([ { id: 'call_1', type: 'function', function: { name: 'runtime.inspect', arguments: '{"deep":true}' }, }, { id: 'call_2', type: 'function', function: { name: 'storage.estimate', arguments: '{"scope":"model"}' }, }, ]); }); it('rejects incomplete or malformed structured calls', () => { const missing = new ToolCallAccumulator(); missing.append([{ index: 1, id: 'call_2', function: { name: 'inspect', arguments: '{}' } }]); expect(() => missing.finish(true)).toThrow(/missing index 0/); const malformed = new ToolCallAccumulator(); malformed.append([{ index: 0, id: 'call_1', function: { name: 'inspect', arguments: '{' } }]); expect(() => malformed.finish(true)).toThrow(/not valid JSON/); }); it('reports live argument growth and safely drops an unfinished non-tool finish', () => { const accumulator = new ToolCallAccumulator(); expect(accumulator.append([{ index: 0, id: 'call_artifact', type: 'function', function: { name: 'html_artifact', arguments: '{"html":"
' }, }])).toEqual([{ index: 0, id: 'call_artifact', name: 'html_artifact', argumentCharacters: 15, }]); expect(accumulator.append([{ index: 0, function: { arguments: '

Draft

' }, }])).toEqual([{ index: 0, id: 'call_artifact', name: 'html_artifact', argumentCharacters: 29, }]); expect(accumulator.finish(false)).toEqual([]); }); it('requires a call when finish_reason is tool_calls', () => { expect(() => new ToolCallAccumulator().finish(true)).toThrow(/contained no tool calls/); }); });