@gammatech/aijsx 0.5.0-beta.1 → 0.5.0-dev.2024-03-12
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 +81 -398
- package/dist/index.d.ts +81 -398
- package/dist/index.js +1127 -1049
- package/dist/index.mjs +1121 -1044
- package/dist/jsx-dev-runtime-LS-DZfkv.d.mts +356 -0
- package/dist/jsx-dev-runtime-LS-DZfkv.d.ts +356 -0
- 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 +4 -3
- package/dist/createElement--C_Hwi_c.d.mts +0 -222
- package/dist/createElement--C_Hwi_c.d.ts +0 -222
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,157 @@ 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();
|
|
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;
|
|
1552
1422
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
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;
|
|
1436
|
+
});
|
|
1555
1437
|
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1438
|
+
finalSpans = [];
|
|
1439
|
+
onAllDonePromise = null;
|
|
1440
|
+
onAllDonePromiseResolve = null;
|
|
1441
|
+
async onStart(span) {
|
|
1442
|
+
this.finalSpans.push({
|
|
1443
|
+
status: "running",
|
|
1444
|
+
span
|
|
1560
1445
|
});
|
|
1561
1446
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
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");
|
|
1453
|
+
}
|
|
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?.();
|
|
1460
|
+
}
|
|
1461
|
+
if (span.parentSpanId == null) {
|
|
1462
|
+
await this.onAllDonePromise;
|
|
1463
|
+
await this.onTraceComplete(enrichedSpan);
|
|
1464
|
+
}
|
|
1465
|
+
this.exporter.export([enrichedSpan]);
|
|
1564
1466
|
}
|
|
1565
|
-
|
|
1566
|
-
this.
|
|
1567
|
-
|
|
1467
|
+
shutdown() {
|
|
1468
|
+
return this.exporter.shutdown?.();
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
var AISpanProcessor = class extends EnrichingSpanProcessor {
|
|
1472
|
+
totalCost = 0;
|
|
1473
|
+
totalUsage = {
|
|
1474
|
+
prompt: 0,
|
|
1475
|
+
completion: 0,
|
|
1476
|
+
total: 0
|
|
1477
|
+
};
|
|
1478
|
+
async onTraceComplete(rootSpan) {
|
|
1479
|
+
rootSpan.attributes.totalCost = this.totalCost;
|
|
1480
|
+
rootSpan.attributes.totalUsage = this.totalUsage;
|
|
1481
|
+
}
|
|
1482
|
+
async enrichSpan(span) {
|
|
1483
|
+
const result1 = await this.evaluatePrompt(span);
|
|
1484
|
+
const result2 = await this.updateCost(result1);
|
|
1485
|
+
const result3 = await this.updateUsage(result2);
|
|
1486
|
+
return result3;
|
|
1487
|
+
}
|
|
1488
|
+
async updateCost(span) {
|
|
1489
|
+
if (!isChatCompletionSpan(span)) {
|
|
1490
|
+
return span;
|
|
1491
|
+
}
|
|
1492
|
+
const { cost } = span.attributes;
|
|
1493
|
+
if (typeof cost === "number") {
|
|
1494
|
+
this.totalCost += cost;
|
|
1495
|
+
}
|
|
1496
|
+
return span;
|
|
1568
1497
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
* @param target a function or event emitter. When target or one of its callbacks is called,
|
|
1573
|
-
* the provided context will be used as the active context for the duration of the call.
|
|
1574
|
-
*/
|
|
1575
|
-
bind(context, target) {
|
|
1576
|
-
if (typeof target === "function") {
|
|
1577
|
-
return this.bindFunction(context, target);
|
|
1498
|
+
async updateUsage(span) {
|
|
1499
|
+
if (!isChatCompletionSpan(span)) {
|
|
1500
|
+
return span;
|
|
1578
1501
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1502
|
+
const tokensUsed = span.attributes.tokensUsed;
|
|
1503
|
+
if (!tokensUsed || tokensUsed.total == null || tokensUsed.completion == null || tokensUsed.prompt == null) {
|
|
1504
|
+
return span;
|
|
1581
1505
|
}
|
|
1582
|
-
|
|
1506
|
+
this.totalUsage.prompt += tokensUsed.prompt;
|
|
1507
|
+
this.totalUsage.completion += tokensUsed.completion;
|
|
1508
|
+
this.totalUsage.total += tokensUsed.total;
|
|
1509
|
+
return span;
|
|
1583
1510
|
}
|
|
1584
|
-
|
|
1585
|
-
const
|
|
1586
|
-
|
|
1587
|
-
return
|
|
1511
|
+
async evaluatePrompt(span) {
|
|
1512
|
+
const { prompt, variables, output } = span.attributes;
|
|
1513
|
+
if (!isPrompt2(prompt)) {
|
|
1514
|
+
return span;
|
|
1515
|
+
}
|
|
1516
|
+
delete span.attributes["prompt"];
|
|
1517
|
+
let evaluators = [];
|
|
1518
|
+
let evaluatorResults = {};
|
|
1519
|
+
let extraAttributes = {};
|
|
1520
|
+
try {
|
|
1521
|
+
evaluators = await evaluatePrompt(prompt, variables, output);
|
|
1522
|
+
evaluatorResults = evaluators.reduce(
|
|
1523
|
+
(accum, result) => {
|
|
1524
|
+
accum[result.key] = result;
|
|
1525
|
+
return accum;
|
|
1526
|
+
},
|
|
1527
|
+
{}
|
|
1528
|
+
);
|
|
1529
|
+
extraAttributes = {
|
|
1530
|
+
evaluators,
|
|
1531
|
+
evaluatorResults
|
|
1532
|
+
};
|
|
1533
|
+
} catch (e) {
|
|
1534
|
+
extraAttributes = {
|
|
1535
|
+
evaluatorError: e.message,
|
|
1536
|
+
evaluators,
|
|
1537
|
+
evaluatorResults
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
const toSend = {
|
|
1541
|
+
...span,
|
|
1542
|
+
attributes: {
|
|
1543
|
+
...span.attributes,
|
|
1544
|
+
...extraAttributes
|
|
1545
|
+
}
|
|
1588
1546
|
};
|
|
1589
|
-
|
|
1590
|
-
enumerable: false,
|
|
1591
|
-
configurable: true,
|
|
1592
|
-
writable: false,
|
|
1593
|
-
value: target.length
|
|
1594
|
-
});
|
|
1595
|
-
return contextWrapper;
|
|
1596
|
-
}
|
|
1597
|
-
bindAsyncGenerator(generator) {
|
|
1598
|
-
generator.next = this.bindFunction(this.active(), generator.next);
|
|
1599
|
-
return generator;
|
|
1547
|
+
return toSend;
|
|
1600
1548
|
}
|
|
1601
1549
|
};
|
|
1550
|
+
var isChatCompletionSpan = (value) => {
|
|
1551
|
+
return Boolean(
|
|
1552
|
+
value && typeof value == "object" && "name" in value && value.name === "ai.chatCompletion"
|
|
1553
|
+
);
|
|
1554
|
+
};
|
|
1555
|
+
var isPrompt2 = (value) => {
|
|
1556
|
+
return Boolean(
|
|
1557
|
+
value && typeof value == "object" && "schema" in value && "evaluators" in value
|
|
1558
|
+
);
|
|
1559
|
+
};
|
|
1602
1560
|
|
|
1603
|
-
// src/tracing/
|
|
1604
|
-
var
|
|
1605
|
-
((
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1561
|
+
// src/tracing/Trace.tsx
|
|
1562
|
+
var Trace = ({ name, attributes, children }, { tracer, render }) => {
|
|
1563
|
+
const result = tracer.trace(name, attributes || {}, () => {
|
|
1564
|
+
return render(children);
|
|
1565
|
+
});
|
|
1566
|
+
return result;
|
|
1567
|
+
};
|
|
1609
1568
|
|
|
1610
1569
|
// src/prompt/createPrompt.tsx
|
|
1611
1570
|
var import_zod = require("zod");
|
|
@@ -1668,19 +1627,6 @@ function createStreamChain(chain) {
|
|
|
1668
1627
|
};
|
|
1669
1628
|
}
|
|
1670
1629
|
|
|
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
1630
|
// src/lib/openai/OpenAI.tsx
|
|
1685
1631
|
var import_openai = require("openai");
|
|
1686
1632
|
|
|
@@ -1777,13 +1723,6 @@ var renderChatMessageContent = (content) => {
|
|
|
1777
1723
|
};
|
|
1778
1724
|
|
|
1779
1725
|
// 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
1726
|
function getEnvVar(name, shouldThrow = true) {
|
|
1788
1727
|
let env = globalThis.process?.env ?? void 0;
|
|
1789
1728
|
if (env === void 0) {
|
|
@@ -1806,15 +1745,19 @@ var OpenAIClientContext = createContext(() => {
|
|
|
1806
1745
|
return defaultClient;
|
|
1807
1746
|
}
|
|
1808
1747
|
const apiKey = getEnvVar("OPENAI_API_KEY", true);
|
|
1809
|
-
|
|
1748
|
+
const client = new import_openai.OpenAI({ apiKey });
|
|
1749
|
+
defaultClient = {
|
|
1750
|
+
client,
|
|
1751
|
+
provider: "openai"
|
|
1752
|
+
};
|
|
1810
1753
|
return defaultClient;
|
|
1811
1754
|
});
|
|
1812
1755
|
function buildOpenAIMessages(childrenXml) {
|
|
1813
1756
|
const messages = [];
|
|
1814
|
-
const
|
|
1815
|
-
const parsed = parseXml(childrenXml).collapse(
|
|
1757
|
+
const chatMessageTags = ["UserMessage", "AssistantMessage", "SystemMessage"];
|
|
1758
|
+
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
1816
1759
|
const topLevelValid = parsed.childNodes.every(
|
|
1817
|
-
(node) =>
|
|
1760
|
+
(node) => chatMessageTags.includes(node.nodeName)
|
|
1818
1761
|
);
|
|
1819
1762
|
if (!topLevelValid) {
|
|
1820
1763
|
throw new Error("Invalid top level chat message tags");
|
|
@@ -1839,105 +1782,111 @@ function buildOpenAIMessages(childrenXml) {
|
|
|
1839
1782
|
}
|
|
1840
1783
|
return messages;
|
|
1841
1784
|
}
|
|
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
|
-
|
|
1785
|
+
function OpenAIChatCompletion(props, { logger, render, tracer, getContext }) {
|
|
1786
|
+
const startTime = performance.now();
|
|
1787
|
+
return tracer.trace(
|
|
1788
|
+
"ai.chatCompletion",
|
|
1789
|
+
{},
|
|
1790
|
+
async function* OpenAIChatCompletionInner(span) {
|
|
1791
|
+
const { client, provider, providerRegion, costFn } = getContext(OpenAIClientContext)();
|
|
1792
|
+
if (!client) {
|
|
1793
|
+
throw new Error("[OpenAI] must supply OpenAI model via context");
|
|
1794
|
+
}
|
|
1795
|
+
const openAIMessages = buildOpenAIMessages(
|
|
1796
|
+
await render(props.children, {
|
|
1797
|
+
preserveTags: true
|
|
1798
|
+
})
|
|
1799
|
+
);
|
|
1800
|
+
const renderedMessages = openAIMessages.map((message) => {
|
|
1801
|
+
return {
|
|
1802
|
+
role: message.role,
|
|
1803
|
+
content: renderChatMessageContent(message.content),
|
|
1804
|
+
tokens: tokenCountForOpenAIMessage(message)
|
|
1805
|
+
};
|
|
1806
|
+
});
|
|
1807
|
+
const chatCompletionRequest = {
|
|
1808
|
+
model: props.model,
|
|
1809
|
+
max_tokens: props.maxTokens,
|
|
1810
|
+
temperature: props.temperature,
|
|
1811
|
+
messages: openAIMessages,
|
|
1812
|
+
response_format: props.responseFormat ? {
|
|
1813
|
+
type: props.responseFormat
|
|
1814
|
+
} : void 0,
|
|
1815
|
+
stream: true
|
|
1816
|
+
};
|
|
1817
|
+
const logRequestData = {
|
|
1818
|
+
startTime,
|
|
1819
|
+
model: props.model,
|
|
1820
|
+
provider,
|
|
1821
|
+
providerRegion,
|
|
1822
|
+
inputMessages: renderedMessages,
|
|
1823
|
+
request: chatCompletionRequest
|
|
1824
|
+
};
|
|
1825
|
+
logger.chatCompletionRequest("openai", logRequestData);
|
|
1826
|
+
span.setAttributes({
|
|
1827
|
+
model: props.model,
|
|
1828
|
+
provider,
|
|
1829
|
+
providerRegion,
|
|
1830
|
+
requestType: "openai",
|
|
1831
|
+
chatCompletionRequest
|
|
1832
|
+
});
|
|
1833
|
+
let chatResponse;
|
|
1834
|
+
try {
|
|
1835
|
+
chatResponse = await client.chat.completions.create(
|
|
1836
|
+
chatCompletionRequest
|
|
1837
|
+
);
|
|
1838
|
+
} catch (ex) {
|
|
1839
|
+
if (ex instanceof import_openai.OpenAI.APIError) {
|
|
1840
|
+
throw new ChatCompletionError(
|
|
1841
|
+
`OpenAIClient.APIError: ${ex.message}`,
|
|
1842
|
+
logRequestData
|
|
1843
|
+
);
|
|
1844
|
+
} else if (ex instanceof Error) {
|
|
1845
|
+
throw new ChatCompletionError(ex.message, logRequestData);
|
|
1846
|
+
}
|
|
1847
|
+
throw ex;
|
|
1848
|
+
}
|
|
1849
|
+
let finishReason = void 0;
|
|
1850
|
+
let content = "";
|
|
1851
|
+
for await (const message of chatResponse) {
|
|
1852
|
+
if (!message.choices || !message.choices[0]) {
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
const delta = message.choices[0].delta;
|
|
1856
|
+
if (message.choices[0].finish_reason) {
|
|
1857
|
+
finishReason = message.choices[0].finish_reason;
|
|
1858
|
+
}
|
|
1859
|
+
if (delta.content) {
|
|
1860
|
+
content += delta.content;
|
|
1861
|
+
yield delta.content;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
const outputMessage = {
|
|
1865
|
+
role: "assistant",
|
|
1866
|
+
content,
|
|
1867
|
+
tokens: tokenCountForOpenAIMessage({
|
|
1868
|
+
role: "assistant",
|
|
1869
|
+
content
|
|
1870
|
+
})
|
|
1871
|
+
};
|
|
1872
|
+
const tokensUsed = computeUsage([...renderedMessages, outputMessage]);
|
|
1873
|
+
const cost = costFn?.(tokensUsed) ?? void 0;
|
|
1874
|
+
const responseData = {
|
|
1875
|
+
...logRequestData,
|
|
1876
|
+
finishReason,
|
|
1877
|
+
latency: performance.now() - startTime,
|
|
1878
|
+
outputMessage,
|
|
1879
|
+
tokensUsed
|
|
1880
|
+
};
|
|
1881
|
+
logger.chatCompletionResponse("openai", responseData);
|
|
1882
|
+
span.setAttributes({
|
|
1883
|
+
tokensUsed,
|
|
1884
|
+
output: content,
|
|
1885
|
+
finishReason,
|
|
1886
|
+
cost
|
|
1887
|
+
});
|
|
1917
1888
|
}
|
|
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();
|
|
1889
|
+
);
|
|
1941
1890
|
}
|
|
1942
1891
|
|
|
1943
1892
|
// src/lib/openai/OpenAIVision.tsx
|
|
@@ -1948,15 +1897,15 @@ var ContentTypeImage = (_props) => {
|
|
|
1948
1897
|
};
|
|
1949
1898
|
function buildOpenAIVisionChatMessages(childrenXml) {
|
|
1950
1899
|
const messages = [];
|
|
1951
|
-
const
|
|
1900
|
+
const chatMessageTags = [
|
|
1952
1901
|
"UserMessage",
|
|
1953
1902
|
"AssistantMessage",
|
|
1954
1903
|
"SystemMessage",
|
|
1955
1904
|
"ContentTypeImage"
|
|
1956
1905
|
];
|
|
1957
|
-
const parsed = parseXml(childrenXml).collapse(
|
|
1906
|
+
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
1958
1907
|
const topLevelValid = parsed.childNodes.every(
|
|
1959
|
-
(node) =>
|
|
1908
|
+
(node) => chatMessageTags.includes(node.nodeName)
|
|
1960
1909
|
);
|
|
1961
1910
|
if (!topLevelValid) {
|
|
1962
1911
|
throw new Error("Invalid top level chat message tags");
|
|
@@ -2003,148 +1952,154 @@ function buildOpenAIVisionChatMessages(childrenXml) {
|
|
|
2003
1952
|
}
|
|
2004
1953
|
return { messages, dimensions };
|
|
2005
1954
|
}
|
|
2006
|
-
|
|
2007
|
-
const
|
|
2008
|
-
const requestId = uuid.requestId();
|
|
2009
|
-
const perfStart = performance.now();
|
|
2010
|
-
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
1955
|
+
function OpenAIVisionChatCompletion(props, { logger, render, tracer, getContext }) {
|
|
1956
|
+
const startTime = performance.now();
|
|
2011
1957
|
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
|
-
}
|
|
1958
|
+
return tracer.trace(
|
|
1959
|
+
"ai.chatCompletion",
|
|
1960
|
+
{},
|
|
1961
|
+
async function* OpenAIVIsionChatCompletionInner(span) {
|
|
1962
|
+
const { client, provider, providerRegion, costFn } = getContext(OpenAIClientContext)();
|
|
1963
|
+
if (!client) {
|
|
1964
|
+
throw new Error("[OpenAI] must supply OpenAI model via context");
|
|
2031
1965
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
1966
|
+
const { messages: openAIMessages, dimensions } = buildOpenAIVisionChatMessages(
|
|
1967
|
+
await render(props.children, {
|
|
1968
|
+
preserveTags: true,
|
|
1969
|
+
renderedProps: {
|
|
1970
|
+
ContentTypeImage: {
|
|
1971
|
+
url: true,
|
|
1972
|
+
dimensions: true,
|
|
1973
|
+
detail: true
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
})
|
|
1977
|
+
);
|
|
1978
|
+
const renderedMessages = openAIMessages.map((message) => {
|
|
1979
|
+
if (message.role === "user") {
|
|
1980
|
+
if (typeof message.content === "string") {
|
|
1981
|
+
return {
|
|
1982
|
+
role: message.role,
|
|
1983
|
+
content: message.content,
|
|
1984
|
+
tokens: tokenCountForOpenAIMessage(message)
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
const BASE_COST = 85;
|
|
1988
|
+
const tokens = message.content.reduce((acc, part) => {
|
|
1989
|
+
if (part.type === "text") {
|
|
1990
|
+
return acc + tokenCountForOpenAIMessage({
|
|
1991
|
+
role: message.role,
|
|
1992
|
+
content: part.text
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1995
|
+
const detail = part.image_url.detail || "auto";
|
|
1996
|
+
if (detail === "low") {
|
|
1997
|
+
return acc + BASE_COST;
|
|
1998
|
+
} else if (detail === "high") {
|
|
1999
|
+
const dim = dimensions.get(part);
|
|
2000
|
+
if (!dim) {
|
|
2001
|
+
return acc + (170 * 4 + BASE_COST);
|
|
2002
|
+
}
|
|
2003
|
+
const area = dim.width * dim.height;
|
|
2004
|
+
const num512Images = area / (512 * 512);
|
|
2005
|
+
const highCost = num512Images * 170;
|
|
2006
|
+
return acc + highCost + BASE_COST;
|
|
2007
|
+
} else {
|
|
2008
|
+
return acc + (170 * 4 + BASE_COST);
|
|
2009
|
+
}
|
|
2010
|
+
}, 0);
|
|
2011
|
+
return {
|
|
2012
|
+
role: message.role,
|
|
2013
|
+
content: renderChatMessageContent(message.content),
|
|
2014
|
+
tokens
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2037
2017
|
return {
|
|
2038
2018
|
role: message.role,
|
|
2039
|
-
content: message.content,
|
|
2019
|
+
content: renderChatMessageContent(message.content),
|
|
2040
2020
|
tokens: tokenCountForOpenAIMessage(message)
|
|
2041
2021
|
};
|
|
2022
|
+
});
|
|
2023
|
+
const chatCompletionRequest = {
|
|
2024
|
+
model,
|
|
2025
|
+
max_tokens: props.maxTokens,
|
|
2026
|
+
temperature: props.temperature,
|
|
2027
|
+
messages: openAIMessages,
|
|
2028
|
+
stream: true
|
|
2029
|
+
};
|
|
2030
|
+
const logRequestData = {
|
|
2031
|
+
startTime,
|
|
2032
|
+
model,
|
|
2033
|
+
provider,
|
|
2034
|
+
providerRegion,
|
|
2035
|
+
inputMessages: renderedMessages,
|
|
2036
|
+
request: chatCompletionRequest
|
|
2037
|
+
};
|
|
2038
|
+
logger.chatCompletionRequest("openai", logRequestData);
|
|
2039
|
+
span.setAttributes({
|
|
2040
|
+
model: props.model,
|
|
2041
|
+
provider,
|
|
2042
|
+
providerRegion,
|
|
2043
|
+
requestType: "openai",
|
|
2044
|
+
chatCompletionRequest
|
|
2045
|
+
});
|
|
2046
|
+
let chatResponse;
|
|
2047
|
+
try {
|
|
2048
|
+
chatResponse = await client.chat.completions.create(
|
|
2049
|
+
chatCompletionRequest
|
|
2050
|
+
);
|
|
2051
|
+
} catch (ex) {
|
|
2052
|
+
if (ex instanceof import_openai2.OpenAI.APIError) {
|
|
2053
|
+
throw new ChatCompletionError(
|
|
2054
|
+
`OpenAIClient.APIError: ${ex.message}`,
|
|
2055
|
+
logRequestData
|
|
2056
|
+
);
|
|
2057
|
+
} else if (ex instanceof Error) {
|
|
2058
|
+
throw new ChatCompletionError(ex.message, logRequestData);
|
|
2059
|
+
}
|
|
2060
|
+
throw ex;
|
|
2042
2061
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
content: part.text
|
|
2049
|
-
});
|
|
2062
|
+
let finishReason = void 0;
|
|
2063
|
+
let content = "";
|
|
2064
|
+
for await (const message of chatResponse) {
|
|
2065
|
+
if (!message.choices || !message.choices[0]) {
|
|
2066
|
+
continue;
|
|
2050
2067
|
}
|
|
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);
|
|
2068
|
+
const delta = message.choices[0].delta;
|
|
2069
|
+
if (message.choices[0].finish_reason) {
|
|
2070
|
+
finishReason = message.choices[0].finish_reason;
|
|
2065
2071
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2072
|
+
if (delta.content) {
|
|
2073
|
+
content += delta.content;
|
|
2074
|
+
yield delta.content;
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
const outputMessage = {
|
|
2078
|
+
role: "assistant",
|
|
2079
|
+
content,
|
|
2080
|
+
tokens: tokenCountForOpenAIMessage({
|
|
2081
|
+
role: "assistant",
|
|
2082
|
+
content
|
|
2083
|
+
})
|
|
2071
2084
|
};
|
|
2085
|
+
const tokensUsed = computeUsage([...renderedMessages, outputMessage]);
|
|
2086
|
+
const cost = costFn?.(tokensUsed) ?? void 0;
|
|
2087
|
+
const responseData = {
|
|
2088
|
+
...logRequestData,
|
|
2089
|
+
finishReason,
|
|
2090
|
+
latency: performance.now() - startTime,
|
|
2091
|
+
outputMessage,
|
|
2092
|
+
tokensUsed
|
|
2093
|
+
};
|
|
2094
|
+
logger.chatCompletionResponse("openai", responseData);
|
|
2095
|
+
span.setAttributes({
|
|
2096
|
+
tokensUsed,
|
|
2097
|
+
output: content,
|
|
2098
|
+
cost,
|
|
2099
|
+
finishReason
|
|
2100
|
+
});
|
|
2072
2101
|
}
|
|
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();
|
|
2102
|
+
);
|
|
2148
2103
|
}
|
|
2149
2104
|
|
|
2150
2105
|
// src/lib/openai/index.ts
|
|
@@ -2154,21 +2109,29 @@ var import_openai3 = require("openai");
|
|
|
2154
2109
|
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
2155
2110
|
var import_tokenizer3 = require("@anthropic-ai/tokenizer");
|
|
2156
2111
|
var defaultClient2 = null;
|
|
2157
|
-
var AnthropicClientContext = createContext(
|
|
2158
|
-
()
|
|
2159
|
-
if (defaultClient2) {
|
|
2160
|
-
return defaultClient2;
|
|
2161
|
-
}
|
|
2162
|
-
defaultClient2 = new import_sdk.default({
|
|
2163
|
-
apiKey: getEnvVar("ANTHROPIC_API_KEY", false)
|
|
2164
|
-
});
|
|
2112
|
+
var AnthropicClientContext = createContext(() => {
|
|
2113
|
+
if (defaultClient2) {
|
|
2165
2114
|
return defaultClient2;
|
|
2166
2115
|
}
|
|
2167
|
-
|
|
2116
|
+
const client = new import_sdk.default({
|
|
2117
|
+
apiKey: getEnvVar("ANTHROPIC_API_KEY", false)
|
|
2118
|
+
});
|
|
2119
|
+
defaultClient2 = {
|
|
2120
|
+
client,
|
|
2121
|
+
provider: "anthropic"
|
|
2122
|
+
};
|
|
2123
|
+
return defaultClient2;
|
|
2124
|
+
});
|
|
2168
2125
|
var defaultMaxTokens = 4096;
|
|
2169
|
-
|
|
2170
|
-
|
|
2126
|
+
function buildAnthropicMessages(childrenXml) {
|
|
2127
|
+
let system = "";
|
|
2171
2128
|
const messages = [];
|
|
2129
|
+
const chatMessageTags = [
|
|
2130
|
+
"UserMessage",
|
|
2131
|
+
"AssistantMessage",
|
|
2132
|
+
"SystemMessage",
|
|
2133
|
+
"ClaudeImageBlockParam"
|
|
2134
|
+
];
|
|
2172
2135
|
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
2173
2136
|
const topLevelValid = parsed.childNodes.every(
|
|
2174
2137
|
(node) => chatMessageTags.includes(node.nodeName)
|
|
@@ -2178,126 +2141,240 @@ function buildChatMessages(childrenXml) {
|
|
|
2178
2141
|
}
|
|
2179
2142
|
for (const node of parsed.childNodes) {
|
|
2180
2143
|
if (node.nodeName === "UserMessage") {
|
|
2181
|
-
|
|
2144
|
+
if (node.childNodes?.length === 1 && node.childNodes[0].nodeName === "#text") {
|
|
2145
|
+
messages.push({
|
|
2146
|
+
content: node.childNodes[0].value,
|
|
2147
|
+
role: "user"
|
|
2148
|
+
});
|
|
2149
|
+
continue;
|
|
2150
|
+
}
|
|
2151
|
+
const parts = node.childNodes.map((n) => {
|
|
2152
|
+
if (n.nodeName === "#text") {
|
|
2153
|
+
return {
|
|
2154
|
+
type: "text",
|
|
2155
|
+
text: n.value
|
|
2156
|
+
};
|
|
2157
|
+
} else if (n.nodeName === "ClaudeImageBlockParam") {
|
|
2158
|
+
const imagePart = {
|
|
2159
|
+
type: "image",
|
|
2160
|
+
source: {
|
|
2161
|
+
type: "base64",
|
|
2162
|
+
media_type: n.attributes.mediaType,
|
|
2163
|
+
data: n.attributes.data
|
|
2164
|
+
}
|
|
2165
|
+
};
|
|
2166
|
+
return imagePart;
|
|
2167
|
+
}
|
|
2168
|
+
throw new Error(
|
|
2169
|
+
"Invalid ChatCompletionContentPart, expecting text or ContentTypeImage"
|
|
2170
|
+
);
|
|
2171
|
+
});
|
|
2182
2172
|
messages.push({
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
tokens: (0, import_tokenizer3.countTokens)(content)
|
|
2173
|
+
content: parts,
|
|
2174
|
+
role: "user"
|
|
2186
2175
|
});
|
|
2187
2176
|
} else if (node.nodeName === "AssistantMessage") {
|
|
2188
|
-
const content = `${import_sdk.default.AI_PROMPT} ${node.textContent}`;
|
|
2189
2177
|
messages.push({
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
tokens: (0, import_tokenizer3.countTokens)(content)
|
|
2178
|
+
content: node.textContent,
|
|
2179
|
+
role: "assistant"
|
|
2193
2180
|
});
|
|
2194
2181
|
} else if (node.nodeName === "SystemMessage") {
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2182
|
+
system = node.textContent;
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
return { messages, system };
|
|
2186
|
+
}
|
|
2187
|
+
function AnthropicChatCompletion(props, { render, logger, tracer, getContext }) {
|
|
2188
|
+
const startTime = performance.now();
|
|
2189
|
+
return tracer.trace(
|
|
2190
|
+
"ai.chatCompletion",
|
|
2191
|
+
{},
|
|
2192
|
+
async function* AnthropicChatCompletionInner(span) {
|
|
2193
|
+
const { client, provider, providerRegion, costFn } = getContext(
|
|
2194
|
+
AnthropicClientContext
|
|
2195
|
+
)();
|
|
2196
|
+
if (!client) {
|
|
2197
|
+
throw new Error(
|
|
2198
|
+
"[AnthropicChatCompletion] must supply AnthropicClient via context"
|
|
2199
|
+
);
|
|
2200
|
+
}
|
|
2201
|
+
const { system, messages } = buildAnthropicMessages(
|
|
2202
|
+
await render(props.children, {
|
|
2203
|
+
preserveTags: true,
|
|
2204
|
+
renderedProps: {
|
|
2205
|
+
ClaudeImageBlockParam: {
|
|
2206
|
+
data: true,
|
|
2207
|
+
mediaType: true
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
})
|
|
2211
|
+
);
|
|
2212
|
+
const inputMessages = getRenderedMessages(system, messages);
|
|
2213
|
+
const anthropicCompletionRequest = {
|
|
2214
|
+
system,
|
|
2215
|
+
messages,
|
|
2216
|
+
max_tokens: props.maxTokens ?? defaultMaxTokens,
|
|
2217
|
+
temperature: props.temperature,
|
|
2218
|
+
model: props.model
|
|
2219
|
+
};
|
|
2220
|
+
const logRequestData = {
|
|
2221
|
+
startTime,
|
|
2222
|
+
model: props.model,
|
|
2223
|
+
provider,
|
|
2224
|
+
providerRegion,
|
|
2225
|
+
inputMessages,
|
|
2226
|
+
request: anthropicCompletionRequest
|
|
2227
|
+
};
|
|
2228
|
+
logger.chatCompletionRequest("anthropic", logRequestData);
|
|
2229
|
+
span.setAttributes({
|
|
2230
|
+
model: props.model,
|
|
2231
|
+
provider,
|
|
2232
|
+
providerRegion,
|
|
2233
|
+
requestType: "anthropic",
|
|
2234
|
+
chatCompletionRequest: anthropicCompletionRequest
|
|
2200
2235
|
});
|
|
2201
|
-
|
|
2202
|
-
|
|
2236
|
+
let response;
|
|
2237
|
+
try {
|
|
2238
|
+
response = client.messages.stream(anthropicCompletionRequest);
|
|
2239
|
+
} catch (err) {
|
|
2240
|
+
if (err instanceof import_sdk.default.APIError) {
|
|
2241
|
+
throw new ChatCompletionError(
|
|
2242
|
+
`AnthropicClient.APIError: ${err.message}`,
|
|
2243
|
+
logRequestData
|
|
2244
|
+
);
|
|
2245
|
+
} else if (err instanceof Error) {
|
|
2246
|
+
throw new ChatCompletionError(err.message, logRequestData);
|
|
2247
|
+
}
|
|
2248
|
+
throw err;
|
|
2249
|
+
}
|
|
2250
|
+
let content = "";
|
|
2251
|
+
let outputUsage = 0;
|
|
2252
|
+
let inputUsage = 0;
|
|
2253
|
+
let finishReason = null;
|
|
2254
|
+
for await (const event of response) {
|
|
2255
|
+
if (event.type === "message_start") {
|
|
2256
|
+
inputUsage = event.message.usage?.input_tokens || 0;
|
|
2257
|
+
}
|
|
2258
|
+
if (event.type === "content_block_delta") {
|
|
2259
|
+
const chunk = event.delta.text;
|
|
2260
|
+
content += chunk;
|
|
2261
|
+
yield chunk;
|
|
2262
|
+
}
|
|
2263
|
+
if (event.type === "message_delta") {
|
|
2264
|
+
finishReason = event.delta.stop_reason;
|
|
2265
|
+
outputUsage = event.usage?.output_tokens;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
const outputMessage = {
|
|
2203
2269
|
role: "assistant",
|
|
2204
|
-
content
|
|
2205
|
-
tokens:
|
|
2270
|
+
content,
|
|
2271
|
+
tokens: outputUsage
|
|
2272
|
+
};
|
|
2273
|
+
const userMessage = inputMessages.find(
|
|
2274
|
+
(m) => m.role === "user" && m.tokens === 0
|
|
2275
|
+
);
|
|
2276
|
+
const restMessages = inputMessages.filter(
|
|
2277
|
+
(m) => m.role !== "assistant" && m.tokens > 0
|
|
2278
|
+
);
|
|
2279
|
+
const restMessagesTokens = restMessages.reduce(
|
|
2280
|
+
(acc, m) => acc + m.tokens,
|
|
2281
|
+
0
|
|
2282
|
+
);
|
|
2283
|
+
if (userMessage && inputUsage) {
|
|
2284
|
+
userMessage.tokens = inputUsage - restMessagesTokens;
|
|
2285
|
+
}
|
|
2286
|
+
const tokensUsed = computeUsage([...inputMessages, outputMessage]);
|
|
2287
|
+
const cost = costFn?.(tokensUsed) ?? void 0;
|
|
2288
|
+
const responseData = {
|
|
2289
|
+
...logRequestData,
|
|
2290
|
+
finishReason,
|
|
2291
|
+
latency: performance.now() - startTime,
|
|
2292
|
+
// NOTE(jordan) we dont REALLY need inputMessages, they are this kind of intermediary that we use
|
|
2293
|
+
// to store the token values for the messages, but we could easily just compute the tokensUsed and call
|
|
2294
|
+
// it a day
|
|
2295
|
+
inputMessages,
|
|
2296
|
+
outputMessage,
|
|
2297
|
+
tokensUsed
|
|
2298
|
+
};
|
|
2299
|
+
logger.chatCompletionResponse("anthropic", responseData);
|
|
2300
|
+
span.setAttributes({
|
|
2301
|
+
tokensUsed,
|
|
2302
|
+
output: content,
|
|
2303
|
+
cost,
|
|
2304
|
+
finishReason
|
|
2206
2305
|
});
|
|
2207
2306
|
}
|
|
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
2307
|
);
|
|
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
|
|
2308
|
+
}
|
|
2309
|
+
function getRenderedMessages(system, messages) {
|
|
2310
|
+
const systemMessage = {
|
|
2311
|
+
role: "system",
|
|
2312
|
+
content: system,
|
|
2313
|
+
tokens: (0, import_tokenizer3.countTokens)(system)
|
|
2252
2314
|
};
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2315
|
+
const renderedMessages = messages.map((message) => {
|
|
2316
|
+
if (message.role === "user") {
|
|
2317
|
+
return {
|
|
2318
|
+
role: message.role,
|
|
2319
|
+
content: renderChatMessageContent2(message.content),
|
|
2320
|
+
// we keep user message tokens 0 and just let anthropic tell us
|
|
2321
|
+
tokens: 0
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2324
|
+
return {
|
|
2325
|
+
role: message.role,
|
|
2326
|
+
content: renderChatMessageContent2(message.content),
|
|
2327
|
+
tokens: (0, import_tokenizer3.countTokens)(message.content)
|
|
2328
|
+
};
|
|
2257
2329
|
});
|
|
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;
|
|
2330
|
+
return [systemMessage, ...renderedMessages];
|
|
2331
|
+
}
|
|
2332
|
+
var renderChatMessageContent2 = (content) => {
|
|
2333
|
+
if (content == null) {
|
|
2334
|
+
return "";
|
|
2268
2335
|
}
|
|
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;
|
|
2336
|
+
if (typeof content === "string") {
|
|
2337
|
+
return content;
|
|
2281
2338
|
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2339
|
+
return content.map((part) => {
|
|
2340
|
+
if (typeof part === "string") {
|
|
2341
|
+
return part;
|
|
2342
|
+
} else if ("text" in part) {
|
|
2343
|
+
return part.text;
|
|
2344
|
+
} else if ("source" in part && typeof part.source === "object") {
|
|
2345
|
+
return `<ImageBlockParam data="base64..." />`;
|
|
2346
|
+
}
|
|
2347
|
+
throw new Error("Invalid ImageBlockParam type");
|
|
2348
|
+
}).join("\n\n");
|
|
2349
|
+
};
|
|
2350
|
+
|
|
2351
|
+
// src/lib/anthropic/ClaudeImageBlock.tsx
|
|
2352
|
+
var ClaudeImageBlockParam = (_props) => {
|
|
2353
|
+
return null;
|
|
2354
|
+
};
|
|
2355
|
+
async function fetchImageAndConvertToBase64(url) {
|
|
2356
|
+
const response = await fetch(url);
|
|
2357
|
+
const contentType = response.headers.get("content-type");
|
|
2358
|
+
const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
2359
|
+
if (!contentType || !allowedTypes.includes(contentType)) {
|
|
2360
|
+
throw new Error(`Unsupported media type: ${contentType}`);
|
|
2361
|
+
}
|
|
2362
|
+
const blob = await response.blob();
|
|
2363
|
+
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
2364
|
+
const base64 = buffer.toString("base64");
|
|
2365
|
+
return {
|
|
2366
|
+
base64,
|
|
2367
|
+
mediaType: contentType
|
|
2294
2368
|
};
|
|
2295
|
-
logger.chatCompletionResponse("anthropic", responseData);
|
|
2296
|
-
span.setAttributes({
|
|
2297
|
-
outputMessage,
|
|
2298
|
-
tokensUsed: computeUsage([...inputMessages, outputMessage])
|
|
2299
|
-
}).end();
|
|
2300
2369
|
}
|
|
2370
|
+
var ClaudeImageBlock = async (props) => {
|
|
2371
|
+
if ("data" in props) {
|
|
2372
|
+
return /* @__PURE__ */ jsx(ClaudeImageBlockParam, { ...props });
|
|
2373
|
+
}
|
|
2374
|
+
const { url } = props;
|
|
2375
|
+
const { base64, mediaType } = await fetchImageAndConvertToBase64(url);
|
|
2376
|
+
return /* @__PURE__ */ jsx(ClaudeImageBlockParam, { mediaType, data: base64 });
|
|
2377
|
+
};
|
|
2301
2378
|
|
|
2302
2379
|
// src/lib/anthropic/index.ts
|
|
2303
2380
|
var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
|
|
@@ -2305,16 +2382,18 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2305
2382
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2306
2383
|
0 && (module.exports = {
|
|
2307
2384
|
AIFragment,
|
|
2385
|
+
AISpanProcessor,
|
|
2308
2386
|
AnthropicChatCompletion,
|
|
2309
2387
|
AnthropicClient,
|
|
2310
2388
|
AnthropicClientContext,
|
|
2311
2389
|
AssistantMessage,
|
|
2312
2390
|
BoundLogger,
|
|
2313
|
-
ChainParseVariablesError,
|
|
2314
2391
|
ChatCompletionError,
|
|
2392
|
+
ClaudeImageBlock,
|
|
2315
2393
|
CombinedLogger,
|
|
2316
2394
|
ConsoleLogger,
|
|
2317
2395
|
ContentTypeImage,
|
|
2396
|
+
EnrichingSpanProcessor,
|
|
2318
2397
|
LogImplementation,
|
|
2319
2398
|
NoopLogImplementation,
|
|
2320
2399
|
OpenAIChatCompletion,
|
|
@@ -2323,10 +2402,9 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2323
2402
|
OpenAIVisionChatCompletion,
|
|
2324
2403
|
ParseVariablesError,
|
|
2325
2404
|
PromptInvalidOutputError,
|
|
2326
|
-
PromptParseVariablesError,
|
|
2327
2405
|
SystemMessage,
|
|
2406
|
+
Trace,
|
|
2328
2407
|
UserMessage,
|
|
2329
|
-
aijsxTracing,
|
|
2330
2408
|
attachedContextSymbol,
|
|
2331
2409
|
computeUsage,
|
|
2332
2410
|
countAnthropicTokens,
|
|
@@ -2336,10 +2414,10 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2336
2414
|
createPrompt,
|
|
2337
2415
|
createRenderContext,
|
|
2338
2416
|
createStreamChain,
|
|
2339
|
-
defaultMaxTokens,
|
|
2340
2417
|
evaluatePrompt,
|
|
2341
2418
|
tokenCountForOpenAIMessage,
|
|
2342
2419
|
tokenCountForOpenAIVisionMessage,
|
|
2343
2420
|
tokenLimitForChatModel,
|
|
2344
|
-
tokenizer
|
|
2421
|
+
tokenizer,
|
|
2422
|
+
tracing
|
|
2345
2423
|
});
|