@tanstack/ai 0.0.2 → 0.1.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/README.md +26 -0
- package/dist/esm/activities/chat/adapter.d.ts +100 -0
- package/dist/esm/activities/chat/adapter.js +14 -0
- package/dist/esm/activities/chat/adapter.js.map +1 -0
- package/dist/esm/{utilities → activities/chat}/agent-loop-strategies.d.ts +4 -4
- package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +165 -0
- package/dist/esm/{core/chat.js → activities/chat/index.js} +131 -33
- package/dist/esm/activities/chat/index.js.map +1 -0
- package/dist/esm/{message-converters.d.ts → activities/chat/messages.d.ts} +1 -1
- package/dist/esm/{message-converters.js → activities/chat/messages.js} +7 -7
- package/dist/esm/activities/chat/messages.js.map +1 -0
- package/dist/esm/activities/chat/stream/json-parser.js.map +1 -0
- package/dist/esm/{stream → activities/chat/stream}/message-updaters.d.ts +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -0
- package/dist/esm/{stream → activities/chat/stream}/processor.d.ts +1 -1
- package/dist/esm/{stream → activities/chat/stream}/processor.js +1 -1
- package/dist/esm/activities/chat/stream/processor.js.map +1 -0
- package/dist/esm/activities/chat/stream/strategies.js.map +1 -0
- package/dist/esm/{stream → activities/chat/stream}/types.d.ts +2 -9
- package/dist/esm/{tools → activities/chat/tools}/tool-calls.d.ts +1 -1
- package/dist/esm/{tools → activities/chat/tools}/tool-calls.js +9 -5
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -0
- package/dist/esm/{tools → activities/chat/tools}/tool-definition.d.ts +14 -14
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -0
- package/dist/esm/activities/chat/tools/zod-converter.d.ts +69 -0
- package/dist/esm/activities/chat/tools/zod-converter.js +99 -0
- package/dist/esm/activities/chat/tools/zod-converter.js.map +1 -0
- package/dist/esm/activities/generateImage/adapter.d.ts +68 -0
- package/dist/esm/activities/generateImage/adapter.js +14 -0
- package/dist/esm/activities/generateImage/adapter.js.map +1 -0
- package/dist/esm/activities/generateImage/index.d.ts +89 -0
- package/dist/esm/activities/generateImage/index.js +15 -0
- package/dist/esm/activities/generateImage/index.js.map +1 -0
- package/dist/esm/activities/generateSpeech/adapter.d.ts +62 -0
- package/dist/esm/activities/generateSpeech/adapter.js +14 -0
- package/dist/esm/activities/generateSpeech/adapter.js.map +1 -0
- package/dist/esm/activities/generateSpeech/index.d.ts +69 -0
- package/dist/esm/activities/generateSpeech/index.js +15 -0
- package/dist/esm/activities/generateSpeech/index.js.map +1 -0
- package/dist/esm/activities/generateTranscription/adapter.d.ts +62 -0
- package/dist/esm/activities/generateTranscription/adapter.js +14 -0
- package/dist/esm/activities/generateTranscription/adapter.js.map +1 -0
- package/dist/esm/activities/generateTranscription/index.d.ts +71 -0
- package/dist/esm/activities/generateTranscription/index.js +15 -0
- package/dist/esm/activities/generateTranscription/index.js.map +1 -0
- package/dist/esm/activities/generateVideo/adapter.d.ts +80 -0
- package/dist/esm/activities/generateVideo/adapter.js +14 -0
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -0
- package/dist/esm/activities/generateVideo/index.d.ts +136 -0
- package/dist/esm/activities/generateVideo/index.js +47 -0
- package/dist/esm/activities/generateVideo/index.js.map +1 -0
- package/dist/esm/activities/index.d.ts +22 -0
- package/dist/esm/activities/index.js +34 -0
- package/dist/esm/activities/index.js.map +1 -0
- package/dist/esm/activities/summarize/adapter.d.ts +74 -0
- package/dist/esm/activities/summarize/adapter.js +14 -0
- package/dist/esm/activities/summarize/adapter.js.map +1 -0
- package/dist/esm/activities/summarize/index.d.ts +100 -0
- package/dist/esm/activities/summarize/index.js +90 -0
- package/dist/esm/activities/summarize/index.js.map +1 -0
- package/dist/esm/event-client.d.ts +4 -45
- package/dist/esm/event-client.js +0 -49
- package/dist/esm/event-client.js.map +1 -1
- package/dist/esm/index.d.ts +16 -14
- package/dist/esm/index.js +28 -19
- package/dist/esm/stream-to-response.d.ts +95 -0
- package/dist/esm/stream-to-response.js +118 -0
- package/dist/esm/stream-to-response.js.map +1 -0
- package/dist/esm/types.d.ts +347 -129
- package/package.json +6 -2
- package/src/activities/chat/adapter.ts +150 -0
- package/src/{utilities → activities/chat}/agent-loop-strategies.ts +4 -4
- package/src/{core/chat.ts → activities/chat/index.ts} +427 -79
- package/src/{message-converters.ts → activities/chat/messages.ts} +10 -13
- package/src/{stream → activities/chat/stream}/message-updaters.ts +1 -1
- package/src/{stream → activities/chat/stream}/processor.ts +2 -5
- package/src/{stream → activities/chat/stream}/types.ts +8 -18
- package/src/{tools → activities/chat/tools}/tool-calls.ts +36 -11
- package/src/{tools → activities/chat/tools}/tool-definition.ts +36 -27
- package/src/activities/chat/tools/zod-converter.ts +235 -0
- package/src/activities/generateImage/adapter.ts +104 -0
- package/src/activities/generateImage/index.ts +162 -0
- package/src/activities/generateSpeech/adapter.ts +87 -0
- package/src/activities/generateSpeech/index.ts +122 -0
- package/src/activities/generateTranscription/adapter.ts +89 -0
- package/src/activities/generateTranscription/index.ts +132 -0
- package/src/activities/generateVideo/adapter.ts +116 -0
- package/src/activities/generateVideo/index.ts +261 -0
- package/src/activities/index.ts +164 -0
- package/src/activities/summarize/adapter.ts +107 -0
- package/src/activities/summarize/index.ts +287 -0
- package/src/event-client.ts +5 -101
- package/src/index.ts +58 -15
- package/src/stream-to-response.ts +237 -0
- package/src/types.ts +404 -280
- package/dist/esm/base-adapter.d.ts +0 -36
- package/dist/esm/base-adapter.js +0 -12
- package/dist/esm/base-adapter.js.map +0 -1
- package/dist/esm/core/chat-common-options.d.ts +0 -52
- package/dist/esm/core/chat.d.ts +0 -30
- package/dist/esm/core/chat.js.map +0 -1
- package/dist/esm/core/embedding.d.ts +0 -8
- package/dist/esm/core/embedding.js +0 -33
- package/dist/esm/core/embedding.js.map +0 -1
- package/dist/esm/core/summarize.d.ts +0 -9
- package/dist/esm/core/summarize.js +0 -36
- package/dist/esm/core/summarize.js.map +0 -1
- package/dist/esm/message-converters.js.map +0 -1
- package/dist/esm/stream/json-parser.js.map +0 -1
- package/dist/esm/stream/message-updaters.js.map +0 -1
- package/dist/esm/stream/processor.js.map +0 -1
- package/dist/esm/stream/strategies.js.map +0 -1
- package/dist/esm/tools/tool-calls.js.map +0 -1
- package/dist/esm/tools/tool-definition.js.map +0 -1
- package/dist/esm/tools/zod-converter.d.ts +0 -30
- package/dist/esm/tools/zod-converter.js +0 -36
- package/dist/esm/tools/zod-converter.js.map +0 -1
- package/dist/esm/utilities/agent-loop-strategies.js.map +0 -1
- package/dist/esm/utilities/chat-options.d.ts +0 -6
- package/dist/esm/utilities/chat-options.js +0 -7
- package/dist/esm/utilities/chat-options.js.map +0 -1
- package/dist/esm/utilities/messages.d.ts +0 -30
- package/dist/esm/utilities/messages.js +0 -7
- package/dist/esm/utilities/messages.js.map +0 -1
- package/dist/esm/utilities/stream-to-response.d.ts +0 -48
- package/dist/esm/utilities/stream-to-response.js +0 -62
- package/dist/esm/utilities/stream-to-response.js.map +0 -1
- package/src/base-adapter.ts +0 -86
- package/src/core/chat-common-options.ts +0 -55
- package/src/core/embedding.ts +0 -54
- package/src/core/summarize.ts +0 -56
- package/src/tools/zod-converter.ts +0 -85
- package/src/utilities/chat-options.ts +0 -35
- package/src/utilities/messages.ts +0 -63
- package/src/utilities/stream-to-response.ts +0 -116
- /package/dist/esm/{utilities → activities/chat}/agent-loop-strategies.js +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/index.d.ts +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/json-parser.d.ts +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/json-parser.js +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/message-updaters.js +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/strategies.d.ts +0 -0
- /package/dist/esm/{stream → activities/chat/stream}/strategies.js +0 -0
- /package/dist/esm/{tools → activities/chat/tools}/tool-definition.js +0 -0
- /package/src/{stream → activities/chat/stream}/index.ts +0 -0
- /package/src/{stream → activities/chat/stream}/json-parser.ts +0 -0
- /package/src/{stream → activities/chat/stream}/strategies.ts +0 -0
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { toJSONSchema } from "zod";
|
|
2
|
-
function convertZodToJsonSchema(schema) {
|
|
3
|
-
if (!schema) return void 0;
|
|
4
|
-
const jsonSchema = toJSONSchema(schema, {
|
|
5
|
-
target: "openapi-3.0",
|
|
6
|
-
reused: "ref"
|
|
7
|
-
});
|
|
8
|
-
let result = jsonSchema;
|
|
9
|
-
if (typeof result === "object" && "$schema" in result) {
|
|
10
|
-
const { $schema, ...rest } = result;
|
|
11
|
-
result = rest;
|
|
12
|
-
}
|
|
13
|
-
if (typeof result === "object") {
|
|
14
|
-
const isZodObject = typeof schema === "object" && "def" in schema && schema.def.type === "object";
|
|
15
|
-
if (isZodObject && !result.type) {
|
|
16
|
-
result.type = "object";
|
|
17
|
-
}
|
|
18
|
-
if (Object.keys(result).length === 0) {
|
|
19
|
-
result.type = "object";
|
|
20
|
-
}
|
|
21
|
-
if ("properties" in result && !result.type) {
|
|
22
|
-
result.type = "object";
|
|
23
|
-
}
|
|
24
|
-
if (result.type === "object" && !("properties" in result)) {
|
|
25
|
-
result.properties = {};
|
|
26
|
-
}
|
|
27
|
-
if (result.type === "object" && !("required" in result)) {
|
|
28
|
-
result.required = [];
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return result;
|
|
32
|
-
}
|
|
33
|
-
export {
|
|
34
|
-
convertZodToJsonSchema
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=zod-converter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"zod-converter.js","sources":["../../../src/tools/zod-converter.ts"],"sourcesContent":["import { toJSONSchema } from 'zod'\nimport type { z } from 'zod'\n/**\n * Converts a Zod schema to JSON Schema format compatible with LLM providers.\n *\n *\n * @param schema - Zod schema to convert\n * @returns JSON Schema object that can be sent to LLM providers\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const schema = z.object({\n * location: z.string().describe('City name'),\n * unit: z.enum(['celsius', 'fahrenheit']).optional()\n * });\n *\n * const jsonSchema = convertZodToJsonSchema(schema);\n * // Returns:\n * // {\n * // type: 'object',\n * // properties: {\n * // location: { type: 'string', description: 'City name' },\n * // unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }\n * // },\n * // required: ['location']\n * // }\n * ```\n */\nexport function convertZodToJsonSchema(\n schema: z.ZodType | undefined,\n): Record<string, any> | undefined {\n if (!schema) return undefined\n\n // Use Alcyone Labs fork which is compatible with Zod v4\n const jsonSchema = toJSONSchema(schema, {\n target: 'openapi-3.0',\n reused: 'ref',\n })\n\n // Remove $schema property as it's not needed for LLM providers\n let result = jsonSchema\n if (typeof result === 'object' && '$schema' in result) {\n const { $schema, ...rest } = result\n result = rest\n }\n\n // Ensure object schemas always have type: \"object\"\n // This fixes cases where zod-to-json-schema doesn't set type for empty objects\n if (typeof result === 'object') {\n // Check if the input schema is a ZodObject by inspecting its internal structure\n const isZodObject =\n typeof schema === 'object' &&\n 'def' in schema &&\n schema.def.type === 'object'\n\n // If we know it's a ZodObject but result doesn't have type, set it\n if (isZodObject && !result.type) {\n result.type = 'object'\n }\n\n // If result is completely empty (no keys), it's likely an empty object schema\n if (Object.keys(result).length === 0) {\n result.type = 'object'\n }\n\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\n return result\n}\n"],"names":[],"mappings":";AA8BO,SAAS,uBACd,QACiC;AACjC,MAAI,CAAC,OAAQ,QAAO;AAGpB,QAAM,aAAa,aAAa,QAAQ;AAAA,IACtC,QAAQ;AAAA,IACR,QAAQ;AAAA,EAAA,CACT;AAGD,MAAI,SAAS;AACb,MAAI,OAAO,WAAW,YAAY,aAAa,QAAQ;AACrD,UAAM,EAAE,SAAS,GAAG,KAAA,IAAS;AAC7B,aAAS;AAAA,EACX;AAIA,MAAI,OAAO,WAAW,UAAU;AAE9B,UAAM,cACJ,OAAO,WAAW,YAClB,SAAS,UACT,OAAO,IAAI,SAAS;AAGtB,QAAI,eAAe,CAAC,OAAO,MAAM;AAC/B,aAAO,OAAO;AAAA,IAChB;AAGA,QAAI,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG;AACpC,aAAO,OAAO;AAAA,IAChB;AAGA,QAAI,gBAAgB,UAAU,CAAC,OAAO,MAAM;AAC1C,aAAO,OAAO;AAAA,IAChB;AAGA,QAAI,OAAO,SAAS,YAAY,EAAE,gBAAgB,SAAS;AACzD,aAAO,aAAa,CAAA;AAAA,IACtB;AAGA,QAAI,OAAO,SAAS,YAAY,EAAE,cAAc,SAAS;AACvD,aAAO,WAAW,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop-strategies.js","sources":["../../../src/utilities/agent-loop-strategies.ts"],"sourcesContent":["import type { AgentLoopStrategy } from '../types'\n\n/**\n * Creates a strategy that continues for a maximum number of iterations\n *\n * @param max - Maximum number of iterations to allow\n * @returns AgentLoopStrategy that stops after max iterations\n *\n * @example\n * ```typescript\n * const stream = chat({\n * adapter: openai(),\n * model: \"gpt-4o\",\n * messages: [...],\n * tools: [weatherTool],\n * agentLoopStrategy: maxIterations(3), // Max 3 iterations\n * });\n * ```\n */\nexport function maxIterations(max: number): AgentLoopStrategy {\n return ({ iterationCount }) => iterationCount < max\n}\n\n/**\n * Creates a strategy that continues until a specific finish reason is encountered\n *\n * @param stopReasons - Finish reasons that should stop the loop\n * @returns AgentLoopStrategy that stops on specific finish reasons\n *\n * @example\n * ```typescript\n * const stream = chat({\n * adapter: openai(),\n * model: \"gpt-4o\",\n * messages: [...],\n * tools: [weatherTool],\n * agentLoopStrategy: untilFinishReason([\"stop\", \"length\"]),\n * });\n * ```\n */\nexport function untilFinishReason(\n stopReasons: Array<string>,\n): AgentLoopStrategy {\n return ({ finishReason, iterationCount }) => {\n // Always allow at least one iteration\n if (iterationCount === 0) return true\n\n // Stop if we hit a stop reason\n if (finishReason && stopReasons.includes(finishReason)) {\n return false\n }\n\n // Otherwise continue\n return true\n }\n}\n\n/**\n * Creates a strategy that combines multiple strategies with AND logic\n * All strategies must return true to continue\n *\n * @param strategies - Array of strategies to combine\n * @returns AgentLoopStrategy that continues only if all strategies return true\n *\n * @example\n * ```typescript\n * const stream = chat({\n * adapter: openai(),\n * model: \"gpt-4o\",\n * messages: [...],\n * tools: [weatherTool],\n * agentLoopStrategy: combineStrategies([\n * maxIterations(10),\n * ({ messages }) => messages.length < 100,\n * ]),\n * });\n * ```\n */\nexport function combineStrategies(\n strategies: Array<AgentLoopStrategy>,\n): AgentLoopStrategy {\n return (state) => {\n return strategies.every((strategy) => strategy(state))\n }\n}\n"],"names":[],"mappings":"AAmBO,SAAS,cAAc,KAAgC;AAC5D,SAAO,CAAC,EAAE,qBAAqB,iBAAiB;AAClD;AAmBO,SAAS,kBACd,aACmB;AACnB,SAAO,CAAC,EAAE,cAAc,qBAAqB;AAE3C,QAAI,mBAAmB,EAAG,QAAO;AAGjC,QAAI,gBAAgB,YAAY,SAAS,YAAY,GAAG;AACtD,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT;AACF;AAuBO,SAAS,kBACd,YACmB;AACnB,SAAO,CAAC,UAAU;AAChB,WAAO,WAAW,MAAM,CAAC,aAAa,SAAS,KAAK,CAAC;AAAA,EACvD;AACF;"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { AIAdapter, ChatStreamOptionsUnion } from '../types.js';
|
|
2
|
-
export declare function chatOptions<TAdapter extends AIAdapter<any, any, any, any, any>, const TModel extends TAdapter extends AIAdapter<infer Models, any, any, any, any> ? Models[number] : string>(options: Omit<ChatStreamOptionsUnion<TAdapter>, 'providerOptions' | 'model' | 'messages' | 'abortController'> & {
|
|
3
|
-
adapter: TAdapter;
|
|
4
|
-
model: TModel;
|
|
5
|
-
providerOptions?: TAdapter extends AIAdapter<any, any, any, any, infer ModelProviderOptions> ? TModel extends keyof ModelProviderOptions ? ModelProviderOptions[TModel] : never : never;
|
|
6
|
-
}): typeof options;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chat-options.js","sources":["../../../src/utilities/chat-options.ts"],"sourcesContent":["import type { AIAdapter, ChatStreamOptionsUnion } from '../types'\n\nexport function chatOptions<\n TAdapter extends AIAdapter<any, any, any, any, any>,\n const TModel extends TAdapter extends AIAdapter<\n infer Models,\n any,\n any,\n any,\n any\n >\n ? Models[number]\n : string,\n>(\n options: Omit<\n ChatStreamOptionsUnion<TAdapter>,\n 'providerOptions' | 'model' | 'messages' | 'abortController'\n > & {\n adapter: TAdapter\n model: TModel\n providerOptions?: TAdapter extends AIAdapter<\n any,\n any,\n any,\n any,\n infer ModelProviderOptions\n >\n ? TModel extends keyof ModelProviderOptions\n ? ModelProviderOptions[TModel]\n : never\n : never\n },\n): typeof options {\n return options\n}\n"],"names":[],"mappings":"AAEO,SAAS,YAYd,SAkBgB;AAChB,SAAO;AACT;"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { AIAdapter, ConstrainedModelMessage, Modality, ModelMessage } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Type-safe helper to create a messages array constrained by a model's supported modalities.
|
|
4
|
-
*
|
|
5
|
-
* This function provides compile-time checking that your messages only contain
|
|
6
|
-
* content types supported by the specified model. It's particularly useful when
|
|
7
|
-
* combining typed messages with untyped data (like from request.json()).
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* import { messages, chat } from '@tanstack/ai'
|
|
12
|
-
* import { openai } from '@tanstack/ai-openai'
|
|
13
|
-
*
|
|
14
|
-
* const adapter = openai()
|
|
15
|
-
*
|
|
16
|
-
* // This will error at compile time because gpt-4o only supports text+image
|
|
17
|
-
* const msgs = messages({ adapter, model: 'gpt-4o' }, [
|
|
18
|
-
* {
|
|
19
|
-
* role: 'user',
|
|
20
|
-
* content: [
|
|
21
|
-
* { type: 'video', source: { type: 'url', value: '...' } } // Error!
|
|
22
|
-
* ]
|
|
23
|
-
* }
|
|
24
|
-
* ])
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export declare function messages<TAdapter extends AIAdapter<any, any, any, any, any, any>, const TModel extends TAdapter extends AIAdapter<infer Models, any, any, any, any, any> ? Models[number] : string>(_options: {
|
|
28
|
-
adapter: TAdapter;
|
|
29
|
-
model: TModel;
|
|
30
|
-
}, msgs: TAdapter extends AIAdapter<any, any, any, any, any, infer ModelInputModalities> ? TModel extends keyof ModelInputModalities ? ModelInputModalities[TModel] extends ReadonlyArray<Modality> ? Array<ConstrainedModelMessage<ModelInputModalities[TModel]>> : Array<ModelMessage> : Array<ModelMessage> : Array<ModelMessage>): typeof msgs;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sources":["../../../src/utilities/messages.ts"],"sourcesContent":["import type {\n AIAdapter,\n ConstrainedModelMessage,\n Modality,\n ModelMessage,\n} from '../types'\n\n/**\n * Type-safe helper to create a messages array constrained by a model's supported modalities.\n *\n * This function provides compile-time checking that your messages only contain\n * content types supported by the specified model. It's particularly useful when\n * combining typed messages with untyped data (like from request.json()).\n *\n * @example\n * ```typescript\n * import { messages, chat } from '@tanstack/ai'\n * import { openai } from '@tanstack/ai-openai'\n *\n * const adapter = openai()\n *\n * // This will error at compile time because gpt-4o only supports text+image\n * const msgs = messages({ adapter, model: 'gpt-4o' }, [\n * {\n * role: 'user',\n * content: [\n * { type: 'video', source: { type: 'url', value: '...' } } // Error!\n * ]\n * }\n * ])\n * ```\n */\nexport function messages<\n TAdapter extends AIAdapter<any, any, any, any, any, any>,\n const TModel extends TAdapter extends AIAdapter<\n infer Models,\n any,\n any,\n any,\n any,\n any\n >\n ? Models[number]\n : string,\n>(\n _options: { adapter: TAdapter; model: TModel },\n msgs: TAdapter extends AIAdapter<\n any,\n any,\n any,\n any,\n any,\n infer ModelInputModalities\n >\n ? TModel extends keyof ModelInputModalities\n ? ModelInputModalities[TModel] extends ReadonlyArray<Modality>\n ? Array<ConstrainedModelMessage<ModelInputModalities[TModel]>>\n : Array<ModelMessage>\n : Array<ModelMessage>\n : Array<ModelMessage>,\n): typeof msgs {\n return msgs\n}\n"],"names":[],"mappings":"AAgCO,SAAS,SAad,UACA,MAca;AACb,SAAO;AACT;"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { StreamChunk } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Convert a StreamChunk async iterable to a ReadableStream in Server-Sent Events format
|
|
4
|
-
*
|
|
5
|
-
* This creates a ReadableStream that emits chunks in SSE format:
|
|
6
|
-
* - Each chunk is prefixed with "data: "
|
|
7
|
-
* - Each chunk is followed by "\n\n"
|
|
8
|
-
* - Stream ends with "data: [DONE]\n\n"
|
|
9
|
-
*
|
|
10
|
-
* @param stream - AsyncIterable of StreamChunks from chat()
|
|
11
|
-
* @param abortController - Optional AbortController to abort when stream is cancelled
|
|
12
|
-
* @returns ReadableStream in Server-Sent Events format
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```typescript
|
|
16
|
-
* const stream = chat({ adapter: openai(), model: "gpt-4o", messages: [...] });
|
|
17
|
-
* const readableStream = toServerSentEventsStream(stream);
|
|
18
|
-
* // Use with Response, or any API that accepts ReadableStream
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export declare function toServerSentEventsStream(stream: AsyncIterable<StreamChunk>, abortController?: AbortController): ReadableStream<Uint8Array>;
|
|
22
|
-
/**
|
|
23
|
-
* Create a streaming HTTP response from a StreamChunk async iterable
|
|
24
|
-
* Includes proper headers for Server-Sent Events
|
|
25
|
-
*
|
|
26
|
-
* @param stream - AsyncIterable of StreamChunks from chat()
|
|
27
|
-
* @param init - Optional Response initialization options
|
|
28
|
-
* @param abortController - Optional AbortController to abort when client disconnects
|
|
29
|
-
* @returns Response object with SSE headers and streaming body
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```typescript
|
|
33
|
-
* export async function POST(request: Request) {
|
|
34
|
-
* const { messages } = await request.json();
|
|
35
|
-
* const abortController = new AbortController();
|
|
36
|
-
* const stream = chat({
|
|
37
|
-
* adapter: openai(),
|
|
38
|
-
* model: "gpt-4o",
|
|
39
|
-
* messages,
|
|
40
|
-
* options: { abortSignal: abortController.signal }
|
|
41
|
-
* });
|
|
42
|
-
* return toStreamResponse(stream, undefined, abortController);
|
|
43
|
-
* }
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
export declare function toStreamResponse(stream: AsyncIterable<StreamChunk>, init?: ResponseInit & {
|
|
47
|
-
abortController?: AbortController;
|
|
48
|
-
}): Response;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
function toServerSentEventsStream(stream, abortController) {
|
|
2
|
-
const encoder = new TextEncoder();
|
|
3
|
-
return new ReadableStream({
|
|
4
|
-
async start(controller) {
|
|
5
|
-
try {
|
|
6
|
-
for await (const chunk of stream) {
|
|
7
|
-
if (abortController?.signal.aborted) {
|
|
8
|
-
break;
|
|
9
|
-
}
|
|
10
|
-
controller.enqueue(
|
|
11
|
-
encoder.encode(`data: ${JSON.stringify(chunk)}
|
|
12
|
-
|
|
13
|
-
`)
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
17
|
-
controller.close();
|
|
18
|
-
} catch (error) {
|
|
19
|
-
if (abortController?.signal.aborted) {
|
|
20
|
-
controller.close();
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
controller.enqueue(
|
|
24
|
-
encoder.encode(
|
|
25
|
-
`data: ${JSON.stringify({
|
|
26
|
-
type: "error",
|
|
27
|
-
error: {
|
|
28
|
-
message: error.message || "Unknown error occurred",
|
|
29
|
-
code: error.code
|
|
30
|
-
}
|
|
31
|
-
})}
|
|
32
|
-
|
|
33
|
-
`
|
|
34
|
-
)
|
|
35
|
-
);
|
|
36
|
-
controller.close();
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
cancel() {
|
|
40
|
-
if (abortController) {
|
|
41
|
-
abortController.abort();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
function toStreamResponse(stream, init) {
|
|
47
|
-
const { headers, abortController, ...responseInit } = init ?? {};
|
|
48
|
-
return new Response(toServerSentEventsStream(stream, abortController), {
|
|
49
|
-
...responseInit,
|
|
50
|
-
headers: {
|
|
51
|
-
"Content-Type": "text/event-stream",
|
|
52
|
-
"Cache-Control": "no-cache",
|
|
53
|
-
Connection: "keep-alive",
|
|
54
|
-
...headers || {}
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
export {
|
|
59
|
-
toServerSentEventsStream,
|
|
60
|
-
toStreamResponse
|
|
61
|
-
};
|
|
62
|
-
//# sourceMappingURL=stream-to-response.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stream-to-response.js","sources":["../../../src/utilities/stream-to-response.ts"],"sourcesContent":["import type { StreamChunk } from '../types'\n\n/**\n * Convert a StreamChunk async iterable to a ReadableStream in Server-Sent Events format\n *\n * This creates a ReadableStream that emits chunks in SSE format:\n * - Each chunk is prefixed with \"data: \"\n * - Each chunk is followed by \"\\n\\n\"\n * - Stream ends with \"data: [DONE]\\n\\n\"\n *\n * @param stream - AsyncIterable of StreamChunks from chat()\n * @param abortController - Optional AbortController to abort when stream is cancelled\n * @returns ReadableStream in Server-Sent Events format\n *\n * @example\n * ```typescript\n * const stream = chat({ adapter: openai(), model: \"gpt-4o\", messages: [...] });\n * const readableStream = toServerSentEventsStream(stream);\n * // Use with Response, or any API that accepts ReadableStream\n * ```\n */\nexport function toServerSentEventsStream(\n stream: AsyncIterable<StreamChunk>,\n abortController?: AbortController,\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder()\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n // Check if stream was cancelled/aborted\n if (abortController?.signal.aborted) {\n break\n }\n\n // Send each chunk as Server-Sent Events format\n controller.enqueue(\n encoder.encode(`data: ${JSON.stringify(chunk)}\\n\\n`),\n )\n }\n\n // Send completion marker\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'))\n controller.close()\n } catch (error: any) {\n // Don't send error if aborted\n if (abortController?.signal.aborted) {\n controller.close()\n return\n }\n\n // Send error chunk\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({\n type: 'error',\n error: {\n message: error.message || 'Unknown error occurred',\n code: error.code,\n },\n })}\\n\\n`,\n ),\n )\n controller.close()\n }\n },\n cancel() {\n // When the ReadableStream is cancelled (e.g., client disconnects),\n // abort the underlying stream\n if (abortController) {\n abortController.abort()\n }\n },\n })\n}\n\n/**\n * Create a streaming HTTP response from a StreamChunk async iterable\n * Includes proper headers for Server-Sent Events\n *\n * @param stream - AsyncIterable of StreamChunks from chat()\n * @param init - Optional Response initialization options\n * @param abortController - Optional AbortController to abort when client disconnects\n * @returns Response object with SSE headers and streaming body\n *\n * @example\n * ```typescript\n * export async function POST(request: Request) {\n * const { messages } = await request.json();\n * const abortController = new AbortController();\n * const stream = chat({\n * adapter: openai(),\n * model: \"gpt-4o\",\n * messages,\n * options: { abortSignal: abortController.signal }\n * });\n * return toStreamResponse(stream, undefined, abortController);\n * }\n * ```\n */\nexport function toStreamResponse(\n stream: AsyncIterable<StreamChunk>,\n init?: ResponseInit & { abortController?: AbortController },\n): Response {\n const { headers, abortController, ...responseInit } = init ?? {}\n return new Response(toServerSentEventsStream(stream, abortController), {\n ...responseInit,\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n ...(headers || {}),\n },\n })\n}\n"],"names":[],"mappings":"AAqBO,SAAS,yBACd,QACA,iBAC4B;AAC5B,QAAM,UAAU,IAAI,YAAA;AAEpB,SAAO,IAAI,eAAe;AAAA,IACxB,MAAM,MAAM,YAAY;AACtB,UAAI;AACF,yBAAiB,SAAS,QAAQ;AAEhC,cAAI,iBAAiB,OAAO,SAAS;AACnC;AAAA,UACF;AAGA,qBAAW;AAAA,YACT,QAAQ,OAAO,SAAS,KAAK,UAAU,KAAK,CAAC;AAAA;AAAA,CAAM;AAAA,UAAA;AAAA,QAEvD;AAGA,mBAAW,QAAQ,QAAQ,OAAO,kBAAkB,CAAC;AACrD,mBAAW,MAAA;AAAA,MACb,SAAS,OAAY;AAEnB,YAAI,iBAAiB,OAAO,SAAS;AACnC,qBAAW,MAAA;AACX;AAAA,QACF;AAGA,mBAAW;AAAA,UACT,QAAQ;AAAA,YACN,SAAS,KAAK,UAAU;AAAA,cACtB,MAAM;AAAA,cACN,OAAO;AAAA,gBACL,SAAS,MAAM,WAAW;AAAA,gBAC1B,MAAM,MAAM;AAAA,cAAA;AAAA,YACd,CACD,CAAC;AAAA;AAAA;AAAA,UAAA;AAAA,QACJ;AAEF,mBAAW,MAAA;AAAA,MACb;AAAA,IACF;AAAA,IACA,SAAS;AAGP,UAAI,iBAAiB;AACnB,wBAAgB,MAAA;AAAA,MAClB;AAAA,IACF;AAAA,EAAA,CACD;AACH;AA0BO,SAAS,iBACd,QACA,MACU;AACV,QAAM,EAAE,SAAS,iBAAiB,GAAG,aAAA,IAAiB,QAAQ,CAAA;AAC9D,SAAO,IAAI,SAAS,yBAAyB,QAAQ,eAAe,GAAG;AAAA,IACrE,GAAG;AAAA,IACH,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,YAAY;AAAA,MACZ,GAAI,WAAW,CAAA;AAAA,IAAC;AAAA,EAClB,CACD;AACH;"}
|
package/src/base-adapter.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AIAdapter,
|
|
3
|
-
AIAdapterConfig,
|
|
4
|
-
ChatOptions,
|
|
5
|
-
DefaultMessageMetadataByModality,
|
|
6
|
-
EmbeddingOptions,
|
|
7
|
-
EmbeddingResult,
|
|
8
|
-
Modality,
|
|
9
|
-
StreamChunk,
|
|
10
|
-
SummarizationOptions,
|
|
11
|
-
SummarizationResult,
|
|
12
|
-
} from './types'
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Base adapter class with support for endpoint-specific models and provider options.
|
|
16
|
-
*
|
|
17
|
-
* Generic parameters:
|
|
18
|
-
* - TChatModels: Models that support chat/text completion
|
|
19
|
-
* - TEmbeddingModels: Models that support embeddings
|
|
20
|
-
* - TChatProviderOptions: Provider-specific options for chat endpoint
|
|
21
|
-
* - TEmbeddingProviderOptions: Provider-specific options for embedding endpoint
|
|
22
|
-
* - TModelProviderOptionsByName: Provider-specific options for model by name
|
|
23
|
-
* - TModelInputModalitiesByName: Map from model name to its supported input modalities
|
|
24
|
-
* - TMessageMetadataByModality: Map from modality type to adapter-specific metadata types
|
|
25
|
-
*/
|
|
26
|
-
export abstract class BaseAdapter<
|
|
27
|
-
TChatModels extends ReadonlyArray<string> = ReadonlyArray<string>,
|
|
28
|
-
TEmbeddingModels extends ReadonlyArray<string> = ReadonlyArray<string>,
|
|
29
|
-
TChatProviderOptions extends Record<string, any> = Record<string, any>,
|
|
30
|
-
TEmbeddingProviderOptions extends Record<string, any> = Record<string, any>,
|
|
31
|
-
TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,
|
|
32
|
-
TModelInputModalitiesByName extends Record<
|
|
33
|
-
string,
|
|
34
|
-
ReadonlyArray<Modality>
|
|
35
|
-
> = Record<string, ReadonlyArray<Modality>>,
|
|
36
|
-
TMessageMetadataByModality extends {
|
|
37
|
-
text: unknown
|
|
38
|
-
image: unknown
|
|
39
|
-
audio: unknown
|
|
40
|
-
video: unknown
|
|
41
|
-
document: unknown
|
|
42
|
-
} = DefaultMessageMetadataByModality,
|
|
43
|
-
> implements
|
|
44
|
-
AIAdapter<
|
|
45
|
-
TChatModels,
|
|
46
|
-
TEmbeddingModels,
|
|
47
|
-
TChatProviderOptions,
|
|
48
|
-
TEmbeddingProviderOptions,
|
|
49
|
-
TModelProviderOptionsByName,
|
|
50
|
-
TModelInputModalitiesByName,
|
|
51
|
-
TMessageMetadataByModality
|
|
52
|
-
>
|
|
53
|
-
{
|
|
54
|
-
abstract name: string
|
|
55
|
-
abstract models: TChatModels
|
|
56
|
-
embeddingModels?: TEmbeddingModels
|
|
57
|
-
protected config: AIAdapterConfig
|
|
58
|
-
|
|
59
|
-
// These properties are used for type inference only, never assigned at runtime
|
|
60
|
-
_providerOptions?: TChatProviderOptions
|
|
61
|
-
_chatProviderOptions?: TChatProviderOptions
|
|
62
|
-
_embeddingProviderOptions?: TEmbeddingProviderOptions
|
|
63
|
-
// Type-only map; concrete adapters should override this with a precise type
|
|
64
|
-
_modelProviderOptionsByName!: TModelProviderOptionsByName
|
|
65
|
-
// Type-only map for model input modalities; concrete adapters should override this
|
|
66
|
-
_modelInputModalitiesByName?: TModelInputModalitiesByName
|
|
67
|
-
// Type-only map for message metadata types; concrete adapters should override this
|
|
68
|
-
_messageMetadataByModality?: TMessageMetadataByModality
|
|
69
|
-
|
|
70
|
-
constructor(config: AIAdapterConfig = {}) {
|
|
71
|
-
this.config = config
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
abstract chatStream(options: ChatOptions): AsyncIterable<StreamChunk>
|
|
75
|
-
|
|
76
|
-
abstract summarize(
|
|
77
|
-
options: SummarizationOptions,
|
|
78
|
-
): Promise<SummarizationResult>
|
|
79
|
-
abstract createEmbeddings(options: EmbeddingOptions): Promise<EmbeddingResult>
|
|
80
|
-
|
|
81
|
-
protected generateId(): string {
|
|
82
|
-
return `${this.name}-${Date.now()}-${Math.random()
|
|
83
|
-
.toString(36)
|
|
84
|
-
.substring(7)}`
|
|
85
|
-
}
|
|
86
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Common options shared across different AI provider implementations.
|
|
3
|
-
* These options represent the standard parameters that work across OpenAI, Anthropic, and Gemini.
|
|
4
|
-
*/
|
|
5
|
-
export interface CommonOptions {
|
|
6
|
-
/**
|
|
7
|
-
* Controls the randomness of the output.
|
|
8
|
-
* Higher values (e.g., 0.8) make output more random, lower values (e.g., 0.2) make it more focused and deterministic.
|
|
9
|
-
* Range: [0.0, 2.0]
|
|
10
|
-
*
|
|
11
|
-
* Note: Generally recommended to use either temperature or topP, but not both.
|
|
12
|
-
*
|
|
13
|
-
* Provider usage:
|
|
14
|
-
* - OpenAI: `temperature` (number) - in text.top_p field
|
|
15
|
-
* - Anthropic: `temperature` (number) - ranges from 0.0 to 1.0, default 1.0
|
|
16
|
-
* - Gemini: `generationConfig.temperature` (number) - ranges from 0.0 to 2.0
|
|
17
|
-
*/
|
|
18
|
-
temperature?: number
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Nucleus sampling parameter. An alternative to temperature sampling.
|
|
22
|
-
* The model considers the results of tokens with topP probability mass.
|
|
23
|
-
* For example, 0.1 means only tokens comprising the top 10% probability mass are considered.
|
|
24
|
-
*
|
|
25
|
-
* Note: Generally recommended to use either temperature or topP, but not both.
|
|
26
|
-
*
|
|
27
|
-
* Provider usage:
|
|
28
|
-
* - OpenAI: `text.top_p` (number)
|
|
29
|
-
* - Anthropic: `top_p` (number | null)
|
|
30
|
-
* - Gemini: `generationConfig.topP` (number)
|
|
31
|
-
*/
|
|
32
|
-
topP?: number
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* The maximum number of tokens to generate in the response.
|
|
36
|
-
*
|
|
37
|
-
* Provider usage:
|
|
38
|
-
* - OpenAI: `max_output_tokens` (number) - includes visible output and reasoning tokens
|
|
39
|
-
* - Anthropic: `max_tokens` (number, required) - range x >= 1
|
|
40
|
-
* - Gemini: `generationConfig.maxOutputTokens` (number)
|
|
41
|
-
*/
|
|
42
|
-
maxTokens?: number
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Additional metadata to attach to the request.
|
|
46
|
-
* Can be used for tracking, debugging, or passing custom information.
|
|
47
|
-
* Structure and constraints vary by provider.
|
|
48
|
-
*
|
|
49
|
-
* Provider usage:
|
|
50
|
-
* - OpenAI: `metadata` (Record<string, string>) - max 16 key-value pairs, keys max 64 chars, values max 512 chars
|
|
51
|
-
* - Anthropic: `metadata` (Record<string, any>) - includes optional user_id (max 256 chars)
|
|
52
|
-
* - Gemini: Not directly available in TextProviderOptions
|
|
53
|
-
*/
|
|
54
|
-
metadata?: Record<string, any>
|
|
55
|
-
}
|
package/src/core/embedding.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { aiEventClient } from '../event-client.js'
|
|
2
|
-
import type {
|
|
3
|
-
AIAdapter,
|
|
4
|
-
EmbeddingOptions,
|
|
5
|
-
EmbeddingResult,
|
|
6
|
-
ExtractModelsFromAdapter,
|
|
7
|
-
} from '../types'
|
|
8
|
-
|
|
9
|
-
function createId(prefix: string): string {
|
|
10
|
-
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Standalone embedding function with type inference from adapter
|
|
15
|
-
*/
|
|
16
|
-
export async function embedding<
|
|
17
|
-
TAdapter extends AIAdapter<any, any, any, any, any>,
|
|
18
|
-
>(
|
|
19
|
-
options: Omit<EmbeddingOptions, 'model'> & {
|
|
20
|
-
adapter: TAdapter
|
|
21
|
-
model: ExtractModelsFromAdapter<TAdapter>
|
|
22
|
-
},
|
|
23
|
-
): Promise<EmbeddingResult> {
|
|
24
|
-
const { adapter, model, ...restOptions } = options
|
|
25
|
-
const requestId = createId('embedding')
|
|
26
|
-
const inputCount = Array.isArray(restOptions.input)
|
|
27
|
-
? restOptions.input.length
|
|
28
|
-
: 1
|
|
29
|
-
const startTime = Date.now()
|
|
30
|
-
|
|
31
|
-
aiEventClient.emit('embedding:started', {
|
|
32
|
-
requestId,
|
|
33
|
-
model: model as string,
|
|
34
|
-
inputCount,
|
|
35
|
-
timestamp: startTime,
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
const result = await adapter.createEmbeddings({
|
|
39
|
-
...restOptions,
|
|
40
|
-
model: model as string,
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const duration = Date.now() - startTime
|
|
44
|
-
|
|
45
|
-
aiEventClient.emit('embedding:completed', {
|
|
46
|
-
requestId,
|
|
47
|
-
model: model as string,
|
|
48
|
-
inputCount,
|
|
49
|
-
duration,
|
|
50
|
-
timestamp: Date.now(),
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
return result
|
|
54
|
-
}
|
package/src/core/summarize.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { aiEventClient } from '../event-client.js'
|
|
2
|
-
import type {
|
|
3
|
-
AIAdapter,
|
|
4
|
-
ExtractModelsFromAdapter,
|
|
5
|
-
SummarizationOptions,
|
|
6
|
-
SummarizationResult,
|
|
7
|
-
} from '../types'
|
|
8
|
-
|
|
9
|
-
function createId(prefix: string): string {
|
|
10
|
-
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Standalone summarize function with type inference from adapter
|
|
15
|
-
*/
|
|
16
|
-
export async function summarize<
|
|
17
|
-
TAdapter extends AIAdapter<any, any, any, any, any>,
|
|
18
|
-
>(
|
|
19
|
-
options: Omit<SummarizationOptions, 'model'> & {
|
|
20
|
-
adapter: TAdapter
|
|
21
|
-
model: ExtractModelsFromAdapter<TAdapter>
|
|
22
|
-
text: string
|
|
23
|
-
},
|
|
24
|
-
): Promise<SummarizationResult> {
|
|
25
|
-
const { adapter, model, text, ...restOptions } = options
|
|
26
|
-
const requestId = createId('summarize')
|
|
27
|
-
const inputLength = text.length
|
|
28
|
-
const startTime = Date.now()
|
|
29
|
-
|
|
30
|
-
aiEventClient.emit('summarize:started', {
|
|
31
|
-
requestId,
|
|
32
|
-
model: model as string,
|
|
33
|
-
inputLength,
|
|
34
|
-
timestamp: startTime,
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const result = await adapter.summarize({
|
|
38
|
-
...restOptions,
|
|
39
|
-
text,
|
|
40
|
-
model: model as string,
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const duration = Date.now() - startTime
|
|
44
|
-
const outputLength = result.summary.length
|
|
45
|
-
|
|
46
|
-
aiEventClient.emit('summarize:completed', {
|
|
47
|
-
requestId,
|
|
48
|
-
model: model as string,
|
|
49
|
-
inputLength,
|
|
50
|
-
outputLength,
|
|
51
|
-
duration,
|
|
52
|
-
timestamp: Date.now(),
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
return result
|
|
56
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { toJSONSchema } from 'zod'
|
|
2
|
-
import type { z } from 'zod'
|
|
3
|
-
/**
|
|
4
|
-
* Converts a Zod schema to JSON Schema format compatible with LLM providers.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @param schema - Zod schema to convert
|
|
8
|
-
* @returns JSON Schema object that can be sent to LLM providers
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```typescript
|
|
12
|
-
* import { z } from 'zod';
|
|
13
|
-
*
|
|
14
|
-
* const schema = z.object({
|
|
15
|
-
* location: z.string().describe('City name'),
|
|
16
|
-
* unit: z.enum(['celsius', 'fahrenheit']).optional()
|
|
17
|
-
* });
|
|
18
|
-
*
|
|
19
|
-
* const jsonSchema = convertZodToJsonSchema(schema);
|
|
20
|
-
* // Returns:
|
|
21
|
-
* // {
|
|
22
|
-
* // type: 'object',
|
|
23
|
-
* // properties: {
|
|
24
|
-
* // location: { type: 'string', description: 'City name' },
|
|
25
|
-
* // unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }
|
|
26
|
-
* // },
|
|
27
|
-
* // required: ['location']
|
|
28
|
-
* // }
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export function convertZodToJsonSchema(
|
|
32
|
-
schema: z.ZodType | undefined,
|
|
33
|
-
): Record<string, any> | undefined {
|
|
34
|
-
if (!schema) return undefined
|
|
35
|
-
|
|
36
|
-
// Use Alcyone Labs fork which is compatible with Zod v4
|
|
37
|
-
const jsonSchema = toJSONSchema(schema, {
|
|
38
|
-
target: 'openapi-3.0',
|
|
39
|
-
reused: 'ref',
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
// Remove $schema property as it's not needed for LLM providers
|
|
43
|
-
let result = jsonSchema
|
|
44
|
-
if (typeof result === 'object' && '$schema' in result) {
|
|
45
|
-
const { $schema, ...rest } = result
|
|
46
|
-
result = rest
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Ensure object schemas always have type: "object"
|
|
50
|
-
// This fixes cases where zod-to-json-schema doesn't set type for empty objects
|
|
51
|
-
if (typeof result === 'object') {
|
|
52
|
-
// Check if the input schema is a ZodObject by inspecting its internal structure
|
|
53
|
-
const isZodObject =
|
|
54
|
-
typeof schema === 'object' &&
|
|
55
|
-
'def' in schema &&
|
|
56
|
-
schema.def.type === 'object'
|
|
57
|
-
|
|
58
|
-
// If we know it's a ZodObject but result doesn't have type, set it
|
|
59
|
-
if (isZodObject && !result.type) {
|
|
60
|
-
result.type = 'object'
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// If result is completely empty (no keys), it's likely an empty object schema
|
|
64
|
-
if (Object.keys(result).length === 0) {
|
|
65
|
-
result.type = 'object'
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// If it has properties (even empty), it should be an object type
|
|
69
|
-
if ('properties' in result && !result.type) {
|
|
70
|
-
result.type = 'object'
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Ensure properties exists for object types (even if empty)
|
|
74
|
-
if (result.type === 'object' && !('properties' in result)) {
|
|
75
|
-
result.properties = {}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Ensure required exists for object types (even if empty array)
|
|
79
|
-
if (result.type === 'object' && !('required' in result)) {
|
|
80
|
-
result.required = []
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return result
|
|
85
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { AIAdapter, ChatStreamOptionsUnion } from '../types'
|
|
2
|
-
|
|
3
|
-
export function chatOptions<
|
|
4
|
-
TAdapter extends AIAdapter<any, any, any, any, any>,
|
|
5
|
-
const TModel extends TAdapter extends AIAdapter<
|
|
6
|
-
infer Models,
|
|
7
|
-
any,
|
|
8
|
-
any,
|
|
9
|
-
any,
|
|
10
|
-
any
|
|
11
|
-
>
|
|
12
|
-
? Models[number]
|
|
13
|
-
: string,
|
|
14
|
-
>(
|
|
15
|
-
options: Omit<
|
|
16
|
-
ChatStreamOptionsUnion<TAdapter>,
|
|
17
|
-
'providerOptions' | 'model' | 'messages' | 'abortController'
|
|
18
|
-
> & {
|
|
19
|
-
adapter: TAdapter
|
|
20
|
-
model: TModel
|
|
21
|
-
providerOptions?: TAdapter extends AIAdapter<
|
|
22
|
-
any,
|
|
23
|
-
any,
|
|
24
|
-
any,
|
|
25
|
-
any,
|
|
26
|
-
infer ModelProviderOptions
|
|
27
|
-
>
|
|
28
|
-
? TModel extends keyof ModelProviderOptions
|
|
29
|
-
? ModelProviderOptions[TModel]
|
|
30
|
-
: never
|
|
31
|
-
: never
|
|
32
|
-
},
|
|
33
|
-
): typeof options {
|
|
34
|
-
return options
|
|
35
|
-
}
|