@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.
Files changed (110) hide show
  1. package/dist/esm/adapters/chat-completions-text.d.ts +76 -0
  2. package/dist/esm/adapters/chat-completions-text.js +411 -0
  3. package/dist/esm/adapters/chat-completions-text.js.map +1 -0
  4. package/dist/esm/adapters/chat-completions-tool-converter.d.ts +24 -0
  5. package/dist/esm/adapters/chat-completions-tool-converter.js +29 -0
  6. package/dist/esm/adapters/chat-completions-tool-converter.js.map +1 -0
  7. package/dist/esm/adapters/image.d.ts +32 -0
  8. package/dist/esm/adapters/image.js +69 -0
  9. package/dist/esm/adapters/image.js.map +1 -0
  10. package/dist/esm/adapters/responses-text.d.ts +115 -0
  11. package/dist/esm/adapters/responses-text.js +635 -0
  12. package/dist/esm/adapters/responses-text.js.map +1 -0
  13. package/dist/esm/adapters/responses-tool-converter.d.ts +35 -0
  14. package/dist/esm/adapters/responses-tool-converter.js +27 -0
  15. package/dist/esm/adapters/responses-tool-converter.js.map +1 -0
  16. package/dist/esm/adapters/summarize.d.ts +28 -0
  17. package/dist/esm/adapters/summarize.js +74 -0
  18. package/dist/esm/adapters/summarize.js.map +1 -0
  19. package/dist/esm/adapters/transcription.d.ts +39 -0
  20. package/dist/esm/adapters/transcription.js +139 -0
  21. package/dist/esm/adapters/transcription.js.map +1 -0
  22. package/dist/esm/adapters/tts.d.ts +26 -0
  23. package/dist/esm/adapters/tts.js +65 -0
  24. package/dist/esm/adapters/tts.js.map +1 -0
  25. package/dist/esm/adapters/video.d.ts +48 -0
  26. package/dist/esm/adapters/video.js +192 -0
  27. package/dist/esm/adapters/video.js.map +1 -0
  28. package/dist/esm/index.d.ts +15 -0
  29. package/dist/esm/index.js +65 -0
  30. package/dist/esm/index.js.map +1 -0
  31. package/dist/esm/tools/apply-patch-tool.d.ts +11 -0
  32. package/dist/esm/tools/apply-patch-tool.js +17 -0
  33. package/dist/esm/tools/apply-patch-tool.js.map +1 -0
  34. package/dist/esm/tools/code-interpreter-tool.d.ts +11 -0
  35. package/dist/esm/tools/code-interpreter-tool.js +22 -0
  36. package/dist/esm/tools/code-interpreter-tool.js.map +1 -0
  37. package/dist/esm/tools/computer-use-tool.d.ts +11 -0
  38. package/dist/esm/tools/computer-use-tool.js +23 -0
  39. package/dist/esm/tools/computer-use-tool.js.map +1 -0
  40. package/dist/esm/tools/custom-tool.d.ts +11 -0
  41. package/dist/esm/tools/custom-tool.js +23 -0
  42. package/dist/esm/tools/custom-tool.js.map +1 -0
  43. package/dist/esm/tools/file-search-tool.d.ts +11 -0
  44. package/dist/esm/tools/file-search-tool.js +30 -0
  45. package/dist/esm/tools/file-search-tool.js.map +1 -0
  46. package/dist/esm/tools/function-tool.d.ts +15 -0
  47. package/dist/esm/tools/function-tool.js +24 -0
  48. package/dist/esm/tools/function-tool.js.map +1 -0
  49. package/dist/esm/tools/image-generation-tool.d.ts +11 -0
  50. package/dist/esm/tools/image-generation-tool.js +27 -0
  51. package/dist/esm/tools/image-generation-tool.js.map +1 -0
  52. package/dist/esm/tools/index.d.ts +27 -0
  53. package/dist/esm/tools/local-shell-tool.d.ts +11 -0
  54. package/dist/esm/tools/local-shell-tool.js +17 -0
  55. package/dist/esm/tools/local-shell-tool.js.map +1 -0
  56. package/dist/esm/tools/mcp-tool.d.ts +12 -0
  57. package/dist/esm/tools/mcp-tool.js +31 -0
  58. package/dist/esm/tools/mcp-tool.js.map +1 -0
  59. package/dist/esm/tools/shell-tool.d.ts +11 -0
  60. package/dist/esm/tools/shell-tool.js +17 -0
  61. package/dist/esm/tools/shell-tool.js.map +1 -0
  62. package/dist/esm/tools/tool-choice.d.ts +17 -0
  63. package/dist/esm/tools/tool-converter.d.ts +6 -0
  64. package/dist/esm/tools/tool-converter.js +61 -0
  65. package/dist/esm/tools/tool-converter.js.map +1 -0
  66. package/dist/esm/tools/web-search-preview-tool.d.ts +11 -0
  67. package/dist/esm/tools/web-search-preview-tool.js +20 -0
  68. package/dist/esm/tools/web-search-preview-tool.js.map +1 -0
  69. package/dist/esm/tools/web-search-tool.d.ts +11 -0
  70. package/dist/esm/tools/web-search-tool.js +16 -0
  71. package/dist/esm/tools/web-search-tool.js.map +1 -0
  72. package/dist/esm/types/config.d.ts +4 -0
  73. package/dist/esm/types/message-metadata.d.ts +19 -0
  74. package/dist/esm/types/provider-options.d.ts +40 -0
  75. package/dist/esm/utils/client.d.ts +3 -0
  76. package/dist/esm/utils/client.js +8 -0
  77. package/dist/esm/utils/client.js.map +1 -0
  78. package/dist/esm/utils/schema-converter.d.ts +12 -0
  79. package/dist/esm/utils/schema-converter.js +65 -0
  80. package/dist/esm/utils/schema-converter.js.map +1 -0
  81. package/package.json +57 -0
  82. package/src/adapters/chat-completions-text.ts +817 -0
  83. package/src/adapters/chat-completions-tool-converter.ts +70 -0
  84. package/src/adapters/image.ts +158 -0
  85. package/src/adapters/responses-text.ts +1147 -0
  86. package/src/adapters/responses-tool-converter.ts +77 -0
  87. package/src/adapters/summarize.ts +174 -0
  88. package/src/adapters/transcription.ts +194 -0
  89. package/src/adapters/tts.ts +124 -0
  90. package/src/adapters/video.ts +385 -0
  91. package/src/index.ts +24 -0
  92. package/src/tools/apply-patch-tool.ts +32 -0
  93. package/src/tools/code-interpreter-tool.ts +39 -0
  94. package/src/tools/computer-use-tool.ts +38 -0
  95. package/src/tools/custom-tool.ts +33 -0
  96. package/src/tools/file-search-tool.ts +51 -0
  97. package/src/tools/function-tool.ts +44 -0
  98. package/src/tools/image-generation-tool.ts +51 -0
  99. package/src/tools/index.ts +41 -0
  100. package/src/tools/local-shell-tool.ts +32 -0
  101. package/src/tools/mcp-tool.ts +47 -0
  102. package/src/tools/shell-tool.ts +30 -0
  103. package/src/tools/tool-choice.ts +31 -0
  104. package/src/tools/tool-converter.ts +68 -0
  105. package/src/tools/web-search-preview-tool.ts +39 -0
  106. package/src/tools/web-search-tool.ts +38 -0
  107. package/src/types/config.ts +5 -0
  108. package/src/utils/client.ts +8 -0
  109. package/src/utils/request-options.ts +16 -0
  110. package/src/utils/schema-converter.ts +89 -0
