@tanstack/ai 0.25.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/extend-adapter.d.ts +23 -1
- package/dist/esm/extend-adapter.js +9 -3
- package/dist/esm/extend-adapter.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/package.json +2 -2
- package/skills/ai-core/adapter-configuration/SKILL.md +70 -10
- package/src/extend-adapter.ts +64 -3
- package/src/index.ts +1 -1
|
@@ -13,13 +13,24 @@ import { Modality } from './types.js';
|
|
|
13
13
|
* ] as const
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
export interface ExtendedModelDef<TName extends string = string, TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>, TOptions = unknown> {
|
|
16
|
+
export interface ExtendedModelDef<TName extends string = string, TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>, TOptions = unknown, TFeatures extends ReadonlyArray<string> = ReadonlyArray<string>, TTools extends ReadonlyArray<string> = ReadonlyArray<string>> {
|
|
17
17
|
/** The model name identifier */
|
|
18
18
|
name: TName;
|
|
19
19
|
/** Supported input modalities for this model */
|
|
20
20
|
input: TInput;
|
|
21
21
|
/** Type brand for provider options - use `{} as YourOptionsType` */
|
|
22
22
|
modelOptions: TOptions;
|
|
23
|
+
/** Optional declared features (e.g. 'reasoning', 'structured_outputs') */
|
|
24
|
+
features?: TFeatures;
|
|
25
|
+
/** Optional declared provider tools (e.g. 'web_search') */
|
|
26
|
+
tools?: TTools;
|
|
27
|
+
}
|
|
28
|
+
/** Capability bag accepted by the object form of `createModel`. */
|
|
29
|
+
export interface ModelCapabilities<TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>, TFeatures extends ReadonlyArray<string> = ReadonlyArray<string>, TTools extends ReadonlyArray<string> = ReadonlyArray<string>, TOptions = unknown> {
|
|
30
|
+
input?: TInput;
|
|
31
|
+
features?: TFeatures;
|
|
32
|
+
tools?: TTools;
|
|
33
|
+
modelOptions?: TOptions;
|
|
23
34
|
}
|
|
24
35
|
/**
|
|
25
36
|
* Creates a custom model definition for use with `extendAdapter`.
|
|
@@ -47,8 +58,19 @@ export interface ExtendedModelDef<TName extends string = string, TInput extends
|
|
|
47
58
|
*
|
|
48
59
|
* const myOpenai = extendAdapter(openaiText, customModels)
|
|
49
60
|
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // Capabilities object form - declare features and provider tools
|
|
65
|
+
* const reasoner = createModel('reasoner', {
|
|
66
|
+
* input: ['text'],
|
|
67
|
+
* features: ['reasoning', 'structured_outputs'],
|
|
68
|
+
* tools: ['web_search'],
|
|
69
|
+
* })
|
|
70
|
+
* ```
|
|
50
71
|
*/
|
|
51
72
|
export declare function createModel<const TName extends string, const TInput extends ReadonlyArray<Modality>>(name: TName, input: TInput): ExtendedModelDef<TName, TInput>;
|
|
73
|
+
export declare function createModel<const TName extends string, const TCaps extends ModelCapabilities>(name: TName, capabilities: TCaps): ExtendedModelDef<TName, TCaps['input'] extends ReadonlyArray<Modality> ? TCaps['input'] : ReadonlyArray<Modality>, TCaps['modelOptions'], TCaps['features'] extends ReadonlyArray<string> ? TCaps['features'] : ReadonlyArray<string>, TCaps['tools'] extends ReadonlyArray<string> ? TCaps['tools'] : ReadonlyArray<string>>;
|
|
52
74
|
/**
|
|
53
75
|
* Extract the model name union from an array of model definitions.
|
|
54
76
|
*/
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
function createModel(name,
|
|
1
|
+
function createModel(name, second) {
|
|
2
|
+
if (Array.isArray(second)) {
|
|
3
|
+
return { name, input: second, modelOptions: {} };
|
|
4
|
+
}
|
|
5
|
+
const caps = second;
|
|
2
6
|
return {
|
|
3
7
|
name,
|
|
4
|
-
input,
|
|
5
|
-
modelOptions: {}
|
|
8
|
+
input: caps.input ?? ["text"],
|
|
9
|
+
modelOptions: caps.modelOptions ?? {},
|
|
10
|
+
features: caps.features,
|
|
11
|
+
tools: caps.tools
|
|
6
12
|
};
|
|
7
13
|
}
|
|
8
14
|
function extendAdapter(factory, _customModels) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extend-adapter.js","sources":["../../src/extend-adapter.ts"],"sourcesContent":["import type { Modality } from './types'\n\n// ===========================\n// Extended Model Definition\n// ===========================\n\n/**\n * Definition for a custom model to add to an adapter.\n *\n * @template TName - The model name as a literal string type\n * @template TInput - Array of supported input modalities\n * @template TOptions - Provider options type for this model\n *\n * @example\n * ```typescript\n * const customModels = [\n * createModel('my-custom-model', ['text', 'image']),\n * ] as const\n * ```\n */\nexport interface ExtendedModelDef<\n TName extends string = string,\n TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>,\n TOptions = unknown,\n> {\n /** The model name identifier */\n name: TName\n /** Supported input modalities for this model */\n input: TInput\n /** Type brand for provider options - use `{} as YourOptionsType` */\n modelOptions: TOptions\n}\n\n/**\n * Creates a custom model definition for use with `extendAdapter`.\n *\n * This is a helper function that provides proper type inference without\n * requiring manual `as const` casts on individual properties.\n *\n * @template TName - The model name (inferred from argument)\n * @template TInput - The input modalities array (inferred from argument)\n *\n * @param name - The model name identifier (literal string)\n * @param input - Array of supported input modalities\n * @returns A properly typed model definition for use with `extendAdapter`\n *\n * @example\n * ```typescript\n * import { extendAdapter, createModel } from '@tanstack/ai'\n * import { openaiText } from '@tanstack/ai-openai'\n *\n * // Define custom models with full type inference\n * const customModels = [\n * createModel('my-fine-tuned-gpt4', ['text', 'image']),\n * createModel('local-llama', ['text']),\n * ] as const\n *\n * const myOpenai = extendAdapter(openaiText, customModels)\n * ```\n */\nexport function createModel<\n const TName extends string,\n const TInput extends ReadonlyArray<Modality>,\n>(name: TName, input: TInput): ExtendedModelDef<TName, TInput> {\n return {\n name,\n input,\n modelOptions: {},\n }\n}\n\n// ===========================\n// Type Extraction Utilities\n// ===========================\n\n/**\n * Extract the model name union from an array of model definitions.\n */\ntype ExtractCustomModelNames<TDefs extends ReadonlyArray<ExtendedModelDef>> =\n TDefs[number]['name']\n\n// ===========================\n// Factory Type Inference\n// ===========================\n\n/**\n * Infer the model parameter type from an adapter factory function.\n * For generic functions like `<T extends Union>(model: T)`, this gets `T` which\n * TypeScript treats as the constraint union when used in parameter position.\n */\ntype InferFactoryModels<TFactory> = TFactory extends (\n model: infer TModel,\n ...args: Array<any>\n) => any\n ? TModel extends string\n ? TModel\n : string\n : string\n\n/**\n * Infer the config parameter type from an adapter factory function.\n */\ntype InferConfig<TFactory> = TFactory extends (\n model: any,\n config?: infer TConfig,\n) => any\n ? TConfig\n : undefined\n\n/**\n * Infer the adapter return type from a factory function.\n */\ntype InferAdapterReturn<TFactory> = TFactory extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn\n : never\n\n// ===========================\n// extendAdapter Function\n// ===========================\n\n/**\n * Extends an existing adapter factory with additional custom models.\n *\n * The extended adapter accepts both original models (with full original type inference)\n * and custom models (with types from your definitions).\n *\n * At runtime, this simply passes through to the original factory - no validation is performed.\n * The original factory's signature is fully preserved, including any config parameters.\n *\n * @param factory - The original adapter factory function (e.g., `openaiText`, `anthropicText`)\n * @param models - Array of custom model definitions with `name` and `input`\n * @returns A new factory function that accepts both original and custom models\n *\n * @example\n * ```typescript\n * import { extendAdapter, createModel } from '@tanstack/ai'\n * import { openaiText } from '@tanstack/ai-openai'\n *\n * // Define custom models\n * const customModels = [\n * createModel('my-fine-tuned-gpt4', ['text', 'image']),\n * createModel('local-llama', ['text']),\n * ] as const\n *\n * // Create extended adapter\n * const myOpenai = extendAdapter(openaiText, customModels)\n *\n * // Use with original models - full type inference preserved\n * const gpt4 = myOpenai('gpt-4o')\n *\n * // Use with custom models\n * const custom = myOpenai('my-fine-tuned-gpt4')\n *\n * // Type error: 'invalid-model' is not a valid model\n * // myOpenai('invalid-model')\n *\n * // Works with chat()\n * chat({\n * adapter: myOpenai('my-fine-tuned-gpt4'),\n * messages: [...]\n * })\n * ```\n */\nexport function extendAdapter<\n TFactory extends (...args: Array<any>) => any,\n const TDefs extends ReadonlyArray<ExtendedModelDef>,\n>(\n factory: TFactory,\n _customModels: TDefs,\n): (\n model: InferFactoryModels<TFactory> | ExtractCustomModelNames<TDefs>,\n ...args: InferConfig<TFactory> extends undefined\n ? []\n : [config?: InferConfig<TFactory>]\n) => InferAdapterReturn<TFactory> {\n // At runtime, we simply pass through to the original factory.\n // The _customModels parameter is only used for type inference.\n // No runtime validation - users are trusted to pass valid model names.\n return factory as any\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extend-adapter.js","sources":["../../src/extend-adapter.ts"],"sourcesContent":["import type { Modality } from './types'\n\n// ===========================\n// Extended Model Definition\n// ===========================\n\n/**\n * Definition for a custom model to add to an adapter.\n *\n * @template TName - The model name as a literal string type\n * @template TInput - Array of supported input modalities\n * @template TOptions - Provider options type for this model\n *\n * @example\n * ```typescript\n * const customModels = [\n * createModel('my-custom-model', ['text', 'image']),\n * ] as const\n * ```\n */\nexport interface ExtendedModelDef<\n TName extends string = string,\n TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>,\n TOptions = unknown,\n TFeatures extends ReadonlyArray<string> = ReadonlyArray<string>,\n TTools extends ReadonlyArray<string> = ReadonlyArray<string>,\n> {\n /** The model name identifier */\n name: TName\n /** Supported input modalities for this model */\n input: TInput\n /** Type brand for provider options - use `{} as YourOptionsType` */\n modelOptions: TOptions\n /** Optional declared features (e.g. 'reasoning', 'structured_outputs') */\n features?: TFeatures\n /** Optional declared provider tools (e.g. 'web_search') */\n tools?: TTools\n}\n\n/** Capability bag accepted by the object form of `createModel`. */\nexport interface ModelCapabilities<\n TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>,\n TFeatures extends ReadonlyArray<string> = ReadonlyArray<string>,\n TTools extends ReadonlyArray<string> = ReadonlyArray<string>,\n TOptions = unknown,\n> {\n input?: TInput\n features?: TFeatures\n tools?: TTools\n modelOptions?: TOptions\n}\n\n/**\n * Creates a custom model definition for use with `extendAdapter`.\n *\n * This is a helper function that provides proper type inference without\n * requiring manual `as const` casts on individual properties.\n *\n * @template TName - The model name (inferred from argument)\n * @template TInput - The input modalities array (inferred from argument)\n *\n * @param name - The model name identifier (literal string)\n * @param input - Array of supported input modalities\n * @returns A properly typed model definition for use with `extendAdapter`\n *\n * @example\n * ```typescript\n * import { extendAdapter, createModel } from '@tanstack/ai'\n * import { openaiText } from '@tanstack/ai-openai'\n *\n * // Define custom models with full type inference\n * const customModels = [\n * createModel('my-fine-tuned-gpt4', ['text', 'image']),\n * createModel('local-llama', ['text']),\n * ] as const\n *\n * const myOpenai = extendAdapter(openaiText, customModels)\n * ```\n *\n * @example\n * ```typescript\n * // Capabilities object form - declare features and provider tools\n * const reasoner = createModel('reasoner', {\n * input: ['text'],\n * features: ['reasoning', 'structured_outputs'],\n * tools: ['web_search'],\n * })\n * ```\n */\n// Overload 1 — legacy positional input array (unchanged behavior)\nexport function createModel<\n const TName extends string,\n const TInput extends ReadonlyArray<Modality>,\n>(name: TName, input: TInput): ExtendedModelDef<TName, TInput>\n// Overload 2 — capabilities object\nexport function createModel<\n const TName extends string,\n const TCaps extends ModelCapabilities,\n>(\n name: TName,\n capabilities: TCaps,\n): ExtendedModelDef<\n TName,\n TCaps['input'] extends ReadonlyArray<Modality>\n ? TCaps['input']\n : ReadonlyArray<Modality>,\n TCaps['modelOptions'],\n TCaps['features'] extends ReadonlyArray<string>\n ? TCaps['features']\n : ReadonlyArray<string>,\n TCaps['tools'] extends ReadonlyArray<string>\n ? TCaps['tools']\n : ReadonlyArray<string>\n>\n// Implementation\nexport function createModel(\n name: string,\n second: ReadonlyArray<Modality> | ModelCapabilities,\n): ExtendedModelDef {\n if (Array.isArray(second)) {\n return { name, input: second, modelOptions: {} }\n }\n const caps = second as ModelCapabilities\n return {\n name,\n input: caps.input ?? (['text'] as ReadonlyArray<Modality>),\n modelOptions: caps.modelOptions ?? {},\n features: caps.features,\n tools: caps.tools,\n }\n}\n\n// ===========================\n// Type Extraction Utilities\n// ===========================\n\n/**\n * Extract the model name union from an array of model definitions.\n */\ntype ExtractCustomModelNames<TDefs extends ReadonlyArray<ExtendedModelDef>> =\n TDefs[number]['name']\n\n// ===========================\n// Factory Type Inference\n// ===========================\n\n/**\n * Infer the model parameter type from an adapter factory function.\n * For generic functions like `<T extends Union>(model: T)`, this gets `T` which\n * TypeScript treats as the constraint union when used in parameter position.\n */\ntype InferFactoryModels<TFactory> = TFactory extends (\n model: infer TModel,\n ...args: Array<any>\n) => any\n ? TModel extends string\n ? TModel\n : string\n : string\n\n/**\n * Infer the config parameter type from an adapter factory function.\n */\ntype InferConfig<TFactory> = TFactory extends (\n model: any,\n config?: infer TConfig,\n) => any\n ? TConfig\n : undefined\n\n/**\n * Infer the adapter return type from a factory function.\n */\ntype InferAdapterReturn<TFactory> = TFactory extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn\n : never\n\n// ===========================\n// extendAdapter Function\n// ===========================\n\n/**\n * Extends an existing adapter factory with additional custom models.\n *\n * The extended adapter accepts both original models (with full original type inference)\n * and custom models (with types from your definitions).\n *\n * At runtime, this simply passes through to the original factory - no validation is performed.\n * The original factory's signature is fully preserved, including any config parameters.\n *\n * @param factory - The original adapter factory function (e.g., `openaiText`, `anthropicText`)\n * @param models - Array of custom model definitions with `name` and `input`\n * @returns A new factory function that accepts both original and custom models\n *\n * @example\n * ```typescript\n * import { extendAdapter, createModel } from '@tanstack/ai'\n * import { openaiText } from '@tanstack/ai-openai'\n *\n * // Define custom models\n * const customModels = [\n * createModel('my-fine-tuned-gpt4', ['text', 'image']),\n * createModel('local-llama', ['text']),\n * ] as const\n *\n * // Create extended adapter\n * const myOpenai = extendAdapter(openaiText, customModels)\n *\n * // Use with original models - full type inference preserved\n * const gpt4 = myOpenai('gpt-4o')\n *\n * // Use with custom models\n * const custom = myOpenai('my-fine-tuned-gpt4')\n *\n * // Type error: 'invalid-model' is not a valid model\n * // myOpenai('invalid-model')\n *\n * // Works with chat()\n * chat({\n * adapter: myOpenai('my-fine-tuned-gpt4'),\n * messages: [...]\n * })\n * ```\n */\nexport function extendAdapter<\n TFactory extends (...args: Array<any>) => any,\n const TDefs extends ReadonlyArray<ExtendedModelDef>,\n>(\n factory: TFactory,\n _customModels: TDefs,\n): (\n model: InferFactoryModels<TFactory> | ExtractCustomModelNames<TDefs>,\n ...args: InferConfig<TFactory> extends undefined\n ? []\n : [config?: InferConfig<TFactory>]\n) => InferAdapterReturn<TFactory> {\n // At runtime, we simply pass through to the original factory.\n // The _customModels parameter is only used for type inference.\n // No runtime validation - users are trusted to pass valid model names.\n return factory as any\n}\n"],"names":[],"mappings":"AAmHO,SAAS,YACd,MACA,QACkB;AAClB,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,EAAE,MAAM,OAAO,QAAQ,cAAc,CAAA,EAAC;AAAA,EAC/C;AACA,QAAM,OAAO;AACb,SAAO;AAAA,IACL;AAAA,IACA,OAAO,KAAK,SAAU,CAAC,MAAM;AAAA,IAC7B,cAAc,KAAK,gBAAgB,CAAA;AAAA,IACnC,UAAU,KAAK;AAAA,IACf,OAAO,KAAK;AAAA,EAAA;AAEhB;AAgGO,SAAS,cAId,SACA,eAMgC;AAIhC,SAAO;AACT;"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -31,6 +31,6 @@ export { uiMessagesToWire } from './utilities/ag-ui-wire.js';
|
|
|
31
31
|
export type { WireMessage } from './utilities/ag-ui-wire.js';
|
|
32
32
|
export { isContentPart, isContentPartArray, normalizeToolResult, } from './utilities/tool-result.js';
|
|
33
33
|
export { createModel, extendAdapter } from './extend-adapter.js';
|
|
34
|
-
export type { ExtendedModelDef } from './extend-adapter.js';
|
|
34
|
+
export type { ExtendedModelDef, ModelCapabilities } from './extend-adapter.js';
|
|
35
35
|
export type { Logger, DebugCategories, DebugConfig, DebugOption, } from './logger/types.js';
|
|
36
36
|
export { ConsoleLogger } from './logger/console-logger.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.1",
|
|
4
4
|
"description": "Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"@ag-ui/core": "^0.0.52",
|
|
69
69
|
"@standard-schema/spec": "^1.1.0",
|
|
70
70
|
"partial-json": "^0.1.7",
|
|
71
|
-
"@tanstack/ai-event-client": "0.5.
|
|
71
|
+
"@tanstack/ai-event-client": "0.5.2"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"@opentelemetry/api": ">=1.9.0"
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
name: ai-core/adapter-configuration
|
|
3
3
|
description: >
|
|
4
4
|
Provider adapter selection and configuration: openaiText, anthropicText,
|
|
5
|
-
geminiText, ollamaText, grokText, groqText, openRouterText. Per-model
|
|
5
|
+
geminiText, ollamaText, grokText, groqText, openRouterText, openaiCompatible. Per-model
|
|
6
6
|
type safety with modelOptions, reasoning/thinking configuration,
|
|
7
7
|
runtime adapter switching, extendAdapter() for custom models, createModel().
|
|
8
|
+
Generic OpenAI-compatible providers (DeepSeek, Together, Fireworks, etc.) via
|
|
9
|
+
openaiCompatible({ baseURL, apiKey, models }) from @tanstack/ai-openai/compatible.
|
|
8
10
|
API key env vars: OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY/GEMINI_API_KEY,
|
|
9
11
|
XAI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY, OLLAMA_HOST.
|
|
10
12
|
type: sub-skill
|
|
@@ -60,15 +62,16 @@ into the factory, not into `chat()`.
|
|
|
60
62
|
Each provider has a dedicated package with tree-shakeable adapter factories.
|
|
61
63
|
The text adapter is the primary one for chat/completions:
|
|
62
64
|
|
|
63
|
-
| Provider
|
|
64
|
-
|
|
|
65
|
-
| OpenAI
|
|
66
|
-
| Anthropic
|
|
67
|
-
| Gemini
|
|
68
|
-
| Grok (xAI)
|
|
69
|
-
| Groq
|
|
70
|
-
| OpenRouter
|
|
71
|
-
| Ollama
|
|
65
|
+
| Provider | Package | Factory | Env Var |
|
|
66
|
+
| ----------------- | -------------------------------- | ------------------------------------------- | ------------------------------------------------- |
|
|
67
|
+
| OpenAI | `@tanstack/ai-openai` | `openaiText` | `OPENAI_API_KEY` |
|
|
68
|
+
| Anthropic | `@tanstack/ai-anthropic` | `anthropicText` | `ANTHROPIC_API_KEY` |
|
|
69
|
+
| Gemini | `@tanstack/ai-gemini` | `geminiText` | `GOOGLE_API_KEY` or `GEMINI_API_KEY` |
|
|
70
|
+
| Grok (xAI) | `@tanstack/ai-grok` | `grokText` | `XAI_API_KEY` |
|
|
71
|
+
| Groq | `@tanstack/ai-groq` | `groqText` | `GROQ_API_KEY` |
|
|
72
|
+
| OpenRouter | `@tanstack/ai-openrouter` | `openRouterText` | `OPENROUTER_API_KEY` |
|
|
73
|
+
| Ollama | `@tanstack/ai-ollama` | `ollamaText` | `OLLAMA_HOST` (default: `http://localhost:11434`) |
|
|
74
|
+
| OpenAI-compatible | `@tanstack/ai-openai/compatible` | `openaiCompatible` / `openaiCompatibleText` | provider-specific (passed via `apiKey`) |
|
|
72
75
|
|
|
73
76
|
```typescript
|
|
74
77
|
// Each factory takes model as first arg, optional config as second
|
|
@@ -252,6 +255,63 @@ Subclasses can override to narrow the capability. When extending an
|
|
|
252
255
|
adapter for a custom model that doesn't support the combination, return
|
|
253
256
|
`false` explicitly.
|
|
254
257
|
|
|
258
|
+
### 6. OpenAI-Compatible Providers
|
|
259
|
+
|
|
260
|
+
Any provider that implements the OpenAI **Chat Completions** API (DeepSeek,
|
|
261
|
+
Moonshot/Kimi, Together, Fireworks, Cerebras, Qwen/DashScope, Perplexity,
|
|
262
|
+
NVIDIA NIM, LM Studio, etc.) can be used through the generic
|
|
263
|
+
`openaiCompatible` factory from `@tanstack/ai-openai/compatible` — no
|
|
264
|
+
dedicated package required.
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import { openaiCompatible } from '@tanstack/ai-openai/compatible'
|
|
268
|
+
import { createModel } from '@tanstack/ai'
|
|
269
|
+
|
|
270
|
+
// Provider-factory: configure baseURL + apiKey + models ONCE,
|
|
271
|
+
// then select a model per call (the model arg is a type-safe union).
|
|
272
|
+
const deepseek = openaiCompatible({
|
|
273
|
+
name: 'deepseek', // optional label for devtools/errors (default 'openai-compatible')
|
|
274
|
+
baseURL: 'https://api.deepseek.com/v1',
|
|
275
|
+
apiKey: process.env.DEEPSEEK_API_KEY!,
|
|
276
|
+
models: [
|
|
277
|
+
'deepseek-chat', // bare string → optimistic defaults: text/image in, streaming, tools, structured output
|
|
278
|
+
createModel('deepseek-reasoner', {
|
|
279
|
+
// rich def → precise per-model capabilities
|
|
280
|
+
input: ['text'],
|
|
281
|
+
features: ['reasoning', 'structured_outputs'],
|
|
282
|
+
}),
|
|
283
|
+
],
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
chat({ adapter: deepseek('deepseek-chat'), messages })
|
|
287
|
+
chat({ adapter: deepseek('deepseek-reasoner'), messages })
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`config` also accepts any OpenAI SDK `ClientOptions` (notably `defaultHeaders`
|
|
291
|
+
and `defaultQuery`) for providers that need extra auth headers or query params.
|
|
292
|
+
|
|
293
|
+
For a single model, use the one-shot helper:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import { openaiCompatibleText } from '@tanstack/ai-openai/compatible'
|
|
297
|
+
|
|
298
|
+
chat({
|
|
299
|
+
adapter: openaiCompatibleText('deepseek-chat', {
|
|
300
|
+
baseURL: 'https://api.deepseek.com/v1',
|
|
301
|
+
apiKey: process.env.DEEPSEEK_API_KEY!,
|
|
302
|
+
}),
|
|
303
|
+
messages,
|
|
304
|
+
})
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Pass `api: 'responses'` to target the OpenAI **Responses** API instead of Chat
|
|
308
|
+
Completions (only for the rare compatible provider that implements it, e.g.
|
|
309
|
+
Azure OpenAI); the default is `'chat-completions'`, which is what nearly all
|
|
310
|
+
compatible providers speak.
|
|
311
|
+
|
|
312
|
+
> Verify the provider's current `baseURL` and model ids against its live docs —
|
|
313
|
+
> they drift. See `docs/adapters/openai-compatible.md` for the full provider table.
|
|
314
|
+
|
|
255
315
|
## Common Mistakes
|
|
256
316
|
|
|
257
317
|
### a. HIGH: Confusing legacy monolithic with tree-shakeable adapter
|
package/src/extend-adapter.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface ExtendedModelDef<
|
|
|
22
22
|
TName extends string = string,
|
|
23
23
|
TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>,
|
|
24
24
|
TOptions = unknown,
|
|
25
|
+
TFeatures extends ReadonlyArray<string> = ReadonlyArray<string>,
|
|
26
|
+
TTools extends ReadonlyArray<string> = ReadonlyArray<string>,
|
|
25
27
|
> {
|
|
26
28
|
/** The model name identifier */
|
|
27
29
|
name: TName
|
|
@@ -29,6 +31,23 @@ export interface ExtendedModelDef<
|
|
|
29
31
|
input: TInput
|
|
30
32
|
/** Type brand for provider options - use `{} as YourOptionsType` */
|
|
31
33
|
modelOptions: TOptions
|
|
34
|
+
/** Optional declared features (e.g. 'reasoning', 'structured_outputs') */
|
|
35
|
+
features?: TFeatures
|
|
36
|
+
/** Optional declared provider tools (e.g. 'web_search') */
|
|
37
|
+
tools?: TTools
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Capability bag accepted by the object form of `createModel`. */
|
|
41
|
+
export interface ModelCapabilities<
|
|
42
|
+
TInput extends ReadonlyArray<Modality> = ReadonlyArray<Modality>,
|
|
43
|
+
TFeatures extends ReadonlyArray<string> = ReadonlyArray<string>,
|
|
44
|
+
TTools extends ReadonlyArray<string> = ReadonlyArray<string>,
|
|
45
|
+
TOptions = unknown,
|
|
46
|
+
> {
|
|
47
|
+
input?: TInput
|
|
48
|
+
features?: TFeatures
|
|
49
|
+
tools?: TTools
|
|
50
|
+
modelOptions?: TOptions
|
|
32
51
|
}
|
|
33
52
|
|
|
34
53
|
/**
|
|
@@ -57,15 +76,57 @@ export interface ExtendedModelDef<
|
|
|
57
76
|
*
|
|
58
77
|
* const myOpenai = extendAdapter(openaiText, customModels)
|
|
59
78
|
* ```
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // Capabilities object form - declare features and provider tools
|
|
83
|
+
* const reasoner = createModel('reasoner', {
|
|
84
|
+
* input: ['text'],
|
|
85
|
+
* features: ['reasoning', 'structured_outputs'],
|
|
86
|
+
* tools: ['web_search'],
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
60
89
|
*/
|
|
90
|
+
// Overload 1 — legacy positional input array (unchanged behavior)
|
|
61
91
|
export function createModel<
|
|
62
92
|
const TName extends string,
|
|
63
93
|
const TInput extends ReadonlyArray<Modality>,
|
|
64
|
-
>(name: TName, input: TInput): ExtendedModelDef<TName, TInput>
|
|
94
|
+
>(name: TName, input: TInput): ExtendedModelDef<TName, TInput>
|
|
95
|
+
// Overload 2 — capabilities object
|
|
96
|
+
export function createModel<
|
|
97
|
+
const TName extends string,
|
|
98
|
+
const TCaps extends ModelCapabilities,
|
|
99
|
+
>(
|
|
100
|
+
name: TName,
|
|
101
|
+
capabilities: TCaps,
|
|
102
|
+
): ExtendedModelDef<
|
|
103
|
+
TName,
|
|
104
|
+
TCaps['input'] extends ReadonlyArray<Modality>
|
|
105
|
+
? TCaps['input']
|
|
106
|
+
: ReadonlyArray<Modality>,
|
|
107
|
+
TCaps['modelOptions'],
|
|
108
|
+
TCaps['features'] extends ReadonlyArray<string>
|
|
109
|
+
? TCaps['features']
|
|
110
|
+
: ReadonlyArray<string>,
|
|
111
|
+
TCaps['tools'] extends ReadonlyArray<string>
|
|
112
|
+
? TCaps['tools']
|
|
113
|
+
: ReadonlyArray<string>
|
|
114
|
+
>
|
|
115
|
+
// Implementation
|
|
116
|
+
export function createModel(
|
|
117
|
+
name: string,
|
|
118
|
+
second: ReadonlyArray<Modality> | ModelCapabilities,
|
|
119
|
+
): ExtendedModelDef {
|
|
120
|
+
if (Array.isArray(second)) {
|
|
121
|
+
return { name, input: second, modelOptions: {} }
|
|
122
|
+
}
|
|
123
|
+
const caps = second as ModelCapabilities
|
|
65
124
|
return {
|
|
66
125
|
name,
|
|
67
|
-
input,
|
|
68
|
-
modelOptions: {},
|
|
126
|
+
input: caps.input ?? (['text'] as ReadonlyArray<Modality>),
|
|
127
|
+
modelOptions: caps.modelOptions ?? {},
|
|
128
|
+
features: caps.features,
|
|
129
|
+
tools: caps.tools,
|
|
69
130
|
}
|
|
70
131
|
}
|
|
71
132
|
|
package/src/index.ts
CHANGED
|
@@ -200,7 +200,7 @@ export {
|
|
|
200
200
|
|
|
201
201
|
// Adapter extension utilities
|
|
202
202
|
export { createModel, extendAdapter } from './extend-adapter'
|
|
203
|
-
export type { ExtendedModelDef } from './extend-adapter'
|
|
203
|
+
export type { ExtendedModelDef, ModelCapabilities } from './extend-adapter'
|
|
204
204
|
|
|
205
205
|
// Logger
|
|
206
206
|
export type {
|