mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-30 05:16:50 +01:00
Replay Claude native options on ACP reconnect (#18135)
## Thinking Path > - Paperclip manages agents and their task execution. > - Runner uses ACPX to connect to Claude sessions. > - Claude receives native options when ACPX creates a session. > - ACPX omits those options when it loads or resumes the same session. > - A reconnect can lose allowed tools, instructions, and settings sources. > - This pull request replays the existing options through the existing Claude metadata contract. > - Resumed tasks keep the configuration admitted for their session. ## Linked Issues or Issue Description **What happened?** A Claude task can complete its first turn and then fail on a warm follow-up. The provider refuses an internal completion tool because `session/load` omits the `allowedTools` options sent with `session/new`. The same omission exists on `session/resume`. **Expected behavior** Creation, load, and resume must supply the same caller-selected native session options. The existing policy for native user settings must stay unchanged. **Steps to reproduce** Create a persistent Claude ACP session with an explicit allowed-tool list and appended instructions. Complete a turn, close its connection, and reconnect to the saved session. Inspect the ACP request. Before this change, the reconnect has no `_meta` field. **Paperclip version or commit** Reproduced on Runner source `e8b78cce5bb557b086bee9ca930eeaab1d09b244`. The offline protocol regression also fails on the current base `80a2b9284bf189e93ca4313085814548f48b8dc8`. Related: #18089 added prepared harness storage. #11798 concerns the separate legacy adapter and does not fix Runner reconnect metadata. ## Upstream status and backport scope ACPX [0.21.1](https://github.com/openclaw/acpx/releases/tag/v0.21.1) already replays session metadata on load and resume in its [released client implementation](https://github.com/openclaw/acpx/blob/v0.21.1/src/acp/client.ts). This PR backports that behavior to the currently qualified 0.13.1 integration. The released 0.21.1 runtime does not expose equivalents for all hooks used by Runner's existing patch: verified executable spawning, synchronous protocol admission guards, provider extension dispatch, and response-delivery receipts. Upgrading requires a compatibility pass that preserves these guarantees and removes local changes already covered upstream. This backport does not add a new Paperclip-specific dependency contract. ## What Changed - Replay existing Claude native options on `session/load` and `session/resume` through the same metadata builder used at creation. Other providers keep their existing reconnect requests. - Test both reconnect methods against the installed ACPX manager and a local ACP wire fixture. Cover allowed tools, model, turn limit, instructions, and both existing settings-source modes. - Update exact source attestations and generated profile declarations required by the shared ACPX patch. Keep historical fixtures unchanged. - Document the reconnect contract. No new home mode, plugin policy, or provider permission rule is added. ## Verification - Confirmed the new load and resume tests fail before the patch because metadata is absent. - Applied the canonical patch to pristine package bytes and confirmed it matches the tested runtime. - Targeted installed-package model-selection and reconnect suite plus changed Grok identity tests: 22 passed. - Rechecked the four new reconnect cases against the cleanly applied patch, with explicit expected values for all supplied options. - Three targeted current-profile and revision-boundary assertions pass locally. Updated the native Pi test digest; native compilation and execution remain in CI. - Maintained profile generators pass their consistency checks. - GitHub CI is green, including typecheck, native Runner checks, package contracts, packaged installation, build, and server/browser suites. One unrelated server database-cleanup timeout passed on the bounded failed-job rerun. No comprehensive local suite was run. Live post-deployment acceptance remains pending. ## Risks Claude reconnects now receive the same native settings sources and options as creation. This corrects configuration loss without changing caller policy. The shared dependency patch requires new source identities for other attested profiles; their reconnect behavior is unchanged. No database migration is required. ## Model Used OpenAI Codex, GPT-6 family, with code and tool use. Exact deployment ID and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
df6156c2e3
commit
aa75ec9d56
20 files changed
+315
-81
No files matched your search
@@ -857,7 +857,9 @@ Prepare authentication, skills, and external MCP servers on the execution machin
|
||||
before launching. Runner does not install skills, copy or remove credentials, or
|
||||
rewrite user configuration in this mode. Providers can still refresh credentials
|
||||
and update their own metadata. Runner still supplies the requested
|
||||
model, task instructions, and its internal task/completion tools. Local permission
|
||||
model, task instructions, and its internal task/completion tools. Claude session
|
||||
loads and resumes receive the same native session options as session creation,
|
||||
including allowed tools and the selected settings sources. Local permission
|
||||
rules and hooks apply. Native Codex tools can read and modify the execution home
|
||||
(read-only for planning); credentials in that home are not isolated from tools.
|
||||
Native Codex separately denies Runner-owned protocol state; ACPX Claude retains
|
||||
|
||||
@@ -5,39 +5,39 @@
|
||||
"protocolVersion": 1,
|
||||
"profiles": {
|
||||
"grok": {
|
||||
"agentProfileVersion": 10,
|
||||
"agentProfileVersion": 11,
|
||||
"agentServerPackage": "builtin:grok-acp",
|
||||
"agentServerVersion": "1",
|
||||
"agentRuntimePackage": "native:grok",
|
||||
"agentRuntimeVersion": "1.0.13",
|
||||
"commandDigest": "sha256:2dccee3800dada11b65692e5cf591e3667a123cba2fbf5629a937f731043b423",
|
||||
"commandDigest": "sha256:f43a6f5a583972cdcb422784969cd6a97654655b0f135f1cf178317909c404f8",
|
||||
"requiresProviderPolicy": false
|
||||
},
|
||||
"pi": {
|
||||
"agentProfileVersion": 32,
|
||||
"agentProfileVersion": 33,
|
||||
"agentServerPackage": "pi-acp",
|
||||
"agentServerVersion": "0.0.33",
|
||||
"agentRuntimePackage": "@earendil-works/pi-coding-agent",
|
||||
"agentRuntimeVersion": "1.0.0",
|
||||
"commandDigest": "sha256:ce13b75699331c813f8a42f2803c3e0e0fb1e6d24847452cb12b50d6ed2d0baf",
|
||||
"commandDigest": "sha256:0260d5810e9247986800ad46c1f9b3511a5abd06cb8f142405d5caacbc3960fc",
|
||||
"requiresProviderPolicy": true
|
||||
},
|
||||
"cursor": {
|
||||
"agentProfileVersion": 15,
|
||||
"agentProfileVersion": 16,
|
||||
"agentServerPackage": "cursor-agent",
|
||||
"agentServerVersion": "2026.09.26-dd393fe",
|
||||
"agentRuntimePackage": null,
|
||||
"agentRuntimeVersion": null,
|
||||
"commandDigest": "sha256:ac8092119542c8fbe95dae18ba5ef4d3689803fec56b7d2735fa193eea42f59b",
|
||||
"commandDigest": "sha256:759e7415fea8ed2b6b0e6f362b57652b8768835f9d1fdae4a94c1b5eb3669301",
|
||||
"requiresProviderPolicy": true
|
||||
},
|
||||
"copilot": {
|
||||
"agentProfileVersion": 78,
|
||||
"agentProfileVersion": 79,
|
||||
"agentServerPackage": "@github/copilot",
|
||||
"agentServerVersion": "1.0.88",
|
||||
"agentRuntimePackage": null,
|
||||
"agentRuntimeVersion": null,
|
||||
"commandDigest": "sha256:f7e7cff356db4b1b37458bd62fd76e9d81aa1cc46795e54b168755fb68bcee8c",
|
||||
"commandDigest": "sha256:a0e9f339935f6ee616fee644c45cb09353e9aed1d1f22215739f9504153ceca1",
|
||||
"requiresProviderPolicy": true
|
||||
},
|
||||
"claude": {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"schema": "paperclip.cursor.production-contract.v1",
|
||||
"profileVersion": 15,
|
||||
"profileVersion": 16,
|
||||
"sourceSnapshot": "22c78242a4e0c2369fecf0c2dc4e7600fbad6706",
|
||||
"base": "dd868ed125cd709506dd9b29fca640a44d580501",
|
||||
"vendor": "2026.09.26-dd393fe",
|
||||
"nativePatch": "paperclip-cursor-usage-v4",
|
||||
"acpxPatchSha256": "00d6af17216cb0cad902b48633eb19bf0ec6b05837a984cb24661fca593f09c1",
|
||||
"acpxPatchSha256": "1e7dae8c83bf8620f53f2bea13c175eeff95e7e955783f6f529bb1dcbdcdb6d2",
|
||||
"publicSetup": "paperclipai runtime setup cursor",
|
||||
"assets": "public-server-and-provider-pack",
|
||||
"modes": [
|
||||
@@ -19,5 +19,5 @@
|
||||
"planAcceptance": "successful-run-open-task-explicit-continuation",
|
||||
"otherProviders": "mainline-gated",
|
||||
"modelSelection": "explicit-provider-verified-startup-and-reconnect",
|
||||
"commandDigest": "sha256:ac8092119542c8fbe95dae18ba5ef4d3689803fec56b7d2735fa193eea42f59b"
|
||||
"commandDigest": "sha256:759e7415fea8ed2b6b0e6f362b57652b8768835f9d1fdae4a94c1b5eb3669301"
|
||||
}
|
||||
@@ -3246,7 +3246,7 @@ mod tests {
|
||||
#[test]
|
||||
fn pi_profile_matches_published_identity_and_rejects_prior_profiles() {
|
||||
let published: Value = serde_json::from_str(include_str!(
|
||||
"../../../../test-fixtures/pi-acp/profile-v32-identity.json"
|
||||
"../../../../test-fixtures/pi-acp/profile-v33-identity.json"
|
||||
))
|
||||
.unwrap();
|
||||
let mut value = descriptor("codex");
|
||||
|
||||
@@ -20,7 +20,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option<AcpxReleaseProfile> {
|
||||
agent_runtime_package: Some("native:grok"),
|
||||
agent_runtime_version: Some("1.0.13"),
|
||||
command_digest:
|
||||
"sha256:2dccee3800dada11b65692e5cf591e3667a123cba2fbf5629a937f731043b423",
|
||||
"sha256:f43a6f5a583972cdcb422784969cd6a97654655b0f135f1cf178317909c404f8",
|
||||
requires_provider_policy: false,
|
||||
},
|
||||
"pi" => AcpxReleaseProfile {
|
||||
@@ -29,7 +29,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option<AcpxReleaseProfile> {
|
||||
agent_runtime_package: Some("@earendil-works/pi-coding-agent"),
|
||||
agent_runtime_version: Some("1.0.0"),
|
||||
command_digest:
|
||||
"sha256:ce13b75699331c813f8a42f2803c3e0e0fb1e6d24847452cb12b50d6ed2d0baf",
|
||||
"sha256:0260d5810e9247986800ad46c1f9b3511a5abd06cb8f142405d5caacbc3960fc",
|
||||
requires_provider_policy: true,
|
||||
},
|
||||
"cursor" => AcpxReleaseProfile {
|
||||
@@ -38,7 +38,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option<AcpxReleaseProfile> {
|
||||
agent_runtime_package: None,
|
||||
agent_runtime_version: None,
|
||||
command_digest:
|
||||
"sha256:ac8092119542c8fbe95dae18ba5ef4d3689803fec56b7d2735fa193eea42f59b",
|
||||
"sha256:759e7415fea8ed2b6b0e6f362b57652b8768835f9d1fdae4a94c1b5eb3669301",
|
||||
requires_provider_policy: true,
|
||||
},
|
||||
"copilot" => AcpxReleaseProfile {
|
||||
@@ -47,7 +47,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option<AcpxReleaseProfile> {
|
||||
agent_runtime_package: None,
|
||||
agent_runtime_version: None,
|
||||
command_digest:
|
||||
"sha256:f7e7cff356db4b1b37458bd62fd76e9d81aa1cc46795e54b168755fb68bcee8c",
|
||||
"sha256:a0e9f339935f6ee616fee644c45cb09353e9aed1d1f22215739f9504153ceca1",
|
||||
requires_provider_policy: true,
|
||||
},
|
||||
"claude" => AcpxReleaseProfile {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ use sha2::{Digest, Sha256};
|
||||
const CODEX_ACPX_DIGEST: &str =
|
||||
"sha256:443491f4e814501a5dc47347e4510e84faeec9c9382e2d4e53bfe69386d5aabc";
|
||||
const PI_ACPX_DIGEST: &str =
|
||||
"sha256:ce13b75699331c813f8a42f2803c3e0e0fb1e6d24847452cb12b50d6ed2d0baf";
|
||||
"sha256:0260d5810e9247986800ad46c1f9b3511a5abd06cb8f142405d5caacbc3960fc";
|
||||
|
||||
fn temporary_directory(label: &str) -> PathBuf {
|
||||
let nonce = SystemTime::now()
|
||||
|
||||
@@ -7,9 +7,9 @@ import { fileURLToPath } from "node:url";
|
||||
import { resolve, dirname } from "node:path";
|
||||
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const fixture = resolve(root, "test/fixtures/copilot-profile-v78-identity.json");
|
||||
const fixture = resolve(root, "test/fixtures/copilot-profile-v79-identity.json");
|
||||
const historical = JSON.parse(readFileSync(resolve(root, "test/fixtures/copilot-profile-v12-identity.json"), "utf8"));
|
||||
const declaration = { ...historical.declaration, agentProfileVersion: 78 };
|
||||
const declaration = { ...historical.declaration, agentProfileVersion: 79 };
|
||||
delete declaration.permissionIdentitySourceSha256;
|
||||
const sources = {
|
||||
displayEventSourceSha256: "src/drivers/acpx/copilot-events.ts",
|
||||
|
||||
@@ -7,9 +7,9 @@ import { fileURLToPath } from "node:url";
|
||||
|
||||
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const repositoryRoot = resolve(packageRoot, "../..");
|
||||
// Versions 1–9 remain decodable historical identities. Versioned fixtures are
|
||||
// Versions 1–10 remain decodable historical identities. Versioned fixtures are
|
||||
// immutable; advance this version before changing a versioned declaration.
|
||||
export const GROK_PROFILE_VERSION = 10;
|
||||
export const GROK_PROFILE_VERSION = 11;
|
||||
// Contract surfaces: ACPX wire patch; sidecar parsing and error translation;
|
||||
// native effort/search/credential admission; host/sandbox/tool-bridge execution;
|
||||
// launcher integrity and platform pins; Rust descriptor writes, session state,
|
||||
|
||||
@@ -87,9 +87,9 @@ vi.mock("./installation-integrity.js", () => ({ verifyNativeAcpxInstallation: vi
|
||||
|
||||
describe("Copilot build-owned installation", () => {
|
||||
it("admits the current profile with environment launch preparation", () => {
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.agentProfileVersion).toBe(78);
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.agentProfileVersion).toBe(79);
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.qualificationStatus).toBeUndefined();
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.commandDigest).toBe("sha256:f7e7cff356db4b1b37458bd62fd76e9d81aa1cc46795e54b168755fb68bcee8c");
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.commandDigest).toBe("sha256:a0e9f339935f6ee616fee644c45cb09353e9aed1d1f22215739f9504153ceca1");
|
||||
});
|
||||
|
||||
it("retains the published profile 75 fixture while advancing the event contract", async () => {
|
||||
|
||||
@@ -9,12 +9,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = {
|
||||
"protocolVersion": 1,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agent": "grok",
|
||||
"agentProfileVersion": 10,
|
||||
"agentProfileVersion": 11,
|
||||
"agentServerPackage": "builtin:grok-acp",
|
||||
"agentServerVersion": "1",
|
||||
"agentRuntimePackage": "native:grok",
|
||||
"agentRuntimeVersion": "1.0.13",
|
||||
"commandDigest": "sha256:2dccee3800dada11b65692e5cf591e3667a123cba2fbf5629a937f731043b423",
|
||||
"commandDigest": "sha256:f43a6f5a583972cdcb422784969cd6a97654655b0f135f1cf178317909c404f8",
|
||||
"permissionPolicy": "interactive"
|
||||
},
|
||||
"pi": {
|
||||
@@ -22,12 +22,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = {
|
||||
"protocolVersion": 1,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agent": "pi",
|
||||
"agentProfileVersion": 32,
|
||||
"agentProfileVersion": 33,
|
||||
"agentServerPackage": "pi-acp",
|
||||
"agentServerVersion": "0.0.33",
|
||||
"agentRuntimePackage": "@earendil-works/pi-coding-agent",
|
||||
"agentRuntimeVersion": "1.0.0",
|
||||
"commandDigest": "sha256:ce13b75699331c813f8a42f2803c3e0e0fb1e6d24847452cb12b50d6ed2d0baf",
|
||||
"commandDigest": "sha256:0260d5810e9247986800ad46c1f9b3511a5abd06cb8f142405d5caacbc3960fc",
|
||||
"permissionPolicy": "interactive"
|
||||
},
|
||||
"cursor": {
|
||||
@@ -35,12 +35,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = {
|
||||
"protocolVersion": 1,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agent": "cursor",
|
||||
"agentProfileVersion": 15,
|
||||
"agentProfileVersion": 16,
|
||||
"agentServerPackage": "cursor-agent",
|
||||
"agentServerVersion": "2026.09.26-dd393fe",
|
||||
"agentRuntimePackage": null,
|
||||
"agentRuntimeVersion": null,
|
||||
"commandDigest": "sha256:ac8092119542c8fbe95dae18ba5ef4d3689803fec56b7d2735fa193eea42f59b",
|
||||
"commandDigest": "sha256:759e7415fea8ed2b6b0e6f362b57652b8768835f9d1fdae4a94c1b5eb3669301",
|
||||
"permissionPolicy": "interactive"
|
||||
},
|
||||
"copilot": {
|
||||
@@ -48,12 +48,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = {
|
||||
"protocolVersion": 1,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agent": "copilot",
|
||||
"agentProfileVersion": 78,
|
||||
"agentProfileVersion": 79,
|
||||
"agentServerPackage": "@github/copilot",
|
||||
"agentServerVersion": "1.0.88",
|
||||
"agentRuntimePackage": null,
|
||||
"agentRuntimeVersion": null,
|
||||
"commandDigest": "sha256:f7e7cff356db4b1b37458bd62fd76e9d81aa1cc46795e54b168755fb68bcee8c",
|
||||
"commandDigest": "sha256:a0e9f339935f6ee616fee644c45cb09353e9aed1d1f22215739f9504153ceca1",
|
||||
"permissionPolicy": "interactive"
|
||||
},
|
||||
"claude": {
|
||||
|
||||
@@ -210,21 +210,21 @@ describe("Pi installation factory", () => {
|
||||
|
||||
it("rejects legacy profiles and tampered executable identities", () => {
|
||||
expect(() => assertPiInstallationProfile(candidate())).not.toThrow();
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 1 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 2 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 3 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 4 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 5 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 6 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 7 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 8 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 9 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 10 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 11 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 12 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 13 })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 14 })).toThrow("version 32");
|
||||
for (const priorVersion of [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: priorVersion })).toThrow("version 32");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 1 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 2 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 3 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 4 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 5 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 6 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 7 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 8 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 9 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 10 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 11 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 12 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 13 })).toThrow("version 33");
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 14 })).toThrow("version 33");
|
||||
for (const priorVersion of [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: priorVersion })).toThrow("version 33");
|
||||
for (const changed of [{ agentServerVersion: "latest" }, { commandDigest: `sha256:${"0".repeat(64)}` }, { agentRuntimePackage: "ambient-pi" }]) {
|
||||
expect(() => assertPiInstallationProfile({ ...candidate(), ...changed })).toThrow("trusted declaration");
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ describe("historical ACPX profile decoding", () => {
|
||||
expect(isSupportedAcpxProfileVersion("pi", 18)).toBe(true);
|
||||
expect(isSupportedAcpxProfileVersion("pi", 23)).toBe(true);
|
||||
expect(isSupportedAcpxProfileVersion("cursor", 15)).toBe(true);
|
||||
expect(isSupportedAcpxProfileVersion("cursor", 16)).toBe(false);
|
||||
expect(isSupportedAcpxProfileVersion("cursor", 16)).toBe(true);
|
||||
expect(isSupportedAcpxProfileVersion("cursor", 17)).toBe(false);
|
||||
for (const agent of ["pi", "copilot"]) {
|
||||
expect(isSupportedAcpxProfileVersion(agent, 16)).toBe(true);
|
||||
const current = QUALIFIED_ACPX_PROFILE_DATA[agent as "pi" | "copilot"].agentProfileVersion;
|
||||
|
||||
@@ -2,13 +2,13 @@ import { QUALIFIED_ACPX_PROFILE_DATA } from "./generated-profiles.js";
|
||||
|
||||
/** Decodable historical profile revisions, not permission to launch them.
|
||||
* Exact current profile/package/digest admission is checked separately. */
|
||||
type HistoricalAcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77;
|
||||
type HistoricalAcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78;
|
||||
type CurrentAcpxProfileVersion = typeof QUALIFIED_ACPX_PROFILE_DATA[keyof typeof QUALIFIED_ACPX_PROFILE_DATA]["agentProfileVersion"];
|
||||
export type AcpxProfileVersion = HistoricalAcpxProfileVersion | CurrentAcpxProfileVersion;
|
||||
|
||||
const historicalVersions: Readonly<Record<string, readonly HistoricalAcpxProfileVersion[]>> = {
|
||||
pi: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], claude: [1, 2, 3, 4, 5], codex: [1, 2, 3, 4, 5],
|
||||
grok: [1, 2, 3, 4, 5, 6, 7, 8, 9], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77],
|
||||
pi: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], claude: [1, 2, 3, 4, 5], codex: [1, 2, 3, 4, 5],
|
||||
grok: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78],
|
||||
cursor: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Grok admission source identity: sha256:1fec0323461ed2e0b1d0172d205237ba23316a7e6a89c325b6eb3be907e373e3
|
||||
// Grok admission source identity: sha256:c5a4628adcdd9190c45558f42014b0055698b8f8c7eb301417238f38d913f503
|
||||
// This launcher is admitted by digest and receives a verified native executable.
|
||||
// Never resolve an executable through PATH or accept command-line overrides.
|
||||
const { isAbsolute, join } = require("node:path");
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"commandDigest": "sha256:0260d5810e9247986800ad46c1f9b3511a5abd06cb8f142405d5caacbc3960fc",
|
||||
"declaration": {
|
||||
"schema": "paperclip.acpx_profile_declaration.v1",
|
||||
"agent": "pi",
|
||||
"agentProfileVersion": 33,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agentServerVersion": "0.0.33",
|
||||
"agentRuntimeVersion": "1.0.0",
|
||||
"nodeVersion": "24.21.0",
|
||||
"closure": {
|
||||
"darwin-arm64": "282022db10150c6632b3444df421342e7d534bdf5d5fb1097a2e79d0625a2bcf",
|
||||
"darwin-x64": "64e251e19009f755c0b04f73ce2138246faab71a961b0f13d75ebfcc34bef12e",
|
||||
"linux-x64": "713b1fdff42fb56a1518bdc084f181d70bee8ebadc3e4b1d76321ed9108c8410"
|
||||
},
|
||||
"wrapperSha256": "9d129b3d38772e93e97080aa6c4e574ac5df4e47ce5bc331a484a9fbf8188b36",
|
||||
"helperSha256": "41e0490b617da0d60e0c8ec58ef311236f945129d99f816cff6897f78da7f91d",
|
||||
"extensionSha256": "f5818573a355702388072b28926897db546a5cf346b5171f646582ce5f9102a4",
|
||||
"agentFilesBinding": "registered-runtime-context-v1",
|
||||
"nativeQuestions": "select-confirm-input-editor-v4-root-field-types",
|
||||
"pathPolicy": "sdk-normalization-v1",
|
||||
"mcpToolNames": "provider-safe-exact-source-v1",
|
||||
"acpxPatchSha256": "1e7dae8c83bf8620f53f2bea13c175eeff95e7e955783f6f529bb1dcbdcdb6d2",
|
||||
"nativeAssistantMessages": "pi1-rpc-deltas-v3-bound-message-and-tool-receipts",
|
||||
"nativeNotices": "session-extension-v2-bounded-runtime-failure",
|
||||
"messageProjectionSha256": "17d1e91b948dfa6a56e1905645add52b502041ad843c8d50a13b07956f22aadd",
|
||||
"noticeProjectionSha256": "014485adc690998e395d334ea3ae67f72be6060a2fc78a1185df7b8d1da28fbf",
|
||||
"sharedRuntimeContract": "paperclip.acpx-runtime-contract.v1",
|
||||
"nativeInputDisposition": "queued-only-v1",
|
||||
"cacheWarming": "disabled-owned-decision-v1",
|
||||
"thinkingLevel": {
|
||||
"supported": [
|
||||
"off",
|
||||
"low",
|
||||
"high",
|
||||
"max"
|
||||
],
|
||||
"newConfigurationDefault": "low",
|
||||
"admission": "explicit-native-effective-before-prompt-v1",
|
||||
"recovery": "mode-bound-v1"
|
||||
},
|
||||
"modelSelection": "caller-selected-native-verified-v1",
|
||||
"providerConfigurationSourceSha256": "75a9a13f13f224dc092bd8ebf49e8747162172943761e44476c8eb18d80c52d4",
|
||||
"credentialEnvironmentSourceSha256": "3a93267146bfc3c489f43262386d6dcb05ec4e3a8b1765414cd43d80d0c64d4a",
|
||||
"runtimeSandboxSourceSha256": "04a49a24e3828ce8fca908de15e31ae932b8b1b4f7ecec0308627f6a8da9ba20",
|
||||
"recoveryIdentitySourceSha256": "f74d061cc07b0c7ca04df62ca991d940a733d9ef6594b3362451769fc10030b8",
|
||||
"nativeCancellation": "acknowledged-cancelled-terminal-preserves-usage-v1",
|
||||
"dependencySecurityPatchSha256": "5273a195b952f233336122842faaf650193c04f36b9359d20d4d63079b0ce814",
|
||||
"openRouterAttributionSourceSha256": "1211191529d6073b733b311c3d69cada4973eede0f3e540c46e261f78e0b90f9",
|
||||
"preparedHarnessHomeSourceSha256": "bb286f7ddc6e9597c56d46bf7ff6e3b556c5b680d7e147fd46518724432b083e"
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,8 @@ async function fixture(t, agent, behavior = {}) {
|
||||
options:[{value:'advertised-model',name:'Advertised'},{value:'custom/model[variant=x]',name:'Variant'}]}];
|
||||
readline.createInterface({input:process.stdin}).on('line',line=>{
|
||||
const m=JSON.parse(line);
|
||||
if(m.method==='initialize') send({id:m.id,result:{protocolVersion:1,agentCapabilities:{loadSession:true},authMethods:[]}});
|
||||
else if(m.method==='session/new'||m.method==='session/load') send({id:m.id,result:{sessionId:'session-1',
|
||||
if(m.method==='initialize') send({id:m.id,result:{protocolVersion:1,agentCapabilities:${JSON.stringify({loadSession:true,...(behavior.resume ? {sessionCapabilities:{resume:{}}} : {})})},authMethods:[]}});
|
||||
else if(m.method==='session/new'||m.method==='session/load'||m.method==='session/resume') send({id:m.id,result:{sessionId:'session-1',
|
||||
...(${JSON.stringify(response === "missing")} ? {} : {configOptions:config(${JSON.stringify(behavior.currentModel ?? "default")}),
|
||||
models:{currentModelId:${JSON.stringify(behavior.currentModel ?? "default")},availableModels:[{modelId:'advertised-model',name:'Advertised'},{modelId:'custom/model[variant=x]',name:'Variant'}]}})}});
|
||||
else if(m.method==='session/set_config_option') {
|
||||
@@ -72,7 +72,7 @@ async function fixture(t, agent, behavior = {}) {
|
||||
async open() {
|
||||
const runtime = createAcpRuntime(options), owner = { runtime, handle: null };
|
||||
runtimes.push(owner);
|
||||
owner.handle = await runtime.ensureSession({ sessionKey: "model-selection", agent, mode: "persistent", cwd, sessionOptions: { model: selectedModel } });
|
||||
owner.handle = await runtime.ensureSession({ sessionKey: "model-selection", agent, mode: "persistent", cwd, sessionOptions: { model: selectedModel, ...behavior.sessionOptions } });
|
||||
return owner;
|
||||
},
|
||||
async prompt(owner) {
|
||||
@@ -143,3 +143,28 @@ test("Cursor command detection never expands a model into an advertised variant"
|
||||
assert.equal((await f.prompt(owner)).status, "completed");
|
||||
assert.deepEqual(f.selected(), [selectedModel]);
|
||||
});
|
||||
|
||||
for (const includeUserSettings of [false, true]) for (const resume of [false, true]) test(`Claude ${resume ? "resume" : "load"} preserves native session options (user settings ${includeUserSettings})`, { timeout: 10_000 }, async t => {
|
||||
const prior = process.env.ACPX_CLAUDE_INCLUDE_USER_SETTINGS;
|
||||
if (includeUserSettings) process.env.ACPX_CLAUDE_INCLUDE_USER_SETTINGS = "1";
|
||||
else delete process.env.ACPX_CLAUDE_INCLUDE_USER_SETTINGS;
|
||||
t.after(() => { if (prior === undefined) delete process.env.ACPX_CLAUDE_INCLUDE_USER_SETTINGS; else process.env.ACPX_CLAUDE_INCLUDE_USER_SETTINGS = prior; });
|
||||
const f = await fixture(t, "claude", {
|
||||
resume, agentCommand: "/paperclip-verified/claude-agent-acp",
|
||||
sessionOptions: { allowedTools: ["mcp__fixture__*"], maxTurns: 5, systemPrompt: { append: "Fixture instructions" } },
|
||||
});
|
||||
const first = await f.open();
|
||||
assert.equal((await f.prompt(first)).status, "completed");
|
||||
await f.close(first);
|
||||
const second = await f.open();
|
||||
assert.equal((await f.prompt(second)).status, "completed");
|
||||
const created = f.requests.find(r => r.method === "session/new");
|
||||
const restored = f.requests.find(r => r.method === (resume ? "session/resume" : "session/load"));
|
||||
assert.ok(restored, "the provider session reconnects");
|
||||
assert.equal(created.params._meta.claudeCode.options.model, selectedModel);
|
||||
assert.equal(created.params._meta.claudeCode.options.maxTurns, 5);
|
||||
assert.deepEqual(created.params._meta.systemPrompt, { append: "Fixture instructions" });
|
||||
assert.deepEqual(created.params._meta.claudeCode.options.allowedTools, ["mcp__fixture__*"]);
|
||||
assert.deepEqual(created.params._meta.claudeCode.options.settingSources, includeUserSettings ? ["user", "project", "local"] : ["project", "local"]);
|
||||
assert.deepEqual(restored.params._meta, created.params._meta, "reconnect must preserve the requested native launch settings");
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"commandDigest": "sha256:a0e9f339935f6ee616fee644c45cb09353e9aed1d1f22215739f9504153ceca1",
|
||||
"declaration": {
|
||||
"schema": "paperclip.acpx_profile_declaration.v1",
|
||||
"agent": "copilot",
|
||||
"agentProfileVersion": 79,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agentServerVersion": "1.0.88",
|
||||
"protocolPolicyRevision": "copilot-agent-manual-v1",
|
||||
"acpxPatchSha256": "1e7dae8c83bf8620f53f2bea13c175eeff95e7e955783f6f529bb1dcbdcdb6d2",
|
||||
"policySha256": "a4be69be43db84052560420a3ca546a665c9165573c24d543eb33d144ba138a3",
|
||||
"distributionSourceSha256": "c0a65e247fc47b263bd369a3d5ab505c4b323d4e6493be8a9ecbeb0e9dbb9107",
|
||||
"agentFilesBinding": "registered-runtime-context-v1",
|
||||
"systemInstructionDelivery": "COPILOT_HOME/copilot-instructions.md:replace-under-lifetime-lease-before-launch:v1",
|
||||
"sharedRuntimeContract": "paperclip.acpx-runtime-contract.v1",
|
||||
"innerDistributionSourceSha256": "9bb08347eed01f1ab44e065c8b06ead9be3a25973d6e6329dc4c0a099096279a",
|
||||
"upstreamAppSha256": "7b48282a19b5b0814a0c96ad5e3a125173d792cc55f9525b2effea962f6063c0",
|
||||
"patchedAppSha256": "61f8eebe0c30cc03b311c6818b2acb158a6d16ca58c8bfac5ebd42db095c2679",
|
||||
"messageIdentityContract": "copilot-native-message-id-v1",
|
||||
"ownedDistributionDelivery": "COPILOT_CLI_DIST_DIR:lease-owned-guarded-inner-distribution:v1",
|
||||
"permissionContextContract": "copilot-edit-permission-context-v1",
|
||||
"permissionContextSourceSha256": "de2d38d702b3c574161af0c0c04790fb6f6347916eb3916ce7a131a8c229121b",
|
||||
"permissionAdapterSourceSha256": "ee5929ed2ee647ad0369465dee9d51a00b2dd28e1ff735b43e969ddc9c164668",
|
||||
"permissionLocationsSourceSha256": "f39a81da395b6e23aa2a1a45572a28846e5e81bfd3d764d9a456f74a79c752e9",
|
||||
"permissionRedactionSourceSha256": "ad6770c69269087951790e2e87e22ac088e3d432769adf17ebc865ed512e6c4f",
|
||||
"permissionClassifierSourceSha256": "1161eabd82e26133e3b3db3ab567f65d52808b03f176e93497e02c8330349fb4",
|
||||
"semanticToolReceiptContract": "paperclip.semantic_tool_receipt.v2",
|
||||
"semanticReceiptSourceSha256": "b2795726b2234a663fec1a6ca11f0551ae69882fe9e82aa39686e952d036e791",
|
||||
"semanticBridgeSourceSha256": "8764b8c9032fdc7d1415b01e75a9fc57c550e7a5e11da4bed7d9100082872ae5",
|
||||
"toolEvidenceSourceSha256": "6eef5039afc75bb851eaf9cd82a6f099e4bd398ca2deb59dd66f5b2a81a7a706",
|
||||
"semanticNormalizedInputContract": "validated-forwarded-input-commit-v1",
|
||||
"semanticSidecarSourceSha256": "7d6e948b7cff4df52a9afc916db46ace0f42b4b2d3134ba0c21ee0a928857e62",
|
||||
"semanticDirectDriverSourceSha256": "d683429427dd8a1a5efe50952018ea486f808bdbf0a92fc5946ee267fe2c72ee",
|
||||
"semanticValidationSourceSha256": "02fbb92681c78c5de5d2f1aae25aabc25a0e5df6b0ff4baccac652192a8da975",
|
||||
"semanticNormalizationSourceSha256": "8b628b82e8eacc91cdcc6fdca2210ba4cf282f01e9c6f74e95ff271655b5047e",
|
||||
"semanticCompletionContractSourceSha256": "f49398b682a5623812f5d3c33d6bb9a749008e47cc0ed969072041615f66df59",
|
||||
"semanticValidatorsSourceSha256": "b20ec8ee6e7165117233ce4421a975bb9d3f276220ce31655c0b9a717cb2d9cb",
|
||||
"semanticSchemaBundleSourceSha256": "81ef98ca7b34896a0f76390ac7af3dd8ef7609fe6f38d54bd6a69373d50fe40b",
|
||||
"semanticSidecarProtocolSourceSha256": "26dd0cfbef8b2b401de6b7862a4af7f243fb703e23678a1a5ed8fa68d4784d42",
|
||||
"semanticSidecarReceiptCommitContract": "correlated-tool-resolve-v1",
|
||||
"displayEventSourceSha256": "d72f9a6035c247bc6a42c067c05753076c54322c4b58984e93922f3325dc6877",
|
||||
"displayProjectionSourceSha256": "75952606b26dd93bbc582c1f0a4424487377272ea745fb3a27ceae031fd5dc7e",
|
||||
"configuredEnvironmentSourceSha256": "5c9008d121979a3a8987e6b8a5752172eafdc4a2b5d725a73f3bbb8fb83be8ff",
|
||||
"configuredEnvironmentRustSourceSha256": "85c87fae62b8a9377e4f0a4c00302c7519fae4397b1c48253f8f2b7ba7faf994",
|
||||
"profileActivitySourceSha256": "4fdb6b0f9125fd8372ba6f27945fa5c8a3d3b2ec891df544092e3dc7a75d5282",
|
||||
"profileExtensionsSourceSha256": "a80ddc95eb4505095bfdbbf85c758199949ab20be9c84b34c77f762eb7180571",
|
||||
"profileInstallationSourceSha256": "3e61c4cdd4b78e38fcb16eaadae4f1fd65ce3c7127184ea7a80948c8e5d77f88",
|
||||
"attachmentPolicySourceSha256": "4f7638b7cc64e18f6a4ba33fd46de2b3d49225e32aeab41f5c695b268fa4f8e2",
|
||||
"singleReadEvidenceSourceSha256": "4069393405089bde613cecec04f5123c426594811da4c668bd96f0e7e283550f",
|
||||
"nativeSessionRuntimeSourceSha256": "1fe6fa9e6b96d84d70432b85a57c473f833606d4a521563d5022b4d3c41576ce",
|
||||
"nativeRuntimeContextSourceSha256": "71607f80dbb8dc5cc6c123d0b8f3995d6c5407277695a8c82cbedc90fb8f4842",
|
||||
"nativeRuntimePromptsSourceSha256": "fff5755dba9b7dce8a5f10ff6ac6d5ed06b92ed079ce1e0a44ac72f2ce7869c1",
|
||||
"nativeSessionContractSourceSha256": "22a8c96ce41ba4f03e976fc37f0cc7c5d05cee99fa789941da31ee1dab440b90",
|
||||
"harnessSessionContractSourceSha256": "baba1a210b863518f01e0c875606ed37f9467c433222251438578bd999bc43b5",
|
||||
"harnessBackendSourceSha256": "dc827e281ae6731545b166ee4d709a4f67f594a556dcbe63c70fe8f1aca26249",
|
||||
"harnessSessionSourceSha256": "81361733e86b56dd5a66415aefc6f72e69be24acc8d3417370154ebb7fef6e94",
|
||||
"transportContractSourceSha256": "03fca93d36a89b0cc0917335e293ad097fdf04356d21b307827bb0ea4c13f523",
|
||||
"nativeBackendSourceSha256": "7495d9898d22dca1ebf6336361d332bafefc4498f6e49f1135025fad846c8586",
|
||||
"nativeBackendFactorySourceSha256": "7e431c926b76d53c4c08e3a4105353dcd34bd940f6588a1a68f79631f6feeb44",
|
||||
"nativeInstructionsSourceSha256": "82ac6e5f7275b4ef79fb166c7330efc504e80cab3d7e9081e4e40a8b570bc50b",
|
||||
"providerLaunchSourceSha256": "c744235b3067ea75973523f78f1e13399337bc155f1775af694e34782d5c9bef",
|
||||
"launchPreparationStoreSourceSha256": "ff6025568bbc0aa6ce545772d73dfca2d3da226740bd3a7b386b069e76cff296",
|
||||
"runtimeRequestBridgeSourceSha256": "93a631b8439df1590b0cf442cf84a9b05f004f12bfee90291651ccfc0861effe",
|
||||
"runtimeRequestFacadeSourceSha256": "d0ed28e0c5ddad34db8f437e704c8a755eb0b47f27e08e44185f66d1d2205295",
|
||||
"runtimeRequestNotificationSourceSha256": "6196c6175f11c69295dc00fc773201f4fdeca26c500653870253c43b81e65211",
|
||||
"guardedInstallationSourceSha256": "56a177d3e702914818dca4ca50e061f0d25f988bfc4c0582c36ce23c1696d82f",
|
||||
"nativeExecutionSourceSha256": "d60b8ea63bad975c0144f0702b2749d7db9a7da50680a6147f20d4d11f2d5297",
|
||||
"profileCompatibilitySourceSha256": "aa36385c5ed723b7f2bd5c96ff70db4587a040151f1ee70f5669b7f46f408713",
|
||||
"installationSourceSha256": "a1c7c6f103b898216973e77ffbac0ef7572e250aa574d1a4065270e9dfa0dc2d",
|
||||
"assetOwnershipSourceSha256": "1785e3f31e5dad5a13b53e25d8cf9482a9bd89a27b6c127830aed6b81acc605c",
|
||||
"assetInstallerSourceSha256": "d3bd9514e5920d0cc3567aa50487fb534c57a6f66b8da0d3f22c5f6e499c841f",
|
||||
"credentialBindingSourceSha256": "3a93267146bfc3c489f43262386d6dcb05ec4e3a8b1765414cd43d80d0c64d4a",
|
||||
"admissionDiagnosticsSourceSha256": "df8f1aa4f2d1bc63b2635bdd09cb8165c8b7681ddcc2618435c7c08ca90475af",
|
||||
"grokAdmissionSourceSha256": "f1e46cf2e1e36b7704bd797b678e3db8db2003f97bdb9d827cfa3d7662698777",
|
||||
"sidecarErrorSourceSha256": "17948ad74350dc487ab20d24a0fb89daf0b426b98396454fff0e3856e922d82c",
|
||||
"profileSourceSha256": "f5538b3dbefa7634a332b87d5ededcefb56aa7e5790cede1c7a0d948a548a456",
|
||||
"metadataProbeSourceSha256": "be4c8416edd27061109bc1f33d0c26071b4facbb3f651beaae6b3c0275cce727",
|
||||
"permissionToolIdentitySourceSha256": "770b47305e571a81f344883057d0e4a482a1cd59ac77d045836593a8e739deb1",
|
||||
"semanticContinuationSourceSha256": "c9cc0fd516b3df92a6655f56ee9bef37615a889c371e2e137d8ac5c1176de811",
|
||||
"preparedHarnessHomeSourceSha256": "bb286f7ddc6e9597c56d46bf7ff6e3b556c5b680d7e147fd46518724432b083e",
|
||||
"runtimeHostSourceSha256": "13f9ac382a279a67adb8974c36bbed38fe43d9b93b87bd7a05e879ead7f03d63",
|
||||
"runtimeAdapterSourceSha256": "7c47c05306ebe7d1ca6b5d046a96f5726a48adec4d27e7c16788f505f25b5db2",
|
||||
"runtimeSandboxSourceSha256": "04a49a24e3828ce8fca908de15e31ae932b8b1b4f7ecec0308627f6a8da9ba20",
|
||||
"cancellationSourceSha256": "a07d1a9e982dec0ae130c1ad1efa5bc75c6a39e013b730ba3ee45256f09ceeca",
|
||||
"agentFilesSourceSha256": "fb32f6badc13dfa22f231479509b631b2f0eba0c99b1ab9f3cd5c0c601aa03ba",
|
||||
"nativeDistributionSourceSha256": "aed327c389e957483a503cb1bb8b247ee7cd7ff4b528fb4567c39bcb4577690b"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"commandDigest": "sha256:f43a6f5a583972cdcb422784969cd6a97654655b0f135f1cf178317909c404f8",
|
||||
"sourceDigest": "sha256:c5a4628adcdd9190c45558f42014b0055698b8f8c7eb301417238f38d913f503",
|
||||
"declaration": {
|
||||
"schema": "paperclip.grok-profile-identity.v1",
|
||||
"agent": "grok",
|
||||
"agentProfileVersion": 11,
|
||||
"agentServerPackage": "builtin:grok-acp",
|
||||
"agentServerVersion": "1",
|
||||
"agentRuntimePackage": "native:grok",
|
||||
"agentRuntimeVersion": "1.0.13",
|
||||
"requiresProviderPolicy": false,
|
||||
"acpxVersion": "0.13.1",
|
||||
"sources": {
|
||||
"patches/acpx@0.13.1.patch": "sha256:1e7dae8c83bf8620f53f2bea13c175eeff95e7e955783f6f529bb1dcbdcdb6d2",
|
||||
"packages/paperclip-runner/src/cli/acpx-runtime-sidecar.ts": "sha256:7d6e948b7cff4df52a9afc916db46ace0f42b4b2d3134ba0c21ee0a928857e62",
|
||||
"packages/paperclip-runner/src/cli/acpx-sidecar-input.ts": "sha256:17948ad74350dc487ab20d24a0fb89daf0b426b98396454fff0e3856e922d82c",
|
||||
"packages/paperclip-runner/src/drivers/acpx/admission-diagnostics.ts": "sha256:df8f1aa4f2d1bc63b2635bdd09cb8165c8b7681ddcc2618435c7c08ca90475af",
|
||||
"packages/paperclip-runner/src/drivers/acpx/grok-effort.ts": "sha256:f1e46cf2e1e36b7704bd797b678e3db8db2003f97bdb9d827cfa3d7662698777",
|
||||
"packages/paperclip-runner/src/drivers/acpx/grok-web-search.ts": "sha256:754b5ca2345c045421f6007f34999508d996e1cea035f0f1952b3d5f00072b9c",
|
||||
"packages/paperclip-runner/src/drivers/acpx/grok-credentials.ts": "sha256:1c4ff0be6da798b6fcc604d20a9198dcc8523a3806d563b5b5345b7260549f73",
|
||||
"packages/paperclip-runner/src/drivers/acpx/codex-runtime-adapter.ts": "sha256:7c47c05306ebe7d1ca6b5d046a96f5726a48adec4d27e7c16788f505f25b5db2",
|
||||
"packages/paperclip-runner/src/drivers/acpx/runtime-host.ts": "sha256:13f9ac382a279a67adb8974c36bbed38fe43d9b93b87bd7a05e879ead7f03d63",
|
||||
"packages/paperclip-runner/src/drivers/preconfigured-home.ts": "sha256:bb286f7ddc6e9597c56d46bf7ff6e3b556c5b680d7e147fd46518724432b083e",
|
||||
"packages/paperclip-runner/src/drivers/acpx/runtime-sandbox.ts": "sha256:04a49a24e3828ce8fca908de15e31ae932b8b1b4f7ecec0308627f6a8da9ba20",
|
||||
"packages/paperclip-runner/src/drivers/acpx/sidecar-protocol.ts": "sha256:26dd0cfbef8b2b401de6b7862a4af7f243fb703e23678a1a5ed8fa68d4784d42",
|
||||
"packages/paperclip-runner/src/drivers/acpx/native-distribution-integrity.ts": "sha256:aed327c389e957483a503cb1bb8b247ee7cd7ff4b528fb4567c39bcb4577690b",
|
||||
"packages/paperclip-runner/src/providers/grok/launcher.cjs": "sha256:f0b698395a3704ed2ffaf84ea19bdb20c36c8a0a70b7c629c7b6ffe144e59e55",
|
||||
"packages/paperclip-runner/src/providers/grok/platforms.json": "sha256:931eed3abbf2bf041e6c72e6e9486d976f4352613cf069b216ddf010c9a8e704",
|
||||
"packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs": "sha256:326deadb929e7c134da407bd3fa4d0853732e37d407c92d404979e7625c6c7cf",
|
||||
"packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_session.rs": "sha256:e97a7c4d2cf9be9c6e0ada78076a5551b01401518597ab81cb6fbd5a1faf4a5e",
|
||||
"packages/paperclip-runner/runner/crates/runner-core/src/acpx_sidecar_transport.rs": "sha256:f711428ec3bb9bcf723a5fd1382a3d266ed14e7ed5340b8a32eafe7357940144"
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
-24
@@ -561,21 +561,52 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
}));
|
||||
result = claudeAcp ? await withTimeout(createPromise, resolveClaudeAcpSessionCreateTimeoutMs()) : await createPromise;
|
||||
} catch (error) {
|
||||
@@ -4589,6 +4808,13 @@
|
||||
} catch (error) {
|
||||
@@ -4454,6 +4673,7 @@
|
||||
}
|
||||
async loadSessionWithOptions(sessionId, cwd = this.options.cwd, options = {}) {
|
||||
const connection = this.getConnection();
|
||||
+ const { command, args } = resolveAgentCommandParts(this.options.agentCommand, this.options.agentArgv);
|
||||
const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
|
||||
const previousSuppression = this.applySessionUpdateSuppression(Boolean(options.suppressReplayUpdates));
|
||||
let response;
|
||||
@@ -4461,7 +4681,9 @@
|
||||
response = await this.runConnectionRequest(() => connection.loadSession({
|
||||
sessionId,
|
||||
cwd: sessionCwd,
|
||||
- mcpServers: this.options.mcpServers ?? []
|
||||
+ mcpServers: this.options.mcpServers ?? [],
|
||||
+ _meta: isClaudeAcpCommand(command, args)
|
||||
+ ? buildClaudeCodeOptionsMeta(this.options.sessionOptions, true) : void 0
|
||||
}));
|
||||
await this.waitForSessionUpdateDrain(options.replayIdleMs ?? REPLAY_IDLE_MS, options.replayDrainTimeoutMs ?? REPLAY_DRAIN_TIMEOUT_MS);
|
||||
} finally {
|
||||
@@ -4474,11 +4696,14 @@
|
||||
}
|
||||
async resumeSession(sessionId, cwd = this.options.cwd) {
|
||||
const connection = this.getConnection();
|
||||
+ const { command, args } = resolveAgentCommandParts(this.options.agentCommand, this.options.agentArgv);
|
||||
const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
|
||||
const response = await this.runConnectionRequest(() => connection.resumeSession({
|
||||
sessionId,
|
||||
cwd: sessionCwd,
|
||||
- mcpServers: this.options.mcpServers ?? []
|
||||
+ mcpServers: this.options.mcpServers ?? [],
|
||||
+ _meta: isClaudeAcpCommand(command, args)
|
||||
+ ? buildClaudeCodeOptionsMeta(this.options.sessionOptions, true) : void 0
|
||||
}));
|
||||
this.loadedSessionId = sessionId;
|
||||
const result = toReconnectedSessionResult(response);
|
||||
@@ -4590,15 +4815,17 @@
|
||||
throw maybeWrapSessionControlError("session/set_config_option", error, `for "${configId}"="${value}"`);
|
||||
}
|
||||
+ }
|
||||
}
|
||||
+ async requestExtension(method, params) {
|
||||
+ closedExtensionMethods([method]);
|
||||
+ const payload = boundedExtensionRecord(params);
|
||||
+ const connection = this.getConnection();
|
||||
+ const result = await this.runConnectionRequest(() => connection.extMethod(method, payload));
|
||||
+ return boundedExtensionRecord(result);
|
||||
}
|
||||
async setSessionModel(sessionId, modelId, controlOverride) {
|
||||
const control = this.resolveModelControl(sessionId, controlOverride);
|
||||
@@ -4593,12 +4819,7 @@
|
||||
+ }
|
||||
async setSessionModel(sessionId, modelId, controlOverride) {
|
||||
const control = this.resolveModelControl(sessionId, controlOverride);
|
||||
if (!control) throw new RequestedModelUnsupportedError(`Cannot set model "${modelId}": the ACP session did not advertise a model config option or legacy session/set_model support.`, "missing-capability");
|
||||
@@ -589,7 +620,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
}
|
||||
async setSessionModelThroughConfig(sessionId, modelId, configId) {
|
||||
const connection = this.getConnection();
|
||||
@@ -4608,7 +4829,9 @@
|
||||
@@ -4608,7 +4835,9 @@
|
||||
configId,
|
||||
value: modelId
|
||||
}));
|
||||
@@ -600,7 +631,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
return response;
|
||||
} catch (error) {
|
||||
return this.throwSessionModelError("session/set_config_option", modelId, error);
|
||||
@@ -4864,7 +5087,7 @@
|
||||
@@ -4864,7 +5093,7 @@
|
||||
}
|
||||
selectAuthMethod(methods) {
|
||||
for (const method of methods) {
|
||||
@@ -609,7 +640,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
if (envCredential) return {
|
||||
methodId: method.id,
|
||||
credential: envCredential,
|
||||
@@ -4890,7 +5113,7 @@
|
||||
@@ -4890,7 +5119,7 @@
|
||||
}
|
||||
readAgentSpecificEnvCredential(methodId) {
|
||||
if (!this.isGrokBuildAcpCommand() || methodId !== "xai.api_key") return;
|
||||
@@ -618,7 +649,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
||||
}
|
||||
selectAgentManagedAuthMethod(methodId) {
|
||||
@@ -4915,9 +5138,9 @@
|
||||
@@ -4915,9 +5144,9 @@
|
||||
await connection.authenticate({ methodId: selected.methodId });
|
||||
this.log(`authenticated with method ${selected.methodId} (${selected.source})`);
|
||||
}
|
||||
@@ -630,7 +661,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
if (hostResponse) return hostResponse;
|
||||
const { response, recorded } = await this.resolvePermissionRequestFromMode(params);
|
||||
if (!recorded) {
|
||||
@@ -4926,14 +5149,81 @@
|
||||
@@ -4926,14 +5155,81 @@
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@@ -714,7 +745,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
})).then((response) => ({
|
||||
kind: "response",
|
||||
response
|
||||
@@ -4970,7 +5260,7 @@
|
||||
@@ -4970,7 +5266,7 @@
|
||||
isElicitationSessionCancelling(sessionId) {
|
||||
return this.closing || this.cancellingSessionIds.has(sessionId);
|
||||
}
|
||||
@@ -723,7 +754,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
if (!this.options.onPermissionRequest) return;
|
||||
const signal = this.cancellationSignalForSession(params.sessionId);
|
||||
try {
|
||||
@@ -4978,7 +5268,7 @@
|
||||
@@ -4978,7 +5274,7 @@
|
||||
sessionId: params.sessionId,
|
||||
raw: params,
|
||||
inferredKind: inferToolKind(params)
|
||||
@@ -732,7 +763,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
return this.hostPermissionDecisionResponse(params, signal, decision);
|
||||
} catch (error) {
|
||||
return this.hostPermissionErrorResponse(params, signal, error);
|
||||
@@ -5028,6 +5318,12 @@
|
||||
@@ -5028,6 +5324,12 @@
|
||||
attachAgentLifecycleObservers(child) {
|
||||
child.once("exit", (exitCode, signal) => {
|
||||
this.recordAgentExit("process_exit", exitCode, signal);
|
||||
@@ -745,7 +776,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
});
|
||||
child.once("close", (exitCode, signal) => {
|
||||
this.recordAgentExit("process_close", exitCode, signal);
|
||||
@@ -5100,6 +5396,9 @@
|
||||
@@ -5100,6 +5402,9 @@
|
||||
return await this.filesystem.readTextFile(params);
|
||||
} catch (error) {
|
||||
this.recordPermissionError(params.sessionId, error);
|
||||
@@ -755,7 +786,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -5239,6 +5538,7 @@
|
||||
@@ -5239,6 +5544,7 @@
|
||||
record.cumulative_token_usage = conversation.cumulative_token_usage;
|
||||
record.cumulative_cost = conversation.cumulative_cost;
|
||||
record.request_token_usage = conversation.request_token_usage;
|
||||
@@ -763,7 +794,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
}
|
||||
//#endregion
|
||||
//#region src/runtime/engine/session-options.ts
|
||||
@@ -5701,7 +6001,8 @@
|
||||
@@ -5701,7 +6007,8 @@
|
||||
updated_at: conversation.updated_at,
|
||||
cumulative_token_usage: deepClone(conversation.cumulative_token_usage ?? {}),
|
||||
cumulative_cost: cloneUsageCost(conversation.cumulative_cost),
|
||||
@@ -773,7 +804,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
};
|
||||
}
|
||||
function cloneUsageCost(cost) {
|
||||
@@ -5771,10 +6072,20 @@
|
||||
@@ -5771,10 +6078,20 @@
|
||||
trimConversationForRuntime(conversation);
|
||||
return acpx;
|
||||
}
|
||||
@@ -796,7 +827,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
updateConversationTimestamp(conversation, timestamp);
|
||||
trimConversationForRuntime(conversation);
|
||||
return true;
|
||||
@@ -6136,6 +6447,7 @@
|
||||
@@ -6136,6 +6453,7 @@
|
||||
pendingAgentSessionId = loadState.pendingAgentSessionId;
|
||||
sessionModels = loadState.sessionModels;
|
||||
const preferenceReplay = await replayFreshSessionPreferences({
|
||||
@@ -804,7 +835,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
client,
|
||||
record,
|
||||
createdFreshSession,
|
||||
@@ -6193,14 +6505,16 @@
|
||||
@@ -6193,14 +6511,16 @@
|
||||
if (shouldReconnect) process.stderr.write(`[acpx] saved session pid ${record.pid} is dead; respawning agent and attempting session reconnect\n`);
|
||||
}
|
||||
async function replayFreshSessionPreferences(params) {
|
||||
@@ -823,7 +854,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
client: params.client,
|
||||
sessionId: params.sessionId,
|
||||
desiredModeId: params.desiredModeId,
|
||||
@@ -6219,7 +6533,7 @@
|
||||
@@ -6219,7 +6539,7 @@
|
||||
verbose: params.verbose,
|
||||
suppressWarnings: params.suppressWarnings
|
||||
});
|
||||
@@ -832,7 +863,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
client: params.client,
|
||||
record: params.record,
|
||||
sessionId: params.sessionId,
|
||||
@@ -6435,6 +6749,27 @@
|
||||
@@ -6435,6 +6755,27 @@
|
||||
//#region src/runtime/engine/prompt-turn.ts
|
||||
const SESSION_REPLY_IDLE_MS = 1e3;
|
||||
const SESSION_REPLY_DRAIN_TIMEOUT_MS = 5e3;
|
||||
@@ -860,7 +891,7 @@ diff --git a/dist/live-checkpoint-BSIrfgVo.js b/dist/live-checkpoint-BSIrfgVo.js
|
||||
async function runPromptTurn(params) {
|
||||
try {
|
||||
const promptPromise = params.client.prompt(params.sessionId, params.prompt, params.onPromptRequestStarted, params.onElicitation);
|
||||
@@ -6444,7 +6779,23 @@
|
||||
@@ -6444,7 +6785,23 @@
|
||||
idleMs: SESSION_REPLY_IDLE_MS,
|
||||
timeoutMs: SESSION_REPLY_DRAIN_TIMEOUT_MS
|
||||
}).catch(() => {});
|
||||
|
||||
@@ -52,8 +52,8 @@ assert.equal(JSON.parse(await readFile(join(server, 'package.json'), 'utf8')).na
|
||||
const { resolvePaperclipRunnerBinary } = await import(pathToFileURL(join(server, 'dist/services/native-runtime/native-codex-runner.js')));
|
||||
const { createCapabilityRunnerdCodexTransport } = await import(pathToFileURL(join(server, 'dist/vendor/paperclip-runner/live/runnerd-codex-transport.js')));
|
||||
const { QUALIFIED_ACPX_PROFILES } = await import(pathToFileURL(join(server, 'dist/vendor/paperclip-runner/drivers/acpx/qualified-profiles.js')));
|
||||
assert.equal(QUALIFIED_ACPX_PROFILES.pi.agentProfileVersion, 32);
|
||||
assert.equal(QUALIFIED_ACPX_PROFILES.pi.commandDigest, 'sha256:ce13b75699331c813f8a42f2803c3e0e0fb1e6d24847452cb12b50d6ed2d0baf');
|
||||
assert.equal(QUALIFIED_ACPX_PROFILES.pi.agentProfileVersion, 33);
|
||||
assert.equal(QUALIFIED_ACPX_PROFILES.pi.commandDigest, 'sha256:0260d5810e9247986800ad46c1f9b3511a5abd06cb8f142405d5caacbc3960fc');
|
||||
assert.equal(Object.hasOwn(QUALIFIED_ACPX_PROFILES.pi, 'qualificationModel'), false);
|
||||
assert.equal(Object.hasOwn(QUALIFIED_ACPX_PROFILES.pi, 'reportedModelId'), false);
|
||||
const daemon = resolvePaperclipRunnerBinary();
|
||||
|
||||
Reference in new issue
Block a user