Files
pikasTech-HWLAB/internal/workbench/cloud-application.ts
T
2026-07-18 15:01:18 +02:00

46 lines
2.4 KiB
TypeScript

import type { WorkbenchApplication } from "./contracts.ts";
import { normalizeWorkbenchCloudAuthorization } from "./cloud-authorization.ts";
export function createCloudWorkbenchApplication(options: {
baseUrl: string;
authorization: string;
fetchImpl?: typeof fetch;
}): WorkbenchApplication {
if (!options.baseUrl) throw codedError("workbench_cloud_api_url_required", "WORKBENCH_CLOUD_API_URL is required");
const authorization = normalizeWorkbenchCloudAuthorization(options.authorization);
if (!authorization) throw codedError("workbench_cloud_api_auth_required", "WORKBENCH_CLOUD_API_AUTHORIZATION is required");
const fetchImpl = options.fetchImpl ?? fetch;
const request = async (method: string, route: string, body: Record<string, unknown> | undefined, actor: { id: string; role?: string | null }) => {
const response = await fetchImpl(`${options.baseUrl.replace(/\/$/u, "")}${route}`, {
method,
headers: {
authorization,
"content-type": "application/json",
"x-workbench-activity-dispatch": "1",
"x-hwlab-actor-id": actor.id,
"x-hwlab-actor-role": actor.role ?? "user"
},
body: body ? JSON.stringify(body) : undefined
});
const payload = await response.json().catch(() => null) as Record<string, unknown> | null;
if (!response.ok || !payload) throw codedError(String((payload?.error as any)?.code ?? "workbench_cloud_api_failed"), String((payload?.error as any)?.message ?? `Cloud API returned ${response.status}`), { status: response.status, route });
return payload;
};
return {
async health() { return { serviceId: "hwlab-workbench", status: "ready", cloudApi: "configured" }; },
async createSession(input) { return request("POST", "/v1/agent/sessions", input.params, input.actor); },
async admitTurn(input) {
await request("POST", "/v1/internal/workbench/admit", { ...input.params, traceId: input.traceId, sessionId: input.sessionId }, input.actor);
return input;
},
async dispatchTurn(input) {
return request("POST", "/v1/agent/chat", { ...input.params, traceId: input.traceId, sessionId: input.sessionId, shortConnection: true }, input.actor);
},
async cancelTurn(input) {
return request("POST", "/v1/agent/chat/cancel", { ...input.params, traceId: input.traceId }, input.actor);
}
};
}
function codedError(code: string, message: string, details?: unknown) { return Object.assign(new Error(message), { code, details }); }