Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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,34 @@ 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(),
);
// The aborted call's row is recorded under the no-run sentinel turn, so
// settlement coverage does not count it as missing usage — a hosted run
// must still settle despite an auxiliary failure.
assert.equal(abortedSummary.projection.coverage.usageMissingAttempts, 0);
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 +4484,196 @@ 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);
// Settlement coverage counts run-owned usage-missing rows only: the
// auxiliary rows under test are recorded under the no-run sentinel
// turn, so `missing` stays at whatever a run's own dispatch produced.
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: 0, 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: 0, 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 stays on the legacy
// zero path: hosted execution settlement refuses any range containing
// usage-missing rows, so a canonical missing row here would mark every
// such hosted run indeterminate. This residual zero is pending a ruling
// on that settlement coverage semantics (#5691); aborted and failed calls
// keep their canonical usage-unknown rows above.
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: 2, missing: 0, errors: 1 });
const silentLegacy = (await legacyGoalRows()).find((row) => row.callId === callId('call-3'));
assert.ok(silentLegacy);
assert.equal(silentLegacy.status, 'success');
assert.equal(silentLegacy.inputTokens, 0);
assert.equal(silentLegacy.outputTokens, 0);
} 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
76 changes: 61 additions & 15 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 { NO_RUN_TURN_ID, 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,14 @@ 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.
* The storage side excludes these rows from settlement coverage, so a failed
* auxiliary call cannot flip a hosted run to indeterminate (#5691).
*/
const AUXILIARY_TURN_ID = NO_RUN_TURN_ID;

function createAuxiliaryModelCallAuthority(
input: AuxiliaryModelCallAuthorityInput,
): AuxiliaryModelCallAuthority {
Expand All @@ -629,6 +642,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 +726,34 @@ async function runHostAuxiliaryModelCall(
modelId: target.model,
startedAt,
};
// Abort and error 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,28 +794,23 @@ async function runHostAuxiliaryModelCall(
if (oauthFailure) throw oauthFailure;
} catch (error) {
const effectiveError = readDeferredOAuthFailure?.() ?? error;
try {
await recordLlmCallStrict(
{ repo: authority.telemetry, lookupPricing: pricing },
{
...baseRecord,
inputTokens: 0,
outputTokens: 0,
latencyMs: Math.max(0, authority.now() - startedAt),
status: input.abortSignal.aborted ? 'aborted' : 'error',
errorClass: evaluatorErrorClass(effectiveError),
},
);
} catch (accountingError) {
throw new AuxiliaryModelCallLocalError('accounting', accountingError);
}
await recordUsageUnknown(
input.abortSignal.aborted ? 'aborted' : 'failed',
evaluatorErrorClass(effectiveError),
);
throw effectiveError;
}
try {
await recordLlmCallStrict(
{ repo: authority.telemetry, lookupPricing: pricing },
{
...baseRecord,
// A completion without reported usage stays on the legacy zero path:
// hosted execution settlement refuses any range containing
// usage-missing rows ('missing_attempt_usage'), so routing these
// rows to the canonical ledger marked every such hosted run
// indeterminate. The residual zero is known dishonesty, pending a
// ruling on that settlement coverage semantics (#5691).
...(result.usage
? llmCallUsageFields(result.usage)
: { inputTokens: 0, outputTokens: 0 }),
Expand Down
Loading