Merge pull request #884 from pikasTech/fix/v02-agentrun-health-cleanup
fix(v02): 收敛 AgentRun Code Agent 健康合同
This commit is contained in:
@@ -31,6 +31,9 @@ const DEFAULT_PROVIDER_ID = "G14";
|
||||
const DEFAULT_REPO_URL = "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git";
|
||||
const DEFAULT_RUNNER_NAMESPACE = "agentrun-v01";
|
||||
const DEFAULT_TIMEOUT_MS = 1_200_000;
|
||||
const AGENTRUN_RUNNER_KIND = "agentrun-v01-shared-runner";
|
||||
const AGENTRUN_SESSION_MODE = "agentrun-v01-durable-session";
|
||||
const AGENTRUN_IMPLEMENTATION_TYPE = "agentrun-v01-shared-execution-infra";
|
||||
const AGENTRUN_BACKENDS = Object.freeze(["codex", "deepseek", "minimax-m3"]);
|
||||
const THREAD_CONTINUITY_POLICY = "hwlab-agentrun-v01-reuse-runner-thread";
|
||||
const SESSION_POLICY_RUN_LOCAL = "hwlab-agentrun-v01-session-runner-reuse";
|
||||
@@ -52,6 +55,160 @@ export function codeAgentAgentRunAdapterEnabled(env = process.env) {
|
||||
return value === ADAPTER_ID || value === "agentrun" || value === "agentrun-v0.1";
|
||||
}
|
||||
|
||||
export function describeAgentRunAdapterAvailability(env = process.env, options = {}) {
|
||||
const params = options.params ?? {};
|
||||
const backendProfile = resolveAgentRunBackendProfile(env, params);
|
||||
const provider = providerForBackendProfile(backendProfile);
|
||||
const backend = `${ADAPTER_ID}/${backendProfile}`;
|
||||
const model = modelForBackendProfile(backendProfile, env);
|
||||
const blockers = [];
|
||||
let managerUrl = null;
|
||||
let repoUrl = null;
|
||||
|
||||
try {
|
||||
managerUrl = resolveAgentRunManagerUrl(env);
|
||||
} catch (error) {
|
||||
blockers.push(agentRunAvailabilityBlocker(error, "manager-url"));
|
||||
}
|
||||
try {
|
||||
repoUrl = resolveAgentRunRepoUrl(env);
|
||||
} catch (error) {
|
||||
blockers.push(agentRunAvailabilityBlocker(error, "repo-url"));
|
||||
}
|
||||
|
||||
const providerId = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID, env.AGENTRUN_PROVIDER_ID, DEFAULT_PROVIDER_ID);
|
||||
const runnerNamespace = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE, env.AGENTRUN_RUNTIME_NAMESPACE, DEFAULT_RUNNER_NAMESPACE);
|
||||
const ready = blockers.length === 0 && Boolean(providerId && runnerNamespace && backendProfile && managerUrl && repoUrl);
|
||||
const managerHost = hostForUrl(managerUrl);
|
||||
const repoHost = hostForUrl(repoUrl);
|
||||
const status = ready ? "agentrun-ready" : "blocked";
|
||||
const capabilityLevel = ready ? CODEX_STDIO_CAPABILITY_LEVEL : "blocked";
|
||||
|
||||
return {
|
||||
endpoint: "POST /v1/agent/chat",
|
||||
adapter: ADAPTER_ID,
|
||||
provider,
|
||||
model,
|
||||
backend,
|
||||
infrastructureBackend: backend,
|
||||
mode: ADAPTER_ID,
|
||||
schema: [
|
||||
"conversationId",
|
||||
"sessionId",
|
||||
"messageId",
|
||||
"status",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"traceId",
|
||||
"provider",
|
||||
"model",
|
||||
"backend",
|
||||
"infrastructureBackend",
|
||||
"agentRun",
|
||||
"runner",
|
||||
"runnerTrace",
|
||||
"session",
|
||||
"sessionMode",
|
||||
"sessionReuse",
|
||||
"threadContinuityPolicy",
|
||||
"error.message",
|
||||
"error.code"
|
||||
],
|
||||
runner: {
|
||||
kind: AGENTRUN_RUNNER_KIND,
|
||||
adapter: ADAPTER_ID,
|
||||
backend,
|
||||
provider,
|
||||
model,
|
||||
namespace: runnerNamespace,
|
||||
managerHost,
|
||||
repoHost,
|
||||
mode: ADAPTER_ID,
|
||||
sessionMode: AGENTRUN_SESSION_MODE,
|
||||
implementationType: AGENTRUN_IMPLEMENTATION_TYPE,
|
||||
status: ready ? "available" : "blocked",
|
||||
ready,
|
||||
capabilityLevel,
|
||||
longLivedSession: ready,
|
||||
durableSession: ready,
|
||||
durable: ready,
|
||||
codexStdio: false,
|
||||
delegatedToAgentRun: true,
|
||||
writeCapable: ready,
|
||||
readOnly: false,
|
||||
runnerLimitations: ready ? [] : ["agentrun-adapter-config-blocked"],
|
||||
secretMaterialRead: false,
|
||||
valuesRedacted: true
|
||||
},
|
||||
agentRun: {
|
||||
adapter: ADAPTER_ID,
|
||||
backendProfile,
|
||||
providerId,
|
||||
runnerNamespace,
|
||||
managerUrl,
|
||||
managerHost,
|
||||
repoUrl,
|
||||
repoHost,
|
||||
managerConfigured: Boolean(managerUrl),
|
||||
repoConfigured: Boolean(repoUrl),
|
||||
internalServiceDns: managerHost === "agentrun-mgr.agentrun-v01.svc.cluster.local",
|
||||
ready,
|
||||
valuesPrinted: false
|
||||
},
|
||||
status,
|
||||
readinessStatus: status,
|
||||
agentKind: "agentrun-v01-adapter",
|
||||
capabilityStatus: status,
|
||||
blocker: ready ? null : blockers[0]?.summary ?? "AgentRun adapter runtime configuration is blocked.",
|
||||
reason: ready ? null : blockers[0]?.code ?? "agentrun_adapter_blocked",
|
||||
summary: ready
|
||||
? "HWLAB Code Agent delegates execution to AgentRun v0.1 shared infrastructure; hwlab-cloud-api keeps session/trace/API ownership and no longer manages a repo-owned runner control plane."
|
||||
: "HWLAB Code Agent is configured for AgentRun v0.1, but the adapter runtime configuration is incomplete or invalid.",
|
||||
missingEnv: [],
|
||||
secretRefs: [],
|
||||
egress: {
|
||||
ready,
|
||||
mode: "agentrun-managed-provider-egress",
|
||||
directPublicOpenAi: false,
|
||||
secretMaterialRead: false,
|
||||
valuesRedacted: true
|
||||
},
|
||||
safety: {
|
||||
secretsRead: false,
|
||||
secretValuesPrinted: false,
|
||||
kubeconfigRead: false,
|
||||
providerCredentialsDelegatedToAgentRun: true,
|
||||
repoOwnedRunnerControlPlane: false,
|
||||
valuesRedacted: true
|
||||
},
|
||||
capabilityLevel,
|
||||
workspace: repoUrl,
|
||||
sandbox: firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_SANDBOX, env.HWLAB_CODE_AGENT_CODEX_SANDBOX, "danger-full-access"),
|
||||
session: null,
|
||||
sessionStatus: null,
|
||||
sessionMode: AGENTRUN_SESSION_MODE,
|
||||
implementationType: AGENTRUN_IMPLEMENTATION_TYPE,
|
||||
runnerLimitations: ready ? [] : ["agentrun-adapter-config-blocked"],
|
||||
longLivedSessionGate: {
|
||||
status: ready ? "pass" : "blocked",
|
||||
provider,
|
||||
runnerKind: AGENTRUN_RUNNER_KIND,
|
||||
sessionMode: AGENTRUN_SESSION_MODE,
|
||||
implementationType: AGENTRUN_IMPLEMENTATION_TYPE,
|
||||
adapter: ADAPTER_ID,
|
||||
codexStdio: false,
|
||||
delegatedToAgentRun: true,
|
||||
blockers,
|
||||
secretMaterialRead: false,
|
||||
valuesRedacted: true
|
||||
},
|
||||
blockers,
|
||||
blockerCodes: blockers.map((blocker) => blocker.code).filter(Boolean),
|
||||
ready,
|
||||
partialReady: false
|
||||
};
|
||||
}
|
||||
|
||||
export function initialAgentRunChatResult({ params = {}, options = {}, traceId }) {
|
||||
const env = options.env ?? process.env;
|
||||
const timestamp = nowIso(options.now);
|
||||
@@ -1540,6 +1697,34 @@ function modelForBackendProfile(profile, env = process.env) {
|
||||
return firstNonEmpty(env.HWLAB_CODE_AGENT_DEEPSEEK_MODEL, "deepseek-chat");
|
||||
}
|
||||
|
||||
function providerForBackendProfile(profile) {
|
||||
if (profile === "codex") return "codex-api";
|
||||
if (profile === "minimax-m3") return "minimax-m3";
|
||||
return "deepseek";
|
||||
}
|
||||
|
||||
function agentRunAvailabilityBlocker(error, scope) {
|
||||
return {
|
||||
code: error?.code ?? `agentrun_${String(scope).replace(/[^a-z0-9]+/giu, "_")}_blocked`,
|
||||
type: "agent_blocker",
|
||||
scope: `agentrun-${scope}`,
|
||||
status: "open",
|
||||
sourceIssue: "pikasTech/HWLAB#879",
|
||||
summary: error?.message ?? `AgentRun ${scope} is not configured correctly.` ,
|
||||
secretMaterialRead: false,
|
||||
valuesRedacted: true
|
||||
};
|
||||
}
|
||||
|
||||
function hostForUrl(value) {
|
||||
if (!value) return null;
|
||||
try {
|
||||
return new URL(value).hostname.toLowerCase();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function waitingForForPhase(phase) {
|
||||
if (phase.includes("runner-job")) return "agentrun-runner";
|
||||
if (phase.includes("resource-bundle")) return "agentrun-resource-bundle";
|
||||
|
||||
@@ -31,6 +31,10 @@ import {
|
||||
codeAgentSessionLifecycleSummary,
|
||||
decorateCodeAgentSession
|
||||
} from "./code-agent-session-lifecycle.ts";
|
||||
import {
|
||||
codeAgentAgentRunAdapterEnabled,
|
||||
describeAgentRunAdapterAvailability
|
||||
} from "./code-agent-agentrun-adapter.ts";
|
||||
const DEFAULT_MODEL = DEV_CODE_AGENT_PROVIDER_CONTRACT.model;
|
||||
const DEFAULT_PROJECT_ID = "prj_hwlab-cloud-workbench";
|
||||
const READONLY_RUNNER_PROVIDER = "codex-readonly-runner";
|
||||
@@ -459,6 +463,10 @@ function decorateChatSessionLifecycle(payload) {
|
||||
}
|
||||
|
||||
export async function describeCodeAgentAvailability(env = process.env, options = {}) {
|
||||
if (codeAgentAgentRunAdapterEnabled(env)) {
|
||||
return describeAgentRunAdapterAvailability(env, options);
|
||||
}
|
||||
|
||||
const providerPlan = resolveProviderPlan(env, options);
|
||||
const providerContract = inspectCodeAgentProviderEnv(env);
|
||||
const missingEnv = providerPlan.mode === "openai"
|
||||
|
||||
@@ -78,6 +78,9 @@ function isDbReady(db) {
|
||||
}
|
||||
|
||||
function isCodeAgentReady(codeAgent) {
|
||||
if (isAgentRunCodeAgent(codeAgent)) {
|
||||
return Boolean(codeAgent?.ready === true && codeAgent?.agentRun?.managerConfigured !== false && codeAgent?.agentRun?.ready !== false);
|
||||
}
|
||||
return Boolean(
|
||||
codeAgent?.ready === true &&
|
||||
codeAgent?.longLivedSessionGate?.status === "pass" &&
|
||||
@@ -116,18 +119,21 @@ function dbBlocker(db) {
|
||||
|
||||
function codeAgentBlocker(codeAgent) {
|
||||
const primaryBlocker = Array.isArray(codeAgent?.blockers) ? codeAgent.blockers[0] : null;
|
||||
const agentRun = isAgentRunCodeAgent(codeAgent);
|
||||
return {
|
||||
code: codeAgent?.reason ?? primaryBlocker?.code ?? "code_agent_long_lived_session_blocked",
|
||||
type: "agent_blocker",
|
||||
scope: "code-agent-long-lived-session",
|
||||
scope: agentRun ? "code-agent-agentrun-adapter" : "code-agent-long-lived-session",
|
||||
status: "open",
|
||||
sourceIssue: primaryBlocker?.sourceIssue ?? "pikasTech/HWLAB#275",
|
||||
sourceIssue: primaryBlocker?.sourceIssue ?? (agentRun ? "pikasTech/HWLAB#879" : "pikasTech/HWLAB#275"),
|
||||
summary: codeAgent?.summary ?? "Code Agent provider readiness is not established",
|
||||
evidence: {
|
||||
adapter: codeAgent?.adapter ?? codeAgent?.agentRun?.adapter ?? null,
|
||||
provider: codeAgent?.provider ?? "unknown",
|
||||
backend: codeAgent?.backend ?? "unknown",
|
||||
agentKind: codeAgent?.agentKind ?? "unknown",
|
||||
capabilityStatus: codeAgent?.capabilityStatus ?? "unknown",
|
||||
agentRun: codeAgent?.agentRun ?? null,
|
||||
longLivedSessionGate: codeAgent?.longLivedSessionGate ?? null,
|
||||
codexStdioFeasibility: codeAgent?.codexStdioFeasibility ?? null,
|
||||
partialReady: codeAgent?.partialReady === true,
|
||||
@@ -205,6 +211,27 @@ function buildRuntimeDurabilityReadiness({ db, runtime, runtimeReady, runtimeBlo
|
||||
}
|
||||
|
||||
function buildProviderReadiness(codeAgent = {}) {
|
||||
if (isAgentRunCodeAgent(codeAgent)) {
|
||||
const ready = codeAgent?.ready === true && codeAgent?.agentRun?.ready !== false;
|
||||
return {
|
||||
status: ready ? "ready" : "blocked",
|
||||
ready,
|
||||
configured: ready,
|
||||
adapter: codeAgent.adapter ?? codeAgent.agentRun?.adapter ?? "agentrun-v01",
|
||||
provider: codeAgent?.provider ?? "unknown",
|
||||
model: codeAgent?.model ?? "unknown",
|
||||
backend: codeAgent?.backend ?? "unknown",
|
||||
mode: codeAgent?.mode ?? "agentrun-v01",
|
||||
backendProfile: codeAgent?.agentRun?.backendProfile ?? null,
|
||||
evidence: "agentrun_runtime_adapter_config",
|
||||
egressReady: codeAgent?.egress?.ready !== false,
|
||||
missingEnv: [],
|
||||
blocker: ready ? null : firstCode(codeAgent?.reason, codeAgent?.blockers?.[0]?.code, "agentrun_adapter_blocked"),
|
||||
secretMaterialRead: false,
|
||||
valuesRedacted: true
|
||||
};
|
||||
}
|
||||
|
||||
const fallback = codeAgent?.fallback ?? {};
|
||||
const fallbackReady = fallback.ready === true || fallback.status === "available";
|
||||
const tokenBoundary = codeAgent?.codexStdioFeasibility?.tokenBoundary ?? codeAgent?.codexStdio?.tokenBoundary ?? null;
|
||||
@@ -230,6 +257,32 @@ function buildProviderReadiness(codeAgent = {}) {
|
||||
}
|
||||
|
||||
function buildSessionRunnerReadiness(codeAgent = {}) {
|
||||
if (isAgentRunCodeAgent(codeAgent)) {
|
||||
const runner = codeAgent?.runner ?? {};
|
||||
const ready = codeAgent?.ready === true && runner.ready !== false;
|
||||
return {
|
||||
status: ready ? "agentrun_ready" : "blocked",
|
||||
ready,
|
||||
kind: runner.kind ?? "agentrun-v01-shared-runner",
|
||||
adapter: codeAgent.adapter ?? codeAgent.agentRun?.adapter ?? "agentrun-v01",
|
||||
provider: codeAgent?.provider ?? runner.provider ?? "unknown",
|
||||
backend: codeAgent?.backend ?? runner.backend ?? "unknown",
|
||||
mode: runner.sessionMode ?? runner.mode ?? codeAgent?.sessionMode ?? "agentrun-v01-durable-session",
|
||||
capabilityLevel: runner.capabilityLevel ?? codeAgent?.capabilityLevel ?? "unknown",
|
||||
longLivedSession: runner.longLivedSession !== false,
|
||||
durableSession: runner.durableSession !== false,
|
||||
codexStdio: false,
|
||||
delegatedToAgentRun: true,
|
||||
writeCapable: runner.writeCapable !== false,
|
||||
readOnly: false,
|
||||
namespace: runner.namespace ?? codeAgent?.agentRun?.runnerNamespace ?? null,
|
||||
managerHost: runner.managerHost ?? codeAgent?.agentRun?.managerHost ?? null,
|
||||
blocker: ready ? null : firstCode(runner.blocker, codeAgent?.reason, codeAgent?.blockers?.[0]?.code, "agentrun_session_runner_blocked"),
|
||||
runnerLimitations: Array.isArray(codeAgent?.runnerLimitations) ? [...codeAgent.runnerLimitations] : [],
|
||||
secretMaterialRead: false
|
||||
};
|
||||
}
|
||||
|
||||
const stdio = codeAgent?.codexStdioFeasibility ?? codeAgent?.codexStdio ?? {};
|
||||
const stdioCommandReady = stdio.commandProbe?.ready === true;
|
||||
const stdioReady = (stdio.ready === true || stdio.canStartLongLivedCodexStdio === true) && stdioCommandReady;
|
||||
@@ -263,6 +316,29 @@ function buildSessionRunnerReadiness(codeAgent = {}) {
|
||||
}
|
||||
|
||||
function buildCodexStdioReadiness(codeAgent = {}) {
|
||||
if (isAgentRunCodeAgent(codeAgent)) {
|
||||
return {
|
||||
status: "not_applicable",
|
||||
ready: false,
|
||||
feasible: false,
|
||||
adapter: codeAgent.adapter ?? codeAgent.agentRun?.adapter ?? "agentrun-v01",
|
||||
delegatedToAgentRun: true,
|
||||
blocker: null,
|
||||
blockerCodes: [],
|
||||
sourceIssue: "pikasTech/HWLAB#879",
|
||||
commandPresent: false,
|
||||
commandExecutable: false,
|
||||
nativeDependencyPresent: false,
|
||||
commandProbeReady: false,
|
||||
commandProbe: null,
|
||||
supervisorConfigured: false,
|
||||
workspaceReady: false,
|
||||
tokenBoundaryPresent: false,
|
||||
egressReady: true,
|
||||
secretMaterialRead: false
|
||||
};
|
||||
}
|
||||
|
||||
const stdio = codeAgent?.codexStdioFeasibility ?? codeAgent?.codexStdio ?? {};
|
||||
const commandReady = stdio.commandProbe?.ready === true;
|
||||
const ready = (stdio.ready === true || stdio.canStartLongLivedCodexStdio === true) && commandReady;
|
||||
@@ -297,24 +373,27 @@ function buildCodexStdioReadiness(codeAgent = {}) {
|
||||
}
|
||||
|
||||
function buildCodeAgentStructuredReadiness({ provider, dbDurable, sessionRunner, codexStdio, codeAgent } = {}) {
|
||||
const agentRun = isAgentRunCodeAgent(codeAgent);
|
||||
const currentBlockers = [
|
||||
provider?.ready === false ? provider.blocker ?? "provider_config_blocked" : null,
|
||||
dbDurable?.ready === false ? dbDurable.blocker ?? "runtime_durable_adapter_not_ready" : null,
|
||||
sessionRunner?.ready === false ? sessionRunner.blocker ?? "session_runner_blocked" : null,
|
||||
codexStdio?.ready === false ? codexStdio.blocker ?? "codex_stdio_feasibility_blocked" : null
|
||||
!agentRun && codexStdio?.ready === false ? codexStdio.blocker ?? "codex_stdio_feasibility_blocked" : null
|
||||
].filter(Boolean);
|
||||
const ready = provider?.ready === true &&
|
||||
dbDurable?.ready === true &&
|
||||
sessionRunner?.ready === true &&
|
||||
codexStdio?.ready === true &&
|
||||
(agentRun || codexStdio?.ready === true) &&
|
||||
codeAgent?.ready === true;
|
||||
return {
|
||||
status: ready ? "ready" : currentBlockers.length > 0 ? "blocked" : "degraded",
|
||||
ready,
|
||||
adapter: codeAgent?.adapter ?? codeAgent?.agentRun?.adapter ?? null,
|
||||
agentRunReady: agentRun ? codeAgent?.agentRun?.ready === true : null,
|
||||
providerReady: provider?.ready === true,
|
||||
durableDbReady: dbDurable?.ready === true,
|
||||
sessionRunnerReady: sessionRunner?.ready === true,
|
||||
codexStdioFeasible: codexStdio?.ready === true,
|
||||
codexStdioFeasible: agentRun ? false : codexStdio?.ready === true,
|
||||
currentBlocker: currentBlockers[0] ?? null,
|
||||
currentBlockers,
|
||||
provider: {
|
||||
@@ -349,6 +428,7 @@ function buildCodeAgentStructuredReadiness({ provider, dbDurable, sessionRunner,
|
||||
status: codexStdio?.status ?? "unknown",
|
||||
ready: codexStdio?.ready === true,
|
||||
feasible: codexStdio?.feasible === true,
|
||||
delegatedToAgentRun: codexStdio?.delegatedToAgentRun === true,
|
||||
blocker: codexStdio?.blocker ?? null,
|
||||
blockerCodes: Array.isArray(codexStdio?.blockerCodes) ? [...codexStdio.blockerCodes] : []
|
||||
},
|
||||
@@ -357,6 +437,10 @@ function buildCodeAgentStructuredReadiness({ provider, dbDurable, sessionRunner,
|
||||
};
|
||||
}
|
||||
|
||||
function isAgentRunCodeAgent(codeAgent = {}) {
|
||||
return codeAgent?.adapter === "agentrun-v01" || codeAgent?.agentRun?.adapter === "agentrun-v01" || codeAgent?.mode === "agentrun-v01";
|
||||
}
|
||||
|
||||
function providerBlockerCode(codeAgent = {}, fallback = {}) {
|
||||
if (Array.isArray(codeAgent?.missingEnv) && codeAgent.missingEnv.length > 0) return "provider_config_blocked";
|
||||
if (fallback?.egress?.directPublicOpenAi === true || codeAgent?.egress?.directPublicOpenAi === true) return "provider_egress_blocked";
|
||||
|
||||
@@ -718,6 +718,83 @@ test("cloud api health reports provider, durable DB, and codex stdio ready when
|
||||
}
|
||||
});
|
||||
|
||||
test("cloud api health reports AgentRun adapter readiness without repo-owned codex stdio control plane", async () => {
|
||||
const server = createCloudApiServer({
|
||||
env: {
|
||||
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
|
||||
AGENTRUN_MGR_URL: "http://agentrun-mgr.agentrun-v01.svc.cluster.local:8080",
|
||||
HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE: "agentrun-v01",
|
||||
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "G14",
|
||||
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "deepseek",
|
||||
HWLAB_CODE_AGENT_DEEPSEEK_MODEL: "deepseek-chat",
|
||||
HWLAB_BOOT_READ_URL: "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git",
|
||||
HWLAB_CLOUD_DB_URL: "postgres://hwlab_test:password@db.internal.local:5432/hwlab",
|
||||
HWLAB_CLOUD_DB_SSL_MODE: "disable"
|
||||
},
|
||||
dbProbe: {
|
||||
probe: async ({ endpointSource, timeoutMs }) => ({
|
||||
attempted: true,
|
||||
networkAttempted: true,
|
||||
endpointSource,
|
||||
probeType: "tcp-connect",
|
||||
endpointRedacted: true,
|
||||
valueRedacted: true,
|
||||
timeoutMs,
|
||||
durationMs: 1,
|
||||
result: "connected",
|
||||
classification: "tcp_connected",
|
||||
errorCode: null,
|
||||
missingEnv: []
|
||||
})
|
||||
},
|
||||
runtimeStore: {
|
||||
async readiness() {
|
||||
return durableReadyRuntime();
|
||||
}
|
||||
}
|
||||
});
|
||||
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}/health/live`);
|
||||
assert.equal(response.status, 200);
|
||||
const payload = await response.json();
|
||||
assert.equal(payload.status, "ok");
|
||||
assert.equal(payload.ready, true);
|
||||
assert.equal(payload.codeAgent.adapter, "agentrun-v01");
|
||||
assert.equal(payload.codeAgent.status, "agentrun-ready");
|
||||
assert.equal(payload.codeAgent.provider, "deepseek");
|
||||
assert.equal(payload.codeAgent.backend, "agentrun-v01/deepseek");
|
||||
assert.equal(payload.codeAgent.agentRun.managerHost, "agentrun-mgr.agentrun-v01.svc.cluster.local");
|
||||
assert.equal(payload.codeAgent.agentRun.runnerNamespace, "agentrun-v01");
|
||||
assert.equal(payload.codeAgent.runner.kind, "agentrun-v01-shared-runner");
|
||||
assert.equal(payload.codeAgent.runner.delegatedToAgentRun, true);
|
||||
assert.equal(payload.codeAgent.runner.codexStdio, false);
|
||||
assert.equal(payload.readiness.components.codeAgent, "ready");
|
||||
assert.equal(payload.readiness.provider.status, "ready");
|
||||
assert.equal(payload.readiness.sessionRunner.status, "agentrun_ready");
|
||||
assert.equal(payload.readiness.sessionRunner.delegatedToAgentRun, true);
|
||||
assert.equal(payload.readiness.codexStdio.status, "not_applicable");
|
||||
assert.equal(payload.readiness.codeAgent.ready, true);
|
||||
assert.equal(payload.readiness.codeAgent.adapter, "agentrun-v01");
|
||||
assert.equal(payload.readiness.codeAgent.agentRunReady, true);
|
||||
assert.equal(payload.readiness.codeAgent.codexStdioFeasible, false);
|
||||
assert.deepEqual(payload.readiness.codeAgent.currentBlockers, []);
|
||||
const serialized = JSON.stringify(payload);
|
||||
assert.equal(serialized.includes("repo-owned-codex"), false);
|
||||
assert.equal(serialized.includes("codex-app-server-stdio"), false);
|
||||
assert.equal(serialized.includes("CODEX_HOME"), false);
|
||||
assert.equal(serialized.includes("/codex-home"), false);
|
||||
assert.equal(serialized.includes("test-openai-key-material"), false);
|
||||
assert.equal(serialized.includes("password"), false);
|
||||
} finally {
|
||||
await new Promise((resolve, reject) => {
|
||||
server.close((error) => (error ? reject(error) : resolve()));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test("cloud api health blocks full Code Agent readiness when Codex stdio command probe fails", async () => {
|
||||
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-health-codex-stdio-probe-fail-"));
|
||||
const codexHome = path.join(workspace, "codex-home");
|
||||
|
||||
Reference in New Issue
Block a user