import { mkdtemp, readFile, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, expect, test } from "bun:test"; import { createNativeAgentRunWorkbenchApplication } from "./native-agentrun-application.ts"; const temporaryDirectories: string[] = []; afterEach(async () => { await Promise.all(temporaryDirectories.splice(0).map((directory) => rm(directory, { force: true, recursive: true }))); }); test("L1 AgentRun application dispatches gpt.pika without polling or projecting a terminal result", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "hwlab-workbench-agentrun-")); temporaryDirectories.push(directory); const stateFile = path.join(directory, "state.json"); const calls: Array<{ method: string; path: string; authorization: string | null; body: any }> = []; const app = createNativeAgentRunWorkbenchApplication({ stateFile, env: agentRunEnvironment(), fetchImpl: fakeAgentRunManager(calls), now: () => "2026-07-20T01:13:12.232Z", }); const created = await app.createSession({ actor: { id: "usr_native", role: "user" }, params: { providerProfile: "gpt.pika" } }); const models = await app.providerModelCatalog!("gpt.pika"); expect(models).toMatchObject({ status: "ok", profile: "gpt.pika", defaultModel: "gpt-5.6", reasoningEfforts: ["low", "medium", "high", "xhigh"] }); const session = created.session as Record; const input = { actor: { id: "usr_native", role: "user" }, traceId: "trc_l1_gpt_pika_smoke", sessionId: session.sessionId, params: { message: "hi", submittedAt: "2026-07-20T01:13:07.699Z", providerProfile: "gpt.pika", model: "gpt-5.6", reasoningEffort: "high" }, }; const admitted = await app.admitTurn(input); const result = await app.dispatchTurn(admitted); const steered = await app.steerTurn({ actor: input.actor, sessionId: input.sessionId, targetTraceId: input.traceId, steerTraceId: "trc_steer_l1_gpt_pika", params: { message: "adjust course", submittedAt: "2026-07-20T01:14:07.699Z", sessionId: input.sessionId, targetTraceId: input.traceId, steerTraceId: "trc_steer_l1_gpt_pika" } }); expect(result).toMatchObject({ status: "running", terminal: false, terminalAuthority: "hwlab.event.v1", resultSynthesized: false, agentRun: { runId: "run_l1_gpt_pika", commandId: "cmd_l1_gpt_pika", runnerJobId: "rjob_l1_gpt_pika", }, }); const state = JSON.parse(await readFile(stateFile, "utf8")); expect(state.turns[input.traceId]).toMatchObject({ status: "running", createdAt: "2026-07-20T01:13:07.699Z", terminal: false, runId: "run_l1_gpt_pika", commandId: "cmd_l1_gpt_pika", runnerJobId: "rjob_l1_gpt_pika", }); expect(state.turns[input.traceId]).not.toHaveProperty("result"); expect(state.turns[input.traceId]).not.toHaveProperty("finalResponse"); expect(state.sessions[session.sessionId]).toMatchObject({ status: "running", providerProfile: "gpt.pika" }); expect(state.sessions[session.sessionId].messages).toHaveLength(1); expect(steered).toMatchObject({ accepted: true, status: "running", traceId: "trc_steer_l1_gpt_pika", targetTraceId: input.traceId, steerTraceId: "trc_steer_l1_gpt_pika", requestedDelivery: "steer", delivery: "steer", agentRun: { steerCommandId: "cmd_l1_gpt_pika_steer", targetCommandId: "cmd_l1_gpt_pika" } }); expect(`${calls[0]?.method} ${calls[0]?.path}`).toBe("GET /api/v1/provider-profiles/gpt-pika/models"); expect(`${calls[1]?.method} ${calls[1]?.path}`).toMatch(/^GET \/api\/v1\/sessions\/ses_agentrun_/); expect(calls.slice(2, 5).map((call) => `${call.method} ${call.path}`)).toEqual([ "POST /api/v1/sessions", "POST /api/v1/runs", "POST /api/v1/runs/run_l1_gpt_pika/commands", ]); expect(`${calls[5]?.method} ${calls[5]?.path}`).toMatch(/^POST \/api\/v1\/sessions\/ses_agentrun_[A-Za-z0-9_]+\/send$/); expect(calls.every((call) => call.authorization === "Bearer test-agentrun-key")).toBe(true); }); test("L0 requested steer resolved to a turn persists the actual control trace", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "hwlab-workbench-agentrun-steer-turn-")); temporaryDirectories.push(directory); const stateFile = path.join(directory, "state.json"); const calls: Array<{ method: string; path: string; authorization: string | null; body: any }> = []; const app = createNativeAgentRunWorkbenchApplication({ stateFile, env: agentRunEnvironment(), fetchImpl: fakeAgentRunManager(calls, "turn"), now: () => "2026-07-20T01:15:12.232Z", }); const created = await app.createSession({ actor: { id: "usr_native", role: "user" }, params: { providerProfile: "gpt.pika" } }); const session = created.session as Record; const input = await app.admitTurn({ actor: { id: "usr_native", role: "user" }, traceId: "trc_l1_gpt_pika_smoke", sessionId: session.sessionId, params: { message: "first", submittedAt: "2026-07-20T01:13:07.699Z", providerProfile: "gpt.pika" }, }); await app.dispatchTurn(input); const result = await app.steerTurn({ actor: input.actor, sessionId: input.sessionId, targetTraceId: input.traceId, steerTraceId: "trc_actual_followup_turn", params: { message: "continue after terminal", submittedAt: "2026-07-20T01:15:07.699Z" }, }); expect(result).toMatchObject({ traceId: "trc_actual_followup_turn", targetTraceId: input.traceId, requestedDelivery: "steer", delivery: "turn", agentRun: { runId: "run_actual_followup_turn", commandId: "cmd_actual_followup_turn" } }); const state = await app.snapshot!(); expect(state.turns[input.traceId]).toMatchObject({ traceId: input.traceId, commandId: "cmd_l1_gpt_pika" }); expect(state.turns.trc_actual_followup_turn).toMatchObject({ traceId: "trc_actual_followup_turn", targetTraceId: input.traceId, requestedDelivery: "steer", delivery: "turn", status: "running", runId: "run_actual_followup_turn", commandId: "cmd_actual_followup_turn" }); expect(state.sessions[input.sessionId]).toMatchObject({ lastTraceId: "trc_actual_followup_turn", status: "running" }); }); test("L1 AgentRun application leaves dispatch failures to Temporal instead of projecting a terminal snapshot", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "hwlab-workbench-agentrun-failure-")); temporaryDirectories.push(directory); const stateFile = path.join(directory, "state.json"); const app = createNativeAgentRunWorkbenchApplication({ stateFile, env: agentRunEnvironment(), fetchImpl: (async () => Response.json({ ok: false, failureKind: "manager-unavailable", message: "manager unavailable" }, { status: 503 })) as typeof fetch, }); const created = await app.createSession({ actor: { id: "usr_native" }, params: { providerProfile: "gpt.pika" } }); const session = created.session as Record; const input = await app.admitTurn({ actor: { id: "usr_native" }, traceId: "trc_l1_manager_failure", sessionId: session.sessionId, params: { message: "hi", providerProfile: "gpt.pika" }, }); await expect(app.dispatchTurn(input)).rejects.toMatchObject({ code: "manager-unavailable" }); expect((await app.snapshot!()).turns[input.traceId]).toMatchObject({ status: "admitted", terminal: false }); }); test("L0 publishes admission, bounded ConnectionRefused retry, and semantic terminal failure to Kafka authority", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "hwlab-workbench-agentrun-visible-failure-")); temporaryDirectories.push(directory); const published: Array> = []; let runCreateAttempts = 0; const app = createNativeAgentRunWorkbenchApplication({ stateFile: path.join(directory, "state.json"), env: agentRunEnvironment(), eventPublisher: { async publish(input) { published.push(input); return { published: true }; }, }, fetchImpl: (async (request) => { const url = new URL(String(request)); if (url.pathname === "/api/v1/sessions") { return Response.json({ ok: true, data: { session: { id: "ses_agentrun_l0_visible_failure", metadata: {} } } }); } if (url.pathname === "/api/v1/runs") runCreateAttempts += 1; throw Object.assign(new Error("Unable to connect. Is the computer able to access the url?"), { code: "ConnectionRefused" }); }) as typeof fetch, now: () => "2026-07-20T11:45:01.000Z", }); const created = await app.createSession({ actor: { id: "usr_native" }, params: { providerProfile: "gpt.pika" } }); const session = created.session as Record; const input = await app.admitTurn({ actor: { id: "usr_native" }, traceId: "trc_l0_connection_refused", sessionId: session.sessionId, params: { message: "hi", providerProfile: "gpt.pika" }, }); await expect(app.dispatchTurn(input)).rejects.toMatchObject({ failureKind: "connection-refused", retryable: true, retryExhausted: true, retryAttempt: 1, }); expect(runCreateAttempts).toBe(2); expect(published[0]?.event.type).toBe("backend_status"); expect(published.filter((item) => item.event.type === "error")).toHaveLength(1); expect(published.filter((item) => item.event.type === "terminal_status")).toHaveLength(1); expect(published[0]?.event).toMatchObject({ phase: "request-admitted", summary: "请求已接纳,正在启动 AgentRun" }); expect(published.find((item) => item.event.retryPhase === "retryScheduled" && item.event.component === "agentrun-manager")?.event).toMatchObject({ retryPhase: "retryScheduled", failureDomain: "infrastructure", component: "agentrun-manager", code: "connection-refused", attempt: 1, maxAttempts: 1, }); expect(published.find((item) => item.event.type === "error")?.event).toMatchObject({ retryPhase: "retryExhausted", summary: "AgentRun 服务暂时不可达" }); expect(published.find((item) => item.event.type === "terminal_status")?.event).toMatchObject({ terminalStatus: "failed", failureKind: "connection-refused", terminal: true }); expect(published.every((item) => item.traceId === input.traceId && item.sessionId === input.sessionId)).toBe(true); }); function agentRunEnvironment(): Record { return { WORKBENCH_MODE: "agentrun-native", AGENTRUN_MGR_URL: "http://127.0.0.1:65535", AGENTRUN_API_KEY: "test-agentrun-key", HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1", HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "NC01", HWLAB_CODE_AGENT_AGENTRUN_GPT_PIKA_SECRET_NAME: "provider-gpt-pika", HWLAB_CODE_AGENT_AGENTRUN_GITHUB_TOOL_SECRET_NAME: "agentrun-test-tool-github-pr", HWLAB_CODE_AGENT_AGENTRUN_UNIDESK_SSH_TOOL_SECRET_NAME: "agentrun-test-tool-unidesk-ssh", HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT: "0123456789abcdef0123456789abcdef01234567", HWLAB_CODE_AGENT_AGENTRUN_REPO_URL: "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git", HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "gpt.pika", HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE: "agentrun-v02", HWLAB_CODE_AGENT_AGENTRUN_DISPATCH_RETRY_MAX: "1", HWLAB_CODE_AGENT_AGENTRUN_DISPATCH_RETRY_BASE_MS: "1", HWLAB_CODE_AGENT_AGENTRUN_DISPATCH_RETRY_MAX_DELAY_MS: "1", HWLAB_RUNTIME_API_URL: "http://hwlab-cloud-api.hwlab-v03.svc.cluster.local:6667", HWLAB_RUNTIME_WEB_URL: "http://hwlab-cloud-web.hwlab-v03.svc.cluster.local:8080", HWLAB_RUNTIME_NAMESPACE: "hwlab-v03", HWLAB_RUNTIME_LANE: "v03", HWLAB_RUNTIME_ENDPOINT_LOCKED: "1", HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME: "1", }; } function fakeAgentRunManager(calls: Array<{ method: string; path: string; authorization: string | null; body: any }>, steerDelivery: "steer" | "turn" = "steer"): typeof fetch { return (async (input: string | URL | Request, init: RequestInit = {}) => { const url = new URL(String(input)); const method = init.method ?? "GET"; const body = init.body ? JSON.parse(String(init.body)) : null; calls.push({ method, path: url.pathname, authorization: new Headers(init.headers).get("authorization"), body }); const send = (data: unknown) => Response.json({ ok: true, data }); if (method === "GET" && url.pathname === "/api/v1/provider-profiles/gpt-pika/models") { return send({ status: "ok", profile: "gpt-pika", source: "upstream", items: [{ id: "gpt-5.6" }, { id: "gpt-5.5" }], defaultModel: "gpt-5.6", reasoningEfforts: ["low", "medium", "high", "xhigh"], defaultReasoningEffort: "medium", warning: null, valuesPrinted: false }); } if (method === "POST" && url.pathname === "/api/v1/sessions") { return send({ session: { id: "ses_agentrun_l1_gpt_pika", metadata: {} } }); } if (method === "POST" && url.pathname === "/api/v1/runs") { expect(body.backendProfile).toBe("gpt-pika"); return send({ id: "run_l1_gpt_pika", status: "pending", sessionRef: body.sessionRef, backendProfile: body.backendProfile }); } if (method === "POST" && url.pathname === "/api/v1/runs/run_l1_gpt_pika/commands") { expect(["hi", "first"]).toContain(body.payload.prompt); expect(body.payload.submittedAt).toBe("2026-07-20T01:13:07.699Z"); if (body.payload.prompt === "hi") { expect(body.payload.model).toBe("gpt-5.6"); expect(body.payload.reasoningEffort).toBe("high"); } return send({ id: "cmd_l1_gpt_pika", runId: "run_l1_gpt_pika", state: "pending", type: "turn", seq: 1, dispatchIntent: { id: "dispatch_l1_gpt_pika", state: "pending", runnerJobId: "rjob_l1_gpt_pika", attemptCount: 0, durable: true }, }); } if (method === "POST" && /^\/api\/v1\/sessions\/ses_agentrun_[A-Za-z0-9_]+\/send$/u.test(url.pathname)) { expect(body.payload.requestedDelivery).toBe("steer"); expect(body.payload.targetTraceId).toBe("trc_l1_gpt_pika_smoke"); if (steerDelivery === "steer") { expect(body.payload.prompt).toBe("adjust course"); expect(body.payload.traceId).toBe("trc_steer_l1_gpt_pika"); return send({ decision: "steer", internalCommandType: "steer", run: { id: "run_l1_gpt_pika", status: "pending", backendProfile: "gpt-pika" }, command: { id: "cmd_l1_gpt_pika_steer", runId: "run_l1_gpt_pika", state: "pending", type: "steer", seq: 2 } }); } return send({ decision: "turn", internalCommandType: "turn", run: { id: "run_actual_followup_turn", status: "pending", backendProfile: "gpt-pika", sessionRef: body.run.sessionRef }, command: { id: "cmd_actual_followup_turn", runId: "run_actual_followup_turn", state: "pending", type: "turn", seq: 1, dispatchIntent: { id: "dispatch_actual_followup_turn", state: "pending", runnerJobId: "rjob_actual_followup_turn", attemptCount: 0, durable: true } }, }); } throw new Error(`unexpected AgentRun call ${method} ${url.pathname}`); }) as typeof fetch; }