@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.
- package/CHANGELOG.md +96 -0
- package/README.md +31 -11
- package/dist/errors/index.d.ts +17 -4
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +19 -3
- package/dist/errors/index.js.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +153 -1930
- package/dist/factory.js.map +1 -1
- package/dist/fanout/index.d.ts +13 -1
- package/dist/fanout/index.d.ts.map +1 -1
- package/dist/fanout/index.js +13 -4
- package/dist/fanout/index.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -9
- package/dist/index.js.map +1 -1
- package/dist/lateral-leak/index.js +1 -1
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/run-state/index.d.ts +32 -6
- package/dist/run-state/index.d.ts.map +1 -1
- package/dist/run-state/index.js +46 -22
- package/dist/run-state/index.js.map +1 -1
- package/dist/runtime/agent-surface.js +122 -0
- package/dist/runtime/agent-surface.js.map +1 -0
- package/dist/runtime/agent-to-tool.d.ts +51 -0
- package/dist/runtime/agent-to-tool.d.ts.map +1 -0
- package/dist/runtime/agent-to-tool.js +145 -0
- package/dist/runtime/agent-to-tool.js.map +1 -0
- package/dist/runtime/approvals.js +0 -0
- package/dist/runtime/approvals.js.map +1 -0
- package/dist/runtime/dispatch.js +108 -0
- package/dist/runtime/dispatch.js.map +1 -0
- package/dist/runtime/executor-wiring.js +128 -0
- package/dist/runtime/executor-wiring.js.map +1 -0
- package/dist/runtime/fallback-chain.js +139 -0
- package/dist/runtime/fallback-chain.js.map +1 -0
- package/dist/runtime/handoff.js +307 -0
- package/dist/runtime/handoff.js.map +1 -0
- package/dist/runtime/messages.d.ts +22 -0
- package/dist/runtime/messages.d.ts.map +1 -0
- package/dist/runtime/messages.js +204 -0
- package/dist/runtime/messages.js.map +1 -0
- package/dist/runtime/provider-events.js +117 -0
- package/dist/runtime/provider-events.js.map +1 -0
- package/dist/runtime/run-compaction.js +210 -0
- package/dist/runtime/run-compaction.js.map +1 -0
- package/dist/runtime/run-finish.js +48 -0
- package/dist/runtime/run-finish.js.map +1 -0
- package/dist/runtime/run-gates.js +336 -0
- package/dist/runtime/run-gates.js.map +1 -0
- package/dist/runtime/run-init.js +81 -0
- package/dist/runtime/run-init.js.map +1 -0
- package/dist/runtime/run-input.js +46 -0
- package/dist/runtime/run-input.js.map +1 -0
- package/dist/runtime/step-catalogue.js +173 -0
- package/dist/runtime/step-catalogue.js.map +1 -0
- package/dist/runtime/tool-call-walk.js +189 -0
- package/dist/runtime/tool-call-walk.js.map +1 -0
- package/dist/runtime/tool-wiring.js +159 -0
- package/dist/runtime/tool-wiring.js.map +1 -0
- package/dist/tooling/adapters.js +1 -1
- package/dist/tooling/dataflow.js +1 -1
- package/dist/tooling/policy.js +2 -0
- package/dist/tooling/policy.js.map +1 -1
- package/dist/types.d.ts +63 -13
- package/dist/types.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/errors/index.ts +320 -0
- package/src/evaluator-optimizer/index.ts +212 -0
- package/src/factory.ts +957 -0
- package/src/fallback/index.ts +108 -0
- package/src/fanout/index.ts +523 -0
- package/src/filters/index.ts +347 -0
- package/src/index.ts +180 -0
- package/src/internal/ids.ts +46 -0
- package/src/internal/usage-accumulator.ts +90 -0
- package/src/lateral-leak/causality-monitor.ts +221 -0
- package/src/lateral-leak/index.ts +35 -0
- package/src/lateral-leak/merge-guard.ts +151 -0
- package/src/lateral-leak/protocol-guard.ts +222 -0
- package/src/preferred-model/index.ts +210 -0
- package/src/progress/index.ts +238 -0
- package/src/run-state/index.ts +607 -0
- package/src/runtime/agent-surface.ts +218 -0
- package/src/runtime/agent-to-tool.ts +323 -0
- package/src/runtime/approvals.ts +0 -0
- package/src/runtime/dispatch.ts +183 -0
- package/src/runtime/executor-wiring.ts +331 -0
- package/src/runtime/fallback-chain.ts +250 -0
- package/src/runtime/handoff.ts +428 -0
- package/src/runtime/messages.ts +309 -0
- package/src/runtime/provider-events.ts +175 -0
- package/src/runtime/run-compaction.ts +288 -0
- package/src/runtime/run-finish.ts +93 -0
- package/src/runtime/run-gates.ts +419 -0
- package/src/runtime/run-init.ts +169 -0
- package/src/runtime/run-input.ts +102 -0
- package/src/runtime/step-catalogue.ts +338 -0
- package/src/runtime/tool-call-walk.ts +301 -0
- package/src/runtime/tool-wiring.ts +218 -0
- package/src/testing/replay-provider.ts +121 -0
- package/src/tooling/adapters.ts +403 -0
- package/src/tooling/catalogue.ts +36 -0
- package/src/tooling/dataflow.ts +171 -0
- package/src/tooling/plan.ts +123 -0
- package/src/tooling/policy.ts +67 -0
- package/src/tooling/registry-build.ts +191 -0
- 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';
|