@standardagents/spec 0.11.0-next.41deba4 → 0.11.0-next.5d2e71b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -327,32 +327,6 @@ interface MessageUpdates {
327
327
  /** Updated metadata (merged with existing) */
328
328
  metadata?: Record<string, unknown>;
329
329
  }
330
- /**
331
- * Options for retrieving logs.
332
- */
333
- interface GetLogsOptions {
334
- /** Maximum number of logs to return */
335
- limit?: number;
336
- /** Number of logs to skip */
337
- offset?: number;
338
- /** Sort order */
339
- order?: 'asc' | 'desc';
340
- }
341
- /**
342
- * An execution log entry.
343
- */
344
- interface Log {
345
- /** Unique log identifier */
346
- id: string;
347
- /** Log type (e.g., 'tool_call', 'llm_request', 'error') */
348
- type: string;
349
- /** Log data (structure varies by type) */
350
- data: Record<string, unknown>;
351
- /** Creation timestamp (microseconds since epoch) */
352
- created_at: number;
353
- /** Parent log ID (for nested operations) */
354
- parent_id?: string | null;
355
- }
356
330
  /**
357
331
  * Storage location identifier.
358
332
  *
@@ -590,12 +564,15 @@ interface ThreadState {
590
564
  */
591
565
  updateMessage(messageId: string, updates: MessageUpdates): Promise<Message>;
592
566
  /**
593
- * Get execution logs.
567
+ * Delete a message from the thread.
568
+ *
569
+ * Removes the message and any associated attachments from storage.
570
+ * Tool call results are cascade-deleted when their parent message is removed.
594
571
  *
595
- * @param options - Query options
596
- * @returns Array of log entries
572
+ * @param messageId - The message ID to delete
573
+ * @returns true if the message was found and deleted, false if not found
597
574
  */
598
- getLogs(options?: GetLogsOptions): Promise<Log[]>;
575
+ deleteMessage(messageId: string): Promise<boolean>;
599
576
  /**
600
577
  * Load a model definition by name.
601
578
  *
@@ -704,6 +681,26 @@ interface ThreadState {
704
681
  * @returns true if the effect was found and removed, false otherwise
705
682
  */
706
683
  removeScheduledEffect(id: string): Promise<boolean>;
684
+ /**
685
+ * Trigger an agent to run on this thread.
686
+ *
687
+ * Starts a new agent execution asynchronously. This is useful for effects
688
+ * that need to trigger background agent work (e.g., running a finalizer
689
+ * agent after a delay).
690
+ *
691
+ * The agent runs in the background - this method returns immediately
692
+ * after queuing the execution.
693
+ *
694
+ * @param agentName - Name of the agent to run (must exist in agents/agents/)
695
+ * @returns Promise that resolves when the execution is queued
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * // In an effect handler, trigger a finalizer agent
700
+ * await state.runAgent('booking_finalizer');
701
+ * ```
702
+ */
703
+ runAgent(agentName: string): Promise<void>;
707
704
  /**
708
705
  * Emit a custom event to connected clients.
709
706
  *
@@ -2004,7 +2001,6 @@ declare function defineController(controller: Controller): Controller;
2004
2001
  *
2005
2002
  * export default defineThreadEndpoint(async (req, state) => {
2006
2003
  * const { messages } = await state.getMessages();
2007
- * const logs = await state.getLogs();
2008
2004
  * return Response.json({
2009
2005
  * thread: {
2010
2006
  * id: state.threadId,
@@ -2013,7 +2009,6 @@ declare function defineController(controller: Controller): Controller;
2013
2009
  * createdAt: state.createdAt,
2014
2010
  * },
2015
2011
  * messages,
2016
- * logs,
2017
2012
  * });
2018
2013
  * });
2019
2014
  * ```
@@ -2035,4 +2030,4 @@ declare function defineController(controller: Controller): Controller;
2035
2030
  */
2036
2031
  declare function defineThreadEndpoint(handler: ThreadEndpointHandler): Controller;
2037
2032
 
