Files
pikasTech-HWLAB/web/hwlab-cloud-web/code-agent-facts.test.mjs
T
2026-05-24 10:45:05 +00:00

421 lines
15 KiB
JavaScript
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,
compactHwlabApiFact
} from "./code-agent-facts.mjs";
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("legacy MCP-shaped Codex stdio is degraded instead of full app-server completion", () => {
const message = {
status: "completed",
provider: "codex-stdio",
model: "gpt-5.5",
backend: "hwlab-cloud-api/codex-mcp-stdio",
workspace: "/workspace/hwlab",
sandbox: "workspace-write",
capabilityLevel: "long-lived-codex-stdio-session",
sessionMode: "codex-mcp-stdio-long-lived",
implementationType: "repo-owned-codex-mcp-stdio-session",
runner: {
kind: "codex-mcp-stdio-runner",
codexStdio: true,
writeCapable: true
},
longLivedSessionGate: {
status: "pass",
pass: true
},
providerTrace: {
transport: "stdio",
protocol: "mcp-jsonrpc-stdio",
command: "codex mcp-server",
terminalStatus: "completed"
},
traceId: "trc_mcp"
};
const facts = codeAgentFactsFromMessage(message);
const runtimePath = codeAgentRuntimePathFromMessage({ role: "agent", ...message });
assert.equal(facts.kind, "codex-mcp-or-other-runner");
assert.equal(facts.fullCodeAgent, false);
assert.equal(runtimePath.kind, "mcp-or-other-runner");
assert.equal(runtimePath.label, "DEGRADEDMCP/其他 runner");
});
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("HWLAB Skill CLI toolCall shows compact copyable /v1/m3/io facts", () => {
const facts = codeAgentFactsFromMessage({
status: "source",
provider: "hwlab-skill-cli",
model: "controlled-m3-io",
backend: "hwlab-cloud-api/hwlab-agent-runtime-skill-cli",
workspace: "/workspace/hwlab",
sandbox: "hwlab-api-route-only",
capabilityLevel: "hwlab-api-control-ready",
sessionMode: "controlled-m3-io-skill-cli",
runner: {
kind: "hwlab-m3-io-skill-cli",
codexStdio: false,
writeCapable: true,
durableSession: false
},
longLivedSessionGate: {
status: "blocked",
pass: false
},
toolCalls: [
{
name: "hwlab-agent-runtime.m3-io",
type: "skill-cli",
status: "completed",
route: "/v1/m3/io",
method: "POST",
operationId: "op_m3_do_write_cli",
traceId: "trc_m3_skill_cli",
auditId: "aud_m3_do_write_cli_succeeded",
evidenceId: "evd_m3_do_write_cli_succeeded",
audit: { auditId: "aud_m3_do_write_cli_succeeded" },
evidence: { evidenceId: "evd_m3_do_write_cli_succeeded" },
accepted: true,
readback: {
status: "succeeded",
value: false,
resourceId: "res_boxsimu_2",
port: "DI1"
},
blocker: { code: "runtime_durable_not_green" },
stdout: JSON.stringify({
route: "/v1/m3/io",
method: "POST",
status: "succeeded",
accepted: true,
traceId: "trc_m3_skill_cli",
operationId: "op_m3_do_write_cli",
auditId: "aud_m3_do_write_cli_succeeded",
evidenceId: "evd_m3_do_write_cli_succeeded",
audit: { auditId: "aud_m3_do_write_cli_succeeded" },
evidence: { evidenceId: "evd_m3_do_write_cli_succeeded" },
readback: {
status: "succeeded",
value: false,
resourceId: "res_boxsimu_2",
port: "DI1"
},
durable: { blocker: "runtime_durable_not_green" }
})
}
],
skills: {
status: "used",
count: 1,
items: [{ name: "hwlab-agent-runtime.m3-io" }]
},
runnerTrace: {
traceId: "trc_m3_skill_cli",
runnerKind: "hwlab-m3-io-skill-cli",
sessionMode: "controlled-m3-io-skill-cli",
route: "/v1/m3/io",
status: "succeeded"
},
traceId: "trc_m3_skill_cli"
});
assert.equal(facts.kind, "hwlab-skill-cli");
assert.equal(facts.fullCodeAgent, false);
assert.equal(facts.hwlabApiFacts.length, 1);
assert.deepEqual(facts.hwlabApiFacts[0], {
tool: "hwlab-agent-runtime.m3-io",
route: "/v1/m3/io",
method: "POST",
operationId: "op_m3_do_write_cli",
traceId: "trc_m3_skill_cli",
auditId: "aud_m3_do_write_cli_succeeded",
evidenceId: "evd_m3_do_write_cli_succeeded",
accepted: true,
readback: {
status: "succeeded",
value: false,
resourceId: "res_boxsimu_2",
port: "DI1"
},
blocker: "runtime_durable_not_green",
status: "completed"
});
assert.equal(
compactHwlabApiFact(facts.hwlabApiFacts[0]),
"route=/v1/m3/io / method=POST / operationId=op_m3_do_write_cli / traceId=trc_m3_skill_cli / auditId=aud_m3_do_write_cli_succeeded / evidenceId=evd_m3_do_write_cli_succeeded / blocker=runtime_durable_not_green"
);
const attribution = codeAgentAttributionFromMessage({
role: "agent",
status: "source",
provider: "hwlab-skill-cli",
backend: "hwlab-cloud-api/hwlab-agent-runtime-skill-cli",
capabilityLevel: "hwlab-api-control-ready",
sessionMode: "controlled-m3-io-skill-cli",
runner: { kind: "hwlab-m3-io-skill-cli" },
toolCalls: facts.hwlabApiFacts.map((fact) => ({
name: fact.tool,
status: fact.status,
route: fact.route,
operationId: fact.operationId,
traceId: fact.traceId,
auditId: fact.auditId,
evidenceId: fact.evidenceId
})),
traceId: "trc_m3_skill_cli"
});
assert.equal(attribution.kind, "hwlab-skill-cli");
assert.equal(attribution.fields.find((field) => field.key === "operationId").value, "op_m3_do_write_cli");
assert.equal(attribution.fields.find((field) => field.key === "audit").value, "aud_m3_do_write_cli_succeeded");
assert.equal(attribution.fields.find((field) => field.key === "evidence").value, "evd_m3_do_write_cli_succeeded");
assert.match(attribution.fields.find((field) => field.key === "toolCalls").value, /hwlab-agent-runtime\.m3-io\(completed\)@\/v1\/m3\/io/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);
});