zidane 5.7.7 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +5 -1
  2. package/dist/{agent-BSPhByzT.d.ts → agent-DYghZGC8.d.ts} +135 -2
  3. package/dist/agent-DYghZGC8.d.ts.map +1 -0
  4. package/dist/chat/pure.d.ts +3 -3
  5. package/dist/chat.d.ts +6 -6
  6. package/dist/chat.js +2 -2
  7. package/dist/headless-DnjYDckH.js +502 -0
  8. package/dist/headless-DnjYDckH.js.map +1 -0
  9. package/dist/headless.d.ts +2 -0
  10. package/dist/headless.js +2 -0
  11. package/dist/{index-B6h9C_JE.d.ts → index-B2cMuK6S.d.ts} +1285 -1124
  12. package/dist/index-B2cMuK6S.d.ts.map +1 -0
  13. package/dist/{index-DmbrQjOk.d.ts → index-CVzpMtdq.d.ts} +2 -2
  14. package/dist/{index-DmbrQjOk.d.ts.map → index-CVzpMtdq.d.ts.map} +1 -1
  15. package/dist/index.d.ts +4 -4
  16. package/dist/index.js +6 -241
  17. package/dist/index.js.map +1 -1
  18. package/dist/{login-C8Kc4gH0.js → login-D-3A5CK7.js} +2 -2
  19. package/dist/{login-C8Kc4gH0.js.map → login-D-3A5CK7.js.map} +1 -1
  20. package/dist/mcp.d.ts +1 -1
  21. package/dist/{presets-DTxFbEZ5.js → presets-B1gWui0v.js} +2 -2
  22. package/dist/{presets-DTxFbEZ5.js.map → presets-B1gWui0v.js.map} +1 -1
  23. package/dist/presets.d.ts +2 -2
  24. package/dist/presets.js +1 -1
  25. package/dist/providers.d.ts +1 -1
  26. package/dist/restate.d.ts +1 -1
  27. package/dist/session/sqlite.d.ts +1 -1
  28. package/dist/session.d.ts +1 -1
  29. package/dist/skills.d.ts +2 -2
  30. package/dist/{tool-formatters-fUAp2Nr4.d.ts → tool-formatters-0FEGRd6w.d.ts} +2 -2
  31. package/dist/{tool-formatters-fUAp2Nr4.d.ts.map → tool-formatters-0FEGRd6w.d.ts.map} +1 -1
  32. package/dist/tools/fetch-url.d.ts +1 -1
  33. package/dist/tools/web-search.d.ts +1 -1
  34. package/dist/{tools-dkB_jARJ.js → tools-BmPeBGU1.js} +196 -5
  35. package/dist/tools-BmPeBGU1.js.map +1 -0
  36. package/dist/tools.d.ts +2 -2
  37. package/dist/tools.js +1 -1
  38. package/dist/{transcript-anchors-Cl7lbbeP.js → transcript-anchors-Bp5bV0Bv.js} +31 -4
  39. package/dist/transcript-anchors-Bp5bV0Bv.js.map +1 -0
  40. package/dist/{transcript-anchors-qxevvEwT.d.ts → transcript-anchors-D2erm5iS.d.ts} +4 -4
  41. package/dist/transcript-anchors-D2erm5iS.d.ts.map +1 -0
  42. package/dist/tui.d.ts +3 -3
  43. package/dist/tui.js +5 -5
  44. package/dist/tui.js.map +1 -1
  45. package/dist/{turn-operations-CE1prnuP.d.ts → turn-operations-CeUrtsaM.d.ts} +3 -3
  46. package/dist/{turn-operations-CE1prnuP.d.ts.map → turn-operations-CeUrtsaM.d.ts.map} +1 -1
  47. package/dist/types-BPw_i5vb.js.map +1 -1
  48. package/dist/types.d.ts +3 -3
  49. package/docs/ARCHITECTURE.md +2 -1
  50. package/docs/CHAT.md +19 -1
  51. package/docs/HEADLESS.md +138 -0
  52. package/docs/SKILL.md +1 -0
  53. package/package.json +8 -2
  54. package/dist/agent-BSPhByzT.d.ts.map +0 -1
  55. package/dist/index-B6h9C_JE.d.ts.map +0 -1
  56. package/dist/tools-dkB_jARJ.js.map +0 -1
  57. package/dist/transcript-anchors-Cl7lbbeP.js.map +0 -1
  58. package/dist/transcript-anchors-qxevvEwT.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { D as SkillConfig, Gt as AgentStats, Kt as ChildRunStats, N as Session, Zt as McpServerConfig, bn as TurnUsage, dn as SessionTurn, ft as StreamOptions, gn as ToolResultContent, i as AgentOptions, l as SkillActivationState, lt as Provider, mn as ThinkingLevel, r as AgentHooks, s as ActiveSkill, v as ToolContext, y as ToolDef } from "./agent-BSPhByzT.js";
1
+ import { D as SkillConfig, Gt as AgentStats, I as SessionStore, Kt as ChildRunStats, N as Session, Sn as TurnUsage, Zt as McpServerConfig, ft as StreamOptions, gn as ThinkingLevel, i as AgentOptions, l as SkillActivationState, lt as Provider, pn as SessionTurn, r as AgentHooks, rn as PromptPart, s as ActiveSkill, v as ToolContext, vn as ToolResultContent, xn as TurnFinishReason, y as ToolDef } from "./agent-DYghZGC8.js";
2
2
  import { a as ExecutionContext, o as ExecutionHandle } from "./types-CEAMIUXw.js";
3
3
  import { Hookable } from "hookable";
4
4
  import { OAuthClientProvider, OAuthDiscoveryState } from "@modelcontextprotocol/sdk/client/auth.js";
@@ -618,1348 +618,1509 @@ declare const BYTES_PER_TOKEN = 4;
618
618
  */
619
619
  declare function estimateTokens(text: string): number;
620
620
  //#endregion
