@graphorin/core 0.6.1 → 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 +82 -0
  2. package/README.md +8 -5
  3. package/dist/channels/index.d.ts +2 -2
  4. package/dist/channels/index.js +2 -2
  5. package/dist/channels/pause.d.ts +47 -2
  6. package/dist/channels/pause.d.ts.map +1 -1
  7. package/dist/channels/pause.js +62 -2
  8. package/dist/channels/pause.js.map +1 -1
  9. package/dist/contracts/checkpoint-store.d.ts +97 -1
  10. package/dist/contracts/checkpoint-store.d.ts.map +1 -1
  11. package/dist/contracts/checkpoint-store.js.map +1 -1
  12. package/dist/contracts/index.d.ts +5 -5
  13. package/dist/contracts/index.js +2 -1
  14. package/dist/contracts/memory-store.d.ts +59 -2
  15. package/dist/contracts/memory-store.d.ts.map +1 -1
  16. package/dist/contracts/provider.d.ts +20 -6
  17. package/dist/contracts/provider.d.ts.map +1 -1
  18. package/dist/contracts/session-store.d.ts +10 -2
  19. package/dist/contracts/session-store.d.ts.map +1 -1
  20. package/dist/contracts/tool.d.ts +75 -1
  21. package/dist/contracts/tool.d.ts.map +1 -1
  22. package/dist/contracts/tool.js +57 -0
  23. package/dist/contracts/tool.js.map +1 -0
  24. package/dist/contracts/tracer.d.ts +53 -5
  25. package/dist/contracts/tracer.d.ts.map +1 -1
  26. package/dist/contracts/tracer.js.map +1 -1
  27. package/dist/index.d.ts +9 -7
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +5 -5
  30. package/dist/package.js +1 -1
  31. package/dist/package.js.map +1 -1
  32. package/dist/types/agent-event-wire.d.ts +74 -0
  33. package/dist/types/agent-event-wire.d.ts.map +1 -0
  34. package/dist/types/agent-event-wire.js +130 -0
  35. package/dist/types/agent-event-wire.js.map +1 -0
  36. package/dist/types/agent-event.d.ts +48 -6
  37. package/dist/types/agent-event.d.ts.map +1 -1
  38. package/dist/types/index.d.ts +3 -2
  39. package/dist/types/index.js +2 -1
  40. package/dist/types/memory.d.ts +11 -0
  41. package/dist/types/memory.d.ts.map +1 -1
  42. package/dist/types/run.d.ts +86 -4
  43. package/dist/types/run.d.ts.map +1 -1
  44. package/dist/types/run.js.map +1 -1
  45. package/dist/types/tool.d.ts +10 -0
  46. package/dist/types/tool.d.ts.map +1 -1
  47. package/dist/types/usage.d.ts +11 -1
  48. package/dist/types/usage.d.ts.map +1 -1
  49. package/dist/types/usage.js.map +1 -1
  50. package/dist/utils/binary-json.d.ts +165 -0
  51. package/dist/utils/binary-json.d.ts.map +1 -0
  52. package/dist/utils/binary-json.js +240 -0
  53. package/dist/utils/binary-json.js.map +1 -0
  54. package/dist/utils/index.d.ts +2 -1
  55. package/dist/utils/index.js +2 -1
  56. package/dist/utils/validation.d.ts +10 -1
  57. package/dist/utils/validation.d.ts.map +1 -1
  58. package/dist/utils/validation.js +1 -1
  59. package/dist/utils/validation.js.map +1 -1
  60. package/package.json +9 -7
  61. package/src/channels/channels.ts +206 -0
  62. package/src/channels/directive.ts +41 -0
  63. package/src/channels/dispatch.ts +37 -0
  64. package/src/channels/durable.ts +151 -0
  65. package/src/channels/index.ts +62 -0
  66. package/src/channels/pause.ts +216 -0
  67. package/src/contracts/auth-token-store.ts +42 -0
  68. package/src/contracts/checkpoint-store.ts +256 -0
  69. package/src/contracts/embedder.ts +42 -0
  70. package/src/contracts/eval-scorer.ts +44 -0
  71. package/src/contracts/index.ts +112 -0
  72. package/src/contracts/local-provider-trust.ts +33 -0
  73. package/src/contracts/logger.ts +61 -0
  74. package/src/contracts/memory-store.ts +187 -0
  75. package/src/contracts/oauth-server-store.ts +78 -0
  76. package/src/contracts/preferred-model.ts +56 -0
  77. package/src/contracts/provider.ts +316 -0
  78. package/src/contracts/reasoning-retention.ts +52 -0
  79. package/src/contracts/redaction-validator.ts +56 -0
  80. package/src/contracts/sandbox.ts +70 -0
  81. package/src/contracts/secret-ref.ts +22 -0
  82. package/src/contracts/secret-value.ts +117 -0
  83. package/src/contracts/secrets-store.ts +90 -0
  84. package/src/contracts/session-store.ts +163 -0
  85. package/src/contracts/token-counter.ts +23 -0
  86. package/src/contracts/tool.ts +397 -0
  87. package/src/contracts/tracer.ts +219 -0
  88. package/src/contracts/trigger-store.ts +40 -0
  89. package/src/index.ts +23 -0
  90. package/src/types/agent-event-wire.ts +193 -0
  91. package/src/types/agent-event.ts +579 -0
  92. package/src/types/handoff.ts +111 -0
  93. package/src/types/index.ts +148 -0
  94. package/src/types/memory.ts +427 -0
  95. package/src/types/message.ts +174 -0
  96. package/src/types/run.ts +312 -0
  97. package/src/types/sensitivity.ts +35 -0
  98. package/src/types/session-scope.ts +18 -0
  99. package/src/types/stop-condition.ts +108 -0
  100. package/src/types/tool-call.ts +24 -0
  101. package/src/types/tool.ts +324 -0
  102. package/src/types/usage.ts +120 -0
  103. package/src/types/workflow-event.ts +132 -0
  104. package/src/utils/assert-never.ts +24 -0
  105. package/src/utils/async-context.ts +55 -0
  106. package/src/utils/binary-json.ts +425 -0
  107. package/src/utils/hash.ts +122 -0
  108. package/src/utils/index.ts +57 -0
  109. package/src/utils/streams.ts +233 -0
  110. package/src/utils/validation.ts +82 -0
