@yourgpt/llm-sdk 1.0.1 → 1.2.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 (42) hide show
  1. package/README.md +23 -15
  2. package/dist/adapters/index.d.mts +23 -9
  3. package/dist/adapters/index.d.ts +23 -9
  4. package/dist/adapters/index.js.map +1 -1
  5. package/dist/adapters/index.mjs.map +1 -1
  6. package/dist/{base-D_FyHFKj.d.mts → base-CXNMfvXg.d.mts} +10 -2
  7. package/dist/{base-D_FyHFKj.d.ts → base-CXNMfvXg.d.ts} +10 -2
  8. package/dist/index.d.mts +33 -13
  9. package/dist/index.d.ts +33 -13
  10. package/dist/index.js +160 -177
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +160 -177
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/providers/anthropic/index.d.mts +2 -2
  15. package/dist/providers/anthropic/index.d.ts +2 -2
  16. package/dist/providers/anthropic/index.js.map +1 -1
  17. package/dist/providers/anthropic/index.mjs.map +1 -1
  18. package/dist/providers/azure/index.d.mts +2 -2
  19. package/dist/providers/azure/index.d.ts +2 -2
  20. package/dist/providers/azure/index.js.map +1 -1
  21. package/dist/providers/azure/index.mjs.map +1 -1
  22. package/dist/providers/google/index.d.mts +23 -10
  23. package/dist/providers/google/index.d.ts +23 -10
  24. package/dist/providers/google/index.js +160 -177
  25. package/dist/providers/google/index.js.map +1 -1
  26. package/dist/providers/google/index.mjs +160 -177
  27. package/dist/providers/google/index.mjs.map +1 -1
  28. package/dist/providers/ollama/index.d.mts +2 -2
  29. package/dist/providers/ollama/index.d.ts +2 -2
  30. package/dist/providers/ollama/index.js.map +1 -1
  31. package/dist/providers/ollama/index.mjs.map +1 -1
  32. package/dist/providers/openai/index.d.mts +2 -2
  33. package/dist/providers/openai/index.d.ts +2 -2
  34. package/dist/providers/openai/index.js.map +1 -1
  35. package/dist/providers/openai/index.mjs.map +1 -1
  36. package/dist/providers/xai/index.d.mts +2 -2
  37. package/dist/providers/xai/index.d.ts +2 -2
  38. package/dist/providers/xai/index.js.map +1 -1
  39. package/dist/providers/xai/index.mjs.map +1 -1
  40. package/dist/{types-BBCZ3Fxy.d.mts → types-B8rxpnYi.d.mts} +1 -1
  41. package/dist/{types-DcoCaVVC.d.ts → types-CrQftISG.d.ts} +1 -1
  42. package/package.json +3 -7
@@ -4,6 +4,21 @@ var core = require('@yourgpt/copilot-sdk/core');
4
4
 
5
5
  // src/providers/google/provider.ts
