fix: stream cloud web trace SSE
This commit is contained in:
@@ -4383,6 +4383,9 @@ async function inspectLegacyFailureWindow(page, { beforeMessageCount }) {
|
||||
contained: panel.scrollWidth <= panel.clientWidth + 2
|
||||
}))
|
||||
: [];
|
||||
const pendingTraceEvents = latestAgent
|
||||
? [...latestAgent.querySelectorAll(".message-trace-events li")].map((item) => item.textContent?.replace(/\s+/gu, " ").trim() ?? "")
|
||||
: [];
|
||||
const latestAgentBox = latestAgent?.getBoundingClientRect();
|
||||
const pendingStillRunning =
|
||||
latestAgent?.classList.contains("status-running") === true ||
|
||||
@@ -4398,6 +4401,7 @@ async function inspectLegacyFailureWindow(page, { beforeMessageCount }) {
|
||||
runningMessageVisible: Boolean(latestAgent?.classList.contains("status-running")),
|
||||
pendingChineseVisible: /正在处理|后端处理中|不会把旧 4500ms|结构化 blocker|真实超时/u.test(pendingText),
|
||||
pendingTraceVisible: /traceId\s*trc_|trace=trc_|trc_/u.test(pendingText),
|
||||
pendingTraceShowsEvents: pendingTraceEvents.some((text) => /#\d+|session|prompt|tool|assistant/u.test(text)),
|
||||
pendingConversationVisible: /conversation\s*cnv_|conversation=cnv_|cnv_/u.test(pendingText),
|
||||
pendingSessionVisible: /session\s*(等待后端分配|cnv_|ses_)/u.test(pendingText),
|
||||
pendingTraceCopyVisible: pendingRows.some((row) => /traceId/u.test(row.text) && /复制/u.test(row.text)),
|
||||
@@ -4789,6 +4793,7 @@ async function runLocalAgentFixtureSmoke({
|
||||
promptResults[0]?.classification?.blocker === "runner-blocked" &&
|
||||
promptResults[0]?.legacyWindow?.permanentFailureAround4500ms === false &&
|
||||
promptResults[0]?.legacyWindow?.pendingChineseVisible === true &&
|
||||
promptResults[0]?.legacyWindow?.pendingTraceShowsEvents === true &&
|
||||
(agentFixtureMode === "external-network-blocker"
|
||||
? ["能力未开放", "Runner 受阻", "服务受阻"].includes(ui.agentChatStatus)
|
||||
: ui.agentChatStatus === "Runner 受阻") &&
|
||||
@@ -4811,6 +4816,7 @@ async function runLocalAgentFixtureSmoke({
|
||||
result.legacyWindow?.runningMessageVisible === true &&
|
||||
result.legacyWindow?.pendingChineseVisible === true &&
|
||||
result.legacyWindow?.pendingTraceVisible === true &&
|
||||
result.legacyWindow?.pendingTraceShowsEvents === true &&
|
||||
result.legacyWindow?.pendingConversationVisible === true &&
|
||||
result.legacyWindow?.pendingSessionVisible === true &&
|
||||
result.legacyWindow?.pendingTraceCopyVisible === true &&
|
||||
@@ -5017,6 +5023,7 @@ async function inspectLocalAgentPendingViewport(browser, url, { width, height, r
|
||||
legacyWindow.runningMessageVisible === true &&
|
||||
legacyWindow.pendingChineseVisible === true &&
|
||||
legacyWindow.pendingTraceVisible === true &&
|
||||
legacyWindow.pendingTraceShowsEvents === true &&
|
||||
legacyWindow.pendingConversationVisible === true &&
|
||||
legacyWindow.pendingSessionVisible === true &&
|
||||
legacyWindow.pendingTraceCopyVisible === true &&
|
||||
@@ -5543,6 +5550,7 @@ async function inspectQuickPromptGeometry(page, viewport) {
|
||||
async function startStaticWebServer(options = {}) {
|
||||
const rootDir = path.resolve(options.rootDir ?? webRoot);
|
||||
const authFixtureSessions = new Set();
|
||||
const agentTraceStore = new Map();
|
||||
const server = http.createServer(async (request, response) => {
|
||||
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
||||
if (options.authFixture && await handleAuthFixtureApi({ request, response, url, authFixtureSessions })) {
|
||||
@@ -5554,7 +5562,7 @@ async function startStaticWebServer(options = {}) {
|
||||
if (options.quickPromptsFixture && await handleQuickPromptsFixtureApi({ request, response, url })) {
|
||||
return;
|
||||
}
|
||||
if (options.agentFixture && await handleLocalAgentFixtureApi({ request, response, url, options })) {
|
||||
if (options.agentFixture && await handleLocalAgentFixtureApi({ request, response, url, options, agentTraceStore })) {
|
||||
return;
|
||||
}
|
||||
if (options.liveBuildsFixture && request.method === "GET" && url.pathname === "/v1/live-builds") {
|
||||
@@ -5591,6 +5599,54 @@ async function startStaticWebServer(options = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function startLocalAgentTrace(agentTraceStore, { traceId, conversationId, delayMs }) {
|
||||
if (!agentTraceStore || agentTraceStore.has(traceId)) return;
|
||||
const startedAt = Date.now();
|
||||
const events = [];
|
||||
const append = (event) => {
|
||||
const normalizedEvent = {
|
||||
traceId,
|
||||
...event
|
||||
};
|
||||
events.push(normalizedEvent);
|
||||
agentTraceStore.set(traceId, localAgentTraceSnapshot({
|
||||
traceId,
|
||||
conversationId,
|
||||
startedAt,
|
||||
events,
|
||||
lastEvent: normalizedEvent
|
||||
}));
|
||||
};
|
||||
|
||||
append({ seq: 1, type: "session", stage: "created", status: "completed", label: "session:created" });
|
||||
const scheduledEvents = [
|
||||
[250, { seq: 2, type: "prompt", stage: "sent", status: "completed", label: "prompt:sent" }],
|
||||
[900, { seq: 3, type: "runner", stage: "started", status: "running", label: "runner:started" }],
|
||||
[1800, { seq: 4, type: "tool_call", stage: "tool_call", status: "running", label: "tool:fixture:running", toolName: "local.source.fixture" }],
|
||||
[Math.min(Math.max(delayMs - 1200, 2400), 3400), { seq: 5, type: "assistant", stage: "waiting", status: "running", label: "assistant:waiting" }]
|
||||
];
|
||||
for (const [waitMs, event] of scheduledEvents) {
|
||||
const timer = setTimeout(() => append(event), waitMs);
|
||||
timer.unref?.();
|
||||
}
|
||||
}
|
||||
|
||||
function localAgentTraceSnapshot({ traceId, conversationId = null, startedAt = Date.now(), events = [], lastEvent = null }) {
|
||||
return {
|
||||
traceId,
|
||||
runnerKind: "codex-mcp-stdio-runner",
|
||||
sessionMode: "codex-mcp-stdio-long-lived",
|
||||
sessionId: conversationId,
|
||||
sessionStatus: events.length > 0 ? "running" : "pending",
|
||||
status: events.length > 0 ? "running" : "pending",
|
||||
elapsedMs: Math.max(0, Date.now() - startedAt),
|
||||
waitingFor: events.length > 0 ? "fixture-response" : "fixture-trace",
|
||||
events: [...events],
|
||||
lastEvent,
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
async function handleAuthFixtureApi({ request, response, url, authFixtureSessions }) {
|
||||
if (url.pathname === "/auth/session" && request.method === "GET") {
|
||||
const token = authFixtureCookie(request);
|
||||
@@ -6100,7 +6156,25 @@ function liveBuildsFixturePayload() {
|
||||
};
|
||||
}
|
||||
|
||||
async function handleLocalAgentFixtureApi({ request, response, url, options = {} }) {
|
||||
async function handleLocalAgentFixtureApi({ request, response, url, options = {}, agentTraceStore = null }) {
|
||||
if (request.method === "GET" && url.pathname.startsWith("/v1/agent/chat/trace/")) {
|
||||
const parts = url.pathname.split("/").filter(Boolean);
|
||||
const traceId = decodeURIComponent(parts[4] ?? "");
|
||||
if (parts[5] === "stream") {
|
||||
jsonResponse(response, 503, {
|
||||
status: "failed",
|
||||
error: {
|
||||
code: "trace_stream_unavailable_for_fixture",
|
||||
message: "fixture intentionally forces EventSource fallback to polling"
|
||||
},
|
||||
traceId
|
||||
});
|
||||
return true;
|
||||
}
|
||||
jsonResponse(response, 200, agentTraceStore?.get(traceId) ?? localAgentTraceSnapshot({ traceId }));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.method === "GET" && (url.pathname === "/health/live" || url.pathname === "/v1")) {
|
||||
jsonResponse(response, 200, {
|
||||
serviceId: "hwlab-cloud-api",
|
||||
@@ -6234,10 +6308,15 @@ async function handleLocalAgentFixtureApi({ request, response, url, options = {}
|
||||
}
|
||||
if (request.method === "POST" && url.pathname === "/v1/agent/chat") {
|
||||
const body = await readJsonBody(request);
|
||||
await delay(options.agentDelayMs ?? 0);
|
||||
const timestamp = "2026-05-22T00:00:00.000Z";
|
||||
const conversationId = stringOrFallback(body?.conversationId, "cnv_source_fixture_browser");
|
||||
const traceId = stringOrFallback(body?.traceId, "trc_source_fixture_browser");
|
||||
startLocalAgentTrace(agentTraceStore, {
|
||||
traceId,
|
||||
conversationId,
|
||||
delayMs: options.agentDelayMs ?? 0
|
||||
});
|
||||
await delay(options.agentDelayMs ?? 0);
|
||||
const normalizedMessage = String(body?.message ?? "");
|
||||
const isSkillListPrompt = /列出你能使用的所有skill/u.test(normalizedMessage);
|
||||
const isExternalNetworkPrompt = /github|https?:\/\/|外网|公网|访问/u.test(normalizedMessage);
|
||||
|
||||
Reference in New Issue
Block a user