/** * Dynamic subagent spawner + task-tool factory. * * Mirrors `python/src/adk_fluent/_subagents/`. The parent LLM keeps * control of the conversation and, when it needs focused work done, * calls a `task(role, prompt)` tool that dispatches a fresh specialist, * waits for the answer, and folds the result back into the parent's * context window. * * A subagent is **not** a long-running teammate — it is a short-lived * worker with its own instruction, its own toolset, and a disposable * context. The parent never sees the specialist's scratchpad, only its * final output. * * This module is intentionally **not** coupled to `@google/adk` — the * runtime contract is a plain `run(spec, prompt, context?) => * SubagentResult` callable. That keeps it unit-testable in isolation * and lets callers plug in a local runner, an A2A endpoint, or canned * responses in tests. */ /** * Declarative description of one dynamically-spawned specialist. * * Specs are immutable value objects so they can be shared across * registries and cached without defensive copies. Construct via the * options-object constructor or via `H.subagentSpec(...)`. */ export interface SubagentSpecOptions { /** Short, stable identifier (`"researcher"`, `"reviewer"`). */ role: string; /** System prompt / role description handed to the specialist. */ instruction: string; /** One-line human description surfaced in the task tool docstring. */ description?: string; /** Optional model override; `undefined` inherits the runner's default. */ model?: string; /** Tool names the specialist may call. The runner resolves names. */ toolNames?: readonly string[]; /** One of the `PermissionMode` constants; defaults to `"default"`. */ permissionMode?: string; /** Optional per-invocation token ceiling. */ maxTokens?: number; /** Free-form runner-specific metadata. */ metadata?: Record; } export declare class SubagentSpec { readonly role: string; readonly instruction: string; readonly description: string; readonly model: string | undefined; readonly toolNames: readonly string[]; readonly permissionMode: string; readonly maxTokens: number | undefined; readonly metadata: Readonly>; constructor(options: SubagentSpecOptions); } /** * Structured output from a subagent run. * * Results are immutable. Errors populate the `error` field and set * `isError = true`; callers use `toToolOutput()` to render the canonical * `[role] output` or `[role:error] reason` string returned from the * task tool. */ export interface SubagentResultOptions { role: string; output: string; usage?: Record; artifacts?: Record; metadata?: Record; error?: string; } export declare class SubagentResult { readonly role: string; readonly output: string; readonly usage: Readonly>; readonly artifacts: Readonly>; readonly metadata: Readonly>; readonly error: string; constructor(options: SubagentResultOptions); get isError(): boolean; /** * Render the canonical tool-output string. Errors surface as * `[role:error] reason`; successful runs prefix the role name so the * parent LLM can reason about provenance. */ toToolOutput(): string; } /** * Ordered catalogue of specs keyed by role. Not thread-safe — registries * are populated at construction time, before any invocation runs. */ export declare class SubagentRegistry { private readonly specs; constructor(specs?: Iterable); /** Register a new spec. Throws if the role is already registered. */ register(spec: SubagentSpec): void; /** Register `spec`, overwriting any existing entry with the same role. */ replace(spec: SubagentSpec): void; /** Remove the spec for `role`. Silent no-op if absent. */ unregister(role: string): void; /** Return the spec for `role` or `undefined` if not registered. */ get(role: string): SubagentSpec | undefined; /** Return the spec for `role` or throw if not registered. */ require(role: string): SubagentSpec; /** Registered role names in insertion order. */ roles(): string[]; get size(): number; has(role: string): boolean; [Symbol.iterator](): IterableIterator; /** * Render a human-readable roster of all registered specialists, used * by `makeTaskTool` to build the task-tool docstring so the parent * LLM can pick a role. */ roster(): string; } /** * Runtime contract: synchronous subagent execution. * * Runners receive a spec, a per-call prompt, and an optional context * dict (the state the parent exposes). They must return a fully * populated `SubagentResult`. Runners that need async execution should * wrap the event loop internally; the task tool never awaits. */ export interface SubagentRunner { run(spec: SubagentSpec, prompt: string, context?: Record): SubagentResult; } export declare class SubagentRunnerError extends Error { constructor(message: string); } type Responder = (spec: SubagentSpec, prompt: string, context?: Record) => string; export interface FakeSubagentRunnerOptions { /** Invoked per run; defaults to echoing the prompt. */ responder?: Responder; /** Fixed usage dict attached to every result. */ usage?: Record; /** Role → error string for simulating per-role failures. */ errorForRole?: Record; } /** Recorded call entry captured by `FakeSubagentRunner`. */ export interface SubagentCall { spec: SubagentSpec; prompt: string; context: Record | undefined; } /** * Deterministic runner used by tests and local sandboxes. * * By default echoes the prompt. Supply `responder` for custom output, * `errorForRole` to simulate failures per role, and `usage` to attach * a fixed usage dict to every result. Every invocation is recorded in * the `.calls` audit log. */ export declare class FakeSubagentRunner implements SubagentRunner { private readonly responder; private readonly fixedUsage; private readonly errors; private readonly log; constructor(options?: FakeSubagentRunnerOptions); /** Return the call log in invocation order. */ get calls(): readonly SubagentCall[]; run(spec: SubagentSpec, prompt: string, context?: Record): SubagentResult; } /** * Task-tool callable with a human-readable docstring enumerating the * available subagent roles. The parent LLM calls this with a role name * and a prompt; the tool dispatches to the runner and returns the * canonical `[role] output` string. */ export interface TaskTool { (role: string, prompt: string): string; /** Name the tool function is exposed under. */ toolName: string; /** Full docstring enumerating the registered roles. */ description: string; } export interface MakeTaskToolOptions { /** * Optional callable returning the context dict to pass into the * runner on every invocation. Use this to thread the parent agent's * state into subagents. */ contextProvider?: () => Record; /** Identifier the tool function is exposed under. Defaults to `"task"`. */ toolName?: string; } /** * Build a `task(role, prompt) => string` callable backed by the * registry and runner. The returned function's `description` property * enumerates every registered role with its description so the parent * LLM sees an accurate menu. */ export declare function makeTaskTool(registry: SubagentRegistry, runner: SubagentRunner, options?: MakeTaskToolOptions): TaskTool; export {}; //# sourceMappingURL=subagents.d.ts.map