Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"./orchestration": "./dist/orchestration.js",
"./plan": "./dist/plan.js",
"./agent-run": "./dist/agent-run.js",
"./model-call-attempt": "./dist/model-call-attempt.js",
"./shell-run": "./dist/shell-run.js",
"./browser": "./dist/browser.js",
"./session-event-health": "./dist/session-event-health.js",
Expand Down
276 changes: 276 additions & 0 deletions packages/core/src/__tests__/model-call-attempt.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
import { describe, test } from 'node:test';
import assert from 'node:assert/strict';

import { decodeAgentRunEvent } from '../agent-run.js';
import {
MODEL_CALL_ATTEMPT_EVENT_TYPE,
MODEL_CALL_ATTEMPT_SCHEMA_VERSION,
decodeModelCallAttempt,
dedupeModelCallAttempts,
groupModelCallAttempts,
isModelCallAttempt,
settledAttempt,
sumModelCallCostUsd,
summarizeModelCallCoverage,
type ModelCallAttempt,
} from '../model-call-attempt.js';

function attempt(overrides: Partial<ModelCallAttempt> = {}): ModelCallAttempt {
return {
schemaVersion: MODEL_CALL_ATTEMPT_SCHEMA_VERSION,
logicalCallId: 'call-1',
attemptId: 'attempt-1',
traceId: 'trace-1',
sessionId: 'session-1',
runId: 'run-1',
turnId: 'turn-1',
step: 0,
attempt: 0,
callKind: 'main',
providerId: 'anthropic',
modelId: 'claude-opus-5',
startedAt: 1_000,
completedAt: 1_250,
latencyMs: 250,
status: 'completed',
usageBasis: 'reported',
inputTokens: 100,
outputTokens: 20,
costBasis: 'priced',
costUsd: 0.004,
...overrides,
};
}

