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