@imenam/unified-llm-client 2.2.0 → 2.3.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 (32) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +383 -359
  3. package/dist/adapters/openrouter/OpenRouterLogAdapter.d.ts +11 -0
  4. package/dist/adapters/openrouter/OpenRouterLogAdapter.d.ts.map +1 -0
  5. package/dist/adapters/openrouter/OpenRouterLogAdapter.js +51 -0
  6. package/dist/adapters/openrouter/OpenRouterOutputAdapter.d.ts +6 -0
  7. package/dist/adapters/openrouter/OpenRouterOutputAdapter.d.ts.map +1 -0
  8. package/dist/adapters/openrouter/OpenRouterOutputAdapter.js +9 -0
  9. package/dist/adapters/openrouter/OpenRouterPromptAdapter.d.ts +15 -0
  10. package/dist/adapters/openrouter/OpenRouterPromptAdapter.d.ts.map +1 -0
  11. package/dist/adapters/openrouter/OpenRouterPromptAdapter.js +374 -0
  12. package/dist/adapters/openrouter/OpenRouterToolAdapter.d.ts +6 -0
  13. package/dist/adapters/openrouter/OpenRouterToolAdapter.d.ts.map +1 -0
  14. package/dist/adapters/openrouter/OpenRouterToolAdapter.js +16 -0
  15. package/dist/common/types.d.ts +10 -1
  16. package/dist/common/types.d.ts.map +1 -1
  17. package/dist/core/LLMAdapter.d.ts.map +1 -1
  18. package/dist/core/LLMAdapter.js +16 -0
  19. package/dist/core/Models.d.ts +6 -0
  20. package/dist/core/Models.d.ts.map +1 -1
  21. package/dist/core/Models.js +9 -0
  22. package/dist/core/UnifiedLLMClient.d.ts +2 -2
  23. package/dist/core/UnifiedLLMClient.d.ts.map +1 -1
  24. package/dist/core/UnifiedLLMClient.js +1 -1
  25. package/dist/examples/audio-example.js +1 -1
  26. package/dist/examples/example.js +16 -16
  27. package/dist/examples/qwen-omni-audio-example.js +5 -5
  28. package/dist/examples/qwen-vl-example.js +7 -7
  29. package/dist/index.d.ts +5 -4
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +4 -1
  32. package/package.json +71 -71
