96 lines
3.5 KiB
JavaScript
96 lines
3.5 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { dirname, join } from 'node:path'
|
|
import vm from 'node:vm'
|
|
|
|
const dir = dirname(fileURLToPath(import.meta.url))
|
|
|
|
function loadToolCallFns() {
|
|
const src = readFileSync(join(dir, '../lib/agent/agent-tui.js'), 'utf8')
|
|
const start = src.indexOf('function bareAgentMergeToolCallDelta')
|
|
const end = src.indexOf('function bareAgentReasoningSettings')
|
|
assert.ok(start >= 0 && end > start, 'tool-call helpers missing in agent-tui.js')
|
|
const sandbox = {}
|
|
vm.createContext(sandbox)
|
|
vm.runInContext(src.slice(start, end), sandbox)
|
|
return sandbox
|
|
}
|
|
|
|
test('finalize drops stream+final duplicate tool calls', () => {
|
|
const { bareAgentMergeToolCallDelta, bareAgentFinalizeToolCalls } = loadToolCallFns()
|
|
/** @type {Map<number, { id: string, name: string, args: string }>} */
|
|
const acc = new Map()
|
|
bareAgentMergeToolCallDelta(acc, {
|
|
index: 0,
|
|
id: 'c1',
|
|
function: { name: 'get_system_info', arguments: '{}' }
|
|
})
|
|
// Same call again under a new stream index (final re-emit bug).
|
|
bareAgentMergeToolCallDelta(acc, {
|
|
index: 1,
|
|
id: 'c1',
|
|
function: { name: 'get_system_info', arguments: '{}' }
|
|
})
|
|
const out = bareAgentFinalizeToolCalls(acc)
|
|
assert.equal(out.length, 1)
|
|
assert.equal(out[0].function.name, 'get_system_info')
|
|
})
|
|
|
|
test('finalize drops duplicate name+args when ids differ', () => {
|
|
const { bareAgentMergeToolCallDelta, bareAgentFinalizeToolCalls } = loadToolCallFns()
|
|
const acc = new Map()
|
|
bareAgentMergeToolCallDelta(acc, {
|
|
index: 0,
|
|
id: 'qvac_call_0',
|
|
function: { name: 'read_proc_file', arguments: '{"path":"/proc/bare_os/features"}' }
|
|
})
|
|
bareAgentMergeToolCallDelta(acc, {
|
|
index: 1,
|
|
id: 'qvac_call_1',
|
|
function: { name: 'read_proc_file', arguments: '{"path":"/proc/bare_os/features"}' }
|
|
})
|
|
const out = bareAgentFinalizeToolCalls(acc)
|
|
assert.equal(out.length, 1)
|
|
})
|
|
|
|
test('extract hermes <tool_call> JSON from assistant text', () => {
|
|
const { bareAgentExtractToolCallsFromText, bareAgentStripToolCallsFromText } =
|
|
loadToolCallFns()
|
|
const text =
|
|
'Working.\n<tool_call>{"name":"read_file","arguments":{"path":"/home/guest/x"}}</tool_call>'
|
|
const out = bareAgentExtractToolCallsFromText(text)
|
|
assert.equal(out.length, 1)
|
|
assert.equal(out[0].function.name, 'read_file')
|
|
assert.ok(String(out[0].function.arguments).includes('/home/guest/x'))
|
|
assert.equal(bareAgentStripToolCallsFromText(text), 'Working.')
|
|
})
|
|
|
|
test('extract qwen3.5 XML tool_call from assistant text', () => {
|
|
const { bareAgentExtractToolCallsFromText } = loadToolCallFns()
|
|
const text =
|
|
'<tool_call><function=list_directory><parameter=path>/home</parameter></function></tool_call>'
|
|
const out = bareAgentExtractToolCallsFromText(text)
|
|
assert.equal(out.length, 1)
|
|
assert.equal(out[0].function.name, 'list_directory')
|
|
assert.equal(JSON.parse(out[0].function.arguments).path, '/home')
|
|
})
|
|
|
|
test('finalize keeps same tool with different args', () => {
|
|
const { bareAgentMergeToolCallDelta, bareAgentFinalizeToolCalls } = loadToolCallFns()
|
|
const acc = new Map()
|
|
bareAgentMergeToolCallDelta(acc, {
|
|
index: 0,
|
|
id: 'a',
|
|
function: { name: 'read_file', arguments: '{"path":"/a"}' }
|
|
})
|
|
bareAgentMergeToolCallDelta(acc, {
|
|
index: 1,
|
|
id: 'b',
|
|
function: { name: 'read_file', arguments: '{"path":"/b"}' }
|
|
})
|
|
const out = bareAgentFinalizeToolCalls(acc)
|
|
assert.equal(out.length, 2)
|
|
})
|