@standardagents/spec 0.10.0-dev.ffffff

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,1914 @@
1
+ import { ZodString, ZodNumber, ZodBoolean, ZodNull, ZodLiteral, ZodEnum, ZodOptional, ZodNullable, ZodDefault, ZodArray, ZodObject, ZodRecord, ZodUnion, z } from 'zod';
2
+
3
+ /**
4
+ * Model definition types for Standard Agents.
5
+ *
6
+ * Models define LLM configurations including provider, model ID, pricing,
7
+ * and fallback chains. Models are referenced by name from prompts.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * Supported LLM provider identifiers.
13
+ *
14
+ * Each provider requires a corresponding API key environment variable:
15
+ * - `openai` → `OPENAI_API_KEY`
16
+ * - `openrouter` → `OPENROUTER_API_KEY`
17
+ * - `anthropic` → `ANTHROPIC_API_KEY`
18
+ * - `google` → `GOOGLE_API_KEY`
19
+ * - `test` → No API key required (for testing with scripted responses)
20
+ */
21
+ type ModelProvider = 'openai' | 'openrouter' | 'anthropic' | 'google' | 'test';
22
+ /**
23
+ * Model capability flags indicating supported features.
24
+ */
25
+ interface ModelCapabilities {
26
+ /**
27
+ * Whether the model supports vision (image understanding).
28
+ * When true, image attachments will be sent to the model as part of the request.
29
+ * Models like GPT-4o, Claude 3, and Gemini support vision.
30
+ */
31
+ vision?: boolean;
32
+ /**
33
+ * Whether the model supports function calling (tool use).
34
+ * Most modern models support this, defaults to true if not specified.
35
+ */
36
+ functionCalling?: boolean;
37
+ /**
38
+ * Whether the model supports structured outputs (JSON mode).
39
+ */
40
+ structuredOutputs?: boolean;
41
+ }
42
+ /**
43
+ * Model definition configuration.
44
+ *
45
+ * Defines an LLM model with its provider, pricing, capabilities, and fallback chain.
46
+ *
47
+ * @template N - The model name as a string literal type for type inference
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { defineModel } from '@standardagents/spec';
52
+ *
53
+ * export default defineModel({
54
+ * name: 'gpt-4o',
55
+ * provider: 'openai',
56
+ * model: 'gpt-4o',
57
+ * fallbacks: ['gpt-4-turbo', 'gpt-3.5-turbo'],
58
+ * inputPrice: 2.5,
59
+ * outputPrice: 10,
60
+ * });
61
+ * ```
62
+ */
63
+ interface ModelDefinition<N extends string = string> {
64
+ /**
65
+ * Unique name for this model definition.
66
+ * Used as the identifier when referencing from prompts.
67
+ * Should be descriptive and consistent (e.g., 'gpt-4o', 'claude-3-opus').
68
+ */
69
+ name: N;
70
+ /**
71
+ * The LLM provider to use for API calls.
72
+ * The corresponding API key environment variable must be set.
73
+ */
74
+ provider: ModelProvider;
75
+ /**
76
+ * The actual model identifier sent to the provider API.
77
+ *
78
+ * For OpenAI: 'gpt-4o', 'gpt-4-turbo', 'gpt-3.5-turbo', etc.
79
+ * For OpenRouter: 'openai/gpt-4o', 'anthropic/claude-3-opus', etc.
80
+ * For Anthropic: 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', etc.
81
+ * For Google: 'gemini-1.5-pro', 'gemini-1.5-flash', etc.
82
+ */
83
+ model: string;
84
+ /**
85
+ * Optional list of additional provider prefixes for OpenRouter.
86
+ * Allows routing through specific providers when using OpenRouter.
87
+ *
88
+ * @example ['anthropic', 'google'] - prefer Anthropic, fallback to Google
89
+ */
90
+ includedProviders?: string[];
91
+ /**
92
+ * Fallback model names to try if this model fails.
93
+ * Referenced by model name (must be defined in agents/models/).
94
+ * Tried in order after primary model exhausts retries.
95
+ *
96
+ * @example ['gpt-4', 'gpt-3.5-turbo']
97
+ */
98
+ fallbacks?: string[];
99
+ /**
100
+ * Cost per 1 million input tokens in USD.
101
+ * Used for cost tracking and reporting in logs.
102
+ */
103
+ inputPrice?: number;
104
+ /**
105
+ * Cost per 1 million output tokens in USD.
106
+ * Used for cost tracking and reporting in logs.
107
+ */
108
+ outputPrice?: number;
109
+ /**
110
+ * Cost per 1 million cached input tokens in USD.
111
+ * Some providers offer reduced pricing for cached/repeated prompts.
112
+ */
113
+ cachedPrice?: number;
114
+ /**
115
+ * Model capabilities - features this model supports.
116
+ */
117
+ capabilities?: ModelCapabilities;
118
+ }
119
+ /**
120
+ * Defines an LLM model configuration.
121
+ *
122
+ * Models are the foundation of the agent system - they specify which
123
+ * AI model to use and how to connect to it. Models can have fallbacks
124
+ * for reliability and include pricing for cost tracking.
125
+ *
126
+ * @template N - The model name as a string literal type
127
+ * @param options - Model configuration options
128
+ * @returns The model definition for registration
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // agents/models/gpt_4o.ts
133
+ * import { defineModel } from '@standardagents/spec';
134
+ *
135
+ * export default defineModel({
136
+ * name: 'gpt-4o',
137
+ * provider: 'openai',
138
+ * model: 'gpt-4o',
139
+ * fallbacks: ['gpt-4-turbo'],
140
+ * inputPrice: 2.5,
141
+ * outputPrice: 10,
142
+ * });
143
+ * ```
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * // Using OpenRouter with provider preferences
148
+ * export default defineModel({
149
+ * name: 'claude-3-opus',
150
+ * provider: 'openrouter',
151
+ * model: 'anthropic/claude-3-opus',
152
+ * includedProviders: ['anthropic'],
153
+ * });
154
+ * ```
155
+ */
156
+ declare function defineModel<N extends string>(options: ModelDefinition<N>): ModelDefinition<N>;
157
+
158
+ /**
159
+ * Thread state types for Standard Agents.
160
+ *
161
+ * ThreadState is the unified interface for all thread operations.
162
+ * It provides access to thread identity, messages, logs, resource loading,
163
+ * tool invocation, event emission, and execution state.
164
+ *
165
+ * @module
166
+ */
167
+
168
+ /**
169
+ * Metadata about a thread.
170
+ *
171
+ * This represents the core identity of a thread, separate from its
172
+ * operational state. Thread metadata is immutable after creation.
173
+ */
174
+ interface ThreadMetadata {
175
+ /** Unique identifier for the thread */
176
+ id: string;
177
+ /** Agent that owns this thread */
178
+ agent_id: string;
179
+ /** User associated with this thread (if any) */
180
+ user_id: string | null;
181
+ /** Creation timestamp (microseconds since epoch) */
182
+ created_at: number;
183
+ }
184
+ /**
185
+ * Options for retrieving messages.
186
+ */
187
+ interface GetMessagesOptions {
188
+ /** Maximum number of messages to return */
189
+ limit?: number;
190
+ /** Number of messages to skip */
191
+ offset?: number;
192
+ /** Sort order ('asc' for oldest first, 'desc' for newest first) */
193
+ order?: 'asc' | 'desc';
194
+ /** Include silent messages (not shown in UI) */
195
+ includeSilent?: boolean;
196
+ /** Maximum nesting depth for sub-prompt messages */
197
+ maxDepth?: number;
198
+ }
199
+ /**
200
+ * Result of a message query.
201
+ */
202
+ interface MessagesResult {
203
+ /** Array of messages */
204
+ messages: Message[];
205
+ /** Total number of messages matching the query */
206
+ total: number;
207
+ /** Whether there are more messages available */
208
+ hasMore: boolean;
209
+ }
210
+ /**
211
+ * A message in the thread conversation.
212
+ */
213
+ interface Message {
214
+ /** Unique message identifier */
215
+ id: string;
216
+ /** Message role */
217
+ role: 'system' | 'user' | 'assistant' | 'tool';
218
+ /** Message content (null for tool calls without text) */
219
+ content: string | null;
220
+ /** Tool name (for tool result messages) */
221
+ name?: string | null;
222
+ /** JSON-encoded array of tool calls (for assistant messages) */
223
+ tool_calls?: string | null;
224
+ /** Tool call ID (for tool result messages) */
225
+ tool_call_id?: string | null;
226
+ /** Creation timestamp (microseconds since epoch) */
227
+ created_at: number;
228
+ /** Parent message ID (for sub-prompt messages) */
229
+ parent_id?: string | null;
230
+ /** Nesting depth (0 for top-level messages) */
231
+ depth?: number;
232
+ /** Whether this message is silent (not shown in UI) */
233
+ silent?: boolean;
234
+ /** Custom metadata */
235
+ metadata?: Record<string, unknown>;
236
+ }
237
+ /**
238
+ * Input for injecting a new message.
239
+ */
240
+ interface InjectMessageInput {
241
+ /** Message role */
242
+ role: 'user' | 'assistant' | 'system';
243
+ /** Message content */
244
+ content: string;
245
+ /** Whether to hide from UI */
246
+ silent?: boolean;
247
+ /** Custom metadata */
248
+ metadata?: Record<string, unknown>;
249
+ }
250
+ /**
251
+ * Updates to apply to an existing message.
252
+ */
253
+ interface MessageUpdates {
254
+ /** New content */
255
+ content?: string;
256
+ /** Updated metadata (merged with existing) */
257
+ metadata?: Record<string, unknown>;
258
+ }
259
+ /**
260
+ * Options for retrieving logs.
261
+ */
262
+ interface GetLogsOptions {
263
+ /** Maximum number of logs to return */
264
+ limit?: number;
265
+ /** Number of logs to skip */
266
+ offset?: number;
267
+ /** Sort order */
268
+ order?: 'asc' | 'desc';
269
+ }
270
+ /**
271
+ * An execution log entry.
272
+ */
273
+ interface Log {
274
+ /** Unique log identifier */
275
+ id: string;
276
+ /** Log type (e.g., 'tool_call', 'llm_request', 'error') */
277
+ type: string;
278
+ /** Log data (structure varies by type) */
279
+ data: Record<string, unknown>;
280
+ /** Creation timestamp (microseconds since epoch) */
281
+ created_at: number;
282
+ /** Parent log ID (for nested operations) */
283
+ parent_id?: string | null;
284
+ }
285
+ /**
286
+ * Storage location identifier.
287
+ *
288
+ * Implementations define their own storage identifiers (e.g., 'local', 'cloud', 's3').
289
+ * The spec does not mandate specific storage backends.
290
+ */
291
+ type FileStorage = string;
292
+ /**
293
+ * Record representing a file in the thread's file system.
294
+ */
295
+ interface FileRecord {
296
+ /** File path (relative to thread root) */
297
+ path: string;
298
+ /** File name */
299
+ name: string;
300
+ /** MIME type */
301
+ mimeType: string;
302
+ /** Storage location */
303
+ storage: FileStorage;
304
+ /** File size in bytes */
305
+ size: number;
306
+ /** Whether this is a directory */
307
+ isDirectory: boolean;
308
+ /** Custom metadata */
309
+ metadata?: Record<string, unknown>;
310
+ /** Image width in pixels (if applicable) */
311
+ width?: number;
312
+ /** Image height in pixels (if applicable) */
313
+ height?: number;
314
+ /** Creation timestamp */
315
+ createdAt?: number;
316
+ /** Last modified timestamp */
317
+ updatedAt?: number;
318
+ }
319
+ /**
320
+ * Options for writing a file.
321
+ */
322
+ interface WriteFileOptions {
323
+ /** Custom metadata to attach to the file */
324
+ metadata?: Record<string, unknown>;
325
+ /** Image width in pixels (if applicable) */
326
+ width?: number;
327
+ /** Image height in pixels (if applicable) */
328
+ height?: number;
329
+ }
330
+ /**
331
+ * Result of reading a directory.
332
+ */
333
+ interface ReaddirResult {
334
+ /** Files and directories in the path */
335
+ entries: FileRecord[];
336
+ }
337
+ /**
338
+ * Statistics about the thread's file system.
339
+ */
340
+ interface FileStats {
341
+ /** Total number of files */
342
+ fileCount: number;
343
+ /** Total number of directories */
344
+ directoryCount: number;
345
+ /** Total size in bytes */
346
+ totalSize: number;
347
+ }
348
+ /**
349
+ * Result of a grep search.
350
+ */
351
+ interface GrepResult {
352
+ /** File path */
353
+ path: string;
354
+ /** Matching lines */
355
+ matches: Array<{
356
+ line: number;
357
+ content: string;
358
+ }>;
359
+ }
360
+ /**
361
+ * Result of a find operation.
362
+ */
363
+ interface FindResult {
364
+ /** Matching file paths */
365
+ paths: string[];
366
+ }
367
+ /**
368
+ * Options for streaming file reads.
369
+ */
370
+ interface ReadFileStreamOptions {
371
+ /**
372
+ * Abort signal for cancellation.
373
+ *
374
+ * When signaled, the stream stops yielding new chunks.
375
+ * Already-yielded chunks remain valid.
376
+ */
377
+ signal?: AbortSignal;
378
+ }
379
+ /**
380
+ * A chunk of file data from a streaming read.
381
+ */
382
+ interface FileChunk {
383
+ /** Raw binary data for this chunk */
384
+ data: Uint8Array;
385
+ /** 0-based index of this chunk */
386
+ index: number;
387
+ /** Total number of chunks (1 for small files) */
388
+ totalChunks: number;
389
+ /** Whether this is the final chunk */
390
+ isLast: boolean;
391
+ }
392
+ /**
393
+ * Execution-specific state available during agent execution.
394
+ *
395
+ * This is present when a thread is actively executing (during tool calls,
396
+ * hook invocations, etc.) and null when accessing a thread at rest
397
+ * (from endpoints, external code, etc.).
398
+ */
399
+ interface ExecutionState {
400
+ /** Current flow ID (unique per execution) */
401
+ readonly flowId: string;
402
+ /** Current side in dual_ai agents ('a' or 'b') */
403
+ readonly currentSide: 'a' | 'b';
404
+ /** Total steps executed in this flow */
405
+ readonly stepCount: number;
406
+ /** Steps executed by side A */
407
+ readonly sideAStepCount: number;
408
+ /** Steps executed by side B */
409
+ readonly sideBStepCount: number;
410
+ /** Whether execution has been stopped */
411
+ readonly stopped: boolean;
412
+ /** Which side initiated the stop (if stopped) */
413
+ readonly stoppedBy?: 'a' | 'b';
414
+ /** Message history loaded for current execution */
415
+ readonly messageHistory: Message[];
416
+ /**
417
+ * Force a specific side to play the next turn.
418
+ *
419
+ * Only valid for dual_ai agents. Has no effect on ai_human agents.
420
+ *
421
+ * @param side - The side to force ('a' or 'b')
422
+ */
423
+ forceTurn(side: 'a' | 'b'): void;
424
+ /**
425
+ * Stop the current execution.
426
+ *
427
+ * Signals the execution loop to terminate after the current operation
428
+ * completes. Does not abort in-progress LLM calls.
429
+ */
430
+ stop(): void;
431
+ /**
432
+ * Abort signal for cancellation.
433
+ *
434
+ * Can be used to abort fetch requests or other async operations
435
+ * when the execution is cancelled.
436
+ */
437
+ readonly abortSignal: AbortSignal;
438
+ }
439
+ /**
440
+ * The unified interface for all thread operations.
441
+ *
442
+ * ThreadState provides a consistent API for interacting with threads
443
+ * regardless of context - whether from tools during execution, hooks,
444
+ * or HTTP endpoints. The same interface is used throughout, with
445
+ * execution-specific state available when applicable.
446
+ *
447
+ * @example
448
+ * ```typescript
449
+ * // In a tool
450
+ * export default defineTool(
451
+ * 'Send a greeting',
452
+ * z.object({ name: z.string() }),
453
+ * async (state, args) => {
454
+ * // Access thread identity
455
+ * console.log(`Thread: ${state.threadId}`);
456
+ *
457
+ * // Check execution state
458
+ * if (state.execution?.stepCount > 10) {
459
+ * state.execution.stop();
460
+ * }
461
+ *
462
+ * // Emit custom event
463
+ * state.emit('greeting', { name: args.name });
464
+ *
465
+ * return { status: 'success', result: `Hello, ${args.name}!` };
466
+ * }
467
+ * );
468
+ * ```
469
+ *
470
+ * @example
471
+ * ```typescript
472
+ * // In an endpoint
473
+ * export default defineThreadEndpoint(async (req, state) => {
474
+ * // state.execution is null (not executing)
475
+ * const { messages } = await state.getMessages({ limit: 50 });
476
+ * return Response.json({ messages });
477
+ * });
478
+ * ```
479
+ */
480
+ interface ThreadState {
481
+ /** Unique thread identifier */
482
+ readonly threadId: string;
483
+ /** Agent that owns this thread */
484
+ readonly agentId: string;
485
+ /** User associated with this thread (if any) */
486
+ readonly userId: string | null;
487
+ /** Thread creation timestamp (microseconds since epoch) */
488
+ readonly createdAt: number;
489
+ /**
490
+ * Get messages from the thread.
491
+ *
492
+ * @param options - Query options (limit, offset, order, etc.)
493
+ * @returns Messages and pagination info
494
+ */
495
+ getMessages(options?: GetMessagesOptions): Promise<MessagesResult>;
496
+ /**
497
+ * Get a single message by ID.
498
+ *
499
+ * @param messageId - The message ID
500
+ * @returns The message, or null if not found
501
+ */
502
+ getMessage(messageId: string): Promise<Message | null>;
503
+ /**
504
+ * Inject a message into the thread.
505
+ *
506
+ * Creates a new message in the conversation history. This can be used
507
+ * to add context, simulate user input, or insert assistant responses.
508
+ *
509
+ * @param message - The message to inject
510
+ * @returns The created message
511
+ */
512
+ injectMessage(message: InjectMessageInput): Promise<Message>;
513
+ /**
514
+ * Update an existing message.
515
+ *
516
+ * @param messageId - The message ID
517
+ * @param updates - The updates to apply
518
+ * @returns The updated message
519
+ */
520
+ updateMessage(messageId: string, updates: MessageUpdates): Promise<Message>;
521
+ /**
522
+ * Get execution logs.
523
+ *
524
+ * @param options - Query options
525
+ * @returns Array of log entries
526
+ */
527
+ getLogs(options?: GetLogsOptions): Promise<Log[]>;
528
+ /**
529
+ * Load a model definition by name.
530
+ *
531
+ * @param name - The model name
532
+ * @returns The model definition
533
+ * @throws If the model is not found
534
+ */
535
+ loadModel<T = unknown>(name: string): Promise<T>;
536
+ /**
537
+ * Load a prompt definition by name.
538
+ *
539
+ * @param name - The prompt name
540
+ * @returns The prompt definition
541
+ * @throws If the prompt is not found
542
+ */
543
+ loadPrompt<T = unknown>(name: string): Promise<T>;
544
+ /**
545
+ * Load an agent definition by name.
546
+ *
547
+ * @param name - The agent name
548
+ * @returns The agent definition
549
+ * @throws If the agent is not found
550
+ */
551
+ loadAgent<T = unknown>(name: string): Promise<T>;
552
+ /**
553
+ * Get available prompt names.
554
+ *
555
+ * @returns Array of prompt names that can be loaded
556
+ */
557
+ getPromptNames(): string[];
558
+ /**
559
+ * Get available agent names.
560
+ *
561
+ * @returns Array of agent names that can be loaded
562
+ */
563
+ getAgentNames(): string[];
564
+ /**
565
+ * Get available model names.
566
+ *
567
+ * @returns Array of model names that can be loaded
568
+ */
569
+ getModelNames(): string[];
570
+ /**
571
+ * Queue a tool for execution.
572
+ *
573
+ * If the thread is currently executing, the tool is added to the
574
+ * execution queue. If not, this starts a new execution with the
575
+ * tool call.
576
+ *
577
+ * @param toolName - Name of the tool to invoke
578
+ * @param args - Arguments to pass to the tool
579
+ */
580
+ queueTool(toolName: string, args: Record<string, unknown>): void;
581
+ /**
582
+ * Invoke a tool directly and wait for the result.
583
+ *
584
+ * If the thread is not currently executing, this creates a minimal
585
+ * execution context for the tool. Unlike queueTool, this blocks
586
+ * until the tool completes.
587
+ *
588
+ * @param toolName - Name of the tool to invoke
589
+ * @param args - Arguments to pass to the tool
590
+ * @returns The tool result
591
+ */
592
+ invokeTool(toolName: string, args: Record<string, unknown>): Promise<ToolResult>;
593
+ /**
594
+ * Emit a custom event to connected clients.
595
+ *
596
+ * Events are sent via WebSocket to any connected clients. Use this
597
+ * for real-time updates, progress notifications, or custom data.
598
+ *
599
+ * @param event - Event name
600
+ * @param data - Event data (must be JSON-serializable)
601
+ */
602
+ emit(event: string, data: unknown): void;
603
+ /**
604
+ * Key-value storage for custom data scoped to this thread.
605
+ *
606
+ * Context data persists across tool calls within a single execution.
607
+ * For persistent storage across executions, use messages or external
608
+ * storage.
609
+ */
610
+ context: Record<string, unknown>;
611
+ /**
612
+ * Write a file to the thread's file system.
613
+ *
614
+ * Large files (>1.75MB) are automatically chunked for storage.
615
+ *
616
+ * @param path - File path (relative to thread root)
617
+ * @param data - File content as ArrayBuffer or string
618
+ * @param mimeType - MIME type of the file
619
+ * @param options - Optional metadata and dimensions
620
+ * @returns The created file record
621
+ */
622
+ writeFile(path: string, data: ArrayBuffer | string, mimeType: string, options?: WriteFileOptions): Promise<FileRecord>;
623
+ /**
624
+ * Read a file from the thread's file system.
625
+ *
626
+ * @param path - File path
627
+ * @returns File content as ArrayBuffer, or null if not found
628
+ */
629
+ readFile(path: string): Promise<ArrayBuffer | null>;
630
+ /**
631
+ * Stream a file from the thread's file system in chunks.
632
+ *
633
+ * For large files (>1.75MB), this yields one chunk at a time, enabling
634
+ * memory-efficient access without loading the entire file. Small files
635
+ * are yielded as a single chunk.
636
+ *
637
+ * Returns null if the file is not found or stored externally (S3, R2, URL).
638
+ *
639
+ * @param path - File path
640
+ * @param options - Optional streaming options (abort signal)
641
+ * @returns Async iterable of file chunks, or null if not found/external
642
+ *
643
+ * @example
644
+ * ```typescript
645
+ * const stream = await state.readFileStream('/uploads/video.mp4');
646
+ * if (stream) {
647
+ * for await (const chunk of stream) {
648
+ * console.log(`Chunk ${chunk.index + 1}/${chunk.totalChunks}`);
649
+ * // Process chunk.data (Uint8Array)
650
+ * }
651
+ * }
652
+ * ```
653
+ */
654
+ readFileStream(path: string, options?: ReadFileStreamOptions): Promise<AsyncIterable<FileChunk> | null>;
655
+ /**
656
+ * Get metadata about a file.
657
+ *
658
+ * @param path - File path
659
+ * @returns File record, or null if not found
660
+ */
661
+ statFile(path: string): Promise<FileRecord | null>;
662
+ /**
663
+ * List contents of a directory.
664
+ *
665
+ * @param path - Directory path
666
+ * @returns Directory entries
667
+ */
668
+ readdirFile(path: string): Promise<ReaddirResult>;
669
+ /**
670
+ * Delete a file.
671
+ *
672
+ * @param path - File path
673
+ */
674
+ unlinkFile(path: string): Promise<void>;
675
+ /**
676
+ * Create a directory.
677
+ *
678
+ * @param path - Directory path
679
+ * @returns The created directory record
680
+ */
681
+ mkdirFile(path: string): Promise<FileRecord>;
682
+ /**
683
+ * Remove a directory.
684
+ *
685
+ * @param path - Directory path (must be empty)
686
+ */
687
+ rmdirFile(path: string): Promise<void>;
688
+ /**
689
+ * Get overall file system statistics.
690
+ *
691
+ * @returns File count, directory count, and total size
692
+ */
693
+ getFileStats(): Promise<FileStats>;
694
+ /**
695
+ * Search file contents for a pattern.
696
+ *
697
+ * @param pattern - Search pattern (regular expression)
698
+ * @returns Matching files and lines
699
+ */
700
+ grepFiles(pattern: string): Promise<GrepResult[]>;
701
+ /**
702
+ * Find files matching a glob pattern.
703
+ *
704
+ * @param pattern - Glob pattern (e.g., "*.txt", "**\/*.json")
705
+ * @returns Matching file paths
706
+ */
707
+ findFiles(pattern: string): Promise<FindResult>;
708
+ /**
709
+ * Get a thumbnail for an image file.
710
+ *
711
+ * @param path - Path to the image file
712
+ * @returns Thumbnail data as ArrayBuffer, or null if not available
713
+ */
714
+ getFileThumbnail(path: string): Promise<ArrayBuffer | null>;
715
+ /**
716
+ * Execution-specific state.
717
+ *
718
+ * This is present when the thread is actively executing (tools, hooks)
719
+ * and null when accessing a thread at rest (endpoints, external code).
720
+ *
721
+ * Use this to access step counts, force turns, or stop execution.
722
+ */
723
+ execution: ExecutionState | null;
724
+ }
725
+
726
+ /**
727
+ * Tool definition types for Standard Agents.
728
+ *
729
+ * Tools are callable functions that agents can invoke during execution.
730
+ * They receive the current ThreadState and validated arguments,
731
+ * and return results that are included in the conversation.
732
+ *
733
+ * @module
734
+ */
735
+
736
+ /**
737
+ * Text content item returned by tools.
738
+ */
739
+ interface TextContent {
740
+ type: 'text';
741
+ text: string;
742
+ }
743
+ /**
744
+ * Image content item returned by tools.
745
+ */
746
+ interface ImageContent {
747
+ type: 'image';
748
+ /** Base64-encoded image data. */
749
+ data: string;
750
+ /** MIME type of the image (e.g., 'image/png', 'image/jpeg'). */
751
+ mimeType: string;
752
+ }
753
+ /**
754
+ * Content types that can be returned by tools.
755
+ */
756
+ type ToolContent = TextContent | ImageContent;
757
+ /**
758
+ * File attachment generated by a tool.
759
+ *
760
+ * Attachments are stored in the thread's file system and linked to
761
+ * the tool result message. Unlike user uploads, tool attachments are
762
+ * not subject to image downsampling.
763
+ */
764
+ interface ToolAttachment {
765
+ /** File name for the attachment. */
766
+ name: string;
767
+ /** MIME type of the attachment. */
768
+ mimeType: string;
769
+ /** Base64-encoded file data. */
770
+ data: string;
771
+ /** Width in pixels (for images). */
772
+ width?: number;
773
+ /** Height in pixels (for images). */
774
+ height?: number;
775
+ }
776
+ /**
777
+ * Reference to a pre-existing attachment in the thread file system.
778
+ */
779
+ interface AttachmentRef {
780
+ /** Unique identifier for the attachment. */
781
+ id: string;
782
+ /** Attachment type. */
783
+ type: 'file';
784
+ /** Path in the thread file system. */
785
+ path: string;
786
+ /** File name. */
787
+ name: string;
788
+ /** MIME type. */
789
+ mimeType: string;
790
+ /** File size in bytes. */
791
+ size: number;
792
+ /** Width in pixels (for images). */
793
+ width?: number;
794
+ /** Height in pixels (for images). */
795
+ height?: number;
796
+ /** AI-generated description. */
797
+ description?: string;
798
+ }
799
+ /**
800
+ * Result returned by a tool execution.
801
+ */
802
+ interface ToolResult {
803
+ /** Status of the tool execution. */
804
+ status: 'success' | 'error';
805
+ /**
806
+ * Text representation of the tool output.
807
+ *
808
+ * For tools that return structured content, this is derived by
809
+ * concatenating all text parts. For simple tools, this is the
810
+ * direct result string.
811
+ */
812
+ result?: string;
813
+ /** Error message if status is 'error'. */
814
+ error?: string;
815
+ /** Stack trace for error debugging. */
816
+ stack?: string;
817
+ /**
818
+ * File attachments returned by the tool.
819
+ *
820
+ * Can contain either:
821
+ * - ToolAttachment: New files with base64 data to be stored
822
+ * - AttachmentRef: References to existing files in the thread filesystem
823
+ *
824
+ * Implementations MUST store new attachments under /attachments/ directory.
825
+ */
826
+ attachments?: Array<ToolAttachment | AttachmentRef>;
827
+ }
828
+ /** Decrement helper to limit recursion depth. */
829
+ 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;
830
+ /**
831
+ * Allowed Zod types for tool argument nodes.
832
+ *
833
+ * This is the single source of truth for which Zod types can be used
834
+ * in tool argument schemas. The depth parameter limits recursion to
835
+ * prevent infinite type expansion.
836
+ *
837
+ * @template D - Maximum nesting depth (default: 7)
838
+ */
839
+ type ToolArgsNode<D extends number = 7> = ZodString | ZodNumber | ZodBoolean | ZodNull | ZodLiteral<string | number | boolean | null> | ZodEnum<Readonly<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<[
840
+ ToolArgsNode<Dec<D>>,
841
+ ToolArgsNode<Dec<D>>,
842
+ ...ToolArgsNode<Dec<D>>[]
843
+ ]>);
844
+ /**
845
+ * Raw shape for a Zod object schema containing tool argument nodes.
846
+ *
847
+ * @template D - Maximum nesting depth (default: 7)
848
+ */
849
+ type ToolArgsRawShape<D extends number = 7> = Record<string, ToolArgsNode<D>>;
850
+ /**
851
+ * Top-level tool argument schema.
852
+ *
853
+ * Tool arguments MUST be defined as a Zod object schema.
854
+ * This is required for compatibility with OpenAI's function calling API.
855
+ *
856
+ * @template D - Maximum nesting depth (default: 7)
857
+ */
858
+ type ToolArgs<D extends number = 7> = z.ZodObject<ToolArgsRawShape<D>>;
859
+ /**
860
+ * Tool function signature.
861
+ *
862
+ * Tools are async functions that receive a ThreadState and
863
+ * optionally validated arguments, returning a ToolResult.
864
+ *
865
+ * @template State - The state type (defaults to ThreadState)
866
+ * @template Args - The Zod schema for tool arguments, or null for no args
867
+ */
868
+ type Tool<State = ThreadState, Args extends ToolArgs | null = null> = Args extends ToolArgs ? (state: State, args: z.infer<Args>) => Promise<ToolResult> : (state: State) => Promise<ToolResult>;
869
+ /**
870
+ * Return type of defineTool function.
871
+ *
872
+ * A tuple containing:
873
+ * - Tool description string
874
+ * - Argument schema (or null)
875
+ * - Tool implementation function
876
+ */
877
+ type ToolDefinition<State = ThreadState, Args extends ToolArgs | null = null> = [string, Args, Tool<State, Args>];
878
+ /**
879
+ * Define a tool with arguments.
880
+ *
881
+ * @param toolDescription - Description of what the tool does (shown to the LLM)
882
+ * @param args - Zod schema for validating tool arguments
883
+ * @param tool - The tool implementation function
884
+ * @returns A tuple containing the tool definition
885
+ */
886
+ declare function defineTool<State = ThreadState, Args extends ToolArgs = ToolArgs>(toolDescription: string, args: Args, tool: Tool<State, Args>): ToolDefinition<State, Args>;
887
+ /**
888
+ * Define a tool without arguments.
889
+ *
890
+ * @param toolDescription - Description of what the tool does (shown to the LLM)
891
+ * @param tool - The tool implementation function
892
+ * @returns A tuple containing the tool definition
893
+ */
894
+ declare function defineTool<State = ThreadState>(toolDescription: string, tool: Tool<State, null>): ToolDefinition<State, null>;
895
+
896
+ /**
897
+ * Prompt definition types for Standard Agents.
898
+ *
899
+ * Prompts define LLM interaction configurations including the system prompt,
900
+ * model selection, available tools, and various behavioral options.
901
+ *
902
+ * @module
903
+ */
904
+
905
+ /**
906
+ * A text part of a prompt - static text content.
907
+ *
908
+ * @example
909
+ * ```typescript
910
+ * { type: 'text', content: 'You are a helpful assistant.\n\n' }
911
+ * ```
912
+ */
913
+ interface PromptTextPart {
914
+ type: 'text';
915
+ /** The text content */
916
+ content: string;
917
+ }
918
+ /**
919
+ * A prompt inclusion part - includes another prompt's content.
920
+ *
921
+ * @example
922
+ * ```typescript
923
+ * { type: 'include', prompt: 'responder_rules' }
924
+ * ```
925
+ */
926
+ interface PromptIncludePart {
927
+ type: 'include';
928
+ /** The name of the prompt to include */
929
+ prompt: string;
930
+ }
931
+ /**
932
+ * A single part of a structured prompt.
933
+ * Discriminated union on `type` field for TypeScript narrowing.
934
+ */
935
+ type PromptPart = PromptTextPart | PromptIncludePart;
936
+ /**
937
+ * A structured prompt is an array of prompt parts.
938
+ * Provides composition with other prompts via includes.
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * prompt: [
943
+ * { type: 'text', content: 'You are a helpful assistant.\n\n' },
944
+ * { type: 'include', prompt: 'common_rules' },
945
+ * { type: 'text', content: '\n\nBe concise.' },
946
+ * ]
947
+ * ```
948
+ */
949
+ type StructuredPrompt = PromptPart[];
950
+ /**
951
+ * The prompt content can be either a plain string or a structured array.
952
+ *
953
+ * @example
954
+ * ```typescript
955
+ * // Simple string prompt:
956
+ * prompt: 'You are a helpful assistant.'
957
+ *
958
+ * // Structured prompt with includes:
959
+ * prompt: [
960
+ * { type: 'text', content: 'You are a helpful assistant.\n\n' },
961
+ * { type: 'include', prompt: 'common_rules' },
962
+ * ]
963
+ * ```
964
+ */
965
+ type PromptContent = string | StructuredPrompt;
966
+ /**
967
+ * Configuration for sub-prompts used as tools.
968
+ * These options control how results from sub-prompts are returned to the caller.
969
+ *
970
+ * @template T - The sub-prompt name type (for type-safe references)
971
+ */
972
+ interface SubpromptConfig<T extends string = string> {
973
+ /**
974
+ * Name of the sub-prompt to call.
975
+ * Must be a prompt defined in agents/prompts/.
976
+ */
977
+ name: T;
978
+ /**
979
+ * Include text response content from sub-prompt execution in the result string.
980
+ * @default true
981
+ */
982
+ includeTextResponse?: boolean;
983
+ /**
984
+ * Serialize tool calls made by the sub-prompt (and their results) into the result string.
985
+ * @default true
986
+ */
987
+ includeToolCalls?: boolean;
988
+ /**
989
+ * Serialize any errors from the sub-prompt into the result string.
990
+ * @default true
991
+ */
992
+ includeErrors?: boolean;
993
+ /**
994
+ * Property from the tool call arguments to use as the initial user message
995
+ * when invoking the sub-prompt.
996
+ *
997
+ * @example
998
+ * If the tool is called with `{ query: "search term", limit: 10 }` and
999
+ * `initUserMessageProperty: 'query'`, the sub-prompt will receive
1000
+ * "search term" as the initial user message.
1001
+ */
1002
+ initUserMessageProperty?: string;
1003
+ }
1004
+ /**
1005
+ * @deprecated Use SubpromptConfig instead
1006
+ */
1007
+ type ToolConfig<T extends string = string> = SubpromptConfig<T>;
1008
+ /**
1009
+ * Reasoning configuration for models that support extended thinking.
1010
+ * Applies to models like OpenAI o1, Anthropic Claude with extended thinking,
1011
+ * Google Gemini with thinking, and Qwen with reasoning.
1012
+ */
1013
+ interface ReasoningConfig {
1014
+ /**
1015
+ * Effort level for reasoning models.
1016
+ * Higher effort = more thinking tokens = potentially better results.
1017
+ *
1018
+ * - `low`: Minimal reasoning, faster responses
1019
+ * - `medium`: Balanced reasoning and speed
1020
+ * - `high`: Maximum reasoning, slower but more thorough
1021
+ *
1022
+ * @default undefined (use model defaults)
1023
+ */
1024
+ effort?: 'low' | 'medium' | 'high';
1025
+ /**
1026
+ * Maximum tokens to allocate for reasoning.
1027
+ * Applies to models that support token limits on reasoning.
1028
+ */
1029
+ maxTokens?: number;
1030
+ /**
1031
+ * Use reasoning internally but exclude from the response.
1032
+ * Model thinks through the problem but only returns the final answer.
1033
+ * Useful for cleaner outputs while maintaining reasoning quality.
1034
+ */
1035
+ exclude?: boolean;
1036
+ /**
1037
+ * Include reasoning content in the message history for multi-turn context.
1038
+ * When true, reasoning is preserved and visible to subsequent turns.
1039
+ * @default false
1040
+ */
1041
+ include?: boolean;
1042
+ }
1043
+ /**
1044
+ * Prompt definition configuration.
1045
+ *
1046
+ * @template N - The prompt name as a string literal type
1047
+ * @template S - The Zod schema type for requiredSchema (inferred automatically)
1048
+ *
1049
+ * @example
1050
+ * ```typescript
1051
+ * import { definePrompt } from '@standardagents/spec';
1052
+ * import { z } from 'zod';
1053
+ *
1054
+ * export default definePrompt({
1055
+ * name: 'customer_support',
1056
+ * toolDescription: 'Handle customer support inquiries',
1057
+ * model: 'gpt-4o',
1058
+ * prompt: 'You are a helpful customer support agent.',
1059
+ * tools: ['search_knowledge_base', 'create_ticket'],
1060
+ * requiredSchema: z.object({
1061
+ * query: z.string().describe('The customer inquiry'),
1062
+ * }),
1063
+ * });
1064
+ * ```
1065
+ */
1066
+ interface PromptDefinition<N extends string = string, S extends ToolArgs = ToolArgs> {
1067
+ /**
1068
+ * Unique name for this prompt.
1069
+ * Used as the identifier when referencing from agents or as a tool.
1070
+ * Should be snake_case (e.g., 'customer_support', 'data_analyst').
1071
+ */
1072
+ name: N;
1073
+ /**
1074
+ * Description shown when this prompt is exposed as a tool.
1075
+ * Should clearly describe what this prompt does for LLM tool selection.
1076
+ */
1077
+ toolDescription: string;
1078
+ /**
1079
+ * The system prompt content sent to the LLM.
1080
+ * Can be either a plain string or a structured array for composition.
1081
+ */
1082
+ prompt: PromptContent;
1083
+ /**
1084
+ * Model to use for this prompt.
1085
+ * Must reference a model defined in agents/models/.
1086
+ */
1087
+ model: string;
1088
+ /**
1089
+ * Include full chat history in the LLM context.
1090
+ * @default false
1091
+ */
1092
+ includeChat?: boolean;
1093
+ /**
1094
+ * Include results from past tool calls in the LLM context.
1095
+ * @default false
1096
+ */
1097
+ includePastTools?: boolean;
1098
+ /**
1099
+ * Allow parallel execution of multiple tool calls.
1100
+ * @default false
1101
+ */
1102
+ parallelToolCalls?: boolean;
1103
+ /**
1104
+ * Tool calling strategy for the LLM.
1105
+ *
1106
+ * - `auto`: Model decides when to call tools (default)
1107
+ * - `none`: Disable tool calling entirely
1108
+ * - `required`: Force the model to call at least one tool
1109
+ *
1110
+ * @default 'auto'
1111
+ */
1112
+ toolChoice?: 'auto' | 'none' | 'required';
1113
+ /**
1114
+ * Zod schema for validating inputs when this prompt is called as a tool.
1115
+ */
1116
+ requiredSchema?: S;
1117
+ /**
1118
+ * Tools available to this prompt.
1119
+ * Can be simple tool names or sub-prompt configurations.
1120
+ * To enable handoffs, include ai_human agent names in this array.
1121
+ */
1122
+ tools?: (string | SubpromptConfig)[];
1123
+ /**
1124
+ * Reasoning configuration for models that support extended thinking.
1125
+ */
1126
+ reasoning?: ReasoningConfig;
1127
+ /**
1128
+ * Number of recent messages to keep actual images for in context.
1129
+ * @default 10
1130
+ */
1131
+ recentImageThreshold?: number;
1132
+ }
1133
+ /**
1134
+ * Helper type to extract the inferred input type from a prompt's Zod schema.
1135
+ *
1136
+ * @template T - The prompt definition type
1137
+ */
1138
+ type PromptInput<T extends PromptDefinition<string, ToolArgs>> = T['requiredSchema'] extends ToolArgs ? z.infer<T['requiredSchema']> : never;
1139
+ /**
1140
+ * Defines a prompt configuration for LLM interactions.
1141
+ *
1142
+ * Prompts are the primary way to configure how agents interact with LLMs.
1143
+ * They specify the system prompt, available tools, input validation,
1144
+ * and various behavioral options.
1145
+ *
1146
+ * @template N - The prompt name as a string literal type
1147
+ * @template S - The Zod schema type for requiredSchema
1148
+ * @param options - Prompt configuration options
1149
+ * @returns The prompt definition for registration
1150
+ *
1151
+ * @example
1152
+ * ```typescript
1153
+ * import { definePrompt } from '@standardagents/spec';
1154
+ * import { z } from 'zod';
1155
+ *
1156
+ * export default definePrompt({
1157
+ * name: 'customer_support',
1158
+ * toolDescription: 'Handle customer support inquiries',
1159
+ * model: 'gpt-4o',
1160
+ * prompt: 'You are a helpful customer support agent.',
1161
+ * tools: ['search_knowledge_base', 'create_ticket'],
1162
+ * includeChat: true,
1163
+ * requiredSchema: z.object({
1164
+ * query: z.string().describe('The customer inquiry'),
1165
+ * }),
1166
+ * });
1167
+ * ```
1168
+ */
1169
+ declare function definePrompt<N extends string, S extends ToolArgs = never>(options: PromptDefinition<N, S>): PromptDefinition<N, S>;
1170
+
1171
+ /**
1172
+ * Hook definition types for Standard Agents.
1173
+ *
1174
+ * Hooks allow intercepting and modifying agent behavior at key points
1175
+ * in the execution lifecycle. They enable logging, validation,
1176
+ * transformation, and side effects.
1177
+ *
1178
+ * Hooks receive ThreadState as their first parameter, providing full
1179
+ * access to thread operations and execution state.
1180
+ *
1181
+ * @module
1182
+ */
1183
+
1184
+ /**
1185
+ * Hook context is ThreadState.
1186
+ *
1187
+ * Hooks receive the full ThreadState, which includes identity, message access,
1188
+ * resource loading, event emission, and execution state (when available).
1189
+ *
1190
+ * @example
1191
+ * ```typescript
1192
+ * const hook = defineHook('filter_messages', async (state, messages) => {
1193
+ * console.log(`Thread: ${state.threadId}`);
1194
+ * if (state.execution) {
1195
+ * console.log(`Turn: ${state.execution.turnCount}`);
1196
+ * }
1197
+ * return messages.slice(-10);
1198
+ * });
1199
+ * ```
1200
+ */
1201
+ type HookContext = ThreadState;
1202
+ /**
1203
+ * Message structure for hook processing.
1204
+ *
1205
+ * Re-exported from threads.ts for convenience.
1206
+ * @see Message
1207
+ */
1208
+ type HookMessage = Message;
1209
+ /**
1210
+ * Tool call structure for hook processing.
1211
+ */
1212
+ interface HookToolCall {
1213
+ /** Unique tool call identifier */
1214
+ id: string;
1215
+ /** Always 'function' for tool calls */
1216
+ type: 'function';
1217
+ /** Function details */
1218
+ function: {
1219
+ /** Tool name */
1220
+ name: string;
1221
+ /** JSON-encoded arguments */
1222
+ arguments: string;
1223
+ };
1224
+ }
1225
+ /**
1226
+ * Tool result structure for hook processing.
1227
+ */
1228
+ interface HookToolResult {
1229
+ /** Execution status */
1230
+ status: 'success' | 'error';
1231
+ /** Result string (for successful executions) */
1232
+ result?: string;
1233
+ /** Error message (for failed executions) */
1234
+ error?: string;
1235
+ /** Stack trace (for debugging) */
1236
+ stack?: string;
1237
+ }
1238
+ /**
1239
+ * LLM message format for prefilter hook.
1240
+ */
1241
+ interface LLMMessage {
1242
+ /** Message role */
1243
+ role: string;
1244
+ /** Message content */
1245
+ content: string | null;
1246
+ /** Tool calls (parsed) */
1247
+ tool_calls?: unknown;
1248
+ /** Tool call ID */
1249
+ tool_call_id?: string;
1250
+ /** Tool name */
1251
+ name?: string;
1252
+ }
1253
+ /**
1254
+ * Hook signatures for all available hooks.
1255
+ *
1256
+ * Each hook has a specific signature that defines when it's called
1257
+ * and what data it receives. Hooks can modify data by returning
1258
+ * transformed values or perform side effects.
1259
+ *
1260
+ * All hooks receive ThreadState as their first parameter.
1261
+ *
1262
+ * @template State - The state type (defaults to ThreadState)
1263
+ * @template Msg - The message type (defaults to HookMessage)
1264
+ * @template ToolCall - The tool call type (defaults to HookToolCall)
1265
+ * @template ToolResult - The tool result type (defaults to HookToolResult)
1266
+ */
1267
+ interface HookSignatures<State = ThreadState, Msg = HookMessage, ToolCall = HookToolCall, ToolResult = HookToolResult> {
1268
+ /**
1269
+ * Called before messages are filtered and sent to the LLM.
1270
+ *
1271
+ * Receives raw message rows from storage before any transformation.
1272
+ * Use for filtering, sorting, or augmenting message history.
1273
+ *
1274
+ * @param state - Thread state
1275
+ * @param messages - Array of messages from storage
1276
+ * @returns Modified message array
1277
+ *
1278
+ * @example
1279
+ * ```typescript
1280
+ * defineHook('filter_messages', async (state, messages) => {
1281
+ * // Only include messages from last 10 turns
1282
+ * return messages.slice(-10);
1283
+ * });
1284
+ * ```
1285
+ */
1286
+ filter_messages: (state: State, messages: Msg[]) => Promise<Msg[]>;
1287
+ /**
1288
+ * Called after message history is loaded and before sending to LLM.
1289
+ *
1290
+ * Receives messages already transformed into chat completion format.
1291
+ * Use for final adjustments before LLM request.
1292
+ *
1293
+ * @param state - Thread state
1294
+ * @param messages - Array of LLM-formatted messages
1295
+ * @returns Modified LLM message array
1296
+ *
1297
+ * @example
1298
+ * ```typescript
1299
+ * defineHook('prefilter_llm_history', async (state, messages) => {
1300
+ * // Add a reminder to the last user message
1301
+ * return messages;
1302
+ * });
1303
+ * ```
1304
+ */
1305
+ prefilter_llm_history: (state: State, messages: LLMMessage[]) => Promise<LLMMessage[]>;
1306
+ /**
1307
+ * Called before a message is created in the database.
1308
+ *
1309
+ * Receives the message data before insertion. Return modified data
1310
+ * to transform the message before storage.
1311
+ *
1312
+ * @param state - Thread state
1313
+ * @param message - Message data to be created
1314
+ * @returns Modified message data
1315
+ *
1316
+ * @example
1317
+ * ```typescript
1318
+ * defineHook('before_create_message', async (state, message) => {
1319
+ * // Add metadata to all messages
1320
+ * return { ...message, metadata: { processed: true } };
1321
+ * });
1322
+ * ```
1323
+ */
1324
+ before_create_message: (state: State, message: Record<string, unknown>) => Promise<Record<string, unknown>>;
1325
+ /**
1326
+ * Called after a message is created in the database.
1327
+ *
1328
+ * Use for logging, analytics, or triggering side effects after
1329
+ * message creation. Cannot modify the message.
1330
+ *
1331
+ * @param state - Thread state
1332
+ * @param message - The created message data
1333
+ *
1334
+ * @example
1335
+ * ```typescript
1336
+ * defineHook('after_create_message', async (state, message) => {
1337
+ * console.log(`Message created: ${message.id}`);
1338
+ * });
1339
+ * ```
1340
+ */
1341
+ after_create_message: (state: State, message: Record<string, unknown>) => Promise<void>;
1342
+ /**
1343
+ * Called before a message is updated in the database.
1344
+ *
1345
+ * Receives the message ID and update data. Return modified updates
1346
+ * to transform the changes before storage.
1347
+ *
1348
+ * @param state - Thread state
1349
+ * @param messageId - ID of message being updated
1350
+ * @param updates - Update data
1351
+ * @returns Modified update data
1352
+ *
1353
+ * @example
1354
+ * ```typescript
1355
+ * defineHook('before_update_message', async (state, messageId, updates) => {
1356
+ * return { ...updates, updated_at: Date.now() };
1357
+ * });
1358
+ * ```
1359
+ */
1360
+ before_update_message: (state: State, messageId: string, updates: Record<string, unknown>) => Promise<Record<string, unknown>>;
1361
+ /**
1362
+ * Called after a message is updated in the database.
1363
+ *
1364
+ * Use for logging, analytics, or triggering side effects after
1365
+ * message update. Cannot modify the message.
1366
+ *
1367
+ * @param state - Thread state
1368
+ * @param message - The updated message
1369
+ *
1370
+ * @example
1371
+ * ```typescript
1372
+ * defineHook('after_update_message', async (state, message) => {
1373
+ * console.log(`Message updated: ${message.id}`);
1374
+ * });
1375
+ * ```
1376
+ */
1377
+ after_update_message: (state: State, message: Msg) => Promise<void>;
1378
+ /**
1379
+ * Called before a tool result is stored in the database.
1380
+ *
1381
+ * Receives the tool call and result before storage. Return modified
1382
+ * result to transform before storage.
1383
+ *
1384
+ * @param state - Thread state
1385
+ * @param toolCall - The tool call that was executed
1386
+ * @param toolResult - The result from tool execution
1387
+ * @returns Modified tool result data
1388
+ *
1389
+ * @example
1390
+ * ```typescript
1391
+ * defineHook('before_store_tool_result', async (state, toolCall, toolResult) => {
1392
+ * // Sanitize sensitive data from results
1393
+ * return { ...toolResult, result: sanitize(toolResult.result) };
1394
+ * });
1395
+ * ```
1396
+ */
1397
+ before_store_tool_result: (state: State, toolCall: Record<string, unknown>, toolResult: Record<string, unknown>) => Promise<Record<string, unknown>>;
1398
+ /**
1399
+ * Called after a successful tool call.
1400
+ *
1401
+ * Receives the tool call and its result. Can return a modified result
1402
+ * or null to use the original. Use for logging, transformation, or
1403
+ * post-processing of successful tool executions.
1404
+ *
1405
+ * @param state - Thread state
1406
+ * @param toolCall - The executed tool call
1407
+ * @param toolResult - The successful result
1408
+ * @returns Modified result or null for original
1409
+ *
1410
+ * @example
1411
+ * ```typescript
1412
+ * defineHook('after_tool_call_success', async (state, toolCall, toolResult) => {
1413
+ * console.log(`Tool ${toolCall.function.name} succeeded`);
1414
+ * return null; // Use original result
1415
+ * });
1416
+ * ```
1417
+ */
1418
+ after_tool_call_success: (state: State, toolCall: ToolCall, toolResult: ToolResult) => Promise<ToolResult | null>;
1419
+ /**
1420
+ * Called after a failed tool call.
1421
+ *
1422
+ * Receives the tool call and error result. Can return a modified result
1423
+ * or null to use the original. Use for error handling, logging, or
1424
+ * recovery attempts.
1425
+ *
1426
+ * @param state - Thread state
1427
+ * @param toolCall - The failed tool call
1428
+ * @param toolResult - The error result
1429
+ * @returns Modified result or null for original
1430
+ *
1431
+ * @example
1432
+ * ```typescript
1433
+ * defineHook('after_tool_call_failure', async (state, toolCall, toolResult) => {
1434
+ * console.error(`Tool ${toolCall.function.name} failed: ${toolResult.error}`);
1435
+ * return null; // Use original error
1436
+ * });
1437
+ * ```
1438
+ */
1439
+ after_tool_call_failure: (state: State, toolCall: ToolCall, toolResult: ToolResult) => Promise<ToolResult | null>;
1440
+ }
1441
+ /**
1442
+ * Valid hook names.
1443
+ */
1444
+ type HookName = keyof HookSignatures;
1445
+ /**
1446
+ * Hook definition tuple.
1447
+ *
1448
+ * A hook definition is a tuple containing the hook name and implementation.
1449
+ *
1450
+ * @template K - The hook name
1451
+ * @template State - The state type (defaults to ThreadState)
1452
+ * @template Msg - The message type
1453
+ * @template ToolCall - The tool call type
1454
+ * @template ToolResult - The tool result type
1455
+ */
1456
+ type HookDefinition<K extends HookName = HookName, State = ThreadState, Msg = HookMessage, ToolCall = HookToolCall, ToolResult = HookToolResult> = [K, HookSignatures<State, Msg, ToolCall, ToolResult>[K]];
1457
+ /**
1458
+ * Define a hook with strict typing based on hook name.
1459
+ *
1460
+ * Hooks intercept specific points in the agent execution lifecycle.
1461
+ * The hook name determines the function signature and when it's called.
1462
+ * All hooks receive ThreadState as their first parameter.
1463
+ *
1464
+ * @template K - The hook name (determines signature)
1465
+ * @param hookName - Name of the hook to define
1466
+ * @param implementation - Hook implementation function
1467
+ * @returns The implementation function (for registration)
1468
+ *
1469
+ * @example
1470
+ * ```typescript
1471
+ * // Filter messages to last 10
1472
+ * export default defineHook('filter_messages', async (state, messages) => {
1473
+ * return messages.slice(-10);
1474
+ * });
1475
+ * ```
1476
+ *
1477
+ * @example
1478
+ * ```typescript
1479
+ * // Log all tool successes
1480
+ * export default defineHook('after_tool_call_success', async (state, toolCall, result) => {
1481
+ * console.log(`Tool ${toolCall.function.name} completed`);
1482
+ * return null; // Use original result
1483
+ * });
1484
+ * ```
1485
+ *
1486
+ * @example
1487
+ * ```typescript
1488
+ * // Transform messages before LLM
1489
+ * export default defineHook('prefilter_llm_history', async (state, messages) => {
1490
+ * // Add instruction to last message
1491
+ * const last = messages[messages.length - 1];
1492
+ * if (last?.role === 'user' && typeof last.content === 'string') {
1493
+ * last.content += '\n\nRemember to be concise.';
1494
+ * }
1495
+ * return messages;
1496
+ * });
1497
+ * ```
1498
+ */
1499
+ declare function defineHook<K extends keyof HookSignatures>(hookName: K, implementation: HookSignatures[K]): HookSignatures[K];
1500
+
1501
+ /**
1502
+ * Agent definition types for Standard Agents.
1503
+ *
1504
+ * Agents orchestrate conversations between AI models (dual_ai) or between
1505
+ * AI and human users (ai_human). They define the prompts, stop conditions,
1506
+ * and behavioral rules for each side of the conversation.
1507
+ *
1508
+ * @module
1509
+ */
1510
+ /**
1511
+ * Agent conversation type.
1512
+ *
1513
+ * - `ai_human`: AI conversing with a human user (most common)
1514
+ * - `dual_ai`: Two AI participants conversing with each other
1515
+ */
1516
+ type AgentType = 'ai_human' | 'dual_ai';
1517
+ /**
1518
+ * Configuration for one side of an agent conversation.
1519
+ *
1520
+ * Each side has a prompt, stop conditions, and turn limits.
1521
+ * For `ai_human` agents, only sideA (the AI) needs configuration.
1522
+ * For `dual_ai` agents, both sides need configuration.
1523
+ *
1524
+ * @template Prompt - The prompt reference type (string or type-safe union)
1525
+ * @template Callable - The callable reference type (string or type-safe union)
1526
+ *
1527
+ * @example
1528
+ * ```typescript
1529
+ * const sideConfig: SideConfig = {
1530
+ * label: 'Support Agent',
1531
+ * prompt: 'customer_support',
1532
+ * stopOnResponse: true,
1533
+ * maxSteps: 10,
1534
+ * };
1535
+ * ```
1536
+ */
1537
+ interface SideConfig<Prompt extends string = string, Callable extends string = string> {
1538
+ /**
1539
+ * Custom label for this side of the conversation.
1540
+ * Used in UI and logs for clarity.
1541
+ *
1542
+ * @example 'Support Agent', 'Customer', 'ATC', 'Pilot'
1543
+ */
1544
+ label?: string;
1545
+ /**
1546
+ * The prompt to use for this side.
1547
+ * Must reference a prompt defined in agents/prompts/.
1548
+ */
1549
+ prompt: Prompt;
1550
+ /**
1551
+ * Stop this side's turn when it returns a text response (no tool calls).
1552
+ * When true, the side's turn ends after producing a message without tools.
1553
+ * @default true
1554
+ */
1555
+ stopOnResponse?: boolean;
1556
+ /**
1557
+ * Stop this side's turn when a specific tool is called.
1558
+ * Overrides stopOnResponse when the named tool is invoked.
1559
+ * Requires stopToolResponseProperty to extract the result.
1560
+ */
1561
+ stopTool?: Callable;
1562
+ /**
1563
+ * Property to extract from the stop tool's result.
1564
+ * Required when stopTool is set.
1565
+ * The extracted value is used to determine the conversation outcome.
1566
+ */
1567
+ stopToolResponseProperty?: string;
1568
+ /**
1569
+ * Maximum steps for this side before forcing a stop.
1570
+ * Safety limit to prevent runaway execution.
1571
+ * A step is one complete LLM request/response cycle.
1572
+ */
1573
+ maxSteps?: number;
1574
+ /**
1575
+ * Tool that ends the entire session when called.
1576
+ * Different from stopTool - this ends the session for both sides,
1577
+ * not just this side's turn.
1578
+ */
1579
+ endSessionTool?: Callable;
1580
+ }
1581
+ /**
1582
+ * Agent definition configuration.
1583
+ *
1584
+ * @template N - The agent name as a string literal type
1585
+ * @template Prompt - The prompt reference type (string or type-safe union)
1586
+ * @template Callable - The callable reference type (string or type-safe union)
1587
+ *
1588
+ * @example
1589
+ * ```typescript
1590
+ * import { defineAgent } from '@standardagents/spec';
1591
+ *
1592
+ * export default defineAgent({
1593
+ * name: 'support_agent',
1594
+ * title: 'Customer Support Agent',
1595
+ * type: 'ai_human',
1596
+ * sideA: {
1597
+ * label: 'Support',
1598
+ * prompt: 'customer_support',
1599
+ * stopOnResponse: true,
1600
+ * },
1601
+ * });
1602
+ * ```
1603
+ */
1604
+ interface AgentDefinition<N extends string = string, Prompt extends string = string, Callable extends string = string> {
1605
+ /**
1606
+ * Unique name for this agent.
1607
+ * Used as the identifier for thread creation and handoffs.
1608
+ * Should be snake_case (e.g., 'support_agent', 'research_flow').
1609
+ */
1610
+ name: N;
1611
+ /**
1612
+ * Human-readable title for the agent.
1613
+ * Optional - if not provided, the name will be used.
1614
+ * @deprecated Use name instead. Title will be removed in a future version.
1615
+ */
1616
+ title?: string;
1617
+ /**
1618
+ * Agent conversation type.
1619
+ *
1620
+ * - `ai_human`: AI conversing with a human user (default)
1621
+ * - `dual_ai`: Two AI participants conversing
1622
+ *
1623
+ * @default 'ai_human'
1624
+ */
1625
+ type?: AgentType;
1626
+ /**
1627
+ * Maximum total turns across both sides.
1628
+ * Only applies to `dual_ai` agents.
1629
+ * Prevents infinite loops in AI-to-AI conversations.
1630
+ */
1631
+ maxSessionTurns?: number;
1632
+ /**
1633
+ * Configuration for Side A.
1634
+ * For `ai_human`: This is the AI side.
1635
+ * For `dual_ai`: This is the first AI participant.
1636
+ */
1637
+ sideA: SideConfig<Prompt, Callable>;
1638
+ /**
1639
+ * Configuration for Side B.
1640
+ * For `ai_human`: Optional, the human side doesn't need config.
1641
+ * For `dual_ai`: Required, the second AI participant.
1642
+ */
1643
+ sideB?: SideConfig<Prompt, Callable>;
1644
+ /**
1645
+ * Expose this agent as a tool for other prompts.
1646
+ * Enables agent composition and handoffs.
1647
+ * When true, other prompts can invoke this agent as a tool.
1648
+ * @default false
1649
+ */
1650
+ exposeAsTool?: boolean;
1651
+ /**
1652
+ * Description shown when agent is used as a tool.
1653
+ * Required if exposeAsTool is true.
1654
+ * Should clearly describe what this agent does.
1655
+ */
1656
+ toolDescription?: string;
1657
+ /**
1658
+ * Brief description of what this agent does.
1659
+ * Useful for UIs and documentation.
1660
+ *
1661
+ * @example 'Handles customer support inquiries and resolves issues'
1662
+ */
1663
+ description?: string;
1664
+ /**
1665
+ * Icon URL or absolute path for the agent.
1666
+ * Absolute paths (starting with `/`) are converted to full URLs in API responses.
1667
+ *
1668
+ * @example 'https://example.com/icon.svg' or '/icons/support.svg'
1669
+ */
1670
+ icon?: string;
1671
+ }
1672
+ /**
1673
+ * Defines an agent configuration.
1674
+ *
1675
+ * Agents orchestrate conversations between AI models, or between AI and
1676
+ * human users. They use prompts to configure each side of the conversation
1677
+ * and define stop conditions to control conversation flow.
1678
+ *
1679
+ * @template N - The agent name as a string literal type
1680
+ * @param options - Agent configuration options
1681
+ * @returns The agent definition for registration
1682
+ *
1683
+ * @example
1684
+ * ```typescript
1685
+ * // agents/agents/support_agent.ts
1686
+ * import { defineAgent } from '@standardagents/spec';
1687
+ *
1688
+ * export default defineAgent({
1689
+ * name: 'support_agent',
1690
+ * title: 'Customer Support Agent',
1691
+ * type: 'ai_human',
1692
+ * sideA: {
1693
+ * label: 'Support',
1694
+ * prompt: 'customer_support',
1695
+ * stopOnResponse: true,
1696
+ * endSessionTool: 'close_ticket',
1697
+ * },
1698
+ * exposeAsTool: true,
1699
+ * toolDescription: 'Hand off to customer support',
1700
+ * });
1701
+ * ```
1702
+ *
1703
+ * @example
1704
+ * ```typescript
1705
+ * // Dual AI agent (two AIs conversing)
1706
+ * export default defineAgent({
1707
+ * name: 'debate_agent',
1708
+ * title: 'AI Debate',
1709
+ * type: 'dual_ai',
1710
+ * maxSessionTurns: 10,
1711
+ * sideA: {
1712
+ * label: 'Pro',
1713
+ * prompt: 'debate_pro',
1714
+ * stopOnResponse: true,
1715
+ * },
1716
+ * sideB: {
1717
+ * label: 'Con',
1718
+ * prompt: 'debate_con',
1719
+ * stopOnResponse: true,
1720
+ * endSessionTool: 'conclude_debate',
1721
+ * },
1722
+ * });
1723
+ * ```
1724
+ */
1725
+ declare function defineAgent<N extends string>(options: AgentDefinition<N>): AgentDefinition<N>;
1726
+
1727
+ /**
1728
+ * Endpoint definition types for Standard Agents.
1729
+ *
1730
+ * Endpoints expose HTTP APIs for interacting with agent threads.
1731
+ * They can be standard controllers or thread-specific endpoints
1732
+ * with automatic ThreadState injection.
1733
+ *
1734
+ * @module
1735
+ */
1736
+
1737
+ /**
1738
+ * Virtual module loader function.
1739
+ *
1740
+ * Lazy-loads a module definition on demand.
1741
+ */
1742
+ type VirtualModuleLoader<T> = () => Promise<T>;
1743
+ /**
1744
+ * Registry of virtual modules by name.
1745
+ *
1746
+ * Maps module names to their lazy loaders.
1747
+ */
1748
+ type VirtualModuleRegistry<T> = Record<string, VirtualModuleLoader<T>>;
1749
+ /**
1750
+ * Controller context passed to route handlers.
1751
+ *
1752
+ * Contains the request, URL parameters, environment bindings,
1753
+ * and optionally the virtual module registries injected at runtime.
1754
+ *
1755
+ * Note: The `env` property contains implementation-specific bindings.
1756
+ * Cloudflare implementations may include Durable Object namespaces,
1757
+ * KV namespaces, etc. Other implementations may provide different bindings.
1758
+ */
1759
+ interface ControllerContext {
1760
+ /** The incoming HTTP request */
1761
+ req: Request;
1762
+ /** URL path parameters extracted by the router */
1763
+ params: Record<string, string>;
1764
+ /** Parsed URL object */
1765
+ url: URL;
1766
+ /**
1767
+ * Environment bindings (implementation-specific).
1768
+ *
1769
+ * Contains platform-specific bindings like Durable Objects, KV, etc.
1770
+ * The exact contents depend on the runtime implementation.
1771
+ */
1772
+ env: Record<string, unknown>;
1773
+ /** Registry of agent definitions (injected at runtime) */
1774
+ agents?: VirtualModuleRegistry<unknown>;
1775
+ /** Available agent names */
1776
+ agentNames?: string[];
1777
+ /** Registry of prompt definitions (injected at runtime) */
1778
+ prompts?: VirtualModuleRegistry<unknown>;
1779
+ /** Available prompt names */
1780
+ promptNames?: string[];
1781
+ /** Registry of model definitions (injected at runtime) */
1782
+ models?: VirtualModuleRegistry<unknown>;
1783
+ /** Available model names */
1784
+ modelNames?: string[];
1785
+ /** Registry of tool definitions (injected at runtime) */
1786
+ tools?: VirtualModuleRegistry<unknown>;
1787
+ /** Registry of hook definitions (injected at runtime) */
1788
+ hooks?: VirtualModuleRegistry<unknown>;
1789
+ /** Additional configuration (injected at runtime) */
1790
+ config?: Record<string, unknown>;
1791
+ }
1792
+ /**
1793
+ * Controller return types.
1794
+ *
1795
+ * Controllers can return various types that are automatically
1796
+ * converted to appropriate HTTP responses.
1797
+ */
1798
+ type ControllerReturn = string | Promise<string> | Response | Promise<Response> | ReadableStream | Promise<ReadableStream> | null | Promise<null> | void | Promise<void> | Promise<object> | object;
1799
+ /**
1800
+ * Controller function type.
1801
+ *
1802
+ * Controllers handle HTTP requests and return responses.
1803
+ * The return value is automatically converted to a Response.
1804
+ *
1805
+ * @example
1806
+ * ```typescript
1807
+ * const handler: Controller = async ({ req, params, url }) => {
1808
+ * return { message: 'Hello, World!' };
1809
+ * };
1810
+ * ```
1811
+ */
1812
+ type Controller = (context: ControllerContext) => ControllerReturn;
1813
+ /**
1814
+ * Thread endpoint handler function.
1815
+ *
1816
+ * Receives the HTTP request and the ThreadState for the requested thread.
1817
+ * The thread is automatically looked up by ID from URL parameters.
1818
+ */
1819
+ type ThreadEndpointHandler = (req: Request, state: ThreadState) => Response | Promise<Response>;
1820
+ /**
1821
+ * Define a standard HTTP controller.
1822
+ *
1823
+ * Controllers handle HTTP requests and return responses. They have
1824
+ * access to the controller context including virtual module registries.
1825
+ *
1826
+ * @param controller - The controller function
1827
+ * @returns The controller for registration
1828
+ *
1829
+ * @example
1830
+ * ```typescript
1831
+ * // agents/api/health.get.ts
1832
+ * import { defineController } from '@standardagents/spec';
1833
+ *
1834
+ * export default defineController(async () => {
1835
+ * return { status: 'ok', timestamp: Date.now() };
1836
+ * });
1837
+ * ```
1838
+ *
1839
+ * @example
1840
+ * ```typescript
1841
+ * // agents/api/agents/index.get.ts
1842
+ * import { defineController } from '@standardagents/spec';
1843
+ *
1844
+ * export default defineController(async ({ agentNames }) => {
1845
+ * return { agents: agentNames };
1846
+ * });
1847
+ * ```
1848
+ */
1849
+ declare function defineController(controller: Controller): Controller;
1850
+ /**
1851
+ * Define a thread-specific endpoint.
1852
+ *
1853
+ * Thread endpoints automatically look up the thread by ID from URL params
1854
+ * and provide access to the ThreadState. The handler receives full
1855
+ * ThreadState with messages, logs, resource loading, event emission,
1856
+ * and (when executing) execution state.
1857
+ *
1858
+ * @param handler - The handler function receiving request and ThreadState
1859
+ * @returns A Controller that can be used with the router
1860
+ *
1861
+ * @example
1862
+ * ```typescript
1863
+ * // agents/api/threads/[id]/status.get.ts
1864
+ * import { defineThreadEndpoint } from '@standardagents/spec';
1865
+ *
1866
+ * export default defineThreadEndpoint(async (req, state) => {
1867
+ * const { messages, total } = await state.getMessages({ limit: 1 });
1868
+ * return Response.json({
1869
+ * threadId: state.threadId,
1870
+ * agent: state.agentId,
1871
+ * messageCount: total,
1872
+ * });
1873
+ * });
1874
+ * ```
1875
+ *
1876
+ * @example
1877
+ * ```typescript
1878
+ * // agents/api/threads/[id]/export.get.ts
1879
+ * import { defineThreadEndpoint } from '@standardagents/spec';
1880
+ *
1881
+ * export default defineThreadEndpoint(async (req, state) => {
1882
+ * const { messages } = await state.getMessages();
1883
+ * const logs = await state.getLogs();
1884
+ * return Response.json({
1885
+ * thread: {
1886
+ * id: state.threadId,
1887
+ * agent: state.agentId,
1888
+ * user: state.userId,
1889
+ * createdAt: state.createdAt,
1890
+ * },
1891
+ * messages,
1892
+ * logs,
1893
+ * });
1894
+ * });
1895
+ * ```
1896
+ *
1897
+ * @example
1898
+ * ```typescript
1899
+ * // agents/api/threads/[id]/invoke.post.ts
1900
+ * import { defineThreadEndpoint } from '@standardagents/spec';
1901
+ *
1902
+ * export default defineThreadEndpoint(async (req, state) => {
1903
+ * const { tool, args } = await req.json();
1904
+ *
1905
+ * // Queue a tool for execution (starts execution if not running)
1906
+ * state.queueTool(tool, args);
1907
+ *
1908
+ * return Response.json({ queued: true });
1909
+ * });
1910
+ * ```
1911
+ */
1912
+ declare function defineThreadEndpoint(handler: ThreadEndpointHandler): Controller;
1913
+
1914
+ export { type AgentDefinition, type AgentType, type AttachmentRef, type Controller, type ControllerContext, type ControllerReturn, type ExecutionState, type FileChunk, type FileRecord, type FileStats, type FileStorage, type FindResult, type GetLogsOptions, type GetMessagesOptions, type GrepResult, type HookContext, type HookDefinition, type HookMessage, type HookName, type HookSignatures, type HookToolCall, type HookToolResult, type ImageContent, type InjectMessageInput, type LLMMessage, type Log, type Message, type MessageUpdates, type MessagesResult, type ModelCapabilities, type ModelDefinition, type ModelProvider, type PromptContent, type PromptDefinition, type PromptIncludePart, type PromptInput, type PromptPart, type PromptTextPart, type ReadFileStreamOptions, type ReaddirResult, type ReasoningConfig, type SideConfig, type StructuredPrompt, type SubpromptConfig, type TextContent, type ThreadEndpointHandler, type ThreadMetadata, type ThreadState, type Tool, type ToolArgs, type ToolArgsNode, type ToolArgsRawShape, type ToolAttachment, type ToolConfig, type ToolContent, type ToolDefinition, type ToolResult, type VirtualModuleLoader, type VirtualModuleRegistry, type WriteFileOptions, defineAgent, defineController, defineHook, defineModel, definePrompt, defineThreadEndpoint, defineTool };