@imenam/unified-llm-client 1.4.1 → 2.0.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 (35) hide show
  1. package/README.md +124 -24
  2. package/dist/common/types.d.ts +1 -0
  3. package/dist/common/types.d.ts.map +1 -1
  4. package/dist/core/LLMAdapter.d.ts +2 -1
  5. package/dist/core/LLMAdapter.d.ts.map +1 -1
  6. package/dist/core/LLMAdapter.js +9 -9
  7. package/dist/core/UnifiedLLMClient.d.ts +10 -2
  8. package/dist/core/UnifiedLLMClient.d.ts.map +1 -1
  9. package/dist/core/UnifiedLLMClient.js +49 -13
  10. package/dist/examples/api-key-resolver-example.d.ts +2 -0
  11. package/dist/examples/api-key-resolver-example.d.ts.map +1 -0
  12. package/dist/examples/api-key-resolver-example.js +65 -0
  13. package/dist/examples/example.js +6 -7
  14. package/dist/examples/proxy-api-key-resolver-example.d.ts +2 -0
  15. package/dist/examples/proxy-api-key-resolver-example.d.ts.map +1 -0
  16. package/dist/examples/proxy-api-key-resolver-example.js +75 -0
  17. package/dist/examples/proxy-example.d.ts +2 -0
  18. package/dist/examples/proxy-example.d.ts.map +1 -0
  19. package/dist/examples/proxy-example.js +120 -0
  20. package/dist/examples/proxy-server-start.d.ts +2 -0
  21. package/dist/examples/proxy-server-start.d.ts.map +1 -0
  22. package/dist/examples/proxy-server-start.js +30 -0
  23. package/dist/index.d.ts +5 -3
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3 -1
  26. package/dist/proxy/ProxyPromptAdapter.d.ts +17 -0
  27. package/dist/proxy/ProxyPromptAdapter.d.ts.map +1 -0
  28. package/dist/proxy/ProxyPromptAdapter.js +238 -0
  29. package/dist/proxy/ProxyServer.d.ts +13 -0
  30. package/dist/proxy/ProxyServer.d.ts.map +1 -0
  31. package/dist/proxy/ProxyServer.js +243 -0
  32. package/dist/proxy/types.d.ts +32 -0
  33. package/dist/proxy/types.d.ts.map +1 -0
  34. package/dist/proxy/types.js +2 -0
  35. package/package.json +6 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @imenam/unified-llm-client
2
2
 
3
- A unified interface for multiple LLM providers — OpenAI, Gemini, Anthropic, and Qwen — with built-in support for tool-calling, streaming, multimodal inputs, and audio generation.
3
+ A unified interface for multiple LLM providers — OpenAI, Gemini, Anthropic, and Qwen — with built-in support for tool-calling, streaming, multimodal inputs, audio generation, and a proxy mode for API key isolation.
4
4
 
5
5
  ## Features
6
6
 
@@ -9,6 +9,9 @@ A unified interface for multiple LLM providers — OpenAI, Gemini, Anthropic, an
9
9
  - **Streaming** — chunk-by-chunk responses via callbacks
10
10
  - **Multimodal** — image and audio file inputs
11
11
  - **Audio generation** — Text-to-Speech (Gemini)
12
+ - **Proxy mode** — delegate LLM calls to a server, no API keys on the client
13
+ - **API key resolver** — dynamically resolve API keys per request from a user-provided context
14
+ - **Cancellation** — native `AbortSignal` support
12
15
  - **Usage tracking** — token counts and estimated costs
13
16
  - **Full TypeScript support** — exported types and `.d.ts` declarations
14
17
 
@@ -35,7 +38,7 @@ Set your API keys in a `.env` file:
35
38
  OPENAI_API_KEY=sk-...
36
39
  GOOGLE_API_KEY=...
37
40
  ANTHROPIC_API_KEY=sk-ant-...
38
- DASHSCOPE_API_KEY=... # for Qwen
41
+ ALIBABA_CLOUD_API_KEY=... # for Qwen
39
42
  ```
40
43
 
41
44
  ```typescript