2038
- export { type AgentDefinition, type AgentType, type AttachmentRef, type Controller, type ControllerContext, type ControllerReturn, type Effect, type EffectDefinition, 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 ScheduledEffect, 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, defineEffect, defineHook, defineModel, definePrompt, defineThreadEndpoint, defineTool };
2033
+ export { type AgentDefinition, type AgentType, type AttachmentRef, type Controller, type ControllerContext, type ControllerReturn, type Effect, type EffectDefinition, type ExecutionState, type FileChunk, type FileRecord, type FileStats, type FileStorage, type FindResult, 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 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 ScheduledEffect, 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, defineEffect, defineHook, defineModel, definePrompt, defineThreadEndpoint, defineTool };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/models.ts","../src/tools.ts","../src/prompts.ts","../src/hooks.ts","../src/effects.ts","../src/agents.ts","../src/endpoints.ts"],"sourcesContent":["/**\n * Model definition types for Standard Agents.\n *\n * Models define LLM configurations including provider, model ID, pricing,\n * and fallback chains. Models are referenced by name from prompts.\n *\n * @module\n */\n\n/**\n * Supported LLM provider identifiers.\n *\n * Each provider requires a corresponding API key environment variable:\n * - `openai` → `OPENAI_API_KEY`\n * - `openrouter` → `OPENROUTER_API_KEY`\n * - `anthropic` → `ANTHROPIC_API_KEY`\n * - `google` → `GOOGLE_API_KEY`\n * - `test` → No API key required (for testing with scripted responses)\n */\nexport type ModelProvider = 'openai' | 'openrouter' | 'anthropic' | 'google' | 'test';\n\n/**\n * Model capability flags indicating supported features.\n */\nexport interface ModelCapabilities {\n /**\n * Whether the model supports vision (image understanding).\n * When true, image attachments will be sent to the model as part of the request.\n * Models like GPT-4o, Claude 3, and Gemini support vision.\n */\n vision?: boolean;\n\n /**\n * Whether the model supports function calling (tool use).\n * Most modern models support this, defaults to true if not specified.\n */\n functionCalling?: boolean;\n\n /**\n * Whether the model supports structured outputs (JSON mode).\n */\n structuredOutputs?: boolean;\n}\n\n/**\n * Model definition configuration.\n *\n * Defines an LLM model with its provider, pricing, capabilities, and fallback chain.\n *\n * @template N - The model name as a string literal type for type inference\n *\n * @example\n * ```typescript\n * import { defineModel } from '@standardagents/spec';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: 'openai',\n * model: 'gpt-4o',\n * fallbacks: ['gpt-4-turbo', 'gpt-3.5-turbo'],\n * inputPrice: 2.5,\n * outputPrice: 10,\n * });\n * ```\n */\nexport interface ModelDefinition<N extends string = string> {\n /**\n * Unique name for this model definition.\n * Used as the identifier when referencing from prompts.\n * Should be descriptive and consistent (e.g., 'gpt-4o', 'claude-3-opus').\n */\n name: N;\n\n /**\n * The LLM provider to use for API calls.\n * The corresponding API key environment variable must be set.\n */\n provider: ModelProvider;\n\n /**\n * The actual model identifier sent to the provider API.\n *\n * For OpenAI: 'gpt-4o', 'gpt-4-turbo', 'gpt-3.5-turbo', etc.\n * For OpenRouter: 'openai/gpt-4o', 'anthropic/claude-3-opus', etc.\n * For Anthropic: 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', etc.\n * For Google: 'gemini-1.5-pro', 'gemini-1.5-flash', etc.\n */\n model: string;\n\n /**\n * Optional list of additional provider prefixes for OpenRouter.\n * Allows routing through specific providers when using OpenRouter.\n *\n * @example ['anthropic', 'google'] - prefer Anthropic, fallback to Google\n */\n includedProviders?: string[];\n\n /**\n * Fallback model names to try if this model fails.\n * Referenced by model name (must be defined in agents/models/).\n * Tried in order after primary model exhausts retries.\n *\n * @example ['gpt-4', 'gpt-3.5-turbo']\n */\n fallbacks?: string[];\n\n /**\n * Cost per 1 million input tokens in USD.\n * Used for cost tracking and reporting in logs.\n */\n inputPrice?: number;\n\n /**\n * Cost per 1 million output tokens in USD.\n * Used for cost tracking and reporting in logs.\n */\n outputPrice?: number;\n\n /**\n * Cost per 1 million cached input tokens in USD.\n * Some providers offer reduced pricing for cached/repeated prompts.\n */\n cachedPrice?: number;\n\n /**\n * Model capabilities - features this model supports.\n */\n capabilities?: ModelCapabilities;\n}\n\n/**\n * Defines an LLM model configuration.\n *\n * Models are the foundation of the agent system - they specify which\n * AI model to use and how to connect to it. Models can have fallbacks\n * for reliability and include pricing for cost tracking.\n *\n * @template N - The model name as a string literal type\n * @param options - Model configuration options\n * @returns The model definition for registration\n *\n * @example\n * ```typescript\n * // agents/models/gpt_4o.ts\n * import { defineModel } from '@standardagents/spec';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: 'openai',\n * model: 'gpt-4o',\n * fallbacks: ['gpt-4-turbo'],\n * inputPrice: 2.5,\n * outputPrice: 10,\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Using OpenRouter with provider preferences\n * export default defineModel({\n * name: 'claude-3-opus',\n * provider: 'openrouter',\n * model: 'anthropic/claude-3-opus',\n * includedProviders: ['anthropic'],\n * });\n * ```\n */\nexport function defineModel<N extends string>(\n options: ModelDefinition<N>\n): ModelDefinition<N> {\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Model name is required');\n }\n if (!options.provider) {\n throw new Error('Model provider is required');\n }\n if (!options.model) {\n throw new Error('Model ID is required');\n }\n\n // Validate provider is a known type\n const validProviders: ModelProvider[] = ['openai', 'openrouter', 'anthropic', 'google', 'test'];\n if (!validProviders.includes(options.provider)) {\n throw new Error(\n `Invalid provider '${options.provider}'. Must be one of: ${validProviders.join(', ')}`\n );\n }\n\n // Validate pricing is non-negative if provided\n if (options.inputPrice !== undefined && options.inputPrice < 0) {\n throw new Error('inputPrice must be non-negative');\n }\n if (options.outputPrice !== undefined && options.outputPrice < 0) {\n throw new Error('outputPrice must be non-negative');\n }\n if (options.cachedPrice !== undefined && options.cachedPrice < 0) {\n throw new Error('cachedPrice must be non-negative');\n }\n\n return options;\n}\n","/**\n * Tool definition types for Standard Agents.\n *\n * Tools are callable functions that agents can invoke during execution.\n * They receive the current ThreadState and validated arguments,\n * and return results that are included in the conversation.\n *\n * @module\n */\n\nimport type { ThreadState } from './threads.js';\nimport type {\n ZodString,\n ZodNumber,\n ZodBoolean,\n ZodEnum,\n ZodArray,\n ZodObject,\n ZodOptional,\n ZodNullable,\n ZodUnion,\n ZodRecord,\n ZodNull,\n ZodLiteral,\n ZodDefault,\n} from 'zod';\nimport { z } from 'zod';\n\n/**\n * Text content item returned by tools.\n */\nexport interface TextContent {\n type: 'text';\n text: string;\n}\n\n/**\n * Image content item returned by tools.\n */\nexport interface ImageContent {\n type: 'image';\n /** Base64-encoded image data. */\n data: string;\n /** MIME type of the image (e.g., 'image/png', 'image/jpeg'). */\n mimeType: string;\n}\n\n/**\n * Content types that can be returned by tools.\n */\nexport type ToolContent = TextContent | ImageContent;\n\n/**\n * File attachment generated by a tool.\n *\n * Attachments are stored in the thread's file system and linked to\n * the tool result message. Unlike user uploads, tool attachments are\n * not subject to image downsampling.\n */\nexport interface ToolAttachment {\n /** File name for the attachment. */\n name: string;\n /** MIME type of the attachment. */\n mimeType: string;\n /** Base64-encoded file data. */\n data: string;\n /** Width in pixels (for images). */\n width?: number;\n /** Height in pixels (for images). */\n height?: number;\n}\n\n/**\n * Reference to a pre-existing attachment in the thread file system.\n */\nexport interface AttachmentRef {\n /** Unique identifier for the attachment. */\n id: string;\n /** Attachment type. */\n type: 'file';\n /** Path in the thread file system. */\n path: string;\n /** File name. */\n name: string;\n /** MIME type. */\n mimeType: string;\n /** File size in bytes. */\n size: number;\n /** Width in pixels (for images). */\n width?: number;\n /** Height in pixels (for images). */\n height?: number;\n /** AI-generated description. */\n description?: string;\n}\n\n/**\n * Result returned by a tool execution.\n */\nexport interface ToolResult {\n /** Status of the tool execution. */\n status: 'success' | 'error';\n /**\n * Text representation of the tool output.\n *\n * For tools that return structured content, this is derived by\n * concatenating all text parts. For simple tools, this is the\n * direct result string.\n */\n result?: string;\n /** Error message if status is 'error'. */\n error?: string;\n /** Stack trace for error debugging. */\n stack?: string;\n /**\n * File attachments returned by the tool.\n *\n * Can contain either:\n * - ToolAttachment: New files with base64 data to be stored\n * - AttachmentRef: References to existing files in the thread filesystem\n *\n * Implementations MUST store new attachments under /attachments/ directory.\n */\n attachments?: Array<ToolAttachment | AttachmentRef>;\n}\n\n// ============================================================================\n// Tool Argument Types (Zod-based)\n// ============================================================================\n\n/** Decrement helper to limit recursion depth. */\ntype Dec<N extends number> = N extends 10\n ? 9\n : N extends 9\n ? 8\n : N extends 8\n ? 7\n : N extends 7\n ? 6\n : N extends 6\n ? 5\n : N extends 5\n ? 4\n : N extends 4\n ? 3\n : N extends 3\n ? 2\n : N extends 2\n ? 1\n : N extends 1\n ? 0\n : 0;\n\n/**\n * Allowed Zod types for tool argument nodes.\n *\n * This is the single source of truth for which Zod types can be used\n * in tool argument schemas. The depth parameter limits recursion to\n * prevent infinite type expansion.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolArgsNode<D extends number = 7> =\n // Primitives and literals\n | ZodString\n | ZodNumber\n | ZodBoolean\n | ZodNull\n | ZodLiteral<string | number | boolean | null>\n // Enums (Zod v4 uses Record<string, string> for enum type parameter)\n | ZodEnum<Readonly<Record<string, string>>>\n // Wrappers (with depth check)\n | (D extends 0 ? never : ZodOptional<ToolArgsNode<Dec<D>>>)\n | (D extends 0 ? never : ZodNullable<ToolArgsNode<Dec<D>>>)\n | (D extends 0 ? never : ZodDefault<ToolArgsNode<Dec<D>>>)\n // Arrays (with depth check)\n | (D extends 0 ? never : ZodArray<ToolArgsNode<Dec<D>>>)\n // Objects and records (with depth check)\n | (D extends 0 ? never : ZodObject<Record<string, ToolArgsNode<Dec<D>>>>)\n | (D extends 0 ? never : ZodRecord<ZodString, ToolArgsNode<Dec<D>>>)\n // Unions (with depth check)\n | (D extends 0\n ? never\n : ZodUnion<\n [\n ToolArgsNode<Dec<D>>,\n ToolArgsNode<Dec<D>>,\n ...ToolArgsNode<Dec<D>>[],\n ]\n >);\n\n/**\n * Raw shape for a Zod object schema containing tool argument nodes.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolArgsRawShape<D extends number = 7> = Record<\n string,\n ToolArgsNode<D>\n>;\n\n/**\n * Top-level tool argument schema.\n *\n * Tool arguments MUST be defined as a Zod object schema.\n * This is required for compatibility with OpenAI's function calling API.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolArgs<D extends number = 7> = z.ZodObject<ToolArgsRawShape<D>>;\n\n\n// ============================================================================\n// Tool Function Types\n// ============================================================================\n\n/**\n * Tool function signature.\n *\n * Tools are async functions that receive a ThreadState and\n * optionally validated arguments, returning a ToolResult.\n *\n * @template State - The state type (defaults to ThreadState)\n * @template Args - The Zod schema for tool arguments, or null for no args\n */\nexport type Tool<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = Args extends ToolArgs\n ? (state: State, args: z.infer<Args>) => Promise<ToolResult>\n : (state: State) => Promise<ToolResult>;\n\n/**\n * Return type of defineTool function.\n *\n * A tuple containing:\n * - Tool description string\n * - Argument schema (or null)\n * - Tool implementation function\n */\nexport type ToolDefinition<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = [string, Args, Tool<State, Args>];\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Define a tool with arguments.\n *\n * @param toolDescription - Description of what the tool does (shown to the LLM)\n * @param args - Zod schema for validating tool arguments\n * @param tool - The tool implementation function\n * @returns A tuple containing the tool definition\n */\nexport function defineTool<State = ThreadState, Args extends ToolArgs = ToolArgs>(\n toolDescription: string,\n args: Args,\n tool: Tool<State, Args>\n): ToolDefinition<State, Args>;\n\n/**\n * Define a tool without arguments.\n *\n * @param toolDescription - Description of what the tool does (shown to the LLM)\n * @param tool - The tool implementation function\n * @returns A tuple containing the tool definition\n */\nexport function defineTool<State = ThreadState>(\n toolDescription: string,\n tool: Tool<State, null>\n): ToolDefinition<State, null>;\n\n/**\n * Defines a tool that agents can call during execution.\n *\n * Tools are the primary way agents interact with external systems.\n * Each tool has a description (shown to the LLM), optional argument\n * schema (validated at runtime), and an implementation function.\n *\n * @example\n * ```typescript\n * import { defineTool } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default defineTool(\n * 'Search the knowledge base for relevant information',\n * z.object({\n * query: z.string().describe('Search query'),\n * limit: z.number().optional().describe('Max results'),\n * }),\n * async (state, args) => {\n * const results = await search(args.query, args.limit);\n * return {\n * status: 'success',\n * result: JSON.stringify(results),\n * };\n * }\n * );\n * ```\n */\nexport function defineTool<\n State = ThreadState,\n Args extends ToolArgs = ToolArgs,\n>(\n toolDescription: string,\n argsOrTool: Args | Tool<State, null>,\n maybeTool?: Tool<State, Args>\n): ToolDefinition<State, Args | null> {\n if (maybeTool) {\n return [\n toolDescription,\n argsOrTool as Args,\n maybeTool,\n ];\n }\n return [\n toolDescription,\n null,\n argsOrTool as Tool<State, null>,\n ];\n}\n","/**\n * Prompt definition types for Standard Agents.\n *\n * Prompts define LLM interaction configurations including the system prompt,\n * model selection, available tools, and various behavioral options.\n *\n * @module\n */\n\nimport type { z } from 'zod';\nimport type { ToolArgs } from './tools.js';\n\n// ============================================================================\n// Structured Prompt Types\n// ============================================================================\n\n/**\n * A text part of a prompt - static text content.\n *\n * @example\n * ```typescript\n * { type: 'text', content: 'You are a helpful assistant.\\n\\n' }\n * ```\n */\nexport interface PromptTextPart {\n type: 'text';\n /** The text content */\n content: string;\n}\n\n/**\n * A prompt inclusion part - includes another prompt's content.\n *\n * @example\n * ```typescript\n * { type: 'include', prompt: 'responder_rules' }\n * ```\n */\nexport interface PromptIncludePart {\n type: 'include';\n /** The name of the prompt to include */\n prompt: string;\n}\n\n/**\n * A single part of a structured prompt.\n * Discriminated union on `type` field for TypeScript narrowing.\n */\nexport type PromptPart = PromptTextPart | PromptIncludePart;\n\n/**\n * A structured prompt is an array of prompt parts.\n * Provides composition with other prompts via includes.\n *\n * @example\n * ```typescript\n * prompt: [\n * { type: 'text', content: 'You are a helpful assistant.\\n\\n' },\n * { type: 'include', prompt: 'common_rules' },\n * { type: 'text', content: '\\n\\nBe concise.' },\n * ]\n * ```\n */\nexport type StructuredPrompt = PromptPart[];\n\n/**\n * The prompt content can be either a plain string or a structured array.\n *\n * @example\n * ```typescript\n * // Simple string prompt:\n * prompt: 'You are a helpful assistant.'\n *\n * // Structured prompt with includes:\n * prompt: [\n * { type: 'text', content: 'You are a helpful assistant.\\n\\n' },\n * { type: 'include', prompt: 'common_rules' },\n * ]\n * ```\n */\nexport type PromptContent = string | StructuredPrompt;\n\n// ============================================================================\n// Sub-Prompt Configuration\n// ============================================================================\n\n/**\n * Configuration for sub-prompts used as tools.\n * These options control how results from sub-prompts are returned to the caller.\n *\n * @template T - The sub-prompt name type (for type-safe references)\n */\nexport interface SubpromptConfig<T extends string = string> {\n /**\n * Name of the sub-prompt to call.\n * Must be a prompt defined in agents/prompts/.\n */\n name: T;\n\n /**\n * Include text response content from sub-prompt execution in the result string.\n * @default true\n */\n includeTextResponse?: boolean;\n\n /**\n * Serialize tool calls made by the sub-prompt (and their results) into the result string.\n * @default true\n */\n includeToolCalls?: boolean;\n\n /**\n * Serialize any errors from the sub-prompt into the result string.\n * @default true\n */\n includeErrors?: boolean;\n\n /**\n * Property from the tool call arguments to use as the initial user message\n * when invoking the sub-prompt.\n *\n * @example\n * If the tool is called with `{ query: \"search term\", limit: 10 }` and\n * `initUserMessageProperty: 'query'`, the sub-prompt will receive\n * \"search term\" as the initial user message.\n */\n initUserMessageProperty?: string;\n}\n\n/**\n * @deprecated Use SubpromptConfig instead\n */\nexport type ToolConfig<T extends string = string> = SubpromptConfig<T>;\n\n// ============================================================================\n// Reasoning Configuration\n// ============================================================================\n\n/**\n * Reasoning configuration for models that support extended thinking.\n * Applies to models like OpenAI o1, Anthropic Claude with extended thinking,\n * Google Gemini with thinking, and Qwen with reasoning.\n */\nexport interface ReasoningConfig {\n /**\n * Effort level for reasoning models.\n * Higher effort = more thinking tokens = potentially better results.\n *\n * - `low`: Minimal reasoning, faster responses\n * - `medium`: Balanced reasoning and speed\n * - `high`: Maximum reasoning, slower but more thorough\n *\n * @default undefined (use model defaults)\n */\n effort?: 'low' | 'medium' | 'high';\n\n /**\n * Maximum tokens to allocate for reasoning.\n * Applies to models that support token limits on reasoning.\n */\n maxTokens?: number;\n\n /**\n * Use reasoning internally but exclude from the response.\n * Model thinks through the problem but only returns the final answer.\n * Useful for cleaner outputs while maintaining reasoning quality.\n */\n exclude?: boolean;\n\n /**\n * Include reasoning content in the message history for multi-turn context.\n * When true, reasoning is preserved and visible to subsequent turns.\n * @default false\n */\n include?: boolean;\n}\n\n// ============================================================================\n// Prompt Definition\n// ============================================================================\n\n/**\n * Prompt definition configuration.\n *\n * @template N - The prompt name as a string literal type\n * @template S - The Zod schema type for requiredSchema (inferred automatically)\n *\n * @example\n * ```typescript\n * import { definePrompt } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default definePrompt({\n * name: 'customer_support',\n * toolDescription: 'Handle customer support inquiries',\n * model: 'gpt-4o',\n * prompt: 'You are a helpful customer support agent.',\n * tools: ['search_knowledge_base', 'create_ticket'],\n * requiredSchema: z.object({\n * query: z.string().describe('The customer inquiry'),\n * }),\n * });\n * ```\n */\nexport interface PromptDefinition<\n N extends string = string,\n S extends ToolArgs = ToolArgs,\n> {\n /**\n * Unique name for this prompt.\n * Used as the identifier when referencing from agents or as a tool.\n * Should be snake_case (e.g., 'customer_support', 'data_analyst').\n */\n name: N;\n\n /**\n * Description shown when this prompt is exposed as a tool.\n * Should clearly describe what this prompt does for LLM tool selection.\n */\n toolDescription: string;\n\n /**\n * The system prompt content sent to the LLM.\n * Can be either a plain string or a structured array for composition.\n */\n prompt: PromptContent;\n\n /**\n * Model to use for this prompt.\n * Must reference a model defined in agents/models/.\n */\n model: string;\n\n /**\n * Include full chat history in the LLM context.\n * @default false\n */\n includeChat?: boolean;\n\n /**\n * Include results from past tool calls in the LLM context.\n * @default false\n */\n includePastTools?: boolean;\n\n /**\n * Allow parallel execution of multiple tool calls.\n * @default false\n */\n parallelToolCalls?: boolean;\n\n /**\n * Tool calling strategy for the LLM.\n *\n * - `auto`: Model decides when to call tools (default)\n * - `none`: Disable tool calling entirely\n * - `required`: Force the model to call at least one tool\n *\n * @default 'auto'\n */\n toolChoice?: 'auto' | 'none' | 'required';\n\n /**\n * Zod schema for validating inputs when this prompt is called as a tool.\n */\n requiredSchema?: S;\n\n /**\n * Tools available to this prompt.\n * Can be simple tool names or sub-prompt configurations.\n * To enable handoffs, include ai_human agent names in this array.\n */\n tools?: (string | SubpromptConfig)[];\n\n /**\n * Reasoning configuration for models that support extended thinking.\n */\n reasoning?: ReasoningConfig;\n\n /**\n * Number of recent messages to keep actual images for in context.\n * @default 10\n */\n recentImageThreshold?: number;\n}\n\n/**\n * Helper type to extract the inferred input type from a prompt's Zod schema.\n *\n * @template T - The prompt definition type\n */\nexport type PromptInput<T extends PromptDefinition<string, ToolArgs>> =\n T['requiredSchema'] extends ToolArgs\n ? z.infer<T['requiredSchema']>\n : never;\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Defines a prompt configuration for LLM interactions.\n *\n * Prompts are the primary way to configure how agents interact with LLMs.\n * They specify the system prompt, available tools, input validation,\n * and various behavioral options.\n *\n * @template N - The prompt name as a string literal type\n * @template S - The Zod schema type for requiredSchema\n * @param options - Prompt configuration options\n * @returns The prompt definition for registration\n *\n * @example\n * ```typescript\n * import { definePrompt } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default definePrompt({\n * name: 'customer_support',\n * toolDescription: 'Handle customer support inquiries',\n * model: 'gpt-4o',\n * prompt: 'You are a helpful customer support agent.',\n * tools: ['search_knowledge_base', 'create_ticket'],\n * includeChat: true,\n * requiredSchema: z.object({\n * query: z.string().describe('The customer inquiry'),\n * }),\n * });\n * ```\n */\nexport function definePrompt<N extends string, S extends ToolArgs = never>(\n options: PromptDefinition<N, S>\n): PromptDefinition<N, S> {\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Prompt name is required');\n }\n if (!options.toolDescription) {\n throw new Error('Prompt toolDescription is required');\n }\n if (!options.model) {\n throw new Error('Prompt model is required');\n }\n if (!options.prompt) {\n throw new Error('Prompt content is required');\n }\n\n // Validate toolChoice is a known value\n if (\n options.toolChoice &&\n !['auto', 'none', 'required'].includes(options.toolChoice)\n ) {\n throw new Error(\n `Invalid toolChoice '${options.toolChoice}'. Must be one of: auto, none, required`\n );\n }\n\n // Validate reasoning effort is a known value\n if (\n options.reasoning?.effort &&\n !['low', 'medium', 'high'].includes(options.reasoning.effort)\n ) {\n throw new Error(\n `Invalid reasoning.effort '${options.reasoning.effort}'. Must be one of: low, medium, high`\n );\n }\n\n // Validate recentImageThreshold is a positive number\n if (\n options.recentImageThreshold !== undefined &&\n (options.recentImageThreshold <= 0 ||\n !Number.isInteger(options.recentImageThreshold))\n ) {\n throw new Error('recentImageThreshold must be a positive integer');\n }\n\n return options;\n}\n","/**\n * Hook definition types for Standard Agents.\n *\n * Hooks allow intercepting and modifying agent behavior at key points\n * in the execution lifecycle. They enable logging, validation,\n * transformation, and side effects.\n *\n * Hooks receive ThreadState as their first parameter, providing full\n * access to thread operations and execution state.\n *\n * @module\n */\n\nimport type { ThreadState, Message } from './threads.js';\n\n// ============================================================================\n// Hook Context Types\n// ============================================================================\n\n/**\n * Hook context is ThreadState.\n *\n * Hooks receive the full ThreadState, which includes identity, message access,\n * resource loading, event emission, and execution state (when available).\n *\n * @example\n * ```typescript\n * const hook = defineHook('filter_messages', async (state, messages) => {\n * console.log(`Thread: ${state.threadId}`);\n * if (state.execution) {\n * console.log(`Turn: ${state.execution.turnCount}`);\n * }\n * return messages.slice(-10);\n * });\n * ```\n */\nexport type HookContext = ThreadState;\n\n/**\n * Message structure for hook processing.\n *\n * Re-exported from threads.ts for convenience.\n * @see Message\n */\nexport type HookMessage = Message;\n\n/**\n * Tool call structure for hook processing.\n */\nexport interface HookToolCall {\n /** Unique tool call identifier */\n id: string;\n /** Always 'function' for tool calls */\n type: 'function';\n /** Function details */\n function: {\n /** Tool name */\n name: string;\n /** JSON-encoded arguments */\n arguments: string;\n };\n}\n\n/**\n * Tool result structure for hook processing.\n */\nexport interface HookToolResult {\n /** Execution status */\n status: 'success' | 'error';\n /** Result string (for successful executions) */\n result?: string;\n /** Error message (for failed executions) */\n error?: string;\n /** Stack trace (for debugging) */\n stack?: string;\n}\n\n/**\n * LLM message format for prefilter hook.\n */\nexport interface LLMMessage {\n /** Message role */\n role: string;\n /** Message content */\n content: string | null;\n /** Tool calls (parsed) */\n tool_calls?: unknown;\n /** Tool call ID */\n tool_call_id?: string;\n /** Tool name */\n name?: string;\n}\n\n// ============================================================================\n// Hook Signatures\n// ============================================================================\n\n/**\n * Hook signatures for all available hooks.\n *\n * Each hook has a specific signature that defines when it's called\n * and what data it receives. Hooks can modify data by returning\n * transformed values or perform side effects.\n *\n * All hooks receive ThreadState as their first parameter.\n *\n * @template State - The state type (defaults to ThreadState)\n * @template Msg - The message type (defaults to HookMessage)\n * @template ToolCall - The tool call type (defaults to HookToolCall)\n * @template ToolResult - The tool result type (defaults to HookToolResult)\n */\nexport interface HookSignatures<\n State = ThreadState,\n Msg = HookMessage,\n ToolCall = HookToolCall,\n ToolResult = HookToolResult,\n> {\n /**\n * Called before messages are filtered and sent to the LLM.\n *\n * Receives raw message rows from storage before any transformation.\n * Use for filtering, sorting, or augmenting message history.\n *\n * @param state - Thread state\n * @param messages - Array of messages from storage\n * @returns Modified message array\n *\n * @example\n * ```typescript\n * defineHook('filter_messages', async (state, messages) => {\n * // Only include messages from last 10 turns\n * return messages.slice(-10);\n * });\n * ```\n */\n filter_messages: (state: State, messages: Msg[]) => Promise<Msg[]>;\n\n /**\n * Called after message history is loaded and before sending to LLM.\n *\n * Receives messages already transformed into chat completion format.\n * Use for final adjustments before LLM request.\n *\n * @param state - Thread state\n * @param messages - Array of LLM-formatted messages\n * @returns Modified LLM message array\n *\n * @example\n * ```typescript\n * defineHook('prefilter_llm_history', async (state, messages) => {\n * // Add a reminder to the last user message\n * return messages;\n * });\n * ```\n */\n prefilter_llm_history: (\n state: State,\n messages: LLMMessage[]\n ) => Promise<LLMMessage[]>;\n\n /**\n * Called before a message is created in the database.\n *\n * Receives the message data before insertion. Return modified data\n * to transform the message before storage.\n *\n * @param state - Thread state\n * @param message - Message data to be created\n * @returns Modified message data\n *\n * @example\n * ```typescript\n * defineHook('before_create_message', async (state, message) => {\n * // Add metadata to all messages\n * return { ...message, metadata: { processed: true } };\n * });\n * ```\n */\n before_create_message: (\n state: State,\n message: Record<string, unknown>\n ) => Promise<Record<string, unknown>>;\n\n /**\n * Called after a message is created in the database.\n *\n * Use for logging, analytics, or triggering side effects after\n * message creation. Cannot modify the message.\n *\n * @param state - Thread state\n * @param message - The created message data\n *\n * @example\n * ```typescript\n * defineHook('after_create_message', async (state, message) => {\n * console.log(`Message created: ${message.id}`);\n * });\n * ```\n */\n after_create_message: (\n state: State,\n message: Record<string, unknown>\n ) => Promise<void>;\n\n /**\n * Called before a message is updated in the database.\n *\n * Receives the message ID and update data. Return modified updates\n * to transform the changes before storage.\n *\n * @param state - Thread state\n * @param messageId - ID of message being updated\n * @param updates - Update data\n * @returns Modified update data\n *\n * @example\n * ```typescript\n * defineHook('before_update_message', async (state, messageId, updates) => {\n * return { ...updates, updated_at: Date.now() };\n * });\n * ```\n */\n before_update_message: (\n state: State,\n messageId: string,\n updates: Record<string, unknown>\n ) => Promise<Record<string, unknown>>;\n\n /**\n * Called after a message is updated in the database.\n *\n * Use for logging, analytics, or triggering side effects after\n * message update. Cannot modify the message.\n *\n * @param state - Thread state\n * @param message - The updated message\n *\n * @example\n * ```typescript\n * defineHook('after_update_message', async (state, message) => {\n * console.log(`Message updated: ${message.id}`);\n * });\n * ```\n */\n after_update_message: (state: State, message: Msg) => Promise<void>;\n\n /**\n * Called before a tool result is stored in the database.\n *\n * Receives the tool call and result before storage. Return modified\n * result to transform before storage.\n *\n * @param state - Thread state\n * @param toolCall - The tool call that was executed\n * @param toolResult - The result from tool execution\n * @returns Modified tool result data\n *\n * @example\n * ```typescript\n * defineHook('before_store_tool_result', async (state, toolCall, toolResult) => {\n * // Sanitize sensitive data from results\n * return { ...toolResult, result: sanitize(toolResult.result) };\n * });\n * ```\n */\n before_store_tool_result: (\n state: State,\n toolCall: Record<string, unknown>,\n toolResult: Record<string, unknown>\n ) => Promise<Record<string, unknown>>;\n\n /**\n * Called after a successful tool call.\n *\n * Receives the tool call and its result. Can return a modified result\n * or null to use the original. Use for logging, transformation, or\n * post-processing of successful tool executions.\n *\n * @param state - Thread state\n * @param toolCall - The executed tool call\n * @param toolResult - The successful result\n * @returns Modified result or null for original\n *\n * @example\n * ```typescript\n * defineHook('after_tool_call_success', async (state, toolCall, toolResult) => {\n * console.log(`Tool ${toolCall.function.name} succeeded`);\n * return null; // Use original result\n * });\n * ```\n */\n after_tool_call_success: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult | null>;\n\n /**\n * Called after a failed tool call.\n *\n * Receives the tool call and error result. Can return a modified result\n * or null to use the original. Use for error handling, logging, or\n * recovery attempts.\n *\n * @param state - Thread state\n * @param toolCall - The failed tool call\n * @param toolResult - The error result\n * @returns Modified result or null for original\n *\n * @example\n * ```typescript\n * defineHook('after_tool_call_failure', async (state, toolCall, toolResult) => {\n * console.error(`Tool ${toolCall.function.name} failed: ${toolResult.error}`);\n * return null; // Use original error\n * });\n * ```\n */\n after_tool_call_failure: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult | null>;\n}\n\n/**\n * Valid hook names.\n */\nexport type HookName = keyof HookSignatures;\n\n// ============================================================================\n// Hook Definition\n// ============================================================================\n\n/**\n * Hook definition tuple.\n *\n * A hook definition is a tuple containing the hook name and implementation.\n *\n * @template K - The hook name\n * @template State - The state type (defaults to ThreadState)\n * @template Msg - The message type\n * @template ToolCall - The tool call type\n * @template ToolResult - The tool result type\n */\nexport type HookDefinition<\n K extends HookName = HookName,\n State = ThreadState,\n Msg = HookMessage,\n ToolCall = HookToolCall,\n ToolResult = HookToolResult,\n> = [K, HookSignatures<State, Msg, ToolCall, ToolResult>[K]];\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Define a hook with strict typing based on hook name.\n *\n * Hooks intercept specific points in the agent execution lifecycle.\n * The hook name determines the function signature and when it's called.\n * All hooks receive ThreadState as their first parameter.\n *\n * @template K - The hook name (determines signature)\n * @param hookName - Name of the hook to define\n * @param implementation - Hook implementation function\n * @returns The implementation function (for registration)\n *\n * @example\n * ```typescript\n * // Filter messages to last 10\n * export default defineHook('filter_messages', async (state, messages) => {\n * return messages.slice(-10);\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Log all tool successes\n * export default defineHook('after_tool_call_success', async (state, toolCall, result) => {\n * console.log(`Tool ${toolCall.function.name} completed`);\n * return null; // Use original result\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Transform messages before LLM\n * export default defineHook('prefilter_llm_history', async (state, messages) => {\n * // Add instruction to last message\n * const last = messages[messages.length - 1];\n * if (last?.role === 'user' && typeof last.content === 'string') {\n * last.content += '\\n\\nRemember to be concise.';\n * }\n * return messages;\n * });\n * ```\n */\nexport function defineHook<K extends keyof HookSignatures>(\n hookName: K,\n implementation: HookSignatures[K]\n): HookSignatures[K] {\n // Validate hook name at runtime\n const validHooks: HookName[] = [\n 'filter_messages',\n 'prefilter_llm_history',\n 'before_create_message',\n 'after_create_message',\n 'before_update_message',\n 'after_update_message',\n 'before_store_tool_result',\n 'after_tool_call_success',\n 'after_tool_call_failure',\n ];\n\n if (!validHooks.includes(hookName)) {\n throw new Error(\n `Invalid hook name '${hookName}'. Valid hooks: ${validHooks.join(', ')}`\n );\n }\n\n return implementation;\n}\n","/**\n * Effect definition types for Standard Agents.\n *\n * Effects are scheduled operations that run outside the tool execution context.\n * They enable implementation-specific side effects with optional delay support,\n * leveraging the runtime's scheduling mechanism (e.g., Cloudflare Durable Object alarms).\n *\n * Unlike tools, effects:\n * - Do not return results to the LLM\n * - Can be delayed for future execution\n * - Run independently of the conversation flow\n * - Are ideal for notifications, cleanup, and async operations\n *\n * @module\n */\n\nimport type { z } from 'zod';\nimport type { ThreadState } from './threads.js';\nimport type { ToolArgs } from './tools.js';\n\n// ============================================================================\n// Effect Function Types\n// ============================================================================\n\n/**\n * Effect function signature.\n *\n * Effects are async functions that receive a ThreadState and\n * optionally validated arguments. Unlike tools, they return void\n * since results are not included in the conversation.\n *\n * @template State - The state type (defaults to ThreadState)\n * @template Args - The Zod schema for effect arguments, or null for no args\n */\nexport type Effect<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = Args extends ToolArgs\n ? (state: State, args: z.infer<Args>) => Promise<void> | void\n : (state: State) => Promise<void> | void;\n\n/**\n * Return type of defineEffect function.\n *\n * A tuple containing:\n * - Effect description string\n * - Argument schema (or null)\n * - Effect implementation function\n */\nexport type EffectDefinition<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = [string, Args, Effect<State, Args>];\n\n// ============================================================================\n// Scheduled Effect Types\n// ============================================================================\n\n/**\n * Record of a scheduled effect.\n *\n * Returned by getScheduledEffects() to inspect pending effects.\n */\nexport interface ScheduledEffect {\n /** Unique identifier for this scheduled effect. */\n id: string;\n /** Name of the effect to execute. */\n name: string;\n /** Arguments to pass to the effect handler. */\n args: Record<string, unknown>;\n /** When the effect is scheduled to run (microseconds since epoch). */\n scheduledAt: number;\n /** When the effect was created (microseconds since epoch). */\n createdAt: number;\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Define an effect with arguments.\n *\n * @param description - Description of what the effect does\n * @param args - Zod schema for validating effect arguments\n * @param handler - The effect implementation function\n * @returns A tuple containing the effect definition\n */\nexport function defineEffect<State = ThreadState, Args extends ToolArgs = ToolArgs>(\n description: string,\n args: Args,\n handler: Effect<State, Args>\n): EffectDefinition<State, Args>;\n\n/**\n * Define an effect without arguments.\n *\n * @param description - Description of what the effect does\n * @param handler - The effect implementation function\n * @returns A tuple containing the effect definition\n */\nexport function defineEffect<State = ThreadState>(\n description: string,\n handler: Effect<State, null>\n): EffectDefinition<State, null>;\n\n/**\n * Defines an effect that can be scheduled for execution.\n *\n * Effects are ideal for operations that should happen outside the\n * main conversation flow, such as:\n * - Sending notification emails after a delay\n * - Triggering webhooks\n * - Scheduling cleanup tasks\n * - Running background data processing\n *\n * @example\n * ```typescript\n * import { defineEffect } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default defineEffect(\n * 'Send a reminder email after a delay',\n * z.object({\n * to: z.string().email().describe('Recipient email'),\n * subject: z.string().describe('Email subject'),\n * body: z.string().describe('Email body'),\n * }),\n * async (state, args) => {\n * const env = state._notPackableRuntimeContext?.env as any;\n * await env.EMAIL_SERVICE.send({\n * to: args.to,\n * subject: args.subject,\n * body: args.body,\n * });\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Schedule an effect from a tool\n * const effectId = state.scheduleEffect(\n * 'send_reminder_email',\n * { to: 'user@example.com', subject: 'Reminder', body: 'Hello!' },\n * 30 * 60 * 1000 // 30 minutes\n * );\n * ```\n */\nexport function defineEffect<\n State = ThreadState,\n Args extends ToolArgs = ToolArgs,\n>(\n description: string,\n argsOrHandler: Args | Effect<State, null>,\n maybeHandler?: Effect<State, Args>\n): EffectDefinition<State, Args | null> {\n if (maybeHandler) {\n return [\n description,\n argsOrHandler as Args,\n maybeHandler,\n ];\n }\n return [\n description,\n null,\n argsOrHandler as Effect<State, null>,\n ];\n}\n","/**\n * Agent definition types for Standard Agents.\n *\n * Agents orchestrate conversations between AI models (dual_ai) or between\n * AI and human users (ai_human). They define the prompts, stop conditions,\n * and behavioral rules for each side of the conversation.\n *\n * @module\n */\n\n// ============================================================================\n// Agent Types\n// ============================================================================\n\n/**\n * Agent conversation type.\n *\n * - `ai_human`: AI conversing with a human user (most common)\n * - `dual_ai`: Two AI participants conversing with each other\n */\nexport type AgentType = 'ai_human' | 'dual_ai';\n\n// ============================================================================\n// Side Configuration\n// ============================================================================\n\n/**\n * Configuration for one side of an agent conversation.\n *\n * Each side has a prompt, stop conditions, and turn limits.\n * For `ai_human` agents, only sideA (the AI) needs configuration.\n * For `dual_ai` agents, both sides need configuration.\n *\n * @template Prompt - The prompt reference type (string or type-safe union)\n * @template Callable - The callable reference type (string or type-safe union)\n *\n * @example\n * ```typescript\n * const sideConfig: SideConfig = {\n * label: 'Support Agent',\n * prompt: 'customer_support',\n * stopOnResponse: true,\n * maxSteps: 10,\n * };\n * ```\n */\nexport interface SideConfig<\n Prompt extends string = string,\n Callable extends string = string,\n> {\n /**\n * Custom label for this side of the conversation.\n * Used in UI and logs for clarity.\n *\n * @example 'Support Agent', 'Customer', 'ATC', 'Pilot'\n */\n label?: string;\n\n /**\n * The prompt to use for this side.\n * Must reference a prompt defined in agents/prompts/.\n */\n prompt: Prompt;\n\n /**\n * Stop this side's turn when it returns a text response (no tool calls).\n * When true, the side's turn ends after producing a message without tools.\n * @default true\n */\n stopOnResponse?: boolean;\n\n /**\n * Stop this side's turn when a specific tool is called.\n * Overrides stopOnResponse when the named tool is invoked.\n * Requires stopToolResponseProperty to extract the result.\n */\n stopTool?: Callable;\n\n /**\n * Property to extract from the stop tool's result.\n * Required when stopTool is set.\n * The extracted value is used to determine the conversation outcome.\n */\n stopToolResponseProperty?: string;\n\n /**\n * Maximum steps for this side before forcing a stop.\n * Safety limit to prevent runaway execution.\n * A step is one complete LLM request/response cycle.\n */\n maxSteps?: number;\n\n /**\n * Tool that ends the entire session when called.\n * Different from stopTool - this ends the session for both sides,\n * not just this side's turn.\n */\n endSessionTool?: Callable;\n}\n\n// ============================================================================\n// Agent Definition\n// ============================================================================\n\n/**\n * Agent definition configuration.\n *\n * @template N - The agent name as a string literal type\n * @template Prompt - The prompt reference type (string or type-safe union)\n * @template Callable - The callable reference type (string or type-safe union)\n *\n * @example\n * ```typescript\n * import { defineAgent } from '@standardagents/spec';\n *\n * export default defineAgent({\n * name: 'support_agent',\n * title: 'Customer Support Agent',\n * type: 'ai_human',\n * sideA: {\n * label: 'Support',\n * prompt: 'customer_support',\n * stopOnResponse: true,\n * },\n * });\n * ```\n */\nexport interface AgentDefinition<\n N extends string = string,\n Prompt extends string = string,\n Callable extends string = string,\n> {\n /**\n * Unique name for this agent.\n * Used as the identifier for thread creation and handoffs.\n * Should be snake_case (e.g., 'support_agent', 'research_flow').\n */\n name: N;\n\n /**\n * Human-readable title for the agent.\n * Optional - if not provided, the name will be used.\n * @deprecated Use name instead. Title will be removed in a future version.\n */\n title?: string;\n\n /**\n * Agent conversation type.\n *\n * - `ai_human`: AI conversing with a human user (default)\n * - `dual_ai`: Two AI participants conversing\n *\n * @default 'ai_human'\n */\n type?: AgentType;\n\n /**\n * Maximum total turns across both sides.\n * Only applies to `dual_ai` agents.\n * Prevents infinite loops in AI-to-AI conversations.\n */\n maxSessionTurns?: number;\n\n /**\n * Configuration for Side A.\n * For `ai_human`: This is the AI side.\n * For `dual_ai`: This is the first AI participant.\n */\n sideA: SideConfig<Prompt, Callable>;\n\n /**\n * Configuration for Side B.\n * For `ai_human`: Optional, the human side doesn't need config.\n * For `dual_ai`: Required, the second AI participant.\n */\n sideB?: SideConfig<Prompt, Callable>;\n\n /**\n * Expose this agent as a tool for other prompts.\n * Enables agent composition and handoffs.\n * When true, other prompts can invoke this agent as a tool.\n * @default false\n */\n exposeAsTool?: boolean;\n\n /**\n * Description shown when agent is used as a tool.\n * Required if exposeAsTool is true.\n * Should clearly describe what this agent does.\n */\n toolDescription?: string;\n\n /**\n * Brief description of what this agent does.\n * Useful for UIs and documentation.\n *\n * @example 'Handles customer support inquiries and resolves issues'\n */\n description?: string;\n\n /**\n * Icon URL or absolute path for the agent.\n * Absolute paths (starting with `/`) are converted to full URLs in API responses.\n *\n * @example 'https://example.com/icon.svg' or '/icons/support.svg'\n */\n icon?: string;\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Defines an agent configuration.\n *\n * Agents orchestrate conversations between AI models, or between AI and\n * human users. They use prompts to configure each side of the conversation\n * and define stop conditions to control conversation flow.\n *\n * @template N - The agent name as a string literal type\n * @param options - Agent configuration options\n * @returns The agent definition for registration\n *\n * @example\n * ```typescript\n * // agents/agents/support_agent.ts\n * import { defineAgent } from '@standardagents/spec';\n *\n * export default defineAgent({\n * name: 'support_agent',\n * title: 'Customer Support Agent',\n * type: 'ai_human',\n * sideA: {\n * label: 'Support',\n * prompt: 'customer_support',\n * stopOnResponse: true,\n * endSessionTool: 'close_ticket',\n * },\n * exposeAsTool: true,\n * toolDescription: 'Hand off to customer support',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Dual AI agent (two AIs conversing)\n * export default defineAgent({\n * name: 'debate_agent',\n * title: 'AI Debate',\n * type: 'dual_ai',\n * maxSessionTurns: 10,\n * sideA: {\n * label: 'Pro',\n * prompt: 'debate_pro',\n * stopOnResponse: true,\n * },\n * sideB: {\n * label: 'Con',\n * prompt: 'debate_con',\n * stopOnResponse: true,\n * endSessionTool: 'conclude_debate',\n * },\n * });\n * ```\n */\nexport function defineAgent<N extends string>(\n options: AgentDefinition<N>\n): AgentDefinition<N> {\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Agent name is required');\n }\n if (!options.sideA) {\n throw new Error('Agent sideA configuration is required');\n }\n if (!options.sideA.prompt) {\n throw new Error('Agent sideA.prompt is required');\n }\n\n // Set default type\n const type = options.type ?? 'ai_human';\n\n // Validate dual_ai requires sideB\n if (type === 'dual_ai') {\n if (!options.sideB) {\n throw new Error('Agent sideB configuration is required for dual_ai type');\n }\n if (!options.sideB.prompt) {\n throw new Error('Agent sideB.prompt is required for dual_ai type');\n }\n }\n\n // Validate exposeAsTool requires toolDescription\n if (options.exposeAsTool && !options.toolDescription) {\n throw new Error('toolDescription is required when exposeAsTool is true');\n }\n\n // Validate stopTool requires stopToolResponseProperty\n if (options.sideA.stopTool && !options.sideA.stopToolResponseProperty) {\n throw new Error('sideA.stopToolResponseProperty is required when sideA.stopTool is set');\n }\n if (options.sideB?.stopTool && !options.sideB.stopToolResponseProperty) {\n throw new Error('sideB.stopToolResponseProperty is required when sideB.stopTool is set');\n }\n\n // Validate maxSteps is positive\n if (options.sideA.maxSteps !== undefined && options.sideA.maxSteps <= 0) {\n throw new Error('sideA.maxSteps must be a positive number');\n }\n if (options.sideB?.maxSteps !== undefined && options.sideB.maxSteps <= 0) {\n throw new Error('sideB.maxSteps must be a positive number');\n }\n if (\n options.maxSessionTurns !== undefined &&\n options.maxSessionTurns !== null &&\n options.maxSessionTurns <= 0\n ) {\n throw new Error('maxSessionTurns must be a positive number');\n }\n\n // Validate type is a known value\n if (!['ai_human', 'dual_ai'].includes(type)) {\n throw new Error(`Invalid type '${type}'. Must be one of: ai_human, dual_ai`);\n }\n\n return {\n ...options,\n type,\n };\n}\n","/**\n * Endpoint definition types for Standard Agents.\n *\n * Endpoints expose HTTP APIs for interacting with agent threads.\n * They can be standard controllers or thread-specific endpoints\n * with automatic ThreadState injection.\n *\n * @module\n */\n\nimport type { ThreadState } from './threads.js';\n\n// ============================================================================\n// Virtual Module Types\n// ============================================================================\n\n/**\n * Virtual module loader function.\n *\n * Lazy-loads a module definition on demand.\n */\nexport type VirtualModuleLoader<T> = () => Promise<T>;\n\n/**\n * Registry of virtual modules by name.\n *\n * Maps module names to their lazy loaders.\n */\nexport type VirtualModuleRegistry<T> = Record<string, VirtualModuleLoader<T>>;\n\n// ============================================================================\n// Controller Types\n// ============================================================================\n\n/**\n * Controller context passed to route handlers.\n *\n * Contains the request, URL parameters, environment bindings,\n * and optionally the virtual module registries injected at runtime.\n *\n * Note: The `env` property contains implementation-specific bindings.\n * Cloudflare implementations may include Durable Object namespaces,\n * KV namespaces, etc. Other implementations may provide different bindings.\n */\nexport interface ControllerContext {\n /** The incoming HTTP request */\n req: Request;\n\n /** URL path parameters extracted by the router */\n params: Record<string, string>;\n\n /** Parsed URL object */\n url: URL;\n\n /**\n * Environment bindings (implementation-specific).\n *\n * Contains platform-specific bindings like Durable Objects, KV, etc.\n * The exact contents depend on the runtime implementation.\n */\n env: Record<string, unknown>;\n\n /** Registry of agent definitions (injected at runtime) */\n agents?: VirtualModuleRegistry<unknown>;\n\n /** Available agent names */\n agentNames?: string[];\n\n /** Registry of prompt definitions (injected at runtime) */\n prompts?: VirtualModuleRegistry<unknown>;\n\n /** Available prompt names */\n promptNames?: string[];\n\n /** Registry of model definitions (injected at runtime) */\n models?: VirtualModuleRegistry<unknown>;\n\n /** Available model names */\n modelNames?: string[];\n\n /** Registry of tool definitions (injected at runtime) */\n tools?: VirtualModuleRegistry<unknown>;\n\n /** Registry of hook definitions (injected at runtime) */\n hooks?: VirtualModuleRegistry<unknown>;\n\n /** Additional configuration (injected at runtime) */\n config?: Record<string, unknown>;\n}\n\n/**\n * Controller return types.\n *\n * Controllers can return various types that are automatically\n * converted to appropriate HTTP responses.\n */\nexport type ControllerReturn =\n | string\n | Promise<string>\n | Response\n | Promise<Response>\n | ReadableStream\n | Promise<ReadableStream>\n | null\n | Promise<null>\n | void\n | Promise<void>\n | Promise<object>\n | object;\n\n/**\n * Controller function type.\n *\n * Controllers handle HTTP requests and return responses.\n * The return value is automatically converted to a Response.\n *\n * @example\n * ```typescript\n * const handler: Controller = async ({ req, params, url }) => {\n * return { message: 'Hello, World!' };\n * };\n * ```\n */\nexport type Controller = (context: ControllerContext) => ControllerReturn;\n\n// ============================================================================\n// Thread Endpoint Types\n// ============================================================================\n\n/**\n * Thread endpoint handler function.\n *\n * Receives the HTTP request and the ThreadState for the requested thread.\n * The thread is automatically looked up by ID from URL parameters.\n */\nexport type ThreadEndpointHandler = (\n req: Request,\n state: ThreadState\n) => Response | Promise<Response>;\n\n// ============================================================================\n// Define Functions\n// ============================================================================\n\n/**\n * Define a standard HTTP controller.\n *\n * Controllers handle HTTP requests and return responses. They have\n * access to the controller context including virtual module registries.\n *\n * @param controller - The controller function\n * @returns The controller for registration\n *\n * @example\n * ```typescript\n * // agents/api/health.get.ts\n * import { defineController } from '@standardagents/spec';\n *\n * export default defineController(async () => {\n * return { status: 'ok', timestamp: Date.now() };\n * });\n * ```\n *\n * @example\n * ```typescript\n * // agents/api/agents/index.get.ts\n * import { defineController } from '@standardagents/spec';\n *\n * export default defineController(async ({ agentNames }) => {\n * return { agents: agentNames };\n * });\n * ```\n */\nexport function defineController(controller: Controller): Controller {\n return controller;\n}\n\n/**\n * Define a thread-specific endpoint.\n *\n * Thread endpoints automatically look up the thread by ID from URL params\n * and provide access to the ThreadState. The handler receives full\n * ThreadState with messages, logs, resource loading, event emission,\n * and (when executing) execution state.\n *\n * @param handler - The handler function receiving request and ThreadState\n * @returns A Controller that can be used with the router\n *\n * @example\n * ```typescript\n * // agents/api/threads/[id]/status.get.ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state) => {\n * const { messages, total } = await state.getMessages({ limit: 1 });\n * return Response.json({\n * threadId: state.threadId,\n * agent: state.agentId,\n * messageCount: total,\n * });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // agents/api/threads/[id]/export.get.ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state) => {\n * const { messages } = await state.getMessages();\n * const logs = await state.getLogs();\n * return Response.json({\n * thread: {\n * id: state.threadId,\n * agent: state.agentId,\n * user: state.userId,\n * createdAt: state.createdAt,\n * },\n * messages,\n * logs,\n * });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // agents/api/threads/[id]/invoke.post.ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state) => {\n * const { tool, args } = await req.json();\n *\n * // Queue a tool for execution (starts execution if not running)\n * state.queueTool(tool, args);\n *\n * return Response.json({ queued: true });\n * });\n * ```\n */\nexport function defineThreadEndpoint(\n handler: ThreadEndpointHandler\n): Controller {\n // The actual implementation is provided by the runtime.\n // This is a marker function that the router recognizes.\n // The runtime wraps this to provide ThreadState.\n return (handler as unknown) as Controller;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/models.ts","../src/tools.ts","../src/prompts.ts","../src/hooks.ts","../src/effects.ts","../src/agents.ts","../src/endpoints.ts"],"sourcesContent":["/**\n * Model definition types for Standard Agents.\n *\n * Models define LLM configurations including provider, model ID, pricing,\n * and fallback chains. Models are referenced by name from prompts.\n *\n * @module\n */\n\n/**\n * Supported LLM provider identifiers.\n *\n * Each provider requires a corresponding API key environment variable:\n * - `openai` → `OPENAI_API_KEY`\n * - `openrouter` → `OPENROUTER_API_KEY`\n * - `anthropic` → `ANTHROPIC_API_KEY`\n * - `google` → `GOOGLE_API_KEY`\n * - `test` → No API key required (for testing with scripted responses)\n */\nexport type ModelProvider = 'openai' | 'openrouter' | 'anthropic' | 'google' | 'test';\n\n/**\n * Model capability flags indicating supported features.\n */\nexport interface ModelCapabilities {\n /**\n * Whether the model supports vision (image understanding).\n * When true, image attachments will be sent to the model as part of the request.\n * Models like GPT-4o, Claude 3, and Gemini support vision.\n */\n vision?: boolean;\n\n /**\n * Whether the model supports function calling (tool use).\n * Most modern models support this, defaults to true if not specified.\n */\n functionCalling?: boolean;\n\n /**\n * Whether the model supports structured outputs (JSON mode).\n */\n structuredOutputs?: boolean;\n}\n\n/**\n * Model definition configuration.\n *\n * Defines an LLM model with its provider, pricing, capabilities, and fallback chain.\n *\n * @template N - The model name as a string literal type for type inference\n *\n * @example\n * ```typescript\n * import { defineModel } from '@standardagents/spec';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: 'openai',\n * model: 'gpt-4o',\n * fallbacks: ['gpt-4-turbo', 'gpt-3.5-turbo'],\n * inputPrice: 2.5,\n * outputPrice: 10,\n * });\n * ```\n */\nexport interface ModelDefinition<N extends string = string> {\n /**\n * Unique name for this model definition.\n * Used as the identifier when referencing from prompts.\n * Should be descriptive and consistent (e.g., 'gpt-4o', 'claude-3-opus').\n */\n name: N;\n\n /**\n * The LLM provider to use for API calls.\n * The corresponding API key environment variable must be set.\n */\n provider: ModelProvider;\n\n /**\n * The actual model identifier sent to the provider API.\n *\n * For OpenAI: 'gpt-4o', 'gpt-4-turbo', 'gpt-3.5-turbo', etc.\n * For OpenRouter: 'openai/gpt-4o', 'anthropic/claude-3-opus', etc.\n * For Anthropic: 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', etc.\n * For Google: 'gemini-1.5-pro', 'gemini-1.5-flash', etc.\n */\n model: string;\n\n /**\n * Optional list of additional provider prefixes for OpenRouter.\n * Allows routing through specific providers when using OpenRouter.\n *\n * @example ['anthropic', 'google'] - prefer Anthropic, fallback to Google\n */\n includedProviders?: string[];\n\n /**\n * Fallback model names to try if this model fails.\n * Referenced by model name (must be defined in agents/models/).\n * Tried in order after primary model exhausts retries.\n *\n * @example ['gpt-4', 'gpt-3.5-turbo']\n */\n fallbacks?: string[];\n\n /**\n * Cost per 1 million input tokens in USD.\n * Used for cost tracking and reporting in logs.\n */\n inputPrice?: number;\n\n /**\n * Cost per 1 million output tokens in USD.\n * Used for cost tracking and reporting in logs.\n */\n outputPrice?: number;\n\n /**\n * Cost per 1 million cached input tokens in USD.\n * Some providers offer reduced pricing for cached/repeated prompts.\n */\n cachedPrice?: number;\n\n /**\n * Model capabilities - features this model supports.\n */\n capabilities?: ModelCapabilities;\n}\n\n/**\n * Defines an LLM model configuration.\n *\n * Models are the foundation of the agent system - they specify which\n * AI model to use and how to connect to it. Models can have fallbacks\n * for reliability and include pricing for cost tracking.\n *\n * @template N - The model name as a string literal type\n * @param options - Model configuration options\n * @returns The model definition for registration\n *\n * @example\n * ```typescript\n * // agents/models/gpt_4o.ts\n * import { defineModel } from '@standardagents/spec';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: 'openai',\n * model: 'gpt-4o',\n * fallbacks: ['gpt-4-turbo'],\n * inputPrice: 2.5,\n * outputPrice: 10,\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Using OpenRouter with provider preferences\n * export default defineModel({\n * name: 'claude-3-opus',\n * provider: 'openrouter',\n * model: 'anthropic/claude-3-opus',\n * includedProviders: ['anthropic'],\n * });\n * ```\n */\nexport function defineModel<N extends string>(\n options: ModelDefinition<N>\n): ModelDefinition<N> {\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Model name is required');\n }\n if (!options.provider) {\n throw new Error('Model provider is required');\n }\n if (!options.model) {\n throw new Error('Model ID is required');\n }\n\n // Validate provider is a known type\n const validProviders: ModelProvider[] = ['openai', 'openrouter', 'anthropic', 'google', 'test'];\n if (!validProviders.includes(options.provider)) {\n throw new Error(\n `Invalid provider '${options.provider}'. Must be one of: ${validProviders.join(', ')}`\n );\n }\n\n // Validate pricing is non-negative if provided\n if (options.inputPrice !== undefined && options.inputPrice < 0) {\n throw new Error('inputPrice must be non-negative');\n }\n if (options.outputPrice !== undefined && options.outputPrice < 0) {\n throw new Error('outputPrice must be non-negative');\n }\n if (options.cachedPrice !== undefined && options.cachedPrice < 0) {\n throw new Error('cachedPrice must be non-negative');\n }\n\n return options;\n}\n","/**\n * Tool definition types for Standard Agents.\n *\n * Tools are callable functions that agents can invoke during execution.\n * They receive the current ThreadState and validated arguments,\n * and return results that are included in the conversation.\n *\n * @module\n */\n\nimport type { ThreadState } from './threads.js';\nimport type {\n ZodString,\n ZodNumber,\n ZodBoolean,\n ZodEnum,\n ZodArray,\n ZodObject,\n ZodOptional,\n ZodNullable,\n ZodUnion,\n ZodRecord,\n ZodNull,\n ZodLiteral,\n ZodDefault,\n} from 'zod';\nimport { z } from 'zod';\n\n/**\n * Text content item returned by tools.\n */\nexport interface TextContent {\n type: 'text';\n text: string;\n}\n\n/**\n * Image content item returned by tools.\n */\nexport interface ImageContent {\n type: 'image';\n /** Base64-encoded image data. */\n data: string;\n /** MIME type of the image (e.g., 'image/png', 'image/jpeg'). */\n mimeType: string;\n}\n\n/**\n * Content types that can be returned by tools.\n */\nexport type ToolContent = TextContent | ImageContent;\n\n/**\n * File attachment generated by a tool.\n *\n * Attachments are stored in the thread's file system and linked to\n * the tool result message. Unlike user uploads, tool attachments are\n * not subject to image downsampling.\n */\nexport interface ToolAttachment {\n /** File name for the attachment. */\n name: string;\n /** MIME type of the attachment. */\n mimeType: string;\n /** Base64-encoded file data. */\n data: string;\n /** Width in pixels (for images). */\n width?: number;\n /** Height in pixels (for images). */\n height?: number;\n}\n\n/**\n * Reference to a pre-existing attachment in the thread file system.\n */\nexport interface AttachmentRef {\n /** Unique identifier for the attachment. */\n id: string;\n /** Attachment type. */\n type: 'file';\n /** Path in the thread file system. */\n path: string;\n /** File name. */\n name: string;\n /** MIME type. */\n mimeType: string;\n /** File size in bytes. */\n size: number;\n /** Width in pixels (for images). */\n width?: number;\n /** Height in pixels (for images). */\n height?: number;\n /** AI-generated description. */\n description?: string;\n}\n\n/**\n * Result returned by a tool execution.\n */\nexport interface ToolResult {\n /** Status of the tool execution. */\n status: 'success' | 'error';\n /**\n * Text representation of the tool output.\n *\n * For tools that return structured content, this is derived by\n * concatenating all text parts. For simple tools, this is the\n * direct result string.\n */\n result?: string;\n /** Error message if status is 'error'. */\n error?: string;\n /** Stack trace for error debugging. */\n stack?: string;\n /**\n * File attachments returned by the tool.\n *\n * Can contain either:\n * - ToolAttachment: New files with base64 data to be stored\n * - AttachmentRef: References to existing files in the thread filesystem\n *\n * Implementations MUST store new attachments under /attachments/ directory.\n */\n attachments?: Array<ToolAttachment | AttachmentRef>;\n}\n\n// ============================================================================\n// Tool Argument Types (Zod-based)\n// ============================================================================\n\n/** Decrement helper to limit recursion depth. */\ntype Dec<N extends number> = N extends 10\n ? 9\n : N extends 9\n ? 8\n : N extends 8\n ? 7\n : N extends 7\n ? 6\n : N extends 6\n ? 5\n : N extends 5\n ? 4\n : N extends 4\n ? 3\n : N extends 3\n ? 2\n : N extends 2\n ? 1\n : N extends 1\n ? 0\n : 0;\n\n/**\n * Allowed Zod types for tool argument nodes.\n *\n * This is the single source of truth for which Zod types can be used\n * in tool argument schemas. The depth parameter limits recursion to\n * prevent infinite type expansion.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolArgsNode<D extends number = 7> =\n // Primitives and literals\n | ZodString\n | ZodNumber\n | ZodBoolean\n | ZodNull\n | ZodLiteral<string | number | boolean | null>\n // Enums (Zod v4 uses Record<string, string> for enum type parameter)\n | ZodEnum<Readonly<Record<string, string>>>\n // Wrappers (with depth check)\n | (D extends 0 ? never : ZodOptional<ToolArgsNode<Dec<D>>>)\n | (D extends 0 ? never : ZodNullable<ToolArgsNode<Dec<D>>>)\n | (D extends 0 ? never : ZodDefault<ToolArgsNode<Dec<D>>>)\n // Arrays (with depth check)\n | (D extends 0 ? never : ZodArray<ToolArgsNode<Dec<D>>>)\n // Objects and records (with depth check)\n | (D extends 0 ? never : ZodObject<Record<string, ToolArgsNode<Dec<D>>>>)\n | (D extends 0 ? never : ZodRecord<ZodString, ToolArgsNode<Dec<D>>>)\n // Unions (with depth check)\n | (D extends 0\n ? never\n : ZodUnion<\n [\n ToolArgsNode<Dec<D>>,\n ToolArgsNode<Dec<D>>,\n ...ToolArgsNode<Dec<D>>[],\n ]\n >);\n\n/**\n * Raw shape for a Zod object schema containing tool argument nodes.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolArgsRawShape<D extends number = 7> = Record<\n string,\n ToolArgsNode<D>\n>;\n\n/**\n * Top-level tool argument schema.\n *\n * Tool arguments MUST be defined as a Zod object schema.\n * This is required for compatibility with OpenAI's function calling API.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolArgs<D extends number = 7> = z.ZodObject<ToolArgsRawShape<D>>;\n\n\n// ============================================================================\n// Tool Function Types\n// ============================================================================\n\n/**\n * Tool function signature.\n *\n * Tools are async functions that receive a ThreadState and\n * optionally validated arguments, returning a ToolResult.\n *\n * @template State - The state type (defaults to ThreadState)\n * @template Args - The Zod schema for tool arguments, or null for no args\n */\nexport type Tool<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = Args extends ToolArgs\n ? (state: State, args: z.infer<Args>) => Promise<ToolResult>\n : (state: State) => Promise<ToolResult>;\n\n/**\n * Return type of defineTool function.\n *\n * A tuple containing:\n * - Tool description string\n * - Argument schema (or null)\n * - Tool implementation function\n */\nexport type ToolDefinition<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = [string, Args, Tool<State, Args>];\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Define a tool with arguments.\n *\n * @param toolDescription - Description of what the tool does (shown to the LLM)\n * @param args - Zod schema for validating tool arguments\n * @param tool - The tool implementation function\n * @returns A tuple containing the tool definition\n */\nexport function defineTool<State = ThreadState, Args extends ToolArgs = ToolArgs>(\n toolDescription: string,\n args: Args,\n tool: Tool<State, Args>\n): ToolDefinition<State, Args>;\n\n/**\n * Define a tool without arguments.\n *\n * @param toolDescription - Description of what the tool does (shown to the LLM)\n * @param tool - The tool implementation function\n * @returns A tuple containing the tool definition\n */\nexport function defineTool<State = ThreadState>(\n toolDescription: string,\n tool: Tool<State, null>\n): ToolDefinition<State, null>;\n\n/**\n * Defines a tool that agents can call during execution.\n *\n * Tools are the primary way agents interact with external systems.\n * Each tool has a description (shown to the LLM), optional argument\n * schema (validated at runtime), and an implementation function.\n *\n * @example\n * ```typescript\n * import { defineTool } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default defineTool(\n * 'Search the knowledge base for relevant information',\n * z.object({\n * query: z.string().describe('Search query'),\n * limit: z.number().optional().describe('Max results'),\n * }),\n * async (state, args) => {\n * const results = await search(args.query, args.limit);\n * return {\n * status: 'success',\n * result: JSON.stringify(results),\n * };\n * }\n * );\n * ```\n */\nexport function defineTool<\n State = ThreadState,\n Args extends ToolArgs = ToolArgs,\n>(\n toolDescription: string,\n argsOrTool: Args | Tool<State, null>,\n maybeTool?: Tool<State, Args>\n): ToolDefinition<State, Args | null> {\n if (maybeTool) {\n return [\n toolDescription,\n argsOrTool as Args,\n maybeTool,\n ];\n }\n return [\n toolDescription,\n null,\n argsOrTool as Tool<State, null>,\n ];\n}\n","/**\n * Prompt definition types for Standard Agents.\n *\n * Prompts define LLM interaction configurations including the system prompt,\n * model selection, available tools, and various behavioral options.\n *\n * @module\n */\n\nimport type { z } from 'zod';\nimport type { ToolArgs } from './tools.js';\n\n// ============================================================================\n// Structured Prompt Types\n// ============================================================================\n\n/**\n * A text part of a prompt - static text content.\n *\n * @example\n * ```typescript\n * { type: 'text', content: 'You are a helpful assistant.\\n\\n' }\n * ```\n */\nexport interface PromptTextPart {\n type: 'text';\n /** The text content */\n content: string;\n}\n\n/**\n * A prompt inclusion part - includes another prompt's content.\n *\n * @example\n * ```typescript\n * { type: 'include', prompt: 'responder_rules' }\n * ```\n */\nexport interface PromptIncludePart {\n type: 'include';\n /** The name of the prompt to include */\n prompt: string;\n}\n\n/**\n * A single part of a structured prompt.\n * Discriminated union on `type` field for TypeScript narrowing.\n */\nexport type PromptPart = PromptTextPart | PromptIncludePart;\n\n/**\n * A structured prompt is an array of prompt parts.\n * Provides composition with other prompts via includes.\n *\n * @example\n * ```typescript\n * prompt: [\n * { type: 'text', content: 'You are a helpful assistant.\\n\\n' },\n * { type: 'include', prompt: 'common_rules' },\n * { type: 'text', content: '\\n\\nBe concise.' },\n * ]\n * ```\n */\nexport type StructuredPrompt = PromptPart[];\n\n/**\n * The prompt content can be either a plain string or a structured array.\n *\n * @example\n * ```typescript\n * // Simple string prompt:\n * prompt: 'You are a helpful assistant.'\n *\n * // Structured prompt with includes:\n * prompt: [\n * { type: 'text', content: 'You are a helpful assistant.\\n\\n' },\n * { type: 'include', prompt: 'common_rules' },\n * ]\n * ```\n */\nexport type PromptContent = string | StructuredPrompt;\n\n// ============================================================================\n// Sub-Prompt Configuration\n// ============================================================================\n\n/**\n * Configuration for sub-prompts used as tools.\n * These options control how results from sub-prompts are returned to the caller.\n *\n * @template T - The sub-prompt name type (for type-safe references)\n */\nexport interface SubpromptConfig<T extends string = string> {\n /**\n * Name of the sub-prompt to call.\n * Must be a prompt defined in agents/prompts/.\n */\n name: T;\n\n /**\n * Include text response content from sub-prompt execution in the result string.\n * @default true\n */\n includeTextResponse?: boolean;\n\n /**\n * Serialize tool calls made by the sub-prompt (and their results) into the result string.\n * @default true\n */\n includeToolCalls?: boolean;\n\n /**\n * Serialize any errors from the sub-prompt into the result string.\n * @default true\n */\n includeErrors?: boolean;\n\n /**\n * Property from the tool call arguments to use as the initial user message\n * when invoking the sub-prompt.\n *\n * @example\n * If the tool is called with `{ query: \"search term\", limit: 10 }` and\n * `initUserMessageProperty: 'query'`, the sub-prompt will receive\n * \"search term\" as the initial user message.\n */\n initUserMessageProperty?: string;\n}\n\n/**\n * @deprecated Use SubpromptConfig instead\n */\nexport type ToolConfig<T extends string = string> = SubpromptConfig<T>;\n\n// ============================================================================\n// Reasoning Configuration\n// ============================================================================\n\n/**\n * Reasoning configuration for models that support extended thinking.\n * Applies to models like OpenAI o1, Anthropic Claude with extended thinking,\n * Google Gemini with thinking, and Qwen with reasoning.\n */\nexport interface ReasoningConfig {\n /**\n * Effort level for reasoning models.\n * Higher effort = more thinking tokens = potentially better results.\n *\n * - `low`: Minimal reasoning, faster responses\n * - `medium`: Balanced reasoning and speed\n * - `high`: Maximum reasoning, slower but more thorough\n *\n * @default undefined (use model defaults)\n */\n effort?: 'low' | 'medium' | 'high';\n\n /**\n * Maximum tokens to allocate for reasoning.\n * Applies to models that support token limits on reasoning.\n */\n maxTokens?: number;\n\n /**\n * Use reasoning internally but exclude from the response.\n * Model thinks through the problem but only returns the final answer.\n * Useful for cleaner outputs while maintaining reasoning quality.\n */\n exclude?: boolean;\n\n /**\n * Include reasoning content in the message history for multi-turn context.\n * When true, reasoning is preserved and visible to subsequent turns.\n * @default false\n */\n include?: boolean;\n}\n\n// ============================================================================\n// Prompt Definition\n// ============================================================================\n\n/**\n * Prompt definition configuration.\n *\n * @template N - The prompt name as a string literal type\n * @template S - The Zod schema type for requiredSchema (inferred automatically)\n *\n * @example\n * ```typescript\n * import { definePrompt } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default definePrompt({\n * name: 'customer_support',\n * toolDescription: 'Handle customer support inquiries',\n * model: 'gpt-4o',\n * prompt: 'You are a helpful customer support agent.',\n * tools: ['search_knowledge_base', 'create_ticket'],\n * requiredSchema: z.object({\n * query: z.string().describe('The customer inquiry'),\n * }),\n * });\n * ```\n */\nexport interface PromptDefinition<\n N extends string = string,\n S extends ToolArgs = ToolArgs,\n> {\n /**\n * Unique name for this prompt.\n * Used as the identifier when referencing from agents or as a tool.\n * Should be snake_case (e.g., 'customer_support', 'data_analyst').\n */\n name: N;\n\n /**\n * Description shown when this prompt is exposed as a tool.\n * Should clearly describe what this prompt does for LLM tool selection.\n */\n toolDescription: string;\n\n /**\n * The system prompt content sent to the LLM.\n * Can be either a plain string or a structured array for composition.\n */\n prompt: PromptContent;\n\n /**\n * Model to use for this prompt.\n * Must reference a model defined in agents/models/.\n */\n model: string;\n\n /**\n * Include full chat history in the LLM context.\n * @default false\n */\n includeChat?: boolean;\n\n /**\n * Include results from past tool calls in the LLM context.\n * @default false\n */\n includePastTools?: boolean;\n\n /**\n * Allow parallel execution of multiple tool calls.\n * @default false\n */\n parallelToolCalls?: boolean;\n\n /**\n * Tool calling strategy for the LLM.\n *\n * - `auto`: Model decides when to call tools (default)\n * - `none`: Disable tool calling entirely\n * - `required`: Force the model to call at least one tool\n *\n * @default 'auto'\n */\n toolChoice?: 'auto' | 'none' | 'required';\n\n /**\n * Zod schema for validating inputs when this prompt is called as a tool.\n */\n requiredSchema?: S;\n\n /**\n * Tools available to this prompt.\n * Can be simple tool names or sub-prompt configurations.\n * To enable handoffs, include ai_human agent names in this array.\n */\n tools?: (string | SubpromptConfig)[];\n\n /**\n * Reasoning configuration for models that support extended thinking.\n */\n reasoning?: ReasoningConfig;\n\n /**\n * Number of recent messages to keep actual images for in context.\n * @default 10\n */\n recentImageThreshold?: number;\n}\n\n/**\n * Helper type to extract the inferred input type from a prompt's Zod schema.\n *\n * @template T - The prompt definition type\n */\nexport type PromptInput<T extends PromptDefinition<string, ToolArgs>> =\n T['requiredSchema'] extends ToolArgs\n ? z.infer<T['requiredSchema']>\n : never;\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Defines a prompt configuration for LLM interactions.\n *\n * Prompts are the primary way to configure how agents interact with LLMs.\n * They specify the system prompt, available tools, input validation,\n * and various behavioral options.\n *\n * @template N - The prompt name as a string literal type\n * @template S - The Zod schema type for requiredSchema\n * @param options - Prompt configuration options\n * @returns The prompt definition for registration\n *\n * @example\n * ```typescript\n * import { definePrompt } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default definePrompt({\n * name: 'customer_support',\n * toolDescription: 'Handle customer support inquiries',\n * model: 'gpt-4o',\n * prompt: 'You are a helpful customer support agent.',\n * tools: ['search_knowledge_base', 'create_ticket'],\n * includeChat: true,\n * requiredSchema: z.object({\n * query: z.string().describe('The customer inquiry'),\n * }),\n * });\n * ```\n */\nexport function definePrompt<N extends string, S extends ToolArgs = never>(\n options: PromptDefinition<N, S>\n): PromptDefinition<N, S> {\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Prompt name is required');\n }\n if (!options.toolDescription) {\n throw new Error('Prompt toolDescription is required');\n }\n if (!options.model) {\n throw new Error('Prompt model is required');\n }\n if (!options.prompt) {\n throw new Error('Prompt content is required');\n }\n\n // Validate toolChoice is a known value\n if (\n options.toolChoice &&\n !['auto', 'none', 'required'].includes(options.toolChoice)\n ) {\n throw new Error(\n `Invalid toolChoice '${options.toolChoice}'. Must be one of: auto, none, required`\n );\n }\n\n // Validate reasoning effort is a known value\n if (\n options.reasoning?.effort &&\n !['low', 'medium', 'high'].includes(options.reasoning.effort)\n ) {\n throw new Error(\n `Invalid reasoning.effort '${options.reasoning.effort}'. Must be one of: low, medium, high`\n );\n }\n\n // Validate recentImageThreshold is a positive number\n if (\n options.recentImageThreshold !== undefined &&\n (options.recentImageThreshold <= 0 ||\n !Number.isInteger(options.recentImageThreshold))\n ) {\n throw new Error('recentImageThreshold must be a positive integer');\n }\n\n return options;\n}\n","/**\n * Hook definition types for Standard Agents.\n *\n * Hooks allow intercepting and modifying agent behavior at key points\n * in the execution lifecycle. They enable logging, validation,\n * transformation, and side effects.\n *\n * Hooks receive ThreadState as their first parameter, providing full\n * access to thread operations and execution state.\n *\n * @module\n */\n\nimport type { ThreadState, Message } from './threads.js';\n\n// ============================================================================\n// Hook Context Types\n// ============================================================================\n\n/**\n * Hook context is ThreadState.\n *\n * Hooks receive the full ThreadState, which includes identity, message access,\n * resource loading, event emission, and execution state (when available).\n *\n * @example\n * ```typescript\n * const hook = defineHook('filter_messages', async (state, messages) => {\n * console.log(`Thread: ${state.threadId}`);\n * if (state.execution) {\n * console.log(`Turn: ${state.execution.turnCount}`);\n * }\n * return messages.slice(-10);\n * });\n * ```\n */\nexport type HookContext = ThreadState;\n\n/**\n * Message structure for hook processing.\n *\n * Re-exported from threads.ts for convenience.\n * @see Message\n */\nexport type HookMessage = Message;\n\n/**\n * Tool call structure for hook processing.\n */\nexport interface HookToolCall {\n /** Unique tool call identifier */\n id: string;\n /** Always 'function' for tool calls */\n type: 'function';\n /** Function details */\n function: {\n /** Tool name */\n name: string;\n /** JSON-encoded arguments */\n arguments: string;\n };\n}\n\n/**\n * Tool result structure for hook processing.\n */\nexport interface HookToolResult {\n /** Execution status */\n status: 'success' | 'error';\n /** Result string (for successful executions) */\n result?: string;\n /** Error message (for failed executions) */\n error?: string;\n /** Stack trace (for debugging) */\n stack?: string;\n}\n\n/**\n * LLM message format for prefilter hook.\n */\nexport interface LLMMessage {\n /** Message role */\n role: string;\n /** Message content */\n content: string | null;\n /** Tool calls (parsed) */\n tool_calls?: unknown;\n /** Tool call ID */\n tool_call_id?: string;\n /** Tool name */\n name?: string;\n}\n\n// ============================================================================\n// Hook Signatures\n// ============================================================================\n\n/**\n * Hook signatures for all available hooks.\n *\n * Each hook has a specific signature that defines when it's called\n * and what data it receives. Hooks can modify data by returning\n * transformed values or perform side effects.\n *\n * All hooks receive ThreadState as their first parameter.\n *\n * @template State - The state type (defaults to ThreadState)\n * @template Msg - The message type (defaults to HookMessage)\n * @template ToolCall - The tool call type (defaults to HookToolCall)\n * @template ToolResult - The tool result type (defaults to HookToolResult)\n */\nexport interface HookSignatures<\n State = ThreadState,\n Msg = HookMessage,\n ToolCall = HookToolCall,\n ToolResult = HookToolResult,\n> {\n /**\n * Called before messages are filtered and sent to the LLM.\n *\n * Receives raw message rows from storage before any transformation.\n * Use for filtering, sorting, or augmenting message history.\n *\n * @param state - Thread state\n * @param messages - Array of messages from storage\n * @returns Modified message array\n *\n * @example\n * ```typescript\n * defineHook('filter_messages', async (state, messages) => {\n * // Only include messages from last 10 turns\n * return messages.slice(-10);\n * });\n * ```\n */\n filter_messages: (state: State, messages: Msg[]) => Promise<Msg[]>;\n\n /**\n * Called after message history is loaded and before sending to LLM.\n *\n * Receives messages already transformed into chat completion format.\n * Use for final adjustments before LLM request.\n *\n * @param state - Thread state\n * @param messages - Array of LLM-formatted messages\n * @returns Modified LLM message array\n *\n * @example\n * ```typescript\n * defineHook('prefilter_llm_history', async (state, messages) => {\n * // Add a reminder to the last user message\n * return messages;\n * });\n * ```\n */\n prefilter_llm_history: (\n state: State,\n messages: LLMMessage[]\n ) => Promise<LLMMessage[]>;\n\n /**\n * Called before a message is created in the database.\n *\n * Receives the message data before insertion. Return modified data\n * to transform the message before storage.\n *\n * @param state - Thread state\n * @param message - Message data to be created\n * @returns Modified message data\n *\n * @example\n * ```typescript\n * defineHook('before_create_message', async (state, message) => {\n * // Add metadata to all messages\n * return { ...message, metadata: { processed: true } };\n * });\n * ```\n */\n before_create_message: (\n state: State,\n message: Record<string, unknown>\n ) => Promise<Record<string, unknown>>;\n\n /**\n * Called after a message is created in the database.\n *\n * Use for logging, analytics, or triggering side effects after\n * message creation. Cannot modify the message.\n *\n * @param state - Thread state\n * @param message - The created message data\n *\n * @example\n * ```typescript\n * defineHook('after_create_message', async (state, message) => {\n * console.log(`Message created: ${message.id}`);\n * });\n * ```\n */\n after_create_message: (\n state: State,\n message: Record<string, unknown>\n ) => Promise<void>;\n\n /**\n * Called before a message is updated in the database.\n *\n * Receives the message ID and update data. Return modified updates\n * to transform the changes before storage.\n *\n * @param state - Thread state\n * @param messageId - ID of message being updated\n * @param updates - Update data\n * @returns Modified update data\n *\n * @example\n * ```typescript\n * defineHook('before_update_message', async (state, messageId, updates) => {\n * return { ...updates, updated_at: Date.now() };\n * });\n * ```\n */\n before_update_message: (\n state: State,\n messageId: string,\n updates: Record<string, unknown>\n ) => Promise<Record<string, unknown>>;\n\n /**\n * Called after a message is updated in the database.\n *\n * Use for logging, analytics, or triggering side effects after\n * message update. Cannot modify the message.\n *\n * @param state - Thread state\n * @param message - The updated message\n *\n * @example\n * ```typescript\n * defineHook('after_update_message', async (state, message) => {\n * console.log(`Message updated: ${message.id}`);\n * });\n * ```\n */\n after_update_message: (state: State, message: Msg) => Promise<void>;\n\n /**\n * Called before a tool result is stored in the database.\n *\n * Receives the tool call and result before storage. Return modified\n * result to transform before storage.\n *\n * @param state - Thread state\n * @param toolCall - The tool call that was executed\n * @param toolResult - The result from tool execution\n * @returns Modified tool result data\n *\n * @example\n * ```typescript\n * defineHook('before_store_tool_result', async (state, toolCall, toolResult) => {\n * // Sanitize sensitive data from results\n * return { ...toolResult, result: sanitize(toolResult.result) };\n * });\n * ```\n */\n before_store_tool_result: (\n state: State,\n toolCall: Record<string, unknown>,\n toolResult: Record<string, unknown>\n ) => Promise<Record<string, unknown>>;\n\n /**\n * Called after a successful tool call.\n *\n * Receives the tool call and its result. Can return a modified result\n * or null to use the original. Use for logging, transformation, or\n * post-processing of successful tool executions.\n *\n * @param state - Thread state\n * @param toolCall - The executed tool call\n * @param toolResult - The successful result\n * @returns Modified result or null for original\n *\n * @example\n * ```typescript\n * defineHook('after_tool_call_success', async (state, toolCall, toolResult) => {\n * console.log(`Tool ${toolCall.function.name} succeeded`);\n * return null; // Use original result\n * });\n * ```\n */\n after_tool_call_success: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult | null>;\n\n /**\n * Called after a failed tool call.\n *\n * Receives the tool call and error result. Can return a modified result\n * or null to use the original. Use for error handling, logging, or\n * recovery attempts.\n *\n * @param state - Thread state\n * @param toolCall - The failed tool call\n * @param toolResult - The error result\n * @returns Modified result or null for original\n *\n * @example\n * ```typescript\n * defineHook('after_tool_call_failure', async (state, toolCall, toolResult) => {\n * console.error(`Tool ${toolCall.function.name} failed: ${toolResult.error}`);\n * return null; // Use original error\n * });\n * ```\n */\n after_tool_call_failure: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult | null>;\n}\n\n/**\n * Valid hook names.\n */\nexport type HookName = keyof HookSignatures;\n\n// ============================================================================\n// Hook Definition\n// ============================================================================\n\n/**\n * Hook definition tuple.\n *\n * A hook definition is a tuple containing the hook name and implementation.\n *\n * @template K - The hook name\n * @template State - The state type (defaults to ThreadState)\n * @template Msg - The message type\n * @template ToolCall - The tool call type\n * @template ToolResult - The tool result type\n */\nexport type HookDefinition<\n K extends HookName = HookName,\n State = ThreadState,\n Msg = HookMessage,\n ToolCall = HookToolCall,\n ToolResult = HookToolResult,\n> = [K, HookSignatures<State, Msg, ToolCall, ToolResult>[K]];\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Define a hook with strict typing based on hook name.\n *\n * Hooks intercept specific points in the agent execution lifecycle.\n * The hook name determines the function signature and when it's called.\n * All hooks receive ThreadState as their first parameter.\n *\n * @template K - The hook name (determines signature)\n * @param hookName - Name of the hook to define\n * @param implementation - Hook implementation function\n * @returns The implementation function (for registration)\n *\n * @example\n * ```typescript\n * // Filter messages to last 10\n * export default defineHook('filter_messages', async (state, messages) => {\n * return messages.slice(-10);\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Log all tool successes\n * export default defineHook('after_tool_call_success', async (state, toolCall, result) => {\n * console.log(`Tool ${toolCall.function.name} completed`);\n * return null; // Use original result\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Transform messages before LLM\n * export default defineHook('prefilter_llm_history', async (state, messages) => {\n * // Add instruction to last message\n * const last = messages[messages.length - 1];\n * if (last?.role === 'user' && typeof last.content === 'string') {\n * last.content += '\\n\\nRemember to be concise.';\n * }\n * return messages;\n * });\n * ```\n */\nexport function defineHook<K extends keyof HookSignatures>(\n hookName: K,\n implementation: HookSignatures[K]\n): HookSignatures[K] {\n // Validate hook name at runtime\n const validHooks: HookName[] = [\n 'filter_messages',\n 'prefilter_llm_history',\n 'before_create_message',\n 'after_create_message',\n 'before_update_message',\n 'after_update_message',\n 'before_store_tool_result',\n 'after_tool_call_success',\n 'after_tool_call_failure',\n ];\n\n if (!validHooks.includes(hookName)) {\n throw new Error(\n `Invalid hook name '${hookName}'. Valid hooks: ${validHooks.join(', ')}`\n );\n }\n\n return implementation;\n}\n","/**\n * Effect definition types for Standard Agents.\n *\n * Effects are scheduled operations that run outside the tool execution context.\n * They enable implementation-specific side effects with optional delay support,\n * leveraging the runtime's scheduling mechanism (e.g., Cloudflare Durable Object alarms).\n *\n * Unlike tools, effects:\n * - Do not return results to the LLM\n * - Can be delayed for future execution\n * - Run independently of the conversation flow\n * - Are ideal for notifications, cleanup, and async operations\n *\n * @module\n */\n\nimport type { z } from 'zod';\nimport type { ThreadState } from './threads.js';\nimport type { ToolArgs } from './tools.js';\n\n// ============================================================================\n// Effect Function Types\n// ============================================================================\n\n/**\n * Effect function signature.\n *\n * Effects are async functions that receive a ThreadState and\n * optionally validated arguments. Unlike tools, they return void\n * since results are not included in the conversation.\n *\n * @template State - The state type (defaults to ThreadState)\n * @template Args - The Zod schema for effect arguments, or null for no args\n */\nexport type Effect<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = Args extends ToolArgs\n ? (state: State, args: z.infer<Args>) => Promise<void> | void\n : (state: State) => Promise<void> | void;\n\n/**\n * Return type of defineEffect function.\n *\n * A tuple containing:\n * - Effect description string\n * - Argument schema (or null)\n * - Effect implementation function\n */\nexport type EffectDefinition<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n> = [string, Args, Effect<State, Args>];\n\n// ============================================================================\n// Scheduled Effect Types\n// ============================================================================\n\n/**\n * Record of a scheduled effect.\n *\n * Returned by getScheduledEffects() to inspect pending effects.\n */\nexport interface ScheduledEffect {\n /** Unique identifier for this scheduled effect. */\n id: string;\n /** Name of the effect to execute. */\n name: string;\n /** Arguments to pass to the effect handler. */\n args: Record<string, unknown>;\n /** When the effect is scheduled to run (microseconds since epoch). */\n scheduledAt: number;\n /** When the effect was created (microseconds since epoch). */\n createdAt: number;\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Define an effect with arguments.\n *\n * @param description - Description of what the effect does\n * @param args - Zod schema for validating effect arguments\n * @param handler - The effect implementation function\n * @returns A tuple containing the effect definition\n */\nexport function defineEffect<State = ThreadState, Args extends ToolArgs = ToolArgs>(\n description: string,\n args: Args,\n handler: Effect<State, Args>\n): EffectDefinition<State, Args>;\n\n/**\n * Define an effect without arguments.\n *\n * @param description - Description of what the effect does\n * @param handler - The effect implementation function\n * @returns A tuple containing the effect definition\n */\nexport function defineEffect<State = ThreadState>(\n description: string,\n handler: Effect<State, null>\n): EffectDefinition<State, null>;\n\n/**\n * Defines an effect that can be scheduled for execution.\n *\n * Effects are ideal for operations that should happen outside the\n * main conversation flow, such as:\n * - Sending notification emails after a delay\n * - Triggering webhooks\n * - Scheduling cleanup tasks\n * - Running background data processing\n *\n * @example\n * ```typescript\n * import { defineEffect } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * export default defineEffect(\n * 'Send a reminder email after a delay',\n * z.object({\n * to: z.string().email().describe('Recipient email'),\n * subject: z.string().describe('Email subject'),\n * body: z.string().describe('Email body'),\n * }),\n * async (state, args) => {\n * const env = state._notPackableRuntimeContext?.env as any;\n * await env.EMAIL_SERVICE.send({\n * to: args.to,\n * subject: args.subject,\n * body: args.body,\n * });\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Schedule an effect from a tool\n * const effectId = state.scheduleEffect(\n * 'send_reminder_email',\n * { to: 'user@example.com', subject: 'Reminder', body: 'Hello!' },\n * 30 * 60 * 1000 // 30 minutes\n * );\n * ```\n */\nexport function defineEffect<\n State = ThreadState,\n Args extends ToolArgs = ToolArgs,\n>(\n description: string,\n argsOrHandler: Args | Effect<State, null>,\n maybeHandler?: Effect<State, Args>\n): EffectDefinition<State, Args | null> {\n if (maybeHandler) {\n return [\n description,\n argsOrHandler as Args,\n maybeHandler,\n ];\n }\n return [\n description,\n null,\n argsOrHandler as Effect<State, null>,\n ];\n}\n","/**\n * Agent definition types for Standard Agents.\n *\n * Agents orchestrate conversations between AI models (dual_ai) or between\n * AI and human users (ai_human). They define the prompts, stop conditions,\n * and behavioral rules for each side of the conversation.\n *\n * @module\n */\n\n// ============================================================================\n// Agent Types\n// ============================================================================\n\n/**\n * Agent conversation type.\n *\n * - `ai_human`: AI conversing with a human user (most common)\n * - `dual_ai`: Two AI participants conversing with each other\n */\nexport type AgentType = 'ai_human' | 'dual_ai';\n\n// ============================================================================\n// Side Configuration\n// ============================================================================\n\n/**\n * Configuration for one side of an agent conversation.\n *\n * Each side has a prompt, stop conditions, and turn limits.\n * For `ai_human` agents, only sideA (the AI) needs configuration.\n * For `dual_ai` agents, both sides need configuration.\n *\n * @template Prompt - The prompt reference type (string or type-safe union)\n * @template Callable - The callable reference type (string or type-safe union)\n *\n * @example\n * ```typescript\n * const sideConfig: SideConfig = {\n * label: 'Support Agent',\n * prompt: 'customer_support',\n * stopOnResponse: true,\n * maxSteps: 10,\n * };\n * ```\n */\nexport interface SideConfig<\n Prompt extends string = string,\n Callable extends string = string,\n> {\n /**\n * Custom label for this side of the conversation.\n * Used in UI and logs for clarity.\n *\n * @example 'Support Agent', 'Customer', 'ATC', 'Pilot'\n */\n label?: string;\n\n /**\n * The prompt to use for this side.\n * Must reference a prompt defined in agents/prompts/.\n */\n prompt: Prompt;\n\n /**\n * Stop this side's turn when it returns a text response (no tool calls).\n * When true, the side's turn ends after producing a message without tools.\n * @default true\n */\n stopOnResponse?: boolean;\n\n /**\n * Stop this side's turn when a specific tool is called.\n * Overrides stopOnResponse when the named tool is invoked.\n * Requires stopToolResponseProperty to extract the result.\n */\n stopTool?: Callable;\n\n /**\n * Property to extract from the stop tool's result.\n * Required when stopTool is set.\n * The extracted value is used to determine the conversation outcome.\n */\n stopToolResponseProperty?: string;\n\n /**\n * Maximum steps for this side before forcing a stop.\n * Safety limit to prevent runaway execution.\n * A step is one complete LLM request/response cycle.\n */\n maxSteps?: number;\n\n /**\n * Tool that ends the entire session when called.\n * Different from stopTool - this ends the session for both sides,\n * not just this side's turn.\n */\n endSessionTool?: Callable;\n}\n\n// ============================================================================\n// Agent Definition\n// ============================================================================\n\n/**\n * Agent definition configuration.\n *\n * @template N - The agent name as a string literal type\n * @template Prompt - The prompt reference type (string or type-safe union)\n * @template Callable - The callable reference type (string or type-safe union)\n *\n * @example\n * ```typescript\n * import { defineAgent } from '@standardagents/spec';\n *\n * export default defineAgent({\n * name: 'support_agent',\n * title: 'Customer Support Agent',\n * type: 'ai_human',\n * sideA: {\n * label: 'Support',\n * prompt: 'customer_support',\n * stopOnResponse: true,\n * },\n * });\n * ```\n */\nexport interface AgentDefinition<\n N extends string = string,\n Prompt extends string = string,\n Callable extends string = string,\n> {\n /**\n * Unique name for this agent.\n * Used as the identifier for thread creation and handoffs.\n * Should be snake_case (e.g., 'support_agent', 'research_flow').\n */\n name: N;\n\n /**\n * Human-readable title for the agent.\n * Optional - if not provided, the name will be used.\n * @deprecated Use name instead. Title will be removed in a future version.\n */\n title?: string;\n\n /**\n * Agent conversation type.\n *\n * - `ai_human`: AI conversing with a human user (default)\n * - `dual_ai`: Two AI participants conversing\n *\n * @default 'ai_human'\n */\n type?: AgentType;\n\n /**\n * Maximum total turns across both sides.\n * Only applies to `dual_ai` agents.\n * Prevents infinite loops in AI-to-AI conversations.\n */\n maxSessionTurns?: number;\n\n /**\n * Configuration for Side A.\n * For `ai_human`: This is the AI side.\n * For `dual_ai`: This is the first AI participant.\n */\n sideA: SideConfig<Prompt, Callable>;\n\n /**\n * Configuration for Side B.\n * For `ai_human`: Optional, the human side doesn't need config.\n * For `dual_ai`: Required, the second AI participant.\n */\n sideB?: SideConfig<Prompt, Callable>;\n\n /**\n * Expose this agent as a tool for other prompts.\n * Enables agent composition and handoffs.\n * When true, other prompts can invoke this agent as a tool.\n * @default false\n */\n exposeAsTool?: boolean;\n\n /**\n * Description shown when agent is used as a tool.\n * Required if exposeAsTool is true.\n * Should clearly describe what this agent does.\n */\n toolDescription?: string;\n\n /**\n * Brief description of what this agent does.\n * Useful for UIs and documentation.\n *\n * @example 'Handles customer support inquiries and resolves issues'\n */\n description?: string;\n\n /**\n * Icon URL or absolute path for the agent.\n * Absolute paths (starting with `/`) are converted to full URLs in API responses.\n *\n * @example 'https://example.com/icon.svg' or '/icons/support.svg'\n */\n icon?: string;\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Defines an agent configuration.\n *\n * Agents orchestrate conversations between AI models, or between AI and\n * human users. They use prompts to configure each side of the conversation\n * and define stop conditions to control conversation flow.\n *\n * @template N - The agent name as a string literal type\n * @param options - Agent configuration options\n * @returns The agent definition for registration\n *\n * @example\n * ```typescript\n * // agents/agents/support_agent.ts\n * import { defineAgent } from '@standardagents/spec';\n *\n * export default defineAgent({\n * name: 'support_agent',\n * title: 'Customer Support Agent',\n * type: 'ai_human',\n * sideA: {\n * label: 'Support',\n * prompt: 'customer_support',\n * stopOnResponse: true,\n * endSessionTool: 'close_ticket',\n * },\n * exposeAsTool: true,\n * toolDescription: 'Hand off to customer support',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Dual AI agent (two AIs conversing)\n * export default defineAgent({\n * name: 'debate_agent',\n * title: 'AI Debate',\n * type: 'dual_ai',\n * maxSessionTurns: 10,\n * sideA: {\n * label: 'Pro',\n * prompt: 'debate_pro',\n * stopOnResponse: true,\n * },\n * sideB: {\n * label: 'Con',\n * prompt: 'debate_con',\n * stopOnResponse: true,\n * endSessionTool: 'conclude_debate',\n * },\n * });\n * ```\n */\nexport function defineAgent<N extends string>(\n options: AgentDefinition<N>\n): AgentDefinition<N> {\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Agent name is required');\n }\n if (!options.sideA) {\n throw new Error('Agent sideA configuration is required');\n }\n if (!options.sideA.prompt) {\n throw new Error('Agent sideA.prompt is required');\n }\n\n // Set default type\n const type = options.type ?? 'ai_human';\n\n // Validate dual_ai requires sideB\n if (type === 'dual_ai') {\n if (!options.sideB) {\n throw new Error('Agent sideB configuration is required for dual_ai type');\n }\n if (!options.sideB.prompt) {\n throw new Error('Agent sideB.prompt is required for dual_ai type');\n }\n }\n\n // Validate exposeAsTool requires toolDescription\n if (options.exposeAsTool && !options.toolDescription) {\n throw new Error('toolDescription is required when exposeAsTool is true');\n }\n\n // Validate stopTool requires stopToolResponseProperty\n if (options.sideA.stopTool && !options.sideA.stopToolResponseProperty) {\n throw new Error('sideA.stopToolResponseProperty is required when sideA.stopTool is set');\n }\n if (options.sideB?.stopTool && !options.sideB.stopToolResponseProperty) {\n throw new Error('sideB.stopToolResponseProperty is required when sideB.stopTool is set');\n }\n\n // Validate maxSteps is positive\n if (options.sideA.maxSteps !== undefined && options.sideA.maxSteps <= 0) {\n throw new Error('sideA.maxSteps must be a positive number');\n }\n if (options.sideB?.maxSteps !== undefined && options.sideB.maxSteps <= 0) {\n throw new Error('sideB.maxSteps must be a positive number');\n }\n if (\n options.maxSessionTurns !== undefined &&\n options.maxSessionTurns !== null &&\n options.maxSessionTurns <= 0\n ) {\n throw new Error('maxSessionTurns must be a positive number');\n }\n\n // Validate type is a known value\n if (!['ai_human', 'dual_ai'].includes(type)) {\n throw new Error(`Invalid type '${type}'. Must be one of: ai_human, dual_ai`);\n }\n\n return {\n ...options,\n type,\n };\n}\n","/**\n * Endpoint definition types for Standard Agents.\n *\n * Endpoints expose HTTP APIs for interacting with agent threads.\n * They can be standard controllers or thread-specific endpoints\n * with automatic ThreadState injection.\n *\n * @module\n */\n\nimport type { ThreadState } from './threads.js';\n\n// ============================================================================\n// Virtual Module Types\n// ============================================================================\n\n/**\n * Virtual module loader function.\n *\n * Lazy-loads a module definition on demand.\n */\nexport type VirtualModuleLoader<T> = () => Promise<T>;\n\n/**\n * Registry of virtual modules by name.\n *\n * Maps module names to their lazy loaders.\n */\nexport type VirtualModuleRegistry<T> = Record<string, VirtualModuleLoader<T>>;\n\n// ============================================================================\n// Controller Types\n// ============================================================================\n\n/**\n * Controller context passed to route handlers.\n *\n * Contains the request, URL parameters, environment bindings,\n * and optionally the virtual module registries injected at runtime.\n *\n * Note: The `env` property contains implementation-specific bindings.\n * Cloudflare implementations may include Durable Object namespaces,\n * KV namespaces, etc. Other implementations may provide different bindings.\n */\nexport interface ControllerContext {\n /** The incoming HTTP request */\n req: Request;\n\n /** URL path parameters extracted by the router */\n params: Record<string, string>;\n\n /** Parsed URL object */\n url: URL;\n\n /**\n * Environment bindings (implementation-specific).\n *\n * Contains platform-specific bindings like Durable Objects, KV, etc.\n * The exact contents depend on the runtime implementation.\n */\n env: Record<string, unknown>;\n\n /** Registry of agent definitions (injected at runtime) */\n agents?: VirtualModuleRegistry<unknown>;\n\n /** Available agent names */\n agentNames?: string[];\n\n /** Registry of prompt definitions (injected at runtime) */\n prompts?: VirtualModuleRegistry<unknown>;\n\n /** Available prompt names */\n promptNames?: string[];\n\n /** Registry of model definitions (injected at runtime) */\n models?: VirtualModuleRegistry<unknown>;\n\n /** Available model names */\n modelNames?: string[];\n\n /** Registry of tool definitions (injected at runtime) */\n tools?: VirtualModuleRegistry<unknown>;\n\n /** Registry of hook definitions (injected at runtime) */\n hooks?: VirtualModuleRegistry<unknown>;\n\n /** Additional configuration (injected at runtime) */\n config?: Record<string, unknown>;\n}\n\n/**\n * Controller return types.\n *\n * Controllers can return various types that are automatically\n * converted to appropriate HTTP responses.\n */\nexport type ControllerReturn =\n | string\n | Promise<string>\n | Response\n | Promise<Response>\n | ReadableStream\n | Promise<ReadableStream>\n | null\n | Promise<null>\n | void\n | Promise<void>\n | Promise<object>\n | object;\n\n/**\n * Controller function type.\n *\n * Controllers handle HTTP requests and return responses.\n * The return value is automatically converted to a Response.\n *\n * @example\n * ```typescript\n * const handler: Controller = async ({ req, params, url }) => {\n * return { message: 'Hello, World!' };\n * };\n * ```\n */\nexport type Controller = (context: ControllerContext) => ControllerReturn;\n\n// ============================================================================\n// Thread Endpoint Types\n// ============================================================================\n\n/**\n * Thread endpoint handler function.\n *\n * Receives the HTTP request and the ThreadState for the requested thread.\n * The thread is automatically looked up by ID from URL parameters.\n */\nexport type ThreadEndpointHandler = (\n req: Request,\n state: ThreadState\n) => Response | Promise<Response>;\n\n// ============================================================================\n// Define Functions\n// ============================================================================\n\n/**\n * Define a standard HTTP controller.\n *\n * Controllers handle HTTP requests and return responses. They have\n * access to the controller context including virtual module registries.\n *\n * @param controller - The controller function\n * @returns The controller for registration\n *\n * @example\n * ```typescript\n * // agents/api/health.get.ts\n * import { defineController } from '@standardagents/spec';\n *\n * export default defineController(async () => {\n * return { status: 'ok', timestamp: Date.now() };\n * });\n * ```\n *\n * @example\n * ```typescript\n * // agents/api/agents/index.get.ts\n * import { defineController } from '@standardagents/spec';\n *\n * export default defineController(async ({ agentNames }) => {\n * return { agents: agentNames };\n * });\n * ```\n */\nexport function defineController(controller: Controller): Controller {\n return controller;\n}\n\n/**\n * Define a thread-specific endpoint.\n *\n * Thread endpoints automatically look up the thread by ID from URL params\n * and provide access to the ThreadState. The handler receives full\n * ThreadState with messages, logs, resource loading, event emission,\n * and (when executing) execution state.\n *\n * @param handler - The handler function receiving request and ThreadState\n * @returns A Controller that can be used with the router\n *\n * @example\n * ```typescript\n * // agents/api/threads/[id]/status.get.ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state) => {\n * const { messages, total } = await state.getMessages({ limit: 1 });\n * return Response.json({\n * threadId: state.threadId,\n * agent: state.agentId,\n * messageCount: total,\n * });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // agents/api/threads/[id]/export.get.ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state) => {\n * const { messages } = await state.getMessages();\n * return Response.json({\n * thread: {\n * id: state.threadId,\n * agent: state.agentId,\n * user: state.userId,\n * createdAt: state.createdAt,\n * },\n * messages,\n * });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // agents/api/threads/[id]/invoke.post.ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state) => {\n * const { tool, args } = await req.json();\n *\n * // Queue a tool for execution (starts execution if not running)\n * state.queueTool(tool, args);\n *\n * return Response.json({ queued: true });\n * });\n * ```\n */\nexport function defineThreadEndpoint(\n handler: ThreadEndpointHandler\n): Controller {\n // The actual implementation is provided by the runtime.\n // This is a marker function that the router recognizes.\n // The runtime wraps this to provide ThreadState.\n return (handler as unknown) as Controller;\n}\n"],"mappings":";AAuKO,SAAS,YACd,SACoB;AAEpB,MAAI,CAAC,QAAQ,MAAM;AACjB,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACA,MAAI,CAAC,QAAQ,UAAU;AACrB,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AACA,MAAI,CAAC,QAAQ,OAAO;AAClB,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AAGA,QAAM,iBAAkC,CAAC,UAAU,cAAc,aAAa,UAAU,MAAM;AAC9F,MAAI,CAAC,eAAe,SAAS,QAAQ,QAAQ,GAAG;AAC9C,UAAM,IAAI;AAAA,MACR,qBAAqB,QAAQ,QAAQ,sBAAsB,eAAe,KAAK,IAAI,CAAC;AAAA,IACtF;AAAA,EACF;AAGA,MAAI,QAAQ,eAAe,UAAa,QAAQ,aAAa,GAAG;AAC9D,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACA,MAAI,QAAQ,gBAAgB,UAAa,QAAQ,cAAc,GAAG;AAChE,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AACA,MAAI,QAAQ,gBAAgB,UAAa,QAAQ,cAAc,GAAG;AAChE,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AAEA,SAAO;AACT;;;ACsGO,SAAS,WAId,iBACA,YACA,WACoC;AACpC,MAAI,WAAW;AACb,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACOO,SAAS,aACd,SACwB;AAExB,MAAI,CAAC,QAAQ,MAAM;AACjB,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AACA,MAAI,CAAC,QAAQ,iBAAiB;AAC5B,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,MAAI,CAAC,QAAQ,OAAO;AAClB,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AACA,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAGA,MACE,QAAQ,cACR,CAAC,CAAC,QAAQ,QAAQ,UAAU,EAAE,SAAS,QAAQ,UAAU,GACzD;AACA,UAAM,IAAI;AAAA,MACR,uBAAuB,QAAQ,UAAU;AAAA,IAC3C;AAAA,EACF;AAGA,MACE,QAAQ,WAAW,UACnB,CAAC,CAAC,OAAO,UAAU,MAAM,EAAE,SAAS,QAAQ,UAAU,MAAM,GAC5D;AACA,UAAM,IAAI;AAAA,MACR,6BAA6B,QAAQ,UAAU,MAAM;AAAA,IACvD;AAAA,EACF;AAGA,MACE,QAAQ,yBAAyB,WAChC,QAAQ,wBAAwB,KAC/B,CAAC,OAAO,UAAU,QAAQ,oBAAoB,IAChD;AACA,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,SAAO;AACT;;;ACqBO,SAAS,WACd,UACA,gBACmB;AAEnB,QAAM,aAAyB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,WAAW,SAAS,QAAQ,GAAG;AAClC,UAAM,IAAI;AAAA,MACR,sBAAsB,QAAQ,mBAAmB,WAAW,KAAK,IAAI,CAAC;AAAA,IACxE;AAAA,EACF;AAEA,SAAO;AACT;;;ACjRO,SAAS,aAId,aACA,eACA,cACsC;AACtC,MAAI,cAAc;AAChB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACiGO,SAAS,YACd,SACoB;AAEpB,MAAI,CAAC,QAAQ,MAAM;AACjB,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACA,MAAI,CAAC,QAAQ,OAAO;AAClB,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AACA,MAAI,CAAC,QAAQ,MAAM,QAAQ;AACzB,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAGA,QAAM,OAAO,QAAQ,QAAQ;AAG7B,MAAI,SAAS,WAAW;AACtB,QAAI,CAAC,QAAQ,OAAO;AAClB,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC1E;AACA,QAAI,CAAC,QAAQ,MAAM,QAAQ;AACzB,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAAA,EACF;AAGA,MAAI,QAAQ,gBAAgB,CAAC,QAAQ,iBAAiB;AACpD,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAGA,MAAI,QAAQ,MAAM,YAAY,CAAC,QAAQ,MAAM,0BAA0B;AACrE,UAAM,IAAI,MAAM,uEAAuE;AAAA,EACzF;AACA,MAAI,QAAQ,OAAO,YAAY,CAAC,QAAQ,MAAM,0BAA0B;AACtE,UAAM,IAAI,MAAM,uEAAuE;AAAA,EACzF;AAGA,MAAI,QAAQ,MAAM,aAAa,UAAa,QAAQ,MAAM,YAAY,GAAG;AACvE,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,MAAI,QAAQ,OAAO,aAAa,UAAa,QAAQ,MAAM,YAAY,GAAG;AACxE,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,MACE,QAAQ,oBAAoB,UAC5B,QAAQ,oBAAoB,QAC5B,QAAQ,mBAAmB,GAC3B;AACA,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAGA,MAAI,CAAC,CAAC,YAAY,SAAS,EAAE,SAAS,IAAI,GAAG;AAC3C,UAAM,IAAI,MAAM,iBAAiB,IAAI,sCAAsC;AAAA,EAC7E;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EACF;AACF;;;AC7JO,SAAS,iBAAiB,YAAoC;AACnE,SAAO;AACT;AA8DO,SAAS,qBACd,SACY;AAIZ,SAAQ;AACV;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@standardagents/spec",
3
- "version": "0.11.0-next.41deba4",
3
+ "version": "0.11.0-next.5d2e71b",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public",