@tanstack/ai 0.28.0 → 0.31.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.
Files changed (67) hide show
  1. package/dist/esm/activities/chat/adapter.d.ts +10 -0
  2. package/dist/esm/activities/chat/adapter.js +1 -0
  3. package/dist/esm/activities/chat/adapter.js.map +1 -1
  4. package/dist/esm/activities/chat/index.d.ts +3 -2
  5. package/dist/esm/activities/chat/index.js +23 -11
  6. package/dist/esm/activities/chat/index.js.map +1 -1
  7. package/dist/esm/activities/chat/messages.js +1 -1
  8. package/dist/esm/activities/chat/messages.js.map +1 -1
  9. package/dist/esm/activities/chat/middleware/builder.d.ts +46 -0
  10. package/dist/esm/activities/chat/middleware/builder.js +17 -0
  11. package/dist/esm/activities/chat/middleware/builder.js.map +1 -0
  12. package/dist/esm/activities/chat/middleware/capabilities.d.ts +93 -0
  13. package/dist/esm/activities/chat/middleware/capabilities.js +45 -0
  14. package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -0
  15. package/dist/esm/activities/chat/middleware/compose.d.ts +10 -0
  16. package/dist/esm/activities/chat/middleware/compose.js +47 -0
  17. package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
  18. package/dist/esm/activities/chat/middleware/define.d.ts +20 -0
  19. package/dist/esm/activities/chat/middleware/define.js +7 -0
  20. package/dist/esm/activities/chat/middleware/define.js.map +1 -0
  21. package/dist/esm/activities/chat/middleware/index.d.ts +8 -0
  22. package/dist/esm/activities/chat/middleware/types.d.ts +51 -0
  23. package/dist/esm/activities/chat/middleware/validate.d.ts +19 -0
  24. package/dist/esm/activities/chat/middleware/validate.js +30 -0
  25. package/dist/esm/activities/chat/middleware/validate.js.map +1 -0
  26. package/dist/esm/activities/chat/stream/message-updaters.js +1 -1
  27. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  28. package/dist/esm/activities/chat/stream/processor.d.ts +6 -0
  29. package/dist/esm/activities/chat/stream/processor.js +18 -3
  30. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  31. package/dist/esm/activities/generateVideo/index.d.ts +2 -1
  32. package/dist/esm/activities/generateVideo/index.js +12 -2
  33. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  34. package/dist/esm/index.d.ts +2 -0
  35. package/dist/esm/index.js +6 -0
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/logger/console-logger.d.ts +18 -0
  38. package/dist/esm/logger/console-logger.js +64 -8
  39. package/dist/esm/logger/console-logger.js.map +1 -1
  40. package/dist/esm/logger/types.d.ts +4 -4
  41. package/dist/esm/middlewares/otel.js +40 -12
  42. package/dist/esm/middlewares/otel.js.map +1 -1
  43. package/dist/esm/realtime/index.d.ts +1 -3
  44. package/dist/esm/realtime/index.js.map +1 -1
  45. package/dist/esm/types.d.ts +7 -1
  46. package/package.json +10 -2
  47. package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -2
  48. package/skills/ai-core/media-generation/SKILL.md +29 -1
  49. package/src/activities/chat/adapter.ts +11 -0
  50. package/src/activities/chat/index.ts +34 -14
  51. package/src/activities/chat/messages.ts +1 -0
  52. package/src/activities/chat/middleware/builder.ts +109 -0
  53. package/src/activities/chat/middleware/capabilities.ts +162 -0
  54. package/src/activities/chat/middleware/compose.ts +51 -0
  55. package/src/activities/chat/middleware/define.ts +34 -0
  56. package/src/activities/chat/middleware/index.ts +20 -0
  57. package/src/activities/chat/middleware/types.ts +60 -0
  58. package/src/activities/chat/middleware/validate.ts +55 -0
  59. package/src/activities/chat/stream/message-updaters.ts +1 -1
  60. package/src/activities/chat/stream/processor.ts +30 -3
  61. package/src/activities/generateVideo/index.ts +12 -0
  62. package/src/index.ts +14 -0
  63. package/src/logger/console-logger.ts +112 -17
  64. package/src/logger/types.ts +4 -4
  65. package/src/middlewares/otel.ts +57 -12
  66. package/src/realtime/index.ts +1 -3
  67. package/src/types.ts +7 -0
