/** * `ManagedToolsClient` — backed by QAR's managed-tools REST surface. * * - `GET /v1/tools` — the tool catalog (discovery). * - `POST /v1/tools/{name}:invoke` — invoke a tool. * - `GET /v1/tools/operations/{id}` — poll a long-running invocation. * - `DELETE /v1/tools/operations/{id}` — cooperative cancel. * * These are plain HTTP (`fetch`), not WebSocket — a consumer can list and * invoke managed tools without opening a task stream. The transport / auth * skeleton mirrors `InfoClient`: same DI bag, the shared `deriveHttpBaseUrl` * gate, mandatory bearer, and `authProvider.handle401Error()` on 401 (a 403 is * authorization, not authentication, so it is typed from the tool-error envelope). * * The headline ergonomic is that `invoke()` **hides the long-running-operation * protocol**: a tool that finishes inside the bounded-wait window returns its * result directly (the `200` fast path); one that escalates to a `202` is * polled to terminal transparently, honoring the server's `poll_interval` / * `Retry-After`. The `operation_id` handle never surfaces — callers `await` a * result or catch a `QodoToolError`. */ import type { JsonObject } from '../qar/json.js'; import type { ToolCatalog, ToolCatalogEntry } from '../qar/tools.js'; /** Options for {@link ManagedToolsClient.invoke}. */ export interface InvokeOptions { /** * Abort the invocation. Aborting during the long-running-operation poll * loop also issues a best-effort `DELETE` on the operation (cooperative * cancel) before the promise rejects with the signal's reason. */ readonly signal?: AbortSignal; /** * Forwarded as the `Idempotency-Key` request header — required by QAR for * mutating tools so a retried invocation doesn't double-execute. */ readonly idempotencyKey?: string; /** * Server-side bounded wait, in seconds, sent as `Prefer: wait=N` (RFC 7240). * The server holds the request open up to `N` seconds before escalating to * a `202` operation. Independent of {@link pollTimeoutMs}, which caps the * client-side poll loop. */ readonly maxWait?: number; /** * Client-side cap on the total poll loop, in milliseconds. When the loop * runs past this without reaching a terminal state, the promise rejects. * Unset means poll until terminal (or aborted). */ readonly pollTimeoutMs?: number; } export declare class ManagedToolsClient { private readonly baseUrl; private readonly apiVersion; private readonly apiPath; private readonly allowInsecureTransport; private readonly authProvider; private readonly extraHeaders; private readonly fetchImpl; private readonly traceContext; private cachedHttpBase; /** * The raw `GET /v1/tools` document, including `catalog_version` (the * content hash that doubles as the ETag). Use {@link list} when you only * want the entries. * * Not cached at this layer today — a consumer that re-reads the catalog per * invocation can revalidate with `catalog_version` itself; ETag * revalidation may move here in a follow-up without changing this shape. * * Throws `QodoAuthError` on 401 (auth source named), `Error` on any * other non-2xx (a 403 is authorization, not authentication). */ catalog(): Promise; /** * The managed-tool catalog as a plain array — `catalog().tools`. Entries are * sorted `(toolset, name)` server-side, so the order is stable across calls. */ list(): Promise; /** * Invoke a managed tool by name and resolve its result, hiding the * long-running-operation protocol: * * - `200` — the tool completed in the bounded-wait window; resolves the * result object. * - `202` — the invocation escalated to an operation; this polls * `GET /v1/tools/operations/{id}` (honoring `poll_interval` / * `Retry-After`) until terminal, then resolves `completed` results or * throws a `QodoToolError` for `failed`. * - non-2xx — throws `QodoToolError` carrying the server's typed `code` / * `message` / `metadata`; a bare 401 is `QodoAuthError`, but a 403 tool-error * envelope (e.g. `MT-REPO-NOT-IN-SCOPE`) is a typed `QodoToolError`. * * `opts.signal` aborts the poll loop and `DELETE`s the operation * (cooperative cancel) before rejecting. `opts.idempotencyKey` → * `Idempotency-Key` (mutating tools). `opts.maxWait` → `Prefer: wait=N`. * `opts.pollTimeoutMs` caps the client-side poll loop. */ invoke(name: string, args?: JsonObject, opts?: InvokeOptions): Promise; /** * Poll an accepted operation to a terminal state. Resolves `completed` * results; throws `QodoToolError` on `failed`. Aborting via `opts.signal` * `DELETE`s the operation before rejecting; `opts.pollTimeoutMs` caps the * loop. */ private pollOperation; /** Best-effort cooperative cancel — swallows errors (we're already aborting). */ private deleteOperation; private getJson; /** * Parse a non-2xx response into a thrown `QodoToolError` (the typed * `{ ok: false, error }` envelope) or a plain `Error` (a non-typed body such * as a framework 422 or an upstream 5xx HTML page). `requestLabel` names the * actual failing request (the invoke POST or an operation-poll GET) so the * fallback message attributes the right endpoint. */ private throwFromResponse; /** * Build a `QodoToolError` from a `failed` operation's `error` block — a bare * dict on the wire, so the `code` / `message` / `metadata` are read * defensively (an outcome with no recoverable code maps to * `OPERATION_OUTCOME_UNKNOWN`). */ private errorFromDetail; /** * Headers shared by every managed-tools request: the SDK-controlled bearer * plus `Accept`. Built via the case-insensitive `Headers` API so a * caller-supplied `authorization` in `ClientOptions.headers` is stripped — * bearer auth is controlled exclusively through `ClientOptions.auth`. */ private baseHeaders; /** * Lazy URL parsing — symmetric with `InfoClient.requireHttpBase`. * `QodoClient.validateOptions` only checks `baseUrl` is a non-empty string; * eager derivation would change behavior for callers who construct a client * with an invalid scheme but never call any HTTP method. */ private requireHttpBase; /** * Resolve the operation URL to poll. Honors the server's `Location` header * (absolute or base-relative) and falls back to the canonical * `/v1/tools/operations/{id}` path when it's absent. */ private static resolveOperationUrl; private validateResponseVersion; /** `Retry-After` (delta-seconds or HTTP-date) as milliseconds, or undefined. */ private static retryAfterMs; /** `Retry-After` as seconds, for `QodoToolError.retryAfter`. */ private static retryAfterSeconds; /** * Normalize a poll delay: a non-finite / negative value falls back to the * default cadence, and every value is floored to {@link MIN_POLL_DELAY_MS} * so a `0` interval (or a 429 with no `Retry-After`) can't tight-loop. */ private static sanitizeDelayMs; private static throwIfAborted; /** Abortable delay — rejects with the signal's reason if it fires mid-wait. */ private static sleep; } //# sourceMappingURL=ManagedToolsClient.d.ts.map