@adriane-ai/graph-sdk 0.1.0-rc.1

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.
@@ -0,0 +1,2684 @@
1
+ type MessageId = Brand<string, "MessageId">;
2
+ type ToolCall = {
3
+ id: string;
4
+ name: string;
5
+ input: unknown;
6
+ };
7
+ type BaseMessage = {
8
+ id: MessageId;
9
+ createdAt: Date;
10
+ metadata?: Record<string, unknown>;
11
+ };
12
+ type HumanMessage = BaseMessage & {
13
+ role: "human";
14
+ content: string;
15
+ };
16
+ type AIMessage = BaseMessage & {
17
+ role: "ai";
18
+ content: string;
19
+ toolCalls?: ToolCall[];
20
+ };
21
+ type ToolMessage = BaseMessage & {
22
+ role: "tool";
23
+ toolCallId: string;
24
+ content: string;
25
+ };
26
+ type SystemMessage = BaseMessage & {
27
+ role: "system";
28
+ content: string;
29
+ };
30
+ type Message = HumanMessage | AIMessage | ToolMessage | SystemMessage;
31
+
32
+ type Brand<T, TBrand extends string> = T & {
33
+ readonly __brand: TBrand;
34
+ };
35
+ type NodeId = Brand<string, "NodeId">;
36
+ type EdgeId = Brand<string, "EdgeId">;
37
+ type GraphId = Brand<string, "GraphId">;
38
+ type RunId = Brand<string, "RunId">;
39
+ type ChannelReducer = "replace" | "append" | "merge";
40
+ type ChannelDefinition<T> = {
41
+ type: string;
42
+ reducer: ChannelReducer;
43
+ default?: T;
44
+ };
45
+ type ChannelsSchema = Record<string, ChannelDefinition<unknown>>;
46
+ type ResolvedChannels<TChannels extends ChannelsSchema> = {
47
+ [K in keyof TChannels]: TChannels[K] extends ChannelDefinition<infer TValue> ? TValue : never;
48
+ };
49
+ declare const NODE_TYPES: readonly ["action", "agent", "tool", "human-gate", "subgraph"];
50
+ type NodeType = (typeof NODE_TYPES)[number];
51
+ declare const EDGE_TYPES: readonly ["default", "conditional"];
52
+ type EdgeType = (typeof EDGE_TYPES)[number];
53
+ declare const GRAPH_STATUSES: readonly ["idle", "running", "suspended", "completed", "failed"];
54
+ type GraphStatus = (typeof GRAPH_STATUSES)[number];
55
+ type RetryPolicy = {
56
+ maxAttempts: number;
57
+ backoffMs: number;
58
+ };
59
+ type Command<TChannels extends ChannelsSchema = ChannelsSchema> = {
60
+ goto: NodeId | NodeId[];
61
+ update?: Partial<ResolvedChannels<TChannels>>;
62
+ };
63
+ type NodeDefinition = {
64
+ id: NodeId;
65
+ type: NodeType;
66
+ label: string;
67
+ subgraphId?: GraphId;
68
+ inputMapping?: Record<string, string>;
69
+ outputMapping?: Record<string, string>;
70
+ fanOut?: {
71
+ parallelTo: NodeId[];
72
+ joinAt: NodeId;
73
+ };
74
+ retryPolicy?: RetryPolicy;
75
+ metadata?: Record<string, unknown>;
76
+ };
77
+ type EdgeDefinition = {
78
+ id: EdgeId;
79
+ from: NodeId;
80
+ to: NodeId;
81
+ type: EdgeType;
82
+ condition?: string;
83
+ };
84
+ type GraphState<TChannels extends ChannelsSchema = ChannelsSchema> = {
85
+ runId: RunId;
86
+ graphId: GraphId;
87
+ currentNodeId: NodeId;
88
+ status: GraphStatus;
89
+ channels: ResolvedChannels<TChannels>;
90
+ version: number;
91
+ checkpointId?: string;
92
+ createdAt: string;
93
+ updatedAt: string;
94
+ };
95
+ type GraphDefinition<TChannels extends ChannelsSchema = ChannelsSchema> = {
96
+ id: GraphId;
97
+ version: string;
98
+ name: string;
99
+ recursionLimit?: number;
100
+ channels: TChannels;
101
+ nodes: NodeDefinition[];
102
+ edges: EdgeDefinition[];
103
+ entryNodeId: NodeId;
104
+ metadata?: Record<string, unknown>;
105
+ };
106
+
107
+ declare const GRAPH_VALIDATION_ERROR_CODES: {
108
+ readonly DUPLICATE_NODE_ID: "DUPLICATE_NODE_ID";
109
+ readonly DUPLICATE_EDGE_ID: "DUPLICATE_EDGE_ID";
110
+ readonly MISSING_ENTRY_NODE: "MISSING_ENTRY_NODE";
111
+ readonly INVALID_EDGE_REFERENCE: "INVALID_EDGE_REFERENCE";
112
+ readonly CYCLE_DETECTED: "CYCLE_DETECTED";
113
+ readonly INVALID_CONDITION_FORMAT: "INVALID_CONDITION_FORMAT";
114
+ };
115
+ type GraphValidationErrorCode = (typeof GRAPH_VALIDATION_ERROR_CODES)[keyof typeof GRAPH_VALIDATION_ERROR_CODES];
116
+ type GraphValidationPath = (string | number)[];
117
+ declare class GraphValidationError extends Error {
118
+ readonly code: GraphValidationErrorCode;
119
+ readonly path: GraphValidationPath;
120
+ constructor(code: GraphValidationErrorCode, message: string, path?: GraphValidationPath);
121
+ }
122
+
123
+ type ArtifactId = string & {
124
+ readonly __brand: "ArtifactId";
125
+ };
126
+ type ArtifactVersion = number;
127
+ type ArtifactRef = {
128
+ id: ArtifactId;
129
+ version: ArtifactVersion;
130
+ };
131
+
132
+ type MemoryNamespace = string[];
133
+ type MemoryKey = string;
134
+ type MemoryItem = {
135
+ namespace: MemoryNamespace;
136
+ key: MemoryKey;
137
+ value: unknown;
138
+ createdAt: string;
139
+ updatedAt: string;
140
+ embedding?: number[];
141
+ };
142
+
143
+ interface BaseStore {
144
+ get(namespace: MemoryNamespace, key: MemoryKey): Promise<MemoryItem | undefined>;
145
+ put(namespace: MemoryNamespace, key: MemoryKey, value: unknown): Promise<MemoryItem>;
146
+ delete(namespace: MemoryNamespace, key: MemoryKey): Promise<void>;
147
+ search(namespace: MemoryNamespace, query: string, topK: number): Promise<MemoryItem[]>;
148
+ list(namespace: MemoryNamespace, prefix?: string): Promise<MemoryItem[]>;
149
+ }
150
+
151
+ type BaseCallbackEvent = {
152
+ runId: string;
153
+ nodeId?: string;
154
+ tags?: string[];
155
+ metadata?: Record<string, unknown>;
156
+ timestamp: string;
157
+ };
158
+ type CallbackEvent = (BaseCallbackEvent & {
159
+ type: "onLLMStart";
160
+ input: unknown;
161
+ }) | (BaseCallbackEvent & {
162
+ type: "onLLMToken";
163
+ token: string;
164
+ }) | (BaseCallbackEvent & {
165
+ type: "onLLMEnd";
166
+ output: unknown;
167
+ }) | (BaseCallbackEvent & {
168
+ type: "onLLMError";
169
+ error: string;
170
+ }) | (BaseCallbackEvent & {
171
+ type: "onToolStart";
172
+ tool: string;
173
+ input: unknown;
174
+ }) | (BaseCallbackEvent & {
175
+ type: "onToolEnd";
176
+ tool: string;
177
+ output: unknown;
178
+ }) | (BaseCallbackEvent & {
179
+ type: "onToolError";
180
+ tool: string;
181
+ error: string;
182
+ }) | (BaseCallbackEvent & {
183
+ type: "onNodeStart";
184
+ input: unknown;
185
+ }) | (BaseCallbackEvent & {
186
+ type: "onNodeEnd";
187
+ output: unknown;
188
+ }) | (BaseCallbackEvent & {
189
+ type: "onNodeError";
190
+ error: string;
191
+ }) | (BaseCallbackEvent & {
192
+ type: "onChainStart";
193
+ input: unknown;
194
+ }) | (BaseCallbackEvent & {
195
+ type: "onChainEnd";
196
+ output: unknown;
197
+ }) | (BaseCallbackEvent & {
198
+ type: "onChainError";
199
+ error: string;
200
+ }) | (BaseCallbackEvent & {
201
+ type: "onAgentAction";
202
+ action: string;
203
+ payload?: unknown;
204
+ }) | (BaseCallbackEvent & {
205
+ type: "onAgentFinish";
206
+ result: unknown;
207
+ });
208
+
209
+ interface CallbackHandler {
210
+ onLLMStart?(event: Extract<CallbackEvent, {
211
+ type: "onLLMStart";
212
+ }>): void | Promise<void>;
213
+ onLLMToken?(event: Extract<CallbackEvent, {
214
+ type: "onLLMToken";
215
+ }>): void | Promise<void>;
216
+ onLLMEnd?(event: Extract<CallbackEvent, {
217
+ type: "onLLMEnd";
218
+ }>): void | Promise<void>;
219
+ onLLMError?(event: Extract<CallbackEvent, {
220
+ type: "onLLMError";
221
+ }>): void | Promise<void>;
222
+ onToolStart?(event: Extract<CallbackEvent, {
223
+ type: "onToolStart";
224
+ }>): void | Promise<void>;
225
+ onToolEnd?(event: Extract<CallbackEvent, {
226
+ type: "onToolEnd";
227
+ }>): void | Promise<void>;
228
+ onToolError?(event: Extract<CallbackEvent, {
229
+ type: "onToolError";
230
+ }>): void | Promise<void>;
231
+ onNodeStart?(event: Extract<CallbackEvent, {
232
+ type: "onNodeStart";
233
+ }>): void | Promise<void>;
234
+ onNodeEnd?(event: Extract<CallbackEvent, {
235
+ type: "onNodeEnd";
236
+ }>): void | Promise<void>;
237
+ onNodeError?(event: Extract<CallbackEvent, {
238
+ type: "onNodeError";
239
+ }>): void | Promise<void>;
240
+ onChainStart?(event: Extract<CallbackEvent, {
241
+ type: "onChainStart";
242
+ }>): void | Promise<void>;
243
+ onChainEnd?(event: Extract<CallbackEvent, {
244
+ type: "onChainEnd";
245
+ }>): void | Promise<void>;
246
+ onChainError?(event: Extract<CallbackEvent, {
247
+ type: "onChainError";
248
+ }>): void | Promise<void>;
249
+ onAgentAction?(event: Extract<CallbackEvent, {
250
+ type: "onAgentAction";
251
+ }>): void | Promise<void>;
252
+ onAgentFinish?(event: Extract<CallbackEvent, {
253
+ type: "onAgentFinish";
254
+ }>): void | Promise<void>;
255
+ }
256
+ interface CallbackManager {
257
+ addHandler(handler: CallbackHandler): void;
258
+ removeHandler(handler: CallbackHandler): void;
259
+ emit(event: CallbackEvent): Promise<void>;
260
+ createChild(tags?: string[], metadata?: Record<string, unknown>): CallbackManager;
261
+ }
262
+
263
+ declare const LLM_PROVIDERS: readonly ["openai", "anthropic", "mistral", "ollama", "mock"];
264
+ type LLMProvider = (typeof LLM_PROVIDERS)[number];
265
+ type LLMModel = string;
266
+ /** A text span in a structured message. */
267
+ type LLMTextBlock = {
268
+ type: "text";
269
+ text: string;
270
+ };
271
+ /** An assistant turn requesting a tool call. */
272
+ type LLMToolUseBlock = {
273
+ type: "tool_use";
274
+ id: string;
275
+ name: string;
276
+ input: unknown;
277
+ };
278
+ /** A user turn returning a tool's result, paired to a prior `tool_use` by id. */
279
+ type LLMToolResultBlock = {
280
+ type: "tool_result";
281
+ toolUseId: string;
282
+ content: string;
283
+ isError?: boolean;
284
+ };
285
+ type LLMContentBlock = LLMTextBlock | LLMToolUseBlock | LLMToolResultBlock;
286
+ type LLMMessage = {
287
+ role: "system" | "user" | "assistant";
288
+ /**
289
+ * Either plain text or a list of content blocks. Blocks carry `tool_use` /
290
+ * `tool_result` turns so a tool-calling agent can hold a real multi-turn
291
+ * conversation with the provider instead of stuffing observations into text.
292
+ */
293
+ content: string | LLMContentBlock[];
294
+ };
295
+ /**
296
+ * Tool definition exposed to the provider. Part of the cacheable prefix: the tool
297
+ * list must be deterministic (stable order, stable schema) or it busts the cache.
298
+ */
299
+ type LLMToolDef = {
300
+ name: string;
301
+ description?: string;
302
+ inputSchema: Record<string, unknown>;
303
+ };
304
+ type LLMRequest = {
305
+ provider: LLMProvider;
306
+ model: LLMModel;
307
+ messages: LLMMessage[];
308
+ /**
309
+ * Immutable system prompt. Forms the cacheable prefix together with `tools`.
310
+ * Keep volatile content (dates, timestamps, session ids) OUT of here.
311
+ */
312
+ system?: string;
313
+ tools?: LLMToolDef[];
314
+ maxTokens?: number;
315
+ temperature?: number;
316
+ stream?: boolean;
317
+ };
318
+ /** A structured tool call surfaced by the provider (e.g. an Anthropic `tool_use` block). */
319
+ type LLMToolCall = {
320
+ id: string;
321
+ name: string;
322
+ input: unknown;
323
+ };
324
+ type LLMResponse = {
325
+ content: string;
326
+ /**
327
+ * Structured tool calls the model wants executed. Present when the provider
328
+ * stops on a tool-use turn; consumers should run these instead of parsing the
329
+ * text content for a tool protocol.
330
+ */
331
+ toolCalls?: LLMToolCall[];
332
+ /** Why the model stopped — `"tool_use"` signals it is waiting on tool results. */
333
+ stopReason?: "end_turn" | "tool_use" | "max_tokens" | "stop_sequence" | string;
334
+ usage: {
335
+ promptTokens: number;
336
+ completionTokens: number;
337
+ /** Tokens served from the prompt cache (~0.1x cost). */
338
+ cacheReadTokens?: number;
339
+ /** Tokens written to the prompt cache this call (~1.25x cost). */
340
+ cacheWriteTokens?: number;
341
+ };
342
+ model: string;
343
+ provider: LLMProvider;
344
+ };
345
+ type LLMStreamChunk = {
346
+ delta: string;
347
+ done: boolean;
348
+ };
349
+
350
+ interface LLMProviderAdapter {
351
+ provider: LLMProvider;
352
+ complete(req: LLMRequest): Promise<LLMResponse>;
353
+ stream(req: LLMRequest): AsyncIterable<LLMStreamChunk>;
354
+ }
355
+ interface LLMGateway {
356
+ complete(req: LLMRequest): Promise<LLMResponse>;
357
+ stream(req: LLMRequest): AsyncIterable<LLMStreamChunk>;
358
+ registerAdapter(adapter: LLMProviderAdapter): void;
359
+ }
360
+
361
+ type Blocker = {
362
+ code: string;
363
+ message: string;
364
+ nodeId?: NodeId;
365
+ };
366
+ type AgentResult = {
367
+ artifacts: ArtifactRef[];
368
+ blockers: Blocker[];
369
+ approvalRequests: Array<{
370
+ subject: ArtifactRef | {
371
+ description: string;
372
+ };
373
+ reason: string;
374
+ }>;
375
+ confidence: number;
376
+ reasoning: string;
377
+ requiresHumanReview: boolean;
378
+ };
379
+
380
+ type ZodSchema<T> = {
381
+ parse(input: unknown): T;
382
+ };
383
+ type ToolId = string & {
384
+ readonly __brand: "ToolId";
385
+ };
386
+ type ToolDefinition<TInput, TOutput> = {
387
+ id: ToolId;
388
+ name: string;
389
+ description: string;
390
+ inputSchema: ZodSchema<TInput>;
391
+ outputSchema: ZodSchema<TOutput>;
392
+ permissions: string[];
393
+ requiresApproval?: boolean;
394
+ /**
395
+ * JSON Schema for the tool's input, advertised to the LLM. `inputSchema` only
396
+ * validates (`.parse`); this is what the provider needs to emit tool calls.
397
+ */
398
+ jsonSchema?: Record<string, unknown>;
399
+ };
400
+ type ToolHandler<TInput, TOutput> = (input: TInput) => Promise<TOutput>;
401
+ interface ToolRegistry {
402
+ register<TInput, TOutput>(definition: ToolDefinition<TInput, TOutput>, handler: ToolHandler<TInput, TOutput>): void;
403
+ resolve(id: ToolId): {
404
+ definition: ToolDefinition<unknown, unknown>;
405
+ handler: ToolHandler<unknown, unknown>;
406
+ } | undefined;
407
+ list(): ToolDefinition<unknown, unknown>[];
408
+ }
409
+ declare class InMemoryToolRegistry implements ToolRegistry {
410
+ private readonly entries;
411
+ register<TInput, TOutput>(definition: ToolDefinition<TInput, TOutput>, handler: ToolHandler<TInput, TOutput>): void;
412
+ resolve(id: ToolId): {
413
+ definition: ToolDefinition<unknown, unknown>;
414
+ handler: ToolHandler<unknown, unknown>;
415
+ } | undefined;
416
+ list(): ToolDefinition<unknown, unknown>[];
417
+ }
418
+
419
+ /**
420
+ * Versioned prompt registry. Agents reference prompts by id (+ optional version)
421
+ * instead of hardcoding them inline (rule 090). The `system` text is the immutable,
422
+ * cacheable prefix — keep volatile/dynamic values out of it and pass those in the
423
+ * per-call user message instead.
424
+ */
425
+ type PromptTemplate = {
426
+ id: string;
427
+ version: string;
428
+ system: string;
429
+ description?: string;
430
+ };
431
+ interface PromptRegistry {
432
+ register(template: PromptTemplate): void;
433
+ get(id: string, version?: string): PromptTemplate;
434
+ list(): PromptTemplate[];
435
+ }
436
+ declare class InMemoryPromptRegistry implements PromptRegistry {
437
+ private readonly byId;
438
+ private readonly latest;
439
+ register(template: PromptTemplate): void;
440
+ get(id: string, version?: string): PromptTemplate;
441
+ list(): PromptTemplate[];
442
+ }
443
+
444
+ type CheckpointId = string & {
445
+ readonly __brand: "CheckpointId";
446
+ };
447
+ type Checkpoint<TChannels extends ChannelsSchema = ChannelsSchema> = {
448
+ id: CheckpointId;
449
+ runId: RunId;
450
+ graphState: GraphState<TChannels>;
451
+ createdAt: string;
452
+ };
453
+ type RunEvent = {
454
+ type: "node_started";
455
+ runId: RunId;
456
+ nodeId: NodeId;
457
+ timestamp: string;
458
+ } | {
459
+ type: "node_completed";
460
+ runId: RunId;
461
+ nodeId: NodeId;
462
+ output: unknown;
463
+ timestamp: string;
464
+ } | {
465
+ type: "node_failed";
466
+ runId: RunId;
467
+ nodeId: NodeId;
468
+ error: string;
469
+ attempt: number;
470
+ timestamp: string;
471
+ } | {
472
+ type: "run_suspended";
473
+ runId: RunId;
474
+ nodeId: NodeId;
475
+ reason: string;
476
+ timestamp: string;
477
+ } | {
478
+ type: "run_resumed";
479
+ runId: RunId;
480
+ nodeId: NodeId;
481
+ timestamp: string;
482
+ } | {
483
+ type: "run_completed";
484
+ runId: RunId;
485
+ finalState: GraphState<ChannelsSchema>;
486
+ timestamp: string;
487
+ } | {
488
+ type: "run_failed";
489
+ runId: RunId;
490
+ error: string;
491
+ timestamp: string;
492
+ };
493
+
494
+ type NodeExecutionContext = {
495
+ memory: BaseStore;
496
+ };
497
+ type NodeHandler<TChannels extends ChannelsSchema = ChannelsSchema, TInput = unknown, TOutput extends Partial<ResolvedChannels<TChannels>> | Command<TChannels> = Partial<ResolvedChannels<TChannels>> | Command<TChannels>> = (input: TInput, state: GraphState<TChannels>, context: NodeExecutionContext) => Promise<TOutput>;
498
+ interface NodeRegistry {
499
+ register(nodeId: NodeId, handler: NodeHandler): void;
500
+ resolve(nodeId: NodeId): NodeHandler | undefined;
501
+ }
502
+ type ConditionFn = (state: GraphState) => boolean;
503
+ interface ConditionRegistry {
504
+ register(name: string, fn: ConditionFn): void;
505
+ resolve(name: string): ConditionFn | undefined;
506
+ }
507
+ interface Checkpointer {
508
+ save(checkpoint: Checkpoint): Promise<void>;
509
+ load(runId: RunId): Promise<Checkpoint | undefined>;
510
+ loadById(id: CheckpointId): Promise<Checkpoint | undefined>;
511
+ list(runId: RunId): Promise<Checkpoint[]>;
512
+ }
513
+ interface EventBus {
514
+ emit(event: RunEvent): void;
515
+ subscribe(handler: (event: RunEvent) => void): () => void;
516
+ }
517
+
518
+ type StepBudget = {
519
+ maxSteps: number;
520
+ currentSteps: number;
521
+ };
522
+
523
+ declare class InMemoryCheckpointer implements Checkpointer {
524
+ private readonly checkpointsById;
525
+ private readonly latestCheckpointByRunId;
526
+ private readonly checkpointIdsByRunId;
527
+ save(checkpoint: Checkpoint): Promise<void>;
528
+ load(runId: RunId): Promise<Checkpoint | undefined>;
529
+ loadById(id: CheckpointId): Promise<Checkpoint | undefined>;
530
+ list(runId: RunId): Promise<Checkpoint[]>;
531
+ }
532
+
533
+ declare const STREAM_MODES: readonly ["values", "updates", "debug", "messages"];
534
+ type StreamMode = (typeof STREAM_MODES)[number];
535
+ type StreamEvent = {
536
+ type: "state_value";
537
+ state: GraphState;
538
+ } | {
539
+ type: "state_update";
540
+ delta: Record<string, unknown>;
541
+ nodeId: NodeId;
542
+ } | {
543
+ type: "message_delta";
544
+ delta: string;
545
+ nodeId: NodeId;
546
+ messageId: string;
547
+ } | {
548
+ type: "tool_call";
549
+ toolId: string;
550
+ input: unknown;
551
+ nodeId: NodeId;
552
+ } | {
553
+ type: "debug";
554
+ payload: unknown;
555
+ nodeId: NodeId;
556
+ };
557
+
558
+ type InterruptConfig = {
559
+ before?: NodeId[];
560
+ after?: NodeId[];
561
+ };
562
+ declare class DynamicInterrupt extends Error {
563
+ readonly reason: string;
564
+ readonly patch?: Record<string, unknown>;
565
+ constructor(reason: string, patch?: Record<string, unknown>);
566
+ }
567
+
568
+ type GraphRuntimeDeps = {
569
+ graph: GraphDefinition<ChannelsSchema>;
570
+ nodeRegistry: NodeRegistry;
571
+ conditionRegistry: ConditionRegistry;
572
+ checkpointer: Checkpointer;
573
+ eventBus: EventBus;
574
+ callbackManager?: CallbackManager;
575
+ memory?: BaseStore;
576
+ stepBudget?: StepBudget;
577
+ subgraphResolver?: (graphId: GraphId) => GraphDefinition | undefined;
578
+ interruptConfig?: InterruptConfig;
579
+ };
580
+ declare class GraphRuntime {
581
+ private readonly graph;
582
+ private readonly nodeRegistry;
583
+ private readonly conditionRegistry;
584
+ private readonly checkpointer;
585
+ private readonly eventBus;
586
+ private readonly callbackManager;
587
+ readonly memory: BaseStore;
588
+ readonly stepBudget: StepBudget;
589
+ private readonly nodeById;
590
+ private readonly subgraphResolver?;
591
+ private readonly interruptConfig?;
592
+ private readonly stateHistoryByRunId;
593
+ private readonly stepsByRunId;
594
+ private readonly inboxByRunId;
595
+ constructor(deps: GraphRuntimeDeps);
596
+ start(runId: RunId, initialData: Record<string, unknown>): Promise<GraphState>;
597
+ stream(runId: RunId, initialData: Record<string, unknown>, mode: StreamMode): AsyncIterable<StreamEvent>;
598
+ resume(runId: RunId): Promise<GraphState>;
599
+ executeNode(nodeId: NodeId, state: GraphState): Promise<GraphState>;
600
+ nextNode(currentNodeId: NodeId, state: GraphState): NodeId | null;
601
+ send(runId: RunId, nodeId: NodeId, input: unknown): Promise<void>;
602
+ private selectNextEdge;
603
+ private runLoop;
604
+ private persistCheckpoint;
605
+ getHistory(runId: RunId): GraphState<ChannelsSchema>[];
606
+ updateState(runId: RunId, patch: Partial<Record<string, unknown>>, resumeFrom?: NodeId): Promise<GraphState>;
607
+ getCheckpoints(runId: RunId): Promise<Checkpoint[]>;
608
+ replayFrom(runId: RunId, checkpointId: CheckpointId): Promise<GraphState>;
609
+ applyUpdate(channels: Record<string, unknown>, partialUpdate: Partial<Record<string, unknown>>): Record<string, unknown>;
610
+ private buildInitialChannels;
611
+ private applyInputMapping;
612
+ private applyOutputMapping;
613
+ private setSubgraphRunId;
614
+ private getOrCreateSubgraphRunId;
615
+ private readInterruptMeta;
616
+ private clearInterruptMeta;
617
+ private suspendRun;
618
+ private computeDelta;
619
+ private areEqual;
620
+ private assertRecursionLimit;
621
+ private consumeStepBudget;
622
+ private consumeInjectedInput;
623
+ private resolveCommand;
624
+ private resolveNextNode;
625
+ private executeFanOut;
626
+ private extractMessageEvents;
627
+ private extractToolCallEvents;
628
+ }
629
+
630
+ declare class DefaultLLMGateway implements LLMGateway {
631
+ private readonly adapters;
632
+ registerAdapter(adapter: LLMProviderAdapter): void;
633
+ complete(req: LLMRequest): Promise<LLMResponse>;
634
+ stream(req: LLMRequest): AsyncIterable<LLMStreamChunk>;
635
+ private validateRequest;
636
+ }
637
+
638
+ type MockAdapterOptions = {
639
+ provider: LLMProvider;
640
+ response?: LLMResponse;
641
+ /**
642
+ * Scripted responses replayed one per `complete()` call (the last repeats once
643
+ * exhausted). Lets a test drive a multi-turn agent — e.g. a `tool_use` turn
644
+ * followed by a final-answer turn. Takes precedence over `response`.
645
+ */
646
+ responses?: LLMResponse[];
647
+ chunks?: LLMStreamChunk[];
648
+ };
649
+ declare class MockLLMProviderAdapter implements LLMProviderAdapter {
650
+ readonly provider: LLMProvider;
651
+ private readonly responses;
652
+ private readonly chunks;
653
+ private index;
654
+ constructor(options: MockAdapterOptions);
655
+ complete(): Promise<LLMResponse>;
656
+ stream(): AsyncIterable<LLMStreamChunk>;
657
+ }
658
+
659
+ /**
660
+ * Provider-shaped request the adapter assembles. This is the cache seam: the
661
+ * `system` and `tools` blocks carry the cache_control breakpoints and must stay
662
+ * byte-stable across calls. The default port translates this into the SDK request;
663
+ * tests fake the port and assert on this shape directly.
664
+ */
665
+ type AnthropicCreateParams = {
666
+ model: string;
667
+ maxTokens: number;
668
+ system?: Array<{
669
+ type: "text";
670
+ text: string;
671
+ cacheable?: boolean;
672
+ }>;
673
+ tools?: Array<{
674
+ name: string;
675
+ description?: string;
676
+ inputSchema: Record<string, unknown>;
677
+ cacheable?: boolean;
678
+ }>;
679
+ messages: Array<{
680
+ role: "user" | "assistant";
681
+ content: string | LLMContentBlock[];
682
+ }>;
683
+ };
684
+ /** Structural subset of the SDK `Message` the adapter actually reads. */
685
+ type AnthropicRawResponse = {
686
+ content: Array<{
687
+ type: string;
688
+ text?: string;
689
+ id?: string;
690
+ name?: string;
691
+ input?: unknown;
692
+ }>;
693
+ stop_reason?: string | null;
694
+ usage: {
695
+ input_tokens: number;
696
+ output_tokens: number;
697
+ cache_read_input_tokens?: number | null;
698
+ cache_creation_input_tokens?: number | null;
699
+ };
700
+ };
701
+ /**
702
+ * The only seam onto the Anthropic SDK. The default implementation wraps a real
703
+ * client; tests supply a fake so the cache + accounting logic is covered without
704
+ * a network call or an API key.
705
+ */
706
+ interface AnthropicClientPort {
707
+ create(params: AnthropicCreateParams): Promise<AnthropicRawResponse>;
708
+ stream(params: AnthropicCreateParams): AsyncIterable<LLMStreamChunk>;
709
+ }
710
+ type AnthropicAdapterOptions = {
711
+ /** Override the model used when the request does not name a Claude model. */
712
+ defaultModel?: string;
713
+ /** Inject a client port (tests) or an API key (production). */
714
+ port?: AnthropicClientPort;
715
+ apiKey?: string;
716
+ };
717
+ declare class AnthropicProviderAdapter implements LLMProviderAdapter {
718
+ readonly provider: "anthropic";
719
+ private readonly port;
720
+ private readonly defaultModel;
721
+ constructor(options?: AnthropicAdapterOptions);
722
+ complete(req: LLMRequest): Promise<LLMResponse>;
723
+ stream(req: LLMRequest): AsyncIterable<LLMStreamChunk>;
724
+ /**
725
+ * Assemble the provider request. The cacheable prefix is `tools` then `system`
726
+ * (Anthropic render order); a breakpoint on the last tool and on the system block
727
+ * caches that prefix. Sampling params are intentionally dropped — Opus 4.7/4.8
728
+ * reject `temperature`/`top_p`/`top_k`. No date/timestamp is added here.
729
+ */
730
+ private buildParams;
731
+ private collectSystem;
732
+ private resolveModel;
733
+ private toResponse;
734
+ }
735
+
736
+ /**
737
+ * The OpenAI `/v1/chat/completions` request body the adapter assembles. This is the
738
+ * seam tests assert against directly: {@link buildRequestBody} is a pure function, so
739
+ * the request mapping is covered without a network call or an API key.
740
+ */
741
+ type OpenAIChatRequestBody = {
742
+ model: string;
743
+ messages: OpenAIChatMessage[];
744
+ tools?: Array<{
745
+ type: "function";
746
+ function: {
747
+ name: string;
748
+ description?: string;
749
+ parameters: Record<string, unknown>;
750
+ };
751
+ }>;
752
+ temperature?: number;
753
+ max_tokens?: number;
754
+ };
755
+ /** A single message in the OpenAI chat shape. */
756
+ type OpenAIChatMessage = {
757
+ role: "system" | "user" | "assistant" | "tool";
758
+ content: string;
759
+ tool_call_id?: string;
760
+ tool_calls?: Array<{
761
+ id: string;
762
+ type: "function";
763
+ function: {
764
+ name: string;
765
+ arguments: string;
766
+ };
767
+ }>;
768
+ };
769
+ /** Structural subset of the OpenAI chat completion response the adapter reads. */
770
+ type OpenAIChatResponse = {
771
+ choices: Array<{
772
+ message: {
773
+ content?: string | null;
774
+ tool_calls?: Array<{
775
+ id: string;
776
+ type?: string;
777
+ function: {
778
+ name: string;
779
+ arguments: string;
780
+ };
781
+ }> | null;
782
+ };
783
+ finish_reason?: string | null;
784
+ }>;
785
+ usage?: {
786
+ prompt_tokens?: number;
787
+ completion_tokens?: number;
788
+ };
789
+ };
790
+ /**
791
+ * The only seam onto the HTTP transport. The default implementation POSTs the body to
792
+ * `baseUrl + '/chat/completions'` via global `fetch`; tests supply a fake so the
793
+ * request/response mapping is covered without a network call.
794
+ */
795
+ interface OpenAICompatibleTransportPort {
796
+ send(body: OpenAIChatRequestBody): Promise<OpenAIChatResponse>;
797
+ }
798
+ type OpenAICompatibleAdapterOptions = {
799
+ /** Provider key this adapter registers under in the gateway map. Default `'mistral'`. */
800
+ provider?: LLMProvider;
801
+ /** API base, e.g. `https://api.mistral.ai/v1` or `http://localhost:11434/v1`. */
802
+ baseUrl: string;
803
+ /** Model used when the request does not name a model id for this provider. */
804
+ defaultModel: string;
805
+ /** Bearer token; omitted for keyless servers such as a local Ollama. */
806
+ apiKey?: string;
807
+ /** Inject a transport port (tests) instead of the default `fetch`-backed one. */
808
+ port?: OpenAICompatibleTransportPort;
809
+ };
810
+ /**
811
+ * One adapter for any server speaking the OpenAI `/v1/chat/completions` shape. Both
812
+ * a local **Ollama** server (`http://localhost:11434/v1`, keyless) and **Mistral
813
+ * cloud** (`https://api.mistral.ai/v1`, bearer key) are driven by this same class;
814
+ * use {@link OpenAICompatibleProviderAdapter.ollama} / `.mistral` to construct them.
815
+ */
816
+ declare class OpenAICompatibleProviderAdapter implements LLMProviderAdapter {
817
+ readonly provider: LLMProvider;
818
+ private readonly port;
819
+ private readonly baseUrl;
820
+ private readonly defaultModel;
821
+ constructor(options: OpenAICompatibleAdapterOptions);
822
+ /** Mistral cloud: bearer-keyed, hosted at `https://api.mistral.ai/v1`. */
823
+ static mistral(apiKey?: string, model?: string): OpenAICompatibleProviderAdapter;
824
+ /**
825
+ * A local Ollama server (keyless, `http://localhost:11434/v1`). Registers under the
826
+ * `'mistral'` provider key so it routes through the same gateway slot as Mistral cloud.
827
+ */
828
+ static ollama(model?: string, baseUrl?: string): OpenAICompatibleProviderAdapter;
829
+ complete(req: LLMRequest): Promise<LLMResponse>;
830
+ stream(req: LLMRequest): AsyncIterable<LLMStreamChunk>;
831
+ private toResponse;
832
+ }
833
+
834
+ /**
835
+ * An abstract capability tier. Wire-compatible (camelCase) with the Rust
836
+ * `ModelTier` enum in `crates/llm-gateway`.
837
+ */
838
+ type ModelTier = "frontier" | "balanced" | "fast" | "creative";
839
+ /** All four tiers, in declaration order — handy for seeding tables. */
840
+ declare const MODEL_TIERS: readonly ModelTier[];
841
+ /**
842
+ * The outcome of {@link ModelPolicy.resolve}: a concrete provider + model, plus
843
+ * whether the model came from the recommended per-tier defaults (`true`) or from
844
+ * an explicit override (`false`).
845
+ */
846
+ type ModelChoice = {
847
+ provider: LLMProvider;
848
+ model: string;
849
+ recommended: boolean;
850
+ };
851
+ /** `tier -> model` for a single provider. */
852
+ type TierModelTable = Record<ModelTier, string>;
853
+ /** Optional override passed to {@link ModelPolicy.resolve}. */
854
+ type ResolveOverride = {
855
+ provider?: LLMProvider;
856
+ model?: string;
857
+ };
858
+ /**
859
+ * The shared capability-tier contract defaults: the recommended model for each
860
+ * provider at each tier. Mirrors the Rust `ModelPolicy::default` table exactly.
861
+ */
862
+ declare const DEFAULT_TIER_TABLE: Partial<Record<LLMProvider, TierModelTable>>;
863
+ /** The default cross-provider preference order, highest first. */
864
+ declare const DEFAULT_PREFERENCE: readonly LLMProvider[];
865
+ /**
866
+ * Capability-tier model policy: map an abstract capability tier
867
+ * (`frontier` / `balanced` / `fast` / `creative`) onto a concrete
868
+ * `{ provider, model }` choice, given which providers are actually available.
869
+ *
870
+ * Mirrors the Rust `crates/llm-gateway` `ModelPolicy` byte for byte in behaviour
871
+ * and wire shape. The point: "I only have Mistral" -> every tier resolves to the
872
+ * mistral column; "only Anthropic" -> `fast` -> haiku, `frontier` -> opus,
873
+ * `creative` -> fable.
874
+ */
875
+ declare class ModelPolicy {
876
+ private readonly table;
877
+ private readonly preference;
878
+ /**
879
+ * Construct a policy. Either argument may be omitted to keep the contract
880
+ * default for that piece.
881
+ */
882
+ constructor(options?: {
883
+ table?: Partial<Record<LLMProvider, TierModelTable>>;
884
+ preference?: readonly LLMProvider[];
885
+ });
886
+ /**
887
+ * Which providers are usable given the current process environment:
888
+ * `anthropic` iff `ANTHROPIC_API_KEY` is set; `mistral` iff `MISTRAL_API_KEY`
889
+ * is set; `ollama` iff `ADRIANE_USE_OLLAMA=1`. Order follows the policy
890
+ * preference so callers get a deterministic list.
891
+ */
892
+ availableFromEnv(env?: NodeJS.ProcessEnv): LLMProvider[];
893
+ /**
894
+ * Resolve a capability tier to a concrete `{ provider, model, recommended }`.
895
+ *
896
+ * - An explicit `override.provider` and/or `override.model` wins, with
897
+ * `recommended = false`. When only one of the two is given, the other is
898
+ * filled from the policy: an override provider maps the tier to that
899
+ * provider's recommended model; an override model rides on the first
900
+ * available provider (or the override provider if also given).
901
+ * - Otherwise the highest-preference provider that is both available and
902
+ * present in the table supplies its tier model, with `recommended = true`.
903
+ * - If nothing is available, the mock provider is returned.
904
+ */
905
+ resolve(tier: ModelTier, available: readonly LLMProvider[], override?: ResolveOverride): ModelChoice;
906
+ /** The recommended model for a provider+tier from the table, if present. */
907
+ private modelFor;
908
+ /** The first preference-ordered provider that is in `available`. */
909
+ private firstAvailable;
910
+ }
911
+
912
+ type ApprovalId = string & {
913
+ readonly __brand: "ApprovalId";
914
+ };
915
+ declare const APPROVAL_STATUSES: readonly ["pending", "approved", "rejected"];
916
+ type ApprovalStatus = (typeof APPROVAL_STATUSES)[number];
917
+ type ApprovalRequest = {
918
+ id: ApprovalId;
919
+ runId: RunId;
920
+ nodeId: NodeId;
921
+ requestedBy: string;
922
+ subject: ArtifactRef | {
923
+ description: string;
924
+ };
925
+ status: ApprovalStatus;
926
+ resolvedBy?: string;
927
+ resolvedAt?: Date;
928
+ rejectionReason?: string;
929
+ createdAt: Date;
930
+ };
931
+
932
+ type RequestApprovalParams = {
933
+ runId: RunId;
934
+ nodeId: NodeId;
935
+ requestedBy: string;
936
+ subject: ArtifactRef | {
937
+ description: string;
938
+ };
939
+ };
940
+ interface ApprovalEngine {
941
+ request(params: RequestApprovalParams): Promise<ApprovalRequest>;
942
+ approve(id: ApprovalId, resolvedBy: string): Promise<ApprovalRequest>;
943
+ reject(id: ApprovalId, resolvedBy: string, reason: string): Promise<ApprovalRequest>;
944
+ getPending(runId?: RunId): Promise<ApprovalRequest[]>;
945
+ getById(id: ApprovalId): Promise<ApprovalRequest | undefined>;
946
+ }
947
+
948
+ /** Default channel an agent node writes its {@link import("@adriane-ai/agents-core").AgentResult} into. */
949
+ declare const DEFAULT_AGENT_OUTPUT_CHANNEL = "agentResult";
950
+ /**
951
+ * Channel holding the names of tools whose human approval has been granted. The
952
+ * control plane writes it (see `CompiledGraph.approveAndResume`) before resuming a
953
+ * run that suspended for approval; the agent then executes those tools.
954
+ */
955
+ declare const APPROVED_TOOLS_CHANNEL = "__approvedTools";
956
+ /** Reason carried by the dynamic interrupt an agent node raises when it needs approval. */
957
+ declare const AGENT_APPROVAL_INTERRUPT = "agent-approval-required";
958
+ /**
959
+ * Channel holding the ApprovalEngine request ids created when a run suspends for
960
+ * approval. On resume the node looks each up; the ones the engine reports as
961
+ * `approved` unlock their tools — the engine is the source of truth, not a flag.
962
+ */
963
+ declare const APPROVAL_IDS_CHANNEL = "__approvalIds";
964
+ /** Where an agent node gets its system prompt. */
965
+ type AgentPromptSource = {
966
+ registry: PromptRegistry;
967
+ id: string;
968
+ version?: string;
969
+ }
970
+ /** Inline convenience: the SDK registers this string and references it by id. */
971
+ | {
972
+ system: string;
973
+ };
974
+ /** Config for {@link GraphBuilder.agentNode}. */
975
+ type AgentNodeConfig = {
976
+ llm: LLMGateway;
977
+ prompt: AgentPromptSource;
978
+ tools?: ToolRegistry;
979
+ provider?: LLMProvider;
980
+ model?: string;
981
+ /**
982
+ * Abstract capability tier (`"frontier" | "balanced" | "fast" | "creative"`). When
983
+ * set and no explicit {@link AgentNodeConfig.model} is given, the concrete model is
984
+ * resolved by the {@link ModelPolicy}: on the Rust path the bridge resolves it from
985
+ * the process env (so "I only have Mistral" maps every tier to the mistral column);
986
+ * on the TS fallback path the SDK resolves it here against `availableFromEnv()` so
987
+ * the agent runs on a consistent concrete provider+model. An explicit `model` (and
988
+ * an explicit `provider`) always wins over the tier (the override stays `false`-
989
+ * recommended in policy terms).
990
+ */
991
+ tier?: ModelTier;
992
+ maxIterations?: number;
993
+ name?: string;
994
+ description?: string;
995
+ /** Channel that receives the agent's result. Defaults to {@link DEFAULT_AGENT_OUTPUT_CHANNEL}. */
996
+ outputChannel?: string;
997
+ /**
998
+ * When true, the node suspends the whole run (a dynamic interrupt) the moment the
999
+ * agent needs approval, instead of just flagging `requiresHumanReview`. Resume with
1000
+ * `CompiledGraph.approveAndResume(runId, { approvedTools })` to continue. Default false.
1001
+ */
1002
+ suspendForApproval?: boolean;
1003
+ /**
1004
+ * Route approvals through an {@link ApprovalEngine}: on suspend the node files a
1005
+ * request per gated tool; on resume it executes the tools the engine reports as
1006
+ * approved. The engine becomes the source of truth (a human resolves it out of
1007
+ * band) instead of the `__approvedTools` channel.
1008
+ */
1009
+ approvalEngine?: ApprovalEngine;
1010
+ label?: string;
1011
+ };
1012
+ /** Config for {@link GraphBuilder.toolNode}. */
1013
+ type ToolNodeConfig = {
1014
+ tools: ToolRegistry;
1015
+ /** Execute all tool calls concurrently instead of sequentially. */
1016
+ parallel?: boolean;
1017
+ label?: string;
1018
+ };
1019
+ /**
1020
+ * A tool's name plus its TS `execute` fn — the data the Rust bridge needs to back a
1021
+ * `jsToolName` with a JS callback. The Rust engine never imports the tool registry;
1022
+ * it calls this `execute` over the napi seam (`on_node` with `kind:"tool"`).
1023
+ */
1024
+ type RustToolBinding = {
1025
+ name: string;
1026
+ execute: (input: unknown) => Promise<unknown>;
1027
+ };
1028
+ /**
1029
+ * The serializable shape of an agent node, plus its JS-backed tool executes, that
1030
+ * the Rust engine bridge consumes (see `EngineSpec.agents` / `jsToolNames`). It is a
1031
+ * pure projection of {@link AgentNodeConfig} — the system prompt is the *resolved*
1032
+ * string (never a registry reference), since the bridge has no prompt registry.
1033
+ *
1034
+ * The LLM gateway itself is **not** carried: the Rust agent path builds its own
1035
+ * gateway (env adapters or a deterministic mock). A graph whose agents rely on a
1036
+ * specific TS `AgentNodeConfig.llm` therefore keeps its semantics only on the TS
1037
+ * engine; the Rust path is opt-in for agents (see `CompiledGraph`).
1038
+ */
1039
+ type RustAgentConfig = {
1040
+ provider: string;
1041
+ model?: string;
1042
+ /**
1043
+ * Abstract capability tier carried to the Rust `AgentSpec.tier`. When set with no
1044
+ * explicit `model`, the Rust bridge resolves the concrete model via `ModelPolicy`
1045
+ * against the process env. An explicit `model` always wins.
1046
+ */
1047
+ tier?: ModelTier;
1048
+ /** Resolved system prompt string. */
1049
+ system?: string;
1050
+ toolNames: string[];
1051
+ maxIterations?: number;
1052
+ suspendForApproval: boolean;
1053
+ /** Tools (by name) requiring approval — those marked `requiresApproval`. */
1054
+ approvalToolNames: string[];
1055
+ outputChannel: string;
1056
+ /** JS-backed tool executes, one per tool in the registry. */
1057
+ toolBindings: RustToolBinding[];
1058
+ /**
1059
+ * SDK-only (never serialized to the wire): whether this agent node was configured
1060
+ * with a TS {@link ApprovalEngine}. The engine-backed approval flow — filing a
1061
+ * request per gated tool and reading the engine's decision on resume — lives in the
1062
+ * TS `createAgentNodeHandler`; the Rust agent path does not invoke it. So a graph
1063
+ * with an `approvalEngine` keeps its agent nodes on the TS engine under `auto`.
1064
+ */
1065
+ usesApprovalEngine: boolean;
1066
+ };
1067
+ /**
1068
+ * The governance binding an agent node contributes to {@link CompiledGraph}: the
1069
+ * (optional) {@link ApprovalEngine} a human resolves requests through, the principal
1070
+ * that *requests* approvals on this node's behalf (`config.name ?? nodeId`, the same
1071
+ * `requestedBy` the node files requests under), and the names of its approval-gated
1072
+ * tools. {@link CompiledGraph.approveAndResume} uses it to (a) approve the matching
1073
+ * pending engine requests before resuming on the TS path, and (b) stamp each granted
1074
+ * tool's `requestedBy` for the Rust engine's no-self-approval guard-rail.
1075
+ */
1076
+ type AgentApprovalBinding = {
1077
+ approvalEngine?: ApprovalEngine;
1078
+ requestedBy: string;
1079
+ approvalToolNames: string[];
1080
+ };
1081
+ /** Project an {@link AgentNodeConfig} into its {@link AgentApprovalBinding}. */
1082
+ declare const toAgentApprovalBinding: (nodeId: string, config: AgentNodeConfig) => AgentApprovalBinding;
1083
+ /**
1084
+ * Project an {@link AgentNodeConfig} into the {@link RustAgentConfig} the Rust engine
1085
+ * bridge consumes. Resolves the system prompt to a concrete string and pulls the tool
1086
+ * names / approval flags / executes out of the registry. Pure — no LLM call.
1087
+ */
1088
+ declare const toRustAgentConfig: (nodeId: string, config: AgentNodeConfig) => RustAgentConfig;
1089
+ /** Config for {@link streamAgentTokens}. */
1090
+ type StreamAgentConfig = {
1091
+ llm: LLMGateway;
1092
+ prompt: AgentPromptSource;
1093
+ provider?: LLMProvider;
1094
+ model?: string;
1095
+ };
1096
+ /**
1097
+ * Stream an agent's reply token by token through the gateway's `stream()`. This is
1098
+ * the single-turn (no-tools) path — ideal for a chat UI that wants live output.
1099
+ * Yields text deltas as they arrive and returns when the provider signals done.
1100
+ *
1101
+ * ```ts
1102
+ * for await (const delta of streamAgentTokens({ llm, prompt: { system } }, "Bonjour ?")) {
1103
+ * process.stdout.write(delta);
1104
+ * }
1105
+ * ```
1106
+ */
1107
+ declare function streamAgentTokens(config: StreamAgentConfig, input: unknown): AsyncIterable<string>;
1108
+ declare const createAgentNodeHandler: (nodeId: string, config: AgentNodeConfig) => NodeHandler;
1109
+ /**
1110
+ * Build the handler for a tool node: executes the tool calls emitted by the last
1111
+ * AI message in the `messages` channel. Tools flagged `requiresApproval` suspend
1112
+ * the run via a dynamic interrupt instead of executing.
1113
+ */
1114
+ declare const createToolNodeHandler: (config: ToolNodeConfig) => NodeHandler;
1115
+
1116
+ /**
1117
+ * The component library surface: pure (no-LLM) compute building blocks addressable
1118
+ * by a string `kind` plus a `params` object. Mirrors the Rust `adriane_components`
1119
+ * library (`crates/components`) one-for-one in kind, params and behaviour.
1120
+ *
1121
+ * Each factory in {@link components} returns a {@link ComponentDescriptor}: the Phase
1122
+ * C carrier the Rust engine needs (`{ kind, params }`, surfaced as the graph's
1123
+ * `componentNodes` map) **and** a faithful TypeScript `handler` for the fallback path
1124
+ * when the native addon is absent. The components are simple and pure, so the two
1125
+ * implementations agree byte-for-byte on ASCII input.
1126
+ *
1127
+ * Use {@link GraphBuilder.component} to push a node carrying both:
1128
+ *
1129
+ * ```ts
1130
+ * import { createGraph, components } from "@adriane-ai/graph-sdk";
1131
+ *
1132
+ * const app = createGraph({ name: "prompt" })
1133
+ * .channel("name", { type: "string", default: "" })
1134
+ * .channel("prompt", { type: "string", default: "" })
1135
+ * .component("build", components.promptBuilder({ template: "Hi {{name}}", into: "prompt" }))
1136
+ * .compile();
1137
+ * ```
1138
+ */
1139
+
1140
+ /** The component kinds the library knows, matching `ComponentRegistry::kinds()`. */
1141
+ type ComponentKind = "promptBuilder" | "jsonValidator" | "outputParser" | "router" | "retriever" | "reranker" | "textCleaner" | "documentSplitter" | "htmlToText" | "csvParser" | "documentJoiner" | "deduplicator" | "truncator" | "regexExtractor" | "answerBuilder" | "fieldMapper" | "fieldExtractor" | "bm25Retriever" | "keywordRetriever" | "sentenceWindowSplitter" | "languageDetector" | "metadataFilter" | "listJoiner" | "mergeRanker" | "evaluator" | "chatMessageBuilder" | "conditionalRouter" | "documentWriter";
1142
+ /**
1143
+ * The serializable projection of a component node the Rust engine bridge consumes
1144
+ * (the Phase C `componentNodes` carrier, camelCase): a component `kind` plus its
1145
+ * validated `params` object. Pure data — no closures.
1146
+ */
1147
+ type RustComponentConfig = {
1148
+ kind: ComponentKind;
1149
+ params: Record<string, unknown>;
1150
+ };
1151
+ /**
1152
+ * What a component factory returns: the Phase C carrier (`kind` + `params`) so the
1153
+ * node runs natively on Rust, plus an equivalent TS {@link NodeHandler} for the
1154
+ * fallback path. {@link GraphBuilder.component} pushes a node from this descriptor.
1155
+ */
1156
+ type ComponentDescriptor = RustComponentConfig & {
1157
+ /** The faithful TS-equivalent handler used when the native addon is absent. */
1158
+ handler: NodeHandler;
1159
+ };
1160
+ /**
1161
+ * What an **integration component** factory returns (the vendor-I/O pattern, e.g.
1162
+ * {@link components.httpFetch} / {@link components.webSearch}). Unlike a
1163
+ * {@link ComponentDescriptor}, an integration component is **not** a Rust component:
1164
+ * it has no `kind`/`params` carrier and is **not** registered in `componentNodes`.
1165
+ * It is a plain `NodeHandler` (an injectable closure over an injected I/O impl) added
1166
+ * as a regular JS node via {@link import("./builder.js").GraphBuilder.node}; on the
1167
+ * Rust engine it runs over the async JS seam (`on_node`) like any other JS handler.
1168
+ *
1169
+ * ```ts
1170
+ * createGraph({ name: "fetch" })
1171
+ * .channel("body", { type: "json", default: null })
1172
+ * .node("get", components.httpFetch({ url: "https://x", into: "body", fetchImpl: fake }));
1173
+ * ```
1174
+ */
1175
+ type IntegrationComponentHandler = NodeHandler;
1176
+ /** Params for {@link components.promptBuilder}. */
1177
+ type PromptBuilderParams = {
1178
+ /** Template with `{{var}}` placeholders filled from the channels. */
1179
+ template: string;
1180
+ /** Channel the rendered string is written into. */
1181
+ into: string;
1182
+ };
1183
+ /** Params for {@link components.jsonValidator}. */
1184
+ type JsonValidatorParams = {
1185
+ /** Channel whose value is validated. */
1186
+ from: string;
1187
+ /** Required object keys to assert present. */
1188
+ requiredKeys?: string[];
1189
+ /** Expected JSON type (`"object" | "array" | "string" | ...`). */
1190
+ expectType?: "string" | "number" | "boolean" | "object" | "array" | "null";
1191
+ /** Channel receiving the `boolean` validity flag. */
1192
+ okInto: string;
1193
+ /** Channel receiving the `string[]` of validation errors. */
1194
+ errorsInto: string;
1195
+ };
1196
+ /** Params for {@link components.outputParser}. */
1197
+ type OutputParserParams = {
1198
+ /** Text channel to extract the first JSON value from. */
1199
+ from: string;
1200
+ /** Channel receiving the parsed value (or `null` when none is found). */
1201
+ into: string;
1202
+ };
1203
+ /** One routing rule for {@link components.router}. */
1204
+ type RouterRule = {
1205
+ /** Exact match against the textual form of the `from` value. */
1206
+ equals?: string;
1207
+ /** Substring match against the textual form of the `from` value. */
1208
+ contains?: string;
1209
+ /** The route string emitted when this rule matches. */
1210
+ route: string;
1211
+ };
1212
+ /** Params for {@link components.router}. */
1213
+ type RouterParams = {
1214
+ /** Channel whose value is matched against the rules. */
1215
+ from: string;
1216
+ /** Ordered rules; the first match wins. */
1217
+ rules: RouterRule[];
1218
+ /** Route emitted when no rule matches. */
1219
+ defaultRoute: string;
1220
+ /** Channel the chosen route string is written into. */
1221
+ into: string;
1222
+ };
1223
+ /** A candidate document for {@link components.retriever}. */
1224
+ type RetrieverDoc = {
1225
+ id: string;
1226
+ content: string;
1227
+ };
1228
+ /** Params for {@link components.retriever}. */
1229
+ type RetrieverParams = {
1230
+ /** Channel holding the query text (falls back to this literal when the channel is empty). */
1231
+ query: string;
1232
+ /** Channel receiving the top-`k` `{ id, content, score }` array. */
1233
+ into: string;
1234
+ /** Number of results to keep (default 4). */
1235
+ k?: number;
1236
+ /** The corpus to score against. */
1237
+ docs: RetrieverDoc[];
1238
+ };
1239
+ /** Params for {@link components.reranker}. */
1240
+ type RerankerParams = {
1241
+ /** Channel holding the retrieval-result array to reorder. */
1242
+ from: string;
1243
+ /** Channel receiving the reordered array. */
1244
+ into: string;
1245
+ /** Optional channel holding query text for embedding-based re-scoring. */
1246
+ query?: string;
1247
+ };
1248
+ /** Params for {@link components.textCleaner}. */
1249
+ type TextCleanerParams = {
1250
+ /** Channel whose text is normalised. */
1251
+ from: string;
1252
+ /** Channel receiving the cleaned text. */
1253
+ into: string;
1254
+ /** Lowercase the text. Defaults to `false`. */
1255
+ lowercase?: boolean;
1256
+ /** Strip `<…>` HTML tags. Defaults to `false`. */
1257
+ stripHtml?: boolean;
1258
+ /** Collapse runs of whitespace to a single space. Defaults to `false`. */
1259
+ collapseWhitespace?: boolean;
1260
+ /** Trim leading/trailing whitespace. Defaults to `false`. */
1261
+ trim?: boolean;
1262
+ };
1263
+ /** Params for {@link components.documentSplitter}. */
1264
+ type DocumentSplitterParams = {
1265
+ /** Channel holding the text to split. */
1266
+ from: string;
1267
+ /** Channel receiving the `string[]` of chunks. */
1268
+ into: string;
1269
+ /** Split unit: `"chars"` sliding windows or greedy `"sentences"` packing. */
1270
+ by: "chars" | "sentences";
1271
+ /** Window size in characters (`by:"chars"`) or sentences (`by:"sentences"`). Must be > 0. */
1272
+ size: number;
1273
+ /** Overlap repeated at the start of each next chunk. Must be smaller than `size`. Defaults to 0. */
1274
+ overlap?: number;
1275
+ };
1276
+ /** Params for {@link components.htmlToText}. */
1277
+ type HtmlToTextParams = {
1278
+ /** Channel holding the HTML text. */
1279
+ from: string;
1280
+ /** Channel receiving the tag-stripped, entity-decoded text. */
1281
+ into: string;
1282
+ };
1283
+ /** Params for {@link components.csvParser}. */
1284
+ type CsvParserParams = {
1285
+ /** Channel holding the CSV text. */
1286
+ from: string;
1287
+ /** Channel receiving the parsed rows array. */
1288
+ into: string;
1289
+ /** Single-character cell delimiter. Defaults to `","`. */
1290
+ delimiter?: string;
1291
+ /** When `true` (default) the first row supplies object keys; otherwise rows are arrays. */
1292
+ header?: boolean;
1293
+ };
1294
+ /** Params for {@link components.documentJoiner}. */
1295
+ type DocumentJoinerParams = {
1296
+ /** Channels whose array values are concatenated in order. */
1297
+ fromChannels: string[];
1298
+ /** Channel receiving the merged array. */
1299
+ into: string;
1300
+ /** Optional object field to de-duplicate the merged items by. */
1301
+ dedupeBy?: string;
1302
+ };
1303
+ /** Params for {@link components.deduplicator}. */
1304
+ type DeduplicatorParams = {
1305
+ /** Channel holding the array to de-duplicate. */
1306
+ from: string;
1307
+ /** Channel receiving the de-duplicated array. */
1308
+ into: string;
1309
+ /** Optional object field to compare items by (else whole-value compare). */
1310
+ key?: string;
1311
+ };
1312
+ /** Params for {@link components.truncator}. */
1313
+ type TruncatorParams = {
1314
+ /** Channel holding the text to truncate. */
1315
+ from: string;
1316
+ /** Channel receiving the (possibly truncated) text. */
1317
+ into: string;
1318
+ /** Maximum character length (the ellipsis counts against this budget). */
1319
+ maxChars: number;
1320
+ /** Suffix appended when truncated. Defaults to `"…"`. */
1321
+ ellipsis?: string;
1322
+ };
1323
+ /** Params for {@link components.regexExtractor}. */
1324
+ type RegexExtractorParams = {
1325
+ /** Channel holding the text to match against. */
1326
+ from: string;
1327
+ /** Channel receiving the match (or matches when `all`). */
1328
+ into: string;
1329
+ /**
1330
+ * Literal-substring pattern with optional leading `^` (start) and trailing `$`
1331
+ * (end) anchors. No character classes / quantifiers / capture groups.
1332
+ */
1333
+ pattern: string;
1334
+ /** Accepted for forward-compat; only `0` (the whole match) is supported. Defaults to 0. */
1335
+ group?: number;
1336
+ /** When `true`, return every non-overlapping occurrence as an array. Defaults to `false`. */
1337
+ all?: boolean;
1338
+ };
1339
+ /** Params for {@link components.answerBuilder}. */
1340
+ type AnswerBuilderParams = {
1341
+ /** Channel supplying the core answer text. */
1342
+ from: string;
1343
+ /** Channel receiving the assembled answer. */
1344
+ into: string;
1345
+ /** Optional channel holding a retrieval-result array rendered as numbered citations. */
1346
+ contextFrom?: string;
1347
+ /** Optional `{{answer}}`/`{{citations}}` template controlling the layout. */
1348
+ template?: string;
1349
+ };
1350
+ /** Params for {@link components.fieldMapper}. */
1351
+ type FieldMapperParams = {
1352
+ /** Channel holding the source object. */
1353
+ from: string;
1354
+ /** Channel receiving the remapped object. */
1355
+ into: string;
1356
+ /** `{ outKey: inKeyPath }` map; `inKeyPath` is a dotted path into the source. */
1357
+ mapping: Record<string, string>;
1358
+ };
1359
+ /** Params for {@link components.fieldExtractor}. */
1360
+ type FieldExtractorParams = {
1361
+ /** Channel holding the source value. */
1362
+ from: string;
1363
+ /** Channel receiving the extracted scalar. */
1364
+ into: string;
1365
+ /** Optional dotted path descended into the `from` value (else the whole value). */
1366
+ path?: string;
1367
+ /**
1368
+ * When `true`, if the resulting value is a string containing a `"final:"` marker,
1369
+ * return only the text after the **last** `"final:"` (trimmed) — reduces an
1370
+ * agent reasoning trace to its final answer. Non-strings pass through. Defaults to `false`.
1371
+ */
1372
+ finalOnly?: boolean;
1373
+ };
1374
+ /** A candidate document for the lexical retrievers. */
1375
+ type LexicalDoc = {
1376
+ id: string;
1377
+ content: string;
1378
+ };
1379
+ /** Params for {@link components.bm25Retriever}. */
1380
+ type Bm25RetrieverParams = {
1381
+ /** Channel holding the query text (falls back to this literal when empty). */
1382
+ query: string;
1383
+ /** Channel receiving the top-`k` `{ id, content, score }` array. */
1384
+ into: string;
1385
+ /** Number of results to keep (default 4). */
1386
+ k?: number;
1387
+ /** The corpus to rank. */
1388
+ docs: LexicalDoc[];
1389
+ /** BM25 term-frequency saturation. Defaults to 1.2. */
1390
+ k1?: number;
1391
+ /** BM25 length-normalization. Defaults to 0.75. */
1392
+ b?: number;
1393
+ };
1394
+ /** Params for {@link components.keywordRetriever}. */
1395
+ type KeywordRetrieverParams = {
1396
+ /** Channel holding the query text (falls back to this literal when empty). */
1397
+ query: string;
1398
+ /** Channel receiving the top-`k` `{ id, content, score }` array. */
1399
+ into: string;
1400
+ /** Number of results to keep (default 4). */
1401
+ k?: number;
1402
+ /** The corpus to rank. */
1403
+ docs: LexicalDoc[];
1404
+ };
1405
+ /** Params for {@link components.sentenceWindowSplitter}. */
1406
+ type SentenceWindowSplitterParams = {
1407
+ /** Channel holding the text to split. */
1408
+ from: string;
1409
+ /** Channel receiving the `string[]` of overlapping sentence windows. */
1410
+ into: string;
1411
+ /** Sentences per window. Defaults to 3. */
1412
+ windowSize?: number;
1413
+ /** Sentences advanced between windows (`1 <= stride <= windowSize`). Defaults to 1. */
1414
+ stride?: number;
1415
+ };
1416
+ /** Params for {@link components.languageDetector}. */
1417
+ type LanguageDetectorParams = {
1418
+ /** Channel holding the text to classify. */
1419
+ from: string;
1420
+ /** Channel receiving the detected language code (`"en" | "fr" | ... | "und"`). */
1421
+ into: string;
1422
+ /** Optional channel receiving the winning language's share of hits in `[0, 1]`. */
1423
+ confidenceInto?: string;
1424
+ };
1425
+ /** A predicate operator shared by {@link components.metadataFilter} and {@link components.conditionalRouter}. */
1426
+ type PredicateOp = "equals" | "notEquals" | "contains" | "exists" | "absent" | "gt" | "gte" | "lt" | "lte";
1427
+ /** Params for {@link components.metadataFilter}. */
1428
+ type MetadataFilterParams = {
1429
+ /** Channel holding the array to filter. */
1430
+ from: string;
1431
+ /** Channel receiving the filtered array. */
1432
+ into: string;
1433
+ /** Dotted path into each item compared by the predicate. */
1434
+ field: string;
1435
+ /** The predicate operator. */
1436
+ op: PredicateOp;
1437
+ /** The comparison value (required except for `exists`/`absent`). */
1438
+ value?: unknown;
1439
+ };
1440
+ /** Params for {@link components.listJoiner}. */
1441
+ type ListJoinerParams = {
1442
+ /** Channels whose array values are combined. */
1443
+ fromChannels: string[];
1444
+ /** Channel receiving the combined array. */
1445
+ into: string;
1446
+ /** Combine mode: `"concat"` (default), `"union"` (dedupe), or `"interleave"`. */
1447
+ mode?: "concat" | "union" | "interleave";
1448
+ };
1449
+ /** Params for {@link components.mergeRanker}. */
1450
+ type MergeRankerParams = {
1451
+ /** Channels each holding a retrieval-result array to fuse. */
1452
+ fromChannels: string[];
1453
+ /** Channel receiving the fused `{ id, content, score }` array. */
1454
+ into: string;
1455
+ /** Object field identifying items across lists. Defaults to `"id"`. */
1456
+ idKey?: string;
1457
+ /** Keep only the top-`k` fused results (default: keep all). */
1458
+ k?: number;
1459
+ /** Reciprocal Rank Fusion constant. Defaults to 60. */
1460
+ rrfK?: number;
1461
+ };
1462
+ /** Params for {@link components.evaluator}. */
1463
+ type EvaluatorParams = {
1464
+ /** Channel holding the expected/reference text. */
1465
+ expectedFrom: string;
1466
+ /** Channel holding the actual/candidate text. */
1467
+ actualFrom: string;
1468
+ /** Channel receiving the numeric score in `[0, 1]`. */
1469
+ into: string;
1470
+ /** Scoring metric. Defaults to `"tokenF1"`. */
1471
+ metric?: "tokenF1" | "overlap" | "exact";
1472
+ /** Optional channel receiving a boolean `score >= threshold`. */
1473
+ passInto?: string;
1474
+ /** Pass threshold for `passInto`. Defaults to 0.5. */
1475
+ threshold?: number;
1476
+ };
1477
+ /** One message spec for {@link components.chatMessageBuilder}. */
1478
+ type ChatMessageSpec = {
1479
+ /** The message role. */
1480
+ role: "system" | "user" | "assistant";
1481
+ /** A literal body, rendered through the `{{var}}` template engine. */
1482
+ content?: string;
1483
+ /** A channel name whose value supplies the body verbatim. */
1484
+ contentFrom?: string;
1485
+ };
1486
+ /** Params for {@link components.chatMessageBuilder}. */
1487
+ type ChatMessageBuilderParams = {
1488
+ /** Channel receiving the `[{ role, content }]` array. */
1489
+ into: string;
1490
+ /** The ordered message specs. */
1491
+ messages: ChatMessageSpec[];
1492
+ /** Optional channel prepended as a leading system message when non-empty. */
1493
+ systemFrom?: string;
1494
+ };
1495
+ /** One branch for {@link components.conditionalRouter}. */
1496
+ type ConditionalRouterBranch = {
1497
+ /** The predicate evaluated against the channels (`field` is a dotted path). */
1498
+ when: {
1499
+ field: string;
1500
+ op: PredicateOp;
1501
+ value?: unknown;
1502
+ };
1503
+ /** The route string emitted when `when` holds. */
1504
+ route: string;
1505
+ };
1506
+ /** Params for {@link components.conditionalRouter}. */
1507
+ type ConditionalRouterParams = {
1508
+ /** Channel the chosen route string is written into. */
1509
+ into: string;
1510
+ /** Route emitted when no branch matches. */
1511
+ defaultRoute: string;
1512
+ /** Ordered branches; the first matching branch wins. */
1513
+ branches: ConditionalRouterBranch[];
1514
+ };
1515
+ /** Params for {@link components.documentWriter}. */
1516
+ type DocumentWriterParams = {
1517
+ /** Channel holding the incoming documents array to append. */
1518
+ from: string;
1519
+ /** Channel receiving the accumulated store array. */
1520
+ into: string;
1521
+ /** Channel holding the current store. Defaults to `into`. */
1522
+ store?: string;
1523
+ /** Optional object field to de-duplicate the merged store by. */
1524
+ dedupeBy?: string;
1525
+ };
1526
+ /**
1527
+ * The result of an HTTP fetch surfaced into the `into` channel.
1528
+ *
1529
+ * The default impl never throws on a non-2xx response or a transport error — a
1530
+ * failure is surfaced as data so a graph degrades gracefully instead of crashing
1531
+ * the run:
1532
+ * - on a completed response: `{ status, ok, body, json }` (`json` is the parsed
1533
+ * body when the `content-type` is JSON, else `undefined`; `ok` mirrors
1534
+ * `Response.ok`, i.e. a 2xx status);
1535
+ * - on a transport error / timeout: `{ ok: false, error }` (`status`/`body` absent).
1536
+ */
1537
+ type HttpFetchResult = {
1538
+ /** The HTTP status code, when a response was received. */
1539
+ status?: number;
1540
+ /** `true` for a 2xx response; `false` on a non-2xx response or a transport error. */
1541
+ ok: boolean;
1542
+ /** The response body as text, when a response was received. */
1543
+ body?: string;
1544
+ /** The parsed JSON body, present only when the response `content-type` was JSON. */
1545
+ json?: unknown;
1546
+ /** The error message, present only on a transport error / timeout. */
1547
+ error?: string;
1548
+ };
1549
+ /**
1550
+ * The transport an {@link HttpFetchImpl} is invoked with: the resolved URL plus the
1551
+ * request options the default impl assembled from the params (method/headers/body/
1552
+ * the abort `signal` driving the timeout). Mirrors the `(input, init)` shape of the
1553
+ * WHATWG `fetch`, so `globalThis.fetch` is itself a valid impl.
1554
+ */
1555
+ type HttpFetchRequestInit = {
1556
+ method: string;
1557
+ headers?: Record<string, string>;
1558
+ body?: string;
1559
+ signal?: AbortSignal;
1560
+ };
1561
+ /**
1562
+ * An injectable fetch implementation. Receives the resolved URL and the assembled
1563
+ * request init, and must resolve to something `Response`-shaped (`status`, `ok`,
1564
+ * `text()`, `headers.get()`). The real `globalThis.fetch` satisfies this — the
1565
+ * default impl simply calls it — so a test can inject a fake `Response`-like object.
1566
+ */
1567
+ type HttpFetchImpl = (url: string, init: HttpFetchRequestInit) => Promise<HttpFetchResponseLike> | HttpFetchResponseLike;
1568
+ /** The minimal `Response`-shaped surface the default httpFetch impl consumes. */
1569
+ type HttpFetchResponseLike = {
1570
+ status: number;
1571
+ ok: boolean;
1572
+ text(): Promise<string> | string;
1573
+ headers: {
1574
+ get(name: string): string | null;
1575
+ };
1576
+ };
1577
+ /** Params for {@link components.httpFetch}. */
1578
+ type HttpFetchParams = {
1579
+ /** A literal URL to fetch (mutually exclusive with `urlFrom`). */
1580
+ url?: string;
1581
+ /** A channel whose value supplies the URL (takes precedence when its channel is set). */
1582
+ urlFrom?: string;
1583
+ /** Channel receiving the {@link HttpFetchResult}. */
1584
+ into: string;
1585
+ /** HTTP method. Defaults to `"GET"`. */
1586
+ method?: string;
1587
+ /** Request headers sent with the call. */
1588
+ headers?: Record<string, string>;
1589
+ /** Request body (sent verbatim) for non-GET methods. */
1590
+ body?: string;
1591
+ /** Abort the request after this many milliseconds (drives an `AbortController`). */
1592
+ timeoutMs?: number;
1593
+ /**
1594
+ * The transport to call. Defaults to the real `globalThis.fetch`. Inject a fake
1595
+ * (a `Response`-like returning function) to keep a test offline, or to point the
1596
+ * call at a stub transport.
1597
+ */
1598
+ fetchImpl?: HttpFetchImpl;
1599
+ };
1600
+ /** One web-search result: a title, a url and a snippet. */
1601
+ type WebSearchResult = {
1602
+ title: string;
1603
+ url: string;
1604
+ snippet: string;
1605
+ };
1606
+ /**
1607
+ * What the web-search connector writes into the `into` channel: the normalized
1608
+ * `results` plus an optional `note`. The default connector populates `note` when it
1609
+ * degrades gracefully (e.g. no `TAVILY_API_KEY`), leaving `results` empty so a graph
1610
+ * runs without crashing.
1611
+ */
1612
+ type WebSearchOutcome = {
1613
+ results: WebSearchResult[];
1614
+ note?: string;
1615
+ };
1616
+ /**
1617
+ * An injectable web-search implementation. Receives the query + `k`, returns either a
1618
+ * bare `WebSearchResult[]` (which is wrapped as `{ results }`) or a full
1619
+ * {@link WebSearchOutcome} (so an impl can attach its own `note`).
1620
+ */
1621
+ type WebSearchImpl = (query: string, k: number) => Promise<WebSearchResult[] | WebSearchOutcome> | WebSearchResult[] | WebSearchOutcome;
1622
+ /**
1623
+ * The minimal transport the default Tavily connector posts through: a function with
1624
+ * the WHATWG `fetch` `(url, init)` shape resolving to a `Response`-like object. The
1625
+ * real `globalThis.fetch` satisfies it; a test injects a fake to stay offline.
1626
+ */
1627
+ type WebSearchTransport = (url: string, init: {
1628
+ method: string;
1629
+ headers: Record<string, string>;
1630
+ body: string;
1631
+ }) => Promise<HttpFetchResponseLike> | HttpFetchResponseLike;
1632
+ /** Params for {@link components.webSearch}. */
1633
+ type WebSearchParams = {
1634
+ /** A literal query (mutually exclusive with `queryFrom`). */
1635
+ query?: string;
1636
+ /** A channel whose value supplies the query (takes precedence when its channel is set). */
1637
+ queryFrom?: string;
1638
+ /** Channel receiving the {@link WebSearchOutcome}. */
1639
+ into: string;
1640
+ /** Number of results to request. Defaults to 3. */
1641
+ k?: number;
1642
+ /**
1643
+ * The search implementation to call. Defaults to a real Tavily connector behind the
1644
+ * `TAVILY_API_KEY` env var: when the key is set it POSTs to the Tavily API; when it
1645
+ * is absent it degrades gracefully (no network, empty results + a note). Inject a
1646
+ * fake to keep a test offline or to point at another provider.
1647
+ */
1648
+ searchImpl?: WebSearchImpl;
1649
+ /**
1650
+ * The HTTP transport the default Tavily connector posts through. Defaults to the real
1651
+ * `globalThis.fetch`. Inject a fake to exercise the connector offline. Ignored when
1652
+ * `searchImpl` is supplied.
1653
+ */
1654
+ transport?: WebSearchTransport;
1655
+ };
1656
+ /**
1657
+ * The component factory surface. Each factory validates nothing here (the Rust
1658
+ * `ComponentRegistry::build_handler` validates `params` at graph-build time, and the
1659
+ * TS handlers tolerate the same shapes), returning a {@link ComponentDescriptor}
1660
+ * carrying both the native carrier and a faithful TS handler.
1661
+ */
1662
+ declare const components: {
1663
+ /** Render `{{var}}` placeholders from the channels into a target channel. */
1664
+ readonly promptBuilder: (params: PromptBuilderParams) => ComponentDescriptor;
1665
+ /** Validate a channel value's type / required keys, writing an ok flag + errors. */
1666
+ readonly jsonValidator: (params: JsonValidatorParams) => ComponentDescriptor;
1667
+ /** Extract the first JSON object/array from a text channel into a target channel. */
1668
+ readonly outputParser: (params: OutputParserParams) => ComponentDescriptor;
1669
+ /** Pick a route string from a channel value (pairs with a conditional edge). */
1670
+ readonly router: (params: RouterParams) => ComponentDescriptor;
1671
+ /** Score candidate docs against a query and keep the top-`k`. */
1672
+ readonly retriever: (params: RetrieverParams) => ComponentDescriptor;
1673
+ /** Reorder a retrieval-result array, optionally re-scoring against a query. */
1674
+ readonly reranker: (params: RerankerParams) => ComponentDescriptor;
1675
+ /** Normalise a text channel: strip HTML, lowercase, collapse whitespace, trim. */
1676
+ readonly textCleaner: (params: TextCleanerParams) => ComponentDescriptor;
1677
+ /** Split a text channel into an array of chunk strings by chars or sentences. */
1678
+ readonly documentSplitter: (params: DocumentSplitterParams) => ComponentDescriptor;
1679
+ /** Strip HTML tags from a text channel and decode the common named entities. */
1680
+ readonly htmlToText: (params: HtmlToTextParams) => ComponentDescriptor;
1681
+ /** Parse a CSV text channel into an array of row objects (or arrays). */
1682
+ readonly csvParser: (params: CsvParserParams) => ComponentDescriptor;
1683
+ /** Concatenate the array values across several channels into one merged array. */
1684
+ readonly documentJoiner: (params: DocumentJoinerParams) => ComponentDescriptor;
1685
+ /** De-duplicate an array channel, keeping the first occurrence and order. */
1686
+ readonly deduplicator: (params: DeduplicatorParams) => ComponentDescriptor;
1687
+ /** Truncate a text channel to at most `maxChars` characters with an ellipsis. */
1688
+ readonly truncator: (params: TruncatorParams) => ComponentDescriptor;
1689
+ /** Extract literal-pattern matches (with `^`/`$` anchors) from a text channel. */
1690
+ readonly regexExtractor: (params: RegexExtractorParams) => ComponentDescriptor;
1691
+ /** Assemble a final answer string, optionally appending numbered citations. */
1692
+ readonly answerBuilder: (params: AnswerBuilderParams) => ComponentDescriptor;
1693
+ /** Remap an object channel's fields (by dotted path) into a new object. */
1694
+ readonly fieldMapper: (params: FieldMapperParams) => ComponentDescriptor;
1695
+ /** Extract a scalar from a channel (optional dotted path; finalOnly reduces an agent trace to its final answer). */
1696
+ readonly fieldExtractor: (params: FieldExtractorParams) => ComponentDescriptor;
1697
+ /** Lexical BM25 ranking of a corpus against a query; keep the top-`k`. */
1698
+ readonly bm25Retriever: (params: Bm25RetrieverParams) => ComponentDescriptor;
1699
+ /** Keyword-overlap ranking of a corpus against a query; keep the top-`k`. */
1700
+ readonly keywordRetriever: (params: KeywordRetrieverParams) => ComponentDescriptor;
1701
+ /** Split text into overlapping windows of whole sentences. */
1702
+ readonly sentenceWindowSplitter: (params: SentenceWindowSplitterParams) => ComponentDescriptor;
1703
+ /** Heuristic language detection over a small set of common languages. */
1704
+ readonly languageDetector: (params: LanguageDetectorParams) => ComponentDescriptor;
1705
+ /** Filter an array channel by a dotted-path metadata predicate. */
1706
+ readonly metadataFilter: (params: MetadataFilterParams) => ComponentDescriptor;
1707
+ /** Combine several array channels by concat / union / interleave. */
1708
+ readonly listJoiner: (params: ListJoinerParams) => ComponentDescriptor;
1709
+ /** Fuse several retrieval streams into one ranking with Reciprocal Rank Fusion. */
1710
+ readonly mergeRanker: (params: MergeRankerParams) => ComponentDescriptor;
1711
+ /** Score actual vs expected text (token-F1 / overlap / exact), with an optional pass flag. */
1712
+ readonly evaluator: (params: EvaluatorParams) => ComponentDescriptor;
1713
+ /** Assemble a role-tagged chat-message array an LLM generator consumes. */
1714
+ readonly chatMessageBuilder: (params: ChatMessageBuilderParams) => ComponentDescriptor;
1715
+ /** Multi-branch rule routing over the channels (pairs with a conditional edge). */
1716
+ readonly conditionalRouter: (params: ConditionalRouterParams) => ComponentDescriptor;
1717
+ /** Append documents into an in-state document store array (optionally de-duplicating). */
1718
+ readonly documentWriter: (params: DocumentWriterParams) => ComponentDescriptor;
1719
+ /**
1720
+ * **Integration component (vendor I/O).** Perform an HTTP request, writing an
1721
+ * {@link HttpFetchResult} (`{ status, ok, body, json }`) to `into`. This is **not**
1722
+ * a Rust component: it returns a plain {@link NodeHandler} added with
1723
+ * {@link import("./builder.js").GraphBuilder.node} and runs over the JS seam on the
1724
+ * Rust engine. The default transport is the real `globalThis.fetch` (supports
1725
+ * `method`/`headers`/`body`/`timeoutMs` via an `AbortController`); it never throws —
1726
+ * a non-2xx is surfaced via `ok`/`status`, and an error/timeout writes
1727
+ * `{ ok: false, error }`. Inject `fetchImpl` to override the transport (e.g. offline
1728
+ * in tests).
1729
+ */
1730
+ readonly httpFetch: (params: HttpFetchParams) => IntegrationComponentHandler;
1731
+ /**
1732
+ * **Integration component (vendor I/O).** Run a web search, writing a
1733
+ * {@link WebSearchOutcome} (`{ results, note? }`) to `into`. This is **not** a Rust
1734
+ * component: it returns a plain {@link NodeHandler} added with
1735
+ * {@link import("./builder.js").GraphBuilder.node} and runs over the JS seam on the
1736
+ * Rust engine. The default is a real Tavily connector behind `TAVILY_API_KEY`
1737
+ * (POSTs to `https://api.tavily.com/search`, normalizing results to
1738
+ * `[{ title, url, snippet }]`); when the key is absent it degrades gracefully with
1739
+ * **no** network call (empty results + a note). Inject `searchImpl` to override the
1740
+ * provider, or `transport` to keep the Tavily connector offline.
1741
+ */
1742
+ readonly webSearch: (params: WebSearchParams) => IntegrationComponentHandler;
1743
+ };
1744
+
1745
+ /** A map of channel name → value type. The generic that flows through the builder. */
1746
+ type ChannelValues = Record<string, unknown>;
1747
+ /** The starting (channel-less) state of a fresh {@link import("./builder.js").GraphBuilder}. */
1748
+ type EmptyChannels = Record<never, never>;
1749
+ /** {@link GraphState} with strongly-typed channels. */
1750
+ type TypedGraphState<TState extends ChannelValues> = Omit<GraphState, "channels"> & {
1751
+ channels: TState;
1752
+ };
1753
+ /**
1754
+ * What a node handler may return: a partial update to the declared channels
1755
+ * (type-checked) plus any additional keys (the runtime passes unknown keys
1756
+ * through), or a routing {@link Command}.
1757
+ */
1758
+ type ChannelUpdate<TState extends ChannelValues> = (Partial<TState> & Record<string, unknown>) | Command;
1759
+ /** A node handler with strongly-typed state and return value. */
1760
+ type TypedNodeHandler<TState extends ChannelValues> = (input: unknown, state: TypedGraphState<TState>, context: NodeExecutionContext) => Promise<ChannelUpdate<TState>>;
1761
+ /** A conditional-edge predicate over strongly-typed state. */
1762
+ type TypedCondition<TState extends ChannelValues> = (state: TypedGraphState<TState>) => boolean;
1763
+ /** Initial data accepted by a run: declared channels (typed) plus arbitrary extras. */
1764
+ type InitialData<TState extends ChannelValues> = Partial<TState> & Record<string, unknown>;
1765
+
1766
+ /** Options for {@link CompiledGraph.approveAndResume}. */
1767
+ type ApproveAndResumeOptions = {
1768
+ /** Names of approval-gated tools the human has granted. They execute on resume. */
1769
+ approvedTools: string[];
1770
+ /**
1771
+ * The principal granting the approval — a human, NEVER the agent that requested it.
1772
+ * It is recorded as each granted tool's `resolvedBy` and carried to the Rust engine,
1773
+ * which rejects the resume if it is empty or equals the tool's requester (the
1774
+ * no-self-approval guard-rail). On the TS path, when an agent node was configured with
1775
+ * an {@link import("@adriane-ai/approval-engine").ApprovalEngine}, the matching pending
1776
+ * requests are approved through the engine under this principal before resuming — so
1777
+ * the engine's own `ensureCanResolve` enforces the same invariant. Defaults to
1778
+ * `"human"` when omitted.
1779
+ */
1780
+ resolvedBy?: string;
1781
+ };
1782
+ /** Wiring assembled by {@link GraphBuilder.compile} and handed to a {@link CompiledGraph}. */
1783
+ type CompiledGraphParts = {
1784
+ definition: GraphDefinition;
1785
+ handlers: Map<string, NodeHandler>;
1786
+ conditions: Map<string, ConditionFn>;
1787
+ /**
1788
+ * Per agent node, the serializable config + JS tool executes the Rust engine bridge
1789
+ * needs (see {@link RustAgentConfig}). Empty for graphs with no agent nodes.
1790
+ */
1791
+ agentConfigs?: Map<string, RustAgentConfig>;
1792
+ /**
1793
+ * Per agent node, the governance binding (the optional {@link ApprovalEngine} plus
1794
+ * the principal that requests approvals and the node's gated tool names) that
1795
+ * {@link CompiledGraph.approveAndResume} uses to approve pending engine requests on
1796
+ * the TS path and to stamp each granted tool's `requestedBy` for the Rust guard-rail.
1797
+ * Empty for graphs with no agent nodes.
1798
+ */
1799
+ agentApprovals?: Map<string, AgentApprovalBinding>;
1800
+ /**
1801
+ * Per component node, the `{ kind, params }` carrier the Rust engine bridge needs to
1802
+ * run the native component handler (see {@link RustComponentConfig}). Empty for
1803
+ * graphs with no component nodes.
1804
+ */
1805
+ componentConfigs?: Map<string, RustComponentConfig>;
1806
+ };
1807
+ /** Options accepted by {@link CompiledGraph.run} / {@link CompiledGraph.stream}. */
1808
+ type RunOptions = {
1809
+ /** Provide a stable run id (e.g. to correlate with an external system). */
1810
+ runId?: RunId;
1811
+ };
1812
+ /**
1813
+ * A validated, runnable graph. Holds the engine wiring (registries, checkpointer,
1814
+ * event bus, runtime) so callers don't touch the lower-level `@adriane-ai/graph-runtime`
1815
+ * primitives unless they want to.
1816
+ *
1817
+ * Execution runs on the **Rust engine** via `@adriane-ai/napi` when the native addon is
1818
+ * present and the graph is one Rust can run faithfully; otherwise it falls back to
1819
+ * the in-process TypeScript {@link GraphRuntime}. The public API is identical either
1820
+ * way — `run` / `resume` / `approveAndResume` / `stream` / `onEvent` behave the same.
1821
+ */
1822
+ declare class CompiledGraph<TState extends ChannelValues = ChannelValues> {
1823
+ readonly definition: GraphDefinition;
1824
+ private readonly checkpointer;
1825
+ private readonly eventBus;
1826
+ private readonly runtime;
1827
+ /**
1828
+ * The Rust runner, when this graph runs on the Rust engine; else `null` (TS path).
1829
+ * Typed on `ChannelValues` (not `TState`) on purpose: the runner round-trips state as
1830
+ * serialized `GraphState`/JSON, so it never needs the precise channel shape — and
1831
+ * keeping `TState` out of every *field* keeps `CompiledGraph<TState>` variance-friendly
1832
+ * (a `CompiledGraph<Specific>` stays assignable to `CompiledGraph<ChannelValues>`,
1833
+ * e.g. when stored in a heterogeneous registry). The public methods re-narrow to
1834
+ * `TState` at their boundary.
1835
+ */
1836
+ private readonly rustRunner;
1837
+ /** The last suspended state seen per run id, fed back into the Rust resume/approve. */
1838
+ private readonly suspendedStates;
1839
+ /** Per agent node, the governance binding used by {@link approveAndResume}. */
1840
+ private readonly agentApprovals;
1841
+ constructor(parts: CompiledGraphParts);
1842
+ /**
1843
+ * Decide whether this graph runs on the Rust engine and, if so, build the runner.
1844
+ *
1845
+ * Since Phase F the napi seam **awaits** a callback's returned `Promise`, so the
1846
+ * SDK's genuinely-async JS node handlers and tool `execute` fns round-trip through
1847
+ * Rust faithfully — the old "synchronous seam" limitation is gone. Two boundaries
1848
+ * remain, and they shape the `"auto"` policy:
1849
+ *
1850
+ * 1. The Rust agent path builds its **own** LLM gateway from env (Mistral / Anthropic
1851
+ * / Ollama / a deterministic mock); it does *not* use the TS `AgentNodeConfig.llm`.
1852
+ * That is the intended "engine on Rust" behavior (the proven live path). The TS
1853
+ * `llm` is consulted only on the TS fallback path. Observable *structure* (final
1854
+ * status, suspend-on-approval, approve-and-resume, lifecycle events) is identical
1855
+ * across engines on the deterministic mock — proven by the fidelity test in
1856
+ * `rust-engine.test.ts`. Only the `AgentResult.reasoning` *text* differs (the two
1857
+ * mocks emit different strings), which is not part of the structural contract.
1858
+ * 2. The TS {@link import("@adriane-ai/approval-engine").ApprovalEngine}-backed approval
1859
+ * flow (file a request per gated tool, read the engine's decision on resume) lives
1860
+ * in `createAgentNodeHandler`; the Rust agent path does not invoke it. So an agent
1861
+ * node configured with `approvalEngine` would not file requests on Rust.
1862
+ *
1863
+ * Therefore `"auto"` (the default) routes a graph to Rust when the addon is present
1864
+ * **unless** any agent node uses a TS `approvalEngine` — that one case stays on the
1865
+ * TS engine to preserve the engine-backed approval semantics. Everything else (agent
1866
+ * nodes on the Rust gateway, JS action/custom/tool nodes, human gates, named
1867
+ * conditions, channel-based `approveAndResume`) runs on Rust. When the addon is
1868
+ * absent it falls back to the TS engine. `"rust"` forces Rust regardless (the caller
1869
+ * accepts the Rust-gateway / no-`approvalEngine` contract); `"ts"` forces TypeScript.
1870
+ * The public SDK API is unchanged across engines.
1871
+ *
1872
+ * Two narrower limitations are *not* gated on (they affect both `auto` and `rust`,
1873
+ * but no SDK API surfaces them as a routing choice): a JS handler that returns a
1874
+ * routing {@link import("@adriane-ai/graph-core").Command} (`{ goto }`) has its `goto`
1875
+ * dropped on Rust (the seam applies a channel update + static-edge routing — build a
1876
+ * conditional edge instead); and a {@link GraphBuilder.toolNode} whose tool is
1877
+ * `requiresApproval` *fails* rather than suspends on Rust (its handler throws a
1878
+ * `DynamicInterrupt`, which the seam surfaces as a node failure, not a clean
1879
+ * suspension). Route such graphs with `ADRIANE_SDK_ENGINE=ts` if you need them.
1880
+ */
1881
+ private maybeCreateRustRunner;
1882
+ /**
1883
+ * Adapt the (async) JS node handlers into the async producers the Rust seam needs.
1884
+ * The Rust side awaits the returned promise, so a handler doing real async work
1885
+ * round-trips faithfully. A handler that returns a routing {@link Command} (not a
1886
+ * plain channel update) is coerced to an empty update — the Rust seam applies a
1887
+ * channel-update map only; in-handler routing commands stay a TS-engine feature.
1888
+ */
1889
+ private buildNodeFns;
1890
+ /** Async tool executes for every JS-backed tool across all agent nodes. */
1891
+ private buildToolFns;
1892
+ /** The named condition predicates, retyped for the Rust seam (already synchronous). */
1893
+ private buildConditionFns;
1894
+ /** True when this graph executes on the Rust engine. */
1895
+ get usesRustEngine(): boolean;
1896
+ /** Start a fresh run from the entry node and execute until completion or suspension. */
1897
+ run(initialData?: InitialData<TState>, options?: RunOptions): Promise<TypedGraphState<TState>>;
1898
+ /** Resume a previously suspended run from its latest checkpoint. */
1899
+ resume(runId: RunId): Promise<TypedGraphState<TState>>;
1900
+ /**
1901
+ * Grant approval for the named tools and resume a run that suspended for approval
1902
+ * (an agent node with `suspendForApproval`). On the Rust path the approved tools are
1903
+ * written into `__approvedTools` by the engine before resuming; on the TS path the
1904
+ * channel is updated directly. Either way the agent re-runs and executes the
1905
+ * now-approved tools instead of gating them again. An agent never approves its own
1906
+ * tools; this is the human seam.
1907
+ */
1908
+ approveAndResume(runId: RunId, options: ApproveAndResumeOptions): Promise<TypedGraphState<TState>>;
1909
+ /**
1910
+ * Project granted tool names into the wire shape the Rust engine validates: each
1911
+ * tool carries the principal that requested it (the owning agent node) and the
1912
+ * distinct principal granting it. Names are sorted so the wire payload is
1913
+ * deterministic regardless of the caller's ordering.
1914
+ */
1915
+ private toApprovedToolWire;
1916
+ /** The agent node that declared `toolName` as approval-gated, as the request principal. */
1917
+ private requesterOfTool;
1918
+ /**
1919
+ * For each agent node with an {@link ApprovalEngine}, approve the pending requests
1920
+ * whose gated tool is in `approvedTools`, through the engine, under `resolvedBy`. The
1921
+ * engine rejects a self-approval, so this is the TS-side enforcement point that
1922
+ * mirrors the Rust guard-rail.
1923
+ */
1924
+ private approvePendingThroughEngines;
1925
+ /**
1926
+ * Stream events as the graph executes. See {@link StreamMode} for the available
1927
+ * shapes. The Rust engine has no incremental stream surface yet, so when running on
1928
+ * Rust this drives a full run and yields a single terminal `state_value`. On the TS
1929
+ * engine it streams natively.
1930
+ */
1931
+ stream(initialData: InitialData<TState>, mode: StreamMode, options?: RunOptions): AsyncIterable<StreamEvent>;
1932
+ /** Single-shot stream for the Rust path: run to terminal state, emit it once. */
1933
+ private streamViaRust;
1934
+ /** Subscribe to the run-event lifecycle stream. Returns an unsubscribe function. */
1935
+ onEvent(handler: (event: RunEvent) => void): () => void;
1936
+ /**
1937
+ * Escape hatch for the TS engine: the underlying runtime (time-travel, manual node
1938
+ * execution). On the Rust path the runtime is present but **not** the executor; use
1939
+ * {@link CompiledGraph.usesRustEngine} to branch, and the run-handle methods
1940
+ * (`run` / `resume` / `approveAndResume`) which behave identically across engines.
1941
+ */
1942
+ get engine(): GraphRuntime;
1943
+ /** Record a run's state if it suspended, so resume/approve can feed it back to Rust. */
1944
+ private captureSuspension;
1945
+ private requireSuspendedState;
1946
+ }
1947
+
1948
+ /**
1949
+ * Discriminated-union result type used across the SDK's "safe" entry points
1950
+ * (e.g. {@link GraphBuilder.safeCompile}). Mirrors Zod's `safeParse` ergonomics.
1951
+ */
1952
+ type Result<T, E> = {
1953
+ success: true;
1954
+ data: T;
1955
+ } | {
1956
+ success: false;
1957
+ error: E;
1958
+ };
1959
+ /** Base class for every error thrown by `@adriane-ai/graph-sdk`. */
1960
+ declare class AdrianeSdkError extends Error {
1961
+ constructor(message: string);
1962
+ }
1963
+ /** Thrown when `.compile()` is called on a graph that fails validation. */
1964
+ declare class GraphCompileError extends AdrianeSdkError {
1965
+ readonly errors: GraphValidationError[];
1966
+ constructor(errors: GraphValidationError[]);
1967
+ }
1968
+ /** Thrown when two nodes are added under the same id. */
1969
+ declare class DuplicateNodeError extends AdrianeSdkError {
1970
+ constructor(nodeId: string);
1971
+ }
1972
+ /** Thrown when an action node is added without an executable handler. */
1973
+ declare class MissingHandlerError extends AdrianeSdkError {
1974
+ constructor(nodeId: string);
1975
+ }
1976
+
1977
+ /** Options passed to {@link createGraph}. */
1978
+ type CreateGraphOptions = {
1979
+ name: string;
1980
+ /** Defaults to a slugified `name`. */
1981
+ id?: string;
1982
+ /** Semver-ish version string. Defaults to `"0.0.0"`. */
1983
+ version?: string;
1984
+ recursionLimit?: number;
1985
+ metadata?: Record<string, unknown>;
1986
+ };
1987
+ /** Channel shorthand: `reducer` defaults to `"replace"`. The value type is inferred from `default`. */
1988
+ type ChannelInput<TValue = unknown> = {
1989
+ type: string;
1990
+ reducer?: ChannelReducer;
1991
+ default?: TValue;
1992
+ };
1993
+ /** Config form for non-trivial nodes. A bare handler is the common case. */
1994
+ type NodeInput<TState extends ChannelValues> = {
1995
+ type?: NodeType;
1996
+ handler?: TypedNodeHandler<TState>;
1997
+ label?: string;
1998
+ retryPolicy?: RetryPolicy;
1999
+ metadata?: Record<string, unknown>;
2000
+ };
2001
+ /**
2002
+ * Fluent builder for an Adriane graph. Add channels, nodes and edges, then
2003
+ * {@link GraphBuilder.compile} into a runnable {@link CompiledGraph}.
2004
+ *
2005
+ * The `TState` type parameter accumulates the declared channels as you call
2006
+ * `.channel(...)`, so handler state and the result of `run`/`resume` are fully
2007
+ * typed without any manual annotation.
2008
+ *
2009
+ * Conditions are always **named predicates** registered here — never `eval`'d
2010
+ * strings — which is what keeps conditional routing safe and inspectable.
2011
+ */
2012
+ declare class GraphBuilder<TState extends ChannelValues = EmptyChannels> {
2013
+ private readonly options;
2014
+ private readonly channels;
2015
+ private readonly nodes;
2016
+ private readonly edges;
2017
+ private readonly handlers;
2018
+ private readonly conditions;
2019
+ /** Per agent node, the serializable config the Rust engine bridge needs. */
2020
+ private readonly agentConfigs;
2021
+ /** Per agent node, the governance binding (approval engine + requester) for resume. */
2022
+ private readonly agentApprovals;
2023
+ /** Per component node, the `{ kind, params }` carrier the Rust engine bridge needs. */
2024
+ private readonly componentConfigs;
2025
+ private entryNodeId;
2026
+ constructor(options: CreateGraphOptions);
2027
+ /** Reinterpret `this` under a wider channel type after declaring a new channel. */
2028
+ private widen;
2029
+ /** Declare a state channel. `reducer` defaults to `"replace"`; value type inferred from `default`. */
2030
+ channel<TName extends string, TValue = unknown>(name: TName, definition: ChannelInput<TValue>): GraphBuilder<TState & {
2031
+ [K in TName]: TValue;
2032
+ }>;
2033
+ /** Declare an append-reduced `messages` channel (the conversational default). */
2034
+ messagesChannel<TName extends string = "messages">(name?: TName): GraphBuilder<TState & {
2035
+ [K in TName]: Message[];
2036
+ }>;
2037
+ /** Shared node-registration path: dedupe, register the handler, default the entry. */
2038
+ private pushNode;
2039
+ /** Declare a channel only if it hasn't been declared yet (for node helpers that need one). */
2040
+ private ensureChannel;
2041
+ /** Add a node. Pass a handler for the common action case, or a config object. */
2042
+ node(id: string, handlerOrConfig: TypedNodeHandler<TState> | NodeInput<TState>): this;
2043
+ /** Convenience for a `human-gate` node that suspends the run for approval. */
2044
+ humanGate(id: string, options?: {
2045
+ label?: string;
2046
+ }): this;
2047
+ /**
2048
+ * Add an agent node: a ReAct agent driven by an LLM gateway. Its result lands in
2049
+ * `config.outputChannel` (default `"agentResult"`), which is auto-declared and
2050
+ * added to the typed state. Route on `result.requiresHumanReview` to gate
2051
+ * sensitive tool use.
2052
+ */
2053
+ agentNode<TOut extends string = typeof DEFAULT_AGENT_OUTPUT_CHANNEL>(id: string, config: AgentNodeConfig & {
2054
+ outputChannel?: TOut;
2055
+ }): GraphBuilder<TState & {
2056
+ [K in TOut]: AgentResult;
2057
+ }>;
2058
+ /**
2059
+ * Add a tool node: executes the tool calls emitted by the last AI message in the
2060
+ * `messages` channel (auto-declared as an append-reduced messages channel).
2061
+ */
2062
+ toolNode(id: string, config: ToolNodeConfig): GraphBuilder<TState & {
2063
+ messages: Message[];
2064
+ }>;
2065
+ /**
2066
+ * Add a **component node**: a pure (no-LLM) compute building block from
2067
+ * {@link import("./components.js").components} (e.g. `promptBuilder`, `router`,
2068
+ * `retriever`). The node carries the Phase C carrier (`{ kind, params }`) so it runs
2069
+ * natively on the Rust engine, *and* registers the descriptor's equivalent TS handler
2070
+ * so the TS fallback path stays faithful when the native addon is absent.
2071
+ *
2072
+ * On the Rust path the component takes precedence over the JS seam even though its id
2073
+ * is also a JS node id — the bridge routes a `componentNodes` entry to the native
2074
+ * handler. So the node always runs the same logic on either engine.
2075
+ *
2076
+ * ```ts
2077
+ * createGraph({ name: "p" })
2078
+ * .channel("name", { type: "string", default: "" })
2079
+ * .channel("prompt", { type: "string", default: "" })
2080
+ * .component("build", components.promptBuilder({ template: "Hi {{name}}", into: "prompt" }));
2081
+ * ```
2082
+ */
2083
+ component(id: string, descriptor: ComponentDescriptor, options?: {
2084
+ label?: string;
2085
+ }): this;
2086
+ /** Add an unconditional edge from one node to another. */
2087
+ edge(from: string, to: string): this;
2088
+ /**
2089
+ * Add a conditional edge guarded by a named predicate. The predicate is
2090
+ * registered under `conditionName` and evaluated against the live (typed) state.
2091
+ */
2092
+ conditionalEdge(from: string, to: string, conditionName: string, predicate: TypedCondition<TState>): this;
2093
+ /** Override the entry node (defaults to the first node added). */
2094
+ entry(nodeId: string): this;
2095
+ private buildDefinition;
2096
+ /** Validate and compile, returning a {@link Result} instead of throwing. */
2097
+ safeCompile(): Result<CompiledGraph<TState>, GraphCompileError>;
2098
+ /** Validate and compile into a runnable graph. Throws {@link GraphCompileError} on failure. */
2099
+ compile(): CompiledGraph<TState>;
2100
+ }
2101
+ /** Entry point: start building a graph. */
2102
+ declare const createGraph: (options: CreateGraphOptions) => GraphBuilder<EmptyChannels>;
2103
+
2104
+ /**
2105
+ * Canonical example graphs authored with the SDK. Shipped so the Studio can render
2106
+ * them and the control plane can seed them — one source of truth for both. Only the
2107
+ * `.definition` (plain data) is meant to cross boundaries.
2108
+ */
2109
+ type ExampleGraph = {
2110
+ slug: string;
2111
+ name: string;
2112
+ description: string;
2113
+ definition: GraphDefinition;
2114
+ };
2115
+ /** Build the example graph definitions. Pure — no LLM call, no I/O. */
2116
+ declare const exampleGraphs: () => ExampleGraph[];
2117
+
2118
+ /**
2119
+ * The Doc-QA REFERENCE GRAPH — a complete input → output retrieval-augmented
2120
+ * question-answering pipeline, composed entirely from the catalog (pure components +
2121
+ * one prebuilt-style agent), authored once and runnable two ways:
2122
+ *
2123
+ * 1. as a {@link CompiledGraph} via {@link buildDocQaReference} — runs on the engine
2124
+ * (Rust when the `@adriane-ai/napi` addon is present, else the TS fallback);
2125
+ * 2. as a plain {@link GraphDefinition} via {@link docQaReferenceDefinition} — every
2126
+ * node carries the shared `node.metadata.component` / `node.metadata.agent`
2127
+ * carrier, so the control plane can persist it, the Studio can render it, and the
2128
+ * catalog run path (`runCatalogGraph`) can execute it on the Rust engine.
2129
+ *
2130
+ * ── THE PIPELINE ──────────────────────────────────────────────────────────────
2131
+ * INPUT { question, documents }
2132
+ * → clean (textCleaner) normalise the raw documents text
2133
+ * → split (documentSplitter) chunk it into passages
2134
+ * → retrieve (retriever) deterministic mock-embedding top-k over the corpus
2135
+ * → rerank (reranker) reorder the hits against the question
2136
+ * → prompt (promptBuilder) build a grounded prompt from context + question
2137
+ * → answer (AGENT, balanced) a grounded RAG answerer writes its AgentResult
2138
+ * → extract (fieldExtractor) reduce AgentResult.reasoning to the final answer text
2139
+ * → assemble (answerBuilder) answer text + numbered citations → OUTPUT { answer }
2140
+ * OUTPUT { answer }
2141
+ *
2142
+ * Single input set, single output channel. Deterministic OFFLINE (a mock gateway, no
2143
+ * keys) and live-capable (Mistral when MISTRAL_API_KEY is present — the balanced tier
2144
+ * resolves to a concrete Mistral model on the Rust path).
2145
+ *
2146
+ * The retriever scores against a fixed corpus baked into its params (the Rust
2147
+ * `retriever` component's `docs` are configuration, not a channel). The `documents`
2148
+ * INPUT channel feeds the clean → split ingestion-prep stages so the graph exercises a
2149
+ * real document-preparation front-end; the corpus the retriever ranks is the same
2150
+ * knowledge the documents describe, kept in params so the run is fully reproducible.
2151
+ */
2152
+
2153
+ /** The default knowledge corpus the retriever ranks against. */
2154
+ declare const DEFAULT_REFERENCE_CORPUS: RetrieverDoc[];
2155
+ /** Options for {@link buildDocQaReference} / {@link docQaReferenceDefinition}. */
2156
+ type DocQaReferenceOptions = {
2157
+ /**
2158
+ * The LLM gateway the answerer agent runs on (TS-engine path). Defaults to a
2159
+ * deterministic mock so the graph runs end-to-end with no provider keys. The Rust
2160
+ * engine path builds its own gateway from env (Mistral when MISTRAL_API_KEY is set,
2161
+ * else a deterministic mock), independent of this.
2162
+ */
2163
+ llm?: LLMGateway;
2164
+ /** The corpus the retriever ranks against. Defaults to {@link DEFAULT_REFERENCE_CORPUS}. */
2165
+ corpus?: RetrieverDoc[];
2166
+ /** How many documents the retriever keeps before reranking. Defaults to 3. */
2167
+ k?: number;
2168
+ /** The answerer's capability tier. Defaults to `"balanced"`. */
2169
+ tier?: ModelTier;
2170
+ /** The LLM provider slot (and the slot the default mock registers under). Defaults to `"mistral"`. */
2171
+ provider?: "openai" | "anthropic" | "mistral";
2172
+ };
2173
+ /**
2174
+ * Build the Doc-QA reference graph as a runnable {@link CompiledGraph}. Drive it with
2175
+ * a single input set and read the single output channel:
2176
+ *
2177
+ * ```ts
2178
+ * const app = buildDocQaReference();
2179
+ * const out = await app.run({ question: "How does Adriane resume after a crash?", documents: "…" });
2180
+ * console.log(out.channels.answer);
2181
+ * ```
2182
+ */
2183
+ declare const buildDocQaReference: (options?: DocQaReferenceOptions) => CompiledGraph;
2184
+ /**
2185
+ * The Doc-QA reference graph as a plain {@link GraphDefinition} carrying the shared
2186
+ * `node.metadata.component` / `node.metadata.agent` carrier on every node. This is the
2187
+ * form the control plane persists, the Studio renders, and `runCatalogGraph` executes
2188
+ * on the Rust engine. Pure data — no handler closures, no LLM gateway.
2189
+ */
2190
+ declare const docQaReferenceDefinition: (options?: DocQaReferenceOptions) => GraphDefinition;
2191
+
2192
+ /**
2193
+ * Prebuilt, tier-tagged micro-agent graphs. Each factory returns a runnable
2194
+ * {@link CompiledGraph} pre-wired with its capability {@link ModelTier} (matching the
2195
+ * Rust `PrebuiltAgent` definitions in `crates/components`), so the concrete model is
2196
+ * resolved by the {@link ModelPolicy} from the providers actually available — on Rust
2197
+ * by the bridge, on the TS fallback path by the SDK.
2198
+ *
2199
+ * A prebuilt agent is a one-agent graph, except {@link prebuilt.ragAnswerer}, which
2200
+ * composes the `retriever` + `reranker` components with an agent step.
2201
+ *
2202
+ * ```ts
2203
+ * import { prebuilt } from "@adriane-ai/graph-sdk";
2204
+ *
2205
+ * const result = await prebuilt.summarizer().run({ question: "long text…" });
2206
+ * console.log(result.channels.summary);
2207
+ * ```
2208
+ *
2209
+ * By default each agent runs on a deterministic mock gateway (registered under the
2210
+ * nominal provider) so a prebuilt graph runs end-to-end with no provider keys. Supply
2211
+ * `llm` to run against a real gateway, `model` to pin a concrete model, or
2212
+ * `tierOverride` to change the capability tier.
2213
+ */
2214
+
2215
+ /** Light options accepted by every prebuilt-agent factory. */
2216
+ type PrebuiltOptions = {
2217
+ /**
2218
+ * The LLM gateway the agent runs on. Defaults to a deterministic mock gateway
2219
+ * registered under the nominal provider, so the graph runs with no provider keys.
2220
+ */
2221
+ llm?: LLMGateway;
2222
+ /** Override the capability tier the agent's model is resolved from. */
2223
+ tierOverride?: ModelTier;
2224
+ /**
2225
+ * Pin a concrete model, bypassing tier resolution (the explicit-override
2226
+ * precedence: an explicit model always wins over the tier).
2227
+ */
2228
+ model?: string;
2229
+ /**
2230
+ * The provider slot for the request (and the slot the default mock gateway
2231
+ * registers under). Defaults to `"anthropic"`. The actual adapter is the mock
2232
+ * unless a custom `llm` is supplied.
2233
+ */
2234
+ provider?: LLMProvider;
2235
+ };
2236
+ /** Options for {@link prebuilt.ragAnswerer}: the simple options plus its retrieval corpus. */
2237
+ type RagAnswererOptions = PrebuiltOptions & {
2238
+ /** The corpus the retriever scores against. Defaults to a small built-in set. */
2239
+ docs?: RetrieverDoc[];
2240
+ /** How many documents the retriever keeps before reranking. Defaults to 4. */
2241
+ k?: number;
2242
+ /** Channel the question is read from (the retriever query). Defaults to `"question"`. */
2243
+ questionChannel?: string;
2244
+ };
2245
+ /**
2246
+ * The prebuilt micro-agent surface. Each factory returns a runnable
2247
+ * {@link CompiledGraph} pre-wired with the agent's tier (matching the Rust
2248
+ * `PrebuiltAgent` definitions).
2249
+ */
2250
+ declare const prebuilt: {
2251
+ /** Condense input text into a short, faithful summary (writes `summary`). */
2252
+ readonly summarizer: (options?: PrebuiltOptions) => CompiledGraph;
2253
+ /** Assign the input to one label from a fixed set (writes `label`). */
2254
+ readonly classifier: (options?: PrebuiltOptions) => CompiledGraph;
2255
+ /** Extract structured fields from text as JSON (writes `extracted`). */
2256
+ readonly extractor: (options?: PrebuiltOptions) => CompiledGraph;
2257
+ /** Generate a SQL query from a natural-language request (writes `sql`). */
2258
+ readonly sqlGenerator: (options?: PrebuiltOptions) => CompiledGraph;
2259
+ /** Answer a question grounded in retrieved documents (retriever + reranker + agent). */
2260
+ readonly ragAnswerer: (options?: RagAnswererOptions) => CompiledGraph;
2261
+ /** Decide on a refund, gated behind human approval before the `refund` tool runs. */
2262
+ readonly refundApprover: (options?: PrebuiltOptions) => CompiledGraph;
2263
+ /** Translate input text into a target language (fast; writes `translation`). */
2264
+ readonly translator: (options?: PrebuiltOptions) => CompiledGraph;
2265
+ /** Classify the emotional tone of the input (fast; writes `sentiment`). */
2266
+ readonly sentimentAnalyzer: (options?: PrebuiltOptions) => CompiledGraph;
2267
+ /** Extract named entities from text as a JSON array (fast; writes `entities`). */
2268
+ readonly entityExtractor: (options?: PrebuiltOptions) => CompiledGraph;
2269
+ /** Redact personally identifiable information from text (fast; writes `redacted`). */
2270
+ readonly piiRedactor: (options?: PrebuiltOptions) => CompiledGraph;
2271
+ /** Map the input to a single conversational intent label (fast; writes `intent`). */
2272
+ readonly intentClassifier: (options?: PrebuiltOptions) => CompiledGraph;
2273
+ /** Generate a short, descriptive title for the input (fast; writes `title`). */
2274
+ readonly titleGenerator: (options?: PrebuiltOptions) => CompiledGraph;
2275
+ /** Extract the key terms from the input as a JSON array (fast; writes `keywords`). */
2276
+ readonly keywordExtractor: (options?: PrebuiltOptions) => CompiledGraph;
2277
+ /** Answer a question directly and concisely (balanced; writes `answer`). */
2278
+ readonly questionAnswerer: (options?: PrebuiltOptions) => CompiledGraph;
2279
+ /** Review a code snippet or diff for correctness and quality (frontier; writes `review`). */
2280
+ readonly codeReviewer: (options?: PrebuiltOptions) => CompiledGraph;
2281
+ /** Polish prose for clarity, grammar, flow, and tone (creative; writes `edited`). */
2282
+ readonly copyEditor: (options?: PrebuiltOptions) => CompiledGraph;
2283
+ };
2284
+
2285
+ /**
2286
+ * Real text embeddings as an exported SDK helper (NOT a catalog component kind).
2287
+ *
2288
+ * {@link createEmbeddings} returns an {@link Embeddings} whose `embed` turns a batch of
2289
+ * texts into dense vectors. The default transport POSTs to the Mistral embeddings API
2290
+ * (`/embeddings` with `{ model, input }` and a `Bearer` key), parsing `data[].embedding`.
2291
+ * The {@link CreateEmbeddingsOptions.transport} hook overrides the network call so a test
2292
+ * can return deterministic vectors with no real network. This is the embedding backbone
2293
+ * behind {@link import("./semantic-retriever.js").semanticRetriever}.
2294
+ *
2295
+ * ```ts
2296
+ * import { createEmbeddings } from "@adriane-ai/graph-sdk";
2297
+ *
2298
+ * const embeddings = createEmbeddings({ apiKey: process.env.MISTRAL_API_KEY });
2299
+ * const [a, b] = await embeddings.embed(["hello", "world"]);
2300
+ * ```
2301
+ */
2302
+ /** An embedder: turn a batch of texts into one dense vector each (order-preserving). */
2303
+ type Embeddings = {
2304
+ /** Embed `texts` into a `number[][]` of the same length and order. */
2305
+ embed(texts: string[]): Promise<number[][]>;
2306
+ };
2307
+ /**
2308
+ * The transport an embeddings client posts through: it receives the assembled request
2309
+ * body and must resolve to the parsed JSON response (the `{ data: [{ embedding }] }`
2310
+ * shape the Mistral embeddings API returns). The real default builds this from `fetch`;
2311
+ * a test injects a fake to stay offline.
2312
+ */
2313
+ type EmbeddingsTransport = (body: EmbeddingsRequestBody) => Promise<unknown> | unknown;
2314
+ /** The request body POSTed to the embeddings endpoint (`{ model, input }`). */
2315
+ type EmbeddingsRequestBody = {
2316
+ model: string;
2317
+ input: string[];
2318
+ };
2319
+ /** Options for {@link createEmbeddings}. */
2320
+ type CreateEmbeddingsOptions = {
2321
+ /** The embeddings provider. Only `"mistral"` is wired today (the default). */
2322
+ provider?: "mistral";
2323
+ /** API key. Defaults to `process.env.MISTRAL_API_KEY`. Required unless `transport` is injected. */
2324
+ apiKey?: string;
2325
+ /** Embedding model. Defaults to `"mistral-embed"`. */
2326
+ model?: string;
2327
+ /** API base URL. Defaults to `"https://api.mistral.ai/v1"`. */
2328
+ baseUrl?: string;
2329
+ /**
2330
+ * An injectable transport overriding the default `fetch`-based call. Receives the
2331
+ * request body and returns the parsed JSON response. Inject a fake to keep a test
2332
+ * offline (or to point at a stub) — when set, no API key is required.
2333
+ */
2334
+ transport?: EmbeddingsTransport;
2335
+ };
2336
+ /** Raised when no API key and no transport were supplied, so a real call is impossible. */
2337
+ declare class MissingEmbeddingsKeyError extends Error {
2338
+ constructor();
2339
+ }
2340
+ /** Raised when the embeddings response doesn't carry the expected `data[].embedding` shape. */
2341
+ declare class EmbeddingsResponseError extends Error {
2342
+ constructor(detail: string);
2343
+ }
2344
+ /**
2345
+ * Create an {@link Embeddings} client. With the default transport it POSTs to the
2346
+ * Mistral embeddings API (`{baseUrl||'https://api.mistral.ai/v1'}/embeddings`) with
2347
+ * `{ model: model||'mistral-embed', input: texts }` and `Authorization: Bearer
2348
+ * (apiKey || process.env.MISTRAL_API_KEY)`, parsing `data[].embedding`. Inject
2349
+ * `transport` to override that for offline tests. Throws {@link MissingEmbeddingsKeyError}
2350
+ * when neither a key nor a transport is available.
2351
+ */
2352
+ declare const createEmbeddings: (options?: CreateEmbeddingsOptions) => Embeddings;
2353
+
2354
+ /**
2355
+ * A small embedding-backed vector store as an exported SDK helper (NOT a catalog
2356
+ * component kind). {@link createVectorStore} keeps `{ id, content, embedding, metadata? }`
2357
+ * items and answers nearest-neighbour {@link VectorStore.query} calls by cosine
2358
+ * similarity (descending). In-memory by default; when `persistPath` is set the store is
2359
+ * persisted to / loaded from a round-trippable JSON file (synchronous `fs`). The exported
2360
+ * {@link cosineSimilarity} powers the ranking and is reusable on its own.
2361
+ *
2362
+ * ```ts
2363
+ * import { createVectorStore } from "@adriane-ai/graph-sdk";
2364
+ *
2365
+ * const store = createVectorStore();
2366
+ * store.upsert([{ id: "a", content: "hello", embedding: [1, 0] }]);
2367
+ * const hits = store.query([1, 0], 1); // [{ id: "a", content: "hello", score: 1 }]
2368
+ * ```
2369
+ */
2370
+ /** An item stored in the vector store: an id, its text, its embedding and optional metadata. */
2371
+ type VectorStoreItem = {
2372
+ id: string;
2373
+ content: string;
2374
+ embedding: number[];
2375
+ metadata?: Record<string, unknown>;
2376
+ };
2377
+ /** A single nearest-neighbour result: the item (minus its embedding) plus a cosine score. */
2378
+ type VectorStoreMatch = {
2379
+ id: string;
2380
+ content: string;
2381
+ score: number;
2382
+ metadata?: Record<string, unknown>;
2383
+ };
2384
+ /** The vector store surface returned by {@link createVectorStore}. */
2385
+ type VectorStore = {
2386
+ /** Insert or replace items by `id` (last write wins); persists when `persistPath` is set. */
2387
+ upsert(items: VectorStoreItem[]): void;
2388
+ /** Return the top-`k` items by cosine similarity to `embedding`, highest score first. */
2389
+ query(embedding: number[], k: number): VectorStoreMatch[];
2390
+ /** The number of items currently held. */
2391
+ size(): number;
2392
+ };
2393
+ /** Options for {@link createVectorStore}. */
2394
+ type CreateVectorStoreOptions = {
2395
+ /**
2396
+ * When set, the store loads its items from this JSON file on creation (if present) and
2397
+ * rewrites it on every {@link VectorStore.upsert}. The file is a round-trippable JSON
2398
+ * array of {@link VectorStoreItem}. Omit for a purely in-memory store.
2399
+ */
2400
+ persistPath?: string;
2401
+ };
2402
+ /**
2403
+ * Cosine similarity of two vectors. Compares over the shorter length (missing
2404
+ * components count as 0) and returns `0` when either vector has zero magnitude, so a
2405
+ * degenerate input never produces `NaN`.
2406
+ */
2407
+ declare const cosineSimilarity: (a: number[], b: number[]) => number;
2408
+ /**
2409
+ * Create a {@link VectorStore}. In-memory by default; with `persistPath` it loads any
2410
+ * existing JSON file on creation and rewrites it on every upsert (round-trippable).
2411
+ */
2412
+ declare const createVectorStore: (options?: CreateVectorStoreOptions) => VectorStore;
2413
+
2414
+ /**
2415
+ * A semantic (vector-store) retrieval connector as an exported SDK helper — the "real
2416
+ * embeddings" sibling of the deterministic mock `components.retriever`. It is NOT a new
2417
+ * catalog component kind: {@link semanticRetriever} returns a plain {@link NodeHandler}
2418
+ * added with {@link import("./builder.js").GraphBuilder.node} (the same vendor-I/O shape
2419
+ * as `components.httpFetch` / `components.webSearch`), so on the Rust engine it runs over
2420
+ * the async JS seam (`on_node`) like any other JS node.
2421
+ *
2422
+ * On each run it (optionally) embeds `docs` into the {@link VectorStore}, embeds the
2423
+ * query, then writes the top-`k` `{ id, content, score }` matches to the `into` channel.
2424
+ * `embeddings` defaults to a real Mistral client ({@link createEmbeddings}); inject a
2425
+ * fake {@link Embeddings} to keep a test offline and deterministic.
2426
+ *
2427
+ * ```ts
2428
+ * import { createGraph, semanticRetriever } from "@adriane-ai/graph-sdk";
2429
+ *
2430
+ * createGraph({ name: "semantic" })
2431
+ * .channel("q", { type: "string", default: "" })
2432
+ * .channel("hits", { type: "json", default: [] })
2433
+ * .node("retrieve", semanticRetriever({
2434
+ * queryFrom: "q",
2435
+ * into: "hits",
2436
+ * k: 3,
2437
+ * docs: [{ id: "d1", content: "Adriane is a graph runtime." }],
2438
+ * embeddings: fakeEmbeddings // deterministic in tests
2439
+ * }));
2440
+ * ```
2441
+ */
2442
+
2443
+ /** A candidate document to embed into the store before querying. */
2444
+ type SemanticRetrieverDoc = {
2445
+ id: string;
2446
+ content: string;
2447
+ };
2448
+ /** Params for {@link semanticRetriever}. */
2449
+ type SemanticRetrieverParams = {
2450
+ /** A literal query (mutually exclusive with `queryFrom`). */
2451
+ query?: string;
2452
+ /** A channel whose value supplies the query (takes precedence when its channel is set). */
2453
+ queryFrom?: string;
2454
+ /** Channel receiving the top-`k` `{ id, content, score }` array. */
2455
+ into: string;
2456
+ /** Number of results to keep. Defaults to 4. */
2457
+ k?: number;
2458
+ /**
2459
+ * Documents to embed into the store before querying. Each run embeds and upserts these
2460
+ * (idempotent by id). Omit to query against an already-populated injected `store`.
2461
+ */
2462
+ docs?: SemanticRetrieverDoc[];
2463
+ /**
2464
+ * The vector store to upsert into / query. Defaults to a fresh in-memory store created
2465
+ * per factory call. Inject a shared/persistent store to reuse embeddings across runs.
2466
+ */
2467
+ store?: VectorStore;
2468
+ /**
2469
+ * The embeddings client. Defaults to a real Mistral client ({@link createEmbeddings}).
2470
+ * Inject a fake (deterministic vectors) to keep a test offline.
2471
+ */
2472
+ embeddings?: Embeddings;
2473
+ };
2474
+ /**
2475
+ * Build the semantic-retriever node handler. Each invocation embeds any supplied `docs`
2476
+ * into the store, embeds the resolved query, and writes the top-`k`
2477
+ * {@link VectorStoreMatch} array (`{ id, content, score }`) to `into`. Throws no special
2478
+ * error class — it surfaces the underlying embeddings error if the real client can't run
2479
+ * (no key / no transport), which is the honest failure mode for a real connector.
2480
+ */
2481
+ declare const semanticRetriever: (params: SemanticRetrieverParams) => NodeHandler;
2482
+
2483
+ /**
2484
+ * The static catalog metadata that backs the API's `/catalog` endpoint: one entry per
2485
+ * component, prebuilt agent and capability tier. This is the SDK's source of truth for
2486
+ * the building-block library; the API validates these arrays against the
2487
+ * `@adriane-ai/contracts` catalog DTOs and forwards them to Studio unchanged.
2488
+ *
2489
+ * The arrays mirror, one-for-one:
2490
+ * - the 30 component factories in {@link import("./components.js").components} (28 pure
2491
+ * Rust-backed components + 2 vendor-I/O integration components), with their real
2492
+ * factory params;
2493
+ * - the 16 prebuilt micro-agent definitions (the Rust `PrebuiltAgent` table);
2494
+ * - the 4 capability tiers, each carrying the {@link DEFAULT_TIER_TABLE} per-provider
2495
+ * recommended models.
2496
+ *
2497
+ * The shapes are deliberately plain data (no closures) so they map 1:1 onto the
2498
+ * contracts DTOs and serialize over the wire as-is.
2499
+ */
2500
+
2501
+ /** The category buckets a component falls into in the library. */
2502
+ type ComponentCategory = "prompt" | "validation" | "parsing" | "routing" | "retrieval" | "text" | "data" | "integration" | "splitter" | "generation" | "evaluation" | "writer";
2503
+ /** A single parameter a component factory accepts. */
2504
+ type ComponentParamMeta = {
2505
+ name: string;
2506
+ type: string;
2507
+ required: boolean;
2508
+ description: string;
2509
+ };
2510
+ /** One entry in the component library: a `kind` plus its presentation + params. */
2511
+ type ComponentCatalogEntry = {
2512
+ /** The component kind — a {@link ComponentKind} for pure components, or an integration name. */
2513
+ kind: ComponentKind | "httpFetch" | "webSearch";
2514
+ title: string;
2515
+ category: ComponentCategory;
2516
+ description: string;
2517
+ params: ComponentParamMeta[];
2518
+ /** `true` for the vendor-I/O integration components (httpFetch / webSearch). */
2519
+ integration: boolean;
2520
+ };
2521
+ /** One entry in the prebuilt-agent catalog, mirroring the Rust `PrebuiltAgent` table. */
2522
+ type PrebuiltAgentCatalogEntry = {
2523
+ name: string;
2524
+ title: string;
2525
+ description: string;
2526
+ tier: ModelTier;
2527
+ tools: string[];
2528
+ suspendForApproval: boolean;
2529
+ outputChannel: string;
2530
+ };
2531
+ /** Describes one capability tier plus its recommended per-provider models. */
2532
+ type ModelTierInfo = {
2533
+ tier: ModelTier;
2534
+ description: string;
2535
+ /** `provider -> model` recommended defaults for this tier. */
2536
+ models: Record<string, string>;
2537
+ };
2538
+ /**
2539
+ * The 30 component catalog entries: 28 pure Rust-backed components (whose `kind`
2540
+ * matches {@link ComponentKind} / `ComponentRegistry::kinds()`) plus 2 vendor-I/O
2541
+ * integration components. Params mirror the real factory `*Params` types in
2542
+ * `./components.ts`.
2543
+ */
2544
+ declare const componentCatalog: readonly ComponentCatalogEntry[];
2545
+ /**
2546
+ * The 16 prebuilt micro-agent catalog entries, mirroring the Rust `PrebuiltAgent`
2547
+ * table (`crates/components/src/prebuilt.rs`) and the SDK `prebuilt-agents.ts` `DEFS`:
2548
+ * name, tier, description, tools, suspend flag and output channel.
2549
+ */
2550
+ declare const prebuiltCatalog: readonly PrebuiltAgentCatalogEntry[];
2551
+ /**
2552
+ * The 4 capability tiers, each carrying its description and the per-provider
2553
+ * recommended models from {@link DEFAULT_TIER_TABLE} (anthropic / mistral / ollama).
2554
+ * Derived from the gateway table so the catalog tracks the source of truth.
2555
+ */
2556
+ declare const tierCatalog: readonly ModelTierInfo[];
2557
+
2558
+ /** True when graph validation is being served by the Rust core. */
2559
+ declare const rustValidatorActive: () => boolean;
2560
+
2561
+ /** True when the native addon exposes the async run bridge (execution can use Rust). */
2562
+ declare const rustEngineAvailable: () => boolean;
2563
+ /**
2564
+ * One granted tool on the approve path, with the governance provenance the Rust
2565
+ * guard-rail validates (matches Rust `ApprovedTool`, camelCase): the principal who
2566
+ * *requested* the approval and the (distinct) principal who *resolved* it. The bridge
2567
+ * rejects the resume if `resolvedBy` is empty or equals `requestedBy` (no self-approval).
2568
+ */
2569
+ type ApprovedToolWire = {
2570
+ name: string;
2571
+ requestedBy: string;
2572
+ resolvedBy: string;
2573
+ };
2574
+
2575
+ /**
2576
+ * Run a **catalog graph** on the Rust engine.
2577
+ *
2578
+ * A catalog graph is a plain {@link GraphDefinition} (e.g. one authored in the Studio
2579
+ * graph editor, persisted as data, with no in-process TS handlers) whose nodes carry
2580
+ * the SHARED CARRIER in `node.metadata`:
2581
+ *
2582
+ * - a COMPONENT node carries `node.metadata.component = { kind, params }`
2583
+ * - an AGENT node carries `node.metadata.agent = { provider?, model?, tier?, system?,
2584
+ * toolNames?, maxIterations?, suspendForApproval?, approvalToolNames?, outputChannel? }`
2585
+ *
2586
+ * This is the seam a control plane uses to EXECUTE a graph built from
2587
+ * the catalog: it reads each node's metadata, assembles the engine's
2588
+ * `EngineSpec.componentNodes` + `agents` maps + the `jsNodeIds` for plain
2589
+ * action/tool nodes, and drives the run on the **Rust engine** via `@adriane-ai/napi`.
2590
+ *
2591
+ * Unlike {@link import("./builder.js").GraphBuilder}, there are no TS handler closures
2592
+ * here — components and agents run **natively** in Rust, and plain action/tool nodes
2593
+ * are inert JS seams (they return an empty channel update). The carrier IS the wiring.
2594
+ *
2595
+ * The carrier readers below mirror the canonical Zod schema in
2596
+ * `@adriane-ai/contracts` (`node-metadata.ts`); the SDK stays dependency-free of the
2597
+ * contracts package, so the narrowing is duplicated structurally here. The control
2598
+ * plane is free to validate the carrier with the contracts schema before handing the
2599
+ * definition to this runner.
2600
+ */
2601
+
2602
+ /** The component carrier on `node.metadata.component`. Mirrors the contracts schema. */
2603
+ type ComponentCarrier = {
2604
+ kind: string;
2605
+ params: Record<string, unknown>;
2606
+ };
2607
+ /** The agent carrier on `node.metadata.agent`. Mirrors the contracts schema. */
2608
+ type AgentCarrier = {
2609
+ provider?: string;
2610
+ model?: string;
2611
+ tier?: ModelTier;
2612
+ system?: string;
2613
+ toolNames?: string[];
2614
+ maxIterations?: number;
2615
+ suspendForApproval?: boolean;
2616
+ approvalToolNames?: string[];
2617
+ outputChannel?: string;
2618
+ };
2619
+ /** Outcome of a catalog-graph run: the terminal/suspended state and a flat status. */
2620
+ type CatalogRunOutcome = {
2621
+ /** The final (or suspended) graph state, channels included. */
2622
+ state: GraphState;
2623
+ /** `"running" | "suspended" | "completed" | "failed"` — the state's status. */
2624
+ status: string;
2625
+ /** True when execution ran on the Rust engine (always, since this seam requires it). */
2626
+ usedRustEngine: true;
2627
+ };
2628
+ /** Options for {@link runCatalogGraph} / {@link resumeCatalogGraph}. */
2629
+ type RunCatalogGraphOptions = {
2630
+ /** A stable run id. Defaults to a generated one. */
2631
+ runId?: RunId;
2632
+ /** Initial channel data seeding the run. */
2633
+ initialData?: Record<string, unknown>;
2634
+ /** Subscribe to forwarded run-lifecycle events (every node transition). */
2635
+ onEvent?: (event: RunEvent) => void;
2636
+ /**
2637
+ * Route the run's approvals through an {@link ApprovalEngine}. When present, the
2638
+ * agents run natively on Rust as usual, but the moment the run suspends for approval
2639
+ * the seam files one request per gated tool (`requestedBy = nodeId`, the agent's own
2640
+ * subject) and stashes the engine ids in the `__approvalIds` channel of the returned
2641
+ * state — so a human resolves them out of band (the engine forbids self-approval) and
2642
+ * the control plane only ever resumes with engine-approved tools. Absent: the run is
2643
+ * ungoverned (the legacy channel-only behaviour).
2644
+ */
2645
+ approvalEngine?: ApprovalEngine;
2646
+ };
2647
+ /** Raised when the native engine is unavailable — catalog graphs require it. */
2648
+ declare class RustEngineUnavailableError extends Error {
2649
+ constructor();
2650
+ }
2651
+ /** Narrow a node's open metadata bag to its COMPONENT carrier, if present and valid. */
2652
+ declare const readComponentCarrier: (metadata: Record<string, unknown> | undefined) => ComponentCarrier | undefined;
2653
+ /** Narrow a node's open metadata bag to its AGENT carrier, if present and valid. */
2654
+ declare const readAgentCarrier: (metadata: Record<string, unknown> | undefined) => AgentCarrier | undefined;
2655
+ /**
2656
+ * Run a catalog {@link GraphDefinition} (whose nodes carry `node.metadata.component`
2657
+ * and `node.metadata.agent`) to completion or suspension on the **Rust engine**.
2658
+ *
2659
+ * Throws {@link RustEngineUnavailableError} when the native addon is absent.
2660
+ */
2661
+ declare const runCatalogGraph: (definition: GraphDefinition, options?: RunCatalogGraphOptions) => Promise<CatalogRunOutcome>;
2662
+ /**
2663
+ * Resume a previously-suspended catalog run (e.g. past a human gate) from its
2664
+ * serialized {@link GraphState}, on the **Rust engine**. The bridge seeds its
2665
+ * checkpointer with this state and resumes from it.
2666
+ *
2667
+ * Throws {@link RustEngineUnavailableError} when the native addon is absent.
2668
+ */
2669
+ declare const resumeCatalogGraph: (definition: GraphDefinition, state: GraphState, options?: Pick<RunCatalogGraphOptions, "onEvent" | "approvalEngine"> & {
2670
+ /**
2671
+ * Human-granted tools to unlock on resume, each carrying its `{ name, requestedBy,
2672
+ * resolvedBy }` provenance. Passed straight through to the Rust bridge, which
2673
+ * re-validates the no-self-approval invariant per tool on `Entry::Resume` and writes
2674
+ * only the validated names into `__approvedTools`. A control plane
2675
+ * is the authority on which tools were approved (drawn from the ApprovalEngine), but
2676
+ * the engine re-checks the provenance here — defence in depth on the PRODUCTION
2677
+ * resume path. Omitted/empty: an ordinary resume that unlocks no tools.
2678
+ */
2679
+ approvedTools?: ApprovedToolWire[];
2680
+ }) => Promise<CatalogRunOutcome>;
2681
+ /** Type guard a node carries either catalog carrier. Useful to decide the run path. */
2682
+ declare const isCatalogGraph: (definition: GraphDefinition) => boolean;
2683
+
2684
+ export { AGENT_APPROVAL_INTERRUPT, type AIMessage, APPROVAL_IDS_CHANNEL, APPROVED_TOOLS_CHANNEL, AdrianeSdkError, type AgentApprovalBinding, type AgentCarrier, type AgentNodeConfig, type AgentPromptSource, type AgentResult, type AnswerBuilderParams, AnthropicProviderAdapter, type ApproveAndResumeOptions, type ApprovedToolWire, type Bm25RetrieverParams, type CatalogRunOutcome, type ChannelInput, type ChannelReducer, type ChannelUpdate, type ChannelValues, type ChatMessageBuilderParams, type ChatMessageSpec, type Command, CompiledGraph, type CompiledGraphParts, type ComponentCarrier, type ComponentCatalogEntry, type ComponentCategory, type ComponentDescriptor, type ComponentKind, type ComponentParamMeta, type ConditionFn, type ConditionalRouterBranch, type ConditionalRouterParams, type CreateEmbeddingsOptions, type CreateGraphOptions, type CreateVectorStoreOptions, type CsvParserParams, DEFAULT_AGENT_OUTPUT_CHANNEL, DEFAULT_PREFERENCE, DEFAULT_REFERENCE_CORPUS, DEFAULT_TIER_TABLE, type DeduplicatorParams, DefaultLLMGateway, type DocQaReferenceOptions, type DocumentJoinerParams, type DocumentSplitterParams, type DocumentWriterParams, DuplicateNodeError, DynamicInterrupt, type Embeddings, type EmbeddingsRequestBody, EmbeddingsResponseError, type EmbeddingsTransport, type EmptyChannels, type EvaluatorParams, type ExampleGraph, type FieldMapperParams, GraphBuilder, GraphCompileError, type GraphDefinition, type GraphState, type GraphStatus, type HtmlToTextParams, type HttpFetchImpl, type HttpFetchParams, type HttpFetchRequestInit, type HttpFetchResponseLike, type HttpFetchResult, InMemoryCheckpointer, InMemoryPromptRegistry, InMemoryToolRegistry, type InitialData, type IntegrationComponentHandler, type JsonValidatorParams, type KeywordRetrieverParams, type LLMGateway, type LLMProvider, type LLMResponse, type LLMStreamChunk, type LLMToolCall, type LanguageDetectorParams, type LexicalDoc, type ListJoinerParams, MODEL_TIERS, type MergeRankerParams, type Message, type MessageId, type MetadataFilterParams, MissingEmbeddingsKeyError, MissingHandlerError, MockLLMProviderAdapter, type ModelChoice, ModelPolicy, type ModelTier, type ModelTierInfo, type NodeHandler, type NodeId, type NodeInput, type OpenAIChatRequestBody, type OpenAIChatResponse, type OpenAICompatibleAdapterOptions, OpenAICompatibleProviderAdapter, type OpenAICompatibleTransportPort, type OutputParserParams, type PrebuiltAgentCatalogEntry, type PrebuiltOptions, type PredicateOp, type PromptBuilderParams, type PromptRegistry, type RagAnswererOptions, type RegexExtractorParams, type RerankerParams, type ResolveOverride, type Result, type RetrieverDoc, type RetrieverParams, type RouterParams, type RouterRule, type RunCatalogGraphOptions, type RunEvent, type RunId, type RunOptions, type RustAgentConfig, type RustComponentConfig, RustEngineUnavailableError, type RustToolBinding, type SemanticRetrieverDoc, type SemanticRetrieverParams, type SentenceWindowSplitterParams, type StreamAgentConfig, type StreamEvent, type StreamMode, type TextCleanerParams, type TierModelTable, type ToolCall, type ToolDefinition, type ToolId, type ToolNodeConfig, type ToolRegistry, type TruncatorParams, type TypedCondition, type TypedGraphState, type TypedNodeHandler, type VectorStore, type VectorStoreItem, type VectorStoreMatch, type WebSearchImpl, type WebSearchOutcome, type WebSearchParams, type WebSearchResult, type WebSearchTransport, buildDocQaReference, componentCatalog, components, cosineSimilarity, createAgentNodeHandler, createEmbeddings, createGraph, createToolNodeHandler, createVectorStore, docQaReferenceDefinition, exampleGraphs, isCatalogGraph, prebuilt, prebuiltCatalog, readAgentCarrier, readComponentCarrier, resumeCatalogGraph, runCatalogGraph, rustEngineAvailable, rustValidatorActive, semanticRetriever, streamAgentTokens, tierCatalog, toAgentApprovalBinding, toRustAgentConfig };