@imenam/unified-llm-client 2.0.3 → 2.1.1
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/common/types.d.ts +17 -1
- package/dist/common/types.d.ts.map +1 -1
- package/dist/core/Models.d.ts +1 -0
- package/dist/core/Models.d.ts.map +1 -1
- package/dist/core/Models.js +10 -0
- package/dist/core/UnifiedLLMClient.d.ts +7 -1
- package/dist/core/UnifiedLLMClient.d.ts.map +1 -1
- package/dist/core/UnifiedLLMClient.js +9 -7
- package/dist/examples/api-key-resolver-example.js +24 -1
- package/dist/examples/proxy-api-key-resolver-example.js +16 -5
- package/dist/proxy/ProxyServer.d.ts.map +1 -1
- package/dist/proxy/ProxyServer.js +10 -9
- package/dist/proxy/types.d.ts +11 -0
- package/dist/proxy/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/common/types.d.ts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
export type Provider = "openai" | "gemini" | "qwen" | "anthropic";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the API key for an LLM call.
|
|
4
|
+
*
|
|
5
|
+
* Return semantics:
|
|
6
|
+
* - `string` → use this key for the current call.
|
|
7
|
+
* - `undefined` (or no return value) → fallback automatique sur la variable
|
|
8
|
+
* d'environnement du provider (comportement natif de `PROVIDERS_CONFIG`).
|
|
9
|
+
* - `false` → access denied (the client throws an "access denied" error).
|
|
10
|
+
*
|
|
11
|
+
* The default context shape `{ provider: Provider } & Record<string, unknown>`
|
|
12
|
+
* reflects the provider auto-injection performed by `UnifiedLLMClient.chat()`.
|
|
13
|
+
* Consumers can narrow the generic `T` to their own context type while still
|
|
14
|
+
* benefiting from auto-completion on `context.provider`.
|
|
15
|
+
*/
|
|
16
|
+
export type ApiKeyResolver<T = {
|
|
17
|
+
provider: Provider;
|
|
18
|
+
} & Record<string, unknown>> = (context: T) => Promise<string | false | undefined> | string | false | undefined;
|
|
3
19
|
export type ChatMessageRole = "user" | "assistant" | "system" | "tool" | "function";
|
|
4
20
|
export interface ChatMessage {
|
|
5
21
|
tool_call_id?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAElE,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"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"}
|
package/dist/core/Models.d.ts
CHANGED
|
@@ -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;kBAWL,KAAK;oBAWL,KAAK;oBAaL,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;kBAWL,KAAK;oBAWL,KAAK;oBAaL,KAAK;sBAWL,KAAK;uBAKL,KAAK;qBAKL,KAAK;CACX,CAAC"}
|
package/dist/core/Models.js
CHANGED
|
@@ -107,6 +107,16 @@ exports.MODELS = {
|
|
|
107
107
|
},
|
|
108
108
|
currency: "USD",
|
|
109
109
|
},
|
|
110
|
+
GEMINI_3_5_FLASH: {
|
|
111
|
+
provider: "gemini",
|
|
112
|
+
modelName: "gemini-3.5-flash",
|
|
113
|
+
costsPer1MTokens: {
|
|
114
|
+
prompt: 1.5,
|
|
115
|
+
prompt_cache: 0.15,
|
|
116
|
+
output: 9.0,
|
|
117
|
+
},
|
|
118
|
+
currency: "USD",
|
|
119
|
+
},
|
|
110
120
|
CLAUDE_SONNET_4_6: {
|
|
111
121
|
provider: "anthropic",
|
|
112
122
|
modelName: "claude-sonnet-4-6",
|
|
@@ -16,7 +16,13 @@ export type ChatOptions = {
|
|
|
16
16
|
stream?: boolean;
|
|
17
17
|
config?: ChatOptionalConfig;
|
|
18
18
|
signal?: AbortSignal;
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Contexte additionnel transmis à l'`apiKeyResolver`. Optionnel : si omis, le resolver
|
|
21
|
+
* reçoit uniquement `{ provider }` (auto-injecté par le client). Toute valeur passée
|
|
22
|
+
* ici est fusionnée avec le `provider` auto-injecté ; en cas de collision sur la clé
|
|
23
|
+
* `provider`, l'auto-injection est prioritaire (source de vérité = `this.model.provider`).
|
|
24
|
+
*/
|
|
25
|
+
apiKeyContext?: Record<string, unknown>;
|
|
20
26
|
};
|
|
21
27
|
export declare class UnifiedLLMClient {
|
|
22
28
|
private promptAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UnifiedLLMClient.d.ts","sourceRoot":"","sources":["../../src/core/UnifiedLLMClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAY,cAAc,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACnK,OAAO,EAAiB,oBAAoB,EAAqE,iBAAiB,EAAgB,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAG3L,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACrD,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,EAAE,CAAC;IAC9C,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,aAAa,EAAE,YAAY,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"UnifiedLLMClient.d.ts","sourceRoot":"","sources":["../../src/core/UnifiedLLMClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -51,7 +51,7 @@ class UnifiedLLMClient {
|
|
|
51
51
|
}
|
|
52
52
|
chat(_a) {
|
|
53
53
|
return __awaiter(this, arguments, void 0, function* ({ message, tools, toolChoice = "auto", onChunk, onFinalResponse, onLog, stream = false, config, signal, apiKeyContext }) {
|
|
54
|
-
var _b;
|
|
54
|
+
var _b, _c;
|
|
55
55
|
let effectiveConfig = config !== undefined || signal !== undefined
|
|
56
56
|
? Object.assign(Object.assign({}, config), (signal !== undefined ? { signal } : {})) : undefined;
|
|
57
57
|
if (apiKeyContext !== undefined) {
|
|
@@ -61,13 +61,15 @@ class UnifiedLLMClient {
|
|
|
61
61
|
let promptAdapter = this.promptAdapter;
|
|
62
62
|
let outputAdapter = this.outputAdapter;
|
|
63
63
|
if (!this.isProxyMode && effectiveResolver) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
const resolvedKey = yield effectiveResolver(
|
|
68
|
-
if (resolvedKey === false)
|
|
64
|
+
// Auto-injection systématique du provider, fusion avec le contexte consommateur s'il existe.
|
|
65
|
+
// L'auto-injection prend la priorité : `this.model.provider` est la source de vérité.
|
|
66
|
+
const fullContext = Object.assign(Object.assign({}, ((_c = apiKeyContext) !== null && _c !== void 0 ? _c : {})), { provider: this.model.provider });
|
|
67
|
+
const resolvedKey = yield effectiveResolver(fullContext);
|
|
68
|
+
if (resolvedKey === false) {
|
|
69
69
|
throw new Error("[ApiKeyResolver] The resolver returned false — access denied.");
|
|
70
|
-
|
|
70
|
+
}
|
|
71
|
+
// resolvedKey === undefined → on laisse PROVIDERS_CONFIG faire son fallback natif sur process.env
|
|
72
|
+
const resolved = LLMAdapter_1.PROVIDERS_CONFIG[this.model.provider](resolvedKey !== null && resolvedKey !== void 0 ? resolvedKey : undefined);
|
|
71
73
|
promptAdapter = resolved.promptAdapter;
|
|
72
74
|
outputAdapter = resolved.outputAdapter;
|
|
73
75
|
}
|
|
@@ -21,9 +21,16 @@ const __1 = require("..");
|
|
|
21
21
|
/**
|
|
22
22
|
* Exemple de resolver : renvoie la clé pour un tenant connu, sinon `false` (refus).
|
|
23
23
|
* En production, vous chargeriez la clé depuis une base, un vault, etc.
|
|
24
|
+
*
|
|
25
|
+
* Le client auto-injecte `provider` dans le contexte (typé `Provider`), et fusionne
|
|
26
|
+
* les clés fournies via `apiKeyContext`. Ces dernières sont accessibles via le type
|
|
27
|
+
* par défaut `Record<string, unknown>` et peuvent être castées vers le contexte
|
|
28
|
+
* applicatif au sein du resolver.
|
|
24
29
|
*/
|
|
25
30
|
const demoResolver = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
|
-
const
|
|
31
|
+
const tenantId = ctx.tenantId;
|
|
32
|
+
if (!tenantId)
|
|
33
|
+
return false;
|
|
27
34
|
const byTenant = {
|
|
28
35
|
// Un seul slot de démo : même clé env que la config Gemini par défaut.
|
|
29
36
|
demo: process.env.GOOGLE_API_KEY,
|
|
@@ -57,6 +64,22 @@ function main() {
|
|
|
57
64
|
apiKeyContext: { tenantId: "demo" },
|
|
58
65
|
});
|
|
59
66
|
console.log(res2.content);
|
|
67
|
+
console.log();
|
|
68
|
+
// Resolver qui consigne le contexte reçu (illustre l'auto-injection de `provider`)
|
|
69
|
+
// et qui retourne `undefined` pour activer le fallback natif sur `process.env`.
|
|
70
|
+
console.log("--- Resolver retournant undefined → fallback env var ---\n");
|
|
71
|
+
const fallbackResolver = (ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
console.log(" [resolver] contexte reçu :", ctx);
|
|
73
|
+
return undefined;
|
|
74
|
+
});
|
|
75
|
+
const fallbackClient = new __1.UnifiedLLMClient(__1.MODELS.GEMINI_FLASH_2_5, {
|
|
76
|
+
apiKeyResolver: fallbackResolver,
|
|
77
|
+
});
|
|
78
|
+
// Aucun apiKeyContext fourni : le resolver reçoit uniquement `{ provider }`.
|
|
79
|
+
const res3 = yield fallbackClient.chat({
|
|
80
|
+
message: "Réponds uniquement par : OK fallback.",
|
|
81
|
+
});
|
|
82
|
+
console.log(res3.content);
|
|
60
83
|
});
|
|
61
84
|
}
|
|
62
85
|
main().catch((err) => {
|
|
@@ -29,11 +29,15 @@ function main() {
|
|
|
29
29
|
const server = new __1.ProxyServer({
|
|
30
30
|
port: PROXY_PORT,
|
|
31
31
|
apiKey: PROXY_API_KEY,
|
|
32
|
+
// Le `ProxyServer` auto-injecte `provider` dans le contexte (typé `Provider`).
|
|
33
|
+
// Si `tenantId` est manquant, on retourne `undefined` pour activer le fallback
|
|
34
|
+
// natif sur `process.env` ; si `tenantId` est inconnu, on refuse explicitement.
|
|
32
35
|
apiKeyResolver: (ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
-
const
|
|
34
|
-
if (tenantId
|
|
36
|
+
const tenantId = ctx.tenantId;
|
|
37
|
+
if (!tenantId)
|
|
38
|
+
return undefined;
|
|
39
|
+
if (tenantId === "demo")
|
|
35
40
|
return process.env.GOOGLE_API_KEY;
|
|
36
|
-
}
|
|
37
41
|
return false;
|
|
38
42
|
}),
|
|
39
43
|
});
|
|
@@ -51,10 +55,17 @@ function main() {
|
|
|
51
55
|
});
|
|
52
56
|
console.log(res.content);
|
|
53
57
|
console.log();
|
|
54
|
-
console.log("---
|
|
58
|
+
console.log("--- No apiKeyContext → resolver returns undefined → fallback env ---\n");
|
|
59
|
+
const res2 = yield client.chat({
|
|
60
|
+
message: "Reply only with: OK fallback.",
|
|
61
|
+
});
|
|
62
|
+
console.log(res2.content);
|
|
63
|
+
console.log();
|
|
64
|
+
console.log("--- Unknown tenantId → resolver returns false → HTTP 403 ---\n");
|
|
55
65
|
try {
|
|
56
66
|
yield client.chat({
|
|
57
|
-
message: "This should
|
|
67
|
+
message: "This should be rejected.",
|
|
68
|
+
apiKeyContext: { tenantId: "ghost" },
|
|
58
69
|
});
|
|
59
70
|
console.error("Expected the request to be rejected.");
|
|
60
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProxyServer.d.ts","sourceRoot":"","sources":["../../src/proxy/ProxyServer.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAoB,MAAM,SAAS,CAAC;AAI/D,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAEjC,OAAO,EAAE,kBAAkB;IAKvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IASrB,OAAO,CAAC,aAAa;YAoCP,WAAW;
|
|
1
|
+
{"version":3,"file":"ProxyServer.d.ts","sourceRoot":"","sources":["../../src/proxy/ProxyServer.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAoB,MAAM,SAAS,CAAC;AAI/D,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAEjC,OAAO,EAAE,kBAAkB;IAKvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IASrB,OAAO,CAAC,aAAa;YAoCP,WAAW;YA4FX,mBAAmB;IAuCjC,OAAO,CAAC,QAAQ;CAGjB"}
|
|
@@ -116,29 +116,30 @@ class ProxyServer {
|
|
|
116
116
|
}
|
|
117
117
|
processChat(body, res) {
|
|
118
118
|
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
var _a;
|
|
119
120
|
let request;
|
|
120
121
|
try {
|
|
121
122
|
request = JSON.parse(body);
|
|
122
123
|
}
|
|
123
|
-
catch (
|
|
124
|
+
catch (_b) {
|
|
124
125
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
125
126
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
129
|
let resolvedApiKey;
|
|
129
130
|
if (this.options.apiKeyResolver) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const result = yield this.options.apiKeyResolver(request.apiKeyContext);
|
|
131
|
+
// Auto-injection systématique du provider, fusion avec le contexte consommateur s'il existe.
|
|
132
|
+
// L'auto-injection prend la priorité : `request.model.provider` est la source de vérité.
|
|
133
|
+
// Comportement aligné sur le mode direct (UnifiedLLMClient.chat()).
|
|
134
|
+
const fullContext = Object.assign(Object.assign({}, ((_a = request.apiKeyContext) !== null && _a !== void 0 ? _a : {})), { provider: request.model.provider });
|
|
135
|
+
const result = yield this.options.apiKeyResolver(fullContext);
|
|
136
136
|
if (result === false) {
|
|
137
137
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
138
138
|
res.end(JSON.stringify({ error: "apiKeyResolver returned false" }));
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
|
-
|
|
141
|
+
// result === undefined → on laisse PROVIDERS_CONFIG faire son fallback natif sur process.env
|
|
142
|
+
resolvedApiKey = result !== null && result !== void 0 ? result : undefined;
|
|
142
143
|
}
|
|
143
144
|
const tempFiles = [];
|
|
144
145
|
try {
|
|
@@ -198,7 +199,7 @@ class ProxyServer {
|
|
|
198
199
|
try {
|
|
199
200
|
fs.unlinkSync(tmpFile);
|
|
200
201
|
}
|
|
201
|
-
catch (
|
|
202
|
+
catch (_c) {
|
|
202
203
|
/* ignore cleanup errors */
|
|
203
204
|
}
|
|
204
205
|
}
|
package/dist/proxy/types.d.ts
CHANGED
|
@@ -3,6 +3,17 @@ import { StreamedChatChunk } from "../core/LLMAdapter";
|
|
|
3
3
|
export interface ProxyServerOptions {
|
|
4
4
|
port: number;
|
|
5
5
|
apiKey?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Resolver côté serveur proxy. Le `ProxyServer` auto-injecte systématiquement
|
|
8
|
+
* la clé `provider` (issue de `request.model.provider`) dans le contexte
|
|
9
|
+
* transmis au resolver, et fusionne les valeurs reçues via `apiKeyContext` du
|
|
10
|
+
* payload HTTP. Comportement aligné sur le mode direct (`UnifiedLLMClient`).
|
|
11
|
+
*
|
|
12
|
+
* Sémantique des retours :
|
|
13
|
+
* - `string` → cette clé est utilisée pour l'appel courant.
|
|
14
|
+
* - `undefined` → fallback natif sur la variable d'environnement du provider.
|
|
15
|
+
* - `false` → HTTP 403 (access denied).
|
|
16
|
+
*/
|
|
6
17
|
apiKeyResolver?: ApiKeyResolver;
|
|
7
18
|
}
|
|
8
19
|
export interface ProxyChatRequest {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/proxy/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,EAAE,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAChC,CAAC;IACF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/proxy/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,EAAE,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAChC,CAAC;IACF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imenam/unified-llm-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "A unified interface for multiple LLM providers (OpenAI, Gemini, Anthropic, Qwen) with tool-calling, streaming, and audio support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|