fix(runner): project ACPX session identity

This commit is contained in:
Dotta 2026-09-02 23:46:08 -05:00
parent d582fbe1aa
commit a02087a5c1
3 changed files with 36 additions and 4 deletions

View File

@ -23,6 +23,7 @@ import {
type NormalizedAcpForm,
} from "../drivers/acpx/acp-question-adapter.js";
import { openCodexAcpxRuntime } from "../drivers/acpx/codex-runtime-adapter.js";
import { acpxProviderSessionIdentity } from "../drivers/acpx/recovery-identity.js";
import {
resolveQualifiedAcpxProfile,
type QualifiedAcpxAgent,
@ -282,7 +283,7 @@ async function dispatch(
startedAt: new Date().toISOString(),
});
return {
identity: opened.identity,
identity: acpxProviderSessionIdentity(openedHost.identity()),
sidecarPid: process.pid,
status: opened.status,
};
@ -397,7 +398,7 @@ async function dispatch(
if (request.command === "session.read") {
const activeHost = requireHost();
return {
identity: activeHost.identity(),
identity: acpxProviderSessionIdentity(activeHost.identity()),
status: sanitizeRuntimeStatus(
await readSidecarHostStatusWithin(activeHost),
),
@ -406,7 +407,7 @@ async function dispatch(
if (request.command === "session.snapshot") {
const activeHost = requireHost();
return {
identity: activeHost.identity(),
identity: acpxProviderSessionIdentity(activeHost.identity()),
status: sanitizeRuntimeStatus(
await readSidecarHostStatusWithin(activeHost),
),
@ -425,7 +426,7 @@ async function dispatch(
// still serialized, and retainActiveHostCleanup keeps admission closed
// until one sequential close proves ownership was released.
const activeHost = requireHost({ allowCleanupRetry: true });
const identity = activeHost.identity();
const identity = acpxProviderSessionIdentity(activeHost.identity());
await closeSidecarHostForCommand(
activeHost,
boundedOptionalText(request.params.reason, "Paperclip suspension", 4_000),

View File

@ -8,6 +8,7 @@ import { afterEach, describe, expect, it } from "vitest";
import { resolveQualifiedAcpxProfile } from "./qualified-profiles.js";
import {
ACPX_IDENTITY_RECORD_SCHEMA,
acpxProviderSessionIdentity,
createAcpxIdentityRecord,
createAcpxRecoveryBinding,
verifyExpectedAcpxIdentity,
@ -41,6 +42,18 @@ describe("ACPX recovery identity", () => {
normalizedSessionId: "session-1",
permissionMode: "approve-reads",
});
expect(acpxProviderSessionIdentity(record)).toEqual({
kind: "acpx",
normalizedSessionId: "session-1",
acpxRecordId: fixture.expected.acpxRecordId,
backendSessionId: fixture.expected.backendSessionId,
agentSessionId: fixture.expected.agentSessionId,
profileDigest: fixture.binding.profileDigest,
workspaceDigest: fixture.binding.workspaceDigest,
requestedModel: fixture.binding.requestedModel,
effectiveModel: fixture.binding.effectiveModel,
permissionMode: "approve-reads",
});
expect(() =>
verifyExpectedAcpxIdentity(fixture.expected, fixture.binding, record),
).not.toThrow();

View File

@ -114,6 +114,24 @@ export function createAcpxIdentityRecord(
};
}
/** Project the private persisted record into the PRP sidecar wire identity. */
export function acpxProviderSessionIdentity(
record: AcpxIdentityRecord,
): AcpxExpectedSessionIdentity {
return {
kind: "acpx",
normalizedSessionId: record.normalizedSessionId,
acpxRecordId: record.acpxRecordId,
backendSessionId: record.backendSessionId,
agentSessionId: record.agentSessionId,
profileDigest: record.profileDigest,
workspaceDigest: record.workspaceDigest,
requestedModel: record.requestedModel,
effectiveModel: record.effectiveModel,
permissionMode: record.permissionMode,
};
}
/**
* Verify both the controller-provided identity and a persisted runtime record.
* Only the complete v1 record is recoverable. Draft schema-less and