fix: complete v03 AgentRun workbench projection

This commit is contained in:
lyon
2026-06-19 03:29:55 +08:00
parent 99a8d92b0e
commit cee702726c
5 changed files with 378 additions and 32 deletions
+111 -2
View File
@@ -922,6 +922,7 @@ function newSessionIdAfterEviction(baseSessionId, traceId) {
}
function buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, sessionId, toolCapabilities = null }) {
const commitId = requireAgentRunSourceCommit(env);
const runtimeAuthority = requireAgentRunRuntimeAuthority(env);
const threadId = safeOpaqueId(params.threadId);
const hwlabProjectId = firstNonEmpty(params.projectId);
rejectRemovedResourceWorkspaceFiles(params.workspaceFiles ?? params.resourceWorkspaceFiles);
@@ -940,8 +941,8 @@ function buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, ses
workspaceRef: {
kind: "opaque",
repo: DEFAULT_PROJECT_ID,
branch: firstNonEmpty(env.HWLAB_BOOT_REF, env.HWLAB_CODE_AGENT_AGENTRUN_BRANCH, "v0.2"),
runtimeNamespace: firstNonEmpty(env.HWLAB_RUNTIME_NAMESPACE, env.POD_NAMESPACE, env.HWLAB_NAMESPACE, "hwlab-v02"),
branch: firstNonEmpty(env.HWLAB_BOOT_REF, env.HWLAB_CODE_AGENT_AGENTRUN_BRANCH, defaultAgentRunBranchForRuntimeLane(runtimeAuthority.lane), "v0.2"),
runtimeNamespace: runtimeAuthority.namespace,
hwlabTraceId: traceId,
valuesPrinted: false
},
@@ -1196,7 +1197,9 @@ async function resolveOwnerApiKey({ params, options, now }) {
return text(key.displaySecret ?? "");
}
function buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities = null, backendProfile }) {
const runtimeAuthority = requireAgentRunRuntimeAuthority(env);
const baseTransient = buildAgentRunTransientEnv(env, { providerProfile: backendProfile, parentTraceId: traceId });
assertAgentRunTransientRuntimeAuthority(baseTransient, runtimeAuthority);
const hwpodAllowed = toolCapabilityAllowed(toolCapabilities, "hwpod");
const transientEnv = ownerApiKey && hwpodAllowed
? baseTransient.concat([{ name: "HWLAB_API_KEY", value: ownerApiKey, sensitive: true }])
@@ -1236,6 +1239,112 @@ function buildAgentRunTransientEnv(env = process.env, options = {}) {
return entries;
}
function requireAgentRunRuntimeAuthority(env = process.env) {
const explicitLane = normalizeAgentRunRuntimeLane(firstNonEmpty(
env.HWLAB_RUNTIME_LANE,
env.HWLAB_GITOPS_LANE,
env.HWLAB_GITOPS_PROFILE,
env.HWLAB_ENVIRONMENT,
env.HWLAB_BOOT_REF
));
const namespace = firstNonEmpty(
env.HWLAB_RUNTIME_NAMESPACE,
env.POD_NAMESPACE,
env.HWLAB_NAMESPACE,
namespaceForAgentRunRuntimeLane(explicitLane)
);
if (!namespace) {
throw agentRunRuntimeAuthorityError("agentrun_runtime_namespace_required", "AgentRun dispatch requires HWLAB_RUNTIME_NAMESPACE/POD_NAMESPACE/HWLAB_NAMESPACE or a supported runtime lane");
}
const namespaceLane = agentRunRuntimeLaneForNamespace(namespace);
if (!namespaceLane) {
throw agentRunRuntimeAuthorityError("agentrun_runtime_namespace_unsupported", `unsupported AgentRun HWLAB runtime namespace: ${namespace}`);
}
if (explicitLane && explicitLane !== namespaceLane) {
throw agentRunRuntimeAuthorityError("agentrun_runtime_authority_mismatch", `AgentRun HWLAB runtime lane ${explicitLane} does not match namespace ${namespace} (${namespaceLane})`);
}
assertAgentRunEndpointNamespace(env.HWLAB_RUNTIME_API_URL, namespace, "HWLAB_RUNTIME_API_URL");
assertAgentRunEndpointNamespace(env.HWLAB_RUNTIME_WEB_URL, namespace, "HWLAB_RUNTIME_WEB_URL");
return { namespace, lane: namespaceLane };
}
function assertAgentRunTransientRuntimeAuthority(entries, runtimeAuthority) {
const values = new Map((Array.isArray(entries) ? entries : []).map((entry) => [entry?.name, firstNonEmpty(entry?.value)]));
if (values.get("HWLAB_RUNTIME_NAMESPACE") !== runtimeAuthority.namespace) {
throw agentRunRuntimeAuthorityError("agentrun_transient_namespace_mismatch", `AgentRun transient HWLAB_RUNTIME_NAMESPACE must be ${runtimeAuthority.namespace}`);
}
if (normalizeAgentRunRuntimeLane(values.get("HWLAB_RUNTIME_LANE")) !== runtimeAuthority.lane) {
throw agentRunRuntimeAuthorityError("agentrun_transient_lane_mismatch", `AgentRun transient HWLAB_RUNTIME_LANE must be ${runtimeAuthority.lane}`);
}
for (const name of ["HWLAB_RUNTIME_API_URL", "HWLAB_RUNTIME_WEB_URL"]) {
const value = values.get(name);
if (!value) {
throw agentRunRuntimeAuthorityError("agentrun_transient_endpoint_required", `AgentRun transient ${name} is required`);
}
assertAgentRunEndpointNamespace(value, runtimeAuthority.namespace, name);
}
}
function assertAgentRunEndpointNamespace(value, namespace, fieldName) {
const endpointNamespace = agentRunRuntimeNamespaceForEndpoint(value);
if (endpointNamespace && endpointNamespace !== namespace) {
throw agentRunRuntimeAuthorityError("agentrun_runtime_endpoint_mismatch", `${fieldName} points at ${endpointNamespace}, not ${namespace}`);
}
}
function agentRunRuntimeNamespaceForEndpoint(value) {
const match = String(value ?? "").match(/\.((?:hwlab-[a-z0-9-]+))\.svc\.cluster\.local(?::|\/|$)/iu);
return match?.[1] ?? null;
}
function agentRunRuntimeLaneForNamespace(namespace) {
const value = String(namespace ?? "").trim().toLowerCase();
if (value === "hwlab-prod") return "prod";
if (value === "hwlab-dev") return "dev";
const versionMatch = value.match(/^hwlab-v(\d+)$/u);
if (versionMatch) return versionAgentRunRuntimeLane(versionMatch[1]);
return null;
}
function normalizeAgentRunRuntimeLane(value) {
const profile = String(value ?? "").trim().toLowerCase();
if (!profile) return null;
if (profile === "prod" || profile === "production") return "prod";
if (profile === "dev" || profile === "development" || profile === "local") return "dev";
const dotted = profile.match(/^v?0+\.(\d+)$/u);
if (dotted) return versionAgentRunRuntimeLane(dotted[1]);
const compact = profile.match(/^v?0*(\d+)$/u);
if (compact) return versionAgentRunRuntimeLane(compact[1]);
throw agentRunRuntimeAuthorityError("agentrun_runtime_lane_unsupported", `unsupported AgentRun HWLAB runtime lane: ${String(value).trim()}`);
}
function versionAgentRunRuntimeLane(value) {
const version = Number.parseInt(value, 10);
if (!Number.isFinite(version) || version <= 0) return null;
return `v${String(version).padStart(2, "0")}`;
}
function namespaceForAgentRunRuntimeLane(lane) {
if (lane === "prod") return "hwlab-prod";
if (lane === "dev") return "hwlab-dev";
if (lane) return `hwlab-${lane}`;
return null;
}
function defaultAgentRunBranchForRuntimeLane(lane) {
const match = String(lane ?? "").match(/^v(\d+)$/u);
if (!match) return null;
return `v0.${Number.parseInt(match[1], 10)}`;
}
function agentRunRuntimeAuthorityError(code, message) {
return Object.assign(new Error(message), {
code,
statusCode: 500,
valuesPrinted: false
});
}
function agentRunToolCredentials(env = process.env, toolCapabilities = null) {
const namespace = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_TOOL_SECRET_NAMESPACE, env.HWLAB_CODE_AGENT_AGENTRUN_SECRET_NAMESPACE, DEFAULT_RUNNER_NAMESPACE);
const githubSecretName = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_GITHUB_TOOL_SECRET_NAME, "agentrun-v01-tool-github-pr");