@tanstack/ai 0.17.0 → 0.19.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 (43) hide show
  1. package/README.md +0 -4
  2. package/dist/esm/activities/chat/index.d.ts +12 -3
  3. package/dist/esm/activities/chat/index.js +75 -7
  4. package/dist/esm/activities/chat/index.js.map +1 -1
  5. package/dist/esm/activities/chat/messages.js +41 -2
  6. package/dist/esm/activities/chat/messages.js.map +1 -1
  7. package/dist/esm/activities/chat/middleware/compose.js +1 -1
  8. package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
  9. package/dist/esm/activities/chat/middleware/types.d.ts +12 -1
  10. package/dist/esm/activities/chat/stream/message-updaters.d.ts +35 -0
  11. package/dist/esm/activities/chat/stream/message-updaters.js +95 -0
  12. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  13. package/dist/esm/activities/chat/stream/processor.d.ts +1 -0
  14. package/dist/esm/activities/chat/stream/processor.js +90 -2
  15. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  16. package/dist/esm/activities/chat/tools/schema-converter.js +5 -0
  17. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
  18. package/dist/esm/adapter-internals.d.ts +1 -0
  19. package/dist/esm/index.d.ts +3 -0
  20. package/dist/esm/index.js +8 -2
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/types.d.ts +86 -16
  23. package/dist/esm/utilities/ag-ui-wire.d.ts +44 -0
  24. package/dist/esm/utilities/ag-ui-wire.js +104 -0
  25. package/dist/esm/utilities/ag-ui-wire.js.map +1 -0
  26. package/dist/esm/utilities/chat-params.d.ts +80 -0
  27. package/dist/esm/utilities/chat-params.js +96 -0
  28. package/dist/esm/utilities/chat-params.js.map +1 -0
  29. package/package.json +3 -3
  30. package/skills/ai-core/ag-ui-protocol/SKILL.md +46 -3
  31. package/skills/ai-core/structured-outputs/SKILL.md +240 -47
  32. package/src/activities/chat/index.ts +144 -10
  33. package/src/activities/chat/messages.ts +70 -4
  34. package/src/activities/chat/middleware/compose.ts +1 -1
  35. package/src/activities/chat/middleware/types.ts +12 -1
  36. package/src/activities/chat/stream/message-updaters.ts +171 -0
  37. package/src/activities/chat/stream/processor.ts +137 -2
  38. package/src/activities/chat/tools/schema-converter.ts +14 -0
  39. package/src/adapter-internals.ts +1 -0
  40. package/src/index.ts +11 -0
  41. package/src/types.ts +104 -15
  42. package/src/utilities/ag-ui-wire.ts +201 -0
  43. package/src/utilities/chat-params.ts +199 -0
