@graphorin/agent 0.6.0 → 0.7.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 (110) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +31 -11
  3. package/dist/errors/index.d.ts +17 -4
  4. package/dist/errors/index.d.ts.map +1 -1
  5. package/dist/errors/index.js +19 -3
  6. package/dist/errors/index.js.map +1 -1
  7. package/dist/factory.d.ts.map +1 -1
  8. package/dist/factory.js +153 -1930
  9. package/dist/factory.js.map +1 -1
  10. package/dist/fanout/index.d.ts +13 -1
  11. package/dist/fanout/index.d.ts.map +1 -1
  12. package/dist/fanout/index.js +13 -4
  13. package/dist/fanout/index.js.map +1 -1
  14. package/dist/index.d.ts +7 -6
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +11 -9
  17. package/dist/index.js.map +1 -1
  18. package/dist/lateral-leak/index.js +1 -1
  19. package/dist/package.js +6 -0
  20. package/dist/package.js.map +1 -0
  21. package/dist/run-state/index.d.ts +32 -6
  22. package/dist/run-state/index.d.ts.map +1 -1
  23. package/dist/run-state/index.js +46 -22
  24. package/dist/run-state/index.js.map +1 -1
  25. package/dist/runtime/agent-surface.js +122 -0
  26. package/dist/runtime/agent-surface.js.map +1 -0
  27. package/dist/runtime/agent-to-tool.d.ts +51 -0
  28. package/dist/runtime/agent-to-tool.d.ts.map +1 -0
  29. package/dist/runtime/agent-to-tool.js +145 -0
  30. package/dist/runtime/agent-to-tool.js.map +1 -0
  31. package/dist/runtime/approvals.js +0 -0
  32. package/dist/runtime/approvals.js.map +1 -0
  33. package/dist/runtime/dispatch.js +108 -0
  34. package/dist/runtime/dispatch.js.map +1 -0
  35. package/dist/runtime/executor-wiring.js +128 -0
  36. package/dist/runtime/executor-wiring.js.map +1 -0
  37. package/dist/runtime/fallback-chain.js +139 -0
  38. package/dist/runtime/fallback-chain.js.map +1 -0
  39. package/dist/runtime/handoff.js +307 -0
  40. package/dist/runtime/handoff.js.map +1 -0
  41. package/dist/runtime/messages.d.ts +22 -0
  42. package/dist/runtime/messages.d.ts.map +1 -0
  43. package/dist/runtime/messages.js +204 -0
  44. package/dist/runtime/messages.js.map +1 -0
  45. package/dist/runtime/provider-events.js +117 -0
  46. package/dist/runtime/provider-events.js.map +1 -0
  47. package/dist/runtime/run-compaction.js +210 -0
  48. package/dist/runtime/run-compaction.js.map +1 -0
  49. package/dist/runtime/run-finish.js +48 -0
  50. package/dist/runtime/run-finish.js.map +1 -0
  51. package/dist/runtime/run-gates.js +336 -0
  52. package/dist/runtime/run-gates.js.map +1 -0
  53. package/dist/runtime/run-init.js +81 -0
  54. package/dist/runtime/run-init.js.map +1 -0
  55. package/dist/runtime/run-input.js +46 -0
  56. package/dist/runtime/run-input.js.map +1 -0
  57. package/dist/runtime/step-catalogue.js +173 -0
  58. package/dist/runtime/step-catalogue.js.map +1 -0
  59. package/dist/runtime/tool-call-walk.js +189 -0
  60. package/dist/runtime/tool-call-walk.js.map +1 -0
  61. package/dist/runtime/tool-wiring.js +159 -0
  62. package/dist/runtime/tool-wiring.js.map +1 -0
  63. package/dist/tooling/adapters.js +1 -1
  64. package/dist/tooling/dataflow.js +1 -1
  65. package/dist/tooling/policy.js +2 -0
  66. package/dist/tooling/policy.js.map +1 -1
  67. package/dist/types.d.ts +63 -13
  68. package/dist/types.d.ts.map +1 -1
  69. package/package.json +20 -20
  70. package/src/errors/index.ts +320 -0
  71. package/src/evaluator-optimizer/index.ts +212 -0
  72. package/src/factory.ts +957 -0
  73. package/src/fallback/index.ts +108 -0
  74. package/src/fanout/index.ts +523 -0
  75. package/src/filters/index.ts +347 -0
  76. package/src/index.ts +180 -0
  77. package/src/internal/ids.ts +46 -0
  78. package/src/internal/usage-accumulator.ts +90 -0
  79. package/src/lateral-leak/causality-monitor.ts +221 -0
  80. package/src/lateral-leak/index.ts +35 -0
  81. package/src/lateral-leak/merge-guard.ts +151 -0
  82. package/src/lateral-leak/protocol-guard.ts +222 -0
  83. package/src/preferred-model/index.ts +210 -0
  84. package/src/progress/index.ts +238 -0
  85. package/src/run-state/index.ts +607 -0
  86. package/src/runtime/agent-surface.ts +218 -0
  87. package/src/runtime/agent-to-tool.ts +323 -0
  88. package/src/runtime/approvals.ts +0 -0
  89. package/src/runtime/dispatch.ts +183 -0
  90. package/src/runtime/executor-wiring.ts +331 -0
  91. package/src/runtime/fallback-chain.ts +250 -0
  92. package/src/runtime/handoff.ts +428 -0
  93. package/src/runtime/messages.ts +309 -0
  94. package/src/runtime/provider-events.ts +175 -0
  95. package/src/runtime/run-compaction.ts +288 -0
  96. package/src/runtime/run-finish.ts +93 -0
  97. package/src/runtime/run-gates.ts +419 -0
  98. package/src/runtime/run-init.ts +169 -0
  99. package/src/runtime/run-input.ts +102 -0
  100. package/src/runtime/step-catalogue.ts +338 -0
  101. package/src/runtime/tool-call-walk.ts +301 -0
  102. package/src/runtime/tool-wiring.ts +218 -0
  103. package/src/testing/replay-provider.ts +121 -0
  104. package/src/tooling/adapters.ts +403 -0
  105. package/src/tooling/catalogue.ts +36 -0
  106. package/src/tooling/dataflow.ts +171 -0
  107. package/src/tooling/plan.ts +123 -0
  108. package/src/tooling/policy.ts +67 -0
  109. package/src/tooling/registry-build.ts +191 -0
  110. package/src/types.ts +696 -0
