fix(hermes): settle direct API usage with complete wire receipts

Export image-owned qualification assets from cloud builds and cover Claude/OpenAI image, question and billing journeys.

Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-09 10:13:33 -05:00
1 parent 8b5d075f0c
commit e025ff2286
38 files changed
+1347 -120

No files matched your search

@@ -57,6 +57,8 @@ import {
} from "../../vendor/paperclip-runner/index.js";
import * as issueServiceModule from "../issues.js";
import { NativePermissionDeclinedError } from "./native-permission-decline.js";
import { priceAnthropicReceipt } from "../anthropic-pricing.js";
import { priceCodexReceipt } from "../codex-pricing.js";
import {
createNativeHarnessBackupStamp,
verifyNativeHarnessBackupStamp,
@@ -1042,6 +1044,78 @@ describe("native provider usage normalization", () => {
billing: { complete: false, amountUsd: 0.25 } });
expect(nativeUsageCostUsd(snapshot.usage, hermes, "openrouter")).toBe(0.25);
});
describe("selected-account direct API wire usage", () => {
const tokens = { inputTokens: 20, outputTokens: 5, cacheReadTokens: 3, cacheWriteTokens: 2 };
const receipt = { schema: "paperclip.usage.tokens/v1", source: "provider_wire", biller: "anthropic", model: "claude-haiku-4-5-20251001", protocol: "messages",
complete: true, requestCount: 2, reportedRequestCount: 2, tokens, pricingContext: { serviceTier: "standard", contextTier: "short" } };
const directHermes = { ...hermes, model: receipt.model } as NativeExecutionInput["provider"];
const event = (eventType: string, turnId: string, payload: object = {}, sourceSeq = 1) => ({
eventType, turnId, payload, sourceSeq, sourceInstanceId: "wire-provider",
}) as unknown as PrpEvent;
const usageEvent = (turnId: string, tokenAccounting: unknown, runDelta: object = tokens, sourceSeq = 2) =>
event("item.completed", turnId, { kind: "usage", usage: { runDelta, tokenAccounting } }, sourceSeq);
it.each(["anthropic", "openai"] as const)("settles %s tokens across replay and queued turns with an explicit estimate", biller => {
const model = biller === "anthropic" ? receipt.model : "gpt-6-luna";
const selected = { ...directHermes, model } as NativeExecutionInput["provider"];
const authority = { ...receipt, biller, model, protocol: biller === "anthropic" ? "messages" : "chat_completions" };
const accounting = createNativeTurnAccounting(selected, biller);
accounting.observe(event("turn.started", "first"));
const firstUsage = usageEvent("first", authority);
accounting.observe(firstUsage); accounting.observe(firstUsage);
expect(accounting.snapshot().complete).toBe(false);
accounting.observe(event("turn.completed", "first", {}, 3));
accounting.observe(event("turn.started", "second", {}, 4));
accounting.observe(usageEvent("second", authority, tokens, 5));
accounting.observe(event("turn.completed", "second", {}, 6));
const snapshot = accounting.snapshot();
expect(snapshot).toMatchObject({ complete: true, settlementReady: true, turnId: "second",
usage: { runDeltaComplete: true, accountingCostIncomplete: false, tokenAccounting: { complete: true, requestCount: 4, reportedRequestCount: 4,
tokens: { inputTokens: 40, outputTokens: 10, cacheReadTokens: 6, cacheWriteTokens: 4 } } } });
expect(nativeUsageCostUsd(snapshot.usage, selected, biller)).toBeUndefined();
const priced = priceAnthropicReceipt(priceCodexReceipt({ complete: true, usageBasis: "per_run", provider: biller, biller, billingType: "metered_api", model,
usage: normalizeNativeUsage(snapshot.usage), pricingContext: authority.pricingContext as { serviceTier: "standard"; contextTier: "short" } }));
expect(priced.costStatus).toBe("estimated");
expect(priced.pricingProvenance?.source).toBe("rate_card");
expect(Number(priced.costUsdExact)).toBeGreaterThan(0);
});
it.each([
undefined, { ...receipt, model: "other-model" }, { ...receipt, biller: "openai", protocol: "responses" },
{ ...receipt, source: "agent_claim" }, { ...receipt, tokens: { ...tokens, outputTokens: 6 } },
])("keeps unowned or legacy accepted-response counters incomplete (%j)", authority => {
const accounting = createNativeTurnAccounting(directHermes, "anthropic");
accounting.observe(event("turn.started", "turn"));
accounting.observe(usageEvent("turn", authority));
accounting.observe(event("turn.completed", "turn", {}, 3));
expect(accounting.snapshot()).toMatchObject({ complete: false, settlementReady: false,
usage: { runDeltaComplete: false, accountingCostIncomplete: true } });
});
it("settles owned interrupted work without pricing its known subset or a placeholder zero", () => {
const accounting = createNativeTurnAccounting(directHermes, "anthropic");
const partial = { ...receipt, complete: false, requestCount: 3, reportedRequestCount: 2 };
accounting.observe(event("turn.started", "turn"));
accounting.observe(usageEvent("turn", partial, {}));
accounting.observe(event("turn.cancelled", "turn", {}, 3));
expect(accounting.snapshot()).toMatchObject({ complete: false, settlementReady: true, turnId: "turn",
usage: { runDeltaComplete: false, accountingCostIncomplete: true, tokenAccounting: { complete: false, tokens } } });
expect(normalizeNativeUsage(accounting.snapshot().usage)).toBeUndefined();
});
it("refuses to certify an aggregate that switches protocol or overflows safe counters", () => {
for (const overflow of [false, true]) {
const model = "gpt-6-luna", selected = { ...hermes, model } as NativeExecutionInput["provider"];
const accounting = createNativeTurnAccounting(selected, "openai");
const counts = overflow ? { inputTokens: Number.MAX_SAFE_INTEGER, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 } : tokens;
const authority = { ...receipt, biller: "openai", model, protocol: "chat_completions", tokens: counts };
accounting.observe(event("turn.started", "first"));
accounting.observe(usageEvent("first", authority, counts));
accounting.observe(event("turn.completed", "first", {}, 3));
accounting.observe(event("turn.started", "second", {}, 4));
accounting.observe(usageEvent("second", { ...authority, protocol: overflow ? "chat_completions" : "responses" }, counts, 5));
accounting.observe(event("turn.completed", "second", {}, 6));
expect(accounting.snapshot()).toMatchObject({ complete: false, usage: { runDeltaComplete: false } });
expect(accounting.snapshot().usage).not.toHaveProperty("tokenAccounting");
}
});
});
it.each([
{}, { inputTokens: 1 }, { outputTokens: 1 },
{ inputTokens: 0, outputTokens: -1 }, { inputTokens: 0.5, outputTokens: 1 },
@@ -4,7 +4,7 @@ import { dotRunnerBroker } from "../dot-runner-broker.js";
import { configuredEnvironment } from "../../vendor/paperclip-runner/index.js";
import { CURSOR_DISTRIBUTION_PINS, QUALIFIED_ACPX_PROFILES, QUALIFIED_ACPX_VERSION } from "../../vendor/paperclip-runner/index.js";
import { isProviderMode } from "../../vendor/paperclip-runner/index.js";
import { readProviderUsageBilling } from "../../vendor/paperclip-runner/index.js";
import { readProviderUsageBilling, readProviderTokenAccounting, type ProviderTokenAccounting } from "../../vendor/paperclip-runner/index.js";
import { bundledRemoteProviderPackManifestPath, bundledRemoteRunnerBinary } from "../../vendor/paperclip-runner/index.js";
import { nativeRetryCancellationEligible, rethrowNativeCancellationLockConflict, assertCancellationRequest, cancellationIntentId as callerCancellationIntentId, cancellationRequestId } from "./native-cancellation-request.js";
import { readNativePlanWait } from "./native-plan-wait.js";
@@ -7958,6 +7958,7 @@ async function executePaperclipNativeSessionWithinScope(
const costUsdExact = typeof usage?.accountingCostUsdExact === "string" ? usage.accountingCostUsdExact : undefined;
await input.onUsage?.({ usage: accountingUsage, ...billing, complete, settlement, usageBasis: "per_run", costUsdExact,
model: input.execution.provider.model ?? "unknown", costUsd: accountingCost ?? null, costStatus,
...(readProviderTokenAccounting(usage?.tokenAccounting)?.complete ? { pricingContext: readProviderTokenAccounting(usage?.tokenAccounting)!.pricingContext } : {}),
...nativeHermesPriceEvidence(usage, input.execution.provider, selectedBiller) });
if (!input.onUsage) await input.db.update(heartbeatRuns).set({
costAccountingPending: true,
@@ -9487,6 +9488,7 @@ async function executePaperclipNativeSessionWithinScope(
? input.execution.provider.kind === "aws_agentcore" ? "estimated" : nativeHermesPriceEvidence(native.usage, input.execution.provider, selectedBiller) ? "reported" : undefined
: "unpriced",
usageComplete: nativeAccountingComplete,
...(readProviderTokenAccounting(native.usage?.tokenAccounting)?.complete ? { pricingContext: readProviderTokenAccounting(native.usage?.tokenAccounting)!.pricingContext } : {}),
...(nativeSettlementReady ? { settlement: { schema: "paperclip.accounting.settlement/v1" as const, providerWorkEnded: true as const, usageComplete: nativeAccountingComplete } } : {}),
...nativeHermesPriceEvidence(native.usage, input.execution.provider, selectedBiller),
usageBasis: "per_run",
@@ -9570,6 +9572,10 @@ export function createNativeTurnAccounting(provider: NativeExecutionInput["provi
let requestCount = 0, reportedRequestCount = 0;
let tokensComplete = true;
let settlementReady = hermes;
let directAccountingReady = hermes && ["anthropic", "openai"].includes(selectedBiller ?? "");
let directAccounting: ProviderTokenAccounting | null = null;
let directRequests = 0, directReported = 0;
const directTokens = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
for (const [turnId, turn] of turns) {
const normalized = normalizeNativeUsage(turn.usage);
tokensComplete &&= normalized !== undefined;
@@ -9581,9 +9587,22 @@ export function createNativeTurnAccounting(provider: NativeExecutionInput["provi
const price = nativeUsageCostUsd(turn.usage, provider, selectedBiller);
const billing = provider.kind === "acpx" && provider.agent === "hermes"
? readProviderUsageBilling(turn.usage?.billing) : null;
settlementReady &&= turnId !== "unattributed" && turn.terminal && billing !== null
&& selectedBiller === billing.biller && turn.usage !== null && nativeUsageMeasurement(turn.usage).providerCostUsd === billing.amountUsd;
if (price === undefined) costIncomplete = true;
const direct = nativeHermesTokenAccounting(turn.usage, provider, selectedBiller);
const compatibleDirect = direct !== null && (!directAccounting || directAccounting.protocol === direct.protocol);
directAccountingReady &&= compatibleDirect;
if (direct) {
if (!compatibleDirect) { tokensComplete = false; complete = false; }
directAccounting = direct;
directRequests += direct.requestCount; directReported += direct.reportedRequestCount;
for (const key of Object.keys(directTokens) as (keyof typeof directTokens)[]) directTokens[key] += direct.tokens[key];
tokensComplete &&= direct.complete;
complete &&= direct.complete;
} else if (hermes && ["anthropic", "openai"].includes(selectedBiller ?? "")) {
tokensComplete = false; complete = false;
}
settlementReady &&= turnId !== "unattributed" && turn.terminal && ((billing !== null
&& selectedBiller === billing.biller && turn.usage !== null && nativeUsageMeasurement(turn.usage).providerCostUsd === billing.amountUsd) || direct !== null);
if (price === undefined) costIncomplete ||= !direct?.complete;
else {
cost += usdToUnits(billing?.amountUsdExact ?? price); costKnown = true;
if (billing) {
@@ -9593,6 +9612,12 @@ export function createNativeTurnAccounting(provider: NativeExecutionInput["provi
}
}
}
const aggregateSafe = [inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens,
inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens,
directRequests, directReported, ...Object.values(directTokens),
Object.values(directTokens).reduce((sum, value) => sum + value, 0)]
.every(value => Number.isSafeInteger(value) && value >= 0);
if (!aggregateSafe) { tokensComplete = false; complete = false; directAccountingReady = false; }
// A free empty attempt contributes no price evidence for later paid work.
// Keep an incomplete zero subtotal absent so complete aggregate tokens can
// still receive an estimate. Preserve positive known spend and true zero totals.
@@ -9602,13 +9627,17 @@ export function createNativeTurnAccounting(provider: NativeExecutionInput["provi
const current = currentTurn ? turns.get(currentTurn) : undefined;
const costExact = `${cost / 1_000_000_000n}.${String(cost % 1_000_000_000n).padStart(9, "0")}`;
return { usage: { runDelta, runDeltaComplete: hermes ? tokensComplete : true, accountingCostIncomplete: costIncomplete,
...(directAccountingReady && directAccounting && Number.isSafeInteger(directRequests) && Number.isSafeInteger(directReported)
? { tokenAccounting: { ...directAccounting, complete: tokensComplete, requestCount: directRequests, reportedRequestCount: directReported,
tokens: directTokens } } : {}),
...(retainCost && provider.kind === "acpx" && provider.agent === "hermes" ? { billing: {
schema: "paperclip.usage.billing/v1", source: "provider_reported", biller: "openrouter", currency: "USD",
complete: !costIncomplete, requestCount, reportedRequestCount,
amountUsd: Number(costExact), amountUsdExact: costExact,
} } : {}),
...(retainCost ? { accountingCostUsdExact: costExact } : {}) },
turnId: current && (normalizeNativeUsage(current.usage) || (settlementReady && readProviderUsageBilling(current.usage?.billing))) ? currentTurn : undefined,
turnId: current && (normalizeNativeUsage(current.usage) || (settlementReady
&& (readProviderUsageBilling(current.usage?.billing) || nativeHermesTokenAccounting(current.usage, provider, selectedBiller)))) ? currentTurn : undefined,
complete, settlementReady };
};
return {
@@ -9634,6 +9663,7 @@ export function createNativeTurnAccounting(provider: NativeExecutionInput["provi
const usage = record(payload.usage);
turn.usage = Object.hasOwn(usage, "runDelta")
? { runDelta: record(usage.runDelta), runDeltaComplete: usage.runDeltaComplete,
...(usage.tokenAccounting === undefined ? {} : { tokenAccounting: usage.tokenAccounting }),
...(usage.billing === undefined ? {} : { billing: usage.billing }) } : null;
}
if (terminal) turn.terminal = true;
@@ -9649,6 +9679,18 @@ export function createNativeTurnAccounting(provider: NativeExecutionInput["provi
};
}
/** Only this versioned, route/model-bound receipt certifies all direct API attempts. */
function nativeHermesTokenAccounting(usage: Record<string, unknown> | null, provider: NativeExecutionInput["provider"], selectedBiller?: string | null) {
if (provider.kind !== "acpx" || provider.agent !== "hermes" || !usage || usage.billing !== undefined) return null;
const receipt = readProviderTokenAccounting(usage.tokenAccounting);
if (!receipt || receipt.biller !== selectedBiller || receipt.model !== provider.model) return null;
// Incomplete receipts preserve settlement authority, but never certify a
// placeholder breakdown as complete tokens or a zero-cost estimate.
if (!receipt.complete) return receipt;
const measurement = nativeUsageMeasurement(usage);
return Object.entries(receipt.tokens).every(([key, value]) => measurement[key] === value) ? receipt : null;
}
export function nativeUsageCostUsd(
usage: Record<string, unknown> | null,
provider?: NativeExecutionInput["provider"],