@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/dist/index.mjs CHANGED
@@ -211,29 +211,30 @@ function coalesceParallelStreams(streams) {
211
211
  return iter;
212
212
  }
213
213
 
214
- // src/logging/log.ts
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", `AIJSX Exception: ${exception}`);
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(level, message) {
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 { success: true, result: schema.parse(variables) };
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 { success: false, error };
307
+ return { parsedVariables: null, error };
314
308
  }
315
309
  }
316
310
 
317
- // src/render.ts
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
- _currentContext;
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._currentContext = parentContext ? new Map(parentContext) : /* @__PURE__ */ new Map();
429
- self.getValue = ({ key }) => self._currentContext.get(key);
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._currentContext);
432
- context._currentContext.set(key, value);
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._currentContext);
437
- context._currentContext.delete(key);
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(context, target) {
531
- return this.getContextManager().bind(context, target);
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 new _HrTime([seconds, Math.floor(nanoseconds)]);
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 KEY");
472
+ var SPAN_KEY = createContextKey("AIJSX SPAN");
575
473
  var AISpan = class {
576
- constructor(spanProcessorProvider, context, spanName, spanContext, parentSpanId, startTime, attributes) {
577
- this.spanProcessorProvider = spanProcessorProvider;
578
- this.name = spanName;
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
- endHrTime = null;
482
+ startTimestamp;
483
+ endTimestamp = null;
484
+ ended = false;
601
485
  duration = -1;
602
- name;
603
- _ended = false;
604
- status = {
605
- code: 0 /* UNSET */
606
- };
607
- spanContext() {
608
- return this._spanContext;
609
- }
610
- setAttribute(key, value) {
611
- if (value == null || this._isSpanEnded())
612
- return this;
613
- this.attributes[key] = value;
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.setAttribute(k, v);
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._isSpanEnded())
513
+ if (this.ended)
638
514
  return this;
639
- this.events.push({
640
- timestamp: startTime.toISOString(),
641
- time: startTime.time,
515
+ const event = {
642
516
  name,
643
- attributes
644
- });
645
- return this;
646
- }
647
- setStatus(status) {
648
- if (this._isSpanEnded())
649
- return this;
650
- this.status = status;
651
- return this;
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(endHrTime = HrTime.now()) {
660
- if (this._isSpanEnded()) {
529
+ end(endTime = HrTime.now()) {
530
+ if (this.ended) {
661
531
  return;
662
532
  }
663
- this._ended = true;
664
- this.endHrTime = endHrTime;
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(this.startHrTime);
667
- const processors = this.spanProcessorProvider.getSpanProcessors();
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
- get ended() {
692
- return this._ended;
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
- _isSpanEnded() {
695
- return this._ended;
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(spanProcessorProvider) {
787
- this.spanProcessorProvider = spanProcessorProvider;
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
- startSpan(name, options = {}, context = contextApi.active()) {
794
- if (options.root) {
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
- let traceId;
801
- let parentSpanId = null;
802
- if (!parentSpanContext) {
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
- void 0,
816
- // auto compute start time
817
- options.attributes
818
- );
673
+ processor: this.processor,
674
+ attributes
675
+ });
819
676
  return span;
820
677
  }
821
- startActiveSpan(name, arg2, arg3, arg4) {
822
- let opts;
823
- let ctx;
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
- setSpanContext(spanContext) {
847
- const ctx = contextApi.active().setValue(SPAN_KEY, new NonRecordingSpan(spanContext));
848
- return ctx;
731
+ bind(target) {
732
+ return contextApi.bind(target);
849
733
  }
850
734
  };
851
-
852
- // src/tracing/NoopTracer.ts
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 contextApi.active().getValue(SPAN_KEY);
748
+ return null;
890
749
  }
891
- setSpanContext(spanContext) {
892
- return contextApi.active().setValue(SPAN_KEY, new NonRecordingSpan(spanContext));
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/SpanProcessorProvider.ts
900
- var SpanProcessorProvider = class {
901
- processors = [];
902
- setSpanProcessors(processors) {
903
- this.processors = processors;
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
- getSpanProcessors() {
906
- return this.processors;
764
+ active() {
765
+ return this.asyncLocalStorage.getStore() ?? ROOT_CONTEXT;
907
766
  }
908
- };
909
-
910
- // src/tracing/api/traceApi.ts
911
- var TraceAPI = class _TraceAPI {
912
- static _instance;
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
- /** Get the singleton instance of the Trace API */
919
- static getInstance() {
920
- if (!this._instance) {
921
- this._instance = new _TraceAPI();
922
- }
923
- return this._instance;
773
+ enable() {
774
+ return this;
924
775
  }
925
- setTracer(tracer) {
926
- this.tracer = tracer;
776
+ disable() {
777
+ this.asyncLocalStorage.disable();
778
+ return this;
927
779
  }
928
780
  /**
929
- * Returns a tracer from the global tracer provider.
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
- getTracer() {
932
- return this.tracer;
933
- }
934
- /** Remove the global tracer provider */
935
- disable() {
936
- this.tracer = new NoopTracer();
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
- setSpanProcessors(spanProcessors) {
939
- this.spanProcessorProvider.setSpanProcessors(spanProcessors);
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
- reset() {
942
- this.spanProcessorProvider = new SpanProcessorProvider();
943
- this.tracer = new AITracer(this.spanProcessorProvider);
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
- initialized = false;
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
- init(options) {
963
- if (this.initialized) {
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
- getActiveContext() {
978
- return contextApi.active();
979
- }
980
- reset() {
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
- traceApi.disable();
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1099
1034
  }
1100
1035
 
1101
1036
  // src/context.tsx
1102
1037
  var StreamRenderContext = class _StreamRenderContext {
1103
- constructor(logImplementation, contextValues, rootTraceContext) {
1104
- this.logImplementation = logImplementation;
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(logImplementation);
1043
+ this.logger = new BoundLogger(logImpl, this);
1109
1044
  this.render = this.render.bind(this);
1110
- this.runChain = this.runChain.bind(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(element)) {
1123
- yield renderEscaped(renderLiteral(element));
1052
+ if (isLiteral(renderable)) {
1053
+ yield renderEscaped(renderLiteral(renderable));
1124
1054
  return;
1125
1055
  }
1126
- if (isAIElement(element)) {
1127
- const newCtx = self.enterElement(attachedContextValues(element) || {});
1128
- const isFragment = element.tag.name === "AIFragment";
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(element, renderedProps);
1062
+ yield renderOpenTag(renderable, renderedProps);
1132
1063
  }
1133
- yield* newCtx.renderElement(element.render(newCtx), opts);
1064
+ yield* newCtx.renderElement(renderable.render(newCtx), opts);
1134
1065
  if (preserveTags && !isFragment) {
1135
- yield renderCloseTag(element);
1066
+ yield renderCloseTag(renderable);
1136
1067
  }
1137
1068
  return;
1138
1069
  } catch (ex) {
1139
- span?.recordException(ex);
1070
+ logger.logException(ex);
1140
1071
  throw ex;
1141
1072
  }
1142
1073
  }
1143
- if (Array.isArray(element)) {
1144
- if (element.every((r) => isLiteral(r))) {
1145
- yield element.map((r) => renderEscaped(renderLiteral(r))).join("");
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 = element.filter((a) => !!a).map((r) => self.renderElement(r, opts));
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 element) {
1159
- return yield* element[Symbol.asyncIterator]();
1089
+ if (Symbol.asyncIterator in renderable) {
1090
+ return yield* renderable[Symbol.asyncIterator]();
1160
1091
  }
1161
- if (!("then" in element)) {
1092
+ if (!("then" in renderable)) {
1162
1093
  throw new Error(
1163
- `Unexpected renderable type: ${JSON.stringify(element)}`
1094
+ `Unexpected renderable type: ${JSON.stringify(renderable)}`
1164
1095
  );
1165
1096
  }
1166
- const next = await element.then(
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("ai.prompt", () => {
1180
- return this.renderPromptParsed(arg1, arg2, arg3 || {});
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("ai.prompt", () => {
1185
- return this.renderPrompt(arg1, arg2);
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("ai.chain", () => {
1190
- return this.runChain(arg1, arg2);
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("ai.chain", () => {
1195
- return this.runChain(arg1, arg2);
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
- return this.trace("ai.component", () => {
1200
- return new GeneratorRenderResult(
1201
- this.renderElement(
1202
- arg1,
1203
- arg2 || { preserveTags: false }
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 (!parsedVariables.success) {
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
- /* @__PURE__ */ jsx(Component, { ...parsedVariables.result }),
1246
- {}
1247
- );
1248
- const result = new AccumulatedRenderResult(generator, {
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 (!parsedVariables.success) {
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
- try {
1279
- const stream = this.renderElement(
1280
- /* @__PURE__ */ jsx(Component, { ...parsedVariables.result })
1281
- );
1282
- const output = await accumResults(stream);
1283
- const parsedOutput = prompt.parse(output);
1284
- if (validateOutput) {
1285
- try {
1286
- prompt.outputSchema.parse(parsedOutput);
1287
- } catch (err) {
1288
- if (err && typeof err === "object" && "flatten" in err) {
1289
- const errors = JSON.stringify(err.flatten());
1290
- throw new PromptInvalidOutputError("Invalid output: " + errors);
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 span = this.tracer.getActiveSpan();
1306
- span?.setData("chain", chain);
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 onChainComplete = (output) => {
1320
- span?.setAttributes({
1321
- output
1322
- }).end();
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
- let chainResult;
1328
- try {
1329
- chainResult = chain.run(parsedVariables.result, this);
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
- onChainComplete(chainResult);
1339
- return chainResult;
1219
+ return onOutput(result);
1340
1220
  }
1341
1221
  if (chain.chainType === "stream") {
1342
- try {
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(newCtx) {
1361
- return new _StreamRenderContext(this.logImplementation, {
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/tracing/AsyncLocalStorageContextManager.ts
1449
- import { AsyncLocalStorage } from "async_hooks";
1450
- var isAsyncGenerator = (obj) => obj != null && typeof obj === "object" && "next" in obj && "return" in obj && "throw" in obj && Symbol.asyncIterator in obj;
1451
- var AsyncLocalStorageContextManager = class {
1452
- asyncLocalStorage;
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
- active() {
1457
- return this.asyncLocalStorage.getStore() ?? ROOT_CONTEXT;
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
- with(context, fn, ...args) {
1460
- return this.asyncLocalStorage.run(context, () => {
1461
- const result = fn(...args);
1462
- return result;
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
- enable() {
1466
- return this;
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
- disable() {
1469
- this.asyncLocalStorage.disable();
1470
- return this;
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
- * Binds a the certain context or the active one to the target function and then returns the target
1474
- * @param context A context (span) to be bind to target
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
- if (isAsyncGenerator(target)) {
1483
- return this.bindAsyncGenerator(target);
1404
+ const tokensUsed = span.attributes.tokensUsed;
1405
+ if (!tokensUsed || tokensUsed.total == null || tokensUsed.completion == null || tokensUsed.prompt == null) {
1406
+ return span;
1484
1407
  }
1485
- return target;
1408
+ this.totalUsage.prompt += tokensUsed.prompt;
1409
+ this.totalUsage.completion += tokensUsed.completion;
1410
+ this.totalUsage.total += tokensUsed.total;
1411
+ return span;
1486
1412
  }
1487
- bindFunction(context, target) {
1488
- const manager = this;
1489
- const contextWrapper = function(...args) {
1490
- return manager.with(context, () => target.apply(this, args));
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
- Object.defineProperty(contextWrapper, "length", {
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/index.ts
1507
- var aijsxTracing;
1508
- ((aijsxTracing2) => {
1509
- aijsxTracing2.api = tracing;
1510
- aijsxTracing2.AsyncLocalStorageContextManager = AsyncLocalStorageContextManager;
1511
- })(aijsxTracing || (aijsxTracing = {}));
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
- defaultClient = new OpenAIClient({ apiKey });
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 chatMessageTags2 = ["UserMessage", "AssistantMessage", "SystemMessage"];
1718
- const parsed = parseXml(childrenXml).collapse(chatMessageTags2);
1659
+ const chatMessageTags = ["UserMessage", "AssistantMessage", "SystemMessage"];
1660
+ const parsed = parseXml(childrenXml).collapse(chatMessageTags);
1719
1661
  const topLevelValid = parsed.childNodes.every(
1720
- (node) => chatMessageTags2.includes(node.nodeName)
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
- async function* OpenAIChatCompletion(props, { render, logger, getContext }) {
1746
- const span = tracing.getTracer().startSpan("ai.chatCompletion");
1747
- const requestId = uuid.requestId();
1748
- const perfStart = performance.now();
1749
- const startTime = (/* @__PURE__ */ new Date()).toISOString();
1750
- span.setAttributes({
1751
- requestId,
1752
- model: props.model,
1753
- provider: props.provider,
1754
- providerRegion: props.providerRegion
1755
- });
1756
- const client = getContext(OpenAIClientContext)();
1757
- if (!client) {
1758
- throw new Error("[OpenAI] must supply OpenAI model via context");
1759
- }
1760
- const openAIMessages = buildOpenAIMessages(
1761
- await render(props.children, {
1762
- preserveTags: true
1763
- })
1764
- );
1765
- const renderedMessages = openAIMessages.map((message) => {
1766
- return {
1767
- role: message.role,
1768
- content: renderChatMessageContent(message.content),
1769
- tokens: tokenCountForOpenAIMessage(message)
1770
- };
1771
- });
1772
- const chatCompletionRequest = {
1773
- model: props.model,
1774
- max_tokens: props.maxTokens,
1775
- temperature: props.temperature,
1776
- messages: openAIMessages,
1777
- response_format: props.responseFormat ? {
1778
- type: props.responseFormat
1779
- } : void 0,
1780
- stream: true
1781
- };
1782
- const logRequestData = {
1783
- requestId,
1784
- startTime,
1785
- model: props.model,
1786
- provider: props.provider,
1787
- providerRegion: props.providerRegion,
1788
- inputMessages: renderedMessages,
1789
- request: chatCompletionRequest
1790
- };
1791
- logger.chatCompletionRequest("openai", logRequestData);
1792
- span.setAttributes({
1793
- inputMessages: renderedMessages,
1794
- request: chatCompletionRequest
1795
- });
1796
- let chatResponse;
1797
- try {
1798
- chatResponse = await client.chat.completions.create(chatCompletionRequest);
1799
- } catch (ex) {
1800
- const error = ex instanceof OpenAIClient.APIError ? new ChatCompletionError(
1801
- `OpenAIClient.APIError: ${ex.message}`,
1802
- span.attributes
1803
- ) : new ChatCompletionError(ex.message, span.attributes);
1804
- span.recordException(error).end();
1805
- throw error;
1806
- }
1807
- let finishReason = void 0;
1808
- let content = "";
1809
- for await (const message of chatResponse) {
1810
- if (!message.choices || !message.choices[0]) {
1811
- continue;
1812
- }
1813
- const delta = message.choices[0].delta;
1814
- if (message.choices[0].finish_reason) {
1815
- finishReason = message.choices[0].finish_reason;
1816
- }
1817
- if (delta.content) {
1818
- content += delta.content;
1819
- yield delta.content;
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 chatMessageTags2 = [
1802
+ const chatMessageTags = [
1855
1803
  "UserMessage",
1856
1804
  "AssistantMessage",
1857
1805
  "SystemMessage",
1858
1806
  "ContentTypeImage"
1859
1807
  ];
1860
- const parsed = parseXml(childrenXml).collapse(chatMessageTags2);
1808
+ const parsed = parseXml(childrenXml).collapse(chatMessageTags);
1861
1809
  const topLevelValid = parsed.childNodes.every(
1862
- (node) => chatMessageTags2.includes(node.nodeName)
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
- async function* OpenAIVisionChatCompletion(props, { render, getContext, logger }) {
1910
- const span = tracing.getTracer().startSpan("ai.chatCompletion");
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
- span.setAttributes({
1916
- requestId,
1917
- model,
1918
- provider: props.provider,
1919
- providerRegion: props.providerRegion
1920
- });
1921
- const client = getContext(OpenAIClientContext)();
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
- const renderedMessages = openAIMessages.map((message) => {
1938
- if (message.role === "user") {
1939
- if (typeof message.content === "string") {
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
- const BASE_COST = 85;
1947
- const tokens = message.content.reduce((acc, part) => {
1948
- if (part.type === "text") {
1949
- return acc + tokenCountForOpenAIMessage({
1950
- role: message.role,
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 detail = part.image_url.detail || "auto";
1955
- if (detail === "low") {
1956
- return acc + BASE_COST;
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
- }, 0);
1970
- return {
1971
- role: message.role,
1972
- content: renderChatMessageContent(message.content),
1973
- tokens
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
- return {
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
- var chatMessageTags = ["UserMessage", "AssistantMessage", "SystemMessage"];
2073
- function buildChatMessages(childrenXml) {
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
- const content = `${AnthropicClient.HUMAN_PROMPT} ${node.textContent}`;
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
- role: "user",
2087
- content,
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
- role: "assistant",
2094
- content,
2095
- tokens: countTokens(content)
2080
+ content: node.textContent,
2081
+ role: "assistant"
2096
2082
  });
2097
2083
  } else if (node.nodeName === "SystemMessage") {
2098
- const userContent = `${AnthropicClient.HUMAN_PROMPT} For subsequent replies you will adhere to the following instructions: ${node.textContent}`;
2099
- messages.push({
2100
- role: "user",
2101
- content: userContent,
2102
- tokens: countTokens(userContent)
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
- const assistantContent = `${AnthropicClient.AI_PROMPT} Okay, I will do that.`;
2105
- messages.push({
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: assistantContent,
2108
- tokens: countTokens(assistantContent)
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
- const prompt = [
2137
- ...inputMessages.map((message) => message.content),
2138
- AnthropicClient.AI_PROMPT
2139
- ].join("");
2140
- const anthropicCompletionRequest = {
2141
- prompt,
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
- logger.chatCompletionRequest("anthropic", logRequestData);
2157
- span.setAttributes({
2158
- inputMessages,
2159
- request: anthropicCompletionRequest
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
- let response;
2162
- try {
2163
- response = await client.completions.create(anthropicCompletionRequest);
2164
- } catch (ex) {
2165
- const error = ex instanceof AnthropicClient.APIError ? new ChatCompletionError(
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
- let content = "";
2173
- let isFirstResponse = true;
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
- const outputMessage = {
2186
- role: "assistant",
2187
- content,
2188
- tokens: countTokens(content)
2189
- };
2190
- const responseData = {
2191
- ...logRequestData,
2192
- endTime: (/* @__PURE__ */ new Date()).toISOString(),
2193
- finishReason: "stop",
2194
- latency: performance.now() - perfStart,
2195
- outputMessage,
2196
- tokensUsed: computeUsage([...inputMessages, outputMessage])
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
  };