Apply the AGENTS.md comments guideline to every .ts under tests/: remove what the code already expresses, keep only what it cannot. Removed: spec-header coverage inventories the describe/test tree already names; comments restating the next line's assertion or its message; helper JSDoc whose body already says it; within-file duplicates; five stale claims (trendChart's "six aggregated turns" against agg.length === 8, agentGraph's "six categories" against CATS' seven, fold-timing's "cheapest call LAST" against a loop that feeds it first, fold-surface's unreachable plain-JSON note, contextView's "two turns" for a one-turn fixture). Kept and condensed: the projection-freeze class, strict wire/state-schema hazards, retention and pricing windows, pairing rules, hostile-input rationale, fixture and expectation-array ground truth, jsdom mechanics, and issue-numbered regressions. Comment lines 2604 -> 2014 (-22%); 85 module headers kept, 30 coverage inventories dropped; every surviving comment line is within the 140-column limit, with 36 wrapped lines joined onto fuller ones. No logic, string, identifier, import or directive changed: a comment-strip gate proves each file's comment-free code is byte-identical to HEAD, and a line-level proof pairs all 845 changed lines with an unchanged code part. pnpm run lint && pnpm run test (106 files / 2061 tests, per-file 100% coverage) && pnpm run build all pass.
124 lines
4.3 KiB
TypeScript
124 lines
4.3 KiB
TypeScript
// Tool-call summaries (src/client/callSummary.ts): argument-JSON parsing and the conversation-block scanners.
|
||
|
||
import assert from 'node:assert/strict'
|
||
import { describe, test } from 'vitest'
|
||
import { blockSummaryOf, callNamesOf, callSummaryOf, parseCallArgs, summaryInArgs } from '../../src/client/callSummary'
|
||
import type { ConversationNodeLike } from '../../src/client/services'
|
||
|
||
function conv(over: Partial<ConversationNodeLike> = {}): ConversationNodeLike {
|
||
return { kind: 'assistant', seq: 1, ...over }
|
||
}
|
||
|
||
describe('parseCallArgs', () => {
|
||
test('non-string and empty input parses to null', () => {
|
||
assert.equal(parseCallArgs(42), null)
|
||
assert.equal(parseCallArgs(undefined), null)
|
||
assert.equal(parseCallArgs(''), null)
|
||
})
|
||
|
||
test('invalid JSON parses to null', () => {
|
||
assert.equal(parseCallArgs('{oops'), null)
|
||
})
|
||
|
||
test('non-object JSON parses to null', () => {
|
||
assert.equal(parseCallArgs('[1,2]'), null)
|
||
assert.equal(parseCallArgs('null'), null)
|
||
assert.equal(parseCallArgs('"text"'), null)
|
||
})
|
||
|
||
test('a JSON object parses to a record', () => {
|
||
assert.deepEqual(parseCallArgs('{"description":"d"}'), { description: 'd' })
|
||
})
|
||
})
|
||
|
||
describe('summaryInArgs', () => {
|
||
test('null args yield null', () => {
|
||
assert.equal(summaryInArgs(null), null)
|
||
})
|
||
|
||
test('the keys win in description, file_path, path, filePath order', () => {
|
||
assert.equal(summaryInArgs({ description: 'd', file_path: 'f', path: 'p', filePath: 'fp' }), 'd')
|
||
assert.equal(summaryInArgs({ file_path: 'f', path: 'p', filePath: 'fp' }), 'f')
|
||
assert.equal(summaryInArgs({ path: 'p', filePath: 'fp' }), 'p')
|
||
assert.equal(summaryInArgs({ filePath: 'fp' }), 'fp')
|
||
})
|
||
|
||
test('empty strings are skipped', () => {
|
||
assert.equal(summaryInArgs({ description: '', file_path: 'f' }), 'f')
|
||
})
|
||
|
||
test('non-string values are skipped', () => {
|
||
assert.equal(summaryInArgs({ description: 42, path: 'p' }), 'p')
|
||
})
|
||
|
||
test('no usable key yields null', () => {
|
||
assert.equal(summaryInArgs({ foo: 'bar' }), null)
|
||
})
|
||
})
|
||
|
||
describe('callSummaryOf', () => {
|
||
test('an undefined conversation yields null', () => {
|
||
assert.equal(callSummaryOf(undefined), null)
|
||
})
|
||
|
||
test('a missing or null call yields null', () => {
|
||
assert.equal(callSummaryOf(conv()), null)
|
||
assert.equal(callSummaryOf(conv({ call: null })), null)
|
||
})
|
||
|
||
test('an unusable call payload yields null', () => {
|
||
assert.equal(callSummaryOf(conv({ call: { name: 'bash', argsRaw: '{oops' } })), null)
|
||
})
|
||
|
||
test('the call’s args supply the summary', () => {
|
||
assert.equal(callSummaryOf(conv({ call: { name: 'edit', argsRaw: '{"file_path":"a.ts"}' } })), 'a.ts')
|
||
})
|
||
})
|
||
|
||
describe('blockSummaryOf', () => {
|
||
test('an undefined conversation or non-array blocks yield null', () => {
|
||
assert.equal(blockSummaryOf(undefined), null)
|
||
assert.equal(blockSummaryOf(conv({ blocks: 'junk' as unknown as unknown[] })), null)
|
||
})
|
||
|
||
test('null, non-object, and non-tool-call entries are skipped', () => {
|
||
const blocks = [null, 42, { kind: 'text' }, { kind: 'tool-call', argsRaw: '{"description":"d"}' }]
|
||
assert.equal(blockSummaryOf(conv({ blocks })), 'd')
|
||
})
|
||
|
||
test('the first tool-call with a usable summary wins', () => {
|
||
const blocks = [
|
||
{ kind: 'tool-call', argsRaw: '{oops' },
|
||
{ kind: 'tool-call', argsRaw: '{"foo":1}' },
|
||
{ kind: 'tool-call', argsRaw: '{"description":"first"}' },
|
||
{ kind: 'tool-call', argsRaw: '{"description":"second"}' },
|
||
]
|
||
assert.equal(blockSummaryOf(conv({ blocks })), 'first')
|
||
})
|
||
|
||
test('no usable tool-call summary yields null', () => {
|
||
const blocks = [{ kind: 'tool-call', argsRaw: '{oops' }, null]
|
||
assert.equal(blockSummaryOf(conv({ blocks })), null)
|
||
})
|
||
})
|
||
|
||
describe('callNamesOf', () => {
|
||
test('an undefined conversation or non-array blocks yield an empty list', () => {
|
||
assert.deepEqual(callNamesOf(undefined), [])
|
||
assert.deepEqual(callNamesOf(conv({ blocks: 'junk' as unknown as unknown[] })), [])
|
||
})
|
||
|
||
test('mixed entries are filtered down to tool-call names in order', () => {
|
||
const blocks = [
|
||
null,
|
||
42,
|
||
{ kind: 'text', name: 'not-a-call' },
|
||
{ kind: 'tool-call' },
|
||
{ kind: 'tool-call', name: 42 },
|
||
{ kind: 'tool-call', name: 'bash' },
|
||
{ kind: 'tool-call', name: 'read' },
|
||
]
|
||
assert.deepEqual(callNamesOf(conv({ blocks })), ['bash', 'read'])
|
||
})
|
||
})
|