/** * Wire types for `task.start { agent: InlineAgentSpec }` (Pattern B) and * `task.start { graph: InlineGraphSpec }` (Pattern C) — also accepted by * `client.specs.validate(spec)` for pre-wire validation. * * **Naming.** The public symbol `AgentSpec` is owned by `QarRegistryClient` * as the *local-registry* agent shape (simple `name` + `instructions` + * tool strings). The `Inline*`-prefixed types here are the *wire* shape * — what flows on the network to QAR's `task.start` and * `POST /v1/specs/validate`. Two different layers, two different types, * kept orthogonal so consumers writing local agents and consumers * writing inline specs don't have to share a single struct trying to * span both. * * Field names match QAR's wire vocabulary verbatim — `apiVersion`, * `instructions` (not `system_prompt`), `tools: FunctionToolDef[]` * (not `{ name }`-refs), `kind: 'AgentSpec'` (the discriminator the * validator routes on; matches QAR's `SPEC_KIND_AGENT`). * * Rule-checking lives at QAR's `qar.specs.validator.validate_spec_payload` * — single source of truth shared between `POST /v1/specs/validate` and * `_handle_task_start`. Client-side, pre-wire * `assertInlineAgentSpecPreWire` (see `TaskClient`) rejects the obvious * forbidden-key cases at intake so the consumer's stack trace points at * their call site instead of a `task.done(failed)` arriving over the * wire. */ import type { JsonObject } from './json.js'; /** * MCP tool annotations — mirrors the upstream `Tool.annotations` shape from * the MCP specification (https://modelcontextprotocol.io/docs/concepts/tools, * checked 2026-05-21). Carried through the SDK's MCP projection layer so * consumers writing dynamic filters (Shape C) and downstream observability * (OTel span attrs) can read the upstream hints verbatim. * * **Annotations are explicitly UNTRUSTED per the MCP spec** — they're * advisory hints from a third-party MCP server, not policy authority. * QAR's trust-tier classification (whether a tool gates on HITL, whether * write operations need confirmation) stays name-based on the consumer * side. The QAR-side OTel span attribute pass-through carries them * through to span attributes for observability tooling. */ export interface McpToolAnnotations { /** Human-readable title — the upstream `Tool.annotations.title` field. */ readonly title?: string; /** True if the tool only reads state; advisory hint for security-aware filters. */ readonly readOnlyHint?: boolean; /** True if the tool may perform destructive operations; advisory. */ readonly destructiveHint?: boolean; /** True if repeated invocations are safe; advisory. */ readonly idempotentHint?: boolean; /** True if the tool interacts with an external/open world; advisory. */ readonly openWorldHint?: boolean; } /** OpenAI function-tool definition body. */ export interface FunctionDef { readonly name: string; readonly description?: string; /** JSON Schema for the call arguments. Free-form `JsonObject`. */ readonly parameters: JsonObject; /** OpenAI strict-mode flag for argument validation. Defaults to true server-side. */ readonly strict?: boolean; /** * Upstream MCP `Tool.annotations` passed through verbatim by the MCP * projection layer. Optional and advisory only — see {@link McpToolAnnotations}. * Consumer-shipped `FunctionToolDef` entries may set this directly for * non-MCP-backed tools that want to carry the same advisory hints. */ readonly annotations?: McpToolAnnotations; } /** Wrapping discriminator for the OpenAI function-tool shape. */ export interface FunctionToolDef { readonly type: 'function'; readonly function: FunctionDef; } /** * Read-only view of a single MCP-discovered tool, passed to a Shape C * filter callback. Carries the upstream MCP `Tool` shape verbatim: * * - `mcpName` — the registry name passed to `client.qar.registerMcp(name, ...)` * - `name` — the upstream tool name as returned by `tools/list` * (BEFORE the SDK's optional `.` prefix) * - `description` — upstream description (may be overridden by * `mcpToolOverrides` at projection time) * - `inputSchema` — JSON Schema for the call arguments, verbatim * - `outputSchema` — optional JSON Schema for the structured output, * verbatim (added in MCP 2025-06-18; absent on older servers) * - `annotations` — see {@link McpToolAnnotations} * * Used by Shape C filter callbacks; consumers can read `annotations` * (`readOnlyHint`, `destructiveHint`, etc.) to build security-aware tool * surfaces without hand-maintaining a per-tool classification table. */ export interface DiscoveredMcpTool { readonly mcpName: string; readonly name: string; readonly description?: string; readonly inputSchema: JsonObject; readonly outputSchema?: JsonObject; readonly annotations?: McpToolAnnotations; } /** * Shape B — static allowlist + blocklist. Entries are either bare MCP * names (matches every tool from that MCP) or `.` dotted * references (matches the specific tool). The effective surface is * `union(allowlist) - blocklist`. An entry referencing an unregistered * MCP, or a dotted name whose tool isn't in the live catalog, is governed * by {@link McpToolsSelectorAllowBlock.onMissing} — soft-dropped by * default, or a typed projection error at task.start under `'reject'`. */ export interface McpToolsSelectorAllowBlock { readonly allowlist?: readonly string[]; readonly blocklist?: readonly string[]; /** * Policy for selector / `mcpToolOverrides` entries that don't resolve * against the live MCP catalog at projection time — an unregistered MCP * name, or a `.` whose tool isn't in the catalog (a * feature-gated MCP that wasn't registered, or a sidecar that crashed * and is gone from the catalog on this task's projection). * * - `'drop'` (default) — soft-drop each unresolved entry (and any * `mcpToolOverrides` keyed on it) from the projected toolset; the * remaining registered tools ship normally and the task runs. Each * drop emits a structured `qodo.sdk.mcp.tool_dropped` event so the * misconfiguration stays observable (a deploy gate can assert zero * drops). One missing or transiently-down MCP no longer rejects the * whole spec — it degrades just that capability. * - `'reject'` — fail the dispatch at task.start with * `QodoUnknownMcpError` / `QodoUnknownMcpToolError`. Opt-in * strictness for consumers that want a typo'd tool name caught at * deploy time rather than silently dropped at runtime. * * Default `'drop'`. Only Shape B carries this field; Shape A * (`string[]`) and Shape C (filter) always use the default — express * them as `{ allowlist: [...], onMissing: 'reject' }` to opt into * strictness. */ readonly onMissing?: 'drop' | 'reject'; } /** * Shape C — dynamic filter callback. Receives every discovered tool * across every registered MCP (per the pool's cached catalog) and * returns `true` to include the tool in the projection. Useful for * security-aware filtering off `annotations.readOnlyHint`, alphabetical * subsetting, or any rule that needs richer logic than a string-list * match. * * The callback runs once per tool per `tasks.start*` call — keep it pure. */ export type McpToolsSelectorFilter = (tool: DiscoveredMcpTool) => boolean; /** * The `mcpTools` selector field. Discriminated union of three shapes: * * - **Shape A** — `readonly string[]`. Entries are either MCP names * (whole-server inclusion) or `.` dotted names (specific * tool). Matches the v1 SDK default ergonomic. * - **Shape B** — `McpToolsSelectorAllowBlock`. Allowlist + optional * blocklist, both using the same `` / `.` entry form. * - **Shape C** — `McpToolsSelectorFilter` callback for dynamic / * security-aware filtering. * * The shapes are mutually exclusive at the type level. Set `mcpTools` to * one of the three; mixing allowlist + dynamic filter requires composing * the callback yourself. */ export type McpToolsSelector = readonly string[] | McpToolsSelectorAllowBlock | McpToolsSelectorFilter; /** * Per-tool description overlay applied after projection. Keys are tool * names AS PROJECTED — including the `.` prefix when the MCP * is registered with `prefixToolNames: true` (default), or the bare tool * name when prefix is opted out. Values override the discovered MCP * `description` only; `inputSchema` / `outputSchema` / `annotations` * remain MCP-authoritative. * * Unknown override keys (no matching projected tool) are governed by the * selector's {@link McpToolsSelectorAllowBlock.onMissing} policy: dropped * with a `qodo.sdk.mcp.tool_dropped` event under the default `'drop'`, or * surfaced as a typed `QodoUnknownMcpToolError` at task.start under * `'reject'`. */ export interface McpToolOverride { readonly description?: string; } export type McpToolOverrides = { readonly [projectedToolName: string]: McpToolOverride; }; export interface InstructionsPreset { readonly preset: 'qodo-default'; readonly append?: string; } export type Instructions = string | InstructionsPreset; /** * Inner shape of `output_schema.json_schema` and `deps_schema`. `strict` * defaults to true server-side so the model's structured output gets * OpenAI strict-mode validation. */ export interface JsonSchemaSpec { readonly name: string; readonly schema: JsonObject; readonly strict?: boolean; } /** `output_schema` wrapper that carries the OpenAI strict-mode flag. */ export interface OutputSchemaSpec { readonly json_schema: JsonSchemaSpec; } /** * A composed-skill reference. `vendor` defaults to `'qodo'` (canonical * first-party namespace); `version` defaults to `'*'` (resolved at * task.start via the deployment's lockfile). */ export interface SkillRef { readonly vendor?: string; readonly name: string; readonly version?: string; readonly config?: JsonObject | null; } export interface SpawnableAgentRef { readonly name: string; readonly agent_id?: string | null; readonly spec?: InlineAgentSpec | null; } export interface InlineAgentSpec { readonly apiVersion: 'qar/v1'; /** * The Pydantic discriminator QAR's `validate_spec_payload` routes on * (`SPEC_KIND_AGENT = "AgentSpec"`). Optional in TypeScript so consumers * can write `{ apiVersion, instructions, model }` literally and the SDK's * pre-wire normalizer fills it in; the server-side validator requires * the field, so an envelope crossing the wire always has it. */ readonly kind?: 'AgentSpec'; readonly name?: string; readonly instructions: Instructions; readonly model: string; readonly tools?: readonly FunctionToolDef[] | null; readonly use_managed_tools?: boolean; readonly excluded_tools?: readonly string[]; readonly output_schema?: OutputSchemaSpec | null; readonly deps_schema?: JsonSchemaSpec | null; readonly skills?: readonly SkillRef[]; readonly spawnable_agents?: readonly SpawnableAgentRef[]; /** * Reserved by `D10-R1`. Rejected by the wire validator until the * sandbox-execution ADR designs the runtime. Typing as literal `null` * means the only value the TS compiler accepts is `null` itself, so a * consumer who tries to attach `custom_code: { ... }` fails at compile * time instead of getting a `task.done(failed)` round-trip. */ readonly custom_code?: null; /** * Content-trust policy. Threads through to QAR's * `AgentSpec.content_trust` and gates how untrusted content sources * (tool outputs, HITL reasons, bulletin posts, evaluator rationale * when this agent dispatches an evaluator) are wrapped before reaching * the model. Absent/null = QAR-side defaults apply. */ readonly content_trust?: ContentTrustPolicy | null; /** * Chat-mode primitive — mirror of QAR's * `AgentSpec.auto_pause_on_turn_end`. When `true`, the runtime * suspends the session on a synthetic `__auto_pause__` HITL after * every successful agent turn so the next user message can resume * the same session via `task.continue`. Default `false`. Field name * is snake_case to match the existing SDK convention (every other * AgentSpec field mirrors the Python wire spelling verbatim — see * `hitl_default`, `use_managed_tools`, `content_trust`). */ readonly auto_pause_on_turn_end?: boolean; /** * MCP tool auto-discovery selector. SDK-only field — the projection * layer resolves this against the live `McpClientPool` catalog at * `tasks.startWithAgent` / `tasks.startWithGraph` time and replaces it * with the concrete `tools[]` shipped to QAR. Never crosses the wire as * `mcpTools`; QAR sees the projected `tools[]` only. * * See {@link McpToolsSelector} for the three shapes (A whole-server, B * allowlist/blocklist, C dynamic filter). Consumer-shipped `tools[]` * entries continue to work and win on name collision with discovered * tools — explicit > implicit. * * A reference that doesn't resolve against the live catalog (an * unregistered MCP, or a tool absent from a registered MCP's catalog) is * soft-dropped by default — one missing MCP degrades that capability * rather than rejecting the whole spec. Opt into strict deploy-time * validation with Shape B's * {@link McpToolsSelectorAllowBlock.onMissing}` : 'reject'`. */ readonly mcpTools?: McpToolsSelector; /** * Per-tool description overlay. SDK-only sibling field to * `mcpTools` — applied AFTER projection so keys are tool names as * projected (prefix-on or prefix-off depending on per-MCP * `prefixToolNames`). Values override the discovered MCP `description` * only; `inputSchema` / `outputSchema` / `annotations` remain * MCP-authoritative. Stripped from the wire envelope alongside * `mcpTools`. See {@link McpToolOverrides}. */ readonly mcpToolOverrides?: McpToolOverrides; } /** * Closed enum for a graph node's role in a `GraphSpec`. * * Widening this set (e.g. adding `router`, `peer`, `swarm`) requires bumping * the wire `apiVersion` — the no-v0-planning rule binds the SDK to one role * set per major version. Required on `InlineGraphAgent` (matches QAR's * Pydantic shape, which has no default). */ export type InlineGraphRole = 'supervisor' | 'collaborator' | 'evaluator'; /** * Closed enum for a graph edge's dispatch kind. * * - `handoff` — control transfers: the producer hands off the task to the * target node and the supervisor resumes when the target completes. * - `ai_tool` — the target appears in the producer's tool catalog as a * callable LLM-tool; results return as a tool response. * - `evaluate` — the producer dispatches the target as an evaluator. The * target must have `role: 'evaluator'`; its response is bound to the * producer's `_verdicts[node]` state slot. * * Required on `InlineGraphEdge` (matches QAR's Pydantic shape; the field has * no default). */ export type InlineGraphEdgeKind = 'handoff' | 'ai_tool' | 'evaluate'; /** * Trust mode for a piece of model-facing content. `'trusted'` means the * content is passed verbatim to downstream prompts; `'untrusted'` means it * is wrapped/sanitized per QAR's content-shielding protocol so injected * instructions inside the content cannot exfiltrate authority. New values * may be added by QAR without an SDK bump — the field is typed as the * union below but the runtime validates against QAR's authoritative set. */ export type ContentTrustMode = 'trusted' | 'untrusted'; /** * Content-trust policy attached to an `AgentSpec` or * `GraphSpec`. Field names match QAR's `ContentTrustPolicy` Pydantic * model verbatim; the SDK does no normalization between this shape and * the wire shape so the typed object posted by a consumer to * `task.start { agent | graph, content_trust }` is what reaches QAR. * * **Policy fields** (every field is optional; absence = QAR-side default): * * - `evaluator_rationale_policy` — trust mode applied to rationale text * emitted by evaluator-role nodes. Controls whether the * rationale is rendered verbatim to the supervisor's prompt context * or wrapped as untrusted content. * - `hitl_reason_policy` — trust mode applied to HITL resolution * `reason` strings. Consumers escalating untrusted user * input (chat operator, end-user resolution) should set this to * `'untrusted'`. * - `tool_output_policy` — trust mode applied to tool response * payloads stitched back into the model's context window. Default * QAR-side is `'untrusted'` for tools fetching external data and * `'trusted'` for in-process SDK tools. * - `bulletin_post_policy` — trust mode applied to bulletin findings * when forwarded into a supervisor's prompt. * - `max_untrusted_bytes` — byte cap applied to any single piece of * untrusted content before truncation. Default QAR-side. Use to * guard against prompt-injection payloads that try to bury * instructions in long content. * - `max_trusted_bytes` — byte cap on trusted content too (defense in * depth against runaway evaluator rationales). Optional. */ export interface ContentTrustPolicy { readonly evaluator_rationale_policy?: ContentTrustMode | null; readonly hitl_reason_policy?: ContentTrustMode | null; readonly tool_output_policy?: ContentTrustMode | null; readonly bulletin_post_policy?: ContentTrustMode | null; readonly max_untrusted_bytes?: number | null; readonly max_trusted_bytes?: number | null; } /** * Agent / graph-node HITL mode. Mirrors QAR's `qar.protocol.hitl.HITLMode` * string-enum verbatim: * * - `'enabled'` — frame MAY auto-resolve in-process (subject to the * `Sensitivity.SECRET` bypass) or forward upward / to the consumer. * - `'passthrough'` — frame forwards every HITL envelope unchanged to its * ancestor; never auto-resolves. * - `'disabled'` — frame rejects any HITL surfaced at this boundary; * synthesized `hitl_resolved` closes the row. ADR-prescribed default — * headless automation is the dominant SDK use case. * * The wire spelling matches Python's `HITLMode` value strings exactly so the * dispatch-side parse doesn't translate. */ export type InlineHITLMode = 'enabled' | 'passthrough' | 'disabled'; /** * Server-static reference inside a graph node's `spec`. Matches QAR's * `qar.specs.models.GraphAgentStaticRef` — the only field is * `agent_id`, a non-empty string that resolves against the deployment's * static agent table. The discriminated-union arm for "this node is a * pre-registered static agent, not an inline spec". */ export interface InlineGraphAgentStaticRef { readonly agent_id: string; } /** * One node in the graph. Matches QAR's `qar.specs.models.GraphAgent`: * * - `spec` is the discriminated union the validator routes on — inline * `InlineAgentSpec` (kind `'AgentSpec'`), nested `InlineGraphSpec` * (kind `'GraphSpec'`, recursive subgraph), or * `InlineGraphAgentStaticRef` (`{ agent_id }`, server-side ref). * The wire validator narrows on `spec.kind` for the first two arms and * by the presence of `agent_id` for the static ref. * - `role` is required (no Pydantic default). * - `hitl` is optional and overrides the enclosing graph's * `hitl_default`. `null`/absent means "inherit from the graph default" * — a distinct semantic from "explicitly set to `'disabled'`". * * **The node name is the dict key in `InlineGraphSpec.agents`**, not a * field on this type — QAR's Pydantic model is `dict[str, GraphAgent]`. * Lifting the name out of the value lets dict key uniqueness enforce * agent-name uniqueness for free (D11-R3) and gives `entry: ` a * referential anchor. */ export interface InlineGraphAgent { readonly spec: InlineAgentSpec | InlineGraphSpec | InlineGraphAgentStaticRef; readonly role: InlineGraphRole; readonly hitl?: InlineHITLMode | null; /** * Chat-mode primitive — per-node override for the graph's * `auto_pause_on_turn_end_default`. `null` / absent means "inherit * the graph default" (matching the `hitl` field's * none-vs-disabled distinction). An explicit `false` opts the * node OUT of chat-mode the graph turned on. Wire-facing * auto-pause only applies to the entry supervisor's turn — see * the chat-mode doc for the per-role semantics. */ readonly auto_pause_on_turn_end?: boolean | null; } /** * Discriminated `on_error` policy for an edge. Mirrors QAR's * `EdgeOnErrorAbort | EdgeOnErrorRoute`: * * - `{ abort: true }` — terminate the graph with the error. * - `{ route_to: }` — route control to the named recovery node. * * Exactly one shape per object (Pydantic `extra='forbid'`). */ export type InlineEdgeOnError = { readonly abort: true; } | { readonly route_to: string; }; /** * A directed edge in the graph (spawn permission `from -> to`). Mirrors * QAR's `Edge`. `kind` is required (no Pydantic default); `on_error` is * optional and carries the same shape across all three edge kinds (no * per-kind subclassing — see `Edge.__doc__` in QAR). */ export interface InlineGraphEdge { readonly from: string; readonly to: string; readonly kind: InlineGraphEdgeKind; readonly on_error?: InlineEdgeOnError | null; } /** * Per-graph budget envelope. Mirrors QAR's `GraphBudget` — every field is * required and must be `> 0` server-side. The SDK exposes the same shape so * a consumer authoring a graph from TS picks the limits explicitly. */ export interface InlineGraphBudget { readonly total_input_tokens: number; readonly total_output_tokens: number; readonly total_wall_clock_s: number; } /** * Graph-wide limits. Mirrors QAR's `GraphLimits`. Pydantic side has defaults * for every numeric field; the SDK type makes `limits` required on * `InlineGraphSpec` so consumers think about the caps explicitly, but * each individual sub-field stays optional so a consumer who only wants * to override `max_steps` doesn't have to copy the other defaults * verbatim. * * `max_depth` is the nesting cap. Pydantic enforces `ge=1`; the * effective ceiling at dispatch time is `min(platform_cap, tenant_cap, * spec_declared)` — the wire validator emits `D13-R2` when this value * exceeds the deployment's effective cap. */ export interface InlineGraphLimits { readonly max_steps?: number; readonly max_depth?: number; readonly per_agent_iterations?: number; readonly budget?: InlineGraphBudget | null; } /** * Per-dispatch * budget envelope handed from an outer supervisor to a subgraph. Carried on * the subgraph-dispatch tool-call's `args` under the reserved key * `allocation`. Mirrors QAR's `SubgraphAllocation`. * * Every field is optional; omitted layers are auto-filled at dispatch time * with `min(inner.declared, outer.remaining)`. The cross-layer comparison * is rule `D13-R3` and runs server-side. */ export interface InlineSubgraphAllocation { readonly input_tokens?: number | null; readonly output_tokens?: number | null; readonly wall_clock_s?: number | null; readonly max_steps?: number | null; } /** * Closed union of termination conditions. Mirrors QAR's `TerminationCondition`: * * - `{ kind: 'agent_returns', agent: }` — graph terminates when the * named agent returns. * - `{ kind: 'max_steps_reached' }` — graph terminates when `limits.max_steps` * is reached. * - `{ kind: 'error_uncaught' }` — graph terminates on an unhandled error. * * `kind` discriminates the three shapes at parse time. QAR's wire validator * (`D11-R*`) checks the union exhaustively; the SDK's pre-wire validator * does the obvious well-formedness checks. */ export type InlineTerminationCondition = { readonly kind: 'agent_returns'; readonly agent: string; } | { readonly kind: 'max_steps_reached'; } | { readonly kind: 'error_uncaught'; }; /** * Inline-graph spec — multi-agent declarative topology. Mirrors QAR's * `qar.specs.models.GraphSpec` verbatim. * * Wire-required fields per QAR's Pydantic model: * - `apiVersion: 'qar/v1'` — discriminator the validator routes on. * - `kind: 'GraphSpec'` — matches `SPEC_KIND_GRAPH`. * - `agents: Record` — dict keyed by node name * (NOT an array; the dict key gives agent names referential integrity * against `entry: ` and edge `from`/`to` fields). * - `entry: string` — name of the entry node (must be a key of `agents`). * - `termination: InlineTerminationCondition[]` — non-empty list of * termination conditions. * * SDK-required (TS-side opinion): * - `limits: InlineGraphLimits` — wire-side this has a Pydantic * `default_factory=GraphLimits`, but the SDK forces consumers to be * explicit. Passing `{}` accepts every default. * * Optional fields (with Pydantic-side defaults): * - `name`, `output_schema`, `deps_schema`, `hitl_default`, * `parent_close_policy` (reserved-and-rejected — must be `null`; * wire validator emits `D13-R5` on any non-null). * - `edges: InlineGraphEdge[]` — defaults to `[]` on the QAR side. */ export interface InlineGraphSpec { readonly apiVersion: 'qar/v1'; readonly kind: 'GraphSpec'; readonly name?: string | null; readonly agents: Readonly>; readonly edges?: readonly InlineGraphEdge[]; readonly entry: string; readonly limits: InlineGraphLimits; readonly termination: readonly InlineTerminationCondition[]; readonly output_schema?: OutputSchemaSpec | null; readonly deps_schema?: JsonSchemaSpec | null; /** Graph-wide default HITL mode applied to nodes whose own `hitl` is unset. */ readonly hitl_default?: InlineHITLMode; /** * Chat-mode primitive — graph-wide default for * `InlineGraphAgent.auto_pause_on_turn_end`. A node whose own * field is `null`/absent inherits this value; an explicit * per-node `true`/`false` wins. Default `false` matches the * ADR-prescribed "headless is default" stance. Threads through to * QAR's `GraphSpec.auto_pause_on_turn_end_default`. */ readonly auto_pause_on_turn_end_default?: boolean; /** * Reserved-and-rejected — must be `null`. Typed as literal `null` so * the only value the TS compiler accepts is `null` itself; QAR's wire * validator emits `D13-R5` on any non-null. Mirrors AgentSpec's * `custom_code`. */ readonly parent_close_policy?: null; /** * Content-trust policy. Graph-wide defaults applied to inline agents * that don't declare their own `content_trust`. Threads through to * QAR's `GraphSpec.content_trust`. Absent/null = QAR-side defaults * apply. */ readonly content_trust?: ContentTrustPolicy | null; } /** * Per-agent verdict shape returned by evaluator-role nodes. Mirrors QAR * QAR's Pydantic `VerdictResult` (and the LLM-as-judge patterns in * RAGAS / OpenAI Evals): * * - `verdict` — closed three-arm enum. The supervisor's next turn branches * on this discriminator. * - `confidence` — optional scalar in `[0, 1]`. QAR's Pydantic model * enforces the range with `ge=0, le=1`; the SDK matches that for * pre-flight rejection (`D11-R12`). * - `rationale` — optional free-form explanation. Surfaced verbatim to * the supervisor's prompt context. * - `[k: string]: unknown` — RAGAS-style additional scores (e.g. * `faithfulness`, `answer_relevancy`). QAR's Pydantic model uses * `extra="allow"`; the SDK mirrors that with the open index signature. * * Bound at runtime to the producer's `_verdicts[node]` state slot — see * QAR's `dispatch_evaluator` runtime. */ export interface VerdictResult { readonly verdict: 'pass' | 'fail' | 'needs_revision'; readonly confidence?: number; readonly rationale?: string; readonly [k: string]: unknown; } /** Discriminated union accepted by `client.specs.validate`. */ export type InlineSpec = InlineAgentSpec | InlineGraphSpec; /** * Discriminator literal — the value of `kind` on each branch. * Matches QAR's `SPEC_KIND_AGENT` / `SPEC_KIND_GRAPH` exactly. */ export type InlineSpecKind = 'AgentSpec' | 'GraphSpec'; /** * Per-rule validation failure. Mirrors QAR's response shape. `rule_id` is * one of the `D10-R*` set, the `D11-R*` set, or a small set of * surface-rejection ids (`D10-UNSUPPORTED`, `D10-UNSUPPORTED-SPAWN`); `path` * is a JSON Pointer (RFC 6901) into the spec, with `""` denoting the root. */ export interface SpecValidationError { readonly rule_id: string; readonly path: string; readonly message: string; } /** * Result envelope returned by `client.specs.validate`. Discriminated on * `valid` so consumers can branch directly on `result.valid` (no extra * type guard needed) — the `errors` array only exists on the `false` arm. */ export type SpecValidateResult = { readonly valid: true; } | { readonly valid: false; readonly errors: readonly SpecValidationError[]; }; //# sourceMappingURL=specs.d.ts.map