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