@@ -73,6 +76,7 @@ MODELS.CLAUDE_OPUS_4_6
73
76
  // Qwen
74
77
  MODELS.QWEN_VL_3
75
78
  MODELS.QWEN_VL_FLASH
79
+ MODELS.QWEN_VL_3_FLASH
76
80
  ```
77
81
 
78
82
  You can also pass a custom model:
@@ -81,6 +85,8 @@ You can also pass a custom model:
81
85
  const client = new UnifiedLLMClient({
82
86
  provider: "openai",
83
87
  modelName: "gpt-4o",
88
+ costsPer1MTokens: { prompt: 2.5, output: 10 },
89
+ currency: "USD",
84
90
  });
85
91
  ```
86
92
 
@@ -124,11 +130,11 @@ console.log(response.content);
124
130
  ```typescript
125
131
  const client = new UnifiedLLMClient(MODELS.GPT_4O_MINI);
126
132
 
127
- const response = await client.chat({
133
+ await client.chat({
128
134
  message: "Tell me a short story.",
129
135
  stream: true,
130
136
  onChunk: (chunk) => {
131
- process.stdout.write(chunk.content ?? "");
137
+ process.stdout.write(chunk.contentChunk ?? "");
132
138
  },
133
139
  onFinalResponse: (final) => {
134
140
  console.log("\n\nTotal tokens:", final.usage?.totalTokens);
@@ -136,23 +142,6 @@ const response = await client.chat({
136
142
  });
137
143
  ```
138
144
 
139
- ## Conversation History
140
-
141
- The client maintains conversation history internally. Use `getHistory()` and `setHistory()` to persist or restore it:
142
-
143
- ```typescript
144
- const client = new UnifiedLLMClient(MODELS.CLAUDE_SONNET_4_6);
145
-
146
- await client.chat({ message: "My name is Alice." });
147
- await client.chat({ message: "What's my name?" });
148
- // → "Your name is Alice."
149
-
150
- const history = client.getHistory();
151
- // Save and restore later:
152
- const newClient = new UnifiedLLMClient(MODELS.CLAUDE_SONNET_4_6);
153
- newClient.setHistory(history);
154
- ```
155
-
156
145
  ## Multimodal Inputs
157
146
 
158
147
  Attach images or audio files directly to a message:
@@ -167,6 +156,18 @@ const response = await client.chat({
167
156
  });
168
157
  ```
169
158
 
159
+ Multiple files are also supported:
160
+
161
+ ```typescript
162
+ await client.chat({
163
+ message: {
164
+ role: "user",
165
+ content: "Compare these two images.",
166
+ attachedFile: ["./image1.jpg", "./image2.png"],
167
+ },
168
+ });
169
+ ```
170
+
170
171
  ## Audio Generation (Gemini)
171
172
 
172
173
  ```typescript
@@ -181,6 +182,87 @@ const audio = await client.generateAudio({
181
182
  });
