openlayer 0.1.28 → 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 +15 -1
- package/dist/index.js +131 -37
- package/package.json +1 -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.
|
|
@@ -200,11 +201,14 @@ export declare class OpenAIMonitor {
|
|
|
200
201
|
*/
|
|
201
202
|
constructor({ openAiApiKey, openlayerApiKey, openlayerProjectName, openlayerInferencePipelineName, openlayerServerUrl, }: OpenAIMonitorConstructorProps);
|
|
202
203
|
private cost;
|
|
203
|
-
private
|
|
204
|
+
private chatCompletionPrompt;
|
|
205
|
+
private threadPrompt;
|
|
206
|
+
private inputVariables;
|
|
204
207
|
/**
|
|
205
208
|
* Creates a chat completion using the OpenAI client and streams the result to Openlayer.
|
|
206
209
|
* @param {ChatCompletionCreateParams} body - The parameters for creating a chat completion.
|
|
207
210
|
* @param {RequestOptions} [options] - Optional request options.
|
|
211
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
208
212
|
* @returns {Promise<ChatCompletion | Stream<ChatCompletionChunk>>} Promise of a ChatCompletion or a Stream
|
|
209
213
|
* @throws {Error} Throws errors from the OpenAI client.
|
|
210
214
|
*/
|
|
@@ -213,10 +217,20 @@ export declare class OpenAIMonitor {
|
|
|
213
217
|
* Creates a completion using the OpenAI client and streams the result to Openlayer.
|
|
214
218
|
* @param {CompletionCreateParams} body - The parameters for creating a completion.
|
|
215
219
|
* @param {RequestOptions} [options] - Optional request options.
|
|
220
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
216
221
|
* @returns {Promise<Completion | Stream<Completion>>} Promise that resolves to a Completion or a Stream.
|
|
217
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
|
@@ -310,20 +310,64 @@ class OpenAIMonitor {
|
|
|
310
310
|
? undefined
|
|
311
311
|
: (inputCost !== null && inputCost !== void 0 ? inputCost : 0) + (outputCost !== null && outputCost !== void 0 ? outputCost : 0);
|
|
312
312
|
};
|
|
313
|
-
this.
|
|
313
|
+
this.chatCompletionPrompt = (fromMessages) => fromMessages.map(({ content, role }, i) => ({
|
|
314
314
|
content: role === 'user' ? `{{ message_${i} }}` : content,
|
|
315
315
|
role,
|
|
316
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
|
+
};
|
|
317
360
|
/**
|
|
318
361
|
* Creates a chat completion using the OpenAI client and streams the result to Openlayer.
|
|
319
362
|
* @param {ChatCompletionCreateParams} body - The parameters for creating a chat completion.
|
|
320
363
|
* @param {RequestOptions} [options] - Optional request options.
|
|
364
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
321
365
|
* @returns {Promise<ChatCompletion | Stream<ChatCompletionChunk>>} Promise of a ChatCompletion or a Stream
|
|
322
366
|
* @throws {Error} Throws errors from the OpenAI client.
|
|
323
367
|
*/
|
|
324
368
|
this.createChatCompletion = (body, options, additionalLogs) => __awaiter(this, void 0, void 0, function* () {
|
|
325
|
-
var
|
|
326
|
-
var
|
|
369
|
+
var _g, e_2, _h, _j;
|
|
370
|
+
var _k, _l, _m, _o, _p, _q, _r;
|
|
327
371
|
if (!this.monitoringOn) {
|
|
328
372
|
console.warn('Monitoring is not active.');
|
|
329
373
|
}
|
|
@@ -337,34 +381,28 @@ class OpenAIMonitor {
|
|
|
337
381
|
const response = yield this.openAIClient.chat.completions.create(body, options);
|
|
338
382
|
try {
|
|
339
383
|
if (this.monitoringOn && typeof this.inferencePipeline !== 'undefined') {
|
|
340
|
-
const prompt = this.
|
|
341
|
-
const inputVariableNames = prompt
|
|
342
|
-
.filter(({ role }) => role === 'user')
|
|
343
|
-
.map(({ content }) => String(content).replace(/{{\s*|\s*}}/g, ''));
|
|
344
|
-
const inputVariables = body.messages
|
|
345
|
-
.filter(({ role }) => role === 'user')
|
|
346
|
-
.map(({ content }) => content);
|
|
347
|
-
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);
|
|
348
386
|
const config = Object.assign(Object.assign({}, this.openlayerClient.defaultConfig), { inputVariableNames,
|
|
349
387
|
prompt });
|
|
350
388
|
if (body.stream) {
|
|
351
389
|
const streamedResponse = response;
|
|
352
390
|
try {
|
|
353
|
-
for (var
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
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;
|
|
357
395
|
// Process each chunk - for example, accumulate input data
|
|
358
|
-
const chunkOutput = (
|
|
396
|
+
const chunkOutput = (_k = chunk.choices[0].delta.content) !== null && _k !== void 0 ? _k : '';
|
|
359
397
|
streamedOutput += chunkOutput;
|
|
360
398
|
}
|
|
361
399
|
}
|
|
362
|
-
catch (
|
|
400
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
363
401
|
finally {
|
|
364
402
|
try {
|
|
365
|
-
if (!
|
|
403
|
+
if (!_s && !_g && (_h = streamedResponse_1.return)) yield _h.call(streamedResponse_1);
|
|
366
404
|
}
|
|
367
|
-
finally { if (
|
|
405
|
+
finally { if (e_2) throw e_2.error; }
|
|
368
406
|
}
|
|
369
407
|
const endTime = Date.now();
|
|
370
408
|
const latency = endTime - startTime;
|
|
@@ -376,9 +414,9 @@ class OpenAIMonitor {
|
|
|
376
414
|
const endTime = Date.now();
|
|
377
415
|
const latency = endTime - startTime;
|
|
378
416
|
const output = nonStreamedResponse.choices[0].message.content;
|
|
379
|
-
const tokens = (
|
|
380
|
-
const inputTokens = (
|
|
381
|
-
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;
|
|
382
420
|
const cost = this.cost(nonStreamedResponse.model, inputTokens, outputTokens);
|
|
383
421
|
if (typeof output === 'string') {
|
|
384
422
|
this.openlayerClient.streamData(Object.assign(Object.assign({ cost,
|
|
@@ -399,12 +437,13 @@ class OpenAIMonitor {
|
|
|
399
437
|
* Creates a completion using the OpenAI client and streams the result to Openlayer.
|
|
400
438
|
* @param {CompletionCreateParams} body - The parameters for creating a completion.
|
|
401
439
|
* @param {RequestOptions} [options] - Optional request options.
|
|
440
|
+
* @param {StreamingData} [additionalLogs] - Optional metadata logs to include with the request sent to Openlayer.
|
|
402
441
|
* @returns {Promise<Completion | Stream<Completion>>} Promise that resolves to a Completion or a Stream.
|
|
403
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
|
*/
|