import { InlineSkill, CustomTool, MemorySettings, TelemetrySettings, SystemPromptResolver, SessionStore, PermissionGate, SkillsSettings, ContextSettings } from '@theokit/sdk'; import { AgentDefinition as AgentDefinition$1 } from '@theokit/sdk/subagents-loader'; import { TheokitAgentError } from '@theokit/sdk/errors'; import { R as ReasoningEffort, H as HumanInTheLoopOptions, M as McpServersMap, a as MemoryOptions, P as ProjectContextOptions, C as CheckpointOptions, T as ToolOptions, A as ApprovalOptions, B as BudgetOptions } from './types-DdltPCj2.js'; import { z } from 'zod'; import { S as SettingSourcesSelection, G as GatedSettingSource, a as GatedCompatSource } from './setting-sources-gate-BJJiKq33.js'; import { H as HookHandlers } from './hook-handlers-Cw2FsnE5.js'; /** * M9 (theokit-ai-first) — guardrail contract + typed errors. * * ADR-0040 § D2: guardrails are a HOME/BOUNDARY concern (filter user input before the SDK, * filter model output before the client). They REUSE the SDK runtime — this module makes zero * LLM calls. A guard reports one of three actions; the pipeline (`pipeline.ts`) enforces them. */ /** What a guard decided for a piece of text. */ type GuardrailAction = 'allow' | 'block' | 'redact'; /** * The result of a single guard check. * - `allow` — text passes untouched. * - `block` — the pipeline throws {@link GuardrailViolationError}; the run stops fail-fast. * - `redact` — the pipeline replaces the text with {@link GuardrailResult.text} and continues. */ interface GuardrailResult { action: GuardrailAction; /** Human-readable reason — required in spirit for `block`, surfaced in the thrown error. */ reason?: string; /** The transformed text — present (and used) only when `action === 'redact'`. */ text?: string; } /** * A guardrail. A guard MAY inspect input (before the model), output (after the model), or both. * A guard that omits a phase hook is skipped for that phase. */ interface Guardrail { readonly name: string; checkInput?(text: string): GuardrailResult | Promise; checkOutput?(text: string): GuardrailResult | Promise; } /** Which boundary phase a violation happened in. */ type GuardrailPhase = 'input' | 'output'; /** * A guard declared `redact` and supplied no replacement text. * * Distinct from {@link GuardrailViolationError} on purpose: that one says the guard REFUSED * something, which is a decision working as designed. This says the guard is MALFORMED — it asked * for a redaction and gave nothing to redact with, so nothing was redacted. * * Until B-008 this condition was silent: `pipeline.ts` tested `r.text !== undefined` and moved on, so * the caller received the original text and believed a guard had run on it. That is the shape this * package's hook engine calls "worse than no hook at all" — a belief in a protection that is not * there. Throwing is fail-fast per `rules/error-handling.md § 2`, and the alternative was leaving * unredacted output to reach a model because a guard was written wrong. * * `''` is NOT this case. An empty replacement is a guard choosing to erase everything, which is the * strongest redaction available, and treating it as absent would invert the defect. */ /** * The base every guardrail error shares, so the seams that must treat them alike can do so BY * CONSTRUCTION rather than by remembering a list. * * The list is how B-020 happened. `run-reflective-loop.ts` let `GuardrailViolationError` pass * through unwrapped, and its sibling in this same file was not added — so a malformed result was * wrapped in a `DelegationError`, whose message interpolates its cause and whose code is on the * delegate tool's message allowlist. The guard's name crossed to the model, and a guard DEFECT was * reported as a delegation failure. * * A base is not airtight on its own: a new class can still extend `TheokitAgentError` directly. * `tests/unit/a-guardrail-defect-does-not-name-its-guard.test.ts` walks this module's barrel and * fails on any exported error class that skipped it. The two together are the construction; either * alone is a convention. * * Abstract because there is nothing to throw at this level — every guardrail failure is one of the * specific kinds below, and a bare `GuardrailError` would say only that something guard-shaped * happened. */ declare abstract class GuardrailError extends TheokitAgentError { } declare class MalformedGuardrailResultError extends GuardrailError { readonly guardName: string; readonly phase: GuardrailPhase; readonly name = "MalformedGuardrailResultError"; constructor(guardName: string, phase: GuardrailPhase); } /** * Thrown (fail-fast) when a guard returns `action: 'block'`. Typed per error-handling.md. * * M80 — extends {@link TheokitAgentError}, not plain `Error`. `isTransientError` is defined over * `TheokitAgentError`, so a class outside that hierarchy is INVISIBLE to it and the only recourse * left to a consumer is matching on message text — a regex over an eight-level `cause` chain, which * is what one actually wrote. `code` is stable across a rename of the class; `isRetryable` is * DECLARED rather than defaulted, because a default would be a retry policy nobody chose. */ declare class GuardrailViolationError extends GuardrailError { readonly guardName: string; readonly phase: GuardrailPhase; readonly reason: string; readonly name = "GuardrailViolationError"; constructor(guardName: string, phase: GuardrailPhase, reason: string); } /** * A text-carrying event arrived with a `content` that is not text. * * Distinct from the two above on purpose: they say a guard REFUSED something or was WRITTEN WRONG. * This says the STREAM is malformed — the event announces itself as text and carries something a * guard cannot read. * * Until B-021 this was silent. Both extractors tested `typeof e.content === 'string'` and returned * `undefined` otherwise, which `moderateOutputStream` reads as "this event carries no text" — so the * payload was never accumulated, never shown to a guard, and yielded VERBATIM. The failure direction * is DELIVER: a guard declared to stop that payload never saw it, and the run reported green. * * Refused rather than coerced. Coercing would moderate `"[object Object]"` — a guard consulted about * a string the model never produced, returning a verdict about nothing, while the real payload rides * along underneath. That is the redaction-computed-and-discarded shape with an extra step. */ declare class UnreadableTextPayloadError extends GuardrailError { readonly eventType: string; readonly received: unknown; readonly name = "UnreadableTextPayloadError"; constructor(eventType: string, received: unknown); } /** Thrown when {@link costGuard}'s cumulative token budget is exceeded. */ /** * M80 — extends {@link TheokitAgentError}, not plain `Error`. * * `isTransientError` is defined over `TheokitAgentError`, so a class outside that hierarchy is * INVISIBLE to it and the only recourse left to a consumer is matching on message text — a regex * over an eight-level `cause` chain, which is what one actually wrote. `code` is stable across a * rename of the class; `isRetryable` is DECLARED rather than defaulted, because a default would be a * retry policy nobody chose. */ declare class CostBudgetExceededError extends GuardrailError { readonly usedTokens: number; readonly maxTokens: number; readonly name = "CostBudgetExceededError"; constructor(usedTokens: number, maxTokens: number); } /** * M13 (theokit-ai-first) — per-request skills resolution (ADR-0040 § D2, home/boundary concern). * * The static `skills.enabled` filter already works (`compile-skills` maps `include` → the SDK's * `enabled`). This adds a PER-REQUEST resolver so multi-tenant apps expose different skill sets to * different users. A selection is either a static list or a function of the request context (the M7 * run-context). Discovery + injection stay in the SDK; this only CHOOSES the enabled set per call. */ /** The request context handed to a skills resolver (the M7 run-context — opaque per-request data). */ type SkillsRequestContext = Record; /** * How the skill set is chosen: * - a static array of `string` (filesystem skill NAMES → `skills.enabled`) and/or `InlineSkill` * objects from `createSkill` (code-defined skills → `skills.inline`, injected into the `` * block). A mixed list is split at compile time. * - a function — resolved per request from the {@link SkillsRequestContext} (sync or async). The * resolver returns filesystem skill NAMES (inline skills are static — declared on the agent). */ type SkillsSelection = readonly (string | InlineSkill)[] | ((ctx: SkillsRequestContext) => readonly string[] | Promise); /** * Resolve the enabled skill names for a request. Returns `undefined` when no selection is given (the * SDK then enables every discovered skill). Fails fast if a resolver returns a non-array. The static * array is compiled ahead of time (see `compileSkillsSelection`), so this is exercised for the * resolver form; a static array is defensively narrowed to its string (name) members. */ declare function resolveEnabledSkills(selection: SkillsSelection | undefined, ctx: SkillsRequestContext): Promise; /** * The shape this layer registers with the SDK's lifecycle-hook seam. * * Deliberately structural and minimal: the SDK owns the full `Plugin` contract, and restating it * here would be a second declaration to drift from. What this needs to know is the one thing that * tells a code plugin from a bundle reference. */ /** * A code plugin, in any of the three kinds `@theokit/sdk`'s `Plugin` union defines. * * `general` `register(ctx)` registers tools, commands, hooks * `model-provider` `profile` supplies a model provider * `memory` `createProvider` supplies a memory adapter * * The first version of this type required `register`, which accepted the first kind and refused the * other two — while the docblock on `AgentBuilder.plugins`, written in the same commit, already * described all three. A real consumer found it: on `@theokit/agents@13.0.0` a `model-provider` * plugin failed to compile with "Property 'register' is missing". A guard written to refuse the * FILESYSTEM-bundle form was refusing two thirds of the CODE form instead. * * Modelled here as name-plus-one-capability rather than by importing the SDK union, for the reason * the module header gives: this layer must not depend on the SDK's value side, and the published * floor is `^4.52.1` where the union's shape is not guaranteed identical. The capability keys ARE * the discriminator, so the refusal below stays exact. */ type CodePlugin = { readonly name: string; } & ({ readonly register: (...args: never[]) => unknown; } | { readonly profile: unknown; } | { readonly createProvider: (...args: never[]) => unknown; }); /** * Project the M8 fields from `CompiledAgentOptions` into `Agent.create()` arguments. Only the async * `@ProjectContext` resolver is built here (it does I/O, so the compiler keeps it raw). `applied` * lists which decorators contributed, for the observability log (wiring triad — runtime metric). */ /** * #686 — a consumer's decision point before the SDK spawns a hook, forwarded to * `Agent.create({ local: { hooks } })`. * * Declared here rather than imported: the SDK's `HookApprovalGate` landed in `5.4.0` and this * package's floor is `^4.52.1`, so importing the type would refuse to build on every version below * it. The shape is structural and small, which is the same reasoning `compatSources` already * records — "a string union is declarable here". * * The SDK calls the option `hooks`. On this layer's authoring surface it is `hookApproval`, because * `defineAgent({ hooks })` is already the LIFECYCLE seam and two different security-relevant things * under one name is how a consumer configures the wrong one. */ interface HookApprovalGate { readonly approve?: (request: HookApprovalRequest) => boolean | Promise; } /** What the consumer is shown when asked to approve a hook. Mirrors the SDK's shape (5.4.0). */ interface HookApprovalRequest { readonly command: string; readonly event: string; readonly sourcePath?: string; readonly matcher?: string; } /** * Refuses when the installed SDK cannot honour a declared hook gate. * * ## Why this THROWS where its `compatSources` sibling only warns * * That one guards a configuration source: ignored, the foreign root is not read, and the agent runs * with less than was asked for. This one guards a SECURITY decision. Ignored, the agent runs with * MORE than was asked for — every hook spawns unreviewed — while the consumer believes it is gated * and stops looking. The consumer that reported #686 asked for the refusal in those words: they * would rather have no gate than a silent one, because their `doctor` would otherwise publish a * guarantee that is false on `@theokit/sdk@5.0.0`. * * ## Why an unreadable version is a refusal and not a shrug * * The sibling stays silent when it cannot read the version, and that is right for a diagnostic. Here * "cannot tell" and "is gated" must not collapse: unproven is not proven, and this whole issue is * one instance of that confusion. A bundled SDK that hides `package.json` gets an explicit refusal * naming what it could not read, which is recoverable; a silent pass is not. */ declare class HookGateUnsupportedError extends TheokitAgentError { readonly name = "HookGateUnsupportedError"; constructor(version: string | undefined); } /** * A narrowed `import` on an SDK that cannot read it. * * Refuses rather than warns, and the asymmetry with {@link warnIfSdkCannotReadCompatSources} is * deliberate: an unrecognised `compatSources` shape means the foreign root is not read, so a * consumer who asked for "the skills but not the hooks" silently gets NOTHING — strictly further * from what they asked for than the un-narrowed form, which at least reads something. Failing loud * is recoverable; a silent nothing is discovered by wondering why a skill is missing. * * ## The cost, which this file argues against two functions above * * An unreadable version is refused too, on the principle {@link assertSdkCanGateHooks} states: * "cannot tell" and "is supported" must not collapse. The sibling WARNING takes the opposite view * for itself — *"a bundled or vendored SDK may not resolve that subpath, and refusing to create an * agent over a diagnostic would be the cure being worse than the disease."* * * Both are right for what they guard, and the difference is what the check IS. A diagnostic that * cannot read a version should stay quiet; a GATE that cannot read one has not established the * thing it exists to establish. But the cost is real and belongs here rather than in a reviewer's * report: a consumer who bundles the SDK so `@theokit/sdk/package.json` does not resolve cannot * create an agent with a narrowed `import`, even on 5.4.0+. Their exit is to omit `import` and read * the whole root. */ declare class CompatImportUnsupportedError extends TheokitAgentError { readonly name = "CompatImportUnsupportedError"; constructor(version: string | undefined); } /** * M2 (theokit-ai-first) — `defineAgent`, the zero-config imperative agent surface. * * ADR-B1: `defineAgent({...})` (default-exported from a top-level `agents/.ts`) is * the canonical zero-config surface; the `@Agent` class decorator stays the advanced/DI * surface. Both compile to {@link CompiledAgentOptions} and run through the same SDK * runtime (`createSdkAgentStream`) — one runtime, two syntaxes. * * This module is PURE metadata (sdk-runtime.md / G2): `defineAgent` describes an agent, it * NEVER calls an LLM. It imports only `zod` (types) + the compiler shape — no `theokit` * core, preserving the agents → (nothing) dependency direction (G1). */ /** * One subagent, as `AgentOptions.agents` in the SDK takes it. * * Declared here rather than imported so the framework states its own contract: the SDK's * `AgentDefinition` carries fields this bridge does not thread, and re-exporting it would promise * every one of them. */ interface SubagentAgentDefinition { /** What the model reads when choosing this subagent. */ readonly description: string; /** The instructions it runs with — the field that carries an applied memory. */ readonly prompt: string; /** Tool names it may call. Absent means the framework decides, as it does for a discovered one. */ readonly tools?: readonly string[]; } /** * Brand tag for a `defineAgent` value. `Symbol.for` (global registry, not `Symbol()`) so * the brand survives duplicate module instances (dual-package / bundling) — the scanner's * brand-check then works regardless of which copy created the definition. */ declare const AGENT_BRAND: unique symbol; /** Config accepted by {@link defineAgent}. */ interface DefineAgentConfig { /** Zod schema for the request body — lifted into the typed client (M2, {@link InferAgentInput}). */ input?: TInput; /** Model id (e.g. `claude-sonnet-4-6`). Falls back to the SDK default when omitted. */ model?: string; /** Static system prompt. */ system?: string; /** Extended-thinking effort. */ reasoningEffort?: ReasoningEffort; /** * theokit#363 — hard ceiling on the agent's tool-calling turns within ONE run. Reaching it ends * the turn instead of letting the model keep calling tools; absent ⇒ the SDK's own ceiling (8). * * Named `maxIterations`, not `maxSteps`, because the concept already has exactly one name here — * `@Agent({ maxIterations })`, `@MainLoop({ maxIterations })`, `AgentRunner.stream({ maxIterations })`, * `delegate({ maxIterations })` — and one name in the SDK it lowers to (`SendOptions.maxIterations`). * A second name would be the only place needing translation, and the translation is invisible where * it costs most: the SDK rejects an invalid value with a message naming `SendOptions.maxIterations`, * which an author who typed `.maxSteps()` has no way to connect to what they wrote. Familiarity * argues for the ai-sdk spelling, but ai-sdk's own name is `stopWhen: stepCountIs(n)` — borrowing * "steps" would buy recognition of a word, not of an API. */ maxIterations?: number; /** * Pre-built tools. Accepts the `@theokit/sdk` `CustomTool` that `defineAgentTool` * (theokit/server) and every `@theokit/sdk-tools` factory return (issue #81) — they are * normalized to the internal {@link CompiledTool} shape at compile time. */ tools?: readonly CustomTool[]; /** * M7 — run-context: an opaque, per-agent object forwarded to every tool handler's * `ctx.context` at run time (injected by the theokit adapter's tool wrapper). Set shared config * (e.g. `{ projectRoot }`) ONCE at the agent level instead of baking it into each tool * factory. Distinct from `@Agent`'s context-window `context`. */ context?: Record; /** * M9 — guardrails: input/output guards applied at the framework boundary (ADR-0040 § D2). * Input guards run on the user message before the SDK runtime; a `block` fails the run fast. * Built-ins live in `@theokit/agents` (`promptInjectionDetector`, `piiDetector`, `costGuard`, * `unicodeNormalizer`, `outputModeration`). */ guardrails?: readonly Guardrail[]; /** * M14 — HITL approvals keyed by tool name. Each gated tool pauses the run and emits an * `approval_required` event until approved (reuses the same `compiled.hitl` wiring the `@Agent` * + `@HumanInTheLoop` path produces). A key that does not match a declared tool fails fast at * compile time. */ approvals?: Record; /** * M13 — skills selection: a static list (compiled straight to the SDK `skills.enabled`) OR a * per-request resolver `(ctx) => string[]` (carried on `compiled.skillsResolver`, resolved by the * request path against the run-context). Absent ⇒ the SDK enables every discovered skill. */ skills?: SkillsSelection; /** * Subagents this agent carries, registered by name — `AgentOptions.agents` in the SDK. * * #825 — distinct from what `settingSources` discovers, and that distinction is the whole reason it * exists. The framework reads `.claude/agents/.md` itself and takes the prompt from the FILE, * so a caller that enriches a definition — `applySubagentMemory` folding in a `MEMORY.md` is the * measured case — had nowhere to put the result. It computed the enriched copy and the framework * used the file's, with nothing reporting a difference. * * A name declared here and also found on disk is the same subagent; the definition given here is * the one that runs, because it is the one an author decided rather than the one a loader guessed. */ subagents?: Record; /** * theokit-file-based-config — opt into `.theokit/` file-based config (skills, subagents, hooks, * MCP, context, cron). The SDK discovers config from these roots under the app's `cwd`: * `project` = `/.theokit/`, `user` = `~/.theokit/`. Absent ⇒ inline (code) config only. * * SECURITY (M68): `project` reads `.theokit/hooks.json`, which **executes shell**, so it requires * a `TrustPosture` rather than a string. This field used to take `readonly SettingSource[]`, and * its own JSDoc justified the risk as *"opt-in because `.theokit/` is the app's own repo (informed * consent)"*. That premise holds for a web app whose `cwd` is its own deploy; it does not hold for * an agent whose `cwd` is a repository the user just cloned, where `.theokit/` is * attacker-controlled content. * * `user` stays a plain boolean — `~/.theokit/` is the operator's own machine. Omitting a root is * not enabling it. The SDK owns discovery + execution (G2 / ADR-0040); theokit resolves the * selection through `resolveSettingSources` and wires the result into * `Agent.create({ local.settingSources })`. */ settingSources?: SettingSourcesSelection; /** * #686 — decide whether a hook declared in a config root is spawned at all, BEFORE it runs. * * Covers any root, including a foreign dialect imported through `settingSources.claudeCode`. * Requires `@theokit/sdk >= 5.4.0`: declaring it against an older SDK is REFUSED at assembly * rather than forwarded, because a gate that silently does not gate is worse than none. */ hookApproval?: HookApprovalGate; /** * B-054 — `MEMORY.md` here is NOT the Claude Code CLI's auto-memory file. This is the durable * subsystem below: a SQLite+FTS5 store under `.theokit/memory/`, with `memory_search`/`memory_get` * tools and no index cap. The CLI's lives under its own home (`CLAUDE_CONFIG_DIR` or `~/.claude`), * is capped at 200 lines / 25 KB on read, and is swept on `cleanupPeriodDays` — none of which is * implemented here. The SDK READS that directory for interop and does not write to it. * * Same filename, different directory, different semantics. Stated at both ends because a checklist * that greps for `MEMORY.md` finds one and concludes the other exists. * * M49 — durable memory (the SDK's `.theokit/memory/` subsystem: `Remember:` capture, MEMORY.md * store, auto-injected `` block, `memory_search`/`memory_get` tools). The shape is the * SDK's own `MemorySettings` — the canonical runtime contract. Projected into * `Agent.create({ memory })` by `assembleM8CreateOptions`. */ memory?: MemorySettings; /** * B-072 — OpenTelemetry for this agent. Forwarded verbatim to `Agent.create({ telemetry })`, * where the SDK emits spans for `agent.send`, `llm.call`, `tool.call` and `memory.search`. * * `{ enabled: true }` is the minimal opt-in. `@opentelemetry/api` is an OPTIONAL peer of the SDK: * without it the whole thing is a silent no-op, which is the usual reason a run reports no spans. */ telemetry?: TelemetrySettings; /** * Code `Plugin` objects forwarded to `Agent.create({ plugins })` — EXTENSION units (tools, * commands, model providers, memory adapters). For lifecycle interception use {@link hooks}. */ /** * Code plugins — `{ name, register }`. NOT the Claude Code filesystem-bundle form, which is * declared by living in a `plugins/` directory rather than by being passed here (B-055). * * `readonly unknown[]` is what let the wrong shape through silently. */ plugins?: readonly CodePlugin[]; /** * Lifecycle hooks keyed by `HookName` (`pre_tool_call` may veto via `{ block, message }`). Set by * the builder's `hooks()`; converted into a code plugin at `build()` and never reaching the SDK * under this name — the plugin is the TRANSPORT, this is the contract callers write against. */ hooks?: HookHandlers | Readonly>; /** * MCP servers available to the agent — the builder-chain equivalent of the `@MCP` class * decorator. Each key is a server name; the value is the server configuration. Forwarded * unchanged to `Agent.create({ mcpServers })` (the SDK owns MCP execution). Absent ⇒ no MCP. */ mcpServers?: McpServersMap; } /** * A branded agent definition — the value {@link defineAgent} returns. * * `TTools` (M8) is a phantom type parameter carrying the tool-name union: the `AgentBuilder.create()` builder * threads its accumulated literal tool names here (`.build()` returns `AgentDefinition`), so the generated client (`.theokit/agents.d.ts`) can expose them via * {@link InferAgentToolNames}. `defineAgent` leaves it `string` (its tools array carries no literal * names). Never present at runtime. */ type AgentDefinition = DefineAgentConfig & { readonly [AGENT_BRAND]: true; readonly __toolNames?: TTools; }; /** Infer the request type of an agent definition from its `input` Zod schema. */ type InferAgentInput = T extends AgentDefinition ? (S extends z.ZodType ? z.infer : never) : never; /** * Infer the tool-name union of an agent definition (M8). Yields the literal union for agents built * with the `AgentBuilder.create()` builder (`'read_file' | 'count_lines'`), or `string` for `defineAgent` agents * whose tools array carries no literal names. */ type InferAgentToolNames = T extends AgentDefinition ? N : never; /** Brand-check: is `value` a {@link defineAgent} result? */ declare function isAgentDefinition(value: unknown): value is AgentDefinition; /** * Lower a definition to the SDK-ready {@link CompiledAgentOptions} — the same shape * `compileAgent` (decorator path) produces, so both surfaces converge on one runtime. */ declare function compileAgentDefinition(def: AgentDefinition): CompiledAgentOptions; /** * Agent compiler — transforms decorator metadata into SDK calls. * * Per ADR D1: @Agent is a macro over Agent.create(). * Per ADR D3: @Tool compiles to defineTool(). * * EC-3: throws if toolbox instance is missing from the instances map. */ /** * M53 — the input shape `compileTools`/`compileHitlGates` consume, declared WITH them now that the * metadata walk that used to own it is gone. `ToolboxCapability` builds this from a class' * `static tools` declaration. */ /** A guard/interceptor class token — identity only (the DI container instantiates it). */ type ClassToken = abstract new (...args: never[]) => object; interface ToolWalkResult { propertyKey: string | symbol; config: ToolOptions; guards: ClassToken[]; approval?: ApprovalOptions; capabilities?: string[]; budget?: BudgetOptions; trace: boolean; audit: boolean; /** HITL config when the tool is gated (M4); absent ⇒ not gated. */ hitl?: HumanInTheLoopOptions; } interface ToolboxWalkResult { /** The toolbox class — used as the identity key into `toolboxInstances`. */ class: ClassToken; namespace: string; tools: ToolWalkResult[]; guards: ClassToken[]; } /** Minimal interface matching defineTool() result shape. */ interface CompiledTool { name: string; description: string; inputSchema: unknown; /** * M7 — the optional 2nd `ctx` arg carries the SDK run context: `ctx.context` is the * `defineAgent({ context })` / per-run value, `ctx.signal` the abort signal. Optional so the * decorator `@Tool` handlers (which ignore it) stay assignable. The SDK calls the tool with * both args; a handler that needs run-context (e.g. a filesystem tool reading `projectRoot`) * reads `ctx?.context`. */ handler: (input: unknown, ctx?: { signal?: AbortSignal; context?: unknown; }) => string | Promise; } /** * Compile @Tool metadata into tool definitions. * * @param toolboxes - Walked toolbox metadata * @param toolboxInstances - Map of Toolbox class → instantiated object (for `this` binding) */ declare function compileTools(toolboxes: ToolboxWalkResult[], toolboxInstances: Map): CompiledTool[]; /** * A compiled sub-agent IS the SDK's own `AgentDefinition`, re-exported here under the name the * public barrel already uses for it. * * It used to be a narrower local type, `CompiledSubAgent { model?, systemPrompt? }`, and ADR D3 * deferred projecting it: "a resolver here is carried, not invoked". **That deferral has ended** — * `assembleM8CreateOptions` now projects `agents` into `Agent.create`. * * The narrow type could not have been projected as it stood. `AgentDefinition` requires * `description` and `prompt`, and the local shape carried neither; a sub-agent with no description * is one the parent model has no basis to delegate to. Every other surface already agreed on the * SDK shape — `RuntimeOverrides.agents` (the per-run door that always worked) is * `Record`, and the same type crosses the barrel as `SubagentDefinition`. * The local type was referenced in exactly two places, both of them its own declaration and the * field that held it, so adopting the SDK shape removed a mismatch rather than migrating users. */ type CompiledSubAgent = AgentDefinition$1; /** Compiled agent options ready for SDK Agent.create(). */ interface CompiledAgentOptions { model?: string; /** Extended-thinking effort; mapped to SDK ModelSelection.params. */ reasoningEffort?: ReasoningEffort; /** Opt-in ``-tag extraction (M2); wraps the stream when true. */ parseThinkTags?: boolean; /** Opt-in tool-dialect stripping (theocode#32); strips leaked `` from text when true. */ stripToolDialect?: boolean; /** Opt-in leaked-dialect recovery (theokit#58); enables the SDK route's `extractToolCallsFromContent` so leaked tool calls EXECUTE when true. */ recoverLeakedToolCalls?: boolean; /** Static prompt OR a per-request {@link SystemPromptResolver} (V4-L.1, Axis-B). */ systemPrompt?: string | SystemPromptResolver; /** * theokit-file-based-config — opt-in `.theokit/` file-based config roots (`"project"`/`"user"`/…). * Projected into `Agent.create({ local: { settingSources } })` by `assembleM8CreateOptions` * (merged with `cwd`, decoupled from inline skills). Absent ⇒ inline (code) config only. */ settingSources?: readonly GatedSettingSource[]; /** * #825 — subagents the AUTHOR declared, carried through to `AgentOptions.agents`. * * Beside `settingSources` on purpose: that field says which roots the SDK may DISCOVER subagents * in, and this one says which subagents exist with which instructions. A caller that applied a * `MEMORY.md` to a definition has only this field to put the result in — through the other, the * SDK re-reads the file and the enriched copy is lost. */ subagents?: Readonly>; /** * Foreign configuration dialects, already authorised (usetheokit/theokit#634). * * Resolved at compile time by `resolveCompatSources`, exactly like `settingSources`: a value here * can only hold a source some posture granted, so the adapter projects rather than decides. */ compatSources?: readonly GatedCompatSource[]; /** * #686 — the consumer's pre-spawn approval gate, forwarded to `Agent.create({ local: { hooks } })`. * * Distinct from `hitl` (which gates TOOLS at run time) and from the lifecycle `plugins` below * (which react to events). This one decides whether a hook declared in a config root — including * a foreign dialect imported through `compatSources` — is spawned at all. */ hookApproval?: HookApprovalGate; /** Code `Plugin` objects forwarded to `Agent.create({ plugins })` (lifecycle-hook seam). */ /** * Code plugins — `{ name, register }` objects registered with the SDK's lifecycle-hook seam. * * `readonly unknown[]` is what let the WRONG shape through silently: a consumer who read the * Claude Code documentation passed `[{ type: 'local', path: './p' }]`, the compiler accepted it, * and the agent ran with the plugin absent. `assertCodePlugins` refuses it at the projection, and * the type says what belongs here. * * NOT the filesystem-bundle form. A bundle is declared by living in a `plugins/` directory under * `.theokit/` or `.claude/`, where its `skills/` and `agents/` are discovered. */ plugins?: readonly CodePlugin[]; /** * B-060 — an external session store (Postgres / Redis / KV / durable object), used by the SDK as * the PRIMARY session store and resume source. * * Without it a serverless deployment resumed from a filesystem that no longer exists, and a * multi-pod one resumed from whichever host happened to take the request. The only way to reach * it was importing `@theokit/sdk` directly — the one thing this layer's doctrine forbids, so the * doctrine and the capability disagreed and the consumer paid. * * Typed against the SDK's own `SessionStore` rather than restated here: a hand-written copy that * drifts by one method stops fitting, which the mirrored `permissionMode` field measured one item * earlier. */ sessionStore?: SessionStore; /** * B-056 — the callback that sees every tool call the earlier steps did not resolve. * * The SDK's engine is fail-closed: an unmatched call resolves to `ask`, and an ABSENT gate blocks * it. So the value of declaring one is not that unresolved calls stop being approved — they never * were — it is that they reach somebody who can decide instead of being refused with nobody to * consult. A tool added after the approvals were written keeps defaulting to asking. * * Typed against the SDK's `PermissionGate`, not restated: its decision shape is veto-or-allow, and * a hand-written copy would be the place an `updatedInput` field gets invented for a seam that * discards it. */ canUseTool?: PermissionGate; tools: CompiledTool[]; agents: Record; memory?: MemoryOptions | MemorySettings; skills?: SkillsSettings; context?: ContextSettings; /** * B-072 — OpenTelemetry settings, projected onto `Agent.create({ telemetry })`. * * Typed against the SDK's `TelemetrySettings` rather than restated, for the reason `canUseTool` * above gives about `PermissionGate`: a hand-written copy is where a field gets invented for a * seam that discards it, and this one has six keys with real defaults behind them. */ telemetry?: TelemetrySettings; /** * M7 — run-context injected into every tool handler's `ctx.context` by the theokit adapter * (`buildSdkTools` wrapper). Populated by `defineAgent({ context })` (functional surface). * NAME NOTE: distinct from the context-window `context` (`ContextSettings`) above — this is * per-run user data for tools, not token-budget config. */ runContext?: Record; /** Raw @ProjectContext config; the adapter builds the (async) systemPrompt resolver from it. */ projectContext?: ProjectContextOptions; mcpServers?: McpServersMap; maxIterations?: number; timeoutMs?: number; stream: boolean; /** * HITL gate map (M4): runtime tool name → `@HumanInTheLoop` config. Absent/empty ⇒ no gated * tools. The harness (`mountAgent`) turns this into the `pre_tool_call` pause wiring. */ hitl?: Map; /** * `@Checkpoint` config (M4): when present the harness emits `checkpoint_saved` and selects the * durable SDK conversation storage (`storage: 'filesystem'`) so a same-`sessionId` request resumes. */ checkpoint?: CheckpointOptions; /** * M9 — guardrails: input/output guards applied at the framework boundary (ADR-0040 § D2). * Input guards run on the user message BEFORE the SDK runtime sees it (fail-fast on `block`). * They REUSE the runtime; they never reimplement it. Absent/empty ⇒ no guards. */ guardrails?: readonly Guardrail[]; /** * M13 — per-request skills resolver (from `defineAgent({ skills: (ctx) => [...] })`). The request * path resolves it against the run-context (`resolveEnabledSkills`) and sets `skills.enabled` * before the SDK runs. Not consumed by the SDK directly (it reads `skills`). Absent ⇒ no resolver. */ skillsResolver?: SkillsSelection; } export { type AgentDefinition as A, type CompiledAgentOptions as C, type DefineAgentConfig as D, type Guardrail as G, type HookApprovalGate as H, type InferAgentInput as I, MalformedGuardrailResultError as M, type SkillsRequestContext as S, type ToolWalkResult as T, UnreadableTextPayloadError as U, type CompiledTool as a, AGENT_BRAND as b, CompatImportUnsupportedError as c, CostBudgetExceededError as d, type GuardrailAction as e, GuardrailError as f, type GuardrailPhase as g, type GuardrailResult as h, GuardrailViolationError as i, type HookApprovalRequest as j, HookGateUnsupportedError as k, type InferAgentToolNames as l, type SkillsSelection as m, type ToolboxWalkResult as n, compileAgentDefinition as o, compileTools as p, isAgentDefinition as q, resolveEnabledSkills as r, type SubagentAgentDefinition as s, type CodePlugin as t };