@@ -1 +1 @@
1
- {"version":3,"file":"schema-converter.js","sources":["../../../../../src/activities/chat/tools/schema-converter.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unnecessary-condition */\n\nimport type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec'\nimport type { JSONSchema, SchemaInput } from '../../../types'\n\n/**\n * Check if a value is a Standard JSON Schema compliant schema.\n * Standard JSON Schema compliant libraries (Zod v4+, ArkType, Valibot with toStandardJsonSchema, etc.)\n * implement the '~standard' property with jsonSchema converter methods.\n */\nexport function isStandardJSONSchema(\n schema: unknown,\n): schema is StandardJSONSchemaV1 {\n return (\n typeof schema === 'object' &&\n schema !== null &&\n '~standard' in schema &&\n typeof (schema as StandardJSONSchemaV1)['~standard'] === 'object' &&\n (schema as StandardJSONSchemaV1)['~standard'].version === 1 &&\n typeof (schema as StandardJSONSchemaV1)['~standard'].jsonSchema ===\n 'object' &&\n typeof (schema as StandardJSONSchemaV1)['~standard'].jsonSchema.input ===\n 'function'\n )\n}\n\n/**\n * Check if a value is a Standard Schema compliant schema (for validation).\n * Standard Schema compliant libraries implement the '~standard' property with a validate function.\n */\nexport function isStandardSchema(schema: unknown): schema is StandardSchemaV1 {\n return (\n typeof schema === 'object' &&\n schema !== null &&\n '~standard' in schema &&\n typeof schema['~standard'] === 'object' &&\n schema !== null &&\n schema['~standard'] !== null &&\n 'version' in schema['~standard'] &&\n schema['~standard'].version === 1 &&\n 'validate' in schema['~standard'] &&\n typeof schema['~standard'].validate === 'function'\n )\n}\n\n/**\n * Transform a JSON schema to be compatible with OpenAI's structured output requirements.\n * OpenAI requires:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for objects\n *\n * @param schema - JSON schema to transform\n * @param originalRequired - Original required array (to know which fields were optional)\n * @returns Transformed schema compatible with OpenAI structured output\n */\nfunction makeStructuredOutputCompatible(\n schema: Record<string, any>,\n originalRequired: Array<string> = [],\n): Record<string, any> {\n const result = { ...schema }\n\n // Handle object types\n if (result.type === 'object' && result.properties) {\n const properties = { ...result.properties }\n const allPropertyNames = Object.keys(properties)\n\n // Transform each property\n for (const propName of allPropertyNames) {\n const prop = properties[propName]\n const wasOptional = !originalRequired.includes(propName)\n\n // Recursively transform nested objects/arrays\n if (prop.type === 'object' && prop.properties) {\n const transformed = makeStructuredOutputCompatible(\n prop,\n prop.required || [],\n )\n properties[propName] = wasOptional\n ? { ...transformed, type: ['object', 'null'] }\n : transformed\n } else if (prop.type === 'array' && prop.items) {\n const transformed = {\n ...prop,\n items: makeStructuredOutputCompatible(\n prop.items,\n prop.items.required || [],\n ),\n }\n properties[propName] = wasOptional\n ? { ...transformed, type: ['array', 'null'] }\n : transformed\n } else if (wasOptional) {\n // Make optional fields nullable by adding null to the type\n if (prop.type && !Array.isArray(prop.type)) {\n properties[propName] = {\n ...prop,\n type: [prop.type, 'null'],\n }\n } else if (Array.isArray(prop.type) && !prop.type.includes('null')) {\n properties[propName] = {\n ...prop,\n type: [...prop.type, 'null'],\n }\n }\n }\n }\n\n result.properties = properties\n // ALL properties must be required for OpenAI structured output\n result.required = allPropertyNames\n // additionalProperties must be false\n result.additionalProperties = false\n }\n\n // Handle array types with object items\n if (result.type === 'array' && result.items) {\n result.items = makeStructuredOutputCompatible(\n result.items,\n result.items.required || [],\n )\n }\n\n return result\n}\n\n/**\n * Options for schema conversion\n */\nexport interface ConvertSchemaOptions {\n /**\n * When true, transforms the schema to be compatible with OpenAI's structured output requirements:\n * - All properties are added to the `required` array\n * - Optional fields get null added to their type union\n * - additionalProperties is set to false for all objects\n *\n * @default false\n */\n forStructuredOutput?: boolean\n}\n\n/**\n * Converts a Standard JSON Schema compliant schema or plain JSONSchema to JSON Schema format\n * compatible with LLM providers.\n *\n * Supports any schema library that implements the Standard JSON Schema spec (v1):\n * - Zod v4+ (natively supports StandardJSONSchemaV1)\n * - ArkType (natively supports StandardJSONSchemaV1)\n * - Valibot (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)\n *\n * If the input is already a plain JSONSchema object, it is returned as-is.\n *\n * @param schema - Standard JSON Schema compliant schema or plain JSONSchema object to convert\n * @param options - Conversion options\n * @returns JSON Schema object that can be sent to LLM providers\n *\n * @example\n * ```typescript\n * // Using Zod v4+ (natively supports Standard JSON Schema)\n * import * as z from 'zod';\n *\n * const zodSchema = z.object({\n * location: z.string().describe('City name'),\n * unit: z.enum(['celsius', 'fahrenheit']).optional()\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(zodSchema);\n *\n * @example\n * // Using ArkType (natively supports Standard JSON Schema)\n * import { type } from 'arktype';\n *\n * const arkSchema = type({\n * location: 'string',\n * unit: \"'celsius' | 'fahrenheit'\"\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(arkSchema);\n *\n * @example\n * // Using Valibot (via toStandardJsonSchema)\n * import * as v from 'valibot';\n * import { toStandardJsonSchema } from '@valibot/to-json-schema';\n *\n * const valibotSchema = toStandardJsonSchema(v.object({\n * location: v.string(),\n * unit: v.optional(v.picklist(['celsius', 'fahrenheit']))\n * }));\n *\n * const jsonSchema = convertSchemaToJsonSchema(valibotSchema);\n *\n * @example\n * // Using JSONSchema directly (passes through unchanged)\n * const rawSchema = {\n * type: 'object',\n * properties: { location: { type: 'string' } },\n * required: ['location']\n * };\n * const result = convertSchemaToJsonSchema(rawSchema);\n * ```\n */\nexport function convertSchemaToJsonSchema(\n schema: SchemaInput | undefined,\n options: ConvertSchemaOptions = {},\n): JSONSchema | undefined {\n if (!schema) return undefined\n\n const { forStructuredOutput = false } = options\n\n // If it's a Standard JSON Schema compliant schema, use the standard interface\n if (isStandardJSONSchema(schema)) {\n const jsonSchema = schema['~standard'].jsonSchema.input({\n target: 'draft-07',\n })\n\n let result = jsonSchema\n\n if (typeof result === 'object' && '$schema' in result) {\n // Remove $schema property as it's not needed for LLM providers\n const { $schema, ...rest } = result\n result = rest\n }\n\n // Ensure object schemas always have type: \"object\"\n\n if (typeof result === 'object') {\n // If it has properties (even empty), it should be an object type\n if ('properties' in result && !result.type) {\n result.type = 'object'\n }\n\n // Ensure properties exists for object types (even if empty)\n if (result.type === 'object' && !('properties' in result)) {\n result.properties = {}\n }\n\n // Ensure required exists for object types (even if empty array)\n if (result.type === 'object' && !('required' in result)) {\n result.required = []\n }\n\n // Apply structured output transformation if requested\n if (forStructuredOutput) {\n result = makeStructuredOutputCompatible(\n result,\n (result.required as Array<string>) || [],\n )\n }\n }\n\n return result as JSONSchema\n }\n\n // If it's not a Standard JSON Schema, assume it's already a JSONSchema and pass through\n // Still apply structured output transformation if requested\n\n if (forStructuredOutput && typeof schema === 'object') {\n return makeStructuredOutputCompatible(\n schema as Record<string, any>,\n ((schema as JSONSchema).required as Array<string>) || [],\n ) as JSONSchema\n }\n\n return schema as JSONSchema\n}\n\n/**\n * Validates data against a Standard Schema compliant schema.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Validation result with success status, data or issues\n */\nexport async function validateWithStandardSchema<T>(\n schema: unknown,\n data: unknown,\n): Promise<\n | { success: true; data: T }\n | { success: false; issues: Array<{ message: string; path?: Array<string> }> }\n> {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return { success: true, data: data as T }\n }\n\n const result = await schema['~standard'].validate(data)\n\n if (!result.issues) {\n return { success: true, data: result.value as T }\n }\n\n return {\n success: false,\n issues: result.issues.map((issue) => ({\n message: issue.message || 'Validation failed',\n path: issue.path?.map(String),\n })),\n }\n}\n\n/**\n * Synchronously validates data against a Standard Schema compliant schema.\n * Note: Some Standard Schema implementations may only support async validation.\n * In those cases, this function will throw.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Parsed/validated data\n * @throws Error if validation fails or if the schema only supports async validation\n */\nexport function parseWithStandardSchema<T>(schema: unknown, data: unknown): T {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return data as T\n }\n\n const result = schema['~standard'].validate(data)\n\n // Handle async result (Promise)\n if (result instanceof Promise) {\n throw new Error(\n 'Schema validation returned a Promise. Use validateWithStandardSchema for async validation.',\n )\n }\n // Standard Schema validation returns { value } for success or { issues } for failure\n if (!result.issues) {\n return result.value as T\n }\n\n // invalid validation, throw error with all issues\n const errorMessages = result.issues\n .map((issue) => issue.message || 'Validation failed')\n .join(', ')\n throw new Error(`Validation failed: ${errorMessages}`)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema-converter.js","sources":["../../../../../src/activities/chat/tools/schema-converter.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unnecessary-condition */\n\nimport type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec'\nimport type { JSONSchema, SchemaInput } from '../../../types'\n\n/**\n * Check if a value is a Standard JSON Schema compliant schema.\n * Standard JSON Schema compliant libraries (Zod v4+, ArkType, Valibot with toStandardJsonSchema, etc.)\n * implement the '~standard' property with jsonSchema converter methods.\n */\nexport function isStandardJSONSchema(\n schema: unknown,\n): schema is StandardJSONSchemaV1 {\n return (\n typeof schema === 'object' &&\n schema !== null &&\n '~standard' in schema &&\n typeof (schema as StandardJSONSchemaV1)['~standard'] === 'object' &&\n (schema as StandardJSONSchemaV1)['~standard'].version === 1 &&\n typeof (schema as StandardJSONSchemaV1)['~standard'].jsonSchema ===\n 'object' &&\n typeof (schema as StandardJSONSchemaV1)['~standard'].jsonSchema.input ===\n 'function'\n )\n}\n\n/**\n * Check if a value is a Standard Schema compliant schema (for validation).\n * Standard Schema compliant libraries implement the '~standard' property with a validate function.\n */\nexport function isStandardSchema(schema: unknown): schema is StandardSchemaV1 {\n return (\n typeof schema === 'object' &&\n schema !== null &&\n '~standard' in schema &&\n typeof schema['~standard'] === 'object' &&\n schema !== null &&\n schema['~standard'] !== null &&\n 'version' in schema['~standard'] &&\n schema['~standard'].version === 1 &&\n 'validate' in schema['~standard'] &&\n typeof schema['~standard'].validate === 'function'\n )\n}\n\n/**\n * Transform a JSON schema to be compatible with OpenAI's structured output requirements.\n * OpenAI requires:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for objects\n *\n * @param schema - JSON schema to transform\n * @param originalRequired - Original required array (to know which fields were optional)\n * @returns Transformed schema compatible with OpenAI structured output\n */\nfunction makeStructuredOutputCompatible(\n schema: Record<string, any>,\n originalRequired: Array<string> = [],\n): Record<string, any> {\n const result = { ...schema }\n\n // Handle object types\n if (result.type === 'object' && result.properties) {\n const properties = { ...result.properties }\n const allPropertyNames = Object.keys(properties)\n\n // Transform each property\n for (const propName of allPropertyNames) {\n const prop = properties[propName]\n const wasOptional = !originalRequired.includes(propName)\n\n // Recursively transform nested objects/arrays\n if (prop.type === 'object' && prop.properties) {\n const transformed = makeStructuredOutputCompatible(\n prop,\n prop.required || [],\n )\n properties[propName] = wasOptional\n ? { ...transformed, type: ['object', 'null'] }\n : transformed\n } else if (prop.type === 'array' && prop.items) {\n const transformed = {\n ...prop,\n items: makeStructuredOutputCompatible(\n prop.items,\n prop.items.required || [],\n ),\n }\n properties[propName] = wasOptional\n ? { ...transformed, type: ['array', 'null'] }\n : transformed\n } else if (wasOptional) {\n // Make optional fields nullable by adding null to the type\n if (prop.type && !Array.isArray(prop.type)) {\n properties[propName] = {\n ...prop,\n type: [prop.type, 'null'],\n }\n } else if (Array.isArray(prop.type) && !prop.type.includes('null')) {\n properties[propName] = {\n ...prop,\n type: [...prop.type, 'null'],\n }\n }\n }\n }\n\n result.properties = properties\n // ALL properties must be required for OpenAI structured output\n result.required = allPropertyNames\n // additionalProperties must be false\n result.additionalProperties = false\n }\n\n // Handle array types with object items\n if (result.type === 'array' && result.items) {\n result.items = makeStructuredOutputCompatible(\n result.items,\n result.items.required || [],\n )\n }\n\n return result\n}\n\n/**\n * Options for schema conversion\n */\nexport interface ConvertSchemaOptions {\n /**\n * When true, transforms the schema to be compatible with OpenAI's structured output requirements:\n * - All properties are added to the `required` array\n * - Optional fields get null added to their type union\n * - additionalProperties is set to false for all objects\n *\n * @default false\n */\n forStructuredOutput?: boolean\n}\n\n/**\n * Converts a Standard JSON Schema compliant schema or plain JSONSchema to JSON Schema format\n * compatible with LLM providers.\n *\n * Supports any schema library that implements the Standard JSON Schema spec (v1):\n * - Zod v4+ (natively supports StandardJSONSchemaV1)\n * - ArkType (natively supports StandardJSONSchemaV1)\n * - Valibot (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)\n *\n * If the input is already a plain JSONSchema object, it is returned as-is.\n *\n * @param schema - Standard JSON Schema compliant schema or plain JSONSchema object to convert\n * @param options - Conversion options\n * @returns JSON Schema object that can be sent to LLM providers\n *\n * @example\n * ```typescript\n * // Using Zod v4+ (natively supports Standard JSON Schema)\n * import * as z from 'zod';\n *\n * const zodSchema = z.object({\n * location: z.string().describe('City name'),\n * unit: z.enum(['celsius', 'fahrenheit']).optional()\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(zodSchema);\n *\n * @example\n * // Using ArkType (natively supports Standard JSON Schema)\n * import { type } from 'arktype';\n *\n * const arkSchema = type({\n * location: 'string',\n * unit: \"'celsius' | 'fahrenheit'\"\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(arkSchema);\n *\n * @example\n * // Using Valibot (via toStandardJsonSchema)\n * import * as v from 'valibot';\n * import { toStandardJsonSchema } from '@valibot/to-json-schema';\n *\n * const valibotSchema = toStandardJsonSchema(v.object({\n * location: v.string(),\n * unit: v.optional(v.picklist(['celsius', 'fahrenheit']))\n * }));\n *\n * const jsonSchema = convertSchemaToJsonSchema(valibotSchema);\n *\n * @example\n * // Using JSONSchema directly (passes through unchanged)\n * const rawSchema = {\n * type: 'object',\n * properties: { location: { type: 'string' } },\n * required: ['location']\n * };\n * const result = convertSchemaToJsonSchema(rawSchema);\n * ```\n */\nexport function convertSchemaToJsonSchema(\n schema: SchemaInput | undefined,\n options: ConvertSchemaOptions = {},\n): JSONSchema | undefined {\n if (!schema) return undefined\n\n const { forStructuredOutput = false } = options\n\n // If it's a Standard JSON Schema compliant schema, use the standard interface\n if (isStandardJSONSchema(schema)) {\n const jsonSchema = schema['~standard'].jsonSchema.input({\n target: 'draft-07',\n })\n\n let result = jsonSchema\n\n if (typeof result === 'object' && '$schema' in result) {\n // Remove $schema property as it's not needed for LLM providers\n const { $schema, ...rest } = result\n result = rest\n }\n\n // Ensure object schemas always have type: \"object\"\n\n if (typeof result === 'object') {\n // If it has properties (even empty), it should be an object type\n if ('properties' in result && !result.type) {\n result.type = 'object'\n }\n\n // Ensure properties exists for object types (even if empty)\n if (result.type === 'object' && !('properties' in result)) {\n result.properties = {}\n }\n\n // Ensure required exists for object types (even if empty array)\n if (result.type === 'object' && !('required' in result)) {\n result.required = []\n }\n\n // Apply structured output transformation if requested\n if (forStructuredOutput) {\n result = makeStructuredOutputCompatible(\n result,\n (result.required as Array<string>) || [],\n )\n }\n }\n\n return result as JSONSchema\n }\n\n // Detect Standard Schema validators (Zod, ArkType, Valibot, …) that don't\n // expose a `~standard.jsonSchema` converter. These would otherwise fall\n // through to the JSONSchema pass-through below and ship `{ '~standard': … }`\n // straight to the LLM provider, producing an opaque downstream error. Fail\n // fast with actionable guidance instead.\n if (isStandardSchema(schema)) {\n throw new Error(\n 'Schema is a Standard Schema validator but does not expose a JSON Schema ' +\n 'converter on `~standard.jsonSchema`. Use Zod v4.2+, ArkType v2.1.28+, ' +\n 'or wrap a Valibot schema with `toStandardJsonSchema()` from ' +\n '`@valibot/to-json-schema` before passing it as `outputSchema`.',\n )\n }\n\n // If it's not a Standard JSON Schema, assume it's already a JSONSchema and pass through\n // Still apply structured output transformation if requested\n\n if (forStructuredOutput && typeof schema === 'object') {\n return makeStructuredOutputCompatible(\n schema as Record<string, any>,\n ((schema as JSONSchema).required as Array<string>) || [],\n ) as JSONSchema\n }\n\n return schema as JSONSchema\n}\n\n/**\n * Validates data against a Standard Schema compliant schema.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Validation result with success status, data or issues\n */\nexport async function validateWithStandardSchema<T>(\n schema: unknown,\n data: unknown,\n): Promise<\n | { success: true; data: T }\n | { success: false; issues: Array<{ message: string; path?: Array<string> }> }\n> {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return { success: true, data: data as T }\n }\n\n const result = await schema['~standard'].validate(data)\n\n if (!result.issues) {\n return { success: true, data: result.value as T }\n }\n\n return {\n success: false,\n issues: result.issues.map((issue) => ({\n message: issue.message || 'Validation failed',\n path: issue.path?.map(String),\n })),\n }\n}\n\n/**\n * Synchronously validates data against a Standard Schema compliant schema.\n * Note: Some Standard Schema implementations may only support async validation.\n * In those cases, this function will throw.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Parsed/validated data\n * @throws Error if validation fails or if the schema only supports async validation\n */\nexport function parseWithStandardSchema<T>(schema: unknown, data: unknown): T {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return data as T\n }\n\n const result = schema['~standard'].validate(data)\n\n // Handle async result (Promise)\n if (result instanceof Promise) {\n throw new Error(\n 'Schema validation returned a Promise. Use validateWithStandardSchema for async validation.',\n )\n }\n // Standard Schema validation returns { value } for success or { issues } for failure\n if (!result.issues) {\n return result.value as T\n }\n\n // invalid validation, throw error with all issues\n const errorMessages = result.issues\n .map((issue) => issue.message || 'Validation failed')\n .join(', ')\n throw new Error(`Validation failed: ${errorMessages}`)\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export type { ResolvedCategories } from './logger/internal-logger.js';
2
2
  export { InternalLogger } from './logger/internal-logger.js';
3
+ export type { Logger } from './logger/types.js';
3
4
  export { resolveDebugOption } from './logger/resolve.js';
4
5
  export { toRunErrorPayload } from './activities/error-payload.js';
@@ -22,6 +22,9 @@ export type { RealtimeToken, RealtimeTokenAdapter, RealtimeTokenOptions, Realtim
22
22
  export { convertMessagesToModelMessages, generateMessageId, uiMessageToModelMessages, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, } from './activities/chat/messages.js';
23
23
  export { StreamProcessor, createReplayStream, ImmediateStrategy, PunctuationStrategy, BatchStrategy, WordBoundaryStrategy, CompositeStrategy, PartialJSONParser, defaultJSONParser, parsePartialJSON, } from './activities/chat/stream/index.js';
24
24
  export type { ChunkStrategy, ChunkRecording, InternalToolCallState, ProcessorResult, ProcessorState, StreamProcessorEvents, StreamProcessorOptions, ToolCallState, ToolResultState, JSONParser, } from './activities/chat/stream/index.js';
25
+ export { chatParamsFromRequest, chatParamsFromRequestBody, mergeAgentTools, } from './utilities/chat-params.js';
26
+ export { uiMessagesToWire } from './utilities/ag-ui-wire.js';
27
+ export type { WireMessage } from './utilities/ag-ui-wire.js';
25
28
  export { createModel, extendAdapter } from './extend-adapter.js';
26
29
  export type { ExtendedModelDef } from './extend-adapter.js';
27
30
  export type { Logger, DebugCategories, DebugConfig, DebugOption, } from './logger/types.js';
package/dist/esm/index.js CHANGED
@@ -14,12 +14,14 @@ import { createFrozenRegistry, createToolRegistry } from "./tool-registry.js";
14
14
  import { detectImageMimeType } from "./utils.js";
15
15
  import { realtimeToken } from "./realtime/index.js";
16
16
  import { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, uiMessageToModelMessages } from "./activities/chat/messages.js";
17
+ import { chatParamsFromRequest, chatParamsFromRequestBody, mergeAgentTools } from "./utilities/chat-params.js";
18
+ import { uiMessagesToWire } from "./utilities/ag-ui-wire.js";
17
19
  import { createModel, extendAdapter } from "./extend-adapter.js";
18
20
  import { ConsoleLogger } from "./logger/console-logger.js";
19
- import { StreamProcessor, createReplayStream } from "./activities/chat/stream/processor.js";
20
21
  import { BatchStrategy, CompositeStrategy, ImmediateStrategy, PunctuationStrategy, WordBoundaryStrategy } from "./activities/chat/stream/strategies.js";
21
- import { PartialJSONParser, defaultJSONParser, parsePartialJSON } from "./activities/chat/stream/json-parser.js";
22
22
  import { EventType } from "@ag-ui/core";
23
+ import { PartialJSONParser, defaultJSONParser, parsePartialJSON } from "./activities/chat/stream/json-parser.js";
24
+ import { StreamProcessor, createReplayStream } from "./activities/chat/stream/processor.js";
23
25
  export {
24
26
  BatchStrategy,
25
27
  CompositeStrategy,
@@ -32,6 +34,8 @@ export {
32
34
  ToolCallManager,
33
35
  WordBoundaryStrategy,
34
36
  chat,
37
+ chatParamsFromRequest,
38
+ chatParamsFromRequestBody,
35
39
  combineStrategies,
36
40
  convertMessagesToModelMessages,
37
41
  convertSchemaToJsonSchema,
@@ -57,6 +61,7 @@ export {
57
61
  generateVideo,
58
62
  getVideoJobStatus,
59
63
  maxIterations,
64
+ mergeAgentTools,
60
65
  modelMessageToUIMessage,
61
66
  modelMessagesToUIMessages,
62
67
  normalizeToUIMessage,
@@ -70,6 +75,7 @@ export {
70
75
  toServerSentEventsStream,
71
76
  toolDefinition,
72
77
  uiMessageToModelMessages,
78
+ uiMessagesToWire,
73
79
  untilFinishReason
74
80
  };
75
81
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,4 +1,4 @@
1
- import { StandardJSONSchemaV1 } from '@standard-schema/spec';
1
+ import { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec';
2
2
  import { InternalLogger } from './logger/internal-logger.js';
3
3
  import { BaseEvent as AGUIBaseEvent, CustomEvent as AGUICustomEvent, MessagesSnapshotEvent as AGUIMessagesSnapshotEvent, ReasoningEncryptedValueEvent as AGUIReasoningEncryptedValueEvent, ReasoningEndEvent as AGUIReasoningEndEvent, ReasoningMessageContentEvent as AGUIReasoningMessageContentEvent, ReasoningMessageEndEvent as AGUIReasoningMessageEndEvent, ReasoningMessageStartEvent as AGUIReasoningMessageStartEvent, ReasoningStartEvent as AGUIReasoningStartEvent, RunErrorEvent as AGUIRunErrorEvent, RunFinishedEvent as AGUIRunFinishedEvent, RunStartedEvent as AGUIRunStartedEvent, StateDeltaEvent as AGUIStateDeltaEvent, StateSnapshotEvent as AGUIStateSnapshotEvent, StepFinishedEvent as AGUIStepFinishedEvent, StepStartedEvent as AGUIStepStartedEvent, TextMessageContentEvent as AGUITextMessageContentEvent, TextMessageEndEvent as AGUITextMessageEndEvent, TextMessageStartEvent as AGUITextMessageStartEvent, ToolCallArgsEvent as AGUIToolCallArgsEvent, ToolCallEndEvent as AGUIToolCallEndEvent, ToolCallResultEvent as AGUIToolCallResultEvent, ToolCallStartEvent as AGUIToolCallStartEvent, EventType } from '@ag-ui/core';
4
4
  /**
@@ -54,22 +54,32 @@ export interface JSONSchema {
54
54
  [key: string]: any;
55
55
  }
56
56
  /**
57
- * Union type for schema input - can be any Standard JSON Schema compliant schema or a plain JSONSchema object.
57
+ * Union type for schema input - can be any Standard Schema compliant validator,
58
+ * any Standard JSON Schema compliant schema, or a plain JSONSchema object.
58
59
  *
59
- * Standard JSON Schema compliant libraries include:
60
+ * Standard JSON Schema compliant libraries (carry the JSON-schema converter):
60
61
  * - Zod v4.2+ (natively supports StandardJSONSchemaV1)
61
62
  * - ArkType v2.1.28+ (natively supports StandardJSONSchemaV1)
62
63
  * - Valibot v1.2+ (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)
63
64
  *
65
+ * StandardSchemaV1 covers libraries whose published types only expose the
66
+ * validator surface — Zod's core `$ZodType['~standard']` is currently typed
67
+ * as `StandardSchemaV1.Props` even though the runtime attaches the
68
+ * `jsonSchema` converter, so this branch is what makes `InferSchemaType`
69
+ * recover the inferred type for callers using `z.ZodType<T>`.
70
+ *
64
71
  * @see https://standardschema.dev/json-schema
65
72
  */
66
- export type SchemaInput = StandardJSONSchemaV1<any, any> | JSONSchema;
73
+ export type SchemaInput = StandardJSONSchemaV1<any, any> | StandardSchemaV1<any, any> | JSONSchema;
67
74
  /**
68
75
  * Infer the TypeScript type from a schema.
69
76
  * For Standard JSON Schema compliant schemas, extracts the input type.
70
- * For plain JSONSchema, returns `any` since we can't infer types from JSON Schema at compile time.
77
+ * For Standard Schema validators (e.g. Zod's `~standard` surface), extracts
78
+ * the input type from the `StandardSchemaV1` shape.
79
+ * For plain JSONSchema, returns `unknown` since we can't infer types from
80
+ * JSON Schema at compile time.
71
81
  */
72
- export type InferSchemaType<T> = T extends StandardJSONSchemaV1<infer TInput, unknown> ? TInput : unknown;
82
+ export type InferSchemaType<T> = T extends StandardJSONSchemaV1<infer TInput, unknown> ? TInput : T extends StandardSchemaV1<infer TInput, unknown> ? TInput : unknown;
73
83
  export interface ToolCall<TMetadata = unknown> {
74
84
  id: string;
75
85
  type: 'function';
@@ -254,15 +264,49 @@ export interface ThinkingPart {
254
264
  stepId?: string;
255
265
  signature?: string;
256
266
  }
257
- export type MessagePart = TextPart | ImagePart | AudioPart | VideoPart | DocumentPart | ToolCallPart | ToolResultPart | ThinkingPart;
267
+ /**
268
+ * Recursive `Partial` — every nested field becomes optional. Used as the
269
+ * `partial` type on a streaming structured-output part since the progressive
270
+ * JSON parse hands back objects whose fields are only filled in as bytes
271
+ * arrive. Defaulted in `DeepPartial<unknown>` → `unknown` so untyped parts
272
+ * keep their existing shape.
273
+ */
274
+ export type DeepPartial<T> = T extends ReadonlyArray<infer U> ? Array<DeepPartial<U>> : T extends object ? {
275
+ [K in keyof T]?: DeepPartial<T[K]>;
276
+ } : T;
277
+ /**
278
+ * StructuredOutputPart — a typed structured response attached to the assistant
279
+ * message that produced it. Generic over the schema-inferred data type so
280
+ * consumers can thread `useChat({ outputSchema })`'s schema all the way down
281
+ * to `messages[i].parts[j].data`. Defaults to `unknown` so untyped consumers
282
+ * (e.g. internal codepaths that don't know about TSchema) keep working.
283
+ */
284
+ export interface StructuredOutputPart<TData = unknown> {
285
+ type: 'structured-output';
286
+ status: 'streaming' | 'complete' | 'error';
287
+ /** Progressive parse of `raw` via parsePartialJSON — populated while streaming and after complete. */
288
+ partial?: DeepPartial<TData>;
289
+ /** Validated final object — only set when `status === 'complete'`. */
290
+ data?: TData;
291
+ /** Accumulating JSON buffer. Source of truth for wire round-trip. */
292
+ raw: string;
293
+ /** Optional chain-of-thought surfaced by reasoning models alongside the structured output. */
294
+ reasoning?: string;
295
+ /** Populated when `status === 'error'`. */
296
+ errorMessage?: string;
297
+ }
298
+ export type MessagePart<TData = unknown> = TextPart | ImagePart | AudioPart | VideoPart | DocumentPart | ToolCallPart | ToolResultPart | ThinkingPart | StructuredOutputPart<TData>;
258
299
  /**
259
300
  * UIMessage - Domain-specific message format optimized for building chat UIs
260
- * Contains parts that can be text, tool calls, or tool results
301
+ * Contains parts that can be text, tool calls, or tool results. Generic over
302
+ * the structured-output data type so `useChat({ outputSchema })`'s schema
303
+ * narrows `parts.find(p => p.type === 'structured-output').data` on the
304
+ * consumer side without manual casts.
261
305
  */
262
- export interface UIMessage {
306
+ export interface UIMessage<TData = unknown> {
263
307
  id: string;
264
308
  role: 'system' | 'user' | 'assistant';
265
- parts: Array<MessagePart>;
309
+ parts: Array<MessagePart<TData>>;
266
310
  createdAt?: Date;
267
311
  }
268
312
  export type InputModalitiesTypes = {
@@ -598,8 +642,14 @@ export interface TextOptions<TProviderOptionsSuperset extends Record<string, any
598
642
  */
599
643
  outputSchema?: SchemaInput;
600
644
  /**
601
- * Conversation ID for correlating client and server-side devtools events.
602
- * When provided, server-side events will be linked to the client conversation in devtools.
645
+ * @deprecated Use `threadId` instead. `conversationId` is the legacy
646
+ * pre-AG-UI name for the same concept (a stable per-conversation
647
+ * identifier used to correlate client/server devtools events). When
648
+ * `conversationId` is omitted, the runtime falls back to `threadId`
649
+ * automatically, so most callers can simply pass `threadId` (or rely
650
+ * on `chatParamsFromRequest`, which surfaces it on `params`).
651
+ *
652
+ * Will be removed in a future major release.
603
653
  */
604
654
  conversationId?: string;
605
655
  /**
@@ -633,6 +683,11 @@ export interface TextOptions<TProviderOptionsSuperset extends Record<string, any
633
683
  * If not provided, a unique ID will be generated.
634
684
  */
635
685
  runId?: string;
686
+ /**
687
+ * Parent run ID for AG-UI protocol nested run correlation.
688
+ * Surfaced for observability/middleware; not consumed by the LLM call.
689
+ */
690
+ parentRunId?: string;
636
691
  }
637
692
  /**
638
693
  * Re-export EventType enum from @ag-ui/core for use in event creation.
@@ -921,11 +976,26 @@ export interface StructuredOutputCompleteEvent<T = unknown> extends Omit<CustomE
921
976
  reasoning?: string;
922
977
  };
923
978
  }
979
+ /**
980
+ * Emitted at the start of a streaming structured-output run, before the JSON
981
+ * deltas. Tells consumers that the upcoming `TEXT_MESSAGE_CONTENT` deltas
982
+ * belong to a structured response so they can route those bytes into a
983
+ * `StructuredOutputPart` instead of building a `TextPart`. Carries the
984
+ * `messageId` the deltas will be tagged with so the routing decision can be
985
+ * made per-message rather than globally.
986
+ */
987
+ export interface StructuredOutputStartEvent extends Omit<CustomEvent, 'name' | 'value'> {
988
+ name: 'structured-output.start';
989
+ value: {
990
+ messageId: string;
991
+ };
992
+ }
924
993
  /**
925
994
  * Emitted when a server tool requires approval before execution. The agent
926
995
  * loop yields this and pauses — `structured-output.complete` will not fire
927
996
  * for that run. The shape is fixed by the orchestrator's tool-approval flow
928
- * (see `buildApprovalChunks` in `activities/chat/index.ts`).
997
+ * (the agent-loop branch of `runStreamingStructuredOutputImpl` in
998
+ * `activities/chat/index.ts` forwards CUSTOM events from `TextEngine.run()`).
929
999
  */
930
1000
  export interface ApprovalRequestedEvent extends Omit<CustomEvent, 'name' | 'value'> {
931
1001
  name: 'approval-requested';
@@ -942,8 +1012,8 @@ export interface ApprovalRequestedEvent extends Omit<CustomEvent, 'name' | 'valu
942
1012
  /**
943
1013
  * Emitted when a client tool is invoked. The agent loop yields this and
944
1014
  * pauses to let the caller run the tool client-side — `structured-output.complete`
945
- * will not fire for that run. Shape fixed by `buildClientToolChunks` in
946
- * `activities/chat/index.ts`.
1015
+ * will not fire for that run. Shape fixed by the agent-loop forwarding in
1016
+ * `runStreamingStructuredOutputImpl` in `activities/chat/index.ts`.
947
1017
  */
948
1018
  export interface ToolInputAvailableEvent extends Omit<CustomEvent, 'name' | 'value'> {
949
1019
  name: 'tool-input-available';
@@ -983,7 +1053,7 @@ export interface ToolInputAvailableEvent extends Omit<CustomEvent, 'name' | 'val
983
1053
  * `emitCustomEvent` plus `outputSchema + stream: true`, branch on `CUSTOM`
984
1054
  * outside the literal-`name` narrows or cast explicitly.
985
1055
  */
986
- export type StructuredOutputStream<T = unknown> = AsyncIterable<Exclude<StreamChunk, CustomEvent> | StructuredOutputCompleteEvent<T> | ApprovalRequestedEvent | ToolInputAvailableEvent>;
1056
+ export type StructuredOutputStream<T = unknown> = AsyncIterable<Exclude<StreamChunk, CustomEvent> | StructuredOutputStartEvent | StructuredOutputCompleteEvent<T> | ApprovalRequestedEvent | ToolInputAvailableEvent>;
987
1057
  /**
988
1058
  * Emitted when reasoning starts for a message.
989
1059
  *
@@ -0,0 +1,44 @@
1
+ import { ContentPart, UIMessage } from '../types.js';
2
+ type AGUITextInputContent = {
3
+ type: 'text';
4
+ text: string;
5
+ };
6
+ type AGUIInputContent = AGUITextInputContent | (ContentPart & {
7
+ type: 'image' | 'audio' | 'video' | 'document';
8
+ });
9
+ type AGUIToolCallMirror = {
10
+ id: string;
11
+ type: 'function';
12
+ function: {
13
+ name: string;
14
+ arguments: string;
15
+ };
16
+ };
17
+ type AGUIToolMessage = {
18
+ role: 'tool';
19
+ id: string;
20
+ toolCallId: string;
21
+ content: string;
22
+ error?: string;
23
+ };
24
+ type AGUIReasoningMessage = {
25
+ role: 'reasoning';
26
+ id: string;
27
+ content: string;
28
+ };
29
+ type WireAnchorMessage = UIMessage & {
30
+ content?: string | Array<AGUIInputContent>;
31
+ toolCalls?: Array<AGUIToolCallMirror>;
32
+ };
33
+ export type WireMessage = WireAnchorMessage | AGUIToolMessage | AGUIReasoningMessage;
34
+ /**
35
+ * Serialize TanStack `UIMessage`s into the AG-UI `RunAgentInput.messages`
36
+ * wire shape. Each anchor (system/user/assistant) carries the canonical
37
+ * `parts` array verbatim plus AG-UI mirror fields (`content`, `toolCalls`)
38
+ * so AG-UI Zod parsing succeeds. Tool results and thinking parts on
39
+ * assistant messages are additionally emitted as fan-out
40
+ * `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict
41
+ * AG-UI server consumers.
42
+ */
43
+ export declare function uiMessagesToWire(messages: Array<UIMessage>): Array<WireMessage>;
44
+ export {};
@@ -0,0 +1,104 @@
1
+ function uiMessagesToWire(messages) {
2
+ const wire = [];
3
+ for (const msg of messages) {
4
+ const parts = msg.parts ?? [];
5
+ if (msg.role === "system") {
6
+ wire.push({
7
+ ...msg,
8
+ content: parts.length > 0 ? collectText(parts) : msg.content ?? ""
9
+ });
10
+ continue;
11
+ }
12
+ if (msg.role === "user") {
13
+ wire.push({
14
+ ...msg,
15
+ content: parts.length > 0 ? collectUserContent(parts) : msg.content ?? ""
16
+ });
17
+ continue;
18
+ }
19
+ for (const part of parts) {
20
+ if (part.type === "thinking") {
21
+ wire.push({
22
+ role: "reasoning",
23
+ id: deriveReasoningId(msg.id, part),
24
+ content: part.content
25
+ });
26
+ }
27
+ }
28
+ const text = collectText(parts);
29
+ const toolCalls = collectToolCalls(parts);
30
+ wire.push({
31
+ ...msg,
32
+ ...text !== "" && { content: text },
33
+ ...toolCalls && { toolCalls }
34
+ });
35
+ for (const part of parts) {
36
+ if (part.type === "tool-result") {
37
+ wire.push({
38
+ role: "tool",
39
+ id: deriveToolMessageId(part.toolCallId),
40
+ toolCallId: part.toolCallId,
41
+ content: part.content,
42
+ ...part.error !== void 0 && { error: part.error }
43
+ });
44
+ }
45
+ }
46
+ }
47
+ return wire;
48
+ }
49
+ function collectText(parts) {
50
+ const out = [];
51
+ for (const p of parts) {
52
+ if (p.type === "text") {
53
+ out.push(p.content);
54
+ } else if (p.type === "structured-output" && p.status === "complete" && p.raw !== "") {
55
+ out.push(p.raw);
56
+ }
57
+ }
58
+ return out.join("");
59
+ }
60
+ function collectUserContent(parts) {
61
+ const hasMultimodal = parts.some(
62
+ (p) => p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document"
63
+ );
64
+ if (!hasMultimodal) {
65
+ return collectText(parts);
66
+ }
67
+ const out = [];
68
+ for (const p of parts) {
69
+ if (p.type === "text") {
70
+ out.push({ type: "text", text: p.content });
71
+ } else if (p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document") {
72
+ out.push(p);
73
+ }
74
+ }
75
+ return out;
76
+ }
77
+ function collectToolCalls(parts) {
78
+ const calls = [];
79
+ for (const p of parts) {
80
+ if (p.type === "tool-call") {
81
+ calls.push({
82
+ id: p.id,
83
+ type: "function",
84
+ function: { name: p.name, arguments: p.arguments }
85
+ });
86
+ }
87
+ }
88
+ return calls.length > 0 ? calls : void 0;
89
+ }
90
+ function deriveReasoningId(messageId, part) {
91
+ return `${messageId}-reasoning-${part.id ?? hashContent(part.content)}`;
92
+ }
93
+ function deriveToolMessageId(toolCallId) {
94
+ return `tool-${toolCallId}`;
95
+ }
96
+ function hashContent(s) {
97
+ let h = 0;
98
+ for (let i = 0; i < s.length; i++) h = h * 31 + s.charCodeAt(i) | 0;
99
+ return Math.abs(h).toString(36);
100
+ }
101
+ export {
102
+ uiMessagesToWire
103
+ };
104
+ //# sourceMappingURL=ag-ui-wire.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ag-ui-wire.js","sources":["../../../src/utilities/ag-ui-wire.ts"],"sourcesContent":["import type { ContentPart, MessagePart, UIMessage } from '../types'\n\ntype AGUITextInputContent = { type: 'text'; text: string }\ntype AGUIInputContent =\n | AGUITextInputContent\n | (ContentPart & { type: 'image' | 'audio' | 'video' | 'document' })\n\ntype AGUIToolCallMirror = {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\ntype AGUIToolMessage = {\n role: 'tool'\n id: string\n toolCallId: string\n content: string\n error?: string\n}\n\ntype AGUIReasoningMessage = {\n role: 'reasoning'\n id: string\n content: string\n}\n\ntype WireAnchorMessage = UIMessage & {\n content?: string | Array<AGUIInputContent>\n toolCalls?: Array<AGUIToolCallMirror>\n}\n\nexport type WireMessage =\n | WireAnchorMessage\n | AGUIToolMessage\n | AGUIReasoningMessage\n\n/**\n * Serialize TanStack `UIMessage`s into the AG-UI `RunAgentInput.messages`\n * wire shape. Each anchor (system/user/assistant) carries the canonical\n * `parts` array verbatim plus AG-UI mirror fields (`content`, `toolCalls`)\n * so AG-UI Zod parsing succeeds. Tool results and thinking parts on\n * assistant messages are additionally emitted as fan-out\n * `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict\n * AG-UI server consumers.\n */\nexport function uiMessagesToWire(\n messages: Array<UIMessage>,\n): Array<WireMessage> {\n const wire: Array<WireMessage> = []\n\n for (const msg of messages) {\n // Defensive: if parts is missing (ModelMessage-shaped input), pass through as-is.\n // UIMessage always has parts; ModelMessage uses content directly.\n const parts: ReadonlyArray<MessagePart> =\n (msg.parts as ReadonlyArray<MessagePart> | undefined) ?? []\n\n if (msg.role === 'system') {\n wire.push({\n ...msg,\n content:\n parts.length > 0\n ? collectText(parts)\n : ((msg as unknown as { content?: string }).content ?? ''),\n })\n continue\n }\n\n if (msg.role === 'user') {\n wire.push({\n ...msg,\n content:\n parts.length > 0\n ? collectUserContent(parts)\n : ((msg as unknown as { content?: string }).content ?? ''),\n })\n continue\n }\n\n // assistant: emit reasoning fan-outs first, then anchor, then tool fan-outs\n for (const part of parts) {\n if (part.type === 'thinking') {\n wire.push({\n role: 'reasoning',\n id: deriveReasoningId(msg.id, part),\n content: part.content,\n })\n }\n }\n\n const text = collectText(parts)\n const toolCalls = collectToolCalls(parts)\n wire.push({\n ...msg,\n ...(text !== '' && { content: text }),\n ...(toolCalls && { toolCalls }),\n })\n\n for (const part of parts) {\n if (part.type === 'tool-result') {\n wire.push({\n role: 'tool',\n id: deriveToolMessageId(part.toolCallId),\n toolCallId: part.toolCallId,\n content: part.content,\n ...(part.error !== undefined && { error: part.error }),\n })\n }\n }\n }\n\n return wire\n}\n\nfunction collectText(parts: ReadonlyArray<MessagePart>): string {\n // The streamed JSON of a completed structured-output part is the source of\n // truth for multi-turn coherence — emitting it back as assistant content\n // lets the LLM see its own prior structured response. Streaming/errored\n // parts are skipped: they'd ship malformed JSON fragments and confuse the\n // model. `completeStructuredOutputPart` tries hard to populate `raw`\n // (caller → existing buffer → `JSON.stringify(data)`), but the stringify\n // fallback can leave it empty when `data` is unserializable (BigInt,\n // circular). The `p.raw !== ''` guard below is what enforces \"no malformed\n // round-trip\" in that case — without it we'd ship `''` and the model would\n // see an empty assistant turn.\n const out: Array<string> = []\n for (const p of parts) {\n if (p.type === 'text') {\n out.push(p.content)\n } else if (\n p.type === 'structured-output' &&\n p.status === 'complete' &&\n p.raw !== ''\n ) {\n out.push(p.raw)\n }\n }\n return out.join('')\n}\n\nfunction collectUserContent(\n parts: ReadonlyArray<MessagePart>,\n): string | Array<AGUIInputContent> {\n const hasMultimodal = parts.some(\n (p) =>\n p.type === 'image' ||\n p.type === 'audio' ||\n p.type === 'video' ||\n p.type === 'document',\n )\n if (!hasMultimodal) {\n return collectText(parts)\n }\n const out: Array<AGUIInputContent> = []\n for (const p of parts) {\n if (p.type === 'text') {\n out.push({ type: 'text', text: p.content })\n } else if (\n p.type === 'image' ||\n p.type === 'audio' ||\n p.type === 'video' ||\n p.type === 'document'\n ) {\n out.push(p as AGUIInputContent)\n }\n }\n return out\n}\n\nfunction collectToolCalls(\n parts: ReadonlyArray<MessagePart>,\n): Array<AGUIToolCallMirror> | undefined {\n const calls: Array<AGUIToolCallMirror> = []\n for (const p of parts) {\n if (p.type === 'tool-call') {\n calls.push({\n id: p.id,\n type: 'function',\n function: { name: p.name, arguments: p.arguments },\n })\n }\n }\n return calls.length > 0 ? calls : undefined\n}\n\nfunction deriveReasoningId(messageId: string, part: MessagePart): string {\n return `${messageId}-reasoning-${(part as { id?: string }).id ?? hashContent((part as { content: string }).content)}`\n}\n\nfunction deriveToolMessageId(toolCallId: string): string {\n return `tool-${toolCallId}`\n}\n\nfunction hashContent(s: string): string {\n // Cheap deterministic id suffix; collisions are tolerable since\n // reasoning ids only matter for AG-UI server consumers, not for our\n // own server's dedup logic (which keys on toolCallId, not reasoning id).\n let h = 0\n for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0\n return Math.abs(h).toString(36)\n}\n"],"names":[],"mappings":"AA8CO,SAAS,iBACd,UACoB;AACpB,QAAM,OAA2B,CAAA;AAEjC,aAAW,OAAO,UAAU;AAG1B,UAAM,QACH,IAAI,SAAoD,CAAA;AAE3D,QAAI,IAAI,SAAS,UAAU;AACzB,WAAK,KAAK;AAAA,QACR,GAAG;AAAA,QACH,SACE,MAAM,SAAS,IACX,YAAY,KAAK,IACf,IAAwC,WAAW;AAAA,MAAA,CAC5D;AACD;AAAA,IACF;AAEA,QAAI,IAAI,SAAS,QAAQ;AACvB,WAAK,KAAK;AAAA,QACR,GAAG;AAAA,QACH,SACE,MAAM,SAAS,IACX,mBAAmB,KAAK,IACtB,IAAwC,WAAW;AAAA,MAAA,CAC5D;AACD;AAAA,IACF;AAGA,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,SAAS,YAAY;AAC5B,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,UACN,IAAI,kBAAkB,IAAI,IAAI,IAAI;AAAA,UAClC,SAAS,KAAK;AAAA,QAAA,CACf;AAAA,MACH;AAAA,IACF;AAEA,UAAM,OAAO,YAAY,KAAK;AAC9B,UAAM,YAAY,iBAAiB,KAAK;AACxC,SAAK,KAAK;AAAA,MACR,GAAG;AAAA,MACH,GAAI,SAAS,MAAM,EAAE,SAAS,KAAA;AAAA,MAC9B,GAAI,aAAa,EAAE,UAAA;AAAA,IAAU,CAC9B;AAED,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,SAAS,eAAe;AAC/B,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,UACN,IAAI,oBAAoB,KAAK,UAAU;AAAA,UACvC,YAAY,KAAK;AAAA,UACjB,SAAS,KAAK;AAAA,UACd,GAAI,KAAK,UAAU,UAAa,EAAE,OAAO,KAAK,MAAA;AAAA,QAAM,CACrD;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,YAAY,OAA2C;AAW9D,QAAM,MAAqB,CAAA;AAC3B,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,SAAS,QAAQ;AACrB,UAAI,KAAK,EAAE,OAAO;AAAA,IACpB,WACE,EAAE,SAAS,uBACX,EAAE,WAAW,cACb,EAAE,QAAQ,IACV;AACA,UAAI,KAAK,EAAE,GAAG;AAAA,IAChB;AAAA,EACF;AACA,SAAO,IAAI,KAAK,EAAE;AACpB;AAEA,SAAS,mBACP,OACkC;AAClC,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,MACC,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS;AAAA,EAAA;AAEf,MAAI,CAAC,eAAe;AAClB,WAAO,YAAY,KAAK;AAAA,EAC1B;AACA,QAAM,MAA+B,CAAA;AACrC,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,SAAS,QAAQ;AACrB,UAAI,KAAK,EAAE,MAAM,QAAQ,MAAM,EAAE,SAAS;AAAA,IAC5C,WACE,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS,YACX;AACA,UAAI,KAAK,CAAqB;AAAA,IAChC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBACP,OACuC;AACvC,QAAM,QAAmC,CAAA;AACzC,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,SAAS,aAAa;AAC1B,YAAM,KAAK;AAAA,QACT,IAAI,EAAE;AAAA,QACN,MAAM;AAAA,QACN,UAAU,EAAE,MAAM,EAAE,MAAM,WAAW,EAAE,UAAA;AAAA,MAAU,CAClD;AAAA,IACH;AAAA,EACF;AACA,SAAO,MAAM,SAAS,IAAI,QAAQ;AACpC;AAEA,SAAS,kBAAkB,WAAmB,MAA2B;AACvE,SAAO,GAAG,SAAS,cAAe,KAAyB,MAAM,YAAa,KAA6B,OAAO,CAAC;AACrH;AAEA,SAAS,oBAAoB,YAA4B;AACvD,SAAO,QAAQ,UAAU;AAC3B;AAEA,SAAS,YAAY,GAAmB;AAItC,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,KAAK,IAAI,KAAK,EAAE,WAAW,CAAC,IAAK;AACpE,SAAO,KAAK,IAAI,CAAC,EAAE,SAAS,EAAE;AAChC;"}
@@ -0,0 +1,80 @@
1
+ import { Context as AGUIContext } from '@ag-ui/core';
2
+ import { JSONSchema, ModelMessage, Tool, UIMessage } from '../types.js';
3
+ /**
4
+ * Parse and validate an HTTP request body as an AG-UI `RunAgentInput`.
5
+ *
6
+ * Returns a spread-friendly object whose `messages` field is suitable for
7
+ * passing directly to `chat({ messages })`. The existing
8
+ * `convertMessagesToModelMessages` handles AG-UI fan-out dedup and
9
+ * reasoning/activity/developer-role normalization internally.
10
+ *
11
+ * @throws An error with a migration-pointing message when the body does
12
+ * not conform to AG-UI 0.0.52 `RunAgentInputSchema`. Surface this as a
13
+ * 400 Bad Request to the client.
14
+ */
15
+ export declare function chatParamsFromRequestBody(body: unknown): Promise<{
16
+ messages: Array<UIMessage | ModelMessage>;
17
+ threadId: string;
18
+ runId: string;
19
+ parentRunId?: string;
20
+ tools: Array<{
21
+ name: string;
22
+ description: string;
23
+ parameters: JSONSchema;
24
+ }>;
25
+ forwardedProps: Record<string, unknown>;
26
+ state: unknown;
27
+ context: Array<AGUIContext>;
28
+ }>;
29
+ /**
30
+ * Read an HTTP `Request`, parse its JSON body, and validate it as an
31
+ * AG-UI `RunAgentInput` — collapsing the standard `req.json()` +
32
+ * `chatParamsFromRequestBody(...)` pair into a single call.
33
+ *
34
+ * On a malformed body or invalid AG-UI shape, this **throws a
35
+ * `Response`** with status 400 and a migration-pointing message in the
36
+ * body. Frameworks that natively handle thrown `Response` objects
37
+ * (TanStack Start, SolidStart, Remix, React Router 7) will return the
38
+ * 400 to the client automatically, so the handler reduces to:
39
+ *
40
+ * ```ts
41
+ * export async function POST(req: Request) {
42
+ * const params = await chatParamsFromRequest(req)
43
+ * // ...use params
44
+ * }
45
+ * ```
46
+ *
47
+ * In frameworks that do not auto-handle thrown `Response` objects
48
+ * (Next.js Route Handlers, SvelteKit, Hono, raw Node), wrap the call
49
+ * with try/catch and return the caught Response yourself, or use
50
+ * `chatParamsFromRequestBody` directly with your own JSON-parsing.
51
+ *
52
+ * @throws {Response} 400 on malformed JSON or invalid AG-UI shape.
53
+ */
54
+ export declare function chatParamsFromRequest(req: Request): Promise<Awaited<ReturnType<typeof chatParamsFromRequestBody>>>;
55
+ /**
56
+ * Merge a server-side tool array with the AG-UI client-declared tools
57
+ * received in the request body.
58
+ *
59
+ * Rules:
60
+ * - Server tools win on name collision. The client's declaration is
61
+ * ignored if the server already has a tool with that name. The client's
62
+ * UI-side handler still fires when the streamed tool-result event comes
63
+ * through (see `chat-client.ts` `onToolCall`), giving the
64
+ * "after server execution the client also handles" semantic for free.
65
+ * - Client-only tools (name not in `serverTools`) become no-execute
66
+ * entries: the runtime's existing `ClientToolRequest` path handles
67
+ * them — server emits a tool-call request, client executes via its
68
+ * registered handler, client posts back the result.
69
+ *
70
+ * @param serverTools - The server's tool array (e.g. from
71
+ * `[myToolDef.server(...)]`). Pass directly to `chat({ tools })`.
72
+ * @param clientTools - The `tools` array received from
73
+ * `chatParamsFromRequest(...)` / `chatParamsFromRequestBody(...)`.
74
+ * @returns A merged array suitable for `chat({ tools })`.
75
+ */
76
+ export declare function mergeAgentTools(serverTools: ReadonlyArray<Tool>, clientTools: ReadonlyArray<{
77
+ name: string;
78
+ description: string;
79
+ parameters: JSONSchema;
80
+ }>): Array<Tool>;