Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -4441,13 +4441,31 @@ test('Host auxiliary models meter provider usage and abort physical requests', {
});
await closing;
assert.equal(transportCloses, 1);
const abortedLogs = await usage.telemetry.logs({ range: 'all' });
// An aborted auxiliary call knows no token counts: it records in the
// canonical ledger as a usage-unknown row (#5691), never as a zero-token
// legacy row that reads as a free call.
const abortedAttempts = await usage.modelCalls.modelCallLogs(
{ range: 'all', sessionId: session.id },
Date.now(),
0,
10,
);
assert.ok(
abortedLogs.rows.some(
abortedAttempts.projection.rows.some(
(row) =>
row.callId === `goal_evaluation_${session.id}_call-2` && row.status === 'aborted',
),
);
const abortedSummary = await usage.modelCalls.modelCallSummary(
{ range: 'all', sessionId: session.id },
Date.now(),
);
assert.equal(abortedSummary.projection.coverage.usageMissingAttempts >= 1, true);
const abortedLegacyLogs = await usage.telemetry.logs({ range: 'all' });
assert.equal(
abortedLegacyLogs.rows.some((row) => row.callId === `goal_evaluation_${session.id}_call-2`),
false,
);
} finally {
abort.abort(new DOMException('Goal evaluator test cleanup', 'AbortError'));
providerRelease.resolve();
Expand All @@ -4463,6 +4481,188 @@ test('Host auxiliary models meter provider usage and abort physical requests', {
}
});

test('Host auxiliary aborts, errors and usage-unknown completions record canonical usage-unknown rows', {
timeout: 20_000,
}, async () => {
const base = await mkdtemp(join(tmpdir(), 'maka-host-aux-usage-unknown-'));
const capability = await resolveStorageRoot({
path: join(base, 'interactive'),
kind: 'interactive',
});
const owner = await tryAcquireInteractiveRootOwner(capability);
assert.ok(owner);
if (!owner) return;

const policy = await openInteractiveRuntimePolicyStoresForWrite(owner.lease);
const usage = await openInteractiveUsageStoresForWrite(owner.lease);
const execution = await openInteractiveExecutionStoresForWrite(owner.lease);
try {
const created = await policy.connectionCatalog.create({
expectedCatalogRevision: 0,
connection: {
slug: 'usage-unknown-provider',
name: 'Usage unknown provider',
providerType: 'opencode-go',
baseUrl: 'http://usage-unknown.test/v1',
enabled: true,
enabledModelIds: [MODEL_ID],
},
});
assert.equal(created.kind, 'committed');
if (created.kind !== 'committed') return;
const connection = created.snapshot.connections[0];
assert.ok(connection);
if (!connection) return;
const credential = await policy.credentialVault.set({
locator: {
scope: 'connection',
connectionId: connection.connectionId,
kind: 'api_key',
},
expected: null,
secret: API_KEY,
});
assert.equal(credential.kind, 'committed');
await publishConnectionModel(policy, connection.connectionId, MODEL_ID);
const session = await execution.sessionStore.create({
cwd: capability.canonicalPath,
llmConnectionId: connection.connectionId,
llmConnectionSlug: 'usage-unknown-provider',
model: MODEL_ID,
permissionMode: 'ask',
});
let callCounter = 0;
const evaluator = (
fetchImpl: (request: unknown, init?: { signal?: AbortSignal }) => Promise<unknown>,
) =>
createHostGoalEvaluator({
runtimePolicy: policy,
oauthCredentials: new HostOAuthExecutionAuthority(policy),
usage,
requestDrain: () => assert.fail('Auxiliary accounting must not drain the Host'),
readSessionHeader: (sessionId: string) =>
execution.sessionStore.readHeaderSnapshot(sessionId),
newId: () => `call-${++callCounter}`,
createFetchTransport: () => ({
fetch: fetchImpl as unknown as ProxiedFetchTransport['fetch'],
close: async () => undefined,
}),
});
const callId = (suffix: string) => `goal_evaluation_${session.id}_${suffix}`;
const canonicalRow = async (suffix: string) => {
const logs = await usage.modelCalls.modelCallLogs(
{ range: 'all', sessionId: session.id },
Date.now(),
0,
10,
);
return logs.projection.rows.find((row) => row.callId === callId(suffix));
};
const legacyGoalRows = async () => {
const logs = await usage.telemetry.logs({ range: 'all' });
return logs.rows.filter((row) => row.callKind === 'goal_evaluation');
};
const assertSummary = async (expected: {
requests: number;
missing: number;
errors: number;
}) => {
const summary = await usage.modelCalls.modelCallSummary(
{ range: 'all', sessionId: session.id },
Date.now(),
);
assert.equal(summary.projection.totalRequests, expected.requests);
assert.equal(summary.projection.coverage.usageMissingAttempts, expected.missing);
assert.equal(summary.projection.coverage.usageReportedAttempts, 0);
assert.equal(summary.projection.errorRequests, expected.errors);
assert.equal(summary.projection.totalTokens.total, 0);
assert.equal(summary.projection.totalCostUsd, 0);
};

// Aborted mid-flight: usage can never be known, so the canonical row says
// so instead of posing as a free call in the legacy table.
let abortSignal: AbortSignal | undefined;
const abortDispatched = deferred<void>();
const abortReleased = deferred<void>();
const abortingEvaluator = evaluator(async (_request, init) => {
abortSignal = init?.signal ?? undefined;
abortDispatched.resolve();
await abortReleased.promise;
throw abortSignal?.reason ?? new DOMException('Aborted', 'AbortError');
});
const abort = new AbortController();
const abortedCall = abortingEvaluator.evaluate(
'Judge the completed Goal.',
session.id,
abort.signal,
);
await settleWithin(abortDispatched.promise);
abort.abort(new DOMException('Goal lane invalidated', 'AbortError'));
abortReleased.resolve();
await assert.rejects(settleWithin(abortedCall));
await assertSummary({ requests: 1, missing: 1, errors: 0 });
const abortedRow = await canonicalRow('call-1');
assert.ok(abortedRow);
assert.equal(abortedRow.status, 'aborted');
assert.equal(abortedRow.callKind, 'goal_evaluation');
assert.deepEqual(await legacyGoalRows(), []);

// A provider error without an abort is usage-unknown all the same.
const failingEvaluator = evaluator(async () => {
throw new Error('provider exploded');
});
await assert.rejects(
failingEvaluator.evaluate(
'Judge the completed Goal.',
session.id,
new AbortController().signal,
),
);
await assertSummary({ requests: 2, missing: 2, errors: 1 });
const failedRow = await canonicalRow('call-2');
assert.ok(failedRow);
assert.equal(failedRow.status, 'error');
assert.equal(failedRow.errorClass, 'Error');
assert.deepEqual(await legacyGoalRows(), []);

// A completion the provider answered without usage is usage-unknown too —
// the call succeeded, but zero tokens were never reported.
const silentEvaluator = evaluator(async () =>
Response.json({
id: 'chatcmpl-usage-unknown',
object: 'chat.completion',
created: 1,
model: MODEL_ID,
choices: [
{
index: 0,
message: { role: 'assistant', content: RESPONSE_TEXT },
finish_reason: 'stop',
},
],
}),
);
assert.equal(
await silentEvaluator.evaluate(
'Judge the completed Goal.',
session.id,
new AbortController().signal,
),
RESPONSE_TEXT,
);
await assertSummary({ requests: 3, missing: 3, errors: 1 });
const silentRow = await canonicalRow('call-3');
assert.ok(silentRow);
assert.equal(silentRow.status, 'success');
assert.deepEqual(await legacyGoalRows(), []);
} finally {
await usage.close();
await execution.sessionStore.close?.();
await owner.close();
await rm(base, { recursive: true, force: true });
}
});