@@ -1,4 +1,5 @@
1
1
  import { DefaultMessageMetadataByModality, JSONSchema, Modality, StreamChunk, TextOptions, TokenUsage } from '../../types.js';
2
+ import { CapabilityHandle } from './middleware/capabilities.js';
2
3
  /**
3
4
  * Configuration for adapter instances
4
5
  */
@@ -59,6 +60,14 @@ export interface TextAdapter<TModel extends string, TProviderOptions extends Rec
59
60
  readonly name: string;
60
61
  /** The model this adapter is configured for */
61
62
  readonly model: TModel;
63
+ /**
64
+ * Capabilities this adapter requires at runtime. `chat()` validates that the
65
+ * configured middleware provides each one. Model adapters omit this; harness
66
+ * adapters (e.g. a future `claudeCode()`) declare e.g. `[sandboxCapability]`.
67
+ * Runtime access to capabilities from inside the adapter is not yet wired —
68
+ * this is the declaration/validation surface only.
69
+ */
70
+ readonly requires?: ReadonlyArray<CapabilityHandle>;
62
71
  /**
63
72
  * @internal Type-only properties for inference. Not assigned at runtime.
64
73
  */
@@ -133,6 +142,7 @@ export declare abstract class BaseTextAdapter<TModel extends string, TProviderOp
133
142
  readonly kind: "text";
134
143
  abstract readonly name: string;
135
144
  readonly model: TModel;
