import { NATIVE_COMPLETION_BUDGET_CENTS } from "./native-completion-defaults.js"; import path from "node:path"; import { installedReleaseDaytonaPlugin } from "./installed-release.js"; import { isManagedHiringCase } from "./chat-cases.js"; import { FixtureRegistry } from "./fixture-registry.js"; import { TASK_TITLE_BUDGET_CENTS } from "./task-titles.js"; import { stageGrokSubscriptionFixture } from "./grok-subscription-fixture.js"; import type { RunnerApi } from "./api.js"; import type { CredentialName, MatrixExecution, SecretReference, SecretReferenceMap, } from "./types.js"; interface CompanyRecord { id: string; issuePrefix?: string | null; name: string; } interface SecretRecord { id: string; } interface PluginRecord { id: string; pluginKey: string; status: string; } interface EnvironmentRecord { id: string; driver: string; config?: Record; } interface AgentRecord { id: string; name: string; companyId: string; } interface ManagedAccountFixture { connectionId: string; binding: { provider: "openai" | "anthropic" | "openrouter"; method: "api_key"; mode: "responsible_user"; }; } interface ProjectRecord { id: string; name: string; primaryWorkspace?: { id: string; cwd?: string | null; } | null; } export interface LiveFixtureValues { company: CompanyRecord; secretRefs: SecretReferenceMap; environment: EnvironmentRecord; agent: AgentRecord; project?: ProjectRecord; aiConnection?: ManagedAccountFixture; onboardingRuntime?: { mode: "production-wizard" | "post-onboarding-runtime-switch"; originalAdapterType: string; originalModel: string | null; testedAdapterType: string; }; teardown(): Promise; } function value(resolved: ReadonlyMap, id: string): T { const result = resolved.get(id); if (!result) throw new Error(`Missing resolved fixture ${id}`); return result as T; } async function deleteDaytonaEnvironment(api: RunnerApi, environmentId: string) { const deadlineAt = Date.now() + 120_000; let lastError: unknown; while (Date.now() < deadlineAt) { try { await api.delete( `/api/environments/${environmentId}?destroyReusableSandboxLeases=true`, { allowNotFound: true, }, ); return; } catch (error) { lastError = error; await new Promise((resolve) => setTimeout(resolve, 3_000)); } } throw new Error( `Daytona lease cleanup failed: ${lastError instanceof Error ? lastError.message : String(lastError)}`, ); } export async function setupLiveFixtures(input: { api: RunnerApi; execution: MatrixExecution; executionNonce: string; workspacePath: string; credentials: Partial>; daytonaImage?: string; }): Promise { const { api, execution } = input; const registry = new FixtureRegistry(); if (execution.environment.id === "daytona") { registry.register({ id: "sandbox-provider", async setup() { return api.post("/api/plugins/install", { packageName: process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_CLI ? installedReleaseDaytonaPlugin(process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_CLI, process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_DAYTONA_PLUGIN, process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_DAYTONA_PLUGIN_VERSION) : path.resolve( import.meta.dirname, "../../packages/plugins/sandbox-providers/daytona", ), isLocalPath: true, }); }, async teardown() { // The plugin is installed only in the isolated instance/database. The // launcher removes that complete instance after the environment lease // has been destroyed, so no global uninstall mutation is necessary. }, }); } registry.register({ id: "company", async setup() { return api.post("/api/companies", { name: `Runner E2E ${execution.id} ${input.executionNonce}`, description: "Ephemeral paid full-stack runner acceptance fixture", budgetMonthlyCents: ["native-completion", "native-instruction-consolidation", "native-connection-guidance"].includes(execution.suite.id) || (execution.suite.id === "everyday-workflows" && ["hire-reuse", "delegate-feedback"].includes(execution.task.id)) ? NATIVE_COMPLETION_BUDGET_CENTS : execution.suite.id === "task-titles" ? TASK_TITLE_BUDGET_CENTS : execution.suite.id === "stock-harness" ? 1_000 : 0, }); }, async teardown() { // The isolated instance/database is removed by the launcher. Do not call // company deletion here: metered runs intentionally retain cost-event // references until that instance-wide teardown. }, }); registry.register({ id: "secrets", dependencies: ["company"], async setup(resolved) { const company = value(resolved, "company"); const refs: SecretReferenceMap = {}; for (const credentialName of execution.requiredCredentials) { if (credentialName === "GROK_AUTH_JSON") continue; const rawValue = input.credentials[credentialName]; if (!rawValue) throw new Error(`Missing credential ${credentialName}`); const secret = await api.postSensitive( `/api/companies/${company.id}/secrets`, { name: `Runner E2E ${credentialName} ${input.executionNonce}`, key: credentialName, value: rawValue, description: `Ephemeral credential for ${execution.id}`, }, ); refs[credentialName] = { type: "secret_ref", secretId: secret.id, version: "latest", } satisfies SecretReference; } return refs; }, }); const grokSubscription = execution.profile.credential === "GROK_AUTH_JSON"; if (grokSubscription) { registry.register<() => Promise>({ id: "subscription-login", dependencies: ["company"], async setup(resolved) { const raw = input.credentials.GROK_AUTH_JSON; if (!raw) throw new Error("Missing credential GROK_AUTH_JSON"); return stageGrokSubscriptionFixture({ raw, companyId: value(resolved, "company").id, environment: process.env, }); }, async teardown(remove) { await remove(); }, }); } registry.register({ id: "environment", dependencies: [ "company", "secrets", ...(grokSubscription ? ["subscription-login"] : []), ...(execution.environment.id === "daytona" ? ["sandbox-provider"] : []), ], async setup(resolved) { const company = value(resolved, "company"); const secretRefs = value(resolved, "secrets"); if (execution.environment.id === "local") { // Paperclip has one instance-managed local environment. The company // creation API ensures it exists; creating a second local environment // is intentionally rejected by the public API. const environments = await api.get( `/api/companies/${company.id}/environments?driver=local`, ); const local = environments.find( (candidate) => candidate.driver === "local", ); if (!local) throw new Error( "Isolated Paperclip instance did not create its managed local environment", ); return local; } return api.post( `/api/companies/${company.id}/environments`, execution.environment.buildEnvironment({ secretRefs, daytonaImage: input.daytonaImage, executionId: input.executionNonce, }), ); }, async teardown(environment) { if (execution.environment.id === "daytona") { await deleteDaytonaEnvironment(api, environment.id); } }, }); const managedHiring = isManagedHiringCase(execution.suite.id, execution.task.id); if (managedHiring) { registry.register({ id: "ai-connection", dependencies: ["company"], async setup(resolved) { const company = value(resolved, "company"); const key = execution.profile.credential; const provider = key === "ANTHROPIC_API_KEY" ? "anthropic" : key === "OPENROUTER_API_KEY" ? "openrouter" : key === "OPENAI_API_KEY" ? "openai" : null; if (!provider) throw new Error(`Unsupported managed hiring credential ${key}`); const apiKey = input.credentials[key]; if (!apiKey) throw new Error(`Missing credential ${key}`); const account = await api.postSensitive<{ connectionId: string }>( `/api/companies/${company.id}/ai-connections`, { provider, method: "api_key", name: `Runner E2E account ${input.executionNonce}`, ownership: "personal", apiKey, agentIds: [], allAgents: false, }, ); return { connectionId: account.connectionId, binding: { provider, method: "api_key", mode: "responsible_user" }, }; }, }); } registry.register({ id: "agent", dependencies: [ "company", "secrets", "environment", ...(grokSubscription ? ["subscription-login"] : []), ...(managedHiring ? ["ai-connection"] : []), ], async setup(resolved) { const company = value(resolved, "company"); const environment = value(resolved, "environment"); const secretRefs = value(resolved, "secrets"); const agent = execution.profile.buildAgent({ environmentId: environment.id, environmentFixtureId: execution.environment.id, workspacePath: input.workspacePath, secretRefs, executionId: input.executionNonce, }); if (["stock-harness", "native-connection-guidance"].includes(execution.suite.id) || (execution.suite.id === "everyday-workflows" && ["hire-reuse", "delegate-feedback"].includes(execution.task.id))) { agent.budgetMonthlyCents = 1_000; } if (managedHiring) { const account = value(resolved, "ai-connection"); const config = agent.adapterConfig as Record; delete config.env; agent.runtimeConfig = { ...(agent.runtimeConfig as Record), aiConnection: account.binding, }; } return api.post( `/api/companies/${company.id}/agents`, agent, ); }, async teardown() { // Agent state is instance-local. Daytona environment teardown below is // the only fixture cleanup that must reach an external provider. }, }); if (execution.task.flow === "warm_three_turn" || (execution.suite.id === "extended-harnesses" && execution.task.id === "file-edit-validate")) { registry.register({ id: "project", dependencies: ["company", "environment"], async setup(resolved) { const company = value(resolved, "company"); const environment = value(resolved, "environment"); return api.post( `/api/companies/${company.id}/projects`, { name: `Runner E2E workspace project ${input.executionNonce}`, description: "Ephemeral project anchoring the fixture execution workspace and file copy-back", executionWorkspacePolicy: { enabled: true, defaultMode: "shared_workspace", sharedWorkspaceConcurrency: "serialize", allowIssueOverride: false, environmentId: environment.id, workspaceStrategy: { type: "project_primary" }, }, workspace: { name: "Primary", sourceType: "local_path", cwd: input.workspacePath, isPrimary: true, }, }, ); }, async teardown() { // The isolated instance is deleted after provider resources are gone. }, }); } const setup = await registry.setupAll(); return { company: value(setup.values, "company"), secretRefs: value(setup.values, "secrets"), environment: value(setup.values, "environment"), agent: value(setup.values, "agent"), ...(setup.values.has("project") ? { project: value(setup.values, "project") } : {}), ...(managedHiring ? { aiConnection: value( setup.values, "ai-connection", ), } : {}), teardown: setup.teardown, }; }