@standardagents/spec 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1647,7 +1647,7 @@ interface ExecutionState {
1647
1647
  readonly stopped: boolean;
1648
1648
  /** Which side initiated the stop (if stopped) */
1649
1649
  readonly stoppedBy?: 'a' | 'b';
1650
- /** Message history loaded for current execution */
1650
+ /** Live chronological persisted history for the current execution */
1651
1651
  readonly messageHistory: Message[];
1652
1652
  /**
1653
1653
  * Force a specific side to play the next turn.
@@ -1873,6 +1873,12 @@ interface ThreadState {
1873
1873
  *
1874
1874
  * Creates a new message in the conversation history. This can be used
1875
1875
  * to add context, simulate user input, or insert assistant responses.
1876
+ * Runs `before_create_message` and `after_create_message`. If a
1877
+ * `before_create_message` hook throws, the returned promise rejects and
1878
+ * no message is persisted. During active execution, the persisted message
1879
+ * becomes immediately visible through `execution.messageHistory`.
1880
+ * `silent` controls client presentation only; silent messages remain
1881
+ * eligible for model context.
1876
1882
  *
1877
1883
  * @param message - The message to inject
1878
1884
  * @returns The created message
@@ -4269,1444 +4275,1533 @@ type PromptInput<T extends PromptDefinition<string, ToolArgs>> = T['requiredSche
4269
4275
  declare function definePrompt<N extends string, S extends ToolArgs = never>(options: PromptDefinition<N, S>): PromptDefinition<N, S>;
4270
4276
 
4271
4277
  /**
4272
- * Hook definition types for Standard Agents.
4273
- *
4274
- * Hooks allow intercepting and modifying agent behavior at key points
4275
- * in the execution lifecycle. They enable logging, validation,
4276
- * transformation, and side effects.
4278
+ * Agent definition types for Standard Agents.
4277
4279
  *
4278
- * Hooks receive ThreadState as their first parameter, providing full
4279
- * access to thread operations and execution state.
4280
+ * Agents orchestrate conversations between AI models (dual_ai) or between
4281
+ * AI and human users (ai_human). They define the prompts, stop conditions,
4282
+ * and behavioral rules for each side of the conversation.
4280
4283
  *
4281
4284
  * @module
4282
4285
  */
4283
-
4284
4286
  /**
4285
- * Hook context is ThreadState.
4286
- *
4287
- * Hooks receive the full ThreadState, which includes identity, message access,
4288
- * resource loading, event emission, and execution state (when available).
4287
+ * Agent conversation type.
4289
4288
  *
4290
- * @example
4291
- * ```typescript
4292
- * const hook = defineHook({
4293
- * hook: 'filter_messages',
4294
- * id: 'keep_recent',
4295
- * execute: async (state, messages) => {
4296
- * console.log(`Thread: ${state.threadId}`);
4297
- * if (state.execution) {
4298
- * console.log(`Step: ${state.execution.stepCount}`);
4299
- * }
4300
- * return messages.slice(-10);
4301
- * },
4302
- * });
4303
- * ```
4289
+ * - `ai_human`: AI conversing with a human user (most common)
4290
+ * - `dual_ai`: Two AI participants conversing with each other
4304
4291
  */
4305
- type HookContext = ThreadState;
4292
+ type AgentType = 'ai_human' | 'dual_ai';
4306
4293
  /**
4307
- * Message structure for hook processing.
4308
- *
4309
- * Re-exported from threads.ts for convenience.
4310
- * @see Message
4294
+ * Ordering position for a child agent's required hook on its parent.
4311
4295
  */
4312
- type HookMessage = Message;
4296
+ type ParentHookStage = 'before_parent' | 'after_parent';
4313
4297
  /**
4314
- * Tool call structure for hook processing.
4298
+ * A thread-scoped hook that a child agent requires on every direct parent.
4299
+ *
4300
+ * Downloading a package is inert. The hook becomes active automatically when
4301
+ * an enabled parent prompt exposes this `dual_ai` agent as a child tool, and
4302
+ * remains active for exactly the lifetime of that relationship.
4315
4303
  */
4316
- interface HookToolCall {
4317
- /** Unique tool call identifier */
4318
- id: string;
4319
- /** Always 'function' for tool calls */
4320
- type: 'function';
4321
- /** Function details */
4322
- function: {
4323
- /** Tool name */
4324
- name: string;
4325
- /** JSON-encoded arguments */
4326
- arguments: string;
4327
- };
4304
+ interface ParentHookRequirement<Hook extends string = StandardAgentSpec.HookIds> {
4305
+ /** Child-local hook ID from `defineHook({ id })`. */
4306
+ hook: Hook;
4307
+ /** Human-facing explanation shown by installers and composition UIs. */
4308
+ reason: string;
4309
+ /** Whether the hook runs before or after the parent's own hook set. */
4310
+ stage?: ParentHookStage;
4328
4311
  }
4329
4312
  /**
4330
- * Tool result structure for hook processing.
4313
+ * Configuration for a session lifecycle tool.
4314
+ *
4315
+ * Used by side-level lifecycle options (`sessionStop`, `sessionFail`, `sessionStatus`)
4316
+ * to declare:
4317
+ * - which tool controls that lifecycle action
4318
+ * - which tool-argument field should be forwarded as message text
4319
+ * - which tool-argument field contains attachment path(s) to forward
4320
+ *
4321
+ * @template Callable - Callable name type
4331
4322
  */
4332
- interface HookToolResult {
4333
- /** Execution status */
4334
- status: 'success' | 'error';
4335
- /** Result string (for successful executions) */
4336
- result?: string;
4337
- /** Error message (for failed executions) */
4338
- error?: string;
4339
- /** Stack trace (for debugging) */
4340
- stack?: string;
4323
+ interface SessionToolConfig<Callable extends string = StandardAgentSpec.Callables> {
4341
4324
  /**
4342
- * File attachments returned by the tool.
4343
- *
4344
- * Can contain either:
4345
- * - ToolAttachment: New files with base64 data to be stored
4346
- * - AttachmentRef: References to existing files in the thread filesystem
4325
+ * Tool name for this session lifecycle action.
4347
4326
  */
4348
- attachments?: Array<ToolAttachment | AttachmentRef>;
4327
+ name: Callable;
4328
+ /**
4329
+ * Optional tool-argument property used as lifecycle message text.
4330
+ */
4331
+ messageProperty?: string;
4332
+ /**
4333
+ * Optional tool-argument property containing attachment path(s).
4334
+ * Supports a single path string or an array of path strings.
4335
+ */
4336
+ attachmentsProperty?: string;
4349
4337
  }
4350
4338
  /**
4351
- * LLM message format for prefilter hook.
4339
+ * Session lifecycle tool reference.
4352
4340
  *
4353
- * Messages passed to the prefilter_llm_history hook are in chat completion
4354
- * format. Content can be a plain string or a multimodal array (for messages
4355
- * with images). Additional provider-specific fields may also be present.
4341
+ * Can be either:
4342
+ * - a plain tool name string (legacy/simple form)
4343
+ * - a {@link SessionToolConfig} object (explicit mapping form)
4356
4344
  */
4357
- interface LLMMessage {
4358
- /** Message role */
4359
- role: string;
4360
- /** Message content (string for text-only, array for multimodal) */
4361
- content?: string | null | unknown[];
4362
- /** Tool calls (parsed) */
4363
- tool_calls?: unknown;
4364
- /** Tool call ID */
4365
- tool_call_id?: string;
4366
- /** Tool name */
4367
- name?: string;
4368
- /** Reasoning content (for models like o1) */
4369
- reasoning_content?: string;
4370
- /** Allow additional provider-specific fields */
4371
- [key: string]: unknown;
4372
- }
4345
+ type SessionToolBinding<Callable extends string = StandardAgentSpec.Callables> = Callable | SessionToolConfig<Callable>;
4373
4346
  /**
4374
- * Hook signatures for all available hooks.
4347
+ * Configuration for one side of an agent conversation.
4375
4348
  *
4376
- * Each hook has a specific signature that defines when it's called
4377
- * and what data it receives. Hooks can modify data by returning
4378
- * transformed values or perform side effects.
4349
+ * Each side has a prompt, stop conditions, and turn limits.
4350
+ * For `ai_human` agents, only sideA (the AI) needs configuration.
4351
+ * For `dual_ai` agents, both sides need configuration.
4379
4352
  *
4380
- * All hooks receive ThreadState as their first parameter.
4353
+ * @template Prompt - The prompt reference type (string or type-safe union)
4354
+ * @template Callable - The callable reference type (string or type-safe union)
4381
4355
  *
4382
- * @template State - The state type (defaults to ThreadState)
4383
- * @template Msg - The message type (defaults to HookMessage)
4384
- * @template ToolCall - The tool call type (defaults to HookToolCall)
4385
- * @template ToolResult - The tool result type (defaults to HookToolResult)
4356
+ * @example
4357
+ * ```typescript
4358
+ * const sideConfig: SideConfig = {
4359
+ * label: 'Support Agent',
4360
+ * prompt: 'customer_support',
4361
+ * stopOnResponse: true,
4362
+ * maxSteps: 10,
4363
+ * };
4364
+ * ```
4386
4365
  */
4387
- interface HookSignatures<State = ThreadState, Msg = HookMessage, ToolCall = HookToolCall, ToolResult = HookToolResult> {
4366
+ interface SideConfig<Prompt extends string = StandardAgentSpec.Prompts, Callable extends string = StandardAgentSpec.Callables> {
4388
4367
  /**
4389
- * Called after a thread is created, before initial message processing or LLM
4390
- * requests for that thread.
4391
- *
4392
- * Only ThreadState is passed. Use for initializing durable thread values,
4393
- * env placeholders, files, or side-effect instrumentation.
4368
+ * Custom label for this side of the conversation.
4369
+ * Used in UI and logs for clarity.
4394
4370
  *
4395
- * @param state - Created thread state
4371
+ * @example 'Support Agent', 'Customer', 'ATC', 'Pilot'
4396
4372
  */
4397
- after_thread_created: (state: State) => Promise<void>;
4373
+ label?: string;
4398
4374
  /**
4399
- * Called on the parent thread immediately after a subagent child thread is
4400
- * created.
4401
- *
4402
- * Receives parent ThreadState and child ThreadState. Use for copying or
4403
- * linking metadata, bookkeeping, or side-effect instrumentation.
4404
- *
4405
- * @param state - Parent thread state
4406
- * @param childState - Created child thread state
4375
+ * The prompt to use for this side.
4376
+ * Must reference a prompt defined in agents/prompts/.
4407
4377
  */
4408
- after_subagent_created: (state: State, childState: State) => Promise<void>;
4378
+ prompt: Prompt;
4409
4379
  /**
4410
- * Called after the prompt system message is rendered for a model request.
4411
- *
4412
- * Return a string to replace the rendered system message. Return null or
4413
- * undefined to keep the original message.
4414
- *
4415
- * @param state - Thread state
4416
- * @param systemMessage - Rendered system message for this request
4417
- * @returns Replacement system message, or null/undefined for no change
4380
+ * Stop this side's turn when it returns a text response (no tool calls).
4381
+ * When true, the side's turn ends after producing a message without tools.
4382
+ * @default true
4383
+ */
4384
+ stopOnResponse?: boolean;
4385
+ /**
4386
+ * Stop this side's turn when a specific tool is called.
4387
+ * Overrides stopOnResponse when the named tool is invoked.
4388
+ * Requires stopToolResponseProperty to extract the result.
4418
4389
  */
4419
- after_system_message: (state: State, systemMessage: string) => string | Promise<string | null | undefined> | null | undefined;
4390
+ stopTool?: Callable;
4391
+ /**
4392
+ * Property to extract from the stop tool's result.
4393
+ * Required when stopTool is set.
4394
+ * The extracted value is used to determine the conversation outcome.
4395
+ */
4396
+ stopToolResponseProperty?: string;
4397
+ /**
4398
+ * Maximum steps for this side before forcing a stop.
4399
+ * Safety limit to prevent runaway execution.
4400
+ * A step is one complete LLM request/response cycle.
4401
+ */
4402
+ maxSteps?: number;
4420
4403
  /**
4421
- * Called before messages are filtered and sent to the LLM.
4404
+ * Tool that ends the entire session when called.
4422
4405
  *
4423
- * Receives raw message rows from storage before any transformation.
4424
- * Use for filtering, sorting, or augmenting message history.
4406
+ * Different from stopTool: this ends the session for both sides,
4407
+ * not just this side's turn.
4425
4408
  *
4426
- * @param state - Thread state
4427
- * @param messages - Array of messages from storage
4428
- * @returns Modified message array
4409
+ * Use object form to explicitly map message/attachment argument fields.
4429
4410
  *
4430
- * @example
4431
- * ```typescript
4432
- * defineHook({
4433
- * hook: 'filter_messages',
4434
- * id: 'limit_to_10',
4435
- * execute: async (state, messages) => messages.slice(-10),
4436
- * });
4437
- * ```
4411
+ * In subagent runtimes, mapped message/attachments are the canonical
4412
+ * completion payload returned from child -> parent.
4438
4413
  */
4439
- filter_messages: (state: State, messages: Msg[]) => Promise<Msg[]>;
4414
+ sessionStop?: SessionToolBinding<Callable>;
4440
4415
  /**
4441
- * Called after message history is loaded and before sending to LLM.
4416
+ * Tool that fails the entire session when called.
4442
4417
  *
4443
- * Receives messages already transformed into chat completion format.
4444
- * Use for final adjustments before LLM request.
4418
+ * Use this when the side cannot fulfill the request and needs to terminate
4419
+ * the session with an error outcome.
4445
4420
  *
4446
- * @param state - Thread state
4447
- * @param messages - Array of LLM-formatted messages
4448
- * @returns Modified LLM message array
4421
+ * When used inside a subagent, this failure is propagated back to the parent
4422
+ * as a terminal failure result.
4449
4423
  *
4450
- * @example
4451
- * ```typescript
4452
- * defineHook({
4453
- * hook: 'prefilter_llm_history',
4454
- * id: 'add_reminder',
4455
- * execute: async (state, messages) => messages,
4456
- * });
4457
- * ```
4424
+ * Use object form to explicitly map message/attachment argument fields.
4425
+ *
4426
+ * In subagent runtimes, mapped message/attachments are the canonical
4427
+ * failure payload returned from child -> parent.
4458
4428
  */
4459
- prefilter_llm_history: (state: State, messages: LLMMessage[]) => Promise<LLMMessage[]>;
4429
+ sessionFail?: SessionToolBinding<Callable>;
4460
4430
  /**
4461
- * Called before a message is created in the database.
4431
+ * Tool that publishes status updates to the parent thread when used as a subagent.
4462
4432
  *
4463
- * Receives the full message object before insertion. Return modified
4464
- * message to transform before storage.
4433
+ * When called from a `dual_ai` subagent, message text is forwarded to
4434
+ * the parent thread's subagent registry as this instance's current status.
4465
4435
  *
4466
- * @param state - Thread state
4467
- * @param message - Message to be created
4468
- * @returns Modified message
4436
+ * Use object form to explicitly map message/attachment argument fields.
4437
+ *
4438
+ * Status updates do not terminate the session.
4469
4439
  *
4470
4440
  * @example
4471
4441
  * ```typescript
4472
- * defineHook({
4473
- * hook: 'before_create_message',
4474
- * id: 'prefix_content',
4475
- * execute: async (state, message) => {
4476
- * // message has full type: id, role, content, created_at, etc.
4477
- * if (message.role === 'user' && message.content) {
4478
- * return { ...message, content: `[user] ${message.content}` };
4479
- * }
4480
- * return message;
4481
- * }
4482
- * });
4483
- * ```
4484
- */
4485
- before_create_message: (state: State, message: Msg) => Promise<Msg>;
4486
- /**
4487
- * Called after a message is created in the database.
4488
- *
4489
- * Use for logging, analytics, or triggering side effects after
4490
- * message creation. Cannot modify the message.
4491
- *
4492
- * @param state - Thread state
4493
- * @param message - The created message
4494
- *
4495
- * @example
4496
- * ```typescript
4497
- * defineHook({
4498
- * hook: 'after_create_message',
4499
- * id: 'log_creation',
4500
- * execute: async (state, message) => {
4501
- * console.log(`Created ${message.role} message: ${message.id}`);
4502
- * }
4503
- * });
4442
+ * sideA: {
4443
+ * prompt: 'research_worker',
4444
+ * sessionStatus: { name: 'update_status', messageProperty: 'status' },
4445
+ * }
4504
4446
  * ```
4505
4447
  */
4506
- after_create_message: (state: State, message: Msg) => Promise<void>;
4448
+ sessionStatus?: SessionToolBinding<Callable>;
4449
+ }
4450
+ /**
4451
+ * Agent definition configuration.
4452
+ *
4453
+ * @template N - The agent name as a string literal type
4454
+ * @template Prompt - The prompt reference type (string or type-safe union)
4455
+ * @template Callable - The callable reference type (string or type-safe union)
4456
+ *
4457
+ * @example
4458
+ * ```typescript
4459
+ * import { defineAgent } from '@standardagents/spec';
4460
+ *
4461
+ * export default defineAgent({
4462
+ * name: 'support_agent',
4463
+ * title: 'Customer Support Agent',
4464
+ * type: 'ai_human',
4465
+ * sideA: {
4466
+ * label: 'Support',
4467
+ * prompt: 'customer_support',
4468
+ * stopOnResponse: true,
4469
+ * },
4470
+ * });
4471
+ * ```
4472
+ */
4473
+ interface AgentDefinition<N extends string = string, Prompt extends string = StandardAgentSpec.Prompts, Callable extends string = StandardAgentSpec.Callables> {
4474
+ /**
4475
+ * Unique name for this agent.
4476
+ * Used as the identifier for thread creation and handoffs.
4477
+ * Should be snake_case (e.g., 'support_agent', 'research_flow').
4478
+ */
4479
+ name: N;
4507
4480
  /**
4508
- * Called before a message is updated in the database.
4509
- *
4510
- * Receives the message ID and update data. Return modified updates
4511
- * to transform the changes before storage.
4481
+ * Human-readable title for the agent.
4482
+ * Optional - if not provided, the name will be used.
4483
+ * @deprecated Use name instead. Title will be removed in a future version.
4484
+ */
4485
+ title?: string;
4486
+ /**
4487
+ * Agent conversation type.
4512
4488
  *
4513
- * @param state - Thread state
4514
- * @param messageId - ID of message being updated
4515
- * @param updates - Update data
4516
- * @returns Modified update data
4489
+ * - `ai_human`: AI conversing with a human user (default)
4490
+ * - `dual_ai`: Two AI participants conversing
4517
4491
  *
4518
- * @example
4519
- * ```typescript
4520
- * defineHook({
4521
- * hook: 'before_update_message',
4522
- * id: 'stamp_updated_at',
4523
- * execute: async (state, messageId, updates) => ({
4524
- * ...updates,
4525
- * updated_at: Date.now(),
4526
- * }),
4527
- * });
4528
- * ```
4492
+ * @default 'ai_human'
4529
4493
  */
4530
- before_update_message: (state: State, messageId: string, updates: Record<string, unknown>) => Promise<Record<string, unknown>>;
4494
+ type?: AgentType;
4531
4495
  /**
4532
- * Called after a message is updated in the database.
4533
- *
4534
- * Use for logging, analytics, or triggering side effects after
4535
- * message update. Cannot modify the message.
4496
+ * Maximum total turns across both sides.
4497
+ * Only applies to `dual_ai` agents.
4498
+ * Prevents infinite loops in AI-to-AI conversations.
4499
+ */
4500
+ maxSessionTurns?: number;
4501
+ /**
4502
+ * Configuration for Side A.
4503
+ * For `ai_human`: This is the AI side.
4504
+ * For `dual_ai`: This is the first AI participant.
4505
+ */
4506
+ sideA: SideConfig<Prompt, Callable>;
4507
+ /**
4508
+ * Configuration for Side B.
4509
+ * For `ai_human`: Optional, the human side doesn't need config.
4510
+ * For `dual_ai`: Required, the second AI participant.
4511
+ */
4512
+ sideB?: SideConfig<Prompt, Callable>;
4513
+ /**
4514
+ * Expose this agent as a tool for other prompts.
4515
+ * Enables agent composition and handoffs.
4516
+ * When true, other prompts can invoke this agent as a tool.
4517
+ * @default false
4518
+ */
4519
+ exposeAsTool?: boolean;
4520
+ /**
4521
+ * Whether this agent is a PRIMARY, user-facing entry point (default true).
4536
4522
  *
4537
- * @param state - Thread state
4538
- * @param message - The updated message
4523
+ * Set `primary: false` on agents that exist only as internal handoff
4524
+ * targets or infrastructure — e.g. the specialist variants of a
4525
+ * domain-routing gearbox. Non-primary agents remain fully addressable
4526
+ * (handoffs, invokeTool, thread resumption) and their threads remain
4527
+ * visible; UIs use this flag to keep them out of top-level agent lists
4528
+ * and pickers so one logical product agent doesn't show up N times.
4529
+ */
4530
+ primary?: boolean;
4531
+ /**
4532
+ * Description shown when agent is used as a tool.
4533
+ * Required if exposeAsTool is true.
4534
+ * Should clearly describe what this agent does.
4535
+ */
4536
+ toolDescription?: string;
4537
+ /**
4538
+ * Brief description of what this agent does.
4539
+ * Useful for UIs and documentation.
4539
4540
  *
4540
- * @example
4541
- * ```typescript
4542
- * defineHook({
4543
- * hook: 'after_update_message',
4544
- * id: 'log_update',
4545
- * execute: async (state, message) => {
4546
- * console.log(`Message updated: ${message.id}`);
4547
- * },
4548
- * });
4549
- * ```
4541
+ * @example 'Handles customer support inquiries and resolves issues'
4550
4542
  */
4551
- after_update_message: (state: State, message: Msg) => Promise<void>;
4543
+ description?: string;
4552
4544
  /**
4553
- * Called before a tool result is stored in the database.
4545
+ * Icon URL or absolute path for the agent.
4546
+ * Absolute paths (starting with `/`) are converted to full URLs in API responses.
4554
4547
  *
4555
- * Receives the tool call and result before storage. Return modified
4556
- * result to transform before storage.
4548
+ * @example 'https://example.com/icon.svg' or '/icons/support.svg'
4549
+ */
4550
+ icon?: string;
4551
+ /**
4552
+ * Environment values provided by this agent.
4553
+ * Agent values are lower priority than thread/account/instance values.
4554
+ */
4555
+ env?: Record<string, string>;
4556
+ /**
4557
+ * @deprecated Use `env` instead.
4558
+ */
4559
+ tenvs?: Record<string, unknown>;
4560
+ /**
4561
+ * npm package name for this agent when packed.
4562
+ * Used by the packing system to maintain consistent package identity
4563
+ * across pack/unpack cycles.
4557
4564
  *
4558
- * @param state - Thread state
4559
- * @param toolCall - The tool call that was executed
4560
- * @param toolResult - The result from tool execution
4561
- * @returns Modified tool result
4565
+ * @example 'standardagent-support-agent', '@myorg/support-agent'
4566
+ */
4567
+ packageName?: string;
4568
+ /**
4569
+ * Package version (semver format).
4570
+ * Used by the packing system to track versions across pack/unpack cycles.
4571
+ * When re-packing, this version is auto-incremented by the pack modal.
4562
4572
  *
4563
- * @example
4564
- * ```typescript
4565
- * defineHook({
4566
- * hook: 'before_store_tool_result',
4567
- * id: 'sanitize_results',
4568
- * execute: async (state, toolCall, toolResult) => {
4569
- * // toolCall has: id, type, function.name, function.arguments
4570
- * // toolResult has: status, result?, error?, stack?, attachments?
4571
- * if (toolResult.result) {
4572
- * return { ...toolResult, result: sanitize(toolResult.result) };
4573
- * }
4574
- * return toolResult;
4575
- * }
4576
- * });
4577
- * ```
4573
+ * @example '1.0.0', '2.3.1-beta.1'
4578
4574
  */
4579
- before_store_tool_result: (state: State, toolCall: ToolCall, toolResult: ToolResult) => Promise<ToolResult>;
4575
+ version?: string;
4580
4576
  /**
4581
- * Called after a successful tool call.
4577
+ * Package author/copyright holder.
4578
+ * Used by the packing system for the LICENSE file and package.json author field.
4582
4579
  *
4583
- * Receives the tool call and its result. Can return a modified result
4584
- * or null to use the original. Use for logging, transformation, or
4585
- * post-processing of successful tool executions.
4580
+ * @example 'John Doe', 'Acme Corp'
4581
+ */
4582
+ author?: string;
4583
+ /**
4584
+ * License identifier (SPDX format).
4585
+ * Used by the packing system for LICENSE file generation.
4586
4586
  *
4587
- * @param state - Thread state
4588
- * @param toolCall - The executed tool call
4589
- * @param toolResult - The successful result
4590
- * @returns Modified result or null for original
4587
+ * @example 'MIT', 'Apache-2.0', 'ISC'
4588
+ */
4589
+ license?: string;
4590
+ /**
4591
+ * Hook IDs to run for this agent.
4592
+ * References hooks by their unique `id` property from defineHook().
4593
+ * These run when prompts don't specify their own hooks.
4591
4594
  *
4592
4595
  * @example
4593
4596
  * ```typescript
4594
- * defineHook({
4595
- * hook: 'after_tool_call_success',
4596
- * id: 'log_success',
4597
- * execute: async (state, toolCall, toolResult) => {
4598
- * console.log(`Tool ${toolCall.function.name} succeeded`);
4599
- * return null; // use original result
4600
- * },
4601
- * });
4597
+ * hooks: ['log_messages', 'track_tool_usage']
4602
4598
  * ```
4603
4599
  */
4604
- after_tool_call_success: (state: State, toolCall: ToolCall, toolResult: ToolResult) => Promise<ToolResult | null>;
4600
+ hooks?: StandardAgentSpec.HookIds[];
4605
4601
  /**
4606
- * Called after a failed tool call.
4607
- *
4608
- * Receives the tool call and error result. Can return a modified result
4609
- * or null to use the original. Use for error handling, logging, or
4610
- * recovery attempts.
4602
+ * Hooks this agent requires on a direct parent when composed as a `dual_ai`
4603
+ * child tool.
4611
4604
  *
4612
- * @param state - Thread state
4613
- * @param toolCall - The failed tool call
4614
- * @param toolResult - The error result
4615
- * @returns Modified result or null for original
4605
+ * Adding an enabled relationship activates these hooks automatically;
4606
+ * downloading the package alone does not. Hooks execute against the
4607
+ * parent's ThreadState and are resolved in this agent's package namespace.
4608
+ * `reason` is required so composition tooling can disclose the behavior.
4616
4609
  *
4617
4610
  * @example
4618
4611
  * ```typescript
4619
- * defineHook({
4620
- * hook: 'after_tool_call_failure',
4621
- * id: 'log_failure',
4622
- * execute: async (state, toolCall, toolResult) => {
4623
- * console.error(`Tool ${toolCall.function.name} failed: ${toolResult.error}`);
4624
- * return null; // use original error
4625
- * },
4626
- * });
4612
+ * parentHooks: [{
4613
+ * hook: 'context_compaction',
4614
+ * reason: 'Compacts the parent history before its context limit is reached.',
4615
+ * stage: 'after_parent',
4616
+ * }]
4627
4617
  * ```
4628
4618
  */
4629
- after_tool_call_failure: (state: State, toolCall: ToolCall, toolResult: ToolResult) => Promise<ToolResult | null>;
4630
- /**
4631
- * Called when a tool call STARTS — before the tool executes, while the model
4632
- * may still be generating the rest of the call. Fires exactly once per tool
4633
- * call. Observational: the return value is ignored.
4634
- *
4635
- * Timing depends on whether the tool declares a `progressArgument`:
4636
- * - **With** `progressArgument`: fires as soon as *just that argument* has
4637
- * finished streaming (not the whole call), passing its value as `progress`.
4638
- * This lets a UI show "fixing index.html" before a large `content` argument
4639
- * finishes generating.
4640
- * - **Without** `progressArgument`: fires as soon as the tool call appears in
4641
- * the stream — its name is known but `toolCall.function.arguments` may be an
4642
- * incomplete JSON fragment (or empty), and `progress` is undefined.
4643
- *
4644
- * Conforming runtimes also broadcast a `tool_call_started` thread event to
4645
- * connected clients with `{ id, name, progress }` at the same moment.
4646
- *
4647
- * @param state - Thread state
4648
- * @param toolCall - The starting tool call; `function.arguments` may be incomplete
4649
- * @param progress - The declared progress-argument value, when available
4650
- *
4651
- * @example
4652
- * ```typescript
4653
- * defineHook({
4654
- * hook: 'tool_call_started',
4655
- * id: 'log_tool_start',
4656
- * execute: async (state, toolCall, progress) => {
4657
- * console.log(`▸ ${toolCall.function.name}${progress ? `: ${progress}` : ''}`);
4658
- * },
4659
- * });
4660
- * ```
4661
- */
4662
- tool_call_started: (state: State, toolCall: ToolCall, progress?: string) => Promise<void>;
4663
- /**
4664
- * Called when a tool call is DONE — after it has executed, with its result,
4665
- * regardless of success or failure. Fires once per tool call. Observational:
4666
- * the return value is ignored.
4667
- *
4668
- * This complements `after_tool_call_success` / `after_tool_call_failure`,
4669
- * which can additionally *modify* the stored result; `tool_call_done` is a
4670
- * single unified observation point that always fires. Conforming runtimes
4671
- * also broadcast a `tool_call_done` thread event to connected clients with
4672
- * `{ id, name, status }` at the same moment.
4673
- *
4674
- * @param state - Thread state
4675
- * @param toolCall - The completed tool call
4676
- * @param toolResult - The tool's result (`status` is `'success'` or `'error'`)
4677
- */
4678
- tool_call_done: (state: State, toolCall: ToolCall, toolResult: ToolResult) => Promise<void>;
4679
- /**
4680
- * Called when a socket attaches to the user's event stream
4681
- * (`{runtime_prefix}/users/me/stream`).
4682
- *
4683
- * @param user - User scope state
4684
- * @param client - The attached client's id and self-declared kind
4685
- */
4686
- user_client_attached: (user: UserState, client: UserClientInfo) => Promise<void>;
4687
- /**
4688
- * Called when a socket detaches from the user's event stream.
4689
- *
4690
- * @param user - User scope state
4691
- * @param client - The detached client's id and self-declared kind
4692
- */
4693
- user_client_detached: (user: UserState, client: UserClientInfo) => Promise<void>;
4694
- /**
4695
- * Called after a durable user value changes, regardless of the writer
4696
- * (user endpoint, thread-side handle, or REST).
4697
- *
4698
- * @param user - User scope state
4699
- * @param key - The key that changed
4700
- */
4701
- user_value_changed: (user: UserState, key: string) => Promise<void>;
4702
- }
4703
- /**
4704
- * Valid hook names.
4705
- */
4706
- type HookName = keyof HookSignatures;
4707
- /**
4708
- * Hook definition tuple.
4709
- *
4710
- * A hook definition is a tuple containing the hook name and implementation.
4711
- *
4712
- * @template K - The hook name
4713
- * @template State - The state type (defaults to ThreadState)
4714
- * @template Msg - The message type
4715
- * @template ToolCall - The tool call type
4716
- * @template ToolResult - The tool result type
4717
- * @deprecated Use the object-based defineHook signature instead
4718
- */
4719
- type HookDefinition<K extends HookName = HookName, State = ThreadState, Msg = HookMessage, ToolCall = HookToolCall, ToolResult = HookToolResult> = [K, HookSignatures<State, Msg, ToolCall, ToolResult>[K]];
4720
- /**
4721
- * Options for defining a hook with explicit ID.
4722
- * The generic K ensures `execute` is properly typed for the specific hook type.
4723
- *
4724
- * @template K - Hook type from HookSignatures (e.g., 'filter_messages')
4725
- */
4726
- interface HookDefinitionOptions<K extends HookName> {
4727
- /** The hook type (e.g., 'filter_messages', 'before_create_message') */
4728
- hook: K;
4729
- /** Unique identifier for this hook implementation (snake_case) */
4730
- id: string;
4731
- /**
4732
- * The hook implementation function.
4733
- * Type is automatically inferred from the hook type.
4734
- */
4735
- execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];
4736
- }
4737
- /**
4738
- * Return type from defineHook - preserves the hook type for type-safe usage.
4739
- *
4740
- * @template K - Hook type from HookSignatures
4741
- */
4742
- interface HookDefinitionResult<K extends HookName> {
4743
- /** The hook type name */
4744
- hook: K;
4745
- /** The unique hook ID */
4746
- id: string;
4747
- /** The typed execute function */
4748
- execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];
4619
+ parentHooks?: ParentHookRequirement[];
4749
4620
  }
4750
4621
  /**
4751
- * Define a hook with a unique identifier and strict typing.
4622
+ * Defines an agent configuration.
4752
4623
  *
4753
- * The hook type determines the execute function signature.
4754
- * TypeScript will enforce correct parameter and return types.
4624
+ * Agents orchestrate conversations between AI models, or between AI and
4625
+ * human users. They use prompts to configure each side of the conversation
4626
+ * and define stop conditions to control conversation flow.
4755
4627
  *
4756
- * @template K - The hook type (inferred from options.hook)
4757
- * @param options - Hook definition with hook type, ID, and execute function
4758
- * @returns Typed hook definition for registration
4628
+ * @template N - The agent name as a string literal type
4629
+ * @param options - Agent configuration options
4630
+ * @returns The agent definition for registration
4759
4631
  *
4760
4632
  * @example
4761
4633
  * ```typescript
4762
- * // Filter messages - execute receives (state: ThreadState, messages: HookMessage[])
4763
- * export default defineHook({
4764
- * hook: 'filter_messages',
4765
- * id: 'limit_to_20_messages',
4766
- * execute: async (state, messages) => {
4767
- * return messages.slice(-20);
4768
- * }
4769
- * });
4770
- * ```
4634
+ * // agents/agents/support_agent.ts
4635
+ * import { defineAgent } from '@standardagents/spec';
4771
4636
  *
4772
- * @example
4773
- * ```typescript
4774
- * // Before create message - execute receives (state: ThreadState, message: Message)
4775
- * export default defineHook({
4776
- * hook: 'before_create_message',
4777
- * id: 'prefix_content',
4778
- * execute: async (state, message) => {
4779
- * if (message.role === 'user' && message.content) {
4780
- * return { ...message, content: `[user] ${message.content}` };
4781
- * }
4782
- * return message;
4783
- * }
4637
+ * export default defineAgent({
4638
+ * name: 'support_agent',
4639
+ * title: 'Customer Support Agent',
4640
+ * type: 'ai_human',
4641
+ * sideA: {
4642
+ * label: 'Support',
4643
+ * prompt: 'customer_support',
4644
+ * stopOnResponse: true,
4645
+ * sessionStop: 'close_ticket',
4646
+ * },
4647
+ * exposeAsTool: true,
4648
+ * toolDescription: 'Hand off to customer support',
4784
4649
  * });
4785
4650
  * ```
4786
4651
  *
4787
4652
  * @example
4788
4653
  * ```typescript
4789
- * // After tool call success - execute receives (state, toolCall, toolResult)
4790
- * export default defineHook({
4791
- * hook: 'after_tool_call_success',
4792
- * id: 'log_tool_usage',
4793
- * execute: async (state, toolCall, toolResult) => {
4794
- * console.log(`Tool ${toolCall.function.name} returned: ${toolResult.result}`);
4795
- * return null; // Use original result
4796
- * }
4654
+ * // Dual AI agent (two AIs conversing)
4655
+ * export default defineAgent({
4656
+ * name: 'debate_agent',
4657
+ * title: 'AI Debate',
4658
+ * type: 'dual_ai',
4659
+ * maxSessionTurns: 10,
4660
+ * sideA: {
4661
+ * label: 'Pro',
4662
+ * prompt: 'debate_pro',
4663
+ * stopOnResponse: true,
4664
+ * },
4665
+ * sideB: {
4666
+ * label: 'Con',
4667
+ * prompt: 'debate_con',
4668
+ * stopOnResponse: true,
4669
+ * sessionStop: 'conclude_debate',
4670
+ * },
4797
4671
  * });
4798
4672
  * ```
4799
4673
  */
4800
- declare function defineHook<K extends HookName>(options: HookDefinitionOptions<K>): HookDefinitionResult<K>;
4674
+ declare function defineAgent<N extends string>(options: AgentDefinition<N>): AgentDefinition<N>;
4801
4675
 
4802
4676
  /**
4803
- * Agent definition types for Standard Agents.
4677
+ * Endpoint definition types for Standard Agents.
4804
4678
  *
4805
- * Agents orchestrate conversations between AI models (dual_ai) or between
4806
- * AI and human users (ai_human). They define the prompts, stop conditions,
4807
- * and behavioral rules for each side of the conversation.
4679
+ * Endpoints expose HTTP APIs for interacting with agent threads.
4680
+ * They can be standard controllers or thread-specific endpoints
4681
+ * with automatic ThreadState injection.
4808
4682
  *
4809
4683
  * @module
4810
4684
  */
4685
+
4811
4686
  /**
4812
- * Agent conversation type.
4687
+ * The access level of an endpoint.
4813
4688
  *
4814
- * - `ai_human`: AI conversing with a human user (most common)
4815
- * - `dual_ai`: Two AI participants conversing with each other
4689
+ * - `authenticated` — the runtime MUST authenticate the request before
4690
+ * invoking the handler, and for thread endpoints MUST additionally enforce
4691
+ * its thread access policy. Requests that fail authentication or
4692
+ * authorization MUST be rejected without invoking the handler.
4693
+ * - `public` — the runtime MUST invoke the handler regardless of the
4694
+ * request's authentication state. The runtime MUST still attempt caller
4695
+ * resolution: a request presenting credentials the runtime can verify is
4696
+ * attributed to that caller, and any other request is treated as anonymous
4697
+ * rather than rejected.
4698
+ *
4699
+ * When no access level is declared, the access level is `authenticated`.
4816
4700
  */
4817
- type AgentType = 'ai_human' | 'dual_ai';
4701
+ type EndpointAccess = 'authenticated' | 'public';
4818
4702
  /**
4819
- * Configuration for a session lifecycle tool.
4820
- *
4821
- * Used by side-level lifecycle options (`sessionStop`, `sessionFail`, `sessionStatus`)
4822
- * to declare:
4823
- * - which tool controls that lifecycle action
4824
- * - which tool-argument field should be forwarded as message text
4825
- * - which tool-argument field contains attachment path(s) to forward
4703
+ * Symbol used to carry an endpoint's declared access level.
4826
4704
  *
4827
- * @template Callable - Callable name type
4705
+ * The declaration is attached to the handler at definition time so that
4706
+ * runtimes can read it before routing the request through their
4707
+ * authentication layer.
4828
4708
  */
4829
- interface SessionToolConfig<Callable extends string = StandardAgentSpec.Callables> {
4830
- /**
4831
- * Tool name for this session lifecycle action.
4832
- */
4833
- name: Callable;
4834
- /**
4835
- * Optional tool-argument property used as lifecycle message text.
4836
- */
4837
- messageProperty?: string;
4709
+ declare const ENDPOINT_ACCESS_SYMBOL: unique symbol;
4710
+ /**
4711
+ * Options accepted when defining an endpoint.
4712
+ */
4713
+ interface EndpointOptions {
4838
4714
  /**
4839
- * Optional tool-argument property containing attachment path(s).
4840
- * Supports a single path string or an array of path strings.
4715
+ * The endpoint's access level. Defaults to `authenticated`.
4841
4716
  */
4842
- attachmentsProperty?: string;
4717
+ access?: EndpointAccess;
4843
4718
  }
4844
4719
  /**
4845
- * Session lifecycle tool reference.
4720
+ * Resolve the declared access level of an endpoint handler.
4846
4721
  *
4847
- * Can be either:
4848
- * - a plain tool name string (legacy/simple form)
4849
- * - a {@link SessionToolConfig} object (explicit mapping form)
4722
+ * Returns `authenticated` when the value carries no declaration.
4850
4723
  */
4851
- type SessionToolBinding<Callable extends string = StandardAgentSpec.Callables> = Callable | SessionToolConfig<Callable>;
4724
+ declare function getEndpointAccess(value: unknown): EndpointAccess;
4852
4725
  /**
4853
- * Configuration for one side of an agent conversation.
4854
- *
4855
- * Each side has a prompt, stop conditions, and turn limits.
4856
- * For `ai_human` agents, only sideA (the AI) needs configuration.
4857
- * For `dual_ai` agents, both sides need configuration.
4726
+ * The authentication context supplied to a thread endpoint handler.
4858
4727
  *
4859
- * @template Prompt - The prompt reference type (string or type-safe union)
4860
- * @template Callable - The callable reference type (string or type-safe union)
4728
+ * The runtime constructs this context for every invocation:
4861
4729
  *
4862
- * @example
4863
- * ```typescript
4864
- * const sideConfig: SideConfig = {
4865
- * label: 'Support Agent',
4866
- * prompt: 'customer_support',
4867
- * stopOnResponse: true,
4868
- * maxSteps: 10,
4869
- * };
4870
- * ```
4730
+ * - `caller` MUST be the authenticated identity when the request presented
4731
+ * credentials the runtime verified, and `null` otherwise. For an endpoint
4732
+ * whose access level is `authenticated`, `caller` is always non-null.
4733
+ * - `threadAccess` MUST be `true` if and only if the runtime's thread access
4734
+ * policy grants the resolved caller access to the requested thread. It
4735
+ * MUST be `false` when `caller` is `null`. For an endpoint whose access
4736
+ * level is `authenticated`, `threadAccess` is always `true`.
4737
+ *
4738
+ * The mechanism by which a runtime authenticates requests is
4739
+ * implementation-defined; this interface defines only the identity contract
4740
+ * observable by endpoint code.
4871
4741
  */
4872
- interface SideConfig<Prompt extends string = StandardAgentSpec.Prompts, Callable extends string = StandardAgentSpec.Callables> {
4873
- /**
4874
- * Custom label for this side of the conversation.
4875
- * Used in UI and logs for clarity.
4876
- *
4877
- * @example 'Support Agent', 'Customer', 'ATC', 'Pilot'
4878
- */
4879
- label?: string;
4880
- /**
4881
- * The prompt to use for this side.
4882
- * Must reference a prompt defined in agents/prompts/.
4883
- */
4884
- prompt: Prompt;
4885
- /**
4886
- * Stop this side's turn when it returns a text response (no tool calls).
4887
- * When true, the side's turn ends after producing a message without tools.
4888
- * @default true
4889
- */
4890
- stopOnResponse?: boolean;
4891
- /**
4892
- * Stop this side's turn when a specific tool is called.
4893
- * Overrides stopOnResponse when the named tool is invoked.
4894
- * Requires stopToolResponseProperty to extract the result.
4895
- */
4896
- stopTool?: Callable;
4897
- /**
4898
- * Property to extract from the stop tool's result.
4899
- * Required when stopTool is set.
4900
- * The extracted value is used to determine the conversation outcome.
4901
- */
4902
- stopToolResponseProperty?: string;
4903
- /**
4904
- * Maximum steps for this side before forcing a stop.
4905
- * Safety limit to prevent runaway execution.
4906
- * A step is one complete LLM request/response cycle.
4907
- */
4908
- maxSteps?: number;
4909
- /**
4910
- * Tool that ends the entire session when called.
4911
- *
4912
- * Different from stopTool: this ends the session for both sides,
4913
- * not just this side's turn.
4914
- *
4915
- * Use object form to explicitly map message/attachment argument fields.
4916
- *
4917
- * In subagent runtimes, mapped message/attachments are the canonical
4918
- * completion payload returned from child -> parent.
4919
- */
4920
- sessionStop?: SessionToolBinding<Callable>;
4742
+ interface ThreadEndpointAuth {
4743
+ /** The authenticated caller, or `null` for an anonymous request. */
4744
+ caller: ThreadUser | null;
4745
+ /** Whether the caller satisfies the runtime's access policy for the requested thread. */
4746
+ threadAccess: boolean;
4747
+ }
4748
+ /**
4749
+ * Symbol used to identify thread endpoint handlers.
4750
+ *
4751
+ * When a handler is created with defineThreadEndpoint, it's marked with this
4752
+ * symbol so the runtime can detect it and wrap it with proper ThreadState injection.
4753
+ */
4754
+ declare const THREAD_ENDPOINT_SYMBOL: unique symbol;
4755
+ /**
4756
+ * A controller that has been marked as a thread endpoint.
4757
+ *
4758
+ * The runtime detects this marker and wraps the handler with ThreadState injection.
4759
+ * The `__handler` property contains the original handler function that expects
4760
+ * `(req: Request, state: ThreadState)` arguments.
4761
+ */
4762
+ interface MarkedThreadEndpoint extends Controller {
4763
+ /** Marker symbol indicating this is a thread endpoint */
4764
+ [THREAD_ENDPOINT_SYMBOL]: true;
4765
+ /** The original handler function before wrapping */
4766
+ __handler: ThreadEndpointHandler;
4767
+ }
4768
+ /**
4769
+ * Type guard to check if a controller is a marked thread endpoint.
4770
+ */
4771
+ declare function isThreadEndpoint(controller: Controller): controller is MarkedThreadEndpoint;
4772
+ /**
4773
+ * Virtual module loader function.
4774
+ *
4775
+ * Lazy-loads a module definition on demand.
4776
+ */
4777
+ type VirtualModuleLoader<T> = () => Promise<T>;
4778
+ /**
4779
+ * Registry of virtual modules by name.
4780
+ *
4781
+ * Maps module names to their lazy loaders.
4782
+ */
4783
+ type VirtualModuleRegistry<T> = Record<string, VirtualModuleLoader<T>>;
4784
+ /**
4785
+ * Controller context passed to route handlers.
4786
+ *
4787
+ * Contains the request, URL parameters, environment bindings,
4788
+ * and optionally the virtual module registries injected at runtime.
4789
+ *
4790
+ * Note: The `env` property contains implementation-specific bindings.
4791
+ * Its shape is defined by the runtime — typical surfaces include handles
4792
+ * to storage, queues, key-value stores, or other platform resources the
4793
+ * runtime chooses to expose.
4794
+ */
4795
+ interface ControllerContext {
4796
+ /** The incoming HTTP request */
4797
+ req: Request;
4921
4798
  /**
4922
- * Tool that fails the entire session when called.
4923
- *
4924
- * Use this when the side cannot fulfill the request and needs to terminate
4925
- * the session with an error outcome.
4926
- *
4927
- * When used inside a subagent, this failure is propagated back to the parent
4928
- * as a terminal failure result.
4929
- *
4930
- * Use object form to explicitly map message/attachment argument fields.
4799
+ * The authenticated caller, or `null` for an anonymous request.
4931
4800
  *
4932
- * In subagent runtimes, mapped message/attachments are the canonical
4933
- * failure payload returned from child -> parent.
4801
+ * Populated under the same contract as {@link ThreadEndpointAuth.caller}:
4802
+ * non-null whenever the request presented credentials the runtime
4803
+ * verified, and always non-null for a controller whose access level is
4804
+ * `authenticated`.
4934
4805
  */
4935
- sessionFail?: SessionToolBinding<Callable>;
4806
+ caller?: ThreadUser | null;
4807
+ /** URL path parameters extracted by the router */
4808
+ params: Record<string, string>;
4809
+ /** Parsed URL object */
4810
+ url: URL;
4936
4811
  /**
4937
- * Tool that publishes status updates to the parent thread when used as a subagent.
4938
- *
4939
- * When called from a `dual_ai` subagent, message text is forwarded to
4940
- * the parent thread's subagent registry as this instance's current status.
4941
- *
4942
- * Use object form to explicitly map message/attachment argument fields.
4943
- *
4944
- * Status updates do not terminate the session.
4812
+ * Environment bindings (implementation-specific).
4945
4813
  *
4946
- * @example
4947
- * ```typescript
4948
- * sideA: {
4949
- * prompt: 'research_worker',
4950
- * sessionStatus: { name: 'update_status', messageProperty: 'status' },
4951
- * }
4952
- * ```
4814
+ * Contains platform-specific bindings — handles to storage,
4815
+ * queues, key-value stores, or other resources the runtime exposes.
4816
+ * The exact contents depend on the runtime implementation.
4953
4817
  */
4954
- sessionStatus?: SessionToolBinding<Callable>;
4818
+ env: Record<string, unknown>;
4819
+ /** Registry of agent definitions (injected at runtime) */
4820
+ agents?: VirtualModuleRegistry<unknown>;
4821
+ /** Available agent names */
4822
+ agentNames?: string[];
4823
+ /** Registry of prompt definitions (injected at runtime) */
4824
+ prompts?: VirtualModuleRegistry<unknown>;
4825
+ /** Available prompt names */
4826
+ promptNames?: string[];
4827
+ /** Registry of model definitions (injected at runtime) */
4828
+ models?: VirtualModuleRegistry<unknown>;
4829
+ /** Available model names */
4830
+ modelNames?: string[];
4831
+ /** Registry of tool definitions (injected at runtime) */
4832
+ tools?: VirtualModuleRegistry<unknown>;
4833
+ /** Registry of hook definitions (injected at runtime) */
4834
+ hooks?: VirtualModuleRegistry<unknown>;
4835
+ /** Additional configuration (injected at runtime) */
4836
+ config?: Record<string, unknown>;
4955
4837
  }
4956
4838
  /**
4957
- * Agent definition configuration.
4839
+ * Controller return types.
4958
4840
  *
4959
- * @template N - The agent name as a string literal type
4960
- * @template Prompt - The prompt reference type (string or type-safe union)
4961
- * @template Callable - The callable reference type (string or type-safe union)
4841
+ * Controllers can return various types that are automatically
4842
+ * converted to appropriate HTTP responses.
4843
+ */
4844
+ type ControllerReturn = string | Promise<string> | Response | Promise<Response> | ReadableStream | Promise<ReadableStream> | null | Promise<null> | void | Promise<void> | Promise<object> | object;
4845
+ /**
4846
+ * Controller function type.
4847
+ *
4848
+ * Controllers handle HTTP requests and return responses.
4849
+ * The return value is automatically converted to a Response.
4962
4850
  *
4963
4851
  * @example
4964
4852
  * ```typescript
4965
- * import { defineAgent } from '@standardagents/spec';
4853
+ * const handler: Controller = async ({ req, params, url }) => {
4854
+ * return { message: 'Hello, World!' };
4855
+ * };
4856
+ * ```
4857
+ */
4858
+ type Controller = (context: ControllerContext) => ControllerReturn;
4859
+ /**
4860
+ * Thread endpoint handler function.
4966
4861
  *
4967
- * export default defineAgent({
4968
- * name: 'support_agent',
4969
- * title: 'Customer Support Agent',
4970
- * type: 'ai_human',
4971
- * sideA: {
4972
- * label: 'Support',
4973
- * prompt: 'customer_support',
4974
- * stopOnResponse: true,
4975
- * },
4862
+ * Receives the HTTP request and the ThreadState for the requested thread.
4863
+ * The supplied ThreadState includes the standard thread surface, including
4864
+ * `runCode`. The thread is automatically looked up by ID from URL parameters. Route
4865
+ * parameters are derived from the endpoint file path. For a dynamic segment
4866
+ * such as `[id].ts`, `params.id` contains the matched segment. For a catch-all
4867
+ * segment `[*].ts`, `params['*']` contains the unmatched path suffix,
4868
+ * including `/` separators when the match spans multiple segments.
4869
+ *
4870
+ * Thread endpoint routes are scoped beneath the runtime's thread ID prefix.
4871
+ * A request under that prefix that does not match any local or packed thread
4872
+ * endpoint route MUST return HTTP 404.
4873
+ *
4874
+ * The fourth argument carries the request's authentication context under the
4875
+ * contract defined by {@link ThreadEndpointAuth}. Handlers that do not
4876
+ * consume it may omit the parameter.
4877
+ */
4878
+ type ThreadEndpointRouteParams = Record<string, string>;
4879
+ type ThreadEndpointHandler = (req: Request, state: ThreadState, params: ThreadEndpointRouteParams, auth: ThreadEndpointAuth) => Response | Promise<Response>;
4880
+ /**
4881
+ * Define a standard HTTP controller.
4882
+ *
4883
+ * Controllers handle HTTP requests and return responses. They have
4884
+ * access to the controller context including virtual module registries.
4885
+ *
4886
+ * A controller's access level is declared through `options.access` and
4887
+ * defaults to `authenticated`; see {@link EndpointAccess} for the
4888
+ * requirements each level places on the runtime.
4889
+ *
4890
+ * @param controller - The controller function
4891
+ * @param options - Endpoint options, including the access level
4892
+ * @returns The controller for registration
4893
+ *
4894
+ * @example
4895
+ * ```typescript
4896
+ * // agents/api/health.get.ts
4897
+ * import { defineController } from '@standardagents/spec';
4898
+ *
4899
+ * export default defineController(async () => {
4900
+ * return { status: 'ok', timestamp: Date.now() };
4976
4901
  * });
4977
4902
  * ```
4978
- */
4979
- interface AgentDefinition<N extends string = string, Prompt extends string = StandardAgentSpec.Prompts, Callable extends string = StandardAgentSpec.Callables> {
4980
- /**
4981
- * Unique name for this agent.
4982
- * Used as the identifier for thread creation and handoffs.
4983
- * Should be snake_case (e.g., 'support_agent', 'research_flow').
4984
- */
4985
- name: N;
4986
- /**
4987
- * Human-readable title for the agent.
4988
- * Optional - if not provided, the name will be used.
4989
- * @deprecated Use name instead. Title will be removed in a future version.
4990
- */
4991
- title?: string;
4992
- /**
4993
- * Agent conversation type.
4994
- *
4995
- * - `ai_human`: AI conversing with a human user (default)
4996
- * - `dual_ai`: Two AI participants conversing
4997
- *
4998
- * @default 'ai_human'
4999
- */
5000
- type?: AgentType;
5001
- /**
5002
- * Maximum total turns across both sides.
5003
- * Only applies to `dual_ai` agents.
5004
- * Prevents infinite loops in AI-to-AI conversations.
5005
- */
5006
- maxSessionTurns?: number;
5007
- /**
5008
- * Configuration for Side A.
5009
- * For `ai_human`: This is the AI side.
5010
- * For `dual_ai`: This is the first AI participant.
5011
- */
5012
- sideA: SideConfig<Prompt, Callable>;
5013
- /**
5014
- * Configuration for Side B.
5015
- * For `ai_human`: Optional, the human side doesn't need config.
5016
- * For `dual_ai`: Required, the second AI participant.
5017
- */
5018
- sideB?: SideConfig<Prompt, Callable>;
5019
- /**
5020
- * Expose this agent as a tool for other prompts.
5021
- * Enables agent composition and handoffs.
5022
- * When true, other prompts can invoke this agent as a tool.
5023
- * @default false
5024
- */
5025
- exposeAsTool?: boolean;
5026
- /**
5027
- * Whether this agent is a PRIMARY, user-facing entry point (default true).
5028
- *
5029
- * Set `primary: false` on agents that exist only as internal handoff
5030
- * targets or infrastructure — e.g. the specialist variants of a
5031
- * domain-routing gearbox. Non-primary agents remain fully addressable
5032
- * (handoffs, invokeTool, thread resumption) and their threads remain
5033
- * visible; UIs use this flag to keep them out of top-level agent lists
5034
- * and pickers so one logical product agent doesn't show up N times.
5035
- */
5036
- primary?: boolean;
5037
- /**
5038
- * Description shown when agent is used as a tool.
5039
- * Required if exposeAsTool is true.
5040
- * Should clearly describe what this agent does.
5041
- */
5042
- toolDescription?: string;
5043
- /**
5044
- * Brief description of what this agent does.
5045
- * Useful for UIs and documentation.
5046
- *
5047
- * @example 'Handles customer support inquiries and resolves issues'
5048
- */
5049
- description?: string;
5050
- /**
5051
- * Icon URL or absolute path for the agent.
5052
- * Absolute paths (starting with `/`) are converted to full URLs in API responses.
5053
- *
5054
- * @example 'https://example.com/icon.svg' or '/icons/support.svg'
5055
- */
5056
- icon?: string;
5057
- /**
5058
- * Environment values provided by this agent.
5059
- * Agent values are lower priority than thread/account/instance values.
5060
- */
5061
- env?: Record<string, string>;
5062
- /**
5063
- * @deprecated Use `env` instead.
5064
- */
5065
- tenvs?: Record<string, unknown>;
5066
- /**
5067
- * npm package name for this agent when packed.
5068
- * Used by the packing system to maintain consistent package identity
5069
- * across pack/unpack cycles.
5070
- *
5071
- * @example 'standardagent-support-agent', '@myorg/support-agent'
5072
- */
5073
- packageName?: string;
5074
- /**
5075
- * Package version (semver format).
5076
- * Used by the packing system to track versions across pack/unpack cycles.
5077
- * When re-packing, this version is auto-incremented by the pack modal.
5078
- *
5079
- * @example '1.0.0', '2.3.1-beta.1'
5080
- */
5081
- version?: string;
5082
- /**
5083
- * Package author/copyright holder.
5084
- * Used by the packing system for the LICENSE file and package.json author field.
5085
- *
5086
- * @example 'John Doe', 'Acme Corp'
5087
- */
5088
- author?: string;
5089
- /**
5090
- * License identifier (SPDX format).
5091
- * Used by the packing system for LICENSE file generation.
5092
- *
5093
- * @example 'MIT', 'Apache-2.0', 'ISC'
5094
- */
5095
- license?: string;
5096
- /**
5097
- * Hook IDs to run for this agent.
5098
- * References hooks by their unique `id` property from defineHook().
5099
- * These run when prompts don't specify their own hooks.
5100
- *
5101
- * @example
5102
- * ```typescript
5103
- * hooks: ['log_messages', 'track_tool_usage']
5104
- * ```
5105
- */
5106
- hooks?: StandardAgentSpec.HookIds[];
5107
- }
4903
+ *
4904
+ * @example
4905
+ * ```typescript
4906
+ * // agents/api/agents/index.get.ts
4907
+ * import { defineController } from '@standardagents/spec';
4908
+ *
4909
+ * export default defineController(async ({ agentNames }) => {
4910
+ * return { agents: agentNames };
4911
+ * });
4912
+ * ```
4913
+ */
4914
+ declare function defineController(controller: Controller, options?: EndpointOptions): Controller;
5108
4915
  /**
5109
- * Defines an agent configuration.
4916
+ * Define a thread-specific endpoint.
5110
4917
  *
5111
- * Agents orchestrate conversations between AI models, or between AI and
5112
- * human users. They use prompts to configure each side of the conversation
5113
- * and define stop conditions to control conversation flow.
4918
+ * Thread endpoints automatically look up the thread by ID from URL params
4919
+ * and provide access to the ThreadState. The handler receives full
4920
+ * ThreadState with messages, logs, resource loading, event emission,
4921
+ * and (when executing) execution state.
5114
4922
  *
5115
- * @template N - The agent name as a string literal type
5116
- * @param options - Agent configuration options
5117
- * @returns The agent definition for registration
4923
+ * Runtimes MUST return HTTP 404 for requests beneath the thread endpoint
4924
+ * prefix that do not match any local or packed thread endpoint route.
4925
+ *
4926
+ * A thread endpoint's access level is declared through `options.access` and
4927
+ * defaults to `authenticated`; see {@link EndpointAccess} for the
4928
+ * requirements each level places on the runtime. Handlers receive the
4929
+ * request's authentication context as their fourth argument under the
4930
+ * contract defined by {@link ThreadEndpointAuth}.
4931
+ *
4932
+ * @param handler - The handler function receiving request, ThreadState, route params, and authentication context
4933
+ * @param options - Endpoint options, including the access level
4934
+ * @returns A Controller that can be used with the router
5118
4935
  *
5119
4936
  * @example
5120
4937
  * ```typescript
5121
- * // agents/agents/support_agent.ts
5122
- * import { defineAgent } from '@standardagents/spec';
4938
+ * // agents/api/status.ts
4939
+ * import { defineThreadEndpoint } from '@standardagents/spec';
5123
4940
  *
5124
- * export default defineAgent({
5125
- * name: 'support_agent',
5126
- * title: 'Customer Support Agent',
5127
- * type: 'ai_human',
5128
- * sideA: {
5129
- * label: 'Support',
5130
- * prompt: 'customer_support',
5131
- * stopOnResponse: true,
5132
- * sessionStop: 'close_ticket',
5133
- * },
5134
- * exposeAsTool: true,
5135
- * toolDescription: 'Hand off to customer support',
4941
+ * export default defineThreadEndpoint(async (req, state) => {
4942
+ * const { messages, total } = await state.getMessages({ limit: 1 });
4943
+ * return Response.json({
4944
+ * threadId: state.threadId,
4945
+ * agent: state.agentId,
4946
+ * messageCount: total,
4947
+ * });
5136
4948
  * });
5137
4949
  * ```
5138
4950
  *
5139
4951
  * @example
5140
4952
  * ```typescript
5141
- * // Dual AI agent (two AIs conversing)
5142
- * export default defineAgent({
5143
- * name: 'debate_agent',
5144
- * title: 'AI Debate',
5145
- * type: 'dual_ai',
5146
- * maxSessionTurns: 10,
5147
- * sideA: {
5148
- * label: 'Pro',
5149
- * prompt: 'debate_pro',
5150
- * stopOnResponse: true,
5151
- * },
5152
- * sideB: {
5153
- * label: 'Con',
5154
- * prompt: 'debate_con',
5155
- * stopOnResponse: true,
5156
- * sessionStop: 'conclude_debate',
5157
- * },
4953
+ * // agents/api/export.ts
4954
+ * import { defineThreadEndpoint } from '@standardagents/spec';
4955
+ *
4956
+ * export default defineThreadEndpoint(async (req, state) => {
4957
+ * const { messages } = await state.getMessages();
4958
+ * return Response.json({
4959
+ * thread: {
4960
+ * id: state.threadId,
4961
+ * agent: state.agentId,
4962
+ * user: state.userId,
4963
+ * createdAt: state.createdAt,
4964
+ * },
4965
+ * messages,
4966
+ * });
5158
4967
  * });
5159
4968
  * ```
5160
- */
5161
- declare function defineAgent<N extends string>(options: AgentDefinition<N>): AgentDefinition<N>;
5162
-
5163
- /**
5164
- * Endpoint definition types for Standard Agents.
5165
4969
  *
5166
- * Endpoints expose HTTP APIs for interacting with agent threads.
5167
- * They can be standard controllers or thread-specific endpoints
5168
- * with automatic ThreadState injection.
5169
- *
5170
- * @module
5171
- */
5172
-
5173
- /**
5174
- * The access level of an endpoint.
4970
+ * @example
4971
+ * ```typescript
4972
+ * // agents/api/invoke.post.ts
4973
+ * import { defineThreadEndpoint } from '@standardagents/spec';
5175
4974
  *
5176
- * - `authenticated` — the runtime MUST authenticate the request before
5177
- * invoking the handler, and for thread endpoints MUST additionally enforce
5178
- * its thread access policy. Requests that fail authentication or
5179
- * authorization MUST be rejected without invoking the handler.
5180
- * - `public` — the runtime MUST invoke the handler regardless of the
5181
- * request's authentication state. The runtime MUST still attempt caller
5182
- * resolution: a request presenting credentials the runtime can verify is
5183
- * attributed to that caller, and any other request is treated as anonymous
5184
- * rather than rejected.
4975
+ * export default defineThreadEndpoint(async (req, state) => {
4976
+ * const { tool, args } = await req.json();
5185
4977
  *
5186
- * When no access level is declared, the access level is `authenticated`.
5187
- */
5188
- type EndpointAccess = 'authenticated' | 'public';
5189
- /**
5190
- * Symbol used to carry an endpoint's declared access level.
4978
+ * // Queue a tool for execution (starts execution if not running)
4979
+ * state.queueTool(tool, args);
5191
4980
  *
5192
- * The declaration is attached to the handler at definition time so that
5193
- * runtimes can read it before routing the request through their
5194
- * authentication layer.
5195
- */
5196
- declare const ENDPOINT_ACCESS_SYMBOL: unique symbol;
5197
- /**
5198
- * Options accepted when defining an endpoint.
5199
- */
5200
- interface EndpointOptions {
5201
- /**
5202
- * The endpoint's access level. Defaults to `authenticated`.
5203
- */
5204
- access?: EndpointAccess;
5205
- }
5206
- /**
5207
- * Resolve the declared access level of an endpoint handler.
4981
+ * return Response.json({ queued: true });
4982
+ * });
4983
+ * ```
5208
4984
  *
5209
- * Returns `authenticated` when the value carries no declaration.
5210
- */
5211
- declare function getEndpointAccess(value: unknown): EndpointAccess;
5212
- /**
5213
- * The authentication context supplied to a thread endpoint handler.
4985
+ * @example
4986
+ * ```typescript
4987
+ * // agents/api/files/[id].ts
4988
+ * import { defineThreadEndpoint } from '@standardagents/spec';
5214
4989
  *
5215
- * The runtime constructs this context for every invocation:
4990
+ * export default defineThreadEndpoint(async (req, state, params) => {
4991
+ * const file = await state.readFile(`/files/${params.id}.json`);
4992
+ * return Response.json({ exists: !!file });
4993
+ * });
4994
+ * ```
5216
4995
  *
5217
- * - `caller` MUST be the authenticated identity when the request presented
5218
- * credentials the runtime verified, and `null` otherwise. For an endpoint
5219
- * whose access level is `authenticated`, `caller` is always non-null.
5220
- * - `threadAccess` MUST be `true` if and only if the runtime's thread access
5221
- * policy grants the resolved caller access to the requested thread. It
5222
- * MUST be `false` when `caller` is `null`. For an endpoint whose access
5223
- * level is `authenticated`, `threadAccess` is always `true`.
4996
+ * @example
4997
+ * ```typescript
4998
+ * // agents/api/status.ts
4999
+ * import { defineThreadEndpoint } from '@standardagents/spec';
5224
5000
  *
5225
- * The mechanism by which a runtime authenticates requests is
5226
- * implementation-defined; this interface defines only the identity contract
5227
- * observable by endpoint code.
5001
+ * export default defineThreadEndpoint(
5002
+ * async (req, state, params, auth) => {
5003
+ * return Response.json({
5004
+ * threadId: state.threadId,
5005
+ * authorized: auth.threadAccess,
5006
+ * });
5007
+ * },
5008
+ * { access: 'public' }
5009
+ * );
5010
+ * ```
5228
5011
  */
5229
- interface ThreadEndpointAuth {
5230
- /** The authenticated caller, or `null` for an anonymous request. */
5231
- caller: ThreadUser | null;
5232
- /** Whether the caller satisfies the runtime's access policy for the requested thread. */
5233
- threadAccess: boolean;
5234
- }
5012
+ declare function defineThreadEndpoint(handler: ThreadEndpointHandler, options?: EndpointOptions): MarkedThreadEndpoint;
5013
+
5235
5014
  /**
5236
- * Symbol used to identify thread endpoint handlers.
5015
+ * Packing types for Standard Agents.
5237
5016
  *
5238
- * When a handler is created with defineThreadEndpoint, it's marked with this
5239
- * symbol so the runtime can detect it and wrap it with proper ThreadState injection.
5017
+ * Defines types for packaging agents with their dependencies into
5018
+ * reusable, encapsulated packages that can be published to npm
5019
+ * or stored locally.
5020
+ *
5021
+ * @module
5240
5022
  */
5241
- declare const THREAD_ENDPOINT_SYMBOL: unique symbol;
5242
5023
  /**
5243
- * A controller that has been marked as a thread endpoint.
5024
+ * Package signature applied to packed definitions.
5244
5025
  *
5245
- * The runtime detects this marker and wraps the handler with ThreadState injection.
5246
- * The `__handler` property contains the original handler function that expects
5247
- * `(req: Request, state: ThreadState)` arguments.
5026
+ * When an agent and its dependencies are packed, each definition
5027
+ * receives this signature marking it as belonging to a specific package.
5028
+ * This enables namespace isolation during execution.
5029
+ *
5030
+ * @example
5031
+ * ```typescript
5032
+ * const signature: PackageSignature = {
5033
+ * packageId: 'standardagent-my-workflow',
5034
+ * version: '1.0.0',
5035
+ * source: 'npm',
5036
+ * packedAt: Date.now(),
5037
+ * };
5038
+ * ```
5248
5039
  */
5249
- interface MarkedThreadEndpoint extends Controller {
5250
- /** Marker symbol indicating this is a thread endpoint */
5251
- [THREAD_ENDPOINT_SYMBOL]: true;
5252
- /** The original handler function before wrapping */
5253
- __handler: ThreadEndpointHandler;
5040
+ interface PackageSignature {
5041
+ /** Unique package identifier (npm name or local identifier) */
5042
+ packageId: string;
5043
+ /** Package version */
5044
+ version: string;
5045
+ /** Source type */
5046
+ source: 'npm' | 'local';
5047
+ /** When packed (timestamp in milliseconds) */
5048
+ packedAt: number;
5254
5049
  }
5255
5050
  /**
5256
- * Type guard to check if a controller is a marked thread endpoint.
5051
+ * Global namespace context - for unpacked code.
5052
+ *
5053
+ * Unpacked code sees:
5054
+ * - All unpacked tools, prompts, models, hooks
5055
+ * - Packed agent entry points (agents with exposeAsTool: true)
5056
+ * - NOT internal packed tools/prompts (those are hidden)
5257
5057
  */
5258
- declare function isThreadEndpoint(controller: Controller): controller is MarkedThreadEndpoint;
5058
+ interface GlobalNamespaceContext {
5059
+ type: 'global';
5060
+ }
5259
5061
  /**
5260
- * Virtual module loader function.
5062
+ * Packed namespace context - for code inside a packed agent.
5261
5063
  *
5262
- * Lazy-loads a module definition on demand.
5064
+ * Packed code sees:
5065
+ * - Only items within its own package (by packageId)
5066
+ * - Other packed agent entry points (for handoffs)
5067
+ * - NOT unpacked global code
5263
5068
  */
5264
- type VirtualModuleLoader<T> = () => Promise<T>;
5069
+ interface PackedNamespaceContext {
5070
+ type: 'packed';
5071
+ /** Package ID this code belongs to */
5072
+ packageId: string;
5073
+ }
5265
5074
  /**
5266
- * Registry of virtual modules by name.
5075
+ * Namespace context for execution.
5076
+ * Determines what items are visible during execution.
5267
5077
  *
5268
- * Maps module names to their lazy loaders.
5078
+ * @example
5079
+ * ```typescript
5080
+ * // Global namespace (unpacked code)
5081
+ * const globalNs: NamespaceContext = { type: 'global' };
5082
+ *
5083
+ * // Packed namespace (inside a packed agent)
5084
+ * const packedNs: NamespaceContext = {
5085
+ * type: 'packed',
5086
+ * packageId: 'standardagent-my-workflow',
5087
+ * };
5088
+ * ```
5269
5089
  */
5270
- type VirtualModuleRegistry<T> = Record<string, VirtualModuleLoader<T>>;
5090
+ type NamespaceContext = GlobalNamespaceContext | PackedNamespaceContext;
5271
5091
  /**
5272
- * Controller context passed to route handlers.
5273
- *
5274
- * Contains the request, URL parameters, environment bindings,
5275
- * and optionally the virtual module registries injected at runtime.
5092
+ * Extended metadata for packed definitions.
5276
5093
  *
5277
- * Note: The `env` property contains implementation-specific bindings.
5278
- * Its shape is defined by the runtime — typical surfaces include handles
5279
- * to storage, queues, key-value stores, or other platform resources the
5280
- * runtime chooses to expose.
5094
+ * This interface is added to agent, prompt, tool, model, and hook
5095
+ * definitions when they are packed. It marks them as belonging
5096
+ * to a specific package and optionally as readonly.
5281
5097
  */
5282
- interface ControllerContext {
5283
- /** The incoming HTTP request */
5284
- req: Request;
5098
+ interface PackedMetadata {
5285
5099
  /**
5286
- * The authenticated caller, or `null` for an anonymous request.
5287
- *
5288
- * Populated under the same contract as {@link ThreadEndpointAuth.caller}:
5289
- * non-null whenever the request presented credentials the runtime
5290
- * verified, and always non-null for a controller whose access level is
5291
- * `authenticated`.
5100
+ * Package signature if this definition is part of a packed agent.
5101
+ * Undefined for unpacked (global) definitions.
5292
5102
  */
5293
- caller?: ThreadUser | null;
5294
- /** URL path parameters extracted by the router */
5295
- params: Record<string, string>;
5296
- /** Parsed URL object */
5297
- url: URL;
5103
+ __package?: PackageSignature;
5298
5104
  /**
5299
- * Environment bindings (implementation-specific).
5300
- *
5301
- * Contains platform-specific bindings — handles to storage,
5302
- * queues, key-value stores, or other resources the runtime exposes.
5303
- * The exact contents depend on the runtime implementation.
5105
+ * Whether this definition is readonly (cannot be edited in UI).
5106
+ * Packed definitions are typically readonly.
5304
5107
  */
5305
- env: Record<string, unknown>;
5306
- /** Registry of agent definitions (injected at runtime) */
5307
- agents?: VirtualModuleRegistry<unknown>;
5308
- /** Available agent names */
5309
- agentNames?: string[];
5310
- /** Registry of prompt definitions (injected at runtime) */
5311
- prompts?: VirtualModuleRegistry<unknown>;
5312
- /** Available prompt names */
5313
- promptNames?: string[];
5314
- /** Registry of model definitions (injected at runtime) */
5315
- models?: VirtualModuleRegistry<unknown>;
5316
- /** Available model names */
5317
- modelNames?: string[];
5318
- /** Registry of tool definitions (injected at runtime) */
5319
- tools?: VirtualModuleRegistry<unknown>;
5320
- /** Registry of hook definitions (injected at runtime) */
5321
- hooks?: VirtualModuleRegistry<unknown>;
5322
- /** Additional configuration (injected at runtime) */
5323
- config?: Record<string, unknown>;
5108
+ __readonly?: boolean;
5324
5109
  }
5325
5110
  /**
5326
- * Controller return types.
5111
+ * Helper type to check if a definition is packed.
5112
+ */
5113
+ declare function isPacked(metadata: PackedMetadata | undefined): metadata is PackedMetadata & {
5114
+ __package: PackageSignature;
5115
+ };
5116
+ /**
5117
+ * Helper to check if a definition belongs to a specific package.
5118
+ */
5119
+ declare function belongsToPackage(metadata: PackedMetadata | undefined, packageId: string): boolean;
5120
+ /**
5121
+ * Helper to check if a definition is visible in a given namespace.
5327
5122
  *
5328
- * Controllers can return various types that are automatically
5329
- * converted to appropriate HTTP responses.
5123
+ * @param metadata - The definition's packed metadata
5124
+ * @param namespace - The current namespace context
5125
+ * @param isEntryPoint - Whether this is an agent with exposeAsTool: true
5330
5126
  */
5331
- type ControllerReturn = string | Promise<string> | Response | Promise<Response> | ReadableStream | Promise<ReadableStream> | null | Promise<null> | void | Promise<void> | Promise<object> | object;
5127
+ declare function isVisibleInNamespace(metadata: PackedMetadata | undefined, namespace: NamespaceContext, isEntryPoint?: boolean): boolean;
5332
5128
  /**
5333
- * Controller function type.
5129
+ * Metadata export for packed packages.
5334
5130
  *
5335
- * Controllers handle HTTP requests and return responses.
5336
- * The return value is automatically converted to a Response.
5131
+ * This is exported as `__meta` from the packed package's index.ts,
5132
+ * replacing the manifest.json file from the old format.
5133
+ *
5134
+ * A packed package's required execution behavior must use capabilities
5135
+ * defined by the Standard Agent Specification. It must not depend on private
5136
+ * runtime RPCs, storage schemas, bindings, undocumented events, sidecars that
5137
+ * replace runtime primitives, or `ThreadState._notPackableRuntimeContext`.
5337
5138
  *
5338
5139
  * @example
5339
5140
  * ```typescript
5340
- * const handler: Controller = async ({ req, params, url }) => {
5341
- * return { message: 'Hello, World!' };
5141
+ * export const __meta: PackedMeta = {
5142
+ * packageId: 'standardagent-my-workflow',
5143
+ * version: '1.0.0',
5144
+ * entryAgents: ['my_agent'],
5145
+ * packedAt: 1705012800000,
5342
5146
  * };
5343
5147
  * ```
5344
5148
  */
5345
- type Controller = (context: ControllerContext) => ControllerReturn;
5346
- /**
5347
- * Thread endpoint handler function.
5348
- *
5349
- * Receives the HTTP request and the ThreadState for the requested thread.
5350
- * The supplied ThreadState includes the standard thread surface, including
5351
- * `runCode`. The thread is automatically looked up by ID from URL parameters. Route
5352
- * parameters are derived from the endpoint file path. For a dynamic segment
5353
- * such as `[id].ts`, `params.id` contains the matched segment. For a catch-all
5354
- * segment `[*].ts`, `params['*']` contains the unmatched path suffix,
5355
- * including `/` separators when the match spans multiple segments.
5356
- *
5357
- * Thread endpoint routes are scoped beneath the runtime's thread ID prefix.
5358
- * A request under that prefix that does not match any local or packed thread
5359
- * endpoint route MUST return HTTP 404.
5360
- *
5361
- * The fourth argument carries the request's authentication context under the
5362
- * contract defined by {@link ThreadEndpointAuth}. Handlers that do not
5363
- * consume it may omit the parameter.
5364
- */
5365
- type ThreadEndpointRouteParams = Record<string, string>;
5366
- type ThreadEndpointHandler = (req: Request, state: ThreadState, params: ThreadEndpointRouteParams, auth: ThreadEndpointAuth) => Response | Promise<Response>;
5149
+ interface PackedMeta {
5150
+ /** Unique package identifier (npm name or local identifier) */
5151
+ packageId: string;
5152
+ /** Package version (semver) */
5153
+ version: string;
5154
+ /** Entry agents exposed as tools (visible from outside the package) */
5155
+ entryAgents: string[];
5156
+ /** When the package was packed (timestamp in milliseconds) */
5157
+ packedAt: number;
5158
+ /** Optional description from the entry agent */
5159
+ description?: string;
5160
+ /**
5161
+ * Required parent-hook disclosures keyed by entry agent name.
5162
+ * This duplicates the executable agent definitions so installers can show
5163
+ * composition effects without importing package code.
5164
+ */
5165
+ parentHooks?: Record<string, ParentHookRequirement[]>;
5166
+ }
5367
5167
  /**
5368
- * Define a standard HTTP controller.
5369
- *
5370
- * Controllers handle HTTP requests and return responses. They have
5371
- * access to the controller context including virtual module registries.
5372
- *
5373
- * A controller's access level is declared through `options.access` and
5374
- * defaults to `authenticated`; see {@link EndpointAccess} for the
5375
- * requirements each level places on the runtime.
5376
- *
5377
- * @param controller - The controller function
5378
- * @param options - Endpoint options, including the access level
5379
- * @returns The controller for registration
5380
- *
5381
- * @example
5382
- * ```typescript
5383
- * // agents/api/health.get.ts
5384
- * import { defineController } from '@standardagents/spec';
5168
+ * Lazy loader type for packed definitions.
5385
5169
  *
5386
- * export default defineController(async () => {
5387
- * return { status: 'ok', timestamp: Date.now() };
5388
- * });
5389
- * ```
5170
+ * Each definition in a packed package is wrapped in a function
5171
+ * that returns a Promise, enabling lazy loading.
5390
5172
  *
5391
5173
  * @example
5392
5174
  * ```typescript
5393
- * // agents/api/agents/index.get.ts
5394
- * import { defineController } from '@standardagents/spec';
5395
- *
5396
- * export default defineController(async ({ agentNames }) => {
5397
- * return { agents: agentNames };
5398
- * });
5175
+ * export const tools = {
5176
+ * search: async (): Promise<ToolDefinition> => ({
5177
+ * description: 'Search for information',
5178
+ * execute: async (state, args) => { ... },
5179
+ * }),
5180
+ * } as const;
5399
5181
  * ```
5400
5182
  */
5401
- declare function defineController(controller: Controller, options?: EndpointOptions): Controller;
5183
+ type DefinitionLoader<T> = () => Promise<T>;
5184
+
5402
5185
  /**
5403
- * Define a thread-specific endpoint.
5404
- *
5405
- * Thread endpoints automatically look up the thread by ID from URL params
5406
- * and provide access to the ThreadState. The handler receives full
5407
- * ThreadState with messages, logs, resource loading, event emission,
5408
- * and (when executing) execution state.
5409
- *
5410
- * Runtimes MUST return HTTP 404 for requests beneath the thread endpoint
5411
- * prefix that do not match any local or packed thread endpoint route.
5412
- *
5413
- * A thread endpoint's access level is declared through `options.access` and
5414
- * defaults to `authenticated`; see {@link EndpointAccess} for the
5415
- * requirements each level places on the runtime. Handlers receive the
5416
- * request's authentication context as their fourth argument under the
5417
- * contract defined by {@link ThreadEndpointAuth}.
5418
- *
5419
- * @param handler - The handler function receiving request, ThreadState, route params, and authentication context
5420
- * @param options - Endpoint options, including the access level
5421
- * @returns A Controller that can be used with the router
5422
- *
5423
- * @example
5424
- * ```typescript
5425
- * // agents/api/status.ts
5426
- * import { defineThreadEndpoint } from '@standardagents/spec';
5186
+ * Standard shape for packed package exports.
5427
5187
  *
5428
- * export default defineThreadEndpoint(async (req, state) => {
5429
- * const { messages, total } = await state.getMessages({ limit: 1 });
5430
- * return Response.json({
5431
- * threadId: state.threadId,
5432
- * agent: state.agentId,
5433
- * messageCount: total,
5434
- * });
5435
- * });
5436
- * ```
5188
+ * Every packed package exports this structure, enabling
5189
+ * consistent discovery and loading.
5437
5190
  *
5438
5191
  * @example
5439
5192
  * ```typescript
5440
- * // agents/api/export.ts
5441
- * import { defineThreadEndpoint } from '@standardagents/spec';
5193
+ * import type { PackedExports } from '@standardagents/spec';
5442
5194
  *
5443
- * export default defineThreadEndpoint(async (req, state) => {
5444
- * const { messages } = await state.getMessages();
5445
- * return Response.json({
5446
- * thread: {
5447
- * id: state.threadId,
5448
- * agent: state.agentId,
5449
- * user: state.userId,
5450
- * createdAt: state.createdAt,
5451
- * },
5452
- * messages,
5453
- * });
5454
- * });
5195
+ * const pkg: PackedExports = await import('standardagent-my-workflow');
5196
+ * const tool = await pkg.tools.search();
5455
5197
  * ```
5198
+ */
5199
+ interface PackedExports {
5200
+ /** Agent definitions, keyed by name */
5201
+ agents: Record<string, DefinitionLoader<AgentDefinition>>;
5202
+ /** Prompt definitions, keyed by name */
5203
+ prompts: Record<string, DefinitionLoader<PromptDefinition>>;
5204
+ /** Tool definitions, keyed by name */
5205
+ tools: Record<string, DefinitionLoader<ToolDefinition<unknown, any, any>>>;
5206
+ /** Model definitions, keyed by name */
5207
+ models: Record<string, DefinitionLoader<ModelDefinition>>;
5208
+ /** Hook definitions, keyed by name */
5209
+ hooks: Record<string, DefinitionLoader<HookDefinitionResult<HookName>>>;
5210
+ /**
5211
+ * Effect definitions, keyed by name.
5212
+ *
5213
+ * Optional for backward compatibility with previously packed packages.
5214
+ */
5215
+ effects?: Record<string, DefinitionLoader<EffectDefinition<any, any>>>;
5216
+ /**
5217
+ * Thread endpoint handlers, keyed by packed route key (for example, `status.get`).
5218
+ *
5219
+ * Runtimes mount these beneath the same thread ID prefix as local thread
5220
+ * endpoints, using the packed route key to derive the endpoint path.
5221
+ * Requests beneath that prefix that do not match any local or packed thread
5222
+ * endpoint route MUST return HTTP 404.
5223
+ *
5224
+ * Optional for backward compatibility with previously packed packages.
5225
+ */
5226
+ threadEndpoints?: Record<string, DefinitionLoader<MarkedThreadEndpoint | Controller>>;
5227
+ /** Package metadata */
5228
+ __meta: PackedMeta;
5229
+ }
5230
+
5231
+ /**
5232
+ * Hook definition types for Standard Agents.
5456
5233
  *
5457
- * @example
5458
- * ```typescript
5459
- * // agents/api/invoke.post.ts
5460
- * import { defineThreadEndpoint } from '@standardagents/spec';
5461
- *
5462
- * export default defineThreadEndpoint(async (req, state) => {
5463
- * const { tool, args } = await req.json();
5464
- *
5465
- * // Queue a tool for execution (starts execution if not running)
5466
- * state.queueTool(tool, args);
5234
+ * Hooks allow intercepting and modifying agent behavior at key points
5235
+ * in the execution lifecycle. They enable logging, validation,
5236
+ * transformation, and side effects.
5467
5237
  *
5468
- * return Response.json({ queued: true });
5469
- * });
5470
- * ```
5238
+ * Thread hooks receive ThreadState as their first parameter and deterministic
5239
+ * execution provenance as their final parameter, providing full access to
5240
+ * thread operations and the reason each hook is active.
5471
5241
  *
5472
- * @example
5473
- * ```typescript
5474
- * // agents/api/files/[id].ts
5475
- * import { defineThreadEndpoint } from '@standardagents/spec';
5242
+ * @module
5243
+ */
5244
+
5245
+ /**
5246
+ * Hook context is ThreadState.
5476
5247
  *
5477
- * export default defineThreadEndpoint(async (req, state, params) => {
5478
- * const file = await state.readFile(`/files/${params.id}.json`);
5479
- * return Response.json({ exists: !!file });
5480
- * });
5481
- * ```
5248
+ * Hooks receive the full ThreadState, which includes identity, message access,
5249
+ * resource loading, event emission, and execution state (when available).
5482
5250
  *
5483
5251
  * @example
5484
5252
  * ```typescript
5485
- * // agents/api/status.ts
5486
- * import { defineThreadEndpoint } from '@standardagents/spec';
5487
- *
5488
- * export default defineThreadEndpoint(
5489
- * async (req, state, params, auth) => {
5490
- * return Response.json({
5491
- * threadId: state.threadId,
5492
- * authorized: auth.threadAccess,
5493
- * });
5253
+ * const hook = defineHook({
5254
+ * hook: 'filter_messages',
5255
+ * id: 'keep_recent',
5256
+ * execute: async (state, messages) => {
5257
+ * console.log(`Thread: ${state.threadId}`);
5258
+ * if (state.execution) {
5259
+ * console.log(`Step: ${state.execution.stepCount}`);
5260
+ * }
5261
+ * return messages.slice(-10);
5494
5262
  * },
5495
- * { access: 'public' }
5496
- * );
5263
+ * });
5497
5264
  * ```
5498
5265
  */
5499
- declare function defineThreadEndpoint(handler: ThreadEndpointHandler, options?: EndpointOptions): MarkedThreadEndpoint;
5500
-
5266
+ type HookContext = ThreadState;
5501
5267
  /**
5502
- * Packing types for Standard Agents.
5503
- *
5504
- * Defines types for packaging agents with their dependencies into
5505
- * reusable, encapsulated packages that can be published to npm
5506
- * or stored locally.
5268
+ * Describes why a thread-scoped hook is active for the current invocation.
5507
5269
  *
5508
- * @module
5270
+ * Parent hooks contributed by a child agent still receive the parent's
5271
+ * ThreadState. The child source additionally identifies the exact relationship
5272
+ * that activated the hook, including the exposed relationship name that may be
5273
+ * passed to `state.invokeTool()` or `state.queueTool()`.
5509
5274
  */
5275
+ type HookExecutionSource = {
5276
+ kind: 'prompt';
5277
+ /** Active prompt whose hook list selected this hook. */
5278
+ promptName: string;
5279
+ } | {
5280
+ kind: 'agent';
5281
+ /** Active agent whose fallback hook list selected this hook. */
5282
+ agentName: string;
5283
+ } | {
5284
+ kind: 'child';
5285
+ /** Model/runtime-facing name of the direct parent-child relationship. */
5286
+ relationshipName: string;
5287
+ /** Implementing child agent reference after alias resolution. */
5288
+ agentName: string;
5289
+ /** Package provenance when the child came from a packed package. */
5290
+ package?: PackageSignature;
5291
+ };
5510
5292
  /**
5511
- * Package signature applied to packed definitions.
5512
- *
5513
- * When an agent and its dependencies are packed, each definition
5514
- * receives this signature marking it as belonging to a specific package.
5515
- * This enables namespace isolation during execution.
5516
- *
5517
- * @example
5518
- * ```typescript
5519
- * const signature: PackageSignature = {
5520
- * packageId: 'standardagent-my-workflow',
5521
- * version: '1.0.0',
5522
- * source: 'npm',
5523
- * packedAt: Date.now(),
5524
- * };
5525
- * ```
5293
+ * Final argument supplied to every thread-scoped hook invocation.
5526
5294
  */
5527
- interface PackageSignature {
5528
- /** Unique package identifier (npm name or local identifier) */
5529
- packageId: string;
5530
- /** Package version */
5531
- version: string;
5532
- /** Source type */
5533
- source: 'npm' | 'local';
5534
- /** When packed (timestamp in milliseconds) */
5535
- packedAt: number;
5295
+ interface HookExecutionContext {
5296
+ source: HookExecutionSource;
5536
5297
  }
5537
5298
  /**
5538
- * Global namespace context - for unpacked code.
5299
+ * Message structure for hook processing.
5539
5300
  *
5540
- * Unpacked code sees:
5541
- * - All unpacked tools, prompts, models, hooks
5542
- * - Packed agent entry points (agents with exposeAsTool: true)
5543
- * - NOT internal packed tools/prompts (those are hidden)
5301
+ * Re-exported from threads.ts for convenience.
5302
+ * @see Message
5544
5303
  */
5545
- interface GlobalNamespaceContext {
5546
- type: 'global';
5304
+ type HookMessage = Message;
5305
+ /**
5306
+ * Tool call structure for hook processing.
5307
+ */
5308
+ interface HookToolCall {
5309
+ /** Unique tool call identifier */
5310
+ id: string;
5311
+ /** Always 'function' for tool calls */
5312
+ type: 'function';
5313
+ /** Function details */
5314
+ function: {
5315
+ /** Tool name */
5316
+ name: string;
5317
+ /** JSON-encoded arguments */
5318
+ arguments: string;
5319
+ };
5320
+ }
5321
+ /**
5322
+ * Tool result structure for hook processing.
5323
+ */
5324
+ interface HookToolResult {
5325
+ /** Execution status */
5326
+ status: 'success' | 'error';
5327
+ /** Result string (for successful executions) */
5328
+ result?: string;
5329
+ /** Error message (for failed executions) */
5330
+ error?: string;
5331
+ /** Stack trace (for debugging) */
5332
+ stack?: string;
5333
+ /**
5334
+ * File attachments returned by the tool.
5335
+ *
5336
+ * Can contain either:
5337
+ * - ToolAttachment: New files with base64 data to be stored
5338
+ * - AttachmentRef: References to existing files in the thread filesystem
5339
+ */
5340
+ attachments?: Array<ToolAttachment | AttachmentRef>;
5341
+ }
5342
+ /**
5343
+ * LLM message format for prefilter hook.
5344
+ *
5345
+ * Messages passed to the prefilter_llm_history hook are in chat completion
5346
+ * format. Content can be a plain string or a multimodal array (for messages
5347
+ * with images). Additional provider-specific fields may also be present.
5348
+ */
5349
+ interface LLMMessage {
5350
+ /** Message role */
5351
+ role: string;
5352
+ /** Message content (string for text-only, array for multimodal) */
5353
+ content?: string | null | unknown[];
5354
+ /** Tool calls (parsed) */
5355
+ tool_calls?: unknown;
5356
+ /** Tool call ID */
5357
+ tool_call_id?: string;
5358
+ /** Tool name */
5359
+ name?: string;
5360
+ /** Reasoning content (for models like o1) */
5361
+ reasoning_content?: string;
5362
+ /** Allow additional provider-specific fields */
5363
+ [key: string]: unknown;
5364
+ }
5365
+ /**
5366
+ * Hook signatures for all available hooks.
5367
+ *
5368
+ * Each hook has a specific signature that defines when it's called
5369
+ * and what data it receives. Hooks can modify data by returning
5370
+ * transformed values or perform side effects.
5371
+ *
5372
+ * All thread hooks receive ThreadState as their first parameter and
5373
+ * HookExecutionContext as their final parameter.
5374
+ *
5375
+ * @template State - The state type (defaults to ThreadState)
5376
+ * @template Msg - The message type (defaults to HookMessage)
5377
+ * @template ToolCall - The tool call type (defaults to HookToolCall)
5378
+ * @template ToolResult - The tool result type (defaults to HookToolResult)
5379
+ */
5380
+ interface HookSignatures<State = ThreadState, Msg = HookMessage, ToolCall = HookToolCall, ToolResult = HookToolResult, Context = HookExecutionContext> {
5381
+ /**
5382
+ * Called after a thread is created, before initial message processing or LLM
5383
+ * requests for that thread.
5384
+ *
5385
+ * Only ThreadState is passed. Use for initializing durable thread values,
5386
+ * env placeholders, files, or side-effect instrumentation.
5387
+ *
5388
+ * @param state - Created thread state
5389
+ */
5390
+ after_thread_created: (state: State, context: Context) => Promise<void>;
5391
+ /**
5392
+ * Called on the parent thread immediately after a subagent child thread is
5393
+ * created.
5394
+ *
5395
+ * Receives parent ThreadState and child ThreadState. Use for copying or
5396
+ * linking metadata, bookkeeping, or side-effect instrumentation.
5397
+ *
5398
+ * @param state - Parent thread state
5399
+ * @param childState - Created child thread state
5400
+ */
5401
+ after_subagent_created: (state: State, childState: State, context: Context) => Promise<void>;
5402
+ /**
5403
+ * Called after the prompt system message is rendered for a model request.
5404
+ *
5405
+ * Return a string to replace the rendered system message. Return null or
5406
+ * undefined to keep the original message.
5407
+ *
5408
+ * @param state - Thread state
5409
+ * @param systemMessage - Rendered system message for this request
5410
+ * @returns Replacement system message, or null/undefined for no change
5411
+ */
5412
+ after_system_message: (state: State, systemMessage: string, context: Context) => string | Promise<string | null | undefined> | null | undefined;
5413
+ /**
5414
+ * Called exactly once per model-context assembly on a stable snapshot of
5415
+ * eligible persisted history.
5416
+ *
5417
+ * Receives raw message rows from storage before any transformation.
5418
+ * Use for filtering, sorting, or augmenting message history.
5419
+ * The result is the request context and does not replace
5420
+ * `state.execution.messageHistory`. Messages injected while this hook runs
5421
+ * become eligible for the following context assembly.
5422
+ *
5423
+ * @param state - Thread state
5424
+ * @param messages - Array of messages from storage
5425
+ * @returns Modified message array
5426
+ *
5427
+ * @example
5428
+ * ```typescript
5429
+ * defineHook({
5430
+ * hook: 'filter_messages',
5431
+ * id: 'limit_to_10',
5432
+ * execute: async (state, messages) => messages.slice(-10),
5433
+ * });
5434
+ * ```
5435
+ */
5436
+ filter_messages: (state: State, messages: Msg[], context: Context) => Promise<Msg[]>;
5437
+ /**
5438
+ * Called after filtered history is transformed into provider messages and
5439
+ * before dispatch.
5440
+ *
5441
+ * Receives messages already transformed into chat completion format.
5442
+ * Use for final request-local adjustments. Messages injected while this
5443
+ * hook runs become eligible for the following context assembly.
5444
+ *
5445
+ * @param state - Thread state
5446
+ * @param messages - Array of LLM-formatted messages
5447
+ * @returns Modified LLM message array
5448
+ *
5449
+ * @example
5450
+ * ```typescript
5451
+ * defineHook({
5452
+ * hook: 'prefilter_llm_history',
5453
+ * id: 'add_reminder',
5454
+ * execute: async (state, messages) => messages,
5455
+ * });
5456
+ * ```
5457
+ */
5458
+ prefilter_llm_history: (state: State, messages: LLMMessage[], context: Context) => Promise<LLMMessage[]>;
5459
+ /**
5460
+ * Called before a message is created in the database.
5461
+ *
5462
+ * Receives the full message object before insertion. Return modified
5463
+ * message to transform before storage.
5464
+ *
5465
+ * A hook that throws during `injectMessage()` rejects the injection and
5466
+ * no message is persisted. Other runtime insertions log the failure and
5467
+ * keep the last good message.
5468
+ *
5469
+ * @param state - Thread state
5470
+ * @param message - Message to be created
5471
+ * @returns Modified message
5472
+ *
5473
+ * @example
5474
+ * ```typescript
5475
+ * defineHook({
5476
+ * hook: 'before_create_message',
5477
+ * id: 'prefix_content',
5478
+ * execute: async (state, message) => {
5479
+ * // message has full type: id, role, content, created_at, etc.
5480
+ * if (message.role === 'user' && message.content) {
5481
+ * return { ...message, content: `[user] ${message.content}` };
5482
+ * }
5483
+ * return message;
5484
+ * }
5485
+ * });
5486
+ * ```
5487
+ */
5488
+ before_create_message: (state: State, message: Msg, context: Context) => Promise<Msg>;
5489
+ /**
5490
+ * Called after a message is created in the database.
5491
+ *
5492
+ * Use for logging, analytics, or triggering side effects after
5493
+ * message creation. Cannot modify the message.
5494
+ *
5495
+ * @param state - Thread state
5496
+ * @param message - The created message
5497
+ *
5498
+ * @example
5499
+ * ```typescript
5500
+ * defineHook({
5501
+ * hook: 'after_create_message',
5502
+ * id: 'log_creation',
5503
+ * execute: async (state, message) => {
5504
+ * console.log(`Created ${message.role} message: ${message.id}`);
5505
+ * }
5506
+ * });
5507
+ * ```
5508
+ */
5509
+ after_create_message: (state: State, message: Msg, context: Context) => Promise<void>;
5510
+ /**
5511
+ * Called before a message is updated in the database.
5512
+ *
5513
+ * Receives the message ID and update data. Return modified updates
5514
+ * to transform the changes before storage.
5515
+ *
5516
+ * @param state - Thread state
5517
+ * @param messageId - ID of message being updated
5518
+ * @param updates - Update data
5519
+ * @returns Modified update data
5520
+ *
5521
+ * @example
5522
+ * ```typescript
5523
+ * defineHook({
5524
+ * hook: 'before_update_message',
5525
+ * id: 'stamp_updated_at',
5526
+ * execute: async (state, messageId, updates) => ({
5527
+ * ...updates,
5528
+ * updated_at: Date.now(),
5529
+ * }),
5530
+ * });
5531
+ * ```
5532
+ */
5533
+ before_update_message: (state: State, messageId: string, updates: Record<string, unknown>, context: Context) => Promise<Record<string, unknown>>;
5534
+ /**
5535
+ * Called after a message is updated in the database.
5536
+ *
5537
+ * Use for logging, analytics, or triggering side effects after
5538
+ * message update. Cannot modify the message.
5539
+ *
5540
+ * @param state - Thread state
5541
+ * @param message - The updated message
5542
+ *
5543
+ * @example
5544
+ * ```typescript
5545
+ * defineHook({
5546
+ * hook: 'after_update_message',
5547
+ * id: 'log_update',
5548
+ * execute: async (state, message) => {
5549
+ * console.log(`Message updated: ${message.id}`);
5550
+ * },
5551
+ * });
5552
+ * ```
5553
+ */
5554
+ after_update_message: (state: State, message: Msg, context: Context) => Promise<void>;
5555
+ /**
5556
+ * Called before a tool result is stored in the database.
5557
+ *
5558
+ * Receives the tool call and result before storage. Return modified
5559
+ * result to transform before storage.
5560
+ *
5561
+ * @param state - Thread state
5562
+ * @param toolCall - The tool call that was executed
5563
+ * @param toolResult - The result from tool execution
5564
+ * @returns Modified tool result
5565
+ *
5566
+ * @example
5567
+ * ```typescript
5568
+ * defineHook({
5569
+ * hook: 'before_store_tool_result',
5570
+ * id: 'sanitize_results',
5571
+ * execute: async (state, toolCall, toolResult) => {
5572
+ * // toolCall has: id, type, function.name, function.arguments
5573
+ * // toolResult has: status, result?, error?, stack?, attachments?
5574
+ * if (toolResult.result) {
5575
+ * return { ...toolResult, result: sanitize(toolResult.result) };
5576
+ * }
5577
+ * return toolResult;
5578
+ * }
5579
+ * });
5580
+ * ```
5581
+ */
5582
+ before_store_tool_result: (state: State, toolCall: ToolCall, toolResult: ToolResult, context: Context) => Promise<ToolResult>;
5583
+ /**
5584
+ * Called after a successful tool call.
5585
+ *
5586
+ * Receives the tool call and its result. Can return a modified result
5587
+ * or null to use the original. Use for logging, transformation, or
5588
+ * post-processing of successful tool executions.
5589
+ *
5590
+ * @param state - Thread state
5591
+ * @param toolCall - The executed tool call
5592
+ * @param toolResult - The successful result
5593
+ * @returns Modified result or null for original
5594
+ *
5595
+ * @example
5596
+ * ```typescript
5597
+ * defineHook({
5598
+ * hook: 'after_tool_call_success',
5599
+ * id: 'log_success',
5600
+ * execute: async (state, toolCall, toolResult) => {
5601
+ * console.log(`Tool ${toolCall.function.name} succeeded`);
5602
+ * return null; // use original result
5603
+ * },
5604
+ * });
5605
+ * ```
5606
+ */
5607
+ after_tool_call_success: (state: State, toolCall: ToolCall, toolResult: ToolResult, context: Context) => Promise<ToolResult | null>;
5608
+ /**
5609
+ * Called after a failed tool call.
5610
+ *
5611
+ * Receives the tool call and error result. Can return a modified result
5612
+ * or null to use the original. Use for error handling, logging, or
5613
+ * recovery attempts.
5614
+ *
5615
+ * @param state - Thread state
5616
+ * @param toolCall - The failed tool call
5617
+ * @param toolResult - The error result
5618
+ * @returns Modified result or null for original
5619
+ *
5620
+ * @example
5621
+ * ```typescript
5622
+ * defineHook({
5623
+ * hook: 'after_tool_call_failure',
5624
+ * id: 'log_failure',
5625
+ * execute: async (state, toolCall, toolResult) => {
5626
+ * console.error(`Tool ${toolCall.function.name} failed: ${toolResult.error}`);
5627
+ * return null; // use original error
5628
+ * },
5629
+ * });
5630
+ * ```
5631
+ */
5632
+ after_tool_call_failure: (state: State, toolCall: ToolCall, toolResult: ToolResult, context: Context) => Promise<ToolResult | null>;
5633
+ /**
5634
+ * Called when a tool call STARTS — before the tool executes, while the model
5635
+ * may still be generating the rest of the call. Fires exactly once per tool
5636
+ * call. Observational: the return value is ignored.
5637
+ *
5638
+ * Timing depends on whether the tool declares a `progressArgument`:
5639
+ * - **With** `progressArgument`: fires as soon as *just that argument* has
5640
+ * finished streaming (not the whole call), passing its value as `progress`.
5641
+ * This lets a UI show "fixing index.html" before a large `content` argument
5642
+ * finishes generating.
5643
+ * - **Without** `progressArgument`: fires as soon as the tool call appears in
5644
+ * the stream — its name is known but `toolCall.function.arguments` may be an
5645
+ * incomplete JSON fragment (or empty), and `progress` is undefined.
5646
+ *
5647
+ * Conforming runtimes also broadcast a `tool_call_started` thread event to
5648
+ * connected clients with `{ id, name, progress }` at the same moment.
5649
+ *
5650
+ * @param state - Thread state
5651
+ * @param toolCall - The starting tool call; `function.arguments` may be incomplete
5652
+ * @param progress - The declared progress-argument value, when available
5653
+ *
5654
+ * @example
5655
+ * ```typescript
5656
+ * defineHook({
5657
+ * hook: 'tool_call_started',
5658
+ * id: 'log_tool_start',
5659
+ * execute: async (state, toolCall, progress) => {
5660
+ * console.log(`▸ ${toolCall.function.name}${progress ? `: ${progress}` : ''}`);
5661
+ * },
5662
+ * });
5663
+ * ```
5664
+ */
5665
+ tool_call_started: (state: State, toolCall: ToolCall, progress: string | undefined, context: Context) => Promise<void>;
5666
+ /**
5667
+ * Called when a tool call is DONE — after it has executed, with its result,
5668
+ * regardless of success or failure. Fires once per tool call. Observational:
5669
+ * the return value is ignored.
5670
+ *
5671
+ * This complements `after_tool_call_success` / `after_tool_call_failure`,
5672
+ * which can additionally *modify* the stored result; `tool_call_done` is a
5673
+ * single unified observation point that always fires. Conforming runtimes
5674
+ * also broadcast a `tool_call_done` thread event to connected clients with
5675
+ * `{ id, name, status }` at the same moment.
5676
+ *
5677
+ * @param state - Thread state
5678
+ * @param toolCall - The completed tool call
5679
+ * @param toolResult - The tool's result (`status` is `'success'` or `'error'`)
5680
+ */
5681
+ tool_call_done: (state: State, toolCall: ToolCall, toolResult: ToolResult, context: Context) => Promise<void>;
5682
+ /**
5683
+ * Called when a socket attaches to the user's event stream
5684
+ * (`{runtime_prefix}/users/me/stream`).
5685
+ *
5686
+ * @param user - User scope state
5687
+ * @param client - The attached client's id and self-declared kind
5688
+ */
5689
+ user_client_attached: (user: UserState, client: UserClientInfo) => Promise<void>;
5690
+ /**
5691
+ * Called when a socket detaches from the user's event stream.
5692
+ *
5693
+ * @param user - User scope state
5694
+ * @param client - The detached client's id and self-declared kind
5695
+ */
5696
+ user_client_detached: (user: UserState, client: UserClientInfo) => Promise<void>;
5697
+ /**
5698
+ * Called after a durable user value changes, regardless of the writer
5699
+ * (user endpoint, thread-side handle, or REST).
5700
+ *
5701
+ * @param user - User scope state
5702
+ * @param key - The key that changed
5703
+ */
5704
+ user_value_changed: (user: UserState, key: string) => Promise<void>;
5547
5705
  }
5548
5706
  /**
5549
- * Packed namespace context - for code inside a packed agent.
5550
- *
5551
- * Packed code sees:
5552
- * - Only items within its own package (by packageId)
5553
- * - Other packed agent entry points (for handoffs)
5554
- * - NOT unpacked global code
5707
+ * Valid hook names.
5555
5708
  */
5556
- interface PackedNamespaceContext {
5557
- type: 'packed';
5558
- /** Package ID this code belongs to */
5559
- packageId: string;
5560
- }
5709
+ type HookName = keyof HookSignatures;
5710
+ /** Hook names that execute in thread scope and may be contributed to a parent. */
5711
+ type ThreadHookName = Exclude<HookName, 'user_client_attached' | 'user_client_detached' | 'user_value_changed'>;
5561
5712
  /**
5562
- * Namespace context for execution.
5563
- * Determines what items are visible during execution.
5713
+ * Hook definition tuple.
5564
5714
  *
5565
- * @example
5566
- * ```typescript
5567
- * // Global namespace (unpacked code)
5568
- * const globalNs: NamespaceContext = { type: 'global' };
5715
+ * A hook definition is a tuple containing the hook name and implementation.
5569
5716
  *
5570
- * // Packed namespace (inside a packed agent)
5571
- * const packedNs: NamespaceContext = {
5572
- * type: 'packed',
5573
- * packageId: 'standardagent-my-workflow',
5574
- * };
5575
- * ```
5717
+ * @template K - The hook name
5718
+ * @template State - The state type (defaults to ThreadState)
5719
+ * @template Msg - The message type
5720
+ * @template ToolCall - The tool call type
5721
+ * @template ToolResult - The tool result type
5722
+ * @deprecated Use the object-based defineHook signature instead
5576
5723
  */
5577
- type NamespaceContext = GlobalNamespaceContext | PackedNamespaceContext;
5724
+ type HookDefinition<K extends HookName = HookName, State = ThreadState, Msg = HookMessage, ToolCall = HookToolCall, ToolResult = HookToolResult> = [K, HookSignatures<State, Msg, ToolCall, ToolResult>[K]];
5578
5725
  /**
5579
- * Extended metadata for packed definitions.
5726
+ * Options for defining a hook with explicit ID.
5727
+ * The generic K ensures `execute` is properly typed for the specific hook type.
5580
5728
  *
5581
- * This interface is added to agent, prompt, tool, model, and hook
5582
- * definitions when they are packed. It marks them as belonging
5583
- * to a specific package and optionally as readonly.
5729
+ * @template K - Hook type from HookSignatures (e.g., 'filter_messages')
5584
5730
  */
5585
- interface PackedMetadata {
5586
- /**
5587
- * Package signature if this definition is part of a packed agent.
5588
- * Undefined for unpacked (global) definitions.
5589
- */
5590
- __package?: PackageSignature;
5731
+ interface HookDefinitionOptions<K extends HookName> {
5732
+ /** The hook type (e.g., 'filter_messages', 'before_create_message') */
5733
+ hook: K;
5734
+ /** Unique identifier for this hook implementation (snake_case) */
5735
+ id: string;
5591
5736
  /**
5592
- * Whether this definition is readonly (cannot be edited in UI).
5593
- * Packed definitions are typically readonly.
5737
+ * The hook implementation function.
5738
+ * Type is automatically inferred from the hook type.
5594
5739
  */
5595
- __readonly?: boolean;
5740
+ execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];
5596
5741
  }
5597
5742
  /**
5598
- * Helper type to check if a definition is packed.
5599
- */
5600
- declare function isPacked(metadata: PackedMetadata | undefined): metadata is PackedMetadata & {
5601
- __package: PackageSignature;
5602
- };
5603
- /**
5604
- * Helper to check if a definition belongs to a specific package.
5605
- */
5606
- declare function belongsToPackage(metadata: PackedMetadata | undefined, packageId: string): boolean;
5607
- /**
5608
- * Helper to check if a definition is visible in a given namespace.
5743
+ * Return type from defineHook - preserves the hook type for type-safe usage.
5609
5744
  *
5610
- * @param metadata - The definition's packed metadata
5611
- * @param namespace - The current namespace context
5612
- * @param isEntryPoint - Whether this is an agent with exposeAsTool: true
5745
+ * @template K - Hook type from HookSignatures
5613
5746
  */
5614
- declare function isVisibleInNamespace(metadata: PackedMetadata | undefined, namespace: NamespaceContext, isEntryPoint?: boolean): boolean;
5747
+ interface HookDefinitionResult<K extends HookName> {
5748
+ /** The hook type name */
5749
+ hook: K;
5750
+ /** The unique hook ID */
5751
+ id: string;
5752
+ /** The typed execute function */
5753
+ execute: HookSignatures<ThreadState, HookMessage, HookToolCall, HookToolResult>[K];
5754
+ }
5615
5755
  /**
5616
- * Metadata export for packed packages.
5756
+ * Define a hook with a unique identifier and strict typing.
5617
5757
  *
5618
- * This is exported as `__meta` from the packed package's index.ts,
5619
- * replacing the manifest.json file from the old format.
5758
+ * The hook type determines the execute function signature.
5759
+ * TypeScript will enforce correct parameter and return types.
5620
5760
  *
5621
- * A packed package's required execution behavior must use capabilities
5622
- * defined by the Standard Agent Specification. It must not depend on private
5623
- * runtime RPCs, storage schemas, bindings, undocumented events, sidecars that
5624
- * replace runtime primitives, or `ThreadState._notPackableRuntimeContext`.
5761
+ * @template K - The hook type (inferred from options.hook)
5762
+ * @param options - Hook definition with hook type, ID, and execute function
5763
+ * @returns Typed hook definition for registration
5625
5764
  *
5626
5765
  * @example
5627
5766
  * ```typescript
5628
- * export const __meta: PackedMeta = {
5629
- * packageId: 'standardagent-my-workflow',
5630
- * version: '1.0.0',
5631
- * entryAgents: ['my_agent'],
5632
- * packedAt: 1705012800000,
5633
- * };
5767
+ * // Filter messages - execute receives (state: ThreadState, messages: HookMessage[])
5768
+ * export default defineHook({
5769
+ * hook: 'filter_messages',
5770
+ * id: 'limit_to_20_messages',
5771
+ * execute: async (state, messages) => {
5772
+ * return messages.slice(-20);
5773
+ * }
5774
+ * });
5634
5775
  * ```
5635
- */
5636
- interface PackedMeta {
5637
- /** Unique package identifier (npm name or local identifier) */
5638
- packageId: string;
5639
- /** Package version (semver) */
5640
- version: string;
5641
- /** Entry agents exposed as tools (visible from outside the package) */
5642
- entryAgents: string[];
5643
- /** When the package was packed (timestamp in milliseconds) */
5644
- packedAt: number;
5645
- /** Optional description from the entry agent */
5646
- description?: string;
5647
- }
5648
- /**
5649
- * Lazy loader type for packed definitions.
5650
- *
5651
- * Each definition in a packed package is wrapped in a function
5652
- * that returns a Promise, enabling lazy loading.
5653
5776
  *
5654
5777
  * @example
5655
5778
  * ```typescript
5656
- * export const tools = {
5657
- * search: async (): Promise<ToolDefinition> => ({
5658
- * description: 'Search for information',
5659
- * execute: async (state, args) => { ... },
5660
- * }),
5661
- * } as const;
5779
+ * // Before create message - execute receives (state: ThreadState, message: Message)
5780
+ * export default defineHook({
5781
+ * hook: 'before_create_message',
5782
+ * id: 'prefix_content',
5783
+ * execute: async (state, message) => {
5784
+ * if (message.role === 'user' && message.content) {
5785
+ * return { ...message, content: `[user] ${message.content}` };
5786
+ * }
5787
+ * return message;
5788
+ * }
5789
+ * });
5662
5790
  * ```
5663
- */
5664
- type DefinitionLoader<T> = () => Promise<T>;
5665
-
5666
- /**
5667
- * Standard shape for packed package exports.
5668
- *
5669
- * Every packed package exports this structure, enabling
5670
- * consistent discovery and loading.
5671
5791
  *
5672
5792
  * @example
5673
5793
  * ```typescript
5674
- * import type { PackedExports } from '@standardagents/spec';
5675
- *
5676
- * const pkg: PackedExports = await import('standardagent-my-workflow');
5677
- * const tool = await pkg.tools.search();
5794
+ * // After tool call success - execute receives (state, toolCall, toolResult)
5795
+ * export default defineHook({
5796
+ * hook: 'after_tool_call_success',
5797
+ * id: 'log_tool_usage',
5798
+ * execute: async (state, toolCall, toolResult) => {
5799
+ * console.log(`Tool ${toolCall.function.name} returned: ${toolResult.result}`);
5800
+ * return null; // Use original result
5801
+ * }
5802
+ * });
5678
5803
  * ```
5679
5804
  */
5680
- interface PackedExports {
5681
- /** Agent definitions, keyed by name */
5682
- agents: Record<string, DefinitionLoader<AgentDefinition>>;
5683
- /** Prompt definitions, keyed by name */
5684
- prompts: Record<string, DefinitionLoader<PromptDefinition>>;
5685
- /** Tool definitions, keyed by name */
5686
- tools: Record<string, DefinitionLoader<ToolDefinition<unknown, any, any>>>;
5687
- /** Model definitions, keyed by name */
5688
- models: Record<string, DefinitionLoader<ModelDefinition>>;
5689
- /** Hook definitions, keyed by name */
5690
- hooks: Record<string, DefinitionLoader<HookSignatures[keyof HookSignatures]>>;
5691
- /**
5692
- * Effect definitions, keyed by name.
5693
- *
5694
- * Optional for backward compatibility with previously packed packages.
5695
- */
5696
- effects?: Record<string, DefinitionLoader<EffectDefinition<any, any>>>;
5697
- /**
5698
- * Thread endpoint handlers, keyed by packed route key (for example, `status.get`).
5699
- *
5700
- * Runtimes mount these beneath the same thread ID prefix as local thread
5701
- * endpoints, using the packed route key to derive the endpoint path.
5702
- * Requests beneath that prefix that do not match any local or packed thread
5703
- * endpoint route MUST return HTTP 404.
5704
- *
5705
- * Optional for backward compatibility with previously packed packages.
5706
- */
5707
- threadEndpoints?: Record<string, DefinitionLoader<MarkedThreadEndpoint | Controller>>;
5708
- /** Package metadata */
5709
- __meta: PackedMeta;
5710
- }
5805
+ declare function defineHook<K extends HookName>(options: HookDefinitionOptions<K>): HookDefinitionResult<K>;
5711
5806
 
5712
- export { type AgentDefinition, type AgentType, type AttachmentRef, type CodeExecution, type CodeExecutionError, type CodeExecutionLog, type CodeExecutionOptions, type CodeExecutionResult, type CodeExecutionStatus, type ContentPart, type Controller, type ControllerContext, type ControllerReturn, type CreateFetch, type CredentialGrant, type DefineToolOptions, type DefinitionLoader, ENDPOINT_ACCESS_SYMBOL, type Effect, type EffectDefinition, type EmptyUsesState, type EndpointAccess, type EndpointOptions, type EnvValueType, type ExecutionState, type FetchLike, type FileChunk, type FilePart, type FileRecord, type FileStats, type FileStorage, type FindResult, type GetMessagesOptions, type GlobalNamespaceContext, type GrepResult, type HookContext, type HookDefinition, type HookDefinitionOptions, type HookDefinitionResult, type HookMessage, type HookName, type HookSignatures, type HookToolCall, type HookToolResult, type ImageContent, type ImagePart, type ImageUrlPart, type InferProviderOptions, type InjectMessageInput, type InspectedRequest, type LLMMessage, type LLMProviderInterface, type ListUserThreadsOptions, type ListUserValuesOptions, type MarkedThreadEndpoint, type MarkedUserEndpoint, type Message, type MessageUpdates, type MessagesResult, type ModelCapabilities, type ModelDefinition, type ModelProvider, type NamespaceContext, type PackageSignature, type PackedExports, type PackedMeta, type PackedMetadata, type PackedNamespaceContext, type PromptContent, type PromptDefinition, type PromptEnvPart, type PromptIncludePart, type PromptInput, type PromptPart, type PromptTextPart, type PromptToolConfig, type ProviderAssistantMessage, type ProviderAttachment, type ProviderConfigSlot, type ProviderConfigSlots, type ProviderConfigValueSource, type ProviderDefinition, ProviderError, type ProviderErrorCode, type ProviderExecutedToolResult, type ProviderFactory, type ProviderFactoryConfig, type ProviderFactoryWithOptions, type ProviderFinishReason, type ProviderGeneratedImage, type ProviderInstance, type ProviderMessage, type ProviderMessageContent, type ProviderMethodOverrides, type ProviderModelInfo, type ProviderModelsPage, type ProviderModelsQuery, type ProviderOverride, type ProviderOverrideContext, type ProviderReasoningDetail, type ProviderRequest, type ProviderResponse, type ProviderStreamChunk, type ProviderSyncOverride, type ProviderSystemMessage, type ProviderTool, type ProviderToolCallPart, type ProviderToolMessage, type ProviderToolResultContent, type ProviderUsage, type ProviderUsagePricing, type ProviderUserMessage, type ProviderWebSearchResult, type QueueMessageInput, type ReadFileStreamOptions, type ReaddirResult, type ReasoningConfig, type ResolveUsesState, type ResponseSummary, type RuntimeByteStream, type RuntimeStreamErrorCode, type RuntimeStreamRequest, type RuntimeStreamResult, type RuntimeStreams, type ScheduledEffect, type SessionToolBinding, type SessionToolConfig, type SetEnvOptions, type SideConfig, type SkillFileInput, type SkillMetadata, type SkillsNamespace, type StopSessionOptions, type StructuredPrompt, type SubagentRegistryEntry, type SubagentToolConfig, type SubpromptConfig, THREAD_ENDPOINT_SYMBOL, THREAD_STREAM_REASONING_PARAM, type TenvRawShape, type TextContent, type TextPart, type ThreadEndpointAuth, type ThreadEndpointHandler, type ThreadEndpointRouteParams, type ThreadMessageChunkEvent, type ThreadMetadata, type ThreadReasoningChunkEvent, type ThreadState, type ThreadUser, type Tool, type ToolArgs, type ToolArgsNode, type ToolArgsRawShape, type ToolAttachment, type ToolConfig, type ToolContent, type ToolDefinition, type ToolResult, type ToolTenvs, type ToolVariables, USER_ENDPOINT_SYMBOL, type UserClientInfo, type UserEndpointHandler, type UserEndpointRouteParams, type UserHandle, type UserIdentity, type UserState, type UserThreadSummary, type UserValueEntry, type UsesAwareExecute, type UsesConstrainedState, type VariableDefinition, type VariableType, type VirtualModuleLoader, type VirtualModuleRegistry, type WriteFileOptions, belongsToPackage, defineAgent, defineController, defineEffect, defineHook, defineModel, definePrompt, defineProvider, defineThreadEndpoint, defineTool, defineUserEndpoint, getEndpointAccess, isPacked, isThreadEndpoint, isUserEndpoint, isVisibleInNamespace, mapReasoningLevel, providerConst, providerEnv, providerValue, validateToolName };
5807
+ export { type AgentDefinition, type AgentType, type AttachmentRef, type CodeExecution, type CodeExecutionError, type CodeExecutionLog, type CodeExecutionOptions, type CodeExecutionResult, type CodeExecutionStatus, type ContentPart, type Controller, type ControllerContext, type ControllerReturn, type CreateFetch, type CredentialGrant, type DefineToolOptions, type DefinitionLoader, ENDPOINT_ACCESS_SYMBOL, type Effect, type EffectDefinition, type EmptyUsesState, type EndpointAccess, type EndpointOptions, type EnvValueType, type ExecutionState, type FetchLike, type FileChunk, type FilePart, type FileRecord, type FileStats, type FileStorage, type FindResult, type GetMessagesOptions, type GlobalNamespaceContext, type GrepResult, type HookContext, type HookDefinition, type HookDefinitionOptions, type HookDefinitionResult, type HookExecutionContext, type HookExecutionSource, type HookMessage, type HookName, type HookSignatures, type HookToolCall, type HookToolResult, type ImageContent, type ImagePart, type ImageUrlPart, type InferProviderOptions, type InjectMessageInput, type InspectedRequest, type LLMMessage, type LLMProviderInterface, type ListUserThreadsOptions, type ListUserValuesOptions, type MarkedThreadEndpoint, type MarkedUserEndpoint, type Message, type MessageUpdates, type MessagesResult, type ModelCapabilities, type ModelDefinition, type ModelProvider, type NamespaceContext, type PackageSignature, type PackedExports, type PackedMeta, type PackedMetadata, type PackedNamespaceContext, type ParentHookRequirement, type ParentHookStage, type PromptContent, type PromptDefinition, type PromptEnvPart, type PromptIncludePart, type PromptInput, type PromptPart, type PromptTextPart, type PromptToolConfig, type ProviderAssistantMessage, type ProviderAttachment, type ProviderConfigSlot, type ProviderConfigSlots, type ProviderConfigValueSource, type ProviderDefinition, ProviderError, type ProviderErrorCode, type ProviderExecutedToolResult, type ProviderFactory, type ProviderFactoryConfig, type ProviderFactoryWithOptions, type ProviderFinishReason, type ProviderGeneratedImage, type ProviderInstance, type ProviderMessage, type ProviderMessageContent, type ProviderMethodOverrides, type ProviderModelInfo, type ProviderModelsPage, type ProviderModelsQuery, type ProviderOverride, type ProviderOverrideContext, type ProviderReasoningDetail, type ProviderRequest, type ProviderResponse, type ProviderStreamChunk, type ProviderSyncOverride, type ProviderSystemMessage, type ProviderTool, type ProviderToolCallPart, type ProviderToolMessage, type ProviderToolResultContent, type ProviderUsage, type ProviderUsagePricing, type ProviderUserMessage, type ProviderWebSearchResult, type QueueMessageInput, type ReadFileStreamOptions, type ReaddirResult, type ReasoningConfig, type ResolveUsesState, type ResponseSummary, type RuntimeByteStream, type RuntimeStreamErrorCode, type RuntimeStreamRequest, type RuntimeStreamResult, type RuntimeStreams, type ScheduledEffect, type SessionToolBinding, type SessionToolConfig, type SetEnvOptions, type SideConfig, type SkillFileInput, type SkillMetadata, type SkillsNamespace, type StopSessionOptions, type StructuredPrompt, type SubagentRegistryEntry, type SubagentToolConfig, type SubpromptConfig, THREAD_ENDPOINT_SYMBOL, THREAD_STREAM_REASONING_PARAM, type TenvRawShape, type TextContent, type TextPart, type ThreadEndpointAuth, type ThreadEndpointHandler, type ThreadEndpointRouteParams, type ThreadHookName, type ThreadMessageChunkEvent, type ThreadMetadata, type ThreadReasoningChunkEvent, type ThreadState, type ThreadUser, type Tool, type ToolArgs, type ToolArgsNode, type ToolArgsRawShape, type ToolAttachment, type ToolConfig, type ToolContent, type ToolDefinition, type ToolResult, type ToolTenvs, type ToolVariables, USER_ENDPOINT_SYMBOL, type UserClientInfo, type UserEndpointHandler, type UserEndpointRouteParams, type UserHandle, type UserIdentity, type UserState, type UserThreadSummary, type UserValueEntry, type UsesAwareExecute, type UsesConstrainedState, type VariableDefinition, type VariableType, type VirtualModuleLoader, type VirtualModuleRegistry, type WriteFileOptions, belongsToPackage, defineAgent, defineController, defineEffect, defineHook, defineModel, definePrompt, defineProvider, defineThreadEndpoint, defineTool, defineUserEndpoint, getEndpointAccess, isPacked, isThreadEndpoint, isUserEndpoint, isVisibleInNamespace, mapReasoningLevel, providerConst, providerEnv, providerValue, validateToolName };