Bind candidate runtimes to task policy and separate Pi price estimates

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-28 11:35:14 -05:00
1 parent a5e26ecc04
commit 411df9fa58
7 files changed
+163 -14

No files matched your search

@@ -36,7 +36,7 @@ const validPath = (value: unknown): value is string => typeof value === "string"
export function parseNativeAcpxDistributionEntries(value: unknown, expectedSha256: string): NativeAcpxDistributionEntry[] {
if (!/^[a-f0-9]{64}$/.test(expectedSha256)) throw new Error("Native ACPX closure pin is invalid");
const entries = value !== null && typeof value === "object" ? (value as { entries?: unknown }).entries : undefined;
if (!Array.isArray(entries) || entries.length === 0 || entries.length > 10_000) throw new Error("Native ACPX closure inventory is invalid");
if (!Array.isArray(entries) || entries.length === 0 || entries.length > 30_000) throw new Error("Native ACPX closure inventory is invalid");
let total = 0;
let previous = "";
const parsed = entries.map(raw => {
@@ -0,0 +1,13 @@
import type { QualifiedAcpxAgent, QualifiedAcpxProfile } from "./qualified-profiles.js";
import { verifyQualifiedAcpxInstallation, type VerifiedAcpxInstallation } from "./installation-integrity.js";
/** Closed build-owned registry. Provider branches add their pinned installations here. */
export async function verifyAcpxProfileInstallation(profile: QualifiedAcpxProfile): Promise<VerifiedAcpxInstallation> {
if (profile.agent !== "claude" && profile.agent !== "codex") {
throw new Error(`ACPX ${profile.agent} verified candidate distribution is not installed in this build`);
}
return verifyQualifiedAcpxInstallation(profile);
}
/** Provider policy admission is repeated immediately before each process launch. */
export async function assertAcpxProfileWorkspace(_agent: QualifiedAcpxAgent, _workspace: string): Promise<void> {}
@@ -713,7 +713,7 @@ describe("ACPX runtime host", () => {
).rejects.toThrow();
});
it("rejects Pi before installation or runtime launch", async () => {
it("rejects Pi without an explicit task policy before installation or runtime launch", async () => {
const fixture = await hostFixture();
const verifyInstallation = vi.fn();
const openRuntime = vi.fn();
@@ -731,11 +731,37 @@ describe("ACPX runtime host", () => {
reportRetainedCleanupFailure: vi.fn(),
},
),
).rejects.toThrow("descriptor-confined verified launch");
).rejects.toThrow("explicit task execution policy");
expect(verifyInstallation).not.toHaveBeenCalled();
expect(openRuntime).not.toHaveBeenCalled();
});
it("binds Pi task policy independently of permissions and rejects an uninstalled candidate", async () => {
const fixture = await hostFixture();
const model = "openrouter/deepseek/deepseek-v4-flash-0731";
const profile = resolveQualifiedAcpxProfile("pi", model);
const openRuntime = vi.fn(async (options: AcpxRuntimePortOpenOptions) => {
expect(options.launchEnvironment.PAPERCLIP_PI_READ_ONLY).toBe("1");
expect(options.launchEnvironment.PAPERCLIP_PI_SYSTEM_INSTRUCTIONS).toBe("Bound instructions");
expect(JSON.parse(options.launchEnvironment.PAPERCLIP_PI_READ_ROOTS!)).toEqual([]);
expect(options.permissionMode).toBe("approve-all");
return runtimePort({ getStatus: async () => ({ models: { currentModelId: model } }) });
});
const options = { ...fixture.options, agent: "pi" as const, model,
permissionMode: "approve-all" as const, providerPolicy: { readOnly: true }, systemInstructions: "Bound instructions" };
await expect(AcpxRuntimeHost.open(options, { openRuntime, reportRetainedCleanupFailure: vi.fn() }))
.rejects.toThrow("verified candidate distribution is not installed");
expect(openRuntime).not.toHaveBeenCalled();
const host = await AcpxRuntimeHost.open(options, fixture.dependencies({
verifyInstallation: async () => ({ commandDigest: profile.commandDigest,
agentServerPackageJsonPath: join(fixture.root, "package.json"), agentRuntimePackageJsonPath: null,
openCommand: async () => ({ spawn: () => { throw new Error("not used"); }, close: async () => {} }),
}), openRuntime,
}));
await host.close({ reason: "policy verified" });
expect(openRuntime).toHaveBeenCalledOnce();
});
it("selects and verifies Claude's qualified reported model", async () => {
const fixture = await hostFixture();
let selected = false;
@@ -1,4 +1,6 @@
import { join } from "node:path";
import { dirname, join } from "node:path";
import { assertAcpxProfileWorkspace, verifyAcpxProfileInstallation } from "./profile-installation.js";
import { createAcpxRuntimeSkillLease } from "./runtime-skill-lease.js";
import { claudeNativeSkillPrompt } from "./native-skill-prompt.js";
import { nativeMcpLaunchBinding } from "../native-mcp.js";
@@ -26,7 +28,6 @@ import {
type AcpxProviderLifetimeLease,
} from "./codex-credentials.js";
import {
verifyQualifiedAcpxInstallation,
type VerifiedAcpxCommandLease,
type VerifiedAcpxInstallation,
} from "./installation-integrity.js";
@@ -51,6 +52,7 @@ import {
import {
prepareAcpxRuntimeSandbox,
type AcpxRuntimeSandbox,
type AcpxProviderRuntimePolicy,
} from "./runtime-sandbox.js";
import type { AcpxExpectedSessionIdentity } from "./sidecar-protocol.js";
@@ -179,7 +181,7 @@ export type AcpxSemanticToolSession = Omit<RunnerToolBridgeOptions, "secret">;
export interface AcpxRetainedCleanupFailure {
resource:
"credential" | "provider_lifetime" | "command" | "runtime" | "tool_bridge";
"credential" | "provider_lifetime" | "command" | "runtime" | "tool_bridge" | "skills";
attempt: number;
error: unknown;
}
@@ -211,6 +213,8 @@ export interface AcpxRuntimeHostDependencies {
}
export interface OpenAcpxRuntimeHostOptions {
/** Explicit task execution policy; never inferred from auto-approval. Required for Pi. */
providerPolicy?: AcpxProviderRuntimePolicy;
/** Never persisted as session options or recovery identity. */
clientCapabilities?: Record<string, unknown>;
runtimeDirectory: string;
@@ -303,10 +307,8 @@ export class AcpxRuntimeHost {
dependencies: AcpxRuntimeHostDependencies,
): Promise<AcpxRuntimeHost> {
options.signal?.throwIfAborted();
if (options.agent === "pi") {
throw new Error(
"ACPX pi is unavailable until its runtime has descriptor-confined verified launch",
);
if (options.agent === "pi" && typeof options.providerPolicy?.readOnly !== "boolean") {
throw new Error("Pi admission requires an explicit task execution policy");
}
const nativeMcp = nativeMcpLaunchBinding(options.environment);
if (nativeMcp?.name === "paperclip") {
@@ -345,7 +347,7 @@ export class AcpxRuntimeHost {
const installation = await runAbortableAdmissionStage(
options.signal,
() =>
(dependencies.verifyInstallation ?? verifyQualifiedAcpxInstallation)(
(dependencies.verifyInstallation ?? verifyAcpxProfileInstallation)(
profile,
),
dependencies.retainAdmissionCleanup,
@@ -403,6 +405,11 @@ export class AcpxRuntimeHost {
agent: options.agent,
environment: options.environment,
tools: options.semanticTools?.tools,
...(options.providerPolicy === undefined ? {} : { providerPolicy: {
...options.providerPolicy,
systemInstructions: boundedInstructions(options.systemInstructions),
protectedPaths: [...(options.providerPolicy.protectedPaths ?? []), dirname(installation.agentServerPackageJsonPath)],
} }),
}),
dependencies.retainAdmissionCleanup,
);
@@ -433,6 +440,29 @@ export class AcpxRuntimeHost {
dependencies.reportRetainedCleanupFailure(failure),
});
}
let launchEnvironment = sandbox.launchEnvironment;
if (options.agent === "pi") {
const skills = await acquireAbortableAdmissionResource({
signal: options.signal,
acquire: () => createAcpxRuntimeSkillLease(options.runtimeContext ?? null),
resource: "skills", releaseLate: value => value.close(),
reportFailure: dependencies.reportRetainedCleanupFailure,
});
const providerLifetime = credential;
credential = {
lifetimeFenceCandidates: providerLifetime.lifetimeFenceCandidates,
lifetimeFenceFds: providerLifetime.lifetimeFenceFds,
activateLifetimeOwner: pid => providerLifetime.activateLifetimeOwner(pid),
async close() {
// Only release assigned files after the provider lifetime quorum closes.
await providerLifetime.close();
await skills.close();
},
};
launchEnvironment = Object.freeze({ ...sandbox.launchEnvironment,
PAPERCLIP_PI_READ_ROOTS: JSON.stringify([...(options.providerPolicy?.readRoots ?? []), ...skills.readRoots]),
});
}
if (options.agent === "claude") {
// The lifetime lease proves the previous provider has stopped. Refresh
// the assigned snapshot before every launch, including durable resume;
@@ -474,8 +504,9 @@ export class AcpxRuntimeHost {
}
runtime = await acquireAbortableAdmissionResource({
signal: options.signal,
acquire: () => {
acquire: async () => {
options.assertWorkspaceHeld?.();
await assertAcpxProfileWorkspace(options.agent, binding.workspacePath);
return dependencies.openRuntime({
...(options.clientCapabilities === undefined ? {} : {
clientCapabilities: structuredClone(options.clientCapabilities),
@@ -490,7 +521,7 @@ export class AcpxRuntimeHost {
permissionPolicy: acpxRuntimePermissionPolicy(
binding.permissionMode,
),
launchEnvironment: sandbox.launchEnvironment,
launchEnvironment,
credentialFenceFds: admittedLifetime.lifetimeFenceFds,
activateCredentialFenceOwner:
admittedLifetime.activateLifetimeOwner.bind(admittedLifetime),
@@ -0,0 +1,22 @@
import { mkdtemp, realpath, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { NativeRuntimeContextSnapshot } from "../../contracts/runtime-context.js";
import { materializeNativeRuntimeSkills, releaseMaterializedNativeRuntimeSkills } from "../runtime-context-materializer.js";
/** Assigned assets live outside the protected credential/runtime tree. */
export async function createAcpxRuntimeSkillLease(context: NativeRuntimeContextSnapshot | null) {
const root = await realpath(await mkdtemp(join(tmpdir(), "paperclip-acpx-skills-")));
const skills = join(root, "skills");
const close = async () => {
await releaseMaterializedNativeRuntimeSkills(skills);
await rm(root, { recursive: true, force: true });
};
try {
await materializeNativeRuntimeSkills(context, skills);
return { readRoots: context?.skills.length ? [await realpath(skills)] : [], close };
} catch (error) {
await close();
throw error;
}
}
@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import {
persistedAcpxTurnUsage,
acpxUsageEstimateNotice,
qualifiedAcpxUsageBreakdown,
} from "./usage-accounting.js";
@@ -130,3 +131,30 @@ describe("persisted terminal ACPX usage", () => {
});
});
});
describe("Pi prompt accounting authority", () => {
const after = { lastRequestId: "turn", usageCost: { amount: 999, currency: "USD" }, requestTokenUsage: {
message: { input_tokens: 12, paperclip_pi: { provenance: "assistant_message_receipts", cost_usd: 0.123 } },
} };
it("preserves an exact new Pi receipt estimate without charging it as billed spend", () => {
const usage = persistedAcpxTurnUsage({}, after, "turn", "pi")!;
expect(usage.cost).toBeUndefined();
expect(usage.pricingEstimateUsd).toBe(0.123);
expect(acpxUsageEstimateNotice(usage, "turn:pricing")?.payload).toMatchObject({
category: "pi_usage_pricing_estimate", summary: expect.stringContaining("Billing cost is unverified"),
});
expect(persistedAcpxTurnUsage(after, after, "turn", "pi")).toBeNull();
});
it("ignores foreign, missing, invalid and unproven estimates", () => {
expect(persistedAcpxTurnUsage({}, after, "turn", "copilot")?.pricingEstimateUsd).toBeUndefined();
for (const receipt of [{}, { provenance: "other", cost_usd: 2 },
{ provenance: "assistant_message_receipts", cost_usd: -1 },
{ provenance: "assistant_message_receipts", cost_usd: Infinity }]) {
const usage = persistedAcpxTurnUsage({}, { ...after, requestTokenUsage: {
message: { input_tokens: 12, paperclip_pi: receipt },
} }, "turn", "pi")!;
expect(usage.cost).toBeUndefined();
expect(acpxUsageEstimateNotice(usage, "turn:pricing")).toBeNull();
}
});
});
@@ -1,3 +1,4 @@
import type { CanonicalProviderEvent } from "../../provider-events.js";
import type { QualifiedAcpxAgent } from "./qualified-profiles.js";
function record(value: unknown): Record<string, unknown> {
@@ -37,6 +38,7 @@ export function persistedAcpxTurnUsage(
before: unknown,
after: unknown,
requestId: string,
agent: QualifiedAcpxAgent | null = null,
): Record<string, unknown> | null {
const current = record(after);
if (current.lastRequestId !== requestId) return null;
@@ -47,11 +49,19 @@ export function persistedAcpxTurnUsage(
);
if (added.length !== 1) return null;
const usage = record(receipts[added[0]!]);
const piReceipt = agent === "pi" ? record(usage.paperclip_pi) : {};
const piReceiptVerified = piReceipt.provenance === "assistant_message_receipts";
const estimate = piReceiptVerified && typeof piReceipt.cost_usd === "number"
&& Number.isFinite(piReceipt.cost_usd) && piReceipt.cost_usd >= 0 ? piReceipt.cost_usd : undefined;
return {
type: "status",
tag: "usage_update",
text: "terminal prompt usage",
cost: current.usageCost,
// Pi calculates cost from catalog prices, not billing receipts. Never feed
// this estimate into the authoritative/cumulative provider spend channel.
cost: agent === "pi" ? undefined : current.usageCost,
...(piReceiptVerified ? { usageProvenance: "pi_assistant_message_receipts" } : {}),
...(estimate === undefined ? {} : { pricingEstimateUsd: estimate }),
breakdown: {
inputTokens: usage.input_tokens,
outputTokens: usage.output_tokens,
@@ -62,3 +72,22 @@ export function persistedAcpxTurnUsage(
},
};
}
/** Preserve the estimate for inspection while keeping billing authority separate. */
export function acpxUsageEstimateNotice(usage: Record<string, unknown>, itemId: string): CanonicalProviderEvent | null {
if (usage.usageProvenance !== "pi_assistant_message_receipts"
|| typeof usage.pricingEstimateUsd !== "number" || !Number.isFinite(usage.pricingEstimateUsd)
|| usage.pricingEstimateUsd < 0) return null;
return {
eventType: "provider.notice.recorded", itemId,
payload: {
schema: "paperclip.provider.notice.v1", noticeId: itemId,
severity: "info", category: "pi_usage_pricing_estimate", scope: "turn",
recoverable: true, userActionable: false,
summary: `Pi estimates this turn at $${usage.pricingEstimateUsd.toFixed(6)} from its model prices. Billing cost is unverified.`,
details: [{ name: "Cost source", value: "Pi model catalog pricing estimate" },
{ name: "Usage source", value: "Assistant message receipts for this prompt" },
{ name: "Estimated USD", value: String(usage.pricingEstimateUsd) }],
},
};
}