fix: remove v0.2 caserun runtime fallback
This commit is contained in:
@@ -9,9 +9,6 @@
|
|||||||
"commitId": "df7a4e6e551fa90d64bde5537cc000f89d63dd20",
|
"commitId": "df7a4e6e551fa90d64bde5537cc000f89d63dd20",
|
||||||
"subdir": "projects/01_baseline"
|
"subdir": "projects/01_baseline"
|
||||||
},
|
},
|
||||||
"runtime": {
|
|
||||||
"apiUrl": "http://74.48.78.17:19667"
|
|
||||||
},
|
|
||||||
"expected": {
|
"expected": {
|
||||||
"compile": {
|
"compile": {
|
||||||
"success": true,
|
"success": true,
|
||||||
|
|||||||
@@ -21,7 +21,12 @@ test("cloud-api exposes web CaseRun cases, run status, events and aggregate", as
|
|||||||
}), "utf8");
|
}), "utf8");
|
||||||
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), sampleSpecYaml(), "utf8");
|
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), sampleSpecYaml(), "utf8");
|
||||||
const seen: any[] = [];
|
const seen: any[] = [];
|
||||||
|
const accessController = {
|
||||||
|
async ensureBootstrap() {},
|
||||||
|
async requireNavAccess() { return true; }
|
||||||
|
};
|
||||||
const server = createCloudApiServer({
|
const server = createCloudApiServer({
|
||||||
|
accessController,
|
||||||
env: { PATH: process.env.PATH, HWLAB_CASERUN_CASE_REPO: root, HWLAB_CASERUN_STATE_DIR: stateRoot },
|
env: { PATH: process.env.PATH, HWLAB_CASERUN_CASE_REPO: root, HWLAB_CASERUN_STATE_DIR: stateRoot },
|
||||||
caseRunExecutor: async (context: any, emit: any) => {
|
caseRunExecutor: async (context: any, emit: any) => {
|
||||||
seen.push(context.parsed);
|
seen.push(context.parsed);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { prepareCaseRun } from "./src/hwlab-caserun-lib.ts";
|
|||||||
|
|
||||||
const NOW = "2026-06-06T00:00:00.000Z";
|
const NOW = "2026-06-06T00:00:00.000Z";
|
||||||
const SUBJECT_COMMIT = "df7a4e6e551fa90d64bde5537cc000f89d63dd20";
|
const SUBJECT_COMMIT = "df7a4e6e551fa90d64bde5537cc000f89d63dd20";
|
||||||
|
const TEST_RUNTIME_API_URL = "http://api.test";
|
||||||
|
|
||||||
test("CaseRun records source root baseline so pre-existing dirty files are not attributed to the run", async () => {
|
test("CaseRun records source root baseline so pre-existing dirty files are not attributed to the run", async () => {
|
||||||
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-caserun-source-root-"));
|
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-caserun-source-root-"));
|
||||||
@@ -26,7 +27,6 @@ test("CaseRun records source root baseline so pre-existing dirty files are not a
|
|||||||
commitId: SUBJECT_COMMIT,
|
commitId: SUBJECT_COMMIT,
|
||||||
subdir: "projects/01_baseline"
|
subdir: "projects/01_baseline"
|
||||||
},
|
},
|
||||||
runtime: { apiUrl: "http://hwlab.test" },
|
|
||||||
agentTask: { workspace: "subjectWorktree", prompt: "record source root baseline", constraints: [] }
|
agentTask: { workspace: "subjectWorktree", prompt: "record source root baseline", constraints: [] }
|
||||||
}, null, 2), "utf8");
|
}, null, 2), "utf8");
|
||||||
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), [
|
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), [
|
||||||
@@ -64,7 +64,7 @@ test("CaseRun records source root baseline so pre-existing dirty files are not a
|
|||||||
|
|
||||||
const result = await prepareCaseRun({
|
const result = await prepareCaseRun({
|
||||||
parsed: { _: [], caseRepo, runId: "source-root-baseline" },
|
parsed: { _: [], caseRepo, runId: "source-root-baseline" },
|
||||||
env: {},
|
env: { HWLAB_RUNTIME_API_URL: TEST_RUNTIME_API_URL },
|
||||||
fetchImpl: fetchImpl as typeof fetch,
|
fetchImpl: fetchImpl as typeof fetch,
|
||||||
cwd: root,
|
cwd: root,
|
||||||
now: () => NOW,
|
now: () => NOW,
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { artifactsFromKeilStatusForTest, extractKeilJobId, jobStatusCommandForTe
|
|||||||
|
|
||||||
const SUBJECT_COMMIT_ID = "df7a4e6e551fa90d64bde5537cc000f89d63dd20";
|
const SUBJECT_COMMIT_ID = "df7a4e6e551fa90d64bde5537cc000f89d63dd20";
|
||||||
const SUBJECT_REPO_LOCAL_PATH = "F:\\Work\\HWLAB-CASE-F103";
|
const SUBJECT_REPO_LOCAL_PATH = "F:\\Work\\HWLAB-CASE-F103";
|
||||||
|
const TEST_RUNTIME_API_URL = "http://api.test";
|
||||||
|
const TEST_RUNTIME_WEB_URL = "http://web.test";
|
||||||
|
const TEST_RUNTIME_ENV = { HWLAB_RUNTIME_API_URL: TEST_RUNTIME_API_URL, HWLAB_RUNTIME_WEB_URL: TEST_RUNTIME_WEB_URL };
|
||||||
|
|
||||||
test("hwlab-cli case prepare copies a case hwpod-spec into isolated run state", async () => {
|
test("hwlab-cli case prepare copies a case hwpod-spec into isolated run state", async () => {
|
||||||
const root = await mkdtempCaseRoot();
|
const root = await mkdtempCaseRoot();
|
||||||
@@ -24,7 +27,7 @@ test("hwlab-cli case prepare copies a case hwpod-spec into isolated run state",
|
|||||||
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
||||||
|
|
||||||
const requests: any[] = [];
|
const requests: any[] = [];
|
||||||
const result = await runHwlabCli(["case", "prepare", "d601-f103-v2-compile", "--case-repo", caseRepo, "--run-id", "run-test"], { cwd, now: () => "2026-06-05T00:00:00.000Z", fetchImpl: subjectWorktreeFetch(requests) });
|
const result = await runHwlabCli(["case", "prepare", "d601-f103-v2-compile", "--case-repo", caseRepo, "--run-id", "run-test"], { cwd, now: () => "2026-06-05T00:00:00.000Z", env: TEST_RUNTIME_ENV, fetchImpl: subjectWorktreeFetch(requests) });
|
||||||
|
|
||||||
assert.equal(result.exitCode, 0);
|
assert.equal(result.exitCode, 0);
|
||||||
assert.equal(result.payload.action, "case.prepare.prepare");
|
assert.equal(result.payload.action, "case.prepare.prepare");
|
||||||
@@ -57,6 +60,40 @@ test("hwlab-cli case prepare copies a case hwpod-spec into isolated run state",
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("case prepare requires an explicit v0.3 runtime API URL", async () => {
|
||||||
|
const root = await mkdtempCaseRoot();
|
||||||
|
const caseRepo = path.join(root, "hwlab-case-registry");
|
||||||
|
const cwd = path.join(root, "hwlab");
|
||||||
|
try {
|
||||||
|
await createCaseRepo(caseRepo, "d601-f103-v2-compile");
|
||||||
|
await mkdir(cwd, { recursive: true });
|
||||||
|
|
||||||
|
const result = await runHwlabCli(["case", "prepare", "d601-f103-v2-compile", "--case-repo", caseRepo], { cwd, now: () => "2026-06-05T00:00:00.000Z" });
|
||||||
|
|
||||||
|
assert.equal(result.exitCode, 1);
|
||||||
|
assert.equal(result.payload.error.code, "caserun_runtime_api_url_required");
|
||||||
|
} finally {
|
||||||
|
await rm(root, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("case prepare rejects the removed v0.2 runtime API URL", async () => {
|
||||||
|
const root = await mkdtempCaseRoot();
|
||||||
|
const caseRepo = path.join(root, "hwlab-case-registry");
|
||||||
|
const cwd = path.join(root, "hwlab");
|
||||||
|
try {
|
||||||
|
await createCaseRepo(caseRepo, "d601-f103-v2-compile");
|
||||||
|
await mkdir(cwd, { recursive: true });
|
||||||
|
|
||||||
|
const result = await runHwlabCli(["case", "prepare", "d601-f103-v2-compile", "--case-repo", caseRepo], { cwd, now: () => "2026-06-05T00:00:00.000Z", env: { HWLAB_RUNTIME_API_URL: "http://74.48.78.17:19667" } });
|
||||||
|
|
||||||
|
assert.equal(result.exitCode, 1);
|
||||||
|
assert.equal(result.payload.error.code, "caserun_removed_v02_runtime_url");
|
||||||
|
} finally {
|
||||||
|
await rm(root, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("case prepare rejects legacy subject repo/ref without a local repo path and commit id", async () => {
|
test("case prepare rejects legacy subject repo/ref without a local repo path and commit id", async () => {
|
||||||
const root = await mkdtempCaseRoot();
|
const root = await mkdtempCaseRoot();
|
||||||
const caseRepo = path.join(root, "hwlab-case-registry");
|
const caseRepo = path.join(root, "hwlab-case-registry");
|
||||||
@@ -70,7 +107,7 @@ test("case prepare rejects legacy subject repo/ref without a local repo path and
|
|||||||
await writeFile(path.join(caseDir, "case.json"), JSON.stringify({ contractVersion: "hwpod-case-v1", caseId: "legacy-case", hwpodSpec: "hwpod-spec.yaml", subject: { repo: "git@github.com:pikasTech/D601-HWLAB.git", ref: "main" } }, null, 2), "utf8");
|
await writeFile(path.join(caseDir, "case.json"), JSON.stringify({ contractVersion: "hwpod-case-v1", caseId: "legacy-case", hwpodSpec: "hwpod-spec.yaml", subject: { repo: "git@github.com:pikasTech/D601-HWLAB.git", ref: "main" } }, null, 2), "utf8");
|
||||||
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
||||||
|
|
||||||
const result = await runHwlabCli(["case", "prepare", "legacy-case", "--case-repo", caseRepo], { cwd, now: () => "2026-06-05T00:00:00.000Z", fetchImpl: subjectWorktreeFetch([]) });
|
const result = await runHwlabCli(["case", "prepare", "legacy-case", "--case-repo", caseRepo], { cwd, now: () => "2026-06-05T00:00:00.000Z", env: TEST_RUNTIME_ENV, fetchImpl: subjectWorktreeFetch([]) });
|
||||||
|
|
||||||
assert.equal(result.exitCode, 1);
|
assert.equal(result.exitCode, 1);
|
||||||
assert.equal(result.payload.error.code, "subject_repo_local_path_required");
|
assert.equal(result.payload.error.code, "subject_repo_local_path_required");
|
||||||
@@ -90,7 +127,7 @@ test("case prepare uses the new registry by default and refuses the removed hwpo
|
|||||||
await createCaseRepo(removedRepo, caseId);
|
await createCaseRepo(removedRepo, caseId);
|
||||||
await mkdir(cwd, { recursive: true });
|
await mkdir(cwd, { recursive: true });
|
||||||
|
|
||||||
const defaultResult = await runHwlabCli(["case", "prepare", caseId, "--run-id", "run-default"], { cwd, now: () => "2026-06-05T00:00:00.000Z", fetchImpl: subjectWorktreeFetch([]) });
|
const defaultResult = await runHwlabCli(["case", "prepare", caseId, "--run-id", "run-default"], { cwd, now: () => "2026-06-05T00:00:00.000Z", env: TEST_RUNTIME_ENV, fetchImpl: subjectWorktreeFetch([]) });
|
||||||
assert.equal(defaultResult.exitCode, 0);
|
assert.equal(defaultResult.exitCode, 0);
|
||||||
assert.equal(defaultResult.payload.caseRepo, newRepo);
|
assert.equal(defaultResult.payload.caseRepo, newRepo);
|
||||||
|
|
||||||
@@ -123,7 +160,7 @@ test("case prompt previews the real assembled prompt in Chinese without starting
|
|||||||
}, null, 2), "utf8");
|
}, null, 2), "utf8");
|
||||||
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
||||||
|
|
||||||
const result = await runHwlabCli(["case", "prompt", "d601-f103-v2-prompt-preview", "--case-repo", caseRepo, "--run-id", "run-prompt-preview"], { cwd, now: () => "2026-06-08T00:00:00.000Z" });
|
const result = await runHwlabCli(["case", "prompt", "d601-f103-v2-prompt-preview", "--case-repo", caseRepo, "--run-id", "run-prompt-preview"], { cwd, now: () => "2026-06-08T00:00:00.000Z", env: TEST_RUNTIME_ENV });
|
||||||
|
|
||||||
assert.equal(result.exitCode, 0);
|
assert.equal(result.exitCode, 0);
|
||||||
assert.equal(result.payload.action, "case.prompt");
|
assert.equal(result.payload.action, "case.prompt");
|
||||||
@@ -190,6 +227,7 @@ test("case run start returns immediately and status/result/logs are short pollin
|
|||||||
], {
|
], {
|
||||||
cwd,
|
cwd,
|
||||||
now: () => "2026-06-05T00:00:00.000Z",
|
now: () => "2026-06-05T00:00:00.000Z",
|
||||||
|
env: TEST_RUNTIME_ENV,
|
||||||
startProcess: async (input) => {
|
startProcess: async (input) => {
|
||||||
workerArgs = input.args;
|
workerArgs = input.args;
|
||||||
await writeFile(input.stdoutPath, "worker accepted\n", "utf8");
|
await writeFile(input.stdoutPath, "worker accepted\n", "utf8");
|
||||||
@@ -328,7 +366,6 @@ test("case run orchestrates agent prompt, diff capture, and compile evidence wit
|
|||||||
hwpodSpec: "hwpod-spec.yaml",
|
hwpodSpec: "hwpod-spec.yaml",
|
||||||
subject: { repoLocalPath: SUBJECT_REPO_LOCAL_PATH, commitId: SUBJECT_COMMIT_ID, subdir: "projects/01_baseline" },
|
subject: { repoLocalPath: SUBJECT_REPO_LOCAL_PATH, commitId: SUBJECT_COMMIT_ID, subdir: "projects/01_baseline" },
|
||||||
agentTask: { workspace: "subjectWorktree", prompt: "请通过 HWPOD 做一个很小的源码修改。", timeoutMs: 234000, pollIntervalMs: 10 },
|
agentTask: { workspace: "subjectWorktree", prompt: "请通过 HWPOD 做一个很小的源码修改。", timeoutMs: 234000, pollIntervalMs: 10 },
|
||||||
runtime: { apiUrl: "http://api.test", webUrl: "http://web.test" }
|
|
||||||
}, null, 2), "utf8");
|
}, null, 2), "utf8");
|
||||||
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
||||||
|
|
||||||
@@ -367,7 +404,7 @@ test("case run orchestrates agent prompt, diff capture, and compile evidence wit
|
|||||||
await writeFile(path.join(runDir, "worker.stderr.log"), "", "utf8");
|
await writeFile(path.join(runDir, "worker.stderr.log"), "", "utf8");
|
||||||
sawAgentRunningState = true;
|
sawAgentRunningState = true;
|
||||||
},
|
},
|
||||||
env: { HWLAB_API_KEY: "hwl_live_test_case_agent_key" },
|
env: { ...TEST_RUNTIME_ENV, HWLAB_API_KEY: "hwl_live_test_case_agent_key" },
|
||||||
runProcess: async (command) => {
|
runProcess: async (command) => {
|
||||||
runProcessCalls.push(command);
|
runProcessCalls.push(command);
|
||||||
const gitArgs = command.slice(1);
|
const gitArgs = command.slice(1);
|
||||||
@@ -594,6 +631,11 @@ test("case run archives rendered trace transcript when finalResponse is null", a
|
|||||||
{ traceId: "trc_final_null", seq: 2, label: "item/commandExecution:completed", type: "tool_call", toolName: "commandExecution", status: "completed", command: "/bin/sh -lc 'hwpod build --spec .hwlab/hwpod-spec.yaml'", stdoutSummary: "build completed", exitCode: 0, createdAt: "2026-06-06T00:00:02.000Z" },
|
{ traceId: "trc_final_null", seq: 2, label: "item/commandExecution:completed", type: "tool_call", toolName: "commandExecution", status: "completed", command: "/bin/sh -lc 'hwpod build --spec .hwlab/hwpod-spec.yaml'", stdoutSummary: "build completed", exitCode: 0, createdAt: "2026-06-06T00:00:02.000Z" },
|
||||||
{ traceId: "trc_final_null", seq: 3, label: "agentrun:terminal:failed", type: "result", terminal: true, status: "failed", message: "Error running remote compact task: unexpected status 404 Not Found", createdAt: "2026-06-06T00:00:03.000Z" }
|
{ traceId: "trc_final_null", seq: 3, label: "agentrun:terminal:failed", type: "result", terminal: true, status: "failed", message: "Error running remote compact task: unexpected status 404 Not Found", createdAt: "2026-06-06T00:00:03.000Z" }
|
||||||
],
|
],
|
||||||
|
rows: [
|
||||||
|
{ rowId: "trace-assistant:1", seq: 1, tone: "source", header: "00:00:01 助手消息", body: "我先检查当前 HWPOD。" },
|
||||||
|
{ rowId: "tool:build", seq: 2, tone: "ok", header: "00:00:02 ok commandExecution", bodyFormat: "text", body: "hwpod build --spec .hwlab/hwpod-spec.yaml\nstdout:\nbuild completed\nexitCode=0" },
|
||||||
|
{ rowId: "trace-terminal:3", seq: 3, tone: "blocked", header: "00:00:03 终止失败", terminal: true, body: "Error running remote compact task: unexpected status 404 Not Found" }
|
||||||
|
],
|
||||||
error: { message: "Error running remote compact task: unexpected status 404 Not Found" }
|
error: { message: "Error running remote compact task: unexpected status 404 Not Found" }
|
||||||
};
|
};
|
||||||
const evidence = {
|
const evidence = {
|
||||||
@@ -604,7 +646,7 @@ test("case run archives rendered trace transcript when finalResponse is null", a
|
|||||||
autoEvaluation: false,
|
autoEvaluation: false,
|
||||||
status: "recorded",
|
status: "recorded",
|
||||||
subject: run.subject,
|
subject: run.subject,
|
||||||
agent: { traceId: "trc_final_null", sessionId: "ses_final_null", conversationId: "cnv_final_null", threadId: "thread-final-null", providerProfile: "deepseek", projectId: "prj_hwpod_workbench", promptSha256: "prompt-sha" },
|
agent: { traceId: "trc_final_null", baseUrl: TEST_RUNTIME_WEB_URL, sessionId: "ses_final_null", conversationId: "cnv_final_null", threadId: "thread-final-null", providerProfile: "deepseek", projectId: "prj_hwpod_workbench", promptSha256: "prompt-sha" },
|
||||||
agentTrace: run.agentTrace,
|
agentTrace: run.agentTrace,
|
||||||
agentDiff: run.agentDiff,
|
agentDiff: run.agentDiff,
|
||||||
hwpod: { source: "case-run-runner-post-agent-compile-check", exitCode: 0 },
|
hwpod: { source: "case-run-runner-post-agent-compile-check", exitCode: 0 },
|
||||||
@@ -705,7 +747,7 @@ test("case aggregate writes one registry markdown entry without grading or broad
|
|||||||
runId,
|
runId,
|
||||||
runDir: "/root/hwlab-v02/.state/hwlab-cli/caserun/case04-completed-run",
|
runDir: "/root/hwlab-v02/.state/hwlab-cli/caserun/case04-completed-run",
|
||||||
caseRepo,
|
caseRepo,
|
||||||
apiUrl: "http://74.48.78.17:19667",
|
apiUrl: TEST_RUNTIME_API_URL,
|
||||||
compileOnly: true,
|
compileOnly: true,
|
||||||
createdAt: "2026-06-08T00:00:00.000Z",
|
createdAt: "2026-06-08T00:00:00.000Z",
|
||||||
completedAt: "2026-06-08T00:10:00.000Z",
|
completedAt: "2026-06-08T00:10:00.000Z",
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPEC: PJ2026-01010305 71FREQ preinstall draft-2026-06-26-71freq-v03-hwpod-preinstall.
|
||||||
|
// Responsibility: v0.3 CaseRun runtime-origin resolution and compile-only HWPOD smoke orchestration.
|
||||||
|
|
||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
import { createHash, randomUUID } from "node:crypto";
|
import { createHash, randomUUID } from "node:crypto";
|
||||||
import { closeSync, openSync } from "node:fs";
|
import { closeSync, openSync } from "node:fs";
|
||||||
@@ -7,8 +10,8 @@ import path from "node:path";
|
|||||||
import { renderTraceRowsMarkdown, traceDisplayRows, traceNoiseEventCount, type TraceEventRow } from "./hwlab-cli/trace-renderer.ts";
|
import { renderTraceRowsMarkdown, traceDisplayRows, traceNoiseEventCount, type TraceEventRow } from "./hwlab-cli/trace-renderer.ts";
|
||||||
import { readHwpodSpec } from "./hwpod-harness-lib.ts";
|
import { readHwpodSpec } from "./hwpod-harness-lib.ts";
|
||||||
|
|
||||||
const DEFAULT_API_URL = "http://74.48.78.17:19667";
|
const REMOVED_V02_API_URL = "http://74.48.78.17:19667";
|
||||||
const DEFAULT_WEB_URL = "http://74.48.78.17:19666";
|
const REMOVED_V02_WEB_URL = "http://74.48.78.17:19666";
|
||||||
const DEFAULT_POLL_INTERVAL_MS = 1000;
|
const DEFAULT_POLL_INTERVAL_MS = 1000;
|
||||||
const DEFAULT_JOB_TIMEOUT_MS = 50000;
|
const DEFAULT_JOB_TIMEOUT_MS = 50000;
|
||||||
const MAX_JOB_TIMEOUT_MS = 300000;
|
const MAX_JOB_TIMEOUT_MS = 300000;
|
||||||
@@ -378,7 +381,7 @@ export async function startCaseRun(context: CaseContext) {
|
|||||||
caseFile: "",
|
caseFile: "",
|
||||||
sourceSpecPath: "",
|
sourceSpecPath: "",
|
||||||
specPath: path.join(runDir, ".hwlab", "hwpod-spec.yaml"),
|
specPath: path.join(runDir, ".hwlab", "hwpod-spec.yaml"),
|
||||||
apiUrl: text(context.parsed.apiUrl ?? context.parsed.apiBaseUrl ?? context.parsed.runtimeApiUrl ?? context.env.HWLAB_RUNTIME_API_URL) || DEFAULT_API_URL,
|
apiUrl: apiUrlFrom(context, {}),
|
||||||
compileOnly: true,
|
compileOnly: true,
|
||||||
createdAt: context.now(),
|
createdAt: context.now(),
|
||||||
updatedAt: context.now(),
|
updatedAt: context.now(),
|
||||||
@@ -1367,12 +1370,19 @@ async function caseFetchJson(context: CaseContext, url: string, init: RequestIni
|
|||||||
|
|
||||||
function caseAgentHeaders(context: CaseContext) {
|
function caseAgentHeaders(context: CaseContext) {
|
||||||
const apiKey = text(context.env.HWLAB_API_KEY);
|
const apiKey = text(context.env.HWLAB_API_KEY);
|
||||||
if (!apiKey.startsWith(HWLAB_API_KEY_PREFIX)) throw cliError("api_key_required", "case run Code Agent stage requires HWLAB_API_KEY for HWLAB v0.2 Cloud Web", { allowed: "HWLAB_API_KEY" });
|
if (!apiKey.startsWith(HWLAB_API_KEY_PREFIX)) throw cliError("api_key_required", "case run Code Agent stage requires HWLAB_API_KEY for HWLAB Cloud Web", { allowed: "HWLAB_API_KEY" });
|
||||||
return { "content-type": "application/json", authorization: `Bearer ${apiKey}` };
|
return { "content-type": "application/json", authorization: `Bearer ${apiKey}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
function webUrlFrom(context: CaseContext, definition: any) {
|
function webUrlFrom(context: CaseContext, definition: any) {
|
||||||
return text(context.parsed.baseUrl ?? context.parsed.webUrl ?? definition?.runtime?.webUrl ?? context.env.HWLAB_RUNTIME_WEB_URL ?? context.env.HWLAB_CLOUD_WEB_URL) || DEFAULT_WEB_URL;
|
const value = text(context.parsed.baseUrl ?? context.parsed.webUrl ?? context.env.HWLAB_RUNTIME_WEB_URL ?? context.env.HWLAB_CLOUD_WEB_URL);
|
||||||
|
if (!value) {
|
||||||
|
throw cliError("caserun_runtime_web_url_required", "CaseRun v0.3 requires an explicit runtime Web URL from --base-url, --web-url, HWLAB_RUNTIME_WEB_URL, or HWLAB_CLOUD_WEB_URL; case runtime.webUrl fallback is removed.", {
|
||||||
|
allowed: ["--base-url", "--web-url", "HWLAB_RUNTIME_WEB_URL", "HWLAB_CLOUD_WEB_URL"],
|
||||||
|
removedFallbacks: ["case.runtime.webUrl", REMOVED_V02_WEB_URL]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rejectRemovedV02RuntimeUrl(value, "web");
|
||||||
}
|
}
|
||||||
|
|
||||||
function firstHwpodOutput(body: any) {
|
function firstHwpodOutput(body: any) {
|
||||||
@@ -1755,7 +1765,23 @@ function keilJobStatus(body: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function apiUrlFrom(context: CaseContext, definition: any) {
|
function apiUrlFrom(context: CaseContext, definition: any) {
|
||||||
return text(context.parsed.apiUrl ?? context.parsed.apiBaseUrl ?? context.parsed.runtimeApiUrl ?? definition?.runtime?.apiUrl ?? context.env.HWLAB_RUNTIME_API_URL) || DEFAULT_API_URL;
|
const value = text(context.parsed.apiUrl ?? context.parsed.apiBaseUrl ?? context.parsed.runtimeApiUrl ?? context.env.HWLAB_RUNTIME_API_URL ?? context.env.HWLAB_CASERUN_RUNTIME_API_URL);
|
||||||
|
if (!value) {
|
||||||
|
throw cliError("caserun_runtime_api_url_required", "CaseRun v0.3 requires an explicit runtime API URL from --api-url, --api-base-url, --runtime-api-url, HWLAB_RUNTIME_API_URL, or HWLAB_CASERUN_RUNTIME_API_URL; case runtime.apiUrl fallback is removed.", {
|
||||||
|
allowed: ["--api-url", "--api-base-url", "--runtime-api-url", "HWLAB_RUNTIME_API_URL", "HWLAB_CASERUN_RUNTIME_API_URL"],
|
||||||
|
removedFallbacks: ["case.runtime.apiUrl", REMOVED_V02_API_URL]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rejectRemovedV02RuntimeUrl(value, "api");
|
||||||
|
}
|
||||||
|
|
||||||
|
function rejectRemovedV02RuntimeUrl(value: string, kind: "api" | "web") {
|
||||||
|
const normalized = value.replace(/\/+$/u, "");
|
||||||
|
const removed = kind === "web" ? REMOVED_V02_WEB_URL : REMOVED_V02_API_URL;
|
||||||
|
if (normalized === removed) {
|
||||||
|
throw cliError("caserun_removed_v02_runtime_url", `CaseRun v0.3 does not support the removed v0.2 ${kind} runtime URL`, { kind, url: normalized });
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stateRoot(context: CaseContext) {
|
function stateRoot(context: CaseContext) {
|
||||||
@@ -1780,16 +1806,11 @@ function agentTraceLookupForRun(run: PreparedCaseRun, evidence?: any) {
|
|||||||
const agent = run.agent ?? evidence?.agent;
|
const agent = run.agent ?? evidence?.agent;
|
||||||
const traceId = text(agent?.traceId ?? evidence?.agentTrace?.traceId ?? run.agentTrace?.traceId);
|
const traceId = text(agent?.traceId ?? evidence?.agentTrace?.traceId ?? run.agentTrace?.traceId);
|
||||||
if (!traceId) return null;
|
if (!traceId) return null;
|
||||||
const baseUrl = text(agent?.baseUrl ?? run.agent?.baseUrl ?? evidence?.agent?.baseUrl) || runtimeWebUrl(run.definition) || DEFAULT_WEB_URL;
|
const baseUrl = text(agent?.baseUrl ?? run.agent?.baseUrl ?? evidence?.agent?.baseUrl);
|
||||||
|
if (!baseUrl) return null;
|
||||||
return agentTraceLookup({ baseUrl, traceId, sessionId: text(agent?.sessionId), conversationId: text(agent?.conversationId), threadId: text(agent?.threadId) });
|
return agentTraceLookup({ baseUrl, traceId, sessionId: text(agent?.sessionId), conversationId: text(agent?.conversationId), threadId: text(agent?.threadId) });
|
||||||
}
|
}
|
||||||
|
|
||||||
function runtimeWebUrl(definition: Record<string, unknown>) {
|
|
||||||
const runtime = definition.runtime;
|
|
||||||
if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) return "";
|
|
||||||
return text((runtime as Record<string, unknown>).webUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderEvidenceSummary(evidence: any) {
|
function renderEvidenceSummary(evidence: any) {
|
||||||
const agentStage = agentStageSummary(evidence);
|
const agentStage = agentStageSummary(evidence);
|
||||||
const traceLookup = evidence.traceLookup ?? evidence.agent?.traceLookup;
|
const traceLookup = evidence.traceLookup ?? evidence.agent?.traceLookup;
|
||||||
@@ -2644,7 +2665,7 @@ async function loadControlRunSkeleton(context: CaseContext, caseId: string, runI
|
|||||||
caseFile: "",
|
caseFile: "",
|
||||||
sourceSpecPath: "",
|
sourceSpecPath: "",
|
||||||
specPath: path.join(runDir, ".hwlab", "hwpod-spec.yaml"),
|
specPath: path.join(runDir, ".hwlab", "hwpod-spec.yaml"),
|
||||||
apiUrl: text(context.parsed.apiUrl ?? context.parsed.apiBaseUrl ?? context.parsed.runtimeApiUrl ?? context.env.HWLAB_RUNTIME_API_URL) || DEFAULT_API_URL,
|
apiUrl: apiUrlFrom(context, {}),
|
||||||
compileOnly: true,
|
compileOnly: true,
|
||||||
createdAt: context.now(),
|
createdAt: context.now(),
|
||||||
updatedAt: context.now(),
|
updatedAt: context.now(),
|
||||||
|
|||||||
Reference in New Issue
Block a user