@@ -0,0 +1,174 @@
1
+ import type { ToolCall } from './tool-call.js';
2
+
3
+ /**
4
+ * A single multimodal content part attached to a chat-style message.
5
+ *
6
+ * The discriminated union is exhaustive: every variant carries a literal
7
+ * `type` field used by both the runtime and the type system to pick the
8
+ * branch. New variants must be added to all three of: this union, every
9
+ * `assertNever` switch in the codebase, and the wire-stable adapters.
10
+ *
11
+ * @stable
12
+ */
13
+ export type MessageContent =
14
+ | TextContent
15
+ | ImageContent
16
+ | AudioContent
17
+ | FileContent
18
+ | ReasoningContent;
19
+
20
+ /**
21
+ * Plain UTF-8 text part. The default for textual replies and tool I/O.
22
+ *
23
+ * @stable
24
+ */
25
+ export interface TextContent {
26
+ readonly type: 'text';
27
+ readonly text: string;
28
+ /**
29
+ * Optional opaque trace of the agent-runtime decisions that produced
30
+ * this content part. Bounded-length, no PII, no secret values.
31
+ * Round-tripped bytes-equal through `Session.push / list / export /
32
+ * import`. See `@graphorin/sessions` commentary-phase sanitization.
33
+ */
34
+ readonly causalityChain?: ReadonlyArray<string>;
35
+ }
36
+
37
+ /**
38
+ * Image attachment. The `image` field accepts either raw bytes or a `URL`
39
+ * - adapters dereference the URL when the provider only accepts inline
40
+ * payloads.
41
+ *
42
+ * @stable
43
+ */
44
+ export interface ImageContent {
45
+ readonly type: 'image';
46
+ readonly image: Uint8Array | URL;
47
+ readonly mimeType?: string;
48
+ /** See {@link TextContent.causalityChain}. */
49
+ readonly causalityChain?: ReadonlyArray<string>;
50
+ }
51
+
52
+ /**
53
+ * Audio attachment (e.g. voice messages). Note: voice realtime / TTS / STT
54
+ * are out of scope for v0.1 - these messages are static blobs.
55
+ *
56
+ * @stable
57
+ */
58
+ export interface AudioContent {
59
+ readonly type: 'audio';
60
+ readonly audio: Uint8Array | URL;
61
+ readonly mimeType?: string;
62
+ /** See {@link TextContent.causalityChain}. */
63
+ readonly causalityChain?: ReadonlyArray<string>;
64
+ }
65
+
66
+ /**
67
+ * Generic file attachment (PDF, CSV, …). `mimeType` is mandatory because
68
+ * many providers gate file ingestion on it.
69
+ *
70
+ * @stable
71
+ */
72
+ export interface FileContent {
73
+ readonly type: 'file';
74
+ readonly file: Uint8Array | URL;
75
+ readonly mimeType: string;
76
+ readonly filename?: string;
77
+ /** See {@link TextContent.causalityChain}. */
78
+ readonly causalityChain?: ReadonlyArray<string>;
79
+ }
80
+
81
+ /**
82
+ * Reasoning content emitted by reasoning-capable models. Stored
83
+ * separately from `text` so that consumers can choose to hide / strip
84
+ * it (per the streaming-first principle and the replay-redaction
85
+ * policy).
86
+ *
87
+ * @stable
88
+ */
89
+ export interface ReasoningContent {
90
+ readonly type: 'reasoning';
91
+ readonly text: string;
92
+ /**
93
+ * Provider-specific opaque metadata that MUST round-trip byte-equal
94
+ * when the effective `reasoningRetention` is not `'strip'`. The
95
+ * field is provider-supplied protocol payload, not user content,
96
+ * and is therefore exempt from prompt-redaction scanning.
97
+ *
98
+ * Anthropic Claude tool-use thinking blocks supply
99
+ * `{ provider: 'anthropic', signature, data? }`; other providers
100
+ * are free to populate whatever opaque keys their wire contract
101
+ * requires. Adapters that do not need round-tripping omit this
102
+ * field entirely.
103
+ */
104
+ readonly meta?: ReasoningContentMeta;
105
+ /** See {@link TextContent.causalityChain}. */
106
+ readonly causalityChain?: ReadonlyArray<string>;
107
+ }
108
+
109
+ /**
110
+ * Opaque metadata round-tripped on `ReasoningContent`. Adapter-defined
111
+ * keys; consumers must NOT introspect or modify the contents.
112
+ *
113
+ * @stable
114
+ */
115
+ export interface ReasoningContentMeta {
116
+ readonly provider?: string;
117
+ readonly signature?: string;
118
+ readonly data?: string;
119
+ readonly [extraKey: string]: unknown;
120
+ }
121
+
122
+ /**
123
+ * Logical role of a message in a conversation.
124
+ *
125
+ * @stable
126
+ */
127
+ export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
128
+
129
+ /**
130
+ * Chat message. The shape is provider-agnostic: adapters convert it to /
131
+ * from the wire format.
132
+ *
133
+ * - System messages must be plain strings (multimodal system messages are
134
+ * not in the v0.1 surface).
135
+ * - Assistant messages may carry `toolCalls` alongside their content.
136
+ * - Tool messages carry the originating `toolCallId` so the model can
137
+ * correlate the response to its previous request.
138
+ *
139
+ * @stable
140
+ */
141
+ export type Message = SystemMessage | UserMessage | AssistantMessage | ToolMessage;
142
+
143
+ /** @stable */
144
+ export interface SystemMessage {
145
+ readonly role: 'system';
146
+ readonly content: string;
147
+ }
148
+
149
+ /** @stable */
150
+ export interface UserMessage {
151
+ readonly role: 'user';
152
+ readonly content: string | readonly MessageContent[];
153
+ /** Multi-agent attribution: which user persona this came from, if any. */
154
+ readonly userId?: string;
155
+ }
156
+
157
+ /** @stable */
158
+ export interface AssistantMessage {
159
+ readonly role: 'assistant';
160
+ readonly content: string | readonly MessageContent[];
161
+ readonly toolCalls?: readonly ToolCall[];
162
+ /**
163
+ * Multi-agent attribution: which agent produced this message. Required
164
+ * by the multi-agent crew acceptance criteria.
165
+ */
166
+ readonly agentId?: string;
167
+ }
168
+
169
+ /** @stable */
170
+ export interface ToolMessage {
171
+ readonly role: 'tool';
172
+ readonly toolCallId: string;
173
+ readonly content: string | readonly MessageContent[];
174
+ }
@@ -0,0 +1,312 @@
1
+ import type { Tracer } from '../contracts/tracer.js';
2
+ import type { HandoffRecord } from './handoff.js';
3
+ import type { Message } from './message.js';
4
+ import type { CompletedToolCall, ToolApproval } from './tool.js';
5
+ import type { ToolCall } from './tool-call.js';
6
+ import type { ModelUsage, Usage, UsageAccumulator } from './usage.js';
7
+
8
+ /**
9
+ * Status of an in-flight or completed agent run. Append-only persistence
10
+ * stores expose this verbatim on the `runs` table.
11
+ *
12
+ * @stable
13
+ */
14
+ export type RunStatus = 'running' | 'completed' | 'failed' | 'aborted' | 'awaiting_approval';
15
+
16
+ /**
17
+ * Single step inside an agent run. The agent runtime appends one
18
+ * `RunStep` per provider call.
19
+ *
20
+ * @stable
21
+ */
22
+ export interface RunStep {
23
+ readonly stepNumber: number;
24
+ readonly startedAt: string;
25
+ readonly endedAt?: string;
26
+ readonly usage?: Usage;
27
+ readonly toolCalls: readonly CompletedToolCall[];
28
+ /**
29
+ * Stable agent id active for this step (changes after a handoff).
30
+ */
31
+ readonly agentId: string;
32
+ /**
33
+ * The model response this step produced, recorded when the agent runs
34
+ * with `recordProviderResponses: true` (C3). Enables deterministic
35
+ * replay: `createReplayProvider(state)` serves these back in order so
36
+ * a run re-executes without live model calls.
37
+ */
38
+ readonly providerResponse?: RunStepProviderResponse;
39
+ }
40
+
41
+ /**
42
+ * Journaled model response for one step (C3, opt-in via the agent's
43
+ * `recordProviderResponses`). Captures the RAW model output - the text
44
+ * before any lateral-leak block replaced it in the transcript - so a
45
+ * replay reproduces the original run faithfully.
46
+ *
47
+ * @stable
48
+ */
49
+ export interface RunStepProviderResponse {
50
+ readonly modelId: string;
51
+ readonly text?: string;
52
+ readonly toolCalls?: ReadonlyArray<ToolCall>;
53
+ }
54
+
55
+ /**
56
+ * Per-model usage breakdown carried alongside the aggregate
57
+ * {@link Usage} on {@link RunState}. Populated by the per-step retry
58
+ * loop when `Agent.fallbackModels` fires; for runs that never fall
59
+ * back, the map carries a single entry for the primary model with
60
+ * `attemptCount: 1`.
61
+ *
62
+ * The aggregate `RunState.usage` is always the sum of every entry's
63
+ * `Usage` portion (the field is asserted in tests).
64
+ *
65
+ * @stable
66
+ */
67
+ export interface RunStateUsageByModel {
68
+ readonly [modelId: string]: Usage & { readonly attemptCount: number };
69
+ }
70
+
71
+ /**
72
+ * The full, serializable state of a run. The agent runtime persists this
73
+ * to the checkpoint store on every `awaiting_approval` boundary, so a
74
+ * separate process can resume the run.
75
+ *
76
+ * JSON stability is guaranteed by the serializer, not by naive
77
+ * `JSON.stringify`: `messages` and tool-outcome `contentParts` may carry
78
+ * `Uint8Array | URL` payloads, which the documented wire projection
79
+ * (`WireRunState` via `toJsonSafeRunState`) encodes as base64 / href
80
+ * envelopes before stringification. No `Map`, `Set` or `Date` appears
81
+ * anywhere in the shape.
82
+ *
83
+ * @stable
84
+ */
85
+ export interface RunState {
86
+ readonly id: string;
87
+ readonly agentId: string;
88
+ /**
89
+ * The agent whose model drives the NEXT step. During a handoff it is
90
+ * the target for exactly the child observation window and is restored
91
+ * to the parent when the child returns (W-034) - the child's identity
92
+ * is durably recorded in {@link RunState.handoffs}, never here.
93
+ */
94
+ readonly currentAgentId: string;
95
+ readonly sessionId: string;
96
+ readonly userId?: string;
97
+ status: RunStatus;
98
+ readonly steps: RunStep[];
99
+ readonly messages: Message[];
100
+ readonly pendingApprovals: ToolApproval[];
101
+ readonly handoffs: HandoffRecord[];
102
+ readonly usage: Usage;
103
+ /**
104
+ * Per-model usage breakdown. Populated by the per-step retry loop
105
+ * when `Agent.fallbackModels` fires (RB-48 / suggested DEC-164 /
106
+ * suggested ADR-052). Backward-compat: rehydrating a serialized
107
+ * state that omits the field synthesizes a single-entry map for
108
+ * the primary model.
109
+ */
110
+ usageByModel?: RunStateUsageByModel;
111
+ /**
112
+ * AG-19: coarse data-flow taint summary, carried across suspend/resume so a
113
+ * resumed run does not start with an empty ledger that silently un-gates
114
+ * sinks exposed before the suspend. Structurally matches
115
+ * `@graphorin/security`'s `TaintLedgerSnapshot` (core takes no security
116
+ * dependency); only the load-bearing flags are persisted - never the tracked
117
+ * untrusted text spans.
118
+ */
119
+ taintSummary?: RunTaintSummary;
120
+ /**
121
+ * AG-19: names of deferred tools promoted by `tool_search` this run, carried
122
+ * across suspend/resume so discovered tools remain in the per-step catalogue.
123
+ */
124
+ promotedTools?: ReadonlyArray<string>;
125
+ /**
126
+ * D6 structured plan/todo list - the agent's own working plan,
127
+ * journaled so it survives suspend/resume (a TodoWrite-style tool
128
+ * mutates it, and attention-recitation renders it back into the
129
+ * prompt each turn). Absent until the agent writes one.
130
+ */
131
+ todos?: ReadonlyArray<TodoItem>;
132
+ /**
133
+ * W-001: sub-agent runs parked on this (parent) run because the
134
+ * child suspended with `awaiting_approval`. Each entry snapshots the
135
+ * suspended child state; the child's pending approvals are mirrored
136
+ * onto this run's `pendingApprovals` with `subRunToolCallId` set to
137
+ * the entry's `toolCallId`. Absent until a child parks.
138
+ */
139
+ pendingSubRuns?: PendingSubRun[];
140
+ readonly startedAt: string;
141
+ finishedAt?: string;
142
+ error?: RunError;
143
+ }
144
+
145
+ /**
146
+ * One sub-agent run parked on its parent because the child suspended
147
+ * awaiting approvals (W-001). `state` is a JSON-compatible snapshot of
148
+ * the suspended child run; in serialized form (the agent package's
149
+ * `SerializedRunState`) it carries the child's own version-stamped,
150
+ * secret-redacted snapshot, recursively.
151
+ *
152
+ * @stable
153
+ */
154
+ export interface PendingSubRun {
155
+ /** The PARENT's toolCallId of the parked handoff / sub-agent call. */
156
+ readonly toolCallId: string;
157
+ /** The parent-side tool name (`transfer_to_<name>` or the toTool name). */
158
+ readonly toolName: string;
159
+ /** The child agent's configured name (for diagnostics and usage folding). */
160
+ readonly targetAgentName: string;
161
+ /** Suspended child run state (carries the child's own pendingApprovals). */
162
+ readonly state: RunState;
163
+ }
164
+
165
+ /**
166
+ * Read-only projection of {@link RunState} handed to tools and hooks
167
+ * via {@link RunContext.state} (W-047). Structurally identical to
168
+ * `RunState` - `RunState` is assignable to it - but every property is
169
+ * `readonly` and every array a `ReadonlyArray`, so typed tool code
170
+ * cannot corrupt run bookkeeping (splice `pendingApprovals`, flip
171
+ * `status`, ...). This is a compile-time contract only: there is no
172
+ * runtime freeze. A hand-written mirror (not a generic DeepReadonly):
173
+ * the nested types are already readonly-typed, and keyof-parity with
174
+ * `RunState` is pinned by type tests.
175
+ *
176
+ * @stable
177
+ */
178
+ export interface ReadonlyRunState {
179
+ readonly id: string;
180
+ readonly agentId: string;
181
+ readonly currentAgentId: string;
182
+ readonly sessionId: string;
183
+ readonly userId?: string;
184
+ readonly status: RunStatus;
185
+ readonly steps: ReadonlyArray<RunStep>;
186
+ readonly messages: ReadonlyArray<Message>;
187
+ readonly pendingApprovals: ReadonlyArray<ToolApproval>;
188
+ readonly handoffs: ReadonlyArray<HandoffRecord>;
189
+ readonly usage: Usage;
190
+ /** See {@link RunState.usageByModel}. */
191
+ readonly usageByModel?: RunStateUsageByModel;
192
+ /** See {@link RunState.taintSummary}. */
193
+ readonly taintSummary?: RunTaintSummary;
194
+ /** See {@link RunState.promotedTools}. */
195
+ readonly promotedTools?: ReadonlyArray<string>;
196
+ /** See {@link RunState.todos}. */
197
+ readonly todos?: ReadonlyArray<TodoItem>;
198
+ /** See {@link RunState.pendingSubRuns}. */
199
+ readonly pendingSubRuns?: ReadonlyArray<PendingSubRun>;
200
+ readonly startedAt: string;
201
+ readonly finishedAt?: string;
202
+ readonly error?: RunError;
203
+ }
204
+
205
+ /**
206
+ * Coarse, serializable data-flow taint summary persisted in {@link RunState}
207
+ * across suspend/resume (AG-19). Structurally identical to
208
+ * `@graphorin/security`'s `TaintLedgerSnapshot`; carries no untrusted text.
209
+ *
210
+ * @stable
211
+ */
212
+ export interface RunTaintSummary {
213
+ readonly untrustedSeen: boolean;
214
+ readonly sensitiveSeen: boolean;
215
+ readonly untrustedSourceKinds: ReadonlyArray<string>;
216
+ /**
217
+ * C6: one-way FNV-1a hashes of normalized untrusted-span tiles. Re-arms
218
+ * the verbatim-carry probe after a resume at tile granularity. Hashes
219
+ * only - no untrusted text is ever persisted (the invariant above
220
+ * holds).
221
+ */
222
+ readonly spanTileHashes?: ReadonlyArray<string>;
223
+ }
224
+
225
+ /**
226
+ * One item in the agent's structured plan (D6). `status` drives both
227
+ * the recitation rendering and progress reporting; `id` lets a
228
+ * status-flip mutation target an item without rewriting the list.
229
+ *
230
+ * @stable
231
+ */
232
+ export interface TodoItem {
233
+ readonly id: string;
234
+ readonly content: string;
235
+ readonly status: 'pending' | 'in_progress' | 'completed';
236
+ }
237
+
238
+ /**
239
+ * Snapshot helper used by `@graphorin/observability` aggregators to
240
+ * convert the on-disk `usageByModel` shape into the canonical
241
+ * {@link ModelUsage} array. Pure utility - kept in core so consumers
242
+ * do not have to take an observability dependency just to flatten a
243
+ * run-state breakdown.
244
+ *
245
+ * @stable
246
+ */
247
+ export function flattenUsageByModel(
248
+ byModel: RunStateUsageByModel | undefined,
249
+ ): ReadonlyArray<ModelUsage> {
250
+ if (byModel === undefined) return [];
251
+ const out: ModelUsage[] = [];
252
+ for (const [modelId, entry] of Object.entries(byModel)) {
253
+ const m: ModelUsage = {
254
+ modelId,
255
+ promptTokens: entry.promptTokens,
256
+ completionTokens: entry.completionTokens,
257
+ totalTokens: entry.totalTokens,
258
+ callCount: entry.attemptCount,
259
+ ...(entry.reasoningTokens !== undefined ? { reasoningTokens: entry.reasoningTokens } : {}),
260
+ ...(entry.cost !== undefined ? { cost: entry.cost } : {}),
261
+ };
262
+ out.push(m);
263
+ }
264
+ return out;
265
+ }
266
+
267
+ /**
268
+ * Failure carried by `RunState.error`. The shape mirrors the wire format
269
+ * used by `agent.error` events.
270
+ *
271
+ * @stable
272
+ */
273
+ export interface RunError {
274
+ readonly message: string;
275
+ readonly code: string;
276
+ readonly details?: unknown;
277
+ }
278
+
279
+ /**
280
+ * Per-run dependency / context bag handed to every tool, hook and
281
+ * provider middleware in scope. Generic over the user-defined deps shape.
282
+ *
283
+ * `tracer`, `signal`, `usage` and `state` are always present; everything
284
+ * else is optional.
285
+ *
286
+ * @stable
287
+ */
288
+ export interface RunContext<TDeps = unknown> {
289
+ readonly runId: string;
290
+ readonly sessionId: string;
291
+ readonly userId?: string;
292
+ readonly agentId: string;
293
+ readonly deps: TDeps;
294
+ readonly tracer: Tracer;
295
+ readonly signal: AbortSignal;
296
+ readonly usage: UsageAccumulator;
297
+ readonly stepNumber: number;
298
+ readonly messages: ReadonlyArray<Message>;
299
+ /**
300
+ * Read-only snapshot of the run's state (W-047). Tools observe the
301
+ * run; they do not mutate its bookkeeping - writes to `status`,
302
+ * `pendingApprovals` etc. are compile errors. The runtime keeps the
303
+ * only mutable reference.
304
+ */
305
+ readonly state: ReadonlyRunState;
306
+ /**
307
+ * C7: the current `agent.step` span (when the runtime traces). Spans
308
+ * created inside tool execution parent under it so a run's traces
309
+ * form one tree.
310
+ */
311
+ readonly span?: import('../contracts/tracer.js').AISpan;
312
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Sensitivity tier for any piece of data flowing through Graphorin.
3
+ *
4
+ * - `'public'` - non-sensitive content; safe for any provider, any sink.
5
+ * - `'internal'` - default for user-generated content; safe for trusted
6
+ * providers (loopback / private-network) but redacted for public-tls
7
+ * exporters and replay consumers.
8
+ * - `'secret'` - credentials, tokens, encryption keys; only ever stays
9
+ * in-process and is never serialized to the wire by default.
10
+ *
11
+ * @stable
12
+ */
13
+ export type Sensitivity = 'public' | 'internal' | 'secret';
14
+
15
+ /**
16
+ * Strict ordering used by sensitivity-aware filters
17
+ * (`record.sensitivity ⊆ provider.acceptsSensitivity`).
18
+ *
19
+ * @stable
20
+ */
21
+ export const SENSITIVITY_ORDER: readonly Sensitivity[] = ['public', 'internal', 'secret'] as const;
22
+
23
+ /**
24
+ * Return `true` iff `record` is allowed to flow to a sink declaring `accepts`.
25
+ *
26
+ * Comparison is **subset** semantics: the record's tier must be one of the
27
+ * tiers in `accepts` (it's not enough for the record's tier to be lower).
28
+ * That mirrors the way provider `acceptsSensitivity` is declared in the
29
+ * Graphorin trust matrix.
30
+ *
31
+ * @stable
32
+ */
33
+ export function acceptsSensitivity(accepts: readonly Sensitivity[], record: Sensitivity): boolean {
34
+ return accepts.includes(record);
35
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Identifies a logical conversational scope: who the user is, which agent
3
+ * is in charge, and (when known) which session they're inside.
4
+ *
5
+ * Used as a parameter to almost every Memory / Sessions API. The agent and
6
+ * session fields are optional because some scopes are user-wide (e.g.
7
+ * shared facts attached to a user, not a particular agent).
8
+ *
9
+ * @stable
10
+ */
11
+ export interface SessionScope {
12
+ /** Stable identifier of the user (single-user-per-process by default). */
13
+ readonly userId: string;
14
+ /** Identifier of the agent owning the scope, when applicable. */
15
+ readonly agentId?: string;
16
+ /** Identifier of the session, when applicable. */
17
+ readonly sessionId?: string;
18
+ }
@@ -0,0 +1,108 @@
1
+ import type { RunState } from './run.js';
2
+
3
+ /**
4
+ * Predicate consulted by the agent runtime after every step to decide
5
+ * whether the loop should stop.
6
+ *
7
+ * Stop conditions are pure - they look at the current `RunState` and
8
+ * return a boolean. The runtime never re-orders or short-circuits the
9
+ * order in which operands of `and` / `or` are evaluated, so users can
10
+ * rely on the obvious left-to-right semantics.
11
+ *
12
+ * @stable
13
+ */
14
+ export interface StopCondition {
15
+ /** Human-friendly label included in observability spans. */
16
+ readonly description: string;
17
+ /** Returns `true` when the run should stop on this state. */
18
+ readonly check: (state: RunState) => boolean;
19
+ }
20
+
21
+ /**
22
+ * Stop after `n` total steps (`stepNumber >= n`). The default condition
23
+ * for the agent runtime is `isStepCount(50)`.
24
+ *
25
+ * @stable
26
+ */
27
+ export function isStepCount(n: number): StopCondition {
28
+ if (!Number.isFinite(n) || n <= 0) {
29
+ throw new RangeError(`isStepCount: n must be a positive integer (got ${String(n)})`);
30
+ }
31
+ return {
32
+ description: `step >= ${n}`,
33
+ check: (state): boolean => state.steps.length >= n,
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Stop as soon as the most recent assistant message contains a tool call
39
+ * with the given name.
40
+ *
41
+ * @stable
42
+ */
43
+ export function hasToolCall(toolName: string): StopCondition {
44
+ return {
45
+ description: `tool-call:${toolName}`,
46
+ check: (state): boolean => {
47
+ for (let i = state.messages.length - 1; i >= 0; i--) {
48
+ const msg = state.messages[i];
49
+ if (msg && msg.role === 'assistant') {
50
+ const calls = msg.toolCalls;
51
+ if (calls?.some((c) => c.toolName === toolName)) {
52
+ return true;
53
+ }
54
+ // First assistant message without the call → not yet matched.
55
+ return false;
56
+ }
57
+ }
58
+ return false;
59
+ },
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Stop when the run reaches a terminal status.
65
+ *
66
+ * @stable
67
+ */
68
+ export const isTerminal: StopCondition = {
69
+ description: 'status:terminal',
70
+ check: (state): boolean =>
71
+ state.status === 'completed' || state.status === 'failed' || state.status === 'aborted',
72
+ };
73
+
74
+ /**
75
+ * Stop when **any** of the supplied conditions is satisfied.
76
+ *
77
+ * @stable
78
+ */
79
+ export function or(...conditions: readonly StopCondition[]): StopCondition {
80
+ return {
81
+ description: `or(${conditions.map((c) => c.description).join(', ')})`,
82
+ check: (state): boolean => conditions.some((c) => c.check(state)),
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Stop only when **all** of the supplied conditions are satisfied.
88
+ *
89
+ * @stable
90
+ */
91
+ export function and(...conditions: readonly StopCondition[]): StopCondition {
92
+ return {
93
+ description: `and(${conditions.map((c) => c.description).join(', ')})`,
94
+ check: (state): boolean => conditions.every((c) => c.check(state)),
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Negate the supplied condition.
100
+ *
101
+ * @stable
102
+ */
103
+ export function not(condition: StopCondition): StopCondition {
104
+ return {
105
+ description: `not(${condition.description})`,
106
+ check: (state): boolean => !condition.check(state),
107
+ };
108
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The {@link ToolCall} leaf type lives in its own module so that
3
+ * `message.ts` (which references `ToolCall`) and `tool.ts` (which
4
+ * references `MessageContent`) can both depend on it without forming a
5
+ * circular import. `tool.ts` re-exports `ToolCall` for backwards
6
+ * compatibility, so external import paths are unchanged.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+
11
+ /**
12
+ * A single tool invocation the model requested, normalised by the
13
+ * provider layer and handed to the tool executor for parallel dispatch.
14
+ *
15
+ * @stable
16
+ */
17
+ export interface ToolCall {
18
+ /** Stable identifier the model uses to correlate input and output. */
19
+ readonly toolCallId: string;
20
+ /** Tool name as registered in the `ToolRegistry`. */
21
+ readonly toolName: string;
22
+ /** Validated input matching the tool's `inputSchema`. */
23
+ readonly args: unknown;
24
+ }