Files
pikasTech-HWLAB/web/hwlab-cloud-web/code-agent-status.mjs
T
2026-05-25 20:55:33 +08:00

570 lines
26 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 {
codeAgentRuntimePathFromMessage,
runnerTraceSummary as compactRunnerTraceSummary,
skillsSummary as compactSkillsSummary,
toolCallsSummary as compactToolCallsSummary
} from "./code-agent-facts.mjs";
const GREEN_TONES = new Set(["ok", "available", "ready", "dev-live", "live", "pass"]);
const SECRET_MARKER = /\b(?:OPENAI_API_KEY|DATABASE_URL|secret|secretref|token|password|passwd|credential|private key|kubeconfig|密钥|密码|凭证)\b/iu;
const NON_LIVE_VALUES = new Set(["", "n/a", "none", "null", "undefined", "unknown", "not_observed", "not-observed"]);
const MAX_FIELD_LENGTH = 96;
const CODEX_APP_SERVER_RUNNER_KIND = "codex-app-server-stdio-runner";
const CODEX_APP_SERVER_SESSION_MODE = "codex-app-server-stdio-long-lived";
const CODEX_APP_SERVER_IMPLEMENTATION_TYPE = "repo-owned-codex-app-server-stdio-session";
export function classifyCodeAgentStatusSummary({ availability = null, latestMessage = null, live = null } = {}) {
const observedAvailability = availability ?? codeAgentAvailabilityFromLive(live);
const payload = safeMerge(observedAvailability, latestMessage);
const blockers = readinessBlockers(payload);
const classification = classifyPayload(payload, blockers);
const safeTone = unsafeGreenForNonReady(classification, blockers) ? "warn" : classification.tone;
const provider = safeField(firstString(payload.provider, observedAvailability?.provider));
const mode = safeField(firstString(payload.mode, payload.providerTrace?.mode, observedAvailability?.mode));
const backend = safeField(firstString(payload.backend, observedAvailability?.backend));
const codeAgentStatus = safeField(firstString(payload.status, payload.readinessStatus, observedAvailability?.status));
const capabilityLevel = safeField(firstString(payload.capabilityLevel, payload.runner?.capabilityLevel, observedAvailability?.capabilityLevel));
const sessionMode = safeField(firstString(payload.sessionMode, payload.session?.sessionMode, payload.runnerTrace?.sessionMode, payload.runner?.sessionMode));
const sessionId = safeField(firstString(payload.session?.sessionId, payload.sessionId, payload.runner?.sessionId, payload.sessionReuse?.sessionId));
const threadId = safeField(firstString(payload.threadId, payload.session?.threadId, payload.sessionReuse?.threadId, payload.providerTrace?.threadId, payload.runnerTrace?.threadId));
const sessionStatus = safeField(firstString(payload.session?.status, payload.sessionStatus, payload.runnerTrace?.sessionStatus, payload.sessionReuse?.status));
const lifecycle = sessionLifecycleSummary(payload);
const sessionLifecycleStatus = safeField(lifecycle.status);
const sessionLifecycleHint = safeField(lifecycle.hint);
const sessionLifecycleLabel = safeField(lifecycle.label);
const workspace = safeField(firstString(payload.workspace, payload.session?.workspace, payload.runner?.workspace, payload.sessionReuse?.workspace));
const sandbox = safeField(firstString(payload.sandbox, payload.session?.sandbox, payload.runner?.sandbox));
const runnerKind = safeField(firstString(payload.runner?.kind, payload.session?.runnerKind, payload.runnerTrace?.runnerKind));
const toolCalls = safeField(compactToolCallsSummary(payload.toolCalls));
const skills = safeField(compactSkillsSummary(payload.skills));
const runnerTrace = safeField(compactRunnerTraceSummary(payload.runnerTrace));
const runtimePath = codeAgentRuntimePathFromMessage({ role: "agent", ...payload });
const protocol = safeField(runtimePath?.protocol);
const implementationType = safeField(runtimePath?.implementationType);
const providerTraceCommand = safeField(runtimePath?.command);
const providerTraceTerminalStatus = safeField(runtimePath?.terminalStatus);
const runtimePathLabel = runtimePath?.label ?? "运行路径证据不足";
const runtimePathSummary = runtimePath?.summary ?? "providerTrace 未观测;不会推断完整 Code Agent。";
const runtimePathTone = runtimePath?.tone ?? "warn";
const lastTraceId = safeTraceId(firstString(
latestMessage?.traceId,
payload.traceId,
payload.session?.lastTraceId,
payload.runnerTrace?.lastTraceId,
payload.runnerTrace?.traceId,
payload.providerTrace?.traceId,
observedAvailability?.traceId
));
const deploymentRevision = currentDeploymentRevision(live);
return {
...classification,
tone: safeTone,
provider,
mode,
backend,
providerModeBackend: compactJoin([provider, mode, backend], " / "),
codeAgentStatus,
capabilityLevel,
sessionMode,
sessionId,
threadId,
sessionStatus,
sessionLifecycleStatus,
sessionLifecycleHint,
sessionLifecycleLabel,
sessionSummary: compactJoin([sessionMode, sessionStatus, sessionLifecycleStatus], " / "),
sessionIdStatus: compactJoin([sessionId, threadId, sessionStatus, sessionLifecycleStatus], " / "),
workspace,
sandbox,
runnerKind,
protocol,
implementationType,
providerTraceCommand,
providerTraceTerminalStatus,
runtimePathLabel,
runtimePathSummary,
runtimePathTone,
toolCalls,
skills,
runnerTrace,
readinessBlockers: blockers,
blockersLabel: blockers.length > 0 ? blockers.join(", ") : "无",
lastTraceId: lastTraceId || "未观测",
deploymentRevision,
fields: {
provider,
mode,
backend,
codeAgentStatus,
capabilityLevel,
sessionMode,
sessionId,
threadId,
sessionStatus,
sessionLifecycleStatus,
sessionLifecycleHint,
sessionLifecycleLabel,
workspace,
sandbox,
runnerKind,
protocol,
implementationType,
providerTraceCommand,
providerTraceTerminalStatus,
runtimePathLabel,
runtimePathSummary,
runtimePathTone,
toolCalls,
skills,
runnerTrace,
readinessBlockers: blockers,
lastTraceId: lastTraceId || null,
deploymentRevision
}
};
}
export function codeAgentAvailabilityFromLive(live = {}) {
return normalizedCodeAgentAvailability(
live?.restIndex?.data?.codeAgent ?? live?.healthLive?.data?.codeAgent ?? live?.health?.data?.codeAgent ?? null,
live?.restIndex?.data?.readiness?.codeAgent ?? live?.healthLive?.data?.readiness?.codeAgent ?? live?.health?.data?.readiness?.codeAgent ?? null
);
}
export function currentDeploymentRevision(live = {}) {
const payloads = [
live?.healthLive?.data,
live?.restIndex?.data,
live?.health?.data,
live?.adapter?.data
].filter(Boolean);
for (const payload of payloads) {
const revision = firstString(
payload?.commit?.id,
payload?.commitId,
payload?.revision,
payload?.runtime?.commitId,
payload?.image?.tag,
payload?.imageTag,
payload?.runtime?.imageTag
);
if (revision && !NON_LIVE_VALUES.has(revision.toLowerCase())) {
return shortRevision(revision);
}
}
return "未观测";
}
function classifyPayload(payload, blockers) {
if (!payload || Object.keys(payload).length === 0) {
return status("unverified", "探测中", "pending", "○", "等待同源接口返回 Code Agent 状态。");
}
const lifecycle = sessionLifecycleSummary(payload);
if (payload.status === "running" || lifecycle.status === "busy" || payload.session?.status === "busy" || payload.runnerTrace?.sessionStatus === "busy") {
return status("busy", "会话忙/请等待", "pending", "●", lifecycle.hint || "当前 Codex stdio 请求仍在 in-flight 状态,trace 会继续更新。");
}
if (lifecycle.status === "expired") {
return status("session-expired", "会话已过期", "blocked", "×", lifecycle.hint || "会话已过期,可重新发送建立新的 Code Agent session。");
}
if (lifecycle.status === "failed" && (payload.session?.status === "failed" || payload.sessionLifecycle?.status === "failed" || payload.sessionSummary?.status === "failed") && !isFallbackTextChatOnly(payload)) {
return status("session-failed", "会话失败", "blocked", "×", lifecycle.hint || "当前 Code Agent session 已失败,需重新发送建立新会话。");
}
if (lifecycle.status === "interrupted" && !["canceled", "timeout", "error"].includes(payload.status)) {
return status("session-interrupted", lifecycle.label || "会话已中断", "blocked", "×", lifecycle.hint || "当前 Code Agent session 已中断,可重试或重新发送。");
}
if (payload.status === "canceled" || payload.session?.status === "canceled" || payload.error?.code === "codex_stdio_canceled") {
return status("canceled", "请求已取消", "blocked", "×", "当前请求已取消,输入、sessionId 和 traceId 已保留,可重试。");
}
if (payload.status === "timeout" || payload.session?.status === "timeout") {
return status("timeout", "等待超时", "blocked", "×", "当前请求超时,输入、sessionId 和 traceId 已保留,可重试。");
}
if (payload.status === "error" || payload.session?.status === "error") {
return status("error", "请求错误", "blocked", "×", "当前请求返回错误,输入、sessionId 和 traceId 已保留,可重试。");
}
if (isLongLivedReady(payload)) {
return status("long-lived-session", "长会话可用", "ok", "●", "repo-owned 长会话通道可复用。");
}
if (payload.provider === "codex-stdio") {
const runtimePath = codeAgentRuntimePathFromMessage({ role: "agent", ...payload });
if (runtimePath?.kind !== "codex-app-server-stdio" || runtimePath?.criticalMissing === true || runtimePath?.terminalStatusOk === false) {
return isBlocked(payload)
? status("blocked", "服务受阻", "blocked", "×", runtimePath?.summary ?? "Codex stdio 缺少 app-server providerTrace 终态证据。")
: status("degraded", "运行路径降级", "warn", "!", runtimePath?.summary ?? "Codex stdio 缺少 app-server providerTrace 终态证据。");
}
}
if (isReadOnlySessionTools(payload)) {
return status("read-only-session-tools", "只读长会话工具", "warn", "◇", "只读 runner 会话可复用,不能写工作区或冒充完整 Codex stdio。");
}
if (isStatelessOneShot(payload)) {
return status("stateless-one-shot", "一次性执行", "warn", "△", "当前回复来自一次性执行,不是可复用长会话。");
}
if (isBlocked(payload)) {
return status("blocked", "服务受阻", "blocked", "×", "Code Agent 通道暂不可用或 readiness 未通过。");
}
if (isFallbackTextChatOnly(payload)) {
return status("fallback-text-chat-only", "会话降级", "warn", "◌", lifecycle.hint || "只有文本对话能力,没有 workspace tools 或 session 控制。");
}
if (isDegraded(payload, blockers)) {
return status("degraded", "降级可用", "warn", "!", "Code Agent 有部分能力,但 readiness 仍有阻塞项。");
}
if (payload.status === "available" || payload.ready === true || payload.status === "completed") {
return status("available", "通道可用", "ok", "●", "受控对话通道已返回可用状态。");
}
return status("unverified", "探测中", "pending", "○", "等待同源接口返回 Code Agent 状态。");
}
function normalizedCodeAgentAvailability(availability, structuredReadiness) {
const base = availability && typeof availability === "object" ? { ...availability } : {};
const structured = structuredReadiness && typeof structuredReadiness === "object" ? structuredReadiness : null;
if (!structured) return Object.keys(base).length > 0 ? base : null;
const provider = structured.provider ?? {};
const sessionRunner = structured.sessionRunner ?? {};
const codexStdio = structured.codexStdio ?? {};
const merged = {
...base,
structuredReadiness: structured,
status: firstString(base.status, structured.status),
ready: base.ready === true || structured.ready === true,
readinessStatus: firstString(base.readinessStatus, structured.status),
providerReady: structured.providerReady === true,
durableDbReady: structured.durableDbReady === true,
sessionRunnerReady: structured.sessionRunnerReady === true,
codexStdioFeasible: structured.codexStdioFeasible === true,
provider: firstString(base.provider, provider.provider),
mode: firstString(base.mode, provider.mode, sessionRunner.mode),
backend: firstString(base.backend, provider.backend),
capabilityLevel: firstString(base.capabilityLevel, sessionRunner.capabilityLevel),
sessionMode: firstString(base.sessionMode, sessionRunner.mode),
currentBlockers: Array.isArray(structured.currentBlockers) ? [...structured.currentBlockers] : [],
blockerCodes: [
...(Array.isArray(structured.currentBlockers) ? structured.currentBlockers : []),
...(Array.isArray(codexStdio.blockerCodes) ? codexStdio.blockerCodes : [])
],
blockers: [
...(Array.isArray(structured.currentBlockers)
? structured.currentBlockers.map((code) => ({ code }))
: [])
],
runner: {
...(base.runner ?? {}),
kind: firstString(base.runner?.kind, sessionRunner.kind),
provider: firstString(base.runner?.provider, provider.provider),
backend: firstString(base.runner?.backend, provider.backend),
sessionMode: firstString(base.runner?.sessionMode, sessionRunner.mode),
capabilityLevel: firstString(base.runner?.capabilityLevel, sessionRunner.capabilityLevel),
longLivedSession: base.runner?.longLivedSession === true || sessionRunner.longLivedSession === true,
durableSession: base.runner?.durableSession === true || sessionRunner.durableSession === true,
codexStdio: base.runner?.codexStdio === true || sessionRunner.codexStdio === true,
writeCapable: base.runner?.writeCapable === true || sessionRunner.writeCapable === true
},
codexStdioFeasibility: {
...(base.codexStdioFeasibility ?? base.codexStdio ?? {}),
ready: codexStdio.ready === true,
canStartLongLivedCodexStdio: codexStdio.feasible === true || codexStdio.ready === true,
status: codexStdio.status,
blockerCodes: Array.isArray(codexStdio.blockerCodes) ? [...codexStdio.blockerCodes] : [],
blockers: codexStdio.blocker ? [{ code: codexStdio.blocker }] : []
}
};
if (structured.currentBlocker) merged.reason = firstString(base.reason, structured.currentBlocker);
return merged;
}
function status(kind, label, tone, icon, summary) {
return { kind, label, tone, icon, summary };
}
function safeMerge(availability, latestMessage) {
const base = availability && typeof availability === "object" ? availability : {};
const message = latestMessage && typeof latestMessage === "object" ? latestMessage : {};
const merged = {
...base,
...message,
runner: { ...(base.runner ?? {}), ...(message.runner ?? {}) },
session: mergeSession(base.session, message.session),
runnerTrace: { ...(base.runnerTrace ?? {}), ...(message.runnerTrace ?? {}) },
providerTrace: { ...(base.providerTrace ?? {}), ...(message.providerTrace ?? {}) },
longLivedSessionGate: { ...(base.longLivedSessionGate ?? {}), ...(message.longLivedSessionGate ?? {}) },
codexStdioFeasibility: { ...(base.codexStdioFeasibility ?? base.codexStdio ?? {}), ...(message.codexStdioFeasibility ?? {}) }
};
if (base.blockers || message.blockers) merged.blockers = [...(base.blockers ?? []), ...(message.blockers ?? [])];
if (base.blockerCodes || message.blockerCodes) merged.blockerCodes = [...(base.blockerCodes ?? []), ...(message.blockerCodes ?? [])];
if (base.runnerLimitations || message.runnerLimitations) merged.runnerLimitations = [...(base.runnerLimitations ?? []), ...(message.runnerLimitations ?? [])];
if (message.toolCalls !== undefined) merged.toolCalls = message.toolCalls;
if (message.skills !== undefined) merged.skills = message.skills;
return merged;
}
function mergeSession(baseSession, messageSession) {
const base = typeof baseSession === "string" ? { status: baseSession } : (baseSession ?? {});
const message = typeof messageSession === "string" ? { status: messageSession } : (messageSession ?? {});
return { ...base, ...message };
}
function isLongLivedReady(payload) {
return (
(
payload.longLivedSessionGate?.status === "pass" ||
payload.longLivedSessionGate?.pass === true ||
payload.codexStdioFeasibility?.canStartLongLivedCodexStdio === true
) &&
(
payload.provider === "codex-stdio" ||
payload.runner?.kind === CODEX_APP_SERVER_RUNNER_KIND ||
payload.runner?.codexStdio === true ||
payload.session?.codexStdio === true
) &&
payload.capabilityLevel === "long-lived-codex-stdio-session" &&
payload.sessionMode === CODEX_APP_SERVER_SESSION_MODE &&
(
!payload.implementationType ||
payload.implementationType === CODEX_APP_SERVER_IMPLEMENTATION_TYPE
)
) && payload.status !== "failed" && payload.status !== "blocked" && payload.ready !== false;
}
function isReadOnlySessionTools(payload) {
return (
payload.capabilityLevel === "read-only-session-tools" ||
payload.capabilityLevel === "read-only-tools" ||
payload.agentKind === "controlled-readonly-session-registry" ||
payload.sessionMode === "controlled-readonly-session-registry" ||
payload.implementationType === "controlled-readonly-session-registry" ||
payload.runner?.kind === "hwlab-readonly-runner" ||
(payload.runner?.writeCapable === false &&
(payload.runner?.ready === true || payload.partialReady === true || payload.sessionRunnerReady === true) &&
payload.capabilityLevel !== "text-chat-only" &&
payload.runner?.kind !== "openai-responses-fallback") ||
payload.partialReady === true
);
}
function isStatelessOneShot(payload) {
return (
payload.sessionMode === "ephemeral-one-shot" ||
payload.runner?.kind === "codex-cli-one-shot-ephemeral" ||
payload.implementationType === "codex-cli-one-shot-ephemeral" ||
array(payload.runnerLimitations).includes("one-shot")
);
}
function isFallbackTextChatOnly(payload) {
return (
payload.capabilityLevel === "text-chat-only" ||
payload.runner?.kind === "openai-responses-fallback" ||
payload.implementationType === "openai-responses-fallback" ||
payload.agentKind === "openai-fallback" ||
payload.provider === "openai-responses"
);
}
function isBlocked(payload) {
return payload.status === "blocked" ||
payload.status === "failed" ||
payload.ready === false ||
payload.capabilityLevel === "blocked" ||
Boolean(payload.error);
}
function sessionLifecycleSummary(payload = {}) {
let status = normalizeSessionLifecycleStatus(firstString(
payload?.sessionLifecycleStatus,
payload?.sessionLifecycle?.status,
payload?.sessionSummary?.status,
payload?.session?.lifecycleStatus,
payload?.session?.lifecycle?.status,
payload?.runnerTrace?.sessionLifecycleStatus,
payload?.session?.status,
payload?.sessionStatus,
payload?.runnerTrace?.sessionStatus,
payload?.sessionReuse?.status,
payload?.status
), {
fallback: fallbackLifecycleStatus(payload)
});
const fallback = isFallbackTextChatOnly(payload) ||
payload?.fallbackUsed === true ||
payload?.sessionLifecycle?.fallback === true ||
payload?.sessionSummary?.fallback === true;
const degraded = fallback ||
payload?.degraded === true ||
payload?.sessionLifecycle?.degraded === true ||
payload?.sessionSummary?.degraded === true ||
payload?.longLivedSessionGate?.status === "blocked" ||
payload?.blocker?.code === "code_agent_session_evidence_missing" ||
payload?.error?.code === "code_agent_session_evidence_missing";
const evidenceSessionId = firstString(
payload?.session?.sessionId,
payload?.sessionReuse?.sessionId,
payload?.runnerTrace?.sessionId
);
const topLevelSessionId = firstString(payload?.sessionId);
const hasSession = Boolean(evidenceSessionId || (topLevelSessionId && topLevelSessionId !== firstString(payload?.conversationId)));
if ((fallback || degraded) && !hasSession) status = "failed";
const concreteLifecycleBlock = ["busy", "expired", "failed", "interrupted"].includes(status) && hasSession;
const evidenceMissing = payload?.blocker?.code === "code_agent_session_evidence_missing" ||
payload?.error?.code === "code_agent_session_evidence_missing";
const reused = payload?.sessionSummary?.reused ??
payload?.sessionLifecycle?.reused ??
payload?.sessionReuse?.reused ??
payload?.session?.reused ??
payload?.runnerTrace?.sessionReused ??
null;
if (fallback) {
return {
status: status ?? "failed",
label: "会话降级",
hint: "会话降级:当前响应来自 fallback/text-only/read-only 路径,不按完整 Code Agent 长会话成功展示。"
};
}
if (degraded && (evidenceMissing || !concreteLifecycleBlock)) {
return {
status: status ?? "failed",
label: "会话降级",
hint: "会话降级:会话证据不完整或运行路径降级,输入已保留,可重新发送建立新会话。"
};
}
if (status === "busy") {
return { status, label: "会话忙", hint: "会话忙/请等待:上一轮仍在处理,稍后重试或取消当前请求。" };
}
if (status === "expired") {
return { status, label: "会话已过期", hint: "会话已过期,可重新发送建立新的 Code Agent session。" };
}
if (status === "failed") {
return { status, label: "会话失败", hint: "当前 Code Agent session 已失败,需重新发送建立新会话。" };
}
if (status === "interrupted") {
return { status, label: "会话已中断", hint: "当前 Code Agent session 已中断;输入和 trace 已保留,可重试或重新发送。" };
}
if (status === "creating") {
return { status, label: "正在建立会话", hint: "正在建立 Code Agent session,请等待后端返回 session/thread。" };
}
if (status === "ready" || status === "idle") {
return reused === true
? { status, label: "继续当前会话", hint: "可继续当前会话:后端已确认复用现有 conversation/session/thread。" }
: { status, label: "新会话已建立", hint: "新会话已建立:后端返回了可复用的 session/thread。" };
}
return { status, label: "会话未确认", hint: "尚未观测到可复用的 Code Agent session 状态。" };
}
function normalizeSessionLifecycleStatus(value, { fallback = null } = {}) {
const text = firstString(value);
const status = String(text ?? "").toLowerCase();
if (["creating", "ready", "busy", "idle", "interrupted", "expired", "failed"].includes(status)) return status;
if (status === "canceled" || status === "cancelled") return "interrupted";
if (status === "timeout" || status === "error" || status === "blocked" || status === "degraded") return "failed";
if (status === "running") return "busy";
if (status === "completed" || status === "available" || status === "feasible" || status === "pass") return "idle";
return fallback;
}
function fallbackLifecycleStatus(payload) {
if (isFallbackTextChatOnly(payload) || payload?.degraded === true) return "failed";
if (payload?.status === "running") return "busy";
if (["failed", "timeout", "error"].includes(payload?.status)) return "failed";
if (payload?.status === "canceled") return "interrupted";
return null;
}
function isDegraded(payload, blockers) {
return payload.status === "partial" ||
payload.status === "degraded" ||
payload.readinessStatus === "partial" ||
payload.capabilityStatus === "controlled-readonly-session-registry" ||
blockers.length > 0;
}
function readinessBlockers(payload) {
const values = [
...array(payload?.blockerCodes),
...array(payload?.blockers).map((item) => item?.code ?? item),
...array(payload?.longLivedSessionGate?.blockers).map((item) => item?.code ?? item),
...array(payload?.codexStdioFeasibility?.blockers).map((item) => item?.code ?? item),
payload?.runtimeContract?.binary?.status === "missing" ? "codex_cli_binary_missing" : null,
payload?.runtimeContract?.binary?.present === true && payload?.runtimeContract?.binary?.executable === false ? "codex_cli_not_executable" : null,
payload?.runtimeContract?.binary?.present === true && payload?.runtimeContract?.binary?.nativeDependencyPresent === false ? "codex_cli_native_dependency_missing" : null,
payload?.runtimeContract?.lifecycleSupervisor?.status === "blocked" ? "runner_lifecycle_missing" : null,
payload?.runtimeContract?.stdioProtocol?.status === "blocked" ? "stdio_protocol_not_wired" : null,
payload?.reason,
payload?.error?.code,
payload?.providerStatus ? `provider_http_${payload.providerStatus}` : null,
payload?.error?.providerStatus ? `provider_http_${payload.error.providerStatus}` : null,
...array(payload?.missingEnv).map(() => "provider_config_blocked")
];
return [...new Set(values.map(safeBlocker).filter(Boolean))].slice(0, 4);
}
function safeBlocker(value) {
if (value && typeof value === "object" && !Array.isArray(value) && !value.code && !value.reason && !value.message) return null;
const text = safeField(typeof value === "object" ? value?.code ?? value?.reason ?? value?.message : value);
if (!text || text === "未观测" || /^_+$/u.test(text)) return null;
if (SECRET_MARKER.test(text)) return "provider_config_blocked";
return text.replace(/[^A-Za-z0-9_.:-]/gu, "_").slice(0, 72);
}
function unsafeGreenForNonReady(classification, blockers) {
return GREEN_TONES.has(classification.tone) &&
(classification.kind.includes("blocked") || classification.kind === "degraded" || blockers.some((blocker) => /blocked|unavailable|failed|degraded/iu.test(blocker)));
}
function currentString(value) {
const text = String(value ?? "").trim();
if (!text || NON_LIVE_VALUES.has(text.toLowerCase())) return null;
return text;
}
function firstString(...values) {
for (const value of values) {
const text = currentString(value);
if (text) return text;
}
return null;
}
function safeField(value) {
const text = currentString(value);
if (!text) return "未观测";
if (SECRET_MARKER.test(text)) return "已隐藏";
return text.replace(/\s+/gu, " ").slice(0, MAX_FIELD_LENGTH);
}
function safeTraceId(value) {
const text = currentString(value);
if (!text || SECRET_MARKER.test(text)) return null;
return text.replace(/\s+/gu, "").slice(0, MAX_FIELD_LENGTH);
}
function shortRevision(value) {
const text = safeTraceId(value);
if (!text) return "未观测";
return /^[a-f0-9]{12,40}$/iu.test(text) ? text.slice(0, 12) : text.slice(0, 24);
}
function compactJoin(values, separator) {
const parts = values.map((value) => value === "未观测" ? null : value).filter(Boolean);
return parts.length > 0 ? parts.join(separator) : "未观测";
}
function array(value) {
return Array.isArray(value) ? value : [];
}