@imenam/unified-llm-client 1.4.0 → 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.
- package/README.md +124 -24
- package/dist/common/types.d.ts +1 -0
- package/dist/common/types.d.ts.map +1 -1
- package/dist/core/LLMAdapter.d.ts +2 -1
- package/dist/core/LLMAdapter.d.ts.map +1 -1
- package/dist/core/LLMAdapter.js +13 -13
- package/dist/core/UnifiedLLMClient.d.ts +11 -2
- package/dist/core/UnifiedLLMClient.d.ts.map +1 -1
- package/dist/core/UnifiedLLMClient.js +50 -12
- package/dist/examples/api-key-resolver-example.d.ts +2 -0
- package/dist/examples/api-key-resolver-example.d.ts.map +1 -0
- package/dist/examples/api-key-resolver-example.js +65 -0
- package/dist/examples/example.js +27 -27
- package/dist/examples/proxy-api-key-resolver-example.d.ts +2 -0
- package/dist/examples/proxy-api-key-resolver-example.d.ts.map +1 -0
- package/dist/examples/proxy-api-key-resolver-example.js +75 -0
- package/dist/examples/proxy-example.d.ts +2 -0
- package/dist/examples/proxy-example.d.ts.map +1 -0
- package/dist/examples/proxy-example.js +120 -0
- package/dist/examples/proxy-server-start.d.ts +2 -0
- package/dist/examples/proxy-server-start.d.ts.map +1 -0
- package/dist/examples/proxy-server-start.js +30 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/proxy/ProxyPromptAdapter.d.ts +17 -0
- package/dist/proxy/ProxyPromptAdapter.d.ts.map +1 -0
- package/dist/proxy/ProxyPromptAdapter.js +238 -0
- package/dist/proxy/ProxyServer.d.ts +13 -0
- package/dist/proxy/ProxyServer.d.ts.map +1 -0
- package/dist/proxy/ProxyServer.js +243 -0
- package/dist/proxy/types.d.ts +32 -0
- package/dist/proxy/types.d.ts.map +1 -0
- package/dist/proxy/types.js +2 -0
- package/package.json +6 -2
package/dist/examples/example.js
CHANGED
|
@@ -74,28 +74,29 @@ const tools = [
|
|
|
74
74
|
function basicUsage() {
|
|
75
75
|
return __awaiter(this, void 0, void 0, function* () {
|
|
76
76
|
const client = new __1.UnifiedLLMClient(__1.MODELS.GEMINI_FLASH_2_5);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
77
|
+
const tools = [
|
|
78
|
+
{
|
|
79
|
+
name: "get_weather",
|
|
80
|
+
description: "Retrieve weather for a given city",
|
|
81
|
+
parameters: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
city: { type: "string", description: "City name" },
|
|
85
|
+
},
|
|
86
|
+
required: ["city"],
|
|
87
|
+
},
|
|
88
|
+
executor: (_a) => __awaiter(this, [_a], void 0, function* ({ city }) {
|
|
89
|
+
// fetch weather data from API and then
|
|
90
|
+
return `Weather in ${city}... `; // Placeholder
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
];
|
|
94
94
|
const res = yield client.chat({
|
|
95
|
-
message: "
|
|
96
|
-
//
|
|
95
|
+
message: "Quelle est la météo à Paris ?",
|
|
96
|
+
// message: "Quel modèle es-tu ? 2.5-flash ou 2.5-pro ? Répond l'un ou l'autre, soit '2.5-flash' ou '2.5-pro', rien d'autre.",
|
|
97
|
+
tools
|
|
97
98
|
});
|
|
98
|
-
console.log("response", JSON.stringify(res.
|
|
99
|
+
console.log("response", JSON.stringify(res.toolCalls));
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
102
|
function basicUsageWithAudio() {
|
|
@@ -242,7 +243,6 @@ function getExercisesBoundaries() {
|
|
|
242
243
|
}
|
|
243
244
|
function exerciseMatching() {
|
|
244
245
|
return __awaiter(this, void 0, void 0, function* () {
|
|
245
|
-
var _a, _b;
|
|
246
246
|
const answers = [
|
|
247
247
|
{
|
|
248
248
|
index: 0,
|
|
@@ -309,14 +309,14 @@ function exerciseMatching() {
|
|
|
309
309
|
const res = yield client.chat({
|
|
310
310
|
message: {
|
|
311
311
|
role: "user",
|
|
312
|
-
content: "Voila les reponses des etudiants, et le sujet du devoir. Peux-tu les associer ? answers:\n" + JSON.stringify(answers),
|
|
313
|
-
|
|
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 ?",
|
|
314
314
|
attachedFile: "./media/subject.pdf"
|
|
315
315
|
},
|
|
316
316
|
tools: [tool]
|
|
317
317
|
});
|
|
318
|
-
|
|
319
|
-
console.log("response",
|
|
318
|
+
console.log("response", res.content);
|
|
319
|
+
// console.log("response", res.toolCalls?.[0]?.arguments);
|
|
320
320
|
});
|
|
321
321
|
}
|
|
322
322
|
function parseSubject() {
|
|
@@ -363,7 +363,7 @@ function multiFileSend() {
|
|
|
363
363
|
console.log("response", res.content);
|
|
364
364
|
});
|
|
365
365
|
}
|
|
366
|
-
basicUsage();
|
|
366
|
+
// basicUsage();
|
|
367
367
|
// Annulation d'une requête chat (côté app consommatrice) :
|
|
368
368
|
// const ac = new AbortController();
|
|
369
369
|
// setTimeout(() => ac.abort(), 500);
|
|
@@ -372,6 +372,6 @@ basicUsage();
|
|
|
372
372
|
// basicUsageWithAudio();
|
|
373
373
|
// basicAudioGeneration();
|
|
374
374
|
// getExercisesBoundaries();
|
|
375
|
-
|
|
375
|
+
exerciseMatching();
|
|
376
376
|
// parseSubject();
|
|
377
377
|
// multiFileSend();
|
|
@@ -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":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
* Example: `apiKeyContext` forwarded to a `ProxyServer` that resolves the LLM API key
|
|
14
|
+
* via `apiKeyResolver` (no resolver on the client — only transport).
|
|
15
|
+
*
|
|
16
|
+
* Requires: `GOOGLE_API_KEY` in the environment (Gemini).
|
|
17
|
+
*
|
|
18
|
+
* Run after build: `npm run example:proxy-api-key-resolver`
|
|
19
|
+
*/
|
|
20
|
+
const __1 = require("..");
|
|
21
|
+
const PROXY_PORT = 5001;
|
|
22
|
+
const PROXY_API_KEY = "my-proxy-secret";
|
|
23
|
+
function main() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
if (!process.env.GOOGLE_API_KEY) {
|
|
26
|
+
console.error("[proxy-api-key-resolver-example] Set GOOGLE_API_KEY to run this example.");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const server = new __1.ProxyServer({
|
|
30
|
+
port: PROXY_PORT,
|
|
31
|
+
apiKey: PROXY_API_KEY,
|
|
32
|
+
apiKeyResolver: (ctx) => {
|
|
33
|
+
const { tenantId } = ctx;
|
|
34
|
+
if (tenantId === "demo") {
|
|
35
|
+
return process.env.GOOGLE_API_KEY;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
yield server.start();
|
|
41
|
+
console.log(`[example] Proxy listening on http://localhost:${PROXY_PORT}\n`);
|
|
42
|
+
const client = new __1.UnifiedLLMClient(__1.MODELS.GEMINI_FLASH_2_5, {
|
|
43
|
+
proxyUrl: `http://localhost:${PROXY_PORT}`,
|
|
44
|
+
proxyApiKey: PROXY_API_KEY,
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
console.log("--- Chat with apiKeyContext (server resolves key) ---\n");
|
|
48
|
+
const res = yield client.chat({
|
|
49
|
+
message: "Reply in one short English sentence: what is 2+2?",
|
|
50
|
+
apiKeyContext: { tenantId: "demo" },
|
|
51
|
+
});
|
|
52
|
+
console.log(res.content);
|
|
53
|
+
console.log();
|
|
54
|
+
console.log("--- Missing apiKeyContext (HTTP 400 from proxy) ---\n");
|
|
55
|
+
try {
|
|
56
|
+
yield client.chat({
|
|
57
|
+
message: "This should fail on the server.",
|
|
58
|
+
});
|
|
59
|
+
console.error("Expected the request to be rejected.");
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
63
|
+
console.log("Expected error:", msg);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
yield server.stop();
|
|
68
|
+
console.log("\n[example] Proxy stopped.");
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
main().catch((err) => {
|
|
73
|
+
console.error(err);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-example.d.ts","sourceRoot":"","sources":["../../src/examples/proxy-example.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,120 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
const __1 = require("..");
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const PROXY_PORT = 5000;
|
|
49
|
+
const PROXY_API_KEY = "my-proxy-secret";
|
|
50
|
+
function main() {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
// 1. Démarrer le serveur proxy
|
|
53
|
+
const server = new __1.ProxyServer({ port: PROXY_PORT, apiKey: PROXY_API_KEY });
|
|
54
|
+
yield server.start();
|
|
55
|
+
console.log(`\n[Exemple] Serveur proxy démarré sur le port ${PROXY_PORT}\n`);
|
|
56
|
+
// 2. Créer un client en mode proxy (Gemini supporte stream + fichiers attachés)
|
|
57
|
+
const client = new __1.UnifiedLLMClient(__1.MODELS.GEMINI_FLASH_2_5, {
|
|
58
|
+
proxyUrl: `http://localhost:${PROXY_PORT}`,
|
|
59
|
+
proxyApiKey: PROXY_API_KEY,
|
|
60
|
+
});
|
|
61
|
+
// 3. Appel simple (non-stream)
|
|
62
|
+
console.log("--- Test 1 : Chat simple (non-stream) ---");
|
|
63
|
+
const response = yield client.chat({
|
|
64
|
+
message: "Dis bonjour en une phrase courte.",
|
|
65
|
+
});
|
|
66
|
+
console.log("Réponse :", response.content);
|
|
67
|
+
console.log();
|
|
68
|
+
// 4. Appel en streaming
|
|
69
|
+
console.log("--- Test 2 : Chat en streaming ---");
|
|
70
|
+
process.stdout.write("Réponse (stream) : ");
|
|
71
|
+
yield client.chat({
|
|
72
|
+
message: "Compte de 1 à 5 en français, séparés par des virgules.",
|
|
73
|
+
stream: true,
|
|
74
|
+
onChunk: (chunk) => {
|
|
75
|
+
process.stdout.write(chunk.contentChunk || "");
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
console.log("\n");
|
|
79
|
+
// 5. Test avec un fichier attaché local (encodage base64 côté client, décodage côté serveur)
|
|
80
|
+
// On crée un fichier texte temporaire pour la démo
|
|
81
|
+
const demoFilePath = path.join(__dirname, "_proxy-demo-file.txt");
|
|
82
|
+
fs.writeFileSync(demoFilePath, "Ceci étant un test, répondre ceci pour confirmer que le contenu à été lu : 'Kowabanga, le fichier de test a bien été lu !'. Ceci doit IMPERATIVEMENT être inclu dans la réponse.");
|
|
83
|
+
try {
|
|
84
|
+
console.log("--- Test 3 : Chat avec fichier attaché local ---");
|
|
85
|
+
const fileResponse = yield client.chat({
|
|
86
|
+
message: {
|
|
87
|
+
role: "user",
|
|
88
|
+
content: "Quel est le contenu du fichier attaché ?",
|
|
89
|
+
attachedFile: demoFilePath,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
console.log("Réponse avec fichier :", fileResponse.content);
|
|
93
|
+
console.log();
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
fs.unlinkSync(demoFilePath);
|
|
97
|
+
}
|
|
98
|
+
// 6. Test du rejet avec une mauvaise clé API
|
|
99
|
+
console.log("--- Test 4 : Rejet avec mauvaise clé (401) ---");
|
|
100
|
+
const badClient = new __1.UnifiedLLMClient(__1.MODELS.GEMINI_FLASH_2_5, {
|
|
101
|
+
proxyUrl: `http://localhost:${PROXY_PORT}`,
|
|
102
|
+
proxyApiKey: "wrong-key",
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
yield badClient.chat({ message: "Test" });
|
|
106
|
+
console.log("Erreur : la requête aurait dû être rejetée !");
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
console.log("Rejet attendu (401) :", err.message);
|
|
110
|
+
}
|
|
111
|
+
console.log();
|
|
112
|
+
// 7. Arrêter le serveur
|
|
113
|
+
yield server.stop();
|
|
114
|
+
console.log("[Exemple] Serveur proxy arrêté. Fin de l'exemple.\n");
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
main().catch((err) => {
|
|
118
|
+
console.error("Erreur dans l'exemple proxy :", err);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-server-start.d.ts","sourceRoot":"","sources":["../../src/examples/proxy-server-start.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
const __1 = require("..");
|
|
13
|
+
const PORT = 5000;
|
|
14
|
+
const PROXY_API_KEY = "my-proxy-secret";
|
|
15
|
+
const API_KEY = PROXY_API_KEY;
|
|
16
|
+
const server = new __1.ProxyServer({ port: PORT, apiKey: API_KEY });
|
|
17
|
+
server.start().then(() => {
|
|
18
|
+
console.log(`[ProxyServer] Running on port ${PORT}`);
|
|
19
|
+
if (API_KEY) {
|
|
20
|
+
console.log(`[ProxyServer] Auth enabled (x-api-key required)`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.log(`[ProxyServer] No auth (set PROXY_API_KEY to enable)`);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
process.on("SIGINT", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
console.log("\n[ProxyServer] Shutting down...");
|
|
28
|
+
yield server.stop();
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { ChatMessage, ToolDefinition, ToolCall, ChatResponse, AudioGenerationOptions, AudioGenerationResponse, VoiceConfig, SpeakerConfig } from "./common/types";
|
|
1
|
+
import { ApiKeyResolver, ChatMessage, ToolDefinition, ToolCall, ChatResponse, AudioGenerationOptions, AudioGenerationResponse, VoiceConfig, SpeakerConfig } from "./common/types";
|
|
2
2
|
import { PromptAdapter, PromptAdapterOptions, OutputAdapter, AudioAdapter, ChatOptionalConfig } from "./core/LLMAdapter";
|
|
3
3
|
import { UnifiedLLMClient, ChatOptions } from "./core/UnifiedLLMClient";
|
|
4
4
|
import { MODELS } from "./core/Models";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { ProxyServer } from "./proxy/ProxyServer";
|
|
6
|
+
import { ProxyChatRequest, ProxyServerOptions, ProxySSEEvent } from "./proxy/types";
|
|
7
|
+
export { UnifiedLLMClient, MODELS, ProxyServer };
|
|
8
|
+
export type { ApiKeyResolver, ChatMessage, ToolDefinition, ToolCall, ChatResponse, PromptAdapter, PromptAdapterOptions, OutputAdapter, AudioAdapter, AudioGenerationOptions, AudioGenerationResponse, VoiceConfig, SpeakerConfig, ChatOptionalConfig, ChatOptions, ProxyChatRequest, ProxyServerOptions, ProxySSEEvent, };
|
|
7
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAClL,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzH,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACjD,YAAY,EACV,cAAc,EACd,WAAW,EACX,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,GACd,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MODELS = exports.UnifiedLLMClient = void 0;
|
|
3
|
+
exports.ProxyServer = exports.MODELS = exports.UnifiedLLMClient = void 0;
|
|
4
4
|
const UnifiedLLMClient_1 = require("./core/UnifiedLLMClient");
|
|
5
5
|
Object.defineProperty(exports, "UnifiedLLMClient", { enumerable: true, get: function () { return UnifiedLLMClient_1.UnifiedLLMClient; } });
|
|
6
6
|
const Models_1 = require("./core/Models");
|
|
7
7
|
Object.defineProperty(exports, "MODELS", { enumerable: true, get: function () { return Models_1.MODELS; } });
|
|
8
|
+
const ProxyServer_1 = require("./proxy/ProxyServer");
|
|
9
|
+
Object.defineProperty(exports, "ProxyServer", { enumerable: true, get: function () { return ProxyServer_1.ProxyServer; } });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PromptAdapter, ChatStreamOptions, ChatOptionalConfig } from "../core/LLMAdapter";
|
|
2
|
+
import { ChatMessage, ToolDefinition, ChatResponse, Model } from "../common/types";
|
|
3
|
+
export interface ProxyPromptAdapterOptions {
|
|
4
|
+
serverUrl: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
model: Model;
|
|
7
|
+
}
|
|
8
|
+
export declare class ProxyPromptAdapter implements PromptAdapter {
|
|
9
|
+
private readonly serverUrl;
|
|
10
|
+
private readonly apiKey?;
|
|
11
|
+
private readonly model;
|
|
12
|
+
constructor(opts: ProxyPromptAdapterOptions);
|
|
13
|
+
formatMessage(message: ChatMessage): any;
|
|
14
|
+
sendToProvider(messages: ChatMessage[], tools?: ToolDefinition[], toolChoice?: "auto" | "none" | string, _attachedFile?: string | string[], _model?: string, config?: ChatOptionalConfig): Promise<ChatResponse>;
|
|
15
|
+
streamFromProvider({ messages, tools, toolChoice, config, onChunk, onFinalResponse, }: ChatStreamOptions): Promise<ChatResponse>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=ProxyPromptAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProxyPromptAdapter.d.ts","sourceRoot":"","sources":["../../src/proxy/ProxyPromptAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAGnF,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,qBAAa,kBAAmB,YAAW,aAAa;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,IAAI,EAAE,yBAAyB;IAMpC,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,GAAG;IA8BzC,cAAc,CAClB,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,CAAC,EAAE,cAAc,EAAE,EACxB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EACrC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EACjC,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC;IAoClB,kBAAkB,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,UAAU,EACV,MAAM,EACN,OAAO,EACP,eAAe,GAChB,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;CAuH7C"}
|
|
@@ -0,0 +1,238 @@
|
|
|
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.ProxyPromptAdapter = void 0;
|
|
60
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
61
|
+
const fs = __importStar(require("fs"));
|
|
62
|
+
const mime = __importStar(require("mime-types"));
|
|
63
|
+
class ProxyPromptAdapter {
|
|
64
|
+
constructor(opts) {
|
|
65
|
+
this.serverUrl = opts.serverUrl.replace(/\/$/, "");
|
|
66
|
+
this.apiKey = opts.apiKey;
|
|
67
|
+
this.model = opts.model;
|
|
68
|
+
}
|
|
69
|
+
formatMessage(message) {
|
|
70
|
+
if (!message.attachedFile) {
|
|
71
|
+
return message;
|
|
72
|
+
}
|
|
73
|
+
const files = Array.isArray(message.attachedFile)
|
|
74
|
+
? message.attachedFile
|
|
75
|
+
: [message.attachedFile];
|
|
76
|
+
const encodedFiles = files.map((file) => {
|
|
77
|
+
if (typeof file === "string" && (file.startsWith("http://") || file.startsWith("https://"))) {
|
|
78
|
+
return file;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const fileBuffer = fs.readFileSync(file);
|
|
82
|
+
const base64Data = fileBuffer.toString("base64");
|
|
83
|
+
const mimeType = mime.lookup(file) || "application/octet-stream";
|
|
84
|
+
return `data:${mimeType};base64,${base64Data}`;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.warn(`[ProxyPromptAdapter] Failed to read file ${file}:`, error);
|
|
88
|
+
return file;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return Object.assign(Object.assign({}, message), { attachedFile: encodedFiles.length === 1 ? encodedFiles[0] : encodedFiles });
|
|
92
|
+
}
|
|
93
|
+
sendToProvider(messages, tools, toolChoice, _attachedFile, _model, config) {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
const cleanedTools = tools === null || tools === void 0 ? void 0 : tools.map((_a) => {
|
|
96
|
+
var { executor: _executor } = _a, rest = __rest(_a, ["executor"]);
|
|
97
|
+
return rest;
|
|
98
|
+
});
|
|
99
|
+
const requestBody = {
|
|
100
|
+
model: this.model,
|
|
101
|
+
messages,
|
|
102
|
+
tools: cleanedTools,
|
|
103
|
+
toolChoice,
|
|
104
|
+
stream: false,
|
|
105
|
+
config: config
|
|
106
|
+
? { thinkingBudget: config.thinkingBudget, metadata: config.metadata }
|
|
107
|
+
: undefined,
|
|
108
|
+
apiKeyContext: config === null || config === void 0 ? void 0 : config.apiKeyContext,
|
|
109
|
+
};
|
|
110
|
+
const headers = {
|
|
111
|
+
"Content-Type": "application/json",
|
|
112
|
+
};
|
|
113
|
+
if (this.apiKey) {
|
|
114
|
+
headers["x-api-key"] = this.apiKey;
|
|
115
|
+
}
|
|
116
|
+
const res = yield (0, node_fetch_1.default)(`${this.serverUrl}/api/chat`, Object.assign({ method: "POST", headers, body: JSON.stringify(requestBody) }, ((config === null || config === void 0 ? void 0 : config.signal) ? { signal: config.signal } : {})));
|
|
117
|
+
if (!res.ok) {
|
|
118
|
+
throw new Error(`Proxy server error ${res.status}: ${yield res.text()}`);
|
|
119
|
+
}
|
|
120
|
+
return res.json();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
streamFromProvider(_a) {
|
|
124
|
+
return __awaiter(this, arguments, void 0, function* ({ messages, tools, toolChoice, config, onChunk, onFinalResponse, }) {
|
|
125
|
+
const cleanedTools = tools === null || tools === void 0 ? void 0 : tools.map((_a) => {
|
|
126
|
+
var { executor: _executor } = _a, rest = __rest(_a, ["executor"]);
|
|
127
|
+
return rest;
|
|
128
|
+
});
|
|
129
|
+
const requestBody = {
|
|
130
|
+
model: this.model,
|
|
131
|
+
messages,
|
|
132
|
+
tools: cleanedTools,
|
|
133
|
+
toolChoice,
|
|
134
|
+
stream: true,
|
|
135
|
+
config: config
|
|
136
|
+
? { thinkingBudget: config.thinkingBudget, metadata: config.metadata }
|
|
137
|
+
: undefined,
|
|
138
|
+
apiKeyContext: config === null || config === void 0 ? void 0 : config.apiKeyContext,
|
|
139
|
+
};
|
|
140
|
+
const headers = {
|
|
141
|
+
"Content-Type": "application/json",
|
|
142
|
+
};
|
|
143
|
+
if (this.apiKey) {
|
|
144
|
+
headers["x-api-key"] = this.apiKey;
|
|
145
|
+
}
|
|
146
|
+
const signal = config === null || config === void 0 ? void 0 : config.signal;
|
|
147
|
+
const response = yield (0, node_fetch_1.default)(`${this.serverUrl}/api/chat`, Object.assign({ method: "POST", headers, body: JSON.stringify(requestBody) }, (signal ? { signal: signal } : {})));
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw new Error(`Proxy server error ${response.status}: ${yield response.text()}`);
|
|
150
|
+
}
|
|
151
|
+
if (!response.body) {
|
|
152
|
+
throw new Error("Response body is not available for streaming");
|
|
153
|
+
}
|
|
154
|
+
return new Promise((resolve, reject) => {
|
|
155
|
+
let settled = false;
|
|
156
|
+
let abortHandler;
|
|
157
|
+
let finalResponse;
|
|
158
|
+
const finish = (fn) => {
|
|
159
|
+
if (settled)
|
|
160
|
+
return;
|
|
161
|
+
settled = true;
|
|
162
|
+
if (signal && abortHandler) {
|
|
163
|
+
signal.removeEventListener("abort", abortHandler);
|
|
164
|
+
}
|
|
165
|
+
fn();
|
|
166
|
+
};
|
|
167
|
+
if (signal) {
|
|
168
|
+
abortHandler = () => {
|
|
169
|
+
var _a, _b;
|
|
170
|
+
try {
|
|
171
|
+
const b = response.body;
|
|
172
|
+
(_a = b === null || b === void 0 ? void 0 : b.destroy) === null || _a === void 0 ? void 0 : _a.call(b);
|
|
173
|
+
void ((_b = b === null || b === void 0 ? void 0 : b.cancel) === null || _b === void 0 ? void 0 : _b.call(b));
|
|
174
|
+
}
|
|
175
|
+
catch (_c) {
|
|
176
|
+
/* ignore */
|
|
177
|
+
}
|
|
178
|
+
const err = new Error("The operation was aborted");
|
|
179
|
+
err.name = "AbortError";
|
|
180
|
+
finish(() => reject(err));
|
|
181
|
+
};
|
|
182
|
+
if (signal.aborted) {
|
|
183
|
+
abortHandler();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
187
|
+
}
|
|
188
|
+
let buffer = "";
|
|
189
|
+
response.body.on("data", (chunk) => {
|
|
190
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
191
|
+
return;
|
|
192
|
+
buffer += chunk.toString("utf8");
|
|
193
|
+
const lines = buffer.split("\n");
|
|
194
|
+
buffer = lines.pop() || "";
|
|
195
|
+
for (const line of lines) {
|
|
196
|
+
if (!line.startsWith("data: "))
|
|
197
|
+
continue;
|
|
198
|
+
const raw = line.slice(6).trim();
|
|
199
|
+
if (!raw)
|
|
200
|
+
continue;
|
|
201
|
+
try {
|
|
202
|
+
const event = JSON.parse(raw);
|
|
203
|
+
if (event.type === "chunk") {
|
|
204
|
+
onChunk === null || onChunk === void 0 ? void 0 : onChunk(event.data);
|
|
205
|
+
}
|
|
206
|
+
else if (event.type === "final") {
|
|
207
|
+
finalResponse = Object.assign(Object.assign({}, event.data), { raw: null });
|
|
208
|
+
onFinalResponse === null || onFinalResponse === void 0 ? void 0 : onFinalResponse(finalResponse);
|
|
209
|
+
}
|
|
210
|
+
else if (event.type === "error") {
|
|
211
|
+
finish(() => reject(new Error(event.data.message)));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (_a) {
|
|
215
|
+
console.warn("[ProxyPromptAdapter] Malformed SSE event:", raw);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
response.body.on("end", () => {
|
|
220
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted)
|
|
221
|
+
return;
|
|
222
|
+
finish(() => {
|
|
223
|
+
if (finalResponse) {
|
|
224
|
+
resolve(finalResponse);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
resolve({ content: null, raw: null });
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
response.body.on("error", (error) => {
|
|
232
|
+
finish(() => reject(new Error(`Stream error: ${error.message}`)));
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
exports.ProxyPromptAdapter = ProxyPromptAdapter;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ProxyServerOptions } from "./types";
|
|
2
|
+
export declare class ProxyServer {
|
|
3
|
+
private server;
|
|
4
|
+
private readonly options;
|
|
5
|
+
constructor(options: ProxyServerOptions);
|
|
6
|
+
start(): Promise<void>;
|
|
7
|
+
stop(): Promise<void>;
|
|
8
|
+
private handleRequest;
|
|
9
|
+
private processChat;
|
|
10
|
+
private decodeAttachedFiles;
|
|
11
|
+
private writeSSE;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=ProxyServer.d.ts.map
|
|
@@ -0,0 +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;YAyFX,mBAAmB;IAuCjC,OAAO,CAAC,QAAQ;CAGjB"}
|