@@ -0,0 +1,11 @@
1
+ import { UnifiedLog } from "../../common/types";
2
+ import { LogAdapter, LogData } from "../../core/LLMAdapter";
3
+ export declare class OpenRouterLogAdapter implements LogAdapter {
4
+ /**
5
+ * Remplace les données base64 (images, PDF, audio) par un marqueur avant
6
+ * journalisation. Les messages reçus ne sont pas modifiés.
7
+ */
8
+ removeAttachments(messages: any[]): any[];
9
+ toUnifiedLog(data: LogData): UnifiedLog;
10
+ }
11
+ //# sourceMappingURL=OpenRouterLogAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenRouterLogAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/openrouter/OpenRouterLogAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAE5D,qBAAa,oBAAqB,YAAW,UAAU;IACrD;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE;IAsBzC,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU;CAmCxC"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenRouterLogAdapter = void 0;
4
+ class OpenRouterLogAdapter {
5
+ /**
6
+ * Remplace les données base64 (images, PDF, audio) par un marqueur avant
7
+ * journalisation. Les messages reçus ne sont pas modifiés.
8
+ */
9
+ removeAttachments(messages) {
10
+ return messages.map((message) => {
11
+ if (!Array.isArray(message === null || message === void 0 ? void 0 : message.content))
12
+ return message;
13
+ return Object.assign(Object.assign({}, message), { content: message.content.map((content) => {
14
+ var _a, _b, _c;
15
+ if ((content === null || content === void 0 ? void 0 : content.type) === "image_url" && typeof ((_a = content.image_url) === null || _a === void 0 ? void 0 : _a.url) === "string") {
16
+ return Object.assign(Object.assign({}, content), { image_url: Object.assign(Object.assign({}, content.image_url), { url: content.image_url.url.split(",")[0] + "removed" }) });
17
+ }
18
+ if ((content === null || content === void 0 ? void 0 : content.type) === "file" && typeof ((_b = content.file) === null || _b === void 0 ? void 0 : _b.file_data) === "string") {
19
+ return Object.assign(Object.assign({}, content), { file: Object.assign(Object.assign({}, content.file), { file_data: content.file.file_data.split(",")[0] + "removed" }) });
20
+ }
21
+ if ((content === null || content === void 0 ? void 0 : content.type) === "input_audio" && typeof ((_c = content.input_audio) === null || _c === void 0 ? void 0 : _c.data) === "string") {
22
+ return Object.assign(Object.assign({}, content), { input_audio: Object.assign(Object.assign({}, content.input_audio), { data: "removed" }) });
23
+ }
24
+ return content;
25
+ }) });
26
+ });
27
+ }
28
+ toUnifiedLog(data) {
29
+ var _a, _b, _c, _d, _e, _f, _g;
30
+ const { model, provider, messages, response, latencyMs, metadata } = data;
31
+ const usage = response.usage;
32
+ const rawUsage = (_a = response.raw) === null || _a === void 0 ? void 0 : _a.usage;
33
+ return {
34
+ requestId: ((_b = response.raw) === null || _b === void 0 ? void 0 : _b.id) || `openrouter-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
35
+ timestamp: new Date(),
36
+ provider: provider,
37
+ model,
38
+ prompt: this.removeAttachments(messages),
39
+ output: Object.assign({ content: response.content, toolCalls: response.toolCalls, finishReason: response.finishReason }, (response.error ? { error: response.error } : {})),
40
+ usage: Object.assign({ promptTokens: (_c = usage === null || usage === void 0 ? void 0 : usage.promptTokens) !== null && _c !== void 0 ? _c : 0, completionTokens: (_d = usage === null || usage === void 0 ? void 0 : usage.completionTokens) !== null && _d !== void 0 ? _d : 0, totalTokens: (_e = usage === null || usage === void 0 ? void 0 : usage.totalTokens) !== null && _e !== void 0 ? _e : 0, promptDetails: {
41
+ cachedTokens: (_f = rawUsage === null || rawUsage === void 0 ? void 0 : rawUsage.prompt_tokens_details) === null || _f === void 0 ? void 0 : _f.cached_tokens,
42
+ audioTokens: (_g = rawUsage === null || rawUsage === void 0 ? void 0 : rawUsage.prompt_tokens_details) === null || _g === void 0 ? void 0 : _g.audio_tokens,
43
+ }, completionDetails: {
44
+ thinkingTokens: usage === null || usage === void 0 ? void 0 : usage.thoughtsToken,
45
+ } }, (typeof (usage === null || usage === void 0 ? void 0 : usage.cost) === "number" ? { cost: usage.cost } : {})),
46
+ latencyMs,
47
+ metadata,
48
+ };
49
+ }
50
+ }
51
+ exports.OpenRouterLogAdapter = OpenRouterLogAdapter;
@@ -0,0 +1,6 @@
1
+ import { ChatResponse } from "../../common/types";
2
+ import { OutputAdapter } from "../../core/LLMAdapter";
3
+ export declare class OpenRouterOutputAdapter implements OutputAdapter {
4
+ parse(providerResponse: any): ChatResponse;
5
+ }
6
+ //# sourceMappingURL=OpenRouterOutputAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenRouterOutputAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/openrouter/OpenRouterOutputAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,qBAAa,uBAAwB,YAAW,aAAa;IACpD,KAAK,CAAC,gBAAgB,EAAE,GAAG,GAAG,YAAY;CAGlD"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenRouterOutputAdapter = void 0;
4
+ class OpenRouterOutputAdapter {
5
+ parse(providerResponse) {
6
+ return providerResponse;
7
+ }
8
+ }
9
+ exports.OpenRouterOutputAdapter = OpenRouterOutputAdapter;
@@ -0,0 +1,15 @@
1
+ import { PromptAdapterOptions, PromptAdapter, ChatStreamOptions, ChatOptionalConfig } from "../../core/LLMAdapter";
2
+ import { ChatMessage, ToolDefinition, ChatResponse } from "../../common/types";
3
+ export declare const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
4
+ export declare class OpenRouterPromptAdapter implements PromptAdapter {
5
+ private readonly opts;
6
+ private readonly endpoint;
7
+ constructor(opts: PromptAdapterOptions);
8
+ formatMessage(message: ChatMessage): any;
9
+ sendToProvider(messages: any, tools?: ToolDefinition[], toolChoice?: "auto" | "none" | string, attachedFile?: string | string[], model?: string, config?: ChatOptionalConfig): Promise<ChatResponse>;
10
+ streamFromProvider({ messages, tools, toolChoice, model, onChunk, onFinalResponse, config, }: ChatStreamOptions): Promise<ChatResponse>;
11
+ private buildBody;
12
+ private post;
13
+ private request;
14
+ }
15
+ //# sourceMappingURL=OpenRouterPromptAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenRouterPromptAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/openrouter/OpenRouterPromptAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACnH,OAAO,EAAE,WAAW,EAAY,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIzF,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAiFlE,qBAAa,uBAAwB,YAAW,aAAa;IAG/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEL,IAAI,EAAE,oBAAoB;IAIhD,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,GAAG;IAiCzC,cAAc,CAClB,QAAQ,EAAE,GAAG,EACb,KAAK,GAAE,cAAc,EAAO,EAC5B,UAAU,GAAE,MAAM,GAAG,MAAM,GAAG,MAAe,EAC7C,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EAChC,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC;IAkClB,kBAAkB,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,UAAU,EACV,KAAK,EACL,OAAO,EACP,eAAe,EACf,MAAM,GACP,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;IA0H5C,OAAO,CAAC,SAAS;YAkCH,IAAI;YAmBJ,OAAO;CAItB"}
@@ -0,0 +1,374 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __rest = (this && this.__rest) || function (s, e) {
45
+ var t = {};
46
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
47
+ t[p] = s[p];
48
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
49
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
50
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
51
+ t[p[i]] = s[p[i]];
52
+ }
53
+ return t;
54
+ };
55
+ var __importDefault = (this && this.__importDefault) || function (mod) {
56
+ return (mod && mod.__esModule) ? mod : { "default": mod };
57
+ };
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.OpenRouterPromptAdapter = exports.OPENROUTER_BASE_URL = void 0;
60
+ const node_fetch_1 = __importDefault(require("node-fetch"));
61
+ const fs = __importStar(require("fs"));
62
+ const path = __importStar(require("path"));
63
+ exports.OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
64
+ const IMAGE_MIME_TYPES = {
65
+ ".jpg": "image/jpeg",
66
+ ".jpeg": "image/jpeg",
67
+ ".png": "image/png",
68
+ ".gif": "image/gif",
69
+ ".webp": "image/webp",
70
+ };
71
+ /** Extensions audio acceptées en `input_audio`, associées à la valeur de `format`. */
72
+ const AUDIO_FORMATS = {
73
+ ".mp3": "mp3",
74
+ ".wav": "wav",
75
+ };
76
+ /**
77
+ * Parse les arguments d'un appel d'outil. Des arguments non parsables sont
78
+ * renvoyés sous `_raw` plutôt que de faire échouer tout l'appel.
79
+ */
80
+ function parseToolArguments(raw) {
81
+ if (raw && typeof raw === "object")
82
+ return raw;
83
+ try {
84
+ return JSON.parse(raw || "{}");
85
+ }
86
+ catch (_a) {
87
+ return { _raw: raw };
88
+ }
89
+ }
90
+ /**
91
+ * Regroupe par `index` les fragments de tool calls reçus en streaming : le
92
+ * premier fragment porte l'identifiant et le nom, les suivants complètent
93
+ * `arguments`.
94
+ */
95
+ function accumulateToolCalls(deltaToolCalls, parts) {
96
+ deltaToolCalls.forEach((toolCall, position) => {
97
+ var _a, _b, _c;
98
+ const index = typeof toolCall.index === "number" ? toolCall.index : position;
99
+ const current = (_a = parts.get(index)) !== null && _a !== void 0 ? _a : { name: "", arguments: "" };
100
+ if (toolCall.id)
101
+ current.id = toolCall.id;
102
+ if ((_b = toolCall.function) === null || _b === void 0 ? void 0 : _b.name)
103
+ current.name = toolCall.function.name;
104
+ if (typeof ((_c = toolCall.function) === null || _c === void 0 ? void 0 : _c.arguments) === "string") {
105
+ current.arguments += toolCall.function.arguments;
106
+ }
107
+ parts.set(index, current);
108
+ });
109
+ }
110
+ function finalizeToolCalls(parts) {
111
+ return [...parts.entries()]
112
+ .sort(([a], [b]) => a - b)
113
+ .map(([, part]) => ({ id: part.id, name: part.name, arguments: parseToolArguments(part.arguments) }));
114
+ }
115
+ /** Convertit l'usage OpenRouter (format OpenAI + `cost`) en usage unifié. */
116
+ function toUsage(usage) {
117
+ var _a, _b, _c, _d, _e;
118
+ if (!usage)
119
+ return undefined;
120
+ return Object.assign({ promptTokens: (_a = usage.prompt_tokens) !== null && _a !== void 0 ? _a : 0, completionTokens: (_b = usage.completion_tokens) !== null && _b !== void 0 ? _b : 0, totalTokens: (_c = usage.total_tokens) !== null && _c !== void 0 ? _c : 0, promptTokensDetails: usage.prompt_tokens_details, thoughtsToken: (_e = (_d = usage.completion_tokens_details) === null || _d === void 0 ? void 0 : _d.reasoning_tokens) !== null && _e !== void 0 ? _e : 0 }, (typeof usage.cost === "number" ? { cost: usage.cost } : {}));
121
+ }
122
+ /**
123
+ * Message d'erreur d'un choix interrompu. Le `native_finish_reason` (ex.
124
+ * `MALFORMED_FUNCTION_CALL` chez Gemini) y figure pour que l'appelant puisse
125
+ * réagir aux erreurs propres au modèle sous-jacent.
126
+ */
127
+ function choiceErrorMessage(choice) {
128
+ var _a;
129
+ const native = (choice === null || choice === void 0 ? void 0 : choice.native_finish_reason) ? ` (${choice.native_finish_reason})` : "";
130
+ const detail = ((_a = choice === null || choice === void 0 ? void 0 : choice.error) === null || _a === void 0 ? void 0 : _a.message) ? `: ${choice.error.message}` : "";
131
+ return `OpenRouter: generation failed${native}${detail}`;
132
+ }
133
+ class OpenRouterPromptAdapter {
134
+ constructor(opts) {
135
+ var _a, _b;
136
+ this.opts = opts;
137
+ this.endpoint = ((_b = (_a = opts.baseUrl) === null || _a === void 0 ? void 0 : _a.replace(/\/$/, "")) !== null && _b !== void 0 ? _b : exports.OPENROUTER_BASE_URL) + "/chat/completions";
138
+ }
139
+ formatMessage(message) {
140
+ var _a;
141
+ if (message.role === "assistant" && message.tool_calls && message.tool_calls.length > 0) {
142
+ return Object.assign({ role: "assistant", content: (_a = message.content) !== null && _a !== void 0 ? _a : null, tool_calls: message.tool_calls.map(tc => {
143
+ var _a;
144
+ return ({
145
+ id: (_a = tc.id) !== null && _a !== void 0 ? _a : tc.name,
146
+ type: "function",
147
+ function: {
148
+ name: tc.name,
149
+ arguments: JSON.stringify(tc.arguments),
150
+ },
151
+ });
152
+ }) }, (message.reasoningDetails ? { reasoning_details: message.reasoningDetails } : {}));
153
+ }
154
+ if (message.attachedFile) {
155
+ const textPart = message.content && typeof message.content === "string" ? { type: "text", text: message.content } : null;
156
+ const files = Array.isArray(message.attachedFile) ? message.attachedFile : [message.attachedFile];
157
+ const fileParts = files.filter((file) => typeof file === "string").map(toContentPart);
158
+ return {
159
+ role: message.role,
160
+ content: [...(textPart ? [textPart] : []), ...fileParts],
161
+ };
162
+ }
163
+ const { attachedFile, reasoningDetails } = message, rest = __rest(message, ["attachedFile", "reasoningDetails"]);
164
+ return rest;
165
+ }
166
+ sendToProvider(messages_1) {
167
+ return __awaiter(this, arguments, void 0, function* (messages, tools = [], toolChoice = "auto", attachedFile, model, config) {
168
+ var _a, _b, _c, _d, _e, _f, _g;
169
+ const body = this.buildBody(messages, tools, toolChoice, model, config, false);
170
+ const response = yield this.request(body, config);
171
+ if (response.error) {
172
+ throw new Error(`OpenRouter ${(_a = response.error.code) !== null && _a !== void 0 ? _a : ""}: ${(_b = response.error.message) !== null && _b !== void 0 ? _b : JSON.stringify(response.error)}`);
173
+ }
174
+ const choice = (_c = response.choices) === null || _c === void 0 ? void 0 : _c[0];
175
+ if (!choice) {
176
+ throw new Error(`OpenRouter: empty response ${JSON.stringify(response).slice(0, 500)}`);
177
+ }
178
+ if (choice.finish_reason === "error" || choice.error) {
179
+ throw new Error(choiceErrorMessage(choice));
180
+ }
181
+ const responseMessage = (_d = choice.message) !== null && _d !== void 0 ? _d : {};
182
+ const calls = (responseMessage.tool_calls || []).map((c) => ({
183
+ id: c.id,
184
+ name: c.function.name,
185
+ arguments: parseToolArguments(c.function.arguments),
186
+ }));
187
+ return Object.assign(Object.assign({ content: (_e = responseMessage.content) !== null && _e !== void 0 ? _e : null, toolCalls: calls, raw: response, usage: toUsage(response.usage), finishReason: (_f = choice.native_finish_reason) !== null && _f !== void 0 ? _f : choice.finish_reason }, (((_g = responseMessage.reasoning_details) === null || _g === void 0 ? void 0 : _g.length) ? { reasoningDetails: responseMessage.reasoning_details } : {})), (calls.length ? { lastToolArguments: calls[calls.length - 1].arguments } : {}));
188
+ });
189
+ }
190
+ streamFromProvider(_a) {
191
+ return __awaiter(this, arguments, void 0, function* ({ messages, tools, toolChoice, model, onChunk, onFinalResponse, config, }) {
192
+ const body = this.buildBody(messages, tools !== null && tools !== void 0 ? tools : [], toolChoice !== null && toolChoice !== void 0 ? toolChoice : "auto", model, config, true);
193
+ const signal = config === null || config === void 0 ? void 0 : config.signal;
194
+ const response = yield this.post(body, signal);
195
+ if (!response.body) {
196
+ throw new Error("Response body is not available for streaming");
197
+ }
198
+ return new Promise((resolve, reject) => {
199
+ let settled = false;
200
+ let abortHandler;
201
+ const finish = (fn) => {
202
+ if (settled)
203
+ return;
204
+ settled = true;
205
+ if (signal && abortHandler) {
206
+ signal.removeEventListener("abort", abortHandler);
207
+ }
208
+ fn();
209
+ };
210
+ if (signal) {
211
+ abortHandler = () => {
212
+ var _a, _b;
213
+ try {
214
+ (_b = (_a = response.body) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
215
+ }
216
+ catch (_c) {
217
+ /* ignore */
218
+ }
219
+ const err = new Error("The operation was aborted");
220
+ err.name = "AbortError";
221
+ finish(() => reject(err));
222
+ };
223
+ if (signal.aborted) {
224
+ abortHandler();
225
+ return;
226
+ }
227
+ signal.addEventListener("abort", abortHandler, { once: true });
228
+ }
229
+ let aggregatedContent = "";
230
+ const toolCallParts = new Map();
231
+ const reasoningDetails = [];
232
+ let buffer = "";
233
+ let streamUsage = null;
234
+ let finishReason = null;
235
+ let lastChunk = null;
236
+ let streamError = null;
237
+ // Les lignes commençant par « : » sont des commentaires SSE (keep-alive OpenRouter).
238
+ const handleLine = (line) => {
239
+ var _a, _b, _c, _d;
240
+ if (!line.startsWith("data: "))
241
+ return;
242
+ const data = line.slice(6).trim();
243
+ if (data === "[DONE]")
244
+ return;
245
+ let parsed;
246
+ try {
247
+ parsed = JSON.parse(data);
248
+ }
249
+ catch (e) {
250
+ console.warn("Malformed chunk:", e);
251
+ return;
252
+ }
253
+ lastChunk = parsed;
254
+ if (parsed.usage)
255
+ streamUsage = parsed.usage;
256
+ if (parsed.error)
257
+ streamError = `OpenRouter ${(_a = parsed.error.code) !== null && _a !== void 0 ? _a : ""}: ${(_b = parsed.error.message) !== null && _b !== void 0 ? _b : ""}`;
258
+ const choice = (_c = parsed.choices) === null || _c === void 0 ? void 0 : _c[0];
259
+ if (!choice)
260
+ return;
261
+ if (choice.finish_reason === "error")
262
+ streamError = choiceErrorMessage(choice);
263
+ if (choice.finish_reason)
264
+ finishReason = (_d = choice.native_finish_reason) !== null && _d !== void 0 ? _d : choice.finish_reason;
265
+ const delta = choice.delta;
266
+ if (delta === null || delta === void 0 ? void 0 : delta.content) {
267
+ aggregatedContent += delta.content;
268
+ onChunk === null || onChunk === void 0 ? void 0 : onChunk({ contentChunk: delta.content, rawChunk: parsed });
269
+ }
270
+ if (delta === null || delta === void 0 ? void 0 : delta.tool_calls) {
271
+ accumulateToolCalls(delta.tool_calls, toolCallParts);
272
+ }
273
+ if (Array.isArray(delta === null || delta === void 0 ? void 0 : delta.reasoning_details)) {
274
+ reasoningDetails.push(...delta.reasoning_details);
275
+ }
276
+ };
277
+ response.body.on("data", (chunk) => {
278
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted)
279
+ return;
280
+ buffer += chunk.toString("utf8");
281
+ const lines = buffer.split("\n");
282
+ buffer = lines.pop() || "";
283
+ lines.forEach(handleLine);
284
+ });
285
+ response.body.on("end", () => {
286
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted)
287
+ return;
288
+ buffer.split("\n").forEach(handleLine);
289
+ if (streamError) {
290
+ finish(() => reject(new Error(streamError)));
291
+ return;
292
+ }
293
+ const aggregatedToolCalls = finalizeToolCalls(toolCallParts);
294
+ const finalResponse = Object.assign(Object.assign({ content: aggregatedContent, toolCalls: aggregatedToolCalls.length > 0 ? aggregatedToolCalls : undefined, raw: lastChunk ? Object.assign(Object.assign({}, lastChunk), { usage: streamUsage }) : null, usage: toUsage(streamUsage) }, (finishReason ? { finishReason } : {})), (reasoningDetails.length ? { reasoningDetails } : {}));
295
+ onFinalResponse === null || onFinalResponse === void 0 ? void 0 : onFinalResponse(finalResponse);
296
+ finish(() => resolve(finalResponse));
297
+ });
298
+ response.body.on("error", (error) => {
299
+ finish(() => reject(new Error(`Stream error: ${error.message}`)));
300
+ });
301
+ });
302
+ });
303
+ }
304
+ //--------------------------------------------------
305
+ buildBody(messages, tools, toolChoice, model, config, stream) {
306
+ const body = {
307
+ model: model || this.opts.model,
308
+ messages,
309
+ stream,
310
+ usage: { include: true },
311
+ };
312
+ if (tools.length) {
313
+ // Les executors sont des fonctions locales : ils ne partent pas dans la requête.
314
+ body.tools = tools.map((_a) => {
315
+ var { executor } = _a, fn = __rest(_a, ["executor"]);
316
+ return ({ type: "function", function: fn });
317
+ });
318
+ body.tool_choice =
319
+ toolChoice === "auto"
320
+ ? "auto"
321
+ : toolChoice === "none"
322
+ ? "none"
323
+ : { type: "function", function: { name: toolChoice } };
324
+ }
325
+ // `thinkingBudget` non défini : on laisse le réglage par défaut du modèle.
326
+ if (typeof (config === null || config === void 0 ? void 0 : config.thinkingBudget) === "number" && config.thinkingBudget > 0) {
327
+ body.reasoning = { max_tokens: config.thinkingBudget };
328
+ }
329
+ return body;
330
+ }
331
+ post(body, signal) {
332
+ return __awaiter(this, void 0, void 0, function* () {
333
+ const res = yield (0, node_fetch_1.default)(this.endpoint, Object.assign({ method: "POST", headers: Object.assign(Object.assign({ "Content-Type": "application/json", Authorization: `Bearer ${this.opts.apiKey}` }, (process.env.OPENROUTER_APP_URL ? { "HTTP-Referer": process.env.OPENROUTER_APP_URL } : {})), (process.env.OPENROUTER_APP_NAME ? { "X-Title": process.env.OPENROUTER_APP_NAME } : {})), body: JSON.stringify(body) }, (signal ? { signal: signal } : {})));
334
+ if (!res.ok) {
335
+ throw new Error(`OpenRouter API ${res.status}: ${yield res.text()}`);
336
+ }
337
+ return res;
338
+ });
339
+ }
340
+ request(body, config) {
341
+ return __awaiter(this, void 0, void 0, function* () {
342
+ const res = yield this.post(body, config === null || config === void 0 ? void 0 : config.signal);
343
+ return res.json();
344
+ });
345
+ }
346
+ }
347
+ exports.OpenRouterPromptAdapter = OpenRouterPromptAdapter;
348
+ /** Convertit un fichier local (ou une URL) en élément de contenu OpenRouter. */
349
+ function toContentPart(file) {
350
+ if (/^https?:\/\//.test(file)) {
351
+ return /\.pdf($|\?)/i.test(file)
352
+ ? { type: "file", file: { filename: path.basename(new URL(file).pathname), file_data: file } }
353
+ : { type: "image_url", image_url: { url: file } };
354
+ }
355
+ const filePath = path.resolve(file);
356
+ const ext = path.extname(filePath).toLowerCase();
357
+ // Les erreurs de lecture sont propagées : un fichier manquant ne doit pas partir en silence.
358
+ const base64Data = fs.readFileSync(filePath).toString("base64");
359
+ if (ext === ".pdf") {
360
+ return {
361
+ type: "file",
362
+ file: { filename: path.basename(filePath), file_data: `data:application/pdf;base64,${base64Data}` },
363
+ };
364
+ }
365
+ const audioFormat = AUDIO_FORMATS[ext];
366
+ if (audioFormat) {
367
+ return { type: "input_audio", input_audio: { data: base64Data, format: audioFormat } };
368
+ }
369
+ const mimeType = IMAGE_MIME_TYPES[ext];
370
+ if (!mimeType) {
371
+ throw new Error(`Attached file type ${ext || "(none)"} is not supported by the OpenRouter adapter: ${file}`);
372
+ }
373
+ return { type: "image_url", image_url: { url: `data:${mimeType};base64,${base64Data}` } };
374
+ }
@@ -0,0 +1,6 @@
1
+ import { ToolCall } from "../../common/types";
2
+ import { ToolAdapter } from "../../core/LLMAdapter";
3
+ export declare class OpenRouterToolAdapter implements ToolAdapter {
4
+ formatToolCallResult(toolCall: ToolCall): any;
5
+ }
6
+ //# sourceMappingURL=OpenRouterToolAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenRouterToolAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/openrouter/OpenRouterToolAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,qBAAa,qBAAsB,YAAW,WAAW;IACvD,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,GAAG;CAU9C"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenRouterToolAdapter = void 0;
4
+ class OpenRouterToolAdapter {
5
+ formatToolCallResult(toolCall) {
6
+ if (!toolCall.id) {
7
+ throw new Error("Tool call ID is required to format response - toolCall: " + JSON.stringify(toolCall));
8
+ }
9
+ return {
10
+ tool_call_id: toolCall.id,
11
+ role: "tool",
12
+ content: typeof toolCall.result === "string" ? toolCall.result : JSON.stringify(toolCall.result),
13
+ };
14
+ }
15
+ }
16
+ exports.OpenRouterToolAdapter = OpenRouterToolAdapter;
@@ -1,4 +1,4 @@
1
- export type Provider = "openai" | "gemini" | "qwen" | "anthropic";
1
+ export type Provider = "openai" | "gemini" | "qwen" | "anthropic" | "openrouter";
2
2
  /**
3
3
  * Resolves the API key for an LLM call.
4
4
  *
@@ -25,6 +25,9 @@ export interface ChatMessage {
25
25
  /** Tool calls declared by the assistant (for multi-turn conversations).
26
26
  * For Gemini tool results (role: "tool"), set tool_call_id to the function name. */
27
27
  tool_calls?: ToolCall[];
28
+ /** OpenRouter : blocs de raisonnement renvoyés avec un appel d'outil. Ils doivent
29
+ * revenir tels quels sur le message assistant du tour suivant (Gemini 3, Claude…). */
30
+ reasoningDetails?: unknown[];
28
31
  }
29
32
  export interface ToolDefinition {
30
33
  name: string;
@@ -49,8 +52,12 @@ export interface ChatResponse {
49
52
  totalTokens: number;
50
53
  promptTokensDetails: any;
51
54
  thoughtsToken: number;
55
+ /** Coût réel de l'appel en USD, quand le provider le fournit (OpenRouter). */
56
+ cost?: number;
52
57
  };
53
58
  finishReason?: string;
59
+ /** OpenRouter : blocs de raisonnement à recopier dans `ChatMessage.reasoningDetails`. */
60
+ reasoningDetails?: unknown[];
54
61
  requestId?: string;
55
62
  llmLogId?: number;
56
63
  error?: string;
@@ -84,6 +91,8 @@ export interface UnifiedUsage {
84
91
  audioTokens?: number;
85
92
  thinkingTokens?: number;
86
93
  };
94
+ /** Coût réel de l'appel en USD, quand le provider le fournit (OpenRouter). */
95
+ cost?: number;
87
96
  }
88
97
  export interface UnifiedLog {
89
98
  requestId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"LLMAdapter.d.ts","sourceRoot":"","sources":["../../src/core/LLMAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LLMAdapter.d.ts","sourceRoot":"","sources":["../../src/core/LLMAdapter.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,10 @@ const AnthropicPromptAdapter_1 = require("../adapters/anthropic/AnthropicPromptA
21
21
  const AnthropicOutputAdapter_1 = require("../adapters/anthropic/AnthropicOutputAdapter");
22
22
  const AnthropicToolAdapter_1 = require("../adapters/anthropic/AnthropicToolAdapter");
23
23
  const AnthropicLogAdapter_1 = require("../adapters/anthropic/AnthropicLogAdapter");
24
+ const OpenRouterPromptAdapter_1 = require("../adapters/openrouter/OpenRouterPromptAdapter");
25
+ const OpenRouterOutputAdapter_1 = require("../adapters/openrouter/OpenRouterOutputAdapter");
26
+ const OpenRouterToolAdapter_1 = require("../adapters/openrouter/OpenRouterToolAdapter");
27
+ const OpenRouterLogAdapter_1 = require("../adapters/openrouter/OpenRouterLogAdapter");
24
28
  const dotenv_1 = __importDefault(require("dotenv"));
25
29
  dotenv_1.default.config();
26
30
  exports.PROVIDERS_CONFIG = {
@@ -67,4 +71,16 @@ exports.PROVIDERS_CONFIG = {
67
71
  toolAdapter: new AnthropicToolAdapter_1.AnthropicToolAdapter(),
68
72
  logAdapter: new AnthropicLogAdapter_1.AnthropicLogAdapter(),
69
73
  }),
74
+ openrouter: (apiKey) => {
75
+ var _a;
76
+ return ({
77
+ promptAdapter: new OpenRouterPromptAdapter_1.OpenRouterPromptAdapter({
78
+ apiKey: (_a = apiKey !== null && apiKey !== void 0 ? apiKey : process.env.OPEN_ROUTER_API_KEY) !== null && _a !== void 0 ? _a : process.env.OPENROUTER_API_KEY,
79
+ model: "google/gemini-2.5-flash",
80
+ }),
81
+ outputAdapter: new OpenRouterOutputAdapter_1.OpenRouterOutputAdapter(),
82
+ toolAdapter: new OpenRouterToolAdapter_1.OpenRouterToolAdapter(),
83
+ logAdapter: new OpenRouterLogAdapter_1.OpenRouterLogAdapter(),
84
+ });
85
+ },
70
86
  };
@@ -15,4 +15,10 @@ export declare const MODELS: {
15
15
  CLAUDE_SONNET_4_6: Model;
16
16
  CLAUDE_OPUS_4_6: Model;
17
17
  };
18
+ /**
19
+ * Construit un modèle OpenRouter à partir de son identifiant (ex.
20
+ * `google/gemini-3-flash-preview`). Les coûts sont facultatifs : OpenRouter
21
+ * renvoie le coût réel de chaque appel dans `usage.cost`.
22
+ */
23
+ export declare function openRouterModel(modelName: string, costsPer1MTokens?: Model["costsPer1MTokens"]): Model;
18
24
  //# sourceMappingURL=Models.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../src/core/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,eAAO,MAAM,MAAM;sBAWZ,KAAK;oBAYL,KAAK;iBAYL,KAAK;WAWL,KAAK;eAWL,KAAK;mBAWL,KAAK;qBAWL,KAAK;qBAaL,KAAK;kBAWL,KAAK;oBAWL,KAAK;oBAaL,KAAK;sBAWL,KAAK;uBAKL,KAAK;qBAKL,KAAK;CACX,CAAC"}
1
+ {"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../src/core/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,eAAO,MAAM,MAAM;sBAWZ,KAAK;oBAYL,KAAK;iBAYL,KAAK;WAWL,KAAK;eAWL,KAAK;mBAWL,KAAK;qBAWL,KAAK;qBAaL,KAAK;kBAWL,KAAK;oBAWL,KAAK;oBAaL,KAAK;sBAWL,KAAK;uBAKL,KAAK;qBAKL,KAAK;CACX,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,gBAAgB,GAAE,KAAK,CAAC,kBAAkB,CAA4B,GACrE,KAAK,CAEP"}