/** * Per-`kind` payload shapes for the QAR envelope union — public surface. * * Backed by the codegen output in `./generated/envelope.ts`. The overlay * sharpens the wire shape with three SDK-side projections that the JSON * Schema cannot express: * * - **Branded UUIDs.** `task_id`, `tool_call_id`, `since_message_id`, and * `offending_message_id` arrive from codegen as plain `string`. Each is * widened back to its branded type (`TaskId`, `ToolCallId`, `MessageId`) * so the compiler stops callers from mixing IDs at API boundaries. * - **`ToolResponseResult`.** The discriminated-union convenience accepted * by `client.tools.respond(node_name, response)`. The wire ships a flat * `status: 'ok' | 'error'` per-response item; the SDK union preserves * `success` / `error` / `denied` semantics, and the glue translates * between the two at send time (denied → `status: 'error'` with * `error.code: 'denied'`). * - **Parallel-batched tool envelope.** `tool.request` carries * `calls: ToolCall[]` (always a list, even for a single call — modern * LLM `parallel_tool_use`) and a required `node_name`; `tool.response` * carries `responses: ToolResponseItem[]` plus the same `node_name`. * The overlay here is the consumer-facing shape; while the QAR-side * schema bump is in flight, the codegen output in * `./generated/envelope.ts` still carries the pre-amendment single-call * shape — the overlay masks it. When `schemas/qar/.qar-version` is * bumped, re-running `npm run codegen:qar` collapses the overlay back * to a thin branded-id projection. * * QAR↔SDK name reconciliation: QAR's `task.start` envelope payload is * `TaskStartPayload` (kept QAR-native here); its inner `task.start.input` * shape is `QodoTaskStartPayload` upstream, surfaced to consumers as * `TaskInput`. The wire-faithful generated names stay internal (`_Gen*`); * the public surface uses the deduplicated `TaskStart*Payload` / `TaskInput` * set. */ import type { TaskStartPayload as _GenTaskStartPayload, TaskContinuePayload as _GenTaskContinuePayload, TaskCancelPayload as _GenTaskCancelPayload, TaskResubscribePayload as _GenTaskResubscribePayload, TaskDeltaPayload as _GenTaskDeltaPayload, TaskDonePayload as _GenTaskDonePayload, StateUpdatePayload as _GenStateUpdatePayload, AgentSpawnPayload as _GenAgentSpawnPayload, ToolActivityPayload as _GenToolActivityPayload, FlowPausePayload as _GenFlowPausePayload, FlowResumePayload as _GenFlowResumePayload, ErrorPayload as _GenErrorPayload, QodoTaskStartPayload as _GenQodoTaskStartInner } from './generated/envelope.js'; import type { JsonObject, JsonValue } from './json.js'; import type { MessageId, TaskId, ToolCallId } from './ids.js'; import type { InlineAgentSpec, InlineGraphSpec } from './specs.js'; /** One option in a `HITLBlock.kind: 'choice'` menu. */ export interface HITLChoiceOption { /** Stable identifier the resolver selects. */ readonly id: string; /** Display label shown to the human resolver. */ readonly label: string; /** Optional longer explanation rendered alongside the label. */ readonly description?: string; } /** * HITL block carried on a `ToolCall.hitl` field. Three discriminated * shapes per QAR's `HITLBlock` Pydantic model: * * - `'prompt'` — free-form text response. * - `'choice'` — closed-set choice from `options[]`. * - `'schema'` — structured response matching `schema` (JSON Schema). * * `prompt` (the user-facing prompt string) is required on every arm — * QAR's `HITLBlock` Pydantic model carries it as a mandatory field. The * `kind`-specific fields gate the resolver UI: a 'choice' block always * carries `options`, a 'schema' block always carries `schema`. */ export type HITLBlock = { readonly kind: 'prompt'; readonly prompt: string; } | { readonly kind: 'choice'; readonly prompt: string; readonly options: readonly HITLChoiceOption[]; } | { readonly kind: 'schema'; readonly prompt: string; /** JSON Schema (`type: 'object'`, etc.) the resolution must validate against. */ readonly schema: JsonObject; }; /** * Inner shape of `task.start.input` — the per-turn agent input bag * (`user_query`, `params`, `metadata`, `content`). Maps to QAR's * `QodoTaskStartPayload` wire model. * * Forward-compatible: every field is optional with a Pydantic default, so * consumers can ship `{}` and let the runtime pick defaults. New fields land * on QAR first; the codegen then propagates them here. */ export type TaskInput = _GenQodoTaskStartInner; /** A text segment of a multimodal user message. */ export interface TextPart { readonly type: 'text'; readonly text: string; } /** * An inline file (image or PDF) segment of a multimodal user message. One * part type serves every file kind — the kind is carried by `media_type`, * never a separate shape. * * - `media_type` — IANA media type of the bytes (e.g. `'image/png'`, * `'application/pdf'`). Required; the runtime allowlist decides which * types it accepts. * - `data` — base64-encoded file bytes (no `data:` URL prefix). * - `filename` — optional client metadata; treated as sensitive * downstream (kept out of span attributes), never load-bearing. */ export interface FilePart { readonly type: 'file'; readonly media_type: string; readonly data: string; readonly filename?: string | null; } /** * One ordered part of a multimodal user turn — discriminated on `type`. * Order is semantically meaningful (an ordered array, not a sidecar list). */ export type ContentPart = TextPart | FilePart; /** * `task.start` payload — server-side static agent dispatch (the original * single-variant shape — `agent_id` references a QAR-registered agent). * * `input` keeps the typed `TaskInput` shape from the schema so * excess fields are caught at compile time — a widened `JsonObject & …` * shape would disable excess-property checking and let legacy `qodo_v1` * payloads slip through. * * Optional `idempotency_key` opt-in. Absent → server mints a fresh * uuidv7 and every call gets a unique session_id (DX default). Present → * server derives `session_id = uuid5(QAR_NS_V1, f"{tenant_id}:{key}")` so * two pods receiving the same `(tenant_id, idempotency_key)` serialize * on the same lease key. Validation: 1–512 Unicode code points, no NUL * byte; `TaskClient` runs the same check pre-wire so a bad value fails * fast. */ export type TaskStartByIdPayload = Omit<_GenTaskStartPayload, 'input'> & { readonly input: TaskInput; /** Discriminator pad — `agent` and `graph` never appear on the by-id arm. */ readonly agent?: never; readonly graph?: never; readonly idempotency_key?: string | null; }; /** * `task.start` payload — client-defined inline single-agent shape. * The body of `agent` is the data-only safe subset enforced by QAR's * wire-validation (`D10-R*` rules). * * Mutually exclusive with `TaskStartByIdPayload` and `TaskStartWithGraphPayload` * via the `agent_id?: never` / `graph?: never` discriminators — TypeScript * narrows on the present field. */ export interface TaskStartWithAgentPayload { readonly agent: InlineAgentSpec; readonly agent_id?: never; readonly graph?: never; readonly input: TaskInput; readonly skill?: string | null; /** Optional caller-supplied idempotency key — see {@link TaskStartByIdPayload.idempotency_key}. */ readonly idempotency_key?: string | null; } /** * `task.start` payload — client-defined inline multi-agent graph. The * body of `graph` is the declarative topology QAR's wire validator * gates with `D11-R*` rules (acyclicity, edge resolution, role + * edge-kind invariants for evaluators). * * Mutually exclusive with the other two variants — see * `TaskStartWithAgentPayload`. */ export interface TaskStartWithGraphPayload { readonly graph: InlineGraphSpec; readonly agent_id?: never; readonly agent?: never; readonly input: TaskInput; readonly skill?: string | null; /** Optional caller-supplied idempotency key — see {@link TaskStartByIdPayload.idempotency_key}. */ readonly idempotency_key?: string | null; } /** * Discriminated union of every `task.start` payload variant QAR accepts. * * Three variants, gated by which top-level key is present: * - `{ agent_id, input }` — server-side static agent dispatch. * - `{ agent, input }` — client-defined inline single-agent. * - `{ graph, input }` — client-defined inline multi-agent graph. * * The variants are mutually exclusive via `?: never` on the absent fields. * `client.tasks.start` accepts a `TaskStartByIdPayload`; * `client.tasks.startWithAgent` / `startWithGraph` take the matching * narrower variant — see `TaskClient`. */ export type TaskStartPayload = TaskStartByIdPayload | TaskStartWithAgentPayload | TaskStartWithGraphPayload; /** * Session lifecycle state — the SDK-side surface for QAR's per-session * state machine carried on `task.started` (idempotent return) and * `task.force_resumed` (stuck-session recovery). * * `'auto-paused'` — admission-committed, runtime has yielded its lease, * waiting on `task.continue` to resume. * `'running'` — runtime is actively executing; a `task.continue` will * queue until the next auto-pause boundary. * `'completed' | 'cancelled' | 'failed'` — terminal. The owning task can * no longer be continued; the session can be re-dispatched (a NEW task on * the same `session_id`, inheriting full `session_messages` history). */ export type SessionState = 'auto-paused' | 'running' | 'completed' | 'cancelled' | 'failed'; /** * `task.started` payload — admission-commit ack. * * QAR emits exactly one `task.started` envelope per successful `task.start` * admission, synchronously after derivation + admission work + lease * acquisition + replay-append succeeds and before the background agent * run is scheduled. The envelope's inherited `session_id` carries the * server-derived UUID; the inherited `parent_message_id` equals the * originating `task.start.message_id` so the SDK correlates without * joining on payload fields. * * **Idempotent admission fields (forward-compatible)**: * * - `is_new` — `true` for a fresh dispatch; `false` when QAR is * returning the existing `task_id` for an already-dispatched session * (idempotent admission). Old SDK clients that read only `task_id` * keep working unchanged — the field is additive. * - `state` — the session's current state at the time of the ack. * Present when `is_new === false`. Omitted on a fresh dispatch * (`'running'` is implied — the agent loop is about to start). * - `previous_task_id` + `previous_state` — populated ONLY on terminal * re-dispatch (consumer asked to start; the previous task was * `completed | cancelled | failed`, so QAR minted a NEW `task_id` * inheriting the full `session_messages` history). Lets the consumer * surface "this is a new task after a prior failure" UX without * joining against external state. * * The SDK doesn't yield this envelope on the public `TaskEvent` iterator * — it's the start ack, not a content event. Instead, `TaskStartIterable` * resolves its `sessionId` / `admittedTaskId` / `admissionResult` * promises from the inherited `session_id` + payload fields when this * envelope arrives. */ export interface TaskStartedPayload { readonly task_id: TaskId; /** * `true` when this `task.started` reports a freshly-admitted task; * `false` when QAR is returning the existing task for an * already-dispatched session (idempotent admission). Optional for * back-compat: old QAR builds omit the field and the SDK treats it as * `true` (the pre-idempotent-admission behavior). */ readonly is_new?: boolean; /** * Session state at the time of the ack. Present when `is_new === false` * (idempotent return); the SDK uses it to decide how to deliver the * caller's `input` (immediate `task.continue` on `'auto-paused'`, * queued `task.continue` on `'running'`). */ readonly state?: SessionState; /** * On terminal re-dispatch — the prior task's id. The current `task_id` * is the NEW task; `previous_task_id` lets the consumer correlate to * persisted state for the failed/completed task. */ readonly previous_task_id?: TaskId; /** * On terminal re-dispatch — the prior task's terminal state. */ readonly previous_state?: SessionState; } /** * `task.forceResume` payload — explicit stuck-session recovery primitive. * * Carries the consumer's `idempotency_key` (deterministic logical-session * identity — Slack thread, IDE workspace path, etc.). QAR derives the * session UUID server-side via the same `uuidv5(QAR_NS_V1, tenant_id + * ":" + idempotency_key)` derivation as `task.start` admission. * * Use case: bot died mid-tool-call / mid-HITL; session stuck `running` * with outstanding `tool_call_id` / `hitl_id` that will never resolve. * QAR cancels in-flight tool/HITL, synth-resolves pending HITLs, appends * a system marker to `session_messages`, and transitions to * `auto-paused`. */ export interface TaskForceResumePayload { readonly idempotency_key: string; } /** * `task.force_resumed` payload — ack for `task.forceResume`. * * Distinct envelope kind from `task.started` (no admission semantics * apply — the session was already admitted; we're recovering it). The * SDK exposes the response via `Promise<{taskId, state}>` from * `tasks.forceResume`. * * `state` is `'auto-paused'` on the common path (in-flight work was * cancelled + session transitioned). For passthrough on already-paused * / terminal sessions, QAR reports the actual state — the SDK doesn't * second-guess. */ export interface TaskForceResumedPayload { readonly task_id: TaskId; readonly state: SessionState; } export type TaskContinuePayload = Omit<_GenTaskContinuePayload, 'task_id'> & { readonly task_id: TaskId; }; export type TaskCancelPayload = Omit<_GenTaskCancelPayload, 'task_id'> & { readonly task_id: TaskId; }; /** * `task.canceling` payload — cancel-ack wire surface. * * Emitted by the pod that processed a `task.cancel` envelope as the * cancellation propagates to the owning pod. Informational: the terminal * `task.done { status: 'canceled' | 'failed' }` still arrives once the * owning pod tears the task down. * * Fields mirror QAR's `TaskCancelingPayload` Pydantic model verbatim: * * - `task_id` — the cancelled task (branded by the SDK overlay so the * id stays distinguishable from `MessageId` / `SessionId` at API * boundaries). * - `received_by_pod` — opaque pod identifier that initially received * the `task.cancel`. Best-effort; do not branch business logic on it. * - `owning_pod` — opaque pod identifier that owns the task right now * (may equal `received_by_pod` for single-pod deployments). * - `cancel_reason` — echo of the consumer's `TaskCancelPayload.reason`, * if any. * - `expected_terminal_within_s` — best-effort SLO hint for how long * until terminal `task.done` arrives. Advisory only — consumers * waiting on the iterator should still wait for the envelope itself. * * Surfaced to consumers via `ClientCancelAckedEvent` rather than as a * `TaskEvent` variant — keeps the consumer `switch (event.kind)` * surface stable while still letting cancellation UIs render the "ack * received, waiting for terminal" intermediate state. */ export interface TaskCancelingPayload { readonly task_id: TaskId; readonly received_by_pod?: string | null; readonly owning_pod?: string | null; readonly cancel_reason?: string | null; readonly expected_terminal_within_s?: number | null; } /** * Resubscribe to an existing task after a transport drop. The codegen'd type * (per the JSON Schema) leaves `task_id` optional, but the operational * contract — and the `TaskClient.resubscribe()` signature, and the * `docs/sdk2/reconnect-replay.md` worked example — requires it. The overlay * tightens the field so raw-envelope users (`client.send({ kind: * 'task.resubscribe', payload: ... })`) can't compile a bad envelope. */ export type TaskResubscribePayload = Omit<_GenTaskResubscribePayload, 'task_id' | 'since_message_id'> & { readonly task_id: TaskId; readonly since_message_id?: MessageId | null; }; export type TaskDeltaPayload = Omit<_GenTaskDeltaPayload, 'task_id'> & { readonly task_id: TaskId; }; export type TaskDonePayload = Omit<_GenTaskDonePayload, 'task_id'> & { readonly task_id: TaskId; }; /** * Single tool call inside a parallel-batched `tool.request` envelope. * * Modern LLM tool-use protocols (OpenAI `parallel_tool_use`, Anthropic * `tool_use` blocks, etc.) emit multiple tool calls per turn; the agent loop * waits until every response lands before resuming. The wire always carries a * list — single-call cases are just `calls.length === 1`, never a special * shape. The branded `ToolCallId` is the dedup key for matching responses * back to calls. */ export interface ToolCall { readonly tool_call_id: ToolCallId; /** Tool name as registered in QAR's tool registry. */ readonly name: string; /** Argument bag — opaque JSON object; the handler narrows against the tool's schema. */ readonly arguments: JsonObject; /** * HITL block. Populated when this tool call * requires a human-in-the-loop resolution before the agent loop can * consume its result. `null`/absent means the tool call is fully * automated. Handlers can `if (call.hitl !== null && call.hitl !== * undefined)` to branch on the structural discriminator and render * the appropriate UI; QAR's runtime owns persistence, resolver auth, * and timeout behavior. */ readonly hitl?: HITLBlock | null; } /** * Single response inside a parallel-batched `tool.response` envelope. * * Wire-faithful: `status` is the two-arm `'ok' | 'error'` discriminator the * runtime expects. The SDK accepts the richer three-arm `ToolResponseResult` * union at its public surface (`success` / `error` / `denied`) and translates * `denied` to `status: 'error'` with `error.code: 'denied'` at the wire * boundary so policy rejections stay distinguishable in QAR's tool-loop * telemetry. */ export interface ToolResponseItem { readonly tool_call_id: ToolCallId; readonly status: 'ok' | 'error'; /** Populated when `status === 'ok'`. Open-shaped JSON value; handler vouches. */ readonly result?: JsonValue; /** * Populated when `status === 'error'`. `code` distinguishes failure modes * (`'denied'` for policy rejection, otherwise generic `'error'`); `message` * is the human-readable reason, truncated at the wire boundary. */ readonly error?: { readonly code: string; readonly message: string; }; } /** * `tool.request` payload — parallel-batched shape. * * `calls` is always a list (length ≥ 1). `node_name` is required on every * envelope so a multi-node graph routes responses back to the right pending * call set: without it, parallel nodes with in-flight tool calls couldn't be * disambiguated. Single-agent Pattern A/B emits `node_name: 'default'` (or * the configured agent identifier); Pattern C graphs emit the originating * graph node id. */ export interface ToolRequestPayload { readonly calls: readonly ToolCall[]; readonly node_name: string; } /** * `tool.response` payload — parallel-batched shape. * * `responses` is always a list (length ≥ 1, matches the originating request's * `calls` by `tool_call_id`, not order). `node_name` echoes the inbound * request so the runtime can route to the correct pending call set. */ export interface ToolResponsePayload { readonly responses: readonly ToolResponseItem[]; readonly node_name: string; } export type StateUpdatePayload = _GenStateUpdatePayload; export type AgentSpawnPayload = _GenAgentSpawnPayload; /** * `tool.activity` payload — redacted managed-tool notification. `outcome` is * `'ok' | 'error'`; `code` carries the `MT-*` error code on the failure path * and is absent on success. Never carries the bearer or the call arguments. */ export type ToolActivityPayload = _GenToolActivityPayload; export type FlowPausePayload = _GenFlowPausePayload; export type FlowResumePayload = _GenFlowResumePayload; export type ErrorPayload = Omit<_GenErrorPayload, 'offending_message_id'> & { readonly offending_message_id?: MessageId | null; /** * SDK retry hint for the `admission_in_progress` error * code. Carries a positive integer (milliseconds) when the server has * load info; absent → SDK falls back to exponential backoff with jitter * (initial 100 ms, doubling, capped at `PENDING_ADMISSION_TIMEOUT`). * Codegen base doesn't include this field yet (QAR schema bump pending); * the overlay adds it so consumers reading the error payload statically * see the hint. */ readonly retry_after_ms?: number | null; }; /** * `bulletin.post` and `artifact.add` payloads stay open-shaped on the QAR * side (`dict[str, Any]`). QAR will narrow once their * upstream finding/artifact work lands. */ export type BulletinPostPayload = JsonObject; export type ArtifactAddPayload = JsonObject; /** Terminal status for a `task.done` envelope. Narrowed from the QAR enum. */ export type TaskStatus = TaskDonePayload['status']; /** * Why a run reached its terminal, when the server volunteers a reason. * Absent on an ordinary terminal, so read it as an enrichment on * `TaskStatus`, not a substitute. Per-value semantics are on the generated * `TaskDonePayload`. Derived, so the union can't drift from the schema. */ export type TerminusReason = NonNullable; /** * SDK-side outcome trichotomy for a tool result. * * Distinct from the wire's two-arm `status: 'ok' | 'error'`: the SDK preserves * `denied` so policy-rejection handlers (approval middleware, capability * gates) stay first-class at the public surface. The wire boundary collapses * `denied` into `status: 'error'` with `error.code: 'denied'`. */ export type ToolOutcome = 'success' | 'error' | 'denied'; /** * SDK-side: discriminated-union convenience accepted by `client.tools.respond` * and returned by `client.tools.onRequest` handlers. * * The wire shape is the flat `ToolResponseItem` (`status` + optional `result` * / `error`). The SDK accepts this stricter form so callers can lean on * TypeScript narrowing — `outcome: 'success'` requires `result`, * `outcome: 'error'` requires `error`, `outcome: 'denied'` allows either. */ export type ToolResponseResult = { readonly outcome: 'success'; readonly result: JsonObject; } | { readonly outcome: 'error'; readonly error: string; } | { readonly outcome: 'denied'; readonly error?: string; }; /** * SDK-side per-call response object accepted by `client.tools.respond`. * * Pairs the `tool_call_id` (the dedup key) with the SDK-side `ToolResponseResult` * union. `node_name` lives on the `respond()` call's separate argument so a * parallel-batched reply doesn't redundantly carry the same string per item. */ export interface ToolResponseFor { readonly tool_call_id: ToolCallId; readonly result: ToolResponseResult; } /** `state.update` mutation kind. Narrowed from the QAR enum. */ export type StateUpdateOp = StateUpdatePayload['op']; /** `agent.spawn` spawn-protocol discriminator. Narrowed from the QAR enum. */ export type SpawnProtocol = AgentSpawnPayload['spawn_protocol']; //# sourceMappingURL=payloads.d.ts.map