@standardagents/builder 0.8.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,2962 @@
1
+ export { AgentPluginOptions, agentbuilder } from './plugin.js';
2
+ import { DurableObjectStorage } from '@cloudflare/workers-types';
3
+ import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
4
+ import { z, ZodString, ZodNumber, ZodBoolean, ZodNull, ZodLiteral, ZodEnum, ZodOptional, ZodNullable, ZodDefault, ZodArray, ZodObject, ZodRecord, ZodUnion } from 'zod';
5
+ import { DurableObject } from 'cloudflare:workers';
6
+ import 'vite';
7
+
8
+ /**
9
+ * Global namespace for AgentBuilder types.
10
+ *
11
+ * This namespace provides type-safe references for models, prompts, agents, and tools.
12
+ * Types are automatically populated when you run `pnpm dev` or `pnpm build`,
13
+ * which scans your `agentbuilder/` directories and generates types.
14
+ *
15
+ * The generated types are placed in `.agentbuilder/types.d.ts` and augment this namespace.
16
+ *
17
+ * Note: We use interfaces as type registries because TypeScript allows interface
18
+ * declaration merging. The user's generated types will add properties to these
19
+ * interfaces, and we extract the union of all property keys.
20
+ */
21
+ declare global {
22
+ namespace AgentBuilder {
23
+ /**
24
+ * Interface for model type registration.
25
+ * Generated types add properties: interface ModelRegistry { 'gpt-4o': true; 'claude-3': true; }
26
+ * This gives us: type Models = keyof ModelRegistry = 'gpt-4o' | 'claude-3'
27
+ */
28
+ interface ModelRegistry {
29
+ }
30
+ /**
31
+ * Interface for prompt type registration.
32
+ */
33
+ interface PromptRegistry {
34
+ }
35
+ /**
36
+ * Interface for agent type registration.
37
+ */
38
+ interface AgentRegistry {
39
+ }
40
+ /**
41
+ * Interface for tool type registration.
42
+ */
43
+ interface ToolRegistry {
44
+ }
45
+ /**
46
+ * Interface for callable type registration (prompts, agents, tools).
47
+ */
48
+ interface CallableRegistry {
49
+ }
50
+ /**
51
+ * Union type of all model names defined in agentbuilder/models/.
52
+ * When ModelRegistry is empty, this defaults to string for flexibility.
53
+ * When populated, it narrows to the specific model names.
54
+ */
55
+ type Models = keyof ModelRegistry extends never ? string : keyof ModelRegistry;
56
+ /**
57
+ * Union type of all prompt names defined in agentbuilder/prompts/.
58
+ */
59
+ type Prompts = keyof PromptRegistry extends never ? string : keyof PromptRegistry;
60
+ /**
61
+ * Union type of all agent names defined in agentbuilder/agents/.
62
+ */
63
+ type Agents = keyof AgentRegistry extends never ? string : keyof AgentRegistry;
64
+ /**
65
+ * Union type of all tool names defined in agentbuilder/tools/.
66
+ */
67
+ type Tools = keyof ToolRegistry extends never ? string : keyof ToolRegistry;
68
+ /**
69
+ * Union type of all callable items (prompts, agents, tools) that can be used as tools.
70
+ */
71
+ type Callables = keyof CallableRegistry extends never ? string : keyof CallableRegistry;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Callback function to execute before stream closes
77
+ */
78
+ type BeforeClose = () => Promise<void> | void;
79
+ /**
80
+ * Manages multiplexed streaming of content (HTTP) and telemetry (WebSocket)
81
+ * Inspired by bod.coach MultiplexedStream pattern
82
+ */
83
+ declare class StreamManager {
84
+ /**
85
+ * HTTP ReadableStream controller for content
86
+ */
87
+ private httpController?;
88
+ /**
89
+ * HTTP ReadableStream for content chunks
90
+ */
91
+ httpStream: ReadableStream<Uint8Array>;
92
+ /**
93
+ * WebSocket connections for telemetry
94
+ */
95
+ private wsConnections;
96
+ /**
97
+ * Active channels
98
+ */
99
+ activeChannels: number;
100
+ /**
101
+ * Before close hooks
102
+ */
103
+ private beforeCloseHooks;
104
+ /**
105
+ * Prevent automatic close
106
+ */
107
+ preventClose: boolean;
108
+ /**
109
+ * Text encoder for streams
110
+ */
111
+ private encoder;
112
+ /**
113
+ * Promise that resolves when stream is completely finished
114
+ */
115
+ then: Promise<void>;
116
+ /**
117
+ * Resolver for the then promise
118
+ */
119
+ private resolver;
120
+ /**
121
+ * Whether the stream has been closed
122
+ */
123
+ private closed;
124
+ constructor(beforeClose?: BeforeClose | BeforeClose[]);
125
+ /**
126
+ * Send content chunk to HTTP stream
127
+ */
128
+ sendContent(chunk: string): void;
129
+ /**
130
+ * Send telemetry event to all WebSocket connections
131
+ */
132
+ sendTelemetry(event: TelemetryEvent): void;
133
+ /**
134
+ * Emit a custom event to all WebSocket connections
135
+ *
136
+ * This sends a custom event message that can be received by frontend
137
+ * clients using the onThreadEvent hook.
138
+ *
139
+ * @param type - The event type name
140
+ * @param data - The event payload (any serializable data)
141
+ */
142
+ emitEvent(type: string, data: unknown): void;
143
+ /**
144
+ * Add a WebSocket connection for telemetry
145
+ */
146
+ addWebSocket(ws: WebSocket): void;
147
+ /**
148
+ * Add a before close hook
149
+ */
150
+ addBeforeClose(hook: BeforeClose | BeforeClose[]): void;
151
+ /**
152
+ * Wait for a callback to complete before allowing stream to close
153
+ */
154
+ waitFor(callback: () => Promise<void> | void): Promise<void>;
155
+ /**
156
+ * Close a channel (decrement active channel count)
157
+ */
158
+ closeChannel(): void;
159
+ /**
160
+ * Close all streams and connections
161
+ */
162
+ close(): Promise<void>;
163
+ /**
164
+ * Force close the stream immediately
165
+ */
166
+ forceClose(): void;
167
+ }
168
+
169
+ /** Decrement helper to stop recursion at depth 0 */
170
+ type Dec<N extends number> = N extends 10 ? 9 : N extends 9 ? 8 : N extends 8 ? 7 : N extends 7 ? 6 : N extends 6 ? 5 : N extends 5 ? 4 : N extends 4 ? 3 : N extends 3 ? 2 : N extends 2 ? 1 : N extends 1 ? 0 : 0;
171
+ /**
172
+ * Allowed Zod node for tool arguments.
173
+ * Tweak this union as your single source of truth for what’s allowed.
174
+ * Increase the default depth if you need crazier nesting.
175
+ */
176
+ type ToolArgsNode<D extends number = 7> = ZodString | ZodNumber | ZodBoolean | ZodNull | ZodLiteral<string | number | boolean | null> | ZodEnum<Record<string, string>> | (D extends 0 ? never : ZodOptional<ToolArgsNode<Dec<D>>>) | (D extends 0 ? never : ZodNullable<ToolArgsNode<Dec<D>>>) | (D extends 0 ? never : ZodDefault<ToolArgsNode<Dec<D>>>) | (D extends 0 ? never : ZodArray<ToolArgsNode<Dec<D>>>) | (D extends 0 ? never : ZodObject<Record<string, ToolArgsNode<Dec<D>>>>) | (D extends 0 ? never : ZodRecord<ZodString, ToolArgsNode<Dec<D>>>) | (D extends 0 ? never : ZodUnion<[
177
+ ToolArgsNode<Dec<D>>,
178
+ ToolArgsNode<Dec<D>>,
179
+ ...ToolArgsNode<Dec<D>>[]
180
+ ]>);
181
+ /**
182
+ * Raw shape for an object whose values are ToolArgsNode.
183
+ * This is what users write inside z.object({ ... }).
184
+ */
185
+ type ToolArgsRawShape<D extends number = 7> = Record<string, ToolArgsNode<D>>;
186
+ /** The top-level schema must be an object for OpenAI tools. */
187
+ type ToolArgs<D extends number = 7> = z.ZodObject<ToolArgsRawShape<D>>;
188
+ type StructuredToolReturn = ToolArgs;
189
+ /**
190
+ * Defines a tool function. Tools accept the current flow state as well as the arguments being passed to them.
191
+ */
192
+ type Tool<Args extends ToolArgs | null = null> = Args extends ToolArgs ? (flow: FlowState, args: z.infer<Args>) => Promise<CallToolResult> : (flow: FlowState) => Promise<CallToolResult>;
193
+ /**
194
+ * @param toolDescription - Description of what the tool does.
195
+ * @param args - The arguments for the tool.
196
+ * @param tool - The tool function.
197
+ * @returns A tuple containing the description, arguments and the tool function.
198
+ */
199
+ declare function defineTool<Args extends ToolArgs>(toolDescription: string, args: Args, tool: Tool<Args>): [string, Args, Tool<Args>, null];
200
+ declare function defineTool(toolDescription: string, tool: Tool<null>): [string, null, Tool<null>, null];
201
+ declare function defineTool<Args extends ToolArgs, RetValue extends StructuredToolReturn>(toolDescription: string, args: Args, tool: Tool<Args>, returnSchema: RetValue): [string, Args, Tool<Args>, RetValue];
202
+
203
+ /**
204
+ * Hook signatures for all available hooks
205
+ */
206
+ interface HookSignatures {
207
+ /**
208
+ * Called before messages are filtered and sent to the LLM
209
+ * Receives SQL row data with all columns before transformation
210
+ * Return value is transformed into chat completion format
211
+ */
212
+ filter_messages: (state: FlowState, rows: Message[]) => Promise<Message[]>;
213
+ /**
214
+ * Called after message history is loaded and before sending to LLM
215
+ * Receives messages in chat completion format (already transformed)
216
+ */
217
+ prefilter_llm_history: (state: FlowState, messages: Array<{
218
+ role: string;
219
+ content: string | null;
220
+ tool_calls?: any;
221
+ tool_call_id?: string;
222
+ name?: string;
223
+ }>) => Promise<Array<{
224
+ role: string;
225
+ content: string | null;
226
+ tool_calls?: any;
227
+ tool_call_id?: string;
228
+ name?: string;
229
+ }>>;
230
+ /**
231
+ * Called before a message is created in the database
232
+ */
233
+ before_create_message: (state: FlowState, message: Record<string, any>) => Promise<Record<string, any>>;
234
+ /**
235
+ * Called after a message is created in the database
236
+ */
237
+ after_create_message: (state: FlowState, message: Record<string, any>) => Promise<void>;
238
+ /**
239
+ * Called before a message is updated in the database
240
+ */
241
+ before_update_message: (state: FlowState, messageId: string, updates: Record<string, any>) => Promise<Record<string, any>>;
242
+ /**
243
+ * Called after a message is updated in the database
244
+ */
245
+ after_update_message: (state: FlowState, message: Message) => Promise<void>;
246
+ /**
247
+ * Called before a tool result is stored in the database
248
+ */
249
+ before_store_tool_result: (state: FlowState, toolCall: Record<string, any>, toolResult: Record<string, any>) => Promise<Record<string, any>>;
250
+ /**
251
+ * Called after a successful tool call
252
+ */
253
+ after_tool_call_success: (state: FlowState, toolCall: ToolCall, toolResult: ToolResult) => Promise<ToolResult | null>;
254
+ /**
255
+ * Called after a failed tool call
256
+ */
257
+ after_tool_call_failure: (state: FlowState, toolCall: ToolCall, toolResult: ToolResult) => Promise<ToolResult | null>;
258
+ }
259
+ /**
260
+ * Define a hook with strict typing based on hook name
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * export default defineHook('filter_messages', async (state, rows) => {
265
+ * // Only include messages from last 10 turns
266
+ * return rows.slice(-10);
267
+ * });
268
+ * ```
269
+ */
270
+ declare function defineHook<K extends keyof HookSignatures>(hookName: K, implementation: HookSignatures[K]): HookSignatures[K];
271
+
272
+ /**
273
+ * Agent configuration from D1 agents table
274
+ */
275
+ interface Agent {
276
+ id: string;
277
+ title: string;
278
+ type: "dual_ai" | "ai_human";
279
+ created_at: number;
280
+ max_session_turns: number | null;
281
+ side_a_label: string | null;
282
+ side_a_agent_prompt: string | null;
283
+ side_a_stop_on_response: boolean;
284
+ side_a_stop_tool: string | null;
285
+ side_a_stop_tool_response_property: string | null;
286
+ side_a_max_turns: number | null;
287
+ side_a_end_conversation_tool: string | null;
288
+ side_b_label: string | null;
289
+ side_b_agent_prompt: string | null;
290
+ side_b_stop_on_response: boolean;
291
+ side_b_stop_tool: string | null;
292
+ side_b_stop_tool_response_property: string | null;
293
+ side_b_max_turns: number | null;
294
+ side_b_end_conversation_tool: string | null;
295
+ }
296
+ /**
297
+ * Message in OpenAI chat completion format
298
+ */
299
+ interface Message {
300
+ id: string;
301
+ role: "system" | "user" | "assistant" | "tool";
302
+ content: string | null;
303
+ name?: string | null;
304
+ tool_calls?: string | null;
305
+ tool_call_id?: string | null;
306
+ log_id?: string | null;
307
+ created_at: number;
308
+ request_sent_at?: number | null;
309
+ response_completed_at?: number | null;
310
+ status?: "pending" | "completed" | "failed";
311
+ silent?: boolean;
312
+ tool_status?: "success" | "error" | null;
313
+ reasoning_content?: string | null;
314
+ reasoning_details?: string | null;
315
+ parent_id?: string | null;
316
+ depth?: number;
317
+ }
318
+ /**
319
+ * Tool call from OpenAI format
320
+ */
321
+ interface ToolCall {
322
+ id: string;
323
+ type: "function";
324
+ function: {
325
+ name: string;
326
+ arguments: string;
327
+ };
328
+ forceAllow?: boolean;
329
+ }
330
+ /**
331
+ * Thread metadata from DurableAgentBuilder
332
+ * Note: agent_id is now the agent name (not UUID) since agents are in TypeScript
333
+ */
334
+ interface ThreadMetadata {
335
+ id: string;
336
+ agent_id: string;
337
+ user_id: string | null;
338
+ created_at: number;
339
+ }
340
+ /**
341
+ * Hook registry type - transforms HookSignatures into lazy-loaded optional hooks
342
+ */
343
+ type HookRegistry = {
344
+ [K in keyof HookSignatures]?: () => Promise<HookSignatures[K]>;
345
+ };
346
+ /**
347
+ * Thread instance (forward reference to avoid circular dependency)
348
+ */
349
+ interface ThreadInstance {
350
+ ctx: DurableObjectState;
351
+ env: ThreadEnv;
352
+ getMessages(limit?: number, offset?: number, order?: "asc" | "desc", includeSilent?: boolean, maxDepth?: number): Promise<{
353
+ messages: Message[];
354
+ total: number;
355
+ hasMore: boolean;
356
+ }>;
357
+ getLogs(limit?: number, offset?: number, order?: "asc" | "desc"): Promise<LogData[]>;
358
+ getThreadMeta(threadId: string): Promise<ThreadMetadata | null>;
359
+ shouldStop(): Promise<boolean>;
360
+ tools(): Record<string, () => Promise<ReturnType<typeof defineTool>>>;
361
+ hooks(): HookRegistry;
362
+ }
363
+ /**
364
+ * Tool call for internal flow management
365
+ */
366
+ type FlowToolCall = {
367
+ tool: string;
368
+ args: Record<string, unknown>;
369
+ };
370
+ /**
371
+ * Prompt call for internal flow management
372
+ */
373
+ type FlowPromptCall = {
374
+ prompt: string;
375
+ args: Record<string, unknown>;
376
+ };
377
+ /**
378
+ * Flow call (tool or prompt)
379
+ */
380
+ type FlowCall = FlowToolCall | FlowPromptCall;
381
+ /**
382
+ * Flow call with retry tracking
383
+ */
384
+ type FlowCallWithRetries = FlowCall & {
385
+ retries: number;
386
+ reasons: string[];
387
+ };
388
+ /**
389
+ * Tool configuration for a prompt - defines options for when a tool is used
390
+ */
391
+ interface ToolConfig$1 {
392
+ name: string;
393
+ initUserMessageProperty?: string;
394
+ includeTextResponse?: boolean;
395
+ includeToolCalls?: boolean;
396
+ includeErrors?: boolean;
397
+ }
398
+ /**
399
+ * Prompt configuration - now loaded from TypeScript virtual modules
400
+ */
401
+ interface PromptData {
402
+ id: string;
403
+ name: string;
404
+ prompt: string | any[];
405
+ system_prompt?: string;
406
+ model: string;
407
+ model_id?: string;
408
+ tool_description: string;
409
+ required_schema: string;
410
+ include_chat: boolean;
411
+ include_past_tools: boolean;
412
+ before_tool: string | null;
413
+ after_tool: string | null;
414
+ prompts: string;
415
+ created_at: number;
416
+ /** @deprecated All prompts are now automatically exposed as tools */
417
+ expose_as_tool?: boolean;
418
+ parallel_tool_calls: boolean;
419
+ tool_choice: "auto" | "none" | "required" | "function";
420
+ reasoning_effort: "low" | "medium" | "high" | null;
421
+ reasoning_max_tokens: number | null;
422
+ reasoning_exclude: boolean;
423
+ include_reasoning: boolean;
424
+ _tools?: (string | ToolConfig$1)[];
425
+ _handoffAgents?: string[];
426
+ _requiredSchema?: any;
427
+ }
428
+ /**
429
+ * Central state object that flows through execution
430
+ */
431
+ interface FlowState {
432
+ threadId: string;
433
+ flowId: string;
434
+ thread: {
435
+ instance: ThreadInstance;
436
+ metadata: ThreadMetadata;
437
+ };
438
+ agentConfig: Agent;
439
+ currentSide: "a" | "b";
440
+ prompts: {
441
+ sideA: PromptData;
442
+ sideB: PromptData | null;
443
+ };
444
+ prompt: PromptData;
445
+ turnCount: number;
446
+ sideATurnCount: number;
447
+ sideBTurnCount: number;
448
+ stopped: boolean;
449
+ stoppedBy?: "a" | "b";
450
+ forcedNextSide?: "side_a" | "side_b";
451
+ pendingForceTurn?: "side_a" | "side_b";
452
+ abortController?: AbortController;
453
+ messageHistory: Message[];
454
+ /**
455
+ * Appends these messages
456
+ */
457
+ extraMessages: Message[];
458
+ sequence: {
459
+ queue: ToolCall[];
460
+ isHandling: boolean;
461
+ };
462
+ active: FlowCallWithRetries;
463
+ queue: FlowCall[];
464
+ pendingHandoff?: {
465
+ agentId: string;
466
+ };
467
+ stream: StreamManager;
468
+ context: Record<string, unknown>;
469
+ retryCount: number;
470
+ retryReason?: string;
471
+ storage: DurableObjectStorage;
472
+ env: ThreadEnv;
473
+ emitLog?: (log: unknown) => void;
474
+ emitMessage?: (message: unknown) => void;
475
+ emitMessageChunk?: (messageId: string, chunk: string, depth?: number) => void;
476
+ rootState: FlowState;
477
+ rootMessageId?: string | null;
478
+ parentLogId?: string | null;
479
+ currentLogId?: string | null;
480
+ parentMessageId?: string;
481
+ depth: number;
482
+ pendingMessageId?: string;
483
+ allowedTools?: ToolDefinition[];
484
+ }
485
+ /**
486
+ * Request context for LLM calls
487
+ */
488
+ interface RequestContext {
489
+ messages: Array<{
490
+ role: "system" | "user" | "assistant" | "tool";
491
+ content?: string;
492
+ tool_calls?: ToolCall[];
493
+ tool_call_id?: string;
494
+ name?: string;
495
+ }>;
496
+ model: string;
497
+ tools?: ToolDefinition[];
498
+ stream?: boolean;
499
+ promptName?: string;
500
+ systemPrompt?: string;
501
+ parentLogId?: string | null;
502
+ parallel_tool_calls?: boolean;
503
+ tool_choice?: "auto" | "none" | "required" | {
504
+ type: "function";
505
+ function: {
506
+ name: string;
507
+ };
508
+ };
509
+ reasoning?: {
510
+ effort?: "low" | "medium" | "high";
511
+ max_tokens?: number;
512
+ exclude?: boolean;
513
+ };
514
+ }
515
+ /**
516
+ * Tool definition for LLM requests
517
+ */
518
+ interface ToolDefinition {
519
+ type: "function";
520
+ function: {
521
+ name: string;
522
+ description: string;
523
+ parameters?: Record<string, any>;
524
+ };
525
+ }
526
+ /**
527
+ * LLM response
528
+ */
529
+ interface LLMResponse {
530
+ id: string;
531
+ model: string;
532
+ content: string | null;
533
+ reasoning_content?: string | null;
534
+ reasoning_details?: any[];
535
+ tool_calls?: ToolCall[];
536
+ finish_reason: string;
537
+ usage: {
538
+ prompt_tokens: number;
539
+ completion_tokens: number;
540
+ total_tokens: number;
541
+ prompt_tokens_details?: {
542
+ cached_tokens?: number;
543
+ };
544
+ completion_tokens_details?: {
545
+ reasoning_tokens?: number;
546
+ };
547
+ cost?: number;
548
+ provider?: string;
549
+ };
550
+ }
551
+ /**
552
+ * Tool result
553
+ */
554
+ interface ToolResult {
555
+ status: "success" | "error";
556
+ /**
557
+ * Flattened text representation of the tool output.
558
+ *
559
+ * For tools that return structured MCP-style content (an array of
560
+ * content parts), this will be derived by concatenating all text
561
+ * parts. For legacy tools that returned a plain string `result`,
562
+ * that value is used directly.
563
+ */
564
+ result?: string;
565
+ error?: string;
566
+ stack?: string;
567
+ }
568
+ /**
569
+ * Flow execution result
570
+ */
571
+ interface FlowResult {
572
+ messages: Message[];
573
+ stopped: boolean;
574
+ stoppedBy?: "a" | "b";
575
+ turnCount: number;
576
+ stream: ReadableStream<Uint8Array>;
577
+ }
578
+ /**
579
+ * Telemetry event types
580
+ */
581
+ type TelemetryEvent = {
582
+ type: "turn_started";
583
+ turn: number;
584
+ side: "a" | "b";
585
+ timestamp: number;
586
+ } | {
587
+ type: "turn_completed";
588
+ turn: number;
589
+ stopped: boolean;
590
+ timestamp: number;
591
+ } | {
592
+ type: "llm_request";
593
+ model: string;
594
+ attempt: number;
595
+ timestamp: number;
596
+ } | {
597
+ type: "llm_response";
598
+ tokens: number;
599
+ latency: number;
600
+ timestamp: number;
601
+ } | {
602
+ type: "validation_failed";
603
+ error: string;
604
+ timestamp: number;
605
+ } | {
606
+ type: "fallback_triggered";
607
+ from: string;
608
+ to: string;
609
+ timestamp: number;
610
+ } | {
611
+ type: "tool_started";
612
+ tool: string;
613
+ timestamp: number;
614
+ } | {
615
+ type: "tool_completed";
616
+ tool: string;
617
+ status: string;
618
+ timestamp: number;
619
+ } | {
620
+ type: "stopped";
621
+ reason: string;
622
+ side: "a" | "b";
623
+ timestamp: number;
624
+ } | {
625
+ type: "stopped_by_user";
626
+ timestamp: number;
627
+ };
628
+ /**
629
+ * Log data for telemetry table
630
+ */
631
+ interface LogData {
632
+ id: string;
633
+ message_id: string;
634
+ provider: string;
635
+ model: string;
636
+ model_name?: string;
637
+ endpoint?: string;
638
+ request_body?: string;
639
+ request_headers?: string;
640
+ response_body?: string;
641
+ response_headers?: string;
642
+ status_code?: number;
643
+ reasoning_content?: string | null;
644
+ input_tokens?: number;
645
+ cached_tokens?: number;
646
+ output_tokens?: number;
647
+ reasoning_tokens?: number;
648
+ total_tokens?: number;
649
+ latency_ms?: number;
650
+ time_to_first_token_ms?: number;
651
+ finish_reason?: string;
652
+ error?: string;
653
+ error_type?: string;
654
+ cost_input?: number;
655
+ cost_output?: number;
656
+ cost_total?: number;
657
+ message_history_length?: number;
658
+ tools_available?: number;
659
+ prompt_name?: string;
660
+ tools_called?: string;
661
+ parent_log_id?: string | null;
662
+ tools_schema?: string | null;
663
+ message_history?: string | null;
664
+ system_prompt?: string | null;
665
+ is_complete?: boolean;
666
+ errors?: string | null;
667
+ retry_of_log_id?: string | null;
668
+ created_at: number;
669
+ }
670
+
671
+ /**
672
+ * Minimum required environment bindings for thread endpoints.
673
+ * User's Env interface should extend this.
674
+ */
675
+ interface ThreadEnv {
676
+ AGENT_BUILDER_THREAD: DurableObjectNamespace;
677
+ AGENT_BUILDER: DurableObjectNamespace;
678
+ }
679
+ interface ControllerContext<Env = any> {
680
+ req: Request;
681
+ params: Record<string, string>;
682
+ env: Env;
683
+ url: URL;
684
+ }
685
+ type Controller<Env = any> = (context: ControllerContext<Env>) => string | Promise<string> | Response | Promise<Response> | ReadableStream | Promise<ReadableStream> | null | Promise<null> | void | Promise<void> | Promise<object> | object;
686
+ interface ThreadEndpointContext {
687
+ req: Request;
688
+ thread: {
689
+ instance: ThreadInstance;
690
+ metadata: ThreadMetadata;
691
+ };
692
+ }
693
+ declare function defineController<Env = any>(controller: Controller<Env>): Controller<Env>;
694
+ /**
695
+ * Define a thread-specific endpoint that has access to the thread's DurableObject instance and metadata.
696
+ * This wraps defineController and automatically looks up the thread by ID from the URL params.
697
+ *
698
+ * @param handler - Function that receives the request and thread context
699
+ * @returns A Controller that can be used with the router
700
+ *
701
+ * @example
702
+ * // agentbuilder/api/status.ts
703
+ * export default defineThreadEndpoint(async (req, { thread }) => {
704
+ * const messages = await thread.instance.getMessages();
705
+ * return Response.json({ status: "ok", messageCount: messages.length });
706
+ * });
707
+ */
708
+ declare function defineThreadEndpoint<Env extends ThreadEnv = ThreadEnv>(handler: (req: Request, context: ThreadEndpointContext["thread"]) => Response | Promise<Response>): Controller<Env>;
709
+
710
+ /**
711
+ * Authentication middleware for protecting API routes
712
+ *
713
+ * Supports multiple authentication types:
714
+ * - Super admin token (signed with ENCRYPTION_KEY)
715
+ * - User session token (validated against DurableAgentBuilder)
716
+ * - API key (validated against DurableAgentBuilder)
717
+ */
718
+ interface AuthUser {
719
+ id: string;
720
+ username: string;
721
+ role: string;
722
+ }
723
+ interface AuthContext {
724
+ user: AuthUser;
725
+ authType: 'super_admin' | 'session' | 'api_key';
726
+ }
727
+ /**
728
+ * Authenticate a request using various token types
729
+ */
730
+ declare function authenticate(request: Request, env: any): Promise<AuthContext | null>;
731
+ /**
732
+ * Middleware to require authentication
733
+ * Returns 401 if not authenticated
734
+ */
735
+ declare function requireAuth(request: Request, env: any): Promise<AuthContext | Response>;
736
+ /**
737
+ * Middleware to require admin role
738
+ * Returns 401 if not authenticated, 403 if not admin
739
+ */
740
+ declare function requireAdmin(request: Request, env: any): Promise<AuthContext | Response>;
741
+
742
+ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableObject<Env> {
743
+ private migratedToVersion;
744
+ private logSockets;
745
+ private messageSockets;
746
+ private alarmQueue;
747
+ private currentAbortController;
748
+ private isExecuting;
749
+ constructor(ctx: DurableObjectState, env: Env);
750
+ /**
751
+ * Returns the tools registry for this thread.
752
+ * This method is implemented when you import DurableThread from 'virtual:@standardagents/builder'.
753
+ *
754
+ * @throws Error if not implemented in a subclass
755
+ * @returns Record of tool name to tool loader function
756
+ *
757
+ * @example
758
+ * ```typescript
759
+ * import { DurableThread } from 'virtual:@standardagents/builder'
760
+ *
761
+ * export class Thread extends DurableThread {}
762
+ * ```
763
+ */
764
+ tools(): Record<string, () => Promise<any>>;
765
+ /**
766
+ * Returns the hooks registry for this thread.
767
+ * This method is implemented when you import DurableThread from 'virtual:@standardagents/builder'.
768
+ *
769
+ * @throws Error if not implemented in a subclass
770
+ * @returns Record of hook name to hook loader function
771
+ *
772
+ * @example
773
+ * ```typescript
774
+ * import { DurableThread } from 'virtual:@standardagents/builder'
775
+ *
776
+ * export class Thread extends DurableThread {}
777
+ * ```
778
+ */
779
+ hooks(): Record<string, () => Promise<any>>;
780
+ /**
781
+ * Returns the models registry for lazy-loading model definitions.
782
+ * This method is implemented when you import DurableThread from 'virtual:@standardagents/builder'.
783
+ *
784
+ * @throws Error if not implemented in a subclass
785
+ * @returns Record of model name to model loader function
786
+ */
787
+ models(): Record<string, () => Promise<any>>;
788
+ /**
789
+ * Returns the prompts registry for lazy-loading prompt definitions.
790
+ * This method is implemented when you import DurableThread from 'virtual:@standardagents/builder'.
791
+ *
792
+ * @throws Error if not implemented in a subclass
793
+ * @returns Record of prompt name to prompt loader function
794
+ */
795
+ prompts(): Record<string, () => Promise<any>>;
796
+ /**
797
+ * Returns the agents registry for lazy-loading agent definitions.
798
+ * This method is implemented when you import DurableThread from 'virtual:@standardagents/builder'.
799
+ *
800
+ * @throws Error if not implemented in a subclass
801
+ * @returns Record of agent name to agent loader function
802
+ */
803
+ agents(): Record<string, () => Promise<any>>;
804
+ /**
805
+ * Load a model definition by name.
806
+ */
807
+ loadModel(name: string): Promise<any>;
808
+ /**
809
+ * List available model names.
810
+ */
811
+ getModelNames(): string[];
812
+ /**
813
+ * Load a prompt definition by name.
814
+ */
815
+ loadPrompt(name: string): Promise<any>;
816
+ /**
817
+ * List available prompt names.
818
+ */
819
+ getPromptNames(): string[];
820
+ /**
821
+ * Load an agent definition by name.
822
+ */
823
+ loadAgent(name: string): Promise<any>;
824
+ /**
825
+ * List available agent names.
826
+ */
827
+ getAgentNames(): string[];
828
+ /**
829
+ * Ensures the database schema is up to date.
830
+ * This method is called on the first request to the Durable Object.
831
+ * It checks the schema version and runs any pending migrations.
832
+ *
833
+ * Performance:
834
+ * - Already migrated to latest: ~0.1ms (single SELECT + integer comparison)
835
+ * - Needs migration: Runs once per Durable Object lifetime per schema version
836
+ * - Detects new migrations after code deployment
837
+ */
838
+ private ensureMigrated;
839
+ /**
840
+ * Gets the current schema version from the database.
841
+ * Returns 0 if the metadata table doesn't exist (brand new database).
842
+ */
843
+ private getCurrentVersion;
844
+ /**
845
+ * Runs all pending migrations sequentially.
846
+ * Each migration is run in order, starting from the current version + 1.
847
+ */
848
+ private runMigrations;
849
+ /**
850
+ * Legacy fetch handler for WebSocket upgrades only
851
+ */
852
+ fetch(request: Request): Promise<Response>;
853
+ /**
854
+ * Execute thread with initial messages (RPC method)
855
+ * Enqueues the execution to be processed by the alarm handler
856
+ */
857
+ execute(threadId: string, agentId: string, initial_messages?: any[], data?: any): Promise<Response>;
858
+ /**
859
+ * Send a new message to the thread (RPC method)
860
+ * Enqueues the message processing to be handled by the alarm handler
861
+ */
862
+ sendMessage(threadId: string, content: string, role?: string): Promise<Response>;
863
+ /**
864
+ * Check if execution should be stopped (called by FlowEngine)
865
+ * Reads from SQLite for persistence across hibernation
866
+ */
867
+ shouldStop(): Promise<boolean>;
868
+ /**
869
+ * Stop the currently executing thread (RPC method)
870
+ * Simple "off" switch - stops turns, only cleared by user messages
871
+ */
872
+ stop(): Promise<Response>;
873
+ /**
874
+ * Get message history (RPC method)
875
+ *
876
+ * By default, returns the newest messages (when truncating), but in chronological
877
+ * order (oldest first in the array). This is ideal for chat UIs where messages
878
+ * should be appended and scrolled to the bottom.
879
+ *
880
+ * The offset parameter allows "scrolling up" to view older messages.
881
+ *
882
+ * Example:
883
+ * - getMessages(10, 0) -> newest 10 messages, oldest first in array
884
+ * - getMessages(10, 10) -> next 10 older messages, oldest first in array
885
+ *
886
+ * @param limit Number of messages to return (default: 100)
887
+ * @param offset Number of newest messages to skip (default: 0)
888
+ * @param order Internal query order - "DESC" (default) fetches newest first then reverses
889
+ * @param includeSilent Include silent messages (UI-only messages)
890
+ * @param maxDepth Maximum depth to include (default: 0 for top-level only)
891
+ */
892
+ getMessages(limit?: number, offset?: number, order?: "ASC" | "DESC", includeSilent?: boolean, maxDepth?: number): Promise<{
893
+ messages: {
894
+ id: string;
895
+ role: string;
896
+ content: string | null;
897
+ name: string | null;
898
+ tool_calls: string | null;
899
+ tool_call_id: string | null;
900
+ tool_status: "success" | "error" | null;
901
+ log_id: string | null;
902
+ created_at: number;
903
+ silent: boolean;
904
+ parent_id: string | null;
905
+ depth: number;
906
+ status: "pending" | "completed" | "failed" | null;
907
+ reasoning_content: string | null;
908
+ reasoning_details: string | null;
909
+ }[];
910
+ total: number;
911
+ hasMore: boolean;
912
+ }>;
913
+ /**
914
+ * Delete a message (RPC method)
915
+ */
916
+ deleteMessage(messageId: string): Promise<{
917
+ success: boolean;
918
+ error?: undefined;
919
+ } | {
920
+ success: boolean;
921
+ error: any;
922
+ }>;
923
+ /**
924
+ * Seed messages directly into the database (RPC method - for testing)
925
+ * This bypasses the normal message processing flow
926
+ */
927
+ seedMessages(args: {
928
+ messages: Array<{
929
+ id: string;
930
+ role: string;
931
+ content: string;
932
+ created_at: number;
933
+ }>;
934
+ }): Promise<{
935
+ success: boolean;
936
+ count: number;
937
+ error?: undefined;
938
+ } | {
939
+ success: boolean;
940
+ error: any;
941
+ count?: undefined;
942
+ }>;
943
+ /**
944
+ * Get logs (RPC method)
945
+ */
946
+ getLogs(limit?: number, offset?: number, order?: "ASC" | "DESC"): Promise<{
947
+ logs: {
948
+ id: string;
949
+ message_id: string;
950
+ provider: string;
951
+ model: string;
952
+ model_name: string | null;
953
+ prompt_name: string | null;
954
+ tools_called: string | null;
955
+ parent_log_id: string | null;
956
+ retry_of_log_id: string | null;
957
+ error: string | null;
958
+ cost_total: number | null;
959
+ is_complete: boolean;
960
+ created_at: number;
961
+ request_body: string | null;
962
+ }[];
963
+ total: number;
964
+ hasMore: boolean;
965
+ }>;
966
+ /**
967
+ * Get detailed information for a single log (RPC method)
968
+ * This includes all fields including large ones like request/response bodies
969
+ */
970
+ getLogDetails(logId: string): Promise<{
971
+ id: string;
972
+ message_id: string;
973
+ provider: string;
974
+ model: string;
975
+ model_name: string | null;
976
+ endpoint: string | null;
977
+ request_body: string | null;
978
+ request_headers: string | null;
979
+ response_body: string | null;
980
+ response_headers: string | null;
981
+ status_code: number | null;
982
+ reasoning_content: string | null;
983
+ input_tokens: number | null;
984
+ cached_tokens: number | null;
985
+ output_tokens: number | null;
986
+ reasoning_tokens: number | null;
987
+ total_tokens: number | null;
988
+ latency_ms: number | null;
989
+ time_to_first_token_ms: number | null;
990
+ finish_reason: string | null;
991
+ error: string | null;
992
+ error_type: string | null;
993
+ cost_input: number | null;
994
+ cost_output: number | null;
995
+ cost_total: number | null;
996
+ message_history_length: number | null;
997
+ tools_available: number | null;
998
+ prompt_name: string | null;
999
+ tools_called: string | null;
1000
+ parent_log_id: string | null;
1001
+ tools_schema: string | null;
1002
+ message_history: string | null;
1003
+ system_prompt: string | null;
1004
+ errors: string | null;
1005
+ retry_of_log_id: string | null;
1006
+ tool_results: string | null;
1007
+ is_complete: boolean;
1008
+ created_at: number;
1009
+ }>;
1010
+ /**
1011
+ * Get thread metadata (RPC method)
1012
+ */
1013
+ getThreadMeta(threadId: string): Promise<Response | {
1014
+ thread: {
1015
+ id: any;
1016
+ agent_id: any;
1017
+ user_id: any;
1018
+ tags: any;
1019
+ created_at: any;
1020
+ };
1021
+ agent: {
1022
+ id: any;
1023
+ title: any;
1024
+ type: any;
1025
+ side_a_label: any;
1026
+ side_b_label: any;
1027
+ } | null;
1028
+ stats: {
1029
+ message_count: number;
1030
+ log_count: number;
1031
+ };
1032
+ }>;
1033
+ /**
1034
+ * Update thread metadata (RPC method)
1035
+ * Calls the DurableAgentBuilder to update the thread registry
1036
+ */
1037
+ updateThreadMeta(threadId: string, params: {
1038
+ agent_name?: string;
1039
+ user_id?: string | null;
1040
+ tags?: string[] | null;
1041
+ }): Promise<{
1042
+ success: boolean;
1043
+ thread: {
1044
+ id: any;
1045
+ agent_id: any;
1046
+ user_id: any;
1047
+ tags: any;
1048
+ created_at: any;
1049
+ };
1050
+ error?: undefined;
1051
+ } | {
1052
+ success: boolean;
1053
+ error: any;
1054
+ thread?: undefined;
1055
+ }>;
1056
+ /**
1057
+ * Delete thread data completely (RPC method)
1058
+ * This will permanently delete the Durable Object instance
1059
+ */
1060
+ deleteThread(): Promise<{
1061
+ success: boolean;
1062
+ message: string;
1063
+ }>;
1064
+ /**
1065
+ * Handle WebSocket upgrade for real-time log streaming
1066
+ * Uses Hibernation API to reduce costs during inactivity
1067
+ */
1068
+ private handleLogsWebSocketUpgrade;
1069
+ /**
1070
+ * Handle WebSocket upgrade for real-time message streaming
1071
+ * Uses Hibernation API to reduce costs during inactivity
1072
+ */
1073
+ private handleMessagesWebSocketUpgrade;
1074
+ /**
1075
+ * Broadcast a log record to all connected WebSocket clients
1076
+ */
1077
+ private broadcastLog;
1078
+ /**
1079
+ * Broadcast a message record to all connected message WebSocket clients
1080
+ * Filters silent messages based on each socket's includeSilent preference
1081
+ */
1082
+ private broadcastMessage;
1083
+ /**
1084
+ * Broadcast a content chunk for real-time streaming
1085
+ * Does NOT update database - only broadcasts to connected clients
1086
+ */
1087
+ private broadcastMessageChunk;
1088
+ /**
1089
+ * WebSocket Hibernation API handler for incoming messages
1090
+ * Called when a message is received on a hibernated WebSocket
1091
+ */
1092
+ webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void>;
1093
+ /**
1094
+ * WebSocket Hibernation API handler for connection close
1095
+ * Called when a WebSocket connection is closed
1096
+ */
1097
+ webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void>;
1098
+ /**
1099
+ * WebSocket Hibernation API handler for errors
1100
+ * Called when a WebSocket encounters an error
1101
+ */
1102
+ webSocketError(ws: WebSocket, error: unknown): Promise<void>;
1103
+ /**
1104
+ * Alarm handler - called by Cloudflare when a scheduled alarm fires
1105
+ * Processes the next item in the alarm queue
1106
+ *
1107
+ * Important: This method must NEVER throw an exception, as that would break
1108
+ * the alarm chain. All errors are caught and logged.
1109
+ */
1110
+ alarm(): Promise<void>;
1111
+ /**
1112
+ * Internal method: Execute a flow (called by alarm queue)
1113
+ * This is the actual execution logic, separate from the public execute() RPC method
1114
+ */
1115
+ private executeFlow;
1116
+ /**
1117
+ * Internal method: Process a message (called by alarm queue)
1118
+ * This is the actual message processing logic, separate from the public sendMessage() RPC method
1119
+ */
1120
+ private processMessage;
1121
+ /**
1122
+ * TEST METHOD: Queue a test operation
1123
+ * Used for testing alarm queue ordering and timing
1124
+ */
1125
+ queueTestOperation(id: string, label: string, expectedOrder: number, delayMs: number): Promise<Response>;
1126
+ /**
1127
+ * TEST METHOD: Get queue state
1128
+ */
1129
+ getQueueState(): Promise<Response>;
1130
+ /**
1131
+ * TEST METHOD: Get test execution logs
1132
+ */
1133
+ getTestLogs(): Promise<Response>;
1134
+ /**
1135
+ * TEST METHOD: Clear test logs
1136
+ */
1137
+ clearTestLogs(): Promise<Response>;
1138
+ /**
1139
+ * TEST METHOD: Insert a malformed message with orphaned tool calls
1140
+ * This allows testing the tool call filtering logic
1141
+ */
1142
+ insertOrphanedToolCall(params: {
1143
+ content?: string;
1144
+ toolCallId: string;
1145
+ toolName: string;
1146
+ toolArgs: string;
1147
+ }): Promise<Response>;
1148
+ /**
1149
+ * TEST METHOD: Execute a test operation
1150
+ * Internal method called by alarm queue
1151
+ */
1152
+ private testOperation;
1153
+ }
1154
+
1155
+ /**
1156
+ * Environment type for DurableAgentBuilder.
1157
+ * Users extend this with their own bindings.
1158
+ */
1159
+ interface AgentBuilderEnv {
1160
+ AGENT_BUILDER: DurableObjectNamespace<DurableAgentBuilder>;
1161
+ AGENT_BUILDER_THREAD: DurableObjectNamespace;
1162
+ GITHUB_TOKEN?: string;
1163
+ GITHUB_REPO?: string;
1164
+ GITHUB_BRANCH?: string;
1165
+ }
1166
+ /**
1167
+ * Thread metadata stored in the registry.
1168
+ */
1169
+ interface ThreadRegistryEntry {
1170
+ id: string;
1171
+ agent_name: string;
1172
+ user_id: string | null;
1173
+ tags: string[] | null;
1174
+ created_at: number;
1175
+ }
1176
+ /**
1177
+ * Parameters for updating a thread.
1178
+ */
1179
+ interface UpdateThreadParams {
1180
+ agent_name?: string;
1181
+ user_id?: string | null;
1182
+ tags?: string[] | null;
1183
+ }
1184
+ /**
1185
+ * User record.
1186
+ */
1187
+ interface User {
1188
+ id: string;
1189
+ username: string;
1190
+ password_hash: string;
1191
+ role: 'admin';
1192
+ created_at: number;
1193
+ updated_at: number;
1194
+ }
1195
+ /**
1196
+ * Provider credentials.
1197
+ */
1198
+ interface Provider {
1199
+ name: string;
1200
+ sdk: string;
1201
+ api_key: string;
1202
+ }
1203
+ declare class DurableAgentBuilder<Env extends AgentBuilderEnv = AgentBuilderEnv> extends DurableObject<Env> {
1204
+ private migratedToVersion;
1205
+ private eventSockets;
1206
+ constructor(ctx: DurableObjectState, env: Env);
1207
+ /**
1208
+ * Returns the tools registry for lazy-loading tool definitions.
1209
+ * Must be overridden in a subclass.
1210
+ */
1211
+ tools(): Record<string, () => Promise<any>>;
1212
+ /**
1213
+ * Returns the hooks registry for lazy-loading hook definitions.
1214
+ * Must be overridden in a subclass.
1215
+ */
1216
+ hooks(): Record<string, () => Promise<any>>;
1217
+ /**
1218
+ * Returns the models registry for lazy-loading model definitions.
1219
+ * Must be overridden in a subclass.
1220
+ */
1221
+ models(): Record<string, () => Promise<any>>;
1222
+ /**
1223
+ * Returns the prompts registry for lazy-loading prompt definitions.
1224
+ * Must be overridden in a subclass.
1225
+ */
1226
+ prompts(): Record<string, () => Promise<any>>;
1227
+ /**
1228
+ * Returns the agents registry for lazy-loading agent definitions.
1229
+ * Must be overridden in a subclass.
1230
+ */
1231
+ agents(): Record<string, () => Promise<any>>;
1232
+ private ensureMigrated;
1233
+ private getCurrentVersion;
1234
+ private runMigrations;
1235
+ /**
1236
+ * Create a new thread and add it to the registry.
1237
+ */
1238
+ createThread(params: {
1239
+ agent_name: string;
1240
+ user_id?: string;
1241
+ tags?: string[];
1242
+ }): Promise<ThreadRegistryEntry>;
1243
+ /**
1244
+ * Get a thread by ID.
1245
+ */
1246
+ getThread(id: string): Promise<ThreadRegistryEntry | null>;
1247
+ /**
1248
+ * List threads with optional filtering.
1249
+ */
1250
+ listThreads(params?: {
1251
+ agent_name?: string;
1252
+ user_id?: string;
1253
+ limit?: number;
1254
+ offset?: number;
1255
+ }): Promise<{
1256
+ threads: ThreadRegistryEntry[];
1257
+ total: number;
1258
+ }>;
1259
+ /**
1260
+ * Delete a thread from the registry.
1261
+ */
1262
+ deleteThread(id: string): Promise<boolean>;
1263
+ /**
1264
+ * Update a thread's agent_name (used during agent handoff).
1265
+ */
1266
+ updateThreadAgent(id: string, agent_name: string): Promise<boolean>;
1267
+ /**
1268
+ * Update a thread's metadata.
1269
+ */
1270
+ updateThread(id: string, params: UpdateThreadParams): Promise<ThreadRegistryEntry | null>;
1271
+ /**
1272
+ * Load a model definition by name.
1273
+ */
1274
+ loadModel(name: string): Promise<any>;
1275
+ /**
1276
+ * List available model names.
1277
+ */
1278
+ getModelNames(): string[];
1279
+ /**
1280
+ * Load a prompt definition by name.
1281
+ */
1282
+ loadPrompt(name: string): Promise<any>;
1283
+ /**
1284
+ * List available prompt names.
1285
+ */
1286
+ getPromptNames(): string[];
1287
+ /**
1288
+ * Load an agent definition by name.
1289
+ */
1290
+ loadAgent(name: string): Promise<any>;
1291
+ /**
1292
+ * List available agent names.
1293
+ */
1294
+ getAgentNames(): string[];
1295
+ /**
1296
+ * Get a provider's credentials.
1297
+ */
1298
+ getProvider(name: string): Promise<Provider | null>;
1299
+ /**
1300
+ * Set a provider's credentials.
1301
+ */
1302
+ setProvider(provider: Provider): Promise<void>;
1303
+ /**
1304
+ * List all providers.
1305
+ */
1306
+ listProviders(): Promise<Provider[]>;
1307
+ /**
1308
+ * Delete a provider.
1309
+ */
1310
+ deleteProvider(name: string): Promise<boolean>;
1311
+ /**
1312
+ * Get a user by username.
1313
+ */
1314
+ getUserByUsername(username: string): Promise<User | null>;
1315
+ /**
1316
+ * Get a user by ID.
1317
+ */
1318
+ getUserById(id: string): Promise<User | null>;
1319
+ /**
1320
+ * Create a new user.
1321
+ */
1322
+ createUser(params: {
1323
+ username: string;
1324
+ password_hash: string;
1325
+ role?: 'admin';
1326
+ }): Promise<User>;
1327
+ /**
1328
+ * Check if any users exist (for first-time setup).
1329
+ */
1330
+ hasUsers(): Promise<boolean>;
1331
+ /**
1332
+ * List all users (excludes password hash).
1333
+ */
1334
+ listUsers(): Promise<Array<{
1335
+ id: string;
1336
+ username: string;
1337
+ role: 'admin';
1338
+ created_at: number;
1339
+ updated_at: number;
1340
+ }>>;
1341
+ /**
1342
+ * Update a user.
1343
+ */
1344
+ updateUser(id: string, params: {
1345
+ username?: string;
1346
+ password_hash?: string;
1347
+ role?: 'admin';
1348
+ }): Promise<User | null>;
1349
+ /**
1350
+ * Delete a user.
1351
+ */
1352
+ deleteUser(id: string): Promise<boolean>;
1353
+ /**
1354
+ * Create a new session.
1355
+ */
1356
+ createSession(params: {
1357
+ user_id: string;
1358
+ token_hash: string;
1359
+ expires_at: number;
1360
+ }): Promise<string>;
1361
+ /**
1362
+ * Validate a session token.
1363
+ */
1364
+ validateSession(tokenHash: string): Promise<{
1365
+ user_id: string;
1366
+ expires_at: number;
1367
+ } | null>;
1368
+ /**
1369
+ * Delete expired sessions.
1370
+ */
1371
+ cleanupSessions(): Promise<number>;
1372
+ /**
1373
+ * Delete a session.
1374
+ */
1375
+ deleteSession(tokenHash: string): Promise<void>;
1376
+ /**
1377
+ * Create an API key.
1378
+ */
1379
+ createApiKey(params: {
1380
+ name: string;
1381
+ key_hash: string;
1382
+ key_prefix: string;
1383
+ last_five: string;
1384
+ user_id: string;
1385
+ }): Promise<string>;
1386
+ /**
1387
+ * Validate an API key.
1388
+ */
1389
+ validateApiKey(keyHash: string): Promise<{
1390
+ user_id: string;
1391
+ id: string;
1392
+ } | null>;
1393
+ /**
1394
+ * List API keys for a user.
1395
+ */
1396
+ listApiKeys(userId: string): Promise<Array<{
1397
+ id: string;
1398
+ name: string;
1399
+ key_prefix: string;
1400
+ last_five: string;
1401
+ created_at: number;
1402
+ last_used_at: number | null;
1403
+ }>>;
1404
+ /**
1405
+ * Delete an API key.
1406
+ */
1407
+ deleteApiKey(id: string, userId: string): Promise<boolean>;
1408
+ /**
1409
+ * Link an OAuth account to a user.
1410
+ */
1411
+ linkOAuthAccount(params: {
1412
+ user_id: string;
1413
+ provider: 'github' | 'google';
1414
+ provider_user_id: string;
1415
+ provider_username?: string;
1416
+ }): Promise<void>;
1417
+ /**
1418
+ * Find user by OAuth account.
1419
+ */
1420
+ findUserByOAuth(provider: 'github' | 'google', providerUserId: string): Promise<User | null>;
1421
+ /**
1422
+ * Acquire edit lock for GitHub commits.
1423
+ */
1424
+ acquireEditLock(params: {
1425
+ locked_by: string;
1426
+ lock_reason: string;
1427
+ }): Promise<boolean>;
1428
+ /**
1429
+ * Release edit lock.
1430
+ */
1431
+ releaseEditLock(lockedBy: string): Promise<boolean>;
1432
+ /**
1433
+ * Get current lock state.
1434
+ */
1435
+ getEditLockState(): Promise<{
1436
+ locked: boolean;
1437
+ locked_by: string | null;
1438
+ locked_at: number | null;
1439
+ lock_reason: string | null;
1440
+ pending_changes: string | null;
1441
+ }>;
1442
+ /**
1443
+ * Store pending changes for commit.
1444
+ */
1445
+ setPendingChanges(changes: string): Promise<void>;
1446
+ /**
1447
+ * Get the Durable Object stub for a thread.
1448
+ */
1449
+ getThreadStub(threadId: string): DurableObjectStub;
1450
+ /**
1451
+ * Handle fetch requests - used for WebSocket upgrades
1452
+ */
1453
+ fetch(request: Request): Promise<Response>;
1454
+ /**
1455
+ * Handle WebSocket upgrade for events channel
1456
+ * Uses Hibernation API to reduce costs during inactivity
1457
+ */
1458
+ private handleEventsWebSocketUpgrade;
1459
+ /**
1460
+ * Broadcast an event to all connected WebSocket clients
1461
+ */
1462
+ private broadcastEvent;
1463
+ /**
1464
+ * WebSocket Hibernation API handler for incoming messages
1465
+ * Called when a message is received on a hibernated WebSocket
1466
+ */
1467
+ webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void>;
1468
+ /**
1469
+ * WebSocket Hibernation API handler for connection close
1470
+ * Called when a WebSocket connection is closed
1471
+ */
1472
+ webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void>;
1473
+ /**
1474
+ * WebSocket Hibernation API handler for errors
1475
+ * Called when a WebSocket encounters an error
1476
+ */
1477
+ webSocketError(ws: WebSocket, error: unknown): Promise<void>;
1478
+ }
1479
+
1480
+ /**
1481
+ * Model definition module for AgentBuilder.
1482
+ *
1483
+ * Models define LLM configurations including provider, model ID, pricing,
1484
+ * and fallback chains. Models are referenced by name from prompts.
1485
+ *
1486
+ * @module
1487
+ */
1488
+ /**
1489
+ * Supported LLM provider types.
1490
+ * Each provider requires a corresponding API key environment variable:
1491
+ * - `openai` → `OPENAI_API_KEY`
1492
+ * - `openrouter` → `OPENROUTER_API_KEY`
1493
+ * - `anthropic` → `ANTHROPIC_API_KEY`
1494
+ * - `google` → `GOOGLE_API_KEY`
1495
+ */
1496
+ type ModelProvider = 'openai' | 'openrouter' | 'anthropic' | 'google';
1497
+ /**
1498
+ * Model definition configuration.
1499
+ *
1500
+ * @template N - The model name as a string literal type for type inference
1501
+ *
1502
+ * @example
1503
+ * ```typescript
1504
+ * import { defineModel } from '@standardagents/builder';
1505
+ *
1506
+ * export default defineModel({
1507
+ * name: 'gpt-4o',
1508
+ * provider: 'openai',
1509
+ * model: 'gpt-4o',
1510
+ * fallbacks: ['gpt-4-turbo', 'gpt-3.5-turbo'],
1511
+ * inputPrice: 2.5,
1512
+ * outputPrice: 10,
1513
+ * });
1514
+ * ```
1515
+ */
1516
+ interface ModelDefinition<N extends string = string> {
1517
+ /**
1518
+ * Unique name for this model definition.
1519
+ * Used as the identifier when referencing from prompts.
1520
+ * Should be descriptive and consistent (e.g., 'gpt-4o', 'claude-3-opus').
1521
+ */
1522
+ name: N;
1523
+ /**
1524
+ * The LLM provider to use for API calls.
1525
+ * The corresponding API key environment variable must be set.
1526
+ */
1527
+ provider: ModelProvider;
1528
+ /**
1529
+ * The actual model identifier sent to the provider API.
1530
+ *
1531
+ * For OpenAI: 'gpt-4o', 'gpt-4-turbo', 'gpt-3.5-turbo', etc.
1532
+ * For OpenRouter: 'openai/gpt-4o', 'anthropic/claude-3-opus', etc.
1533
+ * For Anthropic: 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', etc.
1534
+ * For Google: 'gemini-1.5-pro', 'gemini-1.5-flash', etc.
1535
+ */
1536
+ model: string;
1537
+ /**
1538
+ * Optional list of additional provider prefixes for OpenRouter.
1539
+ * Allows routing through specific providers when using OpenRouter.
1540
+ *
1541
+ * @example ['anthropic', 'google'] - prefer Anthropic, fallback to Google
1542
+ */
1543
+ includedProviders?: string[];
1544
+ /**
1545
+ * Fallback models to try if this model fails.
1546
+ * Referenced by model name (must be defined in agentbuilder/models/).
1547
+ * Tried in order after primary model exhausts retries.
1548
+ *
1549
+ * @example ['gpt-4', 'gpt-3.5-turbo']
1550
+ */
1551
+ fallbacks?: AgentBuilder.Models[];
1552
+ /**
1553
+ * Cost per 1 million input tokens in USD.
1554
+ * Used for cost tracking and reporting in logs.
1555
+ */
1556
+ inputPrice?: number;
1557
+ /**
1558
+ * Cost per 1 million output tokens in USD.
1559
+ * Used for cost tracking and reporting in logs.
1560
+ */
1561
+ outputPrice?: number;
1562
+ /**
1563
+ * Cost per 1 million cached input tokens in USD.
1564
+ * Some providers offer reduced pricing for cached/repeated prompts.
1565
+ */
1566
+ cachedPrice?: number;
1567
+ }
1568
+ /**
1569
+ * Defines an LLM model configuration.
1570
+ *
1571
+ * Models are the foundation of the agent system - they specify which
1572
+ * AI model to use and how to connect to it. Models can have fallbacks
1573
+ * for reliability and include pricing for cost tracking.
1574
+ *
1575
+ * @template N - The model name as a string literal type
1576
+ * @param options - Model configuration options
1577
+ * @returns The model definition for registration
1578
+ *
1579
+ * @example
1580
+ * ```typescript
1581
+ * // agentbuilder/models/gpt_4o.ts
1582
+ * import { defineModel } from '@standardagents/builder';
1583
+ *
1584
+ * export default defineModel({
1585
+ * name: 'gpt-4o',
1586
+ * provider: 'openai',
1587
+ * model: 'gpt-4o',
1588
+ * fallbacks: ['gpt-4-turbo'],
1589
+ * inputPrice: 2.5,
1590
+ * outputPrice: 10,
1591
+ * });
1592
+ * ```
1593
+ *
1594
+ * @example
1595
+ * ```typescript
1596
+ * // Using OpenRouter with provider preferences
1597
+ * export default defineModel({
1598
+ * name: 'claude-3-opus',
1599
+ * provider: 'openrouter',
1600
+ * model: 'anthropic/claude-3-opus',
1601
+ * includedProviders: ['anthropic'],
1602
+ * });
1603
+ * ```
1604
+ */
1605
+ declare function defineModel<N extends string>(options: ModelDefinition<N>): ModelDefinition<N>;
1606
+
1607
+ /**
1608
+ * Prompt definition module for AgentBuilder.
1609
+ *
1610
+ * Prompts define LLM interaction configurations including the system prompt,
1611
+ * model selection, available tools, and various behavioral options.
1612
+ *
1613
+ * @module
1614
+ */
1615
+
1616
+ /**
1617
+ * A text part of a prompt - static text content.
1618
+ *
1619
+ * @example
1620
+ * ```typescript
1621
+ * { type: 'text', content: 'You are a helpful assistant.\n\n' }
1622
+ * ```
1623
+ */
1624
+ interface PromptTextPart {
1625
+ type: 'text';
1626
+ /** The text content */
1627
+ content: string;
1628
+ }
1629
+ /**
1630
+ * A prompt inclusion part - includes another prompt's content.
1631
+ * Uses AgentBuilder.Prompts for type-safe autocomplete of prompt names.
1632
+ *
1633
+ * @example
1634
+ * ```typescript
1635
+ * { type: 'include', prompt: 'responder_rules' }
1636
+ * ```
1637
+ */
1638
+ interface PromptIncludePart {
1639
+ type: 'include';
1640
+ /** The name of the prompt to include (type-safe with autocomplete) */
1641
+ prompt: AgentBuilder.Prompts;
1642
+ }
1643
+ /**
1644
+ * A single part of a structured prompt.
1645
+ * Discriminated union on `type` field for TypeScript narrowing.
1646
+ */
1647
+ type PromptPart = PromptTextPart | PromptIncludePart;
1648
+ /**
1649
+ * A structured prompt is an array of prompt parts.
1650
+ * Provides type-safe composition with other prompts via autocomplete.
1651
+ *
1652
+ * @example
1653
+ * ```typescript
1654
+ * prompt: [
1655
+ * { type: 'text', content: 'You are a helpful assistant.\n\n' },
1656
+ * { type: 'include', prompt: 'common_rules' },
1657
+ * { type: 'text', content: '\n\nBe concise.' },
1658
+ * ]
1659
+ * ```
1660
+ */
1661
+ type StructuredPrompt = PromptPart[];
1662
+ /**
1663
+ * The prompt content can be either a plain string or a structured array.
1664
+ *
1665
+ * @example
1666
+ * ```typescript
1667
+ * // Simple string prompt:
1668
+ * prompt: 'You are a helpful assistant.'
1669
+ *
1670
+ * // Structured prompt with includes:
1671
+ * prompt: [
1672
+ * { type: 'text', content: 'You are a helpful assistant.\n\n' },
1673
+ * { type: 'include', prompt: 'common_rules' },
1674
+ * ]
1675
+ * ```
1676
+ */
1677
+ type PromptContent = string | StructuredPrompt;
1678
+ /**
1679
+ * Tool configuration for including a tool in a prompt.
1680
+ *
1681
+ * @template T - The tool name type (for type-safe tool references)
1682
+ */
1683
+ interface ToolConfig<T extends string = AgentBuilder.Callables> {
1684
+ /**
1685
+ * Name of the tool to include.
1686
+ * Must be a tool, prompt, or agent defined in agentbuilder/.
1687
+ */
1688
+ name: T;
1689
+ /**
1690
+ * Include text response content from sub-prompt execution in the tool result.
1691
+ * @default true
1692
+ */
1693
+ includeTextResponse?: boolean;
1694
+ /**
1695
+ * Include tool call details from sub-prompt execution in the tool result.
1696
+ * @default true
1697
+ */
1698
+ includeToolCalls?: boolean;
1699
+ /**
1700
+ * Include error details from sub-prompt execution in the tool result.
1701
+ * @default true
1702
+ */
1703
+ includeErrors?: boolean;
1704
+ /**
1705
+ * Property from the tool call arguments to use as the initial user message
1706
+ * when this tool triggers a sub-prompt execution.
1707
+ *
1708
+ * @example
1709
+ * If the tool is called with `{ query: "search term", limit: 10 }` and
1710
+ * `initUserMessageProperty: 'query'`, the sub-prompt will receive
1711
+ * "search term" as the initial user message.
1712
+ */
1713
+ initUserMessageProperty?: string;
1714
+ }
1715
+ /**
1716
+ * Reasoning configuration for models that support extended thinking.
1717
+ * Applies to models like OpenAI o1, Anthropic Claude with extended thinking,
1718
+ * Google Gemini with thinking, and Qwen with reasoning.
1719
+ */
1720
+ interface ReasoningConfig {
1721
+ /**
1722
+ * Effort level for reasoning models.
1723
+ * Higher effort = more thinking tokens = potentially better results.
1724
+ *
1725
+ * - `low`: Minimal reasoning, faster responses
1726
+ * - `medium`: Balanced reasoning and speed
1727
+ * - `high`: Maximum reasoning, slower but more thorough
1728
+ *
1729
+ * @default undefined (use model defaults)
1730
+ */
1731
+ effort?: 'low' | 'medium' | 'high';
1732
+ /**
1733
+ * Maximum tokens to allocate for reasoning.
1734
+ * Applies to models that support token limits on reasoning
1735
+ * (Anthropic, Gemini, Qwen).
1736
+ */
1737
+ maxTokens?: number;
1738
+ /**
1739
+ * Use reasoning internally but exclude from the response.
1740
+ * Model thinks through the problem but only returns the final answer.
1741
+ * Useful for cleaner outputs while maintaining reasoning quality.
1742
+ */
1743
+ exclude?: boolean;
1744
+ /**
1745
+ * Include reasoning content in the message history for multi-turn context.
1746
+ * When true, reasoning is preserved and visible to subsequent turns.
1747
+ * @default false
1748
+ */
1749
+ include?: boolean;
1750
+ }
1751
+ /**
1752
+ * Prompt definition configuration.
1753
+ *
1754
+ * @template N - The prompt name as a string literal type
1755
+ * @template S - The Zod schema type for requiredSchema (inferred automatically)
1756
+ *
1757
+ * @example
1758
+ * ```typescript
1759
+ * import { definePrompt } from '@standardagents/builder';
1760
+ * import { z } from 'zod';
1761
+ *
1762
+ * export default definePrompt({
1763
+ * name: 'customer_support',
1764
+ * toolDescription: 'Handle customer support inquiries',
1765
+ * model: 'gpt-4o',
1766
+ * // Simple string prompt:
1767
+ * prompt: `You are a helpful customer support agent.
1768
+ * Always be polite and try to resolve issues quickly.`,
1769
+ * // Or structured prompt with type-safe includes:
1770
+ * // prompt: [
1771
+ * // { type: 'text', content: 'You are a helpful customer support agent.\n\n' },
1772
+ * // { type: 'include', prompt: 'common_rules' },
1773
+ * // ],
1774
+ * tools: ['search_knowledge_base', 'create_ticket'],
1775
+ * requiredSchema: z.object({
1776
+ * query: z.string().describe('The customer inquiry'),
1777
+ * }),
1778
+ * });
1779
+ * ```
1780
+ */
1781
+ interface PromptDefinition<N extends string = string, S extends z.ZodTypeAny = z.ZodTypeAny> {
1782
+ /**
1783
+ * Unique name for this prompt.
1784
+ * Used as the identifier when referencing from agents or as a tool.
1785
+ * Should be snake_case (e.g., 'customer_support', 'data_analyst').
1786
+ */
1787
+ name: N;
1788
+ /**
1789
+ * Description shown when this prompt is exposed as a tool.
1790
+ * Should clearly describe what this prompt does for LLM tool selection.
1791
+ */
1792
+ toolDescription: string;
1793
+ /**
1794
+ * The system prompt content sent to the LLM.
1795
+ *
1796
+ * Can be either:
1797
+ * 1. A plain string - simple prompt text
1798
+ * 2. A structured array - for composing prompts with type-safe includes
1799
+ *
1800
+ * @example
1801
+ * ```typescript
1802
+ * // Simple string prompt:
1803
+ * prompt: 'You are a helpful assistant.'
1804
+ *
1805
+ * // Structured prompt with type-safe includes:
1806
+ * prompt: [
1807
+ * { type: 'text', content: 'You are a helpful assistant.\n\n' },
1808
+ * { type: 'include', prompt: 'common_rules' }, // autocomplete for prompt names!
1809
+ * { type: 'text', content: '\n\nBe concise.' },
1810
+ * ]
1811
+ * ```
1812
+ */
1813
+ prompt: PromptContent;
1814
+ /**
1815
+ * Model to use for this prompt.
1816
+ * Must reference a model defined in agentbuilder/models/.
1817
+ * Provides autocomplete when types are generated.
1818
+ */
1819
+ model: AgentBuilder.Models;
1820
+ /**
1821
+ * @deprecated All prompts are now automatically exposed as tools.
1822
+ * This property is ignored and will be removed in a future version.
1823
+ */
1824
+ exposeAsTool?: boolean;
1825
+ /**
1826
+ * Include full chat history in the LLM context.
1827
+ * When true, all previous messages in the conversation are included.
1828
+ * @default false
1829
+ */
1830
+ includeChat?: boolean;
1831
+ /**
1832
+ * Include results from past tool calls in the LLM context.
1833
+ * When true, previous tool call results are visible to the LLM.
1834
+ * @default false
1835
+ */
1836
+ includePastTools?: boolean;
1837
+ /**
1838
+ * Allow parallel execution of multiple tool calls.
1839
+ * When true, if the LLM requests multiple tools, they execute concurrently.
1840
+ * @default false
1841
+ */
1842
+ parallelToolCalls?: boolean;
1843
+ /**
1844
+ * Tool calling strategy for the LLM.
1845
+ *
1846
+ * - `auto`: Model decides when to call tools (default)
1847
+ * - `none`: Disable tool calling entirely
1848
+ * - `required`: Force the model to call at least one tool
1849
+ *
1850
+ * @default 'auto'
1851
+ */
1852
+ toolChoice?: 'auto' | 'none' | 'required';
1853
+ /**
1854
+ * Zod schema for validating inputs when this prompt is called as a tool.
1855
+ *
1856
+ * The schema provides:
1857
+ * - Runtime validation of tool call arguments
1858
+ * - Type inference for the prompt's input type
1859
+ * - Auto-generated JSON Schema for LLM tool definitions
1860
+ *
1861
+ * Use `.describe()` on schema fields to provide descriptions for the LLM.
1862
+ *
1863
+ * @example
1864
+ * ```typescript
1865
+ * requiredSchema: z.object({
1866
+ * query: z.string().describe('The search query'),
1867
+ * limit: z.number().optional().default(10).describe('Max results'),
1868
+ * })
1869
+ * ```
1870
+ */
1871
+ requiredSchema?: S;
1872
+ /**
1873
+ * Tools available to this prompt.
1874
+ * Can be simple tool names or detailed configurations.
1875
+ *
1876
+ * Tools can be:
1877
+ * - Custom tools defined in agentbuilder/tools/
1878
+ * - Other prompts with exposeAsTool: true
1879
+ * - Agents with exposeAsTool: true
1880
+ *
1881
+ * @example
1882
+ * ```typescript
1883
+ * tools: [
1884
+ * 'search_docs', // Simple reference
1885
+ * { name: 'create_ticket', includeErrors: false }, // With config
1886
+ * ]
1887
+ * ```
1888
+ */
1889
+ tools?: (AgentBuilder.Callables | ToolConfig)[];
1890
+ /**
1891
+ * Agents that can receive handoffs from this prompt.
1892
+ * Enables multi-agent workflows where this prompt can transfer
1893
+ * the conversation to a specialized agent.
1894
+ */
1895
+ handoffAgents?: AgentBuilder.Agents[];
1896
+ /**
1897
+ * Tool to execute before the LLM request.
1898
+ * Useful for data fetching, context preparation, or preprocessing.
1899
+ * The tool result is available in the prompt context.
1900
+ */
1901
+ beforeTool?: AgentBuilder.Callables;
1902
+ /**
1903
+ * Tool to execute after the LLM response.
1904
+ * Useful for post-processing, logging, or side effects.
1905
+ */
1906
+ afterTool?: AgentBuilder.Callables;
1907
+ /**
1908
+ * Reasoning configuration for models that support extended thinking.
1909
+ * Configure effort level, token limits, and visibility of reasoning.
1910
+ */
1911
+ reasoning?: ReasoningConfig;
1912
+ }
1913
+ /**
1914
+ * Helper type to extract the inferred input type from a prompt's Zod schema.
1915
+ *
1916
+ * @template T - The prompt definition type
1917
+ *
1918
+ * @example
1919
+ * ```typescript
1920
+ * const searchPrompt = definePrompt({
1921
+ * name: 'search',
1922
+ * requiredSchema: z.object({ query: z.string(), limit: z.number() }),
1923
+ * // ...
1924
+ * });
1925
+ *
1926
+ * type SearchInput = PromptInput<typeof searchPrompt>;
1927
+ * // { query: string; limit: number }
1928
+ * ```
1929
+ */
1930
+ type PromptInput<T extends PromptDefinition<any, any>> = T['requiredSchema'] extends z.ZodTypeAny ? z.infer<T['requiredSchema']> : never;
1931
+ /**
1932
+ * Defines a prompt configuration for LLM interactions.
1933
+ *
1934
+ * Prompts are the primary way to configure how agents interact with LLMs.
1935
+ * They specify the system prompt, available tools, input validation,
1936
+ * and various behavioral options.
1937
+ *
1938
+ * @template N - The prompt name as a string literal type
1939
+ * @template S - The Zod schema type for requiredSchema
1940
+ * @param options - Prompt configuration options
1941
+ * @returns The prompt definition for registration
1942
+ *
1943
+ * @example
1944
+ * ```typescript
1945
+ * // agentbuilder/prompts/customer_support.ts
1946
+ * import { definePrompt } from '@standardagents/builder';
1947
+ * import { z } from 'zod';
1948
+ *
1949
+ * export default definePrompt({
1950
+ * name: 'customer_support',
1951
+ * toolDescription: 'Handle customer support inquiries',
1952
+ * model: 'gpt-4o',
1953
+ * prompt: `You are a helpful customer support agent.
1954
+ * Always be polite and try to resolve issues quickly.
1955
+ * If you cannot help, offer to escalate to a human.`,
1956
+ * tools: ['search_knowledge_base', 'create_ticket'],
1957
+ * handoffAgents: ['escalation_agent'],
1958
+ * includeChat: true,
1959
+ * exposeAsTool: true,
1960
+ * requiredSchema: z.object({
1961
+ * query: z.string().describe('The customer inquiry'),
1962
+ * }),
1963
+ * });
1964
+ * ```
1965
+ */
1966
+ declare function definePrompt<N extends string, S extends z.ZodTypeAny = never>(options: PromptDefinition<N, S>): PromptDefinition<N, S>;
1967
+
1968
+ /**
1969
+ * Agent definition module for AgentBuilder.
1970
+ *
1971
+ * Agents orchestrate conversations between AI models (dual_ai) or between
1972
+ * AI and human users (ai_human). They define the prompts, stop conditions,
1973
+ * and behavioral rules for each side of the conversation.
1974
+ *
1975
+ * @module
1976
+ */
1977
+ /**
1978
+ * Agent conversation type.
1979
+ *
1980
+ * - `ai_human`: AI conversing with a human user (most common)
1981
+ * - `dual_ai`: Two AI participants conversing with each other
1982
+ */
1983
+ type AgentType = 'ai_human' | 'dual_ai';
1984
+ /**
1985
+ * Configuration for one side of an agent conversation.
1986
+ *
1987
+ * Each side has a prompt, stop conditions, and turn limits.
1988
+ * For `ai_human` agents, only sideA (the AI) needs configuration.
1989
+ * For `dual_ai` agents, both sides need configuration.
1990
+ */
1991
+ interface SideConfig {
1992
+ /**
1993
+ * Custom label for this side of the conversation.
1994
+ * Used in UI and logs for clarity.
1995
+ *
1996
+ * @example 'Support Agent', 'Customer', 'ATC', 'Pilot'
1997
+ */
1998
+ label?: string;
1999
+ /**
2000
+ * The prompt to use for this side.
2001
+ * Must reference a prompt defined in agentbuilder/prompts/.
2002
+ */
2003
+ prompt: AgentBuilder.Prompts;
2004
+ /**
2005
+ * Stop this side's turn when it returns a text response (no tool calls).
2006
+ * When true, the side's turn ends after producing a message without tools.
2007
+ * @default true
2008
+ */
2009
+ stopOnResponse?: boolean;
2010
+ /**
2011
+ * Stop this side's turn when a specific tool is called.
2012
+ * Overrides stopOnResponse when the named tool is invoked.
2013
+ * Requires stopToolResponseProperty to extract the result.
2014
+ */
2015
+ stopTool?: AgentBuilder.Callables;
2016
+ /**
2017
+ * Property to extract from the stop tool's result.
2018
+ * Required when stopTool is set.
2019
+ * The extracted value is used to determine the conversation outcome.
2020
+ */
2021
+ stopToolResponseProperty?: string;
2022
+ /**
2023
+ * Maximum turns for this side before forcing a stop.
2024
+ * Safety limit to prevent runaway conversations.
2025
+ * A turn is one complete request/response cycle.
2026
+ */
2027
+ maxTurns?: number;
2028
+ /**
2029
+ * Tool that ends the entire conversation when called.
2030
+ * Different from stopTool - this ends the conversation for both sides,
2031
+ * not just this side's turn.
2032
+ */
2033
+ endConversationTool?: AgentBuilder.Callables;
2034
+ /**
2035
+ * Enable manual stop condition handling via hooks.
2036
+ * When true, stop conditions are evaluated by custom hook logic
2037
+ * instead of the built-in rules.
2038
+ * @default false
2039
+ */
2040
+ manualStopCondition?: boolean;
2041
+ }
2042
+ /**
2043
+ * Agent definition configuration.
2044
+ *
2045
+ * @template N - The agent name as a string literal type
2046
+ *
2047
+ * @example
2048
+ * ```typescript
2049
+ * import { defineAgent } from '@standardagents/builder';
2050
+ *
2051
+ * export default defineAgent({
2052
+ * name: 'support_agent',
2053
+ * title: 'Customer Support Agent',
2054
+ * type: 'ai_human',
2055
+ * sideA: {
2056
+ * label: 'Support',
2057
+ * prompt: 'customer_support',
2058
+ * stopOnResponse: true,
2059
+ * },
2060
+ * tags: ['support', 'tier-1'],
2061
+ * });
2062
+ * ```
2063
+ */
2064
+ interface AgentDefinition<N extends string = string> {
2065
+ /**
2066
+ * Unique name for this agent.
2067
+ * Used as the identifier for thread creation and handoffs.
2068
+ * Should be snake_case (e.g., 'support_agent', 'research_flow').
2069
+ */
2070
+ name: N;
2071
+ /**
2072
+ * Human-readable title for the agent.
2073
+ * Optional - if not provided, the name will be used.
2074
+ * @deprecated Use name instead. Title will be removed in a future version.
2075
+ */
2076
+ title?: string;
2077
+ /**
2078
+ * Agent conversation type.
2079
+ *
2080
+ * - `ai_human`: AI conversing with a human user (default)
2081
+ * - `dual_ai`: Two AI participants conversing
2082
+ *
2083
+ * @default 'ai_human'
2084
+ */
2085
+ type?: AgentType;
2086
+ /**
2087
+ * Maximum total turns across both sides.
2088
+ * Only applies to `dual_ai` agents.
2089
+ * Prevents infinite loops in AI-to-AI conversations.
2090
+ */
2091
+ maxSessionTurns?: number;
2092
+ /**
2093
+ * Configuration for Side A.
2094
+ * For `ai_human`: This is the AI side.
2095
+ * For `dual_ai`: This is the first AI participant.
2096
+ */
2097
+ sideA: SideConfig;
2098
+ /**
2099
+ * Configuration for Side B.
2100
+ * For `ai_human`: Optional, the human side doesn't need config.
2101
+ * For `dual_ai`: Required, the second AI participant.
2102
+ */
2103
+ sideB?: SideConfig;
2104
+ /**
2105
+ * Expose this agent as a tool for other prompts.
2106
+ * Enables agent composition and handoffs.
2107
+ * When true, other prompts can invoke this agent as a tool.
2108
+ * @default false
2109
+ */
2110
+ exposeAsTool?: boolean;
2111
+ /**
2112
+ * Description shown when agent is used as a tool.
2113
+ * Required if exposeAsTool is true.
2114
+ * Should clearly describe what this agent does.
2115
+ */
2116
+ toolDescription?: string;
2117
+ /**
2118
+ * Tags for categorization and filtering.
2119
+ * Useful for organizing agents in the UI and filtering in queries.
2120
+ *
2121
+ * @example ['customer-service', 'tier-1', 'english']
2122
+ */
2123
+ tags?: string[];
2124
+ }
2125
+ /**
2126
+ * Defines an agent configuration.
2127
+ *
2128
+ * Agents orchestrate conversations between AI models, or between AI and
2129
+ * human users. They use prompts to configure each side of the conversation
2130
+ * and define stop conditions to control conversation flow.
2131
+ *
2132
+ * @template N - The agent name as a string literal type
2133
+ * @param options - Agent configuration options
2134
+ * @returns The agent definition for registration
2135
+ *
2136
+ * @example
2137
+ * ```typescript
2138
+ * // agentbuilder/agents/support_agent.ts
2139
+ * import { defineAgent } from '@standardagents/builder';
2140
+ *
2141
+ * export default defineAgent({
2142
+ * name: 'support_agent',
2143
+ * title: 'Customer Support Agent',
2144
+ * type: 'ai_human',
2145
+ * sideA: {
2146
+ * label: 'Support',
2147
+ * prompt: 'customer_support',
2148
+ * stopOnResponse: true,
2149
+ * endConversationTool: 'close_ticket',
2150
+ * },
2151
+ * exposeAsTool: true,
2152
+ * toolDescription: 'Hand off to customer support',
2153
+ * tags: ['support', 'tier-1'],
2154
+ * });
2155
+ * ```
2156
+ *
2157
+ * @example
2158
+ * ```typescript
2159
+ * // Dual AI agent (two AIs conversing)
2160
+ * export default defineAgent({
2161
+ * name: 'debate_agent',
2162
+ * title: 'AI Debate',
2163
+ * type: 'dual_ai',
2164
+ * maxSessionTurns: 10,
2165
+ * sideA: {
2166
+ * label: 'Pro',
2167
+ * prompt: 'debate_pro',
2168
+ * stopOnResponse: true,
2169
+ * },
2170
+ * sideB: {
2171
+ * label: 'Con',
2172
+ * prompt: 'debate_con',
2173
+ * stopOnResponse: true,
2174
+ * endConversationTool: 'conclude_debate',
2175
+ * },
2176
+ * });
2177
+ * ```
2178
+ */
2179
+ declare function defineAgent<N extends string>(options: AgentDefinition<N>): AgentDefinition<N>;
2180
+
2181
+ /**
2182
+ * Generate a TypeScript file for a model definition.
2183
+ */
2184
+ declare function generateModelFile(data: ModelDefinition): string;
2185
+
2186
+ /**
2187
+ * Converts JSON Schema to Zod code string.
2188
+ *
2189
+ * This is used when saving prompts from the UI - the form editor works with
2190
+ * JSON Schema, but we need to generate Zod code for the TypeScript file.
2191
+ */
2192
+ interface JSONSchema {
2193
+ type?: string;
2194
+ description?: string;
2195
+ properties?: Record<string, JSONSchema>;
2196
+ required?: string[];
2197
+ items?: JSONSchema;
2198
+ enum?: (string | number | boolean)[];
2199
+ anyOf?: JSONSchema[];
2200
+ oneOf?: JSONSchema[];
2201
+ allOf?: JSONSchema[];
2202
+ const?: any;
2203
+ default?: any;
2204
+ minimum?: number;
2205
+ maximum?: number;
2206
+ minLength?: number;
2207
+ maxLength?: number;
2208
+ pattern?: string;
2209
+ format?: string;
2210
+ additionalProperties?: boolean | JSONSchema;
2211
+ nullable?: boolean;
2212
+ }
2213
+
2214
+ /**
2215
+ * Tool configuration from UI (snake_case).
2216
+ */
2217
+ interface ToolConfigInput {
2218
+ name: string;
2219
+ include_text_response?: boolean;
2220
+ include_tool_calls?: boolean;
2221
+ include_errors?: boolean;
2222
+ init_user_message_property?: string | null;
2223
+ }
2224
+ /**
2225
+ * Prompt part as it comes from the UI/API.
2226
+ * Supports both new format (type: 'text'/'include') and legacy format (type: 'string'/'prompt')
2227
+ */
2228
+ interface PromptPartInput {
2229
+ type: 'text' | 'include' | 'string' | 'prompt' | 'variable';
2230
+ content?: string;
2231
+ prompt?: string;
2232
+ value?: string;
2233
+ id?: string;
2234
+ label?: string;
2235
+ schema?: any;
2236
+ }
2237
+ /**
2238
+ * Input data for generating a prompt file.
2239
+ * This can include JSON Schema for requiredSchema which will be converted to Zod.
2240
+ */
2241
+ interface PromptFileData {
2242
+ name: string;
2243
+ toolDescription?: string;
2244
+ /**
2245
+ * Prompt content can be:
2246
+ * - A plain string
2247
+ * - A structured array of prompt parts
2248
+ * - A JSON string of a structured array (legacy format from UI)
2249
+ */
2250
+ prompt?: string | PromptPartInput[];
2251
+ model: string;
2252
+ includeChat?: boolean;
2253
+ includePastTools?: boolean;
2254
+ parallelToolCalls?: boolean;
2255
+ toolChoice?: 'auto' | 'none' | 'required';
2256
+ tools?: (string | ToolConfigInput)[];
2257
+ handoffAgents?: string[];
2258
+ beforeTool?: string;
2259
+ afterTool?: string;
2260
+ reasoning?: {
2261
+ effort?: 'low' | 'medium' | 'high';
2262
+ maxTokens?: number;
2263
+ exclude?: boolean;
2264
+ include?: boolean;
2265
+ };
2266
+ /**
2267
+ * Required schema as JSON Schema (from the UI).
2268
+ * Will be converted to Zod code.
2269
+ */
2270
+ requiredSchema?: JSONSchema;
2271
+ }
2272
+ /**
2273
+ * Generate a TypeScript file for a prompt definition.
2274
+ *
2275
+ * @param data - Prompt data including JSON Schema for requiredSchema
2276
+ * @returns TypeScript code as a string
2277
+ */
2278
+ declare function generatePromptFile(data: PromptFileData): string;
2279
+
2280
+ /**
2281
+ * Generate a TypeScript file for an agent definition.
2282
+ */
2283
+ declare function generateAgentFile(data: AgentDefinition): string;
2284
+
2285
+ /**
2286
+ * Options for injecting a message
2287
+ */
2288
+ interface InjectMessageOptions$1 {
2289
+ /** The message content */
2290
+ content: string;
2291
+ /** The message role */
2292
+ role: "system" | "user" | "assistant" | "tool";
2293
+ /** Optional message ID. If not provided, a UUID will be generated */
2294
+ id?: string;
2295
+ /** Optional message to insert before. If not provided, message is appended to the end */
2296
+ beforeMessageId?: string;
2297
+ /** Optional tool call ID (for role="tool" only) */
2298
+ toolCallId?: string;
2299
+ /** Optional name field */
2300
+ name?: string;
2301
+ /** Whether this message is silent (hidden from LLM, visible in UI only). Default: false */
2302
+ silent?: boolean;
2303
+ /** Force message to be top-level (depth 0) even when called from sub-prompts. Default: false */
2304
+ forceTopLevel?: boolean;
2305
+ /** Force a specific side to play the next turn after injecting the message */
2306
+ forceTurn?: "side_a" | "side_b";
2307
+ }
2308
+ /**
2309
+ * Queue a new tool call to be executed in the current flow
2310
+ *
2311
+ * This adds a tool call to the execution queue without immediately executing it.
2312
+ * The tool will be executed as part of the normal flow processing.
2313
+ *
2314
+ * @param flow - The current FlowState
2315
+ * @param toolName - The name of the tool to call
2316
+ * @param args - The arguments to pass to the tool
2317
+ *
2318
+ * @example
2319
+ * ```typescript
2320
+ * import { queueTool } from '@standardagents/builder';
2321
+ *
2322
+ * queueTool(flow, "search_user", { email: "user@example.com" });
2323
+ * ```
2324
+ */
2325
+ declare function queueTool(flow: FlowState, toolName: string, args?: Record<string, unknown>): void;
2326
+ /**
2327
+ * Inject a message into the thread without triggering execution
2328
+ *
2329
+ * This allows you to add messages to the conversation history programmatically.
2330
+ * The message is persisted to storage but does not cause the agent to execute.
2331
+ *
2332
+ * By default, messages are appended to the end of the conversation.
2333
+ * You can optionally insert a message before another message by providing beforeMessageId.
2334
+ *
2335
+ * @param flow - The current FlowState
2336
+ * @param options - Message options
2337
+ *
2338
+ * @example
2339
+ * ```typescript
2340
+ * import { injectMessage } from '@standardagents/builder';
2341
+ *
2342
+ * // Append a system message
2343
+ * await injectMessage(flow, {
2344
+ * role: "system",
2345
+ * content: "Context has been updated"
2346
+ * });
2347
+ *
2348
+ * // Insert a user message before a specific message
2349
+ * await injectMessage(flow, {
2350
+ * role: "user",
2351
+ * content: "Additional context",
2352
+ * beforeMessageId: "msg-123"
2353
+ * });
2354
+ *
2355
+ * // Inject a message and force a specific side to play next
2356
+ * await injectMessage(flow, {
2357
+ * role: "system",
2358
+ * content: "New instructions for the AI",
2359
+ * forceTurn: "side_a" // Force side_a to respond to this message
2360
+ * });
2361
+ * ```
2362
+ */
2363
+ declare function injectMessage(flow: FlowState, options: InjectMessageOptions$1): Promise<Message>;
2364
+ /**
2365
+ * Get messages from the thread history
2366
+ *
2367
+ * Retrieves message history from the thread's SQLite storage.
2368
+ * Messages are ordered by creation time (oldest first by default).
2369
+ *
2370
+ * @param flow - The current FlowState
2371
+ * @param limit - Maximum number of messages to retrieve (default: 100)
2372
+ * @param offset - Number of messages to skip (default: 0)
2373
+ * @param order - Sort order: "asc" (oldest first) or "desc" (newest first) (default: "asc")
2374
+ * @returns Array of messages
2375
+ *
2376
+ * @example
2377
+ * ```typescript
2378
+ * import { getMessages } from '@standardagents/builder';
2379
+ *
2380
+ * // Get last 10 messages
2381
+ * const messages = await getMessages(flow, 10);
2382
+ *
2383
+ * // Get 10 messages, skipping the first 20
2384
+ * const messages = await getMessages(flow, 10, 20);
2385
+ *
2386
+ * // Get newest 10 messages
2387
+ * const messages = await getMessages(flow, 10, 0, "desc");
2388
+ * ```
2389
+ */
2390
+ declare function getMessages(flow: FlowState, limit?: number, offset?: number, order?: "asc" | "desc"): Promise<Message[]>;
2391
+ /**
2392
+ * Reload message history from storage
2393
+ *
2394
+ * Re-loads the complete message history from the thread's SQLite storage,
2395
+ * applying any filter_messages hooks. This is useful when you need to refresh
2396
+ * the message history after making changes (e.g., injecting silent messages).
2397
+ *
2398
+ * @param flow - The current FlowState
2399
+ * @returns Array of messages (reloaded from storage)
2400
+ *
2401
+ * @example
2402
+ * ```typescript
2403
+ * import { injectMessage, reloadHistory } from '@standardagents/builder';
2404
+ *
2405
+ * // Reload history after injecting a silent message
2406
+ * await injectMessage(flow, { role: "system", content: "...", silent: true });
2407
+ * flow.messageHistory = await reloadHistory(flow);
2408
+ * ```
2409
+ */
2410
+ declare function reloadHistory(state: FlowState): Promise<Message[]>;
2411
+ /**
2412
+ * Emit a custom event to WebSocket clients via the stream
2413
+ *
2414
+ * Sends a custom event to all connected WebSocket clients on the stream channel.
2415
+ * This allows backend code to push arbitrary data to the frontend
2416
+ * outside of the standard message events.
2417
+ *
2418
+ * @param flow - The current FlowState
2419
+ * @param type - The event type name (e.g., "progress", "notification")
2420
+ * @param data - The event payload (any serializable data)
2421
+ *
2422
+ * @example
2423
+ * ```typescript
2424
+ * import { emitThreadEvent } from '@standardagents/builder';
2425
+ *
2426
+ * // Emit a progress update
2427
+ * emitThreadEvent(flow, "progress", { step: 3, total: 10, message: "Processing data..." });
2428
+ *
2429
+ * // Emit a custom notification
2430
+ * emitThreadEvent(flow, "notification", { level: "info", message: "User authenticated" });
2431
+ *
2432
+ * // Emit metadata
2433
+ * emitThreadEvent(flow, "metadata", { userId: "123", sessionId: "abc" });
2434
+ * ```
2435
+ */
2436
+ declare function emitThreadEvent(flow: FlowState, type: string, data: unknown): void;
2437
+ /**
2438
+ * Force a specific side to play the next turn
2439
+ *
2440
+ * This queues the specified side to play next without interrupting the current turn.
2441
+ * The forced turn only takes effect at the END of the current turn execution.
2442
+ *
2443
+ * If the tool queue is currently being processed (sequence.isHandling is true),
2444
+ * the forced turn is deferred until all queued tools complete. This allows patterns like:
2445
+ *
2446
+ * ```typescript
2447
+ * import { queueTool, forceTurn } from '@standardagents/builder';
2448
+ *
2449
+ * queueTool(flow, 'myTool', {});
2450
+ * forceTurn(flow, 'side_a');
2451
+ * // myTool executes first, THEN the turn switches to side_a
2452
+ * ```
2453
+ *
2454
+ * @param flow - The current FlowState
2455
+ * @param side - Which side should play next ('side_a' or 'side_b')
2456
+ *
2457
+ * @example
2458
+ * ```typescript
2459
+ * import { forceTurn } from '@standardagents/builder';
2460
+ *
2461
+ * // Force current side to continue (override stop condition)
2462
+ * // If side_a is playing and would stop, this forces it to play at least 1 more turn
2463
+ * forceTurn(flow, 'side_a');
2464
+ *
2465
+ * // Force switch to other side
2466
+ * // If side_a is playing, this forces side_b to play next turn
2467
+ * forceTurn(flow, 'side_b');
2468
+ *
2469
+ * // Force human turn in ai_human agent (execution stops and waits for user input)
2470
+ * if (flow.agentConfig.type === 'ai_human') {
2471
+ * forceTurn(flow, 'side_b'); // Stops execution, awaits user input
2472
+ * }
2473
+ * ```
2474
+ */
2475
+ declare function forceTurn(flow: FlowState, side: 'side_a' | 'side_b'): void;
2476
+ /**
2477
+ * Thread context from defineThreadEndpoint
2478
+ */
2479
+ interface ThreadContext {
2480
+ instance: {
2481
+ updateThreadMeta: (threadId: string, params: {
2482
+ agent_name?: string;
2483
+ user_id?: string | null;
2484
+ tags?: string[] | null;
2485
+ }) => Promise<{
2486
+ success: boolean;
2487
+ error?: string;
2488
+ thread?: {
2489
+ id: string;
2490
+ agent_id: string;
2491
+ user_id: string | null;
2492
+ tags: string[];
2493
+ created_at: number;
2494
+ };
2495
+ }>;
2496
+ };
2497
+ metadata: {
2498
+ id: string;
2499
+ agent_name: string;
2500
+ user_id: string | null;
2501
+ tags: string[] | null;
2502
+ created_at: number;
2503
+ };
2504
+ }
2505
+ /**
2506
+ * Update a thread's metadata in the DurableAgentBuilder registry
2507
+ *
2508
+ * This allows updating the agent_name, user_id, and tags for an existing thread.
2509
+ * Uses the thread instance from defineThreadEndpoint context.
2510
+ *
2511
+ * @param thread - The thread context from defineThreadEndpoint ({ instance, metadata })
2512
+ * @param params - The fields to update (agent_name, user_id, tags)
2513
+ * @returns The updated thread info, or null if update failed
2514
+ *
2515
+ * @example
2516
+ * ```typescript
2517
+ * import { defineThreadEndpoint, updateThread } from '@standardagents/builder';
2518
+ *
2519
+ * export default defineThreadEndpoint(async (req, thread) => {
2520
+ * // Update thread's user_id
2521
+ * await updateThread(thread, { user_id: 'user-123' });
2522
+ *
2523
+ * // Update thread's tags
2524
+ * await updateThread(thread, { tags: ['support', 'urgent'] });
2525
+ *
2526
+ * // Update multiple fields
2527
+ * const result = await updateThread(thread, {
2528
+ * agent_name: 'new-agent',
2529
+ * user_id: 'user-456',
2530
+ * tags: ['sales']
2531
+ * });
2532
+ *
2533
+ * return Response.json(result);
2534
+ * });
2535
+ * ```
2536
+ */
2537
+ declare function updateThread(thread: ThreadContext, params: {
2538
+ agent_name?: string;
2539
+ user_id?: string | null;
2540
+ tags?: string[] | null;
2541
+ }): Promise<{
2542
+ id: string;
2543
+ agent_id: string;
2544
+ user_id: string | null;
2545
+ tags: string[];
2546
+ created_at: number;
2547
+ } | null>;
2548
+
2549
+ /**
2550
+ * Options for injecting a message
2551
+ */
2552
+ interface InjectMessageOptions {
2553
+ /** The message content */
2554
+ content: string;
2555
+ /** The message role */
2556
+ role: "system" | "user" | "assistant" | "tool";
2557
+ /** Optional message ID. If not provided, a UUID will be generated */
2558
+ id?: string;
2559
+ /** Optional message to insert before. If not provided, message is appended to the end */
2560
+ beforeMessageId?: string;
2561
+ /** Optional tool call ID (for role="tool" only) */
2562
+ toolCallId?: string;
2563
+ /** Optional name field */
2564
+ name?: string;
2565
+ /** Whether this message is silent (hidden from LLM, visible in UI only). Default: false */
2566
+ silent?: boolean;
2567
+ /** Force message to be top-level (depth 0) even when called from sub-prompts. Default: false */
2568
+ forceTopLevel?: boolean;
2569
+ /** Force a specific side to play the next turn after injecting the message */
2570
+ forceTurn?: "side_a" | "side_b";
2571
+ }
2572
+ /**
2573
+ * Options for broadcasting custom data
2574
+ */
2575
+ interface BroadcastOptions {
2576
+ /** The type of the broadcast message */
2577
+ type: string;
2578
+ /** The value/payload of the broadcast message */
2579
+ value: unknown;
2580
+ }
2581
+ /**
2582
+ * FlowState SDK - Utility methods for working with FlowState
2583
+ *
2584
+ * These methods extend the FlowState object with helpful utilities for:
2585
+ * - Queuing tool calls
2586
+ * - Injecting messages
2587
+ * - Retrieving message history
2588
+ * - Broadcasting custom data via WebSocket
2589
+ */
2590
+ declare class FlowStateSdk {
2591
+ /**
2592
+ * Queue a new tool call to be executed in the current flow
2593
+ *
2594
+ * This adds a tool call to the execution queue without immediately executing it.
2595
+ * The tool will be executed as part of the normal flow processing.
2596
+ *
2597
+ * @param flow - The current FlowState
2598
+ * @param toolName - The name of the tool to call
2599
+ * @param args - The arguments to pass to the tool
2600
+ *
2601
+ * @example
2602
+ * ```typescript
2603
+ * FlowStateSdk.queueTool(flow, "search_user", { email: "user@example.com" });
2604
+ * ```
2605
+ */
2606
+ static queueTool(flow: FlowState, toolName: string, args?: Record<string, unknown>): void;
2607
+ /**
2608
+ * Inject a message into the thread without triggering execution
2609
+ *
2610
+ * This allows you to add messages to the conversation history programmatically.
2611
+ * The message is persisted to storage but does not cause the agent to execute.
2612
+ *
2613
+ * By default, messages are appended to the end of the conversation.
2614
+ * You can optionally insert a message before another message by providing beforeMessageId.
2615
+ *
2616
+ * @param flow - The current FlowState
2617
+ * @param options - Message options
2618
+ *
2619
+ * @example
2620
+ * ```typescript
2621
+ * // Append a system message
2622
+ * await FlowStateSdk.injectMessage(flow, {
2623
+ * role: "system",
2624
+ * content: "Context has been updated"
2625
+ * });
2626
+ *
2627
+ * // Insert a user message before a specific message
2628
+ * await FlowStateSdk.injectMessage(flow, {
2629
+ * role: "user",
2630
+ * content: "Additional context",
2631
+ * beforeMessageId: "msg-123"
2632
+ * });
2633
+ *
2634
+ * // Inject a message and force a specific side to play next
2635
+ * await FlowStateSdk.injectMessage(flow, {
2636
+ * role: "system",
2637
+ * content: "New instructions for the AI",
2638
+ * forceTurn: "side_a" // Force side_a to respond to this message
2639
+ * });
2640
+ * ```
2641
+ */
2642
+ static injectMessage(flow: FlowState, options: InjectMessageOptions): Promise<Message>;
2643
+ /**
2644
+ * Get messages from the thread history
2645
+ *
2646
+ * Retrieves message history from the thread's SQLite storage.
2647
+ * Messages are ordered by creation time (oldest first by default).
2648
+ *
2649
+ * @param flow - The current FlowState
2650
+ * @param limit - Maximum number of messages to retrieve (default: 100)
2651
+ * @param offset - Number of messages to skip (default: 0)
2652
+ * @param order - Sort order: "asc" (oldest first) or "desc" (newest first) (default: "asc")
2653
+ * @returns Array of messages
2654
+ *
2655
+ * @example
2656
+ * ```typescript
2657
+ * // Get last 10 messages
2658
+ * const messages = await FlowStateSdk.getMessages(flow, 10);
2659
+ *
2660
+ * // Get 10 messages, skipping the first 20
2661
+ * const messages = await FlowStateSdk.getMessages(flow, 10, 20);
2662
+ *
2663
+ * // Get newest 10 messages
2664
+ * const messages = await FlowStateSdk.getMessages(flow, 10, 0, "desc");
2665
+ * ```
2666
+ */
2667
+ static getMessages(flow: FlowState, limit?: number, offset?: number, order?: "asc" | "desc"): Promise<Message[]>;
2668
+ /**
2669
+ * Reload message history from storage
2670
+ *
2671
+ * Re-loads the complete message history from the thread's SQLite storage,
2672
+ * applying any filter_messages hooks. This is useful when you need to refresh
2673
+ * the message history after making changes (e.g., injecting silent messages).
2674
+ *
2675
+ * @param flow - The current FlowState
2676
+ * @returns Array of messages (reloaded from storage)
2677
+ *
2678
+ * @example
2679
+ * ```typescript
2680
+ * // Reload history after injecting a silent message
2681
+ * await FlowStateSdk.injectMessage(flow, { role: "system", content: "...", silent: true });
2682
+ * flow.messageHistory = await FlowStateSdk.reloadHistory(flow);
2683
+ * ```
2684
+ */
2685
+ static reloadHistory(state: FlowState): Promise<Message[]>;
2686
+ /**
2687
+ * Broadcast custom data to WebSocket clients
2688
+ *
2689
+ * Sends a custom message to all connected WebSocket clients.
2690
+ * This allows backend code to push arbitrary data to the frontend
2691
+ * outside of the standard telemetry events.
2692
+ *
2693
+ * The message is sent with the structure: { type: string, value: unknown }
2694
+ *
2695
+ * @param flow - The current FlowState
2696
+ * @param options - Broadcast options
2697
+ *
2698
+ * @example
2699
+ * ```typescript
2700
+ * // Broadcast a progress update
2701
+ * FlowStateSdk.broadcast(flow, {
2702
+ * type: "progress",
2703
+ * value: { step: 3, total: 10, message: "Processing data..." }
2704
+ * });
2705
+ *
2706
+ * // Broadcast a custom notification
2707
+ * FlowStateSdk.broadcast(flow, {
2708
+ * type: "notification",
2709
+ * value: { level: "info", message: "User authenticated successfully" }
2710
+ * });
2711
+ *
2712
+ * // Broadcast metadata
2713
+ * FlowStateSdk.broadcast(flow, {
2714
+ * type: "metadata",
2715
+ * value: { userId: "123", sessionId: "abc", timestamp: Date.now() }
2716
+ * });
2717
+ * ```
2718
+ */
2719
+ static broadcast(flow: FlowState, options: BroadcastOptions): void;
2720
+ /**
2721
+ * Force a specific side to play the next turn
2722
+ *
2723
+ * This queues the specified side to play next without interrupting the current turn.
2724
+ * The forced turn only takes effect at the END of the current turn execution.
2725
+ *
2726
+ * If the tool queue is currently being processed (sequence.isHandling is true),
2727
+ * the forced turn is deferred until all queued tools complete. This allows patterns like:
2728
+ *
2729
+ * ```typescript
2730
+ * FlowStateSdk.queueTool(flow, 'myTool', {});
2731
+ * FlowStateSdk.forceTurn(flow, 'side_a');
2732
+ * // myTool executes first, THEN the turn switches to side_a
2733
+ * ```
2734
+ *
2735
+ * @param flow - The current FlowState
2736
+ * @param side - Which side should play next ('side_a' or 'side_b')
2737
+ *
2738
+ * @example
2739
+ * ```typescript
2740
+ * // Force current side to continue (override stop condition)
2741
+ * // If side_a is playing and would stop, this forces it to play at least 1 more turn
2742
+ * FlowStateSdk.forceTurn(flow, 'side_a');
2743
+ *
2744
+ * // Force switch to other side
2745
+ * // If side_a is playing, this forces side_b to play next turn
2746
+ * FlowStateSdk.forceTurn(flow, 'side_b');
2747
+ *
2748
+ * // Force human turn in ai_human agent (execution stops and waits for user input)
2749
+ * if (flow.agentConfig.type === 'ai_human') {
2750
+ * FlowStateSdk.forceTurn(flow, 'side_b'); // Stops execution, awaits user input
2751
+ * }
2752
+ * ```
2753
+ */
2754
+ static forceTurn(flow: FlowState, side: 'side_a' | 'side_b'): void;
2755
+ }
2756
+ /**
2757
+ * Convenience methods added to FlowState (optional - can be used via static methods above)
2758
+ *
2759
+ * These are helper methods that can be added to FlowState instances for convenience.
2760
+ * They delegate to the static methods above.
2761
+ */
2762
+ interface FlowStateWithSdk extends FlowState {
2763
+ queueTool: (toolName: string, args?: Record<string, unknown>) => void;
2764
+ injectMessage: (options: InjectMessageOptions) => Promise<Message>;
2765
+ getMessages: (limit?: number, offset?: number, order?: "asc" | "desc") => Promise<Message[]>;
2766
+ reloadHistory: () => Promise<Message[]>;
2767
+ broadcast: (options: BroadcastOptions) => void;
2768
+ forceTurn: (side: 'side_a' | 'side_b') => void;
2769
+ }
2770
+ /**
2771
+ * Enhance a FlowState object with SDK methods
2772
+ *
2773
+ * This adds convenience methods to a FlowState instance that delegate to
2774
+ * the static FlowStateSdk methods.
2775
+ *
2776
+ * @param flow - The FlowState to enhance
2777
+ * @returns The enhanced FlowState with SDK methods
2778
+ *
2779
+ * @example
2780
+ * ```typescript
2781
+ * const enhancedFlow = enhanceFlowState(flow);
2782
+ *
2783
+ * // Now you can use methods directly on the flow object
2784
+ * enhancedFlow.queueTool("search_user", { email: "user@example.com" });
2785
+ * await enhancedFlow.injectMessage({ role: "system", content: "Context updated" });
2786
+ * const messages = await enhancedFlow.getMessages(10);
2787
+ * flow.messageHistory = await enhancedFlow.reloadHistory();
2788
+ * enhancedFlow.broadcast({ type: "progress", value: { step: 1 } });
2789
+ * enhancedFlow.forceTurn('side_b'); // Force side_b to play next turn
2790
+ * ```
2791
+ */
2792
+ declare function enhanceFlowState(flow: FlowState): FlowStateWithSdk;
2793
+
2794
+ /**
2795
+ * Types for GitHub REST API integration.
2796
+ */
2797
+ interface GitHubConfig {
2798
+ token: string;
2799
+ owner: string;
2800
+ repo: string;
2801
+ branch: string;
2802
+ }
2803
+ interface GitHubFileChange {
2804
+ path: string;
2805
+ content: string;
2806
+ mode?: '100644' | '100755';
2807
+ }
2808
+ interface GitHubCommitResult {
2809
+ sha: string;
2810
+ url: string;
2811
+ message: string;
2812
+ }
2813
+ interface GitHubRef {
2814
+ ref: string;
2815
+ node_id: string;
2816
+ url: string;
2817
+ object: {
2818
+ sha: string;
2819
+ type: string;
2820
+ url: string;
2821
+ };
2822
+ }
2823
+ interface GitHubTree {
2824
+ sha: string;
2825
+ url: string;
2826
+ truncated: boolean;
2827
+ tree: Array<{
2828
+ path: string;
2829
+ mode: string;
2830
+ type: string;
2831
+ sha: string;
2832
+ size?: number;
2833
+ url: string;
2834
+ }>;
2835
+ }
2836
+ interface GitHubBlob {
2837
+ sha: string;
2838
+ url: string;
2839
+ }
2840
+ interface GitHubCommit {
2841
+ sha: string;
2842
+ url: string;
2843
+ html_url: string;
2844
+ author: {
2845
+ name: string;
2846
+ email: string;
2847
+ date: string;
2848
+ };
2849
+ committer: {
2850
+ name: string;
2851
+ email: string;
2852
+ date: string;
2853
+ };
2854
+ message: string;
2855
+ tree: {
2856
+ sha: string;
2857
+ url: string;
2858
+ };
2859
+ parents: Array<{
2860
+ sha: string;
2861
+ url: string;
2862
+ }>;
2863
+ }
2864
+
2865
+ /**
2866
+ * GitHub REST API client for committing file changes.
2867
+ *
2868
+ * This client is used in production to commit configuration changes
2869
+ * (prompts, models, agents) to the repository via GitHub's REST API.
2870
+ *
2871
+ * The flow for creating a commit:
2872
+ * 1. Get the current branch ref to find HEAD commit SHA
2873
+ * 2. Get the tree SHA from the HEAD commit
2874
+ * 3. Create blobs for each file to be added/modified
2875
+ * 4. Create a new tree with the file changes
2876
+ * 5. Create a commit pointing to the new tree
2877
+ * 6. Update the branch ref to point to the new commit
2878
+ */
2879
+
2880
+ declare class GitHubClient {
2881
+ private config;
2882
+ constructor(config: GitHubConfig);
2883
+ /**
2884
+ * Create a GitHubClient from environment variables.
2885
+ * Returns null if required env vars are missing.
2886
+ */
2887
+ static fromEnv(env: {
2888
+ GITHUB_TOKEN?: string;
2889
+ GITHUB_REPO?: string;
2890
+ GITHUB_BRANCH?: string;
2891
+ }): GitHubClient | null;
2892
+ /**
2893
+ * Check if GitHub integration is properly configured.
2894
+ */
2895
+ isConfigured(): boolean;
2896
+ /**
2897
+ * Make an authenticated request to GitHub API.
2898
+ */
2899
+ private request;
2900
+ /**
2901
+ * Get the current branch reference.
2902
+ */
2903
+ getBranchRef(): Promise<GitHubRef>;
2904
+ /**
2905
+ * Get a commit by SHA.
2906
+ */
2907
+ getCommit(sha: string): Promise<GitHubCommit>;
2908
+ /**
2909
+ * Get a tree by SHA.
2910
+ */
2911
+ getTree(sha: string): Promise<GitHubTree>;
2912
+ /**
2913
+ * Create a blob (file content).
2914
+ */
2915
+ createBlob(content: string): Promise<GitHubBlob>;
2916
+ /**
2917
+ * Create a tree with file changes.
2918
+ */
2919
+ createTree(baseTreeSha: string, files: Array<{
2920
+ path: string;
2921
+ sha: string;
2922
+ mode: string;
2923
+ }>): Promise<GitHubTree>;
2924
+ /**
2925
+ * Create a commit.
2926
+ */
2927
+ createCommit(message: string, treeSha: string, parentSha: string): Promise<GitHubCommit>;
2928
+ /**
2929
+ * Update a branch reference to point to a new commit.
2930
+ */
2931
+ updateRef(sha: string): Promise<GitHubRef>;
2932
+ /**
2933
+ * Commit multiple file changes atomically.
2934
+ *
2935
+ * @param message - Commit message
2936
+ * @param files - Array of files to add/modify
2937
+ * @returns The commit result with SHA
2938
+ */
2939
+ commitFiles(message: string, files: GitHubFileChange[]): Promise<GitHubCommitResult>;
2940
+ /**
2941
+ * Delete files from the repository.
2942
+ *
2943
+ * @param message - Commit message
2944
+ * @param paths - Array of file paths to delete
2945
+ * @returns The commit result with SHA
2946
+ */
2947
+ deleteFiles(message: string, paths: string[]): Promise<GitHubCommitResult>;
2948
+ /**
2949
+ * Get the current HEAD commit SHA.
2950
+ */
2951
+ getHeadSha(): Promise<string>;
2952
+ }
2953
+ /**
2954
+ * Custom error for GitHub API errors.
2955
+ */
2956
+ declare class GitHubApiError extends Error {
2957
+ status: number;
2958
+ details: unknown;
2959
+ constructor(message: string, status: number, details?: unknown);
2960
+ }
2961
+
2962
+ export { type Agent, type AgentBuilderEnv, type AgentDefinition, type AgentType, type AuthContext, type AuthUser, type BroadcastOptions, type Controller, type ControllerContext, DurableAgentBuilder, DurableThread, type FlowResult, type FlowState, FlowStateSdk, type FlowStateWithSdk, GitHubApiError, GitHubClient, type GitHubCommitResult, type GitHubConfig, type GitHubFileChange, type HookSignatures, type InjectMessageOptions$1 as InjectMessageOptions, type LLMResponse, type Message, type ModelDefinition, type ModelProvider, type PromptContent, type PromptDefinition, type PromptIncludePart, type PromptInput, type PromptPart, type PromptTextPart, type Provider, type ReasoningConfig, type RequestContext, type SideConfig, type StructuredPrompt, type StructuredToolReturn, type TelemetryEvent, type ThreadEndpointContext, type ThreadEnv, type ThreadInstance, type ThreadMetadata, type ThreadRegistryEntry, type Tool, type ToolArgs, type ToolArgsNode, type ToolArgsRawShape, type ToolCall, type ToolConfig, type ToolResult, type UpdateThreadParams, type User, authenticate, defineAgent, defineController, defineHook, defineModel, definePrompt, defineThreadEndpoint, defineTool, emitThreadEvent, enhanceFlowState, forceTurn, generateAgentFile, generateModelFile, generatePromptFile, getMessages, injectMessage, queueTool, reloadHistory, requireAdmin, requireAuth, updateThread };