observa-sdk 0.0.14 → 0.0.16
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.cjs +84 -34
- package/dist/index.js +84 -34
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -451,7 +451,7 @@ function extractProviderFromModel(model) {
|
|
|
451
451
|
}
|
|
452
452
|
if (typeof model === "string") {
|
|
453
453
|
const parts = model.split("/");
|
|
454
|
-
if (parts.length > 1) {
|
|
454
|
+
if (parts.length > 1 && parts[0]) {
|
|
455
455
|
return parts[0].toLowerCase();
|
|
456
456
|
}
|
|
457
457
|
const modelLower = model.toLowerCase();
|
|
@@ -537,6 +537,53 @@ async function traceGenerateText(originalFn, args, options) {
|
|
|
537
537
|
throw error;
|
|
538
538
|
}
|
|
539
539
|
}
|
|
540
|
+
function wrapReadableStream(stream, onComplete, onError) {
|
|
541
|
+
const [userStream, trackingStream] = stream.tee();
|
|
542
|
+
const decoder = new TextDecoder();
|
|
543
|
+
let firstTokenTime = null;
|
|
544
|
+
const streamStartTime = Date.now();
|
|
545
|
+
const chunks = [];
|
|
546
|
+
(async () => {
|
|
547
|
+
try {
|
|
548
|
+
const reader = trackingStream.getReader();
|
|
549
|
+
while (true) {
|
|
550
|
+
const { done, value } = await reader.read();
|
|
551
|
+
if (done) break;
|
|
552
|
+
if (firstTokenTime === null && value !== null && value !== void 0) {
|
|
553
|
+
firstTokenTime = Date.now();
|
|
554
|
+
}
|
|
555
|
+
let text;
|
|
556
|
+
if (typeof value === "string") {
|
|
557
|
+
text = value;
|
|
558
|
+
} else if (value !== null && value !== void 0) {
|
|
559
|
+
try {
|
|
560
|
+
const testValue = value;
|
|
561
|
+
if (testValue instanceof Uint8Array || typeof ArrayBuffer !== "undefined" && typeof ArrayBuffer.isView === "function" && ArrayBuffer.isView(testValue)) {
|
|
562
|
+
text = decoder.decode(testValue, { stream: true });
|
|
563
|
+
} else {
|
|
564
|
+
text = String(value);
|
|
565
|
+
}
|
|
566
|
+
} catch {
|
|
567
|
+
text = String(value);
|
|
568
|
+
}
|
|
569
|
+
} else {
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
chunks.push(text);
|
|
573
|
+
}
|
|
574
|
+
const fullText = chunks.join("");
|
|
575
|
+
onComplete({
|
|
576
|
+
text: fullText,
|
|
577
|
+
timeToFirstToken: firstTokenTime ? firstTokenTime - streamStartTime : null,
|
|
578
|
+
streamingDuration: firstTokenTime ? Date.now() - firstTokenTime : null,
|
|
579
|
+
totalLatency: Date.now() - streamStartTime
|
|
580
|
+
});
|
|
581
|
+
} catch (error) {
|
|
582
|
+
onError(error);
|
|
583
|
+
}
|
|
584
|
+
})();
|
|
585
|
+
return userStream;
|
|
586
|
+
}
|
|
540
587
|
async function traceStreamText(originalFn, args, options) {
|
|
541
588
|
const startTime = Date.now();
|
|
542
589
|
const requestParams = args[0] || {};
|
|
@@ -546,43 +593,46 @@ async function traceStreamText(originalFn, args, options) {
|
|
|
546
593
|
try {
|
|
547
594
|
const result = await originalFn(...args);
|
|
548
595
|
if (result.textStream) {
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
596
|
+
const originalTextStream = result.textStream;
|
|
597
|
+
const isReadableStream = originalTextStream && typeof originalTextStream.getReader === "function";
|
|
598
|
+
if (isReadableStream) {
|
|
599
|
+
const wrappedStream = wrapReadableStream(
|
|
600
|
+
originalTextStream,
|
|
601
|
+
(fullResponse) => {
|
|
602
|
+
recordTrace3(
|
|
603
|
+
{
|
|
604
|
+
model: modelIdentifier,
|
|
605
|
+
prompt: requestParams.prompt || requestParams.messages || null,
|
|
606
|
+
messages: requestParams.messages || null
|
|
607
|
+
},
|
|
608
|
+
fullResponse,
|
|
609
|
+
startTime,
|
|
610
|
+
options,
|
|
611
|
+
fullResponse.timeToFirstToken,
|
|
612
|
+
fullResponse.streamingDuration,
|
|
613
|
+
provider
|
|
614
|
+
);
|
|
615
|
+
},
|
|
616
|
+
(err) => recordError3(
|
|
553
617
|
{
|
|
554
618
|
model: modelIdentifier,
|
|
555
|
-
prompt: requestParams.prompt || requestParams.messages || null
|
|
556
|
-
messages: requestParams.messages || null
|
|
619
|
+
prompt: requestParams.prompt || requestParams.messages || null
|
|
557
620
|
},
|
|
558
|
-
|
|
621
|
+
err,
|
|
559
622
|
startTime,
|
|
560
|
-
options
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
options
|
|
574
|
-
),
|
|
575
|
-
"vercel-ai"
|
|
576
|
-
);
|
|
577
|
-
const wrappedResult = Object.create(Object.getPrototypeOf(result));
|
|
578
|
-
Object.assign(wrappedResult, result);
|
|
579
|
-
Object.defineProperty(wrappedResult, "textStream", {
|
|
580
|
-
value: wrappedStream,
|
|
581
|
-
writable: true,
|
|
582
|
-
enumerable: true,
|
|
583
|
-
configurable: true
|
|
584
|
-
});
|
|
585
|
-
return wrappedResult;
|
|
623
|
+
options
|
|
624
|
+
)
|
|
625
|
+
);
|
|
626
|
+
const wrappedResult = Object.create(Object.getPrototypeOf(result));
|
|
627
|
+
Object.assign(wrappedResult, result);
|
|
628
|
+
Object.defineProperty(wrappedResult, "textStream", {
|
|
629
|
+
value: wrappedStream,
|
|
630
|
+
writable: true,
|
|
631
|
+
enumerable: true,
|
|
632
|
+
configurable: true
|
|
633
|
+
});
|
|
634
|
+
return wrappedResult;
|
|
635
|
+
}
|
|
586
636
|
}
|
|
587
637
|
recordTrace3(
|
|
588
638
|
{
|
package/dist/index.js
CHANGED
|
@@ -431,7 +431,7 @@ function extractProviderFromModel(model) {
|
|
|
431
431
|
}
|
|
432
432
|
if (typeof model === "string") {
|
|
433
433
|
const parts = model.split("/");
|
|
434
|
-
if (parts.length > 1) {
|
|
434
|
+
if (parts.length > 1 && parts[0]) {
|
|
435
435
|
return parts[0].toLowerCase();
|
|
436
436
|
}
|
|
437
437
|
const modelLower = model.toLowerCase();
|
|
@@ -517,6 +517,53 @@ async function traceGenerateText(originalFn, args, options) {
|
|
|
517
517
|
throw error;
|
|
518
518
|
}
|
|
519
519
|
}
|
|
520
|
+
function wrapReadableStream(stream, onComplete, onError) {
|
|
521
|
+
const [userStream, trackingStream] = stream.tee();
|
|
522
|
+
const decoder = new TextDecoder();
|
|
523
|
+
let firstTokenTime = null;
|
|
524
|
+
const streamStartTime = Date.now();
|
|
525
|
+
const chunks = [];
|
|
526
|
+
(async () => {
|
|
527
|
+
try {
|
|
528
|
+
const reader = trackingStream.getReader();
|
|
529
|
+
while (true) {
|
|
530
|
+
const { done, value } = await reader.read();
|
|
531
|
+
if (done) break;
|
|
532
|
+
if (firstTokenTime === null && value !== null && value !== void 0) {
|
|
533
|
+
firstTokenTime = Date.now();
|
|
534
|
+
}
|
|
535
|
+
let text;
|
|
536
|
+
if (typeof value === "string") {
|
|
537
|
+
text = value;
|
|
538
|
+
} else if (value !== null && value !== void 0) {
|
|
539
|
+
try {
|
|
540
|
+
const testValue = value;
|
|
541
|
+
if (testValue instanceof Uint8Array || typeof ArrayBuffer !== "undefined" && typeof ArrayBuffer.isView === "function" && ArrayBuffer.isView(testValue)) {
|
|
542
|
+
text = decoder.decode(testValue, { stream: true });
|
|
543
|
+
} else {
|
|
544
|
+
text = String(value);
|
|
545
|
+
}
|
|
546
|
+
} catch {
|
|
547
|
+
text = String(value);
|
|
548
|
+
}
|
|
549
|
+
} else {
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
chunks.push(text);
|
|
553
|
+
}
|
|
554
|
+
const fullText = chunks.join("");
|
|
555
|
+
onComplete({
|
|
556
|
+
text: fullText,
|
|
557
|
+
timeToFirstToken: firstTokenTime ? firstTokenTime - streamStartTime : null,
|
|
558
|
+
streamingDuration: firstTokenTime ? Date.now() - firstTokenTime : null,
|
|
559
|
+
totalLatency: Date.now() - streamStartTime
|
|
560
|
+
});
|
|
561
|
+
} catch (error) {
|
|
562
|
+
onError(error);
|
|
563
|
+
}
|
|
564
|
+
})();
|
|
565
|
+
return userStream;
|
|
566
|
+
}
|
|
520
567
|
async function traceStreamText(originalFn, args, options) {
|
|
521
568
|
const startTime = Date.now();
|
|
522
569
|
const requestParams = args[0] || {};
|
|
@@ -526,43 +573,46 @@ async function traceStreamText(originalFn, args, options) {
|
|
|
526
573
|
try {
|
|
527
574
|
const result = await originalFn(...args);
|
|
528
575
|
if (result.textStream) {
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
576
|
+
const originalTextStream = result.textStream;
|
|
577
|
+
const isReadableStream = originalTextStream && typeof originalTextStream.getReader === "function";
|
|
578
|
+
if (isReadableStream) {
|
|
579
|
+
const wrappedStream = wrapReadableStream(
|
|
580
|
+
originalTextStream,
|
|
581
|
+
(fullResponse) => {
|
|
582
|
+
recordTrace3(
|
|
583
|
+
{
|
|
584
|
+
model: modelIdentifier,
|
|
585
|
+
prompt: requestParams.prompt || requestParams.messages || null,
|
|
586
|
+
messages: requestParams.messages || null
|
|
587
|
+
},
|
|
588
|
+
fullResponse,
|
|
589
|
+
startTime,
|
|
590
|
+
options,
|
|
591
|
+
fullResponse.timeToFirstToken,
|
|
592
|
+
fullResponse.streamingDuration,
|
|
593
|
+
provider
|
|
594
|
+
);
|
|
595
|
+
},
|
|
596
|
+
(err) => recordError3(
|
|
533
597
|
{
|
|
534
598
|
model: modelIdentifier,
|
|
535
|
-
prompt: requestParams.prompt || requestParams.messages || null
|
|
536
|
-
messages: requestParams.messages || null
|
|
599
|
+
prompt: requestParams.prompt || requestParams.messages || null
|
|
537
600
|
},
|
|
538
|
-
|
|
601
|
+
err,
|
|
539
602
|
startTime,
|
|
540
|
-
options
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
options
|
|
554
|
-
),
|
|
555
|
-
"vercel-ai"
|
|
556
|
-
);
|
|
557
|
-
const wrappedResult = Object.create(Object.getPrototypeOf(result));
|
|
558
|
-
Object.assign(wrappedResult, result);
|
|
559
|
-
Object.defineProperty(wrappedResult, "textStream", {
|
|
560
|
-
value: wrappedStream,
|
|
561
|
-
writable: true,
|
|
562
|
-
enumerable: true,
|
|
563
|
-
configurable: true
|
|
564
|
-
});
|
|
565
|
-
return wrappedResult;
|
|
603
|
+
options
|
|
604
|
+
)
|
|
605
|
+
);
|
|
606
|
+
const wrappedResult = Object.create(Object.getPrototypeOf(result));
|
|
607
|
+
Object.assign(wrappedResult, result);
|
|
608
|
+
Object.defineProperty(wrappedResult, "textStream", {
|
|
609
|
+
value: wrappedStream,
|
|
610
|
+
writable: true,
|
|
611
|
+
enumerable: true,
|
|
612
|
+
configurable: true
|
|
613
|
+
});
|
|
614
|
+
return wrappedResult;
|
|
615
|
+
}
|
|
566
616
|
}
|
|
567
617
|
recordTrace3(
|
|
568
618
|
{
|
package/package.json
CHANGED