Files
dsh-context/tests/client/callSummary.spec.ts
T
bowenliang123 87a2893190 refactor(comments): clean up the test-suite comments to the guideline
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.
2026-10-10 00:50:55 +08:00

124 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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'])
})
})