Files
pikasTech-HWLAB/web/hwlab-cloud-web/code-agent-facts.test.ts
T
Lyon 24060853e7 fix: reuse AgentRun runner for HWLAB turns (#662)
Co-authored-by: Codex <codex@local>
2026-06-01 23:18:40 +08:00

324 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import test from "node:test";
import {
codeAgentAttributionFromMessage,
codeAgentFactsFromMessage,
codeAgentRuntimePathFromMessage
} from "./code-agent-facts.ts";
test("codex-readonly-runner is shown as partial read-only session registry", () => {
const facts = codeAgentFactsFromMessage({
status: "source",
provider: "codex-readonly-runner",
model: "read-only-tools",
backend: "hwlab-cloud-api/codex-readonly-runner",
workspace: "/workspace/hwlab",
sandbox: "read-only",
capabilityLevel: "read-only-session-tools",
sessionMode: "controlled-readonly-session-registry",
implementationType: "controlled-readonly-session-registry",
session: {
sessionId: "ses_readonly",
status: "idle",
turn: 1,
lastTraceId: "trc_readonly"
},
sessionReuse: {
reused: false,
turn: 1,
status: "idle"
},
runner: {
kind: "hwlab-readonly-runner",
codexStdio: false,
writeCapable: false,
durableSession: false,
longLivedSession: true
},
longLivedSessionGate: {
status: "blocked",
pass: false,
blockers: [{ code: "codex_stdio_blocked_readonly_session_available" }]
},
toolCalls: [{ name: "pwd", status: "completed" }],
skills: { status: "not_requested", count: 0 },
runnerTrace: {
traceId: "trc_readonly",
runnerKind: "hwlab-readonly-runner",
sessionMode: "controlled-readonly-session-registry",
turn: 1
},
traceId: "trc_readonly"
});
assert.equal(facts.kind, "controlled-readonly-session-registry");
assert.equal(facts.fullCodeAgent, false);
assert.equal(facts.codexSessionGatePass, false);
assert.match(facts.statusLabel, /只读长会话/u);
assert.match(facts.summary, /可复用/u);
assert.match(facts.summary, /Codex stdio/u);
assert.match(facts.rows.find((row) => row.label === "runner/provider/backend").value, /runner=hwlab-readonly-runner/u);
assert.match(facts.rows.find((row) => row.label === "toolCalls").value, /1\/1 pwd\(completed\)/u);
});
test("long-lived Codex app-server stdio session fields are shown as full Code Agent session", () => {
const message = {
status: "completed",
provider: "codex-stdio",
model: "gpt-5.5",
backend: "hwlab-cloud-api/codex-app-server-stdio",
workspace: "/workspace/hwlab",
sandbox: "workspace-write",
capabilityLevel: "long-lived-codex-stdio-session",
sessionMode: "codex-app-server-stdio-long-lived",
implementationType: "repo-owned-codex-app-server-stdio-session",
session: {
sessionId: "ses_stdio",
status: "idle",
turn: 3,
idleTimeoutMs: 1800000,
lastTraceId: "trc_stdio",
longLivedSession: true,
codexStdio: true
},
runner: {
kind: "codex-app-server-stdio-runner",
codexStdio: true,
writeCapable: true,
durableSession: true
},
longLivedSessionGate: {
status: "pass",
pass: true
},
toolCalls: [{ name: "codex-reply", status: "completed" }],
skills: { status: "not_requested", count: 0 },
runnerTrace: {
traceId: "trc_stdio",
runnerKind: "codex-app-server-stdio-runner",
sessionMode: "codex-app-server-stdio-long-lived",
implementationType: "repo-owned-codex-app-server-stdio-session",
turn: 3
},
providerTrace: {
transport: "stdio",
protocol: "codex-app-server-jsonrpc-stdio",
wireApi: "responses",
command: "codex app-server --listen stdio://",
terminalStatus: "completed"
},
traceId: "trc_stdio"
};
const facts = codeAgentFactsFromMessage(message);
const runtimePath = codeAgentRuntimePathFromMessage({ role: "agent", ...message });
assert.equal(facts.kind, "codex-stdio-long-lived");
assert.equal(facts.statusLabel, "真实 runnerCodex app-server stdio 长会话");
assert.equal(facts.fullCodeAgent, true);
assert.equal(facts.codexSessionGatePass, true);
assert.match(facts.rows.find((row) => row.label === "sandbox").value, /workspace-write/u);
assert.equal(runtimePath.kind, "codex-app-server-stdio");
assert.equal(runtimePath.tone, "ok");
assert.equal(runtimePath.provider, "codex-stdio");
assert.equal(runtimePath.runnerKind, "codex-app-server-stdio-runner");
assert.equal(runtimePath.protocol, "codex-app-server-jsonrpc-stdio");
assert.equal(runtimePath.implementationType, "repo-owned-codex-app-server-stdio-session");
assert.equal(runtimePath.command, "codex app-server --listen stdio://");
assert.equal(runtimePath.terminalStatus, "completed");
assert.equal(runtimePath.wireApi, "responses");
assert.match(runtimePath.summary, /Responses wire API/u);
});
test("AgentRun carried Codex app-server session is shown as full Code Agent session", () => {
const message = {
status: "completed",
provider: "codex-stdio",
model: "deepseek-chat",
backend: "hwlab-cloud-api/codex-app-server-stdio",
infrastructureBackend: "agentrun-v01/deepseek",
workspace: "/home/agentrun/workspace",
sandbox: "danger-full-access",
capabilityLevel: "long-lived-codex-stdio-session",
sessionMode: "codex-app-server-stdio-long-lived",
implementationType: "repo-owned-codex-app-server-stdio-session",
session: {
sessionId: "ses_web_agentrun",
threadId: "019e8078-db67-7750-a5d9-1a99f3abd445",
status: "idle",
lastTraceId: "trc_web_agentrun",
longLivedSession: true,
codexStdio: true,
writeCapable: true,
durable: true,
durableSession: true
},
sessionReuse: {
sessionId: "ses_web_agentrun",
threadId: "019e8078-db67-7750-a5d9-1a99f3abd445",
reused: true
},
runner: {
kind: "codex-app-server-stdio-runner",
codexStdio: true,
writeCapable: true,
durableSession: true,
longLivedSession: true
},
longLivedSessionGate: {
status: "pass",
pass: true
},
toolCalls: [{ name: "codex-app-server.turn", status: "completed" }],
skills: { status: "delegated", count: 0 },
runnerTrace: {
traceId: "trc_web_agentrun",
runnerKind: "codex-app-server-stdio-runner",
sessionMode: "codex-app-server-stdio-long-lived",
implementationType: "repo-owned-codex-app-server-stdio-session"
},
providerTrace: {
transport: "stdio",
protocol: "codex-app-server-jsonrpc-stdio",
wireApi: "responses",
command: "codex app-server --listen stdio://",
terminalStatus: "completed",
source: "agentrun-v01"
},
traceId: "trc_web_agentrun"
};
const facts = codeAgentFactsFromMessage(message);
const runtimePath = codeAgentRuntimePathFromMessage({ role: "agent", ...message });
assert.equal(facts.kind, "codex-stdio-long-lived");
assert.equal(facts.fullCodeAgent, true);
assert.equal(runtimePath.kind, "codex-app-server-stdio");
assert.equal(runtimePath.tone, "ok");
assert.equal(runtimePath.providerTraceMissing, false);
assert.equal(runtimePath.criticalMissing, false);
assert.equal(runtimePath.terminalStatusOk, true);
});
test("Codex app-server without providerTrace is degraded with structured missing fields", () => {
const message = {
role: "agent",
status: "completed",
provider: "codex-stdio",
backend: "hwlab-cloud-api/codex-app-server-stdio",
capabilityLevel: "long-lived-codex-stdio-session",
sessionMode: "codex-app-server-stdio-long-lived",
implementationType: "repo-owned-codex-app-server-stdio-session",
runner: { kind: "codex-app-server-stdio-runner" },
longLivedSessionGate: { status: "pass", pass: true },
traceId: "trc_missing_provider_trace"
};
const facts = codeAgentFactsFromMessage(message);
const runtimePath = codeAgentRuntimePathFromMessage(message);
assert.equal(facts.kind, "codex-stdio-provider-trace-missing");
assert.equal(facts.fullCodeAgent, false);
assert.equal(runtimePath.providerTraceMissing, true);
assert.equal(runtimePath.label, "DEGRADEDproviderTrace 缺失");
assert.deepEqual(runtimePath.missingFields, ["protocol", "providerTrace.command", "providerTrace.terminalStatus"]);
});
test("openai-responses fallback is explicitly text-chat-only", () => {
const message = {
status: "source",
provider: "openai-responses",
model: "gpt-5.5",
backend: "hwlab-cloud-api/openai-responses",
capabilityLevel: "text-chat-only",
sessionMode: "provider-text-request",
runner: {
kind: "openai-responses-fallback",
codexStdio: false,
writeCapable: false,
durableSession: false
},
longLivedSessionGate: {
status: "blocked",
pass: false,
blockers: [{ code: "openai_responses_fallback_not_session" }]
},
toolCalls: [],
skills: { status: "not_requested", count: 0 },
runnerTrace: {
traceId: "trc_fallback",
runnerKind: "openai-responses-fallback",
events: ["fallback:text-chat-only"]
},
traceId: "trc_fallback"
};
const facts = codeAgentFactsFromMessage(message);
const attribution = codeAgentAttributionFromMessage(message);
assert.equal(facts.kind, "text-chat-only");
assert.equal(facts.statusLabel, "OpenAI fallback:只是文本回答 / text-chat-only");
assert.equal(facts.fullCodeAgent, false);
assert.equal(facts.codexSessionGatePass, false);
assert.match(facts.summary, /只是文本回答/u);
assert.match(attribution.label, /只是文本回答/u);
assert.match(attribution.summary, /当前不能执行工具/u);
assert.equal(attribution.fields.find((field) => field.key === "runnerKind").value, "openai-responses-fallback / 不是 runner 控制");
assert.equal(attribution.fields.find((field) => field.key === "capabilityLevel").value, "text-chat-only / 只是文本回答");
assert.equal(attribution.fields.find((field) => field.key === "toolCalls").value, "0/0 / 无工具调用:只是文本回答");
});
test("stateless one-shot is not wrapped as a long-lived session", () => {
const facts = codeAgentFactsFromMessage({
status: "source",
provider: "codex-cli",
model: "gpt-5.5",
backend: "hwlab-cloud-api/codex-cli",
workspace: "/workspace/hwlab",
sandbox: "read-only",
capabilityLevel: "text-chat-only",
sessionMode: "ephemeral-one-shot",
implementationType: "codex-cli-one-shot-ephemeral",
session: {
sessionId: "cnv_one_shot",
status: "expired",
idleTimeoutMs: 0,
lastTraceId: "trc_one_shot"
},
runner: {
kind: "codex-cli-one-shot-ephemeral",
codexStdio: false,
writeCapable: false,
durableSession: false
},
longLivedSessionGate: {
status: "blocked",
pass: false,
blockers: [{ code: "one_shot_runner_not_long_lived" }]
},
traceId: "trc_one_shot"
});
assert.equal(facts.kind, "stateless-one-shot");
assert.equal(facts.fullCodeAgent, false);
assert.equal(facts.codexSessionGatePass, false);
assert.match(facts.summary, /一次性 runner/u);
});
test("missing attribution fields render structured evidence insufficiency", () => {
const attribution = codeAgentAttributionFromMessage({
role: "agent",
status: "failed",
traceId: "trc_missing_fields",
error: {
code: "provider_unavailable",
message: "blocked"
}
});
assert.equal(attribution.label, "BLOCKED:当前不能执行");
assert.equal(attribution.fields.find((field) => field.key === "traceId").value, "trc_missing_fields");
assert.equal(attribution.fields.find((field) => field.key === "provider").missing, true);
assert.equal(attribution.fields.find((field) => field.key === "backend").value, "字段缺失:证据不足");
assert.equal(attribution.fields.find((field) => field.key === "runnerKind").chip, "runnerKind=字段缺失:证据不足");
assert.equal(attribution.fields.find((field) => field.key === "providerTrace.command").missing, true);
assert.match(attribution.summary, /字段缺失/u);
});