fix(runner): include live completion contract in model instructions

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-28 14:46:49 -05:00
1 parent dc58afb28f
commit aa4b88b169
2 files changed
+18 -5

No files matched your search

@@ -907,6 +907,8 @@ describe("Capability live runnerd and Codex session", () => {
expect(names.filter((name) => name === "paperclip_finish")).toHaveLength(1);
expect(names.filter((name) => name === "paperclip_block")).toHaveLength(1);
expect(names).not.toContain("create_task");
expect(opened.params.baseInstructions).toContain('"revision":"paperclip-capability-live-v1"');
expect(opened.params.baseInstructions).toContain('"criterionIds":["objective"]');
await first.suspend();
const restoredService = new CapabilityLiveSessionService({ store, transportFactory: factory });
const restored = await restoredService.restore(first.id);
@@ -914,6 +916,8 @@ describe("Capability live runnerd and Codex session", () => {
expect(authority[1]?.resumeDynamicTools?.map((tool) => tool.name)).toEqual(
names.filter((name) => name !== "paperclip_finish" && name !== "paperclip_block"),
);
const resumed = state.transports[1]!.requests.find((request) => request.method === "thread/resume")!;
expect(resumed.params.baseInstructions).toBe(opened.params.baseInstructions);
await restoredService.shutdown(restored.id);
await firstService.shutdown(first.id);
});
@@ -972,9 +976,11 @@ describe("Capability live runnerd and Codex session", () => {
state.transports[0]?.requests.find(
(request) => request.method === "thread/start",
)?.params.baseInstructions,
).toBe(
).toContain(
"Native instructions\n\nRead-only instruction sibling root: /runtime/instructions",
);
expect(state.transports[0]?.requests.find((request) => request.method === "thread/start")?.params.baseInstructions)
.toContain('Native completion report contract: {"revision":"paperclip-capability-live-v1","criterionIds":["objective"]}');
await service.shutdown(session.id);
});
@@ -2346,6 +2346,15 @@ export class CapabilityLiveSession {
itemId: `item_lab_${identityDigest}`,
};
this.#providerRunBinding = providerRunBinding;
// PRP run-attach metadata binds server validation, but ACP providers receive
// only these system instructions. Make the same immutable contract visible
// without expanding the model's separately governed mock task authority.
const baseInstructions = [
this.#transportOptions.baseInstructions ?? LIVE_BASE_INSTRUCTIONS,
"",
"Native completion report contract: " + JSON.stringify(LIVE_COMPLETION_CONTRACT),
"For paperclip_finish or paperclip_block, use that exact contract revision and criterion IDs. These tools report the current provider run result; they do not change mock task state. Mock task mutations still require separately authorized semantic tools and an explicit user request.",
].join("\n");
const authorizedTools = this.#dispatcher.listTools(this.#authority.runId);
const tools = (this.#config.toolExposure ?? "eager") === "lazy"
? authorizedTools.filter((tool) => tool.annotations.exposure === "always")
@@ -2464,8 +2473,7 @@ export class CapabilityLiveSession {
config: createSkilllessCodexThreadConfig(this.#config.workingDirectory),
permissions: CODEX_PERMISSION_PROFILE,
runtimeWorkspaceRoots: [this.#config.workingDirectory],
baseInstructions:
this.#transportOptions.baseInstructions ?? LIVE_BASE_INSTRUCTIONS,
baseInstructions,
persistExtendedHistory: true,
});
const resumedThread = record(resumed.thread);
@@ -2490,8 +2498,7 @@ export class CapabilityLiveSession {
permissions: CODEX_PERMISSION_PROFILE,
runtimeWorkspaceRoots: [this.#config.workingDirectory],
approvalPolicy: "never",
baseInstructions:
this.#transportOptions.baseInstructions ?? LIVE_BASE_INSTRUCTIONS,
baseInstructions,
completionContract: LIVE_COMPLETION_CONTRACT,
dynamicTools: [...semanticTools, ...codexSemanticToolSpecs()],
experimentalRawEvents: true,