Scope warm acceptance instructions to the active runner protocol

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-17 11:30:19 -05:00
1 parent 3da3d0c307
commit b4574e923e
3 files changed
+29 -3

No files matched your search

+15
View File
@@ -12,6 +12,7 @@ import {
runnerSuites,
runnerTasks,
daytonaWarmContinuityTask,
warmPromptForGeneration,
daytonaWarmEnvironment,
isImmutableDaytonaImage,
suiteDefinitionHash,
@@ -25,6 +26,20 @@ import {
} from "./selectors.js";
describe("runner E2E catalog", () => {
it("gives warm runners only their own completion protocol on all three turns", () => {
const prompts = [daytonaWarmContinuityTask.buildPrompt("nonce"), ...daytonaWarmContinuityTask.buildFollowupMessages!("nonce")];
for (const prompt of prompts) {
const native = warmPromptForGeneration(prompt, "native");
expect(native).toContain("paperclip_finish");
expect(native).not.toContain("PATCH /api/issues");
expect(native).not.toContain("In a legacy runner,");
const legacy = warmPromptForGeneration(prompt, "legacy");
expect(legacy).not.toContain("paperclip_finish");
expect(legacy).toContain("issue");
expect(legacy).toContain("Do not recreate, truncate, reorder, or duplicate prior lines.");
}
});
it("defines sixteen local connection-review journeys without expanding the default matrix", () => {
expect(connectionReviewSuite.expectedMatrixSize).toBe(16);
expect(new Set(connectionReviewSuite.profiles.map(profile => profile.id))).toEqual(new Set(["runner-codex", "runner-acpx-claude", "legacy-codex", "legacy-claude"]));
+8
View File
@@ -799,6 +799,14 @@ const localEnvironment = runnerEnvironments.find(
(environment) => environment.id === "local",
)!;
export function warmPromptForGeneration(prompt: string, generation: RunnerProfileFixture["generation"]): string {
const other = generation === "native" ? "legacy" : "native";
return [
`You are running in a ${generation} runner. Follow the ${generation} completion instructions below.`,
...prompt.split("\n").filter((line) => !line.startsWith(`In a ${other} runner,`)),
].join("\n");
}
function warmTurnMarker(turn: 1 | 2 | 3, nonce: string) {
return `PAPERCLIP_E2E_WARM_T${turn}_${nonce}`;
}
+6 -3
View File
@@ -11,7 +11,7 @@ import path from "node:path";
import { expect, test, type Page } from "@playwright/test";
import { RunnerApi, pollUntil } from "./api.js";
import { buildRuntimeUsage, summarizeExecutionBilling } from "./billing.js";
import { runnerExecutionById } from "./catalog.js";
import { runnerExecutionById, warmPromptForGeneration } from "./catalog.js";
import { classifyFailure } from "./failure-classifier.js";
import { runnerE2EServerControlPaths } from "./harness-env.js";
import { setupConnectionReview } from "./connection-reviews.js";
@@ -525,7 +525,10 @@ for (const execution of executions) {
const nonce = `${randomBytes(6).toString("hex")}-${attempt}`;
const marker = execution.task.buildVisibleMarker(nonce);
const title = execution.task.buildTitle(nonce);
const prompt = execution.task.buildPrompt(nonce);
const rawPrompt = execution.task.buildPrompt(nonce);
const prompt = execution.task.flow === "warm_three_turn"
? warmPromptForGeneration(rawPrompt, execution.profile.generation)
: rawPrompt;
const credentials = credentialValues();
const secrets = normalizedSecrets(Object.values(credentials));
const api = new RunnerApi(request);
@@ -1517,7 +1520,7 @@ for (const execution of executions) {
`warm-turn-${completedTurn}.png`,
);
turnSubmissionTimesMs.push(
await submitTaskRevision(page, followups[completedTurn - 1]),
await submitTaskRevision(page, warmPromptForGeneration(followups[completedTurn - 1], execution.profile.generation)),
);
}
warmLifecycleEvidence = { turns: turnEvidence };