145
+ readonly requires?: ReadonlyArray<CapabilityHandle>;
136
146
  '~types': {
137
147
  providerOptions: TProviderOptions;
138
148
  inputModalities: TInputModalities;
@@ -1,6 +1,7 @@
1
1
  class BaseTextAdapter {
2
2
  kind = "text";
3
3
  model;
4
+ requires = void 0;
4
5
  config;
5
6
  constructor(config = {}, model) {
6
7
  this.config = config;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sources":["../../../../src/activities/chat/adapter.ts"],"sourcesContent":["import type {\n DefaultMessageMetadataByModality,\n JSONSchema,\n Modality,\n StreamChunk,\n TextOptions,\n TokenUsage,\n} from '../../types'\n\n/**\n * Configuration for adapter instances\n */\nexport interface TextAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Options for structured output generation.\n *\n * The internal logger is threaded through `chatOptions.logger` (inherited from\n * `TextOptions`). Adapter implementations must call `logger.request()` before\n * SDK calls, `logger.provider()` for each chunk received, and `logger.errors()`\n * in catch blocks.\n */\nexport interface StructuredOutputOptions<TProviderOptions extends object> {\n /** Text options for the request */\n chatOptions: TextOptions<TProviderOptions>\n /** JSON Schema for structured output - already converted from Zod in the ai layer */\n outputSchema: JSONSchema\n}\n\n/**\n * Result from structured output generation\n */\nexport interface StructuredOutputResult<T = unknown> {\n /** The parsed data conforming to the schema */\n data: T\n /** The raw text response from the model before parsing */\n rawText: string\n /** Token usage information (if provided by the adapter) */\n usage?: TokenUsage\n}\n\n/**\n * Text adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'gpt-4o')\n * - TProviderOptions: Provider-specific options for this model (already resolved)\n * - TInputModalities: Supported input modalities for this model (already resolved)\n * - TMessageMetadata: Metadata types for content parts (already resolved)\n * - TToolCapabilities: Tuple of tool-kind strings supported by this model, resolved from `supports.tools`\n * - TToolCallMetadata: Metadata type that round-trips with tool calls (e.g. Gemini's `thoughtSignature`)\n * - TSystemPromptMetadata: Provider-typed metadata accepted on each\n * `systemPrompts[i]` entry (e.g. Anthropic `cache_control`). Defaults to\n * `never` — adapters without per-prompt metadata reject the `metadata`\n * field at the call site.\n */\nexport interface TextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, any>,\n TInputModalities extends ReadonlyArray<Modality>,\n TMessageMetadataByModality extends DefaultMessageMetadataByModality,\n TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\n TToolCallMetadata = unknown,\n TSystemPromptMetadata = never,\n> {\n /** Discriminator for adapter kind */\n readonly kind: 'text'\n /** Provider name identifier (e.g., 'openai', 'anthropic') */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n inputModalities: TInputModalities\n messageMetadataByModality: TMessageMetadataByModality\n toolCapabilities: TToolCapabilities\n toolCallMetadata: TToolCallMetadata\n systemPromptMetadata: TSystemPromptMetadata\n }\n\n /**\n * Stream text completions from the model\n */\n chatStream: (\n options: TextOptions<TProviderOptions>,\n ) => AsyncIterable<StreamChunk>\n\n /**\n * Generate structured output using the provider's native structured output API.\n * This method uses stream: false and sends the JSON schema to the provider\n * to ensure the response conforms to the expected structure.\n *\n * @param options - Structured output options containing chat options and JSON schema\n * @returns Promise with the raw data (validation is done in the chat function)\n */\n structuredOutput: (\n options: StructuredOutputOptions<TProviderOptions>,\n ) => Promise<StructuredOutputResult<unknown>>\n\n /**\n * Stream structured output using the provider's native streaming structured\n * output API (stream + response_format json_schema in a single request).\n *\n * Optional — adapters without native streaming JSON omit this method and the\n * activity layer synthesizes a stream around the non-streaming\n * `structuredOutput` call.\n *\n * Implementations must emit standard AG-UI lifecycle events (RUN_STARTED,\n * TEXT_MESSAGE_*, RUN_FINISHED) carrying raw JSON text deltas, plus a final\n * `CUSTOM` event named `structured-output.complete` whose `value` is\n * `{ object, raw, reasoning? }`.\n */\n structuredOutputStream?: (\n options: StructuredOutputOptions<TProviderOptions>,\n ) => AsyncIterable<StreamChunk>\n\n /**\n * Declares whether the adapter supports combining `tools` and a\n * schema-constrained final answer in a single streaming request.\n *\n * When `true`, the engine wires `outputSchema` into the regular\n * `chatStream()` call and skips the separate `runStructuredFinalization`\n * round-trip. The model's natural final turn carries the\n * schema-constrained JSON text and the engine harvests it from the agent\n * loop's accumulated content.\n *\n * When `false`, `undefined`, or the method is omitted, the engine runs\n * the agent loop without `outputSchema` and then issues a separate\n * `structuredOutput` / `structuredOutputStream` call against the JSON\n * schema for finalization (the legacy path).\n *\n * The method receives the per-call `modelOptions` so providers whose\n * support depends on the resolved upstream model (e.g. OpenRouter) can\n * answer per-request. Most adapters can return a constant.\n */\n supportsCombinedToolsAndSchema?: (\n modelOptions?: TProviderOptions | undefined,\n ) => boolean\n}\n\n/**\n * A TextAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyTextAdapter = TextAdapter<any, any, any, any, any, any, any>\n\n/**\n * Abstract base class for text adapters.\n * Extend this class to implement a text adapter for a specific provider.\n *\n * Generic parameters match TextAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseTextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, any>,\n TInputModalities extends ReadonlyArray<Modality>,\n TMessageMetadataByModality extends DefaultMessageMetadataByModality,\n TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\n TToolCallMetadata = unknown,\n TSystemPromptMetadata = never,\n> implements TextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n TMessageMetadataByModality,\n TToolCapabilities,\n TToolCallMetadata,\n TSystemPromptMetadata\n> {\n readonly kind = 'text' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n inputModalities: TInputModalities\n messageMetadataByModality: TMessageMetadataByModality\n toolCapabilities: TToolCapabilities\n toolCallMetadata: TToolCallMetadata\n systemPromptMetadata: TSystemPromptMetadata\n }\n\n protected config: TextAdapterConfig\n\n constructor(config: TextAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract chatStream(\n options: TextOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk>\n\n /**\n * Generate structured output using the provider's native structured output API.\n * Concrete implementations should override this to use provider-specific structured output.\n */\n abstract structuredOutput(\n options: StructuredOutputOptions<TProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"AAqKO,MAAe,gBAgBpB;AAAA,EACS,OAAO;AAAA,EAEP;AAAA,EAYC;AAAA,EAEV,YAAY,SAA4B,CAAA,GAAI,OAAe;AACzD,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA,EAcU,aAAqB;AAC7B,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC9E;AACF;"}
1
+ {"version":3,"file":"adapter.js","sources":["../../../../src/activities/chat/adapter.ts"],"sourcesContent":["import type {\n DefaultMessageMetadataByModality,\n JSONSchema,\n Modality,\n StreamChunk,\n TextOptions,\n TokenUsage,\n} from '../../types'\nimport type { CapabilityHandle } from './middleware/capabilities'\n\n/**\n * Configuration for adapter instances\n */\nexport interface TextAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Options for structured output generation.\n *\n * The internal logger is threaded through `chatOptions.logger` (inherited from\n * `TextOptions`). Adapter implementations must call `logger.request()` before\n * SDK calls, `logger.provider()` for each chunk received, and `logger.errors()`\n * in catch blocks.\n */\nexport interface StructuredOutputOptions<TProviderOptions extends object> {\n /** Text options for the request */\n chatOptions: TextOptions<TProviderOptions>\n /** JSON Schema for structured output - already converted from Zod in the ai layer */\n outputSchema: JSONSchema\n}\n\n/**\n * Result from structured output generation\n */\nexport interface StructuredOutputResult<T = unknown> {\n /** The parsed data conforming to the schema */\n data: T\n /** The raw text response from the model before parsing */\n rawText: string\n /** Token usage information (if provided by the adapter) */\n usage?: TokenUsage\n}\n\n/**\n * Text adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'gpt-4o')\n * - TProviderOptions: Provider-specific options for this model (already resolved)\n * - TInputModalities: Supported input modalities for this model (already resolved)\n * - TMessageMetadata: Metadata types for content parts (already resolved)\n * - TToolCapabilities: Tuple of tool-kind strings supported by this model, resolved from `supports.tools`\n * - TToolCallMetadata: Metadata type that round-trips with tool calls (e.g. Gemini's `thoughtSignature`)\n * - TSystemPromptMetadata: Provider-typed metadata accepted on each\n * `systemPrompts[i]` entry (e.g. Anthropic `cache_control`). Defaults to\n * `never` — adapters without per-prompt metadata reject the `metadata`\n * field at the call site.\n */\nexport interface TextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, any>,\n TInputModalities extends ReadonlyArray<Modality>,\n TMessageMetadataByModality extends DefaultMessageMetadataByModality,\n TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\n TToolCallMetadata = unknown,\n TSystemPromptMetadata = never,\n> {\n /** Discriminator for adapter kind */\n readonly kind: 'text'\n /** Provider name identifier (e.g., 'openai', 'anthropic') */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * Capabilities this adapter requires at runtime. `chat()` validates that the\n * configured middleware provides each one. Model adapters omit this; harness\n * adapters (e.g. a future `claudeCode()`) declare e.g. `[sandboxCapability]`.\n * Runtime access to capabilities from inside the adapter is not yet wired —\n * this is the declaration/validation surface only.\n */\n readonly requires?: ReadonlyArray<CapabilityHandle>\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n inputModalities: TInputModalities\n messageMetadataByModality: TMessageMetadataByModality\n toolCapabilities: TToolCapabilities\n toolCallMetadata: TToolCallMetadata\n systemPromptMetadata: TSystemPromptMetadata\n }\n\n /**\n * Stream text completions from the model\n */\n chatStream: (\n options: TextOptions<TProviderOptions>,\n ) => AsyncIterable<StreamChunk>\n\n /**\n * Generate structured output using the provider's native structured output API.\n * This method uses stream: false and sends the JSON schema to the provider\n * to ensure the response conforms to the expected structure.\n *\n * @param options - Structured output options containing chat options and JSON schema\n * @returns Promise with the raw data (validation is done in the chat function)\n */\n structuredOutput: (\n options: StructuredOutputOptions<TProviderOptions>,\n ) => Promise<StructuredOutputResult<unknown>>\n\n /**\n * Stream structured output using the provider's native streaming structured\n * output API (stream + response_format json_schema in a single request).\n *\n * Optional — adapters without native streaming JSON omit this method and the\n * activity layer synthesizes a stream around the non-streaming\n * `structuredOutput` call.\n *\n * Implementations must emit standard AG-UI lifecycle events (RUN_STARTED,\n * TEXT_MESSAGE_*, RUN_FINISHED) carrying raw JSON text deltas, plus a final\n * `CUSTOM` event named `structured-output.complete` whose `value` is\n * `{ object, raw, reasoning? }`.\n */\n structuredOutputStream?: (\n options: StructuredOutputOptions<TProviderOptions>,\n ) => AsyncIterable<StreamChunk>\n\n /**\n * Declares whether the adapter supports combining `tools` and a\n * schema-constrained final answer in a single streaming request.\n *\n * When `true`, the engine wires `outputSchema` into the regular\n * `chatStream()` call and skips the separate `runStructuredFinalization`\n * round-trip. The model's natural final turn carries the\n * schema-constrained JSON text and the engine harvests it from the agent\n * loop's accumulated content.\n *\n * When `false`, `undefined`, or the method is omitted, the engine runs\n * the agent loop without `outputSchema` and then issues a separate\n * `structuredOutput` / `structuredOutputStream` call against the JSON\n * schema for finalization (the legacy path).\n *\n * The method receives the per-call `modelOptions` so providers whose\n * support depends on the resolved upstream model (e.g. OpenRouter) can\n * answer per-request. Most adapters can return a constant.\n */\n supportsCombinedToolsAndSchema?: (\n modelOptions?: TProviderOptions | undefined,\n ) => boolean\n}\n\n/**\n * A TextAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyTextAdapter = TextAdapter<any, any, any, any, any, any, any>\n\n/**\n * Abstract base class for text adapters.\n * Extend this class to implement a text adapter for a specific provider.\n *\n * Generic parameters match TextAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseTextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, any>,\n TInputModalities extends ReadonlyArray<Modality>,\n TMessageMetadataByModality extends DefaultMessageMetadataByModality,\n TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\n TToolCallMetadata = unknown,\n TSystemPromptMetadata = never,\n> implements TextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n TMessageMetadataByModality,\n TToolCapabilities,\n TToolCallMetadata,\n TSystemPromptMetadata\n> {\n readonly kind = 'text' as const\n abstract readonly name: string\n readonly model: TModel\n readonly requires?: ReadonlyArray<CapabilityHandle> = undefined\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n inputModalities: TInputModalities\n messageMetadataByModality: TMessageMetadataByModality\n toolCapabilities: TToolCapabilities\n toolCallMetadata: TToolCallMetadata\n systemPromptMetadata: TSystemPromptMetadata\n }\n\n protected config: TextAdapterConfig\n\n constructor(config: TextAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract chatStream(\n options: TextOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk>\n\n /**\n * Generate structured output using the provider's native structured output API.\n * Concrete implementations should override this to use provider-specific structured output.\n */\n abstract structuredOutput(\n options: StructuredOutputOptions<TProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"AA+KO,MAAe,gBAgBpB;AAAA,EACS,OAAO;AAAA,EAEP;AAAA,EACA,WAA6C;AAAA,EAY5C;AAAA,EAEV,YAAY,SAA4B,CAAA,GAAI,OAAe;AACzD,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA,EAcU,aAAqB;AAC7B,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC9E;AACF;"}
@@ -1,6 +1,7 @@
1
1
  import { AnyTextAdapter } from './adapter.js';
2
2
  import { AnyTool, ConstrainedModelMessage, InferSchemaType, ModelMessage, SchemaInput, StreamChunk, StructuredOutputStream, TextOptions, UIMessage } from '../../types.js';
3
- import { ChatMiddleware } from './middleware/types.js';
3
+ import { AnyChatMiddleware, ChatMiddleware } from './middleware/types.js';
4
+ import { CheckCoverage } from './middleware/builder.js';
4
5
  import { SystemPrompt } from '../../system-prompts.js';
5
6
  import { DebugOption } from '../../logger/types.js';
6
7
  import { ProviderTool } from '../../tools/provider-tool.js';
@@ -30,7 +31,7 @@ type RequiredContextFromInputs<TTools, TMiddleware> = [
30
31
  };
31
32
  type TextActivityOptionsWithContext<TAdapter extends AnyTextAdapter, TSchema extends SchemaInput | undefined, TStream extends boolean, TTools extends TextActivityOptions<TAdapter, TSchema, TStream, any>['tools'], TMiddleware extends TextActivityOptions<TAdapter, TSchema, TStream, any>['middleware']> = Omit<TextActivityOptions<TAdapter, TSchema, TStream, any>, 'tools' | 'middleware' | 'context'> & {
32
33
  tools?: TTools;
33
- middleware?: TMiddleware;
34
+ middleware?: TMiddleware & CheckCoverage<Extract<TMiddleware, ReadonlyArray<AnyChatMiddleware>>>;
34
35
  } & RequiredContextFromInputs<TTools, TMiddleware>;
35
36
  /**
36
37
  * Options for the text activity.
@@ -9,6 +9,8 @@ import { convertSchemaToJsonSchema, isStandardSchema, parseWithStandardSchema }
9
9
  import { maxIterations } from "./agent-loop-strategies.js";
10
10
  import { convertMessagesToModelMessages, generateMessageId } from "./messages.js";
11
11
  import { MiddlewareRunner } from "./middleware/compose.js";
12
+ import { CapabilityRegistry } from "./middleware/capabilities.js";
13
+ import { validateCapabilities } from "./middleware/validate.js";
12
14
  import { MCPManager } from "./mcp/manager.js";
13
15
  import { EventType } from "@ag-ui/core";
14
16
  const kind = "text";
@@ -170,7 +172,15 @@ class TextEngine {
170
172
  accumulatedContent: "",
171
173
  // References
172
174
  messages: this.messages,
173
- createId: (prefix) => this.createId(prefix)
175
+ createId: (prefix) => this.createId(prefix),
176
+ // Capability bookkeeping for this request (populated by middleware setup)
177
+ capabilities: new CapabilityRegistry(),
178
+ // Convenience accessors that delegate to a capability handle's own
179
+ // tuple getter/provider, keyed by this context. `getX(ctx)` and
180
+ // `ctx.get(X)` are interchangeable.
181
+ get: (capability) => capability[0](this.middlewareCtx),
182
+ getOptional: (capability) => capability[0](this.middlewareCtx, { optional: true }),
183
+ provide: (capability, value) => capability[1](this.middlewareCtx, value)
174
184
  };
175
185
  }
176
186
  /** Get the accumulated content after the chat loop completes */
@@ -205,6 +215,7 @@ class TextEngine {
205
215
  threadId: this.middlewareCtx.threadId
206
216
  });
207
217
  try {
218
+ await this.middlewareRunner.runSetup(this.middlewareCtx);
208
219
  this.middlewareCtx.phase = "init";
209
220
  const initialConfig = this.buildMiddlewareConfig();
210
221
  const transformedConfig = await this.middlewareRunner.runOnConfig(
@@ -896,17 +907,17 @@ class TextEngine {
896
907
  delta: args,
897
908
  args
898
909
  });
910
+ chunks.push({
911
+ type: "TOOL_CALL_END",
912
+ timestamp: Date.now(),
913
+ model: finishEvent.model,
914
+ toolCallId: result.toolCallId,
915
+ toolCallName: result.toolName,
916
+ toolName: result.toolName,
917
+ result: wireContent,
918
+ ...result.state !== void 0 && { state: result.state }
919
+ });
899
920
  }
900
- chunks.push({
901
- type: "TOOL_CALL_END",
902
- timestamp: Date.now(),
903
- model: finishEvent.model,
904
- toolCallId: result.toolCallId,
905
- toolCallName: result.toolName,
906
- toolName: result.toolName,
907
- result: wireContent,
908
- ...result.state !== void 0 && { state: result.state }
909
- });
910
921
  chunks.push({
911
922
  type: "TOOL_CALL_RESULT",
912
923
  timestamp: Date.now(),
@@ -1406,6 +1417,7 @@ class TextEngine {
1406
1417
  }
1407
1418
  }
1408
1419
  function chat(options) {
1420
+ validateCapabilities(options.middleware ?? [], options.adapter);
1409
1421
  const { outputSchema, stream } = options;
1410
1422
  if (outputSchema && stream === true) {
1411
1423
  return runStreamingStructuredOutput({