mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-13 07:12:00 +01:00
fix: preserve Codex runner intent and private eval evidence
Retain native setup links and built-in settings, record explicit runner choices, and qualify native/legacy skill fixtures. Keep full grading artifacts private while projecting safe first-task summaries. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
38199ea8e6
commit
1be8502f27
15 files changed
+454
-32
No files matched your search
@@ -11,6 +11,9 @@ import type { BuiltInAgentState } from "@/api/builtInAgents";
|
||||
const provisionMock = vi.hoisted(() => vi.fn());
|
||||
const updateMock = vi.hoisted(() => vi.fn());
|
||||
const adapterModelsMock = vi.hoisted(() => vi.fn());
|
||||
const adapterDiscoveryMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("@/api/adapters", () => ({ adaptersApi: { list: adapterDiscoveryMock } }));
|
||||
|
||||
vi.mock("@/api/builtInAgents", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("@/api/builtInAgents")>();
|
||||
@@ -72,6 +75,15 @@ function makeState(overrides: Partial<BuiltInAgentState> = {}): BuiltInAgentStat
|
||||
};
|
||||
}
|
||||
|
||||
function makeSavedAgent(adapterType: "codex_local" | "paperclip_runner", adapterConfig: Record<string, unknown>): NonNullable<BuiltInAgentState["agent"]> {
|
||||
return {
|
||||
id: "a1", companyId: "c1", name: "Briefs Agent", urlKey: "briefs-agent", role: "general", title: null, icon: null,
|
||||
status: "idle", reportsTo: null, capabilities: null, adapterType, adapterConfig, runtimeConfig: {}, defaultEnvironmentId: null,
|
||||
budgetMonthlyCents: 0, spentMonthlyCents: 0, pauseReason: null, pausedAt: null, permissions: { canCreateAgents: false },
|
||||
lastHeartbeatAt: null, metadata: null, createdAt: new Date(0), updatedAt: new Date(0),
|
||||
};
|
||||
}
|
||||
|
||||
async function flushReact() {
|
||||
for (let index = 0; index < 6; index += 1) {
|
||||
await Promise.resolve();
|
||||
@@ -117,6 +129,7 @@ describe("ConfigureBuiltInAgentModal (PAP-12978)", () => {
|
||||
provisionMock.mockReset();
|
||||
updateMock.mockReset();
|
||||
adapterModelsMock.mockReset().mockResolvedValue([]);
|
||||
adapterDiscoveryMock.mockReset().mockResolvedValue([{ type: "codex_local", supportedRunners: ["paperclip", "legacy"], defaultRunner: "legacy" }]);
|
||||
onOpenChange.mockReset();
|
||||
onConfigured.mockReset();
|
||||
});
|
||||
@@ -189,6 +202,40 @@ describe("ConfigureBuiltInAgentModal (PAP-12978)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["codex_local", "paperclip_runner"] as const)("lets the server translate saved %s settings for a runner-only change", async adapterType => {
|
||||
const savedConfig = { model: "gpt-5", timeoutSec: 45, modelReasoningEffort: "high", env: { CODEX_HOME: { type: "secret_ref", secretId: "account-1" } }, ...(adapterType === "paperclip_runner" ? { provider: "codex", codexPermissionMode: "never", lifecycleMode: "per_turn" } : {}) };
|
||||
const state = makeState({ status: "ready", agentId: "a1", agent: makeSavedAgent(adapterType, savedConfig) });
|
||||
provisionMock.mockResolvedValue(state);
|
||||
await renderModal(state);
|
||||
const summary = document.querySelector("summary")!;
|
||||
flushSync(() => summary.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
flushSync(() => document.querySelector('[aria-label="Runner"]')!.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
await flushReact();
|
||||
const runner = adapterType === "paperclip_runner" ? "legacy" : "paperclip";
|
||||
flushSync(() => document.querySelector(`[role="option"][data-value="${runner}"]`)!.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
await flushReact();
|
||||
flushSync(() => findButton("Configure")!.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
await flushReact();
|
||||
expect(provisionMock).toHaveBeenCalledWith("c1", "briefs", { runner });
|
||||
expect(state.agent?.adapterConfig).toEqual(savedConfig);
|
||||
});
|
||||
|
||||
it("merges a built-in model edit into the saved native configuration", async () => {
|
||||
const savedConfig = { provider: "codex", model: "gpt-5", timeoutSec: 45, modelReasoningEffort: "high", env: { CODEX_HOME: { type: "secret_ref", secretId: "account-1" } } };
|
||||
const state = makeState({ status: "ready", agentId: "a1", agent: makeSavedAgent("paperclip_runner", savedConfig) });
|
||||
provisionMock.mockResolvedValue(state);
|
||||
await renderModal(state);
|
||||
const modelInput = document.querySelector('[data-testid="model-input"]') as HTMLInputElement;
|
||||
flushSync(() => {
|
||||
Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")!.set!.call(modelInput, "gpt-6-sol");
|
||||
modelInput.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
});
|
||||
await flushReact();
|
||||
flushSync(() => findButton("Configure")!.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
await flushReact();
|
||||
expect(provisionMock).toHaveBeenCalledWith("c1", "briefs", { adapterType: "paperclip_runner", adapterConfig: { ...savedConfig, model: "gpt-6-sol" } });
|
||||
});
|
||||
|
||||
it("shows a visible error and blocks provisioning for an unknown model", async () => {
|
||||
adapterModelsMock.mockResolvedValue([
|
||||
{ id: "claude-haiku-4-5", label: "Claude Haiku 4.5" },
|
||||
|
||||
Reference in new issue
Block a user