@gammatech/aijsx 0.5.0-beta.1 → 0.5.0-dev.2024-03-11
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 +2 -0
- package/dist/index.d.mts +91 -390
- package/dist/index.d.ts +91 -390
- package/dist/index.js +1131 -1040
- package/dist/index.mjs +1125 -1035
- package/dist/{createElement--C_Hwi_c.d.mts → jsx-dev-runtime-zWb34twz.d.mts} +234 -109
- package/dist/{createElement--C_Hwi_c.d.ts → jsx-dev-runtime-zWb34twz.d.ts} +234 -109
- package/dist/jsx-dev-runtime.d.mts +1 -2
- package/dist/jsx-dev-runtime.d.ts +1 -2
- package/dist/jsx-runtime.d.mts +1 -29
- package/dist/jsx-runtime.d.ts +1 -29
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -30,16 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var src_exports = {};
|
|
31
31
|
__export(src_exports, {
|
|
32
32
|
AIFragment: () => AIFragment,
|
|
33
|
+
AISpanProcessor: () => AISpanProcessor,
|
|
33
34
|
AnthropicChatCompletion: () => AnthropicChatCompletion,
|
|
34
35
|
AnthropicClient: () => import_sdk2.default,
|
|
35
36
|
AnthropicClientContext: () => AnthropicClientContext,
|
|
36
37
|
AssistantMessage: () => AssistantMessage,
|
|
37
38
|
BoundLogger: () => BoundLogger,
|
|
38
|
-
ChainParseVariablesError: () => ChainParseVariablesError,
|
|
39
39
|
ChatCompletionError: () => ChatCompletionError,
|
|
40
|
+
ClaudeImageBlock: () => ClaudeImageBlock,
|
|
40
41
|
CombinedLogger: () => CombinedLogger,
|
|
41
42
|
ConsoleLogger: () => ConsoleLogger,
|
|
42
43
|
ContentTypeImage: () => ContentTypeImage,
|
|
44
|
+
EnrichingSpanProcessor: () => EnrichingSpanProcessor,
|
|
43
45
|
LogImplementation: () => LogImplementation,
|
|
44
46
|
NoopLogImplementation: () => NoopLogImplementation,
|
|
45
47
|
OpenAIChatCompletion: () => OpenAIChatCompletion,
|
|
@@ -48,10 +50,9 @@ __export(src_exports, {
|
|
|
48
50
|
OpenAIVisionChatCompletion: () => OpenAIVisionChatCompletion,
|
|
49
51
|
ParseVariablesError: () => ParseVariablesError,
|
|
50
52
|
PromptInvalidOutputError: () => PromptInvalidOutputError,
|
|
51
|
-
PromptParseVariablesError: () => PromptParseVariablesError,
|
|
52
53
|
SystemMessage: () => SystemMessage,
|
|
54
|
+
Trace: () => Trace,
|
|
53
55
|
UserMessage: () => UserMessage,
|
|
54
|
-
aijsxTracing: () => aijsxTracing,
|
|
55
56
|
attachedContextSymbol: () => attachedContextSymbol,
|
|
56
57
|
computeUsage: () => computeUsage,
|
|
57
58
|
countAnthropicTokens: () => import_tokenizer4.countTokens,
|
|
@@ -61,12 +62,12 @@ __export(src_exports, {
|
|
|
61
62
|
createPrompt: () => createPrompt,
|
|
62
63
|
createRenderContext: () => createRenderContext,
|
|
63
64
|
createStreamChain: () => createStreamChain,
|
|
64
|
-
defaultMaxTokens: () => defaultMaxTokens,
|
|
65
65
|
evaluatePrompt: () => evaluatePrompt,
|
|
66
66
|
tokenCountForOpenAIMessage: () => tokenCountForOpenAIMessage,
|
|
67
67
|
tokenCountForOpenAIVisionMessage: () => tokenCountForOpenAIVisionMessage,
|
|
68
68
|
tokenLimitForChatModel: () => tokenLimitForChatModel,
|
|
69
|
-
tokenizer: () => tokenizer
|
|
69
|
+
tokenizer: () => tokenizer,
|
|
70
|
+
tracing: () => tracing
|
|
70
71
|
});
|
|
71
72
|
module.exports = __toCommonJS(src_exports);
|
|
72
73
|
|
|
@@ -301,29 +302,30 @@ function coalesceParallelStreams(streams) {
|
|
|
301
302
|
return iter;
|
|
302
303
|
}
|
|
303
304
|
|
|
304
|
-
// src/
|
|
305
|
+
// src/log.ts
|
|
305
306
|
var LogImplementation = class {
|
|
306
307
|
loggedExceptions = /* @__PURE__ */ new WeakMap();
|
|
307
|
-
chatCompletionRequest(provider, payload) {
|
|
308
|
-
}
|
|
309
|
-
chatCompletionResponse(provider, payload) {
|
|
310
|
-
}
|
|
311
308
|
/**
|
|
312
309
|
* Logs exceptions thrown during an element's render.
|
|
313
310
|
*/
|
|
314
|
-
logException(exception) {
|
|
311
|
+
logException(ctx, exception) {
|
|
315
312
|
if (typeof exception === "object" && exception !== null) {
|
|
316
313
|
if (this.loggedExceptions.has(exception)) {
|
|
317
314
|
return;
|
|
318
315
|
}
|
|
319
316
|
this.loggedExceptions.set(exception, true);
|
|
320
317
|
}
|
|
321
|
-
this.log("error", `
|
|
318
|
+
this.log(ctx, "error", `Rendering failed with exception: ${exception}`);
|
|
319
|
+
}
|
|
320
|
+
chatCompletionRequest(_ctx, _provider, _payload) {
|
|
321
|
+
}
|
|
322
|
+
chatCompletionResponse(_ctx, _provider, _payload) {
|
|
322
323
|
}
|
|
323
324
|
};
|
|
324
325
|
var BoundLogger = class {
|
|
325
|
-
constructor(impl) {
|
|
326
|
+
constructor(impl, ctx) {
|
|
326
327
|
this.impl = impl;
|
|
328
|
+
this.ctx = ctx;
|
|
327
329
|
}
|
|
328
330
|
formatMessage = (...msgs) => msgs.map((m) => {
|
|
329
331
|
if (typeof m === "string") {
|
|
@@ -340,24 +342,24 @@ var BoundLogger = class {
|
|
|
340
342
|
return JSON.stringify(m);
|
|
341
343
|
}
|
|
342
344
|
}).join(" ");
|
|
343
|
-
error = (...msgs) => this.impl.log("error", this.formatMessage(...msgs));
|
|
344
|
-
warn = (...msgs) => this.impl.log("warn", this.formatMessage(...msgs));
|
|
345
|
-
info = (...msgs) => this.impl.log("info", this.formatMessage(...msgs));
|
|
346
|
-
debug = (...msgs) => this.impl.log("debug", this.formatMessage(...msgs));
|
|
347
|
-
logException = (exception) => this.impl.logException(exception);
|
|
345
|
+
error = (...msgs) => this.impl.log(this.ctx, "error", this.formatMessage(...msgs));
|
|
346
|
+
warn = (...msgs) => this.impl.log(this.ctx, "warn", this.formatMessage(...msgs));
|
|
347
|
+
info = (...msgs) => this.impl.log(this.ctx, "info", this.formatMessage(...msgs));
|
|
348
|
+
debug = (...msgs) => this.impl.log(this.ctx, "debug", this.formatMessage(...msgs));
|
|
349
|
+
logException = (exception) => this.impl.logException(this.ctx, exception);
|
|
348
350
|
chatCompletionRequest = (provider, payload) => {
|
|
349
|
-
return this.impl.chatCompletionRequest(provider, payload);
|
|
351
|
+
return this.impl.chatCompletionRequest(this.ctx, provider, payload);
|
|
350
352
|
};
|
|
351
353
|
chatCompletionResponse = (provider, payload) => {
|
|
352
|
-
return this.impl.chatCompletionResponse(provider, payload);
|
|
354
|
+
return this.impl.chatCompletionResponse(this.ctx, provider, payload);
|
|
353
355
|
};
|
|
354
356
|
};
|
|
355
357
|
var NoopLogImplementation = class extends LogImplementation {
|
|
356
|
-
log(
|
|
358
|
+
log(_ctx, _level, _message) {
|
|
357
359
|
}
|
|
358
360
|
};
|
|
359
361
|
var ConsoleLogger = class extends LogImplementation {
|
|
360
|
-
log(level, message) {
|
|
362
|
+
log(ctx, level, message) {
|
|
361
363
|
console.log(`[${level}] ${message}`);
|
|
362
364
|
}
|
|
363
365
|
};
|
|
@@ -369,9 +371,6 @@ var CombinedLogger = class extends LogImplementation {
|
|
|
369
371
|
log(...args) {
|
|
370
372
|
this.loggers.forEach((l) => l.log(...args));
|
|
371
373
|
}
|
|
372
|
-
logException(...args) {
|
|
373
|
-
this.loggers.forEach((l) => l.logException(...args));
|
|
374
|
-
}
|
|
375
374
|
chatCompletionRequest(...args) {
|
|
376
375
|
this.loggers.forEach((l) => l.chatCompletionRequest(...args));
|
|
377
376
|
}
|
|
@@ -381,10 +380,6 @@ var CombinedLogger = class extends LogImplementation {
|
|
|
381
380
|
};
|
|
382
381
|
|
|
383
382
|
// src/prompt/errors.ts
|
|
384
|
-
var PromptParseVariablesError = class extends Error {
|
|
385
|
-
};
|
|
386
|
-
var ChainParseVariablesError = class extends Error {
|
|
387
|
-
};
|
|
388
383
|
var ParseVariablesError = class extends Error {
|
|
389
384
|
};
|
|
390
385
|
var PromptInvalidOutputError = class extends Error {
|
|
@@ -393,121 +388,25 @@ var PromptInvalidOutputError = class extends Error {
|
|
|
393
388
|
// src/prompt/parseVariables.ts
|
|
394
389
|
function parseVariables(schema, variables) {
|
|
395
390
|
try {
|
|
396
|
-
return {
|
|
391
|
+
return { parsedVariables: schema.parse(variables), error: null };
|
|
397
392
|
} catch (err) {
|
|
398
393
|
let error = err;
|
|
399
394
|
if (err && typeof err === "object" && "flatten" in err) {
|
|
400
395
|
const errorMessage = JSON.stringify(err.flatten());
|
|
401
396
|
error = new ParseVariablesError(errorMessage);
|
|
402
397
|
}
|
|
403
|
-
return {
|
|
398
|
+
return { parsedVariables: null, error };
|
|
404
399
|
}
|
|
405
400
|
}
|
|
406
401
|
|
|
407
|
-
// src/
|
|
408
|
-
function renderLiteral(renderable) {
|
|
409
|
-
if (typeof renderable === "string") {
|
|
410
|
-
return renderable;
|
|
411
|
-
}
|
|
412
|
-
if (typeof renderable === "number") {
|
|
413
|
-
return renderable.toString();
|
|
414
|
-
}
|
|
415
|
-
if (typeof renderable === "undefined" || typeof renderable === "boolean" || renderable === null) {
|
|
416
|
-
return "";
|
|
417
|
-
}
|
|
418
|
-
return "";
|
|
419
|
-
}
|
|
420
|
-
function createRenderContext({
|
|
421
|
-
parentSpanId = null,
|
|
422
|
-
logger = new NoopLogImplementation(),
|
|
423
|
-
traceId = null,
|
|
424
|
-
contextValues = {}
|
|
425
|
-
} = {}) {
|
|
426
|
-
let spanContext = {};
|
|
427
|
-
if (traceId || parentSpanId) {
|
|
428
|
-
spanContext = {
|
|
429
|
-
traceId: traceId || void 0,
|
|
430
|
-
// set to invalid span id to make sure the span
|
|
431
|
-
// isn't mistakenly tagged for having a parent
|
|
432
|
-
spanId: parentSpanId || ""
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
return new StreamRenderContext(logger, contextValues, spanContext);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// src/RenderResult.ts
|
|
439
|
-
var accumResults = async (result) => {
|
|
440
|
-
let accum = "";
|
|
441
|
-
const iterator = result[Symbol.asyncIterator]();
|
|
442
|
-
for await (const value of iterator) {
|
|
443
|
-
accum += value;
|
|
444
|
-
}
|
|
445
|
-
return accum;
|
|
446
|
-
};
|
|
447
|
-
var GeneratorRenderResult = class {
|
|
448
|
-
// this promise like thing
|
|
449
|
-
constructor(generator) {
|
|
450
|
-
this.generator = generator;
|
|
451
|
-
}
|
|
452
|
-
accumPromise = void 0;
|
|
453
|
-
async next(...args) {
|
|
454
|
-
return this.generator.next(...args);
|
|
455
|
-
}
|
|
456
|
-
async return(value) {
|
|
457
|
-
return this.generator.return(value);
|
|
458
|
-
}
|
|
459
|
-
throw(e) {
|
|
460
|
-
return this.generator.throw(e);
|
|
461
|
-
}
|
|
462
|
-
[Symbol.asyncIterator]() {
|
|
463
|
-
return this;
|
|
464
|
-
}
|
|
465
|
-
then(onFulfilled, onRejected) {
|
|
466
|
-
if (!this.accumPromise) {
|
|
467
|
-
this.accumPromise = accumResults(this);
|
|
468
|
-
}
|
|
469
|
-
return this.accumPromise.then(onFulfilled, onRejected);
|
|
470
|
-
}
|
|
471
|
-
};
|
|
472
|
-
var AccumulatedRenderResult = class extends GeneratorRenderResult {
|
|
473
|
-
constructor(generator, cbs) {
|
|
474
|
-
super(generator);
|
|
475
|
-
this.generator = generator;
|
|
476
|
-
this.cbs = cbs;
|
|
477
|
-
}
|
|
478
|
-
accumulated = "";
|
|
479
|
-
async next(...args) {
|
|
480
|
-
let ret;
|
|
481
|
-
try {
|
|
482
|
-
ret = await this.generator.next(...args);
|
|
483
|
-
} catch (e) {
|
|
484
|
-
this.cbs.onError(e);
|
|
485
|
-
throw e;
|
|
486
|
-
}
|
|
487
|
-
const { done, value } = ret;
|
|
488
|
-
if (done) {
|
|
489
|
-
this.cbs.onDone(this.accumulated);
|
|
490
|
-
}
|
|
491
|
-
this.accumulated += value;
|
|
492
|
-
if (done) {
|
|
493
|
-
return { value: void 0, done: true };
|
|
494
|
-
}
|
|
495
|
-
return { value, done: false };
|
|
496
|
-
}
|
|
497
|
-
async throw(e) {
|
|
498
|
-
this.cbs.onError(e);
|
|
499
|
-
return this.generator.throw(e);
|
|
500
|
-
}
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
// src/tracing/types/TracingContext.ts
|
|
402
|
+
// src/tracing/TracingContext.ts
|
|
504
403
|
function createContextKey(description) {
|
|
505
404
|
return {
|
|
506
405
|
key: Symbol.for(description)
|
|
507
406
|
};
|
|
508
407
|
}
|
|
509
408
|
var BaseTracingContext = class _BaseTracingContext {
|
|
510
|
-
|
|
409
|
+
current;
|
|
511
410
|
/**
|
|
512
411
|
* Construct a new context which inherits values from an optional parent context.
|
|
513
412
|
*
|
|
@@ -515,16 +414,16 @@ var BaseTracingContext = class _BaseTracingContext {
|
|
|
515
414
|
*/
|
|
516
415
|
constructor(parentContext) {
|
|
517
416
|
const self = this;
|
|
518
|
-
self.
|
|
519
|
-
self.getValue = ({ key }) => self.
|
|
417
|
+
self.current = parentContext ? new Map(parentContext) : /* @__PURE__ */ new Map();
|
|
418
|
+
self.getValue = ({ key }) => self.current.get(key);
|
|
520
419
|
self.setValue = ({ key }, value) => {
|
|
521
|
-
const context = new _BaseTracingContext(self.
|
|
522
|
-
context.
|
|
420
|
+
const context = new _BaseTracingContext(self.current);
|
|
421
|
+
context.current.set(key, value);
|
|
523
422
|
return context;
|
|
524
423
|
};
|
|
525
424
|
self.deleteValue = ({ key }) => {
|
|
526
|
-
const context = new _BaseTracingContext(self.
|
|
527
|
-
context.
|
|
425
|
+
const context = new _BaseTracingContext(self.current);
|
|
426
|
+
context.current.delete(key);
|
|
528
427
|
return context;
|
|
529
428
|
};
|
|
530
429
|
}
|
|
@@ -550,8 +449,6 @@ var BaseTracingContext = class _BaseTracingContext {
|
|
|
550
449
|
*/
|
|
551
450
|
deleteValue;
|
|
552
451
|
};
|
|
553
|
-
|
|
554
|
-
// src/tracing/TracingContextManager.ts
|
|
555
452
|
var ROOT_CONTEXT = new BaseTracingContext();
|
|
556
453
|
var NoopTracingContextManager = class {
|
|
557
454
|
active() {
|
|
@@ -611,26 +508,25 @@ var ContextAPI = class _ContextAPI {
|
|
|
611
508
|
with(context, fn, ...args) {
|
|
612
509
|
return this.getContextManager().with(context, fn, ...args);
|
|
613
510
|
}
|
|
511
|
+
enable() {
|
|
512
|
+
this.manager.enable();
|
|
513
|
+
}
|
|
514
|
+
disable() {
|
|
515
|
+
this.manager.disable();
|
|
516
|
+
}
|
|
614
517
|
/**
|
|
615
518
|
* Bind a context to a target function or event emitter
|
|
616
519
|
*
|
|
617
520
|
* @param context context to bind to the event emitter or function. Defaults to the currently active context
|
|
618
521
|
* @param target function or event emitter to bind
|
|
619
522
|
*/
|
|
620
|
-
bind(
|
|
621
|
-
|
|
523
|
+
bind(target, context) {
|
|
524
|
+
const ctx = context || this.active();
|
|
525
|
+
return this.getContextManager().bind(ctx, target);
|
|
622
526
|
}
|
|
623
527
|
getContextManager() {
|
|
624
528
|
return this.manager || NOOP_CONTEXT_MANAGER;
|
|
625
529
|
}
|
|
626
|
-
/** Disable and remove the global context manager */
|
|
627
|
-
disable() {
|
|
628
|
-
this.getContextManager().disable();
|
|
629
|
-
this.manager = NOOP_CONTEXT_MANAGER;
|
|
630
|
-
}
|
|
631
|
-
reset() {
|
|
632
|
-
this.manager = NOOP_CONTEXT_MANAGER;
|
|
633
|
-
}
|
|
634
530
|
};
|
|
635
531
|
var contextApi = ContextAPI.getInstance();
|
|
636
532
|
|
|
@@ -640,13 +536,16 @@ var HrTime = class _HrTime {
|
|
|
640
536
|
this.time = time;
|
|
641
537
|
this.time = time;
|
|
642
538
|
}
|
|
539
|
+
static from(time) {
|
|
540
|
+
return new _HrTime(time);
|
|
541
|
+
}
|
|
643
542
|
static now() {
|
|
644
543
|
const timeOrigin = performance.timeOrigin;
|
|
645
544
|
const now = performance.now();
|
|
646
545
|
const totalNanoseconds = timeOrigin * 1e6 + now * 1e6;
|
|
647
546
|
const seconds = Math.floor(totalNanoseconds / 1e9);
|
|
648
547
|
const nanoseconds = totalNanoseconds % 1e9;
|
|
649
|
-
return
|
|
548
|
+
return [seconds, Math.floor(nanoseconds)];
|
|
650
549
|
}
|
|
651
550
|
toISOString() {
|
|
652
551
|
const milliseconds = this.time[0] * 1e3 + this.time[1] / 1e6;
|
|
@@ -661,61 +560,39 @@ var HrTime = class _HrTime {
|
|
|
661
560
|
};
|
|
662
561
|
|
|
663
562
|
// src/tracing/AISpan.ts
|
|
664
|
-
var SPAN_KEY = createContextKey("SPAN
|
|
563
|
+
var SPAN_KEY = createContextKey("AIJSX SPAN");
|
|
665
564
|
var AISpan = class {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
this._spanContext = spanContext;
|
|
670
|
-
this.parentSpanId = parentSpanId;
|
|
671
|
-
this.startHrTime = startTime || HrTime.now();
|
|
672
|
-
this.startTime = this.startHrTime.toISOString();
|
|
673
|
-
if (attributes != null) {
|
|
674
|
-
this.setAttributes(attributes);
|
|
675
|
-
}
|
|
676
|
-
const processors = spanProcessorProvider.getSpanProcessors();
|
|
677
|
-
processors.forEach((processor) => {
|
|
678
|
-
processor.onStart(this, context);
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
_spanContext;
|
|
565
|
+
name;
|
|
566
|
+
status = "unset";
|
|
567
|
+
spanContext;
|
|
682
568
|
parentSpanId;
|
|
683
569
|
attributes = {};
|
|
684
|
-
data = {};
|
|
685
570
|
events = [];
|
|
686
|
-
//timing
|
|
687
571
|
startTime;
|
|
688
|
-
startHrTime;
|
|
689
572
|
endTime = null;
|
|
690
|
-
|
|
573
|
+
startTimestamp;
|
|
574
|
+
endTimestamp = null;
|
|
575
|
+
ended = false;
|
|
691
576
|
duration = -1;
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
this.
|
|
704
|
-
return this;
|
|
577
|
+
processor;
|
|
578
|
+
constructor(opts) {
|
|
579
|
+
this.name = opts.name;
|
|
580
|
+
this.spanContext = opts.spanContext;
|
|
581
|
+
this.parentSpanId = opts.parentSpanId;
|
|
582
|
+
this.startTimestamp = opts.startTime || HrTime.now();
|
|
583
|
+
this.startTime = new HrTime(this.startTimestamp).toISOString();
|
|
584
|
+
this.processor = opts.processor;
|
|
585
|
+
if (opts.attributes != null) {
|
|
586
|
+
this.setAttributes(opts.attributes);
|
|
587
|
+
}
|
|
588
|
+
this.processor?.onStart?.(this);
|
|
705
589
|
}
|
|
706
590
|
setAttributes(attributes) {
|
|
707
591
|
for (const [k, v] of Object.entries(attributes)) {
|
|
708
|
-
this.
|
|
592
|
+
this.attributes[k] = v;
|
|
709
593
|
}
|
|
710
594
|
return this;
|
|
711
595
|
}
|
|
712
|
-
setData(key, value) {
|
|
713
|
-
this.data[key] = value;
|
|
714
|
-
return this;
|
|
715
|
-
}
|
|
716
|
-
getData(key) {
|
|
717
|
-
return this.data[key];
|
|
718
|
-
}
|
|
719
596
|
/**
|
|
720
597
|
*
|
|
721
598
|
* @param name Span Name
|
|
@@ -724,46 +601,40 @@ var AISpan = class {
|
|
|
724
601
|
* @param [timeStamp] Specified time stamp for the event
|
|
725
602
|
*/
|
|
726
603
|
addEvent(name, attributes, startTime = HrTime.now()) {
|
|
727
|
-
if (this.
|
|
604
|
+
if (this.ended)
|
|
728
605
|
return this;
|
|
729
|
-
|
|
730
|
-
timestamp: startTime.toISOString(),
|
|
731
|
-
time: startTime.time,
|
|
606
|
+
const event = {
|
|
732
607
|
name,
|
|
733
|
-
attributes
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
if (
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
updateName(name) {
|
|
744
|
-
if (this._isSpanEnded())
|
|
745
|
-
return this;
|
|
746
|
-
this.name = name;
|
|
608
|
+
attributes,
|
|
609
|
+
timestamp: new HrTime(startTime).toISOString(),
|
|
610
|
+
time: startTime
|
|
611
|
+
};
|
|
612
|
+
this.events.push(event);
|
|
613
|
+
if (name === "exception") {
|
|
614
|
+
this.processor?.onSpanException?.(event, this);
|
|
615
|
+
} else {
|
|
616
|
+
this.processor?.onSpanEvent?.(event, this);
|
|
617
|
+
}
|
|
747
618
|
return this;
|
|
748
619
|
}
|
|
749
|
-
end(
|
|
750
|
-
if (this.
|
|
620
|
+
end(endTime = HrTime.now()) {
|
|
621
|
+
if (this.ended) {
|
|
751
622
|
return;
|
|
752
623
|
}
|
|
753
|
-
this.
|
|
754
|
-
|
|
624
|
+
if (this.status === "unset") {
|
|
625
|
+
this.status = "ok";
|
|
626
|
+
}
|
|
627
|
+
this.ended = true;
|
|
628
|
+
const endHrTime = new HrTime(endTime);
|
|
629
|
+
const startHrTime = new HrTime(this.startTimestamp);
|
|
630
|
+
this.endTimestamp = endHrTime.time;
|
|
755
631
|
this.endTime = endHrTime.toISOString();
|
|
756
|
-
this.duration = endHrTime.minus(
|
|
757
|
-
|
|
758
|
-
processors.forEach((processor) => {
|
|
759
|
-
processor.onEnd(this);
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
isRecording() {
|
|
763
|
-
return this._ended === false;
|
|
632
|
+
this.duration = endHrTime.minus(startHrTime);
|
|
633
|
+
this.processor?.onEnd?.(this);
|
|
764
634
|
}
|
|
765
635
|
recordException(exception, time = HrTime.now()) {
|
|
766
636
|
let attributes = {};
|
|
637
|
+
this.status = "error";
|
|
767
638
|
if (typeof exception === "string") {
|
|
768
639
|
attributes = {
|
|
769
640
|
name: "Error",
|
|
@@ -778,18 +649,83 @@ var AISpan = class {
|
|
|
778
649
|
}
|
|
779
650
|
return this.addEvent("exception", attributes, time);
|
|
780
651
|
}
|
|
781
|
-
|
|
782
|
-
|
|
652
|
+
};
|
|
653
|
+
var NoopSpan = class extends AISpan {
|
|
654
|
+
constructor() {
|
|
655
|
+
super({
|
|
656
|
+
name: "noop-span",
|
|
657
|
+
spanContext: {
|
|
658
|
+
traceId: "",
|
|
659
|
+
spanId: ""
|
|
660
|
+
},
|
|
661
|
+
parentSpanId: null
|
|
662
|
+
});
|
|
783
663
|
}
|
|
784
|
-
|
|
785
|
-
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
// src/tracing/utils/BoundAsyncGenerator.ts
|
|
667
|
+
var BoundAsyncGenerator = class {
|
|
668
|
+
generator;
|
|
669
|
+
onDone;
|
|
670
|
+
onError;
|
|
671
|
+
constructor(generator, cbs) {
|
|
672
|
+
this.generator = contextApi.bind(generator);
|
|
673
|
+
if (cbs.onDone) {
|
|
674
|
+
this.onDone = cbs.onDone;
|
|
675
|
+
}
|
|
676
|
+
if (cbs.onError) {
|
|
677
|
+
this.onError = cbs.onError;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
async next(...args) {
|
|
681
|
+
try {
|
|
682
|
+
const result = await this.generator.next(...args);
|
|
683
|
+
if (result.done) {
|
|
684
|
+
this.onDone?.();
|
|
685
|
+
}
|
|
686
|
+
return result;
|
|
687
|
+
} catch (e) {
|
|
688
|
+
this.onError?.(e);
|
|
689
|
+
throw e;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
async return(value) {
|
|
693
|
+
return this.generator.return(value);
|
|
694
|
+
}
|
|
695
|
+
throw(e) {
|
|
696
|
+
return this.generator.throw(e);
|
|
697
|
+
}
|
|
698
|
+
[Symbol.asyncIterator]() {
|
|
699
|
+
return this;
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
var BoundRenderResult = class extends BoundAsyncGenerator {
|
|
703
|
+
constructor(renderResult, cbs) {
|
|
704
|
+
super(renderResult, cbs);
|
|
705
|
+
this.renderResult = renderResult;
|
|
706
|
+
}
|
|
707
|
+
then(onFulfilled, onRejected) {
|
|
708
|
+
return this.renderResult.then(
|
|
709
|
+
(val) => {
|
|
710
|
+
this.onDone?.();
|
|
711
|
+
if (!onFulfilled) {
|
|
712
|
+
return val;
|
|
713
|
+
}
|
|
714
|
+
return onFulfilled?.(val);
|
|
715
|
+
},
|
|
716
|
+
(err) => {
|
|
717
|
+
this.onError?.(err);
|
|
718
|
+
if (!onRejected) {
|
|
719
|
+
throw err;
|
|
720
|
+
}
|
|
721
|
+
return onRejected?.(err);
|
|
722
|
+
}
|
|
723
|
+
);
|
|
786
724
|
}
|
|
787
725
|
};
|
|
788
726
|
|
|
789
727
|
// src/tracing/utils/id.ts
|
|
790
728
|
var import_nanoid = require("nanoid");
|
|
791
|
-
var INVALID_SPANID = "0000000000000000";
|
|
792
|
-
var INVALID_TRACEID = "00000000000000000000000000000000";
|
|
793
729
|
var hexAlphabet = "0123456789abcdef";
|
|
794
730
|
var traceIdSize = 32;
|
|
795
731
|
var spanIdSize = 16;
|
|
@@ -797,250 +733,182 @@ var idGenerator = {
|
|
|
797
733
|
traceId: (0, import_nanoid.customAlphabet)(hexAlphabet, traceIdSize),
|
|
798
734
|
spanId: (0, import_nanoid.customAlphabet)(hexAlphabet, spanIdSize)
|
|
799
735
|
};
|
|
800
|
-
function isValidTraceId(traceId) {
|
|
801
|
-
return traceId !== INVALID_TRACEID;
|
|
802
|
-
}
|
|
803
|
-
function isValidSpanId(spanId) {
|
|
804
|
-
return spanId !== INVALID_SPANID;
|
|
805
|
-
}
|
|
806
|
-
function isSpanContextValid(spanContext) {
|
|
807
|
-
return isValidTraceId(spanContext.traceId) && isValidSpanId(spanContext.spanId);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
// src/tracing/NonRecordingSpan.ts
|
|
811
|
-
var INVALID_SPAN_CONTEXT = {
|
|
812
|
-
traceId: INVALID_TRACEID,
|
|
813
|
-
spanId: INVALID_SPANID
|
|
814
|
-
};
|
|
815
|
-
var NonRecordingSpan = class {
|
|
816
|
-
constructor(_spanContext = INVALID_SPAN_CONTEXT) {
|
|
817
|
-
this._spanContext = _spanContext;
|
|
818
|
-
}
|
|
819
|
-
name = "non-recording-span";
|
|
820
|
-
attributes = {};
|
|
821
|
-
data = {};
|
|
822
|
-
events = [];
|
|
823
|
-
startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
824
|
-
endTime = null;
|
|
825
|
-
duration = -1;
|
|
826
|
-
parentSpanId = null;
|
|
827
|
-
setData(key, value) {
|
|
828
|
-
this.data[key] = value;
|
|
829
|
-
return this;
|
|
830
|
-
}
|
|
831
|
-
getData(key) {
|
|
832
|
-
return this.data[key];
|
|
833
|
-
}
|
|
834
|
-
// Returns a SpanContext.
|
|
835
|
-
spanContext() {
|
|
836
|
-
return this._spanContext;
|
|
837
|
-
}
|
|
838
|
-
// By default does nothing
|
|
839
|
-
setAttribute(_key, _value) {
|
|
840
|
-
return this;
|
|
841
|
-
}
|
|
842
|
-
// By default does nothing
|
|
843
|
-
setAttributes(_attributes) {
|
|
844
|
-
return this;
|
|
845
|
-
}
|
|
846
|
-
// By default does nothing
|
|
847
|
-
addEvent(_name, _attributes, _startTime) {
|
|
848
|
-
return this;
|
|
849
|
-
}
|
|
850
|
-
// By default does nothing
|
|
851
|
-
setStatus(_status) {
|
|
852
|
-
return this;
|
|
853
|
-
}
|
|
854
|
-
// By default does nothing
|
|
855
|
-
updateName(_name) {
|
|
856
|
-
return this;
|
|
857
|
-
}
|
|
858
|
-
// By default does nothing
|
|
859
|
-
end(_endTime) {
|
|
860
|
-
}
|
|
861
|
-
// isRecording always returns false for NonRecordingSpan.
|
|
862
|
-
isRecording() {
|
|
863
|
-
return false;
|
|
864
|
-
}
|
|
865
|
-
// By default does nothing
|
|
866
|
-
recordException(exception, time) {
|
|
867
|
-
return this;
|
|
868
|
-
}
|
|
869
|
-
};
|
|
870
736
|
|
|
871
737
|
// src/tracing/AITracer.ts
|
|
872
738
|
var AITracer = class {
|
|
739
|
+
traceId;
|
|
740
|
+
processor;
|
|
873
741
|
/**
|
|
874
742
|
* Constructs a new Tracer instance.
|
|
875
743
|
*/
|
|
876
|
-
constructor(
|
|
877
|
-
|
|
744
|
+
constructor({
|
|
745
|
+
traceId,
|
|
746
|
+
processor
|
|
747
|
+
} = {}) {
|
|
748
|
+
this.traceId = traceId || idGenerator.traceId();
|
|
749
|
+
this.processor = processor;
|
|
878
750
|
}
|
|
879
751
|
/**
|
|
880
752
|
* Starts a new Span or returns the default NoopSpan based on the sampling
|
|
881
753
|
* decision.
|
|
882
754
|
*/
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
context = context.deleteValue(SPAN_KEY);
|
|
886
|
-
}
|
|
887
|
-
const parentSpan = context.getValue(SPAN_KEY);
|
|
888
|
-
const parentSpanContext = parentSpan?.spanContext();
|
|
755
|
+
createSpan(name, attributes = {}) {
|
|
756
|
+
const traceId = this.traceId;
|
|
889
757
|
const spanId = idGenerator.spanId();
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
traceId = idGenerator.traceId();
|
|
894
|
-
} else {
|
|
895
|
-
traceId = isValidTraceId(parentSpanContext.traceId) ? parentSpanContext.traceId : idGenerator.traceId();
|
|
896
|
-
parentSpanId = isValidSpanId(parentSpanContext.spanId) ? parentSpanContext.spanId : null;
|
|
897
|
-
}
|
|
898
|
-
const spanContext = { traceId, spanId };
|
|
899
|
-
const span = new AISpan(
|
|
900
|
-
this.spanProcessorProvider,
|
|
901
|
-
context,
|
|
758
|
+
const parentSpan = contextApi.active().getValue(SPAN_KEY);
|
|
759
|
+
const parentSpanId = parentSpan ? parentSpan.spanContext.spanId : null;
|
|
760
|
+
const span = new AISpan({
|
|
902
761
|
name,
|
|
903
|
-
spanContext,
|
|
762
|
+
spanContext: { traceId, spanId },
|
|
904
763
|
parentSpanId,
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
);
|
|
764
|
+
processor: this.processor,
|
|
765
|
+
attributes
|
|
766
|
+
});
|
|
909
767
|
return span;
|
|
910
768
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
let fn;
|
|
915
|
-
if (arguments.length < 2) {
|
|
916
|
-
return;
|
|
917
|
-
} else if (arguments.length === 2) {
|
|
918
|
-
fn = arg2;
|
|
919
|
-
} else if (arguments.length === 3) {
|
|
920
|
-
opts = arg2;
|
|
921
|
-
fn = arg3;
|
|
922
|
-
} else {
|
|
923
|
-
opts = arg2;
|
|
924
|
-
ctx = arg3;
|
|
925
|
-
fn = arg4;
|
|
926
|
-
}
|
|
927
|
-
const activeContext = ctx || contextApi.active();
|
|
928
|
-
const span = this.startSpan(name, opts, activeContext);
|
|
929
|
-
const newContext = activeContext.setValue(SPAN_KEY, span);
|
|
769
|
+
startSpan(name, attributes, fn) {
|
|
770
|
+
const span = this.createSpan(name, attributes);
|
|
771
|
+
const newContext = contextApi.active().setValue(SPAN_KEY, span);
|
|
930
772
|
return contextApi.with(newContext, fn, span);
|
|
931
773
|
}
|
|
774
|
+
trace(name, attributes, fn) {
|
|
775
|
+
return this.startSpan(name, attributes, (span) => {
|
|
776
|
+
const onError = (e) => {
|
|
777
|
+
span.recordException(e);
|
|
778
|
+
span.end();
|
|
779
|
+
};
|
|
780
|
+
const onDone = () => {
|
|
781
|
+
span.end();
|
|
782
|
+
};
|
|
783
|
+
try {
|
|
784
|
+
const result = fn(span);
|
|
785
|
+
if (isRenderResult(result)) {
|
|
786
|
+
return new BoundRenderResult(result, {
|
|
787
|
+
onDone,
|
|
788
|
+
onError
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
if (isGenerator(result)) {
|
|
792
|
+
return new BoundAsyncGenerator(result, {
|
|
793
|
+
onDone,
|
|
794
|
+
onError
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
if (isPromise(result)) {
|
|
798
|
+
return result.then(
|
|
799
|
+
(val) => {
|
|
800
|
+
onDone();
|
|
801
|
+
return val;
|
|
802
|
+
},
|
|
803
|
+
(e) => {
|
|
804
|
+
onError(e);
|
|
805
|
+
throw e;
|
|
806
|
+
}
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
onDone();
|
|
810
|
+
return result;
|
|
811
|
+
} catch (e) {
|
|
812
|
+
onError(e);
|
|
813
|
+
throw e;
|
|
814
|
+
}
|
|
815
|
+
throw new Error("Did not return result");
|
|
816
|
+
});
|
|
817
|
+
}
|
|
932
818
|
getActiveSpan() {
|
|
933
819
|
const res = contextApi.active().getValue(SPAN_KEY);
|
|
934
|
-
return res;
|
|
820
|
+
return res || null;
|
|
935
821
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
return ctx;
|
|
822
|
+
bind(target) {
|
|
823
|
+
return contextApi.bind(target);
|
|
939
824
|
}
|
|
940
825
|
};
|
|
941
|
-
|
|
942
|
-
|
|
826
|
+
function isRenderResult(val) {
|
|
827
|
+
return isGenerator(val) && isPromise(val);
|
|
828
|
+
}
|
|
829
|
+
function isGenerator(val) {
|
|
830
|
+
return Boolean(
|
|
831
|
+
val && typeof val === "object" && "next" in val && "throw" in val && "return" in val && Symbol.asyncIterator in val
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
var isPromise = (val) => {
|
|
835
|
+
return Boolean(val && typeof val === "object" && "then" in val);
|
|
836
|
+
};
|
|
943
837
|
var NoopTracer = class {
|
|
944
|
-
// startSpan starts a noop span.
|
|
945
|
-
startSpan(name, options, context = contextApi.active()) {
|
|
946
|
-
const root = Boolean(options?.root);
|
|
947
|
-
if (root) {
|
|
948
|
-
return new NonRecordingSpan();
|
|
949
|
-
}
|
|
950
|
-
const parentFromContext = context && context.getValue(SPAN_KEY);
|
|
951
|
-
if (isSpanContext(parentFromContext) && isSpanContextValid(parentFromContext)) {
|
|
952
|
-
return new NonRecordingSpan(parentFromContext);
|
|
953
|
-
} else {
|
|
954
|
-
return new NonRecordingSpan();
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
startActiveSpan(name, arg2, arg3, arg4) {
|
|
958
|
-
let opts;
|
|
959
|
-
let ctx;
|
|
960
|
-
let fn;
|
|
961
|
-
if (arguments.length < 2) {
|
|
962
|
-
return;
|
|
963
|
-
} else if (arguments.length === 2) {
|
|
964
|
-
fn = arg2;
|
|
965
|
-
} else if (arguments.length === 3) {
|
|
966
|
-
opts = arg2;
|
|
967
|
-
fn = arg3;
|
|
968
|
-
} else {
|
|
969
|
-
opts = arg2;
|
|
970
|
-
ctx = arg3;
|
|
971
|
-
fn = arg4;
|
|
972
|
-
}
|
|
973
|
-
const parentContext = ctx ?? contextApi.active();
|
|
974
|
-
const span = this.startSpan(name, opts, parentContext);
|
|
975
|
-
const contextWithSpanSet = parentContext.setValue(SPAN_KEY, span);
|
|
976
|
-
return contextApi.with(contextWithSpanSet, fn, span);
|
|
977
|
-
}
|
|
978
838
|
getActiveSpan() {
|
|
979
|
-
return
|
|
839
|
+
return null;
|
|
980
840
|
}
|
|
981
|
-
|
|
982
|
-
|
|
841
|
+
trace(_name, _attributes, fn) {
|
|
842
|
+
const span = new NoopSpan();
|
|
843
|
+
return fn(span);
|
|
983
844
|
}
|
|
984
845
|
};
|
|
985
|
-
function isSpanContext(spanContext) {
|
|
986
|
-
return typeof spanContext === "object" && typeof spanContext["spanId"] === "string" && typeof spanContext["traceId"] === "string" && typeof spanContext["traceFlags"] === "number";
|
|
987
|
-
}
|
|
988
846
|
|
|
989
|
-
// src/tracing/
|
|
990
|
-
var
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
847
|
+
// src/tracing/AsyncLocalStorageContextManager.ts
|
|
848
|
+
var import_node_async_hooks = require("async_hooks");
|
|
849
|
+
var isAsyncGenerator = (obj) => obj != null && typeof obj === "object" && "next" in obj && "return" in obj && "throw" in obj && Symbol.asyncIterator in obj;
|
|
850
|
+
var AsyncLocalStorageContextManager = class {
|
|
851
|
+
asyncLocalStorage;
|
|
852
|
+
constructor() {
|
|
853
|
+
this.asyncLocalStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
994
854
|
}
|
|
995
|
-
|
|
996
|
-
return this.
|
|
855
|
+
active() {
|
|
856
|
+
return this.asyncLocalStorage.getStore() ?? ROOT_CONTEXT;
|
|
997
857
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
spanProcessorProvider = new SpanProcessorProvider();
|
|
1004
|
-
tracer = new AITracer(this.spanProcessorProvider);
|
|
1005
|
-
/** Empty private constructor prevents end users from constructing a new instance of the API */
|
|
1006
|
-
constructor() {
|
|
858
|
+
with(context, fn, ...args) {
|
|
859
|
+
return this.asyncLocalStorage.run(context, () => {
|
|
860
|
+
const result = fn(...args);
|
|
861
|
+
return result;
|
|
862
|
+
});
|
|
1007
863
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
if (!this._instance) {
|
|
1011
|
-
this._instance = new _TraceAPI();
|
|
1012
|
-
}
|
|
1013
|
-
return this._instance;
|
|
864
|
+
enable() {
|
|
865
|
+
return this;
|
|
1014
866
|
}
|
|
1015
|
-
|
|
1016
|
-
this.
|
|
867
|
+
disable() {
|
|
868
|
+
this.asyncLocalStorage.disable();
|
|
869
|
+
return this;
|
|
1017
870
|
}
|
|
1018
871
|
/**
|
|
1019
|
-
*
|
|
872
|
+
* Binds a the certain context or the active one to the target function and then returns the target
|
|
873
|
+
* @param context A context (span) to be bind to target
|
|
874
|
+
* @param target a function or event emitter. When target or one of its callbacks is called,
|
|
875
|
+
* the provided context will be used as the active context for the duration of the call.
|
|
1020
876
|
*/
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
877
|
+
bind(context, target) {
|
|
878
|
+
if (typeof target === "function") {
|
|
879
|
+
return this.bindFunction(context, target);
|
|
880
|
+
}
|
|
881
|
+
if (isAsyncGenerator(target)) {
|
|
882
|
+
return this.bindAsyncGenerator(target);
|
|
883
|
+
}
|
|
884
|
+
return target;
|
|
1027
885
|
}
|
|
1028
|
-
|
|
1029
|
-
this
|
|
886
|
+
bindFunction(context, target) {
|
|
887
|
+
const manager = this;
|
|
888
|
+
const contextWrapper = function(...args) {
|
|
889
|
+
return manager.with(context, () => target.apply(this, args));
|
|
890
|
+
};
|
|
891
|
+
Object.defineProperty(contextWrapper, "length", {
|
|
892
|
+
enumerable: false,
|
|
893
|
+
configurable: true,
|
|
894
|
+
writable: false,
|
|
895
|
+
value: target.length
|
|
896
|
+
});
|
|
897
|
+
return contextWrapper;
|
|
1030
898
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
899
|
+
bindAsyncGenerator(generator) {
|
|
900
|
+
generator.next = this.bindFunction(this.active(), generator.next);
|
|
901
|
+
return generator;
|
|
1034
902
|
}
|
|
1035
903
|
};
|
|
1036
|
-
var traceApi = TraceAPI.getInstance();
|
|
1037
904
|
|
|
1038
905
|
// src/tracing/api/index.ts
|
|
1039
906
|
var AITraceAPI = class _AITraceAPI {
|
|
1040
907
|
static _instance;
|
|
1041
|
-
|
|
908
|
+
enabled = false;
|
|
1042
909
|
/** Empty private constructor prevents end users from constructing a new instance of the API */
|
|
1043
910
|
constructor() {
|
|
911
|
+
this.enable();
|
|
1044
912
|
}
|
|
1045
913
|
/** Get the singleton instance of the Trace API */
|
|
1046
914
|
static getInstance() {
|
|
@@ -1049,40 +917,102 @@ var AITraceAPI = class _AITraceAPI {
|
|
|
1049
917
|
}
|
|
1050
918
|
return this._instance;
|
|
1051
919
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
throw new Error("Tracing can only be initialized once");
|
|
1055
|
-
}
|
|
1056
|
-
const processors = options.spanProcessors || [];
|
|
1057
|
-
traceApi.setSpanProcessors(processors);
|
|
1058
|
-
if (options.contextManager) {
|
|
1059
|
-
contextApi.setContextManager(options.contextManager);
|
|
1060
|
-
}
|
|
1061
|
-
this.initialized = true;
|
|
1062
|
-
return this.getTracer();
|
|
1063
|
-
}
|
|
1064
|
-
getTracer() {
|
|
1065
|
-
return traceApi.getTracer();
|
|
920
|
+
createTracer(opts = {}) {
|
|
921
|
+
return this.enabled ? new AITracer(opts) : new NoopTracer();
|
|
1066
922
|
}
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
this.initialized = false;
|
|
1072
|
-
traceApi.reset();
|
|
1073
|
-
contextApi.reset();
|
|
923
|
+
enable() {
|
|
924
|
+
this.enabled = true;
|
|
925
|
+
contextApi.setContextManager(new AsyncLocalStorageContextManager());
|
|
926
|
+
contextApi.disable();
|
|
1074
927
|
}
|
|
1075
928
|
disable() {
|
|
1076
|
-
|
|
929
|
+
this.enabled = false;
|
|
930
|
+
contextApi.setContextManager(NOOP_CONTEXT_MANAGER);
|
|
1077
931
|
contextApi.disable();
|
|
1078
932
|
}
|
|
1079
|
-
bind(target) {
|
|
1080
|
-
const activeContext = contextApi.active();
|
|
1081
|
-
return contextApi.bind(activeContext, target);
|
|
1082
|
-
}
|
|
1083
933
|
};
|
|
1084
934
|
var tracing = AITraceAPI.getInstance();
|
|
1085
935
|
|
|
936
|
+
// src/render.ts
|
|
937
|
+
function renderLiteral(renderable) {
|
|
938
|
+
if (typeof renderable === "string") {
|
|
939
|
+
return renderable;
|
|
940
|
+
}
|
|
941
|
+
if (typeof renderable === "number") {
|
|
942
|
+
return renderable.toString();
|
|
943
|
+
}
|
|
944
|
+
if (typeof renderable === "undefined" || typeof renderable === "boolean" || renderable === null) {
|
|
945
|
+
return "";
|
|
946
|
+
}
|
|
947
|
+
return "";
|
|
948
|
+
}
|
|
949
|
+
function createRenderContext({
|
|
950
|
+
logger = new NoopLogImplementation(),
|
|
951
|
+
traceId,
|
|
952
|
+
processor,
|
|
953
|
+
contextValues = {}
|
|
954
|
+
} = {}) {
|
|
955
|
+
const tracer = tracing.createTracer({
|
|
956
|
+
traceId,
|
|
957
|
+
processor
|
|
958
|
+
});
|
|
959
|
+
return new StreamRenderContext(tracer, logger, contextValues);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// src/RenderResult.ts
|
|
963
|
+
var accumResults = async (result) => {
|
|
964
|
+
let accum = "";
|
|
965
|
+
const iterator = result[Symbol.asyncIterator]();
|
|
966
|
+
for await (const value of iterator) {
|
|
967
|
+
accum += value;
|
|
968
|
+
}
|
|
969
|
+
return accum;
|
|
970
|
+
};
|
|
971
|
+
var GeneratorRenderResult = class {
|
|
972
|
+
// this promise like thing
|
|
973
|
+
constructor(generator) {
|
|
974
|
+
this.generator = generator;
|
|
975
|
+
}
|
|
976
|
+
accumPromise = void 0;
|
|
977
|
+
async next(...args) {
|
|
978
|
+
return this.generator.next(...args);
|
|
979
|
+
}
|
|
980
|
+
async return(value) {
|
|
981
|
+
return this.generator.return(value);
|
|
982
|
+
}
|
|
983
|
+
throw(e) {
|
|
984
|
+
return this.generator.throw(e);
|
|
985
|
+
}
|
|
986
|
+
[Symbol.asyncIterator]() {
|
|
987
|
+
return this;
|
|
988
|
+
}
|
|
989
|
+
then(onFulfilled, onRejected) {
|
|
990
|
+
if (!this.accumPromise) {
|
|
991
|
+
this.accumPromise = accumResults(this);
|
|
992
|
+
}
|
|
993
|
+
return this.accumPromise.then(onFulfilled, onRejected);
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
var AccumulatedRenderResult = class extends GeneratorRenderResult {
|
|
997
|
+
constructor(generator, onDone) {
|
|
998
|
+
super(generator);
|
|
999
|
+
this.generator = generator;
|
|
1000
|
+
this.onDone = onDone;
|
|
1001
|
+
}
|
|
1002
|
+
accumulated = "";
|
|
1003
|
+
async next(...args) {
|
|
1004
|
+
const { done, value } = await this.generator.next(...args);
|
|
1005
|
+
if (done) {
|
|
1006
|
+
this.onDone(this.accumulated);
|
|
1007
|
+
}
|
|
1008
|
+
this.accumulated += value;
|
|
1009
|
+
if (done) {
|
|
1010
|
+
return { value: void 0, done: true };
|
|
1011
|
+
}
|
|
1012
|
+
return { done: false, value };
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1086
1016
|
// src/types.ts
|
|
1087
1017
|
var attachedContextSymbol = Symbol("AI.attachedContext");
|
|
1088
1018
|
|
|
@@ -1168,6 +1098,9 @@ function parseXml(input) {
|
|
|
1168
1098
|
const attributeName = Object.keys(nodeObject)[1];
|
|
1169
1099
|
const childObjects = nodeObject[nodeName];
|
|
1170
1100
|
const attributes = Object.entries(nodeObject[attributeName] || {}).reduce((acc, [key, value]) => {
|
|
1101
|
+
if (!value) {
|
|
1102
|
+
return acc;
|
|
1103
|
+
}
|
|
1171
1104
|
try {
|
|
1172
1105
|
acc[key] = JSON.parse(value);
|
|
1173
1106
|
} catch (e) {
|
|
@@ -1185,6 +1118,9 @@ function parseXml(input) {
|
|
|
1185
1118
|
return constructNode(null, parsed[0]);
|
|
1186
1119
|
}
|
|
1187
1120
|
function escape(html) {
|
|
1121
|
+
if (!html) {
|
|
1122
|
+
return "";
|
|
1123
|
+
}
|
|
1188
1124
|
return html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1189
1125
|
}
|
|
1190
1126
|
|
|
@@ -1197,52 +1133,48 @@ function jsx(type, config, maybeKey) {
|
|
|
1197
1133
|
|
|
1198
1134
|
// src/context.tsx
|
|
1199
1135
|
var StreamRenderContext = class _StreamRenderContext {
|
|
1200
|
-
constructor(
|
|
1201
|
-
this.
|
|
1136
|
+
constructor(tracer, logImpl, contextValues) {
|
|
1137
|
+
this.tracer = tracer;
|
|
1138
|
+
this.logImpl = logImpl;
|
|
1202
1139
|
this.contextValues = contextValues;
|
|
1203
|
-
this.rootTraceContext = rootTraceContext;
|
|
1204
1140
|
const self = this;
|
|
1205
|
-
this.logger = new BoundLogger(
|
|
1141
|
+
this.logger = new BoundLogger(logImpl, this);
|
|
1206
1142
|
this.render = this.render.bind(this);
|
|
1207
|
-
this.
|
|
1208
|
-
this.renderElement = (...args) => {
|
|
1209
|
-
const generator = renderElementInternal(...args);
|
|
1210
|
-
return tracing.bind(generator);
|
|
1211
|
-
};
|
|
1212
|
-
async function* renderElementInternal(element, opts = {}) {
|
|
1143
|
+
this.renderElement = async function* (renderable, opts = {}) {
|
|
1213
1144
|
const span = self.tracer.getActiveSpan();
|
|
1214
1145
|
const preserveTags = opts.preserveTags ?? false;
|
|
1215
1146
|
const renderedProps = opts.renderedProps || {};
|
|
1216
1147
|
const renderEscaped = (val) => {
|
|
1217
1148
|
return preserveTags ? escape(val) : val;
|
|
1218
1149
|
};
|
|
1219
|
-
if (isLiteral(
|
|
1220
|
-
yield renderEscaped(renderLiteral(
|
|
1150
|
+
if (isLiteral(renderable)) {
|
|
1151
|
+
yield renderEscaped(renderLiteral(renderable));
|
|
1221
1152
|
return;
|
|
1222
1153
|
}
|
|
1223
|
-
if (isAIElement(
|
|
1224
|
-
const newCtx = self.enterElement(
|
|
1225
|
-
const
|
|
1154
|
+
if (isAIElement(renderable)) {
|
|
1155
|
+
const newCtx = self.enterElement(renderable);
|
|
1156
|
+
const logger = newCtx.logger;
|
|
1157
|
+
const isFragment = renderable.tag.name === "AIFragment";
|
|
1226
1158
|
try {
|
|
1227
1159
|
if (preserveTags && !isFragment) {
|
|
1228
|
-
yield renderOpenTag(
|
|
1160
|
+
yield renderOpenTag(renderable, renderedProps);
|
|
1229
1161
|
}
|
|
1230
|
-
yield* newCtx.renderElement(
|
|
1162
|
+
yield* newCtx.renderElement(renderable.render(newCtx), opts);
|
|
1231
1163
|
if (preserveTags && !isFragment) {
|
|
1232
|
-
yield renderCloseTag(
|
|
1164
|
+
yield renderCloseTag(renderable);
|
|
1233
1165
|
}
|
|
1234
1166
|
return;
|
|
1235
1167
|
} catch (ex) {
|
|
1236
|
-
|
|
1168
|
+
logger.logException(ex);
|
|
1237
1169
|
throw ex;
|
|
1238
1170
|
}
|
|
1239
1171
|
}
|
|
1240
|
-
if (Array.isArray(
|
|
1241
|
-
if (
|
|
1242
|
-
yield
|
|
1172
|
+
if (Array.isArray(renderable)) {
|
|
1173
|
+
if (renderable.every((r) => isLiteral(r))) {
|
|
1174
|
+
yield renderable.map((r) => renderEscaped(renderLiteral(r))).join("");
|
|
1243
1175
|
return;
|
|
1244
1176
|
}
|
|
1245
|
-
const streams =
|
|
1177
|
+
const streams = renderable.filter((a) => !!a).map((r) => self.renderElement(r, opts));
|
|
1246
1178
|
const result = coalesceParallelStreams(streams);
|
|
1247
1179
|
while (true) {
|
|
1248
1180
|
const { value, done } = await result.next();
|
|
@@ -1252,201 +1184,140 @@ var StreamRenderContext = class _StreamRenderContext {
|
|
|
1252
1184
|
yield value;
|
|
1253
1185
|
}
|
|
1254
1186
|
}
|
|
1255
|
-
if (Symbol.asyncIterator in
|
|
1256
|
-
return yield*
|
|
1187
|
+
if (Symbol.asyncIterator in renderable) {
|
|
1188
|
+
return yield* renderable[Symbol.asyncIterator]();
|
|
1257
1189
|
}
|
|
1258
|
-
if (!("then" in
|
|
1190
|
+
if (!("then" in renderable)) {
|
|
1259
1191
|
throw new Error(
|
|
1260
|
-
`Unexpected renderable type: ${JSON.stringify(
|
|
1192
|
+
`Unexpected renderable type: ${JSON.stringify(renderable)}`
|
|
1261
1193
|
);
|
|
1262
1194
|
}
|
|
1263
|
-
const next = await
|
|
1195
|
+
const next = await renderable.then(
|
|
1264
1196
|
(r) => r
|
|
1265
1197
|
);
|
|
1266
1198
|
return yield* self.renderElement(next, opts);
|
|
1267
|
-
}
|
|
1199
|
+
};
|
|
1268
1200
|
}
|
|
1269
1201
|
renderElement;
|
|
1270
1202
|
logger;
|
|
1271
|
-
tracer = tracing.getTracer();
|
|
1272
1203
|
// Implementation of the overloaded function
|
|
1273
1204
|
render(arg1, arg2, arg3) {
|
|
1274
1205
|
switch (true) {
|
|
1275
1206
|
case (isPromptParsed(arg1) && !!arg2): {
|
|
1276
|
-
return this.trace(
|
|
1277
|
-
|
|
1278
|
-
|
|
1207
|
+
return this.tracer.trace(
|
|
1208
|
+
"ai.prompt",
|
|
1209
|
+
{
|
|
1210
|
+
prompt: arg1,
|
|
1211
|
+
promptKey: arg1.key,
|
|
1212
|
+
variables: arg2
|
|
1213
|
+
},
|
|
1214
|
+
() => this.renderPromptParsed(arg1, arg2, arg3 || {})
|
|
1215
|
+
);
|
|
1279
1216
|
}
|
|
1280
1217
|
case (isPrompt(arg1) && !!arg2): {
|
|
1281
|
-
return this.trace(
|
|
1282
|
-
|
|
1283
|
-
|
|
1218
|
+
return this.tracer.trace(
|
|
1219
|
+
"ai.prompt",
|
|
1220
|
+
{
|
|
1221
|
+
prompt: arg1,
|
|
1222
|
+
promptKey: arg1.key,
|
|
1223
|
+
variables: arg2
|
|
1224
|
+
},
|
|
1225
|
+
() => this.renderPrompt(arg1, arg2)
|
|
1226
|
+
);
|
|
1284
1227
|
}
|
|
1285
1228
|
case (isFunctionChain(arg1) && !!arg2): {
|
|
1286
|
-
return this.trace(
|
|
1287
|
-
|
|
1288
|
-
|
|
1229
|
+
return this.tracer.trace(
|
|
1230
|
+
"ai.chain",
|
|
1231
|
+
{ chainKey: arg1.key, chainType: arg1.chainType, variables: arg2 },
|
|
1232
|
+
() => this.runChain(arg1, arg2)
|
|
1233
|
+
);
|
|
1289
1234
|
}
|
|
1290
1235
|
case (isStreamChain(arg1) && !!arg2): {
|
|
1291
|
-
return this.trace(
|
|
1292
|
-
|
|
1293
|
-
|
|
1236
|
+
return this.tracer.trace(
|
|
1237
|
+
"ai.chain",
|
|
1238
|
+
{ chainKey: arg1.key, chainType: arg1.chainType, variables: arg2 },
|
|
1239
|
+
() => this.runChain(arg1, arg2)
|
|
1240
|
+
);
|
|
1294
1241
|
}
|
|
1295
1242
|
default: {
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
);
|
|
1303
|
-
}
|
|
1243
|
+
const currentSpan = this.tracer.getActiveSpan();
|
|
1244
|
+
const stream = this.renderElement(
|
|
1245
|
+
arg1,
|
|
1246
|
+
arg2 || { preserveTags: false }
|
|
1247
|
+
);
|
|
1248
|
+
if (currentSpan) {
|
|
1249
|
+
return new GeneratorRenderResult(stream);
|
|
1250
|
+
}
|
|
1251
|
+
return this.tracer.trace(
|
|
1252
|
+
"ai.component",
|
|
1253
|
+
{},
|
|
1254
|
+
(span) => new AccumulatedRenderResult(stream, (output) => {
|
|
1255
|
+
span.setAttributes({
|
|
1256
|
+
output
|
|
1257
|
+
});
|
|
1258
|
+
})
|
|
1259
|
+
);
|
|
1304
1260
|
}
|
|
1305
1261
|
}
|
|
1306
1262
|
}
|
|
1307
|
-
/**
|
|
1308
|
-
* @internal
|
|
1309
|
-
*
|
|
1310
|
-
* Helper method to create a new span and set it as the active span
|
|
1311
|
-
* if there is a rootTraceContext attached, start a different context
|
|
1312
|
-
* with that spanId / traceId as the SpanContext
|
|
1313
|
-
*
|
|
1314
|
-
* This can safely be used other places becuase it depends on the
|
|
1315
|
-
* current active span, and only uses the rootTraceContext if there
|
|
1316
|
-
* is no active span
|
|
1317
|
-
*/
|
|
1318
|
-
// TODO(jordan) better typing of this
|
|
1319
|
-
trace(spanName, fn) {
|
|
1320
|
-
const currentSpan = this.tracer.getActiveSpan();
|
|
1321
|
-
const ctx = currentSpan ? tracing.getActiveContext() : this.tracer.setSpanContext({
|
|
1322
|
-
traceId: this.rootTraceContext?.traceId || idGenerator.traceId(),
|
|
1323
|
-
spanId: this.rootTraceContext?.spanId || INVALID_SPANID
|
|
1324
|
-
});
|
|
1325
|
-
return this.tracer.startActiveSpan(spanName, {}, ctx, fn);
|
|
1326
|
-
}
|
|
1327
1263
|
renderPrompt(prompt, variables) {
|
|
1328
|
-
const span = this.tracer.getActiveSpan();
|
|
1329
|
-
span?.setData("prompt", prompt);
|
|
1330
|
-
span?.setAttributes({
|
|
1331
|
-
promptKey: prompt.key,
|
|
1332
|
-
variables
|
|
1333
|
-
});
|
|
1334
1264
|
const { schema, component: Component } = prompt;
|
|
1335
|
-
const parsedVariables = parseVariables(schema, variables);
|
|
1336
|
-
if (
|
|
1337
|
-
const { error } = parsedVariables;
|
|
1338
|
-
span?.recordException(error).end();
|
|
1265
|
+
const { error, parsedVariables } = parseVariables(schema, variables);
|
|
1266
|
+
if (error) {
|
|
1339
1267
|
throw error;
|
|
1340
1268
|
}
|
|
1341
|
-
const generator = this.renderElement(
|
|
1342
|
-
|
|
1343
|
-
{
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
onDone: tracing.bind((output) => {
|
|
1347
|
-
span?.setAttributes({
|
|
1348
|
-
output
|
|
1349
|
-
}).end();
|
|
1350
|
-
return output;
|
|
1351
|
-
}),
|
|
1352
|
-
onError: tracing.bind((error) => {
|
|
1353
|
-
span?.recordException(error).end();
|
|
1354
|
-
throw error;
|
|
1355
|
-
})
|
|
1269
|
+
const generator = this.renderElement(/* @__PURE__ */ jsx(Component, { ...parsedVariables }), {});
|
|
1270
|
+
return new AccumulatedRenderResult(generator, (output) => {
|
|
1271
|
+
this.tracer.getActiveSpan()?.setAttributes({
|
|
1272
|
+
output
|
|
1273
|
+
});
|
|
1356
1274
|
});
|
|
1357
|
-
return result;
|
|
1358
1275
|
}
|
|
1359
1276
|
async renderPromptParsed(prompt, variables, options) {
|
|
1360
1277
|
const span = this.tracer.getActiveSpan();
|
|
1361
|
-
span?.setData("prompt", prompt);
|
|
1362
|
-
span?.setAttributes({
|
|
1363
|
-
promptKey: prompt.key,
|
|
1364
|
-
variables,
|
|
1365
|
-
renderPromptOptions: options
|
|
1366
|
-
});
|
|
1367
1278
|
const { validateOutput } = options;
|
|
1368
1279
|
const { schema, component: Component } = prompt;
|
|
1369
|
-
const parsedVariables = parseVariables(schema, variables);
|
|
1370
|
-
if (
|
|
1371
|
-
const { error } = parsedVariables;
|
|
1372
|
-
span?.recordException(error).end();
|
|
1280
|
+
const { error, parsedVariables } = parseVariables(schema, variables);
|
|
1281
|
+
if (error) {
|
|
1373
1282
|
throw error;
|
|
1374
1283
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
throw err;
|
|
1390
|
-
}
|
|
1284
|
+
const stream = this.renderElement(/* @__PURE__ */ jsx(Component, { ...parsedVariables }));
|
|
1285
|
+
const output = await accumResults(stream);
|
|
1286
|
+
const parsedOutput = prompt.parse(output);
|
|
1287
|
+
span?.setAttributes({
|
|
1288
|
+
output,
|
|
1289
|
+
parsedOutput
|
|
1290
|
+
});
|
|
1291
|
+
if (validateOutput) {
|
|
1292
|
+
try {
|
|
1293
|
+
prompt.outputSchema.parse(parsedOutput);
|
|
1294
|
+
} catch (e) {
|
|
1295
|
+
const err = e;
|
|
1296
|
+
const errors = JSON.stringify(err.flatten());
|
|
1297
|
+
throw new PromptInvalidOutputError("Invalid output: " + errors);
|
|
1391
1298
|
}
|
|
1392
|
-
span?.setAttributes({
|
|
1393
|
-
output: parsedOutput
|
|
1394
|
-
}).end();
|
|
1395
|
-
return parsedOutput;
|
|
1396
|
-
} catch (error) {
|
|
1397
|
-
span?.recordException(error).end();
|
|
1398
|
-
throw error;
|
|
1399
1299
|
}
|
|
1300
|
+
return parsedOutput;
|
|
1400
1301
|
}
|
|
1401
1302
|
runChain(chain, variables) {
|
|
1402
|
-
const
|
|
1403
|
-
|
|
1404
|
-
span?.setAttributes({
|
|
1405
|
-
chainKey: chain.key,
|
|
1406
|
-
variables
|
|
1407
|
-
});
|
|
1408
|
-
const { schema } = chain;
|
|
1409
|
-
const parsedVariables = parseVariables(schema, variables);
|
|
1410
|
-
if (!parsedVariables.success) {
|
|
1411
|
-
const { error } = parsedVariables;
|
|
1412
|
-
span?.recordException(error).end();
|
|
1303
|
+
const { error, parsedVariables } = parseVariables(chain.schema, variables);
|
|
1304
|
+
if (error) {
|
|
1413
1305
|
throw error;
|
|
1414
1306
|
}
|
|
1415
1307
|
if (chain.chainType === "function") {
|
|
1416
|
-
const
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
};
|
|
1421
|
-
const onChainError = (error) => {
|
|
1422
|
-
span?.recordException(error).end();
|
|
1308
|
+
const span = this.tracer.getActiveSpan();
|
|
1309
|
+
const onOutput = (output) => {
|
|
1310
|
+
span?.setAttributes({ output });
|
|
1311
|
+
return output;
|
|
1423
1312
|
};
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
} catch (e) {
|
|
1428
|
-
onChainError(e);
|
|
1429
|
-
throw e;
|
|
1430
|
-
}
|
|
1431
|
-
if (chainResult && typeof chainResult === "object" && "then" in chainResult) {
|
|
1432
|
-
chainResult.then(onChainComplete, onChainError);
|
|
1433
|
-
return chainResult;
|
|
1313
|
+
const result = chain.run(parsedVariables, this);
|
|
1314
|
+
if (result && typeof result === "object" && "then" in result) {
|
|
1315
|
+
return result.then(onOutput);
|
|
1434
1316
|
}
|
|
1435
|
-
|
|
1436
|
-
return chainResult;
|
|
1317
|
+
return onOutput(result);
|
|
1437
1318
|
}
|
|
1438
1319
|
if (chain.chainType === "stream") {
|
|
1439
|
-
|
|
1440
|
-
const stream = chain.run(
|
|
1441
|
-
parsedVariables.result,
|
|
1442
|
-
this
|
|
1443
|
-
);
|
|
1444
|
-
span?.end();
|
|
1445
|
-
return tracing.bind(stream);
|
|
1446
|
-
} catch (error) {
|
|
1447
|
-
span?.recordException(error).end();
|
|
1448
|
-
throw error;
|
|
1449
|
-
}
|
|
1320
|
+
return chain.run(parsedVariables, this);
|
|
1450
1321
|
}
|
|
1451
1322
|
throw new Error("Invalid chain type");
|
|
1452
1323
|
}
|
|
@@ -1454,8 +1325,9 @@ var StreamRenderContext = class _StreamRenderContext {
|
|
|
1454
1325
|
return this.contextValues[context.key] ?? context.defaultValue;
|
|
1455
1326
|
};
|
|
1456
1327
|
// @internal
|
|
1457
|
-
enterElement(
|
|
1458
|
-
|
|
1328
|
+
enterElement(element) {
|
|
1329
|
+
const newCtx = attachedContextValues(element);
|
|
1330
|
+
return new _StreamRenderContext(this.tracer, this.logImpl, {
|
|
1459
1331
|
...this.contextValues,
|
|
1460
1332
|
...newCtx
|
|
1461
1333
|
});
|
|
@@ -1506,7 +1378,7 @@ function withContextValues(renderable, additionalContext) {
|
|
|
1506
1378
|
);
|
|
1507
1379
|
}
|
|
1508
1380
|
function attachedContextValues(element) {
|
|
1509
|
-
return element[attachedContextSymbol];
|
|
1381
|
+
return element[attachedContextSymbol] || {};
|
|
1510
1382
|
}
|
|
1511
1383
|
function isPrompt(value) {
|
|
1512
1384
|
return Boolean(value && typeof value === "object" && "component" in value);
|
|
@@ -1542,70 +1414,174 @@ function renderCloseTag(element) {
|
|
|
1542
1414
|
return `</${element.tag.name}>`;
|
|
1543
1415
|
}
|
|
1544
1416
|
|
|
1545
|
-
// src/
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
constructor() {
|
|
1551
|
-
this.asyncLocalStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
1552
|
-
}
|
|
1553
|
-
active() {
|
|
1554
|
-
return this.asyncLocalStorage.getStore() ?? ROOT_CONTEXT;
|
|
1417
|
+
// src/prompt/evaluatePrompt.ts
|
|
1418
|
+
async function evaluatePrompt(prompt, variables, result) {
|
|
1419
|
+
const { error, parsedVariables } = parseVariables(prompt.schema, variables);
|
|
1420
|
+
if (error) {
|
|
1421
|
+
throw error;
|
|
1555
1422
|
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1423
|
+
return (await Promise.all(
|
|
1424
|
+
prompt.evaluators.map(
|
|
1425
|
+
(evaluator) => evaluator(parsedVariables, result)
|
|
1426
|
+
)
|
|
1427
|
+
)).flat();
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
// src/tracing/AISpanProcessor.ts
|
|
1431
|
+
var EnrichingSpanProcessor = class {
|
|
1432
|
+
constructor(exporter) {
|
|
1433
|
+
this.exporter = exporter;
|
|
1434
|
+
this.onAllDonePromise = new Promise((resolve) => {
|
|
1435
|
+
this.onAllDonePromiseResolve = resolve;
|
|
1560
1436
|
});
|
|
1561
1437
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
this.
|
|
1567
|
-
|
|
1438
|
+
finalSpans = [];
|
|
1439
|
+
onAllDonePromise = null;
|
|
1440
|
+
onAllDonePromiseResolve = null;
|
|
1441
|
+
async onStart(span) {
|
|
1442
|
+
this.finalSpans.push({
|
|
1443
|
+
status: "running",
|
|
1444
|
+
span
|
|
1445
|
+
});
|
|
1568
1446
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
bind(context, target) {
|
|
1576
|
-
if (typeof target === "function") {
|
|
1577
|
-
return this.bindFunction(context, target);
|
|
1447
|
+
async onEnd(span) {
|
|
1448
|
+
const entry = this.finalSpans.find(
|
|
1449
|
+
(a) => a.span.spanContext.spanId === span.spanContext.spanId
|
|
1450
|
+
);
|
|
1451
|
+
if (!entry) {
|
|
1452
|
+
throw new Error("onEnd called without onStart");
|
|
1578
1453
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1454
|
+
const enrichedSpan = await this.enrichSpan(span);
|
|
1455
|
+
entry.status = "processing";
|
|
1456
|
+
entry.span = enrichedSpan;
|
|
1457
|
+
entry.status = "done";
|
|
1458
|
+
if (this.finalSpans.every((a) => a.status === "done")) {
|
|
1459
|
+
this.onAllDonePromiseResolve?.();
|
|
1581
1460
|
}
|
|
1582
|
-
|
|
1461
|
+
if (span.parentSpanId == null) {
|
|
1462
|
+
await this.onAllDonePromise;
|
|
1463
|
+
await this.onTraceComplete(enrichedSpan);
|
|
1464
|
+
}
|
|
1465
|
+
this.exporter.export([enrichedSpan]);
|
|
1583
1466
|
}
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1467
|
+
shutdown() {
|
|
1468
|
+
return this.exporter.shutdown?.();
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
var AISpanProcessor = class extends EnrichingSpanProcessor {
|
|
1472
|
+
constructor(exporter, opts = {}) {
|
|
1473
|
+
super(exporter);
|
|
1474
|
+
this.opts = opts;
|
|
1475
|
+
}
|
|
1476
|
+
totalCost = 0;
|
|
1477
|
+
totalUsage = {
|
|
1478
|
+
prompt: 0,
|
|
1479
|
+
completion: 0,
|
|
1480
|
+
total: 0
|
|
1481
|
+
};
|
|
1482
|
+
async onTraceComplete(rootSpan) {
|
|
1483
|
+
rootSpan.attributes.totalCost = this.totalCost;
|
|
1484
|
+
rootSpan.attributes.totalUsage = this.totalUsage;
|
|
1485
|
+
}
|
|
1486
|
+
async enrichSpan(span) {
|
|
1487
|
+
const result1 = await this.evaluatePrompt(span);
|
|
1488
|
+
const result2 = await this.computeCost(result1);
|
|
1489
|
+
const result3 = await this.updateUsage(result2);
|
|
1490
|
+
return result3;
|
|
1491
|
+
}
|
|
1492
|
+
async computeCost(span) {
|
|
1493
|
+
if (!this.opts.costFn) {
|
|
1494
|
+
return span;
|
|
1495
|
+
}
|
|
1496
|
+
if (!isChatCompletionSpan(span)) {
|
|
1497
|
+
return span;
|
|
1498
|
+
}
|
|
1499
|
+
const cost = this.opts.costFn(span.attributes.tokensUsed, {
|
|
1500
|
+
model: span.attributes.model,
|
|
1501
|
+
provider: span.attributes.provider,
|
|
1502
|
+
providerRegion: span.attributes.providerRegion
|
|
1594
1503
|
});
|
|
1595
|
-
|
|
1504
|
+
if (typeof cost === "number") {
|
|
1505
|
+
this.totalCost += cost;
|
|
1506
|
+
}
|
|
1507
|
+
return {
|
|
1508
|
+
...span,
|
|
1509
|
+
attributes: {
|
|
1510
|
+
...span.attributes,
|
|
1511
|
+
cost
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1596
1514
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1515
|
+
async updateUsage(span) {
|
|
1516
|
+
if (!isChatCompletionSpan(span)) {
|
|
1517
|
+
return span;
|
|
1518
|
+
}
|
|
1519
|
+
const tokensUsed = span.attributes.tokensUsed;
|
|
1520
|
+
if (!tokensUsed || tokensUsed.total == null || tokensUsed.completion == null || tokensUsed.prompt == null) {
|
|
1521
|
+
return span;
|
|
1522
|
+
}
|
|
1523
|
+
this.totalUsage.prompt += tokensUsed.prompt;
|
|
1524
|
+
this.totalUsage.completion += tokensUsed.completion;
|
|
1525
|
+
this.totalUsage.total += tokensUsed.total;
|
|
1526
|
+
return span;
|
|
1527
|
+
}
|
|
1528
|
+
async evaluatePrompt(span) {
|
|
1529
|
+
const { prompt, variables, output } = span.attributes;
|
|
1530
|
+
if (!isPrompt2(prompt)) {
|
|
1531
|
+
return span;
|
|
1532
|
+
}
|
|
1533
|
+
delete span.attributes["prompt"];
|
|
1534
|
+
let evaluators = [];
|
|
1535
|
+
let evaluatorResults = {};
|
|
1536
|
+
let extraAttributes = {};
|
|
1537
|
+
try {
|
|
1538
|
+
evaluators = await evaluatePrompt(prompt, variables, output);
|
|
1539
|
+
evaluatorResults = evaluators.reduce(
|
|
1540
|
+
(accum, result) => {
|
|
1541
|
+
accum[result.key] = result;
|
|
1542
|
+
return accum;
|
|
1543
|
+
},
|
|
1544
|
+
{}
|
|
1545
|
+
);
|
|
1546
|
+
extraAttributes = {
|
|
1547
|
+
evaluators,
|
|
1548
|
+
evaluatorResults
|
|
1549
|
+
};
|
|
1550
|
+
} catch (e) {
|
|
1551
|
+
extraAttributes = {
|
|
1552
|
+
evaluatorError: e.message,
|
|
1553
|
+
evaluators,
|
|
1554
|
+
evaluatorResults
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
const toSend = {
|
|
1558
|
+
...span,
|
|
1559
|
+
attributes: {
|
|
1560
|
+
...span.attributes,
|
|
1561
|
+
...extraAttributes
|
|
1562
|
+
}
|
|
1563
|
+
};
|
|
1564
|
+
return toSend;
|
|
1600
1565
|
}
|
|
1601
1566
|
};
|
|
1567
|
+
var isChatCompletionSpan = (value) => {
|
|
1568
|
+
return Boolean(
|
|
1569
|
+
value && typeof value == "object" && "name" in value && value.name === "ai.chatCompletion"
|
|
1570
|
+
);
|
|
1571
|
+
};
|
|
1572
|
+
var isPrompt2 = (value) => {
|
|
1573
|
+
return Boolean(
|
|
1574
|
+
value && typeof value == "object" && "schema" in value && "evaluators" in value
|
|
1575
|
+
);
|
|
1576
|
+
};
|
|
1602
1577
|
|
|
1603
|
-
// src/tracing/
|
|
1604
|
-
var
|
|
1605
|
-
((
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1578
|
+
// src/tracing/Trace.tsx
|
|
1579
|
+
var Trace = ({ name, attributes, children }, { tracer, render }) => {
|
|
1580
|
+
const result = tracer.trace(name, attributes || {}, () => {
|
|
1581
|
+
return render(children);
|
|
1582
|
+
});
|
|
1583
|
+
return result;
|
|
1584
|
+
};
|
|
1609
1585
|
|
|
1610
1586
|
// src/prompt/createPrompt.tsx
|
|
1611
1587
|
var import_zod = require("zod");
|
|
@@ -1668,19 +1644,6 @@ function createStreamChain(chain) {
|
|
|
1668
1644
|
};
|
|
1669
1645
|
}
|
|
1670
1646
|
|
|
1671
|
-
// src/prompt/evaluatePrompt.ts
|
|
1672
|
-
async function evaluatePrompt(prompt, variables, result) {
|
|
1673
|
-
const parsed = parseVariables(prompt.schema, variables);
|
|
1674
|
-
if (!parsed.success) {
|
|
1675
|
-
throw parsed.error;
|
|
1676
|
-
}
|
|
1677
|
-
return (await Promise.all(
|
|
1678
|
-
prompt.evaluators.map(
|
|
1679
|
-
(evaluator) => evaluator(parsed.result, result)
|
|
1680
|
-
)
|
|
1681
|
-
)).flat();
|
|
1682
|
-
}
|
|
1683
|
-
|
|
1684
1647
|
// src/lib/openai/OpenAI.tsx
|
|
1685
1648
|
var import_openai = require("openai");
|
|
1686
1649
|
|
|
@@ -1777,13 +1740,6 @@ var renderChatMessageContent = (content) => {
|
|
|
1777
1740
|
};
|
|
1778
1741
|
|
|
1779
1742
|
// src/utils.ts
|
|
1780
|
-
var import_nanoid2 = require("nanoid");
|
|
1781
|
-
var uuid = {
|
|
1782
|
-
renderId: () => (0, import_nanoid2.nanoid)(),
|
|
1783
|
-
spanId: () => (0, import_nanoid2.nanoid)(),
|
|
1784
|
-
traceId: () => (0, import_nanoid2.nanoid)(),
|
|
1785
|
-
requestId: () => (0, import_nanoid2.nanoid)()
|
|
1786
|
-
};
|
|
1787
1743
|
function getEnvVar(name, shouldThrow = true) {
|
|
1788
1744
|
let env = globalThis.process?.env ?? void 0;
|
|
1789
1745
|
if (env === void 0) {
|
|
@@ -1811,10 +1767,10 @@ var OpenAIClientContext = createContext(() => {
|
|
|
1811
1767
|
});
|
|
1812
1768
|
function buildOpenAIMessages(childrenXml) {
|
|
1813
1769
|
const messages = [];
|
|
1814
|
-
const
|
|
1815
|
-
const parsed = parseXml(childrenXml).collapse(
|
|
1770
|
+
const chatMessageTags = ["UserMessage", "AssistantMessage", "SystemMessage"];
|
|
1771
|
+
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
1816
1772
|
const topLevelValid = parsed.childNodes.every(
|
|
1817
|
-
(node) =>
|
|
1773
|
+
(node) => chatMessageTags.includes(node.nodeName)
|
|
1818
1774
|
);
|
|
1819
1775
|
if (!topLevelValid) {
|
|
1820
1776
|
throw new Error("Invalid top level chat message tags");
|
|
@@ -1839,105 +1795,109 @@ function buildOpenAIMessages(childrenXml) {
|
|
|
1839
1795
|
}
|
|
1840
1796
|
return messages;
|
|
1841
1797
|
}
|
|
1842
|
-
|
|
1843
|
-
const
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1798
|
+
function OpenAIChatCompletion(props, { logger, render, tracer, getContext }) {
|
|
1799
|
+
const startTime = performance.now();
|
|
1800
|
+
return tracer.trace(
|
|
1801
|
+
"ai.chatCompletion",
|
|
1802
|
+
{},
|
|
1803
|
+
async function* OpenAIChatCompletionInner(span) {
|
|
1804
|
+
const client = getContext(OpenAIClientContext)();
|
|
1805
|
+
if (!client) {
|
|
1806
|
+
throw new Error("[OpenAI] must supply OpenAI model via context");
|
|
1807
|
+
}
|
|
1808
|
+
const openAIMessages = buildOpenAIMessages(
|
|
1809
|
+
await render(props.children, {
|
|
1810
|
+
preserveTags: true
|
|
1811
|
+
})
|
|
1812
|
+
);
|
|
1813
|
+
const renderedMessages = openAIMessages.map((message) => {
|
|
1814
|
+
return {
|
|
1815
|
+
role: message.role,
|
|
1816
|
+
content: renderChatMessageContent(message.content),
|
|
1817
|
+
tokens: tokenCountForOpenAIMessage(message)
|
|
1818
|
+
};
|
|
1819
|
+
});
|
|
1820
|
+
const chatCompletionRequest = {
|
|
1821
|
+
model: props.model,
|
|
1822
|
+
max_tokens: props.maxTokens,
|
|
1823
|
+
temperature: props.temperature,
|
|
1824
|
+
messages: openAIMessages,
|
|
1825
|
+
response_format: props.responseFormat ? {
|
|
1826
|
+
type: props.responseFormat
|
|
1827
|
+
} : void 0,
|
|
1828
|
+
stream: true
|
|
1829
|
+
};
|
|
1830
|
+
const logRequestData = {
|
|
1831
|
+
startTime,
|
|
1832
|
+
model: props.model,
|
|
1833
|
+
provider: props.provider,
|
|
1834
|
+
providerRegion: props.providerRegion,
|
|
1835
|
+
inputMessages: renderedMessages,
|
|
1836
|
+
request: chatCompletionRequest
|
|
1837
|
+
};
|
|
1838
|
+
logger.chatCompletionRequest("openai", logRequestData);
|
|
1839
|
+
span.setAttributes({
|
|
1840
|
+
model: props.model,
|
|
1841
|
+
provider: props.provider,
|
|
1842
|
+
providerRegion: props.providerRegion,
|
|
1843
|
+
requestType: "openai",
|
|
1844
|
+
chatCompletionRequest
|
|
1845
|
+
});
|
|
1846
|
+
let chatResponse;
|
|
1847
|
+
try {
|
|
1848
|
+
chatResponse = await client.chat.completions.create(
|
|
1849
|
+
chatCompletionRequest
|
|
1850
|
+
);
|
|
1851
|
+
} catch (ex) {
|
|
1852
|
+
if (ex instanceof import_openai.OpenAI.APIError) {
|
|
1853
|
+
throw new ChatCompletionError(
|
|
1854
|
+
`OpenAIClient.APIError: ${ex.message}`,
|
|
1855
|
+
logRequestData
|
|
1856
|
+
);
|
|
1857
|
+
} else if (ex instanceof Error) {
|
|
1858
|
+
throw new ChatCompletionError(ex.message, logRequestData);
|
|
1859
|
+
}
|
|
1860
|
+
throw ex;
|
|
1861
|
+
}
|
|
1862
|
+
let finishReason = void 0;
|
|
1863
|
+
let content = "";
|
|
1864
|
+
for await (const message of chatResponse) {
|
|
1865
|
+
if (!message.choices || !message.choices[0]) {
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
const delta = message.choices[0].delta;
|
|
1869
|
+
if (message.choices[0].finish_reason) {
|
|
1870
|
+
finishReason = message.choices[0].finish_reason;
|
|
1871
|
+
}
|
|
1872
|
+
if (delta.content) {
|
|
1873
|
+
content += delta.content;
|
|
1874
|
+
yield delta.content;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
const outputMessage = {
|
|
1878
|
+
role: "assistant",
|
|
1879
|
+
content,
|
|
1880
|
+
tokens: tokenCountForOpenAIMessage({
|
|
1881
|
+
role: "assistant",
|
|
1882
|
+
content
|
|
1883
|
+
})
|
|
1884
|
+
};
|
|
1885
|
+
const tokensUsed = computeUsage([...renderedMessages, outputMessage]);
|
|
1886
|
+
const responseData = {
|
|
1887
|
+
...logRequestData,
|
|
1888
|
+
finishReason,
|
|
1889
|
+
latency: performance.now() - startTime,
|
|
1890
|
+
outputMessage,
|
|
1891
|
+
tokensUsed
|
|
1892
|
+
};
|
|
1893
|
+
logger.chatCompletionResponse("openai", responseData);
|
|
1894
|
+
span.setAttributes({
|
|
1895
|
+
tokensUsed,
|
|
1896
|
+
output: content,
|
|
1897
|
+
finishReason
|
|
1898
|
+
});
|
|
1917
1899
|
}
|
|
1918
|
-
|
|
1919
|
-
const outputMessage = {
|
|
1920
|
-
role: "assistant",
|
|
1921
|
-
content,
|
|
1922
|
-
tokens: tokenCountForOpenAIMessage({
|
|
1923
|
-
role: "assistant",
|
|
1924
|
-
content
|
|
1925
|
-
})
|
|
1926
|
-
};
|
|
1927
|
-
const responseData = {
|
|
1928
|
-
...logRequestData,
|
|
1929
|
-
endTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1930
|
-
finishReason,
|
|
1931
|
-
latency: performance.now() - perfStart,
|
|
1932
|
-
outputMessage,
|
|
1933
|
-
tokensUsed: computeUsage([...renderedMessages, outputMessage])
|
|
1934
|
-
};
|
|
1935
|
-
logger.chatCompletionResponse("openai", responseData);
|
|
1936
|
-
span.setAttributes({
|
|
1937
|
-
outputMessage,
|
|
1938
|
-
finishReason,
|
|
1939
|
-
tokensUsed: computeUsage([...renderedMessages, outputMessage])
|
|
1940
|
-
}).end();
|
|
1900
|
+
);
|
|
1941
1901
|
}
|
|
1942
1902
|
|
|
1943
1903
|
// src/lib/openai/OpenAIVision.tsx
|
|
@@ -1948,15 +1908,15 @@ var ContentTypeImage = (_props) => {
|
|
|
1948
1908
|
};
|
|
1949
1909
|
function buildOpenAIVisionChatMessages(childrenXml) {
|
|
1950
1910
|
const messages = [];
|
|
1951
|
-
const
|
|
1911
|
+
const chatMessageTags = [
|
|
1952
1912
|
"UserMessage",
|
|
1953
1913
|
"AssistantMessage",
|
|
1954
1914
|
"SystemMessage",
|
|
1955
1915
|
"ContentTypeImage"
|
|
1956
1916
|
];
|
|
1957
|
-
const parsed = parseXml(childrenXml).collapse(
|
|
1917
|
+
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
1958
1918
|
const topLevelValid = parsed.childNodes.every(
|
|
1959
|
-
(node) =>
|
|
1919
|
+
(node) => chatMessageTags.includes(node.nodeName)
|
|
1960
1920
|
);
|
|
1961
1921
|
if (!topLevelValid) {
|
|
1962
1922
|
throw new Error("Invalid top level chat message tags");
|
|
@@ -2003,148 +1963,152 @@ function buildOpenAIVisionChatMessages(childrenXml) {
|
|
|
2003
1963
|
}
|
|
2004
1964
|
return { messages, dimensions };
|
|
2005
1965
|
}
|
|
2006
|
-
|
|
2007
|
-
const
|
|
2008
|
-
const requestId = uuid.requestId();
|
|
2009
|
-
const perfStart = performance.now();
|
|
2010
|
-
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
1966
|
+
function OpenAIVisionChatCompletion(props, { logger, render, tracer, getContext }) {
|
|
1967
|
+
const startTime = performance.now();
|
|
2011
1968
|
const model = props.model || DEFAULT_MODEL;
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
if (!client) {
|
|
2020
|
-
throw new Error("[OpenAI] must supply OpenAI model via context");
|
|
2021
|
-
}
|
|
2022
|
-
const { messages: openAIMessages, dimensions } = buildOpenAIVisionChatMessages(
|
|
2023
|
-
await render(props.children, {
|
|
2024
|
-
preserveTags: true,
|
|
2025
|
-
renderedProps: {
|
|
2026
|
-
ContentTypeImage: {
|
|
2027
|
-
url: true,
|
|
2028
|
-
dimensions: true,
|
|
2029
|
-
detail: true
|
|
2030
|
-
}
|
|
1969
|
+
return tracer.trace(
|
|
1970
|
+
"ai.chatCompletion",
|
|
1971
|
+
{},
|
|
1972
|
+
async function* OpenAIVIsionChatCompletionInner(span) {
|
|
1973
|
+
const client = getContext(OpenAIClientContext)();
|
|
1974
|
+
if (!client) {
|
|
1975
|
+
throw new Error("[OpenAI] must supply OpenAI model via context");
|
|
2031
1976
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
1977
|
+
const { messages: openAIMessages, dimensions } = buildOpenAIVisionChatMessages(
|
|
1978
|
+
await render(props.children, {
|
|
1979
|
+
preserveTags: true,
|
|
1980
|
+
renderedProps: {
|
|
1981
|
+
ContentTypeImage: {
|
|
1982
|
+
url: true,
|
|
1983
|
+
dimensions: true,
|
|
1984
|
+
detail: true
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
})
|
|
1988
|
+
);
|
|
1989
|
+
const renderedMessages = openAIMessages.map((message) => {
|
|
1990
|
+
if (message.role === "user") {
|
|
1991
|
+
if (typeof message.content === "string") {
|
|
1992
|
+
return {
|
|
1993
|
+
role: message.role,
|
|
1994
|
+
content: message.content,
|
|
1995
|
+
tokens: tokenCountForOpenAIMessage(message)
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
const BASE_COST = 85;
|
|
1999
|
+
const tokens = message.content.reduce((acc, part) => {
|
|
2000
|
+
if (part.type === "text") {
|
|
2001
|
+
return acc + tokenCountForOpenAIMessage({
|
|
2002
|
+
role: message.role,
|
|
2003
|
+
content: part.text
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
const detail = part.image_url.detail || "auto";
|
|
2007
|
+
if (detail === "low") {
|
|
2008
|
+
return acc + BASE_COST;
|
|
2009
|
+
} else if (detail === "high") {
|
|
2010
|
+
const dim = dimensions.get(part);
|
|
2011
|
+
if (!dim) {
|
|
2012
|
+
return acc + (170 * 4 + BASE_COST);
|
|
2013
|
+
}
|
|
2014
|
+
const area = dim.width * dim.height;
|
|
2015
|
+
const num512Images = area / (512 * 512);
|
|
2016
|
+
const highCost = num512Images * 170;
|
|
2017
|
+
return acc + highCost + BASE_COST;
|
|
2018
|
+
} else {
|
|
2019
|
+
return acc + (170 * 4 + BASE_COST);
|
|
2020
|
+
}
|
|
2021
|
+
}, 0);
|
|
2022
|
+
return {
|
|
2023
|
+
role: message.role,
|
|
2024
|
+
content: renderChatMessageContent(message.content),
|
|
2025
|
+
tokens
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2037
2028
|
return {
|
|
2038
2029
|
role: message.role,
|
|
2039
|
-
content: message.content,
|
|
2030
|
+
content: renderChatMessageContent(message.content),
|
|
2040
2031
|
tokens: tokenCountForOpenAIMessage(message)
|
|
2041
2032
|
};
|
|
2033
|
+
});
|
|
2034
|
+
const chatCompletionRequest = {
|
|
2035
|
+
model,
|
|
2036
|
+
max_tokens: props.maxTokens,
|
|
2037
|
+
temperature: props.temperature,
|
|
2038
|
+
messages: openAIMessages,
|
|
2039
|
+
stream: true
|
|
2040
|
+
};
|
|
2041
|
+
const logRequestData = {
|
|
2042
|
+
startTime,
|
|
2043
|
+
model,
|
|
2044
|
+
provider: props.provider,
|
|
2045
|
+
providerRegion: props.providerRegion,
|
|
2046
|
+
inputMessages: renderedMessages,
|
|
2047
|
+
request: chatCompletionRequest
|
|
2048
|
+
};
|
|
2049
|
+
logger.chatCompletionRequest("openai", logRequestData);
|
|
2050
|
+
span.setAttributes({
|
|
2051
|
+
model: props.model,
|
|
2052
|
+
provider: props.provider,
|
|
2053
|
+
providerRegion: props.providerRegion,
|
|
2054
|
+
requestType: "openai",
|
|
2055
|
+
chatCompletionRequest
|
|
2056
|
+
});
|
|
2057
|
+
let chatResponse;
|
|
2058
|
+
try {
|
|
2059
|
+
chatResponse = await client.chat.completions.create(
|
|
2060
|
+
chatCompletionRequest
|
|
2061
|
+
);
|
|
2062
|
+
} catch (ex) {
|
|
2063
|
+
if (ex instanceof import_openai2.OpenAI.APIError) {
|
|
2064
|
+
throw new ChatCompletionError(
|
|
2065
|
+
`OpenAIClient.APIError: ${ex.message}`,
|
|
2066
|
+
logRequestData
|
|
2067
|
+
);
|
|
2068
|
+
} else if (ex instanceof Error) {
|
|
2069
|
+
throw new ChatCompletionError(ex.message, logRequestData);
|
|
2070
|
+
}
|
|
2071
|
+
throw ex;
|
|
2042
2072
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
content: part.text
|
|
2049
|
-
});
|
|
2073
|
+
let finishReason = void 0;
|
|
2074
|
+
let content = "";
|
|
2075
|
+
for await (const message of chatResponse) {
|
|
2076
|
+
if (!message.choices || !message.choices[0]) {
|
|
2077
|
+
continue;
|
|
2050
2078
|
}
|
|
2051
|
-
const
|
|
2052
|
-
if (
|
|
2053
|
-
|
|
2054
|
-
} else if (detail === "high") {
|
|
2055
|
-
const dim = dimensions.get(part);
|
|
2056
|
-
if (!dim) {
|
|
2057
|
-
return acc + (170 * 4 + BASE_COST);
|
|
2058
|
-
}
|
|
2059
|
-
const area = dim.width * dim.height;
|
|
2060
|
-
const num512Images = area / (512 * 512);
|
|
2061
|
-
const highCost = num512Images * 170;
|
|
2062
|
-
return acc + highCost + BASE_COST;
|
|
2063
|
-
} else {
|
|
2064
|
-
return acc + (170 * 4 + BASE_COST);
|
|
2079
|
+
const delta = message.choices[0].delta;
|
|
2080
|
+
if (message.choices[0].finish_reason) {
|
|
2081
|
+
finishReason = message.choices[0].finish_reason;
|
|
2065
2082
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2083
|
+
if (delta.content) {
|
|
2084
|
+
content += delta.content;
|
|
2085
|
+
yield delta.content;
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
const outputMessage = {
|
|
2089
|
+
role: "assistant",
|
|
2090
|
+
content,
|
|
2091
|
+
tokens: tokenCountForOpenAIMessage({
|
|
2092
|
+
role: "assistant",
|
|
2093
|
+
content
|
|
2094
|
+
})
|
|
2071
2095
|
};
|
|
2096
|
+
const tokensUsed = computeUsage([...renderedMessages, outputMessage]);
|
|
2097
|
+
const responseData = {
|
|
2098
|
+
...logRequestData,
|
|
2099
|
+
finishReason,
|
|
2100
|
+
latency: performance.now() - startTime,
|
|
2101
|
+
outputMessage,
|
|
2102
|
+
tokensUsed
|
|
2103
|
+
};
|
|
2104
|
+
logger.chatCompletionResponse("openai", responseData);
|
|
2105
|
+
span.setAttributes({
|
|
2106
|
+
tokensUsed,
|
|
2107
|
+
output: content,
|
|
2108
|
+
finishReason
|
|
2109
|
+
});
|
|
2072
2110
|
}
|
|
2073
|
-
|
|
2074
|
-
role: message.role,
|
|
2075
|
-
content: renderChatMessageContent(message.content),
|
|
2076
|
-
tokens: tokenCountForOpenAIMessage(message)
|
|
2077
|
-
};
|
|
2078
|
-
});
|
|
2079
|
-
const chatCompletionRequest = {
|
|
2080
|
-
model,
|
|
2081
|
-
max_tokens: props.maxTokens,
|
|
2082
|
-
temperature: props.temperature,
|
|
2083
|
-
messages: openAIMessages,
|
|
2084
|
-
stream: true
|
|
2085
|
-
};
|
|
2086
|
-
const logRequestData = {
|
|
2087
|
-
requestId,
|
|
2088
|
-
startTime,
|
|
2089
|
-
model,
|
|
2090
|
-
provider: props.provider,
|
|
2091
|
-
providerRegion: props.providerRegion,
|
|
2092
|
-
inputMessages: renderedMessages,
|
|
2093
|
-
request: chatCompletionRequest
|
|
2094
|
-
};
|
|
2095
|
-
logger.chatCompletionRequest("openai", logRequestData);
|
|
2096
|
-
span.setAttributes({
|
|
2097
|
-
inputMessages: renderedMessages,
|
|
2098
|
-
request: chatCompletionRequest
|
|
2099
|
-
});
|
|
2100
|
-
let chatResponse;
|
|
2101
|
-
try {
|
|
2102
|
-
chatResponse = await client.chat.completions.create(chatCompletionRequest);
|
|
2103
|
-
} catch (ex) {
|
|
2104
|
-
const error = ex instanceof import_openai2.OpenAI.APIError ? new ChatCompletionError(
|
|
2105
|
-
`OpenAIClient.APIError: ${ex.message}`,
|
|
2106
|
-
span.attributes
|
|
2107
|
-
) : new ChatCompletionError(ex.message, span.attributes);
|
|
2108
|
-
span.recordException(error).end();
|
|
2109
|
-
throw error;
|
|
2110
|
-
}
|
|
2111
|
-
let finishReason = void 0;
|
|
2112
|
-
let content = "";
|
|
2113
|
-
for await (const message of chatResponse) {
|
|
2114
|
-
if (!message.choices || !message.choices[0]) {
|
|
2115
|
-
continue;
|
|
2116
|
-
}
|
|
2117
|
-
const delta = message.choices[0].delta;
|
|
2118
|
-
if (message.choices[0].finish_reason) {
|
|
2119
|
-
finishReason = message.choices[0].finish_reason;
|
|
2120
|
-
}
|
|
2121
|
-
if (delta.content) {
|
|
2122
|
-
content += delta.content;
|
|
2123
|
-
yield delta.content;
|
|
2124
|
-
}
|
|
2125
|
-
}
|
|
2126
|
-
const outputMessage = {
|
|
2127
|
-
role: "assistant",
|
|
2128
|
-
content,
|
|
2129
|
-
tokens: tokenCountForOpenAIMessage({
|
|
2130
|
-
role: "assistant",
|
|
2131
|
-
content
|
|
2132
|
-
})
|
|
2133
|
-
};
|
|
2134
|
-
const responseData = {
|
|
2135
|
-
...logRequestData,
|
|
2136
|
-
endTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2137
|
-
finishReason,
|
|
2138
|
-
latency: performance.now() - perfStart,
|
|
2139
|
-
outputMessage,
|
|
2140
|
-
tokensUsed: computeUsage([...renderedMessages, outputMessage])
|
|
2141
|
-
};
|
|
2142
|
-
logger.chatCompletionResponse("openai", responseData);
|
|
2143
|
-
span.setAttributes({
|
|
2144
|
-
outputMessage,
|
|
2145
|
-
finishReason,
|
|
2146
|
-
tokensUsed: computeUsage([...renderedMessages, outputMessage])
|
|
2147
|
-
}).end();
|
|
2111
|
+
);
|
|
2148
2112
|
}
|
|
2149
2113
|
|
|
2150
2114
|
// src/lib/openai/index.ts
|
|
@@ -2166,9 +2130,15 @@ var AnthropicClientContext = createContext(
|
|
|
2166
2130
|
}
|
|
2167
2131
|
);
|
|
2168
2132
|
var defaultMaxTokens = 4096;
|
|
2169
|
-
|
|
2170
|
-
|
|
2133
|
+
function buildAnthropicMessages(childrenXml) {
|
|
2134
|
+
let system = "";
|
|
2171
2135
|
const messages = [];
|
|
2136
|
+
const chatMessageTags = [
|
|
2137
|
+
"UserMessage",
|
|
2138
|
+
"AssistantMessage",
|
|
2139
|
+
"SystemMessage",
|
|
2140
|
+
"ClaudeImageBlockParam"
|
|
2141
|
+
];
|
|
2172
2142
|
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
2173
2143
|
const topLevelValid = parsed.childNodes.every(
|
|
2174
2144
|
(node) => chatMessageTags.includes(node.nodeName)
|
|
@@ -2176,128 +2146,248 @@ function buildChatMessages(childrenXml) {
|
|
|
2176
2146
|
if (!topLevelValid) {
|
|
2177
2147
|
throw new Error("Invalid top level chat message tags");
|
|
2178
2148
|
}
|
|
2149
|
+
const dimensions = /* @__PURE__ */ new WeakMap();
|
|
2179
2150
|
for (const node of parsed.childNodes) {
|
|
2180
2151
|
if (node.nodeName === "UserMessage") {
|
|
2181
|
-
|
|
2152
|
+
if (node.childNodes?.length === 1 && node.childNodes[0].nodeName === "#text") {
|
|
2153
|
+
messages.push({
|
|
2154
|
+
content: node.childNodes[0].value,
|
|
2155
|
+
role: "user"
|
|
2156
|
+
});
|
|
2157
|
+
continue;
|
|
2158
|
+
}
|
|
2159
|
+
const parts = node.childNodes.map((n) => {
|
|
2160
|
+
if (n.nodeName === "#text") {
|
|
2161
|
+
return {
|
|
2162
|
+
type: "text",
|
|
2163
|
+
text: n.value
|
|
2164
|
+
};
|
|
2165
|
+
} else if (n.nodeName === "ClaudeImageBlockParam") {
|
|
2166
|
+
const imagePart = {
|
|
2167
|
+
type: "image",
|
|
2168
|
+
source: {
|
|
2169
|
+
type: "base64",
|
|
2170
|
+
media_type: n.attributes.mediaType,
|
|
2171
|
+
data: n.attributes.data
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
dimensions.set(imagePart, n.attributes.dimensions);
|
|
2175
|
+
return imagePart;
|
|
2176
|
+
}
|
|
2177
|
+
throw new Error(
|
|
2178
|
+
"Invalid ChatCompletionContentPart, expecting text or ContentTypeImage"
|
|
2179
|
+
);
|
|
2180
|
+
});
|
|
2182
2181
|
messages.push({
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
tokens: (0, import_tokenizer3.countTokens)(content)
|
|
2182
|
+
content: parts,
|
|
2183
|
+
role: "user"
|
|
2186
2184
|
});
|
|
2187
2185
|
} else if (node.nodeName === "AssistantMessage") {
|
|
2188
|
-
const content = `${import_sdk.default.AI_PROMPT} ${node.textContent}`;
|
|
2189
2186
|
messages.push({
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
tokens: (0, import_tokenizer3.countTokens)(content)
|
|
2187
|
+
content: node.textContent,
|
|
2188
|
+
role: "assistant"
|
|
2193
2189
|
});
|
|
2194
2190
|
} else if (node.nodeName === "SystemMessage") {
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2191
|
+
system = node.textContent;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return { messages, system, dimensions };
|
|
2195
|
+
}
|
|
2196
|
+
function AnthropicChatCompletion(props, { render, logger, tracer, getContext }) {
|
|
2197
|
+
const startTime = performance.now();
|
|
2198
|
+
return tracer.trace(
|
|
2199
|
+
"ai.chatCompletion",
|
|
2200
|
+
{},
|
|
2201
|
+
async function* AnthropicChatCompletionInner(span) {
|
|
2202
|
+
const client = getContext(AnthropicClientContext)();
|
|
2203
|
+
if (!client) {
|
|
2204
|
+
throw new Error(
|
|
2205
|
+
"[AnthropicChatCompletion] must supply AnthropicClient via context"
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
const { system, messages } = buildAnthropicMessages(
|
|
2209
|
+
await render(props.children, {
|
|
2210
|
+
preserveTags: true,
|
|
2211
|
+
renderedProps: {
|
|
2212
|
+
ClaudeImageBlockParam: {
|
|
2213
|
+
data: true,
|
|
2214
|
+
dimensions: true,
|
|
2215
|
+
mediaType: true
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
})
|
|
2219
|
+
);
|
|
2220
|
+
const inputMessages = getRenderedMessages(system, messages);
|
|
2221
|
+
const anthropicCompletionRequest = {
|
|
2222
|
+
system,
|
|
2223
|
+
messages,
|
|
2224
|
+
max_tokens: props.maxTokens ?? defaultMaxTokens,
|
|
2225
|
+
temperature: props.temperature,
|
|
2226
|
+
model: props.model
|
|
2227
|
+
};
|
|
2228
|
+
const logRequestData = {
|
|
2229
|
+
startTime,
|
|
2230
|
+
model: props.model,
|
|
2231
|
+
provider: props.provider,
|
|
2232
|
+
providerRegion: props.providerRegion,
|
|
2233
|
+
inputMessages,
|
|
2234
|
+
request: anthropicCompletionRequest
|
|
2235
|
+
};
|
|
2236
|
+
logger.chatCompletionRequest("anthropic", logRequestData);
|
|
2237
|
+
span.setAttributes({
|
|
2238
|
+
model: props.model,
|
|
2239
|
+
provider: props.provider,
|
|
2240
|
+
providerRegion: props.providerRegion,
|
|
2241
|
+
requestType: "anthropic",
|
|
2242
|
+
chatCompletionRequest: anthropicCompletionRequest
|
|
2200
2243
|
});
|
|
2201
|
-
|
|
2202
|
-
|
|
2244
|
+
let response;
|
|
2245
|
+
try {
|
|
2246
|
+
response = client.messages.stream(anthropicCompletionRequest);
|
|
2247
|
+
} catch (err) {
|
|
2248
|
+
if (err instanceof import_sdk.default.APIError) {
|
|
2249
|
+
throw new ChatCompletionError(
|
|
2250
|
+
`AnthropicClient.APIError: ${err.message}`,
|
|
2251
|
+
logRequestData
|
|
2252
|
+
);
|
|
2253
|
+
} else if (err instanceof Error) {
|
|
2254
|
+
throw new ChatCompletionError(err.message, logRequestData);
|
|
2255
|
+
}
|
|
2256
|
+
throw err;
|
|
2257
|
+
}
|
|
2258
|
+
let content = "";
|
|
2259
|
+
let outputUsage = 0;
|
|
2260
|
+
let inputUsage = 0;
|
|
2261
|
+
let finishReason = null;
|
|
2262
|
+
for await (const event of response) {
|
|
2263
|
+
if (event.type === "message_start") {
|
|
2264
|
+
inputUsage = event.message.usage?.input_tokens || 0;
|
|
2265
|
+
}
|
|
2266
|
+
if (event.type === "content_block_delta") {
|
|
2267
|
+
const chunk = event.delta.text;
|
|
2268
|
+
content += chunk;
|
|
2269
|
+
yield chunk;
|
|
2270
|
+
}
|
|
2271
|
+
if (event.type === "message_delta") {
|
|
2272
|
+
finishReason = event.delta.stop_reason;
|
|
2273
|
+
outputUsage = event.usage?.output_tokens;
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
const outputMessage = {
|
|
2203
2277
|
role: "assistant",
|
|
2204
|
-
content
|
|
2205
|
-
tokens:
|
|
2278
|
+
content,
|
|
2279
|
+
tokens: outputUsage
|
|
2280
|
+
};
|
|
2281
|
+
const userMessage = inputMessages.find(
|
|
2282
|
+
(m) => m.role === "user" && m.tokens === 0
|
|
2283
|
+
);
|
|
2284
|
+
const restMessages = inputMessages.filter(
|
|
2285
|
+
(m) => m.role !== "assistant" && m.tokens > 0
|
|
2286
|
+
);
|
|
2287
|
+
const restMessagesTokens = restMessages.reduce(
|
|
2288
|
+
(acc, m) => acc + m.tokens,
|
|
2289
|
+
0
|
|
2290
|
+
);
|
|
2291
|
+
if (userMessage && inputUsage) {
|
|
2292
|
+
userMessage.tokens = inputUsage - restMessagesTokens;
|
|
2293
|
+
}
|
|
2294
|
+
const tokensUsed = computeUsage([...inputMessages, outputMessage]);
|
|
2295
|
+
const responseData = {
|
|
2296
|
+
...logRequestData,
|
|
2297
|
+
finishReason,
|
|
2298
|
+
latency: performance.now() - startTime,
|
|
2299
|
+
// NOTE(jordan) we dont REALLY need inputMessages, they are this kind of intermediary that we use
|
|
2300
|
+
// to store the token values for the messages, but we could easily just compute the tokensUsed and call
|
|
2301
|
+
// it a day
|
|
2302
|
+
inputMessages,
|
|
2303
|
+
outputMessage,
|
|
2304
|
+
tokensUsed
|
|
2305
|
+
};
|
|
2306
|
+
logger.chatCompletionResponse("anthropic", responseData);
|
|
2307
|
+
span.setAttributes({
|
|
2308
|
+
tokensUsed,
|
|
2309
|
+
output: content,
|
|
2310
|
+
finishReason
|
|
2206
2311
|
});
|
|
2207
2312
|
}
|
|
2208
|
-
}
|
|
2209
|
-
return messages;
|
|
2210
|
-
}
|
|
2211
|
-
async function* AnthropicChatCompletion(props, { render, getContext, logger }) {
|
|
2212
|
-
const span = tracing.getTracer().startSpan("ai.chatCompletion");
|
|
2213
|
-
const requestId = uuid.requestId();
|
|
2214
|
-
const perfStart = performance.now();
|
|
2215
|
-
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
2216
|
-
span.setAttributes({
|
|
2217
|
-
requestId,
|
|
2218
|
-
model: props.model,
|
|
2219
|
-
provider: props.provider,
|
|
2220
|
-
providerRegion: props.providerRegion
|
|
2221
|
-
});
|
|
2222
|
-
const client = getContext(AnthropicClientContext)();
|
|
2223
|
-
if (!client) {
|
|
2224
|
-
throw new Error(
|
|
2225
|
-
"[AnthropicChatCompletion] must supply AnthropicClient via context"
|
|
2226
|
-
);
|
|
2227
|
-
}
|
|
2228
|
-
const inputMessages = buildChatMessages(
|
|
2229
|
-
await render(props.children, {
|
|
2230
|
-
preserveTags: true
|
|
2231
|
-
})
|
|
2232
2313
|
);
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
max_tokens_to_sample: props.maxTokens ?? defaultMaxTokens,
|
|
2240
|
-
temperature: props.temperature,
|
|
2241
|
-
model: props.model,
|
|
2242
|
-
stream: true
|
|
2243
|
-
};
|
|
2244
|
-
const logRequestData = {
|
|
2245
|
-
requestId,
|
|
2246
|
-
startTime,
|
|
2247
|
-
model: props.model,
|
|
2248
|
-
provider: props.provider,
|
|
2249
|
-
providerRegion: props.providerRegion,
|
|
2250
|
-
inputMessages,
|
|
2251
|
-
request: anthropicCompletionRequest
|
|
2314
|
+
}
|
|
2315
|
+
function getRenderedMessages(system, messages) {
|
|
2316
|
+
const systemMessage = {
|
|
2317
|
+
role: "system",
|
|
2318
|
+
content: system,
|
|
2319
|
+
tokens: (0, import_tokenizer3.countTokens)(system)
|
|
2252
2320
|
};
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2321
|
+
const renderedMessages = messages.map((message) => {
|
|
2322
|
+
if (message.role === "user") {
|
|
2323
|
+
return {
|
|
2324
|
+
role: message.role,
|
|
2325
|
+
content: renderChatMessageContent2(message.content),
|
|
2326
|
+
// we keep user message tokens 0 and just let anthropic tell us
|
|
2327
|
+
tokens: 0
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
return {
|
|
2331
|
+
role: message.role,
|
|
2332
|
+
content: renderChatMessageContent2(message.content),
|
|
2333
|
+
tokens: (0, import_tokenizer3.countTokens)(message.content)
|
|
2334
|
+
};
|
|
2257
2335
|
});
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
`AnthropicClient.APIError: ${ex.message}`,
|
|
2264
|
-
span.attributes
|
|
2265
|
-
) : new ChatCompletionError(ex.message, span.attributes);
|
|
2266
|
-
span.recordException(error).end();
|
|
2267
|
-
throw error;
|
|
2336
|
+
return [systemMessage, ...renderedMessages];
|
|
2337
|
+
}
|
|
2338
|
+
var renderChatMessageContent2 = (content) => {
|
|
2339
|
+
if (content == null) {
|
|
2340
|
+
return "";
|
|
2268
2341
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
for await (const completion of response) {
|
|
2272
|
-
let text = completion.completion;
|
|
2273
|
-
if (isFirstResponse && text.length > 0) {
|
|
2274
|
-
isFirstResponse = false;
|
|
2275
|
-
if (text.startsWith(" ")) {
|
|
2276
|
-
text = text.slice(1);
|
|
2277
|
-
}
|
|
2278
|
-
}
|
|
2279
|
-
content += text;
|
|
2280
|
-
yield text;
|
|
2342
|
+
if (typeof content === "string") {
|
|
2343
|
+
return content;
|
|
2281
2344
|
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2345
|
+
return content.map((part) => {
|
|
2346
|
+
if (typeof part === "string") {
|
|
2347
|
+
return part;
|
|
2348
|
+
} else if ("text" in part) {
|
|
2349
|
+
return part.text;
|
|
2350
|
+
} else if ("source" in part && typeof part.source === "object") {
|
|
2351
|
+
return `<ImageBlockParam data="base64..." />`;
|
|
2352
|
+
}
|
|
2353
|
+
throw new Error("Invalid ImageBlockParam type");
|
|
2354
|
+
}).join("\n\n");
|
|
2355
|
+
};
|
|
2356
|
+
|
|
2357
|
+
// src/lib/anthropic/ClaudeImageBlock.tsx
|
|
2358
|
+
var ClaudeImageBlockParam = (_props) => {
|
|
2359
|
+
return null;
|
|
2360
|
+
};
|
|
2361
|
+
async function fetchImageAndConvertToBase64(url) {
|
|
2362
|
+
const response = await fetch(url);
|
|
2363
|
+
const contentType = response.headers.get("content-type");
|
|
2364
|
+
const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
2365
|
+
if (!contentType || !allowedTypes.includes(contentType)) {
|
|
2366
|
+
throw new Error(`Unsupported media type: ${contentType}`);
|
|
2367
|
+
}
|
|
2368
|
+
const blob = await response.blob();
|
|
2369
|
+
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
2370
|
+
const base64 = buffer.toString("base64");
|
|
2371
|
+
return {
|
|
2372
|
+
base64,
|
|
2373
|
+
mediaType: contentType
|
|
2294
2374
|
};
|
|
2295
|
-
logger.chatCompletionResponse("anthropic", responseData);
|
|
2296
|
-
span.setAttributes({
|
|
2297
|
-
outputMessage,
|
|
2298
|
-
tokensUsed: computeUsage([...inputMessages, outputMessage])
|
|
2299
|
-
}).end();
|
|
2300
2375
|
}
|
|
2376
|
+
var ClaudeImageBlock = async (props) => {
|
|
2377
|
+
if ("data" in props) {
|
|
2378
|
+
return /* @__PURE__ */ jsx(ClaudeImageBlockParam, { ...props });
|
|
2379
|
+
}
|
|
2380
|
+
const { dimensions, url } = props;
|
|
2381
|
+
const { base64, mediaType } = await fetchImageAndConvertToBase64(url);
|
|
2382
|
+
return /* @__PURE__ */ jsx(
|
|
2383
|
+
ClaudeImageBlockParam,
|
|
2384
|
+
{
|
|
2385
|
+
dimensions,
|
|
2386
|
+
mediaType,
|
|
2387
|
+
data: base64
|
|
2388
|
+
}
|
|
2389
|
+
);
|
|
2390
|
+
};
|
|
2301
2391
|
|
|
2302
2392
|
// src/lib/anthropic/index.ts
|
|
2303
2393
|
var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
|
|
@@ -2305,16 +2395,18 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2305
2395
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2306
2396
|
0 && (module.exports = {
|
|
2307
2397
|
AIFragment,
|
|
2398
|
+
AISpanProcessor,
|
|
2308
2399
|
AnthropicChatCompletion,
|
|
2309
2400
|
AnthropicClient,
|
|
2310
2401
|
AnthropicClientContext,
|
|
2311
2402
|
AssistantMessage,
|
|
2312
2403
|
BoundLogger,
|
|
2313
|
-
ChainParseVariablesError,
|
|
2314
2404
|
ChatCompletionError,
|
|
2405
|
+
ClaudeImageBlock,
|
|
2315
2406
|
CombinedLogger,
|
|
2316
2407
|
ConsoleLogger,
|
|
2317
2408
|
ContentTypeImage,
|
|
2409
|
+
EnrichingSpanProcessor,
|
|
2318
2410
|
LogImplementation,
|
|
2319
2411
|
NoopLogImplementation,
|
|
2320
2412
|
OpenAIChatCompletion,
|
|
@@ -2323,10 +2415,9 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2323
2415
|
OpenAIVisionChatCompletion,
|
|
2324
2416
|
ParseVariablesError,
|
|
2325
2417
|
PromptInvalidOutputError,
|
|
2326
|
-
PromptParseVariablesError,
|
|
2327
2418
|
SystemMessage,
|
|
2419
|
+
Trace,
|
|
2328
2420
|
UserMessage,
|
|
2329
|
-
aijsxTracing,
|
|
2330
2421
|
attachedContextSymbol,
|
|
2331
2422
|
computeUsage,
|
|
2332
2423
|
countAnthropicTokens,
|
|
@@ -2336,10 +2427,10 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2336
2427
|
createPrompt,
|
|
2337
2428
|
createRenderContext,
|
|
2338
2429
|
createStreamChain,
|
|
2339
|
-
defaultMaxTokens,
|
|
2340
2430
|
evaluatePrompt,
|
|
2341
2431
|
tokenCountForOpenAIMessage,
|
|
2342
2432
|
tokenCountForOpenAIVisionMessage,
|
|
2343
2433
|
tokenLimitForChatModel,
|
|
2344
|
-
tokenizer
|
|
2434
|
+
tokenizer,
|
|
2435
|
+
tracing
|
|
2345
2436
|
});
|