@standardagents/spec 0.26.0 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +44 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1365,6 +1365,50 @@ interface ThreadState {
|
|
|
1365
1365
|
* to delete the key
|
|
1366
1366
|
*/
|
|
1367
1367
|
setValue(key: string, value: unknown): Promise<void>;
|
|
1368
|
+
/**
|
|
1369
|
+
* Read a value from the account-wide durable key-value store of the user
|
|
1370
|
+
* this thread belongs to.
|
|
1371
|
+
*
|
|
1372
|
+
* The user store is the account-scoped sibling of the thread store: values
|
|
1373
|
+
* persist across every thread the user owns on the instance (e.g. a coding
|
|
1374
|
+
* client's registry of registered machines and projects). Returns `null`
|
|
1375
|
+
* when the thread has no associated user or the key has no value.
|
|
1376
|
+
*
|
|
1377
|
+
* @param key - The key to read
|
|
1378
|
+
*/
|
|
1379
|
+
getUserValue<T = unknown>(key: string): Promise<T | null>;
|
|
1380
|
+
/**
|
|
1381
|
+
* Write a value to the account-wide durable key-value store of the user
|
|
1382
|
+
* this thread belongs to.
|
|
1383
|
+
*
|
|
1384
|
+
* Passing `null` or `undefined` deletes the key. Values MUST be
|
|
1385
|
+
* JSON-serializable. Implementations MUST reject the write when the thread
|
|
1386
|
+
* has no associated user.
|
|
1387
|
+
*
|
|
1388
|
+
* @param key - The key to write
|
|
1389
|
+
* @param value - The value to store (JSON-serializable), or `null`/`undefined`
|
|
1390
|
+
* to delete the key
|
|
1391
|
+
*/
|
|
1392
|
+
setUserValue(key: string, value: unknown): Promise<void>;
|
|
1393
|
+
/**
|
|
1394
|
+
* List entries in the account-wide durable key-value store of the user this
|
|
1395
|
+
* thread belongs to, optionally filtered by key prefix. Returns an empty
|
|
1396
|
+
* list when the thread has no associated user.
|
|
1397
|
+
*
|
|
1398
|
+
* @param options - Optional `prefix`, `limit` (default 100), and `offset`
|
|
1399
|
+
*/
|
|
1400
|
+
listUserValues(options?: {
|
|
1401
|
+
prefix?: string | null;
|
|
1402
|
+
limit?: number;
|
|
1403
|
+
offset?: number;
|
|
1404
|
+
}): Promise<{
|
|
1405
|
+
entries: Array<{
|
|
1406
|
+
key: string;
|
|
1407
|
+
value: unknown;
|
|
1408
|
+
updated_at: number;
|
|
1409
|
+
}>;
|
|
1410
|
+
total: number;
|
|
1411
|
+
}>;
|
|
1368
1412
|
/**
|
|
1369
1413
|
* The profile of the user this thread belongs to, or `null` when the thread
|
|
1370
1414
|
* has no associated user (e.g. unauthenticated local development).
|
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/threads.ts","../src/endpoints.ts","../src/providers.ts","../src/packing.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\nimport type { z, ZodTypeAny } from 'zod';\nimport type {\n ProviderRequest,\n ProviderResponse,\n ProviderStreamChunk,\n InspectedRequest,\n ProviderModelInfo,\n ProviderModelsPage,\n ProviderModelsQuery,\n ResponseSummary,\n} from './providers';\nimport type { ToolDefinition, ToolArgs, ToolTenvs } from './tools';\nimport type { VariableDefinition, VariableType } from './tools';\n\n/**\n * Legacy provider identifiers - kept for reference only.\n * New code should use ProviderFactory imports from provider packages.\n *\n * @deprecated Use ProviderFactory from provider packages instead\n * @internal\n */\nexport type ModelProvider = 'openai' | 'openrouter' | 'anthropic' | 'google' | 'test';\n\n/**\n * Provider interface for LLM providers.\n *\n * Provider packages export a factory function that creates instances\n * implementing this interface. This is structurally compatible with\n * LLMProviderInterface from providers.ts.\n */\nexport interface ProviderInstance {\n readonly name: string;\n readonly specificationVersion: '1';\n generate(request: ProviderRequest): Promise<ProviderResponse>;\n stream(request: ProviderRequest): Promise<AsyncIterable<ProviderStreamChunk>>;\n supportsModel?(modelId: string): boolean;\n /** List available models from this provider */\n getModels?(filter?: string): Promise<ProviderModelInfo[]>;\n /** List available models with optional remote search/pagination */\n getModelsPage?(query?: ProviderModelsQuery): Promise<ProviderModelsPage>;\n /** Fetch capabilities for a specific model */\n getModelCapabilities?(modelId: string): Promise<ModelCapabilities | null>;\n /** Get provider-defined built-in tools available for a model */\n getTools?(modelId?: string): Record<string, ToolDefinition<unknown, ToolArgs | null, ToolTenvs | null>> | Promise<Record<string, ToolDefinition<unknown, ToolArgs | null, ToolTenvs | null>>>;\n /** Get the icon URL for this provider or a specific model */\n getIcon?(modelId?: string): string | undefined;\n /** Inspect a raw request for debugging purposes */\n inspectRequest?(request: ProviderRequest): Promise<InspectedRequest>;\n /** Fetch additional metadata about a completed response */\n getResponseMetadata?(summary: ResponseSummary, signal?: AbortSignal): Promise<Record<string, unknown> | null>;\n}\n\n/**\n * Configuration passed to provider factory functions.\n */\nexport interface ProviderFactoryConfig {\n apiKey: string;\n baseUrl?: string;\n timeout?: number;\n [key: string]: unknown;\n}\n\n/**\n * Declarative connection-level config slot exposed by a provider factory.\n *\n * Slots describe values used to construct a provider client, such as\n * credentials, API endpoints, account IDs, regions, and timeouts. They are\n * different from `providerOptions`, which are per-model or per-request knobs.\n */\nexport interface ProviderConfigSlot<T = unknown> {\n /** Value type, used by UIs for validation and secret handling */\n type: VariableType | 'url' | 'number' | 'boolean';\n /** Whether this value is required to construct the provider */\n required?: boolean;\n /** Default literal value when no override/source provides one */\n default?: T;\n /** Conventional environment variable used by the built-in/default provider */\n defaultEnv?: string;\n /** Whether sub-providers may override this slot */\n overridable?: boolean;\n /** Human-readable description for setup UIs and docs */\n description?: string;\n}\n\n/**\n * Named collection of provider client config slots.\n */\nexport type ProviderConfigSlots = Record<string, ProviderConfigSlot>;\n\n/**\n * Value source used by `defineProvider()` sub-providers to fill base-provider\n * config slots.\n */\nexport type ProviderConfigValueSource<T = unknown> =\n | { type: 'const'; value: T }\n | {\n type: 'env';\n name: string;\n valueType?: VariableType | 'url' | 'number' | 'boolean';\n required?: boolean;\n default?: T;\n description?: string;\n };\n\n/**\n * Convenience helper for constant provider config values.\n */\nexport function providerValue<T>(value: T): ProviderConfigValueSource<T> {\n return { type: 'const', value };\n}\n\n/**\n * Convenience helper for provider config values resolved from environment.\n */\nexport function providerEnv<T = string>(\n name: string,\n options: Omit<Extract<ProviderConfigValueSource<T>, { type: 'env' }>, 'type' | 'name'> = {}\n): ProviderConfigValueSource<T> {\n return { type: 'env', name, ...options };\n}\n\n/**\n * Backward-compatible alias with wording that reads naturally in provider\n * definition files.\n */\nexport const providerConst = providerValue;\n\nexport interface ProviderOverrideContext {\n /** Name of the defined provider being executed */\n providerName: string;\n /** The resolved connection config passed to the base provider */\n config: ProviderFactoryConfig;\n /** Base provider instance before overrides are applied */\n baseProvider: ProviderInstance;\n}\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport type ProviderOverride<Context, Result> = (\n context: ProviderOverrideContext & Context,\n next: () => MaybePromise<Result>\n) => MaybePromise<Result>;\n\nexport type ProviderSyncOverride<Context, Result> = (\n context: ProviderOverrideContext & Context,\n next: () => Result\n) => Result;\n\n/**\n * Overrideable provider methods. Each override can replace the base behavior\n * or call `next()` to compose with the base provider.\n */\nexport interface ProviderMethodOverrides {\n generate?: ProviderOverride<{ request: ProviderRequest }, ProviderResponse>;\n stream?: ProviderOverride<{ request: ProviderRequest }, AsyncIterable<ProviderStreamChunk>>;\n supportsModel?: ProviderSyncOverride<{ modelId: string }, boolean>;\n getModels?: ProviderOverride<{ filter?: string }, ProviderModelInfo[]>;\n getModelsPage?: ProviderOverride<{ query?: ProviderModelsQuery }, ProviderModelsPage>;\n getModelCapabilities?: ProviderOverride<{ modelId: string }, ModelCapabilities | null>;\n getTools?: ProviderOverride<{\n modelId?: string;\n }, Record<string, ToolDefinition<unknown, ToolArgs | null, ToolTenvs | null>>>;\n getIcon?: ProviderSyncOverride<{ modelId?: string }, string | undefined>;\n inspectRequest?: ProviderOverride<{ request: ProviderRequest }, InspectedRequest>;\n getResponseMetadata?: ProviderOverride<{\n summary: ResponseSummary;\n signal?: AbortSignal;\n }, Record<string, unknown> | null>;\n}\n\nexport interface ProviderDefinition<\n N extends string = string,\n Base extends ProviderFactoryWithOptions<ZodTypeAny> = ProviderFactoryWithOptions<ZodTypeAny>\n> {\n name: N;\n label?: string;\n baseProvider: Base;\n config?: Partial<Record<keyof ProviderFactoryConfig | string, ProviderConfigValueSource>>;\n overrides?: ProviderMethodOverrides;\n}\n\n/**\n * Provider factory with optional typed providerOptions schema.\n *\n * The schema property allows type inference and runtime validation of\n * provider-specific options in model definitions.\n *\n * @template TOptions - Zod schema type for providerOptions (defaults to ZodTypeAny)\n *\n * @example\n * ```typescript\n * import { openai } from '@standardagents/openai';\n *\n * // openai is a ProviderFactoryWithOptions with typed schema\n * const provider = openai({ apiKey: 'sk-...' });\n *\n * // Access the schema for validation\n * openai.providerOptions?.parse({ service_tier: 'default' });\n * ```\n */\nexport interface ProviderFactoryWithOptions<\n TOptions extends ZodTypeAny = ZodTypeAny\n> {\n (config: ProviderFactoryConfig): ProviderInstance;\n /** Zod schema for provider-specific options */\n providerOptions?: TOptions;\n /** Connection-level config slots accepted by this provider factory */\n configSlots?: ProviderConfigSlots;\n /** Metadata attached to factories created with defineProvider() */\n providerDefinition?: ProviderDefinition<string, ProviderFactoryWithOptions<TOptions>>;\n}\n\n/**\n * Factory function that creates provider instances.\n *\n * Provider packages (like @standardagents/openai) export this type.\n * This is an alias for ProviderFactoryWithOptions for backward compatibility.\n *\n * @example\n * ```typescript\n * import { openai } from '@standardagents/openai';\n *\n * // openai is a ProviderFactory\n * const provider = openai({ apiKey: 'sk-...' });\n * ```\n */\nexport type ProviderFactory = ProviderFactoryWithOptions<ZodTypeAny>;\n\n/**\n * Define a named sub-provider that uses a base provider implementation with\n * custom connection config sources and optional method overrides.\n */\nexport function defineProvider<\n const N extends string,\n Base extends ProviderFactoryWithOptions<ZodTypeAny>\n>(\n definition: ProviderDefinition<N, Base>\n): ProviderFactoryWithOptions<Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny> {\n if (!definition.name) {\n throw new Error('Provider name is required');\n }\n if (typeof definition.baseProvider !== 'function') {\n throw new Error('baseProvider must be a provider factory function');\n }\n\n const factory = ((config: ProviderFactoryConfig) => {\n const baseProvider = definition.baseProvider(config);\n const commonContext: ProviderOverrideContext = {\n providerName: definition.name,\n config,\n baseProvider,\n };\n\n const provider: ProviderInstance = {\n name: definition.name,\n specificationVersion: '1',\n generate: (request) => {\n const next = () => baseProvider.generate(request);\n return Promise.resolve(definition.overrides?.generate?.({ ...commonContext, request }, next) ?? next());\n },\n stream: (request) => {\n const next = () => baseProvider.stream(request);\n return Promise.resolve(definition.overrides?.stream?.({ ...commonContext, request }, next) ?? next());\n },\n };\n\n if (definition.overrides?.supportsModel || baseProvider.supportsModel) {\n provider.supportsModel = (modelId) => {\n const next = () => baseProvider.supportsModel?.(modelId) ?? true;\n return definition.overrides?.supportsModel?.({ ...commonContext, modelId }, next) ?? next();\n };\n }\n\n if (definition.overrides?.getModels || baseProvider.getModels) {\n provider.getModels = (filter) => {\n const next = () => baseProvider.getModels?.(filter) ?? Promise.resolve([]);\n return Promise.resolve(\n definition.overrides?.getModels?.({ ...commonContext, filter }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getModelsPage || baseProvider.getModelsPage) {\n provider.getModelsPage = (query) => {\n const next = () => baseProvider.getModelsPage?.(query) ?? Promise.resolve({ models: [], hasNextPage: false });\n return Promise.resolve(\n definition.overrides?.getModelsPage?.({ ...commonContext, query }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getModelCapabilities || baseProvider.getModelCapabilities) {\n provider.getModelCapabilities = (modelId) => {\n const next = () => baseProvider.getModelCapabilities?.(modelId) ?? Promise.resolve(null);\n return Promise.resolve(\n definition.overrides?.getModelCapabilities?.({ ...commonContext, modelId }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getTools || baseProvider.getTools) {\n provider.getTools = (modelId) => {\n const next = () => baseProvider.getTools?.(modelId) ?? {};\n return definition.overrides?.getTools?.({ ...commonContext, modelId }, next) ?? next();\n };\n }\n\n if (definition.overrides?.getIcon || baseProvider.getIcon) {\n provider.getIcon = (modelId) => {\n const next = () => baseProvider.getIcon?.(modelId);\n return definition.overrides?.getIcon?.({ ...commonContext, modelId }, next) ?? next();\n };\n }\n\n if (definition.overrides?.inspectRequest || baseProvider.inspectRequest) {\n provider.inspectRequest = (request) => {\n const next = () => {\n if (!baseProvider.inspectRequest) {\n throw new Error(`Provider '${definition.name}' does not support request inspection`);\n }\n return baseProvider.inspectRequest(request);\n };\n return Promise.resolve(\n definition.overrides?.inspectRequest?.({ ...commonContext, request }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getResponseMetadata || baseProvider.getResponseMetadata) {\n provider.getResponseMetadata = (summary, signal) => {\n const next = () => baseProvider.getResponseMetadata?.(summary, signal) ?? Promise.resolve(null);\n return Promise.resolve(\n definition.overrides?.getResponseMetadata?.({ ...commonContext, summary, signal }, next) ?? next()\n );\n };\n }\n\n return provider;\n }) as ProviderFactoryWithOptions<Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny>;\n\n factory.providerOptions = definition.baseProvider.providerOptions as Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny;\n factory.configSlots = definition.baseProvider.configSlots;\n factory.providerDefinition = definition as unknown as ProviderDefinition<string, ProviderFactoryWithOptions<Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny>>;\n\n return factory;\n}\n\n/**\n * Extract providerOptions type from a provider factory.\n *\n * Returns the inferred input type from the provider's Zod schema,\n * or Record<string, unknown> if no schema is defined.\n *\n * @template P - Provider factory type\n */\nexport type InferProviderOptions<P> =\n P extends ProviderFactoryWithOptions<infer S>\n ? S extends ZodTypeAny\n ? z.input<S> extends Record<string, unknown>\n ? z.input<S>\n : Record<string, unknown>\n : Record<string, unknown>\n : Record<string, unknown>;\n\n/**\n * Model capability flags indicating supported features.\n *\n * These capabilities are used by the FlowEngine to determine how to\n * interact with the model and what features are available.\n */\nexport interface ModelCapabilities {\n /**\n * Reasoning level mapping (0-100 scale → model-specific values).\n * Keys are breakpoints, values are model's native reasoning strings.\n *\n * @example\n * // OpenAI o-series\n * reasoningLevels: { 0: null, 33: 'low', 66: 'medium', 100: 'high' }\n *\n * @example\n * // Binary reasoning (Claude extended thinking)\n * reasoningLevels: { 0: null, 100: 'enabled' }\n *\n * @example\n * // No reasoning support\n * reasoningLevels: { 0: null }\n */\n reasoningLevels?: Record<number, string | null>;\n\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 supportsImages?: boolean;\n\n /**\n * @deprecated Use supportsImages instead\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 supportsToolCalls?: boolean;\n\n /**\n * @deprecated Use supportsToolCalls instead\n */\n functionCalling?: boolean;\n\n /**\n * Whether the model supports streaming responses.\n * @default true\n */\n supportsStreaming?: boolean;\n\n /**\n * Whether the model supports structured outputs (JSON mode).\n */\n supportsJsonMode?: boolean;\n\n /**\n * @deprecated Use supportsJsonMode instead\n */\n structuredOutputs?: boolean;\n\n /**\n * Maximum context window size in tokens.\n */\n maxContextTokens?: number;\n\n /**\n * Maximum output tokens the model can generate.\n */\n maxOutputTokens?: number;\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 Basic usage\n * ```typescript\n * import { defineModel } from '@standardagents/spec';\n * import { openai } from '@standardagents/openai';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: openai,\n * model: 'gpt-4o',\n * inputPrice: 2.5,\n * outputPrice: 10,\n * });\n * ```\n *\n * @example With capabilities and typed provider options\n * ```typescript\n * import { defineModel } from '@standardagents/spec';\n * import { openai } from '@standardagents/openai';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: openai,\n * model: 'gpt-4o',\n * inputPrice: 2.5,\n * outputPrice: 10,\n * capabilities: {\n * supportsImages: true,\n * supportsToolCalls: true,\n * supportsJsonMode: true,\n * maxContextTokens: 128000,\n * },\n * providerOptions: {\n * service_tier: 'default', // TypeScript knows this is valid\n * },\n * });\n * ```\n */\nexport interface ModelDefinition<\n N extends string = string,\n P extends ProviderFactoryWithOptions<ZodTypeAny> = ProviderFactoryWithOptions<ZodTypeAny>\n> {\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 factory function to use for API calls.\n *\n * Import from a provider package like @standardagents/openai or @standardagents/openrouter.\n * The provider's type determines what providerOptions are available.\n *\n * @example\n * ```typescript\n * import { openai } from '@standardagents/openai';\n * provider: openai\n * ```\n *\n * @example\n * ```typescript\n * import { openrouter } from '@standardagents/openrouter';\n * provider: openrouter\n * ```\n */\n provider: P;\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?: StandardAgentSpec.Models[];\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 * Provider-specific options passed through to the provider.\n * These are merged with prompt-level providerOptions (model options are defaults).\n *\n * The type is automatically inferred from the provider's schema when available,\n * providing TypeScript autocompletion and runtime validation.\n *\n * @example\n * ```typescript\n * // With OpenAI provider\n * providerOptions: {\n * service_tier: 'default',\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With OpenRouter provider\n * providerOptions: {\n * provider: {\n * zdr: true,\n * max_price: { prompt: 1 },\n * },\n * }\n * ```\n */\n providerOptions?: InferProviderOptions<P>;\n\n /**\n * Provider tools available for this model.\n * References tool names from provider.getTools().\n *\n * Provider tools are built-in tools offered by the provider. Tool names are\n * provider-defined capability names, not Standard Agents global names. These\n * tools can be used in prompts alongside custom tools and are executed by\n * the upstream provider.\n *\n * @example\n * ```typescript\n * providerTools: ['web_search', 'code_interpreter'],\n * ```\n */\n providerTools?: string[];\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 * import { openai } from '@standardagents/openai';\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 typed provider options\n * import { openrouter } from '@standardagents/openrouter';\n *\n * export default defineModel({\n * name: 'claude-3-opus',\n * provider: openrouter,\n * model: 'anthropic/claude-3-opus',\n * providerOptions: {\n * provider: {\n * zdr: true,\n * only: ['anthropic'],\n * },\n * },\n * });\n * ```\n */\nexport function defineModel<\n N extends string,\n P extends ProviderFactoryWithOptions<ZodTypeAny>\n>(\n options: ModelDefinition<N, P>\n): ModelDefinition<N, P> {\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 ProviderFactory function\n if (typeof options.provider !== 'function') {\n throw new Error(\n 'Provider must be a ProviderFactory function imported from a provider package (e.g., @standardagents/openai)'\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 // Runtime validation of providerOptions if schema exists on provider\n if (options.provider.providerOptions && options.providerOptions) {\n const result = options.provider.providerOptions.safeParse(options.providerOptions);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => `${String(i.path.join('.'))}: ${i.message}`)\n .join(', ');\n throw new Error(`Invalid providerOptions for model '${options.name}': ${issues}`);\n }\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 { PackedMetadata } from './packing.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 ZodUnknown,\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 /**\n * Machine-readable error code for structured handling.\n *\n * Example: `subagent_env_required` indicates the client must provide\n * scoped subagent env values before execution can continue.\n */\n error_code?: string;\n /**\n * Structured error payload for machine handling.\n *\n * Implementations should keep this JSON-serializable.\n */\n error_data?: Record<string, unknown>;\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 * Use ZodUnknown for arbitrary JSON slots, such as array items that can\n * be strings, numbers, booleans, null, arrays, or objects.\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 | ZodUnknown\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 readonly [\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// Thread Variable Declaration Types\n// ============================================================================\n\n/**\n * Variable declaration type.\n *\n * - `text`: Plain string configuration value\n * - `secret`: Sensitive value that should be encrypted at rest\n */\nexport type VariableType = 'text' | 'secret';\n\n/**\n * Declares a variable required or optionally consumed by a tool or prompt.\n */\nexport interface VariableDefinition {\n /** Environment variable/property name */\n name: string;\n /** Value type */\n type: VariableType;\n /** Whether this variable is required to execute */\n required: boolean;\n /**\n * Whether this variable is scoped to the declarer subtree.\n *\n * Scoped variables do not inherit parent thread env values. Descendants of\n * the declarer still inherit scoped values from that declarer thread.\n *\n * @default false\n */\n scoped?: boolean;\n /** Human-readable description (empty string when not provided) */\n description: string;\n}\n\n// ============================================================================\n// Legacy Thread Environment Variable Types (Zod-based)\n// ============================================================================\n\n/**\n * Legacy raw shape for `tenvs` schema - uses same pattern as ToolArgsRawShape.\n * Each key is an environment variable name and each value is a Zod schema.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type TenvRawShape<D extends number = 7> = Record<string, ToolArgsNode<D>>;\n\n/**\n * Top-level thread environment variable schema.\n *\n * Defines which thread environment variables a tool requires.\n * Required values are non-optional fields, optional values use `.optional()`.\n *\n * @example\n * ```typescript\n * z.object({\n * VECTOR_STORE_ID: z.string().describe('OpenAI Vector Store ID'), // Required\n * USER_LOCATION: z.string().optional().describe('User location'), // Optional\n * })\n * ```\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolTenvs<D extends number = 7> = z.ZodObject<TenvRawShape<D>>;\n\n/**\n * @deprecated Use VariableDefinition[] via the `variables` property instead.\n */\nexport type ToolVariables = VariableDefinition[];\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// Uses-Constrained State Types\n// ============================================================================\n\n/**\n * Helper type to check if Uses is a non-empty const array.\n * Returns true only if Uses has literal string elements (from `as const`).\n */\ntype IsConstArray<Uses extends readonly string[]> =\n // If Uses is exactly `readonly string[]` (non-const), this becomes `string`\n // If Uses is a const tuple like `readonly ['a', 'b']`, this becomes `'a' | 'b'`\n string extends Uses[number] ? false : true;\n\n/**\n * Helper type to check if Uses array is empty.\n */\ntype IsEmptyArray<Uses extends readonly string[]> = Uses extends readonly [] ? true : false;\n\n/**\n * A ThreadState with queueTool and invokeTool constrained to specific tool names.\n *\n * When a tool declares `uses: ['a', 'b'] as const`, the state passed to execute\n * will only allow calling those specific tools.\n *\n * @template Uses - Readonly array of allowed tool names\n */\nexport type UsesConstrainedState<Uses extends readonly string[]> = Omit<\n ThreadState,\n 'queueTool' | 'invokeTool'\n> & {\n /**\n * Queue a tool for execution.\n *\n * Constrained to only tools declared in `uses` array.\n *\n * @param toolName - Name of the tool to invoke (must be in uses array)\n * @param args - Arguments to pass to the tool\n */\n queueTool(toolName: Uses[number], args?: Record<string, unknown>): void;\n\n /**\n * Invoke a tool directly and wait for the result.\n *\n * Constrained to only tools declared in `uses` array.\n *\n * @param toolName - Name of the tool to invoke (must be in uses array)\n * @param args - Arguments to pass to the tool\n * @returns The tool result\n */\n invokeTool(toolName: Uses[number], args?: Record<string, unknown>): Promise<ToolResult>;\n};\n\n/**\n * A ThreadState where queueTool and invokeTool cannot be called (empty uses).\n */\nexport type EmptyUsesState = Omit<ThreadState, 'queueTool' | 'invokeTool'>;\n\n/**\n * Determines the correct state type based on the Uses array.\n *\n * - Empty `uses: [] as const` → EmptyUsesState (no queueTool/invokeTool)\n * - Const `uses: ['a', 'b'] as const` → UsesConstrainedState (constrained methods)\n * - Non-const `uses: ['a']` or no uses → ThreadState (unconstrained, backward compatible)\n */\nexport type ResolveUsesState<Uses extends readonly string[]> =\n IsEmptyArray<Uses> extends true\n ? EmptyUsesState\n : IsConstArray<Uses> extends true\n ? UsesConstrainedState<Uses>\n : ThreadState;\n\n/**\n * Tool execute function with uses-aware state.\n *\n * When `uses` is declared with `as const`, the state's queueTool and invokeTool\n * are constrained to only the declared tools. When `uses` is not declared or\n * is a regular string[], any tool name is allowed (backward compatible).\n *\n * @template State - Base state type\n * @template Args - Tool arguments schema\n * @template Uses - Readonly array of allowed tool names\n */\nexport type UsesAwareExecute<\n State,\n Args extends ToolArgs | null,\n Uses extends readonly string[],\n> = Args extends ToolArgs\n ? (\n state: ResolveUsesState<Uses>,\n args: z.infer<Args>\n ) => Promise<ToolResult>\n : (\n state: ResolveUsesState<Uses>\n ) => Promise<ToolResult>;\n\n// ============================================================================\n// Tool Definition Types (Object-based API)\n// ============================================================================\n\n/**\n * Options for defining a tool.\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 * @template Tenvs - The Zod schema for thread environment variables, or null\n * @template Uses - Readonly array of tool names this tool can invoke\n */\nexport interface DefineToolOptions<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n Tenvs extends ToolTenvs | null = null,\n Uses extends readonly string[] = readonly string[],\n> {\n /** Description of what the tool does (shown to the LLM). */\n description: string;\n /** Zod schema for validating tool arguments. Omit for tools with no args. */\n args?: Args;\n /** The tool implementation function. */\n execute: UsesAwareExecute<State, Args, Uses>;\n /**\n * Variable declarations required/optionally used by this tool.\n */\n variables?: VariableDefinition[];\n /**\n * @deprecated Use `variables` instead.\n * Zod schema for thread environment variables the tool requires.\n */\n tenvs?: Tenvs;\n /**\n * Where this tool is executed:\n * - 'local': Execute locally by the execution engine (default)\n * - 'provider': Executed by the LLM provider, results come in response\n */\n executionMode?: 'local' | 'provider';\n /**\n * Which provider executes this tool (when executionMode='provider').\n * e.g., 'openai', 'anthropic'\n */\n executionProvider?: string;\n /**\n * Explicit list of tools, prompts, or agents this tool can call.\n *\n * When specified with `as const`, the tool's execute function's state\n * will have queueTool() and invokeTool() constrained to only the\n * declared tools (compile-time type safety).\n *\n * At runtime, attempts to call unlisted items will throw an error.\n *\n * This is required for packed tools to ensure namespace isolation.\n * For unpacked tools, it's optional but recommended for clarity.\n *\n * @example\n * ```typescript\n * // Type-safe: only 'validate_input' and 'format_output' allowed\n * defineTool({\n * description: 'Process data using helper tools',\n * uses: ['validate_input', 'format_output'] as const,\n * execute: async (state) => {\n * state.queueTool('validate_input', { data: '...' }); // ✓ OK\n * state.queueTool('unknown_tool', {}); // ✗ TypeScript error\n * // ...\n * },\n * });\n *\n * // Without `as const`, any tool name is allowed (backward compatible)\n * defineTool({\n * description: 'Flexible tool',\n * uses: ['some_tool'],\n * execute: async (state) => {\n * state.queueTool('any_tool', {}); // ✓ OK (no type constraint)\n * },\n * });\n * ```\n */\n uses?: Uses;\n /**\n * The name of an argument whose value is a short, human-readable description\n * of what this tool call is doing — for example `\"fixing index.html\"`.\n *\n * When set, the `tool_call_started` hook and the `tool_call_started` thread\n * event wait until **just this argument** has finished streaming from the\n * model — not the whole tool call — and include its value as `progress`. This\n * lets a UI show what a tool is about to do before a large argument (such as\n * a file's `content`) finishes generating.\n *\n * When unset, `tool_call_started` fires as soon as the tool call appears in\n * the model stream (its name is known, arguments may still be incomplete).\n *\n * Declare the named argument early in the `args` schema and keep it short so\n * it completes quickly. If the model never emits it, `tool_call_started`\n * still fires once the tool call finishes, with `progress` undefined.\n *\n * @example\n * ```typescript\n * defineTool({\n * description: 'Write a file to the workspace',\n * progressArgument: 'description',\n * args: z.object({\n * description: z.string().describe('e.g. \"writing index.html\"'),\n * path: z.string(),\n * content: z.string(),\n * }),\n * execute: async (state, args) => { ... },\n * });\n * ```\n */\n progressArgument?: string;\n}\n\n/**\n * Tool definition object returned by defineTool().\n *\n * Contains all the metadata and implementation needed to register\n * and execute a tool.\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 * @template Tenvs - The Zod schema for thread environment variables, or null\n * @template Uses - Readonly array of tool names this tool can invoke\n */\nexport interface ToolDefinition<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n Tenvs extends ToolTenvs | null = null,\n Uses extends readonly string[] = readonly string[],\n> {\n /** Description of what the tool does (shown to the LLM). */\n description: string;\n /** Zod schema for validating tool arguments, or null for no args. */\n args: Args;\n /** The tool implementation function. */\n execute: UsesAwareExecute<State, Args, Uses>;\n /** Declared variables for this tool. */\n variables: VariableDefinition[];\n /**\n * @deprecated Use `variables` instead.\n * Zod schema for thread environment variables, or null if none.\n */\n tenvs: Tenvs;\n /**\n * Where this tool is executed:\n * - 'local': Execute locally by the execution engine (default)\n * - 'provider': Executed by the LLM provider, results come in response\n */\n executionMode?: 'local' | 'provider';\n /**\n * Which provider executes this tool (when executionMode='provider').\n */\n executionProvider?: string;\n /**\n * Explicit list of tools, prompts, or agents this tool can call.\n *\n * When specified with `as const`, TypeScript constrains queueTool()\n * and invokeTool() at compile time. At runtime, attempts to call\n * unlisted items throw an error.\n *\n * This is required for packed tools to ensure namespace isolation.\n * For unpacked tools, it's optional but recommended for clarity.\n *\n * Items can be:\n * - Simple names: Resolve within current namespace\n * - Qualified names (e.g., 'other_pkg:agent'): Cross-package entry point\n */\n uses?: Uses;\n /**\n * The name of an argument carrying a short, human-readable description of what\n * this tool call is doing (e.g. `\"fixing index.html\"`). Controls when the\n * `tool_call_started` hook/event fires — see {@link DefineToolOptions.progressArgument}.\n */\n progressArgument?: string;\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\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), an implementation function, and\n * optional variable requirements.\n *\n * @example\n * ```typescript\n * import { defineTool } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * // Tool with arguments\n * export default defineTool({\n * description: 'Search the knowledge base for relevant information',\n * args: z.object({\n * query: z.string().describe('Search query'),\n * limit: z.number().optional().describe('Max results'),\n * }),\n * execute: async (state, args) => {\n * const results = await search(args.query, args.limit);\n * return { status: 'success', result: JSON.stringify(results) };\n * },\n * });\n *\n * // Tool without arguments\n * export default defineTool({\n * description: 'Get the current server time',\n * execute: async (state) => {\n * return { status: 'success', result: new Date().toISOString() };\n * },\n * });\n *\n * // Tool with declared variables\n * export default defineTool({\n * description: 'Search through uploaded files',\n * args: z.object({ query: z.string() }),\n * execute: async (state, args) => ({ status: 'success', result: 'done' }),\n * variables: [\n * {\n * name: 'VECTOR_STORE_ID',\n * type: 'text',\n * required: true,\n * description: 'OpenAI Vector Store ID',\n * },\n * ],\n * });\n *\n * // Provider-executed tool (e.g., OpenAI built-in tools)\n * export default defineTool({\n * description: 'Generate images using DALL-E',\n * args: z.object({ prompt: z.string() }),\n * execute: async () => ({ status: 'success', result: 'Handled by provider' }),\n * executionMode: 'provider',\n * executionProvider: 'openai',\n * });\n * ```\n *\n * @param options - Tool definition options\n * @returns A tool definition object\n */\n/**\n * Validate a tool name does not contain reserved characters.\n * Tools are typically defined without a name field (they get the filename),\n * but this can be called by build tools that assign names.\n */\nexport function validateToolName(name: string): void {\n if (name.includes('/')) {\n throw new Error(`Tool name cannot contain '/'. Reserved for namespace qualification.`);\n }\n}\n\nexport function defineTool<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n Tenvs extends ToolTenvs | null = null,\n Uses extends readonly string[] = readonly string[],\n>(\n options: DefineToolOptions<State, Args, Tenvs, Uses>\n): ToolDefinition<State, Args, Tenvs, Uses> {\n const variables =\n (options.variables ?? extractVariablesFromTenvSchema((options.tenvs ?? null) as ToolTenvs | null))\n .map((entry) => ({\n name: entry.name,\n type: (entry.type === 'secret' ? 'secret' : 'text') as VariableType,\n required: !!entry.required,\n description: typeof entry.description === 'string' ? entry.description : '',\n }));\n\n return {\n description: options.description,\n args: (options.args ?? null) as Args,\n execute: options.execute,\n variables,\n tenvs: (options.tenvs ?? null) as Tenvs,\n executionMode: options.executionMode,\n executionProvider: options.executionProvider,\n uses: options.uses,\n progressArgument: options.progressArgument,\n };\n}\n\n/**\n * @deprecated Helper for backward-compatibility with legacy `tenvs`.\n */\nfunction extractVariablesFromTenvSchema(\n tenvSchema: ToolTenvs | null\n): VariableDefinition[] {\n if (!tenvSchema) return [];\n const shape = (tenvSchema as z.ZodObject<any>).shape;\n if (!shape) return [];\n\n return Object.entries(shape).map(([name, fieldSchema]) => {\n const zodSchema = fieldSchema as z.ZodTypeAny;\n return {\n name,\n type: 'text',\n required: !zodSchema.isOptional(),\n description: zodSchema.description ?? '',\n };\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, VariableDefinition, VariableType } 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: StandardAgentSpec.Prompts;\n}\n\n/**\n * An environment variable insertion part.\n *\n * Loads a thread variable by property name at interpolation time.\n */\nexport interface PromptEnvPart {\n type: 'env';\n /** Variable property name to resolve from thread env */\n property: 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 | PromptEnvPart;\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 or agents used as tools.\n * These options control how results from sub-prompts are returned to the caller.\n *\n * @template T - The sub-prompt/agent name type (for type-safe references)\n */\nexport interface SubpromptConfig<T extends string = StandardAgentSpec.Callables> {\n /**\n * Name of the sub-prompt or agent to call.\n * Must be a prompt defined in agents/prompts/ or an agent in agents/agents/.\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 or agent.\n *\n * Autocompletes to fields from the prompt's requiredSchema (or agent's side_a prompt schema).\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?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Property containing attachment path(s) to include as multimodal content\n * when invoking the sub-prompt or agent.\n *\n * Autocompletes to fields from the prompt's requiredSchema (or agent's side_a prompt schema).\n * Supports both a single path string or an array of paths.\n *\n * @example\n * If the tool is called with `{ image: \"/attachments/123.jpg\" }` and\n * `initAttachmentsProperty: 'image'`, the sub-prompt will receive\n * the image as an attachment in the user message.\n *\n * @example\n * If the tool is called with `{ images: [\"/attachments/a.jpg\", \"/attachments/b.jpg\"] }` and\n * `initAttachmentsProperty: 'images'`, the sub-prompt will receive\n * both images as attachments.\n */\n initAttachmentsProperty?: StandardAgentSpec.SchemaFields<T>;\n}\n\n/**\n * @deprecated Use SubpromptConfig instead\n */\nexport type ToolConfig<T extends string = string> = SubpromptConfig<T>;\n\n// ============================================================================\n// Prompt Tool Configuration\n// ============================================================================\n\n/**\n * Configuration for a tool used in a prompt.\n * Allows specifying environment values and static options for the tool.\n *\n * @example\n * ```typescript\n * // Tool with environment values\n * { name: 'file_search', env: { VECTOR_STORE_ID: 'vs_abc123' } }\n *\n * // Tool with options\n * { name: 'web_search', options: { searchContextSize: 'high' } }\n * ```\n */\nexport interface PromptToolConfig {\n /**\n * Name of the tool (custom tool or provider tool).\n */\n name: StandardAgentSpec.Callables;\n\n /**\n * Environment variable values for this tool.\n */\n env?: Record<string, string>;\n /**\n * @deprecated Use `env` instead.\n */\n tenvs?: Record<string, unknown>;\n\n /**\n * Static options for this tool.\n * Passed to the tool handler at execution time.\n */\n options?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Subagent Tool Configuration\n// ============================================================================\n\n/**\n * Configuration for invoking a `dual_ai` agent as a subagent tool.\n *\n * Subagent tools are always autonomous `dual_ai` agents and support both:\n * - Blocking vs non-blocking execution\n * - Resumable vs non-resumable lifecycles\n *\n * Non-resumable subagents behave like normal tool calls.\n * Resumable subagents are created/messaged through runtime-injected lifecycle\n * tools (for example `subagent_create` and `subagent_message`) and tracked in\n * the parent thread registry. The injected `subagent_create` tool MUST require\n * a non-empty human-readable `name` argument and runtimes SHOULD persist it as\n * a child thread display name.\n *\n * ### Persistent invocation arguments\n *\n * The child side that receives parent messages dictates initial invocation\n * arguments through that side's prompt `requiredSchema`\n * (`resumable.receives_messages`, defaulting to `side_a`). The invoking parent\n * supplies them when calling the subagent tool or `subagent_create` as a\n * structured `arguments` object.\n *\n * Unlike a plain tool call, these arguments are NOT ephemeral: runtimes MUST\n * persist the validated arguments for the life of the child thread and make\n * them available to BOTH `side_a` and `side_b` through `ThreadState.arguments`\n * and prompt variable interpolation on every activation. This lets a system\n * prompt reference spawn-time context for as long as the thread lives.\n *\n * If required arguments are missing or invalid, runtimes MUST reject creation\n * with a `subagent_arguments_required` error rather than spawning the child.\n *\n * @example\n * ```typescript\n * {\n * name: 'browser_agent',\n * blocking: false,\n * resumable: {\n * receives_messages: 'side_a',\n * maxInstances: 1,\n * },\n * }\n * ```\n */\nexport interface SubagentToolConfig<\n T extends string = StandardAgentSpec.Callables,\n> {\n /**\n * Agent callable name.\n *\n * Must reference a `dual_ai` agent with `exposeAsTool: true`.\n */\n name: T;\n\n /**\n * Whether parent execution blocks until the subagent returns a result.\n *\n * - `true`: Parent waits for completion (tool-call style)\n * - `false`: Parent continues immediately and receives results asynchronously\n *\n * @default true\n */\n blocking?: boolean;\n\n /**\n * Property from tool-call arguments used as the initial message sent to the\n * subagent on invocation.\n *\n * Uses the same semantics as {@link SubpromptConfig.initUserMessageProperty}.\n */\n initUserMessageProperty?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Property from tool-call arguments containing attachment path(s) that should\n * be sent to the subagent on invocation.\n *\n * Uses the same semantics as {@link SubpromptConfig.initAttachmentsProperty}.\n */\n initAttachmentsProperty?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Property from tool-call arguments used to assign a human-readable name for\n * each spawned child thread instance.\n *\n * Implementations SHOULD store this as a thread tag in the form\n * `name:<value>` so UIs can render a concise per-instance title.\n */\n initAgentNameProperty?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Execute this tool immediately when the prompt becomes active.\n *\n * - `true`: Execute immediately using runtime defaults.\n * - Object: Execute immediately with explicit per-instance env relationships.\n *\n * When the object form is used:\n * - `scopedEnv` names the per-instance env values copied into the child thread.\n * - `nameEnv` and `descriptionEnv` identify the only per-instance env values\n * that runtimes may expose to an internal bootstrap model when deriving\n * initial child arguments.\n *\n * Runtimes MUST NOT expose `scopedEnv` values to the model unless the same env\n * name is explicitly designated by `nameEnv` or `descriptionEnv`.\n *\n * Immediate tools run before the first LLM step for that activation.\n */\n immediate?:\n | boolean\n | {\n /**\n * Scoped env name whose value may be used as the safe per-instance name\n * hint for child bootstrap.\n */\n nameEnv?: string;\n\n /**\n * Scoped env name whose value may be used as the safe per-instance\n * description hint for child bootstrap.\n */\n descriptionEnv?: string;\n\n /**\n * Scoped env names that should be copied into the child thread for each\n * immediate instance group.\n */\n scopedEnv?: string[];\n };\n\n /**\n * Optional branch flag env name.\n *\n * When set, this subagent is only enabled when the named env resolves to\n * `true`, `1`, or `yes` (case-insensitive).\n */\n optional?: string;\n\n /**\n * Resumability configuration.\n *\n * - `false` (default): Non-resumable subagent\n * - Object: Resumable subagent with message routing and instance limits\n *\n * When resumable mode is enabled, runtimes SHOULD provide a built-in create\n * and message lifecycle interface instead of exposing raw agent callables for\n * new instance creation.\n */\n resumable?:\n | false\n | {\n /**\n * Which side of the child `dual_ai` conversation receives parent messages.\n *\n * - `side_a`: Messages are queued as `role: 'user'`\n * - `side_b`: Messages are queued as `role: 'assistant'`\n */\n receives_messages: 'side_a' | 'side_b';\n\n /**\n * Maximum concurrent instances for this subagent tool.\n *\n * When reached, implementations may remove this tool from subsequent LLM\n * requests and route new messages to existing instances.\n *\n * @default unlimited\n */\n maxInstances?: number;\n\n /**\n * How this child reports back to its parent.\n *\n * - `implicit` (default): Child completion is automatically queued to the parent.\n * - `explicit`: The runtime does not auto-queue child completion; tools/hooks may\n * use thread APIs such as `state.notifyParent()` or `state.stopSession()` when\n * they choose to escalate or terminally end the session.\n */\n parentCommunication?: 'implicit' | 'explicit';\n };\n\n /**\n * How this subagent reports completion back to its parent. Applies to\n * non-resumable subagents; resumable subagents may instead set\n * `resumable.parentCommunication`, which takes precedence when present.\n *\n * - `implicit` (default): the child's completion is auto-queued to the parent,\n * which triggers a parent turn.\n * - `explicit`: the runtime does NOT auto-queue the child's completion, so the\n * parent is not woken. Use for background subagents that deliver their result\n * another way (e.g. writing to the parent's thread KV) and should be \"picked\n * up\" on the parent's next natural turn rather than forcing one.\n */\n parentCommunication?: 'implicit' | 'explicit';\n\n /**\n * Hide this subagent tool from the LLM's tool list while keeping the\n * relationship declared, so runtime code (hooks calling\n * `state.invokeTool()` / `queueTool()`) can still spawn it. Use for\n * infrastructure subagents the model must never call itself (e.g. a\n * background context-compaction agent).\n *\n * @default false\n */\n hidden?: boolean;\n}\n\n// ============================================================================\n// Reasoning Configuration\n// ============================================================================\n\n/**\n * Reasoning configuration for models that support extended thinking.\n * Applies to models like OpenAI o1/o3, Anthropic Claude with extended thinking,\n * Google Gemini with thinking, and Qwen with reasoning.\n */\nexport interface ReasoningConfig {\n /**\n * Numeric reasoning level on a 0-100 scale.\n * The FlowEngine maps this to the model's nearest supported reasoning option.\n *\n * @example\n * // Typical breakpoints:\n * // 0 = No reasoning\n * // 33 = Low effort\n * // 66 = Medium effort\n * // 100 = Maximum effort\n *\n * reasoning: { level: 75 } // Maps to 'high' on most models\n */\n level?: number;\n\n /**\n * @deprecated Use `level` instead. Will be removed in future versions.\n *\n * Effort level for reasoning models.\n * Higher effort = more thinking tokens = potentially better results.\n *\n * - `low`: Minimal reasoning, faster responses (equivalent to level ~33)\n * - `medium`: Balanced reasoning and speed (equivalent to level ~66)\n * - `high`: Maximum reasoning, slower but more thorough (equivalent to level ~100)\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: StandardAgentSpec.Models;\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 * When this prompt is the `side_a` prompt of a `dual_ai` agent exposed as a\n * subagent, this schema also dictates the invocation arguments accepted by\n * the subagent tool (and the runtime-injected `subagent_create` tool).\n * Required fields are mandatory; optional fields are treated as suggested.\n * Runtimes persist the validated arguments for the life of the child thread\n * and expose them to both sides' prompt interpolation (see\n * {@link SubagentToolConfig} \"Persistent invocation arguments\").\n */\n requiredSchema?: S;\n\n /**\n * Declared variables for this prompt.\n */\n variables?: VariableDefinition[];\n\n /**\n * Tools available to this prompt.\n * Can be:\n * - string: Simple tool name (custom or provider tool)\n * - SubpromptConfig: Sub-prompt used as a tool\n * - PromptToolConfig: Tool with environment values and/or options\n * - SubagentToolConfig: `dual_ai` subagent invocation behavior\n *\n * To enable handoffs, include ai_human agent names in this array.\n *\n * @example\n * ```typescript\n * tools: [\n * 'custom_tool', // Simple tool name\n * { name: 'other_prompt' }, // Sub-prompt as tool\n * { name: 'file_search', env: { VECTOR_STORE_ID: 'vs_123' } }, // Tool with env values\n * ]\n * ```\n */\n tools?: (\n | StandardAgentSpec.Callables\n | SubpromptConfig\n | PromptToolConfig\n | SubagentToolConfig\n )[];\n\n /**\n * Environment values provided by this prompt.\n * Prompt values override user-account and AgentBuilder-instance defaults.\n * Agent and thread values override prompt values.\n */\n env?: Record<string, string>;\n /**\n * @deprecated Use `env` instead.\n */\n tenvs?: Record<string, unknown>;\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 * Provider-specific options passed through to the provider.\n * These override model-level providerOptions for this prompt.\n *\n * Options are merged in order (later wins):\n * 1. model.providerOptions (defaults)\n * 2. prompt.providerOptions (this field - overrides)\n *\n * @example\n * ```typescript\n * providerOptions: {\n * response_format: { type: 'json_object' },\n * }\n * ```\n */\n providerOptions?: Record<string, unknown>;\n\n /**\n * Hook IDs to run when this prompt is active.\n * References hooks by their unique `id` property from defineHook().\n * If not specified, falls back to agent-level hooks.\n *\n * @example\n * ```typescript\n * hooks: ['limit_to_20_messages', 'log_tool_calls']\n * ```\n */\n hooks?: StandardAgentSpec.HookIds[];\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.name.includes('/')) {\n throw new Error(`Prompt name cannot contain '/'. Reserved for namespace qualification.`);\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 configuration\n if (options.reasoning) {\n // Validate level is 0-100 if provided\n if (options.reasoning.level !== undefined) {\n if (typeof options.reasoning.level !== 'number' || options.reasoning.level < 0 || options.reasoning.level > 100) {\n throw new Error('reasoning.level must be a number between 0 and 100');\n }\n }\n\n // Validate effort is a known value (deprecated but still supported)\n if (options.reasoning.effort && !['low', 'medium', 'high'].includes(options.reasoning.effort)) {\n throw new Error(\n `Invalid reasoning.effort '${options.reasoning.effort}'. Must be one of: low, medium, high`\n );\n }\n\n // Warn if both level and effort are provided\n if (options.reasoning.level !== undefined && options.reasoning.effort !== undefined) {\n console.warn('Both reasoning.level and reasoning.effort provided. level takes precedence. effort is deprecated.');\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 const normalizedVariables = Array.isArray(options.variables)\n ? options.variables.map((entry) => ({\n name: entry.name,\n type: (entry.type === 'secret' ? 'secret' : 'text') as VariableType,\n required: !!entry.required,\n scoped: !!entry.scoped,\n description: typeof entry.description === 'string' ? entry.description : '',\n }))\n : undefined;\n\n return {\n ...options,\n ...(normalizedVariables ? { variables: normalizedVariables } : {}),\n };\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';\nimport type { ToolAttachment, AttachmentRef } from './tools.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({\n * hook: 'filter_messages',\n * id: 'keep_recent',\n * execute: async (state, messages) => {\n * console.log(`Thread: ${state.threadId}`);\n * if (state.execution) {\n * console.log(`Step: ${state.execution.stepCount}`);\n * }\n * return messages.slice(-10);\n * },\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 * 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 attachments?: Array<ToolAttachment | AttachmentRef>;\n}\n\n/**\n * LLM message format for prefilter hook.\n *\n * Messages passed to the prefilter_llm_history hook are in chat completion\n * format. Content can be a plain string or a multimodal array (for messages\n * with images). Additional provider-specific fields may also be present.\n */\nexport interface LLMMessage {\n /** Message role */\n role: string;\n /** Message content (string for text-only, array for multimodal) */\n content?: string | null | unknown[];\n /** Tool calls (parsed) */\n tool_calls?: unknown;\n /** Tool call ID */\n tool_call_id?: string;\n /** Tool name */\n name?: string;\n /** Reasoning content (for models like o1) */\n reasoning_content?: string;\n /** Allow additional provider-specific fields */\n [key: string]: unknown;\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 after a thread is created, before initial message processing or LLM\n * requests for that thread.\n *\n * Only ThreadState is passed. Use for initializing durable thread values,\n * env placeholders, files, or side-effect instrumentation.\n *\n * @param state - Created thread state\n */\n after_thread_created: (state: State) => Promise<void>;\n\n /**\n * Called on the parent thread immediately after a subagent child thread is\n * created.\n *\n * Receives parent ThreadState and child ThreadState. Use for copying or\n * linking metadata, bookkeeping, or side-effect instrumentation.\n *\n * @param state - Parent thread state\n * @param childState - Created child thread state\n */\n after_subagent_created: (state: State, childState: State) => Promise<void>;\n\n /**\n * Called after the prompt system message is rendered for a model request.\n *\n * Return a string to replace the rendered system message. Return null or\n * undefined to keep the original message.\n *\n * @param state - Thread state\n * @param systemMessage - Rendered system message for this request\n * @returns Replacement system message, or null/undefined for no change\n */\n after_system_message: (\n state: State,\n systemMessage: string\n ) => string | Promise<string | null | undefined> | null | undefined;\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({\n * hook: 'filter_messages',\n * id: 'limit_to_10',\n * execute: async (state, messages) => 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({\n * hook: 'prefilter_llm_history',\n * id: 'add_reminder',\n * execute: async (state, messages) => 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 full message object before insertion. Return modified\n * message to transform before storage.\n *\n * @param state - Thread state\n * @param message - Message to be created\n * @returns Modified message\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'before_create_message',\n * id: 'prefix_content',\n * execute: async (state, message) => {\n * // message has full type: id, role, content, created_at, etc.\n * if (message.role === 'user' && message.content) {\n * return { ...message, content: `[user] ${message.content}` };\n * }\n * return message;\n * }\n * });\n * ```\n */\n before_create_message: (\n state: State,\n message: Msg\n ) => Promise<Msg>;\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\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'after_create_message',\n * id: 'log_creation',\n * execute: async (state, message) => {\n * console.log(`Created ${message.role} message: ${message.id}`);\n * }\n * });\n * ```\n */\n after_create_message: (\n state: State,\n message: Msg\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({\n * hook: 'before_update_message',\n * id: 'stamp_updated_at',\n * execute: async (state, messageId, updates) => ({\n * ...updates,\n * updated_at: Date.now(),\n * }),\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({\n * hook: 'after_update_message',\n * id: 'log_update',\n * execute: async (state, message) => {\n * console.log(`Message updated: ${message.id}`);\n * },\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\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'before_store_tool_result',\n * id: 'sanitize_results',\n * execute: async (state, toolCall, toolResult) => {\n * // toolCall has: id, type, function.name, function.arguments\n * // toolResult has: status, result?, error?, stack?, attachments?\n * if (toolResult.result) {\n * return { ...toolResult, result: sanitize(toolResult.result) };\n * }\n * return toolResult;\n * }\n * });\n * ```\n */\n before_store_tool_result: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult>;\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({\n * hook: 'after_tool_call_success',\n * id: 'log_success',\n * execute: async (state, toolCall, toolResult) => {\n * console.log(`Tool ${toolCall.function.name} succeeded`);\n * return null; // use original result\n * },\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({\n * hook: 'after_tool_call_failure',\n * id: 'log_failure',\n * execute: async (state, toolCall, toolResult) => {\n * console.error(`Tool ${toolCall.function.name} failed: ${toolResult.error}`);\n * return null; // use original error\n * },\n * });\n * ```\n */\n after_tool_call_failure: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult | null>;\n\n /**\n * Called when a tool call STARTS — before the tool executes, while the model\n * may still be generating the rest of the call. Fires exactly once per tool\n * call. Observational: the return value is ignored.\n *\n * Timing depends on whether the tool declares a `progressArgument`:\n * - **With** `progressArgument`: fires as soon as *just that argument* has\n * finished streaming (not the whole call), passing its value as `progress`.\n * This lets a UI show \"fixing index.html\" before a large `content` argument\n * finishes generating.\n * - **Without** `progressArgument`: fires as soon as the tool call appears in\n * the stream — its name is known but `toolCall.function.arguments` may be an\n * incomplete JSON fragment (or empty), and `progress` is undefined.\n *\n * Conforming runtimes also broadcast a `tool_call_started` thread event to\n * connected clients with `{ id, name, progress }` at the same moment.\n *\n * @param state - Thread state\n * @param toolCall - The starting tool call; `function.arguments` may be incomplete\n * @param progress - The declared progress-argument value, when available\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'tool_call_started',\n * id: 'log_tool_start',\n * execute: async (state, toolCall, progress) => {\n * console.log(`▸ ${toolCall.function.name}${progress ? `: ${progress}` : ''}`);\n * },\n * });\n * ```\n */\n tool_call_started: (\n state: State,\n toolCall: ToolCall,\n progress?: string\n ) => Promise<void>;\n\n /**\n * Called when a tool call is DONE — after it has executed, with its result,\n * regardless of success or failure. Fires once per tool call. Observational:\n * the return value is ignored.\n *\n * This complements `after_tool_call_success` / `after_tool_call_failure`,\n * which can additionally *modify* the stored result; `tool_call_done` is a\n * single unified observation point that always fires. Conforming runtimes\n * also broadcast a `tool_call_done` thread event to connected clients with\n * `{ id, name, status }` at the same moment.\n *\n * @param state - Thread state\n * @param toolCall - The completed tool call\n * @param toolResult - The tool's result (`status` is `'success'` or `'error'`)\n */\n tool_call_done: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<void>;\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 * @deprecated Use the object-based defineHook signature instead\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// Hook Definition Options (NEW)\n// ============================================================================\n\n/**\n * Options for defining a hook with explicit ID.\n * The generic K ensures `execute` is properly typed for the specific hook type.\n *\n * @template K - Hook type from HookSignatures (e.g., 'filter_messages')\n */\nexport interface HookDefinitionOptions<K extends HookName> {\n /** The hook type (e.g., 'filter_messages', 'before_create_message') */\n hook: K;\n /** Unique identifier for this hook implementation (snake_case) */\n id: string;\n /**\n * The hook implementation function.\n * Type is automatically inferred from the hook type.\n */\n execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];\n}\n\n/**\n * Return type from defineHook - preserves the hook type for type-safe usage.\n *\n * @template K - Hook type from HookSignatures\n */\nexport interface HookDefinitionResult<K extends HookName> {\n /** The hook type name */\n hook: K;\n /** The unique hook ID */\n id: string;\n /** The typed execute function */\n execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Valid hook names for runtime validation\n */\nconst VALID_HOOKS: HookName[] = [\n 'after_thread_created',\n 'after_subagent_created',\n 'after_system_message',\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 'tool_call_started',\n 'tool_call_done',\n];\n\n/**\n * Define a hook with a unique identifier and strict typing.\n *\n * The hook type determines the execute function signature.\n * TypeScript will enforce correct parameter and return types.\n *\n * @template K - The hook type (inferred from options.hook)\n * @param options - Hook definition with hook type, ID, and execute function\n * @returns Typed hook definition for registration\n *\n * @example\n * ```typescript\n * // Filter messages - execute receives (state: ThreadState, messages: HookMessage[])\n * export default defineHook({\n * hook: 'filter_messages',\n * id: 'limit_to_20_messages',\n * execute: async (state, messages) => {\n * return messages.slice(-20);\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Before create message - execute receives (state: ThreadState, message: Message)\n * export default defineHook({\n * hook: 'before_create_message',\n * id: 'prefix_content',\n * execute: async (state, message) => {\n * if (message.role === 'user' && message.content) {\n * return { ...message, content: `[user] ${message.content}` };\n * }\n * return message;\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // After tool call success - execute receives (state, toolCall, toolResult)\n * export default defineHook({\n * hook: 'after_tool_call_success',\n * id: 'log_tool_usage',\n * execute: async (state, toolCall, toolResult) => {\n * console.log(`Tool ${toolCall.function.name} returned: ${toolResult.result}`);\n * return null; // Use original result\n * }\n * });\n * ```\n */\nexport function defineHook<K extends HookName>(\n options: HookDefinitionOptions<K>\n): HookDefinitionResult<K> {\n // Validate hook name at runtime\n if (!VALID_HOOKS.includes(options.hook)) {\n throw new Error(\n `Invalid hook type '${options.hook}'. Valid hooks: ${VALID_HOOKS.join(', ')}`\n );\n }\n\n if (!options.id || typeof options.id !== 'string') {\n throw new Error('Hook id is required and must be a non-empty string');\n }\n\n // Validate id format (snake_case)\n if (!/^[a-z][a-z0-9_]*$/.test(options.id)) {\n throw new Error(\n `Hook id '${options.id}' must be snake_case (lowercase letters, numbers, underscores, starting with letter)`\n );\n }\n\n return {\n hook: options.hook,\n id: options.id,\n execute: options.execute,\n };\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 whichever scheduling mechanism the runtime provides.\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 a session lifecycle tool.\n *\n * Used by side-level lifecycle options (`sessionStop`, `sessionFail`, `sessionStatus`)\n * to declare:\n * - which tool controls that lifecycle action\n * - which tool-argument field should be forwarded as message text\n * - which tool-argument field contains attachment path(s) to forward\n *\n * @template Callable - Callable name type\n */\nexport interface SessionToolConfig<\n Callable extends string = StandardAgentSpec.Callables,\n> {\n /**\n * Tool name for this session lifecycle action.\n */\n name: Callable;\n\n /**\n * Optional tool-argument property used as lifecycle message text.\n */\n messageProperty?: string;\n\n /**\n * Optional tool-argument property containing attachment path(s).\n * Supports a single path string or an array of path strings.\n */\n attachmentsProperty?: string;\n}\n\n/**\n * Session lifecycle tool reference.\n *\n * Can be either:\n * - a plain tool name string (legacy/simple form)\n * - a {@link SessionToolConfig} object (explicit mapping form)\n */\nexport type SessionToolBinding<\n Callable extends string = StandardAgentSpec.Callables,\n> = Callable | SessionToolConfig<Callable>;\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 = StandardAgentSpec.Prompts,\n Callable extends string = StandardAgentSpec.Callables,\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 *\n * Different from stopTool: this ends the session for both sides,\n * not just this side's turn.\n *\n * Use object form to explicitly map message/attachment argument fields.\n *\n * In subagent runtimes, mapped message/attachments are the canonical\n * completion payload returned from child -> parent.\n */\n sessionStop?: SessionToolBinding<Callable>;\n\n /**\n * Tool that fails the entire session when called.\n *\n * Use this when the side cannot fulfill the request and needs to terminate\n * the session with an error outcome.\n *\n * When used inside a subagent, this failure is propagated back to the parent\n * as a terminal failure result.\n *\n * Use object form to explicitly map message/attachment argument fields.\n *\n * In subagent runtimes, mapped message/attachments are the canonical\n * failure payload returned from child -> parent.\n */\n sessionFail?: SessionToolBinding<Callable>;\n\n /**\n * Tool that publishes status updates to the parent thread when used as a subagent.\n *\n * When called from a `dual_ai` subagent, message text is forwarded to\n * the parent thread's subagent registry as this instance's current status.\n *\n * Use object form to explicitly map message/attachment argument fields.\n *\n * Status updates do not terminate the session.\n *\n * @example\n * ```typescript\n * sideA: {\n * prompt: 'research_worker',\n * sessionStatus: { name: 'update_status', messageProperty: 'status' },\n * }\n * ```\n */\n sessionStatus?: SessionToolBinding<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 = StandardAgentSpec.Prompts,\n Callable extends string = StandardAgentSpec.Callables,\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 * Environment values provided by this agent.\n * Agent values are lower priority than thread/account/instance values.\n */\n env?: Record<string, string>;\n\n /**\n * @deprecated Use `env` instead.\n */\n tenvs?: Record<string, unknown>;\n\n // ============================================================================\n // Package Metadata (for packing/unpacking)\n // ============================================================================\n\n /**\n * npm package name for this agent when packed.\n * Used by the packing system to maintain consistent package identity\n * across pack/unpack cycles.\n *\n * @example 'standardagent-support-agent', '@myorg/support-agent'\n */\n packageName?: string;\n\n /**\n * Package version (semver format).\n * Used by the packing system to track versions across pack/unpack cycles.\n * When re-packing, this version is auto-incremented by the pack modal.\n *\n * @example '1.0.0', '2.3.1-beta.1'\n */\n version?: string;\n\n /**\n * Package author/copyright holder.\n * Used by the packing system for the LICENSE file and package.json author field.\n *\n * @example 'John Doe', 'Acme Corp'\n */\n author?: string;\n\n /**\n * License identifier (SPDX format).\n * Used by the packing system for LICENSE file generation.\n *\n * @example 'MIT', 'Apache-2.0', 'ISC'\n */\n license?: string;\n\n /**\n * Hook IDs to run for this agent.\n * References hooks by their unique `id` property from defineHook().\n * These run when prompts don't specify their own hooks.\n *\n * @example\n * ```typescript\n * hooks: ['log_messages', 'track_tool_usage']\n * ```\n */\n hooks?: StandardAgentSpec.HookIds[];\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 * sessionStop: '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 * sessionStop: 'conclude_debate',\n * },\n * });\n * ```\n */\nexport function defineAgent<N extends string>(\n options: AgentDefinition<N>\n): AgentDefinition<N> {\n const validateSessionBinding = (\n sideLabel: 'sideA' | 'sideB',\n sessionKey: 'sessionStop' | 'sessionFail' | 'sessionStatus',\n ): void => {\n const side = options[sideLabel];\n if (!side) return;\n\n const sessionBinding = side[sessionKey];\n\n if (\n typeof sessionBinding === 'object' &&\n sessionBinding !== null &&\n !Array.isArray(sessionBinding)\n ) {\n if (!('name' in sessionBinding) || typeof sessionBinding.name !== 'string' || !sessionBinding.name) {\n throw new Error(`${sideLabel}.${sessionKey}.name is required when ${sideLabel}.${sessionKey} uses object form`);\n }\n }\n };\n\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Agent name is required');\n }\n if (options.name.includes('/')) {\n throw new Error(`Agent name cannot contain '/'. Reserved for namespace qualification.`);\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 validateSessionBinding('sideA', 'sessionStop');\n validateSessionBinding('sideA', 'sessionFail');\n validateSessionBinding('sideA', 'sessionStatus');\n if (options.sideB) {\n validateSessionBinding('sideB', 'sessionStop');\n validateSessionBinding('sideB', 'sessionFail');\n validateSessionBinding('sideB', 'sessionStatus');\n }\n\n return {\n ...options,\n type,\n };\n}\n","/**\n * Thread state types for Standard Agents.\n *\n * ThreadState is the unified interface for all thread operations.\n * It provides access to thread identity, messages, logs, resource loading,\n * tool invocation, event emission, and execution state.\n *\n * @module\n */\n\nimport type {\n ToolResult,\n ToolAttachment,\n AttachmentRef,\n} from './tools.js';\nimport type { ScheduledEffect } from './effects.js';\nimport type { SkillsNamespace } from './skills.js';\n\n// ============================================================================\n// Thread Identity\n// ============================================================================\n\n/**\n * Metadata about a thread.\n *\n * This represents the core identity of a thread, separate from its\n * operational state. Thread metadata is immutable after creation.\n */\n/**\n * The profile of the user a thread belongs to, as exposed by\n * {@link ThreadState.user}. Identity fields only — never credentials.\n */\nexport interface ThreadUser {\n id: string;\n username: string;\n /** 'admin' | 'user' | 'api' in the reference runtime. */\n role: string;\n /** Explicit permission grants (runtime-defined strings), if any. */\n permissions?: string[] | null;\n email?: string | null;\n display_name?: string | null;\n avatar_url?: string | null;\n}\n\nexport interface ThreadMetadata {\n /** Unique identifier for the thread */\n id: string;\n /** Agent that owns this thread */\n agent_id: string;\n /** User associated with this thread (if any) */\n user_id: string | null;\n /** Creation timestamp (microseconds since epoch) */\n created_at: number;\n}\n\n/**\n * Registry entry for a subagent child thread.\n */\nexport interface SubagentRegistryEntry {\n /** Child thread UUID used as stable reference address */\n reference: string;\n /** Child agent name */\n name: string;\n /** Child agent title (human-readable) */\n title?: string;\n /** Tool description shown to the parent LLM */\n description: string;\n /** Whether this subagent instance is resumable */\n resumable?: boolean;\n /** Whether parent execution blocks on this subagent */\n blocking?: boolean;\n /** Optional human-readable thread name (for example from `name:` tag) */\n threadName?: string;\n /**\n * Initial argument values supplied when the child was created.\n *\n * For resumable subagents, these values persist for the lifetime of the\n * child thread and are visible to both child sides. Runtimes SHOULD source\n * this object from the receiving side's prompt argument schema. The registry\n * copy is parent-visible metadata; the durable child-side source SHOULD live\n * with the child thread metadata/properties and be restored into\n * `ThreadState.arguments` during execution and endpoint access. Top-level\n * keys SHOULD also be exposed to prompt variable interpolation for whichever\n * child side is currently rendering.\n */\n initialArguments?: Record<string, unknown>;\n /** Spawn group identifier used for grouping instances created together */\n spawnGroupId?: string;\n /** Instance creation timestamp (microseconds) */\n createdAt?: number;\n /** Current status (`running`, `idle`, `terminated`, or custom text) */\n status: string;\n /** How this child reports information back to its parent thread */\n parentCommunication?: 'implicit' | 'explicit';\n}\n\n// ============================================================================\n// Message Types\n// ============================================================================\n\n/**\n * Options for retrieving messages.\n */\nexport interface GetMessagesOptions {\n /** Maximum number of messages to return */\n limit?: number;\n /** Number of messages to skip */\n offset?: number;\n /** Sort order ('asc' for oldest first, 'desc' for newest first) */\n order?: 'asc' | 'desc';\n /** Include silent messages (not shown in UI) */\n includeSilent?: boolean;\n /** Maximum nesting depth for sub-prompt messages */\n maxDepth?: number;\n}\n\n/**\n * Result of a message query.\n */\nexport interface MessagesResult {\n /** Array of messages */\n messages: Message[];\n /** Total number of messages matching the query */\n total: number;\n /** Whether there are more messages available */\n hasMore: boolean;\n}\n\n/**\n * A message in the thread conversation.\n */\nexport interface Message {\n /** Unique message identifier */\n id: string;\n /** Message role */\n role: 'system' | 'user' | 'assistant' | 'tool';\n /** Message content (null for tool calls without text) */\n content: string | null;\n /** Tool name (for tool result messages) */\n name?: string | null;\n /** JSON-encoded array of tool calls (for assistant messages) */\n tool_calls?: string | null;\n /** Tool call ID (for tool result messages) */\n tool_call_id?: string | null;\n /** Creation timestamp (microseconds since epoch) */\n created_at: number;\n /** Parent message ID (for sub-prompt messages) */\n parent_id?: string | null;\n /** Nesting depth (0 for top-level messages) */\n depth?: number;\n /** Whether this message is silent (not shown in UI) */\n silent?: boolean;\n /**\n * Custom metadata.\n *\n * Runtimes may attach lifecycle metadata for synthesized status messages\n * (for example: `status_kind`, `subagent_event`). Message APIs may also\n * mark send-message and durable queue entries with `queued: true` until\n * they are injected into stored history.\n */\n metadata?: Record<string, unknown>;\n /** Message processing status */\n status?: 'pending' | 'completed' | 'failed' | null;\n /** Tool execution status (for tool result messages) */\n tool_status?: 'success' | 'error' | null;\n /** Subagent reference UUID associated with this message */\n subagent_id?: string | null;\n /** Subagent agent name projected from runtime registry (when available) */\n subagent_name?: string | null;\n /** Subagent agent title projected from runtime registry (when available) */\n subagent_title?: string | null;\n /** Subagent description projected from runtime registry (when available) */\n subagent_description?: string | null;\n /** Subagent status projected from runtime registry (when available) */\n subagent_status?: string | null;\n /** Whether the associated subagent is resumable (when available) */\n subagent_resumable?: boolean | null;\n /** Whether the associated subagent is blocking (when available) */\n subagent_blocking?: boolean | null;\n /** Optional subagent instance thread name (when available) */\n subagent_thread_name?: string | null;\n /** Spawn group identifier for related subagent instances (when available) */\n subagent_spawn_group_id?: string | null;\n}\n\n/**\n * Input for injecting a new message.\n */\nexport interface InjectMessageInput {\n /** Message role */\n role: 'user' | 'assistant' | 'system';\n /** Message content */\n content: string;\n /** Whether to hide from UI */\n silent?: boolean;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Input for queueing a message for delivery on the thread's next step.\n *\n * Role mapping follows dual_ai conventions:\n * - `assistant` maps to side_a\n * - `user` maps to side_b\n */\nexport interface QueueMessageInput {\n /** Message role (`user` queues side_b perspective, `assistant` queues side_a perspective) */\n role: 'user' | 'assistant';\n /** Message content */\n content: string;\n /** Optional file attachments (new files or existing refs) */\n attachments?: Array<ToolAttachment | AttachmentRef>;\n /** Whether to hide the queued message from normal UI display */\n silent?: boolean;\n /** Optional structured metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Updates to apply to an existing message.\n */\nexport interface MessageUpdates {\n /** New content */\n content?: string;\n /** Updated metadata (merged with existing) */\n metadata?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Thread Message-Stream Events (client-facing WebSocket)\n// ============================================================================\n//\n// The thread message stream — `GET /api/threads/:id/stream` (WebSocket) —\n// broadcasts JSON events as a turn executes. Each socket may set a `depth`\n// preference; events deeper than it (subagents) are filtered out. Documented\n// here so every client (first-party SDKs, the CLI, third parties) shares one\n// contract for the streaming channels below.\n\n/**\n * A streamed fragment of an assistant message's *visible content*.\n *\n * Always broadcast (no opt-in). Clients accumulate `chunk`s by `message_id` to\n * render the answer as it generates; the authoritative final content still\n * arrives separately as a persisted message.\n */\nexport interface ThreadMessageChunkEvent {\n type: 'message_chunk';\n /** The assistant message these fragments belong to. */\n message_id: string;\n /** Message depth: 0 = top-level thread, 1+ = subagent. */\n depth: number;\n /** The next fragment of visible content. */\n chunk: string;\n}\n\n/**\n * A streamed fragment of a model's *internal reasoning* (chain-of-thought).\n *\n * OPT-IN. Unlike content, reasoning is private by default: it is only sent to\n * sockets that explicitly subscribe by connecting with the\n * {@link THREAD_STREAM_REASONING_PARAM} query parameter set to a truthy value\n * (e.g. `?reasoning=1`). Standard SDK consumers therefore never receive it\n * unless they opt in.\n *\n * Reasoning is ephemeral *display* output: it is streamed for live presentation\n * only and is NOT persisted as part of the assistant message content, so it\n * cannot be replayed from message history — a client that wants it must be\n * subscribed while the turn runs.\n */\nexport interface ThreadReasoningChunkEvent {\n type: 'reasoning_chunk';\n /** The assistant message this reasoning accompanies. */\n message_id: string;\n /** Message depth: 0 = top-level thread, 1+ = subagent. */\n depth: number;\n /** The next fragment of internal reasoning. */\n chunk: string;\n}\n\n/**\n * Query-parameter name a client sets (truthy) on the thread stream WebSocket to\n * opt into receiving {@link ThreadReasoningChunkEvent}s. Absent/falsey means the\n * server never emits reasoning to that socket.\n */\nexport const THREAD_STREAM_REASONING_PARAM = 'reasoning';\n\n// ============================================================================\n// File System Types\n// ============================================================================\n\n/**\n * Storage location identifier.\n *\n * Implementations define their own storage identifiers (e.g., 'local', 'cloud', 's3').\n * The spec does not mandate specific storage backends.\n */\nexport type FileStorage = string;\n\n/**\n * Record representing a file in the thread's file system.\n */\nexport interface FileRecord {\n /** File path (relative to thread root) */\n path: string;\n /** File name */\n name: string;\n /** MIME type */\n mimeType: string;\n /** Storage location */\n storage: FileStorage;\n /** File size in bytes */\n size: number;\n /** Whether this is a directory */\n isDirectory: boolean;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n /** Image width in pixels (if applicable) */\n width?: number;\n /** Image height in pixels (if applicable) */\n height?: number;\n /** Creation timestamp */\n createdAt?: number;\n /** Last modified timestamp */\n updatedAt?: number;\n}\n\n/**\n * Options for writing a file.\n */\nexport interface WriteFileOptions {\n /** Custom metadata to attach to the file */\n metadata?: Record<string, unknown>;\n /** Image width in pixels (if applicable) */\n width?: number;\n /** Image height in pixels (if applicable) */\n height?: number;\n}\n\n/**\n * Result of reading a directory.\n */\nexport interface ReaddirResult {\n /** Files and directories in the path */\n entries: FileRecord[];\n}\n\n/**\n * Statistics about the thread's file system.\n */\nexport interface FileStats {\n /** Total number of files */\n fileCount: number;\n /** Total number of directories */\n directoryCount: number;\n /** Total size in bytes */\n totalSize: number;\n}\n\n/**\n * Result of a grep search.\n */\nexport interface GrepResult {\n /** File path */\n path: string;\n /** Matching lines */\n matches: Array<{\n line: number;\n content: string;\n }>;\n}\n\n/**\n * Result of a find operation.\n */\nexport interface FindResult {\n /** Matching file paths */\n paths: string[];\n}\n\n/**\n * Options for streaming file reads.\n */\nexport interface ReadFileStreamOptions {\n /**\n * Abort signal for cancellation.\n *\n * When signaled, the stream stops yielding new chunks.\n * Already-yielded chunks remain valid.\n */\n signal?: AbortSignal;\n}\n\n/**\n * A chunk of file data from a streaming read.\n */\nexport interface FileChunk {\n /** Raw binary data for this chunk */\n data: Uint8Array;\n /** 0-based index of this chunk */\n index: number;\n /** Total number of chunks (1 for small files) */\n totalChunks: number;\n /** Whether this is the final chunk */\n isLast: boolean;\n}\n\n// ============================================================================\n// Code Execution\n// ============================================================================\n\n/**\n * Options passed to {@link ThreadState.runCode}.\n *\n * Code execution is strictly capability-based: the sandbox starts with no\n * ambient capabilities (no `fs`, no `fetch`, no `console`, no host globals).\n * Every capability the sandbox needs must be bridged in explicitly through\n * `imports` or `globals`.\n *\n * Deadlines are **not** an option. Callers impose their own by calling\n * `handle.terminate()` on the returned {@link CodeExecution}.\n *\n * See the [Code Execution specification](https://standardagentspec.com/0.1.0/specification/threads/code-execution)\n * for the full contract.\n */\nexport interface CodeExecutionOptions {\n /**\n * Export to execute from the evaluated module and arguments to pass.\n *\n * By default, runtimes execute the module's `default` export with no\n * arguments. If the selected export is a function, it is called with\n * `args` and the returned value or promise is used as the run result. If the\n * selected export is not a function, `args` MUST be omitted or empty and the\n * export value itself becomes the result.\n *\n * @default { fn: 'default', args: [] }\n *\n * @example\n * ```ts\n * execute: { fn: 'increment', args: [100] }\n * ```\n */\n execute?: {\n /** Export name to execute. Use `'default'` for the default export. */\n fn?: string;\n /** Arguments passed to the selected export when it is a function. */\n args?: unknown[];\n };\n\n /**\n * Map of bare module specifier → named exports exposed to the sandbox.\n *\n * Only bare specifiers resolve from `imports` (e.g., `'fs'`,\n * `'@scope/pkg'`). Relative specifiers resolve only from `modules`; URL\n * (`'https://…'`) imports MUST fail at link time.\n *\n * The key `default` within a namespace becomes that module's default export.\n *\n * @example\n * ```ts\n * imports: {\n * fs: { readFile: (path) => state.readFile(path) },\n * supervisor: { report: (payload) => telemetry.push(payload) },\n * }\n * ```\n */\n imports?: Record<string, Record<string, unknown>>;\n\n /**\n * Additional relative ES modules available to the sandbox.\n *\n * Keys are relative module specifiers from the module graph root, such as\n * `'./helpers.js'` or `'./lib/math.js'`. Entry source imports resolve from\n * `filename` when one is supplied. Entry and module source may import sibling\n * or parent modules with `./` and `../` specifiers when those imports resolve\n * within the supplied module graph. Values are JavaScript or TypeScript module\n * source. Use this when a caller wants the entry source to import local files\n * while still keeping all modules inside the sandbox.\n */\n modules?: Record<string, string>;\n\n /**\n * Map of identifier → value installed on the sandbox's module scope.\n *\n * These identifiers are resolvable as free variables inside the sandbox\n * but MUST NOT appear on `globalThis`.\n *\n * @example\n * ```ts\n * globals: {\n * console: { log: (...args) => logger.info(...args) },\n * getMessage: async () => '...',\n * }\n * ```\n */\n globals?: Record<string, unknown>;\n\n /**\n * Source language. TypeScript source has its types erased before evaluation;\n * no type checking is performed.\n *\n * @default 'typescript'\n */\n language?: 'javascript' | 'typescript';\n\n /**\n * Maximum sandbox heap in bytes. Exceeding this settles the handle with\n * `status: 'memory'`. Runtime default is implementation-defined and\n * documented per runtime.\n */\n memoryLimitBytes?: number;\n\n /**\n * Label used in stack traces and error `specifier` fields.\n *\n * @default '<runCode>'\n */\n filename?: string;\n\n /**\n * Optional host-side sink for the built-in `report` bridge.\n *\n * When provided, the runtime installs a `report` global that forwards values\n * to this callback. Reported values are also appended to the live\n * {@link CodeExecution.reports} view and to the final\n * {@link CodeExecutionResult.reports}.\n */\n report?: (value: unknown) => void;\n}\n\n/**\n * Handle returned by {@link ThreadState.runCode}.\n *\n * `CodeExecution` is a `PromiseLike<CodeExecutionResult>` — `await` the handle\n * to get the final result. The handle also exposes controls that only make\n * sense while the run is in flight: caller-initiated termination and a live\n * view of values emitted via the `report` bridge.\n */\nexport interface CodeExecution extends PromiseLike<CodeExecutionResult> {\n /**\n * Stop the run. Idempotent: subsequent calls are no-ops.\n *\n * Settles the handle with `status: 'terminated'` at the next ECMAScript\n * yield point (microtask boundary, async operation, or runtime interrupt).\n * Typically a few milliseconds and SHOULD be ≤ 50 ms under normal host load;\n * a pure-synchronous tight loop may run until the runtime's own safety cap\n * fires. When `reason` is provided, it surfaces in `error.message`.\n */\n terminate(reason?: string): void;\n\n /** `true` until the handle settles. */\n readonly running: boolean;\n\n /**\n * Snapshot of values emitted via the `report` bridge so far, in call order.\n * The same values appear in {@link CodeExecutionResult.reports} once the\n * run ends.\n */\n readonly reports: readonly unknown[];\n}\n\n/**\n * Outcome classification for {@link CodeExecutionResult.status}.\n *\n * - `success` — Module evaluated and the configured export resolved.\n * - `error` — Uncaught runtime error inside the sandbox.\n * - `memory` — `memoryLimitBytes` exceeded.\n * - `terminated` — Caller called `handle.terminate()`, or the runtime's own\n * safety cap fired. `error.message` distinguishes the two (including any\n * `reason` the caller passed).\n * - `link_error` — Module graph failed to link (unknown specifier, missing\n * named export, parse error).\n */\nexport type CodeExecutionStatus =\n | 'success'\n | 'error'\n | 'memory'\n | 'terminated'\n | 'link_error';\n\n/**\n * A single captured `console.*` call from inside the sandbox.\n *\n * Only populated when the runtime installs a capturing `console` (typically\n * when the caller does not provide one via `options.globals`).\n */\nexport interface CodeExecutionLog {\n level: 'log' | 'info' | 'warn' | 'error' | 'debug';\n /** Marshaled argument values, deep-cloned from the sandbox. */\n args: unknown[];\n /** Millisecond timestamp when the call occurred. */\n timestamp: number;\n}\n\n/**\n * Error surfaced when a {@link CodeExecutionResult} does not have\n * `status: 'success'`.\n *\n * Host-side stack frames MUST NOT leak into this object — only sandbox\n * frames are included.\n */\nexport interface CodeExecutionError {\n name: string;\n message: string;\n stack?: string;\n /** Module specifier that failed to link (for `link_error`). */\n specifier?: string;\n /** Source filename associated with `line` and `column`, when available. */\n filename?: string;\n /** 1-based line number in source, when available. */\n line?: number;\n /** 1-based column number in source, when available. */\n column?: number;\n}\n\n/**\n * Result of a {@link ThreadState.runCode} call.\n *\n * The sandbox has two result channels and both may be used in the same run:\n * - **Configured export** → marshaled into `result` on success.\n * - **Bridge reports** → appended to `reports` in call order as they are emitted.\n */\nexport interface CodeExecutionResult {\n /** Outcome classification — see {@link CodeExecutionStatus}. */\n status: CodeExecutionStatus;\n\n /**\n * Resolved configured export (after awaiting top-level promises).\n * Omitted when `status !== 'success'`. `undefined` is a valid success result\n * when the configured export resolves to `undefined`.\n */\n result?: unknown;\n\n /**\n * Values emitted through the built-in `report` bridge when\n * `options.report` is supplied, in call order. Empty when unused.\n */\n reports: unknown[];\n\n /** Captured `console.*` calls (see {@link CodeExecutionLog}). Empty when the caller supplies its own `console`. */\n logs: CodeExecutionLog[];\n\n /** Error detail. Present iff `status` is not `'success'`. */\n error?: CodeExecutionError;\n\n /** Wall-clock execution time in milliseconds. */\n durationMs: number;\n\n /** Peak sandbox heap in bytes, when the engine can measure it. */\n memoryUsedBytes?: number;\n}\n\n// ============================================================================\n// Execution State\n// ============================================================================\n\n/**\n * Execution-specific state available during agent execution.\n *\n * This is present when a thread is actively executing (during tool calls,\n * hook invocations, etc.) and null when accessing a thread at rest\n * (from endpoints, external code, etc.).\n */\nexport interface ExecutionState {\n /** Current flow ID (unique per execution) */\n readonly flowId: string;\n\n /** Current side in dual_ai agents ('a' or 'b') */\n readonly currentSide: 'a' | 'b';\n\n /** Total steps executed in this flow */\n readonly stepCount: number;\n\n /** Steps executed by side A */\n readonly sideAStepCount: number;\n\n /** Steps executed by side B */\n readonly sideBStepCount: number;\n\n /** Whether execution has been stopped */\n readonly stopped: boolean;\n\n /** Which side initiated the stop (if stopped) */\n readonly stoppedBy?: 'a' | 'b';\n\n /** Message history loaded for current execution */\n readonly messageHistory: Message[];\n\n /**\n * Force a specific side to play the next turn.\n *\n * Only valid for dual_ai agents. Has no effect on ai_human agents.\n *\n * @param side - The side to force ('a' or 'b')\n */\n forceTurn(side: 'a' | 'b'): void;\n\n /**\n * Stop the current execution.\n *\n * Signals the execution loop to terminate after the current operation\n * completes. Does not abort in-progress LLM calls.\n */\n stop(): void;\n\n /**\n * Abort signal for cancellation.\n *\n * Can be used to abort fetch requests or other async operations\n * when the execution is cancelled.\n */\n readonly abortSignal: AbortSignal;\n\n /**\n * Path from root prompt to current prompt.\n *\n * Tracks the current position in the prompt hierarchy:\n * - At root level: `['my_prompt']`\n * - Inside a sub-prompt: `['my_prompt', 'sub_prompt']`\n * - After handoff: `['new_agent_prompt']`\n *\n * This allows tools and hooks to understand their execution context depth.\n */\n readonly promptPath: string[];\n}\n\n/**\n * Display/redaction classification for thread-scoped environment values.\n *\n * `secret` values should be redacted from tool output and logs. `text` values\n * may be displayed.\n */\nexport type EnvValueType = 'text' | 'secret';\n\n/**\n * Options for {@link ThreadState.setEnv}.\n */\nexport interface SetEnvOptions {\n /**\n * Display/redaction classification for this value.\n *\n * Defaults to the existing type for that key, or `secret` for new keys.\n */\n type?: EnvValueType;\n}\n\n/**\n * Options for {@link ThreadState.stopSession}.\n */\nexport interface StopSessionOptions {\n /**\n * Result text returned to a blocking parent/subagent caller.\n *\n * This does not send a parent message by itself. Use `notifyParent` when the\n * session stop should also queue an explicit parent notification.\n */\n result?: string;\n\n /**\n * Optional silent message to queue to this thread's parent before stopping.\n *\n * Omit this for no parent-message side effect.\n */\n notifyParent?: string;\n\n /**\n * Optional parent registry status to set before stopping. Runtimes may ignore\n * this when the thread has no parent registry entry.\n *\n * Omit this for no status side effect.\n */\n status?: string;\n}\n\n// ============================================================================\n// ThreadState Interface\n// ============================================================================\n\n/**\n * The unified interface for all thread operations.\n *\n * ThreadState provides a consistent API for interacting with threads\n * regardless of context - whether from tools during execution, hooks,\n * or HTTP endpoints. The same interface is used throughout, with\n * execution-specific state available when applicable.\n *\n * @example\n * ```typescript\n * // In a tool\n * export default defineTool(\n * 'Send a greeting',\n * z.object({ name: z.string() }),\n * async (state, args) => {\n * // Access thread identity\n * console.log(`Thread: ${state.threadId}`);\n *\n * // Check execution state\n * if (state.execution?.stepCount > 10) {\n * state.execution.stop();\n * }\n *\n * // Emit custom event\n * state.emit('greeting', { name: args.name });\n *\n * return { status: 'success', result: `Hello, ${args.name}!` };\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * // In an endpoint\n * export default defineThreadEndpoint(async (req, state, params) => {\n * // state.execution is null (not executing)\n * const { messages } = await state.getMessages({ limit: 50 });\n * return Response.json({ messages, params });\n * });\n * ```\n */\n/**\n * A request forwarded from a server-side tool to a connected client (CLI) for\n * local execution. Used by \"forwarded\" tools where the agent loop runs remotely\n * but the actual operation (read a file, run a command) must happen on the\n * user's own machine.\n */\nexport interface ClientToolRequest {\n /** Logical operation name the client knows how to perform (e.g. `read_file`). */\n tool: string;\n /** Arguments for the operation. */\n args?: Record<string, unknown>;\n /**\n * Human-readable description of what this call will do, shown to the user when\n * the client needs to ask for permission. Presence signals the operation may\n * carry side effects.\n */\n requestPermission?: string;\n /** Risk level 1 (safe) – 5 (dangerous). Clients slide auto-accept on this. */\n risk?: number;\n /** Milliseconds to wait for the client before failing the call. */\n timeoutMs?: number;\n}\n\n/**\n * The result a connected client returns for a {@link ClientToolRequest}.\n */\nexport interface ClientToolResponse {\n /** Whether the client successfully performed the operation. */\n ok: boolean;\n /** Text result (e.g. file contents, command output). */\n result?: string;\n /** Error message when `ok` is false (including a user denial). */\n error?: string;\n /** Optional structured payload the tool can inspect. */\n data?: unknown;\n}\n\nexport interface ThreadState {\n // ─────────────────────────────────────────────────────────────────────────\n // Identity (readonly)\n // ─────────────────────────────────────────────────────────────────────────\n\n /** Unique thread identifier */\n readonly threadId: string;\n\n /** Agent that owns this thread */\n readonly agentId: string;\n\n /** User associated with this thread (if any) */\n readonly userId: string | null;\n\n /** Thread creation timestamp (microseconds since epoch) */\n readonly createdAt: number;\n\n /**\n * Registry of subagent child instances owned by this thread.\n *\n * Includes both resumable and non-resumable instances.\n */\n readonly children: SubagentRegistryEntry[];\n\n /**\n * Termination timestamp (microseconds) if this thread has been terminated.\n * Null when the thread is active.\n */\n readonly terminated: number | null;\n\n /**\n * Arguments supplied when this thread was created or invoked.\n *\n * For resumable subagent child threads, this is the durable\n * `subagent_create.arguments` object restored from child thread\n * metadata/properties. Both child sides see the same object. Runtimes also\n * expose these keys to prompt variable interpolation, including included\n * prompts.\n */\n readonly arguments: Record<string, unknown>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Messages\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Get messages from the thread.\n *\n * @param options - Query options (limit, offset, order, etc.)\n * @returns Messages and pagination info\n */\n getMessages(options?: GetMessagesOptions): Promise<MessagesResult>;\n\n /**\n * Get a single message by ID.\n *\n * @param messageId - The message ID\n * @returns The message, or null if not found\n */\n getMessage(messageId: string): Promise<Message | null>;\n\n /**\n * Inject a message into the thread.\n *\n * Creates a new message in the conversation history. This can be used\n * to add context, simulate user input, or insert assistant responses.\n *\n * @param message - The message to inject\n * @returns The created message\n */\n injectMessage(message: InjectMessageInput): Promise<Message>;\n\n /**\n * Update an existing message.\n *\n * @param messageId - The message ID\n * @param updates - The updates to apply\n * @returns The updated message\n */\n updateMessage(messageId: string, updates: MessageUpdates): Promise<Message>;\n\n /**\n * Delete a message from the thread.\n *\n * Removes the message and any associated attachments from storage.\n * Tool call results are cascade-deleted when their parent message is removed.\n *\n * @param messageId - The message ID to delete\n * @returns true if the message was found and deleted, false if not found\n */\n deleteMessage(messageId: string): Promise<boolean>;\n\n /**\n * Queue a message for delivery on the thread's next step.\n *\n * If the thread is executing, the message is delivered before the next LLM call.\n * If idle, queueing forces execution by the queued side.\n */\n queueMessage(message: QueueMessageInput): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Resource Loading\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Load a model definition by name.\n *\n * @param name - The model name\n * @returns The model definition\n * @throws If the model is not found\n */\n loadModel<T = unknown>(name: string): Promise<T>;\n\n /**\n * Load a prompt definition by name.\n *\n * @param name - The prompt name\n * @returns The prompt definition\n * @throws If the prompt is not found\n */\n loadPrompt<T = unknown>(name: string): Promise<T>;\n\n /**\n * Load an agent definition by name.\n *\n * @param name - The agent name\n * @returns The agent definition\n * @throws If the agent is not found\n */\n loadAgent<T = unknown>(name: string): Promise<T>;\n\n /**\n * Get available prompt names.\n *\n * @returns Array of prompt names that can be loaded\n */\n getPromptNames(): string[];\n\n /**\n * Get available agent names.\n *\n * @returns Array of agent names that can be loaded\n */\n getAgentNames(): string[];\n\n /**\n * Get available model names.\n *\n * @returns Array of model names that can be loaded\n */\n getModelNames(): string[];\n\n /**\n * Get a child thread by its subagent reference ID.\n *\n * @param referenceId - Child thread UUID\n * @returns Child ThreadState or null if not found\n */\n getChildThread(referenceId: string): Promise<ThreadState | null>;\n\n /**\n * Get this thread's parent thread (if any).\n *\n * @returns Parent ThreadState, or null for top-level threads\n */\n getParentThread(): Promise<ThreadState | null>;\n\n /**\n * Resolve an environment value for this thread by property name.\n *\n * Resolution order:\n * 1. Thread\n * 2. Agent definition\n * 3. Prompt definition\n * 4. User account\n * 5. AgentBuilder instance\n *\n * @throws If the variable is not defined in any source\n */\n env(propertyName: string): Promise<string>;\n\n /**\n * Resolve the display/redaction type for an environment value.\n *\n * Resolution follows the same order as `env()`:\n * thread, agent definition, prompt definition, user account, AgentBuilder instance.\n * User-account and AgentBuilder-instance env stores may persist per-key\n * `text` / `secret` metadata; agent/prompt defaults remain `secret` unless\n * overridden by thread state.\n *\n * Values marked `secret` should be redacted from tool output and logs.\n * Values marked `text` may be shown. Unknown values default to `secret`.\n */\n envType(propertyName: string): Promise<EnvValueType>;\n\n /**\n * Set a thread-scoped environment variable.\n *\n * This writes to thread env storage and propagates the updated thread env\n * to all active descendant threads recursively. Terminated descendants are\n * not modified.\n *\n * @param propertyName - Environment variable name\n * @param value - Environment variable value\n * @param options - Optional display/redaction classification for this value\n */\n setEnv(propertyName: string, value: string, options?: SetEnvOptions): Promise<void>;\n\n /**\n * Queue a silent message to this thread's parent, if one exists.\n *\n * This is useful for explicit child-to-parent escalation paths where tools or\n * hooks decide when the parent should be notified.\n *\n * Implementations SHOULD tag the queued message with the current thread's\n * `subagent_id` metadata so the parent can attribute the notification.\n *\n * @throws If content is empty\n */\n notifyParent(content: string): Promise<void>;\n\n /**\n * Update this thread's status in its parent registry entry.\n *\n * Useful for long-lived watcher/observer children that want to expose their\n * current state without sending a parent message.\n *\n * This is a no-op when the thread has no parent registry entry.\n *\n * @throws If status is empty\n */\n setStatus(status: string): Promise<void>;\n\n /**\n * Force the current agent session to stop successfully.\n *\n * This is stronger than `state.execution.stop()`: it marks the active session\n * as terminal for subagent/session-boundary purposes, without requiring a\n * `sessionStop` tool call. By default it has no parent-message or status side\n * effects. Pass `notifyParent` and/or `status` when those effects are desired.\n *\n * @throws If called outside an active execution context\n */\n stopSession(options?: StopSessionOptions): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tool Invocation\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Queue a tool for execution.\n *\n * If the thread is currently executing, the tool is added to the\n * execution queue. If not, this starts a new execution with the\n * tool call.\n *\n * @param toolName - Name of the tool to invoke\n * @param args - Arguments to pass to the tool\n */\n queueTool(toolName: string, args: Record<string, unknown>): void;\n\n /**\n * Invoke a tool directly and wait for the result.\n *\n * If the thread is not currently executing, this creates a minimal\n * execution context for the tool. Unlike queueTool, this blocks\n * until the tool completes.\n *\n * @param toolName - Name of the tool to invoke\n * @param args - Arguments to pass to the tool\n * @returns The tool result\n */\n invokeTool(toolName: string, args: Record<string, unknown>): Promise<ToolResult>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Effect Scheduling\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Schedule an effect for future execution.\n *\n * Effects are executed outside the current conversation flow, making them\n * ideal for delayed operations like sending notifications, triggering\n * webhooks, or running cleanup tasks.\n *\n * @param name - Name of the effect to schedule (must exist in agents/effects/)\n * @param args - Arguments to pass to the effect handler\n * @param delay - Delay in milliseconds before execution (default: 0 for immediate)\n * @returns Unique ID of the scheduled effect (UUID)\n *\n * @example\n * ```typescript\n * // Schedule a reminder email in 30 minutes\n * const effectId = await state.scheduleEffect(\n * 'send_reminder_email',\n * { to: 'user@example.com', subject: 'Reminder' },\n * 30 * 60 * 1000\n * );\n * ```\n */\n scheduleEffect(name: string, args: Record<string, unknown>, delay?: number): Promise<string>;\n\n /**\n * Get scheduled effects for this thread.\n *\n * Returns effects that are pending execution. Can optionally filter\n * by effect name.\n *\n * @param name - Optional effect name to filter by\n * @returns Array of scheduled effect records\n */\n getScheduledEffects(name?: string): Promise<ScheduledEffect[]>;\n\n /**\n * Cancel a scheduled effect.\n *\n * Cancels a pending effect before it executes. Has no effect if the effect\n * has already executed, was already canceled, or doesn't exist. Runtimes may\n * retain canceled effects in inspection history.\n *\n * @param id - The effect ID returned by scheduleEffect\n * @returns true if the effect was found and canceled, false otherwise\n */\n removeScheduledEffect(id: string): Promise<boolean>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Agent Execution\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Trigger an agent to run on this thread.\n *\n * Starts a new agent execution asynchronously. This is useful for effects\n * that need to trigger background agent work (e.g., running a finalizer\n * agent after a delay).\n *\n * The agent runs in the background - this method returns immediately\n * after queuing the execution.\n *\n * @param agentName - Name of the agent to run (must exist in agents/agents/)\n * @returns Promise that resolves when the execution is queued\n *\n * @example\n * ```typescript\n * // In an effect handler, trigger a finalizer agent\n * await state.runAgent('booking_finalizer');\n * ```\n */\n runAgent(agentName: string): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Thread Lifecycle\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Soft-terminate the thread.\n *\n * Implementations should mark the thread as terminated, abort in-flight\n * execution, and reject subsequent execution/message queue operations.\n */\n terminate(): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Events / Streaming\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Emit a custom event to connected clients.\n *\n * Events are sent via WebSocket to any connected clients. Use this\n * for real-time updates, progress notifications, or custom data.\n *\n * @param event - Event name\n * @param data - Event data (must be JSON-serializable)\n */\n emit(event: string, data: unknown): void;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Context Storage\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Execution-scoped key-value data available while the current agent run is\n * being assembled and executed.\n *\n * Runtimes use this bag for values shared between tools/hooks/effects during\n * one execution. Invocation or creation arguments belong in\n * {@link ThreadState.arguments}, not in `context`.\n *\n * User mutations persist across tool calls within a single execution, but are\n * not durable after execution ends unless the runtime rehydrates a value from\n * another durable source. For durable storage, use\n * {@link ThreadState.getValue} and {@link ThreadState.setValue}, the file\n * system, or external storage.\n */\n context: Record<string, unknown>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Durable Key-Value Store\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Read a value from the thread's durable key-value store.\n *\n * Values written with {@link ThreadState.setValue} persist across executions,\n * tool calls, hook invocations, and endpoint requests for the lifetime of\n * the thread. The key-value store is one of two ways to store persistent\n * data on a thread, alongside the file system.\n *\n * Returns `null` when no value has been set for the given key. Values are\n * returned exactly as they were stored; runtimes MUST preserve JSON-equivalent\n * structure (objects, arrays, strings, numbers, booleans, `null`).\n *\n * @param key - The key to read\n * @returns The stored value, or `null` if the key has no value\n *\n * @example\n * ```typescript\n * const count = (await state.getValue<number>('invocation_count')) ?? 0;\n * await state.setValue('invocation_count', count + 1);\n * ```\n */\n getValue<T = unknown>(key: string): Promise<T | null>;\n\n /**\n * Write a value to the thread's durable key-value store.\n *\n * The value persists across executions for the lifetime of the thread.\n * Passing `null` or `undefined` deletes the key. Values MUST be\n * JSON-serializable; implementations MAY reject non-serializable values.\n *\n * Durable values are **not** automatically copied between threads when\n * subagents are spawned — each thread maintains its own key-value store.\n *\n * @param key - The key to write\n * @param value - The value to store (JSON-serializable), or `null`/`undefined`\n * to delete the key\n */\n setValue(key: string, value: unknown): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // User Identity\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * The profile of the user this thread belongs to, or `null` when the thread\n * has no associated user (e.g. unauthenticated local development).\n *\n * Lets tools and hooks personalize or gate behavior per user — e.g. an\n * entitlement hook enforcing a per-user concurrency limit, or a tool\n * addressing the user by name. Never includes credentials.\n *\n * @example\n * ```typescript\n * const user = await state.user();\n * if (user?.email) await notifyBillingService(user.email);\n * ```\n */\n user(): Promise<ThreadUser | null>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Skills\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * The instance-global Agent Skills library (https://agentskills.io format).\n *\n * Skills are installed once and visible to every thread; their files live\n * server-side (never on a client machine). Agents should follow progressive\n * disclosure: browse metadata via `skills.list()`, and load a skill's\n * SKILL.md body with `skills.get()` only when it is applicable to the task.\n *\n * @example\n * ```typescript\n * const available = await state.skills.list();\n * const skill = await state.skills.get('pdf-processing');\n * const script = await state.skills.readFile('pdf-processing', 'scripts/extract.py');\n * ```\n */\n skills: SkillsNamespace;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Client-forwarded tools\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Forward a tool operation to the connected client (e.g. the coding CLI) and\n * await its result. The agent loop runs remotely, but operations like reading\n * a file or running a shell command must execute on the user's own machine;\n * `callClient` bridges that gap over the thread's `bridge` WebSocket.\n *\n * Resolves with `{ ok: false, error }` (rather than throwing) when no client\n * is connected, the request times out, or the user denies permission, so\n * forwarded tools can surface a normal tool error to the model.\n *\n * @param request - The operation, args, and optional permission/risk metadata\n * @returns The client's response\n */\n callClient(request: ClientToolRequest): Promise<ClientToolResponse>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // File System\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Write a file to the thread's file system.\n *\n * Large files (>1.75MB) are automatically chunked for storage.\n *\n * @param path - File path (relative to thread root)\n * @param data - File content as ArrayBuffer or string\n * @param mimeType - MIME type of the file\n * @param options - Optional metadata and dimensions\n * @returns The created file record\n */\n writeFile(\n path: string,\n data: ArrayBuffer | string,\n mimeType: string,\n options?: WriteFileOptions\n ): Promise<FileRecord>;\n\n /**\n * Read a file from the thread's file system.\n *\n * @param path - File path\n * @returns File content as ArrayBuffer, or null if not found\n */\n readFile(path: string): Promise<ArrayBuffer | null>;\n\n /**\n * Stream a file from the thread's file system in chunks.\n *\n * For large files (>1.75MB), this yields one chunk at a time, enabling\n * memory-efficient access without loading the entire file. Small files\n * are yielded as a single chunk.\n *\n * Returns null if the file is not found or stored externally (S3, R2, URL).\n *\n * @param path - File path\n * @param options - Optional streaming options (abort signal)\n * @returns Async iterable of file chunks, or null if not found/external\n *\n * @example\n * ```typescript\n * const stream = await state.readFileStream('/uploads/video.mp4');\n * if (stream) {\n * for await (const chunk of stream) {\n * console.log(`Chunk ${chunk.index + 1}/${chunk.totalChunks}`);\n * // Process chunk.data (Uint8Array)\n * }\n * }\n * ```\n */\n readFileStream(\n path: string,\n options?: ReadFileStreamOptions\n ): Promise<AsyncIterable<FileChunk> | null>;\n\n /**\n * Get metadata about a file.\n *\n * @param path - File path\n * @returns File record, or null if not found\n */\n statFile(path: string): Promise<FileRecord | null>;\n\n /**\n * List contents of a directory.\n *\n * @param path - Directory path\n * @returns Directory entries\n */\n readdirFile(path: string): Promise<ReaddirResult>;\n\n /**\n * Delete a file.\n *\n * @param path - File path\n */\n unlinkFile(path: string): Promise<void>;\n\n /**\n * Create a directory.\n *\n * @param path - Directory path\n * @returns The created directory record\n */\n mkdirFile(path: string): Promise<FileRecord>;\n\n /**\n * Remove a directory.\n *\n * @param path - Directory path (must be empty)\n */\n rmdirFile(path: string): Promise<void>;\n\n /**\n * Move or rename a file or directory.\n *\n * Relocates the entry at `sourcePath` to `destinationPath`. Works for\n * files and directories; moving a directory relocates its entire subtree,\n * preserving the relative layout of its contents. The destination must not\n * already exist, and a directory cannot be moved into itself or one of its\n * own descendants.\n *\n * @param sourcePath - Existing file or directory path\n * @param destinationPath - New path (must not already exist)\n * @returns The moved entry's record at its new path\n */\n moveFile(sourcePath: string, destinationPath: string): Promise<FileRecord>;\n\n /**\n * Rename a file or directory in place.\n *\n * Keeps the entry in its current parent directory and changes only its\n * final path segment. `newName` must be a bare file name with no path\n * separators. To relocate an entry to a different directory, use\n * {@link ThreadState.moveFile} instead.\n *\n * @param path - Existing file or directory path\n * @param newName - New name (no path separators)\n * @returns The renamed entry's record at its new path\n */\n renameFile(path: string, newName: string): Promise<FileRecord>;\n\n /**\n * Get overall file system statistics.\n *\n * @returns File count, directory count, and total size\n */\n getFileStats(): Promise<FileStats>;\n\n /**\n * Search file contents for a pattern.\n *\n * @param pattern - Search pattern (regular expression)\n * @returns Matching files and lines\n */\n grepFiles(pattern: string): Promise<GrepResult[]>;\n\n /**\n * Find files matching a glob pattern.\n *\n * @param pattern - Glob pattern (e.g., \"*.txt\", \"**\\/*.json\")\n * @returns Matching file paths\n */\n findFiles(pattern: string): Promise<FindResult>;\n\n /**\n * Get a thumbnail for an image file.\n *\n * @param path - Path to the image file\n * @returns Thumbnail data as ArrayBuffer, or null if not available\n */\n getFileThumbnail(path: string): Promise<ArrayBuffer | null>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Execution State\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Execution-specific state.\n *\n * This is present when the thread is actively executing (tools, hooks)\n * and null when accessing a thread at rest (endpoints, external code).\n *\n * Use this to access step counts, force turns, or stop execution.\n */\n execution: ExecutionState | null;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Code Execution\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Execute JavaScript or TypeScript source in an isolated sandbox.\n *\n * The sandbox has **no ambient capabilities**: no filesystem, no network,\n * no timers, no host globals, no access to `state` itself. Every capability\n * the sandbox needs must be bridged in explicitly via `options.imports`,\n * `options.modules`, or `options.globals`.\n *\n * Returns a {@link CodeExecution} handle that is a\n * `PromiseLike<CodeExecutionResult>` — `await` it for the final result — and\n * also exposes `terminate()` for caller-initiated cancellation. The spec\n * does not impose a wall-clock timeout; callers layer their own deadline\n * using a timer plus `handle.terminate()`.\n *\n * Results flow back through either:\n * - the module export selected by `options.execute` (marshaled into\n * `result.result`; defaults to the `default` export with no arguments; if\n * the selected export is a function, it is called with `execute.args` and\n * any returned promise is awaited before marshaling), or\n * - the built-in `report` bridge (accumulated into `result.reports` and\n * visible live on `handle.reports`), or\n * - caller-installed bridge callbacks that the caller owns.\n *\n * See the [Code Execution specification](https://standardagentspec.com/0.1.0/specification/threads/code-execution)\n * for isolation guarantees, module resolution rules, value marshaling, and\n * conformance requirements.\n *\n * @param source - JavaScript or TypeScript source, evaluated as an ES module.\n * @param options - Export selection, imports, globals, memory cap, and language hints.\n * @returns A handle that settles with the execution result and can be\n * terminated at any time before settlement.\n *\n * @example\n * ```typescript\n * const run = state.runCode(\n * `\n * import { readFile } from 'fs';\n * import { report } from 'supervisor';\n *\n * const message = await getMessage();\n * if (/username/.test(message)) {\n * report({ topic: 'username', message });\n * }\n * export default async () => ({ scanned: true });\n * `,\n * {\n * imports: {\n * fs: { readFile: (p) => state.readFile(p) },\n * supervisor: { report: (payload) => flagged.push(payload) },\n * },\n * globals: {\n * console: { log: (...a) => {} },\n * getMessage: async () => 'latest user message',\n * },\n * },\n * );\n *\n * const deadline = setTimeout(() => run.terminate('5s budget'), 5_000);\n * const result = await run;\n * clearTimeout(deadline);\n *\n * if (result.status === 'success') {\n * // result.result === { scanned: true }\n * }\n * ```\n */\n runCode(\n source: string,\n options?: CodeExecutionOptions,\n ): CodeExecution;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Runtime Context (Non-Portable)\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Runtime-specific context that cannot be packed or shared.\n *\n * This property lets runtime implementations inject non-portable context —\n * typically host bindings, database connections, or other\n * platform-specific handles the runtime chooses to expose.\n *\n * WARNING: Tools using this property cannot be packed, shared, or\n * published as they depend on runtime-specific context.\n */\n readonly _notPackableRuntimeContext?: Record<string, unknown>;\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// Thread Endpoint Marker\n// ============================================================================\n\n/**\n * Symbol used to identify thread endpoint handlers.\n *\n * When a handler is created with defineThreadEndpoint, it's marked with this\n * symbol so the runtime can detect it and wrap it with proper ThreadState injection.\n */\nexport const THREAD_ENDPOINT_SYMBOL = Symbol.for('standardagents.threadEndpoint');\n\n/**\n * A controller that has been marked as a thread endpoint.\n *\n * The runtime detects this marker and wraps the handler with ThreadState injection.\n * The `__handler` property contains the original handler function that expects\n * `(req: Request, state: ThreadState)` arguments.\n */\nexport interface MarkedThreadEndpoint extends Controller {\n /** Marker symbol indicating this is a thread endpoint */\n [THREAD_ENDPOINT_SYMBOL]: true;\n /** The original handler function before wrapping */\n __handler: ThreadEndpointHandler;\n}\n\n/**\n * Type guard to check if a controller is a marked thread endpoint.\n */\nexport function isThreadEndpoint(controller: Controller): controller is MarkedThreadEndpoint {\n return THREAD_ENDPOINT_SYMBOL in controller && (controller as any)[THREAD_ENDPOINT_SYMBOL] === true;\n}\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 * Its shape is defined by the runtime — typical surfaces include handles\n * to storage, queues, key-value stores, or other platform resources the\n * runtime chooses to expose.\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 — handles to storage,\n * queues, key-value stores, or other resources the runtime exposes.\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 supplied ThreadState includes the standard thread surface, including\n * `runCode`. The thread is automatically looked up by ID from URL parameters. Route\n * parameters are derived from the endpoint file path. For a dynamic segment\n * such as `[id].ts`, `params.id` contains the matched segment. For a catch-all\n * segment `[*].ts`, `params['*']` contains the unmatched path suffix,\n * including `/` separators when the match spans multiple segments.\n *\n * Thread endpoint routes are scoped beneath the runtime's thread ID prefix.\n * A request under that prefix that does not match any local or packed thread\n * endpoint route MUST return HTTP 404.\n */\nexport type ThreadEndpointRouteParams = Record<string, string>;\n\nexport type ThreadEndpointHandler = (\n req: Request,\n state: ThreadState,\n params: ThreadEndpointRouteParams\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 * Runtimes MUST return HTTP 404 for requests beneath the thread endpoint\n * prefix that do not match any local or packed thread endpoint route.\n *\n * @param handler - The handler function receiving request, ThreadState, and route params\n * @returns A Controller that can be used with the router\n *\n * @example\n * ```typescript\n * // agents/api/status.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/export.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/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 *\n * @example\n * ```typescript\n * // agents/api/files/[id].ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state, params) => {\n * const file = await state.readFile(`/files/${params.id}.json`);\n * return Response.json({ exists: !!file });\n * });\n * ```\n */\nexport function defineThreadEndpoint(\n handler: ThreadEndpointHandler\n): MarkedThreadEndpoint {\n // Mark the handler so the runtime can detect and wrap it with ThreadState injection.\n // The runtime's createThreadEndpointHandler will provide the actual ThreadState.\n const markedHandler = handler as unknown as MarkedThreadEndpoint;\n (markedHandler as any)[THREAD_ENDPOINT_SYMBOL] = true;\n (markedHandler as any).__handler = handler;\n return markedHandler;\n}\n","/**\n * Provider types for Standard Agents.\n *\n * These types define the interface between Standard Agents and LLM providers.\n * Provider packages implement these types to integrate with different LLM APIs.\n *\n * @module\n */\n\nimport type { ModelCapabilities } from './models';\nimport type { ToolDefinition, ToolArgs, ToolTenvs } from './tools';\n\n// =============================================================================\n// Response Summary (for async metadata fetching)\n// =============================================================================\n\n/**\n * Stripped-down response summary for async metadata fetching.\n * Intentionally excludes content/attachments to avoid passing large data.\n */\nexport interface ResponseSummary {\n /** Provider-specific response/generation ID */\n responseId?: string;\n /** Model that handled the request */\n model: string;\n /** How the response ended */\n finishReason: ProviderFinishReason;\n /** Token usage (without detailed breakdowns) */\n usage: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n}\n\n// =============================================================================\n// Provider Interface\n// =============================================================================\n\n/**\n * Model information returned by provider's getModels method.\n */\nexport interface ProviderModelInfo {\n /** The model identifier used in API calls (e.g., 'gpt-4o', 'anthropic/claude-3-opus') */\n id: string;\n /** Human-readable display name */\n name: string;\n /** Optional description of the model */\n description?: string;\n /** Optional context window size in tokens */\n contextLength?: number;\n /** Optional icon identifier for UI display */\n iconId?: string;\n /** Optional slug for additional lookups (e.g., OpenRouter endpoint queries) */\n slug?: string;\n /** Optional cost per 1M input tokens, in USD */\n inputPrice?: number;\n /** Optional cost per 1M output tokens, in USD */\n outputPrice?: number;\n /** Optional cost per 1M cached input tokens, in USD */\n cachedPrice?: number;\n /**\n * Optional capability hints surfaced from the provider's listing\n * payload. Populated when the provider can derive support flags\n * (vision / tool calls / streaming / JSON mode) without an\n * additional per-model probe — lets UIs render the capability\n * matrix on every row in the picker. Omit when the provider\n * doesn't expose enough metadata; consumers must tolerate\n * undefined.\n */\n capabilities?: ModelCapabilities;\n}\n\n/**\n * Query params for provider-backed model discovery.\n */\nexport interface ProviderModelsQuery {\n /** Optional search string */\n search?: string;\n /** 1-based page number */\n page?: number;\n /** Page size */\n perPage?: number;\n}\n\n/**\n * Paginated provider model listing response.\n */\nexport interface ProviderModelsPage {\n /** Models in the current page */\n models: ProviderModelInfo[];\n /** Whether the provider has another page available */\n hasNextPage: boolean;\n}\n\n/**\n * Provider interface - thin translation layer between Standard Agents and LLM APIs\n */\nexport interface LLMProviderInterface {\n readonly name: string;\n readonly specificationVersion: '1';\n\n /**\n * Non-streaming generation\n */\n generate(request: ProviderRequest): Promise<ProviderResponse>;\n\n /**\n * Streaming generation\n */\n stream(request: ProviderRequest): Promise<AsyncIterable<ProviderStreamChunk>>;\n\n /**\n * Check if this provider supports a model\n */\n supportsModel?(modelId: string): boolean;\n\n /**\n * List available models from this provider.\n * Optional for backwards compatibility - providers may implement this\n * to enable model selection in the UI.\n *\n * @param filter - Optional search string to filter models by name/id\n * @returns Array of available models\n */\n getModels?(filter?: string): Promise<ProviderModelInfo[]>;\n\n /**\n * List available models from this provider with remote search/pagination support.\n * Optional for backwards compatibility. When absent, callers should fall back\n * to getModels() and paginate client-side.\n *\n * @param query - Search/pagination parameters\n * @returns Current page of available models\n */\n getModelsPage?(query?: ProviderModelsQuery): Promise<ProviderModelsPage>;\n\n /**\n * Fetch capabilities for a specific model.\n * Optional for backwards compatibility - providers may implement this\n * to enable auto-detection of model features in the UI.\n *\n * @param modelId - The model identifier (e.g., 'gpt-4o', 'anthropic/claude-3-opus')\n * @returns The model capabilities, or null if not available\n */\n getModelCapabilities?(modelId: string): Promise<ModelCapabilities | null>;\n\n /**\n * Get tools embedded in this provider.\n * Optional - providers may implement this to expose built-in tools\n * (e.g., OpenAI's web_search or xAI's x_search).\n *\n * Tool names are provider-defined capability names. Standard Agents defines\n * discovery, selection, execution ownership, and result reporting; providers\n * define their own native request mapping.\n *\n * These tools are defined using defineTool() with optional variable requirements.\n * Tools returned here can be referenced by name in model/prompt definitions.\n *\n * @param modelId - Optional filter to get tools available for a specific model\n * @returns Record of tool name to tool definition (sync or async)\n */\n getTools?(modelId?: string): Record<string, ToolDefinition<any, ToolArgs | null, ToolTenvs | null>> | Promise<Record<string, ToolDefinition<any, ToolArgs | null, ToolTenvs | null>>>;\n\n /**\n * Get an icon for this provider or a specific model.\n * Optional - providers may implement this to provide UI icons.\n *\n * **Preferred return format: SVG data URI** (e.g., 'data:image/svg+xml,...')\n *\n * The data URI format allows icons to be embedded directly in the UI without\n * additional network requests. Use the `svgToDataUri()` helper from provider\n * packages to convert SVG strings.\n *\n * Return value can be:\n * - A data URI (e.g., 'data:image/svg+xml,...') - **PREFERRED**\n * - A full URL (e.g., 'https://example.com/icon.svg')\n * - An icon identifier that the UI resolves (legacy)\n *\n * For providers like OpenRouter that host many models, the modelId parameter\n * allows returning different icons based on the model's origin lab\n * (e.g., 'anthropic/claude-3-opus' -> anthropic icon).\n *\n * @param modelId - Optional model ID to get a model-specific icon\n * @returns SVG data URI (preferred), URL, icon identifier, or undefined\n *\n * @example\n * ```typescript\n * // Provider returning its own icon\n * getIcon() {\n * return svgToDataUri(OPENAI_ICON);\n * }\n *\n * // Provider returning model-specific icon (e.g., OpenRouter)\n * getIcon(modelId?: string) {\n * if (modelId) {\n * const lab = modelId.split('/')[0]; // 'anthropic' from 'anthropic/claude-3'\n * return getLabIconDataUri(lab);\n * }\n * return svgToDataUri(OPENROUTER_ICON);\n * }\n * ```\n */\n getIcon?(modelId?: string): string | undefined;\n\n /**\n * Transform a ProviderRequest to the provider's native format for inspection/debugging.\n * Returns the transformed request as it would be sent to the provider's API.\n *\n * This is used by the admin UI to view logged requests in provider-specific format,\n * helping debug issues like message transformation or tool handling.\n *\n * Implementations should truncate base64 data to ~50 chars for readability.\n *\n * @param request - The Standard Agents format request to transform\n * @returns The transformed request in the provider's native format\n */\n inspectRequest?(request: ProviderRequest): Promise<InspectedRequest>;\n\n /**\n * Fetch additional metadata about a completed response.\n * Called asynchronously after the response is received - does not block the main execution flow.\n *\n * This is useful for providers (like aggregators) where complete metadata isn't available\n * immediately. The execution engine calls this in the background and uses the returned\n * data to update log records.\n *\n * @param summary - Stripped-down response info (no content/attachments)\n * @param signal - Optional abort signal for cancellation\n * @returns Additional metadata or null if unavailable\n */\n getResponseMetadata?(\n summary: ResponseSummary,\n signal?: AbortSignal\n ): Promise<Record<string, unknown> | null>;\n}\n\n// =============================================================================\n// Inspection Types\n// =============================================================================\n\n/**\n * Result from inspectRequest() - the transformed request in provider's native format\n */\nexport interface InspectedRequest {\n /** The transformed request body as it would be sent to the API */\n body: Record<string, unknown>;\n /** Path to the messages array within body (e.g., \"input\" for OpenAI, \"messages\" for others) */\n messagesPath: string;\n /** Optional: Additional metadata about the transformation */\n metadata?: {\n /** The API endpoint that would be called */\n endpoint?: string;\n /** Headers that would be sent (excluding auth) */\n headers?: Record<string, string>;\n };\n}\n\n// =============================================================================\n// Request Types\n// =============================================================================\n\n/**\n * Standard Agent request format - providers translate to their native format\n */\nexport interface ProviderRequest {\n model: string;\n messages: ProviderMessage[];\n tools?: ProviderTool[];\n toolChoice?: 'auto' | 'none' | 'required' | { name: string };\n parallelToolCalls?: boolean;\n maxOutputTokens?: number;\n temperature?: number;\n topP?: number;\n topK?: number;\n stopSequences?: string[];\n reasoning?: {\n level?: number; // 0-100 scale\n maxTokens?: number;\n exclude?: boolean;\n };\n responseFormat?: { type: 'text' } | { type: 'json'; schema?: Record<string, unknown> };\n signal?: AbortSignal;\n /**\n * Stable end-user/session identifier for this request (e.g. the thread id).\n * Providers that support it (OpenAI-compatible `user`; OpenRouter uses it\n * for provider-sticky routing, which improves prompt-cache hit rates by\n * pinning consecutive requests to the same upstream provider) should\n * forward it; others may ignore it.\n */\n user?: string;\n providerOptions?: Record<string, unknown>;\n}\n\n// =============================================================================\n// Message Types\n// =============================================================================\n\nexport type ProviderMessage =\n | ProviderSystemMessage\n | ProviderUserMessage\n | ProviderAssistantMessage\n | ProviderToolMessage;\n\nexport interface ProviderSystemMessage {\n role: 'system';\n content: string;\n}\n\nexport interface ProviderUserMessage {\n role: 'user';\n content: ProviderMessageContent;\n}\n\nexport interface ProviderAssistantMessage {\n role: 'assistant';\n content?: string | null;\n reasoning?: string | null;\n reasoningDetails?: ProviderReasoningDetail[];\n toolCalls?: ProviderToolCallPart[];\n}\n\nexport interface ProviderToolMessage {\n role: 'tool';\n toolCallId: string;\n toolName: string;\n content: ProviderToolResultContent;\n attachments?: ProviderAttachment[];\n}\n\n/**\n * Attachment on a provider message (loaded from storage, ready for provider-specific transformation)\n */\nexport interface ProviderAttachment {\n type: 'image' | 'file';\n data: string; // base64\n mediaType: string;\n name?: string;\n path?: string; // Original file path (for logging/debugging)\n}\n\n// =============================================================================\n// Content Types\n// =============================================================================\n\nexport type ProviderMessageContent = string | ContentPart[];\n\nexport type ContentPart =\n | TextPart\n | ImagePart\n | ImageUrlPart\n | FilePart;\n\nexport interface TextPart {\n type: 'text';\n text: string;\n}\n\nexport interface ImagePart {\n type: 'image';\n data: string; // base64 or URL\n mediaType: string; // 'image/jpeg', 'image/png', etc.\n detail?: 'auto' | 'low' | 'high';\n}\n\n/**\n * Image URL content part (OpenAI/OpenRouter format).\n * Used for passing image URLs directly to providers.\n */\nexport interface ImageUrlPart {\n type: 'image_url';\n image_url: {\n url: string; // Can be data URL (data:image/...) or http(s) URL\n detail?: 'auto' | 'low' | 'high';\n };\n}\n\nexport interface FilePart {\n type: 'file';\n data: string; // base64 or URL\n mediaType: string;\n filename?: string;\n}\n\n// =============================================================================\n// Tool Types\n// =============================================================================\n\nexport interface ProviderTool {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters?: Record<string, unknown>; // JSON Schema\n };\n /**\n * Where this tool is executed:\n * - 'local': Execute locally by the execution engine (default)\n * - 'provider': Executed by the LLM provider, results come in response\n */\n executionMode?: 'local' | 'provider';\n /**\n * Which provider executes this tool (when executionMode='provider')\n * e.g., 'openai', 'anthropic'\n */\n executionProvider?: string;\n}\n\nexport interface ProviderToolCallPart {\n id: string;\n name: string;\n arguments: Record<string, unknown>; // Parsed JSON\n /**\n * Provider-specific metadata that must round-trip with the tool call.\n * For example, Gemini tool calls can include a thought signature that must\n * be echoed back on the next turn for tool calling to continue working.\n */\n extraContent?: Record<string, unknown>;\n}\n\nexport type ProviderToolResultContent =\n | string\n | { type: 'text'; text: string }\n | { type: 'error'; error: string }\n | ContentPart[];\n\n// =============================================================================\n// Response Types\n// =============================================================================\n\nexport interface ProviderResponse {\n content: string | null;\n reasoning?: string | null;\n reasoningDetails?: ProviderReasoningDetail[];\n toolCalls?: ProviderToolCallPart[];\n images?: ProviderGeneratedImage[];\n /**\n * Provider-executed tool calls surfaced for logging and inspection.\n *\n * Providers should populate this when the upstream provider executed a\n * built-in/native tool server-side. These entries are informational for\n * Standard Agents and must not be re-executed locally.\n */\n providerTools?: ProviderExecutedToolResult[];\n finishReason: ProviderFinishReason;\n usage: ProviderUsage;\n metadata?: Record<string, unknown>;\n}\n\nexport type ProviderFinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'error';\n\nexport interface ProviderUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n reasoningTokens?: number;\n cachedTokens?: number;\n cost?: number;\n /** The actual provider that fulfilled the request (e.g., 'google', 'anthropic') */\n provider?: string;\n /**\n * Per-million-token USD unit prices the provider reported for the model\n * that served this request (e.g. from OpenRouter's live models catalog).\n * Lets runtimes split exact input/cached/output cost components even when\n * no static pricing table covers the provider.\n */\n pricing?: ProviderUsagePricing;\n}\n\n/** Provider-reported unit prices for one request, in USD per million tokens. */\nexport interface ProviderUsagePricing {\n inputPerMillion?: number;\n cachedInputPerMillion?: number;\n outputPerMillion?: number;\n}\n\nexport interface ProviderGeneratedImage {\n /** Unique ID for this generated image (used to link to tool call) */\n id?: string;\n /** Name of the tool that generated this image (e.g., 'image_generation') */\n toolName?: string;\n data: string; // base64 or URL\n mediaType: string;\n revisedPrompt?: string;\n}\n\nexport interface ProviderReasoningDetail {\n type: 'summary' | 'encrypted' | 'text';\n /** Original reasoning ID from provider (e.g., rs_xxx for OpenAI) */\n id?: string;\n text?: string;\n data?: string;\n /** Provider-specific format identifier (e.g., \"google-gemini-v1\", \"openai-responses-v1\") */\n format?: string;\n}\n\n// =============================================================================\n// Streaming Types\n// =============================================================================\n\n/**\n * Web search result from provider\n */\nexport interface ProviderWebSearchResult {\n /** Unique ID of the web search call */\n id: string;\n /** Status of the search */\n status: 'in_progress' | 'searching' | 'completed' | 'failed';\n /** Search actions performed */\n actions?: Array<{\n type: 'search' | 'open_page' | 'find';\n query?: string;\n url?: string;\n pattern?: string;\n sources?: Array<{ type: 'url'; url: string; title?: string }>;\n }>;\n}\n\n/**\n * Provider-executed tool call surfaced for logging.\n *\n * Providers use this when the upstream model provider executes a native tool\n * server-side and Standard Agents should record the call without attempting to\n * execute it locally.\n */\nexport interface ProviderExecutedToolResult {\n /** Provider-facing tool name, such as \"web_search\" or \"x_search\" */\n name: string;\n /**\n * Legacy alias for `name`, retained for persisted log compatibility.\n * New provider implementations should set `name`; runtimes may mirror it\n * into `type` when serializing logs for older UIs.\n */\n type?: string;\n /** Provider that executed the tool, such as \"openai\" or \"xai\" */\n provider?: string;\n /** Unique ID of the provider tool call */\n id: string;\n /** Execution status */\n status: 'completed' | 'failed' | 'in_progress';\n /** Optional provider-specific result or argument summary */\n result?: {\n actions?: Array<{\n type: string;\n query?: string;\n url?: string;\n pattern?: string;\n sources?: Array<{ type?: string; url: string; title?: string }>;\n }>;\n input?: Record<string, unknown>;\n output?: string;\n results?: unknown[];\n artifacts?: Array<{\n type: string;\n id?: string;\n mediaType?: string;\n url?: string;\n path?: string;\n title?: string;\n metadata?: Record<string, unknown>;\n }>;\n };\n /** Provider-specific structured details that should stay JSON-serializable */\n metadata?: Record<string, unknown>;\n}\n\nexport type ProviderStreamChunk =\n // Content streaming\n | { type: 'content-delta'; delta: string }\n | { type: 'content-done' }\n // Reasoning streaming\n | { type: 'reasoning-delta'; delta: string }\n | { type: 'reasoning-done' }\n // Tool call streaming\n | { type: 'tool-call-start'; id: string; name: string; extraContent?: Record<string, unknown> }\n | { type: 'tool-call-delta'; id: string; argumentsDelta: string }\n | { type: 'tool-call-done'; id: string; arguments: Record<string, unknown>; extraContent?: Record<string, unknown> }\n // Image generation (partial)\n | { type: 'image-delta'; index: number; data: string }\n | { type: 'image-done'; index: number; image: ProviderGeneratedImage }\n // Web search (legacy compatibility; prefer provider-tool-done for new providers)\n | { type: 'web-search-done'; result: ProviderWebSearchResult }\n // Generic provider-executed tools\n | { type: 'provider-tool-done'; tool: ProviderExecutedToolResult }\n // Completion\n | { type: 'finish'; finishReason: ProviderFinishReason; usage: ProviderUsage; reasoningDetails?: ProviderReasoningDetail[] }\n // Errors\n | { type: 'error'; error: string; code?: string };\n\n// =============================================================================\n// Error Types\n// =============================================================================\n\nexport type ProviderErrorCode =\n | 'rate_limit'\n | 'invalid_request'\n | 'auth_error'\n | 'server_error'\n | 'timeout'\n | 'unknown';\n\nexport class ProviderError extends Error {\n constructor(\n message: string,\n public code: ProviderErrorCode,\n public statusCode?: number,\n public retryAfter?: number\n ) {\n super(message);\n this.name = 'ProviderError';\n }\n\n /**\n * Whether this error is retryable\n */\n get isRetryable(): boolean {\n return this.code === 'rate_limit' || this.code === 'server_error' || this.code === 'timeout';\n }\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Maps a 0-100 reasoning level to the model's nearest supported level\n */\nexport function mapReasoningLevel(\n level: number,\n reasoningLevels: Record<number, string | null> | undefined\n): string | null {\n if (!reasoningLevels) return null;\n\n const breakpoints = Object.keys(reasoningLevels)\n .map(Number)\n .sort((a, b) => a - b);\n\n if (breakpoints.length === 0) return null;\n\n // Find nearest breakpoint\n let nearest = breakpoints[0];\n let minDistance = Math.abs(level - nearest);\n\n for (const bp of breakpoints) {\n const distance = Math.abs(level - bp);\n if (distance < minDistance) {\n minDistance = distance;\n nearest = bp;\n }\n }\n\n return reasoningLevels[nearest];\n}\n","/**\n * Packing types for Standard Agents.\n *\n * Defines types for packaging agents with their dependencies into\n * reusable, encapsulated packages that can be published to npm\n * or stored locally.\n *\n * @module\n */\n\n// ============================================================================\n// Package Signature\n// ============================================================================\n\n/**\n * Package signature applied to packed definitions.\n *\n * When an agent and its dependencies are packed, each definition\n * receives this signature marking it as belonging to a specific package.\n * This enables namespace isolation during execution.\n *\n * @example\n * ```typescript\n * const signature: PackageSignature = {\n * packageId: 'standardagent-my-workflow',\n * version: '1.0.0',\n * source: 'npm',\n * packedAt: Date.now(),\n * };\n * ```\n */\nexport interface PackageSignature {\n /** Unique package identifier (npm name or local identifier) */\n packageId: string;\n /** Package version */\n version: string;\n /** Source type */\n source: 'npm' | 'local';\n /** When packed (timestamp in milliseconds) */\n packedAt: number;\n}\n\n// ============================================================================\n// Namespace Context\n// ============================================================================\n\n/**\n * Global namespace context - for unpacked code.\n *\n * Unpacked code sees:\n * - All unpacked tools, prompts, models, hooks\n * - Packed agent entry points (agents with exposeAsTool: true)\n * - NOT internal packed tools/prompts (those are hidden)\n */\nexport interface GlobalNamespaceContext {\n type: 'global';\n}\n\n/**\n * Packed namespace context - for code inside a packed agent.\n *\n * Packed code sees:\n * - Only items within its own package (by packageId)\n * - Other packed agent entry points (for handoffs)\n * - NOT unpacked global code\n */\nexport interface PackedNamespaceContext {\n type: 'packed';\n /** Package ID this code belongs to */\n packageId: string;\n}\n\n/**\n * Namespace context for execution.\n * Determines what items are visible during execution.\n *\n * @example\n * ```typescript\n * // Global namespace (unpacked code)\n * const globalNs: NamespaceContext = { type: 'global' };\n *\n * // Packed namespace (inside a packed agent)\n * const packedNs: NamespaceContext = {\n * type: 'packed',\n * packageId: 'standardagent-my-workflow',\n * };\n * ```\n */\nexport type NamespaceContext = GlobalNamespaceContext | PackedNamespaceContext;\n\n// ============================================================================\n// Packed Metadata\n// ============================================================================\n\n/**\n * Extended metadata for packed definitions.\n *\n * This interface is added to agent, prompt, tool, model, and hook\n * definitions when they are packed. It marks them as belonging\n * to a specific package and optionally as readonly.\n */\nexport interface PackedMetadata {\n /**\n * Package signature if this definition is part of a packed agent.\n * Undefined for unpacked (global) definitions.\n */\n __package?: PackageSignature;\n\n /**\n * Whether this definition is readonly (cannot be edited in UI).\n * Packed definitions are typically readonly.\n */\n __readonly?: boolean;\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Helper type to check if a definition is packed.\n */\nexport function isPacked(metadata: PackedMetadata | undefined): metadata is PackedMetadata & { __package: PackageSignature } {\n return !!metadata?.__package;\n}\n\n/**\n * Helper to check if a definition belongs to a specific package.\n */\nexport function belongsToPackage(\n metadata: PackedMetadata | undefined,\n packageId: string\n): boolean {\n return metadata?.__package?.packageId === packageId;\n}\n\n/**\n * Helper to check if a definition is visible in a given namespace.\n *\n * @param metadata - The definition's packed metadata\n * @param namespace - The current namespace context\n * @param isEntryPoint - Whether this is an agent with exposeAsTool: true\n */\nexport function isVisibleInNamespace(\n metadata: PackedMetadata | undefined,\n namespace: NamespaceContext,\n isEntryPoint: boolean = false\n): boolean {\n const hasPkg = isPacked(metadata);\n\n if (namespace.type === 'global') {\n // Global sees: unpacked + packed entry points\n return !hasPkg || isEntryPoint;\n }\n\n // Packed sees: own package + other packed entry points\n const isOwnPackage = hasPkg && metadata.__package.packageId === namespace.packageId;\n return isOwnPackage || (hasPkg && isEntryPoint);\n}\n\n// ============================================================================\n// Packed Package Types\n// ============================================================================\n\n/**\n * Metadata export for packed packages.\n *\n * This is exported as `__meta` from the packed package's index.ts,\n * replacing the manifest.json file from the old format.\n *\n * @example\n * ```typescript\n * export const __meta: PackedMeta = {\n * packageId: 'standardagent-my-workflow',\n * version: '1.0.0',\n * entryAgents: ['my_agent'],\n * packedAt: 1705012800000,\n * };\n * ```\n */\nexport interface PackedMeta {\n /** Unique package identifier (npm name or local identifier) */\n packageId: string;\n /** Package version (semver) */\n version: string;\n /** Entry agents exposed as tools (visible from outside the package) */\n entryAgents: string[];\n /** When the package was packed (timestamp in milliseconds) */\n packedAt: number;\n /** Optional description from the entry agent */\n description?: string;\n}\n\n/**\n * Lazy loader type for packed definitions.\n *\n * Each definition in a packed package is wrapped in a function\n * that returns a Promise, enabling lazy loading.\n *\n * @example\n * ```typescript\n * export const tools = {\n * search: async (): Promise<ToolDefinition> => ({\n * description: 'Search for information',\n * execute: async (state, args) => { ... },\n * }),\n * } as const;\n * ```\n */\nexport type DefinitionLoader<T> = () => Promise<T>;\n\n// Import types needed for PackedExports\nimport type { AgentDefinition } from './agents.js';\nimport type { PromptDefinition } from './prompts.js';\nimport type { ToolDefinition } from './tools.js';\nimport type { ModelDefinition } from './models.js';\nimport type { HookSignatures } from './hooks.js';\nimport type { EffectDefinition } from './effects.js';\nimport type { Controller, MarkedThreadEndpoint } from './endpoints.js';\n\n/**\n * Standard shape for packed package exports.\n *\n * Every packed package exports this structure, enabling\n * consistent discovery and loading.\n *\n * @example\n * ```typescript\n * import type { PackedExports } from '@standardagents/spec';\n *\n * const pkg: PackedExports = await import('standardagent-my-workflow');\n * const tool = await pkg.tools.search();\n * ```\n */\nexport interface PackedExports {\n /** Agent definitions, keyed by name */\n agents: Record<string, DefinitionLoader<AgentDefinition>>;\n /** Prompt definitions, keyed by name */\n prompts: Record<string, DefinitionLoader<PromptDefinition>>;\n /** Tool definitions, keyed by name */\n tools: Record<string, DefinitionLoader<ToolDefinition<unknown, any, any>>>;\n /** Model definitions, keyed by name */\n models: Record<string, DefinitionLoader<ModelDefinition>>;\n /** Hook definitions, keyed by name */\n hooks: Record<string, DefinitionLoader<HookSignatures[keyof HookSignatures]>>;\n /**\n * Effect definitions, keyed by name.\n *\n * Optional for backward compatibility with previously packed packages.\n */\n effects?: Record<string, DefinitionLoader<EffectDefinition<any, any>>>;\n /**\n * Thread endpoint handlers, keyed by packed route key (for example, `status.get`).\n *\n * Runtimes mount these beneath the same thread ID prefix as local thread\n * endpoints, using the packed route key to derive the endpoint path.\n * Requests beneath that prefix that do not match any local or packed thread\n * endpoint route MUST return HTTP 404.\n *\n * Optional for backward compatibility with previously packed packages.\n */\n threadEndpoints?: Record<string, DefinitionLoader<MarkedThreadEndpoint | Controller>>;\n /** Package metadata */\n __meta: PackedMeta;\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/threads.ts","../src/endpoints.ts","../src/providers.ts","../src/packing.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\nimport type { z, ZodTypeAny } from 'zod';\nimport type {\n ProviderRequest,\n ProviderResponse,\n ProviderStreamChunk,\n InspectedRequest,\n ProviderModelInfo,\n ProviderModelsPage,\n ProviderModelsQuery,\n ResponseSummary,\n} from './providers';\nimport type { ToolDefinition, ToolArgs, ToolTenvs } from './tools';\nimport type { VariableDefinition, VariableType } from './tools';\n\n/**\n * Legacy provider identifiers - kept for reference only.\n * New code should use ProviderFactory imports from provider packages.\n *\n * @deprecated Use ProviderFactory from provider packages instead\n * @internal\n */\nexport type ModelProvider = 'openai' | 'openrouter' | 'anthropic' | 'google' | 'test';\n\n/**\n * Provider interface for LLM providers.\n *\n * Provider packages export a factory function that creates instances\n * implementing this interface. This is structurally compatible with\n * LLMProviderInterface from providers.ts.\n */\nexport interface ProviderInstance {\n readonly name: string;\n readonly specificationVersion: '1';\n generate(request: ProviderRequest): Promise<ProviderResponse>;\n stream(request: ProviderRequest): Promise<AsyncIterable<ProviderStreamChunk>>;\n supportsModel?(modelId: string): boolean;\n /** List available models from this provider */\n getModels?(filter?: string): Promise<ProviderModelInfo[]>;\n /** List available models with optional remote search/pagination */\n getModelsPage?(query?: ProviderModelsQuery): Promise<ProviderModelsPage>;\n /** Fetch capabilities for a specific model */\n getModelCapabilities?(modelId: string): Promise<ModelCapabilities | null>;\n /** Get provider-defined built-in tools available for a model */\n getTools?(modelId?: string): Record<string, ToolDefinition<unknown, ToolArgs | null, ToolTenvs | null>> | Promise<Record<string, ToolDefinition<unknown, ToolArgs | null, ToolTenvs | null>>>;\n /** Get the icon URL for this provider or a specific model */\n getIcon?(modelId?: string): string | undefined;\n /** Inspect a raw request for debugging purposes */\n inspectRequest?(request: ProviderRequest): Promise<InspectedRequest>;\n /** Fetch additional metadata about a completed response */\n getResponseMetadata?(summary: ResponseSummary, signal?: AbortSignal): Promise<Record<string, unknown> | null>;\n}\n\n/**\n * Configuration passed to provider factory functions.\n */\nexport interface ProviderFactoryConfig {\n apiKey: string;\n baseUrl?: string;\n timeout?: number;\n [key: string]: unknown;\n}\n\n/**\n * Declarative connection-level config slot exposed by a provider factory.\n *\n * Slots describe values used to construct a provider client, such as\n * credentials, API endpoints, account IDs, regions, and timeouts. They are\n * different from `providerOptions`, which are per-model or per-request knobs.\n */\nexport interface ProviderConfigSlot<T = unknown> {\n /** Value type, used by UIs for validation and secret handling */\n type: VariableType | 'url' | 'number' | 'boolean';\n /** Whether this value is required to construct the provider */\n required?: boolean;\n /** Default literal value when no override/source provides one */\n default?: T;\n /** Conventional environment variable used by the built-in/default provider */\n defaultEnv?: string;\n /** Whether sub-providers may override this slot */\n overridable?: boolean;\n /** Human-readable description for setup UIs and docs */\n description?: string;\n}\n\n/**\n * Named collection of provider client config slots.\n */\nexport type ProviderConfigSlots = Record<string, ProviderConfigSlot>;\n\n/**\n * Value source used by `defineProvider()` sub-providers to fill base-provider\n * config slots.\n */\nexport type ProviderConfigValueSource<T = unknown> =\n | { type: 'const'; value: T }\n | {\n type: 'env';\n name: string;\n valueType?: VariableType | 'url' | 'number' | 'boolean';\n required?: boolean;\n default?: T;\n description?: string;\n };\n\n/**\n * Convenience helper for constant provider config values.\n */\nexport function providerValue<T>(value: T): ProviderConfigValueSource<T> {\n return { type: 'const', value };\n}\n\n/**\n * Convenience helper for provider config values resolved from environment.\n */\nexport function providerEnv<T = string>(\n name: string,\n options: Omit<Extract<ProviderConfigValueSource<T>, { type: 'env' }>, 'type' | 'name'> = {}\n): ProviderConfigValueSource<T> {\n return { type: 'env', name, ...options };\n}\n\n/**\n * Backward-compatible alias with wording that reads naturally in provider\n * definition files.\n */\nexport const providerConst = providerValue;\n\nexport interface ProviderOverrideContext {\n /** Name of the defined provider being executed */\n providerName: string;\n /** The resolved connection config passed to the base provider */\n config: ProviderFactoryConfig;\n /** Base provider instance before overrides are applied */\n baseProvider: ProviderInstance;\n}\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport type ProviderOverride<Context, Result> = (\n context: ProviderOverrideContext & Context,\n next: () => MaybePromise<Result>\n) => MaybePromise<Result>;\n\nexport type ProviderSyncOverride<Context, Result> = (\n context: ProviderOverrideContext & Context,\n next: () => Result\n) => Result;\n\n/**\n * Overrideable provider methods. Each override can replace the base behavior\n * or call `next()` to compose with the base provider.\n */\nexport interface ProviderMethodOverrides {\n generate?: ProviderOverride<{ request: ProviderRequest }, ProviderResponse>;\n stream?: ProviderOverride<{ request: ProviderRequest }, AsyncIterable<ProviderStreamChunk>>;\n supportsModel?: ProviderSyncOverride<{ modelId: string }, boolean>;\n getModels?: ProviderOverride<{ filter?: string }, ProviderModelInfo[]>;\n getModelsPage?: ProviderOverride<{ query?: ProviderModelsQuery }, ProviderModelsPage>;\n getModelCapabilities?: ProviderOverride<{ modelId: string }, ModelCapabilities | null>;\n getTools?: ProviderOverride<{\n modelId?: string;\n }, Record<string, ToolDefinition<unknown, ToolArgs | null, ToolTenvs | null>>>;\n getIcon?: ProviderSyncOverride<{ modelId?: string }, string | undefined>;\n inspectRequest?: ProviderOverride<{ request: ProviderRequest }, InspectedRequest>;\n getResponseMetadata?: ProviderOverride<{\n summary: ResponseSummary;\n signal?: AbortSignal;\n }, Record<string, unknown> | null>;\n}\n\nexport interface ProviderDefinition<\n N extends string = string,\n Base extends ProviderFactoryWithOptions<ZodTypeAny> = ProviderFactoryWithOptions<ZodTypeAny>\n> {\n name: N;\n label?: string;\n baseProvider: Base;\n config?: Partial<Record<keyof ProviderFactoryConfig | string, ProviderConfigValueSource>>;\n overrides?: ProviderMethodOverrides;\n}\n\n/**\n * Provider factory with optional typed providerOptions schema.\n *\n * The schema property allows type inference and runtime validation of\n * provider-specific options in model definitions.\n *\n * @template TOptions - Zod schema type for providerOptions (defaults to ZodTypeAny)\n *\n * @example\n * ```typescript\n * import { openai } from '@standardagents/openai';\n *\n * // openai is a ProviderFactoryWithOptions with typed schema\n * const provider = openai({ apiKey: 'sk-...' });\n *\n * // Access the schema for validation\n * openai.providerOptions?.parse({ service_tier: 'default' });\n * ```\n */\nexport interface ProviderFactoryWithOptions<\n TOptions extends ZodTypeAny = ZodTypeAny\n> {\n (config: ProviderFactoryConfig): ProviderInstance;\n /** Zod schema for provider-specific options */\n providerOptions?: TOptions;\n /** Connection-level config slots accepted by this provider factory */\n configSlots?: ProviderConfigSlots;\n /** Metadata attached to factories created with defineProvider() */\n providerDefinition?: ProviderDefinition<string, ProviderFactoryWithOptions<TOptions>>;\n}\n\n/**\n * Factory function that creates provider instances.\n *\n * Provider packages (like @standardagents/openai) export this type.\n * This is an alias for ProviderFactoryWithOptions for backward compatibility.\n *\n * @example\n * ```typescript\n * import { openai } from '@standardagents/openai';\n *\n * // openai is a ProviderFactory\n * const provider = openai({ apiKey: 'sk-...' });\n * ```\n */\nexport type ProviderFactory = ProviderFactoryWithOptions<ZodTypeAny>;\n\n/**\n * Define a named sub-provider that uses a base provider implementation with\n * custom connection config sources and optional method overrides.\n */\nexport function defineProvider<\n const N extends string,\n Base extends ProviderFactoryWithOptions<ZodTypeAny>\n>(\n definition: ProviderDefinition<N, Base>\n): ProviderFactoryWithOptions<Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny> {\n if (!definition.name) {\n throw new Error('Provider name is required');\n }\n if (typeof definition.baseProvider !== 'function') {\n throw new Error('baseProvider must be a provider factory function');\n }\n\n const factory = ((config: ProviderFactoryConfig) => {\n const baseProvider = definition.baseProvider(config);\n const commonContext: ProviderOverrideContext = {\n providerName: definition.name,\n config,\n baseProvider,\n };\n\n const provider: ProviderInstance = {\n name: definition.name,\n specificationVersion: '1',\n generate: (request) => {\n const next = () => baseProvider.generate(request);\n return Promise.resolve(definition.overrides?.generate?.({ ...commonContext, request }, next) ?? next());\n },\n stream: (request) => {\n const next = () => baseProvider.stream(request);\n return Promise.resolve(definition.overrides?.stream?.({ ...commonContext, request }, next) ?? next());\n },\n };\n\n if (definition.overrides?.supportsModel || baseProvider.supportsModel) {\n provider.supportsModel = (modelId) => {\n const next = () => baseProvider.supportsModel?.(modelId) ?? true;\n return definition.overrides?.supportsModel?.({ ...commonContext, modelId }, next) ?? next();\n };\n }\n\n if (definition.overrides?.getModels || baseProvider.getModels) {\n provider.getModels = (filter) => {\n const next = () => baseProvider.getModels?.(filter) ?? Promise.resolve([]);\n return Promise.resolve(\n definition.overrides?.getModels?.({ ...commonContext, filter }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getModelsPage || baseProvider.getModelsPage) {\n provider.getModelsPage = (query) => {\n const next = () => baseProvider.getModelsPage?.(query) ?? Promise.resolve({ models: [], hasNextPage: false });\n return Promise.resolve(\n definition.overrides?.getModelsPage?.({ ...commonContext, query }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getModelCapabilities || baseProvider.getModelCapabilities) {\n provider.getModelCapabilities = (modelId) => {\n const next = () => baseProvider.getModelCapabilities?.(modelId) ?? Promise.resolve(null);\n return Promise.resolve(\n definition.overrides?.getModelCapabilities?.({ ...commonContext, modelId }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getTools || baseProvider.getTools) {\n provider.getTools = (modelId) => {\n const next = () => baseProvider.getTools?.(modelId) ?? {};\n return definition.overrides?.getTools?.({ ...commonContext, modelId }, next) ?? next();\n };\n }\n\n if (definition.overrides?.getIcon || baseProvider.getIcon) {\n provider.getIcon = (modelId) => {\n const next = () => baseProvider.getIcon?.(modelId);\n return definition.overrides?.getIcon?.({ ...commonContext, modelId }, next) ?? next();\n };\n }\n\n if (definition.overrides?.inspectRequest || baseProvider.inspectRequest) {\n provider.inspectRequest = (request) => {\n const next = () => {\n if (!baseProvider.inspectRequest) {\n throw new Error(`Provider '${definition.name}' does not support request inspection`);\n }\n return baseProvider.inspectRequest(request);\n };\n return Promise.resolve(\n definition.overrides?.inspectRequest?.({ ...commonContext, request }, next) ?? next()\n );\n };\n }\n\n if (definition.overrides?.getResponseMetadata || baseProvider.getResponseMetadata) {\n provider.getResponseMetadata = (summary, signal) => {\n const next = () => baseProvider.getResponseMetadata?.(summary, signal) ?? Promise.resolve(null);\n return Promise.resolve(\n definition.overrides?.getResponseMetadata?.({ ...commonContext, summary, signal }, next) ?? next()\n );\n };\n }\n\n return provider;\n }) as ProviderFactoryWithOptions<Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny>;\n\n factory.providerOptions = definition.baseProvider.providerOptions as Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny;\n factory.configSlots = definition.baseProvider.configSlots;\n factory.providerDefinition = definition as unknown as ProviderDefinition<string, ProviderFactoryWithOptions<Base extends ProviderFactoryWithOptions<infer S> ? S : ZodTypeAny>>;\n\n return factory;\n}\n\n/**\n * Extract providerOptions type from a provider factory.\n *\n * Returns the inferred input type from the provider's Zod schema,\n * or Record<string, unknown> if no schema is defined.\n *\n * @template P - Provider factory type\n */\nexport type InferProviderOptions<P> =\n P extends ProviderFactoryWithOptions<infer S>\n ? S extends ZodTypeAny\n ? z.input<S> extends Record<string, unknown>\n ? z.input<S>\n : Record<string, unknown>\n : Record<string, unknown>\n : Record<string, unknown>;\n\n/**\n * Model capability flags indicating supported features.\n *\n * These capabilities are used by the FlowEngine to determine how to\n * interact with the model and what features are available.\n */\nexport interface ModelCapabilities {\n /**\n * Reasoning level mapping (0-100 scale → model-specific values).\n * Keys are breakpoints, values are model's native reasoning strings.\n *\n * @example\n * // OpenAI o-series\n * reasoningLevels: { 0: null, 33: 'low', 66: 'medium', 100: 'high' }\n *\n * @example\n * // Binary reasoning (Claude extended thinking)\n * reasoningLevels: { 0: null, 100: 'enabled' }\n *\n * @example\n * // No reasoning support\n * reasoningLevels: { 0: null }\n */\n reasoningLevels?: Record<number, string | null>;\n\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 supportsImages?: boolean;\n\n /**\n * @deprecated Use supportsImages instead\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 supportsToolCalls?: boolean;\n\n /**\n * @deprecated Use supportsToolCalls instead\n */\n functionCalling?: boolean;\n\n /**\n * Whether the model supports streaming responses.\n * @default true\n */\n supportsStreaming?: boolean;\n\n /**\n * Whether the model supports structured outputs (JSON mode).\n */\n supportsJsonMode?: boolean;\n\n /**\n * @deprecated Use supportsJsonMode instead\n */\n structuredOutputs?: boolean;\n\n /**\n * Maximum context window size in tokens.\n */\n maxContextTokens?: number;\n\n /**\n * Maximum output tokens the model can generate.\n */\n maxOutputTokens?: number;\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 Basic usage\n * ```typescript\n * import { defineModel } from '@standardagents/spec';\n * import { openai } from '@standardagents/openai';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: openai,\n * model: 'gpt-4o',\n * inputPrice: 2.5,\n * outputPrice: 10,\n * });\n * ```\n *\n * @example With capabilities and typed provider options\n * ```typescript\n * import { defineModel } from '@standardagents/spec';\n * import { openai } from '@standardagents/openai';\n *\n * export default defineModel({\n * name: 'gpt-4o',\n * provider: openai,\n * model: 'gpt-4o',\n * inputPrice: 2.5,\n * outputPrice: 10,\n * capabilities: {\n * supportsImages: true,\n * supportsToolCalls: true,\n * supportsJsonMode: true,\n * maxContextTokens: 128000,\n * },\n * providerOptions: {\n * service_tier: 'default', // TypeScript knows this is valid\n * },\n * });\n * ```\n */\nexport interface ModelDefinition<\n N extends string = string,\n P extends ProviderFactoryWithOptions<ZodTypeAny> = ProviderFactoryWithOptions<ZodTypeAny>\n> {\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 factory function to use for API calls.\n *\n * Import from a provider package like @standardagents/openai or @standardagents/openrouter.\n * The provider's type determines what providerOptions are available.\n *\n * @example\n * ```typescript\n * import { openai } from '@standardagents/openai';\n * provider: openai\n * ```\n *\n * @example\n * ```typescript\n * import { openrouter } from '@standardagents/openrouter';\n * provider: openrouter\n * ```\n */\n provider: P;\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?: StandardAgentSpec.Models[];\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 * Provider-specific options passed through to the provider.\n * These are merged with prompt-level providerOptions (model options are defaults).\n *\n * The type is automatically inferred from the provider's schema when available,\n * providing TypeScript autocompletion and runtime validation.\n *\n * @example\n * ```typescript\n * // With OpenAI provider\n * providerOptions: {\n * service_tier: 'default',\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With OpenRouter provider\n * providerOptions: {\n * provider: {\n * zdr: true,\n * max_price: { prompt: 1 },\n * },\n * }\n * ```\n */\n providerOptions?: InferProviderOptions<P>;\n\n /**\n * Provider tools available for this model.\n * References tool names from provider.getTools().\n *\n * Provider tools are built-in tools offered by the provider. Tool names are\n * provider-defined capability names, not Standard Agents global names. These\n * tools can be used in prompts alongside custom tools and are executed by\n * the upstream provider.\n *\n * @example\n * ```typescript\n * providerTools: ['web_search', 'code_interpreter'],\n * ```\n */\n providerTools?: string[];\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 * import { openai } from '@standardagents/openai';\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 typed provider options\n * import { openrouter } from '@standardagents/openrouter';\n *\n * export default defineModel({\n * name: 'claude-3-opus',\n * provider: openrouter,\n * model: 'anthropic/claude-3-opus',\n * providerOptions: {\n * provider: {\n * zdr: true,\n * only: ['anthropic'],\n * },\n * },\n * });\n * ```\n */\nexport function defineModel<\n N extends string,\n P extends ProviderFactoryWithOptions<ZodTypeAny>\n>(\n options: ModelDefinition<N, P>\n): ModelDefinition<N, P> {\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 ProviderFactory function\n if (typeof options.provider !== 'function') {\n throw new Error(\n 'Provider must be a ProviderFactory function imported from a provider package (e.g., @standardagents/openai)'\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 // Runtime validation of providerOptions if schema exists on provider\n if (options.provider.providerOptions && options.providerOptions) {\n const result = options.provider.providerOptions.safeParse(options.providerOptions);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => `${String(i.path.join('.'))}: ${i.message}`)\n .join(', ');\n throw new Error(`Invalid providerOptions for model '${options.name}': ${issues}`);\n }\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 { PackedMetadata } from './packing.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 ZodUnknown,\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 /**\n * Machine-readable error code for structured handling.\n *\n * Example: `subagent_env_required` indicates the client must provide\n * scoped subagent env values before execution can continue.\n */\n error_code?: string;\n /**\n * Structured error payload for machine handling.\n *\n * Implementations should keep this JSON-serializable.\n */\n error_data?: Record<string, unknown>;\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 * Use ZodUnknown for arbitrary JSON slots, such as array items that can\n * be strings, numbers, booleans, null, arrays, or objects.\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 | ZodUnknown\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 readonly [\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// Thread Variable Declaration Types\n// ============================================================================\n\n/**\n * Variable declaration type.\n *\n * - `text`: Plain string configuration value\n * - `secret`: Sensitive value that should be encrypted at rest\n */\nexport type VariableType = 'text' | 'secret';\n\n/**\n * Declares a variable required or optionally consumed by a tool or prompt.\n */\nexport interface VariableDefinition {\n /** Environment variable/property name */\n name: string;\n /** Value type */\n type: VariableType;\n /** Whether this variable is required to execute */\n required: boolean;\n /**\n * Whether this variable is scoped to the declarer subtree.\n *\n * Scoped variables do not inherit parent thread env values. Descendants of\n * the declarer still inherit scoped values from that declarer thread.\n *\n * @default false\n */\n scoped?: boolean;\n /** Human-readable description (empty string when not provided) */\n description: string;\n}\n\n// ============================================================================\n// Legacy Thread Environment Variable Types (Zod-based)\n// ============================================================================\n\n/**\n * Legacy raw shape for `tenvs` schema - uses same pattern as ToolArgsRawShape.\n * Each key is an environment variable name and each value is a Zod schema.\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type TenvRawShape<D extends number = 7> = Record<string, ToolArgsNode<D>>;\n\n/**\n * Top-level thread environment variable schema.\n *\n * Defines which thread environment variables a tool requires.\n * Required values are non-optional fields, optional values use `.optional()`.\n *\n * @example\n * ```typescript\n * z.object({\n * VECTOR_STORE_ID: z.string().describe('OpenAI Vector Store ID'), // Required\n * USER_LOCATION: z.string().optional().describe('User location'), // Optional\n * })\n * ```\n *\n * @template D - Maximum nesting depth (default: 7)\n */\nexport type ToolTenvs<D extends number = 7> = z.ZodObject<TenvRawShape<D>>;\n\n/**\n * @deprecated Use VariableDefinition[] via the `variables` property instead.\n */\nexport type ToolVariables = VariableDefinition[];\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// Uses-Constrained State Types\n// ============================================================================\n\n/**\n * Helper type to check if Uses is a non-empty const array.\n * Returns true only if Uses has literal string elements (from `as const`).\n */\ntype IsConstArray<Uses extends readonly string[]> =\n // If Uses is exactly `readonly string[]` (non-const), this becomes `string`\n // If Uses is a const tuple like `readonly ['a', 'b']`, this becomes `'a' | 'b'`\n string extends Uses[number] ? false : true;\n\n/**\n * Helper type to check if Uses array is empty.\n */\ntype IsEmptyArray<Uses extends readonly string[]> = Uses extends readonly [] ? true : false;\n\n/**\n * A ThreadState with queueTool and invokeTool constrained to specific tool names.\n *\n * When a tool declares `uses: ['a', 'b'] as const`, the state passed to execute\n * will only allow calling those specific tools.\n *\n * @template Uses - Readonly array of allowed tool names\n */\nexport type UsesConstrainedState<Uses extends readonly string[]> = Omit<\n ThreadState,\n 'queueTool' | 'invokeTool'\n> & {\n /**\n * Queue a tool for execution.\n *\n * Constrained to only tools declared in `uses` array.\n *\n * @param toolName - Name of the tool to invoke (must be in uses array)\n * @param args - Arguments to pass to the tool\n */\n queueTool(toolName: Uses[number], args?: Record<string, unknown>): void;\n\n /**\n * Invoke a tool directly and wait for the result.\n *\n * Constrained to only tools declared in `uses` array.\n *\n * @param toolName - Name of the tool to invoke (must be in uses array)\n * @param args - Arguments to pass to the tool\n * @returns The tool result\n */\n invokeTool(toolName: Uses[number], args?: Record<string, unknown>): Promise<ToolResult>;\n};\n\n/**\n * A ThreadState where queueTool and invokeTool cannot be called (empty uses).\n */\nexport type EmptyUsesState = Omit<ThreadState, 'queueTool' | 'invokeTool'>;\n\n/**\n * Determines the correct state type based on the Uses array.\n *\n * - Empty `uses: [] as const` → EmptyUsesState (no queueTool/invokeTool)\n * - Const `uses: ['a', 'b'] as const` → UsesConstrainedState (constrained methods)\n * - Non-const `uses: ['a']` or no uses → ThreadState (unconstrained, backward compatible)\n */\nexport type ResolveUsesState<Uses extends readonly string[]> =\n IsEmptyArray<Uses> extends true\n ? EmptyUsesState\n : IsConstArray<Uses> extends true\n ? UsesConstrainedState<Uses>\n : ThreadState;\n\n/**\n * Tool execute function with uses-aware state.\n *\n * When `uses` is declared with `as const`, the state's queueTool and invokeTool\n * are constrained to only the declared tools. When `uses` is not declared or\n * is a regular string[], any tool name is allowed (backward compatible).\n *\n * @template State - Base state type\n * @template Args - Tool arguments schema\n * @template Uses - Readonly array of allowed tool names\n */\nexport type UsesAwareExecute<\n State,\n Args extends ToolArgs | null,\n Uses extends readonly string[],\n> = Args extends ToolArgs\n ? (\n state: ResolveUsesState<Uses>,\n args: z.infer<Args>\n ) => Promise<ToolResult>\n : (\n state: ResolveUsesState<Uses>\n ) => Promise<ToolResult>;\n\n// ============================================================================\n// Tool Definition Types (Object-based API)\n// ============================================================================\n\n/**\n * Options for defining a tool.\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 * @template Tenvs - The Zod schema for thread environment variables, or null\n * @template Uses - Readonly array of tool names this tool can invoke\n */\nexport interface DefineToolOptions<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n Tenvs extends ToolTenvs | null = null,\n Uses extends readonly string[] = readonly string[],\n> {\n /** Description of what the tool does (shown to the LLM). */\n description: string;\n /** Zod schema for validating tool arguments. Omit for tools with no args. */\n args?: Args;\n /** The tool implementation function. */\n execute: UsesAwareExecute<State, Args, Uses>;\n /**\n * Variable declarations required/optionally used by this tool.\n */\n variables?: VariableDefinition[];\n /**\n * @deprecated Use `variables` instead.\n * Zod schema for thread environment variables the tool requires.\n */\n tenvs?: Tenvs;\n /**\n * Where this tool is executed:\n * - 'local': Execute locally by the execution engine (default)\n * - 'provider': Executed by the LLM provider, results come in response\n */\n executionMode?: 'local' | 'provider';\n /**\n * Which provider executes this tool (when executionMode='provider').\n * e.g., 'openai', 'anthropic'\n */\n executionProvider?: string;\n /**\n * Explicit list of tools, prompts, or agents this tool can call.\n *\n * When specified with `as const`, the tool's execute function's state\n * will have queueTool() and invokeTool() constrained to only the\n * declared tools (compile-time type safety).\n *\n * At runtime, attempts to call unlisted items will throw an error.\n *\n * This is required for packed tools to ensure namespace isolation.\n * For unpacked tools, it's optional but recommended for clarity.\n *\n * @example\n * ```typescript\n * // Type-safe: only 'validate_input' and 'format_output' allowed\n * defineTool({\n * description: 'Process data using helper tools',\n * uses: ['validate_input', 'format_output'] as const,\n * execute: async (state) => {\n * state.queueTool('validate_input', { data: '...' }); // ✓ OK\n * state.queueTool('unknown_tool', {}); // ✗ TypeScript error\n * // ...\n * },\n * });\n *\n * // Without `as const`, any tool name is allowed (backward compatible)\n * defineTool({\n * description: 'Flexible tool',\n * uses: ['some_tool'],\n * execute: async (state) => {\n * state.queueTool('any_tool', {}); // ✓ OK (no type constraint)\n * },\n * });\n * ```\n */\n uses?: Uses;\n /**\n * The name of an argument whose value is a short, human-readable description\n * of what this tool call is doing — for example `\"fixing index.html\"`.\n *\n * When set, the `tool_call_started` hook and the `tool_call_started` thread\n * event wait until **just this argument** has finished streaming from the\n * model — not the whole tool call — and include its value as `progress`. This\n * lets a UI show what a tool is about to do before a large argument (such as\n * a file's `content`) finishes generating.\n *\n * When unset, `tool_call_started` fires as soon as the tool call appears in\n * the model stream (its name is known, arguments may still be incomplete).\n *\n * Declare the named argument early in the `args` schema and keep it short so\n * it completes quickly. If the model never emits it, `tool_call_started`\n * still fires once the tool call finishes, with `progress` undefined.\n *\n * @example\n * ```typescript\n * defineTool({\n * description: 'Write a file to the workspace',\n * progressArgument: 'description',\n * args: z.object({\n * description: z.string().describe('e.g. \"writing index.html\"'),\n * path: z.string(),\n * content: z.string(),\n * }),\n * execute: async (state, args) => { ... },\n * });\n * ```\n */\n progressArgument?: string;\n}\n\n/**\n * Tool definition object returned by defineTool().\n *\n * Contains all the metadata and implementation needed to register\n * and execute a tool.\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 * @template Tenvs - The Zod schema for thread environment variables, or null\n * @template Uses - Readonly array of tool names this tool can invoke\n */\nexport interface ToolDefinition<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n Tenvs extends ToolTenvs | null = null,\n Uses extends readonly string[] = readonly string[],\n> {\n /** Description of what the tool does (shown to the LLM). */\n description: string;\n /** Zod schema for validating tool arguments, or null for no args. */\n args: Args;\n /** The tool implementation function. */\n execute: UsesAwareExecute<State, Args, Uses>;\n /** Declared variables for this tool. */\n variables: VariableDefinition[];\n /**\n * @deprecated Use `variables` instead.\n * Zod schema for thread environment variables, or null if none.\n */\n tenvs: Tenvs;\n /**\n * Where this tool is executed:\n * - 'local': Execute locally by the execution engine (default)\n * - 'provider': Executed by the LLM provider, results come in response\n */\n executionMode?: 'local' | 'provider';\n /**\n * Which provider executes this tool (when executionMode='provider').\n */\n executionProvider?: string;\n /**\n * Explicit list of tools, prompts, or agents this tool can call.\n *\n * When specified with `as const`, TypeScript constrains queueTool()\n * and invokeTool() at compile time. At runtime, attempts to call\n * unlisted items throw an error.\n *\n * This is required for packed tools to ensure namespace isolation.\n * For unpacked tools, it's optional but recommended for clarity.\n *\n * Items can be:\n * - Simple names: Resolve within current namespace\n * - Qualified names (e.g., 'other_pkg:agent'): Cross-package entry point\n */\n uses?: Uses;\n /**\n * The name of an argument carrying a short, human-readable description of what\n * this tool call is doing (e.g. `\"fixing index.html\"`). Controls when the\n * `tool_call_started` hook/event fires — see {@link DefineToolOptions.progressArgument}.\n */\n progressArgument?: string;\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\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), an implementation function, and\n * optional variable requirements.\n *\n * @example\n * ```typescript\n * import { defineTool } from '@standardagents/spec';\n * import { z } from 'zod';\n *\n * // Tool with arguments\n * export default defineTool({\n * description: 'Search the knowledge base for relevant information',\n * args: z.object({\n * query: z.string().describe('Search query'),\n * limit: z.number().optional().describe('Max results'),\n * }),\n * execute: async (state, args) => {\n * const results = await search(args.query, args.limit);\n * return { status: 'success', result: JSON.stringify(results) };\n * },\n * });\n *\n * // Tool without arguments\n * export default defineTool({\n * description: 'Get the current server time',\n * execute: async (state) => {\n * return { status: 'success', result: new Date().toISOString() };\n * },\n * });\n *\n * // Tool with declared variables\n * export default defineTool({\n * description: 'Search through uploaded files',\n * args: z.object({ query: z.string() }),\n * execute: async (state, args) => ({ status: 'success', result: 'done' }),\n * variables: [\n * {\n * name: 'VECTOR_STORE_ID',\n * type: 'text',\n * required: true,\n * description: 'OpenAI Vector Store ID',\n * },\n * ],\n * });\n *\n * // Provider-executed tool (e.g., OpenAI built-in tools)\n * export default defineTool({\n * description: 'Generate images using DALL-E',\n * args: z.object({ prompt: z.string() }),\n * execute: async () => ({ status: 'success', result: 'Handled by provider' }),\n * executionMode: 'provider',\n * executionProvider: 'openai',\n * });\n * ```\n *\n * @param options - Tool definition options\n * @returns A tool definition object\n */\n/**\n * Validate a tool name does not contain reserved characters.\n * Tools are typically defined without a name field (they get the filename),\n * but this can be called by build tools that assign names.\n */\nexport function validateToolName(name: string): void {\n if (name.includes('/')) {\n throw new Error(`Tool name cannot contain '/'. Reserved for namespace qualification.`);\n }\n}\n\nexport function defineTool<\n State = ThreadState,\n Args extends ToolArgs | null = null,\n Tenvs extends ToolTenvs | null = null,\n Uses extends readonly string[] = readonly string[],\n>(\n options: DefineToolOptions<State, Args, Tenvs, Uses>\n): ToolDefinition<State, Args, Tenvs, Uses> {\n const variables =\n (options.variables ?? extractVariablesFromTenvSchema((options.tenvs ?? null) as ToolTenvs | null))\n .map((entry) => ({\n name: entry.name,\n type: (entry.type === 'secret' ? 'secret' : 'text') as VariableType,\n required: !!entry.required,\n description: typeof entry.description === 'string' ? entry.description : '',\n }));\n\n return {\n description: options.description,\n args: (options.args ?? null) as Args,\n execute: options.execute,\n variables,\n tenvs: (options.tenvs ?? null) as Tenvs,\n executionMode: options.executionMode,\n executionProvider: options.executionProvider,\n uses: options.uses,\n progressArgument: options.progressArgument,\n };\n}\n\n/**\n * @deprecated Helper for backward-compatibility with legacy `tenvs`.\n */\nfunction extractVariablesFromTenvSchema(\n tenvSchema: ToolTenvs | null\n): VariableDefinition[] {\n if (!tenvSchema) return [];\n const shape = (tenvSchema as z.ZodObject<any>).shape;\n if (!shape) return [];\n\n return Object.entries(shape).map(([name, fieldSchema]) => {\n const zodSchema = fieldSchema as z.ZodTypeAny;\n return {\n name,\n type: 'text',\n required: !zodSchema.isOptional(),\n description: zodSchema.description ?? '',\n };\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, VariableDefinition, VariableType } 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: StandardAgentSpec.Prompts;\n}\n\n/**\n * An environment variable insertion part.\n *\n * Loads a thread variable by property name at interpolation time.\n */\nexport interface PromptEnvPart {\n type: 'env';\n /** Variable property name to resolve from thread env */\n property: 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 | PromptEnvPart;\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 or agents used as tools.\n * These options control how results from sub-prompts are returned to the caller.\n *\n * @template T - The sub-prompt/agent name type (for type-safe references)\n */\nexport interface SubpromptConfig<T extends string = StandardAgentSpec.Callables> {\n /**\n * Name of the sub-prompt or agent to call.\n * Must be a prompt defined in agents/prompts/ or an agent in agents/agents/.\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 or agent.\n *\n * Autocompletes to fields from the prompt's requiredSchema (or agent's side_a prompt schema).\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?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Property containing attachment path(s) to include as multimodal content\n * when invoking the sub-prompt or agent.\n *\n * Autocompletes to fields from the prompt's requiredSchema (or agent's side_a prompt schema).\n * Supports both a single path string or an array of paths.\n *\n * @example\n * If the tool is called with `{ image: \"/attachments/123.jpg\" }` and\n * `initAttachmentsProperty: 'image'`, the sub-prompt will receive\n * the image as an attachment in the user message.\n *\n * @example\n * If the tool is called with `{ images: [\"/attachments/a.jpg\", \"/attachments/b.jpg\"] }` and\n * `initAttachmentsProperty: 'images'`, the sub-prompt will receive\n * both images as attachments.\n */\n initAttachmentsProperty?: StandardAgentSpec.SchemaFields<T>;\n}\n\n/**\n * @deprecated Use SubpromptConfig instead\n */\nexport type ToolConfig<T extends string = string> = SubpromptConfig<T>;\n\n// ============================================================================\n// Prompt Tool Configuration\n// ============================================================================\n\n/**\n * Configuration for a tool used in a prompt.\n * Allows specifying environment values and static options for the tool.\n *\n * @example\n * ```typescript\n * // Tool with environment values\n * { name: 'file_search', env: { VECTOR_STORE_ID: 'vs_abc123' } }\n *\n * // Tool with options\n * { name: 'web_search', options: { searchContextSize: 'high' } }\n * ```\n */\nexport interface PromptToolConfig {\n /**\n * Name of the tool (custom tool or provider tool).\n */\n name: StandardAgentSpec.Callables;\n\n /**\n * Environment variable values for this tool.\n */\n env?: Record<string, string>;\n /**\n * @deprecated Use `env` instead.\n */\n tenvs?: Record<string, unknown>;\n\n /**\n * Static options for this tool.\n * Passed to the tool handler at execution time.\n */\n options?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Subagent Tool Configuration\n// ============================================================================\n\n/**\n * Configuration for invoking a `dual_ai` agent as a subagent tool.\n *\n * Subagent tools are always autonomous `dual_ai` agents and support both:\n * - Blocking vs non-blocking execution\n * - Resumable vs non-resumable lifecycles\n *\n * Non-resumable subagents behave like normal tool calls.\n * Resumable subagents are created/messaged through runtime-injected lifecycle\n * tools (for example `subagent_create` and `subagent_message`) and tracked in\n * the parent thread registry. The injected `subagent_create` tool MUST require\n * a non-empty human-readable `name` argument and runtimes SHOULD persist it as\n * a child thread display name.\n *\n * ### Persistent invocation arguments\n *\n * The child side that receives parent messages dictates initial invocation\n * arguments through that side's prompt `requiredSchema`\n * (`resumable.receives_messages`, defaulting to `side_a`). The invoking parent\n * supplies them when calling the subagent tool or `subagent_create` as a\n * structured `arguments` object.\n *\n * Unlike a plain tool call, these arguments are NOT ephemeral: runtimes MUST\n * persist the validated arguments for the life of the child thread and make\n * them available to BOTH `side_a` and `side_b` through `ThreadState.arguments`\n * and prompt variable interpolation on every activation. This lets a system\n * prompt reference spawn-time context for as long as the thread lives.\n *\n * If required arguments are missing or invalid, runtimes MUST reject creation\n * with a `subagent_arguments_required` error rather than spawning the child.\n *\n * @example\n * ```typescript\n * {\n * name: 'browser_agent',\n * blocking: false,\n * resumable: {\n * receives_messages: 'side_a',\n * maxInstances: 1,\n * },\n * }\n * ```\n */\nexport interface SubagentToolConfig<\n T extends string = StandardAgentSpec.Callables,\n> {\n /**\n * Agent callable name.\n *\n * Must reference a `dual_ai` agent with `exposeAsTool: true`.\n */\n name: T;\n\n /**\n * Whether parent execution blocks until the subagent returns a result.\n *\n * - `true`: Parent waits for completion (tool-call style)\n * - `false`: Parent continues immediately and receives results asynchronously\n *\n * @default true\n */\n blocking?: boolean;\n\n /**\n * Property from tool-call arguments used as the initial message sent to the\n * subagent on invocation.\n *\n * Uses the same semantics as {@link SubpromptConfig.initUserMessageProperty}.\n */\n initUserMessageProperty?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Property from tool-call arguments containing attachment path(s) that should\n * be sent to the subagent on invocation.\n *\n * Uses the same semantics as {@link SubpromptConfig.initAttachmentsProperty}.\n */\n initAttachmentsProperty?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Property from tool-call arguments used to assign a human-readable name for\n * each spawned child thread instance.\n *\n * Implementations SHOULD store this as a thread tag in the form\n * `name:<value>` so UIs can render a concise per-instance title.\n */\n initAgentNameProperty?: StandardAgentSpec.SchemaFields<T>;\n\n /**\n * Execute this tool immediately when the prompt becomes active.\n *\n * - `true`: Execute immediately using runtime defaults.\n * - Object: Execute immediately with explicit per-instance env relationships.\n *\n * When the object form is used:\n * - `scopedEnv` names the per-instance env values copied into the child thread.\n * - `nameEnv` and `descriptionEnv` identify the only per-instance env values\n * that runtimes may expose to an internal bootstrap model when deriving\n * initial child arguments.\n *\n * Runtimes MUST NOT expose `scopedEnv` values to the model unless the same env\n * name is explicitly designated by `nameEnv` or `descriptionEnv`.\n *\n * Immediate tools run before the first LLM step for that activation.\n */\n immediate?:\n | boolean\n | {\n /**\n * Scoped env name whose value may be used as the safe per-instance name\n * hint for child bootstrap.\n */\n nameEnv?: string;\n\n /**\n * Scoped env name whose value may be used as the safe per-instance\n * description hint for child bootstrap.\n */\n descriptionEnv?: string;\n\n /**\n * Scoped env names that should be copied into the child thread for each\n * immediate instance group.\n */\n scopedEnv?: string[];\n };\n\n /**\n * Optional branch flag env name.\n *\n * When set, this subagent is only enabled when the named env resolves to\n * `true`, `1`, or `yes` (case-insensitive).\n */\n optional?: string;\n\n /**\n * Resumability configuration.\n *\n * - `false` (default): Non-resumable subagent\n * - Object: Resumable subagent with message routing and instance limits\n *\n * When resumable mode is enabled, runtimes SHOULD provide a built-in create\n * and message lifecycle interface instead of exposing raw agent callables for\n * new instance creation.\n */\n resumable?:\n | false\n | {\n /**\n * Which side of the child `dual_ai` conversation receives parent messages.\n *\n * - `side_a`: Messages are queued as `role: 'user'`\n * - `side_b`: Messages are queued as `role: 'assistant'`\n */\n receives_messages: 'side_a' | 'side_b';\n\n /**\n * Maximum concurrent instances for this subagent tool.\n *\n * When reached, implementations may remove this tool from subsequent LLM\n * requests and route new messages to existing instances.\n *\n * @default unlimited\n */\n maxInstances?: number;\n\n /**\n * How this child reports back to its parent.\n *\n * - `implicit` (default): Child completion is automatically queued to the parent.\n * - `explicit`: The runtime does not auto-queue child completion; tools/hooks may\n * use thread APIs such as `state.notifyParent()` or `state.stopSession()` when\n * they choose to escalate or terminally end the session.\n */\n parentCommunication?: 'implicit' | 'explicit';\n };\n\n /**\n * How this subagent reports completion back to its parent. Applies to\n * non-resumable subagents; resumable subagents may instead set\n * `resumable.parentCommunication`, which takes precedence when present.\n *\n * - `implicit` (default): the child's completion is auto-queued to the parent,\n * which triggers a parent turn.\n * - `explicit`: the runtime does NOT auto-queue the child's completion, so the\n * parent is not woken. Use for background subagents that deliver their result\n * another way (e.g. writing to the parent's thread KV) and should be \"picked\n * up\" on the parent's next natural turn rather than forcing one.\n */\n parentCommunication?: 'implicit' | 'explicit';\n\n /**\n * Hide this subagent tool from the LLM's tool list while keeping the\n * relationship declared, so runtime code (hooks calling\n * `state.invokeTool()` / `queueTool()`) can still spawn it. Use for\n * infrastructure subagents the model must never call itself (e.g. a\n * background context-compaction agent).\n *\n * @default false\n */\n hidden?: boolean;\n}\n\n// ============================================================================\n// Reasoning Configuration\n// ============================================================================\n\n/**\n * Reasoning configuration for models that support extended thinking.\n * Applies to models like OpenAI o1/o3, Anthropic Claude with extended thinking,\n * Google Gemini with thinking, and Qwen with reasoning.\n */\nexport interface ReasoningConfig {\n /**\n * Numeric reasoning level on a 0-100 scale.\n * The FlowEngine maps this to the model's nearest supported reasoning option.\n *\n * @example\n * // Typical breakpoints:\n * // 0 = No reasoning\n * // 33 = Low effort\n * // 66 = Medium effort\n * // 100 = Maximum effort\n *\n * reasoning: { level: 75 } // Maps to 'high' on most models\n */\n level?: number;\n\n /**\n * @deprecated Use `level` instead. Will be removed in future versions.\n *\n * Effort level for reasoning models.\n * Higher effort = more thinking tokens = potentially better results.\n *\n * - `low`: Minimal reasoning, faster responses (equivalent to level ~33)\n * - `medium`: Balanced reasoning and speed (equivalent to level ~66)\n * - `high`: Maximum reasoning, slower but more thorough (equivalent to level ~100)\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: StandardAgentSpec.Models;\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 * When this prompt is the `side_a` prompt of a `dual_ai` agent exposed as a\n * subagent, this schema also dictates the invocation arguments accepted by\n * the subagent tool (and the runtime-injected `subagent_create` tool).\n * Required fields are mandatory; optional fields are treated as suggested.\n * Runtimes persist the validated arguments for the life of the child thread\n * and expose them to both sides' prompt interpolation (see\n * {@link SubagentToolConfig} \"Persistent invocation arguments\").\n */\n requiredSchema?: S;\n\n /**\n * Declared variables for this prompt.\n */\n variables?: VariableDefinition[];\n\n /**\n * Tools available to this prompt.\n * Can be:\n * - string: Simple tool name (custom or provider tool)\n * - SubpromptConfig: Sub-prompt used as a tool\n * - PromptToolConfig: Tool with environment values and/or options\n * - SubagentToolConfig: `dual_ai` subagent invocation behavior\n *\n * To enable handoffs, include ai_human agent names in this array.\n *\n * @example\n * ```typescript\n * tools: [\n * 'custom_tool', // Simple tool name\n * { name: 'other_prompt' }, // Sub-prompt as tool\n * { name: 'file_search', env: { VECTOR_STORE_ID: 'vs_123' } }, // Tool with env values\n * ]\n * ```\n */\n tools?: (\n | StandardAgentSpec.Callables\n | SubpromptConfig\n | PromptToolConfig\n | SubagentToolConfig\n )[];\n\n /**\n * Environment values provided by this prompt.\n * Prompt values override user-account and AgentBuilder-instance defaults.\n * Agent and thread values override prompt values.\n */\n env?: Record<string, string>;\n /**\n * @deprecated Use `env` instead.\n */\n tenvs?: Record<string, unknown>;\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 * Provider-specific options passed through to the provider.\n * These override model-level providerOptions for this prompt.\n *\n * Options are merged in order (later wins):\n * 1. model.providerOptions (defaults)\n * 2. prompt.providerOptions (this field - overrides)\n *\n * @example\n * ```typescript\n * providerOptions: {\n * response_format: { type: 'json_object' },\n * }\n * ```\n */\n providerOptions?: Record<string, unknown>;\n\n /**\n * Hook IDs to run when this prompt is active.\n * References hooks by their unique `id` property from defineHook().\n * If not specified, falls back to agent-level hooks.\n *\n * @example\n * ```typescript\n * hooks: ['limit_to_20_messages', 'log_tool_calls']\n * ```\n */\n hooks?: StandardAgentSpec.HookIds[];\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.name.includes('/')) {\n throw new Error(`Prompt name cannot contain '/'. Reserved for namespace qualification.`);\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 configuration\n if (options.reasoning) {\n // Validate level is 0-100 if provided\n if (options.reasoning.level !== undefined) {\n if (typeof options.reasoning.level !== 'number' || options.reasoning.level < 0 || options.reasoning.level > 100) {\n throw new Error('reasoning.level must be a number between 0 and 100');\n }\n }\n\n // Validate effort is a known value (deprecated but still supported)\n if (options.reasoning.effort && !['low', 'medium', 'high'].includes(options.reasoning.effort)) {\n throw new Error(\n `Invalid reasoning.effort '${options.reasoning.effort}'. Must be one of: low, medium, high`\n );\n }\n\n // Warn if both level and effort are provided\n if (options.reasoning.level !== undefined && options.reasoning.effort !== undefined) {\n console.warn('Both reasoning.level and reasoning.effort provided. level takes precedence. effort is deprecated.');\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 const normalizedVariables = Array.isArray(options.variables)\n ? options.variables.map((entry) => ({\n name: entry.name,\n type: (entry.type === 'secret' ? 'secret' : 'text') as VariableType,\n required: !!entry.required,\n scoped: !!entry.scoped,\n description: typeof entry.description === 'string' ? entry.description : '',\n }))\n : undefined;\n\n return {\n ...options,\n ...(normalizedVariables ? { variables: normalizedVariables } : {}),\n };\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';\nimport type { ToolAttachment, AttachmentRef } from './tools.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({\n * hook: 'filter_messages',\n * id: 'keep_recent',\n * execute: async (state, messages) => {\n * console.log(`Thread: ${state.threadId}`);\n * if (state.execution) {\n * console.log(`Step: ${state.execution.stepCount}`);\n * }\n * return messages.slice(-10);\n * },\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 * 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 attachments?: Array<ToolAttachment | AttachmentRef>;\n}\n\n/**\n * LLM message format for prefilter hook.\n *\n * Messages passed to the prefilter_llm_history hook are in chat completion\n * format. Content can be a plain string or a multimodal array (for messages\n * with images). Additional provider-specific fields may also be present.\n */\nexport interface LLMMessage {\n /** Message role */\n role: string;\n /** Message content (string for text-only, array for multimodal) */\n content?: string | null | unknown[];\n /** Tool calls (parsed) */\n tool_calls?: unknown;\n /** Tool call ID */\n tool_call_id?: string;\n /** Tool name */\n name?: string;\n /** Reasoning content (for models like o1) */\n reasoning_content?: string;\n /** Allow additional provider-specific fields */\n [key: string]: unknown;\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 after a thread is created, before initial message processing or LLM\n * requests for that thread.\n *\n * Only ThreadState is passed. Use for initializing durable thread values,\n * env placeholders, files, or side-effect instrumentation.\n *\n * @param state - Created thread state\n */\n after_thread_created: (state: State) => Promise<void>;\n\n /**\n * Called on the parent thread immediately after a subagent child thread is\n * created.\n *\n * Receives parent ThreadState and child ThreadState. Use for copying or\n * linking metadata, bookkeeping, or side-effect instrumentation.\n *\n * @param state - Parent thread state\n * @param childState - Created child thread state\n */\n after_subagent_created: (state: State, childState: State) => Promise<void>;\n\n /**\n * Called after the prompt system message is rendered for a model request.\n *\n * Return a string to replace the rendered system message. Return null or\n * undefined to keep the original message.\n *\n * @param state - Thread state\n * @param systemMessage - Rendered system message for this request\n * @returns Replacement system message, or null/undefined for no change\n */\n after_system_message: (\n state: State,\n systemMessage: string\n ) => string | Promise<string | null | undefined> | null | undefined;\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({\n * hook: 'filter_messages',\n * id: 'limit_to_10',\n * execute: async (state, messages) => 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({\n * hook: 'prefilter_llm_history',\n * id: 'add_reminder',\n * execute: async (state, messages) => 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 full message object before insertion. Return modified\n * message to transform before storage.\n *\n * @param state - Thread state\n * @param message - Message to be created\n * @returns Modified message\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'before_create_message',\n * id: 'prefix_content',\n * execute: async (state, message) => {\n * // message has full type: id, role, content, created_at, etc.\n * if (message.role === 'user' && message.content) {\n * return { ...message, content: `[user] ${message.content}` };\n * }\n * return message;\n * }\n * });\n * ```\n */\n before_create_message: (\n state: State,\n message: Msg\n ) => Promise<Msg>;\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\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'after_create_message',\n * id: 'log_creation',\n * execute: async (state, message) => {\n * console.log(`Created ${message.role} message: ${message.id}`);\n * }\n * });\n * ```\n */\n after_create_message: (\n state: State,\n message: Msg\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({\n * hook: 'before_update_message',\n * id: 'stamp_updated_at',\n * execute: async (state, messageId, updates) => ({\n * ...updates,\n * updated_at: Date.now(),\n * }),\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({\n * hook: 'after_update_message',\n * id: 'log_update',\n * execute: async (state, message) => {\n * console.log(`Message updated: ${message.id}`);\n * },\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\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'before_store_tool_result',\n * id: 'sanitize_results',\n * execute: async (state, toolCall, toolResult) => {\n * // toolCall has: id, type, function.name, function.arguments\n * // toolResult has: status, result?, error?, stack?, attachments?\n * if (toolResult.result) {\n * return { ...toolResult, result: sanitize(toolResult.result) };\n * }\n * return toolResult;\n * }\n * });\n * ```\n */\n before_store_tool_result: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult>;\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({\n * hook: 'after_tool_call_success',\n * id: 'log_success',\n * execute: async (state, toolCall, toolResult) => {\n * console.log(`Tool ${toolCall.function.name} succeeded`);\n * return null; // use original result\n * },\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({\n * hook: 'after_tool_call_failure',\n * id: 'log_failure',\n * execute: async (state, toolCall, toolResult) => {\n * console.error(`Tool ${toolCall.function.name} failed: ${toolResult.error}`);\n * return null; // use original error\n * },\n * });\n * ```\n */\n after_tool_call_failure: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<ToolResult | null>;\n\n /**\n * Called when a tool call STARTS — before the tool executes, while the model\n * may still be generating the rest of the call. Fires exactly once per tool\n * call. Observational: the return value is ignored.\n *\n * Timing depends on whether the tool declares a `progressArgument`:\n * - **With** `progressArgument`: fires as soon as *just that argument* has\n * finished streaming (not the whole call), passing its value as `progress`.\n * This lets a UI show \"fixing index.html\" before a large `content` argument\n * finishes generating.\n * - **Without** `progressArgument`: fires as soon as the tool call appears in\n * the stream — its name is known but `toolCall.function.arguments` may be an\n * incomplete JSON fragment (or empty), and `progress` is undefined.\n *\n * Conforming runtimes also broadcast a `tool_call_started` thread event to\n * connected clients with `{ id, name, progress }` at the same moment.\n *\n * @param state - Thread state\n * @param toolCall - The starting tool call; `function.arguments` may be incomplete\n * @param progress - The declared progress-argument value, when available\n *\n * @example\n * ```typescript\n * defineHook({\n * hook: 'tool_call_started',\n * id: 'log_tool_start',\n * execute: async (state, toolCall, progress) => {\n * console.log(`▸ ${toolCall.function.name}${progress ? `: ${progress}` : ''}`);\n * },\n * });\n * ```\n */\n tool_call_started: (\n state: State,\n toolCall: ToolCall,\n progress?: string\n ) => Promise<void>;\n\n /**\n * Called when a tool call is DONE — after it has executed, with its result,\n * regardless of success or failure. Fires once per tool call. Observational:\n * the return value is ignored.\n *\n * This complements `after_tool_call_success` / `after_tool_call_failure`,\n * which can additionally *modify* the stored result; `tool_call_done` is a\n * single unified observation point that always fires. Conforming runtimes\n * also broadcast a `tool_call_done` thread event to connected clients with\n * `{ id, name, status }` at the same moment.\n *\n * @param state - Thread state\n * @param toolCall - The completed tool call\n * @param toolResult - The tool's result (`status` is `'success'` or `'error'`)\n */\n tool_call_done: (\n state: State,\n toolCall: ToolCall,\n toolResult: ToolResult\n ) => Promise<void>;\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 * @deprecated Use the object-based defineHook signature instead\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// Hook Definition Options (NEW)\n// ============================================================================\n\n/**\n * Options for defining a hook with explicit ID.\n * The generic K ensures `execute` is properly typed for the specific hook type.\n *\n * @template K - Hook type from HookSignatures (e.g., 'filter_messages')\n */\nexport interface HookDefinitionOptions<K extends HookName> {\n /** The hook type (e.g., 'filter_messages', 'before_create_message') */\n hook: K;\n /** Unique identifier for this hook implementation (snake_case) */\n id: string;\n /**\n * The hook implementation function.\n * Type is automatically inferred from the hook type.\n */\n execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];\n}\n\n/**\n * Return type from defineHook - preserves the hook type for type-safe usage.\n *\n * @template K - Hook type from HookSignatures\n */\nexport interface HookDefinitionResult<K extends HookName> {\n /** The hook type name */\n hook: K;\n /** The unique hook ID */\n id: string;\n /** The typed execute function */\n execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];\n}\n\n// ============================================================================\n// Define Function\n// ============================================================================\n\n/**\n * Valid hook names for runtime validation\n */\nconst VALID_HOOKS: HookName[] = [\n 'after_thread_created',\n 'after_subagent_created',\n 'after_system_message',\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 'tool_call_started',\n 'tool_call_done',\n];\n\n/**\n * Define a hook with a unique identifier and strict typing.\n *\n * The hook type determines the execute function signature.\n * TypeScript will enforce correct parameter and return types.\n *\n * @template K - The hook type (inferred from options.hook)\n * @param options - Hook definition with hook type, ID, and execute function\n * @returns Typed hook definition for registration\n *\n * @example\n * ```typescript\n * // Filter messages - execute receives (state: ThreadState, messages: HookMessage[])\n * export default defineHook({\n * hook: 'filter_messages',\n * id: 'limit_to_20_messages',\n * execute: async (state, messages) => {\n * return messages.slice(-20);\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Before create message - execute receives (state: ThreadState, message: Message)\n * export default defineHook({\n * hook: 'before_create_message',\n * id: 'prefix_content',\n * execute: async (state, message) => {\n * if (message.role === 'user' && message.content) {\n * return { ...message, content: `[user] ${message.content}` };\n * }\n * return message;\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // After tool call success - execute receives (state, toolCall, toolResult)\n * export default defineHook({\n * hook: 'after_tool_call_success',\n * id: 'log_tool_usage',\n * execute: async (state, toolCall, toolResult) => {\n * console.log(`Tool ${toolCall.function.name} returned: ${toolResult.result}`);\n * return null; // Use original result\n * }\n * });\n * ```\n */\nexport function defineHook<K extends HookName>(\n options: HookDefinitionOptions<K>\n): HookDefinitionResult<K> {\n // Validate hook name at runtime\n if (!VALID_HOOKS.includes(options.hook)) {\n throw new Error(\n `Invalid hook type '${options.hook}'. Valid hooks: ${VALID_HOOKS.join(', ')}`\n );\n }\n\n if (!options.id || typeof options.id !== 'string') {\n throw new Error('Hook id is required and must be a non-empty string');\n }\n\n // Validate id format (snake_case)\n if (!/^[a-z][a-z0-9_]*$/.test(options.id)) {\n throw new Error(\n `Hook id '${options.id}' must be snake_case (lowercase letters, numbers, underscores, starting with letter)`\n );\n }\n\n return {\n hook: options.hook,\n id: options.id,\n execute: options.execute,\n };\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 whichever scheduling mechanism the runtime provides.\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 a session lifecycle tool.\n *\n * Used by side-level lifecycle options (`sessionStop`, `sessionFail`, `sessionStatus`)\n * to declare:\n * - which tool controls that lifecycle action\n * - which tool-argument field should be forwarded as message text\n * - which tool-argument field contains attachment path(s) to forward\n *\n * @template Callable - Callable name type\n */\nexport interface SessionToolConfig<\n Callable extends string = StandardAgentSpec.Callables,\n> {\n /**\n * Tool name for this session lifecycle action.\n */\n name: Callable;\n\n /**\n * Optional tool-argument property used as lifecycle message text.\n */\n messageProperty?: string;\n\n /**\n * Optional tool-argument property containing attachment path(s).\n * Supports a single path string or an array of path strings.\n */\n attachmentsProperty?: string;\n}\n\n/**\n * Session lifecycle tool reference.\n *\n * Can be either:\n * - a plain tool name string (legacy/simple form)\n * - a {@link SessionToolConfig} object (explicit mapping form)\n */\nexport type SessionToolBinding<\n Callable extends string = StandardAgentSpec.Callables,\n> = Callable | SessionToolConfig<Callable>;\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 = StandardAgentSpec.Prompts,\n Callable extends string = StandardAgentSpec.Callables,\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 *\n * Different from stopTool: this ends the session for both sides,\n * not just this side's turn.\n *\n * Use object form to explicitly map message/attachment argument fields.\n *\n * In subagent runtimes, mapped message/attachments are the canonical\n * completion payload returned from child -> parent.\n */\n sessionStop?: SessionToolBinding<Callable>;\n\n /**\n * Tool that fails the entire session when called.\n *\n * Use this when the side cannot fulfill the request and needs to terminate\n * the session with an error outcome.\n *\n * When used inside a subagent, this failure is propagated back to the parent\n * as a terminal failure result.\n *\n * Use object form to explicitly map message/attachment argument fields.\n *\n * In subagent runtimes, mapped message/attachments are the canonical\n * failure payload returned from child -> parent.\n */\n sessionFail?: SessionToolBinding<Callable>;\n\n /**\n * Tool that publishes status updates to the parent thread when used as a subagent.\n *\n * When called from a `dual_ai` subagent, message text is forwarded to\n * the parent thread's subagent registry as this instance's current status.\n *\n * Use object form to explicitly map message/attachment argument fields.\n *\n * Status updates do not terminate the session.\n *\n * @example\n * ```typescript\n * sideA: {\n * prompt: 'research_worker',\n * sessionStatus: { name: 'update_status', messageProperty: 'status' },\n * }\n * ```\n */\n sessionStatus?: SessionToolBinding<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 = StandardAgentSpec.Prompts,\n Callable extends string = StandardAgentSpec.Callables,\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 * Environment values provided by this agent.\n * Agent values are lower priority than thread/account/instance values.\n */\n env?: Record<string, string>;\n\n /**\n * @deprecated Use `env` instead.\n */\n tenvs?: Record<string, unknown>;\n\n // ============================================================================\n // Package Metadata (for packing/unpacking)\n // ============================================================================\n\n /**\n * npm package name for this agent when packed.\n * Used by the packing system to maintain consistent package identity\n * across pack/unpack cycles.\n *\n * @example 'standardagent-support-agent', '@myorg/support-agent'\n */\n packageName?: string;\n\n /**\n * Package version (semver format).\n * Used by the packing system to track versions across pack/unpack cycles.\n * When re-packing, this version is auto-incremented by the pack modal.\n *\n * @example '1.0.0', '2.3.1-beta.1'\n */\n version?: string;\n\n /**\n * Package author/copyright holder.\n * Used by the packing system for the LICENSE file and package.json author field.\n *\n * @example 'John Doe', 'Acme Corp'\n */\n author?: string;\n\n /**\n * License identifier (SPDX format).\n * Used by the packing system for LICENSE file generation.\n *\n * @example 'MIT', 'Apache-2.0', 'ISC'\n */\n license?: string;\n\n /**\n * Hook IDs to run for this agent.\n * References hooks by their unique `id` property from defineHook().\n * These run when prompts don't specify their own hooks.\n *\n * @example\n * ```typescript\n * hooks: ['log_messages', 'track_tool_usage']\n * ```\n */\n hooks?: StandardAgentSpec.HookIds[];\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 * sessionStop: '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 * sessionStop: 'conclude_debate',\n * },\n * });\n * ```\n */\nexport function defineAgent<N extends string>(\n options: AgentDefinition<N>\n): AgentDefinition<N> {\n const validateSessionBinding = (\n sideLabel: 'sideA' | 'sideB',\n sessionKey: 'sessionStop' | 'sessionFail' | 'sessionStatus',\n ): void => {\n const side = options[sideLabel];\n if (!side) return;\n\n const sessionBinding = side[sessionKey];\n\n if (\n typeof sessionBinding === 'object' &&\n sessionBinding !== null &&\n !Array.isArray(sessionBinding)\n ) {\n if (!('name' in sessionBinding) || typeof sessionBinding.name !== 'string' || !sessionBinding.name) {\n throw new Error(`${sideLabel}.${sessionKey}.name is required when ${sideLabel}.${sessionKey} uses object form`);\n }\n }\n };\n\n // Validate required fields at runtime\n if (!options.name) {\n throw new Error('Agent name is required');\n }\n if (options.name.includes('/')) {\n throw new Error(`Agent name cannot contain '/'. Reserved for namespace qualification.`);\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 validateSessionBinding('sideA', 'sessionStop');\n validateSessionBinding('sideA', 'sessionFail');\n validateSessionBinding('sideA', 'sessionStatus');\n if (options.sideB) {\n validateSessionBinding('sideB', 'sessionStop');\n validateSessionBinding('sideB', 'sessionFail');\n validateSessionBinding('sideB', 'sessionStatus');\n }\n\n return {\n ...options,\n type,\n };\n}\n","/**\n * Thread state types for Standard Agents.\n *\n * ThreadState is the unified interface for all thread operations.\n * It provides access to thread identity, messages, logs, resource loading,\n * tool invocation, event emission, and execution state.\n *\n * @module\n */\n\nimport type {\n ToolResult,\n ToolAttachment,\n AttachmentRef,\n} from './tools.js';\nimport type { ScheduledEffect } from './effects.js';\nimport type { SkillsNamespace } from './skills.js';\n\n// ============================================================================\n// Thread Identity\n// ============================================================================\n\n/**\n * Metadata about a thread.\n *\n * This represents the core identity of a thread, separate from its\n * operational state. Thread metadata is immutable after creation.\n */\n/**\n * The profile of the user a thread belongs to, as exposed by\n * {@link ThreadState.user}. Identity fields only — never credentials.\n */\nexport interface ThreadUser {\n id: string;\n username: string;\n /** 'admin' | 'user' | 'api' in the reference runtime. */\n role: string;\n /** Explicit permission grants (runtime-defined strings), if any. */\n permissions?: string[] | null;\n email?: string | null;\n display_name?: string | null;\n avatar_url?: string | null;\n}\n\nexport interface ThreadMetadata {\n /** Unique identifier for the thread */\n id: string;\n /** Agent that owns this thread */\n agent_id: string;\n /** User associated with this thread (if any) */\n user_id: string | null;\n /** Creation timestamp (microseconds since epoch) */\n created_at: number;\n}\n\n/**\n * Registry entry for a subagent child thread.\n */\nexport interface SubagentRegistryEntry {\n /** Child thread UUID used as stable reference address */\n reference: string;\n /** Child agent name */\n name: string;\n /** Child agent title (human-readable) */\n title?: string;\n /** Tool description shown to the parent LLM */\n description: string;\n /** Whether this subagent instance is resumable */\n resumable?: boolean;\n /** Whether parent execution blocks on this subagent */\n blocking?: boolean;\n /** Optional human-readable thread name (for example from `name:` tag) */\n threadName?: string;\n /**\n * Initial argument values supplied when the child was created.\n *\n * For resumable subagents, these values persist for the lifetime of the\n * child thread and are visible to both child sides. Runtimes SHOULD source\n * this object from the receiving side's prompt argument schema. The registry\n * copy is parent-visible metadata; the durable child-side source SHOULD live\n * with the child thread metadata/properties and be restored into\n * `ThreadState.arguments` during execution and endpoint access. Top-level\n * keys SHOULD also be exposed to prompt variable interpolation for whichever\n * child side is currently rendering.\n */\n initialArguments?: Record<string, unknown>;\n /** Spawn group identifier used for grouping instances created together */\n spawnGroupId?: string;\n /** Instance creation timestamp (microseconds) */\n createdAt?: number;\n /** Current status (`running`, `idle`, `terminated`, or custom text) */\n status: string;\n /** How this child reports information back to its parent thread */\n parentCommunication?: 'implicit' | 'explicit';\n}\n\n// ============================================================================\n// Message Types\n// ============================================================================\n\n/**\n * Options for retrieving messages.\n */\nexport interface GetMessagesOptions {\n /** Maximum number of messages to return */\n limit?: number;\n /** Number of messages to skip */\n offset?: number;\n /** Sort order ('asc' for oldest first, 'desc' for newest first) */\n order?: 'asc' | 'desc';\n /** Include silent messages (not shown in UI) */\n includeSilent?: boolean;\n /** Maximum nesting depth for sub-prompt messages */\n maxDepth?: number;\n}\n\n/**\n * Result of a message query.\n */\nexport interface MessagesResult {\n /** Array of messages */\n messages: Message[];\n /** Total number of messages matching the query */\n total: number;\n /** Whether there are more messages available */\n hasMore: boolean;\n}\n\n/**\n * A message in the thread conversation.\n */\nexport interface Message {\n /** Unique message identifier */\n id: string;\n /** Message role */\n role: 'system' | 'user' | 'assistant' | 'tool';\n /** Message content (null for tool calls without text) */\n content: string | null;\n /** Tool name (for tool result messages) */\n name?: string | null;\n /** JSON-encoded array of tool calls (for assistant messages) */\n tool_calls?: string | null;\n /** Tool call ID (for tool result messages) */\n tool_call_id?: string | null;\n /** Creation timestamp (microseconds since epoch) */\n created_at: number;\n /** Parent message ID (for sub-prompt messages) */\n parent_id?: string | null;\n /** Nesting depth (0 for top-level messages) */\n depth?: number;\n /** Whether this message is silent (not shown in UI) */\n silent?: boolean;\n /**\n * Custom metadata.\n *\n * Runtimes may attach lifecycle metadata for synthesized status messages\n * (for example: `status_kind`, `subagent_event`). Message APIs may also\n * mark send-message and durable queue entries with `queued: true` until\n * they are injected into stored history.\n */\n metadata?: Record<string, unknown>;\n /** Message processing status */\n status?: 'pending' | 'completed' | 'failed' | null;\n /** Tool execution status (for tool result messages) */\n tool_status?: 'success' | 'error' | null;\n /** Subagent reference UUID associated with this message */\n subagent_id?: string | null;\n /** Subagent agent name projected from runtime registry (when available) */\n subagent_name?: string | null;\n /** Subagent agent title projected from runtime registry (when available) */\n subagent_title?: string | null;\n /** Subagent description projected from runtime registry (when available) */\n subagent_description?: string | null;\n /** Subagent status projected from runtime registry (when available) */\n subagent_status?: string | null;\n /** Whether the associated subagent is resumable (when available) */\n subagent_resumable?: boolean | null;\n /** Whether the associated subagent is blocking (when available) */\n subagent_blocking?: boolean | null;\n /** Optional subagent instance thread name (when available) */\n subagent_thread_name?: string | null;\n /** Spawn group identifier for related subagent instances (when available) */\n subagent_spawn_group_id?: string | null;\n}\n\n/**\n * Input for injecting a new message.\n */\nexport interface InjectMessageInput {\n /** Message role */\n role: 'user' | 'assistant' | 'system';\n /** Message content */\n content: string;\n /** Whether to hide from UI */\n silent?: boolean;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Input for queueing a message for delivery on the thread's next step.\n *\n * Role mapping follows dual_ai conventions:\n * - `assistant` maps to side_a\n * - `user` maps to side_b\n */\nexport interface QueueMessageInput {\n /** Message role (`user` queues side_b perspective, `assistant` queues side_a perspective) */\n role: 'user' | 'assistant';\n /** Message content */\n content: string;\n /** Optional file attachments (new files or existing refs) */\n attachments?: Array<ToolAttachment | AttachmentRef>;\n /** Whether to hide the queued message from normal UI display */\n silent?: boolean;\n /** Optional structured metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Updates to apply to an existing message.\n */\nexport interface MessageUpdates {\n /** New content */\n content?: string;\n /** Updated metadata (merged with existing) */\n metadata?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Thread Message-Stream Events (client-facing WebSocket)\n// ============================================================================\n//\n// The thread message stream — `GET /api/threads/:id/stream` (WebSocket) —\n// broadcasts JSON events as a turn executes. Each socket may set a `depth`\n// preference; events deeper than it (subagents) are filtered out. Documented\n// here so every client (first-party SDKs, the CLI, third parties) shares one\n// contract for the streaming channels below.\n\n/**\n * A streamed fragment of an assistant message's *visible content*.\n *\n * Always broadcast (no opt-in). Clients accumulate `chunk`s by `message_id` to\n * render the answer as it generates; the authoritative final content still\n * arrives separately as a persisted message.\n */\nexport interface ThreadMessageChunkEvent {\n type: 'message_chunk';\n /** The assistant message these fragments belong to. */\n message_id: string;\n /** Message depth: 0 = top-level thread, 1+ = subagent. */\n depth: number;\n /** The next fragment of visible content. */\n chunk: string;\n}\n\n/**\n * A streamed fragment of a model's *internal reasoning* (chain-of-thought).\n *\n * OPT-IN. Unlike content, reasoning is private by default: it is only sent to\n * sockets that explicitly subscribe by connecting with the\n * {@link THREAD_STREAM_REASONING_PARAM} query parameter set to a truthy value\n * (e.g. `?reasoning=1`). Standard SDK consumers therefore never receive it\n * unless they opt in.\n *\n * Reasoning is ephemeral *display* output: it is streamed for live presentation\n * only and is NOT persisted as part of the assistant message content, so it\n * cannot be replayed from message history — a client that wants it must be\n * subscribed while the turn runs.\n */\nexport interface ThreadReasoningChunkEvent {\n type: 'reasoning_chunk';\n /** The assistant message this reasoning accompanies. */\n message_id: string;\n /** Message depth: 0 = top-level thread, 1+ = subagent. */\n depth: number;\n /** The next fragment of internal reasoning. */\n chunk: string;\n}\n\n/**\n * Query-parameter name a client sets (truthy) on the thread stream WebSocket to\n * opt into receiving {@link ThreadReasoningChunkEvent}s. Absent/falsey means the\n * server never emits reasoning to that socket.\n */\nexport const THREAD_STREAM_REASONING_PARAM = 'reasoning';\n\n// ============================================================================\n// File System Types\n// ============================================================================\n\n/**\n * Storage location identifier.\n *\n * Implementations define their own storage identifiers (e.g., 'local', 'cloud', 's3').\n * The spec does not mandate specific storage backends.\n */\nexport type FileStorage = string;\n\n/**\n * Record representing a file in the thread's file system.\n */\nexport interface FileRecord {\n /** File path (relative to thread root) */\n path: string;\n /** File name */\n name: string;\n /** MIME type */\n mimeType: string;\n /** Storage location */\n storage: FileStorage;\n /** File size in bytes */\n size: number;\n /** Whether this is a directory */\n isDirectory: boolean;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n /** Image width in pixels (if applicable) */\n width?: number;\n /** Image height in pixels (if applicable) */\n height?: number;\n /** Creation timestamp */\n createdAt?: number;\n /** Last modified timestamp */\n updatedAt?: number;\n}\n\n/**\n * Options for writing a file.\n */\nexport interface WriteFileOptions {\n /** Custom metadata to attach to the file */\n metadata?: Record<string, unknown>;\n /** Image width in pixels (if applicable) */\n width?: number;\n /** Image height in pixels (if applicable) */\n height?: number;\n}\n\n/**\n * Result of reading a directory.\n */\nexport interface ReaddirResult {\n /** Files and directories in the path */\n entries: FileRecord[];\n}\n\n/**\n * Statistics about the thread's file system.\n */\nexport interface FileStats {\n /** Total number of files */\n fileCount: number;\n /** Total number of directories */\n directoryCount: number;\n /** Total size in bytes */\n totalSize: number;\n}\n\n/**\n * Result of a grep search.\n */\nexport interface GrepResult {\n /** File path */\n path: string;\n /** Matching lines */\n matches: Array<{\n line: number;\n content: string;\n }>;\n}\n\n/**\n * Result of a find operation.\n */\nexport interface FindResult {\n /** Matching file paths */\n paths: string[];\n}\n\n/**\n * Options for streaming file reads.\n */\nexport interface ReadFileStreamOptions {\n /**\n * Abort signal for cancellation.\n *\n * When signaled, the stream stops yielding new chunks.\n * Already-yielded chunks remain valid.\n */\n signal?: AbortSignal;\n}\n\n/**\n * A chunk of file data from a streaming read.\n */\nexport interface FileChunk {\n /** Raw binary data for this chunk */\n data: Uint8Array;\n /** 0-based index of this chunk */\n index: number;\n /** Total number of chunks (1 for small files) */\n totalChunks: number;\n /** Whether this is the final chunk */\n isLast: boolean;\n}\n\n// ============================================================================\n// Code Execution\n// ============================================================================\n\n/**\n * Options passed to {@link ThreadState.runCode}.\n *\n * Code execution is strictly capability-based: the sandbox starts with no\n * ambient capabilities (no `fs`, no `fetch`, no `console`, no host globals).\n * Every capability the sandbox needs must be bridged in explicitly through\n * `imports` or `globals`.\n *\n * Deadlines are **not** an option. Callers impose their own by calling\n * `handle.terminate()` on the returned {@link CodeExecution}.\n *\n * See the [Code Execution specification](https://standardagentspec.com/0.1.0/specification/threads/code-execution)\n * for the full contract.\n */\nexport interface CodeExecutionOptions {\n /**\n * Export to execute from the evaluated module and arguments to pass.\n *\n * By default, runtimes execute the module's `default` export with no\n * arguments. If the selected export is a function, it is called with\n * `args` and the returned value or promise is used as the run result. If the\n * selected export is not a function, `args` MUST be omitted or empty and the\n * export value itself becomes the result.\n *\n * @default { fn: 'default', args: [] }\n *\n * @example\n * ```ts\n * execute: { fn: 'increment', args: [100] }\n * ```\n */\n execute?: {\n /** Export name to execute. Use `'default'` for the default export. */\n fn?: string;\n /** Arguments passed to the selected export when it is a function. */\n args?: unknown[];\n };\n\n /**\n * Map of bare module specifier → named exports exposed to the sandbox.\n *\n * Only bare specifiers resolve from `imports` (e.g., `'fs'`,\n * `'@scope/pkg'`). Relative specifiers resolve only from `modules`; URL\n * (`'https://…'`) imports MUST fail at link time.\n *\n * The key `default` within a namespace becomes that module's default export.\n *\n * @example\n * ```ts\n * imports: {\n * fs: { readFile: (path) => state.readFile(path) },\n * supervisor: { report: (payload) => telemetry.push(payload) },\n * }\n * ```\n */\n imports?: Record<string, Record<string, unknown>>;\n\n /**\n * Additional relative ES modules available to the sandbox.\n *\n * Keys are relative module specifiers from the module graph root, such as\n * `'./helpers.js'` or `'./lib/math.js'`. Entry source imports resolve from\n * `filename` when one is supplied. Entry and module source may import sibling\n * or parent modules with `./` and `../` specifiers when those imports resolve\n * within the supplied module graph. Values are JavaScript or TypeScript module\n * source. Use this when a caller wants the entry source to import local files\n * while still keeping all modules inside the sandbox.\n */\n modules?: Record<string, string>;\n\n /**\n * Map of identifier → value installed on the sandbox's module scope.\n *\n * These identifiers are resolvable as free variables inside the sandbox\n * but MUST NOT appear on `globalThis`.\n *\n * @example\n * ```ts\n * globals: {\n * console: { log: (...args) => logger.info(...args) },\n * getMessage: async () => '...',\n * }\n * ```\n */\n globals?: Record<string, unknown>;\n\n /**\n * Source language. TypeScript source has its types erased before evaluation;\n * no type checking is performed.\n *\n * @default 'typescript'\n */\n language?: 'javascript' | 'typescript';\n\n /**\n * Maximum sandbox heap in bytes. Exceeding this settles the handle with\n * `status: 'memory'`. Runtime default is implementation-defined and\n * documented per runtime.\n */\n memoryLimitBytes?: number;\n\n /**\n * Label used in stack traces and error `specifier` fields.\n *\n * @default '<runCode>'\n */\n filename?: string;\n\n /**\n * Optional host-side sink for the built-in `report` bridge.\n *\n * When provided, the runtime installs a `report` global that forwards values\n * to this callback. Reported values are also appended to the live\n * {@link CodeExecution.reports} view and to the final\n * {@link CodeExecutionResult.reports}.\n */\n report?: (value: unknown) => void;\n}\n\n/**\n * Handle returned by {@link ThreadState.runCode}.\n *\n * `CodeExecution` is a `PromiseLike<CodeExecutionResult>` — `await` the handle\n * to get the final result. The handle also exposes controls that only make\n * sense while the run is in flight: caller-initiated termination and a live\n * view of values emitted via the `report` bridge.\n */\nexport interface CodeExecution extends PromiseLike<CodeExecutionResult> {\n /**\n * Stop the run. Idempotent: subsequent calls are no-ops.\n *\n * Settles the handle with `status: 'terminated'` at the next ECMAScript\n * yield point (microtask boundary, async operation, or runtime interrupt).\n * Typically a few milliseconds and SHOULD be ≤ 50 ms under normal host load;\n * a pure-synchronous tight loop may run until the runtime's own safety cap\n * fires. When `reason` is provided, it surfaces in `error.message`.\n */\n terminate(reason?: string): void;\n\n /** `true` until the handle settles. */\n readonly running: boolean;\n\n /**\n * Snapshot of values emitted via the `report` bridge so far, in call order.\n * The same values appear in {@link CodeExecutionResult.reports} once the\n * run ends.\n */\n readonly reports: readonly unknown[];\n}\n\n/**\n * Outcome classification for {@link CodeExecutionResult.status}.\n *\n * - `success` — Module evaluated and the configured export resolved.\n * - `error` — Uncaught runtime error inside the sandbox.\n * - `memory` — `memoryLimitBytes` exceeded.\n * - `terminated` — Caller called `handle.terminate()`, or the runtime's own\n * safety cap fired. `error.message` distinguishes the two (including any\n * `reason` the caller passed).\n * - `link_error` — Module graph failed to link (unknown specifier, missing\n * named export, parse error).\n */\nexport type CodeExecutionStatus =\n | 'success'\n | 'error'\n | 'memory'\n | 'terminated'\n | 'link_error';\n\n/**\n * A single captured `console.*` call from inside the sandbox.\n *\n * Only populated when the runtime installs a capturing `console` (typically\n * when the caller does not provide one via `options.globals`).\n */\nexport interface CodeExecutionLog {\n level: 'log' | 'info' | 'warn' | 'error' | 'debug';\n /** Marshaled argument values, deep-cloned from the sandbox. */\n args: unknown[];\n /** Millisecond timestamp when the call occurred. */\n timestamp: number;\n}\n\n/**\n * Error surfaced when a {@link CodeExecutionResult} does not have\n * `status: 'success'`.\n *\n * Host-side stack frames MUST NOT leak into this object — only sandbox\n * frames are included.\n */\nexport interface CodeExecutionError {\n name: string;\n message: string;\n stack?: string;\n /** Module specifier that failed to link (for `link_error`). */\n specifier?: string;\n /** Source filename associated with `line` and `column`, when available. */\n filename?: string;\n /** 1-based line number in source, when available. */\n line?: number;\n /** 1-based column number in source, when available. */\n column?: number;\n}\n\n/**\n * Result of a {@link ThreadState.runCode} call.\n *\n * The sandbox has two result channels and both may be used in the same run:\n * - **Configured export** → marshaled into `result` on success.\n * - **Bridge reports** → appended to `reports` in call order as they are emitted.\n */\nexport interface CodeExecutionResult {\n /** Outcome classification — see {@link CodeExecutionStatus}. */\n status: CodeExecutionStatus;\n\n /**\n * Resolved configured export (after awaiting top-level promises).\n * Omitted when `status !== 'success'`. `undefined` is a valid success result\n * when the configured export resolves to `undefined`.\n */\n result?: unknown;\n\n /**\n * Values emitted through the built-in `report` bridge when\n * `options.report` is supplied, in call order. Empty when unused.\n */\n reports: unknown[];\n\n /** Captured `console.*` calls (see {@link CodeExecutionLog}). Empty when the caller supplies its own `console`. */\n logs: CodeExecutionLog[];\n\n /** Error detail. Present iff `status` is not `'success'`. */\n error?: CodeExecutionError;\n\n /** Wall-clock execution time in milliseconds. */\n durationMs: number;\n\n /** Peak sandbox heap in bytes, when the engine can measure it. */\n memoryUsedBytes?: number;\n}\n\n// ============================================================================\n// Execution State\n// ============================================================================\n\n/**\n * Execution-specific state available during agent execution.\n *\n * This is present when a thread is actively executing (during tool calls,\n * hook invocations, etc.) and null when accessing a thread at rest\n * (from endpoints, external code, etc.).\n */\nexport interface ExecutionState {\n /** Current flow ID (unique per execution) */\n readonly flowId: string;\n\n /** Current side in dual_ai agents ('a' or 'b') */\n readonly currentSide: 'a' | 'b';\n\n /** Total steps executed in this flow */\n readonly stepCount: number;\n\n /** Steps executed by side A */\n readonly sideAStepCount: number;\n\n /** Steps executed by side B */\n readonly sideBStepCount: number;\n\n /** Whether execution has been stopped */\n readonly stopped: boolean;\n\n /** Which side initiated the stop (if stopped) */\n readonly stoppedBy?: 'a' | 'b';\n\n /** Message history loaded for current execution */\n readonly messageHistory: Message[];\n\n /**\n * Force a specific side to play the next turn.\n *\n * Only valid for dual_ai agents. Has no effect on ai_human agents.\n *\n * @param side - The side to force ('a' or 'b')\n */\n forceTurn(side: 'a' | 'b'): void;\n\n /**\n * Stop the current execution.\n *\n * Signals the execution loop to terminate after the current operation\n * completes. Does not abort in-progress LLM calls.\n */\n stop(): void;\n\n /**\n * Abort signal for cancellation.\n *\n * Can be used to abort fetch requests or other async operations\n * when the execution is cancelled.\n */\n readonly abortSignal: AbortSignal;\n\n /**\n * Path from root prompt to current prompt.\n *\n * Tracks the current position in the prompt hierarchy:\n * - At root level: `['my_prompt']`\n * - Inside a sub-prompt: `['my_prompt', 'sub_prompt']`\n * - After handoff: `['new_agent_prompt']`\n *\n * This allows tools and hooks to understand their execution context depth.\n */\n readonly promptPath: string[];\n}\n\n/**\n * Display/redaction classification for thread-scoped environment values.\n *\n * `secret` values should be redacted from tool output and logs. `text` values\n * may be displayed.\n */\nexport type EnvValueType = 'text' | 'secret';\n\n/**\n * Options for {@link ThreadState.setEnv}.\n */\nexport interface SetEnvOptions {\n /**\n * Display/redaction classification for this value.\n *\n * Defaults to the existing type for that key, or `secret` for new keys.\n */\n type?: EnvValueType;\n}\n\n/**\n * Options for {@link ThreadState.stopSession}.\n */\nexport interface StopSessionOptions {\n /**\n * Result text returned to a blocking parent/subagent caller.\n *\n * This does not send a parent message by itself. Use `notifyParent` when the\n * session stop should also queue an explicit parent notification.\n */\n result?: string;\n\n /**\n * Optional silent message to queue to this thread's parent before stopping.\n *\n * Omit this for no parent-message side effect.\n */\n notifyParent?: string;\n\n /**\n * Optional parent registry status to set before stopping. Runtimes may ignore\n * this when the thread has no parent registry entry.\n *\n * Omit this for no status side effect.\n */\n status?: string;\n}\n\n// ============================================================================\n// ThreadState Interface\n// ============================================================================\n\n/**\n * The unified interface for all thread operations.\n *\n * ThreadState provides a consistent API for interacting with threads\n * regardless of context - whether from tools during execution, hooks,\n * or HTTP endpoints. The same interface is used throughout, with\n * execution-specific state available when applicable.\n *\n * @example\n * ```typescript\n * // In a tool\n * export default defineTool(\n * 'Send a greeting',\n * z.object({ name: z.string() }),\n * async (state, args) => {\n * // Access thread identity\n * console.log(`Thread: ${state.threadId}`);\n *\n * // Check execution state\n * if (state.execution?.stepCount > 10) {\n * state.execution.stop();\n * }\n *\n * // Emit custom event\n * state.emit('greeting', { name: args.name });\n *\n * return { status: 'success', result: `Hello, ${args.name}!` };\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * // In an endpoint\n * export default defineThreadEndpoint(async (req, state, params) => {\n * // state.execution is null (not executing)\n * const { messages } = await state.getMessages({ limit: 50 });\n * return Response.json({ messages, params });\n * });\n * ```\n */\n/**\n * A request forwarded from a server-side tool to a connected client (CLI) for\n * local execution. Used by \"forwarded\" tools where the agent loop runs remotely\n * but the actual operation (read a file, run a command) must happen on the\n * user's own machine.\n */\nexport interface ClientToolRequest {\n /** Logical operation name the client knows how to perform (e.g. `read_file`). */\n tool: string;\n /** Arguments for the operation. */\n args?: Record<string, unknown>;\n /**\n * Human-readable description of what this call will do, shown to the user when\n * the client needs to ask for permission. Presence signals the operation may\n * carry side effects.\n */\n requestPermission?: string;\n /** Risk level 1 (safe) – 5 (dangerous). Clients slide auto-accept on this. */\n risk?: number;\n /** Milliseconds to wait for the client before failing the call. */\n timeoutMs?: number;\n}\n\n/**\n * The result a connected client returns for a {@link ClientToolRequest}.\n */\nexport interface ClientToolResponse {\n /** Whether the client successfully performed the operation. */\n ok: boolean;\n /** Text result (e.g. file contents, command output). */\n result?: string;\n /** Error message when `ok` is false (including a user denial). */\n error?: string;\n /** Optional structured payload the tool can inspect. */\n data?: unknown;\n}\n\nexport interface ThreadState {\n // ─────────────────────────────────────────────────────────────────────────\n // Identity (readonly)\n // ─────────────────────────────────────────────────────────────────────────\n\n /** Unique thread identifier */\n readonly threadId: string;\n\n /** Agent that owns this thread */\n readonly agentId: string;\n\n /** User associated with this thread (if any) */\n readonly userId: string | null;\n\n /** Thread creation timestamp (microseconds since epoch) */\n readonly createdAt: number;\n\n /**\n * Registry of subagent child instances owned by this thread.\n *\n * Includes both resumable and non-resumable instances.\n */\n readonly children: SubagentRegistryEntry[];\n\n /**\n * Termination timestamp (microseconds) if this thread has been terminated.\n * Null when the thread is active.\n */\n readonly terminated: number | null;\n\n /**\n * Arguments supplied when this thread was created or invoked.\n *\n * For resumable subagent child threads, this is the durable\n * `subagent_create.arguments` object restored from child thread\n * metadata/properties. Both child sides see the same object. Runtimes also\n * expose these keys to prompt variable interpolation, including included\n * prompts.\n */\n readonly arguments: Record<string, unknown>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Messages\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Get messages from the thread.\n *\n * @param options - Query options (limit, offset, order, etc.)\n * @returns Messages and pagination info\n */\n getMessages(options?: GetMessagesOptions): Promise<MessagesResult>;\n\n /**\n * Get a single message by ID.\n *\n * @param messageId - The message ID\n * @returns The message, or null if not found\n */\n getMessage(messageId: string): Promise<Message | null>;\n\n /**\n * Inject a message into the thread.\n *\n * Creates a new message in the conversation history. This can be used\n * to add context, simulate user input, or insert assistant responses.\n *\n * @param message - The message to inject\n * @returns The created message\n */\n injectMessage(message: InjectMessageInput): Promise<Message>;\n\n /**\n * Update an existing message.\n *\n * @param messageId - The message ID\n * @param updates - The updates to apply\n * @returns The updated message\n */\n updateMessage(messageId: string, updates: MessageUpdates): Promise<Message>;\n\n /**\n * Delete a message from the thread.\n *\n * Removes the message and any associated attachments from storage.\n * Tool call results are cascade-deleted when their parent message is removed.\n *\n * @param messageId - The message ID to delete\n * @returns true if the message was found and deleted, false if not found\n */\n deleteMessage(messageId: string): Promise<boolean>;\n\n /**\n * Queue a message for delivery on the thread's next step.\n *\n * If the thread is executing, the message is delivered before the next LLM call.\n * If idle, queueing forces execution by the queued side.\n */\n queueMessage(message: QueueMessageInput): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Resource Loading\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Load a model definition by name.\n *\n * @param name - The model name\n * @returns The model definition\n * @throws If the model is not found\n */\n loadModel<T = unknown>(name: string): Promise<T>;\n\n /**\n * Load a prompt definition by name.\n *\n * @param name - The prompt name\n * @returns The prompt definition\n * @throws If the prompt is not found\n */\n loadPrompt<T = unknown>(name: string): Promise<T>;\n\n /**\n * Load an agent definition by name.\n *\n * @param name - The agent name\n * @returns The agent definition\n * @throws If the agent is not found\n */\n loadAgent<T = unknown>(name: string): Promise<T>;\n\n /**\n * Get available prompt names.\n *\n * @returns Array of prompt names that can be loaded\n */\n getPromptNames(): string[];\n\n /**\n * Get available agent names.\n *\n * @returns Array of agent names that can be loaded\n */\n getAgentNames(): string[];\n\n /**\n * Get available model names.\n *\n * @returns Array of model names that can be loaded\n */\n getModelNames(): string[];\n\n /**\n * Get a child thread by its subagent reference ID.\n *\n * @param referenceId - Child thread UUID\n * @returns Child ThreadState or null if not found\n */\n getChildThread(referenceId: string): Promise<ThreadState | null>;\n\n /**\n * Get this thread's parent thread (if any).\n *\n * @returns Parent ThreadState, or null for top-level threads\n */\n getParentThread(): Promise<ThreadState | null>;\n\n /**\n * Resolve an environment value for this thread by property name.\n *\n * Resolution order:\n * 1. Thread\n * 2. Agent definition\n * 3. Prompt definition\n * 4. User account\n * 5. AgentBuilder instance\n *\n * @throws If the variable is not defined in any source\n */\n env(propertyName: string): Promise<string>;\n\n /**\n * Resolve the display/redaction type for an environment value.\n *\n * Resolution follows the same order as `env()`:\n * thread, agent definition, prompt definition, user account, AgentBuilder instance.\n * User-account and AgentBuilder-instance env stores may persist per-key\n * `text` / `secret` metadata; agent/prompt defaults remain `secret` unless\n * overridden by thread state.\n *\n * Values marked `secret` should be redacted from tool output and logs.\n * Values marked `text` may be shown. Unknown values default to `secret`.\n */\n envType(propertyName: string): Promise<EnvValueType>;\n\n /**\n * Set a thread-scoped environment variable.\n *\n * This writes to thread env storage and propagates the updated thread env\n * to all active descendant threads recursively. Terminated descendants are\n * not modified.\n *\n * @param propertyName - Environment variable name\n * @param value - Environment variable value\n * @param options - Optional display/redaction classification for this value\n */\n setEnv(propertyName: string, value: string, options?: SetEnvOptions): Promise<void>;\n\n /**\n * Queue a silent message to this thread's parent, if one exists.\n *\n * This is useful for explicit child-to-parent escalation paths where tools or\n * hooks decide when the parent should be notified.\n *\n * Implementations SHOULD tag the queued message with the current thread's\n * `subagent_id` metadata so the parent can attribute the notification.\n *\n * @throws If content is empty\n */\n notifyParent(content: string): Promise<void>;\n\n /**\n * Update this thread's status in its parent registry entry.\n *\n * Useful for long-lived watcher/observer children that want to expose their\n * current state without sending a parent message.\n *\n * This is a no-op when the thread has no parent registry entry.\n *\n * @throws If status is empty\n */\n setStatus(status: string): Promise<void>;\n\n /**\n * Force the current agent session to stop successfully.\n *\n * This is stronger than `state.execution.stop()`: it marks the active session\n * as terminal for subagent/session-boundary purposes, without requiring a\n * `sessionStop` tool call. By default it has no parent-message or status side\n * effects. Pass `notifyParent` and/or `status` when those effects are desired.\n *\n * @throws If called outside an active execution context\n */\n stopSession(options?: StopSessionOptions): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Tool Invocation\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Queue a tool for execution.\n *\n * If the thread is currently executing, the tool is added to the\n * execution queue. If not, this starts a new execution with the\n * tool call.\n *\n * @param toolName - Name of the tool to invoke\n * @param args - Arguments to pass to the tool\n */\n queueTool(toolName: string, args: Record<string, unknown>): void;\n\n /**\n * Invoke a tool directly and wait for the result.\n *\n * If the thread is not currently executing, this creates a minimal\n * execution context for the tool. Unlike queueTool, this blocks\n * until the tool completes.\n *\n * @param toolName - Name of the tool to invoke\n * @param args - Arguments to pass to the tool\n * @returns The tool result\n */\n invokeTool(toolName: string, args: Record<string, unknown>): Promise<ToolResult>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Effect Scheduling\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Schedule an effect for future execution.\n *\n * Effects are executed outside the current conversation flow, making them\n * ideal for delayed operations like sending notifications, triggering\n * webhooks, or running cleanup tasks.\n *\n * @param name - Name of the effect to schedule (must exist in agents/effects/)\n * @param args - Arguments to pass to the effect handler\n * @param delay - Delay in milliseconds before execution (default: 0 for immediate)\n * @returns Unique ID of the scheduled effect (UUID)\n *\n * @example\n * ```typescript\n * // Schedule a reminder email in 30 minutes\n * const effectId = await state.scheduleEffect(\n * 'send_reminder_email',\n * { to: 'user@example.com', subject: 'Reminder' },\n * 30 * 60 * 1000\n * );\n * ```\n */\n scheduleEffect(name: string, args: Record<string, unknown>, delay?: number): Promise<string>;\n\n /**\n * Get scheduled effects for this thread.\n *\n * Returns effects that are pending execution. Can optionally filter\n * by effect name.\n *\n * @param name - Optional effect name to filter by\n * @returns Array of scheduled effect records\n */\n getScheduledEffects(name?: string): Promise<ScheduledEffect[]>;\n\n /**\n * Cancel a scheduled effect.\n *\n * Cancels a pending effect before it executes. Has no effect if the effect\n * has already executed, was already canceled, or doesn't exist. Runtimes may\n * retain canceled effects in inspection history.\n *\n * @param id - The effect ID returned by scheduleEffect\n * @returns true if the effect was found and canceled, false otherwise\n */\n removeScheduledEffect(id: string): Promise<boolean>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Agent Execution\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Trigger an agent to run on this thread.\n *\n * Starts a new agent execution asynchronously. This is useful for effects\n * that need to trigger background agent work (e.g., running a finalizer\n * agent after a delay).\n *\n * The agent runs in the background - this method returns immediately\n * after queuing the execution.\n *\n * @param agentName - Name of the agent to run (must exist in agents/agents/)\n * @returns Promise that resolves when the execution is queued\n *\n * @example\n * ```typescript\n * // In an effect handler, trigger a finalizer agent\n * await state.runAgent('booking_finalizer');\n * ```\n */\n runAgent(agentName: string): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Thread Lifecycle\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Soft-terminate the thread.\n *\n * Implementations should mark the thread as terminated, abort in-flight\n * execution, and reject subsequent execution/message queue operations.\n */\n terminate(): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Events / Streaming\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Emit a custom event to connected clients.\n *\n * Events are sent via WebSocket to any connected clients. Use this\n * for real-time updates, progress notifications, or custom data.\n *\n * @param event - Event name\n * @param data - Event data (must be JSON-serializable)\n */\n emit(event: string, data: unknown): void;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Context Storage\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Execution-scoped key-value data available while the current agent run is\n * being assembled and executed.\n *\n * Runtimes use this bag for values shared between tools/hooks/effects during\n * one execution. Invocation or creation arguments belong in\n * {@link ThreadState.arguments}, not in `context`.\n *\n * User mutations persist across tool calls within a single execution, but are\n * not durable after execution ends unless the runtime rehydrates a value from\n * another durable source. For durable storage, use\n * {@link ThreadState.getValue} and {@link ThreadState.setValue}, the file\n * system, or external storage.\n */\n context: Record<string, unknown>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Durable Key-Value Store\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Read a value from the thread's durable key-value store.\n *\n * Values written with {@link ThreadState.setValue} persist across executions,\n * tool calls, hook invocations, and endpoint requests for the lifetime of\n * the thread. The key-value store is one of two ways to store persistent\n * data on a thread, alongside the file system.\n *\n * Returns `null` when no value has been set for the given key. Values are\n * returned exactly as they were stored; runtimes MUST preserve JSON-equivalent\n * structure (objects, arrays, strings, numbers, booleans, `null`).\n *\n * @param key - The key to read\n * @returns The stored value, or `null` if the key has no value\n *\n * @example\n * ```typescript\n * const count = (await state.getValue<number>('invocation_count')) ?? 0;\n * await state.setValue('invocation_count', count + 1);\n * ```\n */\n getValue<T = unknown>(key: string): Promise<T | null>;\n\n /**\n * Write a value to the thread's durable key-value store.\n *\n * The value persists across executions for the lifetime of the thread.\n * Passing `null` or `undefined` deletes the key. Values MUST be\n * JSON-serializable; implementations MAY reject non-serializable values.\n *\n * Durable values are **not** automatically copied between threads when\n * subagents are spawned — each thread maintains its own key-value store.\n *\n * @param key - The key to write\n * @param value - The value to store (JSON-serializable), or `null`/`undefined`\n * to delete the key\n */\n setValue(key: string, value: unknown): Promise<void>;\n\n /**\n * Read a value from the account-wide durable key-value store of the user\n * this thread belongs to.\n *\n * The user store is the account-scoped sibling of the thread store: values\n * persist across every thread the user owns on the instance (e.g. a coding\n * client's registry of registered machines and projects). Returns `null`\n * when the thread has no associated user or the key has no value.\n *\n * @param key - The key to read\n */\n getUserValue<T = unknown>(key: string): Promise<T | null>;\n\n /**\n * Write a value to the account-wide durable key-value store of the user\n * this thread belongs to.\n *\n * Passing `null` or `undefined` deletes the key. Values MUST be\n * JSON-serializable. Implementations MUST reject the write when the thread\n * has no associated user.\n *\n * @param key - The key to write\n * @param value - The value to store (JSON-serializable), or `null`/`undefined`\n * to delete the key\n */\n setUserValue(key: string, value: unknown): Promise<void>;\n\n /**\n * List entries in the account-wide durable key-value store of the user this\n * thread belongs to, optionally filtered by key prefix. Returns an empty\n * list when the thread has no associated user.\n *\n * @param options - Optional `prefix`, `limit` (default 100), and `offset`\n */\n listUserValues(options?: { prefix?: string | null; limit?: number; offset?: number }): Promise<{\n entries: Array<{ key: string; value: unknown; updated_at: number }>;\n total: number;\n }>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // User Identity\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * The profile of the user this thread belongs to, or `null` when the thread\n * has no associated user (e.g. unauthenticated local development).\n *\n * Lets tools and hooks personalize or gate behavior per user — e.g. an\n * entitlement hook enforcing a per-user concurrency limit, or a tool\n * addressing the user by name. Never includes credentials.\n *\n * @example\n * ```typescript\n * const user = await state.user();\n * if (user?.email) await notifyBillingService(user.email);\n * ```\n */\n user(): Promise<ThreadUser | null>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Skills\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * The instance-global Agent Skills library (https://agentskills.io format).\n *\n * Skills are installed once and visible to every thread; their files live\n * server-side (never on a client machine). Agents should follow progressive\n * disclosure: browse metadata via `skills.list()`, and load a skill's\n * SKILL.md body with `skills.get()` only when it is applicable to the task.\n *\n * @example\n * ```typescript\n * const available = await state.skills.list();\n * const skill = await state.skills.get('pdf-processing');\n * const script = await state.skills.readFile('pdf-processing', 'scripts/extract.py');\n * ```\n */\n skills: SkillsNamespace;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Client-forwarded tools\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Forward a tool operation to the connected client (e.g. the coding CLI) and\n * await its result. The agent loop runs remotely, but operations like reading\n * a file or running a shell command must execute on the user's own machine;\n * `callClient` bridges that gap over the thread's `bridge` WebSocket.\n *\n * Resolves with `{ ok: false, error }` (rather than throwing) when no client\n * is connected, the request times out, or the user denies permission, so\n * forwarded tools can surface a normal tool error to the model.\n *\n * @param request - The operation, args, and optional permission/risk metadata\n * @returns The client's response\n */\n callClient(request: ClientToolRequest): Promise<ClientToolResponse>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // File System\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Write a file to the thread's file system.\n *\n * Large files (>1.75MB) are automatically chunked for storage.\n *\n * @param path - File path (relative to thread root)\n * @param data - File content as ArrayBuffer or string\n * @param mimeType - MIME type of the file\n * @param options - Optional metadata and dimensions\n * @returns The created file record\n */\n writeFile(\n path: string,\n data: ArrayBuffer | string,\n mimeType: string,\n options?: WriteFileOptions\n ): Promise<FileRecord>;\n\n /**\n * Read a file from the thread's file system.\n *\n * @param path - File path\n * @returns File content as ArrayBuffer, or null if not found\n */\n readFile(path: string): Promise<ArrayBuffer | null>;\n\n /**\n * Stream a file from the thread's file system in chunks.\n *\n * For large files (>1.75MB), this yields one chunk at a time, enabling\n * memory-efficient access without loading the entire file. Small files\n * are yielded as a single chunk.\n *\n * Returns null if the file is not found or stored externally (S3, R2, URL).\n *\n * @param path - File path\n * @param options - Optional streaming options (abort signal)\n * @returns Async iterable of file chunks, or null if not found/external\n *\n * @example\n * ```typescript\n * const stream = await state.readFileStream('/uploads/video.mp4');\n * if (stream) {\n * for await (const chunk of stream) {\n * console.log(`Chunk ${chunk.index + 1}/${chunk.totalChunks}`);\n * // Process chunk.data (Uint8Array)\n * }\n * }\n * ```\n */\n readFileStream(\n path: string,\n options?: ReadFileStreamOptions\n ): Promise<AsyncIterable<FileChunk> | null>;\n\n /**\n * Get metadata about a file.\n *\n * @param path - File path\n * @returns File record, or null if not found\n */\n statFile(path: string): Promise<FileRecord | null>;\n\n /**\n * List contents of a directory.\n *\n * @param path - Directory path\n * @returns Directory entries\n */\n readdirFile(path: string): Promise<ReaddirResult>;\n\n /**\n * Delete a file.\n *\n * @param path - File path\n */\n unlinkFile(path: string): Promise<void>;\n\n /**\n * Create a directory.\n *\n * @param path - Directory path\n * @returns The created directory record\n */\n mkdirFile(path: string): Promise<FileRecord>;\n\n /**\n * Remove a directory.\n *\n * @param path - Directory path (must be empty)\n */\n rmdirFile(path: string): Promise<void>;\n\n /**\n * Move or rename a file or directory.\n *\n * Relocates the entry at `sourcePath` to `destinationPath`. Works for\n * files and directories; moving a directory relocates its entire subtree,\n * preserving the relative layout of its contents. The destination must not\n * already exist, and a directory cannot be moved into itself or one of its\n * own descendants.\n *\n * @param sourcePath - Existing file or directory path\n * @param destinationPath - New path (must not already exist)\n * @returns The moved entry's record at its new path\n */\n moveFile(sourcePath: string, destinationPath: string): Promise<FileRecord>;\n\n /**\n * Rename a file or directory in place.\n *\n * Keeps the entry in its current parent directory and changes only its\n * final path segment. `newName` must be a bare file name with no path\n * separators. To relocate an entry to a different directory, use\n * {@link ThreadState.moveFile} instead.\n *\n * @param path - Existing file or directory path\n * @param newName - New name (no path separators)\n * @returns The renamed entry's record at its new path\n */\n renameFile(path: string, newName: string): Promise<FileRecord>;\n\n /**\n * Get overall file system statistics.\n *\n * @returns File count, directory count, and total size\n */\n getFileStats(): Promise<FileStats>;\n\n /**\n * Search file contents for a pattern.\n *\n * @param pattern - Search pattern (regular expression)\n * @returns Matching files and lines\n */\n grepFiles(pattern: string): Promise<GrepResult[]>;\n\n /**\n * Find files matching a glob pattern.\n *\n * @param pattern - Glob pattern (e.g., \"*.txt\", \"**\\/*.json\")\n * @returns Matching file paths\n */\n findFiles(pattern: string): Promise<FindResult>;\n\n /**\n * Get a thumbnail for an image file.\n *\n * @param path - Path to the image file\n * @returns Thumbnail data as ArrayBuffer, or null if not available\n */\n getFileThumbnail(path: string): Promise<ArrayBuffer | null>;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Execution State\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Execution-specific state.\n *\n * This is present when the thread is actively executing (tools, hooks)\n * and null when accessing a thread at rest (endpoints, external code).\n *\n * Use this to access step counts, force turns, or stop execution.\n */\n execution: ExecutionState | null;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Code Execution\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Execute JavaScript or TypeScript source in an isolated sandbox.\n *\n * The sandbox has **no ambient capabilities**: no filesystem, no network,\n * no timers, no host globals, no access to `state` itself. Every capability\n * the sandbox needs must be bridged in explicitly via `options.imports`,\n * `options.modules`, or `options.globals`.\n *\n * Returns a {@link CodeExecution} handle that is a\n * `PromiseLike<CodeExecutionResult>` — `await` it for the final result — and\n * also exposes `terminate()` for caller-initiated cancellation. The spec\n * does not impose a wall-clock timeout; callers layer their own deadline\n * using a timer plus `handle.terminate()`.\n *\n * Results flow back through either:\n * - the module export selected by `options.execute` (marshaled into\n * `result.result`; defaults to the `default` export with no arguments; if\n * the selected export is a function, it is called with `execute.args` and\n * any returned promise is awaited before marshaling), or\n * - the built-in `report` bridge (accumulated into `result.reports` and\n * visible live on `handle.reports`), or\n * - caller-installed bridge callbacks that the caller owns.\n *\n * See the [Code Execution specification](https://standardagentspec.com/0.1.0/specification/threads/code-execution)\n * for isolation guarantees, module resolution rules, value marshaling, and\n * conformance requirements.\n *\n * @param source - JavaScript or TypeScript source, evaluated as an ES module.\n * @param options - Export selection, imports, globals, memory cap, and language hints.\n * @returns A handle that settles with the execution result and can be\n * terminated at any time before settlement.\n *\n * @example\n * ```typescript\n * const run = state.runCode(\n * `\n * import { readFile } from 'fs';\n * import { report } from 'supervisor';\n *\n * const message = await getMessage();\n * if (/username/.test(message)) {\n * report({ topic: 'username', message });\n * }\n * export default async () => ({ scanned: true });\n * `,\n * {\n * imports: {\n * fs: { readFile: (p) => state.readFile(p) },\n * supervisor: { report: (payload) => flagged.push(payload) },\n * },\n * globals: {\n * console: { log: (...a) => {} },\n * getMessage: async () => 'latest user message',\n * },\n * },\n * );\n *\n * const deadline = setTimeout(() => run.terminate('5s budget'), 5_000);\n * const result = await run;\n * clearTimeout(deadline);\n *\n * if (result.status === 'success') {\n * // result.result === { scanned: true }\n * }\n * ```\n */\n runCode(\n source: string,\n options?: CodeExecutionOptions,\n ): CodeExecution;\n\n // ─────────────────────────────────────────────────────────────────────────\n // Runtime Context (Non-Portable)\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Runtime-specific context that cannot be packed or shared.\n *\n * This property lets runtime implementations inject non-portable context —\n * typically host bindings, database connections, or other\n * platform-specific handles the runtime chooses to expose.\n *\n * WARNING: Tools using this property cannot be packed, shared, or\n * published as they depend on runtime-specific context.\n */\n readonly _notPackableRuntimeContext?: Record<string, unknown>;\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// Thread Endpoint Marker\n// ============================================================================\n\n/**\n * Symbol used to identify thread endpoint handlers.\n *\n * When a handler is created with defineThreadEndpoint, it's marked with this\n * symbol so the runtime can detect it and wrap it with proper ThreadState injection.\n */\nexport const THREAD_ENDPOINT_SYMBOL = Symbol.for('standardagents.threadEndpoint');\n\n/**\n * A controller that has been marked as a thread endpoint.\n *\n * The runtime detects this marker and wraps the handler with ThreadState injection.\n * The `__handler` property contains the original handler function that expects\n * `(req: Request, state: ThreadState)` arguments.\n */\nexport interface MarkedThreadEndpoint extends Controller {\n /** Marker symbol indicating this is a thread endpoint */\n [THREAD_ENDPOINT_SYMBOL]: true;\n /** The original handler function before wrapping */\n __handler: ThreadEndpointHandler;\n}\n\n/**\n * Type guard to check if a controller is a marked thread endpoint.\n */\nexport function isThreadEndpoint(controller: Controller): controller is MarkedThreadEndpoint {\n return THREAD_ENDPOINT_SYMBOL in controller && (controller as any)[THREAD_ENDPOINT_SYMBOL] === true;\n}\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 * Its shape is defined by the runtime — typical surfaces include handles\n * to storage, queues, key-value stores, or other platform resources the\n * runtime chooses to expose.\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 — handles to storage,\n * queues, key-value stores, or other resources the runtime exposes.\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 supplied ThreadState includes the standard thread surface, including\n * `runCode`. The thread is automatically looked up by ID from URL parameters. Route\n * parameters are derived from the endpoint file path. For a dynamic segment\n * such as `[id].ts`, `params.id` contains the matched segment. For a catch-all\n * segment `[*].ts`, `params['*']` contains the unmatched path suffix,\n * including `/` separators when the match spans multiple segments.\n *\n * Thread endpoint routes are scoped beneath the runtime's thread ID prefix.\n * A request under that prefix that does not match any local or packed thread\n * endpoint route MUST return HTTP 404.\n */\nexport type ThreadEndpointRouteParams = Record<string, string>;\n\nexport type ThreadEndpointHandler = (\n req: Request,\n state: ThreadState,\n params: ThreadEndpointRouteParams\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 * Runtimes MUST return HTTP 404 for requests beneath the thread endpoint\n * prefix that do not match any local or packed thread endpoint route.\n *\n * @param handler - The handler function receiving request, ThreadState, and route params\n * @returns A Controller that can be used with the router\n *\n * @example\n * ```typescript\n * // agents/api/status.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/export.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/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 *\n * @example\n * ```typescript\n * // agents/api/files/[id].ts\n * import { defineThreadEndpoint } from '@standardagents/spec';\n *\n * export default defineThreadEndpoint(async (req, state, params) => {\n * const file = await state.readFile(`/files/${params.id}.json`);\n * return Response.json({ exists: !!file });\n * });\n * ```\n */\nexport function defineThreadEndpoint(\n handler: ThreadEndpointHandler\n): MarkedThreadEndpoint {\n // Mark the handler so the runtime can detect and wrap it with ThreadState injection.\n // The runtime's createThreadEndpointHandler will provide the actual ThreadState.\n const markedHandler = handler as unknown as MarkedThreadEndpoint;\n (markedHandler as any)[THREAD_ENDPOINT_SYMBOL] = true;\n (markedHandler as any).__handler = handler;\n return markedHandler;\n}\n","/**\n * Provider types for Standard Agents.\n *\n * These types define the interface between Standard Agents and LLM providers.\n * Provider packages implement these types to integrate with different LLM APIs.\n *\n * @module\n */\n\nimport type { ModelCapabilities } from './models';\nimport type { ToolDefinition, ToolArgs, ToolTenvs } from './tools';\n\n// =============================================================================\n// Response Summary (for async metadata fetching)\n// =============================================================================\n\n/**\n * Stripped-down response summary for async metadata fetching.\n * Intentionally excludes content/attachments to avoid passing large data.\n */\nexport interface ResponseSummary {\n /** Provider-specific response/generation ID */\n responseId?: string;\n /** Model that handled the request */\n model: string;\n /** How the response ended */\n finishReason: ProviderFinishReason;\n /** Token usage (without detailed breakdowns) */\n usage: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n}\n\n// =============================================================================\n// Provider Interface\n// =============================================================================\n\n/**\n * Model information returned by provider's getModels method.\n */\nexport interface ProviderModelInfo {\n /** The model identifier used in API calls (e.g., 'gpt-4o', 'anthropic/claude-3-opus') */\n id: string;\n /** Human-readable display name */\n name: string;\n /** Optional description of the model */\n description?: string;\n /** Optional context window size in tokens */\n contextLength?: number;\n /** Optional icon identifier for UI display */\n iconId?: string;\n /** Optional slug for additional lookups (e.g., OpenRouter endpoint queries) */\n slug?: string;\n /** Optional cost per 1M input tokens, in USD */\n inputPrice?: number;\n /** Optional cost per 1M output tokens, in USD */\n outputPrice?: number;\n /** Optional cost per 1M cached input tokens, in USD */\n cachedPrice?: number;\n /**\n * Optional capability hints surfaced from the provider's listing\n * payload. Populated when the provider can derive support flags\n * (vision / tool calls / streaming / JSON mode) without an\n * additional per-model probe — lets UIs render the capability\n * matrix on every row in the picker. Omit when the provider\n * doesn't expose enough metadata; consumers must tolerate\n * undefined.\n */\n capabilities?: ModelCapabilities;\n}\n\n/**\n * Query params for provider-backed model discovery.\n */\nexport interface ProviderModelsQuery {\n /** Optional search string */\n search?: string;\n /** 1-based page number */\n page?: number;\n /** Page size */\n perPage?: number;\n}\n\n/**\n * Paginated provider model listing response.\n */\nexport interface ProviderModelsPage {\n /** Models in the current page */\n models: ProviderModelInfo[];\n /** Whether the provider has another page available */\n hasNextPage: boolean;\n}\n\n/**\n * Provider interface - thin translation layer between Standard Agents and LLM APIs\n */\nexport interface LLMProviderInterface {\n readonly name: string;\n readonly specificationVersion: '1';\n\n /**\n * Non-streaming generation\n */\n generate(request: ProviderRequest): Promise<ProviderResponse>;\n\n /**\n * Streaming generation\n */\n stream(request: ProviderRequest): Promise<AsyncIterable<ProviderStreamChunk>>;\n\n /**\n * Check if this provider supports a model\n */\n supportsModel?(modelId: string): boolean;\n\n /**\n * List available models from this provider.\n * Optional for backwards compatibility - providers may implement this\n * to enable model selection in the UI.\n *\n * @param filter - Optional search string to filter models by name/id\n * @returns Array of available models\n */\n getModels?(filter?: string): Promise<ProviderModelInfo[]>;\n\n /**\n * List available models from this provider with remote search/pagination support.\n * Optional for backwards compatibility. When absent, callers should fall back\n * to getModels() and paginate client-side.\n *\n * @param query - Search/pagination parameters\n * @returns Current page of available models\n */\n getModelsPage?(query?: ProviderModelsQuery): Promise<ProviderModelsPage>;\n\n /**\n * Fetch capabilities for a specific model.\n * Optional for backwards compatibility - providers may implement this\n * to enable auto-detection of model features in the UI.\n *\n * @param modelId - The model identifier (e.g., 'gpt-4o', 'anthropic/claude-3-opus')\n * @returns The model capabilities, or null if not available\n */\n getModelCapabilities?(modelId: string): Promise<ModelCapabilities | null>;\n\n /**\n * Get tools embedded in this provider.\n * Optional - providers may implement this to expose built-in tools\n * (e.g., OpenAI's web_search or xAI's x_search).\n *\n * Tool names are provider-defined capability names. Standard Agents defines\n * discovery, selection, execution ownership, and result reporting; providers\n * define their own native request mapping.\n *\n * These tools are defined using defineTool() with optional variable requirements.\n * Tools returned here can be referenced by name in model/prompt definitions.\n *\n * @param modelId - Optional filter to get tools available for a specific model\n * @returns Record of tool name to tool definition (sync or async)\n */\n getTools?(modelId?: string): Record<string, ToolDefinition<any, ToolArgs | null, ToolTenvs | null>> | Promise<Record<string, ToolDefinition<any, ToolArgs | null, ToolTenvs | null>>>;\n\n /**\n * Get an icon for this provider or a specific model.\n * Optional - providers may implement this to provide UI icons.\n *\n * **Preferred return format: SVG data URI** (e.g., 'data:image/svg+xml,...')\n *\n * The data URI format allows icons to be embedded directly in the UI without\n * additional network requests. Use the `svgToDataUri()` helper from provider\n * packages to convert SVG strings.\n *\n * Return value can be:\n * - A data URI (e.g., 'data:image/svg+xml,...') - **PREFERRED**\n * - A full URL (e.g., 'https://example.com/icon.svg')\n * - An icon identifier that the UI resolves (legacy)\n *\n * For providers like OpenRouter that host many models, the modelId parameter\n * allows returning different icons based on the model's origin lab\n * (e.g., 'anthropic/claude-3-opus' -> anthropic icon).\n *\n * @param modelId - Optional model ID to get a model-specific icon\n * @returns SVG data URI (preferred), URL, icon identifier, or undefined\n *\n * @example\n * ```typescript\n * // Provider returning its own icon\n * getIcon() {\n * return svgToDataUri(OPENAI_ICON);\n * }\n *\n * // Provider returning model-specific icon (e.g., OpenRouter)\n * getIcon(modelId?: string) {\n * if (modelId) {\n * const lab = modelId.split('/')[0]; // 'anthropic' from 'anthropic/claude-3'\n * return getLabIconDataUri(lab);\n * }\n * return svgToDataUri(OPENROUTER_ICON);\n * }\n * ```\n */\n getIcon?(modelId?: string): string | undefined;\n\n /**\n * Transform a ProviderRequest to the provider's native format for inspection/debugging.\n * Returns the transformed request as it would be sent to the provider's API.\n *\n * This is used by the admin UI to view logged requests in provider-specific format,\n * helping debug issues like message transformation or tool handling.\n *\n * Implementations should truncate base64 data to ~50 chars for readability.\n *\n * @param request - The Standard Agents format request to transform\n * @returns The transformed request in the provider's native format\n */\n inspectRequest?(request: ProviderRequest): Promise<InspectedRequest>;\n\n /**\n * Fetch additional metadata about a completed response.\n * Called asynchronously after the response is received - does not block the main execution flow.\n *\n * This is useful for providers (like aggregators) where complete metadata isn't available\n * immediately. The execution engine calls this in the background and uses the returned\n * data to update log records.\n *\n * @param summary - Stripped-down response info (no content/attachments)\n * @param signal - Optional abort signal for cancellation\n * @returns Additional metadata or null if unavailable\n */\n getResponseMetadata?(\n summary: ResponseSummary,\n signal?: AbortSignal\n ): Promise<Record<string, unknown> | null>;\n}\n\n// =============================================================================\n// Inspection Types\n// =============================================================================\n\n/**\n * Result from inspectRequest() - the transformed request in provider's native format\n */\nexport interface InspectedRequest {\n /** The transformed request body as it would be sent to the API */\n body: Record<string, unknown>;\n /** Path to the messages array within body (e.g., \"input\" for OpenAI, \"messages\" for others) */\n messagesPath: string;\n /** Optional: Additional metadata about the transformation */\n metadata?: {\n /** The API endpoint that would be called */\n endpoint?: string;\n /** Headers that would be sent (excluding auth) */\n headers?: Record<string, string>;\n };\n}\n\n// =============================================================================\n// Request Types\n// =============================================================================\n\n/**\n * Standard Agent request format - providers translate to their native format\n */\nexport interface ProviderRequest {\n model: string;\n messages: ProviderMessage[];\n tools?: ProviderTool[];\n toolChoice?: 'auto' | 'none' | 'required' | { name: string };\n parallelToolCalls?: boolean;\n maxOutputTokens?: number;\n temperature?: number;\n topP?: number;\n topK?: number;\n stopSequences?: string[];\n reasoning?: {\n level?: number; // 0-100 scale\n maxTokens?: number;\n exclude?: boolean;\n };\n responseFormat?: { type: 'text' } | { type: 'json'; schema?: Record<string, unknown> };\n signal?: AbortSignal;\n /**\n * Stable end-user/session identifier for this request (e.g. the thread id).\n * Providers that support it (OpenAI-compatible `user`; OpenRouter uses it\n * for provider-sticky routing, which improves prompt-cache hit rates by\n * pinning consecutive requests to the same upstream provider) should\n * forward it; others may ignore it.\n */\n user?: string;\n providerOptions?: Record<string, unknown>;\n}\n\n// =============================================================================\n// Message Types\n// =============================================================================\n\nexport type ProviderMessage =\n | ProviderSystemMessage\n | ProviderUserMessage\n | ProviderAssistantMessage\n | ProviderToolMessage;\n\nexport interface ProviderSystemMessage {\n role: 'system';\n content: string;\n}\n\nexport interface ProviderUserMessage {\n role: 'user';\n content: ProviderMessageContent;\n}\n\nexport interface ProviderAssistantMessage {\n role: 'assistant';\n content?: string | null;\n reasoning?: string | null;\n reasoningDetails?: ProviderReasoningDetail[];\n toolCalls?: ProviderToolCallPart[];\n}\n\nexport interface ProviderToolMessage {\n role: 'tool';\n toolCallId: string;\n toolName: string;\n content: ProviderToolResultContent;\n attachments?: ProviderAttachment[];\n}\n\n/**\n * Attachment on a provider message (loaded from storage, ready for provider-specific transformation)\n */\nexport interface ProviderAttachment {\n type: 'image' | 'file';\n data: string; // base64\n mediaType: string;\n name?: string;\n path?: string; // Original file path (for logging/debugging)\n}\n\n// =============================================================================\n// Content Types\n// =============================================================================\n\nexport type ProviderMessageContent = string | ContentPart[];\n\nexport type ContentPart =\n | TextPart\n | ImagePart\n | ImageUrlPart\n | FilePart;\n\nexport interface TextPart {\n type: 'text';\n text: string;\n}\n\nexport interface ImagePart {\n type: 'image';\n data: string; // base64 or URL\n mediaType: string; // 'image/jpeg', 'image/png', etc.\n detail?: 'auto' | 'low' | 'high';\n}\n\n/**\n * Image URL content part (OpenAI/OpenRouter format).\n * Used for passing image URLs directly to providers.\n */\nexport interface ImageUrlPart {\n type: 'image_url';\n image_url: {\n url: string; // Can be data URL (data:image/...) or http(s) URL\n detail?: 'auto' | 'low' | 'high';\n };\n}\n\nexport interface FilePart {\n type: 'file';\n data: string; // base64 or URL\n mediaType: string;\n filename?: string;\n}\n\n// =============================================================================\n// Tool Types\n// =============================================================================\n\nexport interface ProviderTool {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters?: Record<string, unknown>; // JSON Schema\n };\n /**\n * Where this tool is executed:\n * - 'local': Execute locally by the execution engine (default)\n * - 'provider': Executed by the LLM provider, results come in response\n */\n executionMode?: 'local' | 'provider';\n /**\n * Which provider executes this tool (when executionMode='provider')\n * e.g., 'openai', 'anthropic'\n */\n executionProvider?: string;\n}\n\nexport interface ProviderToolCallPart {\n id: string;\n name: string;\n arguments: Record<string, unknown>; // Parsed JSON\n /**\n * Provider-specific metadata that must round-trip with the tool call.\n * For example, Gemini tool calls can include a thought signature that must\n * be echoed back on the next turn for tool calling to continue working.\n */\n extraContent?: Record<string, unknown>;\n}\n\nexport type ProviderToolResultContent =\n | string\n | { type: 'text'; text: string }\n | { type: 'error'; error: string }\n | ContentPart[];\n\n// =============================================================================\n// Response Types\n// =============================================================================\n\nexport interface ProviderResponse {\n content: string | null;\n reasoning?: string | null;\n reasoningDetails?: ProviderReasoningDetail[];\n toolCalls?: ProviderToolCallPart[];\n images?: ProviderGeneratedImage[];\n /**\n * Provider-executed tool calls surfaced for logging and inspection.\n *\n * Providers should populate this when the upstream provider executed a\n * built-in/native tool server-side. These entries are informational for\n * Standard Agents and must not be re-executed locally.\n */\n providerTools?: ProviderExecutedToolResult[];\n finishReason: ProviderFinishReason;\n usage: ProviderUsage;\n metadata?: Record<string, unknown>;\n}\n\nexport type ProviderFinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'error';\n\nexport interface ProviderUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n reasoningTokens?: number;\n cachedTokens?: number;\n cost?: number;\n /** The actual provider that fulfilled the request (e.g., 'google', 'anthropic') */\n provider?: string;\n /**\n * Per-million-token USD unit prices the provider reported for the model\n * that served this request (e.g. from OpenRouter's live models catalog).\n * Lets runtimes split exact input/cached/output cost components even when\n * no static pricing table covers the provider.\n */\n pricing?: ProviderUsagePricing;\n}\n\n/** Provider-reported unit prices for one request, in USD per million tokens. */\nexport interface ProviderUsagePricing {\n inputPerMillion?: number;\n cachedInputPerMillion?: number;\n outputPerMillion?: number;\n}\n\nexport interface ProviderGeneratedImage {\n /** Unique ID for this generated image (used to link to tool call) */\n id?: string;\n /** Name of the tool that generated this image (e.g., 'image_generation') */\n toolName?: string;\n data: string; // base64 or URL\n mediaType: string;\n revisedPrompt?: string;\n}\n\nexport interface ProviderReasoningDetail {\n type: 'summary' | 'encrypted' | 'text';\n /** Original reasoning ID from provider (e.g., rs_xxx for OpenAI) */\n id?: string;\n text?: string;\n data?: string;\n /** Provider-specific format identifier (e.g., \"google-gemini-v1\", \"openai-responses-v1\") */\n format?: string;\n}\n\n// =============================================================================\n// Streaming Types\n// =============================================================================\n\n/**\n * Web search result from provider\n */\nexport interface ProviderWebSearchResult {\n /** Unique ID of the web search call */\n id: string;\n /** Status of the search */\n status: 'in_progress' | 'searching' | 'completed' | 'failed';\n /** Search actions performed */\n actions?: Array<{\n type: 'search' | 'open_page' | 'find';\n query?: string;\n url?: string;\n pattern?: string;\n sources?: Array<{ type: 'url'; url: string; title?: string }>;\n }>;\n}\n\n/**\n * Provider-executed tool call surfaced for logging.\n *\n * Providers use this when the upstream model provider executes a native tool\n * server-side and Standard Agents should record the call without attempting to\n * execute it locally.\n */\nexport interface ProviderExecutedToolResult {\n /** Provider-facing tool name, such as \"web_search\" or \"x_search\" */\n name: string;\n /**\n * Legacy alias for `name`, retained for persisted log compatibility.\n * New provider implementations should set `name`; runtimes may mirror it\n * into `type` when serializing logs for older UIs.\n */\n type?: string;\n /** Provider that executed the tool, such as \"openai\" or \"xai\" */\n provider?: string;\n /** Unique ID of the provider tool call */\n id: string;\n /** Execution status */\n status: 'completed' | 'failed' | 'in_progress';\n /** Optional provider-specific result or argument summary */\n result?: {\n actions?: Array<{\n type: string;\n query?: string;\n url?: string;\n pattern?: string;\n sources?: Array<{ type?: string; url: string; title?: string }>;\n }>;\n input?: Record<string, unknown>;\n output?: string;\n results?: unknown[];\n artifacts?: Array<{\n type: string;\n id?: string;\n mediaType?: string;\n url?: string;\n path?: string;\n title?: string;\n metadata?: Record<string, unknown>;\n }>;\n };\n /** Provider-specific structured details that should stay JSON-serializable */\n metadata?: Record<string, unknown>;\n}\n\nexport type ProviderStreamChunk =\n // Content streaming\n | { type: 'content-delta'; delta: string }\n | { type: 'content-done' }\n // Reasoning streaming\n | { type: 'reasoning-delta'; delta: string }\n | { type: 'reasoning-done' }\n // Tool call streaming\n | { type: 'tool-call-start'; id: string; name: string; extraContent?: Record<string, unknown> }\n | { type: 'tool-call-delta'; id: string; argumentsDelta: string }\n | { type: 'tool-call-done'; id: string; arguments: Record<string, unknown>; extraContent?: Record<string, unknown> }\n // Image generation (partial)\n | { type: 'image-delta'; index: number; data: string }\n | { type: 'image-done'; index: number; image: ProviderGeneratedImage }\n // Web search (legacy compatibility; prefer provider-tool-done for new providers)\n | { type: 'web-search-done'; result: ProviderWebSearchResult }\n // Generic provider-executed tools\n | { type: 'provider-tool-done'; tool: ProviderExecutedToolResult }\n // Completion\n | { type: 'finish'; finishReason: ProviderFinishReason; usage: ProviderUsage; reasoningDetails?: ProviderReasoningDetail[] }\n // Errors\n | { type: 'error'; error: string; code?: string };\n\n// =============================================================================\n// Error Types\n// =============================================================================\n\nexport type ProviderErrorCode =\n | 'rate_limit'\n | 'invalid_request'\n | 'auth_error'\n | 'server_error'\n | 'timeout'\n | 'unknown';\n\nexport class ProviderError extends Error {\n constructor(\n message: string,\n public code: ProviderErrorCode,\n public statusCode?: number,\n public retryAfter?: number\n ) {\n super(message);\n this.name = 'ProviderError';\n }\n\n /**\n * Whether this error is retryable\n */\n get isRetryable(): boolean {\n return this.code === 'rate_limit' || this.code === 'server_error' || this.code === 'timeout';\n }\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Maps a 0-100 reasoning level to the model's nearest supported level\n */\nexport function mapReasoningLevel(\n level: number,\n reasoningLevels: Record<number, string | null> | undefined\n): string | null {\n if (!reasoningLevels) return null;\n\n const breakpoints = Object.keys(reasoningLevels)\n .map(Number)\n .sort((a, b) => a - b);\n\n if (breakpoints.length === 0) return null;\n\n // Find nearest breakpoint\n let nearest = breakpoints[0];\n let minDistance = Math.abs(level - nearest);\n\n for (const bp of breakpoints) {\n const distance = Math.abs(level - bp);\n if (distance < minDistance) {\n minDistance = distance;\n nearest = bp;\n }\n }\n\n return reasoningLevels[nearest];\n}\n","/**\n * Packing types for Standard Agents.\n *\n * Defines types for packaging agents with their dependencies into\n * reusable, encapsulated packages that can be published to npm\n * or stored locally.\n *\n * @module\n */\n\n// ============================================================================\n// Package Signature\n// ============================================================================\n\n/**\n * Package signature applied to packed definitions.\n *\n * When an agent and its dependencies are packed, each definition\n * receives this signature marking it as belonging to a specific package.\n * This enables namespace isolation during execution.\n *\n * @example\n * ```typescript\n * const signature: PackageSignature = {\n * packageId: 'standardagent-my-workflow',\n * version: '1.0.0',\n * source: 'npm',\n * packedAt: Date.now(),\n * };\n * ```\n */\nexport interface PackageSignature {\n /** Unique package identifier (npm name or local identifier) */\n packageId: string;\n /** Package version */\n version: string;\n /** Source type */\n source: 'npm' | 'local';\n /** When packed (timestamp in milliseconds) */\n packedAt: number;\n}\n\n// ============================================================================\n// Namespace Context\n// ============================================================================\n\n/**\n * Global namespace context - for unpacked code.\n *\n * Unpacked code sees:\n * - All unpacked tools, prompts, models, hooks\n * - Packed agent entry points (agents with exposeAsTool: true)\n * - NOT internal packed tools/prompts (those are hidden)\n */\nexport interface GlobalNamespaceContext {\n type: 'global';\n}\n\n/**\n * Packed namespace context - for code inside a packed agent.\n *\n * Packed code sees:\n * - Only items within its own package (by packageId)\n * - Other packed agent entry points (for handoffs)\n * - NOT unpacked global code\n */\nexport interface PackedNamespaceContext {\n type: 'packed';\n /** Package ID this code belongs to */\n packageId: string;\n}\n\n/**\n * Namespace context for execution.\n * Determines what items are visible during execution.\n *\n * @example\n * ```typescript\n * // Global namespace (unpacked code)\n * const globalNs: NamespaceContext = { type: 'global' };\n *\n * // Packed namespace (inside a packed agent)\n * const packedNs: NamespaceContext = {\n * type: 'packed',\n * packageId: 'standardagent-my-workflow',\n * };\n * ```\n */\nexport type NamespaceContext = GlobalNamespaceContext | PackedNamespaceContext;\n\n// ============================================================================\n// Packed Metadata\n// ============================================================================\n\n/**\n * Extended metadata for packed definitions.\n *\n * This interface is added to agent, prompt, tool, model, and hook\n * definitions when they are packed. It marks them as belonging\n * to a specific package and optionally as readonly.\n */\nexport interface PackedMetadata {\n /**\n * Package signature if this definition is part of a packed agent.\n * Undefined for unpacked (global) definitions.\n */\n __package?: PackageSignature;\n\n /**\n * Whether this definition is readonly (cannot be edited in UI).\n * Packed definitions are typically readonly.\n */\n __readonly?: boolean;\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Helper type to check if a definition is packed.\n */\nexport function isPacked(metadata: PackedMetadata | undefined): metadata is PackedMetadata & { __package: PackageSignature } {\n return !!metadata?.__package;\n}\n\n/**\n * Helper to check if a definition belongs to a specific package.\n */\nexport function belongsToPackage(\n metadata: PackedMetadata | undefined,\n packageId: string\n): boolean {\n return metadata?.__package?.packageId === packageId;\n}\n\n/**\n * Helper to check if a definition is visible in a given namespace.\n *\n * @param metadata - The definition's packed metadata\n * @param namespace - The current namespace context\n * @param isEntryPoint - Whether this is an agent with exposeAsTool: true\n */\nexport function isVisibleInNamespace(\n metadata: PackedMetadata | undefined,\n namespace: NamespaceContext,\n isEntryPoint: boolean = false\n): boolean {\n const hasPkg = isPacked(metadata);\n\n if (namespace.type === 'global') {\n // Global sees: unpacked + packed entry points\n return !hasPkg || isEntryPoint;\n }\n\n // Packed sees: own package + other packed entry points\n const isOwnPackage = hasPkg && metadata.__package.packageId === namespace.packageId;\n return isOwnPackage || (hasPkg && isEntryPoint);\n}\n\n// ============================================================================\n// Packed Package Types\n// ============================================================================\n\n/**\n * Metadata export for packed packages.\n *\n * This is exported as `__meta` from the packed package's index.ts,\n * replacing the manifest.json file from the old format.\n *\n * @example\n * ```typescript\n * export const __meta: PackedMeta = {\n * packageId: 'standardagent-my-workflow',\n * version: '1.0.0',\n * entryAgents: ['my_agent'],\n * packedAt: 1705012800000,\n * };\n * ```\n */\nexport interface PackedMeta {\n /** Unique package identifier (npm name or local identifier) */\n packageId: string;\n /** Package version (semver) */\n version: string;\n /** Entry agents exposed as tools (visible from outside the package) */\n entryAgents: string[];\n /** When the package was packed (timestamp in milliseconds) */\n packedAt: number;\n /** Optional description from the entry agent */\n description?: string;\n}\n\n/**\n * Lazy loader type for packed definitions.\n *\n * Each definition in a packed package is wrapped in a function\n * that returns a Promise, enabling lazy loading.\n *\n * @example\n * ```typescript\n * export const tools = {\n * search: async (): Promise<ToolDefinition> => ({\n * description: 'Search for information',\n * execute: async (state, args) => { ... },\n * }),\n * } as const;\n * ```\n */\nexport type DefinitionLoader<T> = () => Promise<T>;\n\n// Import types needed for PackedExports\nimport type { AgentDefinition } from './agents.js';\nimport type { PromptDefinition } from './prompts.js';\nimport type { ToolDefinition } from './tools.js';\nimport type { ModelDefinition } from './models.js';\nimport type { HookSignatures } from './hooks.js';\nimport type { EffectDefinition } from './effects.js';\nimport type { Controller, MarkedThreadEndpoint } from './endpoints.js';\n\n/**\n * Standard shape for packed package exports.\n *\n * Every packed package exports this structure, enabling\n * consistent discovery and loading.\n *\n * @example\n * ```typescript\n * import type { PackedExports } from '@standardagents/spec';\n *\n * const pkg: PackedExports = await import('standardagent-my-workflow');\n * const tool = await pkg.tools.search();\n * ```\n */\nexport interface PackedExports {\n /** Agent definitions, keyed by name */\n agents: Record<string, DefinitionLoader<AgentDefinition>>;\n /** Prompt definitions, keyed by name */\n prompts: Record<string, DefinitionLoader<PromptDefinition>>;\n /** Tool definitions, keyed by name */\n tools: Record<string, DefinitionLoader<ToolDefinition<unknown, any, any>>>;\n /** Model definitions, keyed by name */\n models: Record<string, DefinitionLoader<ModelDefinition>>;\n /** Hook definitions, keyed by name */\n hooks: Record<string, DefinitionLoader<HookSignatures[keyof HookSignatures]>>;\n /**\n * Effect definitions, keyed by name.\n *\n * Optional for backward compatibility with previously packed packages.\n */\n effects?: Record<string, DefinitionLoader<EffectDefinition<any, any>>>;\n /**\n * Thread endpoint handlers, keyed by packed route key (for example, `status.get`).\n *\n * Runtimes mount these beneath the same thread ID prefix as local thread\n * endpoints, using the packed route key to derive the endpoint path.\n * Requests beneath that prefix that do not match any local or packed thread\n * endpoint route MUST return HTTP 404.\n *\n * Optional for backward compatibility with previously packed packages.\n */\n threadEndpoints?: Record<string, DefinitionLoader<MarkedThreadEndpoint | Controller>>;\n /** Package metadata */\n __meta: PackedMeta;\n}\n"],"mappings":"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","names":[]}
|