@lupaflow/providers 0.1.0 → 0.1.2
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.
- package/dist/index.cjs +657 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +617 -0
- package/dist/index.js.map +1 -0
- package/package.json +6 -5
- package/tsconfig.json +0 -8
- package/tsup.config.ts +0 -9
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
GoogleProvider: () => GoogleProvider,
|
|
34
|
+
GroqProvider: () => GroqProvider,
|
|
35
|
+
OpenRouterProvider: () => OpenRouterProvider,
|
|
36
|
+
providerRegistry: () => providerRegistry
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(src_exports);
|
|
39
|
+
|
|
40
|
+
// src/registry.ts
|
|
41
|
+
var import_core = require("@lupaflow/core");
|
|
42
|
+
var ProviderRegistry = class {
|
|
43
|
+
providers = /* @__PURE__ */ new Map();
|
|
44
|
+
instances = /* @__PURE__ */ new Map();
|
|
45
|
+
register(name, ctor) {
|
|
46
|
+
this.providers.set(name, ctor);
|
|
47
|
+
}
|
|
48
|
+
get(name, config) {
|
|
49
|
+
if (!config && this.instances.has(name)) {
|
|
50
|
+
return this.instances.get(name);
|
|
51
|
+
}
|
|
52
|
+
const ctor = this.providers.get(name);
|
|
53
|
+
if (!ctor) {
|
|
54
|
+
throw new import_core.ConfigError(`Unknown provider: "${name}"`, {
|
|
55
|
+
available: Array.from(this.providers.keys())
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const instance = new ctor(config || {});
|
|
59
|
+
if (!config) {
|
|
60
|
+
this.instances.set(name, instance);
|
|
61
|
+
}
|
|
62
|
+
return instance;
|
|
63
|
+
}
|
|
64
|
+
has(name) {
|
|
65
|
+
return this.providers.has(name);
|
|
66
|
+
}
|
|
67
|
+
list() {
|
|
68
|
+
return Array.from(this.providers.keys());
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var providerRegistry = new ProviderRegistry();
|
|
72
|
+
|
|
73
|
+
// src/openrouter.ts
|
|
74
|
+
var import_openai = __toESM(require("openai"), 1);
|
|
75
|
+
var import_core2 = require("@lupaflow/core");
|
|
76
|
+
var import_secrets = require("@lupaflow/secrets");
|
|
77
|
+
var import_core3 = require("@lupaflow/core");
|
|
78
|
+
var OpenRouterProvider = class {
|
|
79
|
+
name = "openrouter";
|
|
80
|
+
defaultModel = "openai/gpt-4o-mini";
|
|
81
|
+
config;
|
|
82
|
+
client;
|
|
83
|
+
constructor(config = {}) {
|
|
84
|
+
this.config = config;
|
|
85
|
+
this.client = new import_openai.default({
|
|
86
|
+
apiKey: config.apiKey || (0, import_secrets.getOpenRouterKey)(),
|
|
87
|
+
baseURL: config.baseUrl || "https://openrouter.ai/api/v1",
|
|
88
|
+
defaultHeaders: {
|
|
89
|
+
"HTTP-Referer": "https://lupaflow.dev",
|
|
90
|
+
"X-Title": "LupaFlow"
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
validateConfig() {
|
|
95
|
+
try {
|
|
96
|
+
(0, import_secrets.getOpenRouterKey)();
|
|
97
|
+
return true;
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
buildMessages(request) {
|
|
103
|
+
const messages = [];
|
|
104
|
+
if (request.systemPrompt) {
|
|
105
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
106
|
+
}
|
|
107
|
+
for (const m of request.messages) {
|
|
108
|
+
if (m.role === "assistant" && m.toolCalls?.length) {
|
|
109
|
+
messages.push({
|
|
110
|
+
role: "assistant",
|
|
111
|
+
content: m.content,
|
|
112
|
+
tool_calls: m.toolCalls
|
|
113
|
+
});
|
|
114
|
+
} else if (m.role === "tool") {
|
|
115
|
+
messages.push({
|
|
116
|
+
role: "tool",
|
|
117
|
+
tool_call_id: m.toolCallId || "",
|
|
118
|
+
content: m.content || ""
|
|
119
|
+
});
|
|
120
|
+
} else {
|
|
121
|
+
messages.push({ role: m.role, content: m.content });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return messages;
|
|
125
|
+
}
|
|
126
|
+
buildTools(tools) {
|
|
127
|
+
return tools?.map((t) => ({
|
|
128
|
+
type: "function",
|
|
129
|
+
function: {
|
|
130
|
+
name: t.definition.name,
|
|
131
|
+
description: t.definition.description,
|
|
132
|
+
parameters: {
|
|
133
|
+
type: "object",
|
|
134
|
+
properties: t.definition.parameters,
|
|
135
|
+
required: t.definition.required
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
async complete(request) {
|
|
141
|
+
const start = Date.now();
|
|
142
|
+
const model = request.model || this.config.model || this.defaultModel;
|
|
143
|
+
await import_core3.globalEventBus.emit("provider:start", {
|
|
144
|
+
provider: this.name,
|
|
145
|
+
model
|
|
146
|
+
});
|
|
147
|
+
try {
|
|
148
|
+
const messages = this.buildMessages(request);
|
|
149
|
+
const tools = this.buildTools(request.tools);
|
|
150
|
+
const response = await this.client.chat.completions.create({
|
|
151
|
+
model,
|
|
152
|
+
messages,
|
|
153
|
+
tools,
|
|
154
|
+
temperature: request.temperature ?? this.config.temperature,
|
|
155
|
+
max_tokens: request.maxTokens ?? this.config.maxTokens,
|
|
156
|
+
top_p: request.topP ?? this.config.topP
|
|
157
|
+
});
|
|
158
|
+
const choice = response.choices[0];
|
|
159
|
+
const latencyMs = Date.now() - start;
|
|
160
|
+
const result = {
|
|
161
|
+
content: choice.message.content,
|
|
162
|
+
toolCalls: (choice.message.tool_calls || []).map((tc) => ({
|
|
163
|
+
id: tc.id,
|
|
164
|
+
name: tc.function.name,
|
|
165
|
+
args: JSON.parse(tc.function.arguments)
|
|
166
|
+
})),
|
|
167
|
+
usage: {
|
|
168
|
+
promptTokens: response.usage?.prompt_tokens || 0,
|
|
169
|
+
completionTokens: response.usage?.completion_tokens || 0,
|
|
170
|
+
totalTokens: response.usage?.total_tokens || 0
|
|
171
|
+
},
|
|
172
|
+
model: response.model,
|
|
173
|
+
latencyMs,
|
|
174
|
+
finishReason: choice.finish_reason || "stop"
|
|
175
|
+
};
|
|
176
|
+
await import_core3.globalEventBus.emit("provider:complete", {
|
|
177
|
+
provider: this.name,
|
|
178
|
+
model,
|
|
179
|
+
tokens: result.usage.totalTokens,
|
|
180
|
+
latencyMs
|
|
181
|
+
});
|
|
182
|
+
return result;
|
|
183
|
+
} catch (err) {
|
|
184
|
+
const latencyMs = Date.now() - start;
|
|
185
|
+
await import_core3.globalEventBus.emit("provider:error", {
|
|
186
|
+
provider: this.name,
|
|
187
|
+
model,
|
|
188
|
+
error: err.message
|
|
189
|
+
});
|
|
190
|
+
throw new import_core2.ProviderError(this.name, err.message, { model, latencyMs });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async *streamComplete(request) {
|
|
194
|
+
const start = Date.now();
|
|
195
|
+
const model = request.model || this.config.model || this.defaultModel;
|
|
196
|
+
await import_core3.globalEventBus.emit("provider:start", {
|
|
197
|
+
provider: this.name,
|
|
198
|
+
model
|
|
199
|
+
});
|
|
200
|
+
try {
|
|
201
|
+
const messages = this.buildMessages(request);
|
|
202
|
+
const tools = this.buildTools(request.tools);
|
|
203
|
+
const stream = await this.client.chat.completions.create({
|
|
204
|
+
model,
|
|
205
|
+
messages,
|
|
206
|
+
tools,
|
|
207
|
+
temperature: request.temperature ?? this.config.temperature,
|
|
208
|
+
max_tokens: request.maxTokens ?? this.config.maxTokens,
|
|
209
|
+
top_p: request.topP ?? this.config.topP,
|
|
210
|
+
stream: true
|
|
211
|
+
});
|
|
212
|
+
let fullContent = "";
|
|
213
|
+
const accToolCalls = /* @__PURE__ */ new Map();
|
|
214
|
+
for await (const chunk of stream) {
|
|
215
|
+
const delta = chunk.choices[0]?.delta;
|
|
216
|
+
if (delta?.content) {
|
|
217
|
+
fullContent += delta.content;
|
|
218
|
+
yield { type: "text", text: delta.content };
|
|
219
|
+
}
|
|
220
|
+
if (delta?.tool_calls) {
|
|
221
|
+
for (const tc of delta.tool_calls) {
|
|
222
|
+
if (!accToolCalls.has(tc.index)) {
|
|
223
|
+
accToolCalls.set(tc.index, { id: "", name: "", args: "" });
|
|
224
|
+
}
|
|
225
|
+
const entry = accToolCalls.get(tc.index);
|
|
226
|
+
if (tc.id) entry.id = tc.id;
|
|
227
|
+
if (tc.function?.name) entry.name = tc.function.name;
|
|
228
|
+
if (tc.function?.arguments) entry.args += tc.function.arguments;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (chunk.choices[0]?.finish_reason) {
|
|
232
|
+
const finishReason = chunk.choices[0].finish_reason;
|
|
233
|
+
const toolCalls = Array.from(accToolCalls.values()).filter((tc) => tc.id && tc.name).map((tc) => ({
|
|
234
|
+
id: tc.id,
|
|
235
|
+
name: tc.name,
|
|
236
|
+
args: JSON.parse(tc.args || "{}")
|
|
237
|
+
}));
|
|
238
|
+
yield {
|
|
239
|
+
type: "finish",
|
|
240
|
+
content: fullContent,
|
|
241
|
+
toolCalls,
|
|
242
|
+
usage: {
|
|
243
|
+
promptTokens: chunk.usage?.prompt_tokens || 0,
|
|
244
|
+
completionTokens: chunk.usage?.completion_tokens || 0,
|
|
245
|
+
totalTokens: chunk.usage?.total_tokens || 0
|
|
246
|
+
},
|
|
247
|
+
model,
|
|
248
|
+
finishReason
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
await import_core3.globalEventBus.emit("provider:complete", {
|
|
253
|
+
provider: this.name,
|
|
254
|
+
model,
|
|
255
|
+
tokens: 0,
|
|
256
|
+
latencyMs: Date.now() - start
|
|
257
|
+
});
|
|
258
|
+
} catch (err) {
|
|
259
|
+
await import_core3.globalEventBus.emit("provider:error", {
|
|
260
|
+
provider: this.name,
|
|
261
|
+
model,
|
|
262
|
+
error: err.message
|
|
263
|
+
});
|
|
264
|
+
throw new import_core2.ProviderError(this.name, err.message, { model, latencyMs: Date.now() - start });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async getModels() {
|
|
268
|
+
try {
|
|
269
|
+
const response = await fetch("https://openrouter.ai/api/v1/models");
|
|
270
|
+
const data = await response.json();
|
|
271
|
+
return data.data?.map((m) => m.id) || [];
|
|
272
|
+
} catch {
|
|
273
|
+
return [this.defaultModel];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// src/google.ts
|
|
279
|
+
var import_generative_ai = require("@google/generative-ai");
|
|
280
|
+
var import_core4 = require("@lupaflow/core");
|
|
281
|
+
var import_secrets2 = require("@lupaflow/secrets");
|
|
282
|
+
var import_core5 = require("@lupaflow/core");
|
|
283
|
+
var GoogleProvider = class {
|
|
284
|
+
name = "google";
|
|
285
|
+
defaultModel = "gemini-1.5-flash";
|
|
286
|
+
config;
|
|
287
|
+
client;
|
|
288
|
+
constructor(config = {}) {
|
|
289
|
+
this.config = config;
|
|
290
|
+
this.client = new import_generative_ai.GoogleGenerativeAI(config.apiKey || (0, import_secrets2.getGoogleKey)());
|
|
291
|
+
}
|
|
292
|
+
validateConfig() {
|
|
293
|
+
try {
|
|
294
|
+
(0, import_secrets2.getGoogleKey)();
|
|
295
|
+
return true;
|
|
296
|
+
} catch {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
buildContents(request) {
|
|
301
|
+
const contents = [];
|
|
302
|
+
for (const msg of request.messages) {
|
|
303
|
+
if (msg.role === "system") continue;
|
|
304
|
+
const role = msg.role === "assistant" ? "model" : "user";
|
|
305
|
+
contents.push({
|
|
306
|
+
role,
|
|
307
|
+
parts: [{ text: msg.content || "" }]
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
return contents;
|
|
311
|
+
}
|
|
312
|
+
async complete(request) {
|
|
313
|
+
const start = Date.now();
|
|
314
|
+
const model = request.model || this.config.model || this.defaultModel;
|
|
315
|
+
await import_core5.globalEventBus.emit("provider:start", {
|
|
316
|
+
provider: this.name,
|
|
317
|
+
model
|
|
318
|
+
});
|
|
319
|
+
try {
|
|
320
|
+
const genModel = this.client.getGenerativeModel({ model });
|
|
321
|
+
const systemInstruction = request.systemPrompt;
|
|
322
|
+
const contents = this.buildContents(request);
|
|
323
|
+
const requestOptions = {
|
|
324
|
+
contents,
|
|
325
|
+
generationConfig: {
|
|
326
|
+
temperature: request.temperature ?? this.config.temperature,
|
|
327
|
+
maxOutputTokens: request.maxTokens ?? this.config.maxTokens,
|
|
328
|
+
topP: request.topP ?? this.config.topP
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
if (systemInstruction) {
|
|
332
|
+
requestOptions.systemInstruction = {
|
|
333
|
+
role: "user",
|
|
334
|
+
parts: [{ text: systemInstruction }]
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const result = await genModel.generateContent(requestOptions);
|
|
338
|
+
const latencyMs = Date.now() - start;
|
|
339
|
+
const response = result.response;
|
|
340
|
+
const text = response.text();
|
|
341
|
+
const usage = response.usageMetadata || {};
|
|
342
|
+
const totalTokens = (usage.promptTokenCount || 0) + (usage.candidatesTokenCount || 0);
|
|
343
|
+
const completionResponse = {
|
|
344
|
+
content: text,
|
|
345
|
+
toolCalls: [],
|
|
346
|
+
usage: {
|
|
347
|
+
promptTokens: usage.promptTokenCount || 0,
|
|
348
|
+
completionTokens: usage.candidatesTokenCount || 0,
|
|
349
|
+
totalTokens
|
|
350
|
+
},
|
|
351
|
+
model,
|
|
352
|
+
latencyMs,
|
|
353
|
+
finishReason: "stop"
|
|
354
|
+
};
|
|
355
|
+
await import_core5.globalEventBus.emit("provider:complete", {
|
|
356
|
+
provider: this.name,
|
|
357
|
+
model,
|
|
358
|
+
tokens: totalTokens,
|
|
359
|
+
latencyMs
|
|
360
|
+
});
|
|
361
|
+
return completionResponse;
|
|
362
|
+
} catch (err) {
|
|
363
|
+
const latencyMs = Date.now() - start;
|
|
364
|
+
await import_core5.globalEventBus.emit("provider:error", {
|
|
365
|
+
provider: this.name,
|
|
366
|
+
model,
|
|
367
|
+
error: err.message
|
|
368
|
+
});
|
|
369
|
+
throw new import_core4.ProviderError(this.name, err.message, { model, latencyMs });
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async *streamComplete(request) {
|
|
373
|
+
const start = Date.now();
|
|
374
|
+
const model = request.model || this.config.model || this.defaultModel;
|
|
375
|
+
await import_core5.globalEventBus.emit("provider:start", {
|
|
376
|
+
provider: this.name,
|
|
377
|
+
model
|
|
378
|
+
});
|
|
379
|
+
try {
|
|
380
|
+
const genModel = this.client.getGenerativeModel({ model });
|
|
381
|
+
const systemInstruction = request.systemPrompt;
|
|
382
|
+
const contents = this.buildContents(request);
|
|
383
|
+
const requestOptions = {
|
|
384
|
+
contents,
|
|
385
|
+
generationConfig: {
|
|
386
|
+
temperature: request.temperature ?? this.config.temperature,
|
|
387
|
+
maxOutputTokens: request.maxTokens ?? this.config.maxTokens,
|
|
388
|
+
topP: request.topP ?? this.config.topP
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
if (systemInstruction) {
|
|
392
|
+
requestOptions.systemInstruction = {
|
|
393
|
+
role: "user",
|
|
394
|
+
parts: [{ text: systemInstruction }]
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
const result = await genModel.generateContentStream(requestOptions);
|
|
398
|
+
let fullContent = "";
|
|
399
|
+
for await (const chunk of result.stream) {
|
|
400
|
+
const text = chunk.text();
|
|
401
|
+
if (text) {
|
|
402
|
+
fullContent += text;
|
|
403
|
+
yield { type: "text", text };
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const response = await result.response;
|
|
407
|
+
const usage = response.usageMetadata || {};
|
|
408
|
+
const totalTokens = (usage.promptTokenCount || 0) + (usage.candidatesTokenCount || 0);
|
|
409
|
+
yield {
|
|
410
|
+
type: "finish",
|
|
411
|
+
content: fullContent,
|
|
412
|
+
toolCalls: [],
|
|
413
|
+
usage: {
|
|
414
|
+
promptTokens: usage.promptTokenCount || 0,
|
|
415
|
+
completionTokens: usage.candidatesTokenCount || 0,
|
|
416
|
+
totalTokens
|
|
417
|
+
},
|
|
418
|
+
model,
|
|
419
|
+
finishReason: "stop"
|
|
420
|
+
};
|
|
421
|
+
await import_core5.globalEventBus.emit("provider:complete", {
|
|
422
|
+
provider: this.name,
|
|
423
|
+
model,
|
|
424
|
+
tokens: totalTokens,
|
|
425
|
+
latencyMs: Date.now() - start
|
|
426
|
+
});
|
|
427
|
+
} catch (err) {
|
|
428
|
+
await import_core5.globalEventBus.emit("provider:error", {
|
|
429
|
+
provider: this.name,
|
|
430
|
+
model,
|
|
431
|
+
error: err.message
|
|
432
|
+
});
|
|
433
|
+
throw new import_core4.ProviderError(this.name, err.message, { model, latencyMs: Date.now() - start });
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
async getModels() {
|
|
437
|
+
return ["gemini-1.5-flash", "gemini-1.5-pro", "gemini-2.0-flash-exp"];
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// src/groq.ts
|
|
442
|
+
var import_openai2 = __toESM(require("openai"), 1);
|
|
443
|
+
var import_core6 = require("@lupaflow/core");
|
|
444
|
+
var import_secrets3 = require("@lupaflow/secrets");
|
|
445
|
+
var import_core7 = require("@lupaflow/core");
|
|
446
|
+
var GroqProvider = class {
|
|
447
|
+
name = "groq";
|
|
448
|
+
defaultModel = "llama-3.3-70b-versatile";
|
|
449
|
+
config;
|
|
450
|
+
client;
|
|
451
|
+
constructor(config = {}) {
|
|
452
|
+
this.config = config;
|
|
453
|
+
this.client = new import_openai2.default({
|
|
454
|
+
apiKey: config.apiKey || (0, import_secrets3.getGroqKey)(),
|
|
455
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
validateConfig() {
|
|
459
|
+
try {
|
|
460
|
+
(0, import_secrets3.getGroqKey)();
|
|
461
|
+
return true;
|
|
462
|
+
} catch {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
buildMessages(request) {
|
|
467
|
+
const messages = [];
|
|
468
|
+
if (request.systemPrompt) {
|
|
469
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
470
|
+
}
|
|
471
|
+
for (const m of request.messages) {
|
|
472
|
+
if (m.role === "assistant" && m.toolCalls?.length) {
|
|
473
|
+
messages.push({
|
|
474
|
+
role: "assistant",
|
|
475
|
+
content: m.content,
|
|
476
|
+
tool_calls: m.toolCalls
|
|
477
|
+
});
|
|
478
|
+
} else if (m.role === "tool") {
|
|
479
|
+
messages.push({
|
|
480
|
+
role: "tool",
|
|
481
|
+
tool_call_id: m.toolCallId || "",
|
|
482
|
+
content: m.content || ""
|
|
483
|
+
});
|
|
484
|
+
} else {
|
|
485
|
+
messages.push({ role: m.role, content: m.content });
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return messages;
|
|
489
|
+
}
|
|
490
|
+
buildTools(tools) {
|
|
491
|
+
return tools?.map((t) => ({
|
|
492
|
+
type: "function",
|
|
493
|
+
function: {
|
|
494
|
+
name: t.definition.name,
|
|
495
|
+
description: t.definition.description,
|
|
496
|
+
parameters: {
|
|
497
|
+
type: "object",
|
|
498
|
+
properties: t.definition.parameters,
|
|
499
|
+
required: t.definition.required
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}));
|
|
503
|
+
}
|
|
504
|
+
async complete(request) {
|
|
505
|
+
const start = Date.now();
|
|
506
|
+
const model = request.model || this.config.model || this.defaultModel;
|
|
507
|
+
await import_core7.globalEventBus.emit("provider:start", {
|
|
508
|
+
provider: this.name,
|
|
509
|
+
model
|
|
510
|
+
});
|
|
511
|
+
try {
|
|
512
|
+
const messages = this.buildMessages(request);
|
|
513
|
+
const tools = this.buildTools(request.tools);
|
|
514
|
+
const response = await this.client.chat.completions.create({
|
|
515
|
+
model,
|
|
516
|
+
messages,
|
|
517
|
+
tools,
|
|
518
|
+
temperature: request.temperature ?? this.config.temperature,
|
|
519
|
+
max_tokens: request.maxTokens ?? this.config.maxTokens,
|
|
520
|
+
top_p: request.topP ?? this.config.topP
|
|
521
|
+
});
|
|
522
|
+
const choice = response.choices[0];
|
|
523
|
+
const latencyMs = Date.now() - start;
|
|
524
|
+
const result = {
|
|
525
|
+
content: choice.message.content,
|
|
526
|
+
toolCalls: (choice.message.tool_calls || []).map((tc) => ({
|
|
527
|
+
id: tc.id,
|
|
528
|
+
name: tc.function.name,
|
|
529
|
+
args: JSON.parse(tc.function.arguments)
|
|
530
|
+
})),
|
|
531
|
+
usage: {
|
|
532
|
+
promptTokens: response.usage?.prompt_tokens || 0,
|
|
533
|
+
completionTokens: response.usage?.completion_tokens || 0,
|
|
534
|
+
totalTokens: response.usage?.total_tokens || 0
|
|
535
|
+
},
|
|
536
|
+
model: response.model,
|
|
537
|
+
latencyMs,
|
|
538
|
+
finishReason: choice.finish_reason || "stop"
|
|
539
|
+
};
|
|
540
|
+
await import_core7.globalEventBus.emit("provider:complete", {
|
|
541
|
+
provider: this.name,
|
|
542
|
+
model,
|
|
543
|
+
tokens: result.usage.totalTokens,
|
|
544
|
+
latencyMs
|
|
545
|
+
});
|
|
546
|
+
return result;
|
|
547
|
+
} catch (err) {
|
|
548
|
+
const latencyMs = Date.now() - start;
|
|
549
|
+
await import_core7.globalEventBus.emit("provider:error", {
|
|
550
|
+
provider: this.name,
|
|
551
|
+
model,
|
|
552
|
+
error: err.message
|
|
553
|
+
});
|
|
554
|
+
throw new import_core6.ProviderError(this.name, err.message, { model, latencyMs });
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
async *streamComplete(request) {
|
|
558
|
+
const start = Date.now();
|
|
559
|
+
const model = request.model || this.config.model || this.defaultModel;
|
|
560
|
+
await import_core7.globalEventBus.emit("provider:start", {
|
|
561
|
+
provider: this.name,
|
|
562
|
+
model
|
|
563
|
+
});
|
|
564
|
+
try {
|
|
565
|
+
const messages = this.buildMessages(request);
|
|
566
|
+
const tools = this.buildTools(request.tools);
|
|
567
|
+
const stream = await this.client.chat.completions.create({
|
|
568
|
+
model,
|
|
569
|
+
messages,
|
|
570
|
+
tools,
|
|
571
|
+
temperature: request.temperature ?? this.config.temperature,
|
|
572
|
+
max_tokens: request.maxTokens ?? this.config.maxTokens,
|
|
573
|
+
top_p: request.topP ?? this.config.topP,
|
|
574
|
+
stream: true
|
|
575
|
+
});
|
|
576
|
+
let fullContent = "";
|
|
577
|
+
const accToolCalls = /* @__PURE__ */ new Map();
|
|
578
|
+
for await (const chunk of stream) {
|
|
579
|
+
const delta = chunk.choices[0]?.delta;
|
|
580
|
+
if (delta?.content) {
|
|
581
|
+
fullContent += delta.content;
|
|
582
|
+
yield { type: "text", text: delta.content };
|
|
583
|
+
}
|
|
584
|
+
if (delta?.tool_calls) {
|
|
585
|
+
for (const tc of delta.tool_calls) {
|
|
586
|
+
if (!accToolCalls.has(tc.index)) {
|
|
587
|
+
accToolCalls.set(tc.index, { id: "", name: "", args: "" });
|
|
588
|
+
}
|
|
589
|
+
const entry = accToolCalls.get(tc.index);
|
|
590
|
+
if (tc.id) entry.id = tc.id;
|
|
591
|
+
if (tc.function?.name) entry.name = tc.function.name;
|
|
592
|
+
if (tc.function?.arguments) entry.args += tc.function.arguments;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (chunk.choices[0]?.finish_reason) {
|
|
596
|
+
const finishReason = chunk.choices[0].finish_reason;
|
|
597
|
+
const toolCalls = Array.from(accToolCalls.values()).filter((tc) => tc.id && tc.name).map((tc) => ({
|
|
598
|
+
id: tc.id,
|
|
599
|
+
name: tc.name,
|
|
600
|
+
args: JSON.parse(tc.args || "{}")
|
|
601
|
+
}));
|
|
602
|
+
yield {
|
|
603
|
+
type: "finish",
|
|
604
|
+
content: fullContent,
|
|
605
|
+
toolCalls,
|
|
606
|
+
usage: {
|
|
607
|
+
promptTokens: chunk.usage?.prompt_tokens || 0,
|
|
608
|
+
completionTokens: chunk.usage?.completion_tokens || 0,
|
|
609
|
+
totalTokens: chunk.usage?.total_tokens || 0
|
|
610
|
+
},
|
|
611
|
+
model,
|
|
612
|
+
finishReason
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
await import_core7.globalEventBus.emit("provider:complete", {
|
|
617
|
+
provider: this.name,
|
|
618
|
+
model,
|
|
619
|
+
tokens: 0,
|
|
620
|
+
latencyMs: Date.now() - start
|
|
621
|
+
});
|
|
622
|
+
} catch (err) {
|
|
623
|
+
await import_core7.globalEventBus.emit("provider:error", {
|
|
624
|
+
provider: this.name,
|
|
625
|
+
model,
|
|
626
|
+
error: err.message
|
|
627
|
+
});
|
|
628
|
+
throw new import_core6.ProviderError(this.name, err.message, { model, latencyMs: Date.now() - start });
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
async getModels() {
|
|
632
|
+
try {
|
|
633
|
+
const response = await fetch("https://api.groq.com/openai/v1/models", {
|
|
634
|
+
headers: {
|
|
635
|
+
Authorization: `Bearer ${(0, import_secrets3.getGroqKey)()}`
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
const data = await response.json();
|
|
639
|
+
return data.data?.map((m) => m.id) || [];
|
|
640
|
+
} catch {
|
|
641
|
+
return [this.defaultModel];
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
// src/index.ts
|
|
647
|
+
providerRegistry.register("openrouter", OpenRouterProvider);
|
|
648
|
+
providerRegistry.register("google", GoogleProvider);
|
|
649
|
+
providerRegistry.register("groq", GroqProvider);
|
|
650
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
651
|
+
0 && (module.exports = {
|
|
652
|
+
GoogleProvider,
|
|
653
|
+
GroqProvider,
|
|
654
|
+
OpenRouterProvider,
|
|
655
|
+
providerRegistry
|
|
656
|
+
});
|
|
657
|
+
//# sourceMappingURL=index.cjs.map
|