@@ -0,0 +1,69 @@
1
+ import { BaseImageAdapter } from "@tanstack/ai/adapters";
2
+ import { generateId } from "@tanstack/ai-utils";
3
+ import { createOpenAICompatibleClient } from "../utils/client.js";
4
+ class OpenAICompatibleImageAdapter extends BaseImageAdapter {
5
+ constructor(config, model, name = "openai-compatible") {
6
+ super({}, model);
7
+ this.kind = "image";
8
+ this.name = name;
9
+ this.client = createOpenAICompatibleClient(config);
10
+ }
11
+ async generateImages(options) {
12
+ const { model, prompt, numberOfImages, size } = options;
13
+ this.validatePrompt({ prompt, model });
14
+ this.validateImageSize(model, size);
15
+ this.validateNumberOfImages(model, numberOfImages);
16
+ const request = this.buildRequest(options);
17
+ const response = await this.client.images.generate({
18
+ ...request,
19
+ stream: false
20
+ });
21
+ return this.transformResponse(model, response);
22
+ }
23
+ buildRequest(options) {
24
+ const { model, prompt, numberOfImages, size, modelOptions } = options;
25
+ return {
26
+ model,
27
+ prompt,
28
+ n: numberOfImages ?? 1,
29
+ size,
30
+ ...modelOptions
31
+ };
32
+ }
33
+ transformResponse(model, response) {
34
+ const images = (response.data ?? []).map((item) => ({
35
+ b64Json: item.b64_json,
36
+ url: item.url,
37
+ revisedPrompt: item.revised_prompt
38
+ }));
39
+ return {
40
+ id: generateId(this.name),
41
+ model,
42
+ images,
43
+ usage: response.usage ? {
44
+ inputTokens: response.usage.input_tokens,
45
+ outputTokens: response.usage.output_tokens,
46
+ totalTokens: response.usage.total_tokens
47
+ } : void 0
48
+ };
49
+ }
50
+ validatePrompt(options) {
51
+ if (options.prompt.length === 0) {
52
+ throw new Error("Prompt cannot be empty.");
53
+ }
54
+ }
55
+ validateImageSize(_model, _size) {
56
+ }
57
+ validateNumberOfImages(_model, numberOfImages) {
58
+ if (numberOfImages === void 0) return;
59
+ if (numberOfImages < 1 || numberOfImages > 10) {
60
+ throw new Error(
61
+ `Number of images must be between 1 and 10. Requested: ${numberOfImages}`
62
+ );
63
+ }
64
+ }
65
+ }
66
+ export {
67
+ OpenAICompatibleImageAdapter
68
+ };
69
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.js","sources":["../../../src/adapters/image.ts"],"sourcesContent":["import { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { generateId } from '@tanstack/ai-utils'\nimport { createOpenAICompatibleClient } from '../utils/client'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type { OpenAICompatibleClientConfig } from '../types/config'\n\n/**\n * OpenAI-Compatible Image Generation Adapter\n *\n * A generalized base class for providers that implement OpenAI-compatible image\n * generation APIs. Providers like OpenAI, Grok, and others can extend this class\n * and only need to:\n * - Set `baseURL` in the config\n * - Lock the generic type parameters to provider-specific types\n * - Override validation or request building methods for provider-specific constraints\n *\n * All methods that validate inputs, build requests, or transform responses are\n * `protected` so subclasses can override them.\n */\nexport class OpenAICompatibleImageAdapter<\n TModel extends string,\n TProviderOptions extends object = Record<string, any>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string> = Record<string, string>,\n> extends BaseImageAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName\n> {\n readonly kind = 'image' as const\n readonly name: string\n\n protected client: OpenAI_SDK\n\n constructor(\n config: OpenAICompatibleClientConfig,\n model: TModel,\n name: string = 'openai-compatible',\n ) {\n super({}, model)\n this.name = name\n this.client = createOpenAICompatibleClient(config)\n }\n\n async generateImages(\n options: ImageGenerationOptions<TProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, prompt, numberOfImages, size } = options\n\n // Validate inputs\n this.validatePrompt({ prompt, model })\n this.validateImageSize(model, size)\n this.validateNumberOfImages(model, numberOfImages)\n\n // Build request based on model type\n const request = this.buildRequest(options)\n\n const response = await this.client.images.generate({\n ...request,\n stream: false,\n })\n\n return this.transformResponse(model, response)\n }\n\n protected buildRequest(\n options: ImageGenerationOptions<TProviderOptions>,\n ): OpenAI_SDK.Images.ImageGenerateParams {\n const { model, prompt, numberOfImages, size, modelOptions } = options\n\n return {\n model,\n prompt,\n n: numberOfImages ?? 1,\n size: size as OpenAI_SDK.Images.ImageGenerateParams['size'],\n ...modelOptions,\n }\n }\n\n protected transformResponse(\n model: string,\n response: OpenAI_SDK.Images.ImagesResponse,\n ): ImageGenerationResult {\n const images: Array<GeneratedImage> = (response.data ?? []).map((item) => ({\n b64Json: item.b64_json,\n url: item.url,\n revisedPrompt: item.revised_prompt,\n }))\n\n return {\n id: generateId(this.name),\n model,\n images,\n usage: response.usage\n ? {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.total_tokens,\n }\n : undefined,\n }\n }\n\n protected validatePrompt(options: { prompt: string; model: string }): void {\n if (options.prompt.length === 0) {\n throw new Error('Prompt cannot be empty.')\n }\n }\n\n protected validateImageSize(_model: string, _size: string | undefined): void {\n // Default: no size validation — subclasses can override\n }\n\n protected validateNumberOfImages(\n _model: string,\n numberOfImages: number | undefined,\n ): void {\n if (numberOfImages === undefined) return\n\n if (numberOfImages < 1 || numberOfImages > 10) {\n throw new Error(\n `Number of images must be between 1 and 10. Requested: ${numberOfImages}`,\n )\n }\n }\n}\n"],"names":[],"mappings":";;;AAwBO,MAAM,qCAKH,iBAKR;AAAA,EAMA,YACE,QACA,OACA,OAAe,qBACf;AACA,UAAM,CAAA,GAAI,KAAK;AAVjB,SAAS,OAAO;AAWd,SAAK,OAAO;AACZ,SAAK,SAAS,6BAA6B,MAAM;AAAA,EACnD;AAAA,EAEA,MAAM,eACJ,SACgC;AAChC,UAAM,EAAE,OAAO,QAAQ,gBAAgB,SAAS;AAGhD,SAAK,eAAe,EAAE,QAAQ,MAAA,CAAO;AACrC,SAAK,kBAAkB,OAAO,IAAI;AAClC,SAAK,uBAAuB,OAAO,cAAc;AAGjD,UAAM,UAAU,KAAK,aAAa,OAAO;AAEzC,UAAM,WAAW,MAAM,KAAK,OAAO,OAAO,SAAS;AAAA,MACjD,GAAG;AAAA,MACH,QAAQ;AAAA,IAAA,CACT;AAED,WAAO,KAAK,kBAAkB,OAAO,QAAQ;AAAA,EAC/C;AAAA,EAEU,aACR,SACuC;AACvC,UAAM,EAAE,OAAO,QAAQ,gBAAgB,MAAM,iBAAiB;AAE9D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAG,kBAAkB;AAAA,MACrB;AAAA,MACA,GAAG;AAAA,IAAA;AAAA,EAEP;AAAA,EAEU,kBACR,OACA,UACuB;AACvB,UAAM,UAAiC,SAAS,QAAQ,CAAA,GAAI,IAAI,CAAC,UAAU;AAAA,MACzE,SAAS,KAAK;AAAA,MACd,KAAK,KAAK;AAAA,MACV,eAAe,KAAK;AAAA,IAAA,EACpB;AAEF,WAAO;AAAA,MACL,IAAI,WAAW,KAAK,IAAI;AAAA,MACxB;AAAA,MACA;AAAA,MACA,OAAO,SAAS,QACZ;AAAA,QACE,aAAa,SAAS,MAAM;AAAA,QAC5B,cAAc,SAAS,MAAM;AAAA,QAC7B,aAAa,SAAS,MAAM;AAAA,MAAA,IAE9B;AAAA,IAAA;AAAA,EAER;AAAA,EAEU,eAAe,SAAkD;AACzE,QAAI,QAAQ,OAAO,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAAA,EACF;AAAA,EAEU,kBAAkB,QAAgB,OAAiC;AAAA,EAE7E;AAAA,EAEU,uBACR,QACA,gBACM;AACN,QAAI,mBAAmB,OAAW;AAElC,QAAI,iBAAiB,KAAK,iBAAiB,IAAI;AAC7C,YAAM,IAAI;AAAA,QACR,yDAAyD,cAAc;AAAA,MAAA;AAAA,IAE3E;AAAA,EACF;AACF;"}
@@ -0,0 +1,115 @@
1
+ import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from '@tanstack/ai/adapters';
2
+ import { default as OpenAI_SDK } from 'openai';
3
+ import { Responses } from 'openai/resources';
4
+ import { ContentPart, DefaultMessageMetadataByModality, Modality, ModelMessage, StreamChunk, TextOptions } from '@tanstack/ai';
5
+ import { OpenAICompatibleClientConfig } from '../types/config.js';
6
+ /**
7
+ * OpenAI-compatible Responses API Text Adapter
8
+ *
9
+ * A generalized base class for providers that use the OpenAI Responses API
10
+ * (`/v1/responses`). Providers like OpenAI (native), Azure OpenAI, and others
11
+ * that implement the Responses API can extend this class and only need to:
12
+ * - Set `baseURL` in the config
13
+ * - Lock the generic type parameters to provider-specific types
14
+ * - Override specific methods for quirks
15
+ *
16
+ * Key differences from the Chat Completions adapter:
17
+ * - Uses `client.responses.create()` instead of `client.chat.completions.create()`
18
+ * - Messages use `ResponseInput` format
19
+ * - System prompts go in `instructions` field, not as array messages
20
+ * - Streaming events are completely different (9+ event types vs simple delta chunks)
21
+ * - Supports reasoning/thinking tokens via `response.reasoning_text.delta`
22
+ * - Structured output uses `text.format` in the request (not `response_format`)
23
+ * - Tool calls use `response.function_call_arguments.delta`
24
+ * - Content parts are `input_text`, `input_image`, `input_file`
25
+ *
26
+ * All methods that build requests or process responses are `protected` so subclasses
27
+ * can override them.
28
+ */
29
+ export declare class OpenAICompatibleResponsesTextAdapter<TModel extends string, TProviderOptions extends Record<string, any> = Record<string, any>, TInputModalities extends ReadonlyArray<Modality> = ReadonlyArray<Modality>, TMessageMetadata extends DefaultMessageMetadataByModality = DefaultMessageMetadataByModality> extends BaseTextAdapter<TModel, TProviderOptions, TInputModalities, TMessageMetadata> {
30
+ readonly kind: "text";
31
+ readonly name: string;
32
+ protected client: OpenAI_SDK;
33
+ constructor(config: OpenAICompatibleClientConfig, model: TModel, name?: string);
34
+ chatStream(options: TextOptions<TProviderOptions>): AsyncIterable<StreamChunk>;
35
+ /**
36
+ * Generate structured output using the provider's native JSON Schema response format.
37
+ * Uses stream: false to get the complete response in one call.
38
+ *
39
+ * OpenAI-compatible Responses APIs have strict requirements for structured output:
40
+ * - All properties must be in the `required` array
41
+ * - Optional fields should have null added to their type union
42
+ * - additionalProperties must be false for all objects
43
+ *
44
+ * The outputSchema is already JSON Schema (converted in the ai layer).
45
+ * We apply provider-specific transformations for structured output compatibility.
46
+ */
47
+ structuredOutput(options: StructuredOutputOptions<TProviderOptions>): Promise<StructuredOutputResult<unknown>>;
48
+ /**
49
+ * Applies provider-specific transformations for structured output compatibility.
50
+ * Override this in subclasses to handle provider-specific quirks.
51
+ */
52
+ protected makeStructuredOutputCompatible(schema: Record<string, any>, originalRequired: Array<string>): Record<string, any>;
53
+ /**
54
+ * Extract text content from a non-streaming Responses API response.
55
+ * Override this in subclasses for provider-specific response shapes.
56
+ */
57
+ protected extractTextFromResponse(response: OpenAI_SDK.Responses.Response): string;
58
+ /**
59
+ * Processes streamed chunks from the Responses API and yields AG-UI events.
60
+ * Override this in subclasses to handle provider-specific stream behavior.
61
+ *
62
+ * Handles the following event types:
63
+ * - response.created / response.incomplete / response.failed
64
+ * - response.output_text.delta
65
+ * - response.reasoning_text.delta
66
+ * - response.reasoning_summary_text.delta
67
+ * - response.content_part.added / response.content_part.done
68
+ * - response.output_item.added
69
+ * - response.function_call_arguments.delta / response.function_call_arguments.done
70
+ * - response.completed
71
+ * - error
72
+ */
73
+ protected processStreamChunks(stream: AsyncIterable<OpenAI_SDK.Responses.ResponseStreamEvent>, toolCallMetadata: Map<string, {
74
+ index: number;
75
+ name: string;
76
+ callId: string;
77
+ started: boolean;
78
+ }>, options: TextOptions, aguiState: {
79
+ runId: string;
80
+ messageId: string;
81
+ timestamp: number;
82
+ hasEmittedRunStarted: boolean;
83
+ }): AsyncIterable<StreamChunk>;
84
+ /**
85
+ * Maps common TextOptions to Responses API request format.
86
+ * Override this in subclasses to add provider-specific options.
87
+ */
88
+ protected mapOptionsToRequest(options: TextOptions): Omit<OpenAI_SDK.Responses.ResponseCreateParams, 'stream'>;
89
+ /**
90
+ * Converts ModelMessage[] to Responses API ResponseInput format.
91
+ * Override this in subclasses for provider-specific message format quirks.
92
+ *
93
+ * Key differences from Chat Completions:
94
+ * - Tool results use `function_call_output` type (not `tool` role)
95
+ * - Assistant tool calls are `function_call` objects (not nested in `tool_calls`)
96
+ * - User content uses `input_text`, `input_image`, `input_file` types
97
+ * - System prompts go in `instructions`, not as messages
98
+ */
99
+ protected convertMessagesToInput(messages: Array<ModelMessage>): Responses.ResponseInput;
100
+ /**
101
+ * Converts a ContentPart to Responses API input content item.
102
+ * Handles text, image, and audio content parts.
103
+ * Override this in subclasses for additional content types or provider-specific metadata.
104
+ */
105
+ protected convertContentPartToInput(part: ContentPart): Responses.ResponseInputContent;
106
+ /**
107
+ * Normalizes message content to an array of ContentPart.
108
+ * Handles backward compatibility with string content.
109
+ */
110
+ protected normalizeContent(content: string | null | Array<ContentPart>): Array<ContentPart>;
111
+ /**
112
+ * Extracts text content from a content value that may be string, null, or ContentPart array.
113
+ */
114
+ protected extractTextContent(content: string | null | Array<ContentPart>): string;
115
+ }