182
183
  ```
183
184
 
185
+ ## Proxy Mode
186
+
187
+ Run an HTTP server that holds your API keys server-side, and connect clients without any keys:
188
+
189
+ ```typescript
190
+ import { ProxyServer } from "@imenam/unified-llm-client";
191
+
192
+ // Server side — API keys are read from process.env
193
+ const server = new ProxyServer({ port: 3000, apiKey: "my-secret" });
194
+ await server.start();
195
+ ```
196
+
197
+ ```typescript
198
+ // Client side — no API keys needed
199
+ import { UnifiedLLMClient, MODELS } from "@imenam/unified-llm-client";
200
+
201
+ const client = new UnifiedLLMClient(MODELS.GEMINI_FLASH_2_5, {
202
+ proxyUrl: "http://localhost:3000",
203
+ proxyApiKey: "my-secret",
204
+ });
205
+
206
+ // The chat() API is identical — streaming and file attachments are fully supported
207
+ const response = await client.chat({ message: "Hello!" });
208
+ ```
209
+
210
+ ## API Key Resolver
211
+
212
+ Dynamically resolve which API key to use for each request based on a custom context (e.g. per-user key, request metadata):
213
+
214
+ ```typescript
215
+ import { UnifiedLLMClient, MODELS } from "@imenam/unified-llm-client";
216
+ import type { ApiKeyResolver } from "@imenam/unified-llm-client";
217
+
218
+ const resolver: ApiKeyResolver<{ userId: string }> = (ctx) => {
219
+ const key = userKeyStore.get(ctx.userId);
220
+ return key ?? false; // return false to deny access
221
+ };
222
+
223
+ const client = new UnifiedLLMClient(MODELS.GPT_4O_MINI, {
224
+ apiKeyResolver: resolver,
225
+ });
226
+
227
+ const response = await client.chat({
228
+ message: "Hello!",
229
+ apiKeyContext: { userId: "user-123" },
230
+ });
231
+ ```
232
+
233
+ You can also set a global default resolver for all instances:
234
+
235
+ ```typescript
236
+ UnifiedLLMClient.setDefaultApiKeyResolver((ctx) => {
237
+ return ctx.apiKey ?? false;
238
+ });
239
+ ```
240
+
241
+ > The resolver is called on every `chat()` call. Returning `false` throws an access-denied error.
242
+ > The `apiKeyResolver` option is incompatible with proxy mode.
243
+
244
+ ## Cancellation
245
+
246
+ Pass an `AbortSignal` to cancel a request mid-flight:
247
+
248
+ ```typescript
249
+ const ac = new AbortController();
250
+ setTimeout(() => ac.abort(), 800);
251
+
252
+ try {
253
+ await client.chat({
254
+ message: "Write a very long story...",
255
+ stream: true,
256
+ signal: ac.signal,
257
+ onChunk: (chunk) => process.stdout.write(chunk.contentChunk ?? ""),
258
+ });
259
+ } catch (e) {
260
+ if (e instanceof Error && e.name === "AbortError") {
261
+ console.log("Request cancelled.");
262
+ }
263
+ }
264
+ ```
265
+
184
266
  ## Logging
185
267
 
186
268
  Pass a `logger` callback to capture structured logs for every request:
@@ -188,30 +270,46 @@ Pass a `logger` callback to capture structured logs for every request:
188
270
  ```typescript
189
271
  const client = new UnifiedLLMClient(MODELS.GPT_4O_MINI, {
190
272
  logger: (log) => {
191
- console.log(`[${log.provider}] ${log.model} — ${log.totalTokens} tokens`);
273
+ console.log(`[${log.provider}] ${log.model} — ${log.usage.totalTokens} tokens`);
192
274
  },
193
275
  });
194
276
  ```
195
277
 
278
+ Set a global default logger applied to all instances:
279
+
280
+ ```typescript
281
+ UnifiedLLMClient.setDefaultLogger((log) => {
282
+ console.log(`[${log.provider}] ${log.model} — ${log.usage.totalTokens} tokens`);
283
+ });
284
+ ```
285
+
196
286
  ## API Reference
197
287
 
198
288
  ### `new UnifiedLLMClient(model, options?)`
199
289
 
200
290
  | Parameter | Type | Description |
201
291
  |-----------|------|-------------|
202
- | `model` | `Model` | Model object from `MODELS` or a custom `{ provider, modelName }` |
292
+ | `model` | `Model` | Model object from `MODELS` or a custom `{ provider, modelName, costsPer1MTokens, currency }` |
203
293
  | `options.logger` | `(log: UnifiedLog) => void` | Optional logging callback |
294
+ | `options.proxyUrl` | `string` | Proxy server URL — activates proxy mode |
295
+ | `options.proxyApiKey` | `string` | Key sent in the `x-api-key` header (proxy mode) |
296
+ | `options.apiKey` | `string` | Static API key passed directly to the provider (overrides env var) |
297
+ | `options.apiKeyResolver` | `ApiKeyResolver` | Dynamic per-request key resolver (incompatible with proxy mode) |
204
298
 
205
299
  ### `client.chat(options)`
206
300
 
207
301
  | Option | Type | Default | Description |
208
302
  |--------|------|---------|-------------|
209
- | `message` | `string \| ChatMessage \| ChatMessage[]` | — | User message or history |
303
+ | `message` | `string \| ChatMessage \| ChatMessage[]` | — | User message or full conversation history |
210
304
  | `tools` | `ToolDefinition[]` | `[]` | Tools available to the LLM |
211
305
  | `toolChoice` | `"auto" \| "none" \| string` | `"auto"` | Tool selection strategy |
212
306
  | `stream` | `boolean` | `false` | Enable streaming |
213
307
  | `onChunk` | `(chunk: StreamedChatChunk) => void` | — | Streaming chunk callback |
214
308
  | `onFinalResponse` | `(res: ChatResponse) => void` | — | Final response callback |
309
+ | `onLog` | `(log: UnifiedLog) => void` | — | Per-call log callback |
310
+ | `config` | `ChatOptionalConfig` | — | Advanced options: `thinkingBudget`, `metadata` |
311
+ | `signal` | `AbortSignal` | — | Cancellation signal |
312
+ | `apiKeyContext` | `unknown` | — | Context passed to `apiKeyResolver` to resolve the API key |
215
313
 
216
314
  ### `ChatResponse`
217
315
 
@@ -224,6 +322,8 @@ interface ChatResponse {
224
322
  completionTokens: number;
225
323
  totalTokens: number;
226
324
  };
325
+ finishReason?: string;
326
+ requestId?: string;
227
327
  raw: unknown;
228
328
  }
229
329
  ```
