@node-llm/core 0.2.2 → 0.4.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 (127) hide show
  1. package/README.md +288 -16
  2. package/dist/chat/Chat.d.ts +58 -17
  3. package/dist/chat/Chat.d.ts.map +1 -1
  4. package/dist/chat/Chat.js +185 -33
  5. package/dist/chat/ChatOptions.d.ts +10 -0
  6. package/dist/chat/ChatOptions.d.ts.map +1 -1
  7. package/dist/chat/ChatResponse.d.ts +23 -0
  8. package/dist/chat/ChatResponse.d.ts.map +1 -0
  9. package/dist/chat/ChatResponse.js +38 -0
  10. package/dist/chat/Stream.d.ts.map +1 -1
  11. package/dist/chat/Stream.js +10 -0
  12. package/dist/constants.d.ts +7 -0
  13. package/dist/constants.d.ts.map +1 -0
  14. package/dist/constants.js +6 -0
  15. package/dist/embedding/Embedding.d.ts +17 -0
  16. package/dist/embedding/Embedding.d.ts.map +1 -0
  17. package/dist/embedding/Embedding.js +24 -0
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/llm.d.ts +35 -3
  22. package/dist/llm.d.ts.map +1 -1
  23. package/dist/llm.js +88 -14
  24. package/dist/models/ModelRegistry.d.ts +23 -0
  25. package/dist/models/ModelRegistry.d.ts.map +1 -0
  26. package/dist/models/ModelRegistry.js +54 -0
  27. package/dist/moderation/Moderation.d.ts +56 -0
  28. package/dist/moderation/Moderation.d.ts.map +1 -0
  29. package/dist/moderation/Moderation.js +92 -0
  30. package/dist/providers/Embedding.d.ts +20 -0
  31. package/dist/providers/Embedding.d.ts.map +1 -0
  32. package/dist/providers/Provider.d.ts +50 -4
  33. package/dist/providers/Provider.d.ts.map +1 -1
  34. package/dist/providers/gemini/Capabilities.d.ts +30 -0
  35. package/dist/providers/gemini/Capabilities.d.ts.map +1 -0
  36. package/dist/providers/gemini/Capabilities.js +148 -0
  37. package/dist/providers/gemini/Chat.d.ts +8 -0
  38. package/dist/providers/gemini/Chat.d.ts.map +1 -0
  39. package/dist/providers/gemini/Chat.js +69 -0
  40. package/dist/providers/gemini/ChatUtils.d.ts +9 -0
  41. package/dist/providers/gemini/ChatUtils.d.ts.map +1 -0
  42. package/dist/providers/gemini/ChatUtils.js +83 -0
  43. package/dist/providers/gemini/Embeddings.d.ts +8 -0
  44. package/dist/providers/gemini/Embeddings.d.ts.map +1 -0
  45. package/dist/providers/gemini/Embeddings.js +44 -0
  46. package/dist/providers/gemini/Errors.d.ts +2 -0
  47. package/dist/providers/gemini/Errors.d.ts.map +1 -0
  48. package/dist/providers/gemini/Errors.js +34 -0
  49. package/dist/providers/gemini/GeminiProvider.d.ts +34 -0
  50. package/dist/providers/gemini/GeminiProvider.d.ts.map +1 -0
  51. package/dist/providers/gemini/GeminiProvider.js +55 -0
  52. package/dist/providers/gemini/Image.d.ts +8 -0
  53. package/dist/providers/gemini/Image.d.ts.map +1 -0
  54. package/dist/providers/gemini/Image.js +47 -0
  55. package/dist/providers/gemini/Models.d.ts +8 -0
  56. package/dist/providers/gemini/Models.d.ts.map +1 -0
  57. package/dist/providers/gemini/Models.js +38 -0
  58. package/dist/providers/gemini/Streaming.d.ts +8 -0
  59. package/dist/providers/gemini/Streaming.d.ts.map +1 -0
  60. package/dist/providers/gemini/Streaming.js +70 -0
  61. package/dist/providers/gemini/Transcription.d.ts +9 -0
  62. package/dist/providers/gemini/Transcription.d.ts.map +1 -0
  63. package/dist/providers/gemini/Transcription.js +63 -0
  64. package/dist/providers/gemini/index.d.ts +11 -0
  65. package/dist/providers/gemini/index.d.ts.map +1 -0
  66. package/dist/providers/gemini/index.js +24 -0
  67. package/dist/providers/gemini/types.d.ts +118 -0
  68. package/dist/providers/gemini/types.d.ts.map +1 -0
  69. package/dist/providers/gemini/types.js +1 -0
  70. package/dist/providers/openai/Capabilities.d.ts +7 -2
  71. package/dist/providers/openai/Capabilities.d.ts.map +1 -1
  72. package/dist/providers/openai/Capabilities.js +52 -214
  73. package/dist/providers/openai/Chat.d.ts.map +1 -1
  74. package/dist/providers/openai/Chat.js +4 -0
  75. package/dist/providers/openai/Embedding.d.ts +8 -0
  76. package/dist/providers/openai/Embedding.d.ts.map +1 -0
  77. package/dist/providers/openai/Embedding.js +48 -0
  78. package/dist/providers/openai/ModelDefinitions.d.ts +25 -0
  79. package/dist/providers/openai/ModelDefinitions.d.ts.map +1 -0
  80. package/dist/providers/openai/ModelDefinitions.js +211 -0
  81. package/dist/providers/openai/Moderation.d.ts +8 -0
  82. package/dist/providers/openai/Moderation.d.ts.map +1 -0
  83. package/dist/providers/openai/Moderation.js +27 -0
  84. package/dist/providers/openai/OpenAIProvider.d.ts +13 -1
  85. package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -1
  86. package/dist/providers/openai/OpenAIProvider.js +22 -0
  87. package/dist/providers/openai/Streaming.d.ts.map +1 -1
  88. package/dist/providers/openai/Streaming.js +19 -8
  89. package/dist/providers/openai/Transcription.d.ts +10 -0
  90. package/dist/providers/openai/Transcription.d.ts.map +1 -0
  91. package/dist/providers/openai/Transcription.js +162 -0
  92. package/dist/providers/openai/index.d.ts +8 -0
  93. package/dist/providers/openai/index.d.ts.map +1 -1
  94. package/dist/providers/openai/index.js +12 -0
  95. package/dist/schema/Schema.d.ts +20 -0
  96. package/dist/schema/Schema.d.ts.map +1 -0
  97. package/dist/schema/Schema.js +22 -0
  98. package/dist/schema/to-json-schema.d.ts +3 -0
  99. package/dist/schema/to-json-schema.d.ts.map +1 -0
  100. package/dist/schema/to-json-schema.js +10 -0
  101. package/dist/transcription/Transcription.d.ts +11 -0
  102. package/dist/transcription/Transcription.d.ts.map +1 -0
  103. package/dist/transcription/Transcription.js +21 -0
  104. package/dist/utils/Binary.d.ts +12 -0
  105. package/dist/utils/Binary.d.ts.map +1 -0
  106. package/dist/utils/Binary.js +71 -0
  107. package/dist/utils/FileLoader.d.ts.map +1 -1
  108. package/dist/utils/FileLoader.js +12 -1
  109. package/dist/utils/audio.d.ts +10 -0
  110. package/dist/utils/audio.d.ts.map +1 -0
  111. package/dist/utils/audio.js +46 -0
  112. package/package.json +18 -7
  113. package/dist/providers/openai/register.d.ts +0 -2
  114. package/dist/providers/openai/register.d.ts.map +0 -1
  115. package/dist/providers/openai/register.js +0 -15
  116. package/dist/tools/Tool.d.ts +0 -8
  117. package/dist/tools/Tool.d.ts.map +0 -1
  118. package/dist/tools/ToolSet.d.ts +0 -15
  119. package/dist/tools/ToolSet.d.ts.map +0 -1
  120. package/dist/tools/ToolSet.js +0 -29
  121. package/dist/tools/index.d.ts +0 -2
  122. package/dist/tools/index.d.ts.map +0 -1
  123. package/dist/tools/index.js +0 -1
  124. package/dist/tools/runCommandTool.d.ts +0 -8
  125. package/dist/tools/runCommandTool.d.ts.map +0 -1
  126. package/dist/tools/runCommandTool.js +0 -19
  127. /package/dist/{tools/Tool.js → providers/Embedding.js} +0 -0