describe('ModelCallAttempt codec', () => {
test('accepts a complete priced attempt', () => {
const decoded = decodeModelCallAttempt(attempt());
assert.equal(decoded.logicalCallId, 'call-1');
assert.equal(decoded.costUsd, 0.004);
});

test('accepts an unpriced attempt that carries usage but no cost', () => {
const decoded = decodeModelCallAttempt(attempt({ costBasis: 'unpriced', costUsd: undefined }));
assert.equal(decoded.costBasis, 'unpriced');
assert.equal(decoded.costUsd, undefined);
});

test('rejects an unpriced attempt that carries a cost', () => {
assert.throws(
() => decodeModelCallAttempt(attempt({ costBasis: 'unpriced', costUsd: 0 })),
/unpriced record carries a cost/,
);
});

test('rejects a priced attempt that carries no cost', () => {
// Otherwise coverage counts it as priced while the sum skips it, and
// "every call priced, total $0" reads as genuinely free.
assert.throws(
() => decodeModelCallAttempt(attempt({ costBasis: 'priced', costUsd: undefined })),
/priced record carries no cost/,
);
});

test('accepts a priced attempt costing exactly zero', () => {
const decoded = decodeModelCallAttempt(attempt({ costBasis: 'priced', costUsd: 0 }));
assert.equal(decoded.costUsd, 0);
});

test('rejects missing usage that still carries tokens', () => {
assert.throws(
() => decodeModelCallAttempt(attempt({ usageBasis: 'missing' })),
/missing usage but carries tokens/,
);
});

test('accepts missing usage with no token fields', () => {
const decoded = decodeModelCallAttempt(
attempt({
usageBasis: 'missing',
inputTokens: undefined,
outputTokens: undefined,
status: 'failed',
costBasis: 'unpriced',
costUsd: undefined,
}),
);
assert.equal(decoded.usageBasis, 'missing');
});

test('rejects completedAt before startedAt', () => {
assert.throws(
() => decodeModelCallAttempt(attempt({ startedAt: 2_000, completedAt: 1_000 })),
/completedAt precedes startedAt/,
);
});

test('rejects unknown fields, wrong schema version, and bad enums', () => {
assert.throws(() => decodeModelCallAttempt({ ...attempt(), unexpected: true } as unknown));
assert.throws(() => decodeModelCallAttempt(attempt({ schemaVersion: 2 as never })));
assert.throws(() => decodeModelCallAttempt(attempt({ callKind: 'tool' as never })));
assert.throws(() => decodeModelCallAttempt(attempt({ usageBasis: 'guessed' as never })));
assert.throws(() => decodeModelCallAttempt(attempt({ costBasis: 'free' as never })));
});

test('rejects empty identity and non-integer ordinals', () => {
assert.throws(() => decodeModelCallAttempt(attempt({ logicalCallId: '' })));
assert.throws(() => decodeModelCallAttempt(attempt({ attemptId: '' })));
assert.throws(() => decodeModelCallAttempt(attempt({ step: 1.5 })));
assert.throws(() => decodeModelCallAttempt(attempt({ attempt: -1 })));
});

test('rejects empty attribution keys', () => {
for (const field of ['traceId', 'sessionId', 'runId', 'turnId', 'providerId', 'modelId']) {
assert.throws(
() => decodeModelCallAttempt(attempt({ [field]: '' } as Partial<ModelCallAttempt>)),
`expected empty ${field} to be rejected`,
);
}
});

test('rejects negative and non-finite amounts', () => {
for (const costUsd of [-1, Number.NaN, Number.POSITIVE_INFINITY]) {
assert.throws(() => decodeModelCallAttempt(attempt({ costUsd })));
}
for (const inputTokens of [-1, Number.NaN, Number.POSITIVE_INFINITY]) {
assert.throws(() => decodeModelCallAttempt(attempt({ inputTokens })));
}
assert.throws(() => decodeModelCallAttempt(attempt({ latencyMs: -1 })));
assert.throws(() => decodeModelCallAttempt(attempt({ pricingRevision: -1 })));
});

test('validates optional pricing rates when present', () => {
const decoded = decodeModelCallAttempt(
attempt({
pricingRevision: 7,
pricingRates: { modelKey: 'claude-opus-5', inputUsdPer1M: 15, outputUsdPer1M: 75 },
}),
);
assert.equal(decoded.pricingRevision, 7);
// Incomplete, negative, or unrecognized rate shapes make a recorded amount
// unexplainable, which defeats storing the basis at all.
assert.throws(() =>
decodeModelCallAttempt(attempt({ pricingRates: { modelKey: 'x' } as never })),
);
assert.throws(() =>
decodeModelCallAttempt(
attempt({
pricingRates: { modelKey: 'x', inputUsdPer1M: -1, outputUsdPer1M: 75 } as never,
}),
),
);
assert.throws(() =>
decodeModelCallAttempt(
attempt({
pricingRates: {
modelKey: 'x',
inputUsdPer1M: 15,
outputUsdPer1M: 75,
surcharge: 3,
} as never,
}),
),
);
});

test('isModelCallAttempt narrows without throwing', () => {
assert.equal(isModelCallAttempt(attempt()), true);
assert.equal(isModelCallAttempt({ nope: true }), false);
});

test('the AgentRun ledger accepts the new event type', () => {
const decoded = decodeAgentRunEvent({
type: MODEL_CALL_ATTEMPT_EVENT_TYPE,
id: 'attempt-1',
runId: 'run-1',
sessionId: 'session-1',
turnId: 'turn-1',
ts: 1_250,
data: attempt() as unknown as Record<string, unknown>,
});
assert.equal(decoded.type, MODEL_CALL_ATTEMPT_EVENT_TYPE);
assert.equal(decodeModelCallAttempt(decoded.data).attemptId, 'attempt-1');
});
});