@@ -1,4 +1,5 @@
1
1
  export type Provider = "openai" | "gemini" | "qwen" | "anthropic";
2
+ export type ApiKeyResolver<T = unknown> = (context: T) => string | false;
2
3
  export type ChatMessageRole = "user" | "assistant" | "system" | "tool" | "function";
3
4
  export interface ChatMessage {
4
5
  tool_call_id?: 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,5 +1,5 @@
1
1
  import { ChatMessage, ToolDefinition, ChatResponse, ToolCall, AudioGenerationOptions, AudioGenerationResponse, UnifiedLog, Provider } from "../common/types";
2
- export declare const PROVIDERS_CONFIG: Record<Provider, () => ProviderOptions>;
2
+ export declare const PROVIDERS_CONFIG: Record<Provider, (apiKey?: string) => ProviderOptions>;
3
3
  export type StreamedChatChunk = {
4
4
  contentChunk?: string;
5
5
  toolCallChunk?: ToolCall[];
@@ -28,6 +28,7 @@ export type ChatOptionalConfig = {
28
28
  thinkingBudget?: number;
29
29
  metadata?: Record<string, any>;
30
30
  signal?: AbortSignal;
31
+ apiKeyContext?: unknown;
31
32
  };
32
33
  export interface LogData {
33
34
  model: string;
@@ -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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"}
@@ -24,22 +24,22 @@ const AnthropicLogAdapter_1 = require("../adapters/anthropic/AnthropicLogAdapter
24
24
  const dotenv_1 = __importDefault(require("dotenv"));
25
25
  dotenv_1.default.config();
26
26
  exports.PROVIDERS_CONFIG = {
27
- gemini: () => ({
27
+ gemini: (apiKey) => ({
28
28
  promptAdapter: new GeminiPromptAdapter_1.GeminiPromptAdapter({
29
- apiKey: process.env.GOOGLE_API_KEY,
29
+ apiKey: apiKey !== null && apiKey !== void 0 ? apiKey : process.env.GOOGLE_API_KEY,
30
30
  model: "gemini-2.5-flash",
31
31
  }),
32
32
  outputAdapter: new GeminiOutputAdapter_1.GeminiOutputAdapter(),
33
33
  toolAdapter: new GeminiToolAdapter_1.GeminiToolAdapter(),
34
34
  audioAdapter: new GeminiAudioAdapter_1.GeminiAudioAdapter({
35
- apiKey: process.env.GOOGLE_API_KEY,
35
+ apiKey: apiKey !== null && apiKey !== void 0 ? apiKey : process.env.GOOGLE_API_KEY,
36
36
  model: "gemini-2.5-pro-preview-tts",
37
37
  }),
38
38
  logAdapter: new GeminiLogAdapter_1.GeminiLogAdapter(),
39
39
  }),
40
- openai: () => ({
40
+ openai: (apiKey) => ({
41
41
  promptAdapter: new OpenAIPromptAdapter_1.OpenAIPromptAdapter({
42
- apiKey: process.env.OPENAI_API_KEY,
42
+ apiKey: apiKey !== null && apiKey !== void 0 ? apiKey : process.env.OPENAI_API_KEY,
43
43
  model: "gpt-4o-mini",
44
44
  }),
45
45
  toolAdapter: new OpenAiToolAdapter_1.OpenAiToolAdapter(),
@@ -47,9 +47,9 @@ exports.PROVIDERS_CONFIG = {
47
47
  logAdapter: new OpenAiLogAdapter_1.OpenAiLogAdapter(),
48
48
  // Note: OpenAI n'a pas encore d'audioAdapter - peut être ajouté plus tard
49
49
  }),
50
- qwen: () => ({
50
+ qwen: (apiKey) => ({
51
51
  promptAdapter: new QwenPromptAdapter_1.QwenPromptAdapter({
52
- apiKey: process.env.ALIBABA_CLOUD_API_KEY,
52
+ apiKey: apiKey !== null && apiKey !== void 0 ? apiKey : process.env.ALIBABA_CLOUD_API_KEY,
53
53
  model: "qwen3-vl-235b-a22b-instruct",
54
54
  baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
55
55
  }),
@@ -58,9 +58,9 @@ exports.PROVIDERS_CONFIG = {
58
58
  logAdapter: new QwenLogAdapter_1.QwenLogAdapter(),
59
59
  // Note: Qwen n'a pas d'audioAdapter pour le moment
60
60
  }),
61
- anthropic: () => ({
61
+ anthropic: (apiKey) => ({
62
62
  promptAdapter: new AnthropicPromptAdapter_1.AnthropicPromptAdapter({
63
- apiKey: process.env.ANTHROPIC_API_KEY,
63
+ apiKey: apiKey !== null && apiKey !== void 0 ? apiKey : process.env.ANTHROPIC_API_KEY,
64
64
  model: "claude-sonnet-4-5-20250929",
65
65
  }),
66
66
  outputAdapter: new AnthropicOutputAdapter_1.AnthropicOutputAdapter(),
@@ -1,4 +1,4 @@
1
- import { ChatMessage, ChatResponse, ToolDefinition, AudioGenerationOptions, AudioGenerationResponse, UnifiedLog } from "../common/types";
1
+ import { ApiKeyResolver, ChatMessage, ChatResponse, ToolDefinition, AudioGenerationOptions, AudioGenerationResponse, UnifiedLog } from "../common/types";
2
2
  import { PromptAdapterOptions, StreamedChatChunk, ChatOptionalConfig } from "./LLMAdapter";
3
3
  import { Model } from "../common/types";
4
4
  export type UnifiedLLMClientOptions = {
@@ -16,6 +16,7 @@ export type ChatOptions = {
16
16
  stream?: boolean;
17
17
  config?: ChatOptionalConfig;
18
18
  signal?: AbortSignal;
19
+ apiKeyContext?: unknown;
19
20
  };
20
21
  export declare class UnifiedLLMClient {
21
22
  private promptAdapter;
@@ -26,12 +27,19 @@ export declare class UnifiedLLMClient {
26
27
  private rawMessages;
27
28
  private model;
28
29
  private logger?;
30
+ private apiKeyResolver?;
31
+ private readonly isProxyMode;
29
32
  static setDefaultLogger(logger: (log: UnifiedLog) => any | Promise<any>): void;
33
+ static setDefaultApiKeyResolver(resolver: ApiKeyResolver): void;
30
34
  constructor(model: Model, options?: {
31
35
  logger?: (log: UnifiedLog) => any | Promise<any>;
36
+ proxyUrl?: string;
37
+ proxyApiKey?: string;
38
+ apiKeyResolver?: ApiKeyResolver;
39
+ apiKey?: string;
32
40
  });
33
41
  private checkNotImplementedFeatures;
34
- chat({ message, tools, toolChoice, onChunk, onFinalResponse, onLog, stream, config, signal }: ChatOptions): Promise<ChatResponse>;
42
+ chat({ message, tools, toolChoice, onChunk, onFinalResponse, onLog, stream, config, signal, apiKeyContext }: ChatOptions): Promise<ChatResponse>;
35
43
  private handleLogging;
36
44
  /**
37
45
  * Vérifie si la génération d'audio est supportée pour le provider actuel
@@ -1 +1 @@
1
- {"version":3,"file":"UnifiedLLMClient.d.ts","sourceRoot":"","sources":["../../src/core/UnifiedLLMClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UnifiedLLMClient.d.ts","sourceRoot":"","sources":["../../src/core/UnifiedLLMClient.ts"],"names":[],"mappings":"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"}
@@ -11,19 +11,37 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.UnifiedLLMClient = void 0;
13
13
  const LLMAdapter_1 = require("./LLMAdapter");
14
+ const ProxyPromptAdapter_1 = require("../proxy/ProxyPromptAdapter");
14
15
  class UnifiedLLMClient {
15
16
  static setDefaultLogger(logger) {
16
17
  global._unifiedLlmDefaultLogger = logger;
17
18
  }
19
+ static setDefaultApiKeyResolver(resolver) {
20
+ global._unifiedLlmDefaultApiKeyResolver = resolver;
21
+ }
18
22
  constructor(model, options) {
19
23
  this.rawMessages = [];
20
24
  this.model = model;
21
- const config = LLMAdapter_1.PROVIDERS_CONFIG[model.provider]();
22
- this.promptAdapter = config.promptAdapter;
23
- this.outputAdapter = config.outputAdapter;
24
- this.toolAdapter = config.toolAdapter;
25
- this.audioAdapter = config.audioAdapter;
26
- this.logAdapter = config.logAdapter;
25
+ this.apiKeyResolver = options === null || options === void 0 ? void 0 : options.apiKeyResolver;
26
+ this.isProxyMode = Boolean(options === null || options === void 0 ? void 0 : options.proxyUrl);
27
+ if (options === null || options === void 0 ? void 0 : options.proxyUrl) {
28
+ const proxyAdapter = new ProxyPromptAdapter_1.ProxyPromptAdapter({
29
+ serverUrl: options.proxyUrl,
30
+ apiKey: options.proxyApiKey,
31
+ model,
32
+ });
33
+ this.promptAdapter = proxyAdapter;
34
+ this.outputAdapter = { parse: (r) => r };
35
+ this.toolAdapter = { formatToolCallResult: (tc) => tc };
36
+ }
37
+ else {
38
+ const config = LLMAdapter_1.PROVIDERS_CONFIG[model.provider](options === null || options === void 0 ? void 0 : options.apiKey);
39
+ this.promptAdapter = config.promptAdapter;
40
+ this.outputAdapter = config.outputAdapter;
41
+ this.toolAdapter = config.toolAdapter;
42
+ this.audioAdapter = config.audioAdapter;
43
+ this.logAdapter = config.logAdapter;
44
+ }
27
45
  this.logger = (options === null || options === void 0 ? void 0 : options.logger) || global._unifiedLlmDefaultLogger;
28
46
  }
29
47
  checkNotImplementedFeatures(message) {
@@ -32,23 +50,41 @@ class UnifiedLLMClient {
32
50
  }
33
51
  }
34
52
  chat(_a) {
35
- return __awaiter(this, arguments, void 0, function* ({ message, tools, toolChoice = "auto", onChunk, onFinalResponse, onLog, stream = false, config, signal }) {
36
- const effectiveConfig = config !== undefined || signal !== undefined
53
+ return __awaiter(this, arguments, void 0, function* ({ message, tools, toolChoice = "auto", onChunk, onFinalResponse, onLog, stream = false, config, signal, apiKeyContext }) {
54
+ var _b;
55
+ let effectiveConfig = config !== undefined || signal !== undefined
37
56
  ? Object.assign(Object.assign({}, config), (signal !== undefined ? { signal } : {})) : undefined;
57
+ if (apiKeyContext !== undefined) {
58
+ effectiveConfig = Object.assign(Object.assign({}, effectiveConfig), { apiKeyContext });
59
+ }
60
+ const effectiveResolver = (_b = this.apiKeyResolver) !== null && _b !== void 0 ? _b : global._unifiedLlmDefaultApiKeyResolver;
61
+ let promptAdapter = this.promptAdapter;
62
+ let outputAdapter = this.outputAdapter;
63
+ if (!this.isProxyMode && effectiveResolver) {
64
+ if (apiKeyContext === undefined) {
65
+ throw new Error("[ApiKeyResolver] A resolver is defined but no apiKeyContext was provided.");
66
+ }
67
+ const resolvedKey = effectiveResolver(apiKeyContext);
68
+ if (resolvedKey === false)
69
+ throw new Error("[ApiKeyResolver] The resolver returned false — access denied.");
70
+ const resolved = LLMAdapter_1.PROVIDERS_CONFIG[this.model.provider](resolvedKey);
71
+ promptAdapter = resolved.promptAdapter;
72
+ outputAdapter = resolved.outputAdapter;
73
+ }
38
74
  const startTime = Date.now();
39
75
  const messageArray = Array.isArray(message)
40
76
  ? message
41
77
  : [typeof message === "string" ? { role: "user", content: message } : message];
42
78
  for (const m of messageArray)
43
79
  this.checkNotImplementedFeatures(m);
44
- const messages = yield Promise.all(messageArray.map(m => this.promptAdapter.formatMessage(m)));
80
+ const messages = yield Promise.all(messageArray.map(m => promptAdapter.formatMessage(m)));
45
81
  let finalResponse;
46
82
  if (stream) {
47
- if (!this.promptAdapter.streamFromProvider) {
83
+ if (!promptAdapter.streamFromProvider) {
48
84
  throw new Error("The current adapter does not support streaming.");
49
85
  }
50
86
  let aggregatedContent = "";
51
- finalResponse = yield this.promptAdapter.streamFromProvider({
87
+ finalResponse = yield promptAdapter.streamFromProvider({
52
88
  messages,
53
89
  tools,
54
90
  toolChoice,
@@ -70,8 +106,8 @@ class UnifiedLLMClient {
70
106
  finalResponse.content = aggregatedContent;
71
107
  }
72
108
  else {
73
- const providerResponse = yield this.promptAdapter.sendToProvider(messages, tools, toolChoice, undefined, this.model.modelName, effectiveConfig);
74
- finalResponse = this.outputAdapter.parse(providerResponse);
109
+ const providerResponse = yield promptAdapter.sendToProvider(messages, tools, toolChoice, undefined, this.model.modelName, effectiveConfig);
110
+ finalResponse = outputAdapter.parse(providerResponse);
75
111
  }
76
112
  const latencyMs = Date.now() - startTime;
77
113
  yield this.handleLogging(messageArray, finalResponse, latencyMs, effectiveConfig === null || effectiveConfig === void 0 ? void 0 : effectiveConfig.metadata, onLog);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api-key-resolver-example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-resolver-example.d.ts","sourceRoot":"","sources":["../../src/examples/api-key-resolver-example.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ /**
13
+ * Exemple : résolution dynamique de clé API (`apiKeyResolver`) en mode direct,
14
+ * sans serveur proxy. Les clés viennent ici d’un mapping applicatif (ex. par tenant).
15
+ *
16
+ * Prérequis : `GOOGLE_API_KEY` dans l’environnement (provider Gemini dans cet exemple).
17
+ *
18
+ * Lancer après build : `npm run example:api-key-resolver`
19
+ */
20
+ const __1 = require("..");
21
+ /**
22
+ * Exemple de resolver : renvoie la clé pour un tenant connu, sinon `false` (refus).
23
+ * En production, vous chargeriez la clé depuis une base, un vault, etc.
24
+ */
25
+ const demoResolver = (ctx) => {
26
+ const { tenantId } = ctx;
27
+ const byTenant = {
28
+ // Un seul slot de démo : même clé env que la config Gemini par défaut.
29
+ demo: process.env.GOOGLE_API_KEY,
30
+ };
31
+ const key = byTenant[tenantId];
32
+ if (!key)
33
+ return false;
34
+ return key;
35
+ };
36
+ function main() {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ if (!process.env.GOOGLE_API_KEY) {
39
+ console.error("[api-key-resolver-example] Définissez GOOGLE_API_KEY pour exécuter cet exemple.");
40
+ process.exit(1);
41
+ }
42
+ const client = new __1.UnifiedLLMClient(__1.MODELS.GEMINI_FLASH_2_5, {
43
+ apiKeyResolver: demoResolver,
44
+ });
45
+ console.log("--- Chat avec apiKeyContext (resolver instance) ---\n");
46
+ const res = yield client.chat({
47
+ message: "Réponds en une courte phrase : que signifie « apiKeyResolver » dans ce SDK ?",
48
+ apiKeyContext: { tenantId: "demo" },
49
+ });
50
+ console.log(res.content);
51
+ console.log();
52
+ console.log("--- setDefaultApiKeyResolver (global) + même appel ---\n");
53
+ __1.UnifiedLLMClient.setDefaultApiKeyResolver(demoResolver);
54
+ const clientNoInstanceResolver = new __1.UnifiedLLMClient(__1.MODELS.GEMINI_FLASH_2_5);
55
+ const res2 = yield clientNoInstanceResolver.chat({
56
+ message: "Dis seulement : OK.",
57
+ apiKeyContext: { tenantId: "demo" },
58
+ });
59
+ console.log(res2.content);
60
+ });
61
+ }
62
+ main().catch((err) => {
63
+ console.error(err);
64
+ process.exit(1);
65
+ });
@@ -243,7 +243,6 @@ function getExercisesBoundaries() {
243
243
  }
244
244
  function exerciseMatching() {
245
245
  return __awaiter(this, void 0, void 0, function* () {
246
- var _a, _b;
247
246
  const answers = [
248
247
  {
249
248
  index: 0,
@@ -310,14 +309,14 @@ function exerciseMatching() {
310
309
  const res = yield client.chat({
311
310
  message: {
312
311
  role: "user",
313
- content: "Voila les reponses des etudiants, et le sujet du devoir. Peux-tu les associer ? answers:\n" + JSON.stringify(answers),
314
- // content: "Quelles sont les questions du sujet ?",
312
+ // content: "Voila les reponses des etudiants, et le sujet du devoir. Peux-tu les associer ? answers:\n" + JSON.stringify(answers),
313
+ content: "Quelles sont les questions du sujet ?",
315
314
  attachedFile: "./media/subject.pdf"
316
315
  },
317
316
  tools: [tool]
318
317
  });
319
- // console.log("response", res);
320
- console.log("response", (_b = (_a = res.toolCalls) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.arguments);
318
+ console.log("response", res.content);
319
+ // console.log("response", res.toolCalls?.[0]?.arguments);
321
320
  });
322
321
  }
323
322
  function parseSubject() {
@@ -364,7 +363,7 @@ function multiFileSend() {
364
363
  console.log("response", res.content);
365
364
  });
366
365
  }
367
- basicUsage();
366
+ // basicUsage();
368
367
  // Annulation d'une requête chat (côté app consommatrice) :
369
368
  // const ac = new AbortController();
370
369
  // setTimeout(() => ac.abort(), 500);
@@ -373,6 +372,6 @@ basicUsage();
373
372
  // basicUsageWithAudio();
374
373
  // basicAudioGeneration();
375
374
  // getExercisesBoundaries();
376
- // exerciseMatching();
375
+ exerciseMatching();
377
376
  // parseSubject();
378
377
  // multiFileSend();
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=proxy-api-key-resolver-example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-api-key-resolver-example.d.ts","sourceRoot":"","sources":["../../src/examples/proxy-api-key-resolver-example.ts"],"names":[],"mappings":""}