openlayer 0.1.27 → 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +17 -3
- package/dist/index.js +133 -39
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RequestOptions } from 'openai/core';
|
|
2
2
|
import { ChatCompletion, ChatCompletionChunk, ChatCompletionCreateParams, ChatCompletionMessageParam, Completion, CompletionCreateParams } from 'openai/resources';
|
|
3
|
+
import { Run } from 'openai/resources/beta/threads/runs/runs';
|
|
3
4
|
import { Stream } from 'openai/streaming';
|
|
4
5
|
/**
|
|
5
6
|
* Represents the data structure for a chat completion.
|
|
@@ -143,7 +144,6 @@ export declare class OpenlayerClient {
|
|
|
143
144
|
/**
|
|
144
145
|
* Constructs an OpenlayerClient instance.
|
|
145
146
|
* @param {OpenlayerClientConstructorProps} props - The config for the Openlayer client. The API key is required.
|
|
146
|
-
* @throws {Error} Throws an error if the Openlayer API key is not provided.
|
|
147
147
|
*/
|
|
148
148
|
constructor({ openlayerApiKey, openlayerServerUrl, }: OpenlayerClientConstructorProps);
|
|
149
149
|
private resolvedQuery;
|
|
@@ -201,22 +201,36 @@ export declare class OpenAIMonitor {
|
|
|
201
201
|
*/
|
|
202
202
|
constructor({ openAiApiKey, openlayerApiKey, openlayerProjectName, openlayerInferencePipelineName, openlayerServerUrl, }: OpenAIMonitorConstructorProps);
|
|
203
203
|
private cost;
|
|
204
|
-
private
|
|
204
|
+
private chatCompletionPrompt;
|
|
205
|
+
private threadPrompt;
|
|
206
|
+
private inputVariables;
|
|
205
207
|
/**
|
|
206
208
|
* Creates a chat completion using the OpenAI client and streams the result to Openlayer.
|
|
207
209
|
* @param {ChatCompletionCreateParams} body - The parameters for creating a chat completion.
|
|
208
210
|
* @param {RequestOptions} [options] - Optional request options.
|
|
211
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
209
212
|
* @returns {Promise<ChatCompletion | Stream<ChatCompletionChunk>>} Promise of a ChatCompletion or a Stream
|
|
210
|
-
* @throws {Error} Throws
|
|
213
|
+
* @throws {Error} Throws errors from the OpenAI client.
|
|
211
214
|
*/
|
|
212
215
|
createChatCompletion: (body: ChatCompletionCreateParams, options?: RequestOptions, additionalLogs?: StreamingData) => Promise<ChatCompletion | Stream<ChatCompletionChunk>>;
|
|
213
216
|
/**
|
|
214
217
|
* Creates a completion using the OpenAI client and streams the result to Openlayer.
|
|
215
218
|
* @param {CompletionCreateParams} body - The parameters for creating a completion.
|
|
216
219
|
* @param {RequestOptions} [options] - Optional request options.
|
|
220
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
217
221
|
* @returns {Promise<Completion | Stream<Completion>>} Promise that resolves to a Completion or a Stream.
|
|
222
|
+
* @throws {Error} Throws errors from the OpenAI client.
|
|
218
223
|
*/
|
|
219
224
|
createCompletion: (body: CompletionCreateParams, options?: RequestOptions, additionalLogs?: StreamingData) => Promise<Completion | Stream<Completion>>;
|
|
225
|
+
/**
|
|
226
|
+
* Monitor a run from an OpenAI assistant.
|
|
227
|
+
* Once the run is completed, the thread data is published to Openlayer,
|
|
228
|
+
* along with the latency, cost, and number of tokens used.
|
|
229
|
+
* @param {Run} run - The run created by the OpenAI assistant.
|
|
230
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
231
|
+
* @returns {Promise<void>} A promise that resolves when the run data has been successfully published to Openlayer.
|
|
232
|
+
*/
|
|
233
|
+
logThreadRun(run: Run, additionalLogs?: StreamingData): Promise<void>;
|
|
220
234
|
/**
|
|
221
235
|
* Starts monitoring for the OpenAI Monitor instance. If monitoring is already active, a warning is logged.
|
|
222
236
|
*/
|
package/dist/index.js
CHANGED
|
@@ -98,7 +98,6 @@ class OpenlayerClient {
|
|
|
98
98
|
/**
|
|
99
99
|
* Constructs an OpenlayerClient instance.
|
|
100
100
|
* @param {OpenlayerClientConstructorProps} props - The config for the Openlayer client. The API key is required.
|
|
101
|
-
* @throws {Error} Throws an error if the Openlayer API key is not provided.
|
|
102
101
|
*/
|
|
103
102
|
constructor({ openlayerApiKey, openlayerServerUrl, }) {
|
|
104
103
|
this.defaultConfig = {
|
|
@@ -311,20 +310,64 @@ class OpenAIMonitor {
|
|
|
311
310
|
? undefined
|
|
312
311
|
: (inputCost !== null && inputCost !== void 0 ? inputCost : 0) + (outputCost !== null && outputCost !== void 0 ? outputCost : 0);
|
|
313
312
|
};
|
|
314
|
-
this.
|
|
313
|
+
this.chatCompletionPrompt = (fromMessages) => fromMessages.map(({ content, role }, i) => ({
|
|
315
314
|
content: role === 'user' ? `{{ message_${i} }}` : content,
|
|
316
315
|
role,
|
|
317
316
|
}));
|
|
317
|
+
this.threadPrompt = (fromMessages) => __awaiter(this, void 0, void 0, function* () {
|
|
318
|
+
var _a, e_1, _b, _c;
|
|
319
|
+
const messages = [];
|
|
320
|
+
try {
|
|
321
|
+
for (var _d = true, _e = __asyncValues(fromMessages.iterPages()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
322
|
+
_c = _f.value;
|
|
323
|
+
_d = false;
|
|
324
|
+
const page = _c;
|
|
325
|
+
messages.push(...page.getPaginatedItems());
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
329
|
+
finally {
|
|
330
|
+
try {
|
|
331
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
332
|
+
}
|
|
333
|
+
finally { if (e_1) throw e_1.error; }
|
|
334
|
+
}
|
|
335
|
+
return messages
|
|
336
|
+
.map(({ content, role }) => content.map((item) => ({
|
|
337
|
+
content: (() => {
|
|
338
|
+
switch (item.type) {
|
|
339
|
+
case 'image_file':
|
|
340
|
+
return item.image_file.file_id;
|
|
341
|
+
case 'text':
|
|
342
|
+
default:
|
|
343
|
+
return item.text.value;
|
|
344
|
+
}
|
|
345
|
+
})(),
|
|
346
|
+
role,
|
|
347
|
+
})))
|
|
348
|
+
.flat();
|
|
349
|
+
});
|
|
350
|
+
this.inputVariables = (fromPrompt, andMessages) => {
|
|
351
|
+
const inputVariableNames = fromPrompt
|
|
352
|
+
.filter(({ role }) => role === 'user')
|
|
353
|
+
.map(({ content }) => String(content).replace(/{{\s*|\s*}}/g, ''));
|
|
354
|
+
const inputVariables = andMessages
|
|
355
|
+
.filter(({ role }) => role === 'user')
|
|
356
|
+
.map(({ content }) => content);
|
|
357
|
+
const inputVariablesMap = inputVariableNames.reduce((acc, name, i) => (Object.assign(Object.assign({}, acc), { [name]: inputVariables[i] })), {});
|
|
358
|
+
return { inputVariableNames, inputVariables, inputVariablesMap };
|
|
359
|
+
};
|
|
318
360
|
/**
|
|
319
361
|
* Creates a chat completion using the OpenAI client and streams the result to Openlayer.
|
|
320
362
|
* @param {ChatCompletionCreateParams} body - The parameters for creating a chat completion.
|
|
321
363
|
* @param {RequestOptions} [options] - Optional request options.
|
|
364
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
322
365
|
* @returns {Promise<ChatCompletion | Stream<ChatCompletionChunk>>} Promise of a ChatCompletion or a Stream
|
|
323
|
-
* @throws {Error} Throws
|
|
366
|
+
* @throws {Error} Throws errors from the OpenAI client.
|
|
324
367
|
*/
|
|
325
368
|
this.createChatCompletion = (body, options, additionalLogs) => __awaiter(this, void 0, void 0, function* () {
|
|
326
|
-
var
|
|
327
|
-
var
|
|
369
|
+
var _g, e_2, _h, _j;
|
|
370
|
+
var _k, _l, _m, _o, _p, _q, _r;
|
|
328
371
|
if (!this.monitoringOn) {
|
|
329
372
|
console.warn('Monitoring is not active.');
|
|
330
373
|
}
|
|
@@ -338,34 +381,28 @@ class OpenAIMonitor {
|
|
|
338
381
|
const response = yield this.openAIClient.chat.completions.create(body, options);
|
|
339
382
|
try {
|
|
340
383
|
if (this.monitoringOn && typeof this.inferencePipeline !== 'undefined') {
|
|
341
|
-
const prompt = this.
|
|
342
|
-
const inputVariableNames = prompt
|
|
343
|
-
.filter(({ role }) => role === 'user')
|
|
344
|
-
.map(({ content }) => String(content).replace(/{{\s*|\s*}}/g, ''));
|
|
345
|
-
const inputVariables = body.messages
|
|
346
|
-
.filter(({ role }) => role === 'user')
|
|
347
|
-
.map(({ content }) => content);
|
|
348
|
-
const inputVariablesMap = inputVariableNames.reduce((acc, name, i) => (Object.assign(Object.assign({}, acc), { [name]: inputVariables[i] })), {});
|
|
384
|
+
const prompt = this.chatCompletionPrompt(body.messages);
|
|
385
|
+
const { inputVariableNames, inputVariablesMap } = this.inputVariables(prompt, body.messages);
|
|
349
386
|
const config = Object.assign(Object.assign({}, this.openlayerClient.defaultConfig), { inputVariableNames,
|
|
350
387
|
prompt });
|
|
351
388
|
if (body.stream) {
|
|
352
389
|
const streamedResponse = response;
|
|
353
390
|
try {
|
|
354
|
-
for (var
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const chunk =
|
|
391
|
+
for (var _s = true, streamedResponse_1 = __asyncValues(streamedResponse), streamedResponse_1_1; streamedResponse_1_1 = yield streamedResponse_1.next(), _g = streamedResponse_1_1.done, !_g; _s = true) {
|
|
392
|
+
_j = streamedResponse_1_1.value;
|
|
393
|
+
_s = false;
|
|
394
|
+
const chunk = _j;
|
|
358
395
|
// Process each chunk - for example, accumulate input data
|
|
359
|
-
const chunkOutput = (
|
|
396
|
+
const chunkOutput = (_k = chunk.choices[0].delta.content) !== null && _k !== void 0 ? _k : '';
|
|
360
397
|
streamedOutput += chunkOutput;
|
|
361
398
|
}
|
|
362
399
|
}
|
|
363
|
-
catch (
|
|
400
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
364
401
|
finally {
|
|
365
402
|
try {
|
|
366
|
-
if (!
|
|
403
|
+
if (!_s && !_g && (_h = streamedResponse_1.return)) yield _h.call(streamedResponse_1);
|
|
367
404
|
}
|
|
368
|
-
finally { if (
|
|
405
|
+
finally { if (e_2) throw e_2.error; }
|
|
369
406
|
}
|
|
370
407
|
const endTime = Date.now();
|
|
371
408
|
const latency = endTime - startTime;
|
|
@@ -377,9 +414,9 @@ class OpenAIMonitor {
|
|
|
377
414
|
const endTime = Date.now();
|
|
378
415
|
const latency = endTime - startTime;
|
|
379
416
|
const output = nonStreamedResponse.choices[0].message.content;
|
|
380
|
-
const tokens = (
|
|
381
|
-
const inputTokens = (
|
|
382
|
-
const outputTokens = (
|
|
417
|
+
const tokens = (_m = (_l = nonStreamedResponse.usage) === null || _l === void 0 ? void 0 : _l.total_tokens) !== null && _m !== void 0 ? _m : 0;
|
|
418
|
+
const inputTokens = (_p = (_o = nonStreamedResponse.usage) === null || _o === void 0 ? void 0 : _o.prompt_tokens) !== null && _p !== void 0 ? _p : 0;
|
|
419
|
+
const outputTokens = (_r = (_q = nonStreamedResponse.usage) === null || _q === void 0 ? void 0 : _q.completion_tokens) !== null && _r !== void 0 ? _r : 0;
|
|
383
420
|
const cost = this.cost(nonStreamedResponse.model, inputTokens, outputTokens);
|
|
384
421
|
if (typeof output === 'string') {
|
|
385
422
|
this.openlayerClient.streamData(Object.assign(Object.assign({ cost,
|
|
@@ -400,11 +437,13 @@ class OpenAIMonitor {
|
|
|
400
437
|
* Creates a completion using the OpenAI client and streams the result to Openlayer.
|
|
401
438
|
* @param {CompletionCreateParams} body - The parameters for creating a completion.
|
|
402
439
|
* @param {RequestOptions} [options] - Optional request options.
|
|
440
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
403
441
|
* @returns {Promise<Completion | Stream<Completion>>} Promise that resolves to a Completion or a Stream.
|
|
442
|
+
* @throws {Error} Throws errors from the OpenAI client.
|
|
404
443
|
*/
|
|
405
444
|
this.createCompletion = (body, options, additionalLogs) => __awaiter(this, void 0, void 0, function* () {
|
|
406
|
-
var
|
|
407
|
-
var
|
|
445
|
+
var _t, e_3, _u, _v;
|
|
446
|
+
var _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7;
|
|
408
447
|
if (!body.prompt) {
|
|
409
448
|
console.error('No prompt provided.');
|
|
410
449
|
}
|
|
@@ -429,24 +468,24 @@ class OpenAIMonitor {
|
|
|
429
468
|
if (body.stream) {
|
|
430
469
|
const streamedResponse = response;
|
|
431
470
|
try {
|
|
432
|
-
for (var
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const chunk =
|
|
471
|
+
for (var _8 = true, streamedResponse_2 = __asyncValues(streamedResponse), streamedResponse_2_1; streamedResponse_2_1 = yield streamedResponse_2.next(), _t = streamedResponse_2_1.done, !_t; _8 = true) {
|
|
472
|
+
_v = streamedResponse_2_1.value;
|
|
473
|
+
_8 = false;
|
|
474
|
+
const chunk = _v;
|
|
436
475
|
// Process each chunk - for example, accumulate input data
|
|
437
476
|
streamedModel = chunk.model;
|
|
438
477
|
streamedOutput += chunk.choices[0].text.trim();
|
|
439
|
-
streamedTokens += (
|
|
440
|
-
streamedInputTokens += (
|
|
441
|
-
streamedOutputTokens += (
|
|
478
|
+
streamedTokens += (_x = (_w = chunk.usage) === null || _w === void 0 ? void 0 : _w.total_tokens) !== null && _x !== void 0 ? _x : 0;
|
|
479
|
+
streamedInputTokens += (_z = (_y = chunk.usage) === null || _y === void 0 ? void 0 : _y.prompt_tokens) !== null && _z !== void 0 ? _z : 0;
|
|
480
|
+
streamedOutputTokens += (_1 = (_0 = chunk.usage) === null || _0 === void 0 ? void 0 : _0.completion_tokens) !== null && _1 !== void 0 ? _1 : 0;
|
|
442
481
|
}
|
|
443
482
|
}
|
|
444
|
-
catch (
|
|
483
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
445
484
|
finally {
|
|
446
485
|
try {
|
|
447
|
-
if (!
|
|
486
|
+
if (!_8 && !_t && (_u = streamedResponse_2.return)) yield _u.call(streamedResponse_2);
|
|
448
487
|
}
|
|
449
|
-
finally { if (
|
|
488
|
+
finally { if (e_3) throw e_3.error; }
|
|
450
489
|
}
|
|
451
490
|
const endTime = Date.now();
|
|
452
491
|
const latency = endTime - startTime;
|
|
@@ -458,9 +497,9 @@ class OpenAIMonitor {
|
|
|
458
497
|
// Handle regular (non-streamed) response
|
|
459
498
|
const endTime = Date.now();
|
|
460
499
|
const latency = endTime - startTime;
|
|
461
|
-
const tokens = (
|
|
462
|
-
const inputTokens = (
|
|
463
|
-
const outputTokens = (
|
|
500
|
+
const tokens = (_3 = (_2 = nonStreamedResponse.usage) === null || _2 === void 0 ? void 0 : _2.total_tokens) !== null && _3 !== void 0 ? _3 : 0;
|
|
501
|
+
const inputTokens = (_5 = (_4 = nonStreamedResponse.usage) === null || _4 === void 0 ? void 0 : _4.prompt_tokens) !== null && _5 !== void 0 ? _5 : 0;
|
|
502
|
+
const outputTokens = (_7 = (_6 = nonStreamedResponse.usage) === null || _6 === void 0 ? void 0 : _6.completion_tokens) !== null && _7 !== void 0 ? _7 : 0;
|
|
464
503
|
const cost = this.cost(nonStreamedResponse.model, inputTokens, outputTokens);
|
|
465
504
|
this.openlayerClient.streamData(Object.assign({ cost, input: body.prompt, latency, output: nonStreamedResponse.choices[0].text, timestamp: startTime, tokens }, additionalLogs), config, this.inferencePipeline.id);
|
|
466
505
|
}
|
|
@@ -484,6 +523,61 @@ class OpenAIMonitor {
|
|
|
484
523
|
dangerouslyAllowBrowser: true,
|
|
485
524
|
});
|
|
486
525
|
}
|
|
526
|
+
/**
|
|
527
|
+
* Monitor a run from an OpenAI assistant.
|
|
528
|
+
* Once the run is completed, the thread data is published to Openlayer,
|
|
529
|
+
* along with the latency, cost, and number of tokens used.
|
|
530
|
+
* @param {Run} run - The run created by the OpenAI assistant.
|
|
531
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
532
|
+
* @returns {Promise<void>} A promise that resolves when the run data has been successfully published to Openlayer.
|
|
533
|
+
*/
|
|
534
|
+
logThreadRun(run, additionalLogs) {
|
|
535
|
+
var _a;
|
|
536
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
537
|
+
if (typeof this.inferencePipeline === 'undefined') {
|
|
538
|
+
console.error('No inference pipeline found.');
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
if (run.status !== 'completed') {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
try {
|
|
545
|
+
const { assistant_id, completed_at, created_at, model, thread_id,
|
|
546
|
+
// @ts-ignore
|
|
547
|
+
usage, } = run;
|
|
548
|
+
// @ts-ignore
|
|
549
|
+
const { completion_tokens, prompt_tokens, total_tokens } = typeof usage === 'undefined' ||
|
|
550
|
+
typeof usage !== 'object' ||
|
|
551
|
+
usage === null
|
|
552
|
+
? {}
|
|
553
|
+
: usage;
|
|
554
|
+
const cost = this.cost(model, prompt_tokens, completion_tokens);
|
|
555
|
+
const latency = completed_at === null ||
|
|
556
|
+
created_at === null ||
|
|
557
|
+
isNaN(completed_at) ||
|
|
558
|
+
isNaN(created_at)
|
|
559
|
+
? undefined
|
|
560
|
+
: (completed_at - created_at) * 1000;
|
|
561
|
+
const messages = yield this.openAIClient.beta.threads.messages.list(thread_id, { order: 'asc' });
|
|
562
|
+
const populatedPrompt = yield this.threadPrompt(messages);
|
|
563
|
+
const prompt = this.chatCompletionPrompt(populatedPrompt);
|
|
564
|
+
const { inputVariableNames, inputVariablesMap } = this.inputVariables(prompt, populatedPrompt);
|
|
565
|
+
const config = Object.assign(Object.assign({}, this.openlayerClient.defaultConfig), { inputVariableNames, prompt: prompt.slice(0, prompt.length - 1) });
|
|
566
|
+
const output = (_a = prompt[prompt.length - 1]) === null || _a === void 0 ? void 0 : _a.content;
|
|
567
|
+
const resolvedOutput = typeof output === 'string'
|
|
568
|
+
? output
|
|
569
|
+
: typeof output === 'undefined' || output === null
|
|
570
|
+
? ''
|
|
571
|
+
: `${output}`;
|
|
572
|
+
this.openlayerClient.streamData(Object.assign(Object.assign({ assistant_id,
|
|
573
|
+
cost,
|
|
574
|
+
latency, output: resolvedOutput, thread_id, timestamp: run.created_at, tokens: total_tokens }, inputVariablesMap), additionalLogs), config, this.inferencePipeline.id);
|
|
575
|
+
}
|
|
576
|
+
catch (error) {
|
|
577
|
+
console.error('Error logging thread run:', error);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
}
|
|
487
581
|
/**
|
|
488
582
|
* Starts monitoring for the OpenAI Monitor instance. If monitoring is already active, a warning is logged.
|
|
489
583
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openlayer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "The Openlayer TypeScript client",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"eslint-plugin-typescript-sort-keys": "^3.1.0",
|
|
21
21
|
"node-fetch": "^3.3.2",
|
|
22
22
|
"openai": "^4.19.0",
|
|
23
|
+
"openlayer": "^0.1.27",
|
|
23
24
|
"uuid": "^9.0.1"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|