621
- //#region src/logger.d.ts
622
- type LogLevel = 'debug' | 'info' | 'warn' | 'error';
623
- interface LogRecord {
624
- level: LogLevel;
625
- /** Unix ms — set by `Logger` at emit time. */
626
- timestamp: number;
627
- /** Free-form message. Sinks render this as the human-facing line. */
621
+ //#region src/run-summary.d.ts
622
+ interface RunSummaryTokens {
623
+ input: number;
624
+ output: number;
625
+ cacheRead: number;
626
+ cacheCreation: number;
627
+ cost?: number;
628
+ /** First observable byte from the provider, ms from run start. */
629
+ ttftMs?: number;
630
+ }
631
+ interface RunSummaryByModel {
632
+ modelId: string;
633
+ input: number;
634
+ output: number;
635
+ cacheRead: number;
636
+ cacheCreation: number;
637
+ cost: number;
638
+ turns: number;
639
+ }
640
+ interface RunSummaryError {
641
+ kind: 'stream' | 'tool' | 'mcp-tool' | 'mcp' | 'spawn';
628
642
  message: string;
629
- /** Structured fields. Correlation ids land here automatically. */
630
- attrs: Record<string, unknown>;
643
+ errorType?: string;
644
+ turnId?: string;
645
+ callId?: string;
646
+ server?: string;
647
+ toolName?: string;
648
+ childId?: string;
649
+ statusCode?: number;
650
+ requestId?: string;
631
651
  }
632
- interface LogSink {
633
- emit: (record: LogRecord) => void;
652
+ interface RunSummaryBlock {
653
+ callId: string;
654
+ toolName: string;
655
+ outcome: 'gate-block' | 'unknown' | 'invalid-input';
656
+ reason?: string;
634
657
  }
635
- interface Logger {
636
- debug: (message: string, attrs?: Record<string, unknown>) => void;
637
- info: (message: string, attrs?: Record<string, unknown>) => void;
638
- warn: (message: string, attrs?: Record<string, unknown>) => void;
639
- error: (message: string, attrs?: Record<string, unknown>) => void;
640
- /**
641
- * Returns a child logger that prepends the given attributes onto every
642
- * subsequent emit. Equivalent to `pino.child` / `winston.child`. The
643
- * parent and child share the same sink — children are zero-cost.
644
- */
645
- with: (extra: Record<string, unknown>) => Logger;
646
- /**
647
- * Inspectable baseline attributes — handy for tests and for hook
648
- * handlers that want to clone-with-extra without recursing.
649
- */
650
- readonly baseAttributes: Readonly<Record<string, unknown>>;
658
+ interface RunSummaryValidation {
659
+ callId: string;
660
+ toolName: string;
661
+ reason: string;
662
+ }
663
+ interface RunSummaryBudget {
664
+ kind: 'bytes' | 'tool-count';
665
+ /** Tool name (for `'tool-count'`); absent for byte budgets. */
666
+ toolName?: string;
667
+ /** `mode` for `'tool-count'`; absent for byte budgets. */
668
+ mode?: 'steer' | 'block';
669
+ observed: number;
670
+ limit: number;
671
+ turnId?: string;
672
+ }
673
+ interface RunSummaryRepeatGuard {
674
+ toolName: string;
675
+ /** Consecutive identical calls including the one that tripped the guard. */
676
+ count: number;
677
+ threshold: number;
678
+ action: 'block' | 'abort';
679
+ turnId?: string;
651
680
  }
652
681
  /**
653
- * Build a Logger from a sink. Stateless and cheap; create one per agent
654
- * (or per app) and use `.with()` to attach correlation ids per-call.
682
+ * Postmortem snapshot of one `agent.run()`. Strictly serializable every
683
+ * field round-trips through `JSON.stringify` / `JSON.parse` without loss
684
+ * so a log aggregator can ingest it as-is.
655
685
  */
656
- declare function createLogger(sink: LogSink, baseAttributes?: Readonly<Record<string, unknown>>): Logger;
657
- interface ConsoleSinkOptions {
686
+ interface RunSummary {
687
+ runId?: string;
688
+ parentRunId?: string;
689
+ depth: number;
690
+ agentName?: string;
691
+ startedAt: number;
692
+ endedAt: number;
693
+ durationMs: number;
694
+ status: 'completed' | 'aborted';
695
+ turns: number;
696
+ totals: RunSummaryTokens;
697
+ byModel: RunSummaryByModel[];
698
+ errors: RunSummaryError[];
699
+ blocks: RunSummaryBlock[];
700
+ validationRejects: RunSummaryValidation[];
701
+ budgetEvents: RunSummaryBudget[];
658
702
  /**
659
- * Minimum level to emit. Defaults to `'info'` — `debug` is dropped so
660
- * the harness's lifecycle logging is not noisy by default. Set to
661
- * `'debug'` to see every event.
703
+ * Consecutive-identical repeat-guard escalations. An `action: 'abort'`
704
+ * entry means the guard terminated the run via the agent's
705
+ * `AbortController` (the run finalizes as `'aborted'`).
662
706
  */
663
- minLevel?: LogLevel;
664
- /** Custom output stream. Defaults to `process.stderr` so logs don't pollute stdout. */
665
- stream?: {
666
- write: (chunk: string) => void;
667
- };
668
- }
669
- /**
670
- * Human-readable terminal sink. Renders each record as
671
- * `<ISO timestamp> <LEVEL> <message> <attrs as kv pairs>`.
672
- *
673
- * Honors `process.stderr` by default so log lines don't interleave with
674
- * the agent's stdout-bound output (chat responses, JSON results).
675
- */
676
- declare function consoleSink(options?: ConsoleSinkOptions): LogSink;
677
- /**
678
- * One-JSON-object-per-line sink. Suitable for piping into log aggregators
679
- * (Datadog Agent, Fluent Bit, Loki, Vector) that expect JSONL.
680
- */
681
- declare function jsonSink(options?: ConsoleSinkOptions): LogSink;
682
- interface LoggingHooksOptions {
683
- logger: Logger;
707
+ repeatGuardEvents: RunSummaryRepeatGuard[];
708
+ /** Counts of pairing repairs, keyed by repair mode. */
709
+ pairingRepairs: Record<string, number>;
684
710
  /**
685
- * Minimum interesting level for harness-emitted lines. Default `'info'`.
686
- * Set to `'debug'` to see every tool dispatch / stream event. Set to
687
- * `'warn'` to mute the chatty ones and only see failures + budgets.
711
+ * Postmortem snapshots of child runs that bubbled their stats up via
712
+ * `spawn:complete`. Only present when the run actually spawned.
688
713
  */
689
- level?: LogLevel;
714
+ children?: RunSummary[];
715
+ }
716
+ interface RunSummaryCollectorOptions {
690
717
  /**
691
- * When true (default), lifecycle events (`agent:start`, `turn:before`,
692
- * `tool:before`, `mcp:bootstrap:start`) emit at `debug` level so they
693
- * stay quiet by default. Set false to mute them entirely regardless of
694
- * the configured minimum level — useful when piping into a tracer
695
- * that already captures lifecycle.
718
+ * Called with the assembled {@link RunSummary} on every `agent:done`.
719
+ * Synchronous heavy I/O should be deferred (e.g. via `setImmediate`).
696
720
  */
697
- includeLifecycle?: boolean;
721
+ onSummary?: (summary: RunSummary) => void;
698
722
  }
699
- interface LoggingHookSet {
723
+ interface RunSummaryCollector {
724
+ /** Install the collector's hook handlers. Returns an uninstall fn. */
700
725
  install: (hooks: Hookable<AgentHooks>) => () => void;
726
+ /** Most-recent summary; `undefined` until the first `agent:done` fires. */
727
+ latest: () => RunSummary | undefined;
701
728
  }
702
729
  /**
703
- * Install a bundle of hook handlers that emit a structured line per
704
- * relevant lifecycle event, automatically attaching correlation ids
705
- * (`runId`, `turnId`, `callId`, `childId`, `depth`, `agentName`).
730
+ * Build a run-summary collector. State is created fresh inside each
731
+ * `install()` call, so a single collector instance can be installed
732
+ * across multiple agents without attribution cross-talk. `latest()`
733
+ * returns the most-recent summary across **any** install — install
734
+ * per-agent collectors if you need separate post-run snapshots.
706
735
  *
707
736
  * @example
708
737
  * ```ts
709
- * const logger = createLogger(consoleSink({ minLevel: 'debug' }), { service: 'tui' })
710
- * const lh = createLoggingHooks({ logger })
711
- * const uninstall = lh.install(agent.hooks)
738
+ * const collector = createRunSummaryCollector({
739
+ * onSummary: s => console.log(JSON.stringify(s)),
740
+ * })
741
+ * const uninstall = collector.install(agent.hooks)
712
742
  * try { await agent.run({ prompt }) }
713
743
  * finally { uninstall() }
714
744
  * ```
715
745
  */
716
- declare function createLoggingHooks(options: LoggingHooksOptions): LoggingHookSet;
746
+ declare function createRunSummaryCollector(options?: RunSummaryCollectorOptions): RunSummaryCollector;
717
747
  //#endregion
718
- //#region src/loop.d.ts
719
- /**
720
- * Canonical tool_result text emitted when a tool call is interrupted by the
721
- * user mid-flight (Esc / Ctrl-C / external `AbortSignal`). Mirrors Claude
722
- * Code's `INTERRUPT_MESSAGE_FOR_TOOL_USE` so downstream consumers can pattern
723
- * match a single string across both harnesses. Always paired with
724
- * `isError: true` on the wire — the model treats it as a failed call rather
725
- * than a successful tool response.
726
- */
727
- declare const INTERRUPT_MESSAGE_FOR_TOOL_USE = "[Request interrupted by user for tool use]";
728
- /**
729
- * Canonical tool_result text emitted when a tool call is skipped because a
730
- * steering message arrived between dispatches inside
731
- * {@link executeToolBatch}. Distinguished from
732
- * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} so consumers can split "user
733
- * cancelled" from "framework superseded".
734
- */
735
- declare const TOOL_USE_SKIPPED_MESSAGE = "[Tool use skipped \u2014 superseded by user message]";
748
+ //#region src/tools/edit.d.ts
736
749
  /**
737
- * Canonical tool_result text emitted when a single tool call is cancelled
738
- * mid-flight via `agent.cancelTool(callId)` (typically the TUI's
739
- * "cancel this tool" affordance). Distinguished from
740
- * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} (run-wide user abort) and
741
- * {@link TOOL_USE_SKIPPED_MESSAGE} (steered) so the model — and downstream
742
- * consumers — can tell the three apart by string match.
750
+ * Surgical edit replace `old_string` with `new_string` in a single file.
743
751
  *
744
- * Always paired with `isError: true` on the wire so the model treats the
745
- * call as failed rather than as a successful response. The remaining tool
746
- * calls in the batch continue running, in contrast with a full-run abort.
747
- */
748
- declare const TOOL_USE_CANCELLED_MESSAGE = "[Tool call cancelled by user]";
749
- /**
750
- * Canonical `tool_result.content` text emitted to siblings that were
751
- * cancelled by a `shell` error in the same batch. Distinct from
752
- * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} (user-issued abort) and
753
- * {@link TOOL_USE_SKIPPED_MESSAGE} (steered) so consumers can split
754
- * the three causes by string-match.
752
+ * Mirrors Claude Code's `Edit` semantics so models post-trained on Anthropic's
753
+ * tool surface need no relearning. Fails clearly when `old_string` isn't unique
754
+ * (unless `replace_all: true`) and when not found, with a nearest-match preview
755
+ * so the model can recover without a separate `read_file` round-trip.
755
756
  */
756
- declare const SHELL_CASCADE_CANCEL_MESSAGE = "Cancelled: a sibling `shell` call in the same batch errored; re-run independently if still needed.";
757
+ declare const edit: ToolDef;
757
758
  //#endregion
758
- //#region src/loop-persistence.d.ts
759
- /**
760
- * Bytes of head content included in the inline preview block. 2 KiB matches
761
- * Claude Code's `PREVIEW_SIZE_BYTES` — enough for the model to identify the
762
- * content class (error output / structured data / log shape) and decide
763
- * whether to call `read_file` on the persisted path for the full payload.
764
- *
765
- * Tail-priority preview (matching `shell`'s truncation strategy) was
766
- * considered but rejected: most "what is this?" decisions get made from
767
- * the head, and the path is in the stub for the rare case where the tail
768
- * matters.
769
- */
770
- declare const PERSISTENCE_PREVIEW_BYTES: number;
759
+ //#region src/tools/glob.d.ts
760
+ declare const glob: ToolDef;
761
+ //#endregion
762
+ //#region src/tools/grep.d.ts
763
+ declare const grep: ToolDef;
764
+ //#endregion
765
+ //#region src/tools/interaction.d.ts
766
+ interface InteractionToolOptions {
767
+ /** JSON Schema for the request payload the model sends */
768
+ schema: Record<string, unknown>;
769
+ /** Tool name (default: 'interaction') */
770
+ name?: string;
771
+ /** Tool description shown to the model */
772
+ description?: string;
773
+ /** Called when the model invokes this tool. Receives the validated payload and tool context, returns data for the model. */
774
+ onRequest: (payload: Record<string, unknown>, ctx: ToolContext) => Promise<Record<string, unknown> | string>;
775
+ }
771
776
  /**
772
- * Byte-stable prefix every {@link buildPersistedStub} output starts with.
773
- * Exported so wire-level passes (tail compaction, future stale-output
774
- * elision) can recognize a persisted stub and preserve its path attribute
775
- * rather than replacing the stub with their own — losing the pointer to
776
- * the on-disk blob.
777
+ * Create an interaction tool that lets the agent request structured input.
777
778
  *
778
- * Bound to the literal opening of the XML tag; changing the stub format
779
- * requires updating this constant in lockstep (and shipping a migration
780
- * for in-flight sessions).
779
+ * The model calls this tool with a payload matching the schema.
780
+ * `onRequest` is called with the payload and should return the response
781
+ * (string or object) that gets sent back to the model as the tool result.
781
782
  */
782
- declare const PERSISTED_STUB_PREFIX = "<persisted-output tool=\"";
783
- /**
784
- * Resolve the per-session persistence directory under `<userDir>/tool-results/<sessionId>/`.
785
- *
786
- * The chat layer calls this at session activation and forwards the result
787
- * via `behavior.persistDir`. Exposed as a public helper so SDK consumers
788
- * pick the same layout — single source of truth for "where do blobs live".
789
- */
790
- declare function resolvePersistDir(opts: {
791
- userDir: string;
792
- sessionId: string;
793
- }): string;
794
- /**
795
- * Resolve the per-session background-tasks directory under
796
- * `<userDir>/<sessionId>/tasks/`.
797
- *
798
- * The chat layer calls this at session activation and forwards the result
799
- * via `behavior.tasksDir`. Same shape as {@link resolvePersistDir}: hosts
800
- * get a single source of truth for "where do task log files live".
801
- * Created on first write; cleanup is the session-delete path's job.
802
- */
803
- declare function resolveTasksDir(opts: {
804
- userDir: string;
805
- sessionId: string;
806
- }): string;
807
- /**
808
- * Inputs to {@link maybePersistToolResult}. Kept as a struct so the loop's
809
- * call site stays readable and additional optional knobs (compression,
810
- * mime detection, …) land without re-threading every call site.
811
- */
812
- interface PersistInput {
813
- /** Canonical tool name — checked against `excludeTools`. */
814
- toolName: string;
815
- /** `tool_use` id from the assistant turn. Used as the filename. */
816
- callId: string;
817
- /** Result returned by the tool (post-`tool:transform`). */
818
- output: string | ToolResultContent[];
819
- /** Byte threshold; outputs at or below stay inline. */
820
- threshold: number;
821
- /** Canonical tool names that bypass persistence. */
822
- excludeTools?: readonly string[];
823
- /** Persistence root directory. Created on first write. */
824
- persistDir: string;
783
+ declare function createInteractionTool(options: InteractionToolOptions): ToolDef;
784
+ //#endregion
785
+ //#region src/tools/list-files.d.ts
786
+ declare const listFiles: ToolDef;
787
+ //#endregion
788
+ //#region src/tools/multi-edit.d.ts
789
+ declare const multiEdit: ToolDef;
790
+ //#endregion
791
+ //#region src/tools/read-file.d.ts
792
+ declare const readFile: ToolDef;
793
+ //#endregion
794
+ //#region src/tools/shell.d.ts
795
+ interface CreateShellToolOptions {
825
796
  /**
826
- * Optional cap on the total bytes of persisted blobs under `persistDir`.
827
- * When set (and > 0), after a successful write the helper sweeps the
828
- * directory and removes the oldest `*.txt` blobs (by mtime) until the
829
- * sum of remaining sizes is at or below the cap.
797
+ * Whether to expose the `run_in_background` flag in the input schema +
798
+ * the background-mode paragraphs in the description. When `false`, the
799
+ * model never sees the flag and won't try to use it. The execute path
800
+ * still has a defensive fallback: an explicit `run_in_background: true`
801
+ * call (e.g. from a hand-crafted message) returns a clean error rather
802
+ * than silently running foreground.
830
803
  *
831
- * Bound to the **current session** because `persistDir` is per-session
832
- * (see {@link resolvePersistDir}); eviction never crosses session
833
- * boundaries. The new blob is always preserved — its mtime is the
834
- * latest, so the LRU sort guarantees older blobs go first.
804
+ * Default: `true`.
805
+ */
806
+ allowBackground?: boolean;
807
+ /**
808
+ * Canonical names of tools registered alongside `shell` on the same
809
+ * agent. When non-empty, the description gains a "prefer the dedicated
810
+ * tool" block for each known sibling (`read_file`, `glob`, `grep`,
811
+ * `list_files`, `edit`, `write_file`) — useful against the
812
+ * `ls`/`cat`-to-re-verify loop some models fall into when both a
813
+ * dedicated tool AND `shell` are visible. Unknown / unrecognized names
814
+ * are ignored.
835
815
  *
836
- * Skipped when the value isn't a positive finite number. Eviction
837
- * failures (permissions, races) are surfaced through `ZIDANE_DEBUG`
838
- * but never block the calling tool result; an over-cap dir is a
839
- * housekeeping concern, not a correctness one.
816
+ * Set by `createAgent` per-run from the tool registry; hosts that
817
+ * construct a `shell` directly can pass it explicitly. Omit to suppress
818
+ * the block entirely (no nudge for shell-only agents, no nudge for
819
+ * hosts that prefer to author their own anti-loop prose).
840
820
  */
841
- maxBytes?: number;
821
+ registeredCanonicals?: ReadonlySet<string>;
822
+ /**
823
+ * The agent's `toolAliases` map, used to render the wire-level name of
824
+ * each sibling in the swap block. Without this, the block always prints
825
+ * canonical names — fine for the default preset, wrong for hosts that
826
+ * alias-rename (the model would be told to call a name it doesn't see
827
+ * in the tool spec).
828
+ */
829
+ toolAliases?: Record<string, string>;
842
830
  }
843
- type PersistOutcome = {
844
- kind: 'skip';
845
- reason: 'disabled' | 'excluded' | 'under-threshold' | 'unsupported-shape' | 'unsafe-call-id' | 'invalid-persist-dir';
846
- } | {
847
- kind: 'persisted';
848
- output: string;
849
- originalBytes: number;
850
- persistedPath: string;
851
- evicted?: {
852
- files: number;
853
- bytes: number;
854
- };
855
- } | {
856
- kind: 'error';
857
- reason: 'write-failed';
858
- error: Error;
859
- };
860
831
  /**
861
- * Decide-and-persist for a single tool result. Pure decision + filesystem
862
- * side-effect; returns the new wire-level `output` string when substitution
863
- * happened, otherwise tells the caller to leave the result alone.
864
- *
865
- * Atomicity: writes go through `<path>.tmp` + `rename` so a concurrent
866
- * read (or a crash mid-write) never sees a half-written blob.
832
+ * Factory for the `shell` tool. The default exported `shell` is
833
+ * equivalent to `createShellTool({ allowBackground: true })`. The
834
+ * factory is the entry point hosts use when they want to override the
835
+ * default — e.g. to ship a preset that always disables background mode
836
+ * regardless of `behavior.tasksDir`.
867
837
  *
868
- * `ToolResultContent[]` results (images, structured blocks) currently bypass
869
- * persistence the inline image bytes are the point of the call, and a
870
- * mixed text/image array isn't representable as a single `.txt` file. We
871
- * may revisit if a tool starts returning very large text-only arrays.
838
+ * Hosts that use the framework's `createAgent` typically don't need to
839
+ * call this directly: when `behavior.tasksDir` is unset or
840
+ * `behavior.disableBackgroundTasks: true` is set, the agent
841
+ * automatically rewrites the registered `shell` (if it's the
842
+ * framework's built-in) using this factory.
872
843
  */
873
- declare function maybePersistToolResult(input: PersistInput): Promise<PersistOutcome>;
874
- interface BuildStubInput {
875
- toolName: string;
876
- originalBytes: number;
877
- persistedPath: string;
878
- output: string;
879
- }
844
+ declare function createShellTool(opts?: CreateShellToolOptions): ToolDef;
880
845
  /**
881
- * Render the byte-stable `<persisted-output>` stub the model sees in place
882
- * of the original `tool_result`.
883
- *
884
- * Format choices:
885
- * - XML wrapper because models reliably parse it as structural.
886
- * - Byte count + path in attributes so the model can decide whether to
887
- * `read_file` the persisted blob without scanning the preview.
888
- * - Preview always shows the head — `shell`'s tail-priority truncation is
889
- * irrelevant here because the model has the full path if it needs the
890
- * tail.
891
- * - No timestamps, no random UUIDs inside the stub: every byte must be
892
- * reproducible from the inputs, otherwise re-emission on subsequent
893
- * turns would bust the prompt cache.
846
+ * Default `shell` tool with background mode enabled.
894
847
  *
895
- * Exported for tests (asserting the byte-stable contract) and for SDK
896
- * consumers wiring their own persistence middleware against the same
897
- * surface.
848
+ * Most hosts use this directly via `basicTools`. When the agent's
849
+ * `behavior.tasksDir` is unset OR `behavior.disableBackgroundTasks:
850
+ * true` is set, `createAgent` auto-rewrites this identity to a
851
+ * `createShellTool({ allowBackground: false })` variant so the model
852
+ * never sees a flag it can't use. Hosts who want to bypass that
853
+ * auto-rewrite can register a `createShellTool({ allowBackground })`
854
+ * directly — the rewrite only fires on identity-equal references to
855
+ * this constant.
898
856
  */
899
- declare function buildPersistedStub(input: BuildStubInput): string;
857
+ declare const shell: ToolDef;
858
+ //#endregion
859
+ //#region src/tools/shell-kill.d.ts
860
+ declare const shellKill: ToolDef;
861
+ //#endregion
862
+ //#region src/tools/skills-read.d.ts
863
+ interface SkillsReadToolOptions {
864
+ catalog: readonly SkillConfig[];
865
+ state: SkillActivationState;
866
+ }
867
+ declare function createSkillsReadTool(options: SkillsReadToolOptions): ToolDef;
868
+ //#endregion
869
+ //#region src/tools/skills-run-script.d.ts
870
+ interface SkillsRunScriptToolOptions {
871
+ catalog: readonly SkillConfig[];
872
+ state: SkillActivationState;
873
+ /** Script timeout in milliseconds. Default 60000. */
874
+ scriptTimeoutMs?: number;
875
+ }
876
+ declare function createSkillsRunScriptTool(options: SkillsRunScriptToolOptions): ToolDef;
877
+ //#endregion
878
+ //#region src/tools/skills-use.d.ts
879
+ interface SkillsUseToolOptions {
880
+ /** Resolved skills catalog for this run. */
881
+ catalog: readonly SkillConfig[];
882
+ /** Per-agent activation state the tool mutates. */
883
+ state: SkillActivationState;
884
+ /** Agent hooks — used to fire `skills:activate` on first activation. */
885
+ hooks: Hookable<AgentHooks>;
886
+ }
900
887
  /**
901
- * Remove every persisted blob belonging to a session. Called by the chat
902
- * layer from its session-delete path so closing a session frees the disk
903
- * footprint alongside the SQLite row.
888
+ * Factory for `skills_use`. Auto-injected into the agent's tool set by the
889
+ * agent runtime when a non-empty skills catalog is available (unless
890
+ * `SkillsConfig.tool === false`).
904
891
  *
905
- * Idempotent missing directory (session never persisted anything) is a
906
- * no-op, not an error. Wraps the `rm -rf` so a permissions blip on one
907
- * blob doesn't propagate to the caller; the chat layer can't usefully
908
- * recover from "couldn't unlink a result file" mid-delete.
892
+ * The tool schema's `name` property is `enum`-constrained to the resolved
893
+ * catalog so the LLM cannot hallucinate a skill that doesn't exist.
909
894
  */
910
- declare function cleanupPersistedSession(persistRoot: string): Promise<void>;
895
+ declare function createSkillsUseTool(options: SkillsUseToolOptions): ToolDef;
911
896
  //#endregion
912
- //#region src/mcp/oauth-provider.d.ts
913
- /**
914
- * Per-server persisted state. Subfields are optional so a partial save
915
- * (e.g. `saveCodeVerifier` arriving before `saveTokens`) doesn't blow away
916
- * earlier subfields — the provider always patches, never replaces.
917
- */
918
- interface McpCredentialEntry {
919
- tokens?: OAuthTokens;
920
- clientInformation?: OAuthClientInformationMixed;
921
- discoveryState?: OAuthDiscoveryState;
897
+ //#region src/tools/spawn.d.ts
898
+ interface ChildAgent {
899
+ id: string;
900
+ task: string;
901
+ startedAt: number;
902
+ /** Subagent depth — 1 for a direct child of a top-level agent. */
903
+ depth: number;
922
904
  }
923
- interface McpCredentialStore {
924
- load: (name: string) => McpCredentialEntry | undefined;
925
- save: (name: string, entry: McpCredentialEntry) => void;
926
- delete: (name: string) => void;
905
+ interface SpawnToolState {
906
+ /** Currently running children. */
907
+ readonly children: ReadonlyMap<string, ChildAgent>;
908
+ /**
909
+ * Cumulative stats across every completed direct child of this spawn-tool
910
+ * instance (returns a copy). Each child's contribution is the cumulative
911
+ * `AgentStats` returned by its `agent.run()` — so
912
+ * `totalIn`/`totalOut`/`totalCacheRead`/`totalCacheCreation` cover the
913
+ * entire subtree (children + grandchildren + …), while `turns` and
914
+ * `elapsed` stay parent-loop-only per child and are summed across direct
915
+ * children. `elapsed` over-counts when children ran in parallel.
916
+ *
917
+ * Lives across multiple parent runs that share this instance.
918
+ */
919
+ readonly totalChildStats: Readonly<AgentStats>;
927
920
  }
928
- /**
929
- * In-memory store primarily for tests, but valid as a no-persistence option
930
- * (tokens evaporate on process exit, the user re-auths every cold start).
931
- */
932
- declare function createMemoryMcpCredentialStore(seed?: Record<string, McpCredentialEntry>): McpCredentialStore;
933
- interface McpOAuthProviderOptions {
934
- /** Server name — used as the storage key. */
935
- name: string;
936
- /** Persistence backend. */
937
- store: McpCredentialStore;
921
+ interface SpawnToolOptions {
922
+ /** Maximum concurrent sub-agents (default: 3). */
923
+ maxConcurrent?: number;
938
924
  /**
939
- * Loopback callback URI. Pass `undefined` for bootstrap (non-interactive
940
- * mode stored tokens + refresh only, never opens a browser).
925
+ * Maximum subagent depth. 0 disables spawning entirely; 1 allows top-level
926
+ * spawns but forbids grandchildren; 3 (default) allows three levels of
927
+ * recursion — enough for most orchestration patterns, a sharp ceiling
928
+ * against runaway loops.
941
929
  */
942
- redirectUri?: string;
930
+ maxDepth?: number;
931
+ /** Child model override. */
932
+ model?: string;
933
+ /** Child system prompt override. Per-spawn `input.system` takes precedence. */
934
+ system?: string;
935
+ /** Child thinking level. */
936
+ thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high';
937
+ /** Preset override for children. Shallow-merged over the parent's preset (parent fields still win for anything left unset). */
938
+ preset?: Preset;
943
939
  /**
944
- * Invoked when the SDK wants the user agent to navigate to the authorization
945
- * URL. Typically the host opens the browser AND emits a hook so the TUI can
946
- * render the URL in a status row. No-op in non-interactive mode (the SDK
947
- * still calls this before throwing `UnauthorizedError` from connect).
940
+ * Per-child timeout, in milliseconds. When the child exceeds it the spawn
941
+ * tool returns a timeout marker, fires `spawn:error`, and destroys the
942
+ * child agent. Default: none.
948
943
  */
949
- onAuthorizationUrl?: (url: URL) => void | Promise<void>;
944
+ timeoutMs?: number;
950
945
  /**
951
- * `client_name` used in dynamic client registration. Defaults to `'zidane'`.
952
- * Some servers display this string to the user on the consent screen.
946
+ * When `true` and the parent has a session, the child reuses the parent's
947
+ * session child turns are appended with the child's own `runId`, and the
948
+ * resulting `SessionRun` carries `parentRunId` so the tree is
949
+ * reconstructible. Default: `false` (child is in-memory only).
950
+ *
951
+ * **Read-state isolation.** Sharing the session also shares the
952
+ * `read_file` / `requireReadBeforeEdit` tracking map (it's keyed
953
+ * by `Session`). With `persist: false` the child gets no session,
954
+ * so reads inside the subagent populate nothing the parent can see —
955
+ * a follow-up `edit` / `multi_edit` in the parent will trip the
956
+ * gate with `"has not been read"` even though the model just
957
+ * read the file in the child. Use {@link shareReadState} when
958
+ * you want the parent's gate to honor the child's reads WITHOUT
959
+ * also persisting child turns to the parent's session.
953
960
  */
954
- clientName?: string;
961
+ persist?: boolean;
955
962
  /**
956
- * Override the requested OAuth scope. Default: unset (the SDK negotiates
957
- * via the server's metadata).
963
+ * Forward the parent's read-state map to the child agent so the
964
+ * `requireReadBeforeEdit` gate and `dedupReads` cache see reads
965
+ * across the parent/child boundary. Orthogonal to {@link persist} —
966
+ * use this when you want shared read tracking without sharing the
967
+ * session's turn history. Default: `false`.
968
+ *
969
+ * Has no effect when the parent has no read-state to share (no
970
+ * session and no explicit `readState` on the parent agent's
971
+ * options). Implementation: passes the parent's resolved
972
+ * `ReadStateMap` to the child via `AgentOptions.readState`, which
973
+ * tools resolve via `ctx.readState ?? getReadState(ctx.session)`.
958
974
  */
959
- scope?: string;
960
- }
961
- declare class McpOAuthProvider implements OAuthClientProvider {
962
- private readonly name;
963
- private readonly store;
964
- private readonly _redirectUri?;
965
- private readonly onAuthorizationUrl?;
966
- private readonly clientName;
967
- private readonly _scope?;
968
- private codeVerifierValue;
969
- constructor(opts: McpOAuthProviderOptions);
970
- get redirectUrl(): string | URL | undefined;
971
- get clientMetadata(): OAuthClientMetadata;
972
- tokens(): OAuthTokens | undefined;
973
- saveTokens(tokens: OAuthTokens): void;
974
- clientInformation(): OAuthClientInformationMixed | undefined;
975
- saveClientInformation(info: OAuthClientInformationMixed): void;
976
- discoveryState(): OAuthDiscoveryState | undefined;
977
- saveDiscoveryState(state: OAuthDiscoveryState): void;
978
- saveCodeVerifier(verifier: string): void;
979
- codeVerifier(): string;
980
- redirectToAuthorization(url: URL): Promise<void>;
975
+ shareReadState?: boolean;
981
976
  /**
982
- * Wipe stored credentials when the server reports the cached state is no
983
- * longer valid. The SDK calls this with a scope hint:
984
- * - `'tokens'` → access/refresh revoked, keep client registration
985
- * - `'client'` → client registration invalidated, reset everything
986
- * - `'verifier'`→ PKCE state stale (e.g. mismatched state param)
987
- * - `'discovery'` → discovery metadata stale (servers re-keyed)
988
- * - `'all'` → full reset
977
+ * Forward a curated subset of child hook events (`stream:*`, `tool:*`,
978
+ * `turn:after`) onto the parent's hook bus as `child:*` events. Default:
979
+ * `true`. Grandchildren bubble through their child transparently.
989
980
  */
990
- invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): Promise<void>;
991
- private patch;
981
+ forwardHooks?: boolean;
982
+ /** Called when a child agent starts. */
983
+ onSpawn?: (child: ChildAgent) => void;
984
+ /** Called when a child agent completes (success, abort, timeout, or error). */
985
+ onComplete?: (child: ChildAgent, stats: AgentStats, status: NonNullable<ChildRunStats['status']>) => void;
986
+ /**
987
+ * Named subagent presets the model can select via the `subagent_type`
988
+ * input field. Mirrors the Claude Code SDK's surface — models trained
989
+ * on it routinely emit `subagent_type: 'Explore' | 'Plan' |
990
+ * 'Verification' | 'general-purpose'`, and without a registry the
991
+ * field is silently dropped, so hosts wanting type-specialized
992
+ * subagents have to invent their own dispatch layer.
993
+ *
994
+ * Each entry overlays the base spawn config for that particular
995
+ * dispatch. Per-call `input.system` still wins over `subagents[type].system`
996
+ * so the model can always specialize further.
997
+ *
998
+ * When the registry is non-empty:
999
+ * - `subagent_type` appears in the spawn input schema as a `string`
1000
+ * enum of the registered keys (plus the always-available
1001
+ * `'general-purpose'` fallback).
1002
+ * - Models that pass an unregistered type are routed to
1003
+ * `'general-purpose'` (no error — degrade gracefully so trained
1004
+ * models keep working even on hosts that haven't wired every
1005
+ * type Claude Code uses).
1006
+ *
1007
+ * When the registry is empty / unset, the field is omitted entirely
1008
+ * (preserves the historical schema for hosts that never use this).
1009
+ *
1010
+ * Default: `undefined` (no subagent types; `subagent_type` schema
1011
+ * field hidden).
1012
+ */
1013
+ subagents?: SubagentRegistry;
992
1014
  }
993
1015
  /**
994
- * True when an HTTP transport's auth headers already include an explicit
995
- * Authorization. Used by the bootstrap escape-hatch: a user who provided
996
- * their own bearer token shouldn't be auto-promoted to OAuth on a 401.
997
- *
998
- * Case-insensitive — Node normalizes outgoing headers to lowercase but
999
- * users hand-write `Authorization` in configs.
1016
+ * Per-type subagent override applied when the model calls
1017
+ * `spawn({ subagent_type: '…' })`. All fields are optional; absent
1018
+ * fields fall back to the parent's resolved configuration (see
1019
+ * {@link SpawnToolOptions} comments for the merge order).
1000
1020
  */
1001
- declare function hasAuthorizationHeader(headers: Record<string, string> | undefined): boolean;
1002
- //#endregion
1003
- //#region src/mcp/login.d.ts
1004
- interface LoginMcpServerOptions {
1005
- /** Persistence — same store the bootstrap path reads from. */
1006
- store: McpCredentialStore;
1021
+ interface SubagentDef {
1007
1022
  /**
1008
- * Invoked with the authorization URL once it's ready. Hosts typically
1009
- * (a) emit `mcp:auth:url` for the TUI, and (b) call `tryOpenBrowser`.
1010
- * The URL is identical to the one passed to the `mcp:auth:url` hook
1011
- * fired automatically — this callback is a synchronous hook for callers
1012
- * that don't want to wire the agent hook machinery.
1023
+ * System prompt override for this subagent type. Per-call
1024
+ * `input.system` still wins model-supplied specialization beats
1025
+ * preset defaults.
1013
1026
  */
1014
- onAuthorizationUrl?: (url: URL) => void | Promise<void>;
1015
- /** Cancels the flow (esc / close modal / SIGINT). */
1016
- signal?: AbortSignal;
1017
- /** Agent hooks. The flow emits `mcp:auth:url`/`success`/`error` when wired. */
1018
- hooks?: Hookable<AgentHooks>;
1019
- /** Override `client_name` shown on consent screens. Default: 'zidane'. */
1020
- clientName?: string;
1021
- /** Override the requested OAuth scope. */
1022
- scope?: string;
1027
+ system?: string;
1023
1028
  /**
1024
- * Override the loopback callback path. Default: `/callback`. Useful only
1025
- * for servers that pinned a different path during registration.
1029
+ * Restrict the child agent's tool registry to this list of canonical
1030
+ * tool names. Operates as a filter over the parent's tools (the
1031
+ * parent's selection is the upper bound — a subagent can never gain
1032
+ * tools the parent doesn't have). When unset, the child inherits the
1033
+ * parent's full tool list.
1034
+ *
1035
+ * Tool names are canonical (registry-key) not wire/alias names — the
1036
+ * filter runs before aliases are applied. Names that don't match a
1037
+ * parent tool are silently dropped (matches the lenient behaviour of
1038
+ * `enabledTools` on MCP configs).
1026
1039
  */
1027
- callbackPath?: string;
1040
+ tools?: readonly string[];
1028
1041
  /**
1029
- * Maximum time to wait for the user to complete the browser flow, in ms.
1030
- * The user can also cancel via `signal`. Default: 5 minutes.
1042
+ * Mark this subagent as read-only equivalent to listing only
1043
+ * obviously-non-mutating tools (`read_file`, `grep`, `glob`,
1044
+ * `list_files`) in {@link SubagentDef.tools}. Convenience for the
1045
+ * common "Plan" / "Explore" subagent shape Claude Code ships.
1046
+ *
1047
+ * When both `readonly: true` and `tools` are set, `tools` wins
1048
+ * (explicit beats implicit).
1031
1049
  */
1032
- timeoutMs?: number;
1033
- }
1034
- interface LoginMcpServerResult {
1035
- /** Stored OAuth tokens after a successful exchange. */
1036
- tokens: NonNullable<ReturnType<McpOAuthProvider['tokens']>>;
1050
+ readonly?: boolean;
1037
1051
  /**
1038
- * Upstream tool descriptors discovered after re-connecting with the new
1039
- * tokens. Already filtered by the server's `enabledTools` / `disabledTools`
1040
- * is NOT applied here that's a bootstrap concern. Hosts that want filtering
1041
- * should pass the result through `connectMcpServers` rebuild on the next
1042
- * session activation rather than reusing this list verbatim.
1043
- */
1044
- tools: Array<{
1045
- name: string;
1046
- description?: string | null;
1047
- inputSchema?: unknown;
1048
- }>;
1049
- }
1050
- /**
1051
- * Run the full interactive OAuth flow for `config`. Only supports `sse` and
1052
- * `streamable-http` transports — `stdio` MCP servers don't speak OAuth.
1053
- *
1054
- * Throws on:
1055
- * - Wrong transport.
1056
- * - Abort signal.
1057
- * - Browser-side error (user denied, server rejected, etc.).
1058
- * - Code exchange failure.
1059
- * - Post-exchange connect failure.
1060
- *
1061
- * Always closes the loopback callback server before returning, success or
1062
- * failure.
1063
- */
1064
- declare function loginMcpServer(config: McpServerConfig, options: LoginMcpServerOptions): Promise<LoginMcpServerResult>;
1065
- //#endregion
1066
- //#region src/mcp/oauth-callback.d.ts
1067
- /**
1068
- * Local loopback HTTP callback for OAuth 2.0 authorization code flows.
1069
- *
1070
- * Stands up a one-shot server on `127.0.0.1:<random>` that captures the
1071
- * `?code=...` redirect from a browser-driven OAuth flow and resolves a
1072
- * promise with the code. Used as the `redirectUrl` half of the MCP SDK's
1073
- * `OAuthClientProvider` (the persistence half lives separately).
1074
- *
1075
- * Design:
1076
- * - Loopback-only (`127.0.0.1`) — the OAuth spec treats `http://127.0.0.1:<port>`
1077
- * as a public-client redirect URI per RFC 8252 §7.3. Browsers do NOT block it,
1078
- * and Anthropic / OpenAI / Linear / GitHub all accept it.
1079
- * - Random port (`port = 0`) — the OS picks an unused one. We read the actual
1080
- * port back from `server.address()` after `listen()`.
1081
- * - Single-shot — the first GET to `path` with a `code` (or `error`) wins;
1082
- * subsequent requests get 404. The server keeps listening (in case the user
1083
- * hits "back" and re-authorizes), so callers must `close()` once they have
1084
- * the code or have given up.
1085
- * - Abort-aware — wiring an external `AbortSignal` rejects the promise and
1086
- * closes the server immediately. Required for the TUI's "esc cancels login"
1087
- * UX.
1088
- * - No HTML framework — a single inline `<html>` string keeps this isolated
1089
- * from any UI dependency.
1052
+ * Short description rendered into the spawn tool's schema (the
1053
+ * `subagent_type` field's description) so the model can pick a type
1054
+ * that matches the task without round-tripping through docs.
1055
+ */
1056
+ description?: string;
1057
+ }
1058
+ /**
1059
+ * Map of subagent-type key → preset. Keys are case-sensitive and
1060
+ * appear verbatim in the spawn input schema's enum so the model emits
1061
+ * them with the same casing. Common conventions: `'Explore'`,
1062
+ * `'Plan'`, `'Verification'`, `'general-purpose'` (Claude Code SDK's
1063
+ * built-in set).
1090
1064
  */
1065
+ type SubagentRegistry = Record<string, SubagentDef>;
1091
1066
  /**
1092
- * Result of a successful callback. `state` is forwarded verbatim from the
1093
- * query string — callers verify it against their pre-flight value to defend
1094
- * against CSRF (the MCP SDK does this internally when it controls `state`).
1067
+ * Create a configured spawn tool.
1068
+ *
1069
+ * State (`children`, `totalChildStats`, counters, active count) is scoped to
1070
+ * the returned instance. Multiple parent agents using the same instance will
1071
+ * share counters + stats + concurrency slots — call `createSpawnTool()` per
1072
+ * agent (or use the stateless default `spawn`) to keep them isolated.
1095
1073
  */
1096
- interface OAuthCallbackResult {
1097
- code: string;
1098
- state?: string;
1099
- }
1100
- interface OAuthCallbackHandle {
1101
- /**
1102
- * Full URI to register with the authorization server, e.g.
1103
- * `http://127.0.0.1:51823/callback`. Stable for the lifetime of the
1104
- * handle.
1105
- */
1106
- redirectUri: string;
1074
+ declare function createSpawnTool(options?: SpawnToolOptions): ToolDef & SpawnToolState;
1075
+ //#endregion
1076
+ //#region src/tools/tool-search.d.ts
1077
+ interface LazyToolEntry {
1107
1078
  /**
1108
- * Resolves with `{ code, state }` on a successful callback. Rejects with:
1109
- * - The OAuth-spec `error` field (`access_denied`, `server_error`, ...)
1110
- * when the authorization server redirects with `?error=...`.
1111
- * - `'OAuth callback aborted'` when the external `AbortSignal` fires.
1112
- * - `'OAuth callback server closed'` when `close()` is called before any
1113
- * callback arrives.
1114
- *
1115
- * Single-shot — only the first matching request resolves the promise.
1079
+ * Wire name (after `toolAliases` rewrite). What the model sees in the
1080
+ * catalog, what `tool_search` matches against, and what the provider's
1081
+ * tool list will carry once the entry is unlocked.
1116
1082
  */
1117
- promise: Promise<OAuthCallbackResult>;
1083
+ name: string;
1118
1084
  /**
1119
- * Idempotent shutdown. Safe to call from a `finally` block whether the
1120
- * flow succeeded, failed, or was aborted. Resolves once the server stops
1121
- * accepting connections.
1085
+ * Canonical (registry-key) name used for unlock-set membership and for the
1086
+ * loop's `ctx.tools[name]` dispatch lookup. Equal to `name` when no alias
1087
+ * is configured for this tool.
1122
1088
  */
1123
- close: () => Promise<void>;
1089
+ canonicalName: string;
1090
+ description: string;
1091
+ inputSchema: Record<string, unknown>;
1092
+ /** Source MCP server, when applicable. Used for `server`-bulk unlock. */
1093
+ server?: string;
1124
1094
  }
1125
- interface OAuthCallbackOptions {
1126
- /** Cancels the flow — rejects `promise` and closes the server. */
1127
- signal?: AbortSignal;
1095
+ interface ToolSearchToolOptions {
1128
1096
  /**
1129
- * Path component the authorization server should redirect to. Defaults
1130
- * to `/callback`. Useful when matching a pre-registered URI that uses a
1131
- * different path.
1097
+ * Snapshot of every lazy tool the model can discover. Built once per run by
1098
+ * the agent the tool closes over this array and never mutates it.
1132
1099
  */
1133
- path?: string;
1100
+ catalog: readonly LazyToolEntry[];
1134
1101
  /**
1135
- * Override the loopback host. Defaults to `127.0.0.1`. Don't bind to
1136
- * `0.0.0.0` here the OAuth code is a one-time secret and the server
1137
- * would otherwise accept it from any host on the LAN.
1102
+ * Mutable per-run set of unlocked **canonical** tool names. The tool adds
1103
+ * matches in place; the loop reads the set when rebuilding the wire-level
1104
+ * tool list. Keyed by canonical (not wire) so dispatch lookups stay
1105
+ * alias-stable.
1106
+ *
1107
+ * Prefer `addUnlock` for cache-stable wire-tool ordering: writes through a
1108
+ * Set lose unlock order, so the wire-level rebuild that filters by `unlocked`
1109
+ * has to fall back to registry iteration order — which moves entries every
1110
+ * time a lazy tool earlier in the registry is unlocked, breaking provider
1111
+ * prompt-cache breakpoints. The agent passes both when it owns the unlock
1112
+ * tracker, with `addUnlock` mirroring writes into an ordered log.
1138
1113
  */
1139
- host?: string;
1114
+ unlocked: Set<string>;
1140
1115
  /**
1141
- * Override the port. Defaults to `0` (OS-assigned). Pin to a fixed port
1142
- * only when the authorization server requires a pre-registered redirect
1143
- * URI; the random-port path is preferred so concurrent flows don't clash.
1116
+ * Optional callback fired for every canonical name the tool unlocks. When
1117
+ * set, the agent uses this to maintain an append-only `dynamicUnlockOrder`
1118
+ * so the wire-level tool list emits new unlocks at the tail and keeps the
1119
+ * provider prefix cache warm. Idempotent on repeat unlocks of the same
1120
+ * name — callers may dedupe internally.
1121
+ *
1122
+ * Invoked **in addition to** the `unlocked.add` (which still happens for
1123
+ * back-compat with callers that only watch the Set).
1144
1124
  */
1145
- port?: number;
1125
+ addUnlock?: (canonical: string) => void;
1126
+ /** Default cap on returned matches when the model omits `limit`. */
1127
+ defaultLimit?: number;
1146
1128
  }
1147
1129
  /**
1148
- * Start a one-shot OAuth callback server. The returned handle's `redirectUri`
1149
- * should be passed to the authorization server as the `redirect_uri` query
1150
- * parameter; `promise` resolves once the user finishes the browser flow.
1151
- *
1152
- * Always `await handle.close()` in a `finally` block — even on success, the
1153
- * server stays open until told to shut down (so it can serve the
1154
- * "you can close this tab" page).
1130
+ * Factory for `tool_search`. Auto-injected by the agent when
1131
+ * `behavior.toolDisclosure === 'lazy'` and at least one MCP tool is in the
1132
+ * registry. Opt out via `behavior.toolSearch.tool === false`.
1155
1133
  */
1156
- declare function startOAuthCallback(opts?: OAuthCallbackOptions): Promise<OAuthCallbackHandle>;
1134
+ declare function createToolSearchTool(options: ToolSearchToolOptions): ToolDef;
1157
1135
  //#endregion
1158
- //#region src/metrics.d.ts
1159
- type MetricAttributes = Record<string, string | number | boolean | undefined>;
1160
- interface Counter {
1161
- add: (value: number, attributes?: MetricAttributes) => void;
1162
- }
1163
- interface Histogram {
1164
- record: (value: number, attributes?: MetricAttributes) => void;
1165
- }
1166
- interface UpDownCounter {
1167
- add: (value: number, attributes?: MetricAttributes) => void;
1168
- }
1169
- interface InstrumentOptions {
1170
- description?: string;
1171
- unit?: string;
1172
- }
1136
+ //#region src/tools/validation.d.ts
1173
1137
  /**
1174
- * Minimal Meter interface structurally identical to OTel's `Meter`.
1175
- * Hosts passing `metrics.getMeter(name)` (from `@opentelemetry/api`)
1176
- * satisfy this without adaptation.
1138
+ * Tool argument validation against JSON Schema-style inputSchema.
1139
+ *
1140
+ * Two passes:
1141
+ * 1. Required-field presence. Missing or null/undefined required fields fail.
1142
+ * 2. Per-property type checks with **best-effort coercion**. Small/OSS models
1143
+ * routinely send `"true"` for a `boolean` field or `"42"` for a `number`,
1144
+ * and rejecting outright forces a confusing retry. Instead, we auto-heal
1145
+ * coerce when the conversion is unambiguous, fail only when the value
1146
+ * cannot be reasonably normalized to any of the declared types.
1147
+ *
1148
+ * Recursion: when a property declares `type: 'array'` with an `items` schema,
1149
+ * each item is validated against `items`. Object items are walked one level
1150
+ * deep (their declared `properties` get the same coercion + enum checks the
1151
+ * top level does). Items that can't be coerced are dropped rather than
1152
+ * rejecting the whole call — the model rarely benefits from an
1153
+ * all-or-nothing failure on a 20-item list because one entry was malformed.
1154
+ * Dropped items are reported back via `droppedItems` so the tool's `execute`
1155
+ * can surface a hint to the model if it wants to.
1177
1156
  */
1178
- interface Meter {
1179
- createCounter: (name: string, options?: InstrumentOptions) => Counter;
1180
- createHistogram: (name: string, options?: InstrumentOptions) => Histogram;
1181
- createUpDownCounter: (name: string, options?: InstrumentOptions) => UpDownCounter;
1182
- }
1183
- interface MetricsHooksOptions {
1184
- meter: Meter;
1157
+ interface ValidationResult {
1158
+ valid: boolean;
1159
+ /** Human-readable reason. Present on failure only. */
1160
+ error?: string;
1185
1161
  /**
1186
- * Optional prefix prepended to every instrument name. Default: no prefix
1187
- * (instrument names follow OTel Gen AI semantic conventions verbatim,
1188
- * which is the most-portable shape). Set to e.g. `'zidane.'` to
1189
- * namespace inside a shared meter registry.
1162
+ * Possibly-coerced input. Present iff `valid: true`. Tools should call
1163
+ * `execute(coercedInput, ctx)` so auto-healed values reach the tool body.
1164
+ * When no coercion was applied, this is reference-equal to the input.
1190
1165
  */
1191
- namespace?: string;
1166
+ coercedInput?: Record<string, unknown>;
1192
1167
  /**
1193
- * Optional baseline attributes applied to every measurement. Typical
1194
- * use: `{ service: 'tui', env: 'prod' }`. Per-event attributes win on
1195
- * key collision.
1168
+ * Names of fields whose values were coerced. Empty when nothing changed.
1169
+ * Useful for telemetry (`validation:reject` on failure already carries the
1170
+ * reason; this is the success-path equivalent).
1196
1171
  */
1197
- baseAttributes?: MetricAttributes;
1172
+ coercions?: readonly string[];
1198
1173
  /**
1199
- * Error sink for meter failures. The helper still swallows the throw
1200
- * so a broken backend can't crash a run; this callback surfaces the
1201
- * failure for ops dashboards.
1174
+ * Indexes of array items dropped during recursive validation, keyed by
1175
+ * the property name. Empty / absent when nothing was dropped. Tools that
1176
+ * care about the discrepancy (e.g. `todowrite` wanting to surface
1177
+ * "ignored 2 malformed items") can inspect this.
1202
1178
  */
1203
- onError?: (kind: string, err: unknown) => void;
1204
- }
1205
- interface MetricsHookSet {
1206
- install: (hooks: Hookable<AgentHooks>) => () => void;
1179
+ droppedItems?: Readonly<Record<string, readonly number[]>>;
1207
1180
  }
1181
+ declare function validateToolArgs(input: Record<string, unknown>, schema: Record<string, unknown>): ValidationResult;
1182
+ //#endregion
1183
+ //#region src/tools/write-file.d.ts
1208
1184
  /**
1209
- * Build a set of metrics hook handlers that can be installed on an agent.
1185
+ * Write a file, with an idempotency signal when the content is unchanged.
1210
1186
  *
1211
- * @example OpenTelemetry
1212
- * ```ts
1213
- * import { metrics } from '@opentelemetry/api'
1214
- * const meter = metrics.getMeter('zidane')
1215
- * const m = createMetricsHooks({ meter, baseAttributes: { service: 'tui' } })
1216
- * const uninstall = m.install(agent.hooks)
1217
- * try { await agent.run({ prompt }) }
1218
- * finally { uninstall() }
1219
- * ```
1187
+ * Three return shapes — chosen so the model can recognize a no-op without a
1188
+ * separate read:
1189
+ * - `Created path (N bytes)` file did not exist
1190
+ * - `Updated path (N bytes)` — content differed from on-disk
1191
+ * - `No change needed: path already at target state (N bytes)` — equal
1192
+ *
1193
+ * Race window: in non-process execution contexts (docker, sandbox) shared by
1194
+ * multiple agents, another writer can mutate the file between our read and
1195
+ * our write. Local process context is single-writer per agent so the race is
1196
+ * a non-issue there. Documented rather than locked because the cost of
1197
+ * cross-context locking outweighs the cost of a stale "No change" message.
1220
1198
  */
1221
- declare function createMetricsHooks(options: MetricsHooksOptions): MetricsHookSet;
1199
+ declare const writeFile: ToolDef;
1222
1200
  //#endregion
1223
- //#region src/run-summary.d.ts
1224
- interface RunSummaryTokens {
1201
+ //#region src/headless.d.ts
1202
+ type HeadlessStatus = 'completed' | 'aborted' | 'error' | 'timeout';
1203
+ interface HeadlessUsage {
1225
1204
  input: number;
1226
1205
  output: number;
1227
1206
  cacheRead: number;
1228
1207
  cacheCreation: number;
1208
+ /** Cumulative USD cost when the provider/registry could price the run. */
1229
1209
  cost?: number;
1230
- /** First observable byte from the provider, ms from run start. */
1231
- ttftMs?: number;
1232
1210
  }
1233
- interface RunSummaryByModel {
1234
- modelId: string;
1235
- input: number;
1236
- output: number;
1237
- cacheRead: number;
1238
- cacheCreation: number;
1239
- cost: number;
1211
+ interface HeadlessErrorInfo {
1212
+ message: string;
1213
+ /** Typed-error class name (`AgentAbortedError`, `AgentContextExceededError`, …). */
1214
+ type: string;
1215
+ }
1216
+ /**
1217
+ * Strictly JSON-serializable postmortem of one headless run. Everything an RL
1218
+ * reward function needs: the final answer (`finalText`), the verifiable
1219
+ * structured output (`output`, present iff a `schema` was set), usage/turns,
1220
+ * and the lossless `transcript` (the SFT training data).
1221
+ */
1222
+ interface HeadlessResult {
1223
+ status: HeadlessStatus;
1224
+ /** Concatenated text of the last assistant turn that produced any text. */
1225
+ finalText: string;
1226
+ /** Schema-enforced structured output (only when `opts.schema` is set). */
1227
+ output?: Record<string, unknown>;
1228
+ usage: HeadlessUsage;
1240
1229
  turns: number;
1230
+ durationMs: number;
1231
+ /** Total `tool_call` blocks across the whole transcript. */
1232
+ numToolCalls: number;
1233
+ /** Finish reason of the final turn that reported one. */
1234
+ finishReason?: TurnFinishReason;
1235
+ error?: HeadlessErrorInfo;
1236
+ sessionId: string;
1237
+ /** Incident postmortem (errors, gate blocks, budget events) via run-summary. */
1238
+ summary?: RunSummary;
1239
+ /** Lossless transcript — raw `session.turns`. Thinking stripped when `includeThinking: false`. */
1240
+ transcript: SessionTurn[];
1241
+ }
1242
+ /**
1243
+ * Live event union — the in-process equivalent of a `stream-json` line. Every
1244
+ * member is JSON-serializable; render to JSONL with {@link headlessEventToJsonl}.
1245
+ */
1246
+ type HeadlessEvent = {
1247
+ type: 'start';
1248
+ runId: string;
1249
+ provider?: string;
1250
+ } | {
1251
+ type: 'text';
1252
+ delta: string;
1253
+ } | {
1254
+ type: 'thinking';
1255
+ delta: string;
1256
+ } | {
1257
+ type: 'tool_call';
1258
+ callId: string;
1259
+ name: string;
1260
+ input: Record<string, unknown>;
1261
+ } | {
1262
+ type: 'tool_result';
1263
+ callId: string;
1264
+ name: string;
1265
+ output: string;
1266
+ isError: boolean;
1267
+ } | {
1268
+ type: 'turn';
1269
+ index: number;
1270
+ usage: TurnUsage;
1271
+ } | {
1272
+ type: 'spawn';
1273
+ event: 'before' | 'complete' | 'error';
1274
+ id: string;
1275
+ info?: Record<string, unknown>;
1276
+ } | {
1277
+ type: 'error';
1278
+ message: string;
1279
+ errorType?: string;
1280
+ } | {
1281
+ type: 'result';
1282
+ result: HeadlessResult;
1283
+ };
1284
+ /** Serialize one event as a newline-terminated JSON line (stream-json). */
1285
+ declare function headlessEventToJsonl(event: HeadlessEvent): string;
1286
+ interface HeadlessOptions {
1287
+ /** User prompt — plain string or multimodal `PromptPart[]`. */
1288
+ prompt: string | PromptPart[];
1289
+ /** Built provider (e.g. `local()`, `openaiCompat(...)`, `anthropic(...)`). */
1290
+ provider: Provider;
1291
+ model?: string;
1292
+ /** Override the preset system prompt for this run. */
1293
+ system?: string;
1294
+ thinking?: ThinkingLevel;
1295
+ maxTurns?: number;
1296
+ maxTokens?: number;
1297
+ /** Wall-clock cap; on expiry the run is aborted and `status` becomes `'timeout'`. */
1298
+ timeoutMs?: number;
1299
+ /** External abort signal — chained with the internal timeout controller. */
1300
+ signal?: AbortSignal;
1301
+ /** JSON Schema for structured-output enforcement → populates `result.output`. */
1302
+ schema?: Record<string, unknown>;
1303
+ /** Tool overrides. Omit to use the basic preset's tools. */
1304
+ tools?: Record<string, ToolDef>;
1305
+ mcpServers?: McpServerConfig[];
1306
+ skills?: AgentOptions['skills'];
1307
+ /** Execution context. Defaults to a process context rooted at `cwd`. */
1308
+ execution?: ExecutionContext;
1309
+ /** Working directory for the default process context (ignored if `execution` is set). */
1310
+ cwd?: string;
1311
+ /** Reuse / resume an existing session. */
1312
+ session?: Session;
1313
+ /** Session store for a fresh session (defaults to an in-memory store). */
1314
+ store?: SessionStore;
1315
+ /** Keep `thinking` blocks in `result.transcript` (default true). */
1316
+ includeThinking?: boolean;
1317
+ /** Live event callback — the in-process stream-json equivalent. */
1318
+ onEvent?: (event: HeadlessEvent) => void;
1241
1319
  }
1242
- interface RunSummaryError {
1243
- kind: 'stream' | 'tool' | 'mcp-tool' | 'mcp' | 'spawn';
1244
- message: string;
1245
- errorType?: string;
1246
- turnId?: string;
1247
- callId?: string;
1248
- server?: string;
1249
- toolName?: string;
1250
- childId?: string;
1251
- statusCode?: number;
1252
- requestId?: string;
1320
+ /**
1321
+ * Run a prompt to completion, headless, and return a single serializable
1322
+ * {@link HeadlessResult}. Safe to call concurrently for parallel rollouts —
1323
+ * each call builds its own agent + session and tears them down in `finally`.
1324
+ */
1325
+ declare function runHeadless(opts: HeadlessOptions): Promise<HeadlessResult>;
1326
+ interface OpenAIChatMessage {
1327
+ role: 'system' | 'user' | 'assistant' | 'tool';
1328
+ content: string | null;
1329
+ tool_calls?: Array<{
1330
+ id: string;
1331
+ type: 'function';
1332
+ function: {
1333
+ name: string;
1334
+ arguments: string;
1335
+ };
1336
+ }>;
1337
+ tool_call_id?: string;
1253
1338
  }
1254
- interface RunSummaryBlock {
1255
- callId: string;
1256
- toolName: string;
1257
- outcome: 'gate-block' | 'unknown' | 'invalid-input';
1258
- reason?: string;
1339
+ /**
1340
+ * Convert raw `session.turns` into standard OpenAI chat-completion messages:
1341
+ * assistant turns carry `tool_calls`, and each `tool_result` becomes its own
1342
+ * `role: 'tool'` message. This is the drop-in shape for an SFT renderer —
1343
+ * unlike `toOpenAI` (session/messages.ts), which emits an internal `_tag`
1344
+ * envelope meant for re-sending to a provider, not for training data.
1345
+ */
1346
+ declare function transcriptToOpenAIMessages(turns: SessionTurn[]): OpenAIChatMessage[];
1347
+ //#endregion
1348
+ //#region src/logger.d.ts
1349
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
1350
+ interface LogRecord {
1351
+ level: LogLevel;
1352
+ /** Unix ms — set by `Logger` at emit time. */
1353
+ timestamp: number;
1354
+ /** Free-form message. Sinks render this as the human-facing line. */
1355
+ message: string;
1356
+ /** Structured fields. Correlation ids land here automatically. */
1357
+ attrs: Record<string, unknown>;
1259
1358
  }
1260
- interface RunSummaryValidation {
1261
- callId: string;
1262
- toolName: string;
1263
- reason: string;
1359
+ interface LogSink {
1360
+ emit: (record: LogRecord) => void;
1264
1361
  }
1265
- interface RunSummaryBudget {
1266
- kind: 'bytes' | 'tool-count';
1267
- /** Tool name (for `'tool-count'`); absent for byte budgets. */
1268
- toolName?: string;
1269
- /** `mode` for `'tool-count'`; absent for byte budgets. */
1270
- mode?: 'steer' | 'block';
1271
- observed: number;
1272
- limit: number;
1273
- turnId?: string;
1362
+ interface Logger {
1363
+ debug: (message: string, attrs?: Record<string, unknown>) => void;
1364
+ info: (message: string, attrs?: Record<string, unknown>) => void;
1365
+ warn: (message: string, attrs?: Record<string, unknown>) => void;
1366
+ error: (message: string, attrs?: Record<string, unknown>) => void;
1367
+ /**
1368
+ * Returns a child logger that prepends the given attributes onto every
1369
+ * subsequent emit. Equivalent to `pino.child` / `winston.child`. The
1370
+ * parent and child share the same sink — children are zero-cost.
1371
+ */
1372
+ with: (extra: Record<string, unknown>) => Logger;
1373
+ /**
1374
+ * Inspectable baseline attributes — handy for tests and for hook
1375
+ * handlers that want to clone-with-extra without recursing.
1376
+ */
1377
+ readonly baseAttributes: Readonly<Record<string, unknown>>;
1274
1378
  }
1275
1379
  /**
1276
- * Postmortem snapshot of one `agent.run()`. Strictly serializable every
1277
- * field round-trips through `JSON.stringify` / `JSON.parse` without loss
1278
- * so a log aggregator can ingest it as-is.
1380
+ * Build a Logger from a sink. Stateless and cheap; create one per agent
1381
+ * (or per app) and use `.with()` to attach correlation ids per-call.
1279
1382
  */
1280
- interface RunSummary {
1281
- runId?: string;
1282
- parentRunId?: string;
1283
- depth: number;
1284
- agentName?: string;
1285
- startedAt: number;
1286
- endedAt: number;
1287
- durationMs: number;
1288
- status: 'completed' | 'aborted';
1289
- turns: number;
1290
- totals: RunSummaryTokens;
1291
- byModel: RunSummaryByModel[];
1292
- errors: RunSummaryError[];
1293
- blocks: RunSummaryBlock[];
1294
- validationRejects: RunSummaryValidation[];
1295
- budgetEvents: RunSummaryBudget[];
1296
- /** Counts of pairing repairs, keyed by repair mode. */
1297
- pairingRepairs: Record<string, number>;
1383
+ declare function createLogger(sink: LogSink, baseAttributes?: Readonly<Record<string, unknown>>): Logger;
1384
+ interface ConsoleSinkOptions {
1298
1385
  /**
1299
- * Postmortem snapshots of child runs that bubbled their stats up via
1300
- * `spawn:complete`. Only present when the run actually spawned.
1386
+ * Minimum level to emit. Defaults to `'info'` `debug` is dropped so
1387
+ * the harness's lifecycle logging is not noisy by default. Set to
1388
+ * `'debug'` to see every event.
1301
1389
  */
1302
- children?: RunSummary[];
1390
+ minLevel?: LogLevel;
1391
+ /** Custom output stream. Defaults to `process.stderr` so logs don't pollute stdout. */
1392
+ stream?: {
1393
+ write: (chunk: string) => void;
1394
+ };
1303
1395
  }
1304
- interface RunSummaryCollectorOptions {
1396
+ /**
1397
+ * Human-readable terminal sink. Renders each record as
1398
+ * `<ISO timestamp> <LEVEL> <message> <attrs as kv pairs>`.
1399
+ *
1400
+ * Honors `process.stderr` by default so log lines don't interleave with
1401
+ * the agent's stdout-bound output (chat responses, JSON results).
1402
+ */
1403
+ declare function consoleSink(options?: ConsoleSinkOptions): LogSink;
1404
+ /**
1405
+ * One-JSON-object-per-line sink. Suitable for piping into log aggregators
1406
+ * (Datadog Agent, Fluent Bit, Loki, Vector) that expect JSONL.
1407
+ */
1408
+ declare function jsonSink(options?: ConsoleSinkOptions): LogSink;
1409
+ interface LoggingHooksOptions {
1410
+ logger: Logger;
1305
1411
  /**
1306
- * Called with the assembled {@link RunSummary} on every `agent:done`.
1307
- * Synchronous heavy I/O should be deferred (e.g. via `setImmediate`).
1412
+ * Minimum interesting level for harness-emitted lines. Default `'info'`.
1413
+ * Set to `'debug'` to see every tool dispatch / stream event. Set to
1414
+ * `'warn'` to mute the chatty ones and only see failures + budgets.
1308
1415
  */
1309
- onSummary?: (summary: RunSummary) => void;
1416
+ level?: LogLevel;
1417
+ /**
1418
+ * When true (default), lifecycle events (`agent:start`, `turn:before`,
1419
+ * `tool:before`, `mcp:bootstrap:start`) emit at `debug` level so they
1420
+ * stay quiet by default. Set false to mute them entirely regardless of
1421
+ * the configured minimum level — useful when piping into a tracer
1422
+ * that already captures lifecycle.
1423
+ */
1424
+ includeLifecycle?: boolean;
1310
1425
  }
1311
- interface RunSummaryCollector {
1312
- /** Install the collector's hook handlers. Returns an uninstall fn. */
1426
+ interface LoggingHookSet {
1313
1427
  install: (hooks: Hookable<AgentHooks>) => () => void;
1314
- /** Most-recent summary; `undefined` until the first `agent:done` fires. */
1315
- latest: () => RunSummary | undefined;
1316
1428
  }
1317
1429
  /**
1318
- * Build a run-summary collector. State is created fresh inside each
1319
- * `install()` call, so a single collector instance can be installed
1320
- * across multiple agents without attribution cross-talk. `latest()`
1321
- * returns the most-recent summary across **any** install — install
1322
- * per-agent collectors if you need separate post-run snapshots.
1430
+ * Install a bundle of hook handlers that emit a structured line per
1431
+ * relevant lifecycle event, automatically attaching correlation ids
1432
+ * (`runId`, `turnId`, `callId`, `childId`, `depth`, `agentName`).
1323
1433
  *
1324
1434
  * @example
1325
1435
  * ```ts
1326
- * const collector = createRunSummaryCollector({
1327
- * onSummary: s => console.log(JSON.stringify(s)),
1328
- * })
1329
- * const uninstall = collector.install(agent.hooks)
1436
+ * const logger = createLogger(consoleSink({ minLevel: 'debug' }), { service: 'tui' })
1437
+ * const lh = createLoggingHooks({ logger })
1438
+ * const uninstall = lh.install(agent.hooks)
1330
1439
  * try { await agent.run({ prompt }) }
1331
1440
  * finally { uninstall() }
1332
1441
  * ```
1333
1442
  */
1334
- declare function createRunSummaryCollector(options?: RunSummaryCollectorOptions): RunSummaryCollector;
1443
+ declare function createLoggingHooks(options: LoggingHooksOptions): LoggingHookSet;
1335
1444
  //#endregion
1336
- //#region src/stats.d.ts
1445
+ //#region src/loop.d.ts
1337
1446
  /**
1338
- * Per-model usage rollup produced by {@link statsByModel}.
1339
- *
1340
- * `turns` counts the number of `TurnUsage` entries attributed to the model
1341
- * across the whole tree (parent loop + every recursively-spawned child).
1342
- * Cache and cost numbers are summed from the same set of turns.
1447
+ * Canonical tool_result text emitted when a tool call is interrupted by the
1448
+ * user mid-flight (Esc / Ctrl-C / external `AbortSignal`). Mirrors Claude
1449
+ * Code's `INTERRUPT_MESSAGE_FOR_TOOL_USE` so downstream consumers can pattern
1450
+ * match a single string across both harnesses. Always paired with
1451
+ * `isError: true` on the wire the model treats it as a failed call rather
1452
+ * than a successful tool response.
1343
1453
  */
1344
- interface ModelUsage {
1345
- input: number;
1346
- output: number;
1347
- cost: number;
1348
- cacheRead: number;
1349
- cacheCreation: number;
1350
- turns: number;
1351
- }
1454
+ declare const INTERRUPT_MESSAGE_FOR_TOOL_USE = "[Request interrupted by user for tool use]";
1352
1455
  /**
1353
- * Depth-first walk over the stats tree, returning every `TurnUsage` entry
1354
- * parent loop first, then each child subtree in completion order.
1355
- *
1356
- * Closes the cache-token aggregation gap: `TurnUsage.cacheRead` /
1357
- * `cacheCreation` live only on per-turn entries, and the top-level
1358
- * `AgentStats` deliberately doesn't carry cumulative forms (one source of
1359
- * truth, no risk of drift). Anything that needs a tree-wide sum walks
1360
- * through this.
1456
+ * Canonical tool_result text emitted when a tool call is skipped because a
1457
+ * steering message arrived between dispatches inside
1458
+ * {@link executeToolBatch}. Distinguished from
1459
+ * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} so consumers can split "user
1460
+ * cancelled" from "framework superseded".
1361
1461
  */
1362
- declare function flattenTurns(stats: AgentStats): TurnUsage[];
1462
+ declare const TOOL_USE_SKIPPED_MESSAGE = "[Tool use skipped \u2014 superseded by user message]";
1363
1463
  /**
1364
- * Group cumulative usage by `TurnUsage.modelId`. Each entry sums the input,
1365
- * output, cache, cost, and turn-count across every turn the tree attributed
1366
- * to that model naturally handling cross-model runs (vision-fallback,
1367
- * model-shifted subagents, mixed-provider workflows).
1464
+ * Canonical tool_result text emitted when a single tool call is cancelled
1465
+ * mid-flight via `agent.cancelTool(callId)` (typically the TUI's
1466
+ * "cancel this tool" affordance). Distinguished from
1467
+ * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} (run-wide user abort) and
1468
+ * {@link TOOL_USE_SKIPPED_MESSAGE} (steered) so the model — and downstream
1469
+ * consumers — can tell the three apart by string match.
1368
1470
  *
1369
- * Turns missing `modelId` (mock providers, providers that don't echo a model
1370
- * id) are bucketed under the literal string `'(unknown)'`.
1471
+ * Always paired with `isError: true` on the wire so the model treats the
1472
+ * call as failed rather than as a successful response. The remaining tool
1473
+ * calls in the batch continue running, in contrast with a full-run abort.
1371
1474
  */
1372
- declare function statsByModel(stats: AgentStats): Map<string, ModelUsage>;
1475
+ declare const TOOL_USE_CANCELLED_MESSAGE = "[Tool call cancelled by user]";
1476
+ /**
1477
+ * Canonical `tool_result.content` text emitted to siblings that were
1478
+ * cancelled by a `shell` error in the same batch. Distinct from
1479
+ * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} (user-issued abort) and
1480
+ * {@link TOOL_USE_SKIPPED_MESSAGE} (steered) so consumers can split
1481
+ * the three causes by string-match.
1482
+ */
1483
+ declare const SHELL_CASCADE_CANCEL_MESSAGE = "Cancelled: a sibling `shell` call in the same batch errored; re-run independently if still needed.";
1373
1484
  //#endregion
1374
- //#region src/system-prompt.d.ts
1485
+ //#region src/loop-persistence.d.ts
1375
1486
  /**
1376
- * System-prompt boundary marker splits a system prompt into a stable static
1377
- * prefix (cached) and a per-turn dynamic suffix (NOT cached).
1378
- *
1379
- * Why this exists: providers attach `cache_control` markers on the last block
1380
- * of the system prompt, so the cached prefix covers the entire system text.
1381
- * Any byte change anywhere — including a per-turn `<env>` rewrite — busts the
1382
- * cache for the doctrine that sits below. A literal marker in the system
1383
- * string lets providers split it into:
1384
- *
1385
- * ┌──────────────┐ cache_control: ephemeral
1386
- * │ STATIC half │ — doctrine, skills catalog, tool catalog,
1387
- * │ │ user instructions
1388
- * ├──────────────┤ ← SYSTEM_PROMPT_BOUNDARY
1389
- * │ DYNAMIC half │ — env, cwd, mtimes, anything per-turn
1390
- * └──────────────┘ (no cache_control)
1391
- *
1392
- * The static prefix rides the prompt cache across turns/sessions; the dynamic
1393
- * suffix re-bills per turn. Net effect: a cwd change between turns no longer
1394
- * invalidates 4 KB of doctrine.
1395
- *
1396
- * Wire contract:
1487
+ * Bytes of head content included in the inline preview block. 2 KiB matches
1488
+ * Claude Code's `PREVIEW_SIZE_BYTES` enough for the model to identify the
1489
+ * content class (error output / structured data / log shape) and decide
1490
+ * whether to call `read_file` on the persisted path for the full payload.
1397
1491
  *
1398
- * - `splitSystemPrompt(s)` is pure; missing marker ⇒ entire string is static
1399
- * (current behavior no caller is forced to opt in).
1400
- * - `renderSystemForWire(s)` strips the marker so it never reaches the model;
1401
- * used by every provider before the bytes hit the wire, including the
1402
- * cache-disabled path on providers that DO support `cache_control`.
1403
- * - The marker uses underscores rather than XML/punctuation so it's
1404
- * unambiguous when scanning prompts manually and unlikely to collide with
1405
- * model-written content.
1406
- * - Providers handle the split internally (Anthropic emits a 2-block array;
1407
- * OpenAI-compat splits the leading `system` message into multi-part text).
1408
- * Callers always pass a single `string` — no API break.
1492
+ * Tail-priority preview (matching `shell`'s truncation strategy) was
1493
+ * considered but rejected: most "what is this?" decisions get made from
1494
+ * the head, and the path is in the stub for the rare case where the tail
1495
+ * matters.
1409
1496
  */
1497
+ declare const PERSISTENCE_PREVIEW_BYTES: number;
1410
1498
  /**
1411
- * Literal marker inserted in a system prompt to separate cacheable doctrine
1412
- * from per-turn dynamic content. Providers split on this token.
1499
+ * Byte-stable prefix every {@link buildPersistedStub} output starts with.
1500
+ * Exported so wire-level passes (tail compaction, future stale-output
1501
+ * elision) can recognize a persisted stub and preserve its path attribute
1502
+ * rather than replacing the stub with their own — losing the pointer to
1503
+ * the on-disk blob.
1413
1504
  *
1414
- * Underscored on both sides for visual distinctiveness a stray instance in
1415
- * model-written prose is implausible. Don't change the value without shipping
1416
- * a migration; existing sessions carry the old marker in their cached
1417
- * prompts.
1505
+ * Bound to the literal opening of the XML tag; changing the stub format
1506
+ * requires updating this constant in lockstep (and shipping a migration
1507
+ * for in-flight sessions).
1418
1508
  */
1419
- declare const SYSTEM_PROMPT_BOUNDARY = "__ZIDANE_SYSTEM_PROMPT_BOUNDARY__";
1420
- /** Result of {@link splitSystemPrompt} — both halves stripped of the marker. */
1421
- interface SystemPromptParts {
1422
- /** Bytes BEFORE the marker (or the entire string when no marker present). Cacheable. */
1423
- static: string;
1424
- /** Bytes AFTER the marker. Empty when no marker present. NOT cached. */
1425
- dynamic: string;
1426
- }
1509
+ declare const PERSISTED_STUB_PREFIX = "<persisted-output tool=\"";
1427
1510
  /**
1428
- * Split a system prompt around the first {@link SYSTEM_PROMPT_BOUNDARY}.
1429
- *
1430
- * Splits on the FIRST occurrence — subsequent markers are folded into the
1431
- * dynamic half. This way callers can append additional `<env>` style blocks
1432
- * with extra markers without each one creating a new cache layer (Anthropic
1433
- * caps breakpoints; we use the budget elsewhere). The marker itself is
1434
- * stripped from both sides — providers attach `cache_control` directly to
1435
- * the static half's text content.
1436
- *
1437
- * A single blank line (`\n\n`) immediately adjacent to the marker on each
1438
- * side is trimmed — callers conventionally write
1439
- * `<doctrine>\n\n<MARKER>\n\n<env>` and expect the rendered wire bytes to
1440
- * read as one logical paragraph. Blank lines beyond that immediate pair
1441
- * (e.g. `\n\n\n<env>`) are preserved verbatim so callers composing their
1442
- * own spacing don't lose intentional gaps.
1511
+ * Resolve the per-session persistence directory under `<userDir>/tool-results/<sessionId>/`.
1443
1512
  *
1444
- * Pure / no I/O / no allocation when the marker is absent (returns the input
1445
- * verbatim on the static side and the empty string on the dynamic side).
1513
+ * The chat layer calls this at session activation and forwards the result
1514
+ * via `behavior.persistDir`. Exposed as a public helper so SDK consumers
1515
+ * pick the same layout — single source of truth for "where do blobs live".
1446
1516
  */
1447
- declare function splitSystemPrompt(system: string): SystemPromptParts;
1517
+ declare function resolvePersistDir(opts: {
1518
+ userDir: string;
1519
+ sessionId: string;
1520
+ }): string;
1448
1521
  /**
1449
- * Compose a system prompt from a static prefix and an optional dynamic
1450
- * suffix. Inserts {@link SYSTEM_PROMPT_BOUNDARY} between them only when the
1451
- * dynamic side is non-empty — single-block prompts stay marker-free, so
1452
- * callers that never opt in pay zero overhead and providers fall back to the
1453
- * existing whole-string caching path.
1522
+ * Resolve the per-session background-tasks directory under
1523
+ * `<userDir>/<sessionId>/tasks/`.
1454
1524
  *
1455
- * Spacing is `\n\n` on both sides of the marker so doctrine fragments,
1456
- * which conventionally separate sections with a blank line, read cleanly
1457
- * around the boundary.
1525
+ * The chat layer calls this at session activation and forwards the result
1526
+ * via `behavior.tasksDir`. Same shape as {@link resolvePersistDir}: hosts
1527
+ * get a single source of truth for "where do task log files live".
1528
+ * Created on first write; cleanup is the session-delete path's job.
1458
1529
  */
1459
- declare function joinSystemPrompt(staticPart: string, dynamicPart: string): string;
1530
+ declare function resolveTasksDir(opts: {
1531
+ userDir: string;
1532
+ sessionId: string;
1533
+ }): string;
1460
1534
  /**
1461
- * Append `extra` to the STATIC half of a system prompt, preserving any
1462
- * existing dynamic suffix.
1463
- *
1464
- * Used by the agent to fold in run-stable content (skills catalog, lazy tool
1465
- * catalog) without bumping it into the dynamic half — both catalogs are
1466
- * built once per run and remain byte-stable for the duration, so they
1467
- * belong in the cached prefix.
1468
- *
1469
- * Returns a new string; the input is not mutated. When `extra` is empty,
1470
- * returns the input verbatim.
1535
+ * Inputs to {@link maybePersistToolResult}. Kept as a struct so the loop's
1536
+ * call site stays readable and additional optional knobs (compression,
1537
+ * mime detection, …) land without re-threading every call site.
1471
1538
  */
1472
- declare function appendStaticSection(system: string, extra: string): string;
1539
+ interface PersistInput {
1540
+ /** Canonical tool name — checked against `excludeTools`. */
1541
+ toolName: string;
1542
+ /** `tool_use` id from the assistant turn. Used as the filename. */
1543
+ callId: string;
1544
+ /** Result returned by the tool (post-`tool:transform`). */
1545
+ output: string | ToolResultContent[];
1546
+ /** Byte threshold; outputs at or below stay inline. */
1547
+ threshold: number;
1548
+ /** Canonical tool names that bypass persistence. */
1549
+ excludeTools?: readonly string[];
1550
+ /** Persistence root directory. Created on first write. */
1551
+ persistDir: string;
1552
+ /**
1553
+ * Optional cap on the total bytes of persisted blobs under `persistDir`.
1554
+ * When set (and > 0), after a successful write the helper sweeps the
1555
+ * directory and removes the oldest `*.txt` blobs (by mtime) until the
1556
+ * sum of remaining sizes is at or below the cap.
1557
+ *
1558
+ * Bound to the **current session** because `persistDir` is per-session
1559
+ * (see {@link resolvePersistDir}); eviction never crosses session
1560
+ * boundaries. The new blob is always preserved — its mtime is the
1561
+ * latest, so the LRU sort guarantees older blobs go first.
1562
+ *
1563
+ * Skipped when the value isn't a positive finite number. Eviction
1564
+ * failures (permissions, races) are surfaced through `ZIDANE_DEBUG`
1565
+ * but never block the calling tool result; an over-cap dir is a
1566
+ * housekeeping concern, not a correctness one.
1567
+ */
1568
+ maxBytes?: number;
1569
+ }
1570
+ type PersistOutcome = {
1571
+ kind: 'skip';
1572
+ reason: 'disabled' | 'excluded' | 'under-threshold' | 'unsupported-shape' | 'unsafe-call-id' | 'invalid-persist-dir';
1573
+ } | {
1574
+ kind: 'persisted';
1575
+ output: string;
1576
+ originalBytes: number;
1577
+ persistedPath: string;
1578
+ evicted?: {
1579
+ files: number;
1580
+ bytes: number;
1581
+ };
1582
+ } | {
1583
+ kind: 'error';
1584
+ reason: 'write-failed';
1585
+ error: Error;
1586
+ };
1473
1587
  /**
1474
- * Append `extra` to the DYNAMIC half of a system prompt. Inserts the boundary
1475
- * marker if the input didn't already carry one.
1588
+ * Decide-and-persist for a single tool result. Pure decision + filesystem
1589
+ * side-effect; returns the new wire-level `output` string when substitution
1590
+ * happened, otherwise tells the caller to leave the result alone.
1476
1591
  *
1477
- * Used by hosts (typically the TUI) to inject per-turn state — current cwd,
1478
- * IDE selection, project root without forcing every caller to know the
1479
- * marker format. The host's `system:transform` hook rewrites the dynamic
1480
- * half each turn; the static doctrine above stays byte-stable and rides the
1481
- * cache.
1592
+ * Atomicity: writes go through `<path>.tmp` + `rename` so a concurrent
1593
+ * read (or a crash mid-write) never sees a half-written blob.
1482
1594
  *
1483
- * Returns a new string; the input is not mutated. When `extra` is empty,
1484
- * returns the input verbatim.
1595
+ * `ToolResultContent[]` results (images, structured blocks) currently bypass
1596
+ * persistence the inline image bytes are the point of the call, and a
1597
+ * mixed text/image array isn't representable as a single `.txt` file. We
1598
+ * may revisit if a tool starts returning very large text-only arrays.
1485
1599
  */
1486
- declare function appendDynamicSection(system: string, extra: string): string;
1600
+ declare function maybePersistToolResult(input: PersistInput): Promise<PersistOutcome>;
1601
+ interface BuildStubInput {
1602
+ toolName: string;
1603
+ originalBytes: number;
1604
+ persistedPath: string;
1605
+ output: string;
1606
+ }
1487
1607
  /**
1488
- * Replace the entire dynamic half of a system prompt with `next`. Used by
1489
- * the TUI's `<env>` rewriter where the entire dynamic section is regenerated
1490
- * each turn rather than appended to.
1608
+ * Render the byte-stable `<persisted-output>` stub the model sees in place
1609
+ * of the original `tool_result`.
1491
1610
  *
1492
- * When `next` is empty, drops the dynamic half (and the marker) entirely.
1611
+ * Format choices:
1612
+ * - XML wrapper because models reliably parse it as structural.
1613
+ * - Byte count + path in attributes so the model can decide whether to
1614
+ * `read_file` the persisted blob without scanning the preview.
1615
+ * - Preview always shows the head — `shell`'s tail-priority truncation is
1616
+ * irrelevant here because the model has the full path if it needs the
1617
+ * tail.
1618
+ * - No timestamps, no random UUIDs inside the stub: every byte must be
1619
+ * reproducible from the inputs, otherwise re-emission on subsequent
1620
+ * turns would bust the prompt cache.
1621
+ *
1622
+ * Exported for tests (asserting the byte-stable contract) and for SDK
1623
+ * consumers wiring their own persistence middleware against the same
1624
+ * surface.
1493
1625
  */
1494
- declare function replaceDynamicSection(system: string, next: string): string;
1626
+ declare function buildPersistedStub(input: BuildStubInput): string;
1495
1627
  /**
1496
- * Strip the boundary marker so it never reaches the wire collapses
1497
- * `<static>${BOUNDARY}<dynamic>` into `<static>\n\n<dynamic>` for providers
1498
- * that can't honor `cache_control` (vanilla OpenAI Chat Completions, Codex,
1499
- * Cerebras, ...) or for the cache-disabled path on any provider.
1500
- *
1501
- * Cache-aware providers re-derive the split from the original (un-rendered)
1502
- * system string via `splitSystemPrompt` — `renderSystemForWire` is the
1503
- * marker-free counterpart used to build the actual wire bytes.
1628
+ * Remove every persisted blob belonging to a session. Called by the chat
1629
+ * layer from its session-delete path so closing a session frees the disk
1630
+ * footprint alongside the SQLite row.
1504
1631
  *
1505
- * No-op when the input has no marker. Pure / no I/O.
1632
+ * Idempotent missing directory (session never persisted anything) is a
1633
+ * no-op, not an error. Wraps the `rm -rf` so a permissions blip on one
1634
+ * blob doesn't propagate to the caller; the chat layer can't usefully
1635
+ * recover from "couldn't unlink a result file" mid-delete.
1506
1636
  */
1507
- declare function renderSystemForWire(system: string): string;
1508
- /** True when `system` contains the boundary marker. */
1509
- declare function hasSystemPromptBoundary(system: string): boolean;
1637
+ declare function cleanupPersistedSession(persistRoot: string): Promise<void>;
1510
1638
  //#endregion
1511
- //#region src/tools/edit.d.ts
1639
+ //#region src/mcp/oauth-provider.d.ts
1512
1640
  /**
1513
- * Surgical edit replace `old_string` with `new_string` in a single file.
1514
- *
1515
- * Mirrors Claude Code's `Edit` semantics so models post-trained on Anthropic's
1516
- * tool surface need no relearning. Fails clearly when `old_string` isn't unique
1517
- * (unless `replace_all: true`) and when not found, with a nearest-match preview
1518
- * so the model can recover without a separate `read_file` round-trip.
1641
+ * Per-server persisted state. Subfields are optional so a partial save
1642
+ * (e.g. `saveCodeVerifier` arriving before `saveTokens`) doesn't blow away
1643
+ * earlier subfields the provider always patches, never replaces.
1519
1644
  */
1520
- declare const edit: ToolDef;
1521
- //#endregion
1522
- //#region src/tools/glob.d.ts
1523
- declare const glob: ToolDef;
1524
- //#endregion
1525
- //#region src/tools/grep.d.ts
1526
- declare const grep: ToolDef;
1527
- //#endregion
1528
- //#region src/tools/interaction.d.ts
1529
- interface InteractionToolOptions {
1530
- /** JSON Schema for the request payload the model sends */
1531
- schema: Record<string, unknown>;
1532
- /** Tool name (default: 'interaction') */
1533
- name?: string;
1534
- /** Tool description shown to the model */
1535
- description?: string;
1536
- /** Called when the model invokes this tool. Receives the validated payload and tool context, returns data for the model. */
1537
- onRequest: (payload: Record<string, unknown>, ctx: ToolContext) => Promise<Record<string, unknown> | string>;
1645
+ interface McpCredentialEntry {
1646
+ tokens?: OAuthTokens;
1647
+ clientInformation?: OAuthClientInformationMixed;
1648
+ discoveryState?: OAuthDiscoveryState;
1649
+ }
1650
+ interface McpCredentialStore {
1651
+ load: (name: string) => McpCredentialEntry | undefined;
1652
+ save: (name: string, entry: McpCredentialEntry) => void;
1653
+ delete: (name: string) => void;
1654
+ }
1655
+ /**
1656
+ * In-memory store — primarily for tests, but valid as a no-persistence option
1657
+ * (tokens evaporate on process exit, the user re-auths every cold start).
1658
+ */
1659
+ declare function createMemoryMcpCredentialStore(seed?: Record<string, McpCredentialEntry>): McpCredentialStore;
1660
+ interface McpOAuthProviderOptions {
1661
+ /** Server name used as the storage key. */
1662
+ name: string;
1663
+ /** Persistence backend. */
1664
+ store: McpCredentialStore;
1665
+ /**
1666
+ * Loopback callback URI. Pass `undefined` for bootstrap (non-interactive
1667
+ * mode — stored tokens + refresh only, never opens a browser).
1668
+ */
1669
+ redirectUri?: string;
1670
+ /**
1671
+ * Invoked when the SDK wants the user agent to navigate to the authorization
1672
+ * URL. Typically the host opens the browser AND emits a hook so the TUI can
1673
+ * render the URL in a status row. No-op in non-interactive mode (the SDK
1674
+ * still calls this before throwing `UnauthorizedError` from connect).
1675
+ */
1676
+ onAuthorizationUrl?: (url: URL) => void | Promise<void>;
1677
+ /**
1678
+ * `client_name` used in dynamic client registration. Defaults to `'zidane'`.
1679
+ * Some servers display this string to the user on the consent screen.
1680
+ */
1681
+ clientName?: string;
1682
+ /**
1683
+ * Override the requested OAuth scope. Default: unset (the SDK negotiates
1684
+ * via the server's metadata).
1685
+ */
1686
+ scope?: string;
1687
+ }
1688
+ declare class McpOAuthProvider implements OAuthClientProvider {
1689
+ private readonly name;
1690
+ private readonly store;
1691
+ private readonly _redirectUri?;
1692
+ private readonly onAuthorizationUrl?;
1693
+ private readonly clientName;
1694
+ private readonly _scope?;
1695
+ private codeVerifierValue;
1696
+ constructor(opts: McpOAuthProviderOptions);
1697
+ get redirectUrl(): string | URL | undefined;
1698
+ get clientMetadata(): OAuthClientMetadata;
1699
+ tokens(): OAuthTokens | undefined;
1700
+ saveTokens(tokens: OAuthTokens): void;
1701
+ clientInformation(): OAuthClientInformationMixed | undefined;
1702
+ saveClientInformation(info: OAuthClientInformationMixed): void;
1703
+ discoveryState(): OAuthDiscoveryState | undefined;
1704
+ saveDiscoveryState(state: OAuthDiscoveryState): void;
1705
+ saveCodeVerifier(verifier: string): void;
1706
+ codeVerifier(): string;
1707
+ redirectToAuthorization(url: URL): Promise<void>;
1708
+ /**
1709
+ * Wipe stored credentials when the server reports the cached state is no
1710
+ * longer valid. The SDK calls this with a scope hint:
1711
+ * - `'tokens'` → access/refresh revoked, keep client registration
1712
+ * - `'client'` → client registration invalidated, reset everything
1713
+ * - `'verifier'`→ PKCE state stale (e.g. mismatched state param)
1714
+ * - `'discovery'` → discovery metadata stale (servers re-keyed)
1715
+ * - `'all'` → full reset
1716
+ */
1717
+ invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): Promise<void>;
1718
+ private patch;
1538
1719
  }
1539
1720
  /**
1540
- * Create an interaction tool that lets the agent request structured input.
1721
+ * True when an HTTP transport's auth headers already include an explicit
1722
+ * Authorization. Used by the bootstrap escape-hatch: a user who provided
1723
+ * their own bearer token shouldn't be auto-promoted to OAuth on a 401.
1541
1724
  *
1542
- * The model calls this tool with a payload matching the schema.
1543
- * `onRequest` is called with the payload and should return the response
1544
- * (string or object) that gets sent back to the model as the tool result.
1725
+ * Case-insensitive Node normalizes outgoing headers to lowercase but
1726
+ * users hand-write `Authorization` in configs.
1545
1727
  */
1546
- declare function createInteractionTool(options: InteractionToolOptions): ToolDef;
1547
- //#endregion
1548
- //#region src/tools/list-files.d.ts
1549
- declare const listFiles: ToolDef;
1550
- //#endregion
1551
- //#region src/tools/multi-edit.d.ts
1552
- declare const multiEdit: ToolDef;
1553
- //#endregion
1554
- //#region src/tools/read-file.d.ts
1555
- declare const readFile: ToolDef;
1728
+ declare function hasAuthorizationHeader(headers: Record<string, string> | undefined): boolean;
1556
1729
  //#endregion
1557
- //#region src/tools/shell.d.ts
1558
- interface CreateShellToolOptions {
1730
+ //#region src/mcp/login.d.ts
1731
+ interface LoginMcpServerOptions {
1732
+ /** Persistence — same store the bootstrap path reads from. */
1733
+ store: McpCredentialStore;
1559
1734
  /**
1560
- * Whether to expose the `run_in_background` flag in the input schema +
1561
- * the background-mode paragraphs in the description. When `false`, the
1562
- * model never sees the flag and won't try to use it. The execute path
1563
- * still has a defensive fallback: an explicit `run_in_background: true`
1564
- * call (e.g. from a hand-crafted message) returns a clean error rather
1565
- * than silently running foreground.
1566
- *
1567
- * Default: `true`.
1735
+ * Invoked with the authorization URL once it's ready. Hosts typically
1736
+ * (a) emit `mcp:auth:url` for the TUI, and (b) call `tryOpenBrowser`.
1737
+ * The URL is identical to the one passed to the `mcp:auth:url` hook
1738
+ * fired automatically this callback is a synchronous hook for callers
1739
+ * that don't want to wire the agent hook machinery.
1568
1740
  */
1569
- allowBackground?: boolean;
1741
+ onAuthorizationUrl?: (url: URL) => void | Promise<void>;
1742
+ /** Cancels the flow (esc / close modal / SIGINT). */
1743
+ signal?: AbortSignal;
1744
+ /** Agent hooks. The flow emits `mcp:auth:url`/`success`/`error` when wired. */
1745
+ hooks?: Hookable<AgentHooks>;
1746
+ /** Override `client_name` shown on consent screens. Default: 'zidane'. */
1747
+ clientName?: string;
1748
+ /** Override the requested OAuth scope. */
1749
+ scope?: string;
1570
1750
  /**
1571
- * Canonical names of tools registered alongside `shell` on the same
1572
- * agent. When non-empty, the description gains a "prefer the dedicated
1573
- * tool" block for each known sibling (`read_file`, `glob`, `grep`,
1574
- * `list_files`, `edit`, `write_file`) — useful against the
1575
- * `ls`/`cat`-to-re-verify loop some models fall into when both a
1576
- * dedicated tool AND `shell` are visible. Unknown / unrecognized names
1577
- * are ignored.
1578
- *
1579
- * Set by `createAgent` per-run from the tool registry; hosts that
1580
- * construct a `shell` directly can pass it explicitly. Omit to suppress
1581
- * the block entirely (no nudge for shell-only agents, no nudge for
1582
- * hosts that prefer to author their own anti-loop prose).
1751
+ * Override the loopback callback path. Default: `/callback`. Useful only
1752
+ * for servers that pinned a different path during registration.
1583
1753
  */
1584
- registeredCanonicals?: ReadonlySet<string>;
1754
+ callbackPath?: string;
1585
1755
  /**
1586
- * The agent's `toolAliases` map, used to render the wire-level name of
1587
- * each sibling in the swap block. Without this, the block always prints
1588
- * canonical names — fine for the default preset, wrong for hosts that
1589
- * alias-rename (the model would be told to call a name it doesn't see
1590
- * in the tool spec).
1756
+ * Maximum time to wait for the user to complete the browser flow, in ms.
1757
+ * The user can also cancel via `signal`. Default: 5 minutes.
1591
1758
  */
1592
- toolAliases?: Record<string, string>;
1759
+ timeoutMs?: number;
1760
+ }
1761
+ interface LoginMcpServerResult {
1762
+ /** Stored OAuth tokens after a successful exchange. */
1763
+ tokens: NonNullable<ReturnType<McpOAuthProvider['tokens']>>;
1764
+ /**
1765
+ * Upstream tool descriptors discovered after re-connecting with the new
1766
+ * tokens. Already filtered by the server's `enabledTools` / `disabledTools`
1767
+ * is NOT applied here — that's a bootstrap concern. Hosts that want filtering
1768
+ * should pass the result through `connectMcpServers` rebuild on the next
1769
+ * session activation rather than reusing this list verbatim.
1770
+ */
1771
+ tools: Array<{
1772
+ name: string;
1773
+ description?: string | null;
1774
+ inputSchema?: unknown;
1775
+ }>;
1593
1776
  }
1594
1777
  /**
1595
- * Factory for the `shell` tool. The default exported `shell` is
1596
- * equivalent to `createShellTool({ allowBackground: true })`. The
1597
- * factory is the entry point hosts use when they want to override the
1598
- * default — e.g. to ship a preset that always disables background mode
1599
- * regardless of `behavior.tasksDir`.
1778
+ * Run the full interactive OAuth flow for `config`. Only supports `sse` and
1779
+ * `streamable-http` transports `stdio` MCP servers don't speak OAuth.
1600
1780
  *
1601
- * Hosts that use the framework's `createAgent` typically don't need to
1602
- * call this directly: when `behavior.tasksDir` is unset or
1603
- * `behavior.disableBackgroundTasks: true` is set, the agent
1604
- * automatically rewrites the registered `shell` (if it's the
1605
- * framework's built-in) using this factory.
1606
- */
1607
- declare function createShellTool(opts?: CreateShellToolOptions): ToolDef;
1608
- /**
1609
- * Default `shell` tool with background mode enabled.
1781
+ * Throws on:
1782
+ * - Wrong transport.
1783
+ * - Abort signal.
1784
+ * - Browser-side error (user denied, server rejected, etc.).
1785
+ * - Code exchange failure.
1786
+ * - Post-exchange connect failure.
1610
1787
  *
1611
- * Most hosts use this directly via `basicTools`. When the agent's
1612
- * `behavior.tasksDir` is unset OR `behavior.disableBackgroundTasks:
1613
- * true` is set, `createAgent` auto-rewrites this identity to a
1614
- * `createShellTool({ allowBackground: false })` variant so the model
1615
- * never sees a flag it can't use. Hosts who want to bypass that
1616
- * auto-rewrite can register a `createShellTool({ allowBackground })`
1617
- * directly — the rewrite only fires on identity-equal references to
1618
- * this constant.
1788
+ * Always closes the loopback callback server before returning, success or
1789
+ * failure.
1619
1790
  */
1620
- declare const shell: ToolDef;
1621
- //#endregion
1622
- //#region src/tools/shell-kill.d.ts
1623
- declare const shellKill: ToolDef;
1624
- //#endregion
1625
- //#region src/tools/skills-read.d.ts
1626
- interface SkillsReadToolOptions {
1627
- catalog: readonly SkillConfig[];
1628
- state: SkillActivationState;
1629
- }
1630
- declare function createSkillsReadTool(options: SkillsReadToolOptions): ToolDef;
1631
- //#endregion
1632
- //#region src/tools/skills-run-script.d.ts
1633
- interface SkillsRunScriptToolOptions {
1634
- catalog: readonly SkillConfig[];
1635
- state: SkillActivationState;
1636
- /** Script timeout in milliseconds. Default 60000. */
1637
- scriptTimeoutMs?: number;
1638
- }
1639
- declare function createSkillsRunScriptTool(options: SkillsRunScriptToolOptions): ToolDef;
1791
+ declare function loginMcpServer(config: McpServerConfig, options: LoginMcpServerOptions): Promise<LoginMcpServerResult>;
1640
1792
  //#endregion
1641
- //#region src/tools/skills-use.d.ts
1642
- interface SkillsUseToolOptions {
1643
- /** Resolved skills catalog for this run. */
1644
- catalog: readonly SkillConfig[];
1645
- /** Per-agent activation state the tool mutates. */
1646
- state: SkillActivationState;
1647
- /** Agent hooks — used to fire `skills:activate` on first activation. */
1648
- hooks: Hookable<AgentHooks>;
1649
- }
1793
+ //#region src/mcp/oauth-callback.d.ts
1650
1794
  /**
1651
- * Factory for `skills_use`. Auto-injected into the agent's tool set by the
1652
- * agent runtime when a non-empty skills catalog is available (unless
1653
- * `SkillsConfig.tool === false`).
1795
+ * Local loopback HTTP callback for OAuth 2.0 authorization code flows.
1654
1796
  *
1655
- * The tool schema's `name` property is `enum`-constrained to the resolved
1656
- * catalog so the LLM cannot hallucinate a skill that doesn't exist.
1797
+ * Stands up a one-shot server on `127.0.0.1:<random>` that captures the
1798
+ * `?code=...` redirect from a browser-driven OAuth flow and resolves a
1799
+ * promise with the code. Used as the `redirectUrl` half of the MCP SDK's
1800
+ * `OAuthClientProvider` (the persistence half lives separately).
1801
+ *
1802
+ * Design:
1803
+ * - Loopback-only (`127.0.0.1`) — the OAuth spec treats `http://127.0.0.1:<port>`
1804
+ * as a public-client redirect URI per RFC 8252 §7.3. Browsers do NOT block it,
1805
+ * and Anthropic / OpenAI / Linear / GitHub all accept it.
1806
+ * - Random port (`port = 0`) — the OS picks an unused one. We read the actual
1807
+ * port back from `server.address()` after `listen()`.
1808
+ * - Single-shot — the first GET to `path` with a `code` (or `error`) wins;
1809
+ * subsequent requests get 404. The server keeps listening (in case the user
1810
+ * hits "back" and re-authorizes), so callers must `close()` once they have
1811
+ * the code or have given up.
1812
+ * - Abort-aware — wiring an external `AbortSignal` rejects the promise and
1813
+ * closes the server immediately. Required for the TUI's "esc cancels login"
1814
+ * UX.
1815
+ * - No HTML framework — a single inline `<html>` string keeps this isolated
1816
+ * from any UI dependency.
1657
1817
  */
1658
- declare function createSkillsUseTool(options: SkillsUseToolOptions): ToolDef;
1659
- //#endregion
1660
- //#region src/tools/spawn.d.ts
1661
- interface ChildAgent {
1662
- id: string;
1663
- task: string;
1664
- startedAt: number;
1665
- /** Subagent depth — 1 for a direct child of a top-level agent. */
1666
- depth: number;
1818
+ /**
1819
+ * Result of a successful callback. `state` is forwarded verbatim from the
1820
+ * query string — callers verify it against their pre-flight value to defend
1821
+ * against CSRF (the MCP SDK does this internally when it controls `state`).
1822
+ */
1823
+ interface OAuthCallbackResult {
1824
+ code: string;
1825
+ state?: string;
1667
1826
  }
1668
- interface SpawnToolState {
1669
- /** Currently running children. */
1670
- readonly children: ReadonlyMap<string, ChildAgent>;
1827
+ interface OAuthCallbackHandle {
1828
+ /**
1829
+ * Full URI to register with the authorization server, e.g.
1830
+ * `http://127.0.0.1:51823/callback`. Stable for the lifetime of the
1831
+ * handle.
1832
+ */
1833
+ redirectUri: string;
1671
1834
  /**
1672
- * Cumulative stats across every completed direct child of this spawn-tool
1673
- * instance (returns a copy). Each child's contribution is the cumulative
1674
- * `AgentStats` returned by its `agent.run()` — so
1675
- * `totalIn`/`totalOut`/`totalCacheRead`/`totalCacheCreation` cover the
1676
- * entire subtree (children + grandchildren + …), while `turns` and
1677
- * `elapsed` stay parent-loop-only per child and are summed across direct
1678
- * children. `elapsed` over-counts when children ran in parallel.
1835
+ * Resolves with `{ code, state }` on a successful callback. Rejects with:
1836
+ * - The OAuth-spec `error` field (`access_denied`, `server_error`, ...)
1837
+ * when the authorization server redirects with `?error=...`.
1838
+ * - `'OAuth callback aborted'` when the external `AbortSignal` fires.
1839
+ * - `'OAuth callback server closed'` when `close()` is called before any
1840
+ * callback arrives.
1679
1841
  *
1680
- * Lives across multiple parent runs that share this instance.
1842
+ * Single-shot only the first matching request resolves the promise.
1681
1843
  */
1682
- readonly totalChildStats: Readonly<AgentStats>;
1844
+ promise: Promise<OAuthCallbackResult>;
1845
+ /**
1846
+ * Idempotent shutdown. Safe to call from a `finally` block whether the
1847
+ * flow succeeded, failed, or was aborted. Resolves once the server stops
1848
+ * accepting connections.
1849
+ */
1850
+ close: () => Promise<void>;
1683
1851
  }
1684
- interface SpawnToolOptions {
1685
- /** Maximum concurrent sub-agents (default: 3). */
1686
- maxConcurrent?: number;
1852
+ interface OAuthCallbackOptions {
1853
+ /** Cancels the flow rejects `promise` and closes the server. */
1854
+ signal?: AbortSignal;
1687
1855
  /**
1688
- * Maximum subagent depth. 0 disables spawning entirely; 1 allows top-level
1689
- * spawns but forbids grandchildren; 3 (default) allows three levels of
1690
- * recursion — enough for most orchestration patterns, a sharp ceiling
1691
- * against runaway loops.
1856
+ * Path component the authorization server should redirect to. Defaults
1857
+ * to `/callback`. Useful when matching a pre-registered URI that uses a
1858
+ * different path.
1692
1859
  */
1693
- maxDepth?: number;
1694
- /** Child model override. */
1695
- model?: string;
1696
- /** Child system prompt override. Per-spawn `input.system` takes precedence. */
1697
- system?: string;
1698
- /** Child thinking level. */
1699
- thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high';
1700
- /** Preset override for children. Shallow-merged over the parent's preset (parent fields still win for anything left unset). */
1701
- preset?: Preset;
1860
+ path?: string;
1702
1861
  /**
1703
- * Per-child timeout, in milliseconds. When the child exceeds it the spawn
1704
- * tool returns a timeout marker, fires `spawn:error`, and destroys the
1705
- * child agent. Default: none.
1862
+ * Override the loopback host. Defaults to `127.0.0.1`. Don't bind to
1863
+ * `0.0.0.0` here the OAuth code is a one-time secret and the server
1864
+ * would otherwise accept it from any host on the LAN.
1706
1865
  */
1707
- timeoutMs?: number;
1866
+ host?: string;
1708
1867
  /**
1709
- * When `true` and the parent has a session, the child reuses the parent's
1710
- * session child turns are appended with the child's own `runId`, and the
1711
- * resulting `SessionRun` carries `parentRunId` so the tree is
1712
- * reconstructible. Default: `false` (child is in-memory only).
1713
- *
1714
- * **Read-state isolation.** Sharing the session also shares the
1715
- * `read_file` / `requireReadBeforeEdit` tracking map (it's keyed
1716
- * by `Session`). With `persist: false` the child gets no session,
1717
- * so reads inside the subagent populate nothing the parent can see —
1718
- * a follow-up `edit` / `multi_edit` in the parent will trip the
1719
- * gate with `"has not been read"` even though the model just
1720
- * read the file in the child. Use {@link shareReadState} when
1721
- * you want the parent's gate to honor the child's reads WITHOUT
1722
- * also persisting child turns to the parent's session.
1868
+ * Override the port. Defaults to `0` (OS-assigned). Pin to a fixed port
1869
+ * only when the authorization server requires a pre-registered redirect
1870
+ * URI; the random-port path is preferred so concurrent flows don't clash.
1723
1871
  */
1724
- persist?: boolean;
1872
+ port?: number;
1873
+ }
1874
+ /**
1875
+ * Start a one-shot OAuth callback server. The returned handle's `redirectUri`
1876
+ * should be passed to the authorization server as the `redirect_uri` query
1877
+ * parameter; `promise` resolves once the user finishes the browser flow.
1878
+ *
1879
+ * Always `await handle.close()` in a `finally` block — even on success, the
1880
+ * server stays open until told to shut down (so it can serve the
1881
+ * "you can close this tab" page).
1882
+ */
1883
+ declare function startOAuthCallback(opts?: OAuthCallbackOptions): Promise<OAuthCallbackHandle>;
1884
+ //#endregion
1885
+ //#region src/metrics.d.ts
1886
+ type MetricAttributes = Record<string, string | number | boolean | undefined>;
1887
+ interface Counter {
1888
+ add: (value: number, attributes?: MetricAttributes) => void;
1889
+ }
1890
+ interface Histogram {
1891
+ record: (value: number, attributes?: MetricAttributes) => void;
1892
+ }
1893
+ interface UpDownCounter {
1894
+ add: (value: number, attributes?: MetricAttributes) => void;
1895
+ }
1896
+ interface InstrumentOptions {
1897
+ description?: string;
1898
+ unit?: string;
1899
+ }
1900
+ /**
1901
+ * Minimal Meter interface — structurally identical to OTel's `Meter`.
1902
+ * Hosts passing `metrics.getMeter(name)` (from `@opentelemetry/api`)
1903
+ * satisfy this without adaptation.
1904
+ */
1905
+ interface Meter {
1906
+ createCounter: (name: string, options?: InstrumentOptions) => Counter;
1907
+ createHistogram: (name: string, options?: InstrumentOptions) => Histogram;
1908
+ createUpDownCounter: (name: string, options?: InstrumentOptions) => UpDownCounter;
1909
+ }
1910
+ interface MetricsHooksOptions {
1911
+ meter: Meter;
1725
1912
  /**
1726
- * Forward the parent's read-state map to the child agent so the
1727
- * `requireReadBeforeEdit` gate and `dedupReads` cache see reads
1728
- * across the parent/child boundary. Orthogonal to {@link persist}
1729
- * use this when you want shared read tracking without sharing the
1730
- * session's turn history. Default: `false`.
1731
- *
1732
- * Has no effect when the parent has no read-state to share (no
1733
- * session and no explicit `readState` on the parent agent's
1734
- * options). Implementation: passes the parent's resolved
1735
- * `ReadStateMap` to the child via `AgentOptions.readState`, which
1736
- * tools resolve via `ctx.readState ?? getReadState(ctx.session)`.
1913
+ * Optional prefix prepended to every instrument name. Default: no prefix
1914
+ * (instrument names follow OTel Gen AI semantic conventions verbatim,
1915
+ * which is the most-portable shape). Set to e.g. `'zidane.'` to
1916
+ * namespace inside a shared meter registry.
1737
1917
  */
1738
- shareReadState?: boolean;
1918
+ namespace?: string;
1739
1919
  /**
1740
- * Forward a curated subset of child hook events (`stream:*`, `tool:*`,
1741
- * `turn:after`) onto the parent's hook bus as `child:*` events. Default:
1742
- * `true`. Grandchildren bubble through their child transparently.
1920
+ * Optional baseline attributes applied to every measurement. Typical
1921
+ * use: `{ service: 'tui', env: 'prod' }`. Per-event attributes win on
1922
+ * key collision.
1743
1923
  */
1744
- forwardHooks?: boolean;
1745
- /** Called when a child agent starts. */
1746
- onSpawn?: (child: ChildAgent) => void;
1747
- /** Called when a child agent completes (success, abort, timeout, or error). */
1748
- onComplete?: (child: ChildAgent, stats: AgentStats, status: NonNullable<ChildRunStats['status']>) => void;
1924
+ baseAttributes?: MetricAttributes;
1749
1925
  /**
1750
- * Named subagent presets the model can select via the `subagent_type`
1751
- * input field. Mirrors the Claude Code SDK's surface models trained
1752
- * on it routinely emit `subagent_type: 'Explore' | 'Plan' |
1753
- * 'Verification' | 'general-purpose'`, and without a registry the
1754
- * field is silently dropped, so hosts wanting type-specialized
1755
- * subagents have to invent their own dispatch layer.
1756
- *
1757
- * Each entry overlays the base spawn config for that particular
1758
- * dispatch. Per-call `input.system` still wins over `subagents[type].system`
1759
- * so the model can always specialize further.
1760
- *
1761
- * When the registry is non-empty:
1762
- * - `subagent_type` appears in the spawn input schema as a `string`
1763
- * enum of the registered keys (plus the always-available
1764
- * `'general-purpose'` fallback).
1765
- * - Models that pass an unregistered type are routed to
1766
- * `'general-purpose'` (no error — degrade gracefully so trained
1767
- * models keep working even on hosts that haven't wired every
1768
- * type Claude Code uses).
1769
- *
1770
- * When the registry is empty / unset, the field is omitted entirely
1771
- * (preserves the historical schema for hosts that never use this).
1772
- *
1773
- * Default: `undefined` (no subagent types; `subagent_type` schema
1774
- * field hidden).
1926
+ * Error sink for meter failures. The helper still swallows the throw
1927
+ * so a broken backend can't crash a run; this callback surfaces the
1928
+ * failure for ops dashboards.
1775
1929
  */
1776
- subagents?: SubagentRegistry;
1930
+ onError?: (kind: string, err: unknown) => void;
1931
+ }
1932
+ interface MetricsHookSet {
1933
+ install: (hooks: Hookable<AgentHooks>) => () => void;
1934
+ }
1935
+ /**
1936
+ * Build a set of metrics hook handlers that can be installed on an agent.
1937
+ *
1938
+ * @example OpenTelemetry
1939
+ * ```ts
1940
+ * import { metrics } from '@opentelemetry/api'
1941
+ * const meter = metrics.getMeter('zidane')
1942
+ * const m = createMetricsHooks({ meter, baseAttributes: { service: 'tui' } })
1943
+ * const uninstall = m.install(agent.hooks)
1944
+ * try { await agent.run({ prompt }) }
1945
+ * finally { uninstall() }
1946
+ * ```
1947
+ */
1948
+ declare function createMetricsHooks(options: MetricsHooksOptions): MetricsHookSet;
1949
+ //#endregion
1950
+ //#region src/stats.d.ts
1951
+ /**
1952
+ * Per-model usage rollup produced by {@link statsByModel}.
1953
+ *
1954
+ * `turns` counts the number of `TurnUsage` entries attributed to the model
1955
+ * across the whole tree (parent loop + every recursively-spawned child).
1956
+ * Cache and cost numbers are summed from the same set of turns.
1957
+ */
1958
+ interface ModelUsage {
1959
+ input: number;
1960
+ output: number;
1961
+ cost: number;
1962
+ cacheRead: number;
1963
+ cacheCreation: number;
1964
+ turns: number;
1777
1965
  }
1778
1966
  /**
1779
- * Per-type subagent override applied when the model calls
1780
- * `spawn({ subagent_type: '…' })`. All fields are optional; absent
1781
- * fields fall back to the parent's resolved configuration (see
1782
- * {@link SpawnToolOptions} comments for the merge order).
1967
+ * Depth-first walk over the stats tree, returning every `TurnUsage` entry
1968
+ * parent loop first, then each child subtree in completion order.
1969
+ *
1970
+ * Closes the cache-token aggregation gap: `TurnUsage.cacheRead` /
1971
+ * `cacheCreation` live only on per-turn entries, and the top-level
1972
+ * `AgentStats` deliberately doesn't carry cumulative forms (one source of
1973
+ * truth, no risk of drift). Anything that needs a tree-wide sum walks
1974
+ * through this.
1975
+ */
1976
+ declare function flattenTurns(stats: AgentStats): TurnUsage[];
1977
+ /**
1978
+ * Group cumulative usage by `TurnUsage.modelId`. Each entry sums the input,
1979
+ * output, cache, cost, and turn-count across every turn the tree attributed
1980
+ * to that model — naturally handling cross-model runs (vision-fallback,
1981
+ * model-shifted subagents, mixed-provider workflows).
1982
+ *
1983
+ * Turns missing `modelId` (mock providers, providers that don't echo a model
1984
+ * id) are bucketed under the literal string `'(unknown)'`.
1985
+ */
1986
+ declare function statsByModel(stats: AgentStats): Map<string, ModelUsage>;
1987
+ //#endregion
1988
+ //#region src/system-prompt.d.ts
1989
+ /**
1990
+ * System-prompt boundary marker — splits a system prompt into a stable static
1991
+ * prefix (cached) and a per-turn dynamic suffix (NOT cached).
1992
+ *
1993
+ * Why this exists: providers attach `cache_control` markers on the last block
1994
+ * of the system prompt, so the cached prefix covers the entire system text.
1995
+ * Any byte change anywhere — including a per-turn `<env>` rewrite — busts the
1996
+ * cache for the doctrine that sits below. A literal marker in the system
1997
+ * string lets providers split it into:
1998
+ *
1999
+ * ┌──────────────┐ cache_control: ephemeral
2000
+ * │ STATIC half │ — doctrine, skills catalog, tool catalog,
2001
+ * │ │ user instructions
2002
+ * ├──────────────┤ ← SYSTEM_PROMPT_BOUNDARY
2003
+ * │ DYNAMIC half │ — env, cwd, mtimes, anything per-turn
2004
+ * └──────────────┘ (no cache_control)
2005
+ *
2006
+ * The static prefix rides the prompt cache across turns/sessions; the dynamic
2007
+ * suffix re-bills per turn. Net effect: a cwd change between turns no longer
2008
+ * invalidates 4 KB of doctrine.
2009
+ *
2010
+ * Wire contract:
2011
+ *
2012
+ * - `splitSystemPrompt(s)` is pure; missing marker ⇒ entire string is static
2013
+ * (current behavior — no caller is forced to opt in).
2014
+ * - `renderSystemForWire(s)` strips the marker so it never reaches the model;
2015
+ * used by every provider before the bytes hit the wire, including the
2016
+ * cache-disabled path on providers that DO support `cache_control`.
2017
+ * - The marker uses underscores rather than XML/punctuation so it's
2018
+ * unambiguous when scanning prompts manually and unlikely to collide with
2019
+ * model-written content.
2020
+ * - Providers handle the split internally (Anthropic emits a 2-block array;
2021
+ * OpenAI-compat splits the leading `system` message into multi-part text).
2022
+ * Callers always pass a single `string` — no API break.
2023
+ */
2024
+ /**
2025
+ * Literal marker inserted in a system prompt to separate cacheable doctrine
2026
+ * from per-turn dynamic content. Providers split on this token.
2027
+ *
2028
+ * Underscored on both sides for visual distinctiveness — a stray instance in
2029
+ * model-written prose is implausible. Don't change the value without shipping
2030
+ * a migration; existing sessions carry the old marker in their cached
2031
+ * prompts.
1783
2032
  */
1784
- interface SubagentDef {
1785
- /**
1786
- * System prompt override for this subagent type. Per-call
1787
- * `input.system` still wins model-supplied specialization beats
1788
- * preset defaults.
1789
- */
1790
- system?: string;
1791
- /**
1792
- * Restrict the child agent's tool registry to this list of canonical
1793
- * tool names. Operates as a filter over the parent's tools (the
1794
- * parent's selection is the upper bound — a subagent can never gain
1795
- * tools the parent doesn't have). When unset, the child inherits the
1796
- * parent's full tool list.
1797
- *
1798
- * Tool names are canonical (registry-key) not wire/alias names — the
1799
- * filter runs before aliases are applied. Names that don't match a
1800
- * parent tool are silently dropped (matches the lenient behaviour of
1801
- * `enabledTools` on MCP configs).
1802
- */
1803
- tools?: readonly string[];
1804
- /**
1805
- * Mark this subagent as read-only — equivalent to listing only
1806
- * obviously-non-mutating tools (`read_file`, `grep`, `glob`,
1807
- * `list_files`) in {@link SubagentDef.tools}. Convenience for the
1808
- * common "Plan" / "Explore" subagent shape Claude Code ships.
1809
- *
1810
- * When both `readonly: true` and `tools` are set, `tools` wins
1811
- * (explicit beats implicit).
1812
- */
1813
- readonly?: boolean;
1814
- /**
1815
- * Short description rendered into the spawn tool's schema (the
1816
- * `subagent_type` field's description) so the model can pick a type
1817
- * that matches the task without round-tripping through docs.
1818
- */
1819
- description?: string;
2033
+ declare const SYSTEM_PROMPT_BOUNDARY = "__ZIDANE_SYSTEM_PROMPT_BOUNDARY__";
2034
+ /** Result of {@link splitSystemPrompt} — both halves stripped of the marker. */
2035
+ interface SystemPromptParts {
2036
+ /** Bytes BEFORE the marker (or the entire string when no marker present). Cacheable. */
2037
+ static: string;
2038
+ /** Bytes AFTER the marker. Empty when no marker present. NOT cached. */
2039
+ dynamic: string;
1820
2040
  }
1821
2041
  /**
1822
- * Map of subagent-type key preset. Keys are case-sensitive and
1823
- * appear verbatim in the spawn input schema's enum so the model emits
1824
- * them with the same casing. Common conventions: `'Explore'`,
1825
- * `'Plan'`, `'Verification'`, `'general-purpose'` (Claude Code SDK's
1826
- * built-in set).
2042
+ * Split a system prompt around the first {@link SYSTEM_PROMPT_BOUNDARY}.
2043
+ *
2044
+ * Splits on the FIRST occurrence subsequent markers are folded into the
2045
+ * dynamic half. This way callers can append additional `<env>` style blocks
2046
+ * with extra markers without each one creating a new cache layer (Anthropic
2047
+ * caps breakpoints; we use the budget elsewhere). The marker itself is
2048
+ * stripped from both sides — providers attach `cache_control` directly to
2049
+ * the static half's text content.
2050
+ *
2051
+ * A single blank line (`\n\n`) immediately adjacent to the marker on each
2052
+ * side is trimmed — callers conventionally write
2053
+ * `<doctrine>\n\n<MARKER>\n\n<env>` and expect the rendered wire bytes to
2054
+ * read as one logical paragraph. Blank lines beyond that immediate pair
2055
+ * (e.g. `\n\n\n<env>`) are preserved verbatim so callers composing their
2056
+ * own spacing don't lose intentional gaps.
2057
+ *
2058
+ * Pure / no I/O / no allocation when the marker is absent (returns the input
2059
+ * verbatim on the static side and the empty string on the dynamic side).
1827
2060
  */
1828
- type SubagentRegistry = Record<string, SubagentDef>;
2061
+ declare function splitSystemPrompt(system: string): SystemPromptParts;
1829
2062
  /**
1830
- * Create a configured spawn tool.
2063
+ * Compose a system prompt from a static prefix and an optional dynamic
2064
+ * suffix. Inserts {@link SYSTEM_PROMPT_BOUNDARY} between them only when the
2065
+ * dynamic side is non-empty — single-block prompts stay marker-free, so
2066
+ * callers that never opt in pay zero overhead and providers fall back to the
2067
+ * existing whole-string caching path.
1831
2068
  *
1832
- * State (`children`, `totalChildStats`, counters, active count) is scoped to
1833
- * the returned instance. Multiple parent agents using the same instance will
1834
- * share counters + stats + concurrency slots — call `createSpawnTool()` per
1835
- * agent (or use the stateless default `spawn`) to keep them isolated.
2069
+ * Spacing is `\n\n` on both sides of the marker so doctrine fragments,
2070
+ * which conventionally separate sections with a blank line, read cleanly
2071
+ * around the boundary.
1836
2072
  */
1837
- declare function createSpawnTool(options?: SpawnToolOptions): ToolDef & SpawnToolState;
1838
- //#endregion
1839
- //#region src/tools/tool-search.d.ts
1840
- interface LazyToolEntry {
1841
- /**
1842
- * Wire name (after `toolAliases` rewrite). What the model sees in the
1843
- * catalog, what `tool_search` matches against, and what the provider's
1844
- * tool list will carry once the entry is unlocked.
1845
- */
1846
- name: string;
1847
- /**
1848
- * Canonical (registry-key) name used for unlock-set membership and for the
1849
- * loop's `ctx.tools[name]` dispatch lookup. Equal to `name` when no alias
1850
- * is configured for this tool.
1851
- */
1852
- canonicalName: string;
1853
- description: string;
1854
- inputSchema: Record<string, unknown>;
1855
- /** Source MCP server, when applicable. Used for `server`-bulk unlock. */
1856
- server?: string;
1857
- }
1858
- interface ToolSearchToolOptions {
1859
- /**
1860
- * Snapshot of every lazy tool the model can discover. Built once per run by
1861
- * the agent — the tool closes over this array and never mutates it.
1862
- */
1863
- catalog: readonly LazyToolEntry[];
1864
- /**
1865
- * Mutable per-run set of unlocked **canonical** tool names. The tool adds
1866
- * matches in place; the loop reads the set when rebuilding the wire-level
1867
- * tool list. Keyed by canonical (not wire) so dispatch lookups stay
1868
- * alias-stable.
1869
- *
1870
- * Prefer `addUnlock` for cache-stable wire-tool ordering: writes through a
1871
- * Set lose unlock order, so the wire-level rebuild that filters by `unlocked`
1872
- * has to fall back to registry iteration order — which moves entries every
1873
- * time a lazy tool earlier in the registry is unlocked, breaking provider
1874
- * prompt-cache breakpoints. The agent passes both when it owns the unlock
1875
- * tracker, with `addUnlock` mirroring writes into an ordered log.
1876
- */
1877
- unlocked: Set<string>;
1878
- /**
1879
- * Optional callback fired for every canonical name the tool unlocks. When
1880
- * set, the agent uses this to maintain an append-only `dynamicUnlockOrder`
1881
- * so the wire-level tool list emits new unlocks at the tail and keeps the
1882
- * provider prefix cache warm. Idempotent on repeat unlocks of the same
1883
- * name — callers may dedupe internally.
1884
- *
1885
- * Invoked **in addition to** the `unlocked.add` (which still happens for
1886
- * back-compat with callers that only watch the Set).
1887
- */
1888
- addUnlock?: (canonical: string) => void;
1889
- /** Default cap on returned matches when the model omits `limit`. */
1890
- defaultLimit?: number;
1891
- }
2073
+ declare function joinSystemPrompt(staticPart: string, dynamicPart: string): string;
1892
2074
  /**
1893
- * Factory for `tool_search`. Auto-injected by the agent when
1894
- * `behavior.toolDisclosure === 'lazy'` and at least one MCP tool is in the
1895
- * registry. Opt out via `behavior.toolSearch.tool === false`.
2075
+ * Append `extra` to the STATIC half of a system prompt, preserving any
2076
+ * existing dynamic suffix.
2077
+ *
2078
+ * Used by the agent to fold in run-stable content (skills catalog, lazy tool
2079
+ * catalog) without bumping it into the dynamic half — both catalogs are
2080
+ * built once per run and remain byte-stable for the duration, so they
2081
+ * belong in the cached prefix.
2082
+ *
2083
+ * Returns a new string; the input is not mutated. When `extra` is empty,
2084
+ * returns the input verbatim.
1896
2085
  */
1897
- declare function createToolSearchTool(options: ToolSearchToolOptions): ToolDef;
1898
- //#endregion
1899
- //#region src/tools/validation.d.ts
2086
+ declare function appendStaticSection(system: string, extra: string): string;
1900
2087
  /**
1901
- * Tool argument validation against JSON Schema-style inputSchema.
2088
+ * Append `extra` to the DYNAMIC half of a system prompt. Inserts the boundary
2089
+ * marker if the input didn't already carry one.
1902
2090
  *
1903
- * Two passes:
1904
- * 1. Required-field presence. Missing or null/undefined required fields fail.
1905
- * 2. Per-property type checks with **best-effort coercion**. Small/OSS models
1906
- * routinely send `"true"` for a `boolean` field or `"42"` for a `number`,
1907
- * and rejecting outright forces a confusing retry. Instead, we auto-heal
1908
- * coerce when the conversion is unambiguous, fail only when the value
1909
- * cannot be reasonably normalized to any of the declared types.
2091
+ * Used by hosts (typically the TUI) to inject per-turn state — current cwd,
2092
+ * IDE selection, project root without forcing every caller to know the
2093
+ * marker format. The host's `system:transform` hook rewrites the dynamic
2094
+ * half each turn; the static doctrine above stays byte-stable and rides the
2095
+ * cache.
1910
2096
  *
1911
- * Recursion: when a property declares `type: 'array'` with an `items` schema,
1912
- * each item is validated against `items`. Object items are walked one level
1913
- * deep (their declared `properties` get the same coercion + enum checks the
1914
- * top level does). Items that can't be coerced are dropped rather than
1915
- * rejecting the whole call — the model rarely benefits from an
1916
- * all-or-nothing failure on a 20-item list because one entry was malformed.
1917
- * Dropped items are reported back via `droppedItems` so the tool's `execute`
1918
- * can surface a hint to the model if it wants to.
2097
+ * Returns a new string; the input is not mutated. When `extra` is empty,
2098
+ * returns the input verbatim.
1919
2099
  */
1920
- interface ValidationResult {
1921
- valid: boolean;
1922
- /** Human-readable reason. Present on failure only. */
1923
- error?: string;
1924
- /**
1925
- * Possibly-coerced input. Present iff `valid: true`. Tools should call
1926
- * `execute(coercedInput, ctx)` so auto-healed values reach the tool body.
1927
- * When no coercion was applied, this is reference-equal to the input.
1928
- */
1929
- coercedInput?: Record<string, unknown>;
1930
- /**
1931
- * Names of fields whose values were coerced. Empty when nothing changed.
1932
- * Useful for telemetry (`validation:reject` on failure already carries the
1933
- * reason; this is the success-path equivalent).
1934
- */
1935
- coercions?: readonly string[];
1936
- /**
1937
- * Indexes of array items dropped during recursive validation, keyed by
1938
- * the property name. Empty / absent when nothing was dropped. Tools that
1939
- * care about the discrepancy (e.g. `todowrite` wanting to surface
1940
- * "ignored 2 malformed items") can inspect this.
1941
- */
1942
- droppedItems?: Readonly<Record<string, readonly number[]>>;
1943
- }
1944
- declare function validateToolArgs(input: Record<string, unknown>, schema: Record<string, unknown>): ValidationResult;
1945
- //#endregion
1946
- //#region src/tools/write-file.d.ts
2100
+ declare function appendDynamicSection(system: string, extra: string): string;
1947
2101
  /**
1948
- * Write a file, with an idempotency signal when the content is unchanged.
2102
+ * Replace the entire dynamic half of a system prompt with `next`. Used by
2103
+ * the TUI's `<env>` rewriter where the entire dynamic section is regenerated
2104
+ * each turn rather than appended to.
1949
2105
  *
1950
- * Three return shapes chosen so the model can recognize a no-op without a
1951
- * separate read:
1952
- * - `Created path (N bytes)` — file did not exist
1953
- * - `Updated path (N bytes)` — content differed from on-disk
1954
- * - `No change needed: path already at target state (N bytes)`equal
2106
+ * When `next` is empty, drops the dynamic half (and the marker) entirely.
2107
+ */
2108
+ declare function replaceDynamicSection(system: string, next: string): string;
2109
+ /**
2110
+ * Strip the boundary marker so it never reaches the wirecollapses
2111
+ * `<static>${BOUNDARY}<dynamic>` into `<static>\n\n<dynamic>` for providers
2112
+ * that can't honor `cache_control` (vanilla OpenAI Chat Completions, Codex,
2113
+ * Cerebras, ...) or for the cache-disabled path on any provider.
1955
2114
  *
1956
- * Race window: in non-process execution contexts (docker, sandbox) shared by
1957
- * multiple agents, another writer can mutate the file between our read and
1958
- * our write. Local process context is single-writer per agent so the race is
1959
- * a non-issue there. Documented rather than locked because the cost of
1960
- * cross-context locking outweighs the cost of a stale "No change" message.
2115
+ * Cache-aware providers re-derive the split from the original (un-rendered)
2116
+ * system string via `splitSystemPrompt` `renderSystemForWire` is the
2117
+ * marker-free counterpart used to build the actual wire bytes.
2118
+ *
2119
+ * No-op when the input has no marker. Pure / no I/O.
1961
2120
  */
1962
- declare const writeFile: ToolDef;
2121
+ declare function renderSystemForWire(system: string): string;
2122
+ /** True when `system` contains the boundary marker. */
2123
+ declare function hasSystemPromptBoundary(system: string): boolean;
1963
2124
  //#endregion
1964
2125
  //#region src/tracing.d.ts
1965
2126
  /** Minimal span shape — any tracer that provides these methods is compatible. */
@@ -2281,5 +2442,5 @@ declare function definePreset(config: Preset): Preset;
2281
2442
  */
2282
2443
  declare function composePresets(...presets: Preset[]): Preset;
2283
2444
  //#endregion
2284
- export { ModelUsage as $, LoggingHooksOptions as $t, SkillsReadToolOptions as A, ANCHOR_PREVIEW_MAX_CHARS as An, McpOAuthProvider as At, createInteractionTool as B, CacheDimensionDiff as Bn, maybePersistToolResult as Bt, SubagentDef as C, NO_TOOLS_PREAMBLE as Cn, OAuthCallbackResult as Ct, createSkillsUseTool as D, buildFullCompactPrompt as Dn, loginMcpServer as Dt, SkillsUseToolOptions as E, buildFromCompactPrompt as En, LoginMcpServerResult as Et, shell as F, sliceForCompaction as Fn, PERSISTENCE_PREVIEW_BYTES as Ft, SystemPromptParts as G, installCacheBreakLogger as Gn, TOOL_USE_CANCELLED_MESSAGE as Gt, glob as H, CacheDimensionSnapshot as Hn, resolveTasksDir as Ht, readFile as I, stripImagesFromTurns as In, PersistInput as It, hasSystemPromptBoundary as J, LogLevel as Jt, appendDynamicSection as K, snapshotCacheDimensions as Kn, TOOL_USE_SKIPPED_MESSAGE as Kt, multiEdit as L, summaryToTurn as Ln, PersistOutcome as Lt, shellKill as M, CompactionSlice as Mn, createMemoryMcpCredentialStore as Mt, CreateShellToolOptions as N, SummaryToTurnInput as Nn, hasAuthorizationHeader as Nt, SkillsRunScriptToolOptions as O, buildTailCompactPrompt as On, McpCredentialEntry as Ot, createShellTool as P, anchorPreviewFor as Pn, PERSISTED_STUB_PREFIX as Pt, splitSystemPrompt as Q, LoggingHookSet as Qt, listFiles as R, truncateHeadForPtlRetry as Rn, buildPersistedStub as Rt, SpawnToolState as S, CompactPromptOptions as Sn, OAuthCallbackOptions as St, createSpawnTool as T, buildCompactPrompt as Tn, LoginMcpServerOptions as Tt, edit as U, diffCacheDimensions as Un, INTERRUPT_MESSAGE_FOR_TOOL_USE as Ut, grep as V, CacheDimensionName as Vn, resolvePersistDir as Vt, SYSTEM_PROMPT_BOUNDARY as W, fnv1a32 as Wn, SHELL_CASCADE_CANCEL_MESSAGE as Wt, renderSystemForWire as X, LogSink as Xt, joinSystemPrompt as Y, LogRecord as Yt, replaceDynamicSection as Z, Logger as Zt, LazyToolEntry as _, CompactInvalidInputError as _n, MetricsHookSet as _t, basicTools as a, estimateTokens as an, RunSummaryByModel as at, ChildAgent as b, CompactDirection as bn, createMetricsHooks as bt, Span as c, PostCompactRestoreOptions as cn, RunSummaryError as ct, TracingHookSet as d, selectFilesFromReadState as dn, createRunSummaryCollector as dt, consoleSink as en, flattenTurns as et, TracingHooksOptions as f, selectFilesFromSession as fn, Counter as ft, validateToolArgs as g, compactConversation as gn, MetricAttributes as gt, ValidationResult as h, CompactResult as hn, Meter as ht, _default as i, BYTES_PER_TOKEN as in, RunSummaryBudget as it, createSkillsReadTool as j, CompactScope as jn, McpOAuthProviderOptions as jt, createSkillsRunScriptTool as k, buildUpToCompactPrompt as kn, McpCredentialStore as kt, StartSpan as l, RecentFile as ln, RunSummaryTokens as lt, writeFile as m, CompactOptions as mn, InstrumentOptions as mt, composePresets as n, createLoggingHooks as nn, RunSummary as nt, zodToJsonSchema as o, utf8ByteLength as on, RunSummaryCollector as ot, createTracingHooks as p, selectRecentFiles as pn, Histogram as pt, appendStaticSection as q, ConsoleSinkOptions as qt, definePreset as r, jsonSink as rn, RunSummaryBlock as rt, GEN_AI_ATTRIBUTES as s, PostCompactAttachments as sn, RunSummaryCollectorOptions as st, Preset as t, createLogger as tn, statsByModel as tt, TracingConventions as u, buildPostCompactAttachments as un, RunSummaryValidation as ut, ToolSearchToolOptions as v, CompactPromptTooLongError as vn, MetricsHooksOptions as vt, SubagentRegistry as w, TRAILER as wn, startOAuthCallback as wt, SpawnToolOptions as x, CompactPromptBuilder as xn, OAuthCallbackHandle as xt, createToolSearchTool as y, BASE_INSTRUCTIONS as yn, UpDownCounter as yt, InteractionToolOptions as z, CacheBreakLoggerOptions as zn, cleanupPersistedSession as zt };
2285
- //# sourceMappingURL=index-B6h9C_JE.d.ts.map
2445
+ export { cleanupPersistedSession as $, CacheDimensionSnapshot as $n, InteractionToolOptions as $t, MetricAttributes as A, BASE_INSTRUCTIONS as An, validateToolArgs as At, LoginMcpServerResult as B, buildUpToCompactPrompt as Bn, SkillsUseToolOptions as Bt, ModelUsage as C, selectFilesFromSession as Cn, HeadlessUsage as Ct, Histogram as D, compactConversation as Dn, transcriptToOpenAIMessages as Dt, Counter as E, CompactResult as En, runHeadless as Et, OAuthCallbackHandle as F, TRAILER as Fn, SpawnToolOptions as Ft, McpOAuthProviderOptions as G, anchorPreviewFor as Gn, createSkillsReadTool as Gt, McpCredentialEntry as H, CompactScope as Hn, SkillsRunScriptToolOptions as Ht, OAuthCallbackOptions as I, buildCompactPrompt as In, SpawnToolState as It, PERSISTED_STUB_PREFIX as J, summaryToTurn as Jn, createShellTool as Jt, createMemoryMcpCredentialStore as K, sliceForCompaction as Kn, shellKill as Kt, OAuthCallbackResult as L, buildFromCompactPrompt as Ln, SubagentDef as Lt, MetricsHooksOptions as M, CompactPromptBuilder as Mn, ToolSearchToolOptions as Mt, UpDownCounter as N, CompactPromptOptions as Nn, createToolSearchTool as Nt, InstrumentOptions as O, CompactInvalidInputError as On, writeFile as Ot, createMetricsHooks as P, NO_TOOLS_PREAMBLE as Pn, ChildAgent as Pt, buildPersistedStub as Q, CacheDimensionName as Qn, listFiles as Qt, startOAuthCallback as R, buildFullCompactPrompt as Rn, SubagentRegistry as Rt, splitSystemPrompt as S, selectFilesFromReadState as Sn, HeadlessStatus as St, statsByModel as T, CompactOptions as Tn, headlessEventToJsonl as Tt, McpCredentialStore as U, CompactionSlice as Un, createSkillsRunScriptTool as Ut, loginMcpServer as V, ANCHOR_PREVIEW_MAX_CHARS as Vn, createSkillsUseTool as Vt, McpOAuthProvider as W, SummaryToTurnInput as Wn, SkillsReadToolOptions as Wt, PersistInput as X, CacheBreakLoggerOptions as Xn, readFile as Xt, PERSISTENCE_PREVIEW_BYTES as Y, truncateHeadForPtlRetry as Yn, shell as Yt, PersistOutcome as Z, CacheDimensionDiff as Zn, multiEdit as Zt, appendStaticSection as _, utf8ByteLength as _n, jsonSink as _t, basicTools as a, RunSummaryBlock as an, TOOL_USE_CANCELLED_MESSAGE as at, renderSystemForWire as b, RecentFile as bn, HeadlessOptions as bt, Span as c, RunSummaryCollector as cn, LogLevel as ct, TracingHookSet as d, RunSummaryRepeatGuard as dn, Logger as dt, createInteractionTool as en, diffCacheDimensions as er, maybePersistToolResult as et, TracingHooksOptions as f, RunSummaryTokens as fn, LoggingHookSet as ft, appendDynamicSection as g, estimateTokens as gn, createLoggingHooks as gt, SystemPromptParts as h, BYTES_PER_TOKEN as hn, createLogger as ht, _default as i, RunSummary as in, SHELL_CASCADE_CANCEL_MESSAGE as it, MetricsHookSet as j, CompactDirection as jn, LazyToolEntry as jt, Meter as k, CompactPromptTooLongError as kn, ValidationResult as kt, StartSpan as l, RunSummaryCollectorOptions as ln, LogRecord as lt, SYSTEM_PROMPT_BOUNDARY as m, createRunSummaryCollector as mn, consoleSink as mt, composePresets as n, glob as nn, installCacheBreakLogger as nr, resolveTasksDir as nt, zodToJsonSchema as o, RunSummaryBudget as on, TOOL_USE_SKIPPED_MESSAGE as ot, createTracingHooks as p, RunSummaryValidation as pn, LoggingHooksOptions as pt, hasAuthorizationHeader as q, stripImagesFromTurns as qn, CreateShellToolOptions as qt, definePreset as r, edit as rn, snapshotCacheDimensions as rr, INTERRUPT_MESSAGE_FOR_TOOL_USE as rt, GEN_AI_ATTRIBUTES as s, RunSummaryByModel as sn, ConsoleSinkOptions as st, Preset as t, grep as tn, fnv1a32 as tr, resolvePersistDir as tt, TracingConventions as u, RunSummaryError as un, LogSink as ut, hasSystemPromptBoundary as v, PostCompactAttachments as vn, HeadlessErrorInfo as vt, flattenTurns as w, selectRecentFiles as wn, OpenAIChatMessage as wt, replaceDynamicSection as x, buildPostCompactAttachments as xn, HeadlessResult as xt, joinSystemPrompt as y, PostCompactRestoreOptions as yn, HeadlessEvent as yt, LoginMcpServerOptions as z, buildTailCompactPrompt as zn, createSpawnTool as zt };
2446
+ //# sourceMappingURL=index-B2cMuK6S.d.ts.map