test('one turn shares one canonical Skill inventory across prompt and lazy tools', async () => {
const policy = {
revision: 7,
Expand Down
81 changes: 60 additions & 21 deletions packages/runtime-host/src/server/execution-model-authority.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ import { resolveModelRuntime } from '@maka/runtime/model-runtime';
import { type BackendFactoryContext } from '@maka/runtime/session-manager';
import { type GoalEvaluatorResource } from '@maka/runtime/goal-evaluator';
import { type ModelMessage } from '@maka/runtime/model-protocol';
import { type ModelCallAttemptStatus } from '@maka/core/model-call-attempt';
import { type UsageUnknownModelCallRecord } from '@maka/storage/model-call-ledger';
import {
memoryExtractionMaxOutputTokens,
type MemoryExtractionSourceSnapshot,
Expand Down Expand Up @@ -560,6 +562,9 @@ interface AuxiliaryModelCallAuthority {
record: Parameters<InteractiveUsageStoresWriter['telemetry']['recordLlmCall']>[0],
): Promise<void>;
};
readonly modelCalls: {
recordUsageUnknownAttempt(record: UsageUnknownModelCallRecord): Promise<void>;
};
readonly requestDrain: () => void;
readonly now: () => number;
readonly newId: () => string;
Expand Down Expand Up @@ -605,6 +610,12 @@ interface HostAuxiliaryModelCallInput {
) => AuxiliaryModelRequest;
}

/**
* Turn placeholder for canonical rows of calls no run owns: auxiliary calls
* happen outside any turn, and the ledger's countable rows require the column.
*/
const AUXILIARY_TURN_ID = 'auxiliary';

function createAuxiliaryModelCallAuthority(
input: AuxiliaryModelCallAuthorityInput,
): AuxiliaryModelCallAuthority {
Expand All @@ -629,6 +640,16 @@ function createAuxiliaryModelCallAuthority(
}
},
},
modelCalls: {
recordUsageUnknownAttempt: async (record) => {
try {
await input.usage.modelCalls.recordUsageUnknownAttempt(record);
} catch (error) {
requestDrain();
throw error;
}
},
},
requestDrain,
now: input.now ?? Date.now,
newId: input.newId ?? randomUUID,
Expand Down Expand Up @@ -703,6 +724,34 @@ async function runHostAuxiliaryModelCall(
modelId: target.model,
startedAt,
};
// Abort and no-usage paths know no token counts: their canonical row says
// usage-unknown (`usageBasis: 'missing'`, no tokens) instead of posing as a
// free call (#5691). Auxiliary calls run outside any AgentRun, so the
// canonical writer is this store seam, not the run's event stream.
const recordUsageUnknown = async (
status: ModelCallAttemptStatus,
errorClass?: string,
): Promise<void> => {
const completedAt = authority.now();
try {
await authority.modelCalls.recordUsageUnknownAttempt({
attemptId: input.callId,
completedAt,
...(input.telemetrySessionId ? { sessionId: input.telemetrySessionId } : {}),
logicalCallId: input.callId,
turnId: AUXILIARY_TURN_ID,
callKind: input.callKind,
connectionSlug: target.connection.slug,
providerId: target.connection.providerType,
modelId: target.model,
latencyMs: Math.max(0, completedAt - startedAt),
status,
...(errorClass ? { errorClass } : {}),
});
} catch (accountingError) {
throw new AuxiliaryModelCallLocalError('accounting', accountingError);
}
};
let result:
| Awaited<ReturnType<typeof generateToolFreeModelCall>>
| Awaited<ReturnType<typeof generateProviderPrefixModelCall>>;
Expand Down Expand Up @@ -743,38 +792,28 @@ async function runHostAuxiliaryModelCall(
if (oauthFailure) throw oauthFailure;
} catch (error) {
const effectiveError = readDeferredOAuthFailure?.() ?? error;
await recordUsageUnknown(
input.abortSignal.aborted ? 'aborted' : 'failed',
evaluatorErrorClass(effectiveError),
);
throw effectiveError;
}
if (result.usage) {
try {
await recordLlmCallStrict(
{ repo: authority.telemetry, lookupPricing: pricing },
{
...baseRecord,
inputTokens: 0,
outputTokens: 0,
...llmCallUsageFields(result.usage),
latencyMs: Math.max(0, authority.now() - startedAt),
status: input.abortSignal.aborted ? 'aborted' : 'error',
errorClass: evaluatorErrorClass(effectiveError),
status: 'success',
},
);
} catch (accountingError) {
throw new AuxiliaryModelCallLocalError('accounting', accountingError);
}
throw effectiveError;
}
try {
await recordLlmCallStrict(
{ repo: authority.telemetry, lookupPricing: pricing },
{
...baseRecord,
...(result.usage
? llmCallUsageFields(result.usage)
: { inputTokens: 0, outputTokens: 0 }),
...(result.finishReason && !result.usage ? { rawFinishReason: result.finishReason } : {}),
latencyMs: Math.max(0, authority.now() - startedAt),
status: 'success',
},
);
} catch (accountingError) {
throw new AuxiliaryModelCallLocalError('accounting', accountingError);
} else {
await recordUsageUnknown('completed');
}
return {
text: result.text,
Expand Down
11 changes: 5 additions & 6 deletions packages/storage/src/__tests__/public-entrypoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,16 @@ test('every published entrypoint target is emitted by the build', async () => {
* means removing the entry, and publishing a *new* consumer-less entrypoint
* fails outright, which is the direction this guard exists to hold.
*
* `./model-call-ledger` is on the list without this change touching it: it was
* already published, and `repairPendingModelCallProjections` lost its last
* caller when `canonical-usage-reader` was rewritten on `main`. It is listed
* here rather than unpublished for the same reason as the rest — retiring a
* subpath that already shipped is a compatibility call of its own.
* `./model-call-ledger` was on this list until the usage-unknown seam
* (`fix(usage)`): it had been published without consumers since
* `repairPendingModelCallProjections` lost its last caller when
* `canonical-usage-reader` was rewritten on `main`; the auxiliary-call
* recorder in runtime-host is its first external consumer again.
*/
const PREEXISTING_UNCONSUMED_ENTRYPOINTS = [
'./activation-secret-injector',
'./encrypted-file-managed-secret-store',
'./managed-secret-store',
'./model-call-ledger',
'./write-queue',
];

Expand Down
Loading
Loading