import type { JsonRecord, JsonValue } from "../common/types.js"; import { AgentRunError } from "../common/errors.js"; import { managerAuthorizationHeader, managerClientAuthConfigFromEnv } from "./auth.js"; export interface ManagerClientOptions { apiKey?: string | null; } export class ManagerClient { constructor(readonly baseUrl: string, readonly options: ManagerClientOptions = {}) {} async get(path: string): Promise { return this.request("GET", path); } async post(path: string, body: JsonValue): Promise { return this.request("POST", path, body); } async put(path: string, body: JsonValue): Promise { return this.request("PUT", path, body); } async patch(path: string, body: JsonValue): Promise { return this.request("PATCH", path, body); } async delete(path: string): Promise { return this.request("DELETE", path); } private async request(method: string, path: string, body?: JsonValue): Promise { const headers: Record = {}; const authHeader = managerAuthorizationHeader(this.options.apiKey === undefined ? managerClientAuthConfigFromEnv().apiKey : this.options.apiKey); if (authHeader) headers.authorization = authHeader; const init: RequestInit = { method, headers }; if (body !== undefined) { headers["content-type"] = "application/json"; init.body = JSON.stringify(body); } const response = await fetch(new URL(path, this.baseUrl), init); const text = await response.text(); if (text.trim().length === 0) throw new AgentRunError("infra-failed", `manager returned empty response for ${method} ${path}`, { httpStatus: 502 }); const envelope = JSON.parse(text) as JsonRecord; if (envelope.ok !== true) throw new AgentRunError(typeof envelope.failureKind === "string" ? envelope.failureKind as never : "infra-failed", typeof envelope.message === "string" ? envelope.message : `manager request failed: ${method} ${path}`, { httpStatus: response.status, details: envelope }); return envelope.data ?? null; } }