Merge pull request #1840 from pikasTech/fix/workbench-sessions-go-1839

将 Workbench session list 迁移到 Go runtime
This commit is contained in:
Lyon
2026-06-21 21:25:54 +08:00
committed by GitHub
3 changed files with 731 additions and 132 deletions
+29
View File
@@ -14,6 +14,7 @@ import {
sendJson
} from "./server-http-utils.ts";
import { createWorkbenchReadModel } from "./workbench-read-model.ts";
import { createWorkbenchRuntimeClient } from "./workbench-runtime-client.ts";
import { createWorkbenchTurnProjection, createWorkbenchTurnTimingProjection, durableTraceStatus, RUNNING_STATUSES, TERMINAL_STATUSES } from "./workbench-turn-projection.ts";
import { emitHttpServerRequestSpan } from "./otel-trace.ts";
@@ -404,6 +405,34 @@ async function authenticateWorkbenchRead(request, response, options) {
}
async function handleWorkbenchSessionList(response, url, options, actor) {
if (url.searchParams.has("projectId") || url.searchParams.has("workspaceId")) return sendJson(response, 400, workbenchError("workbench_authority_removed", "Workbench session list is keyed by sessionId only."));
const limit = boundedSessionListLimit(url.searchParams.get("limit"));
const offset = cursorOffset(url.searchParams.get("cursor") ?? url.searchParams.get("after"));
const includeSessionId = safeSessionId(url.searchParams.get("includeSessionId"));
const includeRouteId = includeSessionId ?? safeConversationId(url.searchParams.get("includeSessionId"));
const runtime = options.workbenchRuntime ?? createWorkbenchRuntimeClient({ env: options.env ?? process.env, fetch: options.fetch, logger: options.logger });
if (typeof runtime?.listWorkbenchSessions !== "function") {
throw runtimeDependencyError("workbench_runtime_unconfigured", "Workbench runtime service is required for session list.", false);
}
const payload = await runtime.listWorkbenchSessions({
limit,
offset,
cursor: url.searchParams.get("cursor") ?? url.searchParams.get("after") ?? null,
includeSessionId: includeRouteId ?? null,
actor: { id: actor.id, role: actor.role ?? "user", valuesRedacted: true }
});
return sendJson(response, 200, payload);
}
function runtimeDependencyError(code, message, retryable = true) {
const error = new Error(message || code);
error.name = "WorkbenchRuntimeDependencyError";
error.code = code;
error.data = { serviceId: "hwlab-workbench-runtime", retryable, transient: retryable, valuesRedacted: true };
return error;
}
async function handleWorkbenchSessionListBunLegacy(response, url, options, actor) {
if (url.searchParams.has("projectId") || url.searchParams.has("workspaceId")) return sendJson(response, 400, workbenchError("workbench_authority_removed", "Workbench session list is keyed by sessionId only."));
const perf = options.backendPerformance;
const limit = boundedSessionListLimit(url.searchParams.get("limit"));
@@ -15,6 +15,7 @@ export function createWorkbenchRuntimeClient(options = {}) {
serviceId: "hwlab-workbench-runtime",
queryWorkbenchFacts: (params = {}) => postRuntime({ fetchFn, baseUrl, timeoutMs, path: "/v1/workbench-runtime/facts", body: params }),
queryAgentTraceEvents: (params = {}) => postRuntime({ fetchFn, baseUrl, timeoutMs, path: "/v1/workbench-runtime/trace-events", body: params }),
listWorkbenchSessions: (params = {}) => postRuntime({ fetchFn, baseUrl, timeoutMs, path: "/v1/workbench-runtime/sessions", body: params }),
readWorkbenchProjectionOutbox: (params = {}) => postRuntime({ fetchFn, baseUrl, timeoutMs, path: "/v1/workbench-runtime/projection-outbox", body: params }).then((result) => Array.isArray(result?.rows) ? result.rows : [])
};
}
File diff suppressed because it is too large Load Diff