@tanstack/ai-lovable 0.0.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 (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/esm/adapters/embedding.d.ts +16 -0
  4. package/dist/esm/adapters/embedding.js +66 -0
  5. package/dist/esm/adapters/embedding.js.map +1 -0
  6. package/dist/esm/adapters/factory.d.ts +16 -0
  7. package/dist/esm/adapters/factory.js +28 -0
  8. package/dist/esm/adapters/factory.js.map +1 -0
  9. package/dist/esm/adapters/image.d.ts +26 -0
  10. package/dist/esm/adapters/image.js +145 -0
  11. package/dist/esm/adapters/image.js.map +1 -0
  12. package/dist/esm/adapters/responses-text.d.ts +24 -0
  13. package/dist/esm/adapters/responses-text.js +30 -0
  14. package/dist/esm/adapters/responses-text.js.map +1 -0
  15. package/dist/esm/adapters/summarize.d.ts +9 -0
  16. package/dist/esm/adapters/summarize.js +17 -0
  17. package/dist/esm/adapters/summarize.js.map +1 -0
  18. package/dist/esm/adapters/text.d.ts +20 -0
  19. package/dist/esm/adapters/text.js +21 -0
  20. package/dist/esm/adapters/text.js.map +1 -0
  21. package/dist/esm/adapters/transcription.d.ts +19 -0
  22. package/dist/esm/adapters/transcription.js +123 -0
  23. package/dist/esm/adapters/transcription.js.map +1 -0
  24. package/dist/esm/adapters/tts.d.ts +16 -0
  25. package/dist/esm/adapters/tts.js +69 -0
  26. package/dist/esm/adapters/tts.js.map +1 -0
  27. package/dist/esm/adapters/video.d.ts +41 -0
  28. package/dist/esm/adapters/video.js +164 -0
  29. package/dist/esm/adapters/video.js.map +1 -0
  30. package/dist/esm/audio/transcription-provider-options.d.ts +6 -0
  31. package/dist/esm/audio/tts-provider-options.d.ts +8 -0
  32. package/dist/esm/byok.d.ts +1 -0
  33. package/dist/esm/byok.js +11 -0
  34. package/dist/esm/byok.js.map +1 -0
  35. package/dist/esm/embedding/embedding-provider-options.d.ts +9 -0
  36. package/dist/esm/image/image-input-to-file.d.ts +8 -0
  37. package/dist/esm/image/image-input-to-file.js +47 -0
  38. package/dist/esm/image/image-input-to-file.js.map +1 -0
  39. package/dist/esm/image/image-provider-options.d.ts +12 -0
  40. package/dist/esm/index.d.ts +26 -0
  41. package/dist/esm/index.js +12 -0
  42. package/dist/esm/message-types.d.ts +44 -0
  43. package/dist/esm/model-meta.d.ts +71 -0
  44. package/dist/esm/model-meta.js +63 -0
  45. package/dist/esm/model-meta.js.map +1 -0
  46. package/dist/esm/text/responses-provider-options.d.ts +3 -0
  47. package/dist/esm/text/text-provider-options.d.ts +17 -0
  48. package/dist/esm/utils/client.d.ts +14 -0
  49. package/dist/esm/utils/client.js +35 -0
  50. package/dist/esm/utils/client.js.map +1 -0
  51. package/dist/esm/video/video-provider-options.d.ts +19 -0
  52. package/dist/esm/video/video-provider-options.js +47 -0
  53. package/dist/esm/video/video-provider-options.js.map +1 -0
  54. package/package.json +79 -0
  55. package/src/adapters/embedding.ts +102 -0
  56. package/src/adapters/factory.ts +78 -0
  57. package/src/adapters/image.ts +304 -0
  58. package/src/adapters/responses-text.ts +66 -0
  59. package/src/adapters/summarize.ts +35 -0
  60. package/src/adapters/text.ts +49 -0
  61. package/src/adapters/transcription.ts +226 -0
  62. package/src/adapters/tts.ts +97 -0
  63. package/src/adapters/video.ts +303 -0
  64. package/src/audio/transcription-provider-options.ts +7 -0
  65. package/src/audio/tts-provider-options.ts +21 -0
  66. package/src/byok.ts +7 -0
  67. package/src/embedding/embedding-provider-options.ts +9 -0
  68. package/src/image/image-input-to-file.ts +81 -0
  69. package/src/image/image-provider-options.ts +17 -0
  70. package/src/index.ts +125 -0
  71. package/src/message-types.ts +45 -0
  72. package/src/model-meta.ts +161 -0
  73. package/src/text/responses-provider-options.ts +8 -0
  74. package/src/text/text-provider-options.ts +18 -0
  75. package/src/utils/client.ts +50 -0
  76. package/src/video/video-provider-options.ts +128 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tanner Linsley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # @tanstack/ai-lovable
2
+
3
+ Lovable AI Gateway adapter for TanStack AI.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @tanstack/ai-lovable
9
+ ```
10
+
11
+ ## Auth
12
+
13
+ Set `LOVABLE_API_KEY`. Lovable creates this key per Cloud project.
14
+
15
+ ```bash
16
+ export LOVABLE_API_KEY="..."
17
+ ```
18
+
19
+ You can also pass the key to a `create*` factory.
20
+
21
+ ## Usage
22
+
23
+ ```typescript
24
+ import { chat } from '@tanstack/ai'
25
+ import { lovableText } from '@tanstack/ai-lovable'
26
+
27
+ const adapter = lovableText('google/gemini-3.7-flash')
28
+
29
+ const stream = chat({
30
+ adapter,
31
+ messages: [{ role: 'user', content: 'Hello' }],
32
+ })
33
+ ```
34
+
35
+ The default text adapter uses the Responses API. Pass `{ api: 'chat' }` for Chat Completions.
36
+
37
+ See [docs/adapters/lovable.md](../../docs/adapters/lovable.md) for chat, images, video, embeddings, speech, transcription, and BYOK.
@@ -0,0 +1,16 @@
1
+ import { default as OpenAI } from 'openai';
2
+ import { BaseEmbeddingAdapter } from '@tanstack/ai/adapters';
3
+ import { EmbeddingOptions, EmbeddingResult } from '@tanstack/ai';
4
+ import { LovableEmbeddingModel, LovableEmbeddingModelInputModalitiesByName, LovableEmbeddingModelProviderOptionsByName } from '../model-meta.js';
5
+ import { LovableEmbeddingProviderOptions } from '../embedding/embedding-provider-options.js';
6
+ import { LovableClientConfig } from '../utils/client.js';
7
+ export interface LovableEmbeddingConfig extends LovableClientConfig {
8
+ }
9
+ export declare class LovableEmbeddingAdapter<TModel extends LovableEmbeddingModel> extends BaseEmbeddingAdapter<TModel, LovableEmbeddingProviderOptions, LovableEmbeddingModelProviderOptionsByName, LovableEmbeddingModelInputModalitiesByName> {
10
+ readonly name: "lovable";
11
+ protected client: OpenAI;
12
+ constructor(config: LovableEmbeddingConfig, model: TModel);
13
+ createEmbeddings(options: EmbeddingOptions<LovableEmbeddingProviderOptions>): Promise<EmbeddingResult>;
14
+ }
15
+ export declare function createLovableEmbedding<TModel extends LovableEmbeddingModel>(model: TModel, apiKey: string, config?: Omit<LovableEmbeddingConfig, 'apiKey'>): LovableEmbeddingAdapter<TModel>;
16
+ export declare function lovableEmbedding<TModel extends LovableEmbeddingModel>(model: TModel, config?: Omit<LovableEmbeddingConfig, 'apiKey'>): LovableEmbeddingAdapter<TModel>;
@@ -0,0 +1,66 @@
1
+ import { getLovableApiKeyFromEnv, withLovableDefaults } from "../utils/client.js";
2
+ import OpenAI from "openai";
3
+ import { generateId } from "@tanstack/ai-utils";
4
+ import { BaseEmbeddingAdapter } from "@tanstack/ai/adapters";
5
+ import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
6
+ import { requireTextOnlyEmbeddingInput } from "@tanstack/ai";
7
+ //#region src/adapters/embedding.ts
8
+ var LovableEmbeddingAdapter = class extends BaseEmbeddingAdapter {
9
+ name = "lovable";
10
+ client;
11
+ constructor(config, model) {
12
+ super(model, {});
13
+ this.client = new OpenAI(withLovableDefaults(config));
14
+ }
15
+ async createEmbeddings(options) {
16
+ const { model, logger, modelOptions } = options;
17
+ const texts = requireTextOnlyEmbeddingInput(options.input, this.name, model);
18
+ try {
19
+ const request = {
20
+ ...modelOptions,
21
+ model,
22
+ input: texts,
23
+ encoding_format: "float"
24
+ };
25
+ if (options.dimensions !== void 0) request.dimensions = options.dimensions;
26
+ logger.request(`activity=embed provider=${this.name} model=${model} inputs=${texts.length}`, {
27
+ provider: this.name,
28
+ model
29
+ });
30
+ const response = await this.client.embeddings.create(request);
31
+ const usage = {
32
+ promptTokens: response.usage.prompt_tokens,
33
+ completionTokens: 0,
34
+ totalTokens: response.usage.total_tokens
35
+ };
36
+ return {
37
+ id: generateId(this.name),
38
+ model,
39
+ embeddings: response.data.map((item) => ({
40
+ vector: item.embedding,
41
+ index: item.index
42
+ })),
43
+ usage
44
+ };
45
+ } catch (error) {
46
+ logger.errors(`${this.name}.createEmbeddings fatal`, {
47
+ error: toRunErrorPayload(error, `${this.name}.createEmbeddings failed`),
48
+ source: `${this.name}.createEmbeddings`
49
+ });
50
+ throw error;
51
+ }
52
+ }
53
+ };
54
+ function createLovableEmbedding(model, apiKey, config) {
55
+ return new LovableEmbeddingAdapter({
56
+ apiKey,
57
+ ...config
58
+ }, model);
59
+ }
60
+ function lovableEmbedding(model, config) {
61
+ return createLovableEmbedding(model, getLovableApiKeyFromEnv(), config);
62
+ }
63
+ //#endregion
64
+ export { LovableEmbeddingAdapter, createLovableEmbedding, lovableEmbedding };
65
+
66
+ //# sourceMappingURL=embedding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding.js","names":[],"sources":["../../../src/adapters/embedding.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { BaseEmbeddingAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { generateId } from '@tanstack/ai-utils'\nimport { requireTextOnlyEmbeddingInput } from '@tanstack/ai'\nimport { getLovableApiKeyFromEnv, withLovableDefaults } from '../utils/client'\nimport type {\n EmbeddingOptions,\n EmbeddingResult,\n TokenUsage,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type {\n LovableEmbeddingModel,\n LovableEmbeddingModelInputModalitiesByName,\n LovableEmbeddingModelProviderOptionsByName,\n} from '../model-meta'\nimport type { LovableEmbeddingProviderOptions } from '../embedding/embedding-provider-options'\nimport type { LovableClientConfig } from '../utils/client'\n\nexport interface LovableEmbeddingConfig extends LovableClientConfig {}\n\nexport class LovableEmbeddingAdapter<\n TModel extends LovableEmbeddingModel,\n> extends BaseEmbeddingAdapter<\n TModel,\n LovableEmbeddingProviderOptions,\n LovableEmbeddingModelProviderOptionsByName,\n LovableEmbeddingModelInputModalitiesByName\n> {\n readonly name = 'lovable' as const\n\n protected client: OpenAI\n\n constructor(config: LovableEmbeddingConfig, model: TModel) {\n super(model, {})\n this.client = new OpenAI(withLovableDefaults(config))\n }\n\n async createEmbeddings(\n options: EmbeddingOptions<LovableEmbeddingProviderOptions>,\n ): Promise<EmbeddingResult> {\n const { model, logger, modelOptions } = options\n const texts = requireTextOnlyEmbeddingInput(options.input, this.name, model)\n\n try {\n const request: OpenAI_SDK.EmbeddingCreateParams = {\n ...modelOptions,\n model,\n input: texts,\n encoding_format: 'float',\n }\n if (options.dimensions !== undefined) {\n request.dimensions = options.dimensions\n }\n\n logger.request(\n `activity=embed provider=${this.name} model=${model} inputs=${texts.length}`,\n { provider: this.name, model },\n )\n\n const response = await this.client.embeddings.create(request)\n\n const usage: TokenUsage = {\n promptTokens: response.usage.prompt_tokens,\n completionTokens: 0,\n totalTokens: response.usage.total_tokens,\n }\n\n return {\n id: generateId(this.name),\n model,\n embeddings: response.data.map((item) => ({\n vector: item.embedding,\n index: item.index,\n })),\n usage,\n }\n } catch (error: unknown) {\n logger.errors(`${this.name}.createEmbeddings fatal`, {\n error: toRunErrorPayload(error, `${this.name}.createEmbeddings failed`),\n source: `${this.name}.createEmbeddings`,\n })\n throw error\n }\n }\n}\n\nexport function createLovableEmbedding<TModel extends LovableEmbeddingModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<LovableEmbeddingConfig, 'apiKey'>,\n): LovableEmbeddingAdapter<TModel> {\n return new LovableEmbeddingAdapter({ apiKey, ...config }, model)\n}\n\nexport function lovableEmbedding<TModel extends LovableEmbeddingModel>(\n model: TModel,\n config?: Omit<LovableEmbeddingConfig, 'apiKey'>,\n): LovableEmbeddingAdapter<TModel> {\n return createLovableEmbedding(model, getLovableApiKeyFromEnv(), config)\n}\n"],"mappings":";;;;;;;AAsBA,IAAa,0BAAb,cAEU,qBAKR;CACA,OAAgB;CAEhB;CAEA,YAAY,QAAgC,OAAe;EACzD,MAAM,OAAO,CAAC,CAAC;EACf,KAAK,SAAS,IAAI,OAAO,oBAAoB,MAAM,CAAC;CACtD;CAEA,MAAM,iBACJ,SAC0B;EAC1B,MAAM,EAAE,OAAO,QAAQ,iBAAiB;EACxC,MAAM,QAAQ,8BAA8B,QAAQ,OAAO,KAAK,MAAM,KAAK;EAE3E,IAAI;GACF,MAAM,UAA4C;IAChD,GAAG;IACH;IACA,OAAO;IACP,iBAAiB;GACnB;GACA,IAAI,QAAQ,eAAe,KAAA,GACzB,QAAQ,aAAa,QAAQ;GAG/B,OAAO,QACL,2BAA2B,KAAK,KAAK,SAAS,MAAM,UAAU,MAAM,UACpE;IAAE,UAAU,KAAK;IAAM;GAAM,CAC/B;GAEA,MAAM,WAAW,MAAM,KAAK,OAAO,WAAW,OAAO,OAAO;GAE5D,MAAM,QAAoB;IACxB,cAAc,SAAS,MAAM;IAC7B,kBAAkB;IAClB,aAAa,SAAS,MAAM;GAC9B;GAEA,OAAO;IACL,IAAI,WAAW,KAAK,IAAI;IACxB;IACA,YAAY,SAAS,KAAK,KAAK,UAAU;KACvC,QAAQ,KAAK;KACb,OAAO,KAAK;IACd,EAAE;IACF;GACF;EACF,SAAS,OAAgB;GACvB,OAAO,OAAO,GAAG,KAAK,KAAK,0BAA0B;IACnD,OAAO,kBAAkB,OAAO,GAAG,KAAK,KAAK,yBAAyB;IACtE,QAAQ,GAAG,KAAK,KAAK;GACvB,CAAC;GACD,MAAM;EACR;CACF;AACF;AAEA,SAAgB,uBACd,OACA,QACA,QACiC;CACjC,OAAO,IAAI,wBAAwB;EAAE;EAAQ,GAAG;CAAO,GAAG,KAAK;AACjE;AAEA,SAAgB,iBACd,OACA,QACiC;CACjC,OAAO,uBAAuB,OAAO,wBAAwB,GAAG,MAAM;AACxE"}
@@ -0,0 +1,16 @@
1
+ import { LovableTextAdapter, LovableTextConfig } from './text.js';
2
+ import { LovableResponsesTextAdapter, LovableResponsesTextConfig } from './responses-text.js';
3
+ import { LovableModelId } from '../model-meta.js';
4
+ export type LovableTextApi = 'responses' | 'chat' | 'chat-completions';
5
+ /** Config for the branching factory's Responses mode (default, or api: 'responses'). */
6
+ export type LovableResponsesApiConfig = Omit<LovableResponsesTextConfig, 'apiKey'> & {
7
+ api?: 'responses';
8
+ };
9
+ /** Config for the branching factory's Chat Completions mode (api required). */
10
+ export type LovableChatApiConfig = Omit<LovableTextConfig, 'apiKey'> & {
11
+ api: 'chat' | 'chat-completions';
12
+ };
13
+ export declare function createLovableText<TModel extends LovableModelId>(model: TModel, apiKey: string, config?: LovableResponsesApiConfig): LovableResponsesTextAdapter<TModel>;
14
+ export declare function createLovableText<TModel extends LovableModelId>(model: TModel, apiKey: string, config: LovableChatApiConfig): LovableTextAdapter<TModel>;
15
+ export declare function lovableText<TModel extends LovableModelId>(model: TModel, config?: LovableResponsesApiConfig): LovableResponsesTextAdapter<TModel>;
16
+ export declare function lovableText<TModel extends LovableModelId>(model: TModel, config: LovableChatApiConfig): LovableTextAdapter<TModel>;
@@ -0,0 +1,28 @@
1
+ import { getLovableApiKeyFromEnv } from "../utils/client.js";
2
+ import { LovableTextAdapter } from "./text.js";
3
+ import { LovableResponsesTextAdapter } from "./responses-text.js";
4
+ //#region src/adapters/factory.ts
5
+ function stripApi(config) {
6
+ const { api, ...rest } = config;
7
+ return rest;
8
+ }
9
+ function build(model, config) {
10
+ if (config.api === "chat" || config.api === "chat-completions") return new LovableTextAdapter(stripApi(config), model);
11
+ return new LovableResponsesTextAdapter(stripApi(config), model);
12
+ }
13
+ function createLovableText(model, apiKey, config) {
14
+ return build(model, {
15
+ ...config,
16
+ apiKey
17
+ });
18
+ }
19
+ function lovableText(model, config) {
20
+ return build(model, {
21
+ ...config,
22
+ apiKey: getLovableApiKeyFromEnv()
23
+ });
24
+ }
25
+ //#endregion
26
+ export { createLovableText, lovableText };
27
+
28
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","names":[],"sources":["../../../src/adapters/factory.ts"],"sourcesContent":["import { getLovableApiKeyFromEnv } from '../utils/client'\nimport { LovableTextAdapter } from './text'\nimport { LovableResponsesTextAdapter } from './responses-text'\nimport type { LovableClientConfig } from '../utils/client'\nimport type { LovableTextConfig } from './text'\nimport type { LovableResponsesTextConfig } from './responses-text'\nimport type { LovableModelId } from '../model-meta'\n\nexport type LovableTextApi = 'responses' | 'chat' | 'chat-completions'\n\n/** Config for the branching factory's Responses mode (default, or api: 'responses'). */\nexport type LovableResponsesApiConfig = Omit<\n LovableResponsesTextConfig,\n 'apiKey'\n> & {\n api?: 'responses'\n}\n\n/** Config for the branching factory's Chat Completions mode (api required). */\nexport type LovableChatApiConfig = Omit<LovableTextConfig, 'apiKey'> & {\n api: 'chat' | 'chat-completions'\n}\n\ntype AnyLovableTextAdapter<TModel extends LovableModelId> =\n | LovableResponsesTextAdapter<TModel>\n | LovableTextAdapter<TModel>\n\nfunction stripApi<T extends { api?: unknown }>(config: T): Omit<T, 'api'> {\n const { api, ...rest } = config\n void api\n return rest\n}\n\nfunction build<TModel extends LovableModelId>(\n model: TModel,\n config: LovableClientConfig & { api?: LovableTextApi },\n): AnyLovableTextAdapter<TModel> {\n if (config.api === 'chat' || config.api === 'chat-completions') {\n return new LovableTextAdapter(stripApi(config), model)\n }\n return new LovableResponsesTextAdapter(stripApi(config), model)\n}\n\nexport function createLovableText<TModel extends LovableModelId>(\n model: TModel,\n apiKey: string,\n config?: LovableResponsesApiConfig,\n): LovableResponsesTextAdapter<TModel>\nexport function createLovableText<TModel extends LovableModelId>(\n model: TModel,\n apiKey: string,\n config: LovableChatApiConfig,\n): LovableTextAdapter<TModel>\nexport function createLovableText<TModel extends LovableModelId>(\n model: TModel,\n apiKey: string,\n config?: LovableResponsesApiConfig | LovableChatApiConfig,\n): AnyLovableTextAdapter<TModel> {\n return build(model, { ...config, apiKey })\n}\n\nexport function lovableText<TModel extends LovableModelId>(\n model: TModel,\n config?: LovableResponsesApiConfig,\n): LovableResponsesTextAdapter<TModel>\nexport function lovableText<TModel extends LovableModelId>(\n model: TModel,\n config: LovableChatApiConfig,\n): LovableTextAdapter<TModel>\nexport function lovableText<TModel extends LovableModelId>(\n model: TModel,\n config?: LovableResponsesApiConfig | LovableChatApiConfig,\n): AnyLovableTextAdapter<TModel> {\n return build(model, {\n ...config,\n apiKey: getLovableApiKeyFromEnv(),\n })\n}\n"],"mappings":";;;;AA2BA,SAAS,SAAsC,QAA2B;CACxE,MAAM,EAAE,KAAK,GAAG,SAAS;CAEzB,OAAO;AACT;AAEA,SAAS,MACP,OACA,QAC+B;CAC/B,IAAI,OAAO,QAAQ,UAAU,OAAO,QAAQ,oBAC1C,OAAO,IAAI,mBAAmB,SAAS,MAAM,GAAG,KAAK;CAEvD,OAAO,IAAI,4BAA4B,SAAS,MAAM,GAAG,KAAK;AAChE;AAYA,SAAgB,kBACd,OACA,QACA,QAC+B;CAC/B,OAAO,MAAM,OAAO;EAAE,GAAG;EAAQ;CAAO,CAAC;AAC3C;AAUA,SAAgB,YACd,OACA,QAC+B;CAC/B,OAAO,MAAM,OAAO;EAClB,GAAG;EACH,QAAQ,wBAAwB;CAClC,CAAC;AACH"}
@@ -0,0 +1,26 @@
1
+ import { default as OpenAI } from 'openai';
2
+ import { BaseImageAdapter } from '@tanstack/ai/adapters';
3
+ import { ImageGenerationOptions, ImageGenerationResult } from '@tanstack/ai';
4
+ import { LovableImageModel, LovableImageModelInputModalitiesByName, LovableImageModelProviderOptionsByName, LovableImageModelSizeByName } from '../model-meta.js';
5
+ import { LovableImageProviderOptions } from '../image/image-provider-options.js';
6
+ import { LovableClientConfig } from '../utils/client.js';
7
+ export interface LovableImageConfig extends LovableClientConfig {
8
+ /**
9
+ * Opt into fetching HTTP(S) image URL inputs for image edits. The gateway
10
+ * `/images/edits` endpoint requires uploaded file bytes, so an HTTP(S) URL
11
+ * has to be downloaded and buffered in memory. When `false` (the default),
12
+ * HTTP(S) URL image inputs throw.
13
+ */
14
+ allowUrlFetch?: boolean;
15
+ }
16
+ export declare class LovableImageAdapter<TModel extends LovableImageModel> extends BaseImageAdapter<TModel, LovableImageProviderOptions, LovableImageModelProviderOptionsByName, LovableImageModelSizeByName, LovableImageModelInputModalitiesByName> {
17
+ readonly kind: "image";
18
+ readonly name: "lovable";
19
+ protected client: OpenAI;
20
+ private readonly allowUrlFetch;
21
+ constructor(config: LovableImageConfig, model: TModel);
22
+ generateImages(options: ImageGenerationOptions<LovableImageProviderOptions>): Promise<ImageGenerationResult>;
23
+ private editImages;
24
+ }
25
+ export declare function createLovableImage<TModel extends LovableImageModel>(model: TModel, apiKey: string, config?: Omit<LovableImageConfig, 'apiKey'>): LovableImageAdapter<TModel>;
26
+ export declare function lovableImage<TModel extends LovableImageModel>(model: TModel, config?: Omit<LovableImageConfig, 'apiKey'>): LovableImageAdapter<TModel>;
@@ -0,0 +1,145 @@
1
+ import { getLovableApiKeyFromEnv, openaiRequestOptions, withLovableDefaults } from "../utils/client.js";
2
+ import { imagePartToFile } from "../image/image-input-to-file.js";
3
+ import OpenAI from "openai";
4
+ import { buildImagesUsage } from "@tanstack/openai-base";
5
+ import { generateId } from "@tanstack/ai-utils";
6
+ import { BaseImageAdapter } from "@tanstack/ai/adapters";
7
+ import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
8
+ import { resolveMediaPrompt } from "@tanstack/ai";
9
+ //#region src/adapters/image.ts
10
+ var MAX_EDIT_IMAGES = 16;
11
+ function supportsImageMask(model) {
12
+ return model.startsWith("openai/");
13
+ }
14
+ function generatedImagesFromResponse(data, emptyMessage) {
15
+ const images = (data ?? []).flatMap((item) => {
16
+ const revisedPromptField = item.revised_prompt !== void 0 && item.revised_prompt !== null ? { revisedPrompt: item.revised_prompt } : {};
17
+ if (item.b64_json) return [{
18
+ b64Json: item.b64_json,
19
+ ...revisedPromptField
20
+ }];
21
+ if (item.url) return [{
22
+ url: item.url,
23
+ ...revisedPromptField
24
+ }];
25
+ return [];
26
+ });
27
+ if (images.length === 0) throw new Error(emptyMessage);
28
+ return images;
29
+ }
30
+ var LovableImageAdapter = class extends BaseImageAdapter {
31
+ kind = "image";
32
+ name = "lovable";
33
+ client;
34
+ allowUrlFetch;
35
+ constructor(config, model) {
36
+ super(model, {});
37
+ const { allowUrlFetch, ...clientOptions } = config;
38
+ this.client = new OpenAI(withLovableDefaults(clientOptions));
39
+ this.allowUrlFetch = allowUrlFetch ?? false;
40
+ }
41
+ async generateImages(options) {
42
+ const { model, numberOfImages, size, modelOptions } = options;
43
+ const resolved = resolveMediaPrompt(options.prompt);
44
+ const prompt = resolved.text;
45
+ if (resolved.videos.length > 0) throw new Error(`${this.name}.generateImages does not support video prompt parts (model: ${model}).`);
46
+ if (resolved.audios.length > 0) throw new Error(`${this.name}.generateImages does not support audio prompt parts (model: ${model}).`);
47
+ if (resolved.images.length > 0) return this.editImages({
48
+ model,
49
+ prompt,
50
+ numberOfImages,
51
+ size,
52
+ modelOptions,
53
+ imageInputs: resolved.images,
54
+ logger: options.logger,
55
+ abortSignal: options.abortSignal
56
+ });
57
+ const request = {
58
+ model,
59
+ prompt,
60
+ n: numberOfImages ?? 1,
61
+ ...modelOptions ?? {}
62
+ };
63
+ if (size !== void 0) request.size = size;
64
+ try {
65
+ options.logger.request(`activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? "default"}`, {
66
+ provider: this.name,
67
+ model
68
+ });
69
+ const response = await this.client.images.generate({
70
+ ...request,
71
+ stream: false
72
+ }, openaiRequestOptions(options.abortSignal));
73
+ const images = generatedImagesFromResponse(response.data, `${this.name}: image response contained no images`);
74
+ const usage = buildImagesUsage(response.usage);
75
+ return {
76
+ id: generateId(this.name),
77
+ model,
78
+ images,
79
+ ...usage ? { usage } : {}
80
+ };
81
+ } catch (error) {
82
+ options.logger.errors(`${this.name}.generateImages fatal`, {
83
+ error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
84
+ source: `${this.name}.generateImages`
85
+ });
86
+ throw error;
87
+ }
88
+ }
89
+ async editImages(args) {
90
+ const { model, prompt, numberOfImages, size, modelOptions, logger, abortSignal } = args;
91
+ const maskParts = args.imageInputs.filter((part) => part.metadata?.role === "mask");
92
+ const sourceParts = args.imageInputs.filter((part) => part.metadata?.role !== "mask");
93
+ if (maskParts.length > 0 && !supportsImageMask(model)) throw new Error(`${this.name}: model "${model}" does not support mask image parts. Use an openai/ image model for masked edits.`);
94
+ if (maskParts.length > 1) throw new Error(`${this.name}: only one input with metadata.role === 'mask' is supported per request.`);
95
+ if (sourceParts.length === 0) throw new Error(`${this.name}: the prompt contained only mask image parts; at least one source image is required.`);
96
+ if (sourceParts.length > MAX_EDIT_IMAGES) throw new Error(`${this.name}: model "${model}" accepts at most ${MAX_EDIT_IMAGES} source image(s); received ${sourceParts.length}.`);
97
+ const sourceFiles = await Promise.all(sourceParts.map((part, i) => imagePartToFile(part, `source-${i}`, this.allowUrlFetch, abortSignal)));
98
+ const [firstSourceFile] = sourceFiles;
99
+ const maskFile = maskParts[0] ? await imagePartToFile(maskParts[0], "mask", this.allowUrlFetch, abortSignal) : void 0;
100
+ const request = {
101
+ model,
102
+ prompt,
103
+ image: firstSourceFile && sourceFiles.length === 1 ? firstSourceFile : sourceFiles,
104
+ n: numberOfImages ?? 1,
105
+ stream: false,
106
+ ...modelOptions ?? {}
107
+ };
108
+ if (size !== void 0) request.size = size;
109
+ if (maskFile) request.mask = maskFile;
110
+ try {
111
+ logger.request(`activity=imageEdit provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? "default"} sources=${sourceFiles.length}${maskFile ? " mask" : ""}`, {
112
+ provider: this.name,
113
+ model
114
+ });
115
+ const response = await this.client.images.edit(request, openaiRequestOptions(abortSignal));
116
+ const images = generatedImagesFromResponse(response.data, `${this.name}: image edit response contained no images`);
117
+ const usage = buildImagesUsage(response.usage);
118
+ return {
119
+ id: generateId(this.name),
120
+ model,
121
+ images,
122
+ ...usage ? { usage } : {}
123
+ };
124
+ } catch (error) {
125
+ logger.errors(`${this.name}.editImages fatal`, {
126
+ error: toRunErrorPayload(error, `${this.name}.editImages failed`),
127
+ source: `${this.name}.editImages`
128
+ });
129
+ throw error;
130
+ }
131
+ }
132
+ };
133
+ function createLovableImage(model, apiKey, config) {
134
+ return new LovableImageAdapter({
135
+ apiKey,
136
+ ...config
137
+ }, model);
138
+ }
139
+ function lovableImage(model, config) {
140
+ return createLovableImage(model, getLovableApiKeyFromEnv(), config);
141
+ }
142
+ //#endregion
143
+ export { LovableImageAdapter, createLovableImage, lovableImage };
144
+
145
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.js","names":[],"sources":["../../../src/adapters/image.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { resolveMediaPrompt } from '@tanstack/ai'\nimport { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { buildImagesUsage } from '@tanstack/openai-base'\nimport { generateId } from '@tanstack/ai-utils'\nimport {\n getLovableApiKeyFromEnv,\n openaiRequestOptions,\n withLovableDefaults,\n} from '../utils/client'\nimport { imagePartToFile } from '../image/image-input-to-file'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n ImagePart,\n MediaInputMetadata,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type {\n LovableImageModel,\n LovableImageModelInputModalitiesByName,\n LovableImageModelProviderOptionsByName,\n LovableImageModelSizeByName,\n} from '../model-meta'\nimport type { LovableImageProviderOptions } from '../image/image-provider-options'\nimport type { LovableClientConfig } from '../utils/client'\n\nconst MAX_EDIT_IMAGES = 16\n\nexport interface LovableImageConfig extends LovableClientConfig {\n /**\n * Opt into fetching HTTP(S) image URL inputs for image edits. The gateway\n * `/images/edits` endpoint requires uploaded file bytes, so an HTTP(S) URL\n * has to be downloaded and buffered in memory. When `false` (the default),\n * HTTP(S) URL image inputs throw.\n */\n allowUrlFetch?: boolean\n}\n\nfunction supportsImageMask(model: string): boolean {\n return model.startsWith('openai/')\n}\n\nfunction generatedImagesFromResponse(\n data:\n | Array<{\n b64_json?: string | null\n url?: string | null\n revised_prompt?: string | null\n }>\n | undefined\n | null,\n emptyMessage: string,\n): Array<GeneratedImage> {\n const images: Array<GeneratedImage> = (data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n const revisedPromptField =\n item.revised_prompt !== undefined && item.revised_prompt !== null\n ? { revisedPrompt: item.revised_prompt }\n : {}\n if (item.b64_json) {\n return [{ b64Json: item.b64_json, ...revisedPromptField }]\n }\n if (item.url) {\n return [{ url: item.url, ...revisedPromptField }]\n }\n return []\n },\n )\n\n if (images.length === 0) {\n throw new Error(emptyMessage)\n }\n\n return images\n}\n\nexport class LovableImageAdapter<\n TModel extends LovableImageModel,\n> extends BaseImageAdapter<\n TModel,\n LovableImageProviderOptions,\n LovableImageModelProviderOptionsByName,\n LovableImageModelSizeByName,\n LovableImageModelInputModalitiesByName\n> {\n override readonly kind = 'image' as const\n readonly name = 'lovable' as const\n\n protected client: OpenAI\n private readonly allowUrlFetch: boolean\n\n constructor(config: LovableImageConfig, model: TModel) {\n super(model, {})\n const { allowUrlFetch, ...clientOptions } = config\n this.client = new OpenAI(withLovableDefaults(clientOptions))\n this.allowUrlFetch = allowUrlFetch ?? false\n }\n\n async generateImages(\n options: ImageGenerationOptions<LovableImageProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions } = options\n const resolved = resolveMediaPrompt(options.prompt)\n const prompt = resolved.text\n\n if (resolved.videos.length > 0) {\n throw new Error(\n `${this.name}.generateImages does not support video prompt parts (model: ${model}).`,\n )\n }\n if (resolved.audios.length > 0) {\n throw new Error(\n `${this.name}.generateImages does not support audio prompt parts (model: ${model}).`,\n )\n }\n\n if (resolved.images.length > 0) {\n return this.editImages({\n model,\n prompt,\n numberOfImages,\n size,\n modelOptions,\n imageInputs: resolved.images,\n logger: options.logger,\n abortSignal: options.abortSignal,\n })\n }\n\n const request: OpenAI_SDK.Images.ImageGenerateParams = {\n model,\n prompt,\n n: numberOfImages ?? 1,\n ...(modelOptions ?? {}),\n }\n if (size !== undefined) {\n request.size = size\n }\n\n try {\n options.logger.request(\n `activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,\n { provider: this.name, model },\n )\n const response = await this.client.images.generate(\n {\n ...request,\n stream: false,\n },\n openaiRequestOptions(options.abortSignal),\n )\n\n const images = generatedImagesFromResponse(\n response.data,\n `${this.name}: image response contained no images`,\n )\n const usage = buildImagesUsage(response.usage)\n\n return {\n id: generateId(this.name),\n model,\n images,\n ...(usage ? { usage } : {}),\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n\n private async editImages(args: {\n model: string\n prompt: string\n numberOfImages?: number\n size?: string\n modelOptions?: LovableImageProviderOptions\n imageInputs: ReadonlyArray<ImagePart<MediaInputMetadata>>\n logger: ImageGenerationOptions<LovableImageProviderOptions>['logger']\n abortSignal?: AbortSignal\n }): Promise<ImageGenerationResult> {\n const {\n model,\n prompt,\n numberOfImages,\n size,\n modelOptions,\n logger,\n abortSignal,\n } = args\n\n const maskParts = args.imageInputs.filter(\n (part) => part.metadata?.role === 'mask',\n )\n const sourceParts = args.imageInputs.filter(\n (part) => part.metadata?.role !== 'mask',\n )\n\n if (maskParts.length > 0 && !supportsImageMask(model)) {\n throw new Error(\n `${this.name}: model \"${model}\" does not support mask image parts. Use an openai/ image model for masked edits.`,\n )\n }\n if (maskParts.length > 1) {\n throw new Error(\n `${this.name}: only one input with metadata.role === 'mask' is supported per request.`,\n )\n }\n if (sourceParts.length === 0) {\n throw new Error(\n `${this.name}: the prompt contained only mask image parts; at least one source image is required.`,\n )\n }\n if (sourceParts.length > MAX_EDIT_IMAGES) {\n throw new Error(\n `${this.name}: model \"${model}\" accepts at most ${MAX_EDIT_IMAGES} source image(s); received ${sourceParts.length}.`,\n )\n }\n\n const sourceFiles = await Promise.all(\n sourceParts.map((part, i) =>\n imagePartToFile(part, `source-${i}`, this.allowUrlFetch, abortSignal),\n ),\n )\n const [firstSourceFile] = sourceFiles\n const maskFile = maskParts[0]\n ? await imagePartToFile(\n maskParts[0],\n 'mask',\n this.allowUrlFetch,\n abortSignal,\n )\n : undefined\n\n const request: OpenAI_SDK.Images.ImageEditParamsNonStreaming = {\n model,\n prompt,\n image:\n firstSourceFile && sourceFiles.length === 1\n ? firstSourceFile\n : sourceFiles,\n n: numberOfImages ?? 1,\n stream: false,\n ...((modelOptions ??\n {}) as Partial<OpenAI_SDK.Images.ImageEditParamsNonStreaming>),\n }\n if (size !== undefined) {\n request.size = size\n }\n if (maskFile) {\n request.mask = maskFile\n }\n\n try {\n logger.request(\n `activity=imageEdit provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'} sources=${sourceFiles.length}${maskFile ? ' mask' : ''}`,\n { provider: this.name, model },\n )\n const response = await this.client.images.edit(\n request,\n openaiRequestOptions(abortSignal),\n )\n\n const images = generatedImagesFromResponse(\n response.data,\n `${this.name}: image edit response contained no images`,\n )\n const usage = buildImagesUsage(response.usage)\n\n return {\n id: generateId(this.name),\n model,\n images,\n ...(usage ? { usage } : {}),\n }\n } catch (error: unknown) {\n logger.errors(`${this.name}.editImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.editImages failed`),\n source: `${this.name}.editImages`,\n })\n throw error\n }\n }\n}\n\nexport function createLovableImage<TModel extends LovableImageModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<LovableImageConfig, 'apiKey'>,\n): LovableImageAdapter<TModel> {\n return new LovableImageAdapter({ apiKey, ...config }, model)\n}\n\nexport function lovableImage<TModel extends LovableImageModel>(\n model: TModel,\n config?: Omit<LovableImageConfig, 'apiKey'>,\n): LovableImageAdapter<TModel> {\n return createLovableImage(model, getLovableApiKeyFromEnv(), config)\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { OpenAIBaseResponsesTextAdapter } from '@tanstack/openai-base';
2
+ import { Modality } from '@tanstack/ai';
3
+ import { LovableChatModelToolCapabilitiesByName, LovableModelId, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
4
+ import { LovableMessageMetadataByModality } from '../message-types.js';
5
+ import { ExternalResponsesProviderOptions } from '../text/responses-provider-options.js';
6
+ import { LovableClientConfig } from '../utils/client.js';
7
+ export interface LovableResponsesTextConfig extends LovableClientConfig {
8
+ }
9
+ export type LovableResponsesTextProviderOptions = ExternalResponsesProviderOptions;
10
+ type ResolveToolCapabilities<TModel extends string> = TModel extends keyof LovableChatModelToolCapabilitiesByName ? NonNullable<LovableChatModelToolCapabilitiesByName[TModel]> : readonly [];
11
+ /**
12
+ * Lovable AI Gateway Responses text adapter.
13
+ *
14
+ * Talks to the OpenAI-compatible Responses API at
15
+ * `https://ai.gateway.lovable.dev/v1`.
16
+ */
17
+ export declare class LovableResponsesTextAdapter<TModel extends LovableModelId, TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends OpenAIBaseResponsesTextAdapter<TModel, TProviderOptions, TInputModalities, LovableMessageMetadataByModality, TToolCapabilities> {
18
+ readonly kind: "text";
19
+ readonly name: "lovable";
20
+ constructor(config: LovableResponsesTextConfig, model: TModel);
21
+ }
22
+ export declare function createLovableResponsesText<TModel extends LovableModelId>(model: TModel, apiKey: string, config?: Omit<LovableResponsesTextConfig, 'apiKey'>): LovableResponsesTextAdapter<TModel>;
23
+ export declare function lovableResponsesText<TModel extends LovableModelId>(model: TModel, config?: Omit<LovableResponsesTextConfig, 'apiKey'>): LovableResponsesTextAdapter<TModel>;
24
+ export {};
@@ -0,0 +1,30 @@
1
+ import { getLovableApiKeyFromEnv, withLovableDefaults } from "../utils/client.js";
2
+ import OpenAI from "openai";
3
+ import { OpenAIBaseResponsesTextAdapter } from "@tanstack/openai-base";
4
+ //#region src/adapters/responses-text.ts
5
+ /**
6
+ * Lovable AI Gateway Responses text adapter.
7
+ *
8
+ * Talks to the OpenAI-compatible Responses API at
9
+ * `https://ai.gateway.lovable.dev/v1`.
10
+ */
11
+ var LovableResponsesTextAdapter = class extends OpenAIBaseResponsesTextAdapter {
12
+ kind = "text";
13
+ name = "lovable";
14
+ constructor(config, model) {
15
+ super(model, "lovable", new OpenAI(withLovableDefaults(config)));
16
+ }
17
+ };
18
+ function createLovableResponsesText(model, apiKey, config) {
19
+ return new LovableResponsesTextAdapter({
20
+ apiKey,
21
+ ...config
22
+ }, model);
23
+ }
24
+ function lovableResponsesText(model, config) {
25
+ return createLovableResponsesText(model, getLovableApiKeyFromEnv(), config);
26
+ }
27
+ //#endregion
28
+ export { LovableResponsesTextAdapter, createLovableResponsesText, lovableResponsesText };
29
+
30
+ //# sourceMappingURL=responses-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responses-text.js","names":[],"sources":["../../../src/adapters/responses-text.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { OpenAIBaseResponsesTextAdapter } from '@tanstack/openai-base'\nimport { getLovableApiKeyFromEnv, withLovableDefaults } from '../utils/client'\nimport type { Modality } from '@tanstack/ai'\nimport type {\n LovableChatModelToolCapabilitiesByName,\n LovableModelId,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type { LovableMessageMetadataByModality } from '../message-types'\nimport type { ExternalResponsesProviderOptions } from '../text/responses-provider-options'\nimport type { LovableClientConfig } from '../utils/client'\n\nexport interface LovableResponsesTextConfig extends LovableClientConfig {}\n\nexport type LovableResponsesTextProviderOptions =\n ExternalResponsesProviderOptions\n\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof LovableChatModelToolCapabilitiesByName\n ? NonNullable<LovableChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\n/**\n * Lovable AI Gateway Responses text adapter.\n *\n * Talks to the OpenAI-compatible Responses API at\n * `https://ai.gateway.lovable.dev/v1`.\n */\nexport class LovableResponsesTextAdapter<\n TModel extends LovableModelId,\n TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n TToolCapabilities extends ReadonlyArray<string> =\n ResolveToolCapabilities<TModel>,\n> extends OpenAIBaseResponsesTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n LovableMessageMetadataByModality,\n TToolCapabilities\n> {\n override readonly kind = 'text' as const\n override readonly name = 'lovable' as const\n\n constructor(config: LovableResponsesTextConfig, model: TModel) {\n super(model, 'lovable', new OpenAI(withLovableDefaults(config)))\n }\n}\n\nexport function createLovableResponsesText<TModel extends LovableModelId>(\n model: TModel,\n apiKey: string,\n config?: Omit<LovableResponsesTextConfig, 'apiKey'>,\n): LovableResponsesTextAdapter<TModel> {\n return new LovableResponsesTextAdapter({ apiKey, ...config }, model)\n}\n\nexport function lovableResponsesText<TModel extends LovableModelId>(\n model: TModel,\n config?: Omit<LovableResponsesTextConfig, 'apiKey'>,\n): LovableResponsesTextAdapter<TModel> {\n return createLovableResponsesText(model, getLovableApiKeyFromEnv(), config)\n}\n"],"mappings":";;;;;;;;;;AA8BA,IAAa,8BAAb,cAOU,+BAMR;CACA,OAAyB;CACzB,OAAyB;CAEzB,YAAY,QAAoC,OAAe;EAC7D,MAAM,OAAO,WAAW,IAAI,OAAO,oBAAoB,MAAM,CAAC,CAAC;CACjE;AACF;AAEA,SAAgB,2BACd,OACA,QACA,QACqC;CACrC,OAAO,IAAI,4BAA4B;EAAE;EAAQ,GAAG;CAAO,GAAG,KAAK;AACrE;AAEA,SAAgB,qBACd,OACA,QACqC;CACrC,OAAO,2BAA2B,OAAO,wBAAwB,GAAG,MAAM;AAC5E"}
@@ -0,0 +1,9 @@
1
+ import { ChatStreamSummarizeAdapter, InferTextProviderOptions } from '@tanstack/ai/adapters';
2
+ import { LovableTextAdapter } from './text.js';
3
+ import { LovableModelId } from '../model-meta.js';
4
+ import { LovableClientConfig } from '../utils/client.js';
5
+ export interface LovableSummarizeConfig extends LovableClientConfig {
6
+ }
7
+ export type LovableSummarizeModel = LovableModelId;
8
+ export declare function createLovableSummarize<TModel extends LovableSummarizeModel>(model: TModel, apiKey: string, config?: Omit<LovableSummarizeConfig, 'apiKey'>): ChatStreamSummarizeAdapter<TModel, InferTextProviderOptions<LovableTextAdapter<TModel>>>;
9
+ export declare function lovableSummarize<TModel extends LovableSummarizeModel>(model: TModel, config?: Omit<LovableSummarizeConfig, 'apiKey'>): ChatStreamSummarizeAdapter<TModel, InferTextProviderOptions<LovableTextAdapter<TModel>>>;
@@ -0,0 +1,17 @@
1
+ import { getLovableApiKeyFromEnv } from "../utils/client.js";
2
+ import { LovableTextAdapter } from "./text.js";
3
+ import { ChatStreamSummarizeAdapter } from "@tanstack/ai/adapters";
4
+ //#region src/adapters/summarize.ts
5
+ function createLovableSummarize(model, apiKey, config) {
6
+ return new ChatStreamSummarizeAdapter(new LovableTextAdapter({
7
+ apiKey,
8
+ ...config
9
+ }, model), model, "lovable");
10
+ }
11
+ function lovableSummarize(model, config) {
12
+ return createLovableSummarize(model, getLovableApiKeyFromEnv(), config);
13
+ }
14
+ //#endregion
15
+ export { createLovableSummarize, lovableSummarize };
16
+
17
+ //# sourceMappingURL=summarize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarize.js","names":[],"sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { getLovableApiKeyFromEnv } from '../utils/client'\nimport { LovableTextAdapter } from './text'\nimport type { InferTextProviderOptions } from '@tanstack/ai/adapters'\nimport type { LovableModelId } from '../model-meta'\nimport type { LovableClientConfig } from '../utils/client'\n\nexport interface LovableSummarizeConfig extends LovableClientConfig {}\n\nexport type LovableSummarizeModel = LovableModelId\n\nexport function createLovableSummarize<TModel extends LovableSummarizeModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<LovableSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<LovableTextAdapter<TModel>>\n> {\n return new ChatStreamSummarizeAdapter(\n new LovableTextAdapter({ apiKey, ...config }, model),\n model,\n 'lovable',\n )\n}\n\nexport function lovableSummarize<TModel extends LovableSummarizeModel>(\n model: TModel,\n config?: Omit<LovableSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<LovableTextAdapter<TModel>>\n> {\n return createLovableSummarize(model, getLovableApiKeyFromEnv(), config)\n}\n"],"mappings":";;;;AAWA,SAAgB,uBACd,OACA,QACA,QAIA;CACA,OAAO,IAAI,2BACT,IAAI,mBAAmB;EAAE;EAAQ,GAAG;CAAO,GAAG,KAAK,GACnD,OACA,SACF;AACF;AAEA,SAAgB,iBACd,OACA,QAIA;CACA,OAAO,uBAAuB,OAAO,wBAAwB,GAAG,MAAM;AACxE"}
@@ -0,0 +1,20 @@
1
+ import { OpenAIBaseChatCompletionsTextAdapter } from '@tanstack/openai-base';
2
+ import { Modality } from '@tanstack/ai';
3
+ import { LovableChatModelToolCapabilitiesByName, LovableModelId, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
4
+ import { LovableMessageMetadataByModality } from '../message-types.js';
5
+ import { LovableClientConfig } from '../utils/client.js';
6
+ type ResolveToolCapabilities<TModel extends string> = TModel extends keyof LovableChatModelToolCapabilitiesByName ? NonNullable<LovableChatModelToolCapabilitiesByName[TModel]> : readonly [];
7
+ export interface LovableTextConfig extends LovableClientConfig {
8
+ }
9
+ export type { ExternalTextProviderOptions as LovableTextProviderOptions } from '../text/text-provider-options.js';
10
+ /**
11
+ * Lovable AI Gateway text adapter.
12
+ *
13
+ * Talks to the OpenAI-compatible Chat Completions API at
14
+ * `https://ai.gateway.lovable.dev/v1`.
15
+ */
16
+ export declare class LovableTextAdapter<TModel extends LovableModelId, TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends OpenAIBaseChatCompletionsTextAdapter<TModel, TProviderOptions, TInputModalities, LovableMessageMetadataByModality, TToolCapabilities> {
17
+ readonly kind: "text";
18
+ readonly name: "lovable";
19
+ constructor(config: LovableTextConfig, model: TModel);
20
+ }
@@ -0,0 +1,21 @@
1
+ import { withLovableDefaults } from "../utils/client.js";
2
+ import OpenAI from "openai";
3
+ import { OpenAIBaseChatCompletionsTextAdapter } from "@tanstack/openai-base";
4
+ //#region src/adapters/text.ts
5
+ /**
6
+ * Lovable AI Gateway text adapter.
7
+ *
8
+ * Talks to the OpenAI-compatible Chat Completions API at
9
+ * `https://ai.gateway.lovable.dev/v1`.
10
+ */
11
+ var LovableTextAdapter = class extends OpenAIBaseChatCompletionsTextAdapter {
12
+ kind = "text";
13
+ name = "lovable";
14
+ constructor(config, model) {
15
+ super(model, "lovable", new OpenAI(withLovableDefaults(config)));
16
+ }
17
+ };
18
+ //#endregion
19
+ export { LovableTextAdapter };
20
+
21
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","names":[],"sources":["../../../src/adapters/text.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { OpenAIBaseChatCompletionsTextAdapter } from '@tanstack/openai-base'\nimport { withLovableDefaults } from '../utils/client'\nimport type { Modality } from '@tanstack/ai'\nimport type {\n LovableChatModelToolCapabilitiesByName,\n LovableModelId,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type { LovableMessageMetadataByModality } from '../message-types'\nimport type { LovableClientConfig } from '../utils/client'\n\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof LovableChatModelToolCapabilitiesByName\n ? NonNullable<LovableChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\nexport interface LovableTextConfig extends LovableClientConfig {}\n\nexport type { ExternalTextProviderOptions as LovableTextProviderOptions } from '../text/text-provider-options'\n\n/**\n * Lovable AI Gateway text adapter.\n *\n * Talks to the OpenAI-compatible Chat Completions API at\n * `https://ai.gateway.lovable.dev/v1`.\n */\nexport class LovableTextAdapter<\n TModel extends LovableModelId,\n TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n TToolCapabilities extends ReadonlyArray<string> =\n ResolveToolCapabilities<TModel>,\n> extends OpenAIBaseChatCompletionsTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n LovableMessageMetadataByModality,\n TToolCapabilities\n> {\n override readonly kind = 'text' as const\n override readonly name = 'lovable' as const\n\n constructor(config: LovableTextConfig, model: TModel) {\n super(model, 'lovable', new OpenAI(withLovableDefaults(config)))\n }\n}\n"],"mappings":";;;;;;;;;;AA4BA,IAAa,qBAAb,cAOU,qCAMR;CACA,OAAyB;CACzB,OAAyB;CAEzB,YAAY,QAA2B,OAAe;EACpD,MAAM,OAAO,WAAW,IAAI,OAAO,oBAAoB,MAAM,CAAC,CAAC;CACjE;AACF"}
@@ -0,0 +1,19 @@
1
+ import { default as OpenAI } from 'openai';
2
+ import { BaseTranscriptionAdapter } from '@tanstack/ai/adapters';
3
+ import { TranscriptionOptions, TranscriptionResult } from '@tanstack/ai';
4
+ import { LovableTranscriptionModel } from '../model-meta.js';
5
+ import { LovableTranscriptionProviderOptions } from '../audio/transcription-provider-options.js';
6
+ import { LovableClientConfig } from '../utils/client.js';
7
+ export interface LovableTranscriptionConfig extends LovableClientConfig {
8
+ }
9
+ export declare class LovableTranscriptionAdapter<TModel extends LovableTranscriptionModel> extends BaseTranscriptionAdapter<TModel, LovableTranscriptionProviderOptions> {
10
+ readonly name: "lovable";
11
+ protected client: OpenAI;
12
+ constructor(config: LovableTranscriptionConfig, model: TModel);
13
+ transcribe(options: TranscriptionOptions<LovableTranscriptionProviderOptions>): Promise<TranscriptionResult>;
14
+ private buildTranscriptionRequest;
15
+ protected prepareAudioFile(audio: string | File | Blob | ArrayBuffer): File;
16
+ private ensureFileSupport;
17
+ }
18
+ export declare function createLovableTranscription<TModel extends LovableTranscriptionModel>(model: TModel, apiKey: string, config?: Omit<LovableTranscriptionConfig, 'apiKey'>): LovableTranscriptionAdapter<TModel>;
19
+ export declare function lovableTranscription<TModel extends LovableTranscriptionModel>(model: TModel, config?: Omit<LovableTranscriptionConfig, 'apiKey'>): LovableTranscriptionAdapter<TModel>;