@tanstack/openai-base 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/dist/esm/adapters/chat-completions-text.d.ts +76 -0
- package/dist/esm/adapters/chat-completions-text.js +411 -0
- package/dist/esm/adapters/chat-completions-text.js.map +1 -0
- package/dist/esm/adapters/chat-completions-tool-converter.d.ts +24 -0
- package/dist/esm/adapters/chat-completions-tool-converter.js +29 -0
- package/dist/esm/adapters/chat-completions-tool-converter.js.map +1 -0
- package/dist/esm/adapters/image.d.ts +32 -0
- package/dist/esm/adapters/image.js +69 -0
- package/dist/esm/adapters/image.js.map +1 -0
- package/dist/esm/adapters/responses-text.d.ts +115 -0
- package/dist/esm/adapters/responses-text.js +635 -0
- package/dist/esm/adapters/responses-text.js.map +1 -0
- package/dist/esm/adapters/responses-tool-converter.d.ts +35 -0
- package/dist/esm/adapters/responses-tool-converter.js +27 -0
- package/dist/esm/adapters/responses-tool-converter.js.map +1 -0
- package/dist/esm/adapters/summarize.d.ts +28 -0
- package/dist/esm/adapters/summarize.js +74 -0
- package/dist/esm/adapters/summarize.js.map +1 -0
- package/dist/esm/adapters/transcription.d.ts +39 -0
- package/dist/esm/adapters/transcription.js +139 -0
- package/dist/esm/adapters/transcription.js.map +1 -0
- package/dist/esm/adapters/tts.d.ts +26 -0
- package/dist/esm/adapters/tts.js +65 -0
- package/dist/esm/adapters/tts.js.map +1 -0
- package/dist/esm/adapters/video.d.ts +48 -0
- package/dist/esm/adapters/video.js +192 -0
- package/dist/esm/adapters/video.js.map +1 -0
- package/dist/esm/index.d.ts +15 -0
- package/dist/esm/index.js +65 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/tools/apply-patch-tool.d.ts +11 -0
- package/dist/esm/tools/apply-patch-tool.js +17 -0
- package/dist/esm/tools/apply-patch-tool.js.map +1 -0
- package/dist/esm/tools/code-interpreter-tool.d.ts +11 -0
- package/dist/esm/tools/code-interpreter-tool.js +22 -0
- package/dist/esm/tools/code-interpreter-tool.js.map +1 -0
- package/dist/esm/tools/computer-use-tool.d.ts +11 -0
- package/dist/esm/tools/computer-use-tool.js +23 -0
- package/dist/esm/tools/computer-use-tool.js.map +1 -0
- package/dist/esm/tools/custom-tool.d.ts +11 -0
- package/dist/esm/tools/custom-tool.js +23 -0
- package/dist/esm/tools/custom-tool.js.map +1 -0
- package/dist/esm/tools/file-search-tool.d.ts +11 -0
- package/dist/esm/tools/file-search-tool.js +30 -0
- package/dist/esm/tools/file-search-tool.js.map +1 -0
- package/dist/esm/tools/function-tool.d.ts +15 -0
- package/dist/esm/tools/function-tool.js +24 -0
- package/dist/esm/tools/function-tool.js.map +1 -0
- package/dist/esm/tools/image-generation-tool.d.ts +11 -0
- package/dist/esm/tools/image-generation-tool.js +27 -0
- package/dist/esm/tools/image-generation-tool.js.map +1 -0
- package/dist/esm/tools/index.d.ts +27 -0
- package/dist/esm/tools/local-shell-tool.d.ts +11 -0
- package/dist/esm/tools/local-shell-tool.js +17 -0
- package/dist/esm/tools/local-shell-tool.js.map +1 -0
- package/dist/esm/tools/mcp-tool.d.ts +12 -0
- package/dist/esm/tools/mcp-tool.js +31 -0
- package/dist/esm/tools/mcp-tool.js.map +1 -0
- package/dist/esm/tools/shell-tool.d.ts +11 -0
- package/dist/esm/tools/shell-tool.js +17 -0
- package/dist/esm/tools/shell-tool.js.map +1 -0
- package/dist/esm/tools/tool-choice.d.ts +17 -0
- package/dist/esm/tools/tool-converter.d.ts +6 -0
- package/dist/esm/tools/tool-converter.js +61 -0
- package/dist/esm/tools/tool-converter.js.map +1 -0
- package/dist/esm/tools/web-search-preview-tool.d.ts +11 -0
- package/dist/esm/tools/web-search-preview-tool.js +20 -0
- package/dist/esm/tools/web-search-preview-tool.js.map +1 -0
- package/dist/esm/tools/web-search-tool.d.ts +11 -0
- package/dist/esm/tools/web-search-tool.js +16 -0
- package/dist/esm/tools/web-search-tool.js.map +1 -0
- package/dist/esm/types/config.d.ts +4 -0
- package/dist/esm/types/message-metadata.d.ts +19 -0
- package/dist/esm/types/provider-options.d.ts +40 -0
- package/dist/esm/utils/client.d.ts +3 -0
- package/dist/esm/utils/client.js +8 -0
- package/dist/esm/utils/client.js.map +1 -0
- package/dist/esm/utils/schema-converter.d.ts +12 -0
- package/dist/esm/utils/schema-converter.js +65 -0
- package/dist/esm/utils/schema-converter.js.map +1 -0
- package/package.json +57 -0
- package/src/adapters/chat-completions-text.ts +817 -0
- package/src/adapters/chat-completions-tool-converter.ts +70 -0
- package/src/adapters/image.ts +158 -0
- package/src/adapters/responses-text.ts +1147 -0
- package/src/adapters/responses-tool-converter.ts +77 -0
- package/src/adapters/summarize.ts +174 -0
- package/src/adapters/transcription.ts +194 -0
- package/src/adapters/tts.ts +124 -0
- package/src/adapters/video.ts +385 -0
- package/src/index.ts +24 -0
- package/src/tools/apply-patch-tool.ts +32 -0
- package/src/tools/code-interpreter-tool.ts +39 -0
- package/src/tools/computer-use-tool.ts +38 -0
- package/src/tools/custom-tool.ts +33 -0
- package/src/tools/file-search-tool.ts +51 -0
- package/src/tools/function-tool.ts +44 -0
- package/src/tools/image-generation-tool.ts +51 -0
- package/src/tools/index.ts +41 -0
- package/src/tools/local-shell-tool.ts +32 -0
- package/src/tools/mcp-tool.ts +47 -0
- package/src/tools/shell-tool.ts +30 -0
- package/src/tools/tool-choice.ts +31 -0
- package/src/tools/tool-converter.ts +68 -0
- package/src/tools/web-search-preview-tool.ts +39 -0
- package/src/tools/web-search-tool.ts +38 -0
- package/src/types/config.ts +5 -0
- package/src/utils/client.ts +8 -0
- package/src/utils/request-options.ts +16 -0
- package/src/utils/schema-converter.ts +89 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { makeStructuredOutputCompatible } from '../utils/schema-converter'
|
|
2
|
+
import type { JSONSchema, Tool } from '@tanstack/ai'
|
|
3
|
+
import type OpenAI from 'openai'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Chat Completions API tool format.
|
|
7
|
+
* This is distinct from the Responses API tool format.
|
|
8
|
+
*/
|
|
9
|
+
export type ChatCompletionFunctionTool =
|
|
10
|
+
OpenAI.Chat.Completions.ChatCompletionTool
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Converts a standard Tool to OpenAI Chat Completions ChatCompletionTool format.
|
|
14
|
+
*
|
|
15
|
+
* Tool schemas are already converted to JSON Schema in the ai layer.
|
|
16
|
+
* We apply OpenAI-compatible transformations for strict mode:
|
|
17
|
+
* - All properties in required array
|
|
18
|
+
* - Optional fields made nullable
|
|
19
|
+
* - additionalProperties: false
|
|
20
|
+
*
|
|
21
|
+
* This enables strict mode for all tools automatically.
|
|
22
|
+
*/
|
|
23
|
+
export function convertFunctionToolToChatCompletionsFormat(
|
|
24
|
+
tool: Tool,
|
|
25
|
+
schemaConverter: (
|
|
26
|
+
schema: Record<string, any>,
|
|
27
|
+
required: Array<string>,
|
|
28
|
+
) => Record<string, any> = makeStructuredOutputCompatible,
|
|
29
|
+
): ChatCompletionFunctionTool {
|
|
30
|
+
const inputSchema = (tool.inputSchema ?? {
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: {},
|
|
33
|
+
required: [],
|
|
34
|
+
}) as JSONSchema
|
|
35
|
+
|
|
36
|
+
// Shallow-copy the converter's result before mutating: a subclass-supplied
|
|
37
|
+
// schemaConverter has no contract requirement to return a fresh object,
|
|
38
|
+
// and a passthrough `(s) => s` would otherwise have its caller's schema
|
|
39
|
+
// mutated by the `additionalProperties = false` assignment below.
|
|
40
|
+
const jsonSchema = {
|
|
41
|
+
...schemaConverter(inputSchema, inputSchema.required || []),
|
|
42
|
+
}
|
|
43
|
+
jsonSchema.additionalProperties = false
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
type: 'function',
|
|
47
|
+
function: {
|
|
48
|
+
name: tool.name,
|
|
49
|
+
description: tool.description,
|
|
50
|
+
parameters: jsonSchema,
|
|
51
|
+
strict: true,
|
|
52
|
+
},
|
|
53
|
+
} satisfies ChatCompletionFunctionTool
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Converts an array of standard Tools to Chat Completions format.
|
|
58
|
+
* Chat Completions API primarily supports function tools.
|
|
59
|
+
*/
|
|
60
|
+
export function convertToolsToChatCompletionsFormat(
|
|
61
|
+
tools: Array<Tool>,
|
|
62
|
+
schemaConverter?: (
|
|
63
|
+
schema: Record<string, any>,
|
|
64
|
+
required: Array<string>,
|
|
65
|
+
) => Record<string, any>,
|
|
66
|
+
): Array<ChatCompletionFunctionTool> {
|
|
67
|
+
return tools.map((tool) =>
|
|
68
|
+
convertFunctionToolToChatCompletionsFormat(tool, schemaConverter),
|
|
69
|
+
)
|
|
70
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { BaseImageAdapter } from '@tanstack/ai/adapters'
|
|
2
|
+
import { toRunErrorPayload } from '@tanstack/ai/adapter-internals'
|
|
3
|
+
import { generateId } from '@tanstack/ai-utils'
|
|
4
|
+
import { createOpenAICompatibleClient } from '../utils/client'
|
|
5
|
+
import type {
|
|
6
|
+
GeneratedImage,
|
|
7
|
+
ImageGenerationOptions,
|
|
8
|
+
ImageGenerationResult,
|
|
9
|
+
} from '@tanstack/ai'
|
|
10
|
+
import type OpenAI_SDK from 'openai'
|
|
11
|
+
import type { OpenAICompatibleClientConfig } from '../types/config'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* OpenAI-Compatible Image Generation Adapter
|
|
15
|
+
*
|
|
16
|
+
* A generalized base class for providers that implement OpenAI-compatible image
|
|
17
|
+
* generation APIs. Providers like OpenAI, Grok, and others can extend this class
|
|
18
|
+
* and only need to:
|
|
19
|
+
* - Set `baseURL` in the config
|
|
20
|
+
* - Lock the generic type parameters to provider-specific types
|
|
21
|
+
* - Override validation or request building methods for provider-specific constraints
|
|
22
|
+
*
|
|
23
|
+
* All methods that validate inputs, build requests, or transform responses are
|
|
24
|
+
* `protected` so subclasses can override them.
|
|
25
|
+
*/
|
|
26
|
+
export class OpenAICompatibleImageAdapter<
|
|
27
|
+
TModel extends string,
|
|
28
|
+
TProviderOptions extends object = Record<string, any>,
|
|
29
|
+
TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,
|
|
30
|
+
TModelSizeByName extends Record<string, string> = Record<string, string>,
|
|
31
|
+
> extends BaseImageAdapter<
|
|
32
|
+
TModel,
|
|
33
|
+
TProviderOptions,
|
|
34
|
+
TModelProviderOptionsByName,
|
|
35
|
+
TModelSizeByName
|
|
36
|
+
> {
|
|
37
|
+
readonly kind = 'image' as const
|
|
38
|
+
readonly name: string
|
|
39
|
+
|
|
40
|
+
protected client: OpenAI_SDK
|
|
41
|
+
|
|
42
|
+
constructor(
|
|
43
|
+
config: OpenAICompatibleClientConfig,
|
|
44
|
+
model: TModel,
|
|
45
|
+
name: string = 'openai-compatible',
|
|
46
|
+
) {
|
|
47
|
+
super(model, {})
|
|
48
|
+
this.name = name
|
|
49
|
+
this.client = createOpenAICompatibleClient(config)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async generateImages(
|
|
53
|
+
options: ImageGenerationOptions<TProviderOptions>,
|
|
54
|
+
): Promise<ImageGenerationResult> {
|
|
55
|
+
const { model, prompt, numberOfImages, size } = options
|
|
56
|
+
|
|
57
|
+
// Validate inputs
|
|
58
|
+
this.validatePrompt({ prompt, model })
|
|
59
|
+
this.validateImageSize(model, size)
|
|
60
|
+
this.validateNumberOfImages(model, numberOfImages)
|
|
61
|
+
|
|
62
|
+
// Build request based on model type
|
|
63
|
+
const request = this.buildRequest(options)
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
options.logger.request(
|
|
67
|
+
`activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,
|
|
68
|
+
{ provider: this.name, model },
|
|
69
|
+
)
|
|
70
|
+
const response = await this.client.images.generate({
|
|
71
|
+
...request,
|
|
72
|
+
stream: false,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
return this.transformResponse(model, response)
|
|
76
|
+
} catch (error: unknown) {
|
|
77
|
+
// Narrow before logging: raw SDK errors can carry request metadata
|
|
78
|
+
// (including auth headers) which we must never surface to user loggers.
|
|
79
|
+
options.logger.errors(`${this.name}.generateImages fatal`, {
|
|
80
|
+
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
81
|
+
source: `${this.name}.generateImages`,
|
|
82
|
+
})
|
|
83
|
+
throw error
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
protected buildRequest(
|
|
88
|
+
options: ImageGenerationOptions<TProviderOptions>,
|
|
89
|
+
): OpenAI_SDK.Images.ImageGenerateParams {
|
|
90
|
+
const { model, prompt, numberOfImages, size, modelOptions } = options
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
model,
|
|
94
|
+
prompt,
|
|
95
|
+
n: numberOfImages ?? 1,
|
|
96
|
+
size: size as OpenAI_SDK.Images.ImageGenerateParams['size'],
|
|
97
|
+
...modelOptions,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected transformResponse(
|
|
102
|
+
model: string,
|
|
103
|
+
response: OpenAI_SDK.Images.ImagesResponse,
|
|
104
|
+
): ImageGenerationResult {
|
|
105
|
+
const images: Array<GeneratedImage> = (response.data ?? []).flatMap(
|
|
106
|
+
(item): Array<GeneratedImage> => {
|
|
107
|
+
const revisedPrompt = item.revised_prompt
|
|
108
|
+
if (item.b64_json) {
|
|
109
|
+
return [{ b64Json: item.b64_json, revisedPrompt }]
|
|
110
|
+
}
|
|
111
|
+
if (item.url) {
|
|
112
|
+
return [{ url: item.url, revisedPrompt }]
|
|
113
|
+
}
|
|
114
|
+
return []
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
id: generateId(this.name),
|
|
120
|
+
model,
|
|
121
|
+
images,
|
|
122
|
+
usage: response.usage
|
|
123
|
+
? {
|
|
124
|
+
inputTokens: response.usage.input_tokens,
|
|
125
|
+
outputTokens: response.usage.output_tokens,
|
|
126
|
+
totalTokens: response.usage.total_tokens,
|
|
127
|
+
}
|
|
128
|
+
: undefined,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
protected validatePrompt(options: { prompt: string; model: string }): void {
|
|
133
|
+
if (options.prompt.length === 0) {
|
|
134
|
+
throw new Error('Prompt cannot be empty.')
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
protected validateImageSize(_model: string, _size: string | undefined): void {
|
|
139
|
+
// Default: no size validation — subclasses can override
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
protected validateNumberOfImages(
|
|
143
|
+
_model: string,
|
|
144
|
+
numberOfImages: number | undefined,
|
|
145
|
+
): void {
|
|
146
|
+
if (numberOfImages === undefined) return
|
|
147
|
+
|
|
148
|
+
// The base adapter only enforces "must be at least 1". Per-provider /
|
|
149
|
+
// per-model upper bounds vary widely (some support 4, some 10, some
|
|
150
|
+
// unlimited), so concrete adapter subclasses are expected to override
|
|
151
|
+
// this method with a model-specific cap.
|
|
152
|
+
if (numberOfImages < 1) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`Number of images must be at least 1. Requested: ${numberOfImages}`,
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|