Admit current ACP profiles and verify cross-language pin agreement

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-29 10:07:49 -05:00
1 parent 25de20d702
commit ec0991d4ba
4 files changed
+43 -6

No files matched your search

@@ -1,4 +1,5 @@
import { createHash } from "node:crypto";
import { QUALIFIED_ACPX_PROFILES } from "../drivers/acpx/qualified-profiles.js";
import { describe, expect, it } from "vitest";
import { buildNativeModelEnvelope, parseNativeExecutionInput, NATIVE_EXECUTION_INPUT_SCHEMA, type NativeExecutionInputV1 } from "./native-execution.js";
@@ -280,7 +281,7 @@ describe("NativeExecutionInputV1", () => {
})).toThrow("eventExpiryDays");
});
it.each([1, 2, 3, 4, 5] as const)("accepts only a closed ACPX profile matching the driver and agent at profile version %s", (agentProfileVersion) => {
it.each([1, 2, 3, 4, 5, 6] as const)("accepts only a closed ACPX profile matching the driver and agent at profile version %s", (agentProfileVersion) => {
const provider = {
kind: "acpx",
agent: "pi",
@@ -312,7 +313,7 @@ describe("NativeExecutionInputV1", () => {
profile: provider.profile,
});
expect(parseNativeExecutionInput(parsed)).toEqual(parsed);
for (const unsupportedVersion of [0, 6, 1.5, "5", null]) {
for (const unsupportedVersion of [0, 7, 1.5, "6", null]) {
expect(() => parseNativeExecutionInput({
...input,
session: { ...input.session, driverKind: "acpx_runtime" },
@@ -332,6 +333,26 @@ describe("NativeExecutionInputV1", () => {
})).toThrow("does not match");
});
it.each(Object.values(QUALIFIED_ACPX_PROFILES))(
"admits the current $agent profile through the native execution boundary",
(declaration) => {
const { qualificationModel, reportedModelId: _reported, permissionPolicy,
modelPolicy: _modelPolicy, qualificationStatus: _status, ...profile } = declaration;
const provider = {
kind: "acpx", agent: declaration.agent,
model: qualificationModel || "explicit-provider-model",
permissionPolicy, profile,
};
const parsed = parseNativeExecutionInput({
...input,
session: { ...input.session, driverKind: "acpx_runtime" },
provider,
});
expect(parsed.provider).toEqual(provider);
expect(parseNativeExecutionInput(parsed)).toEqual(parsed);
},
);
it("defaults legacy lifecycle state to per-turn and validates warm timeouts", () => {
const legacy = structuredClone(input) as Record<string, unknown>;
delete (legacy.session as Record<string, unknown>).lifecyclePolicy;
@@ -90,7 +90,7 @@ export interface NativeAcpxProfileSnapshot {
protocolVersion: 1;
acpxVersion: "0.13.1";
agent: NativeAcpxAgent;
agentProfileVersion: 1 | 2 | 3 | 4 | 5;
agentProfileVersion: 1 | 2 | 3 | 4 | 5 | 6;
agentServerPackage: string;
agentServerVersion: string;
agentRuntimePackage: string | null;
@@ -596,7 +596,7 @@ export function parseNativeExecutionInput(value: unknown): NativeExecutionInput
|| profile.protocolVersion !== 1
|| profile.acpxVersion !== "0.13.1"
|| profile.agent !== provider.agent
|| (profile.agentProfileVersion !== 1 && profile.agentProfileVersion !== 2 && profile.agentProfileVersion !== 3 && profile.agentProfileVersion !== 4 && profile.agentProfileVersion !== 5)
|| (profile.agentProfileVersion !== 1 && profile.agentProfileVersion !== 2 && profile.agentProfileVersion !== 3 && profile.agentProfileVersion !== 4 && profile.agentProfileVersion !== 5 && profile.agentProfileVersion !== 6)
) {
throw new NativeExecutionInputError("input.provider.profile does not match the qualified ACPX v1 profile");
}
@@ -1,4 +1,5 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import {
QUALIFIED_ACPX_PROFILES,
@@ -6,6 +7,21 @@ import {
} from "./qualified-profiles.js";
describe("qualified ACPX profiles", () => {
it.each(Object.values(QUALIFIED_ACPX_PROFILES))(
"keeps the Rust admission digest synchronized with the current $agent profile",
(profile) => {
const rust = readFileSync(new URL("../../../runner/crates/runner-core/src/acpx_provider_backend.rs", import.meta.url), "utf8");
const start = rust.indexOf(`"${profile.agent}" => (`);
expect(start).toBeGreaterThan(0);
const end = rust.indexOf("\n ),", start);
expect(end).toBeGreaterThan(start);
const admission = rust.slice(start, end);
expect(admission).toContain(JSON.stringify(profile.agentServerPackage));
expect(admission).toContain(JSON.stringify(profile.agentServerVersion));
expect(admission).toContain(JSON.stringify(profile.commandDigest));
},
);
it("binds each agent to one immutable package and model declaration", () => {
for (const agent of ["pi", "claude", "codex", "grok"] as const) {
const profile = QUALIFIED_ACPX_PROFILES[agent];
@@ -2,7 +2,7 @@ export const QUALIFIED_ACPX_VERSION = "0.13.1" as const;
export const ACPX_DRIVER_KIND = "acpx_runtime" as const;
export const ACPX_DRIVER_PROTOCOL_VERSION = 1 as const;
import type { NativeAcpxAgent } from "../../contracts/native-execution.js";
import type { NativeAcpxAgent, NativeAcpxProfileSnapshot } from "../../contracts/native-execution.js";
export type QualifiedAcpxAgent = NativeAcpxAgent;
@@ -11,7 +11,7 @@ export interface QualifiedAcpxProfile {
readonly protocolVersion: typeof ACPX_DRIVER_PROTOCOL_VERSION;
readonly acpxVersion: typeof QUALIFIED_ACPX_VERSION;
readonly agent: QualifiedAcpxAgent;
readonly agentProfileVersion: 1 | 2 | 3 | 4 | 5 | 6;
readonly agentProfileVersion: NativeAcpxProfileSnapshot["agentProfileVersion"];
readonly qualificationStatus?: "pending";
readonly modelPolicy?: "explicit-provider-verified";
/** Wire identity: an npm package name or a runner-owned builtin: identifier. */