Files
dsh-context/tests/host/pricing.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

269 lines
10 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.
// The token-pricing heuristic (src/host/pricing.ts) — a mirror of the harness token-meter's
// fixed-density estimator with the image-block refinement. Pure functions over real payloads.
import assert from 'node:assert/strict'
import { describe, test } from 'vitest'
import {
estimateMessage,
estimateToolSchema,
estimateToolsTotal,
firstText,
imageCountOf,
injectionSourceName,
isInjection,
toolCallNames,
} from '../../src/host/pricing'
import { estimateSystemTokens } from '../../src/shared/estimate'
import type { ContentBlock } from '../../src/host/pricing'
describe('estimateToolsTotal', () => {
test('empty tool list prices zero', () => {
assert.equal(estimateToolsTotal([]), 0)
})
test('non-empty list prices the whole-array JSON plus one block', () => {
const tools = [{ name: 'bash', description: 'run a command' }]
assert.equal(estimateToolsTotal(tools), Math.ceil(JSON.stringify(tools).length / 4) + 4)
})
})
describe('estimateMessage', () => {
test('text blocks price chars/4 plus block and role overhead', () => {
// 16 chars → 4, +4 block, +4 role
assert.equal(estimateMessage({ content: [{ type: 'text', text: '0123456789abcdef' }] }), 12)
})
test('reasoning blocks price like text', () => {
assert.equal(estimateMessage({ content: [{ type: 'reasoning', text: '0123456789abcdef' }] }), 12)
})
test('tool-call blocks price name plus arguments', () => {
// 'bash' → 1, '{}' → 1, +4 block, +4 role
assert.equal(estimateMessage({ content: [{ type: 'tool-call', name: 'bash', arguments: '{}' }] }), 10)
})
test('tool-call blocks tolerate missing name/arguments', () => {
assert.equal(estimateMessage({ content: [{ type: 'tool-call' }] }), 8)
})
test('a retired wrapper block prices as generic JSON (the meter parity branch)', () => {
// The supported log generation carries no wrapper blocks; a hostile one
// prices through the same structural-JSON arm the meter applies to every unknown block.
const block = { type: 'tool-result', content: [{ type: 'text', text: 'ok' }] }
assert.equal(
estimateMessage({ content: [block] }),
4 + Math.ceil(JSON.stringify(block).length / 4) + 4,
)
})
test('unknown block types fall back to the generic JSON price', () => {
const block = { type: 'mystery', payload: { a: 1 } }
assert.equal(
estimateMessage({ content: [block] }),
4 + Math.ceil(JSON.stringify(block).length / 4) + 4,
)
})
test('image blocks with known dimensions price through the vision calculator', () => {
// 800×600 → 341 (docs-verified) +4 block +4 role
assert.equal(
estimateMessage({ content: [{ type: 'image', attachment: { width: 800, height: 600 } }] }),
341 + 8,
)
})
test('image blocks with a null attachment fall back to the JSON price', () => {
const block = { type: 'image', attachment: null }
assert.equal(estimateMessage({ content: [block] }), Math.ceil(JSON.stringify(block).length / 4) + 8)
})
test('image blocks with a non-object attachment fall back to the JSON price', () => {
const block = { type: 'image', attachment: 'ref' } as unknown as ContentBlock
assert.equal(estimateMessage({ content: [block] }), Math.ceil(JSON.stringify(block).length / 4) + 8)
})
test('image blocks missing one dimension fall back to the JSON price', () => {
const block = { type: 'image', attachment: { width: 800 } }
assert.equal(estimateMessage({ content: [block] }), Math.ceil(JSON.stringify(block).length / 4) + 8)
})
test('image blocks with non-finite dimensions price the calculator null through the JSON fallback', () => {
// typeof NaN === 'number' passes the guard; the calculator rejects non-finite input.
const block = { type: 'image', attachment: { width: NaN, height: 100 } }
assert.equal(estimateMessage({ content: [block] }), Math.ceil(JSON.stringify(block).length / 4) + 8)
})
test('message without an array content pays role framing only', () => {
assert.equal(estimateMessage({}), 4)
assert.equal(estimateMessage({ content: 'not-an-array' as never }), 4)
})
test('emptyIsZero short-circuits null/undefined/empty messages to zero', () => {
assert.equal(estimateMessage(null, true), 0)
assert.equal(estimateMessage(undefined, true), 0)
assert.equal(estimateMessage({}, true), 0)
assert.equal(estimateMessage({ content: [] }, true), 0)
assert.equal(estimateMessage({ content: 'x' as never }, true), 0)
// …but a non-empty message still prices normally under emptyIsZero.
assert.equal(estimateMessage({ content: [{ type: 'text', text: 'abcd' }] }, true), 9)
})
test('emptyIsZero=false prices a null message as role framing only', () => {
assert.equal(estimateMessage(null), 4)
assert.equal(estimateMessage(undefined), 4)
})
})
describe('estimateSystem', () => {
test('non-strings and the empty string price zero', () => {
assert.equal(estimateSystemTokens(undefined), 0)
assert.equal(estimateSystemTokens(null), 0)
assert.equal(estimateSystemTokens(42), 0)
assert.equal(estimateSystemTokens(''), 0)
})
test('text prices chars/4 plus role framing', () => {
assert.equal(estimateSystemTokens('abcd'), 5)
})
})
describe('estimateToolSchema', () => {
test('prices the tool JSON plus one block', () => {
const tool = { name: 'bash' }
assert.equal(estimateToolSchema(tool), Math.ceil(JSON.stringify(tool).length / 4) + 4)
})
})
describe('imageCountOf', () => {
test('counts image blocks, recursing into nested content', () => {
assert.equal(imageCountOf([
{ type: 'image' },
{ type: 'tool-result', content: [{ type: 'image' }, { type: 'text', text: 'x' }] },
{ type: 'text', text: 'y' },
]), 2)
})
test('non-array input counts zero', () => {
assert.equal(imageCountOf(undefined), 0)
assert.equal(imageCountOf('x' as never), 0)
})
})
describe('firstText', () => {
test('returns the first non-blank text block, whitespace-normalized and truncated to 80', () => {
const long = 'word '.repeat(30) // 150 chars
const out = firstText([{ type: 'text', text: long }])
assert.equal(out.length, 80)
assert.ok(!out.includes(' '))
})
test('skips non-text blocks, non-string text, and whitespace-only text', () => {
assert.equal(firstText([
{ type: 'image' },
{ type: 'text' },
{ type: 'text', text: ' \n\t ' },
{ type: 'text', text: ' real text ' },
]), 'real text')
})
test('non-array input yields the empty string', () => {
assert.equal(firstText(undefined), '')
assert.equal(firstText(null as never), '')
})
})
describe('toolCallNames', () => {
test('collects tool-call block names in order', () => {
assert.deepEqual(toolCallNames([
{ type: 'tool-call', name: 'bash' },
{ type: 'text', text: 'x' },
{ type: 'tool-call', name: 'read' },
{ type: 'tool-call' }, // no name: skipped
]), ['bash', 'read'])
})
test('non-array input yields an empty list', () => {
assert.deepEqual(toolCallNames(undefined), [])
})
})
describe('injectionSourceName', () => {
test('agent-instructions sources name their deduped change paths', () => {
assert.equal(injectionSourceName({
kind: 'agent-instructions',
changes: [{ path: 'AGENTS.md' }, { path: 'AGENTS.md' }, { path: 'docs/TEAM.md' }],
}), 'AGENTS.md, docs/TEAM.md')
})
test('agent-instructions skips null entries and empty paths', () => {
assert.equal(injectionSourceName({
kind: 'agent-instructions',
changes: [null, { path: '' }, { path: 'A.md' }],
}), 'A.md')
})
test('agent-instructions with no usable path falls through to kind', () => {
assert.equal(injectionSourceName({ kind: 'agent-instructions', changes: [null] }), 'agent-instructions')
assert.equal(injectionSourceName({ kind: 'agent-instructions', changes: [] }), 'agent-instructions')
})
test('agent-instructions without a changes array falls through to kind', () => {
assert.equal(injectionSourceName({ kind: 'agent-instructions' }), 'agent-instructions')
})
test('plugin sources name the plugin id', () => {
assert.equal(injectionSourceName({ kind: 'plugin', plugin: 'dsh-agent-presets' }), 'dsh-agent-presets')
})
test('an empty plugin id falls through to kind', () => {
assert.equal(injectionSourceName({ kind: 'plugin', plugin: '' }), 'plugin')
})
test('any other producer names its own kind; an unreadable source yields empty', () => {
assert.equal(injectionSourceName({ kind: 'goal' }), 'goal')
assert.equal(injectionSourceName({ kind: '' }), '')
assert.equal(injectionSourceName({}), '')
})
test('a missing source degrades to empty instead of throwing (issue #69)', () => {
assert.equal(injectionSourceName(undefined), '')
assert.equal(injectionSourceName(null), '')
})
})
describe('isInjection', () => {
test('null and undefined sources are not injections', () => {
assert.equal(isInjection(null), false)
assert.equal(isInjection(undefined), false)
})
test('a plain user source is not an injection', () => {
assert.equal(isInjection({ kind: 'user' }), false)
assert.equal(isInjection({}), false)
})
test('any non-user kind is an injection, even with a form', () => {
assert.equal(isInjection({ kind: 'plugin', form: 'notice' }), true)
// 'user-rpc' keeps kind "user" in the log but a transport form must not flip the class…
assert.equal(isInjection({ kind: 'user', form: 'rpc' }), true) // form fallback, per the fold comment
})
test('a foreign source declaring only a form classifies as an injection', () => {
assert.equal(isInjection({ form: 'notice' }), true)
})
})
describe('hostile block shapes', () => {
test('null and primitive elements degrade to overhead instead of throwing', () => {
const junk = [null, 7, 'x'] as never
assert.ok(estimateMessage({ content: junk }) > 0)
assert.equal(imageCountOf(junk), 0)
assert.equal(firstText(junk), '')
assert.deepEqual(toolCallNames(junk), [])
// A null element nested inside a tool-result block is tolerated too.
const nested = [{ type: 'tool-result', content: [null, { type: 'image' }] }] as never
assert.equal(imageCountOf(nested), 1)
assert.ok(estimateMessage({ content: nested }) > 0)
})
})