fix: relax workbench live status timeout
This commit is contained in:
@@ -608,6 +608,11 @@ function runStaticSmoke() {
|
||||
evidence: ["API 正常", "API 错误", "等待验证", "只读模式", "hwlab-cloud-api /health/live", "/v1/agent/chat", "/v1/m3/io", "raw degraded kept as internalRawStatuses"]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "workbench-live-surface-timeout-contract", hasWorkbenchLiveSurfaceTimeoutContract(files), "Workbench live status uses a dedicated live-surface timeout instead of the 4500ms light API budget.", {
|
||||
blocker: "runtime_blocker",
|
||||
evidence: ["DEFAULT_LIVE_SURFACE_TIMEOUT_MS=12000", "liveSurfaceFetch", "liveSurfaceRpc", "/v1/m3/status", "system.health"]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "code-agent-chat-primary-flow", hasCodeAgentChatContract(files), "Center Agent conversation sends to the controlled Code Agent chat endpoint and no longer uses 添加草稿 as the primary flow.", {
|
||||
blocker: "runtime_blocker",
|
||||
evidence: ["command-send", "agent-chat-status", "/v1/agent/chat", "conversationId/messageId/status/timestamps/error.message"]
|
||||
@@ -2641,6 +2646,25 @@ function hasCodeAgentLongTimeoutContract(files) {
|
||||
);
|
||||
}
|
||||
|
||||
function hasWorkbenchLiveSurfaceTimeoutContract(files) {
|
||||
const app = files.app;
|
||||
return (
|
||||
/DEFAULT_API_TIMEOUT_MS\s*=\s*4500/u.test(app) &&
|
||||
/DEFAULT_LIVE_SURFACE_TIMEOUT_MS\s*=\s*12000/u.test(app) &&
|
||||
/LIVE_SURFACE_TIMEOUT_MS\s*=\s*resolveTimeoutMs\("liveSurfaceTimeoutMs"/u.test(app) &&
|
||||
/timeoutMs:\s*LIVE_SURFACE_TIMEOUT_MS/u.test(functionBody(app, "liveSurfaceFetch")) &&
|
||||
/timeoutName:\s*`工作台实况 \$\{path\}`/u.test(functionBody(app, "liveSurfaceFetch")) &&
|
||||
/callRpc\(method,\s*params,\s*\{/u.test(functionBody(app, "liveSurfaceRpc")) &&
|
||||
/timeoutMs:\s*LIVE_SURFACE_TIMEOUT_MS/u.test(functionBody(app, "liveSurfaceRpc")) &&
|
||||
/timeoutMs:\s*options\?\.timeoutMs \?\? API_TIMEOUT_MS/u.test(functionBody(app, "callRpc")) &&
|
||||
/liveSurfaceFetch\("\/health\/live"\)/u.test(functionBody(app, "loadLiveSurface")) &&
|
||||
/liveSurfaceFetch\("\/v1\/m3\/status"\)/u.test(functionBody(app, "loadLiveSurface")) &&
|
||||
/liveSurfaceRpc\("system\.health"\)/u.test(functionBody(app, "loadLiveSurface")) &&
|
||||
/timeoutMs:\s*LIVE_SURFACE_TIMEOUT_MS/u.test(functionBody(app, "loadGateDiagnostics")) &&
|
||||
/timeoutName:\s*"工作台 M3 状态刷新"/u.test(functionBody(app, "runM3IoAction"))
|
||||
);
|
||||
}
|
||||
|
||||
function hasCodeAgentTraceReplayDisclosure({ app, styles }) {
|
||||
const tracePanelBody = functionBody(app, "messageTracePanel");
|
||||
const traceToolbarBody = functionBody(app, "messageTraceToolbar");
|
||||
|
||||
+36
-13
@@ -18,6 +18,7 @@ import {
|
||||
} from "./code-agent-m3-evidence.mjs";
|
||||
|
||||
const DEFAULT_API_TIMEOUT_MS = 4500;
|
||||
const DEFAULT_LIVE_SURFACE_TIMEOUT_MS = 12000;
|
||||
const DEFAULT_CODE_AGENT_TIMEOUT_MS = 600000;
|
||||
const DEFAULT_CODE_AGENT_SUBMIT_TIMEOUT_MS = 60000;
|
||||
const DEFAULT_CODE_AGENT_CANCEL_TIMEOUT_MS = 30000;
|
||||
@@ -28,6 +29,7 @@ const TRACE_STREAM_FALLBACK_MS = 2500;
|
||||
const TRACE_POLL_INTERVAL_MS = 1000;
|
||||
const FULL_TRACE_REPLAY_TIMEOUT_MS = 15000;
|
||||
const API_TIMEOUT_MS = resolveTimeoutMs("apiTimeoutMs", DEFAULT_API_TIMEOUT_MS, { min: 500, max: 30000 });
|
||||
const LIVE_SURFACE_TIMEOUT_MS = resolveTimeoutMs("liveSurfaceTimeoutMs", DEFAULT_LIVE_SURFACE_TIMEOUT_MS, { min: 5000, max: 60000 });
|
||||
let CODE_AGENT_TIMEOUT_MS = resolveUserCodeAgentTimeoutMs();
|
||||
let GATEWAY_SHELL_TIMEOUT_MS = resolveUserGatewayShellTimeoutMs();
|
||||
const CODE_AGENT_SUBMIT_TIMEOUT_MS = resolveTimeoutMs("codeAgentSubmitTimeoutMs", DEFAULT_CODE_AGENT_SUBMIT_TIMEOUT_MS, { min: configuredTimeoutMinMs("codeAgentSubmitTimeoutMs", 5000), max: 120000 });
|
||||
@@ -1593,15 +1595,15 @@ function wait(ms) {
|
||||
async function loadLiveSurface() {
|
||||
const projectId = gateSummary.topology.projectId;
|
||||
const [healthLive, liveBuilds, restIndex, m3Control, m3Status, health, adapter, audit, evidence] = await Promise.all([
|
||||
fetchJson("/health/live"),
|
||||
fetchJson("/v1/live-builds"),
|
||||
fetchJson("/v1"),
|
||||
fetchJson("/v1/m3/io"),
|
||||
fetchJson("/v1/m3/status"),
|
||||
callRpc("system.health"),
|
||||
callRpc("cloud.adapter.describe"),
|
||||
callRpc("audit.event.query", { projectId, limit: 6 }),
|
||||
callRpc("evidence.record.query", { projectId, limit: 6 })
|
||||
liveSurfaceFetch("/health/live"),
|
||||
liveSurfaceFetch("/v1/live-builds"),
|
||||
liveSurfaceFetch("/v1"),
|
||||
liveSurfaceFetch("/v1/m3/io"),
|
||||
liveSurfaceFetch("/v1/m3/status"),
|
||||
liveSurfaceRpc("system.health"),
|
||||
liveSurfaceRpc("cloud.adapter.describe"),
|
||||
liveSurfaceRpc("audit.event.query", { projectId, limit: 6 }),
|
||||
liveSurfaceRpc("evidence.record.query", { projectId, limit: 6 })
|
||||
]);
|
||||
|
||||
return {
|
||||
@@ -1618,13 +1620,27 @@ async function loadLiveSurface() {
|
||||
};
|
||||
}
|
||||
|
||||
function liveSurfaceFetch(path) {
|
||||
return fetchJson(path, {
|
||||
timeoutMs: LIVE_SURFACE_TIMEOUT_MS,
|
||||
timeoutName: `工作台实况 ${path}`
|
||||
});
|
||||
}
|
||||
|
||||
function liveSurfaceRpc(method, params = {}) {
|
||||
return callRpc(method, params, {
|
||||
timeoutMs: LIVE_SURFACE_TIMEOUT_MS,
|
||||
timeoutName: `工作台实况 /json-rpc ${method}`
|
||||
});
|
||||
}
|
||||
|
||||
async function loadGateDiagnostics() {
|
||||
if (state.gateDiagnostics.loading) return;
|
||||
state.gateDiagnostics.loading = true;
|
||||
state.gateDiagnostics.error = null;
|
||||
renderGateTable();
|
||||
const response = await fetchJson("/v1/diagnostics/gate", {
|
||||
timeoutMs: API_TIMEOUT_MS,
|
||||
timeoutMs: LIVE_SURFACE_TIMEOUT_MS,
|
||||
timeoutName: "内部复核 live 聚合"
|
||||
});
|
||||
state.gateDiagnostics.loading = false;
|
||||
@@ -1733,7 +1749,7 @@ function readActivityRef(activityRef, fallbackMs = Date.now()) {
|
||||
};
|
||||
}
|
||||
|
||||
async function callRpc(method, params = {}) {
|
||||
async function callRpc(method, params = {}, options = {}) {
|
||||
const id = nextProtocolId("req");
|
||||
const traceId = nextProtocolId("trc");
|
||||
const response = await fetchJson("/json-rpc", {
|
||||
@@ -1751,7 +1767,9 @@ async function callRpc(method, params = {}) {
|
||||
serviceId: "hwlab-cloud-web",
|
||||
environment: "dev"
|
||||
}
|
||||
})
|
||||
}),
|
||||
timeoutMs: options?.timeoutMs ?? API_TIMEOUT_MS,
|
||||
timeoutName: options?.timeoutName ?? `/json-rpc ${method}`
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -1837,6 +1855,8 @@ async function runM3IoAction(action) {
|
||||
"X-Trace-Id": traceId,
|
||||
"X-Actor-Id": "usr_hwlab_cloud_web"
|
||||
},
|
||||
timeoutMs: LIVE_SURFACE_TIMEOUT_MS,
|
||||
timeoutName: `工作台 M3 IO ${action}`,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
@@ -1857,7 +1877,10 @@ async function runM3IoAction(action) {
|
||||
sourceKind: response.data?.evidenceState?.status === "green" ? "DEV-LIVE" : "BLOCKED"
|
||||
};
|
||||
}
|
||||
const refreshedStatus = await fetchJson("/v1/m3/status");
|
||||
const refreshedStatus = await fetchJson("/v1/m3/status", {
|
||||
timeoutMs: LIVE_SURFACE_TIMEOUT_MS,
|
||||
timeoutName: "工作台 M3 状态刷新"
|
||||
});
|
||||
if (refreshedStatus.ok) {
|
||||
state.m3Control.status = refreshedStatus.data;
|
||||
}
|
||||
|
||||
@@ -401,6 +401,8 @@ assert.match(app, /renderRecords\(state\.liveSurface\)/);
|
||||
assert.match(app, /traceId: error\.traceId \|\| traceId/);
|
||||
assert.match(app, /error\.traceId = (?:traceId|response\.data\?\.traceId \|\| traceId)/);
|
||||
assert.match(app, /DEFAULT_API_TIMEOUT_MS\s*=\s*4500/);
|
||||
assert.match(app, /DEFAULT_LIVE_SURFACE_TIMEOUT_MS\s*=\s*12000/);
|
||||
assert.match(app, /LIVE_SURFACE_TIMEOUT_MS\s*=\s*resolveTimeoutMs\("liveSurfaceTimeoutMs"/);
|
||||
assert.match(app, /DEFAULT_CODE_AGENT_TIMEOUT_MS\s*=\s*600000/);
|
||||
assert.match(app, /DEFAULT_CODE_AGENT_SUBMIT_TIMEOUT_MS\s*=\s*60000/);
|
||||
assert.match(app, /CODE_AGENT_TIMEOUT_STORAGE_KEY/);
|
||||
@@ -414,6 +416,11 @@ assert.match(styles, /\.agent-timeout-control\s*{/);
|
||||
assert.match(app, /activityRef:\s*\(\)\s*=>\s*state\.currentRequest/);
|
||||
assert.match(functionBody(app, "fetchJson"), /timeoutMs\s*=\s*API_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "fetchJson"), /无新事件/);
|
||||
assert.match(functionBody(app, "liveSurfaceFetch"), /timeoutMs:\s*LIVE_SURFACE_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "liveSurfaceRpc"), /timeoutMs:\s*LIVE_SURFACE_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "loadLiveSurface"), /liveSurfaceFetch\("\/v1\/m3\/status"\)/);
|
||||
assert.match(functionBody(app, "loadLiveSurface"), /liveSurfaceRpc\("system\.health"\)/);
|
||||
assert.match(functionBody(app, "callRpc"), /timeoutMs:\s*options\?\.timeoutMs \?\? API_TIMEOUT_MS/);
|
||||
for (const hardwareTerm of [
|
||||
"Gateway 在线",
|
||||
"BOX 在线",
|
||||
@@ -1014,11 +1021,17 @@ assert.match(app, /createdAt/);
|
||||
assert.match(app, /updatedAt/);
|
||||
assert.match(app, /error\?\.message/);
|
||||
assert.match(app, /DEFAULT_API_TIMEOUT_MS\s*=\s*4500/);
|
||||
assert.match(app, /DEFAULT_LIVE_SURFACE_TIMEOUT_MS\s*=\s*12000/);
|
||||
assert.match(app, /LIVE_SURFACE_TIMEOUT_MS\s*=\s*resolveTimeoutMs\("liveSurfaceTimeoutMs"/);
|
||||
assert.match(app, /DEFAULT_CODE_AGENT_TIMEOUT_MS\s*=\s*600000/);
|
||||
assert.match(app, /CODE_AGENT_SUBMIT_TIMEOUT_MS/);
|
||||
assert.match(app, /CODE_AGENT_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "sendAgentMessage"), /timeoutMs:\s*CODE_AGENT_SUBMIT_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "waitForAgentMessageResult"), /CODE_AGENT_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "liveSurfaceFetch"), /timeoutMs:\s*LIVE_SURFACE_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "liveSurfaceRpc"), /timeoutMs:\s*LIVE_SURFACE_TIMEOUT_MS/);
|
||||
assert.match(functionBody(app, "loadLiveSurface"), /liveSurfaceFetch\("\/health\/live"\)/);
|
||||
assert.match(functionBody(app, "loadLiveSurface"), /liveSurfaceRpc\("system\.health"\)/);
|
||||
assert.match(app, /HWLAB_CLOUD_WEB_CONFIG/);
|
||||
assert.match(app, /sourceKind:\s*"PENDING"/);
|
||||
assert.match(app, /旧 4500ms/);
|
||||
|
||||
Reference in New Issue
Block a user