Files
pikasTech-HWLAB/internal/cloud/server-agent-chat-session.test.ts
T

1359 lines
65 KiB
TypeScript

// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0.
// Responsibility: Cloud API AgentRun session/profile continuity regression tests.
import assert from "node:assert/strict";
import { createServer as createHttpServer } from "node:http";
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { test } from "bun:test";
import { createCloudApiServer } from "./server.ts";
import { createCloudRuntimeStore } from "../db/runtime-store.ts";
import { validateCodeAgentChatSchema } from "./code-agent-chat.ts";
import { createCodexStdioSessionManager } from "./codex-stdio-session.ts";
import { createCodeAgentTraceStore } from "./code-agent-trace-store.ts";
import { submitAgentRunChatTurn } from "./code-agent-agentrun-adapter.ts";
import {
codexStdioChatFixture,
codexStdioReadyFixture,
createFakeAppServerClient,
createFakeCodexCommand,
createManualAgentSession,
delay,
ensureTestAgentAuth,
pollAgentResult,
postAgent,
postAgentRaw,
prepareFakeCodexHome
} from "./server-test-helpers.ts";
const TEST_AGENT_ACTOR = { id: "usr_agent_owner", username: "agent-owner", displayName: "Agent Owner", role: "user", status: "active" };
const TEST_AUTH_SESSION = { id: "auth_ses_agent_owner" };
function testAgentSessionRecord(input = {}) {
const sessionId = input.sessionId ?? input.id;
return {
id: sessionId,
sessionId,
projectId: input.projectId ?? "pikasTech/HWLAB",
agentId: input.agentId ?? "hwlab-code-agent",
status: input.status ?? "idle",
ownerUserId: input.ownerUserId ?? TEST_AGENT_ACTOR.id,
ownerRole: input.ownerRole ?? TEST_AGENT_ACTOR.role,
conversationId: input.conversationId ?? null,
threadId: input.threadId ?? null,
lastTraceId: input.traceId ?? input.lastTraceId ?? null,
session: input.session ?? {},
updatedAt: input.updatedAt ?? "2026-06-03T00:00:00.000Z"
};
}
test("cloud api AgentRun adapter keeps AgentRun sessions scoped to HWLAB session across backend profile switches", async () => {
const calls = [];
const hwlabSessionId = "ses_server-test-profile-switch";
const minimaxSessionId = "ses_agentrun_server_test_profile_switch";
const ownerSessions = new Map([[hwlabSessionId, testAgentSessionRecord({
sessionId: hwlabSessionId,
conversationId: "cnv_server-test-profile-switch",
threadId: "019e8078-db67-7750-a5d9-1a99f3abd445",
traceId: "trc_existing_deepseek",
status: "active",
session: {
agentRun: {
adapter: "agentrun-v01",
backendProfile: "deepseek",
runId: "run_existing_deepseek",
commandId: "cmd_existing_deepseek",
jobName: "agentrun-v01-runner-existing-deepseek",
namespace: "agentrun-v01",
sessionId: "ses_agentrun_server_test_profile_switch",
reuseEligible: true,
managerUrl: "http://127.0.0.1:1",
status: "runner-job-created"
}
}
})]]);
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
const chunks = [];
for await (const chunk of request) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
const body = chunks.length ? JSON.parse(Buffer.concat(chunks).toString("utf8")) : null;
calls.push({ method: request.method, path: url.pathname, body });
const send = (data) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: true, data, traceId: "trc_fake_profile_switch" })}\n`);
};
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_existing_deepseek") {
response.writeHead(500, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, failureKind: "unexpected-reuse", message: "deepseek run must not be reused for minimax-m3" })}\n`);
return;
}
if (request.method === "POST" && url.pathname === "/api/v1/runs") {
assert.equal(body.backendProfile, "minimax-m3");
assert.equal(body.sessionRef.sessionId, minimaxSessionId);
assert.equal(body.sessionRef.threadId, undefined);
assert.equal(body.sessionRef.metadata.hwlabSessionId, hwlabSessionId);
assert.equal(body.sessionRef.metadata.agentRunSessionProfile, "minimax-m3");
return send({ id: "run_hwlab_profile_switch_m3", status: "pending", backendProfile: "minimax-m3", sessionRef: body.sessionRef, resourceBundleRef: body.resourceBundleRef });
}
if (request.method === "POST" && url.pathname === "/api/v1/runs/run_hwlab_profile_switch_m3/commands") {
assert.equal(body.payload.providerProfile, "minimax-m3");
assert.equal(body.payload.sessionId, minimaxSessionId);
assert.equal(body.payload.hwlabSessionId, hwlabSessionId);
assert.equal(body.payload.threadId, null);
assert.equal(body.dispatch?.kind, "kubernetes-job");
assert.equal(body.dispatch?.input?.commandId, undefined);
return send({
id: "cmd_hwlab_profile_switch_m3",
runId: "run_hwlab_profile_switch_m3",
state: "pending",
type: "turn",
seq: 1,
dispatchIntent: {
id: "dispatch_hwlab_profile_switch_m3",
state: "pending",
runnerJobId: "rjob_hwlab_profile_switch_m3",
attemptCount: 0,
durable: true
}
});
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_hwlab_profile_switch_m3/commands") {
return send({ items: [
{ id: "cmd_hwlab_profile_switch_m3", runId: "run_hwlab_profile_switch_m3", state: "completed", type: "turn", seq: 1, idempotencyKey: "trc_server-test-agentrun-profile-switch", payload: { traceId: "trc_server-test-agentrun-profile-switch", conversationId: "cnv_server-test-profile-switch", hwlabSessionId, threadId: "019e8078-db67-7750-a5d9-1a99f3abd445", providerProfile: "minimax-m3" } }
] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_hwlab_profile_switch_m3/events") {
return send({ items: [
{ id: "evt_profile_switch_1", runId: "run_hwlab_profile_switch_m3", seq: 1, type: "backend_status", payload: { phase: "runner-job-created", commandId: "cmd_hwlab_profile_switch_m3", attemptId: "attempt_hwlab_profile_switch_m3", jobName: "agentrun-v01-runner-profile-switch-m3", namespace: "agentrun-v01" }, createdAt: "2026-06-02T00:00:00.000Z" },
{ id: "evt_profile_switch_2", runId: "run_hwlab_profile_switch_m3", seq: 2, type: "assistant_message", payload: { commandId: "cmd_hwlab_profile_switch_m3", text: "AGENTRUN_HWLAB_MINIMAX_M3_OK" }, createdAt: "2026-06-02T00:00:01.000Z" },
{ id: "evt_profile_switch_3", runId: "run_hwlab_profile_switch_m3", seq: 3, type: "terminal_status", payload: { commandId: "cmd_hwlab_profile_switch_m3", terminalStatus: "completed" }, createdAt: "2026-06-02T00:00:02.000Z" }
] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_hwlab_profile_switch_m3/commands/cmd_hwlab_profile_switch_m3/result") {
return send({
runId: "run_hwlab_profile_switch_m3",
commandId: "cmd_hwlab_profile_switch_m3",
attemptId: "attempt_hwlab_profile_switch_m3",
runnerId: "runner_hwlab_profile_switch_m3",
jobName: "agentrun-v01-runner-profile-switch-m3",
namespace: "agentrun-v01",
status: "completed",
runStatus: "completed",
commandState: "completed",
terminalStatus: "completed",
completed: true,
messageId: "msg_profile_switch_m3",
reply: "AGENTRUN_HWLAB_MINIMAX_M3_OK",
lastSeq: 3,
eventCount: 3,
sessionRef: { sessionId: minimaxSessionId, conversationId: "cnv_server-test-profile-switch", threadId: "019e8078-db67-7750-a5d9-1a99f3abd445" }
});
}
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, failureKind: "schema-invalid", message: `unexpected ${request.method} ${url.pathname}`, traceId: "trc_fake_profile_switch" })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
const server = createCloudApiServer({
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT: "0123456789abcdef0123456789abcdef01234567",
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "deepseek",
HWLAB_ENVIRONMENT: "v02",
HWLAB_GITOPS_PROFILE: "v02"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
},
async recordAgentSessionOwner(input) {
const record = testAgentSessionRecord(input);
ownerSessions.set(record.id, record);
return record;
},
async getAgentSession(sessionId) {
return ownerSessions.get(sessionId) ?? null;
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const traceId = "trc_server-test-agentrun-profile-switch";
const submit = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: { "content-type": "application/json", "x-trace-id": traceId, cookie: "hwlab_session=test-stub-session" },
body: JSON.stringify({
conversationId: "cnv_server-test-profile-switch",
sessionId: hwlabSessionId,
ownerUserId: "usr_agent_owner",
ownerRole: "user",
threadId: "019e8078-db67-7750-a5d9-1a99f3abd445",
providerProfile: "minimax-m3",
message: "Switch this HWLAB session to MiniMax-M3 through AgentRun"
})
});
assert.equal(submit.status, 202);
const payload = await pollAgentResult(port, traceId);
assert.equal(payload.status, "completed");
assert.equal(payload.sessionId, hwlabSessionId);
assert.equal(payload.agentRun.backendProfile, "minimax-m3");
assert.equal(payload.agentRun.runId, "run_hwlab_profile_switch_m3");
assert.equal(payload.agentRun.sessionId, minimaxSessionId);
assert.equal(calls.some((call) => call.method === "GET" && call.path === "/api/v1/runs/run_existing_deepseek"), false);
assert.equal(calls.filter((call) => call.method === "POST" && call.path === "/api/v1/runs").length, 1);
const stored = ownerSessions.get(hwlabSessionId);
assert.equal(stored.session.providerProfile, "minimax-m3");
assert.equal(stored.session.agentRun.backendProfile, "minimax-m3");
assert.equal(stored.session.agentRun.sessionId, minimaxSessionId);
assert.equal(calls.some((call) => call.path.endsWith("/runner-jobs")), false);
} finally {
await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
await new Promise((resolve, reject) => agentRunServer.close((error) => (error ? reject(error) : resolve())));
}
});
test("cloud api AgentRun adapter starts a fresh AgentRun session after a failed stale continuation when provider changes", async () => {
const calls = [];
const hwlabSessionId = "ses_server-test-stale-continuation-switch";
const conversationId = "cnv_server-test-stale-continuation-switch";
const staleThreadId = "thread_stale_bad_model";
const ownerSessions = new Map([[hwlabSessionId, testAgentSessionRecord({
sessionId: hwlabSessionId,
conversationId,
threadId: staleThreadId,
traceId: "trc_stale_bad_model",
status: "thread-resume-failed",
session: {
providerProfile: "codex-api",
codeAgentProviderProfile: "codex-api",
continuation: {
requiresFreshSession: true,
reasonCode: "provider-stream-disconnected",
staleThreadId,
traceId: "trc_stale_bad_model",
valuesRedacted: true
},
agentRun: {
adapter: "agentrun-v01",
backendProfile: "codex-api",
runId: "run_stale_bad_model",
commandId: "cmd_stale_bad_model",
sessionId: "ses_agentrun_stale_bad_model",
threadId: staleThreadId,
terminalStatus: "failed",
reuseEligible: false
}
}
})]]);
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
const chunks = [];
for await (const chunk of request) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
const body = chunks.length ? JSON.parse(Buffer.concat(chunks).toString("utf8")) : null;
calls.push({ method: request.method, path: url.pathname, body });
const send = (data, status = 200) => {
response.writeHead(status, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: status < 400, data, traceId: "trc_fake_stale_continuation_switch" })}\n`);
};
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_stale_bad_model") {
return send({ message: "stale run must not be reused after provider switch" }, 500);
}
if (request.method === "POST" && url.pathname === "/api/v1/sessions") {
assert.match(body.sessionId, /-reset-/u);
assert.equal(body.backendProfile, "dsflash-go");
return send({ sessionId: body.sessionId, backendProfile: body.backendProfile });
}
if (request.method === "POST" && url.pathname === "/api/v1/runs") {
assert.equal(body.backendProfile, "dsflash-go");
assert.match(body.sessionRef?.sessionId, /-reset-/u);
assert.equal(body.sessionRef?.threadId, undefined);
assert.equal(body.sessionRef?.metadata?.hwlabSessionId, hwlabSessionId);
assert.equal(body.sessionRef?.metadata?.agentRunSessionProfile, "dsflash-go");
return send({ id: "run_stale_recovery_dsflash", status: "pending", backendProfile: "dsflash-go", sessionRef: body.sessionRef, resourceBundleRef: body.resourceBundleRef });
}
if (request.method === "POST" && url.pathname === "/api/v1/runs/run_stale_recovery_dsflash/commands") {
assert.equal(body.payload.providerProfile, "dsflash-go");
assert.match(body.payload.sessionId, /-reset-/u);
assert.equal(body.payload.hwlabSessionId, hwlabSessionId);
assert.equal(body.payload.threadId, null);
assert.equal(body.dispatch?.kind, "kubernetes-job");
assert.equal(body.dispatch?.input?.commandId, undefined);
return send({
id: "cmd_stale_recovery_dsflash",
runId: "run_stale_recovery_dsflash",
state: "pending",
type: "turn",
seq: 1,
dispatchIntent: {
id: "dispatch_stale_recovery_dsflash",
state: "pending",
runnerJobId: "rjob_stale_recovery_dsflash",
attemptCount: 0,
durable: true
}
});
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_stale_recovery_dsflash/commands") {
return send({ items: [
{ id: "cmd_stale_recovery_dsflash", runId: "run_stale_recovery_dsflash", state: "completed", type: "turn", seq: 1, idempotencyKey: "trc_server-test-stale-continuation-switch", payload: { traceId: "trc_server-test-stale-continuation-switch", conversationId, hwlabSessionId, threadId: "thread_recovered_dsflash", providerProfile: "dsflash-go" } }
] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_stale_recovery_dsflash/events") {
return send({ items: [
{ id: "evt_stale_recovery_1", runId: "run_stale_recovery_dsflash", seq: 1, type: "backend_status", payload: { phase: "runner-job-created", commandId: "cmd_stale_recovery_dsflash" }, createdAt: "2026-06-30T00:00:00.000Z" },
{ id: "evt_stale_recovery_2", runId: "run_stale_recovery_dsflash", seq: 2, type: "assistant_message", payload: { commandId: "cmd_stale_recovery_dsflash", text: "AGENTRUN_STALE_RECOVERY_OK", final: true, replyAuthority: true }, createdAt: "2026-06-30T00:00:01.000Z" },
{ id: "evt_stale_recovery_3", runId: "run_stale_recovery_dsflash", seq: 3, type: "terminal_status", payload: { commandId: "cmd_stale_recovery_dsflash", terminalStatus: "completed" }, createdAt: "2026-06-30T00:00:02.000Z" }
] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_stale_recovery_dsflash/commands/cmd_stale_recovery_dsflash/result") {
return send({
runId: "run_stale_recovery_dsflash",
commandId: "cmd_stale_recovery_dsflash",
attemptId: "attempt_stale_recovery_dsflash",
runnerId: "runner_stale_recovery_dsflash",
jobName: "agentrun-v01-runner-stale-recovery-dsflash",
namespace: "agentrun-v01",
status: "completed",
runStatus: "completed",
commandState: "completed",
terminalStatus: "completed",
completed: true,
reply: "AGENTRUN_STALE_RECOVERY_OK",
lastSeq: 3,
eventCount: 3,
sessionRef: { sessionId: calls.find((call) => call.method === "POST" && call.path === "/api/v1/runs")?.body?.sessionRef?.sessionId, conversationId, threadId: "thread_recovered_dsflash" }
});
}
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, failureKind: "schema-invalid", message: `unexpected ${request.method} ${url.pathname}`, traceId: "trc_fake_stale_continuation_switch" })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
const server = createCloudApiServer({
traceStore: createCodeAgentTraceStore(),
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "JD01",
HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT: "0123456789abcdef0123456789abcdef01234567",
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "codex-api",
HWLAB_ENVIRONMENT: "v03",
HWLAB_GITOPS_PROFILE: "v03"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
},
async recordAgentSessionOwner(input) {
const previous = ownerSessions.get(input.sessionId) ?? null;
const record = testAgentSessionRecord({
...(previous ?? {}),
...input,
threadId: input.threadId ?? previous?.threadId ?? null,
session: { ...(previous?.session ?? {}), ...(input.session ?? {}) }
});
ownerSessions.set(record.id, record);
return record;
},
async getAgentSession(sessionId) {
return ownerSessions.get(sessionId) ?? null;
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const traceId = "trc_server-test-stale-continuation-switch";
const submit = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: { "content-type": "application/json", "x-trace-id": traceId, cookie: "hwlab_session=test-stub-session" },
body: JSON.stringify({
conversationId,
sessionId: hwlabSessionId,
ownerUserId: "usr_agent_owner",
ownerRole: "user",
threadId: staleThreadId,
providerProfile: "dsflash-go",
message: "Continue after the first model failed"
})
});
assert.equal(submit.status, 202);
const payload = await pollAgentResult(port, traceId);
assert.equal(payload.status, "completed");
assert.equal(payload.finalResponse?.text ?? payload.reply?.content, "AGENTRUN_STALE_RECOVERY_OK");
assert.equal(payload.agentRun.backendProfile, "dsflash-go");
assert.match(payload.agentRun.sessionId, /-reset-/u);
assert.equal(calls.some((call) => call.method === "GET" && call.path === "/api/v1/runs/run_stale_bad_model"), false);
assert.equal(calls.filter((call) => call.method === "POST" && call.path === "/api/v1/runs").length, 1);
const commandCall = calls.find((call) => call.method === "POST" && call.path === "/api/v1/runs/run_stale_recovery_dsflash/commands");
assert.equal(commandCall.body.payload.threadId, null);
const stored = ownerSessions.get(hwlabSessionId);
assert.equal(stored.status, "completed");
assert.equal(stored.threadId, "thread_recovered_dsflash");
assert.equal(stored.session.providerProfile, "dsflash-go");
assert.equal(stored.session.continuation.requiresFreshSession, false);
assert.equal(calls.some((call) => call.path.endsWith("/runner-jobs")), false);
} finally {
await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
await new Promise((resolve, reject) => agentRunServer.close((error) => (error ? reject(error) : resolve())));
}
});
test("cloud api AgentRun adapter inherits session provider profile when a recovered Workbench page omits it", async () => {
const calls = [];
const hwlabSessionId = "ses_server-test-profile-inherit";
const agentRunSessionId = "ses_agentrun_server_test_profile_inherit";
const conversationId = "cnv_server-test-profile-inherit";
const threadId = "019e8078-db67-7750-a5d9-1a99f3abd446";
const ownerSessions = new Map([[hwlabSessionId, testAgentSessionRecord({
sessionId: hwlabSessionId,
conversationId,
threadId,
traceId: "trc_existing_dsflash_go",
status: "active",
session: {
providerProfile: "dsflash-go",
codeAgentProviderProfile: "dsflash-go",
agentRun: {
adapter: "agentrun-v01",
backendProfile: "dsflash-go",
runId: "run_existing_dsflash_go",
commandId: "cmd_existing_dsflash_go",
sessionId: agentRunSessionId,
terminalStatus: "completed",
reuseEligible: false
}
}
})]]);
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
const chunks = [];
for await (const chunk of request) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
const body = chunks.length ? JSON.parse(Buffer.concat(chunks).toString("utf8")) : null;
calls.push({ method: request.method, path: url.pathname, body });
const send = (data) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: true, data, traceId: "trc_fake_profile_inherit" })}\n`);
};
if (request.method === "POST" && url.pathname === "/api/v1/runs") {
assert.equal(body.backendProfile, "dsflash-go");
assert.equal(body.sessionRef.sessionId, agentRunSessionId);
assert.equal(body.sessionRef.metadata.hwlabSessionId, hwlabSessionId);
assert.equal(body.sessionRef.metadata.agentRunSessionProfile, "dsflash-go");
return send({ id: "run_hwlab_profile_inherit", status: "pending", backendProfile: "dsflash-go", sessionRef: body.sessionRef, resourceBundleRef: body.resourceBundleRef });
}
if (request.method === "POST" && url.pathname === "/api/v1/runs/run_hwlab_profile_inherit/commands") {
assert.equal(body.payload.providerProfile, "dsflash-go");
assert.equal(body.payload.sessionId, agentRunSessionId);
assert.equal(body.payload.hwlabSessionId, hwlabSessionId);
assert.equal(body.payload.threadId, null);
assert.equal(body.dispatch?.kind, "kubernetes-job");
assert.equal(body.dispatch?.input?.commandId, undefined);
return send({
id: "cmd_hwlab_profile_inherit",
runId: "run_hwlab_profile_inherit",
state: "pending",
type: "turn",
seq: 1,
dispatchIntent: {
id: "dispatch_hwlab_profile_inherit",
state: "pending",
runnerJobId: "rjob_hwlab_profile_inherit",
attemptCount: 0,
durable: true
}
});
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_hwlab_profile_inherit/commands") {
return send({ items: [
{ id: "cmd_hwlab_profile_inherit", runId: "run_hwlab_profile_inherit", state: "completed", type: "turn", seq: 1, idempotencyKey: "trc_server-test-agentrun-profile-inherit", payload: { traceId: "trc_server-test-agentrun-profile-inherit", conversationId, hwlabSessionId, threadId, providerProfile: "dsflash-go" } }
] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_hwlab_profile_inherit/events") {
return send({ items: [
{ id: "evt_profile_inherit_1", runId: "run_hwlab_profile_inherit", seq: 1, type: "backend_status", payload: { phase: "runner-job-created", commandId: "cmd_hwlab_profile_inherit", attemptId: "attempt_hwlab_profile_inherit", jobName: "agentrun-v01-runner-profile-inherit", namespace: "agentrun-v01" }, createdAt: "2026-06-02T00:00:00.000Z" },
{ id: "evt_profile_inherit_2", runId: "run_hwlab_profile_inherit", seq: 2, type: "assistant_message", payload: { commandId: "cmd_hwlab_profile_inherit", text: "AGENTRUN_DSFLASH_GO_OK" }, createdAt: "2026-06-02T00:00:01.000Z" },
{ id: "evt_profile_inherit_3", runId: "run_hwlab_profile_inherit", seq: 3, type: "terminal_status", payload: { commandId: "cmd_hwlab_profile_inherit", terminalStatus: "completed" }, createdAt: "2026-06-02T00:00:02.000Z" }
] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_hwlab_profile_inherit/commands/cmd_hwlab_profile_inherit/result") {
return send({
runId: "run_hwlab_profile_inherit",
commandId: "cmd_hwlab_profile_inherit",
attemptId: "attempt_hwlab_profile_inherit",
runnerId: "runner_hwlab_profile_inherit",
jobName: "agentrun-v01-runner-profile-inherit",
namespace: "agentrun-v01",
status: "completed",
runStatus: "completed",
commandState: "completed",
terminalStatus: "completed",
completed: true,
messageId: "msg_profile_inherit",
reply: "AGENTRUN_DSFLASH_GO_OK",
lastSeq: 3,
eventCount: 3,
sessionRef: { sessionId: agentRunSessionId, conversationId, threadId }
});
}
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, failureKind: "schema-invalid", message: `unexpected ${request.method} ${url.pathname}`, traceId: "trc_fake_profile_inherit" })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
const server = createCloudApiServer({
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT: "0123456789abcdef0123456789abcdef01234567",
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "codex",
HWLAB_ENVIRONMENT: "v02",
HWLAB_GITOPS_PROFILE: "v02"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
},
async recordAgentSessionOwner(input) {
const previous = ownerSessions.get(input.sessionId)?.session ?? {};
const record = testAgentSessionRecord({ ...input, session: { ...previous, ...(input.session ?? {}) } });
ownerSessions.set(record.id, record);
return record;
},
async getAgentSession(sessionId) {
return ownerSessions.get(sessionId) ?? null;
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const traceId = "trc_server-test-agentrun-profile-inherit";
const submit = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: { "content-type": "application/json", "x-trace-id": traceId, cookie: "hwlab_session=test-stub-session" },
body: JSON.stringify({
conversationId,
sessionId: hwlabSessionId,
ownerUserId: "usr_agent_owner",
ownerRole: "user",
message: "Continue with the Workbench session provider profile"
})
});
assert.equal(submit.status, 202);
const payload = await pollAgentResult(port, traceId);
assert.equal(payload.status, "completed");
assert.equal(payload.agentRun.backendProfile, "dsflash-go");
assert.equal(calls.filter((call) => call.method === "POST" && call.path === "/api/v1/runs").length, 1);
const stored = ownerSessions.get(hwlabSessionId);
assert.equal(stored.session.providerProfile, "dsflash-go");
assert.equal(stored.session.agentRun.backendProfile, "dsflash-go");
assert.equal(calls.some((call) => call.path.endsWith("/runner-jobs")), false);
} finally {
await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
await new Promise((resolve, reject) => agentRunServer.close((error) => (error ? reject(error) : resolve())));
}
});
test("cloud api AgentRun adapter rejects non-internal manager URLs by default", async () => {
const server = createCloudApiServer({
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
AGENTRUN_MGR_URL: "http://74.48.78.17:8080"
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const manualSession = await createManualAgentSession(port, {
conversationId: "cnv_server-test-agentrun-public-url"
});
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: { "content-type": "application/json", "x-trace-id": "trc_server-test-agentrun-public-url", cookie: manualSession.cookie },
body: JSON.stringify({ conversationId: manualSession.conversationId, sessionId: manualSession.sessionId, message: "must reject public manager url" })
});
assert.equal(response.status, 202);
const body = await response.json();
assert.equal(body.accepted, true);
const result = await pollAgentResult(port, "trc_server-test-agentrun-public-url");
assert.equal(result.status, "failed");
assert.match(JSON.stringify(result), /internal k3s Service DNS/u);
} finally {
await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
}
});
test("cloud api /v1/agent/chat records authenticated owner on agent session", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-owner-"));
const codexHome = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-owner-codex-home-"));
const ownerRecords = [];
const ownerSessions = new Map([["ses_server-test-owner", testAgentSessionRecord({
sessionId: "ses_server-test-owner",
conversationId: "cnv_server-test-owner",
status: "idle"
})]]);
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_SANDBOX: "danger-full-access",
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
accessController: {
required: true,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
},
async recordAgentSessionOwner(input) {
const record = testAgentSessionRecord(input);
ownerRecords.push(input);
ownerSessions.set(record.id, record);
return record;
},
async getAgentSession(sessionId) {
return ownerSessions.get(sessionId) ?? null;
}
},
codexStdioManager: {
describe() { return { ...codexStdioReadyFixture({ workspace, codexHome }), sandbox: "danger-full-access" }; },
async probe() { return { ...codexStdioReadyFixture({ workspace, codexHome }), sandbox: "danger-full-access" }; },
async chat(params = {}) {
return {
...codexStdioChatFixture({ workspace, codexHome, params }),
sandbox: "danger-full-access"
};
},
cancel() {},
reapIdle() {}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server-test-owner",
sessionId: "ses_server-test-owner",
traceId: "trc_server-test-owner",
message: "owner binding smoke"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.ownerUserId, "usr_agent_owner");
assert.equal(ownerRecords.length, 2);
assert.equal(ownerRecords[0].status, "running");
const terminalOwnerRecord = ownerRecords.at(-1);
assert.equal(terminalOwnerRecord.ownerUserId, "usr_agent_owner");
assert.equal(terminalOwnerRecord.sessionId, "ses_server_stdio_pwd");
assert.equal(terminalOwnerRecord.conversationId, "cnv_server-test-owner");
assert.equal(terminalOwnerRecord.traceId, "trc_server-test-owner");
assert.equal(terminalOwnerRecord.status, "completed");
assert.equal(terminalOwnerRecord.session.messageCount, 2);
assert.equal(terminalOwnerRecord.session.messages.length, 2);
assert.equal(terminalOwnerRecord.session.messages[0].role, "user");
assert.equal(terminalOwnerRecord.session.messages[0].text, "owner binding smoke");
assert.equal(terminalOwnerRecord.session.messages[0].status, "sent");
assert.equal(terminalOwnerRecord.session.messages[1].role, "agent");
assert.equal(terminalOwnerRecord.session.messages[1].status, "completed");
assert.equal(terminalOwnerRecord.session.messages[1].traceId, "trc_server-test-owner");
assert.equal(terminalOwnerRecord.session.firstUserMessagePreview, "owner binding smoke");
assert.equal(terminalOwnerRecord.session.valuesRedacted, true);
assert.equal(JSON.stringify(ownerRecords).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(codexHome, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat/inspect maps conversation session and thread details to trace evidence", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-inspect-"));
const codexHome = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-inspect-codex-home-"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_SANDBOX: "danger-full-access",
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: {
describe() {
return {
...codexStdioReadyFixture({ workspace, codexHome }),
sandbox: "danger-full-access",
recentSessions: [{
sessionId: "ses_server_stdio_pwd",
conversationId: "cnv_server-test-inspect",
threadId: "019e6c72-2373-75e3-9856-eff286db7163",
status: "idle",
currentTraceId: null,
lastTraceId: "trc_server-test-inspect",
workspace,
sandbox: "danger-full-access",
secretMaterialStored: false,
valuesRedacted: true
}]
};
},
async probe() {
return {
...codexStdioReadyFixture({ workspace, codexHome }),
sandbox: "danger-full-access"
};
},
async chat(params = {}) {
const base = codexStdioChatFixture({ workspace, codexHome, params });
return {
...base,
sandbox: "danger-full-access",
session: {
...base.session,
threadId: "019e6c72-2373-75e3-9856-eff286db7163",
sandbox: "danger-full-access"
},
sessionReuse: {
...base.sessionReuse,
threadId: "019e6c72-2373-75e3-9856-eff286db7163"
}
};
},
get(sessionId) {
if (sessionId !== "ses_server_stdio_pwd") return null;
return {
sessionId,
conversationId: "cnv_server-test-inspect",
threadId: "019e6c72-2373-75e3-9856-eff286db7163",
status: "idle",
lastTraceId: "trc_server-test-inspect",
workspace,
sandbox: "danger-full-access",
secretMaterialStored: false,
valuesRedacted: true
};
},
cancel() {},
reapIdle() {}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const traceId = "trc_server-test-inspect";
const manualSession = await createManualAgentSession(port, {
conversationId: "cnv_server-test-inspect"
});
const submit = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
cookie: manualSession.cookie,
"x-trace-id": traceId,
"prefer": "respond-async",
"x-hwlab-short-connection": "1"
},
body: JSON.stringify({
conversationId: manualSession.conversationId,
sessionId: manualSession.sessionId,
message: "inspect mapping smoke"
})
});
assert.equal(submit.status, 202);
const payload = await pollAgentResult(port, traceId);
assert.equal(payload.status, "completed");
const inspect = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/inspect?conversationId=cnv_server-test-inspect&sessionId=${manualSession.sessionId}&threadId=019e6c72-2373-75e3-9856-eff286db7163`);
assert.equal(inspect.status, 200);
const body = await inspect.json();
assert.equal(body.ok, true);
assert.equal(body.status, "found");
assert.equal(body.latestTraceId, traceId);
assert.equal(body.traceUrl, `/v1/agent/traces/${traceId}`);
assert.equal(body.resultUrl, `/v1/agent/chat/result/${traceId}`);
assert.equal(body.query.sessionId, manualSession.sessionId);
assert.equal(body.query.threadId, "019e6c72-2373-75e3-9856-eff286db7163");
assert.equal(body.session.sessionId, "ses_server_stdio_pwd");
assert.equal(body.session.threadId, "019e6c72-2373-75e3-9856-eff286db7163");
assert.equal(body.conversationFacts.conversationId, "cnv_server-test-inspect");
assert.equal(body.runnerTrace.traceId, traceId);
assert.equal(body.valuesRedacted, true);
assert.equal(body.secretMaterialStored, false);
assert.equal(JSON.stringify(body).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(codexHome, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat/inspect returns not_found for empty conversation facts", async () => {
const server = createCloudApiServer();
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/inspect?conversationId=cnv_server-test-inspect-missing&sessionId=ses_server_test_missing&threadId=019e6c72-2373-75e3-9856-eff286db7163&traceId=trc_server_test_missing`);
assert.equal(response.status, 404);
const body = await response.json();
assert.equal(body.ok, false);
assert.equal(body.status, "not_found");
assert.equal(body.latestTraceId, null);
assert.deepEqual(body.traceIds, []);
assert.equal(body.traceUrl, null);
assert.equal(body.resultUrl, null);
assert.equal(body.conversationFacts.turnCount, 0);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api trace reports expired projection without AgentRun read-through when live trace store has expired (#1519)", async () => {
const ownerSessions = new Map();
const agentRunCalls = [];
const commandFinalText = "历史 trace 已过期,但 final response 来自 AgentRun command result。";
ownerSessions.set("ses_issue842_expired", testAgentSessionRecord({
sessionId: "ses_issue842_expired",
projectId: "prj_v02_code_agent",
conversationId: "cnv_issue842_expired",
threadId: "thread-issue-842-expired",
traceId: "trc_issue842_expired",
status: "active",
session: {
finalResponse: {
text: "旧 session snapshot final 不应作为历史 trace 权威。",
textChars: 30,
role: "assistant",
status: "completed",
traceId: "trc_issue842_expired",
source: "code-agent-result",
valuesPrinted: false
},
traceSummary: {
traceId: "trc_issue842_expired",
source: "stale-derived-session-evidence",
sourceEventCount: 26,
terminalStatus: "completed",
noiseEventCount: 4,
omittedNoiseCount: 4,
valuesPrinted: false
},
agentRun: {
adapter: "agentrun-v01",
runId: "run_issue842_expired",
commandId: "cmd_issue842_expired",
runnerId: "runner_issue842_expired",
jobName: "agentrun-v01-runner-issue842-expired",
namespace: "agentrun-v01",
terminalStatus: "completed",
valuesPrinted: false
},
valuesRedacted: true
}
}));
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
agentRunCalls.push({ method: request.method, path: url.pathname, search: url.search });
const send = (data) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: true, data, traceId: "trc_fake_issue842_expired" })}\n`);
};
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_issue842_expired/commands") {
return send({ items: [
{ id: "cmd_issue842_expired", runId: "run_issue842_expired", state: "completed", type: "turn", seq: 1, idempotencyKey: "trc_issue842_expired", payload: { traceId: "trc_issue842_expired", conversationId: "cnv_issue842_expired", hwlabSessionId: "ses_issue842_expired", threadId: "thread-issue-842-expired", providerProfile: "deepseek" } }
] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_issue842_expired/events") {
return send({ items: [] });
}
if (request.method === "GET" && url.pathname === "/api/v1/runs/run_issue842_expired/commands/cmd_issue842_expired/result") {
return send({
runId: "run_issue842_expired",
commandId: "cmd_issue842_expired",
attemptId: "attempt_issue842_expired",
runnerId: "runner_issue842_expired",
jobName: "agentrun-v01-runner-issue842-expired",
namespace: "agentrun-v01",
status: "completed",
runStatus: "completed",
commandState: "completed",
terminalStatus: "completed",
completed: true,
reply: commandFinalText,
lastSeq: 26,
eventCount: 26,
sessionRef: { sessionId: "ses_agentrun_issue842_expired", conversationId: "cnv_issue842_expired", threadId: "thread-issue-842-expired" }
});
}
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, message: `unexpected ${request.method} ${url.pathname}` })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
const traceStore = createCodeAgentTraceStore();
const server = createCloudApiServer({
traceStore,
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
HWLAB_ENVIRONMENT: "v02",
HWLAB_GITOPS_PROFILE: "v02"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
},
async getAgentSessionByTraceId(traceId) {
return [...ownerSessions.values()].find((session) => session.lastTraceId === traceId) ?? null;
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/traces/trc_issue842_expired`, {
headers: { cookie: "hwlab_session=test-stub-session" }
});
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.ok, false);
assert.equal(body.status, "missing");
assert.equal(body.traceStatus, "missing");
assert.equal(body.eventCount, 0);
assert.equal(body.projectionStatus, "unknown");
assert.equal(body.retention.liveTraceStore, "missing");
assert.equal(JSON.stringify(body).includes("旧 session snapshot final"), false);
assert.deepEqual(agentRunCalls, []);
assert.equal(JSON.stringify(body).includes("password"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
agentRunServer.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api trace does not replay an earlier AgentRun command from GET after same-run lastSeq advances (#1519)", async () => {
const calls = [];
const firstTraceId = "trc_issue955_first_trace";
const codeAgentChatResults = new Map();
const runId = "run_issue955_replay";
const firstCommandId = "cmd_issue955_first";
const secondCommandId = "cmd_issue955_second";
const firstFinalText = "目前只有一个 HWPOD 可用:\n\n- d601-f103-v2 (board: D601-F103-V2 / STM32F103)\n\nAPI 返回 count=1, availableCount=1。";
const firstEvents = [
{ id: "evt_issue955_first_setup", runId, seq: 1, type: "backend_status", payload: { phase: "runner-job-created", commandId: firstCommandId, jobName: "agentrun-v01-runner-issue955-first", namespace: "agentrun-v01" }, createdAt: "2026-06-06T01:43:25.000Z" },
{ id: "evt_issue955_first_tool", runId, seq: 18, type: "tool_call", payload: { method: "item/completed", type: "commandExecution", toolName: "commandExecution", itemId: "call_issue955_hwpod_list", command: "/bin/sh -lc 'hwpod list --available'", status: "completed", exitCode: 0, outputSummary: '{"count":1,"availableCount":1,"ids":["d601-f103-v2"]}', commandId: firstCommandId }, createdAt: "2026-06-06T01:43:42.000Z" },
{ id: "evt_issue955_first_assistant", runId, seq: 27, type: "assistant_message", payload: { commandId: firstCommandId, itemId: "msg_item_0", text: firstFinalText }, createdAt: "2026-06-06T01:43:55.000Z" },
{ id: "evt_issue955_first_terminal", runId, seq: 35, type: "terminal_status", payload: { commandId: firstCommandId, terminalStatus: "completed" }, createdAt: "2026-06-06T01:43:56.000Z" }
];
const secondEvents = [
{ id: "evt_issue955_second_setup", runId, seq: 47, type: "backend_status", payload: { phase: "runner-claim-waiting-for-stale-lease" }, createdAt: "2026-06-06T01:45:56.000Z" },
{ id: "evt_issue955_second_assistant", runId, seq: 58, type: "assistant_message", payload: { commandId: secondCommandId, itemId: "msg_item_0", text: "编译成功!来总结一下结果。" }, createdAt: "2026-06-06T01:46:24.000Z" },
{ id: "evt_issue955_second_terminal", runId, seq: 66, type: "terminal_status", payload: { commandId: secondCommandId, terminalStatus: "completed" }, createdAt: "2026-06-06T01:46:28.000Z" }
];
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
calls.push({ method: request.method, path: url.pathname, afterSeq: url.searchParams.get("afterSeq") });
const send = (data) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: true, data, traceId: "trc_fake_issue955_replay" })}\n`);
};
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/commands`) {
return send({ items: [
{ id: firstCommandId, runId, state: "completed", idempotencyKey: firstTraceId, createdAt: "2026-06-06T01:43:30.040Z", updatedAt: "2026-06-06T01:43:56.000Z", payload: { traceId: firstTraceId, conversationId: "cnv_issue955_replay", hwlabSessionId: "ses_issue955_replay", threadId: "thread-issue955-replay", providerProfile: "deepseek" } },
{ id: secondCommandId, runId, state: "completed", idempotencyKey: "trc_issue955_second_trace", createdAt: "2026-06-06T01:46:11.000Z", updatedAt: "2026-06-06T01:46:28.000Z", payload: { traceId: "trc_issue955_second_trace", conversationId: "cnv_issue955_replay", hwlabSessionId: "ses_issue955_replay", threadId: "thread-issue955-replay", providerProfile: "deepseek" } }
] });
}
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/commands/${firstCommandId}/result`) {
return send({ runId, commandId: firstCommandId, status: "completed", runStatus: "completed", commandState: "completed", terminalStatus: "completed", completed: true, reply: firstFinalText, lastSeq: 35, eventCount: 35, sessionRef: { sessionId: "ses_agentrun_deepseek_issue955_replay", conversationId: "cnv_issue955_replay", threadId: "thread-issue955-replay" } });
}
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/events`) {
return send({ items: [...firstEvents, ...secondEvents] });
}
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, message: `unexpected ${request.method} ${url.pathname}` })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
codeAgentChatResults.set(firstTraceId, {
accepted: true,
status: "completed",
shortConnection: true,
traceId: firstTraceId,
conversationId: "cnv_issue955_replay",
sessionId: "ses_issue955_replay",
threadId: "thread-issue955-replay",
ownerUserId: TEST_AGENT_ACTOR.id,
ownerRole: TEST_AGENT_ACTOR.role,
reply: { role: "assistant", content: firstFinalText },
finalResponse: { text: firstFinalText, textChars: firstFinalText.length, role: "assistant", status: "completed", traceId: firstTraceId, valuesPrinted: false },
traceSummary: { traceId: firstTraceId, source: "code-agent-derived-session-evidence", sourceEventCount: 41, terminalStatus: "completed", agentRun: { runId, commandId: firstCommandId, lastSeq: 35, valuesPrinted: false }, valuesPrinted: false },
agentRun: { adapter: "agentrun-v01", managerUrl: `http://127.0.0.1:${agentRunPort}`, runId, commandId: firstCommandId, lastSeq: 66, terminalStatus: "completed", valuesPrinted: false },
valuesPrinted: false
});
const traceStore = createCodeAgentTraceStore();
const server = createCloudApiServer({
traceStore,
codeAgentChatResults,
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
HWLAB_ENVIRONMENT: "v02",
HWLAB_GITOPS_PROFILE: "v02"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/traces/${firstTraceId}`, {
headers: { cookie: "hwlab_session=test-stub-session" }
});
assert.equal(response.status, 200);
const body = await response.json();
const text = JSON.stringify(body);
assert.equal(body.traceId, firstTraceId);
assert.equal(body.status, "expired");
assert.equal(body.projectionStatus, "caught-up");
assert.deepEqual(calls, []);
assert.equal(body.eventCount, 0);
assert.deepEqual(body.events, []);
assert.equal(body.finalResponse.text, firstFinalText);
assert.match(text, /d601-f103-v2/u);
assert.doesNotMatch(text, /编译成功/u);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
agentRunServer.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api running trace reports current projection without AgentRun event refresh (#1519)", async () => {
const calls = [];
const traceId = "trc_issue1000_running_trace";
const runId = "run_issue1000_running_trace";
const commandId = "cmd_issue1000_running_trace";
const codeAgentChatResults = new Map();
const events = [
{ id: "evt_issue1000_created", runId, seq: 1, type: "backend_status", payload: { phase: "runner-job-created", commandId, jobName: "agentrun-v01-runner-issue1000", namespace: "agentrun-v01" }, createdAt: "2026-06-06T08:34:30.000Z" },
{ id: "evt_issue1000_turn", runId, seq: 2, type: "backend_status", payload: { phase: "turn/started", commandId }, createdAt: "2026-06-06T08:34:31.000Z" },
{ id: "evt_issue1000_tool", runId, seq: 3, type: "tool_call", payload: { method: "item/completed", type: "commandExecution", toolName: "commandExecution", itemId: "call_issue1000_hwpod", command: "hwpod list --available", status: "completed", exitCode: 0, outputSummary: "available=1", commandId }, createdAt: "2026-06-06T08:34:32.000Z" },
{ id: "evt_issue1000_output", runId, seq: 4, type: "assistant_message", payload: { commandId, itemId: "msg_issue1000_running", text: "正在查看 HWPOD。" }, createdAt: "2026-06-06T08:34:33.000Z" }
];
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
calls.push({ method: request.method, path: url.pathname, search: url.search });
const send = (data) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: true, data, traceId: "trc_fake_issue1000_running" })}\n`);
};
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/events`) return send({ items: events });
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/commands/${commandId}/result`) {
return send({ runId, commandId, status: "running", runStatus: "running", commandState: "running", terminalStatus: null, completed: false, reply: null, lastSeq: 3, eventCount: 3 });
}
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, message: `unexpected ${request.method} ${url.pathname}` })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
codeAgentChatResults.set(traceId, {
accepted: true,
status: "running",
shortConnection: true,
traceId,
conversationId: "cnv_issue1000_running_trace",
sessionId: "ses_issue1000_running_trace",
threadId: "thread-issue1000-running-trace",
ownerUserId: TEST_AGENT_ACTOR.id,
ownerRole: TEST_AGENT_ACTOR.role,
agentRun: { adapter: "agentrun-v01", managerUrl: `http://127.0.0.1:${agentRunPort}`, runId, commandId, traceId, providerTrace: { traceId }, lastSeq: 0, status: "running", commandState: "running", valuesPrinted: false },
valuesPrinted: false
});
const server = createCloudApiServer({
traceStore: createCodeAgentTraceStore(),
codeAgentChatResults,
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
HWLAB_ENVIRONMENT: "v02",
HWLAB_GITOPS_PROFILE: "v02"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/traces/${traceId}`, {
headers: { cookie: "hwlab_session=test-stub-session" }
});
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.status, "missing");
assert.equal(body.projectionStatus, "projecting");
assert.equal(body.eventCount, 0);
assert.deepEqual(body.events, []);
assert.deepEqual(calls, []);
assert.equal(calls.some((call) => call.path === `/api/v1/runs/${runId}/commands/${commandId}/result`), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
agentRunServer.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api turn status does not backfill terminal AgentRun projection on GET (#1585)", async () => {
const calls = [];
const traceId = "trc_issue1422_turn_status_fast_path";
const runId = "run_issue1422_turn_status_fast_path";
const commandId = "cmd_issue1422_turn_status_fast_path";
const events = [
{ id: "evt_issue1422_created", runId, seq: 1, type: "backend_status", payload: { phase: "runner-job-created", commandId }, createdAt: "2026-06-18T04:30:00.000Z" },
{ id: "evt_issue1422_terminal", runId, seq: 2, type: "terminal_status", payload: { commandId, terminalStatus: "completed" }, createdAt: "2026-06-18T04:30:01.000Z" }
];
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
calls.push({ method: request.method, path: url.pathname, search: url.search });
const send = (data) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: true, data, traceId: "trc_fake_issue1422_turn" })}\n`);
};
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/events`) return send({ items: events });
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/commands/${commandId}/result`) return send({
runId,
commandId,
status: "completed",
runStatus: "claimed",
commandState: "completed",
terminalStatus: "completed",
completed: true,
reply: { content: "issue 1555 read-side backfill completed" },
lastSeq: 2,
eventCount: 2
});
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, message: `unexpected ${request.method} ${url.pathname}` })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
const codeAgentChatResults = new Map([[traceId, {
accepted: true,
status: "running",
shortConnection: true,
traceId,
conversationId: "cnv_issue1422_turn_status",
sessionId: "ses_issue1422_turn_status",
threadId: "thread-issue1422-turn-status",
ownerUserId: TEST_AGENT_ACTOR.id,
ownerRole: TEST_AGENT_ACTOR.role,
agentRun: { adapter: "agentrun-v01", managerUrl: `http://127.0.0.1:${agentRunPort}`, runId, commandId, traceId, providerTrace: { traceId }, lastSeq: 0, status: "running", commandState: "running", valuesPrinted: false },
valuesPrinted: false
}]]);
const server = createCloudApiServer({
traceStore: createCodeAgentTraceStore(),
codeAgentChatResults,
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
HWLAB_ENVIRONMENT: "v02",
HWLAB_GITOPS_PROFILE: "v02"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/turns/${traceId}`, {
headers: { cookie: "hwlab_session=test-stub-session" }
});
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.status, "running");
assert.equal(body.terminal, false);
assert.equal(body.projectionStatus, "projecting");
assert.equal(body.agentRun.commandState, "running");
assert.equal(body.agentRun.terminalStatus ?? null, null);
assert.equal(body.finalResponse, null);
assert.deepEqual(calls, []);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
agentRunServer.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api turn status reuses request session lookup without loading persisted AgentRun result (#1519)", async () => {
const calls = [];
const traceId = "trc_issue1422_turn_status_session_cache";
const runId = "run_issue1422_turn_status_session_cache";
const commandId = "cmd_issue1422_turn_status_session_cache";
const agentRunServer = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
calls.push({ method: request.method, path: url.pathname, search: url.search });
const send = (data) => {
response.writeHead(200, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: true, data, traceId: "trc_fake_issue1422_session_cache" })}\n`);
};
if (request.method === "GET" && url.pathname === `/api/v1/runs/${runId}/events`) {
return send({ items: [
{ id: "evt_issue1422_session_cache_running", runId, seq: 1, type: "backend_status", payload: { phase: "runner-job-created", commandId }, createdAt: "2026-06-18T05:20:00.000Z" }
] });
}
response.writeHead(404, { "content-type": "application/json" });
response.end(`${JSON.stringify({ ok: false, message: `unexpected ${request.method} ${url.pathname}` })}\n`);
});
await new Promise((resolve) => agentRunServer.listen(0, "127.0.0.1", resolve));
const agentRunPort = agentRunServer.address().port;
let sessionLookupCount = 0;
const session = testAgentSessionRecord({
sessionId: "ses_issue1422_turn_status_session_cache",
projectId: "prj_hwpod_workbench",
conversationId: "cnv_issue1422_turn_status_session_cache",
threadId: "thread-issue1422-turn-status-session-cache",
lastTraceId: traceId,
status: "running",
session: {
agentRun: {
adapter: "agentrun-v01",
managerUrl: `http://127.0.0.1:${agentRunPort}`,
runId,
commandId,
traceId,
providerTrace: { traceId, valuesPrinted: false },
lastSeq: 0,
status: "running",
commandState: "running",
backendProfile: "deepseek",
valuesPrinted: false
},
valuesRedacted: true
}
});
const server = createCloudApiServer({
traceStore: createCodeAgentTraceStore(),
codeAgentChatResults: new Map(),
env: {
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`,
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "D601",
HWLAB_ENVIRONMENT: "v02",
HWLAB_GITOPS_PROFILE: "v02"
},
accessController: {
required: false,
async authenticate() {
return { ok: true, actor: TEST_AGENT_ACTOR, session: TEST_AUTH_SESSION };
},
async getAgentSessionByTraceId(requestTraceId) {
sessionLookupCount += 1;
return requestTraceId === traceId ? session : null;
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/turns/${traceId}?projectId=prj_hwpod_workbench`, {
headers: { cookie: "hwlab_session=test-stub-session" }
});
assert.equal(response.status, 404);
const body = await response.json();
assert.equal(body.status, "unknown");
assert.equal(body.projectionStatus, "unknown");
assert.equal(sessionLookupCount, 1);
assert.equal(calls.filter((call) => call.path === `/api/v1/runs/${runId}/events`).length, 0);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
agentRunServer.close((error) => (error ? reject(error) : resolve()));
});
}
});