@@ -0,0 +1,148 @@
1
+ export class Capabilities {
2
+ static getContextWindow(modelId) {
3
+ const id = this.normalizeModelId(modelId);
4
+ if (id.match(/gemini-2\.5-pro-exp-03-25|gemini-2\.0-flash|gemini-2\.0-flash-lite|gemini-1\.5-flash|gemini-1\.5-flash-8b/)) {
5
+ return 1_048_576;
6
+ }
7
+ if (id.match(/gemini-1\.5-pro/)) {
8
+ return 2_097_152;
9
+ }
10
+ if (id.match(/gemini-embedding-exp/)) {
11
+ return 8_192;
12
+ }
13
+ if (id.match(/text-embedding-004|embedding-001/)) {
14
+ return 2_048;
15
+ }
16
+ if (id.match(/aqa/)) {
17
+ return 7_168;
18
+ }
19
+ return 32_768;
20
+ }
21
+ static getMaxOutputTokens(modelId) {
22
+ const id = this.normalizeModelId(modelId);
23
+ if (id.match(/gemini-2\.5-pro-exp-03-25/)) {
24
+ return 64_000;
25
+ }
26
+ if (id.match(/gemini-2\.0-flash|gemini-2\.0-flash-lite|gemini-1\.5-flash|gemini-1\.5-flash-8b|gemini-1\.5-pro/)) {
27
+ return 8_192;
28
+ }
29
+ if (id.match(/text-embedding-004|embedding-001/)) {
30
+ return 768;
31
+ }
32
+ if (id.match(/imagen-3/)) {
33
+ return 4;
34
+ }
35
+ return 4_096;
36
+ }
37
+ static supportsVision(modelId) {
38
+ const id = this.normalizeModelId(modelId);
39
+ if (id.match(/text-embedding|embedding-001|aqa/)) {
40
+ return false;
41
+ }
42
+ return !!id.match(/gemini|flash|pro|imagen/);
43
+ }
44
+ static supportsTools(modelId) {
45
+ const id = this.normalizeModelId(modelId);
46
+ if (id.match(/text-embedding|embedding-001|aqa|flash-lite|imagen|gemini-2\.0-flash-lite/)) {
47
+ return false;
48
+ }
49
+ return !!id.match(/gemini|pro|flash/);
50
+ }
51
+ static supportsStructuredOutput(modelId) {
52
+ // Explicitly disabled until implementation is validated
53
+ return false;
54
+ }
55
+ static supportsJsonMode(modelId) {
56
+ return this.supportsStructuredOutput(modelId);
57
+ }
58
+ static supportsEmbeddings(modelId) {
59
+ const id = this.normalizeModelId(modelId);
60
+ return !!id.match(/text-embedding|embedding|gemini-embedding/);
61
+ }
62
+ static supportsImageGeneration(modelId) {
63
+ const id = this.normalizeModelId(modelId);
64
+ return !!id.match(/imagen/);
65
+ }
66
+ static supportsTranscription(modelId) {
67
+ const id = this.normalizeModelId(modelId);
68
+ return !!id.match(/gemini|flash|pro/);
69
+ }
70
+ static supportsModeration(modelId) {
71
+ return false;
72
+ }
73
+ static normalizeTemperature(temperature, _modelId) {
74
+ return temperature;
75
+ }
76
+ static getFamily(modelId) {
77
+ const id = this.normalizeModelId(modelId);
78
+ if (id.startsWith("gemini-1.5-pro"))
79
+ return "gemini-1.5-pro";
80
+ if (id.startsWith("gemini-1.5-flash"))
81
+ return "gemini-1.5-flash";
82
+ if (id.startsWith("gemini-2.0-flash"))
83
+ return "gemini-2.0-flash";
84
+ if (id.startsWith("gemini-2.0-flash-lite"))
85
+ return "gemini-2.0-flash-lite";
86
+ if (id.startsWith("text-embedding"))
87
+ return "text-embedding";
88
+ if (id.startsWith("imagen"))
89
+ return "imagen";
90
+ return "other";
91
+ }
92
+ static getModalities(modelId) {
93
+ const input = ["text"];
94
+ const output = ["text"];
95
+ const id = this.normalizeModelId(modelId);
96
+ if (this.supportsVision(id))
97
+ input.push("image", "video", "audio", "pdf");
98
+ if (this.supportsImageGeneration(id))
99
+ output.push("image");
100
+ if (this.supportsEmbeddings(id))
101
+ output.push("embeddings");
102
+ return { input, output };
103
+ }
104
+ static getCapabilities(modelId) {
105
+ const caps = ["streaming"];
106
+ const id = this.normalizeModelId(modelId);
107
+ if (this.supportsTools(id))
108
+ caps.push("function_calling");
109
+ if (this.supportsStructuredOutput(id))
110
+ caps.push("structured_output");
111
+ if (this.supportsEmbeddings(id))
112
+ caps.push("embeddings");
113
+ if (this.supportsImageGeneration(id))
114
+ caps.push("image_generation");
115
+ return caps;
116
+ }
117
+ static getPricing(modelId) {
118
+ const id = this.normalizeModelId(modelId);
119
+ let input = 0;
120
+ let output = 0;
121
+ if (id.match(/gemini-1\.5-flash/)) {
122
+ input = 0.075;
123
+ output = 0.3;
124
+ }
125
+ else if (id.match(/gemini-1\.5-pro/)) {
126
+ input = 3.5;
127
+ output = 10.5;
128
+ }
129
+ else if (id.match(/gemini-2\.0-flash/)) {
130
+ input = 0.10;
131
+ output = 0.40;
132
+ }
133
+ return {
134
+ text_tokens: {
135
+ standard: {
136
+ input_per_million: input,
137
+ output_per_million: output
138
+ }
139
+ }
140
+ };
141
+ }
142
+ static formatDisplayName(modelId) {
143
+ return modelId.replace("models/", "").replace(/-/g, " ").replace(/\b\w/g, l => l.toUpperCase());
144
+ }
145
+ static normalizeModelId(modelId) {
146
+ return modelId.replace("models/", "");
147
+ }
148
+ }
@@ -0,0 +1,8 @@
1
+ import { ChatRequest, ChatResponse } from "../Provider.js";
2
+ export declare class GeminiChat {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(request: ChatRequest): Promise<ChatResponse>;
7
+ }
8
+ //# sourceMappingURL=Chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM3D,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CAqE3D"}
@@ -0,0 +1,69 @@
1
+ import { Capabilities } from "./Capabilities.js";
2
+ import { handleGeminiError } from "./Errors.js";
3
+ import { GeminiChatUtils } from "./ChatUtils.js";
4
+ export class GeminiChat {
5
+ baseUrl;
6
+ apiKey;
7
+ constructor(baseUrl, apiKey) {
8
+ this.baseUrl = baseUrl;
9
+ this.apiKey = apiKey;
10
+ }
11
+ async execute(request) {
12
+ const temperature = Capabilities.normalizeTemperature(request.temperature, request.model);
13
+ const url = `${this.baseUrl}/models/${request.model}:generateContent?key=${this.apiKey}`;
14
+ const { contents, systemInstructionParts } = await GeminiChatUtils.convertMessages(request.messages);
15
+ const payload = {
16
+ contents,
17
+ generationConfig: {
18
+ temperature: temperature ?? undefined,
19
+ maxOutputTokens: request.max_tokens,
20
+ },
21
+ };
22
+ if (systemInstructionParts.length > 0) {
23
+ payload.systemInstruction = { parts: systemInstructionParts };
24
+ }
25
+ if (request.tools && request.tools.length > 0) {
26
+ payload.tools = [
27
+ {
28
+ functionDeclarations: request.tools.map((t) => ({
29
+ name: t.function.name,
30
+ description: t.function.description,
31
+ parameters: t.function.parameters,
32
+ })),
33
+ },
34
+ ];
35
+ }
36
+ const response = await fetch(url, {
37
+ method: "POST",
38
+ headers: {
39
+ "Content-Type": "application/json",
40
+ },
41
+ body: JSON.stringify(payload),
42
+ });
43
+ if (!response.ok) {
44
+ await handleGeminiError(response, request.model);
45
+ }
46
+ const json = (await response.json());
47
+ const candidate = json.candidates?.[0];
48
+ const content = candidate?.content?.parts
49
+ ?.filter(p => p.text)
50
+ .map(p => p.text)
51
+ .join("\n") || null;
52
+ const tool_calls = candidate?.content?.parts
53
+ ?.filter((p) => p.functionCall)
54
+ .map((p) => ({
55
+ id: p.functionCall.name,
56
+ type: "function",
57
+ function: {
58
+ name: p.functionCall.name,
59
+ arguments: JSON.stringify(p.functionCall.args),
60
+ },
61
+ }));
62
+ const usage = json.usageMetadata ? {
63
+ input_tokens: json.usageMetadata.promptTokenCount,
64
+ output_tokens: json.usageMetadata.candidatesTokenCount,
65
+ total_tokens: json.usageMetadata.totalTokenCount,
66
+ } : undefined;
67
+ return { content, tool_calls, usage };
68
+ }
69
+ }
@@ -0,0 +1,9 @@
1
+ import { Message } from "../../chat/Message.js";
2
+ import { GeminiContent, GeminiPart } from "./types.js";
3
+ export declare class GeminiChatUtils {
4
+ static convertMessages(messages: Message[]): Promise<{
5
+ contents: GeminiContent[];
6
+ systemInstructionParts: GeminiPart[];
7
+ }>;
8
+ }
9
+ //# sourceMappingURL=ChatUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatUtils.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/ChatUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGvD,qBAAa,eAAe;WACb,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;QAAC,sBAAsB,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;CAgFhI"}
@@ -0,0 +1,83 @@
1
+ import { BinaryUtils } from "../../utils/Binary.js";
2
+ export class GeminiChatUtils {
3
+ static async convertMessages(messages) {
4
+ const contents = [];
5
+ const systemInstructionParts = [];
6
+ for (const msg of messages) {
7
+ if (msg.role === "system") {
8
+ if (typeof msg.content === "string") {
9
+ systemInstructionParts.push({ text: msg.content });
10
+ }
11
+ }
12
+ else if (msg.role === "user" || msg.role === "assistant" || msg.role === "tool") {
13
+ const parts = [];
14
+ if (msg.role === "tool") {
15
+ parts.push({
16
+ functionResponse: {
17
+ name: msg.tool_call_id || "unknown",
18
+ response: { result: msg.content },
19
+ },
20
+ });
21
+ contents.push({ role: "user", parts });
22
+ }
23
+ else {
24
+ const role = msg.role === "assistant" ? "model" : "user";
25
+ if (typeof msg.content === "string" && msg.content) {
26
+ parts.push({ text: msg.content });
27
+ }
28
+ else if (Array.isArray(msg.content)) {
29
+ for (const part of msg.content) {
30
+ if (part.type === "text") {
31
+ parts.push({ text: part.text });
32
+ }
33
+ else if (part.type === "image_url") {
34
+ const binary = await BinaryUtils.toBase64(part.image_url.url);
35
+ if (binary) {
36
+ parts.push({
37
+ inlineData: {
38
+ mimeType: binary.mimeType,
39
+ data: binary.data,
40
+ },
41
+ });
42
+ }
43
+ }
44
+ else if (part.type === "input_audio") {
45
+ parts.push({
46
+ inlineData: {
47
+ mimeType: `audio/${part.input_audio.format}`,
48
+ data: part.input_audio.data,
49
+ },
50
+ });
51
+ }
52
+ else if (part.type === "video_url") {
53
+ const binary = await BinaryUtils.toBase64(part.video_url.url);
54
+ if (binary) {
55
+ parts.push({
56
+ inlineData: {
57
+ mimeType: binary.mimeType,
58
+ data: binary.data,
59
+ },
60
+ });
61
+ }
62
+ }
63
+ }
64
+ }
65
+ if (msg.role === "assistant" && msg.tool_calls) {
66
+ for (const call of msg.tool_calls) {
67
+ parts.push({
68
+ functionCall: {
69
+ name: call.function.name,
70
+ args: JSON.parse(call.function.arguments),
71
+ },
72
+ });
73
+ }
74
+ }
75
+ if (parts.length > 0) {
76
+ contents.push({ role, parts });
77
+ }
78
+ }
79
+ }
80
+ }
81
+ return { contents, systemInstructionParts };
82
+ }
83
+ }
@@ -0,0 +1,8 @@
1
+ import { EmbeddingRequest, EmbeddingResponse } from "../Embedding.js";
2
+ export declare class GeminiEmbeddings {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(request: EmbeddingRequest): Promise<EmbeddingResponse>;
7
+ }
8
+ //# sourceMappingURL=Embeddings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Embeddings.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Embeddings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAItE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAwCrE"}
@@ -0,0 +1,44 @@
1
+ import { handleGeminiError } from "./Errors.js";
2
+ export class GeminiEmbeddings {
3
+ baseUrl;
4
+ apiKey;
5
+ constructor(baseUrl, apiKey) {
6
+ this.baseUrl = baseUrl;
7
+ this.apiKey = apiKey;
8
+ }
9
+ async execute(request) {
10
+ const modelId = request.model || "text-embedding-004";
11
+ const url = `${this.baseUrl}/models/${modelId}:batchEmbedContents?key=${this.apiKey}`;
12
+ const inputs = Array.isArray(request.input) ? request.input : [request.input];
13
+ const payload = {
14
+ requests: inputs.map(text => {
15
+ const item = {
16
+ model: `models/${modelId}`,
17
+ content: {
18
+ parts: [{ text: String(text) }]
19
+ }
20
+ };
21
+ if (request.dimensions) {
22
+ item.outputDimensionality = request.dimensions;
23
+ }
24
+ return item;
25
+ })
26
+ };
27
+ const response = await fetch(url, {
28
+ method: "POST",
29
+ headers: { "Content-Type": "application/json" },
30
+ body: JSON.stringify(payload)
31
+ });
32
+ if (!response.ok) {
33
+ await handleGeminiError(response, modelId);
34
+ }
35
+ const json = (await response.json());
36
+ const vectors = json.embeddings?.map(e => e.values) || [];
37
+ return {
38
+ model: modelId,
39
+ vectors: vectors,
40
+ input_tokens: 0,
41
+ dimensions: vectors[0]?.length || 0
42
+ };
43
+ }
44
+ }
@@ -0,0 +1,2 @@
1
+ export declare function handleGeminiError(response: Response, model?: string): Promise<never>;
2
+ //# sourceMappingURL=Errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Errors.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Errors.ts"],"names":[],"mappings":"AASA,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAuC1F"}
@@ -0,0 +1,34 @@
1
+ import { BadRequestError, AuthenticationError, RateLimitError, ServerError, ServiceUnavailableError, APIError } from "../../errors/index.js";
2
+ export async function handleGeminiError(response, model) {
3
+ const status = response.status;
4
+ let body;
5
+ let message = `Gemini error (${status})`;
6
+ try {
7
+ body = await response.json();
8
+ if (body?.error?.message) {
9
+ message = body.error.message;
10
+ }
11
+ }
12
+ catch {
13
+ // If not JSON, use the status text
14
+ body = await response.text().catch(() => "Unknown error");
15
+ message = `Gemini error (${status}): ${body}`;
16
+ }
17
+ const provider = "gemini";
18
+ if (status === 400) {
19
+ throw new BadRequestError(message, body, provider, model);
20
+ }
21
+ if (status === 401 || status === 403) {
22
+ throw new AuthenticationError(message, status, body, provider);
23
+ }
24
+ if (status === 429) {
25
+ throw new RateLimitError(message, body, provider, model);
26
+ }
27
+ if (status === 502 || status === 503 || status === 504) {
28
+ throw new ServiceUnavailableError(message, status, body, provider, model);
29
+ }
30
+ if (status >= 500) {
31
+ throw new ServerError(message, status, body, provider, model);
32
+ }
33
+ throw new APIError(message, status, body, provider, model);
34
+ }
@@ -0,0 +1,34 @@
1
+ import { Provider, ChatRequest, ChatResponse, ModelInfo, ChatChunk, ImageRequest, ImageResponse, TranscriptionRequest, TranscriptionResponse } from "../Provider.js";
2
+ import { EmbeddingRequest, EmbeddingResponse } from "../Embedding.js";
3
+ export interface GeminiProviderOptions {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ }
7
+ export declare class GeminiProvider implements Provider {
8
+ private readonly options;
9
+ private readonly baseUrl;
10
+ private readonly chatHandler;
11
+ private readonly streamingHandler;
12
+ private readonly modelsHandler;
13
+ private readonly imageHandler;
14
+ private readonly embeddingHandler;
15
+ private readonly transcriptionHandler;
16
+ capabilities: {
17
+ supportsVision: (model: string) => boolean;
18
+ supportsTools: (model: string) => boolean;
19
+ supportsStructuredOutput: (model: string) => boolean;
20
+ supportsEmbeddings: (model: string) => boolean;
21
+ supportsImageGeneration: (model: string) => boolean;
22
+ supportsTranscription: (model: string) => boolean;
23
+ supportsModeration: (model: string) => boolean;
24
+ getContextWindow: (model: string) => number | null;
25
+ };
26
+ constructor(options: GeminiProviderOptions);
27
+ chat(request: ChatRequest): Promise<ChatResponse>;
28
+ stream(request: ChatRequest): AsyncGenerator<ChatChunk>;
29
+ listModels(): Promise<ModelInfo[]>;
30
+ paint(request: ImageRequest): Promise<ImageResponse>;
31
+ embed(request: EmbeddingRequest): Promise<EmbeddingResponse>;
32
+ transcribe(request: TranscriptionRequest): Promise<TranscriptionResponse>;
33
+ }
34
+ //# sourceMappingURL=GeminiProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GeminiProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/GeminiProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAQrK,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,YAAW,QAAQ;IAoBjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAnBpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAsB;IAEpD,YAAY;gCACO,MAAM;+BACP,MAAM;0CACK,MAAM;oCACZ,MAAM;yCACD,MAAM;uCACR,MAAM;oCACT,MAAM;kCACR,MAAM;MAChC;gBAE2B,OAAO,EAAE,qBAAqB;IAUrD,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhD,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;IAIxD,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIlC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI5D,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAGhF"}
@@ -0,0 +1,55 @@
1
+ import { Capabilities } from "./Capabilities.js";
2
+ import { GeminiChat } from "./Chat.js";
3
+ import { GeminiStreaming } from "./Streaming.js";
4
+ import { GeminiModels } from "./Models.js";
5
+ import { GeminiImage } from "./Image.js";
6
+ import { GeminiEmbeddings } from "./Embeddings.js";
7
+ import { GeminiTranscription } from "./Transcription.js";
8
+ export class GeminiProvider {
9
+ options;
10
+ baseUrl;
11
+ chatHandler;
12
+ streamingHandler;
13
+ modelsHandler;
14
+ imageHandler;
15
+ embeddingHandler;
16
+ transcriptionHandler;
17
+ capabilities = {
18
+ supportsVision: (model) => Capabilities.supportsVision(model),
19
+ supportsTools: (model) => Capabilities.supportsTools(model),
20
+ supportsStructuredOutput: (model) => Capabilities.supportsStructuredOutput(model),
21
+ supportsEmbeddings: (model) => Capabilities.supportsEmbeddings(model),
22
+ supportsImageGeneration: (model) => Capabilities.supportsImageGeneration(model),
23
+ supportsTranscription: (model) => Capabilities.supportsTranscription(model),
24
+ supportsModeration: (model) => Capabilities.supportsModeration(model),
25
+ getContextWindow: (model) => Capabilities.getContextWindow(model),
26
+ };
27
+ constructor(options) {
28
+ this.options = options;
29
+ this.baseUrl = options.baseUrl ?? "https://generativelanguage.googleapis.com/v1beta";
30
+ this.chatHandler = new GeminiChat(this.baseUrl, options.apiKey);
31
+ this.streamingHandler = new GeminiStreaming(this.baseUrl, options.apiKey);
32
+ this.modelsHandler = new GeminiModels(this.baseUrl, options.apiKey);
33
+ this.imageHandler = new GeminiImage(this.baseUrl, options.apiKey);
34
+ this.embeddingHandler = new GeminiEmbeddings(this.baseUrl, options.apiKey);
35
+ this.transcriptionHandler = new GeminiTranscription(this.baseUrl, options.apiKey);
36
+ }
37
+ async chat(request) {
38
+ return this.chatHandler.execute(request);
39
+ }
40
+ async *stream(request) {
41
+ yield* this.streamingHandler.execute(request);
42
+ }
43
+ async listModels() {
44
+ return this.modelsHandler.execute();
45
+ }
46
+ async paint(request) {
47
+ return this.imageHandler.execute(request);
48
+ }
49
+ async embed(request) {
50
+ return this.embeddingHandler.execute(request);
51
+ }
52
+ async transcribe(request) {
53
+ return this.transcriptionHandler.execute(request);
54
+ }
55
+ }
@@ -0,0 +1,8 @@
1
+ import { ImageRequest, ImageResponse } from "../Provider.js";
2
+ export declare class GeminiImage {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(request: ImageRequest): Promise<ImageResponse>;
7
+ }
8
+ //# sourceMappingURL=Image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CA8C7D"}
@@ -0,0 +1,47 @@
1
+ import { handleGeminiError } from "./Errors.js";
2
+ export class GeminiImage {
3
+ baseUrl;
4
+ apiKey;
5
+ constructor(baseUrl, apiKey) {
6
+ this.baseUrl = baseUrl;
7
+ this.apiKey = apiKey;
8
+ }
9
+ async execute(request) {
10
+ const modelId = request.model || "imagen-4.0-generate-001";
11
+ const url = `${this.baseUrl}/models/${modelId}:predict?key=${this.apiKey}`;
12
+ if (request.size) {
13
+ console.log(`[Gemini] Ignoring size ${request.size}. Gemini does not support image size customization.`);
14
+ }
15
+ const body = {
16
+ instances: [
17
+ {
18
+ prompt: request.prompt,
19
+ },
20
+ ],
21
+ parameters: {
22
+ sampleCount: 1,
23
+ },
24
+ };
25
+ const response = await fetch(url, {
26
+ method: "POST",
27
+ headers: {
28
+ "Content-Type": "application/json",
29
+ },
30
+ body: JSON.stringify(body),
31
+ });
32
+ if (!response.ok) {
33
+ await handleGeminiError(response, modelId);
34
+ }
35
+ const json = await response.json();
36
+ const imageData = json.predictions?.[0];
37
+ if (!imageData || !imageData.bytesBase64Encoded) {
38
+ throw new Error("Unexpected response format from Gemini image generation API");
39
+ }
40
+ const mimeType = imageData.mimeType || "image/png";
41
+ const base64Data = imageData.bytesBase64Encoded;
42
+ return {
43
+ data: base64Data,
44
+ mime_type: mimeType,
45
+ };
46
+ }
47
+ }
@@ -0,0 +1,8 @@
1
+ import { ModelInfo } from "../Provider.js";
2
+ export declare class GeminiModels {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(): Promise<ModelInfo[]>;
7
+ }
8
+ //# sourceMappingURL=Models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAI3C,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;CAgCtC"}
@@ -0,0 +1,38 @@
1
+ import { Capabilities } from "./Capabilities.js";
2
+ export class GeminiModels {
3
+ baseUrl;
4
+ apiKey;
5
+ constructor(baseUrl, apiKey) {
6
+ this.baseUrl = baseUrl;
7
+ this.apiKey = apiKey;
8
+ }
9
+ async execute() {
10
+ const url = `${this.baseUrl}/models?key=${this.apiKey}`;
11
+ const response = await fetch(url);
12
+ if (!response.ok) {
13
+ const errorText = await response.text();
14
+ throw new Error(`Gemini error (${response.status}): ${errorText}`);
15
+ }
16
+ const json = (await response.json());
17
+ return json.models
18
+ .filter(m => m.supportedGenerationMethods.includes("generateContent"))
19
+ .map((model) => {
20
+ const id = model.name.replace("models/", "");
21
+ return {
22
+ id: id,
23
+ name: model.displayName || Capabilities.formatDisplayName(id),
24
+ provider: "gemini",
25
+ family: Capabilities.getFamily(id),
26
+ context_window: model.inputTokenLimit || Capabilities.getContextWindow(id),
27
+ max_output_tokens: model.outputTokenLimit || Capabilities.getMaxOutputTokens(id),
28
+ modalities: Capabilities.getModalities(id),
29
+ capabilities: Capabilities.getCapabilities(id),
30
+ pricing: Capabilities.getPricing(id),
31
+ metadata: {
32
+ description: model.description,
33
+ version: model.version,
34
+ },
35
+ };
36
+ });
37
+ }
38
+ }
@@ -0,0 +1,8 @@
1
+ import { ChatRequest, ChatChunk } from "../Provider.js";
2
+ export declare class GeminiStreaming {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(request: ChatRequest): AsyncGenerator<ChatChunk>;
7
+ }
8
+ //# sourceMappingURL=Streaming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;CAoEhE"}