fix: 收敛 workbench 会话选择权威

This commit is contained in:
lyon
2026-06-18 08:49:31 +08:00
parent e9f09d0664
commit d29882c656
7 changed files with 170 additions and 10 deletions
@@ -90,6 +90,12 @@ async function handleRequest(request: IncomingMessage, response: ServerResponse)
if (/^\/v1\/workbench\/workspace\/[^/]+\/select-conversation$/u.test(path) && method === "POST") {
const body = await readJson(request);
state.selectRequests.push(redactRequestBody(body));
if (state.scenarioId === "server-authoritative-create" && body.create === true) {
const conversationId = "cnv_server_created";
if (!conversationById(conversationId)) state.conversations.unshift(createConversationFromSelect({ ...body, sessionId: "ses_server_created", threadId: null }, conversationId));
state.selectedConversationId = conversationId;
return json(response, 200, { workspace: workspacePayload() });
}
const conversationId = String(body.conversationId ?? "");
if (conversationId && !conversationById(conversationId) && body.create === true) state.conversations.unshift(createConversationFromSelect(body, conversationId));
if (conversationId && conversationById(conversationId)) state.selectedConversationId = conversationId;
@@ -112,7 +118,10 @@ async function handleRequest(request: IncomingMessage, response: ServerResponse)
}
const conversationMatch = path.match(/^\/v1\/agent\/conversations\/([^/]+)$/u);
if (conversationMatch && method === "GET") {
const conversation = conversationById(decodeURIComponent(conversationMatch[1] ?? ""));
const conversationId = decodeURIComponent(conversationMatch[1] ?? "");
if (state.scenarioId === "session-switch-detail-404-isolated" && conversationId === "cnv_stale_404") return json(response, 404, { ok: false, status: 404, error: { code: "conversation_not_found" } });
if (state.scenarioId === "completed-replay-detail-404" && conversationId === "cnv_completed") return json(response, 404, { ok: false, status: 404, error: { code: "conversation_replay_unavailable" } });
const conversation = conversationById(conversationId);
if (conversation && conversationProjectMismatch(conversation, url)) return json(response, 404, { ok: false, status: 404, error: { code: "conversation_project_mismatch" } });
return conversation ? json(response, 200, { conversation }) : json(response, 404, { ok: false, status: 404, error: { code: "conversation_not_found" } });
}
@@ -124,6 +133,7 @@ async function handleRequest(request: IncomingMessage, response: ServerResponse)
const turnMatch = path.match(/^\/v1\/agent\/turns\/([^/]+)$/u);
if (turnMatch && method === "GET") {
const traceId = decodeURIComponent(turnMatch[1] ?? "");
if (state.scenarioId === "completed-replay-detail-404" && traceId === "trc_completed") return json(response, 404, { ok: false, status: 404, error: { code: "turn_replay_unavailable" } });
if (traceId === state.staleNestedTraceId) return json(response, 502, { ok: false, status: 502, error: { code: "upstream_unavailable", message: "stale trace is unavailable" } });
if (traceProjectMismatch(traceId, url)) return json(response, 404, { ok: false, status: 404, error: { code: "trace_project_mismatch" } });
return json(response, 200, turnPayload(traceId));
@@ -132,6 +142,7 @@ async function handleRequest(request: IncomingMessage, response: ServerResponse)
const traceMatch = path.match(/^\/v1\/agent\/traces\/([^/]+)$/u);
if (traceMatch && method === "GET") {
const traceId = decodeURIComponent(traceMatch[1] ?? "");
if (state.scenarioId === "completed-replay-detail-404" && traceId === "trc_completed") return json(response, 404, { ok: false, status: 404, error: { code: "trace_replay_unavailable" } });
if (traceId === state.staleNestedTraceId) return json(response, 502, { ok: false, status: 502, error: { code: "upstream_unavailable", message: "stale trace is unavailable" } });
if (traceProjectMismatch(traceId, url)) return json(response, 404, { ok: false, status: 404, error: { code: "trace_project_mismatch" } });
return json(response, 200, tracePayload(traceId, url));
@@ -156,6 +167,10 @@ function createScenarioState(scenarioId: string): ScenarioState {
conversations.push(crossProjectConversation());
traces.trc_cross_project = crossProjectTrace();
}
if (id === "session-switch-detail-404-isolated") {
conversations.unshift(staleDetailConversation());
conversations.push(emptyConversation());
}
if (id === "terminal-empty-trace") {
conversations.push(terminalEmptyTraceConversation());
traces.trc_terminal_empty = terminalEmptyTrace();
@@ -163,6 +178,8 @@ function createScenarioState(scenarioId: string): ScenarioState {
if (id === "session-switch-empty-reload") conversations.push(emptyConversation());
const selectedConversationId = id === "deep-link" || id === "stale-nested-trace"
? "cnv_failed"
: id === "session-switch-detail-404-isolated" || id === "completed-replay-detail-404"
? "cnv_completed"
: id === "terminal-turn-stale-session-active"
? "cnv_completed"
: id === "terminal-empty-trace"
@@ -316,6 +333,23 @@ function terminalEmptyTrace(): JsonRecord {
return { traceId: "trc_terminal_empty", status: "completed", conversationId: "cnv_terminal_empty", sessionId: "ses_terminal_empty", threadId: "thr_terminal_empty", events: [], eventCount: 0, fullTraceLoaded: true, hasMore: false, finalResponse: { text: "终态空 Trace 已完成。" } };
}
function staleDetailConversation(): ConversationRecord {
const now = new Date().toISOString();
return {
conversationId: "cnv_stale_404",
projectId: state?.projectId ?? capture.scenario.projectId,
sessionId: "ses_stale_404",
threadId: "thr_stale_404",
status: "active",
startedAt: now,
updatedAt: now,
messageCount: 0,
firstUserMessagePreview: "已失效的列表项",
session: { sessionId: "ses_stale_404", threadId: "thr_stale_404", status: "active" },
messages: []
};
}
function emptyConversation(): ConversationRecord {
const now = new Date().toISOString();
return { conversationId: "cnv_empty", projectId: state?.projectId ?? capture.scenario.projectId, sessionId: "ses_empty", threadId: "thr_empty", status: "active", startedAt: now, updatedAt: now, messageCount: 0, firstUserMessagePreview: "空白会话", session: { sessionId: "ses_empty", threadId: "thr_empty", status: "active" }, messages: [] };