package/src/types.ts ADDED
@@ -0,0 +1,696 @@
1
+ /**
2
+ * Public types for the agent runtime. The interfaces sit in a
3
+ * dedicated module so consumers can import them without pulling in
4
+ * the loop implementation.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import type {
10
+ AgentEvent,
11
+ AgentResult,
12
+ AISpan,
13
+ AnyTool,
14
+ CheckpointStore,
15
+ HandoffFilter,
16
+ Message,
17
+ ModelHint,
18
+ ModelSpec,
19
+ ProgressArtifactRef,
20
+ Provider,
21
+ ProviderCachePolicy,
22
+ ReasoningRetention,
23
+ RunContext,
24
+ RunState,
25
+ Sensitivity,
26
+ StopCondition,
27
+ Tool,
28
+ ToolChoice,
29
+ Tracer,
30
+ } from '@graphorin/core';
31
+ import type { Memory, PostCompactionHook as MemoryPostCompactionHook } from '@graphorin/memory';
32
+ import type { DataFlowPolicyConfig } from '@graphorin/security/dataflow';
33
+ import type { InputGuardrail, OutputGuardrail } from '@graphorin/security/guardrails';
34
+ import type { RuleOfTwoProfile, ToolArgumentPolicy } from '@graphorin/security/policy';
35
+ import type { ToolRegistry } from '@graphorin/tools/registry';
36
+ import type { ResultReader } from '@graphorin/tools/result';
37
+ import type { AgentFallbackPolicy } from './fallback/index.js';
38
+ import type { FanOutOptions, FanOutResult, MergeStrategy, PerChildBudget } from './fanout/index.js';
39
+ import type { CausalityMonitorConfig } from './lateral-leak/causality-monitor.js';
40
+ import type { MergeGuardConfig } from './lateral-leak/merge-guard.js';
41
+ import type { ProgressReadOptions, ProgressWriteOptions } from './progress/index.js';
42
+
43
+ /**
44
+ * Forward-compatible type alias for the input accepted by
45
+ * `Agent.stream / run / steer / followUp`. v0.1 ships with the
46
+ * canonical text + multimodal Message shape; future versions may
47
+ * add structured inputs.
48
+ *
49
+ * @stable
50
+ */
51
+ export type AgentInput = string | Message | ReadonlyArray<Message>;
52
+
53
+ /**
54
+ * Output type specification.
55
+ *
56
+ * @stable
57
+ */
58
+ export interface OutputSpec<TOutput> {
59
+ readonly kind: 'text' | 'structured';
60
+ /**
61
+ * Local validator (Zod-compatible `{ parse }`) applied to the final
62
+ * model output on the completed path (AG-3). A parse failure fails
63
+ * the run with `output-validation-failed` - never a silent cast.
64
+ */
65
+ readonly schema?: { parse(value: unknown): TOutput };
66
+ /** Optional description shown to the model alongside the schema. */
67
+ readonly description?: string;
68
+ /**
69
+ * Wire-format JSON Schema advertised to the model: forwarded on
70
+ * `ProviderRequest.outputType` for adapters with native structured
71
+ * output, and embedded in the fallback JSON instruction appended as
72
+ * a trailing system message (the documented contract until adapters
73
+ * consume `outputType` natively - PS-24).
74
+ */
75
+ readonly jsonSchema?: Readonly<Record<string, unknown>>;
76
+ }
77
+
78
+ /**
79
+ * Per-step override hook. Receives the current `RunContext` and may
80
+ * return overrides applied to the next provider call only.
81
+ *
82
+ * @stable
83
+ */
84
+ export type PrepareStepHook<TDeps = unknown> = (
85
+ ctx: RunContext<TDeps>,
86
+ ) => Promise<PrepareStepOverrides<TDeps>> | PrepareStepOverrides<TDeps>;
87
+
88
+ /** @stable */
89
+ export interface PrepareStepOverrides<TDeps = unknown> {
90
+ readonly provider?: Provider;
91
+ readonly tools?: ReadonlyArray<AnyTool<TDeps>>;
92
+ readonly toolChoice?: ToolChoice;
93
+ readonly temperature?: number;
94
+ readonly maxTokens?: number;
95
+ }
96
+
97
+ /**
98
+ * Compaction post-hook factory accepted by `createAgent({...})`.
99
+ * Re-exported from `@graphorin/memory` here for ergonomic typing.
100
+ *
101
+ * @stable
102
+ */
103
+ export type PostCompactionHook = MemoryPostCompactionHook;
104
+
105
+ /**
106
+ * Skill-registry shape consumed by the agent loop. Implementations
107
+ * live in `@graphorin/skills`. We accept any structurally-compatible
108
+ * value to avoid the heavyweight peer dependency on the typing
109
+ * surface.
110
+ *
111
+ * @stable
112
+ */
113
+ export interface SkillsRegistryLike {
114
+ list?(): ReadonlyArray<unknown>;
115
+ }
116
+
117
+ /**
118
+ * Handoff target entry accepted by `createAgent({ handoffs })`.
119
+ * Either a bare {@link Agent} reference (default filter applied) or
120
+ * an explicit `{ target, inputFilter? }` envelope.
121
+ *
122
+ * @stable
123
+ */
124
+ // `TOutput` is existential here: handoff targets legitimately vary in
125
+ // output type, and `Agent` is invariant in `TOutput` (the result is
126
+ // covariant, `guardrails.output` is contravariant) - `unknown` would
127
+ // reject every concretely-typed agent.
128
+ export type HandoffEntry<TDeps = unknown> =
129
+ // biome-ignore lint/suspicious/noExplicitAny: existential TOutput (see above)
130
+ | Agent<TDeps, any>
131
+ | {
132
+ // biome-ignore lint/suspicious/noExplicitAny: existential TOutput (see above)
133
+ readonly target: Agent<TDeps, any>;
134
+ readonly inputFilter?: HandoffFilter;
135
+ /** W-036: which child events forward into the parent stream. */
136
+ readonly forwardEvents?: SubagentForwardPolicy;
137
+ };
138
+
139
+ /**
140
+ * W-036: sub-agent event-forwarding policy. `'lifecycle'` (default)
141
+ * forwards tool execution/approval, guardrail, lateral-leak,
142
+ * compaction and error events - never the high-frequency text deltas;
143
+ * `'all'` forwards everything; `'none'` keeps the child a black box.
144
+ *
145
+ * @stable
146
+ */
147
+ export type SubagentForwardPolicy = 'none' | 'lifecycle' | 'all';
148
+
149
+ /**
150
+ * The full options object accepted by {@link createAgent}.
151
+ *
152
+ * @stable
153
+ */
154
+ export interface AgentConfig<TDeps = unknown, TOutput = string> {
155
+ readonly name: string;
156
+ /**
157
+ * The agent's system prompt. A string is used verbatim; a function is
158
+ * resolved **once per run** (sync or async, awaited) against a
159
+ * {@link RunContext} snapshot at step 0, and its result is pinned as the
160
+ * run's system-prompt prefix for the whole run (it is not re-evaluated
161
+ * per step). An empty string injects no system message.
162
+ */
163
+ readonly instructions: string | ((ctx: RunContext<TDeps>) => string | Promise<string>);
164
+ readonly provider: Provider;
165
+ readonly tools?: ReadonlyArray<AnyTool<TDeps>>;
166
+ readonly skills?: SkillsRegistryLike;
167
+ readonly memory?: Memory;
168
+ /**
169
+ * Opt in to building the per-run system prompt from the memory
170
+ * `ContextEngine` (CE-1). When `true` **and** `memory` is wired, the
171
+ * runtime calls `memory.contextEngine.assemble(...)` once at run start: the
172
+ * agent's `instructions` become Layer 2 and the engine prepends the memory
173
+ * base and appends working blocks, procedural rules, skill cards, the
174
+ * metadata counts, and - when `factsAutoRecall` is configured - auto-recalled
175
+ * facts. Defaults `false`: the prompt is built from `instructions` alone and
176
+ * the model reaches memory only through the memory tools it calls (the
177
+ * documented explicit pattern). Has no effect without `memory`.
178
+ */
179
+ readonly autoAssembleContext?: boolean;
180
+ readonly handoffs?: ReadonlyArray<HandoffEntry<TDeps>>;
181
+ readonly outputType?: OutputSpec<TOutput>;
182
+ /**
183
+ * Deterministic checks run by the loop (AG-2; canonical contract is
184
+ * `@graphorin/security`'s `GuardrailDefinition` - SDF-4).
185
+ *
186
+ * - `input` guardrails run over each **fresh-run seed user message**
187
+ * (string content) before the first provider call. `'block'` fails
188
+ * the run (`guardrail-blocked`) without reaching the model;
189
+ * `'rewrite'` replaces the message content (mirrored into the
190
+ * persisted `RunState`); `'warn'` logs and continues.
191
+ * - `output` guardrails run over the **final output** on the
192
+ * completed path before `agent.end`. `'block'` fails the run;
193
+ * `'rewrite'` replaces `result.output` (text deltas were already
194
+ * streamed - the rewrite governs the durable result, not the
195
+ * live token stream).
196
+ *
197
+ * Every trip emits a `guardrail.tripped` event.
198
+ */
199
+ readonly guardrails?: {
200
+ readonly input?: ReadonlyArray<InputGuardrail<string>>;
201
+ readonly output?: ReadonlyArray<OutputGuardrail<TOutput>>;
202
+ };
203
+ readonly stopWhen?: StopCondition;
204
+ readonly toolChoice?: ToolChoice;
205
+ readonly prepareStep?: PrepareStepHook<TDeps>;
206
+ readonly maxParallelTools?: number;
207
+ /**
208
+ * How the model invokes tools (P1-2).
209
+ *
210
+ * - `'direct'` (default) - the model emits one provider tool-call per
211
+ * tool, each result inlined into the conversation.
212
+ * - `'code-mode'` - the agent advertises only the `code_execute` /
213
+ * `code_search` meta-tools; the model writes a script that calls
214
+ * tools in a sandbox via `tools.<name>(args)`, and **only the
215
+ * script's final result re-enters context** (intermediate results
216
+ * stay inside the sandbox). Each in-script call still runs through
217
+ * the executor, so per-tool ACL / sanitization / truncation apply.
218
+ * Approval-gated tools are not reachable from code-mode (there is no
219
+ * durable-HITL path mid-script); call those in `'direct'` mode.
220
+ *
221
+ * @default 'direct'
222
+ */
223
+ readonly toolInvocation?: 'direct' | 'code-mode';
224
+ readonly fallbackModels?: ReadonlyArray<ModelSpec>;
225
+ readonly fallbackPolicy?: AgentFallbackPolicy;
226
+ readonly preferredModel?: ModelHint | ModelSpec;
227
+ readonly modelTierMap?: Partial<Record<ModelHint, ModelSpec>>;
228
+ /**
229
+ * Per-agent override of the per-provider auto-detected
230
+ * {@link ReasoningRetention} default. Wins over the provider-
231
+ * level default when both are present. The agent runtime feeds
232
+ * the effective value into every `provider.stream(...)` call so
233
+ * the wire-correct contract is honoured per RB-42 / suggested
234
+ * DEC-158 / suggested ADR-046.
235
+ */
236
+ readonly reasoningRetention?: ReasoningRetention;
237
+ readonly causalityMonitor?: CausalityMonitorConfig;
238
+ /**
239
+ * Sideways-injection merge guard for `agent.fanOut` `'judge-merge'`
240
+ * (AG-7): scores per-child source trust × contribution weight against
241
+ * the judge's merged output; a biased merge emits
242
+ * `agent.lateral-leak.detected` and `'detect-and-block'` throws
243
+ * `MergeBlockedError`.
244
+ */
245
+ readonly mergeGuard?: MergeGuardConfig;
246
+ /**
247
+ * Provenance / taint-based data-flow policy (P1-3, opt-in). Enforces
248
+ * data-flow rules at the tool-execution boundary using the provenance
249
+ * Graphorin already tracks (trust class + source + sensitivity), to
250
+ * defuse the lethal trifecta: a sink (`side-effecting` /
251
+ * `external-stateful` tool) is blocked when untrusted content flows
252
+ * into it verbatim, or - conservatively - when it fires while both
253
+ * untrusted content and secret-tier data are present in the run.
254
+ *
255
+ * - `mode: 'shadow'` - audit-only; tainted flows are flagged
256
+ * (`tool:dataflow:flagged` audit + counter) but never blocked. Ship
257
+ * this first to surface false positives.
258
+ * - `mode: 'enforce'` - tainted flows are blocked (the sink does not
259
+ * run; the call yields a `dataflow_policy_blocked` error) unless the
260
+ * sink is listed in `declassifySinks` (an audited operator override).
261
+ *
262
+ * Composes with `'code-mode'`: each in-script tool call flows through
263
+ * the same executor gate. Absent (the default) leaves the loop
264
+ * unchanged.
265
+ */
266
+ readonly dataFlowPolicy?: DataFlowPolicyConfig;
267
+ /**
268
+ * Additional result-handle readers (P1-4 / WI-13), tried after the
269
+ * built-in spill-file reader. Wire an MCP resource reader
270
+ * (`createMcpResourceReader` from `@graphorin/mcp/client`) here so the
271
+ * model can resolve an MCP `resource_link` on demand via the built-in
272
+ * `read_result` tool, instead of inlining the resource body. Supplying
273
+ * any reader force-registers `read_result` even when no tool spills.
274
+ */
275
+ readonly resultReaders?: ReadonlyArray<ResultReader>;
276
+ /**
277
+ * Opt-in prompt-cache breakpoint policy (core-provider-02), forwarded
278
+ * verbatim on every `ProviderRequest` the loop issues. With
279
+ * `{ breakpoints: 'auto' }` the Anthropic path (vercel adapter) anchors
280
+ * `cache_control` markers on the first and last conversation messages,
281
+ * so the stable prefix (tools + system + early turns) is written to the
282
+ * provider cache once and read at the discounted rate on every later
283
+ * step. Providers with automatic caching ignore it. Pair with the
284
+ * append-only transcript the loop already maintains - cache hit rate is
285
+ * the #1 production cost lever for multi-step agents.
286
+ */
287
+ readonly cachePolicy?: ProviderCachePolicy;
288
+ /**
289
+ * When deferred-tool promotions (via `tool_search`) take effect (C1):
290
+ *
291
+ * - `'immediate'` (default) - a promoted tool joins the catalogue on the
292
+ * NEXT step. Costs one provider-cache invalidation per promotion
293
+ * (the tools block changes), which is the standard trade for tool
294
+ * discovery.
295
+ * - `'run-boundary'` - the catalogue advertised to the model is frozen
296
+ * for the whole run; promotions are still recorded (and persisted on
297
+ * `RunState.promotedTools`) but only join the catalogue on the next
298
+ * run / resume. Keeps the provider prompt cache byte-stable across
299
+ * every step of a run.
300
+ */
301
+ readonly toolPromotion?: 'immediate' | 'run-boundary';
302
+ /**
303
+ * C3: rules-based verifiers that run when the model emits a terminal
304
+ * (no-tool-call) response. A failing verifier's feedback is appended
305
+ * to the transcript as a user message and the loop continues, up to
306
+ * `maxVerifierRounds` extra rounds. Verifiers are DETERMINISTIC checks
307
+ * (lint/test runners, format validators, exit codes) - deliberately
308
+ * not an evidence-free "reflect on your answer" step, which the
309
+ * self-correction literature shows degrades performance.
310
+ */
311
+ readonly verifiers?: ReadonlyArray<ResponseVerifier>;
312
+ /**
313
+ * Cap on verifier-triggered continuation rounds per run (C3).
314
+ * @default 1
315
+ */
316
+ readonly maxVerifierRounds?: number;
317
+ /**
318
+ * C3: transparent bounded retry for transient tool failures, forwarded
319
+ * to the executor. Defaults (when set): `maxAttempts: 3`,
320
+ * `backoffMs: 250`, `kinds: ['rate_limited']`; retries only ever run
321
+ * for `pure` / `read-only` tools or tools with an `idempotencyKey`.
322
+ */
323
+ readonly toolRetry?: {
324
+ readonly maxAttempts?: number;
325
+ readonly backoffMs?: number;
326
+ readonly kinds?: ReadonlyArray<import('@graphorin/core').ToolErrorKind>;
327
+ };
328
+ /**
329
+ * C3: journal each step's raw model response (text + tool calls +
330
+ * model id) onto `RunState.steps[].providerResponse`, enabling
331
+ * deterministic replay via `createReplayProvider(state)` - reproduce
332
+ * an entire run without live model calls.
333
+ * @default false
334
+ */
335
+ readonly recordProviderResponses?: boolean;
336
+ readonly tracer?: Tracer;
337
+ readonly checkpointStore?: CheckpointStore;
338
+ /**
339
+ * What happens to the run's checkpoint thread when the run reaches a
340
+ * terminal status (W-005). `'keep'` (default) preserves the current
341
+ * behaviour: checkpoints survive for post-hoc debugging and
342
+ * process-restart resume. `'delete-on-terminal'` best-effort deletes
343
+ * the thread after `completed` / `failed` runs; `awaiting_approval`
344
+ * and `aborted` runs always keep theirs (the thread IS the resume
345
+ * state). Requires {@link AgentConfig.checkpointStore}.
346
+ * @default 'keep'
347
+ */
348
+ readonly checkpointPolicy?: 'keep' | 'delete-on-terminal';
349
+ readonly sensitivity?: Sensitivity;
350
+ /**
351
+ * Agent-default capability restriction (D2). `'read-only'` builds a
352
+ * side-effect-free agent: writer tools and handoffs are never
353
+ * advertised and the executor blocks writer calls deterministically
354
+ * (`capability_blocked`). Per-call override:
355
+ * {@link AgentCallOptions.capability}. See {@link AgentCapability}.
356
+ */
357
+ readonly capability?: AgentCapability;
358
+ /**
359
+ * Declarative tool-argument policy (D4 / Progent). Forbid-before-allow
360
+ * rules over tool name + validated args, evaluated by the executor on
361
+ * every call; default-deny sensitive tools with `defaultDenySensitive`.
362
+ * A forbid verdict blocks the call (`capability_blocked`). Composes on
363
+ * top of {@link ruleOfTwo}. See `@graphorin/security/policy`.
364
+ */
365
+ readonly toolPolicy?: ToolArgumentPolicy;
366
+ /**
367
+ * Rule-of-Two capability profile (D4). Declares which of {untrusted
368
+ * input, sensitive data, external side effects} this agent may hold;
369
+ * denying external side effects forces a read-only capability floor
370
+ * and blocks writer tools, denying sensitive data default-denies
371
+ * sensitive tools. Holding all three is the dangerous configuration
372
+ * the preset is designed to prevent. See `@graphorin/security/policy`.
373
+ */
374
+ readonly ruleOfTwo?: RuleOfTwoProfile;
375
+ /**
376
+ * Register the D6 structured plan tool (`update_plan`, TodoWrite-style)
377
+ * and recite the plan back into each step's prompt (attention
378
+ * recitation). The plan is journaled in `RunState.todos` and survives
379
+ * resume. Default `false` - off keeps the tool surface unchanged.
380
+ */
381
+ readonly plan?: boolean;
382
+ readonly sessionId?: string;
383
+ readonly userId?: string;
384
+ readonly deps?: TDeps;
385
+ }
386
+
387
+ /**
388
+ * Outcome of one {@link ResponseVerifier} check (C3).
389
+ *
390
+ * @stable
391
+ */
392
+ export type VerifierResult =
393
+ | { readonly ok: true }
394
+ | { readonly ok: false; readonly feedback: string };
395
+
396
+ /**
397
+ * A deterministic check over the model's terminal response (C3). Runs
398
+ * when the loop is about to complete; `ok: false` feeds `feedback` back
399
+ * to the model (as a user message prefixed `[verifier:<id>]`) and the
400
+ * loop continues for up to `AgentConfig.maxVerifierRounds` extra rounds.
401
+ *
402
+ * A verifier that THROWS is treated as passed (the `verifier.result`
403
+ * event still fires with `ok: true`): a buggy verifier must never
404
+ * take down a run.
405
+ *
406
+ * @stable
407
+ */
408
+ export interface ResponseVerifier {
409
+ readonly id: string;
410
+ verify(ctx: {
411
+ /** The model's terminal text output (raw, pre-structured-parse). */
412
+ readonly output: string;
413
+ readonly state: RunState;
414
+ readonly stepNumber: number;
415
+ }): VerifierResult | Promise<VerifierResult>;
416
+ }
417
+
418
+ /**
419
+ * Single approval decision attached to a {@link ResumeDirective}.
420
+ * Mirrors the directive surface the HITL caller supplies on resume
421
+ * (per `Command(approval: { granted, reason? })` in the agent-loop
422
+ * reference, renamed to `Directive` per Graphorin's own naming).
423
+ *
424
+ * @stable
425
+ */
426
+ export interface ApprovalDecision {
427
+ readonly toolCallId: string;
428
+ readonly granted: boolean;
429
+ readonly reason?: string;
430
+ /**
431
+ * W-001: echo of `ToolApproval.subRunToolCallId` for approvals that
432
+ * belong to a parked sub-agent run. Operators read the pair
433
+ * (`toolCallId`, `subRunToolCallId`) from `RunState.pendingApprovals`
434
+ * and return BOTH fields; decisions match on the composite key, so
435
+ * child-local toolCallId collisions across two parked children never
436
+ * cross-apply. A decision without this field applies only to the
437
+ * parent's own (unparked) approvals.
438
+ */
439
+ readonly subRunToolCallId?: string;
440
+ }
441
+
442
+ /**
443
+ * Resume directive accepted by `agent.run(input | RunState, { directive })`.
444
+ *
445
+ * The library-mode pickup pattern is: the operator stores the
446
+ * suspended `RunState` from the previous `agent.run(...)` call,
447
+ * waits for the user / cron / webhook to resolve the pending
448
+ * approval, and re-invokes `agent.run(savedState, { directive: {
449
+ * approvals: [...] } })` to resume.
450
+ *
451
+ * @stable
452
+ */
453
+ export interface ResumeDirective {
454
+ readonly approvals?: ReadonlyArray<ApprovalDecision>;
455
+ }
456
+
457
+ /**
458
+ * Per-call options accepted by `agent.stream(...)` / `agent.run(...)`.
459
+ *
460
+ * @stable
461
+ */
462
+ export interface AgentCallOptions<TDeps> {
463
+ readonly deps?: TDeps;
464
+ readonly signal?: AbortSignal;
465
+ readonly sessionId?: string;
466
+ readonly userId?: string;
467
+ /**
468
+ * HITL resume directive. Supplied alongside a `RunState` to
469
+ * resolve any approvals that were pending when the previous
470
+ * `agent.run(...)` call suspended.
471
+ */
472
+ readonly directive?: ResumeDirective;
473
+ /**
474
+ * Per-run capability restriction (D2) - overrides
475
+ * {@link AgentConfig.capability} for this invocation. See that field
476
+ * for semantics. Not persisted in `RunState`: re-supply it when
477
+ * resuming a suspended run.
478
+ */
479
+ readonly capability?: AgentCapability;
480
+ /**
481
+ * W-036: parent span for this run's `agent.run` root span - a
482
+ * multi-agent invocation forms ONE trace tree (the child's run span
483
+ * parents under the caller's step/tool span). The runtime supplies it
484
+ * automatically for handoffs and `toTool` sub-agents. Like
485
+ * `capability`, it is NOT persisted in `RunState`: re-supply on
486
+ * resume when stitching matters.
487
+ */
488
+ readonly parentSpan?: AISpan;
489
+ }
490
+
491
+ /**
492
+ * Run-level capability restriction (D2 - the single-writer constraint
493
+ * from multi-agent practice). `'read-only'` makes the run
494
+ * side-effect-free by construction: writer tools (`side-effecting` /
495
+ * `external-stateful`) and handoffs are never advertised to the model,
496
+ * and the tool executor deterministically blocks any writer call the
497
+ * model fabricates anyway (`capability_blocked`). Use it to run
498
+ * parallel research / explorer sub-agents while exactly one agent in
499
+ * the topology keeps write capability.
500
+ *
501
+ * @stable
502
+ */
503
+ export type AgentCapability = 'read-only';
504
+
505
+ /**
506
+ * `agent.toTool({...})` options.
507
+ *
508
+ * @stable
509
+ */
510
+ export interface AgentToToolOptions {
511
+ readonly name?: string;
512
+ readonly description?: string;
513
+ readonly exposeTurns?: 'final' | 'all' | 'none';
514
+ /**
515
+ * Shapes the sub-agent seed from the parent history (AG-17): when
516
+ * supplied, the sub-agent is seeded with
517
+ * `[...inputFilter(parentMessages), { role: 'user', content: input }]`.
518
+ * Without a filter the sub-agent sees ONLY the input string - no
519
+ * parent conversation crosses the boundary (least authority by
520
+ * construction; there is no secret-inheritance mechanism at this
521
+ * boundary at all).
522
+ */
523
+ readonly inputFilter?: HandoffFilter;
524
+ /** W-036: which child events forward into the parent stream. */
525
+ readonly forwardEvents?: SubagentForwardPolicy;
526
+ /**
527
+ * Run the sub-agent under a restricted capability (D2): a
528
+ * `'read-only'` worker cannot execute or advertise writer tools. The
529
+ * orchestrator-worker recipe is `parent (full capability) + workers
530
+ * via toTool({ capability: 'read-only', contextFold: true })`.
531
+ */
532
+ readonly capability?: AgentCapability;
533
+ /**
534
+ * Context folding at the sub-agent boundary (D2): instead of the raw
535
+ * final output, the parent receives a compact distilled outcome -
536
+ * status, step/tool-call counts, tools used, and the final text
537
+ * clamped to `maxChars` (default 2000). Keeps tool-heavy child runs
538
+ * from flooding the parent window. Default off (raw output).
539
+ */
540
+ readonly contextFold?: boolean | { readonly maxChars?: number };
541
+ /**
542
+ * Propagate the child run's coarse taint flags across the fold (D2,
543
+ * default `true`): when the child saw untrusted / sensitive content,
544
+ * the tool result carries a widen-only `taint` override
545
+ * (`sourceKind: 'sub-agent'`) that re-arms the PARENT's data-flow
546
+ * ledger. A no-op when the parent has no `dataFlowPolicy`. Set
547
+ * `false` only for children whose inputs are fully trusted.
548
+ */
549
+ readonly propagateTaint?: boolean;
550
+ }
551
+
552
+ /**
553
+ * Cancellation options accepted by `agent.abort({...})`.
554
+ *
555
+ * @stable
556
+ */
557
+ export interface AbortOptions {
558
+ /**
559
+ * When `true`, let the in-flight provider stream finish (the current step
560
+ * reaches its boundary) instead of interrupting it mid-event, then stop at the
561
+ * next step. Default `false` hard-kills the in-flight stream immediately. (The
562
+ * step's tool calls still observe the cancellation once the signal is set.)
563
+ */
564
+ readonly drain?: boolean;
565
+ /**
566
+ * What to do with approvals that were already requested but not
567
+ * resolved at abort time (W-038).
568
+ *
569
+ * - `'deny'` (default) - auto-deny pending approvals; each drained
570
+ * toolCallId gets a matching tool message so the transcript keeps
571
+ * no dangling `tool_use`, and the run ends `'aborted'`.
572
+ * - `'hold'` - keep the approvals on `RunState.pendingApprovals` of
573
+ * the `'aborted'` state; such a state re-enters the loop only via
574
+ * an explicit resume directive.
575
+ * - `'fail'` - reject the run with `RunError(code: 'run-aborted')`
576
+ * ONLY when approvals are actually pending; an abort with an empty
577
+ * queue ends `'aborted'`, never `'failed'`.
578
+ */
579
+ readonly onPendingApprovals?: 'deny' | 'hold' | 'fail';
580
+ }
581
+
582
+ /**
583
+ * `agent.compact({...})` options.
584
+ *
585
+ * @stable
586
+ */
587
+ export interface CompactOptions {
588
+ readonly source?: 'manual' | 'pre-step';
589
+ readonly preserveRecentTurns?: number;
590
+ }
591
+
592
+ /**
593
+ * Result of `agent.compact({...})`.
594
+ *
595
+ * @stable
596
+ */
597
+ export interface CompactionApiResult {
598
+ readonly beforeTokens: number;
599
+ readonly afterTokens: number;
600
+ readonly summaryTokens: number;
601
+ readonly durationMs: number;
602
+ readonly hooksFiredCount: number;
603
+ readonly summary: string;
604
+ /**
605
+ * `true` when the compaction trimmed + spliced the live run buffer
606
+ * (CE-3/AG-13). `false` results carry an explicit
607
+ * {@link skippedReason} instead of silently reporting zeros.
608
+ */
609
+ readonly applied: boolean;
610
+ /** Why nothing was spliced, when {@link applied} is `false`. */
611
+ readonly skippedReason?: 'no-memory' | 'no-active-run' | 'nothing-to-trim' | 'sensitivity-gated';
612
+ }
613
+
614
+ /**
615
+ * Per-call shape accepted by `Agent.fanOut(...)`. Mirrors the
616
+ * pure-function {@link FanOutOptions} but omits the runtime-supplied
617
+ * identifiers - the `Agent` instance carries those.
618
+ *
619
+ * @stable
620
+ */
621
+ export interface AgentFanOutOptions<TOutput = unknown> {
622
+ readonly children: FanOutOptions<TOutput>['children'];
623
+ readonly maxConcurrentChildren?: number;
624
+ readonly perBudget?: PerChildBudget;
625
+ readonly mergeStrategy?: MergeStrategy<TOutput>;
626
+ readonly signal?: AbortSignal;
627
+ }
628
+
629
+ /**
630
+ * Progress IO surface exposed on the `Agent` instance. The methods
631
+ * default the `runId` cursor to the in-flight run when present, so
632
+ * callers can use them inside an `agent.run(...)` boundary without
633
+ * repeating the cursor.
634
+ *
635
+ * @stable
636
+ */
637
+ export interface AgentProgressIO {
638
+ write(content: string, options?: ProgressWriteOptions): Promise<ProgressArtifactRef>;
639
+ read(options?: ProgressReadOptions): Promise<ReadonlyArray<ProgressArtifactRef>>;
640
+ }
641
+
642
+ /**
643
+ * Public agent surface returned by {@link createAgent}.
644
+ *
645
+ * @stable
646
+ */
647
+ export interface Agent<TDeps = unknown, TOutput = string> {
648
+ readonly id: string;
649
+ readonly config: AgentConfig<TDeps, TOutput>;
650
+ stream(
651
+ input: AgentInput | RunState,
652
+ options?: AgentCallOptions<TDeps>,
653
+ ): AsyncIterable<AgentEvent<TOutput>>;
654
+ run(
655
+ input: AgentInput | RunState,
656
+ options?: AgentCallOptions<TDeps>,
657
+ ): Promise<AgentResult<TOutput>>;
658
+ steer(message: AgentInput): void;
659
+ followUp(message: AgentInput): void;
660
+ abort(options?: AbortOptions): void;
661
+ toTool(options?: AgentToToolOptions): Tool<{ readonly input: string }, TOutput, TDeps>;
662
+ compact(options?: CompactOptions): Promise<CompactionApiResult>;
663
+ /**
664
+ * Convenience wrapper around the standalone `runFanOut(...)`. The
665
+ * returned `FanOutResult` carries per-child status + the merged
666
+ * output. Per-child failures are captured in `children[].status`
667
+ * - this method never throws on a child failure (the merge
668
+ * strategy decides whether to propagate).
669
+ */
670
+ fanOut<TFanOutOutput = unknown>(
671
+ options: AgentFanOutOptions<TFanOutOutput>,
672
+ ): Promise<FanOutResult<TFanOutOutput>>;
673
+ /**
674
+ * Structured handoff-artifact APIs. Persists / reads UTF-8 text
675
+ * artifacts under the configured artifact root; cross-run reads
676
+ * require an explicit `runId` cursor on the read options.
677
+ */
678
+ readonly progress: AgentProgressIO;
679
+ /**
680
+ * The unified tool registry assembled at `createAgent(...)` warm-up
681
+ * (Principle #12): every first-party + skill tool, with cross-source
682
+ * name collisions resolved deterministically. Read-only and exposed
683
+ * for inspection; the run loop and `tool_search` consume it. Always
684
+ * present on agents built by `createAgent(...)`.
685
+ */
686
+ readonly registry?: ToolRegistry;
687
+ }
688
+
689
+ export type {
690
+ ChildResult,
691
+ FanOutOptions,
692
+ FanOutResult,
693
+ MergeStrategy,
694
+ PerChildBudget,
695
+ } from './fanout/index.js';
696
+ export type { ProgressIO, ProgressReadOptions, ProgressWriteOptions } from './progress/index.js';