describe('ModelCallAttempt projections', () => {
test('dedupes re-appended records by attemptId, keeping the last', () => {
const first = attempt({ costUsd: 0.004 });
const replayed = attempt({ costUsd: 0.005 });
const unique = dedupeModelCallAttempts([first, replayed]);
assert.equal(unique.length, 1);
assert.equal(unique[0]?.costUsd, 0.005);
});

test('groups retries under one logical call and derives the settled attempt', () => {
const groups = groupModelCallAttempts([
attempt({ attemptId: 'a-0', attempt: 0, status: 'failed', costUsd: 0.001 }),
attempt({ attemptId: 'a-1', attempt: 1, status: 'completed', costUsd: 0.004 }),
attempt({ attemptId: 'b-0', logicalCallId: 'call-2' }),
]);
assert.equal(groups.length, 2);
const retried = groups.find((g) => g.logicalCallId === 'call-1');
assert.equal(retried?.attempts.length, 2);
assert.equal(settledAttempt(retried!)?.attemptId, 'a-1');
});

test('coverage counts priced, unpriced, and usage bases separately', () => {
const coverage = summarizeModelCallCoverage([
attempt({ attemptId: 'a' }),
attempt({ attemptId: 'b', costBasis: 'unpriced', costUsd: undefined }),
attempt({
attemptId: 'c',
costBasis: 'unpriced',
costUsd: undefined,
usageBasis: 'missing',
inputTokens: undefined,
outputTokens: undefined,
}),
attempt({ attemptId: 'd', usageBasis: 'partial', outputTokens: undefined }),
]);
assert.deepEqual(coverage, {
attempts: 4,
pricedAttempts: 2,
unpricedAttempts: 2,
usageReportedAttempts: 2,
usagePartialAttempts: 1,
usageMissingAttempts: 1,
});
});

test('cost sum reports the qualifying coverage alongside the total', () => {
const { costUsd, coverage } = sumModelCallCostUsd([
attempt({ attemptId: 'a', costUsd: 0.004 }),
attempt({ attemptId: 'b', costUsd: 0.006 }),
attempt({ attemptId: 'c', costBasis: 'unpriced', costUsd: undefined }),
]);
assert.equal(Math.round(costUsd * 1000) / 1000, 0.01);
// The unpriced call is real spend the total cannot express.
assert.equal(coverage.unpricedAttempts, 1);
});

test('a replayed attemptId is counted once through sum and coverage', () => {
// The bare dedupe helper is covered above; this locks the same guarantee on
// the paths a consumer actually calls, across a multi-id stream.
const stream = [
attempt({ attemptId: 'a', logicalCallId: 'call-1', costUsd: 0.004 }),
attempt({ attemptId: 'b', logicalCallId: 'call-2', costUsd: 0.006 }),
attempt({ attemptId: 'a', logicalCallId: 'call-1', costUsd: 0.004 }),
];
const { costUsd, coverage } = sumModelCallCostUsd(stream);
assert.equal(Math.round(costUsd * 1000) / 1000, 0.01);
assert.equal(coverage.attempts, 2);
assert.equal(coverage.pricedAttempts, 2);
assert.equal(summarizeModelCallCoverage(stream).attempts, 2);
assert.equal(groupModelCallAttempts(stream).length, 2);
});

test('a genuinely free priced call is distinguishable from an unpriced one', () => {
const free = attempt({ attemptId: 'free', costBasis: 'priced', costUsd: 0 });
const unknown = attempt({ attemptId: 'unknown', costBasis: 'unpriced', costUsd: undefined });
const { costUsd, coverage } = sumModelCallCostUsd([free, unknown]);
assert.equal(costUsd, 0);
assert.equal(coverage.pricedAttempts, 1);
assert.equal(coverage.unpricedAttempts, 1);
});
});
1 change: 1 addition & 0 deletions packages/core/src/agent-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ export const AGENT_RUN_EVENT_TYPES = [
'usage_recorded',
'provider_request_captured',
'provider_request_attempt_recorded',
'model_call_attempt_recorded',
'history_compact_checkpoint_recorded',
'active_full_compact_block_recorded',
'semantic_compact_block_recorded',
Expand Down
26 changes: 26 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,32 @@ export {
isSessionInlineRun,
} from './agent-run.js';

// model-call-attempt.ts
export type {
ModelCallAttempt,
ModelCallAttemptStatus,
ModelCallCostBasis,
ModelCallCoverage,
ModelCallGroup,
ModelCallKind,
ModelCallUsageBasis,
} from './model-call-attempt.js';
export {
MODEL_CALL_ATTEMPT_EVENT_TYPE,
MODEL_CALL_ATTEMPT_SCHEMA_VERSION,
MODEL_CALL_ATTEMPT_STATUSES,
MODEL_CALL_COST_BASES,
MODEL_CALL_KINDS,
MODEL_CALL_USAGE_BASES,
decodeModelCallAttempt,
dedupeModelCallAttempts,
groupModelCallAttempts,
isModelCallAttempt,
settledAttempt,
sumModelCallCostUsd,
summarizeModelCallCoverage,
} from './model-call-attempt.js';

// shell-run.ts
export type {
PipeShellOutput,
Expand Down
Loading
Loading