6
6
  var GOOGLE_MODELS = {
7
+ // Gemini 2.5 (Experimental)
8
+ "gemini-2.5-pro-preview-05-06": {
9
+ vision: true,
10
+ tools: true,
11
+ audio: true,
12
+ video: true,
13
+ maxTokens: 1048576
14
+ },
15
+ "gemini-2.5-flash-preview-05-20": {
16
+ vision: true,
17
+ tools: true,
18
+ audio: true,
19
+ video: true,
20
+ maxTokens: 1048576
21
+ },
7
22
  // Gemini 2.0
8
23
  "gemini-2.0-flash": {
9
24
  vision: true,
@@ -19,6 +34,13 @@ var GOOGLE_MODELS = {
19
34
  video: true,
20
35
  maxTokens: 1048576
21
36
  },
37
+ "gemini-2.0-flash-lite": {
38
+ vision: true,
39
+ tools: true,
40
+ audio: false,
41
+ video: false,
42
+ maxTokens: 1048576
43
+ },
22
44
  "gemini-2.0-flash-thinking-exp": {
23
45
  vision: true,
24
46
  tools: false,
@@ -65,11 +87,15 @@ var GOOGLE_MODELS = {
65
87
  };
66
88
  function google(modelId, options = {}) {
67
89
  const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
90
+ const baseURL = options.baseURL ?? "https://generativelanguage.googleapis.com/v1beta/openai/";
68
91
  let client = null;
69
92
  async function getClient() {
70
93
  if (!client) {
71
- const { GoogleGenerativeAI } = await import('@google/generative-ai');
72
- client = new GoogleGenerativeAI(apiKey);
94
+ const { default: OpenAI } = await import('openai');
95
+ client = new OpenAI({
96
+ apiKey,
97
+ baseURL
98
+ });
73
99
  }
74
100
  return client;
75
101
  }
@@ -89,219 +115,176 @@ function google(modelId, options = {}) {
89
115
  },
90
116
  async doGenerate(params) {
91
117
  const client2 = await getClient();
92
- const model = client2.getGenerativeModel({
118
+ const messages = formatMessagesForGoogle(params.messages);
119
+ const response = await client2.chat.completions.create({
93
120
  model: modelId,
94
- safetySettings: options.safetySettings
121
+ messages,
122
+ tools: params.tools,
123
+ temperature: params.temperature,
124
+ max_tokens: params.maxTokens
95
125
  });
96
- const { systemInstruction, contents } = formatMessagesForGemini(
97
- params.messages
126
+ const choice = response.choices[0];
127
+ const message = choice.message;
128
+ const toolCalls = (message.tool_calls ?? []).map(
129
+ (tc) => ({
130
+ id: tc.id,
131
+ name: tc.function.name,
132
+ args: JSON.parse(tc.function.arguments || "{}")
133
+ })
98
134
  );
99
- const chat = model.startChat({
100
- history: contents.slice(0, -1),
101
- systemInstruction: systemInstruction ? { parts: [{ text: systemInstruction }] } : void 0,
102
- tools: params.tools ? [{ functionDeclarations: formatToolsForGemini(params.tools) }] : void 0,
103
- generationConfig: {
104
- temperature: params.temperature,
105
- maxOutputTokens: params.maxTokens
106
- }
107
- });
108
- const lastMessage = contents[contents.length - 1];
109
- const result = await chat.sendMessage(lastMessage.parts);
110
- const response = result.response;
111
- let text = "";
112
- const toolCalls = [];
113
- let toolCallIndex = 0;
114
- const candidate = response.candidates?.[0];
115
- if (candidate?.content?.parts) {
116
- for (const part of candidate.content.parts) {
117
- if ("text" in part && part.text) {
118
- text += part.text;
119
- }
120
- if ("functionCall" in part && part.functionCall) {
121
- toolCalls.push({
122
- id: `call_${toolCallIndex++}`,
123
- name: part.functionCall.name,
124
- args: part.functionCall.args || {}
125
- });
126
- }
127
- }
128
- }
129
135
  return {
130
- text,
136
+ text: message.content ?? "",
131
137
  toolCalls,
132
- finishReason: mapFinishReason(candidate?.finishReason),
138
+ finishReason: mapFinishReason(choice.finish_reason),
133
139
  usage: {
134
- promptTokens: response.usageMetadata?.promptTokenCount ?? 0,
135
- completionTokens: response.usageMetadata?.candidatesTokenCount ?? 0,
136
- totalTokens: response.usageMetadata?.totalTokenCount ?? 0
140
+ promptTokens: response.usage?.prompt_tokens ?? 0,
141
+ completionTokens: response.usage?.completion_tokens ?? 0,
142
+ totalTokens: response.usage?.total_tokens ?? 0
137
143
  },
138
144
  rawResponse: response
139
145
  };
140
146
  },
141
147
  async *doStream(params) {
142
148
  const client2 = await getClient();
143
- const model = client2.getGenerativeModel({
149
+ const messages = formatMessagesForGoogle(params.messages);
150
+ const stream = await client2.chat.completions.create({
144
151
  model: modelId,
145
- safetySettings: options.safetySettings
152
+ messages,
153
+ tools: params.tools,
154
+ temperature: params.temperature,
155
+ max_tokens: params.maxTokens,
156
+ stream: true
146
157
  });
147
- const { systemInstruction, contents } = formatMessagesForGemini(
148
- params.messages
149
- );
150
- const chat = model.startChat({
151
- history: contents.slice(0, -1),
152
- systemInstruction: systemInstruction ? { parts: [{ text: systemInstruction }] } : void 0,
153
- tools: params.tools ? [{ functionDeclarations: formatToolsForGemini(params.tools) }] : void 0,
154
- generationConfig: {
155
- temperature: params.temperature,
156
- maxOutputTokens: params.maxTokens
158
+ let currentToolCall = null;
159
+ let totalPromptTokens = 0;
160
+ let totalCompletionTokens = 0;
161
+ for await (const chunk of stream) {
162
+ if (params.signal?.aborted) {
163
+ yield { type: "error", error: new Error("Aborted") };
164
+ return;
157
165
  }
158
- });
159
- const lastMessage = contents[contents.length - 1];
160
- const result = await chat.sendMessageStream(lastMessage.parts);
161
- let toolCallIndex = 0;
162
- let promptTokens = 0;
163
- let completionTokens = 0;
164
- try {
165
- for await (const chunk of result.stream) {
166
- if (params.signal?.aborted) {
167
- yield { type: "error", error: new Error("Aborted") };
168
- return;
169
- }
170
- const candidate = chunk.candidates?.[0];
171
- if (!candidate?.content?.parts) continue;
172
- for (const part of candidate.content.parts) {
173
- if ("text" in part && part.text) {
174
- yield { type: "text-delta", text: part.text };
175
- }
176
- if ("functionCall" in part && part.functionCall) {
177
- yield {
178
- type: "tool-call",
179
- toolCall: {
180
- id: `call_${toolCallIndex++}`,
181
- name: part.functionCall.name,
182
- args: part.functionCall.args || {}
183
- }
166
+ const choice = chunk.choices[0];
167
+ const delta = choice?.delta;
168
+ if (delta?.content) {
169
+ yield { type: "text-delta", text: delta.content };
170
+ }
171
+ if (delta?.tool_calls) {
172
+ for (const tc of delta.tool_calls) {
173
+ if (tc.id) {
174
+ if (currentToolCall) {
175
+ yield {
176
+ type: "tool-call",
177
+ toolCall: {
178
+ id: currentToolCall.id,
179
+ name: currentToolCall.name,
180
+ args: JSON.parse(currentToolCall.arguments || "{}")
181
+ }
182
+ };
183
+ }
184
+ currentToolCall = {
185
+ id: tc.id,
186
+ name: tc.function?.name ?? "",
187
+ arguments: tc.function?.arguments ?? ""
184
188
  };
189
+ } else if (currentToolCall && tc.function?.arguments) {
190
+ currentToolCall.arguments += tc.function.arguments;
185
191
  }
186
192
  }
187
- if (chunk.usageMetadata) {
188
- promptTokens = chunk.usageMetadata.promptTokenCount ?? 0;
189
- completionTokens = chunk.usageMetadata.candidatesTokenCount ?? 0;
190
- }
191
- if (candidate.finishReason) {
193
+ }
194
+ if (choice?.finish_reason) {
195
+ if (currentToolCall) {
192
196
  yield {
193
- type: "finish",
194
- finishReason: mapFinishReason(candidate.finishReason),
195
- usage: {
196
- promptTokens,
197
- completionTokens,
198
- totalTokens: promptTokens + completionTokens
197
+ type: "tool-call",
198
+ toolCall: {
199
+ id: currentToolCall.id,
200
+ name: currentToolCall.name,
201
+ args: JSON.parse(currentToolCall.arguments || "{}")
199
202
  }
200
203
  };
204
+ currentToolCall = null;
205
+ }
206
+ if (chunk.usage) {
207
+ totalPromptTokens = chunk.usage.prompt_tokens;
208
+ totalCompletionTokens = chunk.usage.completion_tokens;
201
209
  }
210
+ yield {
211
+ type: "finish",
212
+ finishReason: mapFinishReason(choice.finish_reason),
213
+ usage: {
214
+ promptTokens: totalPromptTokens,
215
+ completionTokens: totalCompletionTokens,
216
+ totalTokens: totalPromptTokens + totalCompletionTokens
217
+ }
218
+ };
202
219
  }
203
- } catch (error) {
204
- yield {
205
- type: "error",
206
- error: error instanceof Error ? error : new Error(String(error))
207
- };
208
220
  }
209
221
  }
210
222
  };
211
223
  }
212
224
  function mapFinishReason(reason) {
213
225
  switch (reason) {
214
- case "STOP":
226
+ case "stop":
215
227
  return "stop";
216
- case "MAX_TOKENS":
228
+ case "length":
217
229
  return "length";
218
- case "SAFETY":
230
+ case "tool_calls":
231
+ case "function_call":
232
+ return "tool-calls";
233
+ case "content_filter":
219
234
  return "content-filter";
220
235
  default:
221
236
  return "unknown";
222
237
  }
223
238
  }
224
- function formatMessagesForGemini(messages) {
225
- let systemInstruction = "";
226
- const contents = [];
227
- for (const msg of messages) {
228
- if (msg.role === "system") {
229
- systemInstruction += (systemInstruction ? "\n" : "") + msg.content;
230
- continue;
231
- }
232
- const parts = [];
233
- if (msg.role === "user") {
234
- if (typeof msg.content === "string") {
235
- parts.push({ text: msg.content });
236
- } else {
237
- for (const part of msg.content) {
238
- if (part.type === "text") {
239
- parts.push({ text: part.text });
240
- } else if (part.type === "image") {
241
- const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
242
- const base64 = imageData.startsWith("data:") ? imageData.split(",")[1] : imageData;
243
- parts.push({
244
- inlineData: {
245
- mimeType: part.mimeType ?? "image/png",
246
- data: base64
247
- }
248
- });
249
- }
239
+ function formatMessagesForGoogle(messages) {
240
+ return messages.map((msg) => {
241
+ switch (msg.role) {
242
+ case "system":
243
+ return { role: "system", content: msg.content };
244
+ case "user":
245
+ if (typeof msg.content === "string") {
246
+ return { role: "user", content: msg.content };
250
247
  }
251
- }
252
- contents.push({ role: "user", parts });
253
- } else if (msg.role === "assistant") {
254
- if (msg.content) {
255
- parts.push({ text: msg.content });
256
- }
257
- if (msg.toolCalls?.length) {
258
- for (const tc of msg.toolCalls) {
259
- parts.push({
260
- functionCall: {
248
+ return {
249
+ role: "user",
250
+ content: msg.content.map((part) => {
251
+ if (part.type === "text") {
252
+ return { type: "text", text: part.text };
253
+ }
254
+ if (part.type === "image") {
255
+ const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
256
+ const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
257
+ return { type: "image_url", image_url: { url, detail: "auto" } };
258
+ }
259
+ return { type: "text", text: "" };
260
+ })
261
+ };
262
+ case "assistant":
263
+ const assistantMsg = {
264
+ role: "assistant",
265
+ content: msg.content
266
+ };
267
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
268
+ assistantMsg.tool_calls = msg.toolCalls.map((tc) => ({
269
+ id: tc.id,
270
+ type: "function",
271
+ function: {
261
272
  name: tc.name,
262
- args: tc.args
273
+ arguments: JSON.stringify(tc.args)
263
274
  }
264
- });
275
+ }));
265
276
  }
266
- }
267
- if (parts.length > 0) {
268
- contents.push({ role: "model", parts });
269
- }
270
- } else if (msg.role === "tool") {
271
- contents.push({
272
- role: "user",
273
- parts: [
274
- {
275
- functionResponse: {
276
- name: "tool",
277
- // Gemini doesn't track by ID
278
- response: JSON.parse(msg.content || "{}")
279
- }
280
- }
281
- ]
282
- });
283
- }
284
- }
285
- if (contents.length === 0 || contents[0].role !== "user") {
286
- contents.unshift({ role: "user", parts: [{ text: "" }] });
287
- }
288
- const merged = [];
289
- for (const content of contents) {
290
- const last = merged[merged.length - 1];
291
- if (last && last.role === content.role) {
292
- last.parts.push(...content.parts);
293
- } else {
294
- merged.push({ ...content, parts: [...content.parts] });
277
+ return assistantMsg;
278
+ case "tool":
279
+ return {
280
+ role: "tool",
281
+ tool_call_id: msg.toolCallId,
282
+ content: msg.content
283
+ };
284
+ default:
285
+ return msg;
295
286
  }
296
- }
297
- return { systemInstruction, contents: merged };
298
- }
299
- function formatToolsForGemini(tools) {
300
- return tools.map((t) => ({
301
- name: t.function.name,
302
- description: t.function.description,
303
- parameters: t.function.parameters
304
- }));
287
+ });
305
288
  }
306
289
  function attachmentToGeminiPart(attachment) {
307
290
  if (!attachment.data) {
@@ -394,7 +377,7 @@ function messageToGeminiContent(msg) {
394
377
  parts
395
378
  };
396
379
  }
397
- function formatToolsForGemini2(actions) {
380
+ function formatToolsForGemini(actions) {
398
381
  if (!actions || actions.length === 0) return void 0;
399
382
  return {
400
383
  functionDeclarations: actions.map((action) => ({
@@ -480,7 +463,7 @@ var GoogleAdapter = class {
480
463
  mergedContents.push({ ...content, parts: [...content.parts] });
481
464
  }
482
465
  }
483
- const tools = formatToolsForGemini2(request.actions);
466
+ const tools = formatToolsForGemini(request.actions);
484
467
  const messageId = core.generateMessageId();
485
468
  yield { type: "message:start", id: messageId };
486
469
  try {
@@ -586,7 +569,7 @@ var GoogleAdapter = class {
586
569
  mergedContents.push({ ...content, parts: [...content.parts] });
587
570
  }
588
571
  }
589
- const tools = formatToolsForGemini2(request.actions);
572
+ const tools = formatToolsForGemini(request.actions);
590
573
  const chat = model.startChat({
591
574
  history: mergedContents.slice(0, -1),
592
575
  systemInstruction: systemInstruction ? { parts: [{ text: systemInstruction }] } : void 0,