braintrust 3.28.0 → 3.30.0
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 +1 -1
- package/dev/dist/index.d.mts +356 -7
- package/dev/dist/index.d.ts +356 -7
- package/dev/dist/index.js +2679 -1828
- package/dev/dist/index.mjs +1862 -1011
- package/dist/apply-auto-instrumentation.js +298 -265
- package/dist/apply-auto-instrumentation.mjs +85 -52
- package/dist/auto-instrumentations/bundler/esbuild.cjs +56 -6
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/next.cjs +56 -6
- package/dist/auto-instrumentations/bundler/next.mjs +3 -3
- package/dist/auto-instrumentations/bundler/rollup.cjs +56 -6
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +56 -6
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +56 -6
- package/dist/auto-instrumentations/bundler/webpack.cjs +56 -6
- package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
- package/dist/auto-instrumentations/{chunk-26PKVUKB.mjs → chunk-LW4HDHXT.mjs} +12 -4
- package/dist/auto-instrumentations/{chunk-HD35AM3M.mjs → chunk-OXINGIEZ.mjs} +1 -1
- package/dist/auto-instrumentations/{chunk-NP7V4XB2.mjs → chunk-U64OYU4Q.mjs} +45 -3
- package/dist/auto-instrumentations/hook.mjs +967 -136
- package/dist/auto-instrumentations/index.cjs +45 -3
- package/dist/auto-instrumentations/index.mjs +1 -1
- package/dist/browser.d.mts +893 -24
- package/dist/browser.d.ts +893 -24
- package/dist/browser.js +2795 -1136
- package/dist/browser.mjs +2795 -1136
- package/dist/{chunk-BBE7SNRV.js → chunk-2XDW3UCG.js} +155 -23
- package/dist/{chunk-UPFNQCGB.mjs → chunk-BU6SM54N.mjs} +1830 -1045
- package/dist/{chunk-ZHUHZWFY.mjs → chunk-N3JKQ3D3.mjs} +152 -20
- package/dist/{chunk-OBBWQW6K.js → chunk-TWCDSYJN.js} +2890 -2105
- package/dist/cli.js +5976 -1348
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +2795 -1136
- package/dist/edge-light.mjs +2795 -1136
- package/dist/index.d.mts +893 -24
- package/dist/index.d.ts +893 -24
- package/dist/index.js +1448 -699
- package/dist/index.mjs +848 -99
- package/dist/instrumentation/index.d.mts +563 -9
- package/dist/instrumentation/index.d.ts +563 -9
- package/dist/instrumentation/index.js +2794 -989
- package/dist/instrumentation/index.mjs +2794 -989
- package/dist/vitest-evals-reporter.js +16 -16
- package/dist/vitest-evals-reporter.mjs +2 -2
- package/dist/workerd.d.mts +1 -1
- package/dist/workerd.d.ts +1 -1
- package/dist/workerd.js +2795 -1136
- package/dist/workerd.mjs +2795 -1136
- package/package.json +1 -1
- package/util/dist/index.d.mts +42 -0
- package/util/dist/index.d.ts +42 -0
|
@@ -699,8 +699,6 @@ function newGlobalTracingChannel(nameOrChannels) {
|
|
|
699
699
|
var DefaultAsyncLocalStorage = class {
|
|
700
700
|
constructor() {
|
|
701
701
|
}
|
|
702
|
-
enterWith(_) {
|
|
703
|
-
}
|
|
704
702
|
run(_, callback) {
|
|
705
703
|
return callback();
|
|
706
704
|
}
|
|
@@ -2622,7 +2620,9 @@ var AclObjectType = import_v36.z.union([
|
|
|
2622
2620
|
"project_log",
|
|
2623
2621
|
"org_project",
|
|
2624
2622
|
"org_audit_logs",
|
|
2625
|
-
"project_group"
|
|
2623
|
+
"project_group",
|
|
2624
|
+
"ai_secret",
|
|
2625
|
+
"org_ai_secret"
|
|
2626
2626
|
]),
|
|
2627
2627
|
import_v36.z.null()
|
|
2628
2628
|
]);
|
|
@@ -3455,7 +3455,7 @@ var PromptParserNullish = import_v36.z.union([
|
|
|
3455
3455
|
}),
|
|
3456
3456
|
import_v36.z.null()
|
|
3457
3457
|
]);
|
|
3458
|
-
var
|
|
3458
|
+
var PreprocessorId = import_v36.z.union([
|
|
3459
3459
|
import_v36.z.object({
|
|
3460
3460
|
type: import_v36.z.literal("function"),
|
|
3461
3461
|
id: import_v36.z.string(),
|
|
@@ -3466,6 +3466,7 @@ var PreprocessorSavedFunctionId = import_v36.z.union([
|
|
|
3466
3466
|
name: import_v36.z.string(),
|
|
3467
3467
|
function_type: import_v36.z.literal("preprocessor").optional().default("preprocessor")
|
|
3468
3468
|
}),
|
|
3469
|
+
import_v36.z.object({ type: import_v36.z.literal("inline"), code: import_v36.z.string().min(1) }),
|
|
3469
3470
|
import_v36.z.null()
|
|
3470
3471
|
]);
|
|
3471
3472
|
var PromptDataNullish = import_v36.z.union([
|
|
@@ -3473,7 +3474,7 @@ var PromptDataNullish = import_v36.z.union([
|
|
|
3473
3474
|
prompt: PromptBlockDataNullish,
|
|
3474
3475
|
options: PromptOptionsNullish,
|
|
3475
3476
|
parser: PromptParserNullish,
|
|
3476
|
-
preprocessor:
|
|
3477
|
+
preprocessor: PreprocessorId,
|
|
3477
3478
|
tool_functions: import_v36.z.union([import_v36.z.array(SavedFunctionId), import_v36.z.null()]),
|
|
3478
3479
|
template_format: import_v36.z.union([
|
|
3479
3480
|
import_v36.z.enum(["mustache", "nunjucks", "none"]),
|
|
@@ -3675,7 +3676,7 @@ var PromptData = import_v36.z.object({
|
|
|
3675
3676
|
prompt: PromptBlockDataNullish,
|
|
3676
3677
|
options: PromptOptionsNullish,
|
|
3677
3678
|
parser: PromptParserNullish,
|
|
3678
|
-
preprocessor:
|
|
3679
|
+
preprocessor: PreprocessorId,
|
|
3679
3680
|
tool_functions: import_v36.z.union([import_v36.z.array(SavedFunctionId), import_v36.z.null()]),
|
|
3680
3681
|
template_format: import_v36.z.union([
|
|
3681
3682
|
import_v36.z.enum(["mustache", "nunjucks", "none"]),
|
|
@@ -4619,6 +4620,7 @@ var View = import_v36.z.object({
|
|
|
4619
4620
|
]),
|
|
4620
4621
|
name: import_v36.z.string(),
|
|
4621
4622
|
description: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
|
|
4623
|
+
starred: import_v36.z.boolean().optional(),
|
|
4622
4624
|
created: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
|
|
4623
4625
|
updated_at: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
|
|
4624
4626
|
view_data: ViewData.optional(),
|
|
@@ -4708,6 +4710,34 @@ var registerTemplatePlugin = templateRegistry.register.bind(templateRegistry);
|
|
|
4708
4710
|
var getTemplateRenderer = templateRegistry.get.bind(templateRegistry);
|
|
4709
4711
|
registerTemplatePlugin(mustachePlugin);
|
|
4710
4712
|
|
|
4713
|
+
// src/template/renderer.ts
|
|
4714
|
+
function isTemplateFormat(v) {
|
|
4715
|
+
return v === "mustache" || v === "nunjucks" || v === "none";
|
|
4716
|
+
}
|
|
4717
|
+
function parseTemplateFormat(value, defaultFormat = "mustache") {
|
|
4718
|
+
return isTemplateFormat(value) ? value : defaultFormat;
|
|
4719
|
+
}
|
|
4720
|
+
function renderTemplateContent(template, variables, escape, options) {
|
|
4721
|
+
const strict = !!options.strict;
|
|
4722
|
+
const templateFormat = parseTemplateFormat(options.templateFormat);
|
|
4723
|
+
if (templateFormat === "none") {
|
|
4724
|
+
return template;
|
|
4725
|
+
}
|
|
4726
|
+
const renderer = getTemplateRenderer(templateFormat);
|
|
4727
|
+
if (!renderer) {
|
|
4728
|
+
if (templateFormat === "nunjucks") {
|
|
4729
|
+
throw new Error(
|
|
4730
|
+
"Nunjucks templating requires @braintrust/template-nunjucks. Install and import it to enable templateFormat: 'nunjucks'."
|
|
4731
|
+
);
|
|
4732
|
+
}
|
|
4733
|
+
throw new Error(`No template renderer registered for ${templateFormat}`);
|
|
4734
|
+
}
|
|
4735
|
+
if (strict && renderer.lint) {
|
|
4736
|
+
renderer.lint(template, variables);
|
|
4737
|
+
}
|
|
4738
|
+
return renderer.render(template, variables, escape, strict);
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4711
4741
|
// src/logger.ts
|
|
4712
4742
|
var import_v38 = require("zod/v3");
|
|
4713
4743
|
|
|
@@ -5292,44 +5322,72 @@ function createCacheLayers({
|
|
|
5292
5322
|
}
|
|
5293
5323
|
|
|
5294
5324
|
// src/prompt-cache/prompt-cache.ts
|
|
5295
|
-
function createCacheKey(key) {
|
|
5325
|
+
function createCacheKey(key, namespace) {
|
|
5326
|
+
let cacheKey;
|
|
5296
5327
|
if (key.id) {
|
|
5297
|
-
|
|
5298
|
-
}
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5328
|
+
cacheKey = `id:${key.id}`;
|
|
5329
|
+
} else {
|
|
5330
|
+
const prefix = key.projectId ?? key.projectName;
|
|
5331
|
+
if (!prefix) {
|
|
5332
|
+
throw new Error("Either projectId or projectName must be provided");
|
|
5333
|
+
}
|
|
5334
|
+
if (!key.slug) {
|
|
5335
|
+
throw new Error("Slug must be provided when not using ID");
|
|
5336
|
+
}
|
|
5337
|
+
cacheKey = `${prefix}:${key.slug}:${key.version ?? "latest"}`;
|
|
5305
5338
|
}
|
|
5306
|
-
return `${
|
|
5339
|
+
return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
|
|
5307
5340
|
}
|
|
5308
|
-
var PromptCache = class {
|
|
5341
|
+
var PromptCache = class _PromptCache {
|
|
5309
5342
|
memoryCache;
|
|
5310
5343
|
diskCache;
|
|
5344
|
+
namespace;
|
|
5345
|
+
expectedResolvedOrgIdentity;
|
|
5311
5346
|
constructor(options) {
|
|
5312
5347
|
this.memoryCache = options.memoryCache;
|
|
5313
5348
|
this.diskCache = options.diskCache;
|
|
5349
|
+
this.namespace = options.namespace;
|
|
5350
|
+
this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
|
|
5351
|
+
}
|
|
5352
|
+
/**
|
|
5353
|
+
* Returns a cache view that shares the same storage layers but isolates all
|
|
5354
|
+
* entries under the provided namespace.
|
|
5355
|
+
*/
|
|
5356
|
+
withNamespace(namespace, expectedResolvedOrgIdentity) {
|
|
5357
|
+
return new _PromptCache({
|
|
5358
|
+
memoryCache: this.memoryCache,
|
|
5359
|
+
diskCache: this.diskCache,
|
|
5360
|
+
namespace,
|
|
5361
|
+
expectedResolvedOrgIdentity
|
|
5362
|
+
});
|
|
5314
5363
|
}
|
|
5315
5364
|
/**
|
|
5316
5365
|
* Retrieves a prompt from the cache.
|
|
5317
5366
|
* First checks the in-memory LRU cache, then falls back to checking the disk cache if available.
|
|
5318
5367
|
*/
|
|
5319
5368
|
async get(key) {
|
|
5320
|
-
const cacheKey = createCacheKey(key);
|
|
5369
|
+
const cacheKey = createCacheKey(key, this.namespace);
|
|
5321
5370
|
if (this.memoryCache) {
|
|
5322
|
-
const
|
|
5323
|
-
if (
|
|
5324
|
-
return
|
|
5371
|
+
const memoryEntry = this.memoryCache.get(cacheKey);
|
|
5372
|
+
if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
|
|
5373
|
+
return memoryEntry.value;
|
|
5325
5374
|
}
|
|
5326
5375
|
}
|
|
5327
5376
|
if (this.diskCache) {
|
|
5328
|
-
const
|
|
5329
|
-
if (!
|
|
5377
|
+
const diskEntry = await this.diskCache.get(cacheKey);
|
|
5378
|
+
if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
|
|
5330
5379
|
return void 0;
|
|
5331
5380
|
}
|
|
5332
|
-
|
|
5381
|
+
const serializedPrompt = diskEntry.value;
|
|
5382
|
+
const diskPrompt = new Prompt2(
|
|
5383
|
+
serializedPrompt.metadata,
|
|
5384
|
+
serializedPrompt.defaults,
|
|
5385
|
+
serializedPrompt.noTrace
|
|
5386
|
+
);
|
|
5387
|
+
this.memoryCache?.set(cacheKey, {
|
|
5388
|
+
value: diskPrompt,
|
|
5389
|
+
resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
|
|
5390
|
+
});
|
|
5333
5391
|
return diskPrompt;
|
|
5334
5392
|
}
|
|
5335
5393
|
return void 0;
|
|
@@ -5343,58 +5401,91 @@ var PromptCache = class {
|
|
|
5343
5401
|
* @throws If there is an error writing to the disk cache.
|
|
5344
5402
|
*/
|
|
5345
5403
|
async set(key, value) {
|
|
5346
|
-
const cacheKey = createCacheKey(key);
|
|
5347
|
-
|
|
5404
|
+
const cacheKey = createCacheKey(key, this.namespace);
|
|
5405
|
+
const memoryEntry = {
|
|
5406
|
+
value,
|
|
5407
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5408
|
+
};
|
|
5409
|
+
this.memoryCache?.set(cacheKey, memoryEntry);
|
|
5348
5410
|
if (this.diskCache) {
|
|
5349
|
-
await this.diskCache.set(cacheKey,
|
|
5411
|
+
await this.diskCache.set(cacheKey, {
|
|
5412
|
+
value: value._internalSerializeForCache(),
|
|
5413
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5414
|
+
});
|
|
5350
5415
|
}
|
|
5351
5416
|
}
|
|
5352
5417
|
};
|
|
5353
5418
|
|
|
5354
5419
|
// src/prompt-cache/parameters-cache.ts
|
|
5355
|
-
function createCacheKey2(key) {
|
|
5420
|
+
function createCacheKey2(key, namespace) {
|
|
5421
|
+
let cacheKey;
|
|
5356
5422
|
if (key.id) {
|
|
5357
|
-
|
|
5358
|
-
}
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5423
|
+
cacheKey = `parameters:id:${key.id}`;
|
|
5424
|
+
} else {
|
|
5425
|
+
const prefix = key.projectId ?? key.projectName;
|
|
5426
|
+
if (!prefix) {
|
|
5427
|
+
throw new Error("Either projectId or projectName must be provided");
|
|
5428
|
+
}
|
|
5429
|
+
if (!key.slug) {
|
|
5430
|
+
throw new Error("Slug must be provided when not using ID");
|
|
5431
|
+
}
|
|
5432
|
+
cacheKey = `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
|
|
5365
5433
|
}
|
|
5366
|
-
return
|
|
5434
|
+
return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
|
|
5367
5435
|
}
|
|
5368
|
-
var ParametersCache = class {
|
|
5436
|
+
var ParametersCache = class _ParametersCache {
|
|
5369
5437
|
memoryCache;
|
|
5370
5438
|
diskCache;
|
|
5439
|
+
namespace;
|
|
5440
|
+
expectedResolvedOrgIdentity;
|
|
5371
5441
|
constructor(options) {
|
|
5372
5442
|
this.memoryCache = options.memoryCache;
|
|
5373
5443
|
this.diskCache = options.diskCache;
|
|
5444
|
+
this.namespace = options.namespace;
|
|
5445
|
+
this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
|
|
5446
|
+
}
|
|
5447
|
+
withNamespace(namespace, expectedResolvedOrgIdentity) {
|
|
5448
|
+
return new _ParametersCache({
|
|
5449
|
+
memoryCache: this.memoryCache,
|
|
5450
|
+
diskCache: this.diskCache,
|
|
5451
|
+
namespace,
|
|
5452
|
+
expectedResolvedOrgIdentity
|
|
5453
|
+
});
|
|
5374
5454
|
}
|
|
5375
5455
|
async get(key) {
|
|
5376
|
-
const cacheKey = createCacheKey2(key);
|
|
5456
|
+
const cacheKey = createCacheKey2(key, this.namespace);
|
|
5377
5457
|
if (this.memoryCache) {
|
|
5378
|
-
const
|
|
5379
|
-
if (
|
|
5380
|
-
return
|
|
5458
|
+
const memoryEntry = this.memoryCache.get(cacheKey);
|
|
5459
|
+
if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
|
|
5460
|
+
return memoryEntry.value;
|
|
5381
5461
|
}
|
|
5382
5462
|
}
|
|
5383
5463
|
if (this.diskCache) {
|
|
5384
|
-
const
|
|
5385
|
-
if (!
|
|
5464
|
+
const diskEntry = await this.diskCache.get(cacheKey);
|
|
5465
|
+
if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
|
|
5386
5466
|
return void 0;
|
|
5387
5467
|
}
|
|
5388
|
-
|
|
5389
|
-
|
|
5468
|
+
const diskParameters = new RemoteEvalParameters(diskEntry.value.metadata);
|
|
5469
|
+
this.memoryCache?.set(cacheKey, {
|
|
5470
|
+
value: diskParameters,
|
|
5471
|
+
resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
|
|
5472
|
+
});
|
|
5473
|
+
return diskParameters;
|
|
5390
5474
|
}
|
|
5391
5475
|
return void 0;
|
|
5392
5476
|
}
|
|
5393
5477
|
async set(key, value) {
|
|
5394
|
-
const cacheKey = createCacheKey2(key);
|
|
5395
|
-
|
|
5478
|
+
const cacheKey = createCacheKey2(key, this.namespace);
|
|
5479
|
+
const memoryEntry = {
|
|
5480
|
+
value,
|
|
5481
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5482
|
+
};
|
|
5483
|
+
this.memoryCache?.set(cacheKey, memoryEntry);
|
|
5396
5484
|
if (this.diskCache) {
|
|
5397
|
-
await this.diskCache.set(cacheKey,
|
|
5485
|
+
await this.diskCache.set(cacheKey, {
|
|
5486
|
+
value: value._internalSerializeForCache(),
|
|
5487
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5488
|
+
});
|
|
5398
5489
|
}
|
|
5399
5490
|
}
|
|
5400
5491
|
};
|
|
@@ -5698,6 +5789,7 @@ var INSTRUMENTATION_NAMES = {
|
|
|
5698
5789
|
CLOUDFLARE_THINK: "cloudflare-think",
|
|
5699
5790
|
COHERE: "cohere",
|
|
5700
5791
|
CURSOR_SDK: "cursor-sdk",
|
|
5792
|
+
DEEPSEEK_HARNESS: "deepseek-harness",
|
|
5701
5793
|
EVE: "eve",
|
|
5702
5794
|
FLUE: "flue",
|
|
5703
5795
|
GENKIT: "genkit",
|
|
@@ -5723,7 +5815,7 @@ var INSTRUMENTATION_NAMES = {
|
|
|
5723
5815
|
var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
|
|
5724
5816
|
"braintrust.spanInstrumentationName"
|
|
5725
5817
|
);
|
|
5726
|
-
var SDK_VERSION = true ? "3.
|
|
5818
|
+
var SDK_VERSION = true ? "3.30.0" : "0.0.0";
|
|
5727
5819
|
function withSpanInstrumentationName(args, instrumentationName) {
|
|
5728
5820
|
return {
|
|
5729
5821
|
...args,
|
|
@@ -5842,6 +5934,16 @@ var datasetSnapshotRegisterResponseSchema = import_v38.z.object({
|
|
|
5842
5934
|
dataset_snapshot: DatasetSnapshot,
|
|
5843
5935
|
found_existing: import_v38.z.boolean().optional()
|
|
5844
5936
|
});
|
|
5937
|
+
var datasetObjectInfoSchema = import_v38.z.object({
|
|
5938
|
+
object_id: import_v38.z.string(),
|
|
5939
|
+
object_name: import_v38.z.string(),
|
|
5940
|
+
parent_cols: import_v38.z.object({
|
|
5941
|
+
project: import_v38.z.object({
|
|
5942
|
+
id: import_v38.z.string(),
|
|
5943
|
+
name: import_v38.z.string()
|
|
5944
|
+
})
|
|
5945
|
+
})
|
|
5946
|
+
});
|
|
5845
5947
|
var datasetRestorePreviewResultSchema = import_v38.z.object({
|
|
5846
5948
|
rows_to_restore: import_v38.z.number(),
|
|
5847
5949
|
rows_to_delete: import_v38.z.number()
|
|
@@ -6055,12 +6157,53 @@ var loginSchema = import_v38.z.strictObject({
|
|
|
6055
6157
|
});
|
|
6056
6158
|
var stateNonce = 0;
|
|
6057
6159
|
var V1_PROXY_SUFFIX = "/v1/proxy";
|
|
6160
|
+
var LOADER_LOGIN_CACHE_MAX = 16;
|
|
6058
6161
|
function normalizeProxyConnUrl(proxyUrl) {
|
|
6059
6162
|
return proxyUrl.endsWith(V1_PROXY_SUFFIX) ? proxyUrl.slice(0, proxyUrl.length - V1_PROXY_SUFFIX.length) : proxyUrl;
|
|
6060
6163
|
}
|
|
6061
6164
|
var BraintrustState = class _BraintrustState {
|
|
6165
|
+
id;
|
|
6166
|
+
currentExperiment;
|
|
6167
|
+
// Note: the value of IsAsyncFlush doesn't really matter here, since we
|
|
6168
|
+
// (safely) dynamically cast it whenever retrieving the logger.
|
|
6169
|
+
currentLogger;
|
|
6170
|
+
currentParent;
|
|
6171
|
+
currentSpan;
|
|
6172
|
+
// Any time we re-log in, we directly update the apiConn inside the logger.
|
|
6173
|
+
// This is preferable to replacing the whole logger, which would create the
|
|
6174
|
+
// possibility of multiple loggers floating around, which may not log in a
|
|
6175
|
+
// deterministic order.
|
|
6176
|
+
_bgLogger;
|
|
6177
|
+
_overrideBgLogger = null;
|
|
6178
|
+
appUrl = null;
|
|
6179
|
+
appPublicUrl = null;
|
|
6180
|
+
loginToken = null;
|
|
6181
|
+
orgId = null;
|
|
6182
|
+
orgName = null;
|
|
6183
|
+
apiUrl = null;
|
|
6184
|
+
proxyUrl = null;
|
|
6185
|
+
loggedIn = false;
|
|
6186
|
+
gitMetadataSettings;
|
|
6187
|
+
debugLogLevel;
|
|
6188
|
+
debugLogLevelConfigured = false;
|
|
6189
|
+
fetch = globalThis.fetch;
|
|
6190
|
+
_appConn = null;
|
|
6191
|
+
_apiConn = null;
|
|
6192
|
+
_proxyConn = null;
|
|
6193
|
+
promptCache;
|
|
6194
|
+
parametersCache;
|
|
6195
|
+
spanCache;
|
|
6196
|
+
_idGenerator = null;
|
|
6197
|
+
_contextManager = null;
|
|
6198
|
+
_otelFlushCallback = null;
|
|
6199
|
+
spanOriginEnvironment;
|
|
6200
|
+
traceContextSigningSecret;
|
|
6201
|
+
loaderLoginCache = /* @__PURE__ */ new WeakMap();
|
|
6202
|
+
loginParams;
|
|
6203
|
+
activeLoginOrgNameSelector;
|
|
6062
6204
|
constructor(loginParams) {
|
|
6063
|
-
this.loginParams = loginParams;
|
|
6205
|
+
this.loginParams = { ...loginParams };
|
|
6206
|
+
this.activeLoginOrgNameSelector = loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
|
|
6064
6207
|
this.id = `${(/* @__PURE__ */ new Date()).toLocaleString()}-${stateNonce++}`;
|
|
6065
6208
|
this.currentExperiment = void 0;
|
|
6066
6209
|
this.currentLogger = void 0;
|
|
@@ -6097,12 +6240,14 @@ var BraintrustState = class _BraintrustState {
|
|
|
6097
6240
|
const {
|
|
6098
6241
|
memoryCache: parametersMemoryCache,
|
|
6099
6242
|
diskCache: parametersDiskCache
|
|
6100
|
-
} = createCacheLayers(
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6243
|
+
} = createCacheLayers(
|
|
6244
|
+
{
|
|
6245
|
+
memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
|
|
6246
|
+
diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
|
|
6247
|
+
diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
|
|
6248
|
+
getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
|
|
6249
|
+
}
|
|
6250
|
+
);
|
|
6106
6251
|
this.parametersCache = new ParametersCache({
|
|
6107
6252
|
memoryCache: parametersMemoryCache,
|
|
6108
6253
|
diskCache: parametersDiskCache
|
|
@@ -6111,43 +6256,6 @@ var BraintrustState = class _BraintrustState {
|
|
|
6111
6256
|
this.spanOriginEnvironment = detectSpanOriginEnvironment();
|
|
6112
6257
|
this._internalSetTraceContextSigningSecret(loginParams.apiKey);
|
|
6113
6258
|
}
|
|
6114
|
-
loginParams;
|
|
6115
|
-
id;
|
|
6116
|
-
currentExperiment;
|
|
6117
|
-
// Note: the value of IsAsyncFlush doesn't really matter here, since we
|
|
6118
|
-
// (safely) dynamically cast it whenever retrieving the logger.
|
|
6119
|
-
currentLogger;
|
|
6120
|
-
currentParent;
|
|
6121
|
-
currentSpan;
|
|
6122
|
-
// Any time we re-log in, we directly update the apiConn inside the logger.
|
|
6123
|
-
// This is preferable to replacing the whole logger, which would create the
|
|
6124
|
-
// possibility of multiple loggers floating around, which may not log in a
|
|
6125
|
-
// deterministic order.
|
|
6126
|
-
_bgLogger;
|
|
6127
|
-
_overrideBgLogger = null;
|
|
6128
|
-
appUrl = null;
|
|
6129
|
-
appPublicUrl = null;
|
|
6130
|
-
loginToken = null;
|
|
6131
|
-
orgId = null;
|
|
6132
|
-
orgName = null;
|
|
6133
|
-
apiUrl = null;
|
|
6134
|
-
proxyUrl = null;
|
|
6135
|
-
loggedIn = false;
|
|
6136
|
-
gitMetadataSettings;
|
|
6137
|
-
debugLogLevel;
|
|
6138
|
-
debugLogLevelConfigured = false;
|
|
6139
|
-
fetch = globalThis.fetch;
|
|
6140
|
-
_appConn = null;
|
|
6141
|
-
_apiConn = null;
|
|
6142
|
-
_proxyConn = null;
|
|
6143
|
-
promptCache;
|
|
6144
|
-
parametersCache;
|
|
6145
|
-
spanCache;
|
|
6146
|
-
_idGenerator = null;
|
|
6147
|
-
_contextManager = null;
|
|
6148
|
-
_otelFlushCallback = null;
|
|
6149
|
-
spanOriginEnvironment;
|
|
6150
|
-
traceContextSigningSecret;
|
|
6151
6259
|
/** @internal */
|
|
6152
6260
|
_internalSetTraceContextSigningSecret(secret) {
|
|
6153
6261
|
const normalizedSecret = secret?.trim();
|
|
@@ -6172,6 +6280,101 @@ var BraintrustState = class _BraintrustState {
|
|
|
6172
6280
|
this._appConn = null;
|
|
6173
6281
|
this._apiConn = null;
|
|
6174
6282
|
this._proxyConn = null;
|
|
6283
|
+
this.loaderLoginCache = /* @__PURE__ */ new WeakMap();
|
|
6284
|
+
}
|
|
6285
|
+
/** @internal */
|
|
6286
|
+
async _internalResolveLoaderLoginOptions({
|
|
6287
|
+
apiKey,
|
|
6288
|
+
appUrl,
|
|
6289
|
+
orgName,
|
|
6290
|
+
fetch: fetch2,
|
|
6291
|
+
forceLogin
|
|
6292
|
+
}) {
|
|
6293
|
+
const resolvedAppUrl = appUrl ?? (this.loggedIn ? this.appUrl ?? void 0 : void 0) ?? this.loginParams.appUrl ?? isomorph_default.getEnv("BRAINTRUST_APP_URL") ?? "https://www.braintrust.dev";
|
|
6294
|
+
const resolvedApiKey = apiKey ?? (this.loggedIn ? this.loginToken ?? void 0 : void 0) ?? this.loginParams.apiKey ?? await isomorph_default.getBraintrustApiKey();
|
|
6295
|
+
if (!resolvedApiKey) {
|
|
6296
|
+
throw new Error(
|
|
6297
|
+
"Please specify an api key (e.g. by setting BRAINTRUST_API_KEY)."
|
|
6298
|
+
);
|
|
6299
|
+
}
|
|
6300
|
+
const normalizedApiKey = HTTPConnection.sanitize_token(resolvedApiKey);
|
|
6301
|
+
const usesActiveCredential = this.loggedIn && normalizedApiKey === this.loginToken;
|
|
6302
|
+
const requestedOrgName = orgName ?? (usesActiveCredential ? this.activeLoginOrgNameSelector : void 0) ?? this.loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
|
|
6303
|
+
const resolvedOrgName = orgName ?? (usesActiveCredential ? this.orgName ?? void 0 : void 0) ?? requestedOrgName;
|
|
6304
|
+
const resolvedFetch = fetch2 ?? (this.loggedIn ? this.fetch : void 0) ?? this.loginParams.fetch ?? globalThis.fetch;
|
|
6305
|
+
const credentialCacheNamespace = JSON.stringify([
|
|
6306
|
+
"loader-credential",
|
|
6307
|
+
resolvedAppUrl,
|
|
6308
|
+
requestedOrgName,
|
|
6309
|
+
normalizedApiKey
|
|
6310
|
+
]);
|
|
6311
|
+
return {
|
|
6312
|
+
apiKey: normalizedApiKey,
|
|
6313
|
+
appUrl: resolvedAppUrl,
|
|
6314
|
+
orgName: resolvedOrgName,
|
|
6315
|
+
fetch: resolvedFetch,
|
|
6316
|
+
forceLogin,
|
|
6317
|
+
credentialCacheNamespace,
|
|
6318
|
+
existingState: !forceLogin && usesActiveCredential && resolvedAppUrl === this.appUrl && resolvedOrgName === this.orgName && resolvedFetch === this.fetch ? this : void 0
|
|
6319
|
+
};
|
|
6320
|
+
}
|
|
6321
|
+
/** @internal */
|
|
6322
|
+
_internalGetLoaderCacheViews(loginOptions, requestState) {
|
|
6323
|
+
const expectedResolvedOrgIdentity = requestState?.orgId && requestState.appUrl ? JSON.stringify([
|
|
6324
|
+
"loader-org",
|
|
6325
|
+
requestState.appUrl,
|
|
6326
|
+
requestState.orgId
|
|
6327
|
+
]) : void 0;
|
|
6328
|
+
return {
|
|
6329
|
+
promptCache: this.promptCache.withNamespace(
|
|
6330
|
+
loginOptions.credentialCacheNamespace,
|
|
6331
|
+
expectedResolvedOrgIdentity
|
|
6332
|
+
),
|
|
6333
|
+
parametersCache: this.parametersCache.withNamespace(
|
|
6334
|
+
loginOptions.credentialCacheNamespace,
|
|
6335
|
+
expectedResolvedOrgIdentity
|
|
6336
|
+
)
|
|
6337
|
+
};
|
|
6338
|
+
}
|
|
6339
|
+
/** @internal */
|
|
6340
|
+
async _internalGetLoaderState({
|
|
6341
|
+
apiKey,
|
|
6342
|
+
appUrl,
|
|
6343
|
+
orgName,
|
|
6344
|
+
fetch: fetch2,
|
|
6345
|
+
forceLogin,
|
|
6346
|
+
existingState
|
|
6347
|
+
}) {
|
|
6348
|
+
if (existingState) {
|
|
6349
|
+
return existingState;
|
|
6350
|
+
}
|
|
6351
|
+
let cache = this.loaderLoginCache.get(fetch2);
|
|
6352
|
+
if (!cache) {
|
|
6353
|
+
cache = new LRUCache({ max: LOADER_LOGIN_CACHE_MAX });
|
|
6354
|
+
this.loaderLoginCache.set(fetch2, cache);
|
|
6355
|
+
}
|
|
6356
|
+
const cacheKey = JSON.stringify([appUrl, orgName, apiKey]);
|
|
6357
|
+
if (!forceLogin) {
|
|
6358
|
+
const cachedState = cache.get(cacheKey);
|
|
6359
|
+
if (cachedState) {
|
|
6360
|
+
return cachedState;
|
|
6361
|
+
}
|
|
6362
|
+
}
|
|
6363
|
+
const statePromise = loginToLoaderRequestState({
|
|
6364
|
+
orgName,
|
|
6365
|
+
apiKey,
|
|
6366
|
+
appUrl,
|
|
6367
|
+
fetch: fetch2
|
|
6368
|
+
});
|
|
6369
|
+
cache.set(cacheKey, statePromise);
|
|
6370
|
+
try {
|
|
6371
|
+
return await statePromise;
|
|
6372
|
+
} catch (error) {
|
|
6373
|
+
if (cache.get(cacheKey) === statePromise) {
|
|
6374
|
+
cache.delete(cacheKey);
|
|
6375
|
+
}
|
|
6376
|
+
throw error;
|
|
6377
|
+
}
|
|
6175
6378
|
}
|
|
6176
6379
|
resetIdGenState() {
|
|
6177
6380
|
this._idGenerator = null;
|
|
@@ -6220,6 +6423,8 @@ var BraintrustState = class _BraintrustState {
|
|
|
6220
6423
|
this.debugLogLevel = other.debugLogLevel;
|
|
6221
6424
|
this.debugLogLevelConfigured = other.debugLogLevelConfigured;
|
|
6222
6425
|
this.traceContextSigningSecret = other.traceContextSigningSecret;
|
|
6426
|
+
this.fetch = other.fetch;
|
|
6427
|
+
this.activeLoginOrgNameSelector = other.activeLoginOrgNameSelector;
|
|
6223
6428
|
setGlobalDebugLogLevel(
|
|
6224
6429
|
this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
|
|
6225
6430
|
);
|
|
@@ -6414,36 +6619,76 @@ var FailedHTTPResponse = class extends Error {
|
|
|
6414
6619
|
status;
|
|
6415
6620
|
text;
|
|
6416
6621
|
data;
|
|
6417
|
-
|
|
6622
|
+
cause;
|
|
6623
|
+
constructor(status, text, data, cause) {
|
|
6418
6624
|
super(`${status}: ${text} (${data})`);
|
|
6419
6625
|
this.status = status;
|
|
6420
6626
|
this.text = text;
|
|
6421
6627
|
this.data = data;
|
|
6628
|
+
this.cause = cause;
|
|
6422
6629
|
}
|
|
6423
6630
|
};
|
|
6631
|
+
var HTTPTransportError = class extends Error {
|
|
6632
|
+
cause;
|
|
6633
|
+
constructor(cause) {
|
|
6634
|
+
super(cause instanceof Error ? cause.message : String(cause));
|
|
6635
|
+
this.name = "HTTPTransportError";
|
|
6636
|
+
this.cause = cause;
|
|
6637
|
+
}
|
|
6638
|
+
};
|
|
6639
|
+
var httpTransportErrorCauses = /* @__PURE__ */ new WeakSet();
|
|
6640
|
+
function recordHTTPTransportError(error) {
|
|
6641
|
+
if (typeof error === "object" && error !== null || typeof error === "function") {
|
|
6642
|
+
httpTransportErrorCauses.add(error);
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
function rethrowHTTPTransportError(error, classifyTransportErrors) {
|
|
6646
|
+
if (classifyTransportErrors) {
|
|
6647
|
+
throw new HTTPTransportError(error);
|
|
6648
|
+
}
|
|
6649
|
+
recordHTTPTransportError(error);
|
|
6650
|
+
throw error;
|
|
6651
|
+
}
|
|
6652
|
+
async function readJSONResponse(response, classifyTransportErrors = false) {
|
|
6653
|
+
let data;
|
|
6654
|
+
try {
|
|
6655
|
+
data = await response.text();
|
|
6656
|
+
} catch (error) {
|
|
6657
|
+
rethrowHTTPTransportError(error, classifyTransportErrors);
|
|
6658
|
+
}
|
|
6659
|
+
return JSON.parse(data);
|
|
6660
|
+
}
|
|
6424
6661
|
async function checkResponse(resp) {
|
|
6425
6662
|
if (resp.ok) {
|
|
6426
6663
|
return resp;
|
|
6427
|
-
}
|
|
6664
|
+
}
|
|
6665
|
+
let data;
|
|
6666
|
+
try {
|
|
6667
|
+
data = await resp.text();
|
|
6668
|
+
} catch (error) {
|
|
6428
6669
|
throw new FailedHTTPResponse(
|
|
6429
6670
|
resp.status,
|
|
6430
6671
|
resp.statusText,
|
|
6431
|
-
|
|
6672
|
+
"Unable to read response body",
|
|
6673
|
+
error
|
|
6432
6674
|
);
|
|
6433
6675
|
}
|
|
6676
|
+
throw new FailedHTTPResponse(resp.status, resp.statusText, data);
|
|
6434
6677
|
}
|
|
6435
6678
|
var HTTPConnection = class _HTTPConnection {
|
|
6436
|
-
base_url
|
|
6437
|
-
|
|
6438
|
-
headers;
|
|
6439
|
-
fetch;
|
|
6440
|
-
constructor(base_url, fetch2) {
|
|
6679
|
+
constructor(base_url, fetch2, classifyTransportErrors = false) {
|
|
6680
|
+
this.classifyTransportErrors = classifyTransportErrors;
|
|
6441
6681
|
this.base_url = base_url;
|
|
6442
6682
|
this.token = null;
|
|
6443
6683
|
this.headers = {};
|
|
6444
6684
|
this._reset();
|
|
6445
6685
|
this.fetch = fetch2;
|
|
6446
6686
|
}
|
|
6687
|
+
classifyTransportErrors;
|
|
6688
|
+
base_url;
|
|
6689
|
+
token;
|
|
6690
|
+
headers;
|
|
6691
|
+
fetch;
|
|
6447
6692
|
setFetch(fetch2) {
|
|
6448
6693
|
this.fetch = fetch2;
|
|
6449
6694
|
}
|
|
@@ -6483,9 +6728,9 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6483
6728
|
).toString();
|
|
6484
6729
|
const this_fetch = this.fetch;
|
|
6485
6730
|
const this_headers = this.headers;
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
await this_fetch(url.toString(), {
|
|
6731
|
+
let response;
|
|
6732
|
+
try {
|
|
6733
|
+
response = await this_fetch(url.toString(), {
|
|
6489
6734
|
headers: {
|
|
6490
6735
|
Accept: "application/json",
|
|
6491
6736
|
...this_headers,
|
|
@@ -6493,8 +6738,14 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6493
6738
|
},
|
|
6494
6739
|
keepalive: true,
|
|
6495
6740
|
...rest
|
|
6496
|
-
})
|
|
6497
|
-
)
|
|
6741
|
+
});
|
|
6742
|
+
} catch (error) {
|
|
6743
|
+
if (config?.signal?.aborted) {
|
|
6744
|
+
throw getAbortReason(config.signal);
|
|
6745
|
+
}
|
|
6746
|
+
rethrowHTTPTransportError(error, this.classifyTransportErrors);
|
|
6747
|
+
}
|
|
6748
|
+
return await checkResponse(response);
|
|
6498
6749
|
}
|
|
6499
6750
|
async post(path, params, config, retries = 0) {
|
|
6500
6751
|
const { headers, ...rest } = config || {};
|
|
@@ -6504,8 +6755,9 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6504
6755
|
const tries = retries + 1;
|
|
6505
6756
|
for (let i = 0; i < tries; i++) {
|
|
6506
6757
|
try {
|
|
6507
|
-
|
|
6508
|
-
|
|
6758
|
+
let response;
|
|
6759
|
+
try {
|
|
6760
|
+
response = await this_fetch(_urljoin(this_base_url, path), {
|
|
6509
6761
|
method: "POST",
|
|
6510
6762
|
headers: {
|
|
6511
6763
|
Accept: "application/json",
|
|
@@ -6516,8 +6768,14 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6516
6768
|
body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
|
|
6517
6769
|
keepalive: true,
|
|
6518
6770
|
...rest
|
|
6519
|
-
})
|
|
6520
|
-
)
|
|
6771
|
+
});
|
|
6772
|
+
} catch (error) {
|
|
6773
|
+
if (config?.signal?.aborted) {
|
|
6774
|
+
throw getAbortReason(config.signal);
|
|
6775
|
+
}
|
|
6776
|
+
rethrowHTTPTransportError(error, this.classifyTransportErrors);
|
|
6777
|
+
}
|
|
6778
|
+
return await checkResponse(response);
|
|
6521
6779
|
} catch (error) {
|
|
6522
6780
|
if (config?.signal?.aborted) {
|
|
6523
6781
|
throw getAbortReason(config.signal);
|
|
@@ -6542,7 +6800,7 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6542
6800
|
for (let i = 0; i < tries; i++) {
|
|
6543
6801
|
try {
|
|
6544
6802
|
const resp = await this.get(`${object_type}`, args);
|
|
6545
|
-
return await resp.
|
|
6803
|
+
return await readJSONResponse(resp, this.classifyTransportErrors);
|
|
6546
6804
|
} catch (e) {
|
|
6547
6805
|
if (i < tries - 1) {
|
|
6548
6806
|
debugLogger.debug(
|
|
@@ -6565,7 +6823,7 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6565
6823
|
const resp = await this.post(`${object_type}`, args, {
|
|
6566
6824
|
headers: { "Content-Type": "application/json" }
|
|
6567
6825
|
});
|
|
6568
|
-
return await resp.
|
|
6826
|
+
return await readJSONResponse(resp, this.classifyTransportErrors);
|
|
6569
6827
|
}
|
|
6570
6828
|
// Custom inspect for Node.js console.log
|
|
6571
6829
|
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
@@ -8120,6 +8378,52 @@ function initLogger(options = {}) {
|
|
|
8120
8378
|
}
|
|
8121
8379
|
return ret;
|
|
8122
8380
|
}
|
|
8381
|
+
async function loginToLoaderRequestState({
|
|
8382
|
+
appUrl,
|
|
8383
|
+
apiKey,
|
|
8384
|
+
orgName,
|
|
8385
|
+
fetch: fetch2
|
|
8386
|
+
}) {
|
|
8387
|
+
let orgId;
|
|
8388
|
+
let apiUrl;
|
|
8389
|
+
if (apiKey === TEST_API_KEY) {
|
|
8390
|
+
orgId = "test-org-id";
|
|
8391
|
+
apiUrl = "https://braintrust.dev/fake-api-url";
|
|
8392
|
+
} else {
|
|
8393
|
+
let loginResponse;
|
|
8394
|
+
try {
|
|
8395
|
+
loginResponse = await fetch2(_urljoin(appUrl, `/api/apikey/login`), {
|
|
8396
|
+
method: "POST",
|
|
8397
|
+
headers: {
|
|
8398
|
+
"Content-Type": "application/json",
|
|
8399
|
+
Authorization: `Bearer ${apiKey}`
|
|
8400
|
+
}
|
|
8401
|
+
});
|
|
8402
|
+
} catch (error) {
|
|
8403
|
+
throw new HTTPTransportError(error);
|
|
8404
|
+
}
|
|
8405
|
+
const info = await readJSONResponse(
|
|
8406
|
+
await checkResponse(loginResponse),
|
|
8407
|
+
true
|
|
8408
|
+
);
|
|
8409
|
+
const org = selectLoginOrg(info.org_info, orgName);
|
|
8410
|
+
orgId = org.id;
|
|
8411
|
+
apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
|
|
8412
|
+
if (!apiUrl) {
|
|
8413
|
+
throw new Error(
|
|
8414
|
+
orgName ? `Unable to log into organization '${orgName}'. Are you sure this credential is scoped to the organization?` : "Unable to log into any organization with the provided credential."
|
|
8415
|
+
);
|
|
8416
|
+
}
|
|
8417
|
+
}
|
|
8418
|
+
const apiConnection = new HTTPConnection(apiUrl, fetch2, true);
|
|
8419
|
+
apiConnection.set_token(apiKey);
|
|
8420
|
+
apiConnection.make_long_lived();
|
|
8421
|
+
return {
|
|
8422
|
+
appUrl,
|
|
8423
|
+
orgId,
|
|
8424
|
+
apiConn: () => apiConnection
|
|
8425
|
+
};
|
|
8426
|
+
}
|
|
8123
8427
|
async function loginToState(options = {}) {
|
|
8124
8428
|
const {
|
|
8125
8429
|
appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
|
|
@@ -8151,16 +8455,18 @@ async function loginToState(options = {}) {
|
|
|
8151
8455
|
_saveOrgInfo(state, testOrgInfo, testOrgInfo[0].name);
|
|
8152
8456
|
return state;
|
|
8153
8457
|
} else {
|
|
8154
|
-
const
|
|
8155
|
-
|
|
8458
|
+
const loginResponse = await fetch2(
|
|
8459
|
+
_urljoin(state.appUrl, `/api/apikey/login`),
|
|
8460
|
+
{
|
|
8156
8461
|
method: "POST",
|
|
8157
8462
|
headers: {
|
|
8158
8463
|
"Content-Type": "application/json",
|
|
8159
8464
|
Authorization: `Bearer ${apiKey}`
|
|
8160
8465
|
}
|
|
8161
|
-
}
|
|
8466
|
+
}
|
|
8162
8467
|
);
|
|
8163
|
-
const
|
|
8468
|
+
const resp = await checkResponse(loginResponse);
|
|
8469
|
+
const info = await readJSONResponse(resp);
|
|
8164
8470
|
_saveOrgInfo(state, info.org_info, orgName);
|
|
8165
8471
|
if (!state.apiUrl) {
|
|
8166
8472
|
if (orgName) {
|
|
@@ -8225,6 +8531,9 @@ function getSpanParentObjectAndPropagatedState(options) {
|
|
|
8225
8531
|
}
|
|
8226
8532
|
return { parentObject: NOOP_SPAN, propagatedState: void 0 };
|
|
8227
8533
|
}
|
|
8534
|
+
function getSpanParentObject(options) {
|
|
8535
|
+
return getSpanParentObjectAndPropagatedState(options).parentObject;
|
|
8536
|
+
}
|
|
8228
8537
|
function currentBraintrustParent(state) {
|
|
8229
8538
|
const resolvedState = state ?? _globalState;
|
|
8230
8539
|
const experiment = currentExperiment({ state: resolvedState });
|
|
@@ -8471,6 +8780,15 @@ function _internalStartSpanWithInitialMerge(args) {
|
|
|
8471
8780
|
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
8472
8781
|
}).span;
|
|
8473
8782
|
}
|
|
8783
|
+
function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
|
|
8784
|
+
return startSpanAndIsLogger(
|
|
8785
|
+
{
|
|
8786
|
+
...args,
|
|
8787
|
+
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
8788
|
+
},
|
|
8789
|
+
{ useParentSpanIdsForObjectParent: true }
|
|
8790
|
+
).span;
|
|
8791
|
+
}
|
|
8474
8792
|
function _internalStartSpanWithContext(args, context) {
|
|
8475
8793
|
return startSpanAndIsLogger({
|
|
8476
8794
|
...args,
|
|
@@ -8481,7 +8799,7 @@ async function flush(options) {
|
|
|
8481
8799
|
const state = options?.state ?? _globalState;
|
|
8482
8800
|
return await state.bgLogger().flush();
|
|
8483
8801
|
}
|
|
8484
|
-
function startSpanAndIsLogger(args) {
|
|
8802
|
+
function startSpanAndIsLogger(args, internalOptions) {
|
|
8485
8803
|
const state = args?.state ?? _globalState;
|
|
8486
8804
|
const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
|
|
8487
8805
|
asyncFlush: args?.asyncFlush,
|
|
@@ -8495,7 +8813,7 @@ function startSpanAndIsLogger(args) {
|
|
|
8495
8813
|
) ? {
|
|
8496
8814
|
spanId: parentObject.data.span_id,
|
|
8497
8815
|
rootSpanId: parentObject.data.root_span_id
|
|
8498
|
-
} : void 0;
|
|
8816
|
+
} : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
|
|
8499
8817
|
const { parent: _ignoredParent, ...spanArgs } = args ?? {};
|
|
8500
8818
|
const span = new SpanImpl({
|
|
8501
8819
|
state,
|
|
@@ -8528,27 +8846,28 @@ function withCurrent(span, callback, state = void 0) {
|
|
|
8528
8846
|
const currentState = state ?? _globalState;
|
|
8529
8847
|
return currentState.contextManager.runInContext(span, () => callback(span));
|
|
8530
8848
|
}
|
|
8531
|
-
function _saveOrgInfo(state,
|
|
8532
|
-
|
|
8849
|
+
function _saveOrgInfo(state, orgInfo, orgName) {
|
|
8850
|
+
const org = selectLoginOrg(orgInfo, orgName);
|
|
8851
|
+
state.orgId = org.id;
|
|
8852
|
+
state.orgName = org.name;
|
|
8853
|
+
state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
|
|
8854
|
+
state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
|
|
8855
|
+
state.gitMetadataSettings = org.git_metadata || void 0;
|
|
8856
|
+
}
|
|
8857
|
+
function selectLoginOrg(orgInfo, orgName) {
|
|
8858
|
+
if (orgInfo.length === 0) {
|
|
8533
8859
|
throw new LoginInvalidOrgError(
|
|
8534
8860
|
"This user is not part of any organizations."
|
|
8535
8861
|
);
|
|
8536
8862
|
}
|
|
8537
|
-
for (const org of
|
|
8538
|
-
if (
|
|
8539
|
-
|
|
8540
|
-
state.orgName = org.name;
|
|
8541
|
-
state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
|
|
8542
|
-
state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
|
|
8543
|
-
state.gitMetadataSettings = org.git_metadata || void 0;
|
|
8544
|
-
break;
|
|
8863
|
+
for (const org of orgInfo) {
|
|
8864
|
+
if (orgName === void 0 || org.name === orgName) {
|
|
8865
|
+
return org;
|
|
8545
8866
|
}
|
|
8546
8867
|
}
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
);
|
|
8551
|
-
}
|
|
8868
|
+
throw new LoginInvalidOrgError(
|
|
8869
|
+
`Organization ${orgName} not found. Must be one of ${orgInfo.map((org) => org.name).join(", ")}`
|
|
8870
|
+
);
|
|
8552
8871
|
}
|
|
8553
8872
|
function validateTags(tags) {
|
|
8554
8873
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8713,6 +9032,19 @@ function enrichAttachments(event, state) {
|
|
|
8713
9032
|
}
|
|
8714
9033
|
return event;
|
|
8715
9034
|
}
|
|
9035
|
+
async function resolveAttachmentsToBase64(event, state) {
|
|
9036
|
+
for (const [key, value] of Object.entries(event)) {
|
|
9037
|
+
if (value instanceof ReadonlyAttachment) {
|
|
9038
|
+
event[key] = await value.asBase64Url();
|
|
9039
|
+
continue;
|
|
9040
|
+
}
|
|
9041
|
+
if (!(value instanceof Object)) {
|
|
9042
|
+
continue;
|
|
9043
|
+
}
|
|
9044
|
+
await resolveAttachmentsToBase64(value, state);
|
|
9045
|
+
}
|
|
9046
|
+
return event;
|
|
9047
|
+
}
|
|
8716
9048
|
function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
|
|
8717
9049
|
if ("input" in event && !isEmpty2(event.input) && "inputs" in event && !isEmpty2(event.inputs) || !("input" in event) && !("inputs" in event)) {
|
|
8718
9050
|
throw new Error(
|
|
@@ -10002,6 +10334,473 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
10002
10334
|
return typeof data === "object" && data !== null && "__braintrust_dataset_marker" in data;
|
|
10003
10335
|
}
|
|
10004
10336
|
};
|
|
10337
|
+
function isAttachmentObject(value) {
|
|
10338
|
+
return BraintrustAttachmentReference.safeParse(value).success || InlineAttachmentReferenceSchema.safeParse(value).success || ExternalAttachmentReference.safeParse(value).success;
|
|
10339
|
+
}
|
|
10340
|
+
function isURL(url) {
|
|
10341
|
+
try {
|
|
10342
|
+
const parsedUrl = new URL(url.trim());
|
|
10343
|
+
return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
|
|
10344
|
+
} catch {
|
|
10345
|
+
return false;
|
|
10346
|
+
}
|
|
10347
|
+
}
|
|
10348
|
+
function expandAttachmentArrayPreTemplate(content, variables) {
|
|
10349
|
+
if (typeof content !== "string") return null;
|
|
10350
|
+
const match = content.match(/^\{\{\s*([\w.]+)\s*\}\}$/);
|
|
10351
|
+
if (!match) return null;
|
|
10352
|
+
const varPath = match[1];
|
|
10353
|
+
const value = varPath.includes(".") ? getObjValueByPath(variables, varPath.split(".")) : variables[varPath];
|
|
10354
|
+
if (!Array.isArray(value)) return null;
|
|
10355
|
+
const allValid = value.every(
|
|
10356
|
+
(v) => isAttachmentObject(v) || typeof v === "string" && isURL(v)
|
|
10357
|
+
);
|
|
10358
|
+
if (!allValid) return null;
|
|
10359
|
+
return value.map((item) => ({
|
|
10360
|
+
type: "image_url",
|
|
10361
|
+
image_url: { url: item }
|
|
10362
|
+
}));
|
|
10363
|
+
}
|
|
10364
|
+
function renderMessageImpl(render, message, variables) {
|
|
10365
|
+
return {
|
|
10366
|
+
...message,
|
|
10367
|
+
..."content" in message ? {
|
|
10368
|
+
content: isEmpty2(message.content) ? void 0 : typeof message.content === "string" ? render(message.content) : message.content.flatMap((c) => {
|
|
10369
|
+
switch (c.type) {
|
|
10370
|
+
case "text":
|
|
10371
|
+
return [{ ...c, text: render(c.text) }];
|
|
10372
|
+
case "image_url":
|
|
10373
|
+
if (isObject(c.image_url.url)) {
|
|
10374
|
+
throw new Error(
|
|
10375
|
+
"Attachments must be replaced with URLs before calling `build()`"
|
|
10376
|
+
);
|
|
10377
|
+
}
|
|
10378
|
+
if (variables) {
|
|
10379
|
+
const expanded = expandAttachmentArrayPreTemplate(
|
|
10380
|
+
c.image_url.url,
|
|
10381
|
+
variables
|
|
10382
|
+
);
|
|
10383
|
+
if (expanded) {
|
|
10384
|
+
return expanded;
|
|
10385
|
+
}
|
|
10386
|
+
}
|
|
10387
|
+
return [
|
|
10388
|
+
{
|
|
10389
|
+
...c,
|
|
10390
|
+
image_url: {
|
|
10391
|
+
...c.image_url,
|
|
10392
|
+
url: render(c.image_url.url)
|
|
10393
|
+
}
|
|
10394
|
+
}
|
|
10395
|
+
];
|
|
10396
|
+
case "file":
|
|
10397
|
+
return [
|
|
10398
|
+
{
|
|
10399
|
+
...c,
|
|
10400
|
+
file: {
|
|
10401
|
+
...c.file.file_data && {
|
|
10402
|
+
file_data: render(c.file.file_data)
|
|
10403
|
+
},
|
|
10404
|
+
...c.file.file_id && {
|
|
10405
|
+
file_id: render(c.file.file_id)
|
|
10406
|
+
},
|
|
10407
|
+
...c.file.filename && {
|
|
10408
|
+
filename: render(c.file.filename)
|
|
10409
|
+
}
|
|
10410
|
+
}
|
|
10411
|
+
}
|
|
10412
|
+
];
|
|
10413
|
+
default:
|
|
10414
|
+
const _exhaustiveCheck = c;
|
|
10415
|
+
return _exhaustiveCheck;
|
|
10416
|
+
}
|
|
10417
|
+
})
|
|
10418
|
+
} : {},
|
|
10419
|
+
..."tool_calls" in message ? {
|
|
10420
|
+
tool_calls: isEmpty2(message.tool_calls) ? void 0 : message.tool_calls.map((t) => {
|
|
10421
|
+
return {
|
|
10422
|
+
type: t.type,
|
|
10423
|
+
id: render(t.id),
|
|
10424
|
+
function: {
|
|
10425
|
+
name: render(t.function.name),
|
|
10426
|
+
arguments: render(t.function.arguments)
|
|
10427
|
+
}
|
|
10428
|
+
};
|
|
10429
|
+
})
|
|
10430
|
+
} : {},
|
|
10431
|
+
..."tool_call_id" in message ? {
|
|
10432
|
+
tool_call_id: render(message.tool_call_id)
|
|
10433
|
+
} : {}
|
|
10434
|
+
};
|
|
10435
|
+
}
|
|
10436
|
+
function deserializePlainStringAsJSON(s) {
|
|
10437
|
+
if (s.trim() === "") {
|
|
10438
|
+
return { value: null, error: void 0 };
|
|
10439
|
+
}
|
|
10440
|
+
try {
|
|
10441
|
+
return { value: JSON.parse(s), error: void 0 };
|
|
10442
|
+
} catch (e) {
|
|
10443
|
+
return { value: s, error: e };
|
|
10444
|
+
}
|
|
10445
|
+
}
|
|
10446
|
+
function renderTemplatedObject(obj, args, options) {
|
|
10447
|
+
if (typeof obj === "string") {
|
|
10448
|
+
return renderTemplateContent(
|
|
10449
|
+
obj,
|
|
10450
|
+
args,
|
|
10451
|
+
(value) => typeof value === "string" ? value : JSON.stringify(value),
|
|
10452
|
+
{
|
|
10453
|
+
strict: options.strict,
|
|
10454
|
+
templateFormat: options.templateFormat
|
|
10455
|
+
}
|
|
10456
|
+
);
|
|
10457
|
+
} else if (isArray(obj)) {
|
|
10458
|
+
return obj.map((item) => renderTemplatedObject(item, args, options));
|
|
10459
|
+
} else if (isObject(obj)) {
|
|
10460
|
+
return Object.fromEntries(
|
|
10461
|
+
Object.entries(obj).map(([key, value]) => [
|
|
10462
|
+
key,
|
|
10463
|
+
renderTemplatedObject(value, args, options)
|
|
10464
|
+
])
|
|
10465
|
+
);
|
|
10466
|
+
}
|
|
10467
|
+
return obj;
|
|
10468
|
+
}
|
|
10469
|
+
function renderPromptParams(params, args, options = {}) {
|
|
10470
|
+
const templateFormat = parseTemplateFormat(options.templateFormat);
|
|
10471
|
+
const strict = !!options.strict;
|
|
10472
|
+
const schemaParsed = import_v38.z.object({
|
|
10473
|
+
response_format: import_v38.z.object({
|
|
10474
|
+
type: import_v38.z.literal("json_schema"),
|
|
10475
|
+
json_schema: ResponseFormatJsonSchema.omit({ schema: true }).extend({
|
|
10476
|
+
schema: import_v38.z.unknown()
|
|
10477
|
+
})
|
|
10478
|
+
})
|
|
10479
|
+
}).safeParse(params);
|
|
10480
|
+
if (schemaParsed.success) {
|
|
10481
|
+
const rawSchema = schemaParsed.data.response_format.json_schema.schema;
|
|
10482
|
+
const templatedSchema = renderTemplatedObject(rawSchema, args, {
|
|
10483
|
+
strict,
|
|
10484
|
+
templateFormat
|
|
10485
|
+
});
|
|
10486
|
+
const parsedSchema = typeof templatedSchema === "string" ? deserializePlainStringAsJSON(templatedSchema).value : templatedSchema;
|
|
10487
|
+
return {
|
|
10488
|
+
...params,
|
|
10489
|
+
response_format: {
|
|
10490
|
+
...schemaParsed.data.response_format,
|
|
10491
|
+
json_schema: {
|
|
10492
|
+
...schemaParsed.data.response_format.json_schema,
|
|
10493
|
+
schema: parsedSchema
|
|
10494
|
+
}
|
|
10495
|
+
}
|
|
10496
|
+
};
|
|
10497
|
+
}
|
|
10498
|
+
return params;
|
|
10499
|
+
}
|
|
10500
|
+
var Prompt2 = class _Prompt {
|
|
10501
|
+
constructor(metadata, defaults, noTrace) {
|
|
10502
|
+
this.metadata = metadata;
|
|
10503
|
+
this.defaults = defaults;
|
|
10504
|
+
this.noTrace = noTrace;
|
|
10505
|
+
void this.__braintrust_prompt_marker;
|
|
10506
|
+
}
|
|
10507
|
+
metadata;
|
|
10508
|
+
defaults;
|
|
10509
|
+
noTrace;
|
|
10510
|
+
parsedPromptData;
|
|
10511
|
+
hasParsedPromptData = false;
|
|
10512
|
+
__braintrust_prompt_marker = true;
|
|
10513
|
+
get id() {
|
|
10514
|
+
return this.metadata.id;
|
|
10515
|
+
}
|
|
10516
|
+
get projectId() {
|
|
10517
|
+
return this.metadata.project_id;
|
|
10518
|
+
}
|
|
10519
|
+
get name() {
|
|
10520
|
+
return "name" in this.metadata ? this.metadata.name : `Playground function ${this.metadata.id}`;
|
|
10521
|
+
}
|
|
10522
|
+
get slug() {
|
|
10523
|
+
return "slug" in this.metadata ? this.metadata.slug : this.metadata.id;
|
|
10524
|
+
}
|
|
10525
|
+
get prompt() {
|
|
10526
|
+
return this.getParsedPromptData()?.prompt;
|
|
10527
|
+
}
|
|
10528
|
+
get version() {
|
|
10529
|
+
return this.metadata[TRANSACTION_ID_FIELD];
|
|
10530
|
+
}
|
|
10531
|
+
get options() {
|
|
10532
|
+
return this.getParsedPromptData()?.options || {};
|
|
10533
|
+
}
|
|
10534
|
+
get templateFormat() {
|
|
10535
|
+
return this.getParsedPromptData()?.template_format;
|
|
10536
|
+
}
|
|
10537
|
+
get promptData() {
|
|
10538
|
+
return this.getParsedPromptData();
|
|
10539
|
+
}
|
|
10540
|
+
/**
|
|
10541
|
+
* Build the prompt with the given formatting options. The args you pass in will
|
|
10542
|
+
* be forwarded to the mustache template that defines the prompt and rendered with
|
|
10543
|
+
* the `mustache-js` library.
|
|
10544
|
+
*
|
|
10545
|
+
* @param buildArgs Args to forward along to the prompt template.
|
|
10546
|
+
*/
|
|
10547
|
+
build(buildArgs, options = {}) {
|
|
10548
|
+
return this.runBuild(buildArgs, {
|
|
10549
|
+
flavor: options.flavor ?? "chat",
|
|
10550
|
+
messages: options.messages,
|
|
10551
|
+
strict: options.strict,
|
|
10552
|
+
templateFormat: options.templateFormat
|
|
10553
|
+
});
|
|
10554
|
+
}
|
|
10555
|
+
/**
|
|
10556
|
+
* This is a special build method that first resolves attachment references, and then
|
|
10557
|
+
* calls the regular build method. You should use this if you are building prompts from
|
|
10558
|
+
* dataset rows that contain attachments.
|
|
10559
|
+
*
|
|
10560
|
+
* @param buildArgs Args to forward along to the prompt template.
|
|
10561
|
+
*/
|
|
10562
|
+
async buildWithAttachments(buildArgs, options = {}) {
|
|
10563
|
+
const hydrated = buildArgs instanceof Object ? await resolveAttachmentsToBase64(buildArgs, options.state) : buildArgs;
|
|
10564
|
+
return this.runBuild(hydrated, {
|
|
10565
|
+
flavor: options.flavor ?? "chat",
|
|
10566
|
+
messages: options.messages,
|
|
10567
|
+
strict: options.strict,
|
|
10568
|
+
templateFormat: options.templateFormat
|
|
10569
|
+
});
|
|
10570
|
+
}
|
|
10571
|
+
runBuild(buildArgs, options) {
|
|
10572
|
+
const { flavor } = options;
|
|
10573
|
+
const params = Object.fromEntries(
|
|
10574
|
+
Object.entries({
|
|
10575
|
+
...this.defaults,
|
|
10576
|
+
...Object.fromEntries(
|
|
10577
|
+
Object.entries(this.options.params || {}).filter(
|
|
10578
|
+
([k, _v]) => !BRAINTRUST_PARAMS.includes(k)
|
|
10579
|
+
)
|
|
10580
|
+
),
|
|
10581
|
+
...!isEmpty2(this.options.model) ? {
|
|
10582
|
+
model: this.options.model
|
|
10583
|
+
} : {}
|
|
10584
|
+
}).filter(([key, value]) => key !== "response_format" || value !== null)
|
|
10585
|
+
);
|
|
10586
|
+
if (!("model" in params) || isEmpty2(params.model)) {
|
|
10587
|
+
throw new Error(
|
|
10588
|
+
"No model specified. Either specify it in the prompt or as a default"
|
|
10589
|
+
);
|
|
10590
|
+
}
|
|
10591
|
+
const spanInfo = this.noTrace ? {} : {
|
|
10592
|
+
span_info: {
|
|
10593
|
+
metadata: {
|
|
10594
|
+
prompt: this.id ? {
|
|
10595
|
+
variables: buildArgs,
|
|
10596
|
+
id: this.id,
|
|
10597
|
+
project_id: this.projectId,
|
|
10598
|
+
version: this.version,
|
|
10599
|
+
..."prompt_session_id" in this.metadata ? { prompt_session_id: this.metadata.prompt_session_id } : {}
|
|
10600
|
+
} : void 0
|
|
10601
|
+
}
|
|
10602
|
+
}
|
|
10603
|
+
};
|
|
10604
|
+
const prompt = this.prompt;
|
|
10605
|
+
if (!prompt) {
|
|
10606
|
+
throw new Error("Empty prompt");
|
|
10607
|
+
}
|
|
10608
|
+
const dictArgParsed = import_v38.z.record(import_v38.z.unknown()).safeParse(buildArgs);
|
|
10609
|
+
const variables = {
|
|
10610
|
+
input: buildArgs,
|
|
10611
|
+
...dictArgParsed.success ? dictArgParsed.data : {}
|
|
10612
|
+
};
|
|
10613
|
+
const promptDataTemplateFormat = this.templateFormat;
|
|
10614
|
+
const resolvedTemplateFormat = parseTemplateFormat(
|
|
10615
|
+
options.templateFormat ?? promptDataTemplateFormat
|
|
10616
|
+
);
|
|
10617
|
+
const renderedPrompt = _Prompt.renderPrompt({
|
|
10618
|
+
prompt,
|
|
10619
|
+
buildArgs,
|
|
10620
|
+
options: { ...options, templateFormat: resolvedTemplateFormat }
|
|
10621
|
+
});
|
|
10622
|
+
if (flavor === "chat") {
|
|
10623
|
+
if (renderedPrompt.type !== "chat") {
|
|
10624
|
+
throw new Error(
|
|
10625
|
+
"Prompt is a completion prompt. Use buildCompletion() instead"
|
|
10626
|
+
);
|
|
10627
|
+
}
|
|
10628
|
+
return {
|
|
10629
|
+
...renderPromptParams(params, variables, {
|
|
10630
|
+
strict: options.strict,
|
|
10631
|
+
templateFormat: resolvedTemplateFormat
|
|
10632
|
+
}),
|
|
10633
|
+
...spanInfo,
|
|
10634
|
+
messages: renderedPrompt.messages,
|
|
10635
|
+
...renderedPrompt.tools ? {
|
|
10636
|
+
tools: ChatCompletionTool.array().parse(JSON.parse(renderedPrompt.tools))
|
|
10637
|
+
} : void 0
|
|
10638
|
+
};
|
|
10639
|
+
} else if (flavor === "completion") {
|
|
10640
|
+
if (renderedPrompt.type !== "completion") {
|
|
10641
|
+
throw new Error(`Prompt is a chat prompt. Use flavor: 'chat' instead`);
|
|
10642
|
+
}
|
|
10643
|
+
return {
|
|
10644
|
+
...renderPromptParams(params, variables, {
|
|
10645
|
+
strict: options.strict,
|
|
10646
|
+
templateFormat: resolvedTemplateFormat
|
|
10647
|
+
}),
|
|
10648
|
+
...spanInfo,
|
|
10649
|
+
prompt: renderedPrompt.content
|
|
10650
|
+
};
|
|
10651
|
+
} else {
|
|
10652
|
+
throw new Error("never!");
|
|
10653
|
+
}
|
|
10654
|
+
}
|
|
10655
|
+
static renderPrompt({
|
|
10656
|
+
prompt,
|
|
10657
|
+
buildArgs,
|
|
10658
|
+
options
|
|
10659
|
+
}) {
|
|
10660
|
+
const escape = (v) => {
|
|
10661
|
+
if (v === void 0) {
|
|
10662
|
+
throw new Error("Missing!");
|
|
10663
|
+
} else if (typeof v === "string") {
|
|
10664
|
+
return v;
|
|
10665
|
+
} else if (v instanceof ReadonlyAttachment) {
|
|
10666
|
+
throw new Error(
|
|
10667
|
+
"Use buildWithAttachments() to build prompts with attachments"
|
|
10668
|
+
);
|
|
10669
|
+
} else {
|
|
10670
|
+
return JSON.stringify(v);
|
|
10671
|
+
}
|
|
10672
|
+
};
|
|
10673
|
+
const dictArgParsed = import_v38.z.record(import_v38.z.unknown()).safeParse(buildArgs);
|
|
10674
|
+
const variables = {
|
|
10675
|
+
input: buildArgs,
|
|
10676
|
+
...dictArgParsed.success ? dictArgParsed.data : {}
|
|
10677
|
+
};
|
|
10678
|
+
const templateFormat = parseTemplateFormat(options.templateFormat);
|
|
10679
|
+
if (prompt.type === "chat") {
|
|
10680
|
+
const render = (template) => renderTemplateContent(template, variables, escape, {
|
|
10681
|
+
strict: options.strict,
|
|
10682
|
+
templateFormat
|
|
10683
|
+
});
|
|
10684
|
+
const baseMessages = (prompt.messages || []).map(
|
|
10685
|
+
(m) => renderMessageImpl(render, m, variables)
|
|
10686
|
+
);
|
|
10687
|
+
const hasSystemPrompt = baseMessages.some((m) => m.role === "system");
|
|
10688
|
+
const messages = [
|
|
10689
|
+
...baseMessages,
|
|
10690
|
+
...(options.messages ?? []).filter(
|
|
10691
|
+
(m) => !(hasSystemPrompt && m.role === "system")
|
|
10692
|
+
)
|
|
10693
|
+
];
|
|
10694
|
+
return {
|
|
10695
|
+
type: "chat",
|
|
10696
|
+
messages,
|
|
10697
|
+
...prompt.tools?.trim() ? {
|
|
10698
|
+
tools: render(prompt.tools)
|
|
10699
|
+
} : void 0
|
|
10700
|
+
};
|
|
10701
|
+
} else if (prompt.type === "completion") {
|
|
10702
|
+
if (options.messages) {
|
|
10703
|
+
throw new Error(
|
|
10704
|
+
"extra messages are not supported for completion prompts"
|
|
10705
|
+
);
|
|
10706
|
+
}
|
|
10707
|
+
const content = renderTemplateContent(prompt.content, variables, escape, {
|
|
10708
|
+
strict: options.strict,
|
|
10709
|
+
templateFormat
|
|
10710
|
+
});
|
|
10711
|
+
return {
|
|
10712
|
+
type: "completion",
|
|
10713
|
+
content
|
|
10714
|
+
};
|
|
10715
|
+
} else {
|
|
10716
|
+
const _ = prompt;
|
|
10717
|
+
throw new Error(`Invalid prompt type: ${_}`);
|
|
10718
|
+
}
|
|
10719
|
+
}
|
|
10720
|
+
getParsedPromptData() {
|
|
10721
|
+
if (!this.hasParsedPromptData) {
|
|
10722
|
+
this.parsedPromptData = PromptData.parse(this.metadata.prompt_data);
|
|
10723
|
+
this.hasParsedPromptData = true;
|
|
10724
|
+
}
|
|
10725
|
+
return this.parsedPromptData;
|
|
10726
|
+
}
|
|
10727
|
+
static isPrompt(data) {
|
|
10728
|
+
return typeof data === "object" && data !== null && "__braintrust_prompt_marker" in data;
|
|
10729
|
+
}
|
|
10730
|
+
/** @internal */
|
|
10731
|
+
_internalSerializeForCache() {
|
|
10732
|
+
return {
|
|
10733
|
+
metadata: this.metadata,
|
|
10734
|
+
defaults: this.defaults,
|
|
10735
|
+
noTrace: this.noTrace
|
|
10736
|
+
};
|
|
10737
|
+
}
|
|
10738
|
+
static fromPromptData(name, promptData) {
|
|
10739
|
+
return new _Prompt(
|
|
10740
|
+
{
|
|
10741
|
+
name,
|
|
10742
|
+
slug: name,
|
|
10743
|
+
prompt_data: promptData
|
|
10744
|
+
},
|
|
10745
|
+
{},
|
|
10746
|
+
false
|
|
10747
|
+
);
|
|
10748
|
+
}
|
|
10749
|
+
};
|
|
10750
|
+
var RemoteEvalParameters = class {
|
|
10751
|
+
constructor(metadata) {
|
|
10752
|
+
this.metadata = metadata;
|
|
10753
|
+
void this.__braintrust_parameters_marker;
|
|
10754
|
+
}
|
|
10755
|
+
metadata;
|
|
10756
|
+
__braintrust_parameters_marker = true;
|
|
10757
|
+
get id() {
|
|
10758
|
+
return this.metadata.id;
|
|
10759
|
+
}
|
|
10760
|
+
get projectId() {
|
|
10761
|
+
return this.metadata.project_id;
|
|
10762
|
+
}
|
|
10763
|
+
get name() {
|
|
10764
|
+
return this.metadata.name;
|
|
10765
|
+
}
|
|
10766
|
+
get slug() {
|
|
10767
|
+
return this.metadata.slug;
|
|
10768
|
+
}
|
|
10769
|
+
get version() {
|
|
10770
|
+
return this.metadata[TRANSACTION_ID_FIELD];
|
|
10771
|
+
}
|
|
10772
|
+
get schema() {
|
|
10773
|
+
return this.metadata.function_data.__schema;
|
|
10774
|
+
}
|
|
10775
|
+
get data() {
|
|
10776
|
+
return this.metadata.function_data.data ?? {};
|
|
10777
|
+
}
|
|
10778
|
+
/** @internal */
|
|
10779
|
+
_internalSerializeForCache() {
|
|
10780
|
+
return { metadata: this.metadata };
|
|
10781
|
+
}
|
|
10782
|
+
validate(data) {
|
|
10783
|
+
if (typeof data !== "object" || data === null) {
|
|
10784
|
+
return false;
|
|
10785
|
+
}
|
|
10786
|
+
const schemaProps = this.schema.properties;
|
|
10787
|
+
if (typeof schemaProps !== "object" || schemaProps === null) {
|
|
10788
|
+
return true;
|
|
10789
|
+
}
|
|
10790
|
+
for (const key of Object.keys(schemaProps)) {
|
|
10791
|
+
if (!(key in data)) {
|
|
10792
|
+
const required = Array.isArray(this.schema.required) ? this.schema.required : [];
|
|
10793
|
+
if (required.includes(key)) {
|
|
10794
|
+
return false;
|
|
10795
|
+
}
|
|
10796
|
+
}
|
|
10797
|
+
}
|
|
10798
|
+
return true;
|
|
10799
|
+
}
|
|
10800
|
+
static isParameters(x) {
|
|
10801
|
+
return typeof x === "object" && x !== null && "__braintrust_parameters_marker" in x && x.__braintrust_parameters_marker === true;
|
|
10802
|
+
}
|
|
10803
|
+
};
|
|
10005
10804
|
var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
|
|
10006
10805
|
|
|
10007
10806
|
// src/instrumentation/core/channel-tracing-utils.ts
|
|
@@ -10447,56 +11246,14 @@ function suppressionStore() {
|
|
|
10447
11246
|
autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
|
|
10448
11247
|
return autoInstrumentationSuppressionStore;
|
|
10449
11248
|
}
|
|
10450
|
-
function currentFrames() {
|
|
10451
|
-
return suppressionStore().getStore()?.frames ?? [];
|
|
10452
|
-
}
|
|
10453
11249
|
function isAutoInstrumentationSuppressed() {
|
|
10454
|
-
|
|
10455
|
-
return frames[frames.length - 1]?.mode === "suppress";
|
|
11250
|
+
return suppressionStore().getStore() === true;
|
|
10456
11251
|
}
|
|
10457
11252
|
function runWithAutoInstrumentationSuppressed(callback) {
|
|
10458
|
-
|
|
10459
|
-
id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
|
|
10460
|
-
mode: "suppress"
|
|
10461
|
-
};
|
|
10462
|
-
return suppressionStore().run(
|
|
10463
|
-
{ frames: [...currentFrames(), frame] },
|
|
10464
|
-
callback
|
|
10465
|
-
);
|
|
10466
|
-
}
|
|
10467
|
-
function bindAutoInstrumentationSuppressionToStart(tracingChannel) {
|
|
10468
|
-
const startChannel = tracingChannel.start;
|
|
10469
|
-
if (!startChannel) {
|
|
10470
|
-
return void 0;
|
|
10471
|
-
}
|
|
10472
|
-
const store = suppressionStore();
|
|
10473
|
-
startChannel.bindStore(store, () => ({
|
|
10474
|
-
frames: [
|
|
10475
|
-
...currentFrames(),
|
|
10476
|
-
{
|
|
10477
|
-
id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
|
|
10478
|
-
mode: "suppress"
|
|
10479
|
-
}
|
|
10480
|
-
]
|
|
10481
|
-
}));
|
|
10482
|
-
return () => {
|
|
10483
|
-
startChannel.unbindStore(store);
|
|
10484
|
-
};
|
|
11253
|
+
return suppressionStore().run(true, callback);
|
|
10485
11254
|
}
|
|
10486
|
-
function
|
|
10487
|
-
|
|
10488
|
-
id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
|
|
10489
|
-
mode: "allow"
|
|
10490
|
-
};
|
|
10491
|
-
suppressionStore().enterWith({
|
|
10492
|
-
frames: [...currentFrames(), frame]
|
|
10493
|
-
});
|
|
10494
|
-
return () => {
|
|
10495
|
-
const frames = currentFrames().filter(
|
|
10496
|
-
(candidate) => candidate.id !== frame.id
|
|
10497
|
-
);
|
|
10498
|
-
suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
|
|
10499
|
-
};
|
|
11255
|
+
function runWithAutoInstrumentationAllowed(callback) {
|
|
11256
|
+
return suppressionStore().run(void 0, callback);
|
|
10500
11257
|
}
|
|
10501
11258
|
|
|
10502
11259
|
// src/instrumentation/core/channel-tracing.ts
|
|
@@ -11086,6 +11843,131 @@ function unsubscribeAll(unsubscribers) {
|
|
|
11086
11843
|
return [];
|
|
11087
11844
|
}
|
|
11088
11845
|
|
|
11846
|
+
// src/instrumentation/core/channel-definitions.ts
|
|
11847
|
+
function channel(spec) {
|
|
11848
|
+
return spec;
|
|
11849
|
+
}
|
|
11850
|
+
function defineChannels(pkg, channels, options) {
|
|
11851
|
+
const { instrumentationName } = options;
|
|
11852
|
+
return Object.fromEntries(
|
|
11853
|
+
Object.entries(channels).map(([key, spec]) => {
|
|
11854
|
+
const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
|
|
11855
|
+
if (spec.kind === "async") {
|
|
11856
|
+
const asyncSpec = spec;
|
|
11857
|
+
const tracingChannel2 = () => isomorph_default.newTracingChannel(
|
|
11858
|
+
fullChannelName
|
|
11859
|
+
);
|
|
11860
|
+
const intercept2 = (interceptor) => {
|
|
11861
|
+
const hook = tracingChannel2();
|
|
11862
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
11863
|
+
};
|
|
11864
|
+
};
|
|
11865
|
+
return [
|
|
11866
|
+
key,
|
|
11867
|
+
{
|
|
11868
|
+
...asyncSpec,
|
|
11869
|
+
instrumentationName,
|
|
11870
|
+
intercept: intercept2,
|
|
11871
|
+
invoke: (target, thisArg, args, additional) => {
|
|
11872
|
+
const hook = tracingChannel2();
|
|
11873
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11874
|
+
},
|
|
11875
|
+
tracingChannel: tracingChannel2,
|
|
11876
|
+
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
11877
|
+
fn,
|
|
11878
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11879
|
+
context
|
|
11880
|
+
)
|
|
11881
|
+
}
|
|
11882
|
+
];
|
|
11883
|
+
}
|
|
11884
|
+
const syncSpec = spec;
|
|
11885
|
+
const tracingChannel = () => isomorph_default.newTracingChannel(
|
|
11886
|
+
fullChannelName
|
|
11887
|
+
);
|
|
11888
|
+
const intercept = (interceptor) => {
|
|
11889
|
+
const hook = tracingChannel();
|
|
11890
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
11891
|
+
};
|
|
11892
|
+
};
|
|
11893
|
+
return [
|
|
11894
|
+
key,
|
|
11895
|
+
{
|
|
11896
|
+
...syncSpec,
|
|
11897
|
+
instrumentationName,
|
|
11898
|
+
intercept,
|
|
11899
|
+
invoke: (target, thisArg, args, additional) => {
|
|
11900
|
+
const hook = tracingChannel();
|
|
11901
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11902
|
+
},
|
|
11903
|
+
tracingChannel,
|
|
11904
|
+
traceSync: (fn, context) => tracingChannel().traceSync(
|
|
11905
|
+
fn,
|
|
11906
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11907
|
+
context
|
|
11908
|
+
)
|
|
11909
|
+
}
|
|
11910
|
+
];
|
|
11911
|
+
})
|
|
11912
|
+
);
|
|
11913
|
+
}
|
|
11914
|
+
|
|
11915
|
+
// src/instrumentation/plugins/openai-channels.ts
|
|
11916
|
+
var openAIChannels = defineChannels(
|
|
11917
|
+
"openai",
|
|
11918
|
+
{
|
|
11919
|
+
filesCreateTraced: channel({
|
|
11920
|
+
channelName: "files.create-traced",
|
|
11921
|
+
kind: "async"
|
|
11922
|
+
}),
|
|
11923
|
+
batchesRetrieveTraced: channel({
|
|
11924
|
+
channelName: "batches.retrieve-traced",
|
|
11925
|
+
kind: "async"
|
|
11926
|
+
}),
|
|
11927
|
+
batchesCompleteTrace: channel({
|
|
11928
|
+
channelName: "batches.complete-trace",
|
|
11929
|
+
kind: "async"
|
|
11930
|
+
}),
|
|
11931
|
+
chatCompletionsCreate: channel({
|
|
11932
|
+
channelName: "chat.completions.create",
|
|
11933
|
+
kind: "async"
|
|
11934
|
+
}),
|
|
11935
|
+
embeddingsCreate: channel({
|
|
11936
|
+
channelName: "embeddings.create",
|
|
11937
|
+
kind: "async"
|
|
11938
|
+
}),
|
|
11939
|
+
betaChatCompletionsParse: channel({
|
|
11940
|
+
channelName: "beta.chat.completions.parse",
|
|
11941
|
+
kind: "async"
|
|
11942
|
+
}),
|
|
11943
|
+
betaChatCompletionsStream: channel({
|
|
11944
|
+
channelName: "beta.chat.completions.stream",
|
|
11945
|
+
kind: "sync-stream"
|
|
11946
|
+
}),
|
|
11947
|
+
moderationsCreate: channel({
|
|
11948
|
+
channelName: "moderations.create",
|
|
11949
|
+
kind: "async"
|
|
11950
|
+
}),
|
|
11951
|
+
responsesCreate: channel({
|
|
11952
|
+
channelName: "responses.create",
|
|
11953
|
+
kind: "async"
|
|
11954
|
+
}),
|
|
11955
|
+
responsesStream: channel({
|
|
11956
|
+
channelName: "responses.stream",
|
|
11957
|
+
kind: "sync-stream"
|
|
11958
|
+
}),
|
|
11959
|
+
responsesParse: channel({
|
|
11960
|
+
channelName: "responses.parse",
|
|
11961
|
+
kind: "async"
|
|
11962
|
+
}),
|
|
11963
|
+
responsesCompact: channel({
|
|
11964
|
+
channelName: "responses.compact",
|
|
11965
|
+
kind: "async"
|
|
11966
|
+
})
|
|
11967
|
+
},
|
|
11968
|
+
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
11969
|
+
);
|
|
11970
|
+
|
|
11089
11971
|
// src/wrappers/attachment-utils.ts
|
|
11090
11972
|
function getExtensionFromMediaType(mediaType) {
|
|
11091
11973
|
const extensionMap = {
|
|
@@ -11261,118 +12143,91 @@ function processInputAttachments(input) {
|
|
|
11261
12143
|
return processNode(input);
|
|
11262
12144
|
}
|
|
11263
12145
|
|
|
11264
|
-
// src/instrumentation/
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
...asyncSpec,
|
|
11287
|
-
instrumentationName,
|
|
11288
|
-
intercept: intercept2,
|
|
11289
|
-
invoke: (target, thisArg, args, additional) => {
|
|
11290
|
-
const hook = tracingChannel2();
|
|
11291
|
-
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11292
|
-
},
|
|
11293
|
-
tracingChannel: tracingChannel2,
|
|
11294
|
-
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
11295
|
-
fn,
|
|
11296
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11297
|
-
context
|
|
11298
|
-
)
|
|
11299
|
-
}
|
|
11300
|
-
];
|
|
12146
|
+
// src/instrumentation/plugins/openai-span-data.ts
|
|
12147
|
+
var OPENAI_METADATA_KEYS = [
|
|
12148
|
+
"model",
|
|
12149
|
+
"temperature",
|
|
12150
|
+
"top_p",
|
|
12151
|
+
"max_tokens",
|
|
12152
|
+
"frequency_penalty",
|
|
12153
|
+
"presence_penalty",
|
|
12154
|
+
"stop",
|
|
12155
|
+
"response_format",
|
|
12156
|
+
"tools",
|
|
12157
|
+
"tool_choice",
|
|
12158
|
+
"parallel_tool_calls",
|
|
12159
|
+
"max_tool_calls"
|
|
12160
|
+
];
|
|
12161
|
+
function batchMetadata(params) {
|
|
12162
|
+
const metadata = { provider: "openai" };
|
|
12163
|
+
for (const key of OPENAI_METADATA_KEYS) {
|
|
12164
|
+
try {
|
|
12165
|
+
const value = Reflect.get(params, key);
|
|
12166
|
+
if (value !== void 0) {
|
|
12167
|
+
metadata[key] = value;
|
|
11301
12168
|
}
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
|
|
12169
|
+
} catch {
|
|
12170
|
+
}
|
|
12171
|
+
}
|
|
12172
|
+
return metadata;
|
|
12173
|
+
}
|
|
12174
|
+
function extractOpenAIBatchInput(endpoint, params) {
|
|
12175
|
+
const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
|
|
12176
|
+
return {
|
|
12177
|
+
input: processInputAttachments(input),
|
|
12178
|
+
metadata: batchMetadata(params)
|
|
12179
|
+
};
|
|
12180
|
+
}
|
|
12181
|
+
function extractOpenAIChatInput(params) {
|
|
12182
|
+
const { messages, ...metadata } = params;
|
|
12183
|
+
return {
|
|
12184
|
+
input: processInputAttachments(messages),
|
|
12185
|
+
metadata: { ...metadata, provider: "openai" }
|
|
12186
|
+
};
|
|
12187
|
+
}
|
|
12188
|
+
function extractOpenAIResponsesInput(params) {
|
|
12189
|
+
const { input, ...metadata } = params;
|
|
12190
|
+
return {
|
|
12191
|
+
input: processInputAttachments(input),
|
|
12192
|
+
metadata: { ...metadata, provider: "openai" }
|
|
12193
|
+
};
|
|
12194
|
+
}
|
|
12195
|
+
function extractOpenAIResponsesMetadata(result) {
|
|
12196
|
+
if (!result) {
|
|
12197
|
+
return void 0;
|
|
12198
|
+
}
|
|
12199
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
12200
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12201
|
+
}
|
|
12202
|
+
function processImagesInOutput(output) {
|
|
12203
|
+
if (Array.isArray(output)) {
|
|
12204
|
+
return output.map(processImagesInOutput);
|
|
12205
|
+
}
|
|
12206
|
+
if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
|
|
12207
|
+
const fileExtension = output.output_format || "png";
|
|
12208
|
+
const contentType = `image/${fileExtension}`;
|
|
12209
|
+
const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
12210
|
+
let binaryString;
|
|
12211
|
+
try {
|
|
12212
|
+
binaryString = atob(output.result);
|
|
12213
|
+
} catch {
|
|
12214
|
+
return output;
|
|
12215
|
+
}
|
|
12216
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
12217
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
12218
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
12219
|
+
}
|
|
12220
|
+
return {
|
|
12221
|
+
...output,
|
|
12222
|
+
result: new Attachment({
|
|
12223
|
+
data: new Blob([bytes], { type: contentType }),
|
|
12224
|
+
filename: `${baseFilename}.${fileExtension}`,
|
|
12225
|
+
contentType
|
|
12226
|
+
})
|
|
12227
|
+
};
|
|
12228
|
+
}
|
|
12229
|
+
return output;
|
|
11331
12230
|
}
|
|
11332
|
-
|
|
11333
|
-
// src/instrumentation/plugins/openai-channels.ts
|
|
11334
|
-
var openAIChannels = defineChannels(
|
|
11335
|
-
"openai",
|
|
11336
|
-
{
|
|
11337
|
-
chatCompletionsCreate: channel({
|
|
11338
|
-
channelName: "chat.completions.create",
|
|
11339
|
-
kind: "async"
|
|
11340
|
-
}),
|
|
11341
|
-
embeddingsCreate: channel({
|
|
11342
|
-
channelName: "embeddings.create",
|
|
11343
|
-
kind: "async"
|
|
11344
|
-
}),
|
|
11345
|
-
betaChatCompletionsParse: channel({
|
|
11346
|
-
channelName: "beta.chat.completions.parse",
|
|
11347
|
-
kind: "async"
|
|
11348
|
-
}),
|
|
11349
|
-
betaChatCompletionsStream: channel({
|
|
11350
|
-
channelName: "beta.chat.completions.stream",
|
|
11351
|
-
kind: "sync-stream"
|
|
11352
|
-
}),
|
|
11353
|
-
moderationsCreate: channel({
|
|
11354
|
-
channelName: "moderations.create",
|
|
11355
|
-
kind: "async"
|
|
11356
|
-
}),
|
|
11357
|
-
responsesCreate: channel({
|
|
11358
|
-
channelName: "responses.create",
|
|
11359
|
-
kind: "async"
|
|
11360
|
-
}),
|
|
11361
|
-
responsesStream: channel({
|
|
11362
|
-
channelName: "responses.stream",
|
|
11363
|
-
kind: "sync-stream"
|
|
11364
|
-
}),
|
|
11365
|
-
responsesParse: channel({
|
|
11366
|
-
channelName: "responses.parse",
|
|
11367
|
-
kind: "async"
|
|
11368
|
-
}),
|
|
11369
|
-
responsesCompact: channel({
|
|
11370
|
-
channelName: "responses.compact",
|
|
11371
|
-
kind: "async"
|
|
11372
|
-
})
|
|
11373
|
-
},
|
|
11374
|
-
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
11375
|
-
);
|
|
11376
12231
|
|
|
11377
12232
|
// src/openai-utils.ts
|
|
11378
12233
|
var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
|
|
@@ -11429,23 +12284,573 @@ function getCachedMetricFromHeaders(headers) {
|
|
|
11429
12284
|
return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
|
|
11430
12285
|
}
|
|
11431
12286
|
|
|
12287
|
+
// src/instrumentation/plugins/openai-batch-instrumentation.ts
|
|
12288
|
+
var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
|
|
12289
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
12290
|
+
"completed",
|
|
12291
|
+
"failed",
|
|
12292
|
+
"expired",
|
|
12293
|
+
"cancelled"
|
|
12294
|
+
]);
|
|
12295
|
+
var pendingBatchTraces = /* @__PURE__ */ new Map();
|
|
12296
|
+
function read(value, key) {
|
|
12297
|
+
if (!isObject(value)) {
|
|
12298
|
+
return void 0;
|
|
12299
|
+
}
|
|
12300
|
+
try {
|
|
12301
|
+
return Reflect.get(value, key);
|
|
12302
|
+
} catch {
|
|
12303
|
+
return void 0;
|
|
12304
|
+
}
|
|
12305
|
+
}
|
|
12306
|
+
function isBatchRecordIterable(value) {
|
|
12307
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
12308
|
+
return false;
|
|
12309
|
+
}
|
|
12310
|
+
return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
|
|
12311
|
+
}
|
|
12312
|
+
function validCustomId(value) {
|
|
12313
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64;
|
|
12314
|
+
}
|
|
12315
|
+
function logBatchInstrumentationError(context, error) {
|
|
12316
|
+
debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
|
|
12317
|
+
}
|
|
12318
|
+
async function exportParent(parent) {
|
|
12319
|
+
if ("toStr" in parent && typeof parent.toStr === "function") {
|
|
12320
|
+
return parent.toStr();
|
|
12321
|
+
}
|
|
12322
|
+
if ("export" in parent && typeof parent.export === "function") {
|
|
12323
|
+
return await parent.export();
|
|
12324
|
+
}
|
|
12325
|
+
return void 0;
|
|
12326
|
+
}
|
|
12327
|
+
async function deterministicDigest(namespace, ...parts) {
|
|
12328
|
+
const encoded = new TextEncoder().encode(
|
|
12329
|
+
[namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
|
|
12330
|
+
);
|
|
12331
|
+
return new Uint8Array(
|
|
12332
|
+
await globalThis.crypto.subtle.digest("SHA-256", encoded)
|
|
12333
|
+
);
|
|
12334
|
+
}
|
|
12335
|
+
function digestHex(bytes, length) {
|
|
12336
|
+
return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
12337
|
+
}
|
|
12338
|
+
function digestUuid(bytes) {
|
|
12339
|
+
const hex = digestHex(bytes, 16);
|
|
12340
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
12341
|
+
}
|
|
12342
|
+
async function batchSpanIds(inputFileId) {
|
|
12343
|
+
const [row, span, root] = await Promise.all([
|
|
12344
|
+
deterministicDigest("openai:batch:row", inputFileId),
|
|
12345
|
+
deterministicDigest("openai:batch:span", inputFileId),
|
|
12346
|
+
deterministicDigest("openai:batch:root", inputFileId)
|
|
12347
|
+
]);
|
|
12348
|
+
return {
|
|
12349
|
+
rowId: digestUuid(row),
|
|
12350
|
+
spanId: digestHex(span, 8),
|
|
12351
|
+
rootSpanId: digestHex(root, 16)
|
|
12352
|
+
};
|
|
12353
|
+
}
|
|
12354
|
+
async function childSpanIds(inputFileId, customId) {
|
|
12355
|
+
const [row, span] = await Promise.all([
|
|
12356
|
+
deterministicDigest("openai:batch:child:row", inputFileId, customId),
|
|
12357
|
+
deterministicDigest("openai:batch:child:span", inputFileId, customId)
|
|
12358
|
+
]);
|
|
12359
|
+
return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
|
|
12360
|
+
}
|
|
12361
|
+
async function startBatchSpan(context) {
|
|
12362
|
+
const ids = await batchSpanIds(context.inputFileId);
|
|
12363
|
+
const parent = SpanComponentsV4.fromStr(context.parent);
|
|
12364
|
+
const hasParentSpan = Boolean(
|
|
12365
|
+
parent.data.row_id && parent.data.span_id && parent.data.root_span_id
|
|
12366
|
+
);
|
|
12367
|
+
return withCurrent(
|
|
12368
|
+
NOOP_SPAN,
|
|
12369
|
+
() => _internalStartSpanWithInitialMergeAndParentSpanIds(
|
|
12370
|
+
withSpanInstrumentationName(
|
|
12371
|
+
{
|
|
12372
|
+
name: "openai.batch",
|
|
12373
|
+
type: "task" /* TASK */,
|
|
12374
|
+
parent: context.parent,
|
|
12375
|
+
...!hasParentSpan ? {
|
|
12376
|
+
parentSpanIds: {
|
|
12377
|
+
parentSpanIds: [],
|
|
12378
|
+
rootSpanId: ids.rootSpanId
|
|
12379
|
+
}
|
|
12380
|
+
} : {},
|
|
12381
|
+
spanId: ids.spanId,
|
|
12382
|
+
startTime: context.taskStartTime,
|
|
12383
|
+
event: {
|
|
12384
|
+
id: ids.rowId,
|
|
12385
|
+
metadata: {
|
|
12386
|
+
endpoint: context.endpoint,
|
|
12387
|
+
input_file_id: context.inputFileId,
|
|
12388
|
+
provider: "openai"
|
|
12389
|
+
}
|
|
12390
|
+
}
|
|
12391
|
+
},
|
|
12392
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
12393
|
+
)
|
|
12394
|
+
)
|
|
12395
|
+
);
|
|
12396
|
+
}
|
|
12397
|
+
async function startBatchChild(context, taskParent, input) {
|
|
12398
|
+
const ids = await childSpanIds(context.inputFileId, input.customId);
|
|
12399
|
+
return withCurrent(
|
|
12400
|
+
NOOP_SPAN,
|
|
12401
|
+
() => _internalStartSpanWithInitialMerge(
|
|
12402
|
+
withSpanInstrumentationName(
|
|
12403
|
+
{
|
|
12404
|
+
name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
|
|
12405
|
+
type: "llm" /* LLM */,
|
|
12406
|
+
parent: taskParent,
|
|
12407
|
+
spanId: ids.spanId,
|
|
12408
|
+
startTime: context.childStartTime,
|
|
12409
|
+
event: {
|
|
12410
|
+
id: ids.rowId,
|
|
12411
|
+
...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
|
|
12412
|
+
metadata: {
|
|
12413
|
+
...input.spanData?.metadata,
|
|
12414
|
+
custom_id: input.customId,
|
|
12415
|
+
provider: "openai"
|
|
12416
|
+
}
|
|
12417
|
+
}
|
|
12418
|
+
},
|
|
12419
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
12420
|
+
)
|
|
12421
|
+
)
|
|
12422
|
+
);
|
|
12423
|
+
}
|
|
12424
|
+
async function* jsonlRecords(file, onIssue = () => {
|
|
12425
|
+
}) {
|
|
12426
|
+
const resolvedFile = await file;
|
|
12427
|
+
if (typeof resolvedFile === "string") {
|
|
12428
|
+
for (const line of resolvedFile.split("\n")) {
|
|
12429
|
+
if (!line.trim()) {
|
|
12430
|
+
continue;
|
|
12431
|
+
}
|
|
12432
|
+
try {
|
|
12433
|
+
yield JSON.parse(line.replace(/\r$/, ""));
|
|
12434
|
+
} catch (error) {
|
|
12435
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12436
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12437
|
+
}
|
|
12438
|
+
}
|
|
12439
|
+
return;
|
|
12440
|
+
}
|
|
12441
|
+
const body = read(resolvedFile, "body");
|
|
12442
|
+
const getReader = read(body, "getReader");
|
|
12443
|
+
if (isObject(body) && typeof getReader === "function") {
|
|
12444
|
+
let reader;
|
|
12445
|
+
try {
|
|
12446
|
+
reader = Reflect.apply(getReader, body, []);
|
|
12447
|
+
const decoder = new TextDecoder();
|
|
12448
|
+
let pending = "";
|
|
12449
|
+
while (true) {
|
|
12450
|
+
const readChunk = read(reader, "read");
|
|
12451
|
+
if (typeof readChunk !== "function") {
|
|
12452
|
+
throw new Error("Response body stream has no read method");
|
|
12453
|
+
}
|
|
12454
|
+
const chunk = await Reflect.apply(readChunk, reader, []);
|
|
12455
|
+
if (!isObject(chunk)) {
|
|
12456
|
+
throw new Error("Response body stream returned an invalid chunk");
|
|
12457
|
+
}
|
|
12458
|
+
if (chunk.done === true) {
|
|
12459
|
+
pending += decoder.decode();
|
|
12460
|
+
break;
|
|
12461
|
+
}
|
|
12462
|
+
if (!(chunk.value instanceof Uint8Array)) {
|
|
12463
|
+
throw new Error("Response body stream returned a non-byte chunk");
|
|
12464
|
+
}
|
|
12465
|
+
pending += decoder.decode(chunk.value, { stream: true });
|
|
12466
|
+
let newline = pending.indexOf("\n");
|
|
12467
|
+
while (newline !== -1) {
|
|
12468
|
+
const line = pending.slice(0, newline).replace(/\r$/, "");
|
|
12469
|
+
pending = pending.slice(newline + 1);
|
|
12470
|
+
if (line.trim()) {
|
|
12471
|
+
try {
|
|
12472
|
+
yield JSON.parse(line);
|
|
12473
|
+
} catch (error) {
|
|
12474
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12475
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12476
|
+
}
|
|
12477
|
+
}
|
|
12478
|
+
newline = pending.indexOf("\n");
|
|
12479
|
+
}
|
|
12480
|
+
}
|
|
12481
|
+
if (pending.trim()) {
|
|
12482
|
+
try {
|
|
12483
|
+
yield JSON.parse(pending.replace(/\r$/, ""));
|
|
12484
|
+
} catch (error) {
|
|
12485
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12486
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12487
|
+
}
|
|
12488
|
+
}
|
|
12489
|
+
} catch (error) {
|
|
12490
|
+
logBatchInstrumentationError("could not read JSONL response body", error);
|
|
12491
|
+
onIssue(new Error("OpenAI Batch response body could not be read"));
|
|
12492
|
+
} finally {
|
|
12493
|
+
const releaseLock = read(reader, "releaseLock");
|
|
12494
|
+
if (typeof releaseLock === "function") {
|
|
12495
|
+
try {
|
|
12496
|
+
Reflect.apply(releaseLock, reader, []);
|
|
12497
|
+
} catch (error) {
|
|
12498
|
+
logBatchInstrumentationError(
|
|
12499
|
+
"could not release stream reader",
|
|
12500
|
+
error
|
|
12501
|
+
);
|
|
12502
|
+
}
|
|
12503
|
+
}
|
|
12504
|
+
}
|
|
12505
|
+
return;
|
|
12506
|
+
}
|
|
12507
|
+
if (isBatchRecordIterable(resolvedFile)) {
|
|
12508
|
+
for await (const record of resolvedFile) {
|
|
12509
|
+
yield record;
|
|
12510
|
+
}
|
|
12511
|
+
return;
|
|
12512
|
+
}
|
|
12513
|
+
logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
|
|
12514
|
+
onIssue(new Error("OpenAI Batch file source is invalid"));
|
|
12515
|
+
}
|
|
12516
|
+
async function readBatchInputs(file) {
|
|
12517
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
12518
|
+
const issues = [];
|
|
12519
|
+
let endpoint;
|
|
12520
|
+
try {
|
|
12521
|
+
for await (const value of jsonlRecords(
|
|
12522
|
+
file,
|
|
12523
|
+
(issue) => issues.push(issue)
|
|
12524
|
+
)) {
|
|
12525
|
+
const customId = read(value, "custom_id");
|
|
12526
|
+
const url = read(value, "url");
|
|
12527
|
+
const body = read(value, "body");
|
|
12528
|
+
if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
|
|
12529
|
+
issues.push(new Error("OpenAI Batch input contains an invalid record"));
|
|
12530
|
+
continue;
|
|
12531
|
+
}
|
|
12532
|
+
endpoint = url;
|
|
12533
|
+
let spanData;
|
|
12534
|
+
try {
|
|
12535
|
+
spanData = extractOpenAIBatchInput(url, body);
|
|
12536
|
+
} catch (error) {
|
|
12537
|
+
logBatchInstrumentationError("could not extract batch input", error);
|
|
12538
|
+
}
|
|
12539
|
+
inputs.set(customId, { customId, spanData });
|
|
12540
|
+
}
|
|
12541
|
+
} catch (error) {
|
|
12542
|
+
logBatchInstrumentationError("could not process input file", error);
|
|
12543
|
+
issues.push(new Error("OpenAI Batch input file could not be processed"));
|
|
12544
|
+
}
|
|
12545
|
+
if (!endpoint || inputs.size === 0) {
|
|
12546
|
+
issues.push(new Error("OpenAI Batch input contains no supported records"));
|
|
12547
|
+
}
|
|
12548
|
+
return { endpoint, inputs, issues };
|
|
12549
|
+
}
|
|
12550
|
+
async function writePendingSpans(trace, endTime) {
|
|
12551
|
+
const task = await startBatchSpan(trace.context);
|
|
12552
|
+
const taskParent = await task.export();
|
|
12553
|
+
for (const input of trace.inputs.values()) {
|
|
12554
|
+
try {
|
|
12555
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
12556
|
+
if (endTime !== void 0) {
|
|
12557
|
+
child.end({ endTime });
|
|
12558
|
+
}
|
|
12559
|
+
} catch (error) {
|
|
12560
|
+
logBatchInstrumentationError("could not write batch request span", error);
|
|
12561
|
+
}
|
|
12562
|
+
}
|
|
12563
|
+
if (endTime !== void 0) {
|
|
12564
|
+
if (trace.status && trace.status !== "completed") {
|
|
12565
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12566
|
+
}
|
|
12567
|
+
task.end({ endTime });
|
|
12568
|
+
}
|
|
12569
|
+
}
|
|
12570
|
+
var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
|
|
12571
|
+
const startTime = getCurrentUnixTimestamp();
|
|
12572
|
+
const inputPromise = readBatchInputs(args[0].inputFileContent);
|
|
12573
|
+
const parentPromise = exportParent(args[0].parent);
|
|
12574
|
+
const file = await Reflect.apply(target, thisArg, args);
|
|
12575
|
+
try {
|
|
12576
|
+
const inputFileId = read(file, "id");
|
|
12577
|
+
const [inputData, exportedParent2] = await Promise.all([
|
|
12578
|
+
inputPromise,
|
|
12579
|
+
parentPromise
|
|
12580
|
+
]);
|
|
12581
|
+
if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
|
|
12582
|
+
if (inputData.issues[0]) {
|
|
12583
|
+
logBatchInstrumentationError(
|
|
12584
|
+
"skipped invalid input file",
|
|
12585
|
+
inputData.issues[0]
|
|
12586
|
+
);
|
|
12587
|
+
}
|
|
12588
|
+
return file;
|
|
12589
|
+
}
|
|
12590
|
+
const trace = {
|
|
12591
|
+
context: {
|
|
12592
|
+
inputFileId,
|
|
12593
|
+
endpoint: inputData.endpoint,
|
|
12594
|
+
parent: exportedParent2,
|
|
12595
|
+
taskStartTime: startTime,
|
|
12596
|
+
childStartTime: startTime
|
|
12597
|
+
},
|
|
12598
|
+
inputs: inputData.inputs
|
|
12599
|
+
};
|
|
12600
|
+
pendingBatchTraces.set(inputFileId, trace);
|
|
12601
|
+
await writePendingSpans(trace);
|
|
12602
|
+
} catch (error) {
|
|
12603
|
+
logBatchInstrumentationError("could not start batch spans", error);
|
|
12604
|
+
}
|
|
12605
|
+
return file;
|
|
12606
|
+
};
|
|
12607
|
+
function validTimestamp(value) {
|
|
12608
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
12609
|
+
}
|
|
12610
|
+
function terminalEndTime(batch, startTime) {
|
|
12611
|
+
let timestamp;
|
|
12612
|
+
switch (batch.status) {
|
|
12613
|
+
case "completed":
|
|
12614
|
+
timestamp = batch.completed_at;
|
|
12615
|
+
break;
|
|
12616
|
+
case "failed":
|
|
12617
|
+
timestamp = batch.failed_at;
|
|
12618
|
+
break;
|
|
12619
|
+
case "expired":
|
|
12620
|
+
timestamp = batch.expired_at;
|
|
12621
|
+
break;
|
|
12622
|
+
default:
|
|
12623
|
+
timestamp = batch.cancelled_at;
|
|
12624
|
+
}
|
|
12625
|
+
return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
|
|
12626
|
+
}
|
|
12627
|
+
async function updateBatchTimestamps(batch) {
|
|
12628
|
+
const trace = pendingBatchTraces.get(batch.input_file_id);
|
|
12629
|
+
if (!trace || trace.context.endpoint !== batch.endpoint) {
|
|
12630
|
+
return;
|
|
12631
|
+
}
|
|
12632
|
+
if (validTimestamp(batch.created_at)) {
|
|
12633
|
+
trace.context.taskStartTime = batch.created_at;
|
|
12634
|
+
}
|
|
12635
|
+
trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
|
|
12636
|
+
trace.status = batch.status;
|
|
12637
|
+
if (TERMINAL_STATUSES.has(batch.status)) {
|
|
12638
|
+
trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
|
|
12639
|
+
}
|
|
12640
|
+
await writePendingSpans(trace, trace.endTime);
|
|
12641
|
+
}
|
|
12642
|
+
var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
|
|
12643
|
+
try {
|
|
12644
|
+
await updateBatchTimestamps(batch);
|
|
12645
|
+
} catch (error) {
|
|
12646
|
+
logBatchInstrumentationError("could not update batch timestamps", error);
|
|
12647
|
+
}
|
|
12648
|
+
return batch;
|
|
12649
|
+
});
|
|
12650
|
+
function errorFromResult(result) {
|
|
12651
|
+
const error = read(result.value, "error");
|
|
12652
|
+
if (isObject(error)) {
|
|
12653
|
+
const message = read(error, "message");
|
|
12654
|
+
return new Error(
|
|
12655
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
12656
|
+
);
|
|
12657
|
+
}
|
|
12658
|
+
const response = read(result.value, "response");
|
|
12659
|
+
const statusCode = read(response, "status_code");
|
|
12660
|
+
if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
|
|
12661
|
+
const message = read(read(read(response, "body"), "error"), "message");
|
|
12662
|
+
return new Error(
|
|
12663
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
12664
|
+
);
|
|
12665
|
+
}
|
|
12666
|
+
return void 0;
|
|
12667
|
+
}
|
|
12668
|
+
async function completeBatchResult(context, taskParent, endTime, input, result) {
|
|
12669
|
+
const child = await startBatchChild(context, taskParent, input);
|
|
12670
|
+
try {
|
|
12671
|
+
const resultError = errorFromResult(result);
|
|
12672
|
+
const responseBody = read(read(result.value, "response"), "body");
|
|
12673
|
+
if (resultError) {
|
|
12674
|
+
child.log({ error: resultError });
|
|
12675
|
+
} else if (isObject(responseBody)) {
|
|
12676
|
+
const model = read(responseBody, "model");
|
|
12677
|
+
child.log({
|
|
12678
|
+
output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
|
|
12679
|
+
...typeof model === "string" ? { metadata: { model } } : {},
|
|
12680
|
+
metrics: parseMetricsFromUsage(read(responseBody, "usage"))
|
|
12681
|
+
});
|
|
12682
|
+
} else {
|
|
12683
|
+
child.log({ error: new Error("OpenAI Batch response body is missing") });
|
|
12684
|
+
}
|
|
12685
|
+
} catch (error) {
|
|
12686
|
+
child.log({ error });
|
|
12687
|
+
} finally {
|
|
12688
|
+
child.end({ endTime });
|
|
12689
|
+
}
|
|
12690
|
+
}
|
|
12691
|
+
async function completeResultFile({
|
|
12692
|
+
context,
|
|
12693
|
+
endTime,
|
|
12694
|
+
file,
|
|
12695
|
+
inputs,
|
|
12696
|
+
issues,
|
|
12697
|
+
seen,
|
|
12698
|
+
source,
|
|
12699
|
+
taskParent
|
|
12700
|
+
}) {
|
|
12701
|
+
if (file === void 0) {
|
|
12702
|
+
return;
|
|
12703
|
+
}
|
|
12704
|
+
for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
|
|
12705
|
+
const customId = read(value, "custom_id");
|
|
12706
|
+
if (!validCustomId(customId) || !isObject(value)) {
|
|
12707
|
+
issues.push(
|
|
12708
|
+
new Error("OpenAI Batch result is missing a valid custom_id")
|
|
12709
|
+
);
|
|
12710
|
+
continue;
|
|
12711
|
+
}
|
|
12712
|
+
if (seen.has(customId)) {
|
|
12713
|
+
issues.push(new Error("OpenAI Batch result contains a duplicate"));
|
|
12714
|
+
continue;
|
|
12715
|
+
}
|
|
12716
|
+
const input = inputs.get(customId);
|
|
12717
|
+
if (!input) {
|
|
12718
|
+
issues.push(
|
|
12719
|
+
new Error("OpenAI Batch result does not match an input record")
|
|
12720
|
+
);
|
|
12721
|
+
continue;
|
|
12722
|
+
}
|
|
12723
|
+
seen.add(customId);
|
|
12724
|
+
await completeBatchResult(context, taskParent, endTime, input, {
|
|
12725
|
+
value,
|
|
12726
|
+
source
|
|
12727
|
+
});
|
|
12728
|
+
}
|
|
12729
|
+
}
|
|
12730
|
+
function sameInputs(first, second) {
|
|
12731
|
+
return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
|
|
12732
|
+
}
|
|
12733
|
+
async function contextForCompletion(inputFileId, inputData) {
|
|
12734
|
+
if (!inputData.endpoint || inputData.issues.length > 0) {
|
|
12735
|
+
return void 0;
|
|
12736
|
+
}
|
|
12737
|
+
const existing = pendingBatchTraces.get(inputFileId);
|
|
12738
|
+
if (existing) {
|
|
12739
|
+
if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
|
|
12740
|
+
return void 0;
|
|
12741
|
+
}
|
|
12742
|
+
return { ...existing, inputs: inputData.inputs };
|
|
12743
|
+
}
|
|
12744
|
+
const parent = await exportParent(getSpanParentObject());
|
|
12745
|
+
if (!parent) {
|
|
12746
|
+
return void 0;
|
|
12747
|
+
}
|
|
12748
|
+
const startTime = getCurrentUnixTimestamp();
|
|
12749
|
+
return {
|
|
12750
|
+
context: {
|
|
12751
|
+
inputFileId,
|
|
12752
|
+
endpoint: inputData.endpoint,
|
|
12753
|
+
parent,
|
|
12754
|
+
taskStartTime: startTime,
|
|
12755
|
+
childStartTime: startTime
|
|
12756
|
+
},
|
|
12757
|
+
inputs: inputData.inputs
|
|
12758
|
+
};
|
|
12759
|
+
}
|
|
12760
|
+
async function completeBatch(args) {
|
|
12761
|
+
const inputData = await readBatchInputs(args.inputFileContent);
|
|
12762
|
+
const trace = await contextForCompletion(args.inputFileId, inputData);
|
|
12763
|
+
if (!trace) {
|
|
12764
|
+
logBatchInstrumentationError(
|
|
12765
|
+
"left batch spans pending",
|
|
12766
|
+
inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
|
|
12767
|
+
);
|
|
12768
|
+
return;
|
|
12769
|
+
}
|
|
12770
|
+
const endTime = trace.endTime ?? getCurrentUnixTimestamp();
|
|
12771
|
+
const task = await startBatchSpan(trace.context);
|
|
12772
|
+
const taskParent = await task.export();
|
|
12773
|
+
const issues = [];
|
|
12774
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12775
|
+
await Promise.all([
|
|
12776
|
+
completeResultFile({
|
|
12777
|
+
context: trace.context,
|
|
12778
|
+
endTime,
|
|
12779
|
+
file: args.outputFileContent,
|
|
12780
|
+
inputs: trace.inputs,
|
|
12781
|
+
issues,
|
|
12782
|
+
seen,
|
|
12783
|
+
source: "output",
|
|
12784
|
+
taskParent
|
|
12785
|
+
}),
|
|
12786
|
+
completeResultFile({
|
|
12787
|
+
context: trace.context,
|
|
12788
|
+
endTime,
|
|
12789
|
+
file: args.errorFileContent,
|
|
12790
|
+
inputs: trace.inputs,
|
|
12791
|
+
issues,
|
|
12792
|
+
seen,
|
|
12793
|
+
source: "error",
|
|
12794
|
+
taskParent
|
|
12795
|
+
})
|
|
12796
|
+
]);
|
|
12797
|
+
if (issues.length > 0) {
|
|
12798
|
+
logBatchInstrumentationError("left batch spans pending", issues[0]);
|
|
12799
|
+
return;
|
|
12800
|
+
}
|
|
12801
|
+
const missing = [...trace.inputs.values()].filter(
|
|
12802
|
+
({ customId }) => !seen.has(customId)
|
|
12803
|
+
);
|
|
12804
|
+
if (!trace.status || trace.status === "completed") {
|
|
12805
|
+
if (missing.length > 0) {
|
|
12806
|
+
logBatchInstrumentationError(
|
|
12807
|
+
"left batch spans pending",
|
|
12808
|
+
new Error("OpenAI Batch result files are incomplete")
|
|
12809
|
+
);
|
|
12810
|
+
return;
|
|
12811
|
+
}
|
|
12812
|
+
} else {
|
|
12813
|
+
for (const input of missing) {
|
|
12814
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
12815
|
+
child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12816
|
+
child.end({ endTime });
|
|
12817
|
+
}
|
|
12818
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12819
|
+
}
|
|
12820
|
+
task.end({ endTime });
|
|
12821
|
+
pendingBatchTraces.delete(args.inputFileId);
|
|
12822
|
+
}
|
|
12823
|
+
var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
|
|
12824
|
+
try {
|
|
12825
|
+
await completeBatch(args[0]);
|
|
12826
|
+
} catch (error) {
|
|
12827
|
+
logBatchInstrumentationError("could not complete batch", error);
|
|
12828
|
+
}
|
|
12829
|
+
return result;
|
|
12830
|
+
});
|
|
12831
|
+
|
|
11432
12832
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
11433
12833
|
var OpenAIPlugin = class extends BasePlugin {
|
|
11434
12834
|
constructor() {
|
|
11435
12835
|
super();
|
|
11436
12836
|
}
|
|
11437
12837
|
onEnable() {
|
|
12838
|
+
this.unsubscribers.push(
|
|
12839
|
+
openAIChannels.filesCreateTraced.intercept(
|
|
12840
|
+
interceptOpenAIFilesCreateTraced
|
|
12841
|
+
),
|
|
12842
|
+
openAIChannels.batchesRetrieveTraced.intercept(
|
|
12843
|
+
interceptOpenAIBatchesRetrieveTraced
|
|
12844
|
+
),
|
|
12845
|
+
openAIChannels.batchesCompleteTrace.intercept(
|
|
12846
|
+
interceptOpenAIBatchTraceComplete
|
|
12847
|
+
)
|
|
12848
|
+
);
|
|
11438
12849
|
this.unsubscribers.push(
|
|
11439
12850
|
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
11440
12851
|
name: "Chat Completion",
|
|
11441
12852
|
type: "llm" /* LLM */,
|
|
11442
|
-
extractInput: ([params]) =>
|
|
11443
|
-
const { messages, ...metadata } = params;
|
|
11444
|
-
return {
|
|
11445
|
-
input: processInputAttachments(messages),
|
|
11446
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11447
|
-
};
|
|
11448
|
-
},
|
|
12853
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
11449
12854
|
extractOutput: (result) => {
|
|
11450
12855
|
return result?.choices;
|
|
11451
12856
|
},
|
|
@@ -11491,13 +12896,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11491
12896
|
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
11492
12897
|
name: "Chat Completion",
|
|
11493
12898
|
type: "llm" /* LLM */,
|
|
11494
|
-
extractInput: ([params]) =>
|
|
11495
|
-
const { messages, ...metadata } = params;
|
|
11496
|
-
return {
|
|
11497
|
-
input: processInputAttachments(messages),
|
|
11498
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11499
|
-
};
|
|
11500
|
-
},
|
|
12899
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
11501
12900
|
extractOutput: (result) => {
|
|
11502
12901
|
return result?.choices;
|
|
11503
12902
|
},
|
|
@@ -11519,13 +12918,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11519
12918
|
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
11520
12919
|
name: "Chat Completion",
|
|
11521
12920
|
type: "llm" /* LLM */,
|
|
11522
|
-
extractInput: ([params]) =>
|
|
11523
|
-
const { messages, ...metadata } = params;
|
|
11524
|
-
return {
|
|
11525
|
-
input: processInputAttachments(messages),
|
|
11526
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11527
|
-
};
|
|
11528
|
-
}
|
|
12921
|
+
extractInput: ([params]) => extractOpenAIChatInput(params)
|
|
11529
12922
|
})
|
|
11530
12923
|
);
|
|
11531
12924
|
this.unsubscribers.push(
|
|
@@ -11555,23 +12948,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11555
12948
|
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
11556
12949
|
name: "openai.responses.create",
|
|
11557
12950
|
type: "llm" /* LLM */,
|
|
11558
|
-
extractInput: ([params]) =>
|
|
11559
|
-
const { input, ...metadata } = params;
|
|
11560
|
-
return {
|
|
11561
|
-
input: processInputAttachments(input),
|
|
11562
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11563
|
-
};
|
|
11564
|
-
},
|
|
12951
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11565
12952
|
extractOutput: (result) => {
|
|
11566
12953
|
return processImagesInOutput(result?.output);
|
|
11567
12954
|
},
|
|
11568
|
-
extractMetadata: (result) =>
|
|
11569
|
-
if (!result) {
|
|
11570
|
-
return void 0;
|
|
11571
|
-
}
|
|
11572
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
11573
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11574
|
-
},
|
|
12955
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
11575
12956
|
extractMetrics: (result, startTime, endEvent) => {
|
|
11576
12957
|
const metrics = withCachedMetric(
|
|
11577
12958
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -11590,13 +12971,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11590
12971
|
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
11591
12972
|
name: "openai.responses.create",
|
|
11592
12973
|
type: "llm" /* LLM */,
|
|
11593
|
-
extractInput: ([params]) =>
|
|
11594
|
-
const { input, ...metadata } = params;
|
|
11595
|
-
return {
|
|
11596
|
-
input: processInputAttachments(input),
|
|
11597
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11598
|
-
};
|
|
11599
|
-
},
|
|
12974
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11600
12975
|
extractFromEvent: (event) => {
|
|
11601
12976
|
if (event.type !== "response.completed" || !event.response) {
|
|
11602
12977
|
return {};
|
|
@@ -11619,23 +12994,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11619
12994
|
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
11620
12995
|
name: "openai.responses.parse",
|
|
11621
12996
|
type: "llm" /* LLM */,
|
|
11622
|
-
extractInput: ([params]) =>
|
|
11623
|
-
const { input, ...metadata } = params;
|
|
11624
|
-
return {
|
|
11625
|
-
input: processInputAttachments(input),
|
|
11626
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11627
|
-
};
|
|
11628
|
-
},
|
|
12997
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11629
12998
|
extractOutput: (result) => {
|
|
11630
12999
|
return processImagesInOutput(result?.output);
|
|
11631
13000
|
},
|
|
11632
|
-
extractMetadata: (result) =>
|
|
11633
|
-
if (!result) {
|
|
11634
|
-
return void 0;
|
|
11635
|
-
}
|
|
11636
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
11637
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11638
|
-
},
|
|
13001
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
11639
13002
|
extractMetrics: (result, startTime, endEvent) => {
|
|
11640
13003
|
const metrics = withCachedMetric(
|
|
11641
13004
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -11654,23 +13017,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11654
13017
|
traceAsyncChannel(openAIChannels.responsesCompact, {
|
|
11655
13018
|
name: "openai.responses.compact",
|
|
11656
13019
|
type: "llm" /* LLM */,
|
|
11657
|
-
extractInput: ([params]) =>
|
|
11658
|
-
const { input, ...metadata } = params;
|
|
11659
|
-
return {
|
|
11660
|
-
input: processInputAttachments(input),
|
|
11661
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11662
|
-
};
|
|
11663
|
-
},
|
|
13020
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11664
13021
|
extractOutput: (result) => {
|
|
11665
13022
|
return processImagesInOutput(result?.output);
|
|
11666
13023
|
},
|
|
11667
|
-
extractMetadata: (result) =>
|
|
11668
|
-
if (!result) {
|
|
11669
|
-
return void 0;
|
|
11670
|
-
}
|
|
11671
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
11672
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11673
|
-
},
|
|
13024
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
11674
13025
|
extractMetrics: (result, startTime, endEvent) => {
|
|
11675
13026
|
const metrics = withCachedMetric(
|
|
11676
13027
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -11726,35 +13077,6 @@ function withCachedMetric(metrics, result, endEvent) {
|
|
|
11726
13077
|
cached
|
|
11727
13078
|
};
|
|
11728
13079
|
}
|
|
11729
|
-
function processImagesInOutput(output) {
|
|
11730
|
-
if (Array.isArray(output)) {
|
|
11731
|
-
return output.map(processImagesInOutput);
|
|
11732
|
-
}
|
|
11733
|
-
if (isObject(output)) {
|
|
11734
|
-
if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
|
|
11735
|
-
const fileExtension = output.output_format || "png";
|
|
11736
|
-
const contentType = `image/${fileExtension}`;
|
|
11737
|
-
const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
11738
|
-
const filename = `${baseFilename}.${fileExtension}`;
|
|
11739
|
-
const binaryString = atob(output.result);
|
|
11740
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
11741
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
11742
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
11743
|
-
}
|
|
11744
|
-
const blob = new Blob([bytes], { type: contentType });
|
|
11745
|
-
const attachment = new Attachment({
|
|
11746
|
-
data: blob,
|
|
11747
|
-
filename,
|
|
11748
|
-
contentType
|
|
11749
|
-
});
|
|
11750
|
-
return {
|
|
11751
|
-
...output,
|
|
11752
|
-
result: attachment
|
|
11753
|
-
};
|
|
11754
|
-
}
|
|
11755
|
-
}
|
|
11756
|
-
return output;
|
|
11757
|
-
}
|
|
11758
13080
|
function mergeLogprobTokens(existing, incoming) {
|
|
11759
13081
|
if (incoming === void 0) {
|
|
11760
13082
|
return existing;
|
|
@@ -11785,13 +13107,33 @@ function aggregateChatLogprobs(existing, incoming) {
|
|
|
11785
13107
|
}
|
|
11786
13108
|
return aggregated;
|
|
11787
13109
|
}
|
|
13110
|
+
function createAggregatedChatChoice(index) {
|
|
13111
|
+
return {
|
|
13112
|
+
index,
|
|
13113
|
+
role: void 0,
|
|
13114
|
+
content: void 0,
|
|
13115
|
+
refusal: void 0,
|
|
13116
|
+
toolCallsByIndex: /* @__PURE__ */ new Map(),
|
|
13117
|
+
logprobs: void 0,
|
|
13118
|
+
finish_reason: void 0
|
|
13119
|
+
};
|
|
13120
|
+
}
|
|
13121
|
+
function toChatChoice(choice) {
|
|
13122
|
+
const toolCalls = Array.from(choice.toolCallsByIndex.entries()).sort(([left], [right]) => left - right).map(([, toolCall]) => toolCall);
|
|
13123
|
+
return {
|
|
13124
|
+
index: choice.index,
|
|
13125
|
+
message: {
|
|
13126
|
+
role: choice.role,
|
|
13127
|
+
content: choice.content,
|
|
13128
|
+
...choice.refusal !== void 0 ? { refusal: choice.refusal } : {},
|
|
13129
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
13130
|
+
},
|
|
13131
|
+
logprobs: choice.logprobs ?? null,
|
|
13132
|
+
finish_reason: choice.finish_reason
|
|
13133
|
+
};
|
|
13134
|
+
}
|
|
11788
13135
|
function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
|
|
11789
|
-
|
|
11790
|
-
let content = void 0;
|
|
11791
|
-
let refusal = void 0;
|
|
11792
|
-
let tool_calls = void 0;
|
|
11793
|
-
let logprobs = void 0;
|
|
11794
|
-
let finish_reason = void 0;
|
|
13136
|
+
const choicesByIndex = /* @__PURE__ */ new Map();
|
|
11795
13137
|
let metrics = {};
|
|
11796
13138
|
for (const chunk of chunks) {
|
|
11797
13139
|
if (chunk.usage) {
|
|
@@ -11800,62 +13142,75 @@ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
|
|
|
11800
13142
|
...parseMetricsFromUsage(chunk.usage)
|
|
11801
13143
|
};
|
|
11802
13144
|
}
|
|
11803
|
-
const
|
|
11804
|
-
if (!
|
|
11805
|
-
continue;
|
|
11806
|
-
}
|
|
11807
|
-
if (choice.finish_reason) {
|
|
11808
|
-
finish_reason = choice.finish_reason;
|
|
11809
|
-
}
|
|
11810
|
-
logprobs = aggregateChatLogprobs(logprobs, choice.logprobs);
|
|
11811
|
-
const delta = choice.delta;
|
|
11812
|
-
if (!delta) {
|
|
13145
|
+
const choices = chunk.choices;
|
|
13146
|
+
if (!choices?.length) {
|
|
11813
13147
|
continue;
|
|
11814
13148
|
}
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
13149
|
+
for (const choice of choices) {
|
|
13150
|
+
const choiceIndex = choice.index;
|
|
13151
|
+
let aggregatedChoice = choicesByIndex.get(choiceIndex);
|
|
13152
|
+
if (!aggregatedChoice) {
|
|
13153
|
+
aggregatedChoice = createAggregatedChatChoice(choiceIndex);
|
|
13154
|
+
choicesByIndex.set(choiceIndex, aggregatedChoice);
|
|
13155
|
+
}
|
|
13156
|
+
if (choice.finish_reason) {
|
|
13157
|
+
aggregatedChoice.finish_reason = choice.finish_reason;
|
|
13158
|
+
}
|
|
13159
|
+
aggregatedChoice.logprobs = aggregateChatLogprobs(
|
|
13160
|
+
aggregatedChoice.logprobs,
|
|
13161
|
+
choice.logprobs
|
|
13162
|
+
);
|
|
13163
|
+
const delta = choice.delta;
|
|
13164
|
+
if (!delta) {
|
|
13165
|
+
continue;
|
|
13166
|
+
}
|
|
13167
|
+
if (delta.finish_reason) {
|
|
13168
|
+
aggregatedChoice.finish_reason = delta.finish_reason;
|
|
13169
|
+
}
|
|
13170
|
+
if (!aggregatedChoice.role && delta.role) {
|
|
13171
|
+
aggregatedChoice.role = delta.role;
|
|
13172
|
+
}
|
|
13173
|
+
if (delta.content) {
|
|
13174
|
+
aggregatedChoice.content = (aggregatedChoice.content || "") + delta.content;
|
|
13175
|
+
}
|
|
13176
|
+
if (delta.refusal) {
|
|
13177
|
+
aggregatedChoice.refusal = (aggregatedChoice.refusal || "") + delta.refusal;
|
|
13178
|
+
}
|
|
13179
|
+
if (delta.tool_calls) {
|
|
13180
|
+
for (const toolDelta of delta.tool_calls) {
|
|
13181
|
+
let aggregatedToolCall = aggregatedChoice.toolCallsByIndex.get(
|
|
13182
|
+
toolDelta.index
|
|
13183
|
+
);
|
|
13184
|
+
if (!aggregatedToolCall) {
|
|
13185
|
+
aggregatedToolCall = {
|
|
13186
|
+
function: { arguments: "" }
|
|
13187
|
+
};
|
|
13188
|
+
aggregatedChoice.toolCallsByIndex.set(
|
|
13189
|
+
toolDelta.index,
|
|
13190
|
+
aggregatedToolCall
|
|
13191
|
+
);
|
|
11836
13192
|
}
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
13193
|
+
if (toolDelta.id !== void 0) {
|
|
13194
|
+
aggregatedToolCall.id = toolDelta.id;
|
|
13195
|
+
}
|
|
13196
|
+
if (toolDelta.type !== void 0) {
|
|
13197
|
+
aggregatedToolCall.type = toolDelta.type;
|
|
13198
|
+
}
|
|
13199
|
+
if (toolDelta.function?.name !== void 0) {
|
|
13200
|
+
aggregatedToolCall.function.name = toolDelta.function.name;
|
|
13201
|
+
}
|
|
13202
|
+
if (toolDelta.function?.arguments !== void 0) {
|
|
13203
|
+
aggregatedToolCall.function.arguments += toolDelta.function.arguments;
|
|
13204
|
+
}
|
|
13205
|
+
}
|
|
11840
13206
|
}
|
|
11841
13207
|
}
|
|
11842
13208
|
}
|
|
11843
13209
|
metrics = withCachedMetric(metrics, streamResult, endEvent);
|
|
13210
|
+
const output = Array.from(choicesByIndex.values()).sort((left, right) => left.index - right.index).map(toChatChoice);
|
|
11844
13211
|
return {
|
|
11845
13212
|
metrics,
|
|
11846
|
-
output: [
|
|
11847
|
-
{
|
|
11848
|
-
index: 0,
|
|
11849
|
-
message: {
|
|
11850
|
-
role,
|
|
11851
|
-
content,
|
|
11852
|
-
...refusal !== void 0 ? { refusal } : {},
|
|
11853
|
-
tool_calls
|
|
11854
|
-
},
|
|
11855
|
-
logprobs: logprobs ?? null,
|
|
11856
|
-
finish_reason
|
|
11857
|
-
}
|
|
11858
|
-
]
|
|
13213
|
+
output: output.length > 0 ? output : [toChatChoice(createAggregatedChatChoice(0))]
|
|
11859
13214
|
};
|
|
11860
13215
|
}
|
|
11861
13216
|
function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
|
|
@@ -13178,6 +14533,12 @@ function parseMetricsFromUsage2(usage) {
|
|
|
13178
14533
|
}
|
|
13179
14534
|
}
|
|
13180
14535
|
}
|
|
14536
|
+
if (isObject(usage.output_tokens_details)) {
|
|
14537
|
+
const thinkingTokens = usage.output_tokens_details.thinking_tokens;
|
|
14538
|
+
if (typeof thinkingTokens === "number") {
|
|
14539
|
+
metrics.completion_reasoning_tokens = thinkingTokens;
|
|
14540
|
+
}
|
|
14541
|
+
}
|
|
13181
14542
|
if (isObject(usage.server_tool_use)) {
|
|
13182
14543
|
for (const [name, value] of Object.entries(usage.server_tool_use)) {
|
|
13183
14544
|
if (typeof value === "number") {
|
|
@@ -14134,7 +15495,6 @@ function endHarnessTurn(parent) {
|
|
|
14134
15495
|
function braintrustAISDKTelemetry() {
|
|
14135
15496
|
const operations = /* @__PURE__ */ new Map();
|
|
14136
15497
|
const operationKeysByCallId = /* @__PURE__ */ new Map();
|
|
14137
|
-
const workflowOperationKeyStore = isomorph_default.newAsyncLocalStorage();
|
|
14138
15498
|
const modelSpans = /* @__PURE__ */ new Map();
|
|
14139
15499
|
const objectSpans = /* @__PURE__ */ new Map();
|
|
14140
15500
|
const embedSpans = /* @__PURE__ */ new Map();
|
|
@@ -14177,9 +15537,6 @@ function braintrustAISDKTelemetry() {
|
|
|
14177
15537
|
return;
|
|
14178
15538
|
}
|
|
14179
15539
|
operations.delete(operationKey);
|
|
14180
|
-
if (workflowOperationKeyStore.getStore() === operationKey) {
|
|
14181
|
-
workflowOperationKeyStore.enterWith(void 0);
|
|
14182
|
-
}
|
|
14183
15540
|
const keys = operationKeysByCallId.get(state.callId);
|
|
14184
15541
|
if (!keys) {
|
|
14185
15542
|
return;
|
|
@@ -14227,14 +15584,7 @@ function braintrustAISDKTelemetry() {
|
|
|
14227
15584
|
return key;
|
|
14228
15585
|
}
|
|
14229
15586
|
}
|
|
14230
|
-
|
|
14231
|
-
if (workflowOperationKey && keys.includes(workflowOperationKey)) {
|
|
14232
|
-
return workflowOperationKey;
|
|
14233
|
-
}
|
|
14234
|
-
if (callId === "workflow-agent") {
|
|
14235
|
-
return void 0;
|
|
14236
|
-
}
|
|
14237
|
-
return mode === "finish" ? keys[0] : keys[keys.length - 1];
|
|
15587
|
+
return callId === "workflow-agent" || mode === "active" ? keys[keys.length - 1] : keys[0];
|
|
14238
15588
|
};
|
|
14239
15589
|
const operationKeyFromEvent = (event, mode = "active") => {
|
|
14240
15590
|
const explicit = explicitOperationKey(event);
|
|
@@ -14248,17 +15598,13 @@ function braintrustAISDKTelemetry() {
|
|
|
14248
15598
|
if (operationKey) {
|
|
14249
15599
|
return operationKey;
|
|
14250
15600
|
}
|
|
14251
|
-
const
|
|
14252
|
-
if (
|
|
14253
|
-
return
|
|
15601
|
+
const workflowAgentKeys2 = operationKeysByCallId.get("workflow-agent");
|
|
15602
|
+
if (workflowAgentKeys2?.length) {
|
|
15603
|
+
return workflowAgentKeys2[workflowAgentKeys2.length - 1];
|
|
14254
15604
|
}
|
|
14255
15605
|
return callId === "workflow-agent" ? void 0 : callId;
|
|
14256
15606
|
}
|
|
14257
15607
|
}
|
|
14258
|
-
const workflowOperationKey = workflowOperationKeyStore.getStore();
|
|
14259
|
-
if (workflowOperationKey && operations.has(workflowOperationKey)) {
|
|
14260
|
-
return workflowOperationKey;
|
|
14261
|
-
}
|
|
14262
15608
|
const wrapperSpan = currentWorkflowAgentWrapperSpan();
|
|
14263
15609
|
if (wrapperSpan?.spanId) {
|
|
14264
15610
|
for (const [operationKey, state] of operations) {
|
|
@@ -14268,8 +15614,8 @@ function braintrustAISDKTelemetry() {
|
|
|
14268
15614
|
}
|
|
14269
15615
|
}
|
|
14270
15616
|
const workflowAgentKeys = operationKeysByCallId.get("workflow-agent");
|
|
14271
|
-
if (workflowAgentKeys?.length
|
|
14272
|
-
return workflowAgentKeys[
|
|
15617
|
+
if (workflowAgentKeys?.length) {
|
|
15618
|
+
return workflowAgentKeys[workflowAgentKeys.length - 1];
|
|
14273
15619
|
}
|
|
14274
15620
|
if (operations.size === 1) {
|
|
14275
15621
|
return operations.keys().next().value;
|
|
@@ -14472,9 +15818,6 @@ function braintrustAISDKTelemetry() {
|
|
|
14472
15818
|
if (!ownsSpan) {
|
|
14473
15819
|
return;
|
|
14474
15820
|
}
|
|
14475
|
-
if (workflowAgent) {
|
|
14476
|
-
workflowOperationKeyStore.enterWith(operationKey);
|
|
14477
|
-
}
|
|
14478
15821
|
let metadata = metadataFromEvent(event);
|
|
14479
15822
|
const logPayload = { metadata };
|
|
14480
15823
|
const workflowAgentCallInput = workflowAgent ? operationInput(event, operationName) : void 0;
|
|
@@ -14946,6 +16289,10 @@ var aiSDKChannels = defineChannels(
|
|
|
14946
16289
|
channelName: "generateText",
|
|
14947
16290
|
kind: "async"
|
|
14948
16291
|
}),
|
|
16292
|
+
generateImage: channel({
|
|
16293
|
+
channelName: "generateImage",
|
|
16294
|
+
kind: "async"
|
|
16295
|
+
}),
|
|
14949
16296
|
streamText: channel({
|
|
14950
16297
|
channelName: "streamText",
|
|
14951
16298
|
kind: "async"
|
|
@@ -15133,7 +16480,7 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
15133
16480
|
}
|
|
15134
16481
|
subscribeToAISDK() {
|
|
15135
16482
|
const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
|
|
15136
|
-
this.unsubscribers.push(
|
|
16483
|
+
this.unsubscribers.push(interceptAISDKV7TelemetryDispatcher());
|
|
15137
16484
|
this.unsubscribers.push(subscribeToHarnessAgentCreateSession());
|
|
15138
16485
|
this.unsubscribers.push(
|
|
15139
16486
|
subscribeToHarnessContinuation(
|
|
@@ -15161,6 +16508,18 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
15161
16508
|
aggregateChunks: aggregateAISDKChunks
|
|
15162
16509
|
})
|
|
15163
16510
|
);
|
|
16511
|
+
this.unsubscribers.push(
|
|
16512
|
+
traceAsyncChannel(aiSDKChannels.generateImage, {
|
|
16513
|
+
name: "generateImage",
|
|
16514
|
+
type: "llm" /* LLM */,
|
|
16515
|
+
extractInput: ([params], event) => prepareAISDKGenerateImageInput(params, event.self),
|
|
16516
|
+
extractOutput: (result, endEvent) => processAISDKGenerateImageOutput(
|
|
16517
|
+
result,
|
|
16518
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
16519
|
+
),
|
|
16520
|
+
extractMetrics: (result) => extractTokenMetrics(result)
|
|
16521
|
+
})
|
|
16522
|
+
);
|
|
15164
16523
|
this.unsubscribers.push(
|
|
15165
16524
|
traceStreamingChannel(aiSDKChannels.streamText, {
|
|
15166
16525
|
name: "streamText",
|
|
@@ -15650,26 +17009,29 @@ function subscribeToHarnessContinuation(continuationChannel, defaultDenyOutputPa
|
|
|
15650
17009
|
channel2.unsubscribe(handlers);
|
|
15651
17010
|
};
|
|
15652
17011
|
}
|
|
15653
|
-
function
|
|
15654
|
-
const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
|
|
17012
|
+
function interceptAISDKV7TelemetryDispatcher() {
|
|
15655
17013
|
const telemetry = braintrustAISDKTelemetry();
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
const
|
|
15659
|
-
|
|
15660
|
-
|
|
17014
|
+
return aiSDKChannels.v7CreateTelemetryDispatcher.intercept(
|
|
17015
|
+
(target, thisArg, args) => {
|
|
17016
|
+
const dispatcher = Reflect.apply(target, thisArg, args);
|
|
17017
|
+
const telemetryOptions = args[0]?.telemetry;
|
|
17018
|
+
if (telemetryOptions?.isEnabled !== false) {
|
|
17019
|
+
try {
|
|
17020
|
+
patchAISDKV7TelemetryDispatcher(
|
|
17021
|
+
dispatcher,
|
|
17022
|
+
telemetry,
|
|
17023
|
+
telemetryOptions
|
|
17024
|
+
);
|
|
17025
|
+
} catch (error) {
|
|
17026
|
+
debugLogger.error(
|
|
17027
|
+
"Error instrumenting AI SDK v7 telemetry dispatcher:",
|
|
17028
|
+
error
|
|
17029
|
+
);
|
|
17030
|
+
}
|
|
15661
17031
|
}
|
|
15662
|
-
|
|
15663
|
-
event.result,
|
|
15664
|
-
telemetry,
|
|
15665
|
-
telemetryOptions
|
|
15666
|
-
);
|
|
17032
|
+
return dispatcher;
|
|
15667
17033
|
}
|
|
15668
|
-
|
|
15669
|
-
channel2.subscribe(handlers);
|
|
15670
|
-
return () => {
|
|
15671
|
-
channel2.unsubscribe(handlers);
|
|
15672
|
-
};
|
|
17034
|
+
);
|
|
15673
17035
|
}
|
|
15674
17036
|
function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry, telemetryOptions) {
|
|
15675
17037
|
if (!isObject(dispatcher)) {
|
|
@@ -15994,16 +17356,10 @@ var convertImageToAttachment = (image, explicitMimeType) => {
|
|
|
15994
17356
|
}
|
|
15995
17357
|
}
|
|
15996
17358
|
if (explicitMimeType) {
|
|
15997
|
-
|
|
17359
|
+
const blob = convertDataToBlob(image, explicitMimeType);
|
|
17360
|
+
if (blob) {
|
|
15998
17361
|
return new Attachment({
|
|
15999
|
-
data:
|
|
16000
|
-
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
16001
|
-
contentType: explicitMimeType
|
|
16002
|
-
});
|
|
16003
|
-
}
|
|
16004
|
-
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
16005
|
-
return new Attachment({
|
|
16006
|
-
data: new Blob([image], { type: explicitMimeType }),
|
|
17362
|
+
data: blob,
|
|
16007
17363
|
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
16008
17364
|
contentType: explicitMimeType
|
|
16009
17365
|
});
|
|
@@ -16057,6 +17413,25 @@ var convertDataToAttachment = (data, mimeType, filename) => {
|
|
|
16057
17413
|
function processAISDKCallInput(params) {
|
|
16058
17414
|
return processInputAttachmentsSync(params);
|
|
16059
17415
|
}
|
|
17416
|
+
function processAISDKGenerateImageInput(params) {
|
|
17417
|
+
const prompt = params.prompt;
|
|
17418
|
+
if (!isObject(prompt) || Array.isArray(prompt)) {
|
|
17419
|
+
return processAISDKCallInput(params);
|
|
17420
|
+
}
|
|
17421
|
+
const processedPrompt = { ...prompt };
|
|
17422
|
+
if (Array.isArray(prompt.images)) {
|
|
17423
|
+
processedPrompt.images = prompt.images.map(
|
|
17424
|
+
(image) => convertImageToAttachment(image, "image/png") ?? image
|
|
17425
|
+
);
|
|
17426
|
+
}
|
|
17427
|
+
if (prompt.mask !== void 0) {
|
|
17428
|
+
processedPrompt.mask = convertImageToAttachment(prompt.mask, "image/png") ?? prompt.mask;
|
|
17429
|
+
}
|
|
17430
|
+
return processAISDKCallInput({
|
|
17431
|
+
...params,
|
|
17432
|
+
prompt: processedPrompt
|
|
17433
|
+
});
|
|
17434
|
+
}
|
|
16060
17435
|
function processAISDKWorkflowAgentCallInput(params) {
|
|
16061
17436
|
const processed = processAISDKCallInput(params);
|
|
16062
17437
|
return {
|
|
@@ -16195,6 +17570,12 @@ function prepareAISDKEmbedInput(params, self) {
|
|
|
16195
17570
|
metadata: extractMetadataFromEmbedParams(params, self)
|
|
16196
17571
|
};
|
|
16197
17572
|
}
|
|
17573
|
+
function prepareAISDKGenerateImageInput(params, self) {
|
|
17574
|
+
return {
|
|
17575
|
+
input: processAISDKGenerateImageInput(params).input,
|
|
17576
|
+
metadata: extractMetadataFromCallParams(params, self)
|
|
17577
|
+
};
|
|
17578
|
+
}
|
|
16198
17579
|
function prepareAISDKRerankInput(params, self) {
|
|
16199
17580
|
const { documents, query } = params;
|
|
16200
17581
|
return {
|
|
@@ -17570,6 +18951,57 @@ function processAISDKOutput(output, denyOutputPaths) {
|
|
|
17570
18951
|
}
|
|
17571
18952
|
return normalizeAISDKLoggedOutput(sanitized);
|
|
17572
18953
|
}
|
|
18954
|
+
function processAISDKGenerateImageOutput(output, denyOutputPaths) {
|
|
18955
|
+
if (!output || typeof output !== "object") {
|
|
18956
|
+
return output;
|
|
18957
|
+
}
|
|
18958
|
+
const summarized = {};
|
|
18959
|
+
for (const field of [
|
|
18960
|
+
"usage",
|
|
18961
|
+
"warnings",
|
|
18962
|
+
"providerMetadata",
|
|
18963
|
+
"experimental_providerMetadata",
|
|
18964
|
+
"responses"
|
|
18965
|
+
]) {
|
|
18966
|
+
const value = safeSerializableFieldRead(output, field);
|
|
18967
|
+
if (value !== void 0 && isSerializableOutputValue(value)) {
|
|
18968
|
+
summarized[field] = value;
|
|
18969
|
+
}
|
|
18970
|
+
}
|
|
18971
|
+
const images = safeSerializableFieldRead(output, "images");
|
|
18972
|
+
const image = safeSerializableFieldRead(output, "image");
|
|
18973
|
+
const generatedFiles = Array.isArray(images) && images.length > 0 ? images : image !== void 0 ? [image] : [];
|
|
18974
|
+
const loggedOutput = normalizeAISDKLoggedOutput(
|
|
18975
|
+
omit(summarized, denyOutputPaths)
|
|
18976
|
+
);
|
|
18977
|
+
if (generatedFiles.length > 0) {
|
|
18978
|
+
loggedOutput.images = generatedFiles.map(
|
|
18979
|
+
(file, index) => convertAISDKGeneratedFileToAttachment(file, index)
|
|
18980
|
+
);
|
|
18981
|
+
}
|
|
18982
|
+
return loggedOutput;
|
|
18983
|
+
}
|
|
18984
|
+
function convertAISDKGeneratedFileToAttachment(file, index) {
|
|
18985
|
+
if (!file || typeof file !== "object") {
|
|
18986
|
+
return file;
|
|
18987
|
+
}
|
|
18988
|
+
const generatedFile = file;
|
|
18989
|
+
const generatedMediaType = safeSerializableFieldRead(
|
|
18990
|
+
generatedFile,
|
|
18991
|
+
"mediaType"
|
|
18992
|
+
);
|
|
18993
|
+
const mediaType = typeof generatedMediaType === "string" ? generatedMediaType : "application/octet-stream";
|
|
18994
|
+
const data = safeSerializableFieldRead(generatedFile, "base64") ?? safeSerializableFieldRead(generatedFile, "uint8Array");
|
|
18995
|
+
const blob = convertDataToBlob(data, mediaType);
|
|
18996
|
+
if (blob) {
|
|
18997
|
+
return new Attachment({
|
|
18998
|
+
data: blob,
|
|
18999
|
+
filename: `generated_image_${index}.${getExtensionFromMediaType(mediaType)}`,
|
|
19000
|
+
contentType: mediaType
|
|
19001
|
+
});
|
|
19002
|
+
}
|
|
19003
|
+
return file;
|
|
19004
|
+
}
|
|
17573
19005
|
function processAISDKEmbeddingOutput(output, denyOutputPaths) {
|
|
17574
19006
|
if (!output || typeof output !== "object") {
|
|
17575
19007
|
return output;
|
|
@@ -18070,118 +19502,22 @@ var claudeAgentSDKChannels = defineChannels(
|
|
|
18070
19502
|
var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
|
|
18071
19503
|
|
|
18072
19504
|
// src/instrumentation/plugins/claude-agent-sdk-local-tool-context.ts
|
|
18073
|
-
var
|
|
18074
|
-
|
|
18075
|
-
)
|
|
18076
|
-
|
|
18077
|
-
const maybeIsoWithAsyncLocalStorage = isomorph_default;
|
|
18078
|
-
if (typeof maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage === "function") {
|
|
18079
|
-
return maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage();
|
|
18080
|
-
}
|
|
18081
|
-
let currentStore;
|
|
18082
|
-
return {
|
|
18083
|
-
enterWith(store) {
|
|
18084
|
-
currentStore = store;
|
|
18085
|
-
},
|
|
18086
|
-
getStore() {
|
|
18087
|
-
return currentStore;
|
|
18088
|
-
},
|
|
18089
|
-
run(store, callback) {
|
|
18090
|
-
const previousStore = currentStore;
|
|
18091
|
-
currentStore = store;
|
|
18092
|
-
try {
|
|
18093
|
-
return callback();
|
|
18094
|
-
} finally {
|
|
18095
|
-
currentStore = previousStore;
|
|
18096
|
-
}
|
|
18097
|
-
}
|
|
18098
|
-
};
|
|
18099
|
-
}
|
|
18100
|
-
var localToolContextStore = createLocalToolContextStore();
|
|
18101
|
-
var fallbackLocalToolParentResolver;
|
|
18102
|
-
function createClaudeLocalToolContext() {
|
|
18103
|
-
return {};
|
|
18104
|
-
}
|
|
18105
|
-
function runWithClaudeLocalToolContext(callback, context) {
|
|
18106
|
-
return localToolContextStore.run(
|
|
18107
|
-
context ?? createClaudeLocalToolContext(),
|
|
18108
|
-
callback
|
|
18109
|
-
);
|
|
19505
|
+
var localToolContextStore = isomorph_default.newAsyncLocalStorage();
|
|
19506
|
+
var localToolParentResolversByToolUseId = /* @__PURE__ */ new Map();
|
|
19507
|
+
function runWithClaudeLocalToolContext(callback, resolver) {
|
|
19508
|
+
return localToolContextStore.run(resolver, callback);
|
|
18110
19509
|
}
|
|
18111
|
-
function
|
|
18112
|
-
|
|
18113
|
-
if (existing) {
|
|
18114
|
-
return existing;
|
|
18115
|
-
}
|
|
18116
|
-
const created = {};
|
|
18117
|
-
localToolContextStore.enterWith(created);
|
|
18118
|
-
return created;
|
|
18119
|
-
}
|
|
18120
|
-
function setClaudeLocalToolParentResolver(resolver) {
|
|
18121
|
-
fallbackLocalToolParentResolver = resolver;
|
|
18122
|
-
const context = ensureClaudeLocalToolContext();
|
|
18123
|
-
if (!context) {
|
|
18124
|
-
return;
|
|
18125
|
-
}
|
|
18126
|
-
context.resolveLocalToolParent = resolver;
|
|
18127
|
-
}
|
|
18128
|
-
function getClaudeLocalToolParentResolver() {
|
|
18129
|
-
return localToolContextStore.getStore()?.resolveLocalToolParent ?? fallbackLocalToolParentResolver;
|
|
18130
|
-
}
|
|
18131
|
-
function isAsyncIterable3(value) {
|
|
18132
|
-
return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
19510
|
+
function registerClaudeLocalToolParentResolver(toolUseId, resolver) {
|
|
19511
|
+
localToolParentResolversByToolUseId.set(toolUseId, resolver);
|
|
18133
19512
|
}
|
|
18134
|
-
function
|
|
18135
|
-
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
const stream = result;
|
|
18139
|
-
const originalAsyncIterator = stream[Symbol.asyncIterator];
|
|
18140
|
-
if (originalAsyncIterator[LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED]) {
|
|
18141
|
-
return result;
|
|
19513
|
+
function getClaudeLocalToolParentResolver(toolUseId) {
|
|
19514
|
+
const currentResolver = localToolContextStore.getStore();
|
|
19515
|
+
if (!toolUseId) {
|
|
19516
|
+
return currentResolver;
|
|
18142
19517
|
}
|
|
18143
|
-
const
|
|
18144
|
-
|
|
18145
|
-
|
|
18146
|
-
if (!iterator || typeof iterator !== "object") {
|
|
18147
|
-
return iterator;
|
|
18148
|
-
}
|
|
18149
|
-
const patchMethod = (methodName) => {
|
|
18150
|
-
const originalMethod = Reflect.get(iterator, methodName);
|
|
18151
|
-
if (typeof originalMethod !== "function") {
|
|
18152
|
-
return;
|
|
18153
|
-
}
|
|
18154
|
-
Reflect.set(
|
|
18155
|
-
iterator,
|
|
18156
|
-
methodName,
|
|
18157
|
-
(...args) => runWithClaudeLocalToolContext(
|
|
18158
|
-
() => Reflect.apply(
|
|
18159
|
-
originalMethod,
|
|
18160
|
-
iterator,
|
|
18161
|
-
args
|
|
18162
|
-
),
|
|
18163
|
-
localToolContext
|
|
18164
|
-
)
|
|
18165
|
-
);
|
|
18166
|
-
};
|
|
18167
|
-
patchMethod("next");
|
|
18168
|
-
patchMethod("return");
|
|
18169
|
-
patchMethod("throw");
|
|
18170
|
-
return iterator;
|
|
18171
|
-
}, localToolContext);
|
|
18172
|
-
};
|
|
18173
|
-
Object.defineProperty(
|
|
18174
|
-
patchedAsyncIterator,
|
|
18175
|
-
LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED,
|
|
18176
|
-
{
|
|
18177
|
-
configurable: false,
|
|
18178
|
-
enumerable: false,
|
|
18179
|
-
value: true,
|
|
18180
|
-
writable: false
|
|
18181
|
-
}
|
|
18182
|
-
);
|
|
18183
|
-
Reflect.set(stream, Symbol.asyncIterator, patchedAsyncIterator);
|
|
18184
|
-
return result;
|
|
19518
|
+
const registeredResolver = localToolParentResolversByToolUseId.get(toolUseId);
|
|
19519
|
+
localToolParentResolversByToolUseId.delete(toolUseId);
|
|
19520
|
+
return currentResolver ?? registeredResolver;
|
|
18185
19521
|
}
|
|
18186
19522
|
|
|
18187
19523
|
// src/instrumentation/plugins/claude-agent-sdk-local-tool-spans.ts
|
|
@@ -18207,7 +19543,7 @@ function wrapLocalClaudeToolHandler(handler, getMetadata) {
|
|
|
18207
19543
|
const metadata = getMetadata();
|
|
18208
19544
|
const rawToolName = metadata.serverName ? `mcp__${metadata.serverName}__${metadata.toolName}` : metadata.toolName;
|
|
18209
19545
|
const toolUseId = getToolUseIdFromExtra(handlerArgs[1]);
|
|
18210
|
-
const localToolParentResolver = getClaudeLocalToolParentResolver();
|
|
19546
|
+
const localToolParentResolver = getClaudeLocalToolParentResolver(toolUseId);
|
|
18211
19547
|
const spanName = metadata.serverName ? `tool: ${metadata.serverName}/${metadata.toolName}` : `tool: ${metadata.toolName}`;
|
|
18212
19548
|
const runWithResolvedParent = async () => {
|
|
18213
19549
|
const parent = toolUseId && localToolParentResolver ? await localToolParentResolver(toolUseId).catch(() => void 0) : void 0;
|
|
@@ -18734,6 +20070,7 @@ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToP
|
|
|
18734
20070
|
}
|
|
18735
20071
|
}
|
|
18736
20072
|
if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
|
|
20073
|
+
registerClaudeLocalToolParentResolver(toolUseID, resolveParentSpan);
|
|
18737
20074
|
return {};
|
|
18738
20075
|
}
|
|
18739
20076
|
const parsed = parseToolName(input.tool_name);
|
|
@@ -19444,7 +20781,7 @@ async function finalizeQuerySpan(state) {
|
|
|
19444
20781
|
}
|
|
19445
20782
|
var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
19446
20783
|
onEnable() {
|
|
19447
|
-
this.
|
|
20784
|
+
this.interceptQuery();
|
|
19448
20785
|
}
|
|
19449
20786
|
onDisable() {
|
|
19450
20787
|
for (const unsubscribe of this.unsubscribers) {
|
|
@@ -19452,211 +20789,218 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
19452
20789
|
}
|
|
19453
20790
|
this.unsubscribers = [];
|
|
19454
20791
|
}
|
|
19455
|
-
|
|
19456
|
-
const
|
|
19457
|
-
|
|
19458
|
-
|
|
19459
|
-
|
|
19460
|
-
|
|
19461
|
-
|
|
19462
|
-
|
|
19463
|
-
|
|
19464
|
-
|
|
19465
|
-
|
|
19466
|
-
|
|
19467
|
-
|
|
19468
|
-
|
|
19469
|
-
|
|
19470
|
-
|
|
19471
|
-
|
|
19472
|
-
|
|
19473
|
-
|
|
19474
|
-
|
|
19475
|
-
try {
|
|
19476
|
-
for await (const message of promptStream) {
|
|
19477
|
-
capturedPromptMessages.push(message);
|
|
19478
|
-
yield message;
|
|
19479
|
-
}
|
|
19480
|
-
} finally {
|
|
19481
|
-
resolvePromptDone?.();
|
|
20792
|
+
interceptQuery() {
|
|
20793
|
+
const startQuery = (params) => {
|
|
20794
|
+
const originalPrompt = params.prompt;
|
|
20795
|
+
const options = params.options ?? {};
|
|
20796
|
+
const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
|
|
20797
|
+
let promptStarted = false;
|
|
20798
|
+
let capturedPromptMessages;
|
|
20799
|
+
let resolvePromptDone;
|
|
20800
|
+
const promptDone = new Promise((resolve) => {
|
|
20801
|
+
resolvePromptDone = resolve;
|
|
20802
|
+
});
|
|
20803
|
+
if (promptIsAsyncIterable) {
|
|
20804
|
+
capturedPromptMessages = [];
|
|
20805
|
+
const promptStream = originalPrompt;
|
|
20806
|
+
params.prompt = (async function* () {
|
|
20807
|
+
promptStarted = true;
|
|
20808
|
+
try {
|
|
20809
|
+
for await (const message of promptStream) {
|
|
20810
|
+
capturedPromptMessages.push(message);
|
|
20811
|
+
yield message;
|
|
19482
20812
|
}
|
|
19483
|
-
}
|
|
19484
|
-
|
|
19485
|
-
const span = startSpan(
|
|
19486
|
-
withSpanInstrumentationName(
|
|
19487
|
-
{
|
|
19488
|
-
name: "Claude Agent",
|
|
19489
|
-
spanAttributes: {
|
|
19490
|
-
type: "task" /* TASK */
|
|
19491
|
-
}
|
|
19492
|
-
},
|
|
19493
|
-
INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
|
|
19494
|
-
)
|
|
19495
|
-
);
|
|
19496
|
-
const startTime = getCurrentUnixTimestamp();
|
|
19497
|
-
try {
|
|
19498
|
-
span.log({
|
|
19499
|
-
input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
|
|
19500
|
-
metadata: filterSerializableOptions(options)
|
|
19501
|
-
});
|
|
19502
|
-
} catch (error) {
|
|
19503
|
-
console.error("Error extracting input for Claude Agent SDK:", error);
|
|
19504
|
-
}
|
|
19505
|
-
const activeToolSpans = /* @__PURE__ */ new Map();
|
|
19506
|
-
const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
|
|
19507
|
-
const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
|
|
19508
|
-
const subAgentSpans = /* @__PURE__ */ new Map();
|
|
19509
|
-
const endedSubAgentSpans = /* @__PURE__ */ new Set();
|
|
19510
|
-
const toolUseToParent = /* @__PURE__ */ new Map();
|
|
19511
|
-
const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
|
|
19512
|
-
const latestRootLlmParentRef = {
|
|
19513
|
-
value: void 0
|
|
19514
|
-
};
|
|
19515
|
-
const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
|
|
19516
|
-
const taskIdToToolUseId = /* @__PURE__ */ new Map();
|
|
19517
|
-
const promptMessagesByParentKey = /* @__PURE__ */ new Map();
|
|
19518
|
-
const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
|
|
19519
|
-
const localToolContext = createClaudeLocalToolContext();
|
|
19520
|
-
const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
|
|
19521
|
-
const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
|
|
19522
|
-
const resolveToolUseParentSpan = async (toolUseID, context) => {
|
|
19523
|
-
const trackedParentToolUseId = toolUseToParent.get(toolUseID);
|
|
19524
|
-
const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
|
|
19525
|
-
const parentKey = llmParentKey(parentToolUseId);
|
|
19526
|
-
const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
|
|
19527
|
-
const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
|
|
19528
|
-
if (!activeLlmSpan && !latestLlmParent) {
|
|
19529
|
-
await ensureActiveLlmSpanForParentToolUse(
|
|
19530
|
-
span,
|
|
19531
|
-
activeLlmSpansByParentToolUse,
|
|
19532
|
-
subAgentDetailsByToolUseId,
|
|
19533
|
-
activeToolSpans,
|
|
19534
|
-
subAgentSpans,
|
|
19535
|
-
parentToolUseId,
|
|
19536
|
-
getCurrentUnixTimestamp()
|
|
19537
|
-
);
|
|
19538
|
-
}
|
|
19539
|
-
if (parentToolUseId) {
|
|
19540
|
-
const subAgentSpan = await ensureSubAgentSpan(
|
|
19541
|
-
subAgentDetailsByToolUseId,
|
|
19542
|
-
span,
|
|
19543
|
-
activeToolSpans,
|
|
19544
|
-
subAgentSpans,
|
|
19545
|
-
parentToolUseId
|
|
19546
|
-
);
|
|
19547
|
-
return subAgentSpan.export();
|
|
20813
|
+
} finally {
|
|
20814
|
+
resolvePromptDone?.();
|
|
19548
20815
|
}
|
|
19549
|
-
|
|
19550
|
-
|
|
19551
|
-
|
|
19552
|
-
|
|
19553
|
-
|
|
19554
|
-
|
|
19555
|
-
|
|
19556
|
-
|
|
19557
|
-
|
|
19558
|
-
|
|
19559
|
-
|
|
19560
|
-
|
|
19561
|
-
|
|
19562
|
-
|
|
19563
|
-
|
|
19564
|
-
|
|
19565
|
-
|
|
19566
|
-
|
|
19567
|
-
spans.set(event, {
|
|
19568
|
-
activeLlmSpansByParentToolUse,
|
|
19569
|
-
activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
|
|
19570
|
-
activeToolSpans,
|
|
19571
|
-
conversationHistoryByParentKey,
|
|
19572
|
-
capturedPromptMessages,
|
|
19573
|
-
currentMessageId: void 0,
|
|
19574
|
-
currentMessageStartTime: startTime,
|
|
19575
|
-
currentMessages: [],
|
|
19576
|
-
endedSubAgentSpans,
|
|
19577
|
-
finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
|
|
19578
|
-
finalResults: [],
|
|
19579
|
-
options: optionsWithHooks,
|
|
19580
|
-
originalPrompt,
|
|
19581
|
-
processing: Promise.resolve(),
|
|
19582
|
-
promptDone,
|
|
19583
|
-
promptMessagesByParentKey,
|
|
19584
|
-
promptStarted: () => promptStarted,
|
|
19585
|
-
promptSourcePriorityByParentKey,
|
|
19586
|
-
span,
|
|
19587
|
-
subAgentDetailsByToolUseId,
|
|
19588
|
-
subAgentSpans,
|
|
19589
|
-
taskIdToToolUseId,
|
|
19590
|
-
latestLlmParentBySubAgentToolUse,
|
|
19591
|
-
latestRootLlmParentRef,
|
|
19592
|
-
toolUseToParent,
|
|
19593
|
-
usageByMessageId: /* @__PURE__ */ new Map(),
|
|
19594
|
-
localToolContext
|
|
20816
|
+
})();
|
|
20817
|
+
}
|
|
20818
|
+
const span = startSpan(
|
|
20819
|
+
withSpanInstrumentationName(
|
|
20820
|
+
{
|
|
20821
|
+
name: "Claude Agent",
|
|
20822
|
+
spanAttributes: {
|
|
20823
|
+
type: "task" /* TASK */
|
|
20824
|
+
}
|
|
20825
|
+
},
|
|
20826
|
+
INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
|
|
20827
|
+
)
|
|
20828
|
+
);
|
|
20829
|
+
const startTime = getCurrentUnixTimestamp();
|
|
20830
|
+
try {
|
|
20831
|
+
span.log({
|
|
20832
|
+
input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
|
|
20833
|
+
metadata: filterSerializableOptions(options)
|
|
19595
20834
|
});
|
|
19596
|
-
}
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
|
|
19609
|
-
|
|
19610
|
-
|
|
19611
|
-
|
|
19612
|
-
|
|
19613
|
-
|
|
19614
|
-
|
|
19615
|
-
|
|
19616
|
-
|
|
19617
|
-
|
|
19618
|
-
|
|
19619
|
-
|
|
19620
|
-
|
|
19621
|
-
|
|
19622
|
-
|
|
19623
|
-
|
|
19624
|
-
|
|
19625
|
-
|
|
19626
|
-
|
|
19627
|
-
|
|
19628
|
-
|
|
19629
|
-
|
|
19630
|
-
|
|
19631
|
-
})
|
|
19632
|
-
});
|
|
19633
|
-
return;
|
|
19634
|
-
}
|
|
19635
|
-
try {
|
|
19636
|
-
state.span.log({ output: eventResult });
|
|
19637
|
-
} catch (error) {
|
|
19638
|
-
console.error("Error extracting output for Claude Agent SDK:", error);
|
|
19639
|
-
} finally {
|
|
19640
|
-
state.span.end();
|
|
19641
|
-
spans.delete(event);
|
|
20835
|
+
} catch (error) {
|
|
20836
|
+
console.error("Error extracting input for Claude Agent SDK:", error);
|
|
20837
|
+
}
|
|
20838
|
+
const activeToolSpans = /* @__PURE__ */ new Map();
|
|
20839
|
+
const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
|
|
20840
|
+
const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
|
|
20841
|
+
const subAgentSpans = /* @__PURE__ */ new Map();
|
|
20842
|
+
const endedSubAgentSpans = /* @__PURE__ */ new Set();
|
|
20843
|
+
const toolUseToParent = /* @__PURE__ */ new Map();
|
|
20844
|
+
const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
|
|
20845
|
+
const latestRootLlmParentRef = {
|
|
20846
|
+
value: void 0
|
|
20847
|
+
};
|
|
20848
|
+
const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
|
|
20849
|
+
const taskIdToToolUseId = /* @__PURE__ */ new Map();
|
|
20850
|
+
const promptMessagesByParentKey = /* @__PURE__ */ new Map();
|
|
20851
|
+
const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
|
|
20852
|
+
const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
|
|
20853
|
+
const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
|
|
20854
|
+
const resolveToolUseParentSpan = async (toolUseID, context) => {
|
|
20855
|
+
const trackedParentToolUseId = toolUseToParent.get(toolUseID);
|
|
20856
|
+
const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
|
|
20857
|
+
const parentKey = llmParentKey(parentToolUseId);
|
|
20858
|
+
const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
|
|
20859
|
+
const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
|
|
20860
|
+
if (!activeLlmSpan && !latestLlmParent) {
|
|
20861
|
+
await ensureActiveLlmSpanForParentToolUse(
|
|
20862
|
+
span,
|
|
20863
|
+
activeLlmSpansByParentToolUse,
|
|
20864
|
+
subAgentDetailsByToolUseId,
|
|
20865
|
+
activeToolSpans,
|
|
20866
|
+
subAgentSpans,
|
|
20867
|
+
parentToolUseId,
|
|
20868
|
+
getCurrentUnixTimestamp()
|
|
20869
|
+
);
|
|
19642
20870
|
}
|
|
19643
|
-
|
|
19644
|
-
|
|
19645
|
-
|
|
19646
|
-
|
|
19647
|
-
|
|
20871
|
+
if (parentToolUseId) {
|
|
20872
|
+
const subAgentSpan = await ensureSubAgentSpan(
|
|
20873
|
+
subAgentDetailsByToolUseId,
|
|
20874
|
+
span,
|
|
20875
|
+
activeToolSpans,
|
|
20876
|
+
subAgentSpans,
|
|
20877
|
+
parentToolUseId
|
|
20878
|
+
);
|
|
20879
|
+
return subAgentSpan.export();
|
|
19648
20880
|
}
|
|
19649
|
-
|
|
19650
|
-
|
|
20881
|
+
return span.export();
|
|
20882
|
+
};
|
|
20883
|
+
const optionsWithHooks = injectTracingHooks(
|
|
20884
|
+
options,
|
|
20885
|
+
resolveToolUseParentSpan,
|
|
20886
|
+
taskIdToToolUseId,
|
|
20887
|
+
toolUseToParent,
|
|
20888
|
+
activeToolSpans,
|
|
20889
|
+
localToolHookNames,
|
|
20890
|
+
skipLocalToolHooks,
|
|
20891
|
+
subAgentDetailsByToolUseId,
|
|
20892
|
+
subAgentSpans,
|
|
20893
|
+
endedSubAgentSpans
|
|
20894
|
+
);
|
|
20895
|
+
params.options = optionsWithHooks;
|
|
20896
|
+
return {
|
|
20897
|
+
activeLlmSpansByParentToolUse,
|
|
20898
|
+
activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
|
|
20899
|
+
activeToolSpans,
|
|
20900
|
+
conversationHistoryByParentKey,
|
|
20901
|
+
capturedPromptMessages,
|
|
20902
|
+
currentMessageId: void 0,
|
|
20903
|
+
currentMessageStartTime: startTime,
|
|
20904
|
+
currentMessages: [],
|
|
20905
|
+
endedSubAgentSpans,
|
|
20906
|
+
finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
|
|
20907
|
+
finalResults: [],
|
|
20908
|
+
options: optionsWithHooks,
|
|
20909
|
+
originalPrompt,
|
|
20910
|
+
processing: Promise.resolve(),
|
|
20911
|
+
promptDone,
|
|
20912
|
+
promptMessagesByParentKey,
|
|
20913
|
+
promptStarted: () => promptStarted,
|
|
20914
|
+
promptSourcePriorityByParentKey,
|
|
20915
|
+
span,
|
|
20916
|
+
subAgentDetailsByToolUseId,
|
|
20917
|
+
subAgentSpans,
|
|
20918
|
+
taskIdToToolUseId,
|
|
20919
|
+
latestLlmParentBySubAgentToolUse,
|
|
20920
|
+
latestRootLlmParentRef,
|
|
20921
|
+
toolUseToParent,
|
|
20922
|
+
usageByMessageId: /* @__PURE__ */ new Map(),
|
|
20923
|
+
localToolParentResolver: resolveToolUseParentSpan
|
|
20924
|
+
};
|
|
20925
|
+
};
|
|
20926
|
+
const finishQuery = (state, result) => {
|
|
20927
|
+
if (isAsyncIterable(result)) {
|
|
20928
|
+
patchStreamIfNeeded(result, {
|
|
20929
|
+
aroundNext: (callback) => runWithClaudeLocalToolContext(
|
|
20930
|
+
callback,
|
|
20931
|
+
state.localToolParentResolver
|
|
20932
|
+
),
|
|
20933
|
+
onChunk: (message) => {
|
|
20934
|
+
maybeTrackToolUseContext(state, message);
|
|
20935
|
+
state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
|
|
20936
|
+
console.error(
|
|
20937
|
+
"Error processing Claude Agent SDK stream chunk:",
|
|
20938
|
+
error
|
|
20939
|
+
);
|
|
20940
|
+
});
|
|
20941
|
+
},
|
|
20942
|
+
onComplete: () => state.processing.then(() => finalizeQuerySpan(state)),
|
|
20943
|
+
onError: (error) => state.processing.then(() => {
|
|
20944
|
+
state.span.log({ error: error.message });
|
|
20945
|
+
}).then(() => finalizeQuerySpan(state))
|
|
19651
20946
|
});
|
|
20947
|
+
return;
|
|
20948
|
+
}
|
|
20949
|
+
try {
|
|
20950
|
+
state.span.log({ output: result });
|
|
20951
|
+
} catch (error) {
|
|
20952
|
+
console.error("Error extracting output for Claude Agent SDK:", error);
|
|
20953
|
+
} finally {
|
|
19652
20954
|
state.span.end();
|
|
19653
|
-
spans.delete(event);
|
|
19654
20955
|
}
|
|
19655
20956
|
};
|
|
19656
|
-
|
|
19657
|
-
|
|
19658
|
-
|
|
19659
|
-
|
|
20957
|
+
this.unsubscribers.push(
|
|
20958
|
+
claudeAgentSDKChannels.query.intercept((target, thisArg, args) => {
|
|
20959
|
+
let state;
|
|
20960
|
+
try {
|
|
20961
|
+
args[0] ??= {};
|
|
20962
|
+
state = startQuery(args[0]);
|
|
20963
|
+
} catch (error) {
|
|
20964
|
+
debugLogger.error(
|
|
20965
|
+
"Error starting Claude Agent SDK instrumentation:",
|
|
20966
|
+
error
|
|
20967
|
+
);
|
|
20968
|
+
}
|
|
20969
|
+
const invokeTarget = () => Reflect.apply(target, thisArg, args);
|
|
20970
|
+
try {
|
|
20971
|
+
const result = state ? runWithClaudeLocalToolContext(
|
|
20972
|
+
invokeTarget,
|
|
20973
|
+
state.localToolParentResolver
|
|
20974
|
+
) : invokeTarget();
|
|
20975
|
+
if (state) {
|
|
20976
|
+
try {
|
|
20977
|
+
finishQuery(state, result);
|
|
20978
|
+
} catch (error) {
|
|
20979
|
+
debugLogger.error(
|
|
20980
|
+
"Error finalizing Claude Agent SDK instrumentation:",
|
|
20981
|
+
error
|
|
20982
|
+
);
|
|
20983
|
+
}
|
|
20984
|
+
}
|
|
20985
|
+
return result;
|
|
20986
|
+
} catch (error) {
|
|
20987
|
+
if (state) {
|
|
20988
|
+
try {
|
|
20989
|
+
state.span.log({
|
|
20990
|
+
error: error instanceof Error ? error.message : String(error)
|
|
20991
|
+
});
|
|
20992
|
+
state.span.end();
|
|
20993
|
+
} catch (instrumentationError) {
|
|
20994
|
+
debugLogger.error(
|
|
20995
|
+
"Error handling Claude Agent SDK instrumentation failure:",
|
|
20996
|
+
instrumentationError
|
|
20997
|
+
);
|
|
20998
|
+
}
|
|
20999
|
+
}
|
|
21000
|
+
throw error;
|
|
21001
|
+
}
|
|
21002
|
+
})
|
|
21003
|
+
);
|
|
19660
21004
|
}
|
|
19661
21005
|
};
|
|
19662
21006
|
|
|
@@ -23770,7 +25114,7 @@ function patchOpenRouterCallModelResult(args) {
|
|
|
23770
25114
|
span,
|
|
23771
25115
|
() => originalMethod.apply(resultLike, args2)
|
|
23772
25116
|
);
|
|
23773
|
-
if (!
|
|
25117
|
+
if (!isAsyncIterable3(stream)) {
|
|
23774
25118
|
return stream;
|
|
23775
25119
|
}
|
|
23776
25120
|
return wrapAsyncIterableWithSpan({
|
|
@@ -23965,7 +25309,7 @@ function wrapAsyncIterableWithSpan(args) {
|
|
|
23965
25309
|
}
|
|
23966
25310
|
};
|
|
23967
25311
|
}
|
|
23968
|
-
function
|
|
25312
|
+
function isAsyncIterable3(value) {
|
|
23969
25313
|
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
23970
25314
|
}
|
|
23971
25315
|
function normalizeError(error) {
|
|
@@ -24843,7 +26187,7 @@ function patchOpenRouterCallModelResult2(args) {
|
|
|
24843
26187
|
span,
|
|
24844
26188
|
() => originalMethod.apply(resultLike, args2)
|
|
24845
26189
|
);
|
|
24846
|
-
if (!
|
|
26190
|
+
if (!isAsyncIterable4(stream)) {
|
|
24847
26191
|
return stream;
|
|
24848
26192
|
}
|
|
24849
26193
|
return wrapAsyncIterableWithSpan2({
|
|
@@ -25038,7 +26382,7 @@ function wrapAsyncIterableWithSpan2(args) {
|
|
|
25038
26382
|
}
|
|
25039
26383
|
};
|
|
25040
26384
|
}
|
|
25041
|
-
function
|
|
26385
|
+
function isAsyncIterable4(value) {
|
|
25042
26386
|
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
25043
26387
|
}
|
|
25044
26388
|
function normalizeError2(error) {
|
|
@@ -31030,12 +32374,14 @@ function getMetricsFromResponse(response) {
|
|
|
31030
32374
|
continue;
|
|
31031
32375
|
}
|
|
31032
32376
|
const inputTokenDetails = usageMetadata.input_token_details;
|
|
32377
|
+
const outputTokenDetails = usageMetadata.output_token_details;
|
|
31033
32378
|
return normalizeTokenMetrics({
|
|
31034
32379
|
total_tokens: usageMetadata.total_tokens,
|
|
31035
32380
|
prompt_tokens: usageMetadata.input_tokens,
|
|
31036
32381
|
completion_tokens: usageMetadata.output_tokens,
|
|
31037
32382
|
prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
|
|
31038
|
-
prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
|
|
32383
|
+
prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
|
|
32384
|
+
completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
|
|
31039
32385
|
});
|
|
31040
32386
|
}
|
|
31041
32387
|
const llmOutput = response.llmOutput || {};
|
|
@@ -31622,6 +32968,9 @@ var piCodingAgentChannels = defineChannels(
|
|
|
31622
32968
|
// src/instrumentation/plugins/pi-coding-agent-plugin.ts
|
|
31623
32969
|
var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
|
|
31624
32970
|
var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
|
|
32971
|
+
var PI_TOOL_EXECUTE_WRAPPED = /* @__PURE__ */ Symbol.for(
|
|
32972
|
+
"braintrust.pi_coding_agent.tool_execute_wrapped"
|
|
32973
|
+
);
|
|
31625
32974
|
var piPromptContextStore;
|
|
31626
32975
|
var PiCodingAgentPlugin = class extends BasePlugin {
|
|
31627
32976
|
activePromptStates = /* @__PURE__ */ new Set();
|
|
@@ -31702,6 +33051,7 @@ function startPiPromptRun(event, onFinalize) {
|
|
|
31702
33051
|
return void 0;
|
|
31703
33052
|
}
|
|
31704
33053
|
installPiAgentInstrumentation(agent);
|
|
33054
|
+
wrapPiToolExecutors(agent.state?.tools);
|
|
31705
33055
|
const metadata = {
|
|
31706
33056
|
...extractSessionMetadata(session),
|
|
31707
33057
|
...extractPromptOptionsMetadata(event.arguments[1]),
|
|
@@ -31746,7 +33096,7 @@ function extractSession(event) {
|
|
|
31746
33096
|
return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
|
|
31747
33097
|
}
|
|
31748
33098
|
function isPiAgent(value) {
|
|
31749
|
-
return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
|
|
33099
|
+
return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
|
|
31750
33100
|
}
|
|
31751
33101
|
function promptContextStore() {
|
|
31752
33102
|
piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
|
|
@@ -31756,17 +33106,21 @@ function currentPiPromptState() {
|
|
|
31756
33106
|
return promptContextStore().getStore();
|
|
31757
33107
|
}
|
|
31758
33108
|
function installPiAgentInstrumentation(agent) {
|
|
33109
|
+
const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
|
|
33110
|
+
const streamFunction = agent[property];
|
|
31759
33111
|
const existing = piAgentPatchStates.get(agent);
|
|
31760
|
-
if (!existing ||
|
|
33112
|
+
if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
|
|
31761
33113
|
const patchState = {
|
|
31762
|
-
|
|
31763
|
-
|
|
33114
|
+
originalStreamFunction: streamFunction,
|
|
33115
|
+
property,
|
|
33116
|
+
wrappedStreamFunction: streamFunction
|
|
31764
33117
|
};
|
|
31765
|
-
patchState.
|
|
33118
|
+
patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
|
|
31766
33119
|
agent,
|
|
31767
|
-
patchState.
|
|
33120
|
+
patchState.originalStreamFunction,
|
|
33121
|
+
property
|
|
31768
33122
|
);
|
|
31769
|
-
agent
|
|
33123
|
+
agent[property] = patchState.wrappedStreamFunction;
|
|
31770
33124
|
piAgentPatchStates.set(agent, patchState);
|
|
31771
33125
|
}
|
|
31772
33126
|
if (piAgentEventSubscriptions.has(agent)) {
|
|
@@ -31791,14 +33145,21 @@ function installPiAgentInstrumentation(agent) {
|
|
|
31791
33145
|
logInstrumentationError4("Pi Coding Agent event subscription", error);
|
|
31792
33146
|
}
|
|
31793
33147
|
}
|
|
31794
|
-
function
|
|
31795
|
-
return async function
|
|
31796
|
-
const invokeOriginal = () => Reflect.apply(
|
|
33148
|
+
function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
|
|
33149
|
+
return async function instrumentedPiStreamFunction(model, context, options) {
|
|
33150
|
+
const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
|
|
31797
33151
|
const state = currentPiPromptState();
|
|
31798
33152
|
if (!state || state.agent !== agent || state.finalized) {
|
|
31799
33153
|
return invokeOriginal();
|
|
31800
33154
|
}
|
|
31801
|
-
|
|
33155
|
+
wrapPiToolExecutors(context.tools);
|
|
33156
|
+
const llmState = await startPiLlmSpan(
|
|
33157
|
+
state,
|
|
33158
|
+
model,
|
|
33159
|
+
context,
|
|
33160
|
+
property,
|
|
33161
|
+
options
|
|
33162
|
+
);
|
|
31802
33163
|
try {
|
|
31803
33164
|
const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
|
|
31804
33165
|
return patchAssistantMessageStream(stream, state, llmState);
|
|
@@ -31808,12 +33169,39 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
|
|
|
31808
33169
|
}
|
|
31809
33170
|
};
|
|
31810
33171
|
}
|
|
31811
|
-
|
|
33172
|
+
function wrapPiToolExecutors(tools) {
|
|
33173
|
+
if (!tools) {
|
|
33174
|
+
return;
|
|
33175
|
+
}
|
|
33176
|
+
for (const tool of tools) {
|
|
33177
|
+
try {
|
|
33178
|
+
const execute = tool.execute;
|
|
33179
|
+
if (typeof execute !== "function" || execute[PI_TOOL_EXECUTE_WRAPPED]) {
|
|
33180
|
+
continue;
|
|
33181
|
+
}
|
|
33182
|
+
const wrappedExecute = function(...args) {
|
|
33183
|
+
return runWithAutoInstrumentationAllowed(
|
|
33184
|
+
() => Reflect.apply(execute, this, args)
|
|
33185
|
+
);
|
|
33186
|
+
};
|
|
33187
|
+
Object.defineProperty(wrappedExecute, PI_TOOL_EXECUTE_WRAPPED, {
|
|
33188
|
+
configurable: false,
|
|
33189
|
+
enumerable: false,
|
|
33190
|
+
value: true,
|
|
33191
|
+
writable: false
|
|
33192
|
+
});
|
|
33193
|
+
tool.execute = wrappedExecute;
|
|
33194
|
+
} catch (error) {
|
|
33195
|
+
logInstrumentationError4("Pi Coding Agent tool wrapping", error);
|
|
33196
|
+
}
|
|
33197
|
+
}
|
|
33198
|
+
}
|
|
33199
|
+
async function startPiLlmSpan(state, model, context, property, options) {
|
|
31812
33200
|
const metadata = {
|
|
31813
33201
|
...extractModelMetadata2(model),
|
|
31814
33202
|
...extractStreamOptionsMetadata(options),
|
|
31815
33203
|
...extractToolMetadata(context.tools),
|
|
31816
|
-
"pi_coding_agent.operation":
|
|
33204
|
+
"pi_coding_agent.operation": `agent.${property}`
|
|
31817
33205
|
};
|
|
31818
33206
|
const span = startSpan(
|
|
31819
33207
|
withSpanInstrumentationName(
|
|
@@ -31979,35 +33367,26 @@ async function startPiToolSpan(state, event) {
|
|
|
31979
33367
|
if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
|
|
31980
33368
|
return;
|
|
31981
33369
|
}
|
|
31982
|
-
const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
|
|
31983
33370
|
const metadata = {
|
|
31984
33371
|
"gen_ai.tool.call.id": event.toolCallId,
|
|
31985
33372
|
"gen_ai.tool.name": event.toolName,
|
|
31986
33373
|
"pi_coding_agent.tool.name": event.toolName
|
|
31987
33374
|
};
|
|
31988
|
-
|
|
31989
|
-
|
|
31990
|
-
|
|
31991
|
-
{
|
|
31992
|
-
|
|
31993
|
-
|
|
31994
|
-
metadata
|
|
31995
|
-
},
|
|
31996
|
-
name: event.toolName || "tool",
|
|
31997
|
-
parent: await state.span.export(),
|
|
31998
|
-
spanAttributes: { type: "tool" /* TOOL */ }
|
|
33375
|
+
const span = startSpan(
|
|
33376
|
+
withSpanInstrumentationName(
|
|
33377
|
+
{
|
|
33378
|
+
event: {
|
|
33379
|
+
input: event.args,
|
|
33380
|
+
metadata
|
|
31999
33381
|
},
|
|
32000
|
-
|
|
32001
|
-
|
|
32002
|
-
|
|
32003
|
-
|
|
32004
|
-
|
|
32005
|
-
|
|
32006
|
-
|
|
32007
|
-
|
|
32008
|
-
restoreAutoInstrumentation();
|
|
32009
|
-
throw error;
|
|
32010
|
-
}
|
|
33382
|
+
name: event.toolName || "tool",
|
|
33383
|
+
parent: await state.span.export(),
|
|
33384
|
+
spanAttributes: { type: "tool" /* TOOL */ }
|
|
33385
|
+
},
|
|
33386
|
+
INSTRUMENTATION_NAMES.PI_CODING_AGENT
|
|
33387
|
+
)
|
|
33388
|
+
);
|
|
33389
|
+
state.activeToolSpans.set(event.toolCallId, { span });
|
|
32011
33390
|
}
|
|
32012
33391
|
function finishPiToolSpan(state, event) {
|
|
32013
33392
|
const toolState = state.activeToolSpans.get(event.toolCallId);
|
|
@@ -32028,11 +33407,7 @@ function finishPiToolSpan(state, event) {
|
|
|
32028
33407
|
output: event.result
|
|
32029
33408
|
});
|
|
32030
33409
|
} finally {
|
|
32031
|
-
|
|
32032
|
-
toolState.span.end();
|
|
32033
|
-
} finally {
|
|
32034
|
-
toolState.restoreAutoInstrumentation?.();
|
|
32035
|
-
}
|
|
33410
|
+
toolState.span.end();
|
|
32036
33411
|
}
|
|
32037
33412
|
}
|
|
32038
33413
|
function finishPiPromptRun(state, error) {
|
|
@@ -32082,10 +33457,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
|
|
|
32082
33457
|
...cleanMetrics5(llmState.metrics),
|
|
32083
33458
|
...buildDurationMetrics3(llmState.startTime)
|
|
32084
33459
|
};
|
|
32085
|
-
const
|
|
32086
|
-
if (Object.keys(
|
|
33460
|
+
const usageMetrics2 = extractUsageMetrics2(message?.usage);
|
|
33461
|
+
if (Object.keys(usageMetrics2).length > 0) {
|
|
32087
33462
|
promptState.collectedLlmUsageMetrics = true;
|
|
32088
|
-
addMetrics(promptState.metrics,
|
|
33463
|
+
addMetrics(promptState.metrics, usageMetrics2);
|
|
32089
33464
|
}
|
|
32090
33465
|
try {
|
|
32091
33466
|
safeLog4(llmState.span, {
|
|
@@ -32103,14 +33478,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
|
|
|
32103
33478
|
}
|
|
32104
33479
|
function finishOpenToolSpans(state, error) {
|
|
32105
33480
|
for (const [, toolState] of state.activeToolSpans) {
|
|
32106
|
-
|
|
32107
|
-
|
|
32108
|
-
|
|
32109
|
-
|
|
32110
|
-
toolState.span.end();
|
|
32111
|
-
} finally {
|
|
32112
|
-
toolState.restoreAutoInstrumentation?.();
|
|
32113
|
-
}
|
|
33481
|
+
safeLog4(toolState.span, {
|
|
33482
|
+
error: error ? toLoggedError(error) : "Pi tool did not complete"
|
|
33483
|
+
});
|
|
33484
|
+
toolState.span.end();
|
|
32114
33485
|
}
|
|
32115
33486
|
state.activeToolSpans.clear();
|
|
32116
33487
|
}
|
|
@@ -32429,12 +33800,12 @@ var MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES = 32;
|
|
|
32429
33800
|
var StrandsAgentSDKPlugin = class extends BasePlugin {
|
|
32430
33801
|
activeChildParents = /* @__PURE__ */ new WeakMap();
|
|
32431
33802
|
onEnable() {
|
|
32432
|
-
this.
|
|
32433
|
-
this.
|
|
33803
|
+
this.interceptAgentStream();
|
|
33804
|
+
this.interceptMultiAgentStream(
|
|
32434
33805
|
strandsAgentSDKChannels.graphStream,
|
|
32435
33806
|
"Graph.stream"
|
|
32436
33807
|
);
|
|
32437
|
-
this.
|
|
33808
|
+
this.interceptMultiAgentStream(
|
|
32438
33809
|
strandsAgentSDKChannels.swarmStream,
|
|
32439
33810
|
"Swarm.stream"
|
|
32440
33811
|
);
|
|
@@ -32445,122 +33816,92 @@ var StrandsAgentSDKPlugin = class extends BasePlugin {
|
|
|
32445
33816
|
}
|
|
32446
33817
|
this.unsubscribers = [];
|
|
32447
33818
|
}
|
|
32448
|
-
|
|
32449
|
-
|
|
32450
|
-
|
|
32451
|
-
|
|
32452
|
-
|
|
32453
|
-
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
|
|
32458
|
-
|
|
32459
|
-
|
|
32460
|
-
|
|
32461
|
-
|
|
32462
|
-
|
|
32463
|
-
|
|
32464
|
-
const result = event.result;
|
|
32465
|
-
if (isAsyncIterable(result)) {
|
|
32466
|
-
patchStreamIfNeeded(result, {
|
|
32467
|
-
aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
|
|
32468
|
-
onChunk: (chunk) => handleAgentStreamEvent(state, chunk),
|
|
32469
|
-
onComplete: () => {
|
|
32470
|
-
finalizeAgentStream(state);
|
|
32471
|
-
states.delete(event);
|
|
32472
|
-
},
|
|
32473
|
-
onError: (error) => {
|
|
32474
|
-
finalizeAgentStream(state, error);
|
|
32475
|
-
states.delete(event);
|
|
32476
|
-
}
|
|
32477
|
-
});
|
|
32478
|
-
return;
|
|
32479
|
-
}
|
|
32480
|
-
finalizeAgentStream(state, void 0, result);
|
|
32481
|
-
states.delete(event);
|
|
32482
|
-
},
|
|
32483
|
-
error: (event) => {
|
|
32484
|
-
const state = states.get(event);
|
|
32485
|
-
if (!state || !event.error) {
|
|
32486
|
-
return;
|
|
32487
|
-
}
|
|
32488
|
-
finalizeAgentStream(state, event.error);
|
|
32489
|
-
states.delete(event);
|
|
32490
|
-
}
|
|
32491
|
-
};
|
|
32492
|
-
channel2.subscribe(handlers);
|
|
32493
|
-
this.unsubscribers.push(() => {
|
|
32494
|
-
unbindAutoInstrumentationSuppression?.();
|
|
32495
|
-
channel2.unsubscribe(handlers);
|
|
32496
|
-
});
|
|
33819
|
+
interceptAgentStream() {
|
|
33820
|
+
this.unsubscribers.push(
|
|
33821
|
+
strandsAgentSDKChannels.agentStream.intercept(
|
|
33822
|
+
(target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
|
|
33823
|
+
finalize: finalizeAgentStream,
|
|
33824
|
+
handleChunk: handleAgentStreamEvent,
|
|
33825
|
+
invoke: () => Reflect.apply(target, thisArg, args),
|
|
33826
|
+
name: "Strands Agent SDK",
|
|
33827
|
+
start: () => startAgentStream(
|
|
33828
|
+
args[0],
|
|
33829
|
+
extractAgent(additional.agent, thisArg),
|
|
33830
|
+
this.activeChildParents
|
|
33831
|
+
)
|
|
33832
|
+
})
|
|
33833
|
+
)
|
|
33834
|
+
);
|
|
32497
33835
|
}
|
|
32498
|
-
|
|
32499
|
-
|
|
32500
|
-
|
|
32501
|
-
|
|
32502
|
-
|
|
32503
|
-
|
|
32504
|
-
|
|
32505
|
-
|
|
32506
|
-
|
|
32507
|
-
|
|
32508
|
-
|
|
32509
|
-
|
|
32510
|
-
|
|
32511
|
-
|
|
32512
|
-
|
|
32513
|
-
|
|
32514
|
-
|
|
32515
|
-
|
|
32516
|
-
|
|
32517
|
-
}
|
|
32518
|
-
|
|
32519
|
-
|
|
32520
|
-
|
|
32521
|
-
|
|
32522
|
-
|
|
32523
|
-
|
|
32524
|
-
|
|
32525
|
-
|
|
32526
|
-
|
|
32527
|
-
|
|
32528
|
-
|
|
32529
|
-
|
|
32530
|
-
|
|
32531
|
-
|
|
32532
|
-
|
|
32533
|
-
|
|
32534
|
-
|
|
32535
|
-
|
|
32536
|
-
|
|
32537
|
-
|
|
32538
|
-
|
|
32539
|
-
|
|
32540
|
-
this.activeChildParents,
|
|
32541
|
-
void 0,
|
|
32542
|
-
result
|
|
33836
|
+
interceptMultiAgentStream(channel2, operation) {
|
|
33837
|
+
this.unsubscribers.push(
|
|
33838
|
+
channel2.intercept(
|
|
33839
|
+
(target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
|
|
33840
|
+
finalize: (state, error, output) => finalizeMultiAgentStream(
|
|
33841
|
+
state,
|
|
33842
|
+
this.activeChildParents,
|
|
33843
|
+
error,
|
|
33844
|
+
output
|
|
33845
|
+
),
|
|
33846
|
+
handleChunk: (state, chunk) => handleMultiAgentStreamEvent(state, chunk, this.activeChildParents),
|
|
33847
|
+
invoke: () => Reflect.apply(target, thisArg, args),
|
|
33848
|
+
name: "Strands multi-agent",
|
|
33849
|
+
start: () => startMultiAgentStream(
|
|
33850
|
+
args[0],
|
|
33851
|
+
extractOrchestrator(additional.orchestrator, thisArg),
|
|
33852
|
+
operation,
|
|
33853
|
+
this.activeChildParents
|
|
33854
|
+
)
|
|
33855
|
+
})
|
|
33856
|
+
)
|
|
33857
|
+
);
|
|
33858
|
+
}
|
|
33859
|
+
};
|
|
33860
|
+
function instrumentStrandsStreamInvocation(options) {
|
|
33861
|
+
let state;
|
|
33862
|
+
try {
|
|
33863
|
+
state = options.start();
|
|
33864
|
+
} catch (error) {
|
|
33865
|
+
debugLogger.error(`Error starting ${options.name} instrumentation:`, error);
|
|
33866
|
+
}
|
|
33867
|
+
let result;
|
|
33868
|
+
try {
|
|
33869
|
+
result = runWithAutoInstrumentationSuppressed(options.invoke);
|
|
33870
|
+
} catch (error) {
|
|
33871
|
+
if (state) {
|
|
33872
|
+
try {
|
|
33873
|
+
options.finalize(state, error);
|
|
33874
|
+
} catch (instrumentationError) {
|
|
33875
|
+
debugLogger.error(
|
|
33876
|
+
`Error handling ${options.name} instrumentation failure:`,
|
|
33877
|
+
instrumentationError
|
|
32543
33878
|
);
|
|
32544
|
-
states.delete(event);
|
|
32545
|
-
},
|
|
32546
|
-
error: (event) => {
|
|
32547
|
-
const state = states.get(event);
|
|
32548
|
-
if (!state || !event.error) {
|
|
32549
|
-
return;
|
|
32550
|
-
}
|
|
32551
|
-
finalizeMultiAgentStream(state, this.activeChildParents, event.error);
|
|
32552
|
-
states.delete(event);
|
|
32553
33879
|
}
|
|
32554
|
-
}
|
|
32555
|
-
|
|
32556
|
-
this.unsubscribers.push(() => {
|
|
32557
|
-
unbindAutoInstrumentationSuppression?.();
|
|
32558
|
-
tracingChannel.unsubscribe(handlers);
|
|
32559
|
-
});
|
|
33880
|
+
}
|
|
33881
|
+
throw error;
|
|
32560
33882
|
}
|
|
32561
|
-
|
|
32562
|
-
|
|
32563
|
-
|
|
33883
|
+
if (state) {
|
|
33884
|
+
try {
|
|
33885
|
+
if (isAsyncIterable(result)) {
|
|
33886
|
+
patchStreamIfNeeded(result, {
|
|
33887
|
+
aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
|
|
33888
|
+
onChunk: (chunk) => options.handleChunk(state, chunk),
|
|
33889
|
+
onComplete: () => options.finalize(state),
|
|
33890
|
+
onError: (error) => options.finalize(state, error)
|
|
33891
|
+
});
|
|
33892
|
+
} else {
|
|
33893
|
+
options.finalize(state, void 0, result);
|
|
33894
|
+
}
|
|
33895
|
+
} catch (error) {
|
|
33896
|
+
debugLogger.error(
|
|
33897
|
+
`Error finalizing ${options.name} instrumentation:`,
|
|
33898
|
+
error
|
|
33899
|
+
);
|
|
33900
|
+
}
|
|
33901
|
+
}
|
|
33902
|
+
return result;
|
|
33903
|
+
}
|
|
33904
|
+
function startAgentStream(input, agent, activeChildParents) {
|
|
32564
33905
|
const model = agent?.model;
|
|
32565
33906
|
const metadata = {
|
|
32566
33907
|
...extractAgentMetadata2(agent),
|
|
@@ -32570,17 +33911,14 @@ function startAgentStream(event, activeChildParents) {
|
|
|
32570
33911
|
};
|
|
32571
33912
|
const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
|
|
32572
33913
|
const attachmentCache = createStrandsAttachmentCache();
|
|
32573
|
-
const
|
|
32574
|
-
event.arguments[0],
|
|
32575
|
-
attachmentCache
|
|
32576
|
-
);
|
|
33914
|
+
const processedInput = processStrandsInputAttachments(input, attachmentCache);
|
|
32577
33915
|
const span = parentSpan ? withCurrent(
|
|
32578
33916
|
parentSpan,
|
|
32579
33917
|
() => startSpan(
|
|
32580
33918
|
withSpanInstrumentationName(
|
|
32581
33919
|
{
|
|
32582
33920
|
event: {
|
|
32583
|
-
input,
|
|
33921
|
+
input: processedInput,
|
|
32584
33922
|
metadata
|
|
32585
33923
|
},
|
|
32586
33924
|
name: formatAgentSpanName(agent),
|
|
@@ -32593,7 +33931,7 @@ function startAgentStream(event, activeChildParents) {
|
|
|
32593
33931
|
withSpanInstrumentationName(
|
|
32594
33932
|
{
|
|
32595
33933
|
event: {
|
|
32596
|
-
input,
|
|
33934
|
+
input: processedInput,
|
|
32597
33935
|
metadata
|
|
32598
33936
|
},
|
|
32599
33937
|
name: formatAgentSpanName(agent),
|
|
@@ -32611,22 +33949,21 @@ function startAgentStream(event, activeChildParents) {
|
|
|
32611
33949
|
startTime: getCurrentUnixTimestamp()
|
|
32612
33950
|
};
|
|
32613
33951
|
}
|
|
32614
|
-
function startMultiAgentStream(
|
|
32615
|
-
const orchestrator = extractOrchestrator(event);
|
|
33952
|
+
function startMultiAgentStream(input, orchestrator, operation, activeChildParents) {
|
|
32616
33953
|
const metadata = {
|
|
32617
33954
|
"strands.operation": operation,
|
|
32618
33955
|
provider: "strands",
|
|
32619
33956
|
...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
|
|
32620
33957
|
};
|
|
32621
33958
|
const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
|
|
32622
|
-
const
|
|
33959
|
+
const processedInput = processStrandsInputAttachments(input);
|
|
32623
33960
|
const span = parentSpan ? withCurrent(
|
|
32624
33961
|
parentSpan,
|
|
32625
33962
|
() => startSpan(
|
|
32626
33963
|
withSpanInstrumentationName(
|
|
32627
33964
|
{
|
|
32628
33965
|
event: {
|
|
32629
|
-
input,
|
|
33966
|
+
input: processedInput,
|
|
32630
33967
|
metadata
|
|
32631
33968
|
},
|
|
32632
33969
|
name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
|
|
@@ -32639,7 +33976,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
|
|
|
32639
33976
|
withSpanInstrumentationName(
|
|
32640
33977
|
{
|
|
32641
33978
|
event: {
|
|
32642
|
-
input,
|
|
33979
|
+
input: processedInput,
|
|
32643
33980
|
metadata
|
|
32644
33981
|
},
|
|
32645
33982
|
name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
|
|
@@ -33010,12 +34347,12 @@ function finalizeMultiAgentStream(state, activeChildParents, error, output) {
|
|
|
33010
34347
|
});
|
|
33011
34348
|
state.span.end();
|
|
33012
34349
|
}
|
|
33013
|
-
function extractAgent(
|
|
33014
|
-
const candidate =
|
|
34350
|
+
function extractAgent(agent, self) {
|
|
34351
|
+
const candidate = agent ?? self;
|
|
33015
34352
|
return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
|
|
33016
34353
|
}
|
|
33017
|
-
function extractOrchestrator(
|
|
33018
|
-
const candidate =
|
|
34354
|
+
function extractOrchestrator(orchestrator, self) {
|
|
34355
|
+
const candidate = orchestrator ?? self;
|
|
33019
34356
|
return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
|
|
33020
34357
|
}
|
|
33021
34358
|
function extractAgentMetadata2(agent) {
|
|
@@ -34535,7 +35872,7 @@ function braintrustEveHook(options) {
|
|
|
34535
35872
|
}
|
|
34536
35873
|
};
|
|
34537
35874
|
}
|
|
34538
|
-
function
|
|
35875
|
+
function createLegacyEveInstrumentation(options) {
|
|
34539
35876
|
const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
|
|
34540
35877
|
return {
|
|
34541
35878
|
events: {
|
|
@@ -35923,8 +37260,10 @@ function capturedModelInput(modelInput) {
|
|
|
35923
37260
|
const value = [];
|
|
35924
37261
|
if (typeof instructions === "string") {
|
|
35925
37262
|
value.push({ content: instructions, role: "system" });
|
|
35926
|
-
} else if (instructions) {
|
|
37263
|
+
} else if (Array.isArray(instructions)) {
|
|
35927
37264
|
value.push(...instructions.map(capturedEveModelMessage));
|
|
37265
|
+
} else if (instructions) {
|
|
37266
|
+
value.push(capturedEveModelMessage(instructions));
|
|
35928
37267
|
}
|
|
35929
37268
|
value.push(...messages.map(capturedEveModelMessage));
|
|
35930
37269
|
try {
|
|
@@ -36168,6 +37507,472 @@ async function deterministicEveId(...parts) {
|
|
|
36168
37507
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
36169
37508
|
}
|
|
36170
37509
|
|
|
37510
|
+
// src/instrumentation/plugins/eve-provider.ts
|
|
37511
|
+
var MAX_EVE_PROVIDER_CACHE_ENTRIES = 1e4;
|
|
37512
|
+
function createEveInstrumentationProvider(options = {}) {
|
|
37513
|
+
const bridge = new EveProviderBridge(options.metadata);
|
|
37514
|
+
return {
|
|
37515
|
+
// Eve versions before tracePolicy use capture to decide whether provider
|
|
37516
|
+
// events include content. Newer versions prefer tracePolicy when both are
|
|
37517
|
+
// present, so keep the deprecated field for backwards compatibility.
|
|
37518
|
+
capture: "content",
|
|
37519
|
+
tracePolicy: () => ({
|
|
37520
|
+
emit: true,
|
|
37521
|
+
recordInputs: true,
|
|
37522
|
+
recordOutputs: true
|
|
37523
|
+
}),
|
|
37524
|
+
events: {
|
|
37525
|
+
"action.completed": (event, context) => bridge.handleActionTerminal(event, context),
|
|
37526
|
+
"action.failed": (event, context) => bridge.handleActionTerminal(event, context),
|
|
37527
|
+
"action.started": (event, context) => bridge.handleActionStarted(event, context),
|
|
37528
|
+
"model.call.completed": (event, context) => bridge.handleModelTerminal(event, context),
|
|
37529
|
+
"model.call.failed": (event, context) => bridge.handleModelTerminal(event, context),
|
|
37530
|
+
"model.call.started": (event, context) => bridge.handleModelStarted(event, context),
|
|
37531
|
+
"step.attempt.completed": (event) => bridge.handleStepAttemptTerminal(event),
|
|
37532
|
+
"step.attempt.failed": (event) => bridge.handleStepAttemptTerminal(event),
|
|
37533
|
+
"turn.cancelled": (event, context) => bridge.handleTurnTerminal(event, context),
|
|
37534
|
+
"turn.completed": (event, context) => bridge.handleTurnTerminal(event, context),
|
|
37535
|
+
"turn.failed": (event, context) => bridge.handleTurnTerminal(event, context),
|
|
37536
|
+
"turn.started": (event, context) => bridge.handleTurnStarted(event, context)
|
|
37537
|
+
},
|
|
37538
|
+
flush,
|
|
37539
|
+
setup: options.setup
|
|
37540
|
+
};
|
|
37541
|
+
}
|
|
37542
|
+
var EveProviderBridge = class {
|
|
37543
|
+
constructor(metadata) {
|
|
37544
|
+
this.metadata = metadata;
|
|
37545
|
+
}
|
|
37546
|
+
metadata;
|
|
37547
|
+
activeActions = /* @__PURE__ */ new Map();
|
|
37548
|
+
activeModels = /* @__PURE__ */ new Map();
|
|
37549
|
+
modelsByAttempt = /* @__PURE__ */ new Map();
|
|
37550
|
+
settledOperations = new LRUCache({
|
|
37551
|
+
max: MAX_EVE_PROVIDER_CACHE_ENTRIES
|
|
37552
|
+
});
|
|
37553
|
+
turns = new LRUCache({
|
|
37554
|
+
max: MAX_EVE_PROVIDER_CACHE_ENTRIES
|
|
37555
|
+
});
|
|
37556
|
+
async handleTurnStarted(event, context) {
|
|
37557
|
+
await this.contain("turn start", async () => {
|
|
37558
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37559
|
+
context.state.set({ skip: true });
|
|
37560
|
+
return;
|
|
37561
|
+
}
|
|
37562
|
+
const { rowId, spanId } = await generateEveIds(
|
|
37563
|
+
"turn",
|
|
37564
|
+
event.idempotencyKey
|
|
37565
|
+
);
|
|
37566
|
+
const key = turnKey3(event.sessionId, event.turnId);
|
|
37567
|
+
const stored = storedSpan(context);
|
|
37568
|
+
if (stored && "exported" in stored && stored.rootSpanId) {
|
|
37569
|
+
this.turns.set(key, { rootSpanId: stored.rootSpanId, spanId });
|
|
37570
|
+
return;
|
|
37571
|
+
}
|
|
37572
|
+
let rootSpanId = spanId;
|
|
37573
|
+
let parentSpanId;
|
|
37574
|
+
if (event.parentLineage) {
|
|
37575
|
+
const parentTurnKey = turnKey3(
|
|
37576
|
+
event.parentLineage.sessionId,
|
|
37577
|
+
event.parentLineage.turnId
|
|
37578
|
+
);
|
|
37579
|
+
const parentTurn = this.turns.get(parentTurnKey);
|
|
37580
|
+
rootSpanId = parentTurn?.rootSpanId ?? // Eve propagates the root session through every nested subagent. Use
|
|
37581
|
+
// it instead of the immediate parent session when no ancestor ran
|
|
37582
|
+
// in-process.
|
|
37583
|
+
(await generateEveIds(
|
|
37584
|
+
"turn",
|
|
37585
|
+
turnIdempotencyKey(
|
|
37586
|
+
event.rootSessionId,
|
|
37587
|
+
event.parentLineage.turnId
|
|
37588
|
+
)
|
|
37589
|
+
)).spanId;
|
|
37590
|
+
parentSpanId = (await generateEveIds(
|
|
37591
|
+
"subagent",
|
|
37592
|
+
actionIdempotencyKey(
|
|
37593
|
+
event.parentLineage.sessionId,
|
|
37594
|
+
event.parentLineage.turnId,
|
|
37595
|
+
event.parentLineage.callId
|
|
37596
|
+
)
|
|
37597
|
+
)).spanId;
|
|
37598
|
+
}
|
|
37599
|
+
const metadata = this.spanMetadata(event.sessionId);
|
|
37600
|
+
const span = await this.startSpan(
|
|
37601
|
+
context,
|
|
37602
|
+
{
|
|
37603
|
+
event: { id: rowId, metadata },
|
|
37604
|
+
name: "eve.turn",
|
|
37605
|
+
parentSpanIds: parentSpanId ? { rootSpanId, spanId: parentSpanId } : { parentSpanIds: [], rootSpanId },
|
|
37606
|
+
spanAttributes: { type: "task" /* TASK */ },
|
|
37607
|
+
spanId
|
|
37608
|
+
},
|
|
37609
|
+
rootSpanId
|
|
37610
|
+
);
|
|
37611
|
+
span?.log({ metadata });
|
|
37612
|
+
this.turns.set(key, {
|
|
37613
|
+
rootSpanId,
|
|
37614
|
+
spanId
|
|
37615
|
+
});
|
|
37616
|
+
});
|
|
37617
|
+
}
|
|
37618
|
+
async handleTurnTerminal(event, context) {
|
|
37619
|
+
await this.contain("turn terminal", async () => {
|
|
37620
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37621
|
+
context.state.set(void 0);
|
|
37622
|
+
return;
|
|
37623
|
+
}
|
|
37624
|
+
const error = event.type === "turn.failed" ? event.error : void 0;
|
|
37625
|
+
this.drainActionsForTurn(event.sessionId, event.turnId, error);
|
|
37626
|
+
const stored = storedSpan(context);
|
|
37627
|
+
if (stored && "exported" in stored) {
|
|
37628
|
+
updateSpan({
|
|
37629
|
+
exported: stored.exported,
|
|
37630
|
+
...error !== void 0 ? { error } : {},
|
|
37631
|
+
metrics: { end: Date.now() / 1e3 }
|
|
37632
|
+
});
|
|
37633
|
+
}
|
|
37634
|
+
this.settledOperations.set(event.idempotencyKey, true);
|
|
37635
|
+
context.state.set(void 0);
|
|
37636
|
+
this.turns.delete(turnKey3(event.sessionId, event.turnId));
|
|
37637
|
+
});
|
|
37638
|
+
}
|
|
37639
|
+
async handleModelStarted(event, context) {
|
|
37640
|
+
await this.contain("model start", async () => {
|
|
37641
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37642
|
+
context.state.set({ skip: true });
|
|
37643
|
+
return;
|
|
37644
|
+
}
|
|
37645
|
+
const parent = await this.parentForScope(event.scope);
|
|
37646
|
+
const { rowId, spanId } = await generateEveIds(
|
|
37647
|
+
"step",
|
|
37648
|
+
event.idempotencyKey
|
|
37649
|
+
);
|
|
37650
|
+
const input = event.input ? capturedModelInput(event.input) : void 0;
|
|
37651
|
+
const metadata = {
|
|
37652
|
+
...this.spanMetadata(event.scope.sessionId),
|
|
37653
|
+
model: event.model.modelId,
|
|
37654
|
+
provider: event.model.provider
|
|
37655
|
+
};
|
|
37656
|
+
const span = await this.startSpan(context, {
|
|
37657
|
+
event: {
|
|
37658
|
+
id: rowId,
|
|
37659
|
+
...input !== void 0 ? { input } : {},
|
|
37660
|
+
metadata
|
|
37661
|
+
},
|
|
37662
|
+
name: "eve.step",
|
|
37663
|
+
parentSpanIds: parent,
|
|
37664
|
+
spanAttributes: { type: "llm" /* LLM */ },
|
|
37665
|
+
spanId
|
|
37666
|
+
});
|
|
37667
|
+
if (!span) return;
|
|
37668
|
+
span.log({ ...input !== void 0 ? { input } : {}, metadata });
|
|
37669
|
+
this.activeModels.set(event.idempotencyKey, {
|
|
37670
|
+
span,
|
|
37671
|
+
turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
|
|
37672
|
+
});
|
|
37673
|
+
const keys = this.modelsByAttempt.get(event.scope.attemptId) ?? /* @__PURE__ */ new Set();
|
|
37674
|
+
keys.add(event.idempotencyKey);
|
|
37675
|
+
this.modelsByAttempt.set(event.scope.attemptId, keys);
|
|
37676
|
+
});
|
|
37677
|
+
}
|
|
37678
|
+
async handleModelTerminal(event, context) {
|
|
37679
|
+
await this.contain("model terminal", async () => {
|
|
37680
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37681
|
+
context.state.set(void 0);
|
|
37682
|
+
return;
|
|
37683
|
+
}
|
|
37684
|
+
const active = this.activeModels.get(event.idempotencyKey);
|
|
37685
|
+
if (active) {
|
|
37686
|
+
const span = active.span;
|
|
37687
|
+
if (event.type === "model.call.failed") {
|
|
37688
|
+
if (event.error !== void 0) span.log({ error: event.error });
|
|
37689
|
+
} else {
|
|
37690
|
+
span.log({
|
|
37691
|
+
metrics: usageMetrics(event.usage),
|
|
37692
|
+
output: modelOutput(event)
|
|
37693
|
+
});
|
|
37694
|
+
}
|
|
37695
|
+
span.end();
|
|
37696
|
+
} else {
|
|
37697
|
+
const stored = storedSpan(context);
|
|
37698
|
+
if (stored && "exported" in stored) {
|
|
37699
|
+
updateSpan({
|
|
37700
|
+
exported: stored.exported,
|
|
37701
|
+
...event.type === "model.call.failed" ? event.error !== void 0 ? { error: event.error } : {} : { output: modelOutput(event) },
|
|
37702
|
+
metrics: {
|
|
37703
|
+
...event.type === "model.call.completed" ? usageMetrics(event.usage) : {},
|
|
37704
|
+
end: Date.now() / 1e3
|
|
37705
|
+
}
|
|
37706
|
+
});
|
|
37707
|
+
}
|
|
37708
|
+
}
|
|
37709
|
+
this.settledOperations.set(event.idempotencyKey, true);
|
|
37710
|
+
this.forgetModel(event.scope.attemptId, event.idempotencyKey);
|
|
37711
|
+
context.state.set(void 0);
|
|
37712
|
+
});
|
|
37713
|
+
}
|
|
37714
|
+
async handleActionStarted(event, context) {
|
|
37715
|
+
await this.contain("action start", async () => {
|
|
37716
|
+
if (event.kind === "load-skill" || this.settledOperations.has(event.idempotencyKey)) {
|
|
37717
|
+
context.state.set({ skip: true });
|
|
37718
|
+
return;
|
|
37719
|
+
}
|
|
37720
|
+
const parent = await this.parentForScope(event.scope);
|
|
37721
|
+
const { rowId, spanId } = await generateEveIds(
|
|
37722
|
+
event.kind === "subagent-call" ? "subagent" : "tool",
|
|
37723
|
+
event.idempotencyKey
|
|
37724
|
+
);
|
|
37725
|
+
const metadata = {
|
|
37726
|
+
...this.spanMetadata(event.scope.sessionId),
|
|
37727
|
+
"eve.action_kind": event.kind
|
|
37728
|
+
};
|
|
37729
|
+
const span = await this.startSpan(context, {
|
|
37730
|
+
event: {
|
|
37731
|
+
id: rowId,
|
|
37732
|
+
...event.input !== void 0 ? { input: event.input } : {},
|
|
37733
|
+
metadata
|
|
37734
|
+
},
|
|
37735
|
+
name: event.name,
|
|
37736
|
+
parentSpanIds: parent,
|
|
37737
|
+
spanAttributes: { type: "tool" /* TOOL */ },
|
|
37738
|
+
spanId
|
|
37739
|
+
});
|
|
37740
|
+
if (!span) return;
|
|
37741
|
+
span.log({
|
|
37742
|
+
...event.input !== void 0 ? { input: event.input } : {},
|
|
37743
|
+
metadata
|
|
37744
|
+
});
|
|
37745
|
+
this.activeActions.set(event.idempotencyKey, {
|
|
37746
|
+
span,
|
|
37747
|
+
turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
|
|
37748
|
+
});
|
|
37749
|
+
});
|
|
37750
|
+
}
|
|
37751
|
+
async handleActionTerminal(event, context) {
|
|
37752
|
+
await this.contain("action terminal", async () => {
|
|
37753
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37754
|
+
context.state.set(void 0);
|
|
37755
|
+
return;
|
|
37756
|
+
}
|
|
37757
|
+
const stored = storedSpan(context);
|
|
37758
|
+
if (stored?.skip) {
|
|
37759
|
+
context.state.set(void 0);
|
|
37760
|
+
return;
|
|
37761
|
+
}
|
|
37762
|
+
const active = this.activeActions.get(event.idempotencyKey);
|
|
37763
|
+
const end = finiteTimestamp(event.acceptedAtMs) ?? Date.now();
|
|
37764
|
+
if (active) {
|
|
37765
|
+
const span = active.span;
|
|
37766
|
+
if (event.type === "action.failed") {
|
|
37767
|
+
span.log({
|
|
37768
|
+
error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
|
|
37769
|
+
});
|
|
37770
|
+
} else if (event.output.type === "error") {
|
|
37771
|
+
span.log({
|
|
37772
|
+
error: event.output.error ?? new Error("Eve action returned an error")
|
|
37773
|
+
});
|
|
37774
|
+
} else {
|
|
37775
|
+
span.log({ output: event.output.output });
|
|
37776
|
+
}
|
|
37777
|
+
span.end({ endTime: end / 1e3 });
|
|
37778
|
+
} else {
|
|
37779
|
+
const stored2 = storedSpan(context);
|
|
37780
|
+
if (stored2 && "exported" in stored2) {
|
|
37781
|
+
updateSpan({
|
|
37782
|
+
exported: stored2.exported,
|
|
37783
|
+
...event.type === "action.failed" ? {
|
|
37784
|
+
error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
|
|
37785
|
+
} : event.output.type === "error" ? {
|
|
37786
|
+
error: event.output.error ?? new Error("Eve action returned an error")
|
|
37787
|
+
} : { output: event.output.output },
|
|
37788
|
+
metrics: { end: end / 1e3 }
|
|
37789
|
+
});
|
|
37790
|
+
}
|
|
37791
|
+
}
|
|
37792
|
+
this.settledOperations.set(event.idempotencyKey, true);
|
|
37793
|
+
this.activeActions.delete(event.idempotencyKey);
|
|
37794
|
+
context.state.set(void 0);
|
|
37795
|
+
});
|
|
37796
|
+
}
|
|
37797
|
+
handleStepAttemptTerminal(event) {
|
|
37798
|
+
void this.contain("step attempt terminal", () => {
|
|
37799
|
+
const keys = this.modelsByAttempt.get(event.scope.attemptId);
|
|
37800
|
+
if (!keys) return;
|
|
37801
|
+
for (const key of keys) {
|
|
37802
|
+
const active = this.activeModels.get(key);
|
|
37803
|
+
if (!active) continue;
|
|
37804
|
+
if (event.type === "step.attempt.failed" && event.error !== void 0) {
|
|
37805
|
+
active.span.log({ error: event.error });
|
|
37806
|
+
}
|
|
37807
|
+
active.span.end();
|
|
37808
|
+
this.activeModels.delete(key);
|
|
37809
|
+
}
|
|
37810
|
+
this.modelsByAttempt.delete(event.scope.attemptId);
|
|
37811
|
+
});
|
|
37812
|
+
}
|
|
37813
|
+
async parentForScope(scope) {
|
|
37814
|
+
const key = turnKey3(scope.sessionId, scope.turnId);
|
|
37815
|
+
const known = this.turns.get(key);
|
|
37816
|
+
if (known) {
|
|
37817
|
+
return { rootSpanId: known.rootSpanId, spanId: known.spanId };
|
|
37818
|
+
}
|
|
37819
|
+
const [{ spanId }, { spanId: rootSpanId }] = await Promise.all([
|
|
37820
|
+
generateEveIds("turn", turnIdempotencyKey(scope.sessionId, scope.turnId)),
|
|
37821
|
+
generateEveIds(
|
|
37822
|
+
"turn",
|
|
37823
|
+
turnIdempotencyKey(
|
|
37824
|
+
scope.rootSessionId ?? scope.sessionId,
|
|
37825
|
+
scope.turnId
|
|
37826
|
+
)
|
|
37827
|
+
)
|
|
37828
|
+
]);
|
|
37829
|
+
return { rootSpanId, spanId };
|
|
37830
|
+
}
|
|
37831
|
+
async startSpan(context, args, rootSpanId) {
|
|
37832
|
+
const span = withCurrent(
|
|
37833
|
+
NOOP_SPAN,
|
|
37834
|
+
() => _internalStartSpanWithInitialMerge(
|
|
37835
|
+
withSpanInstrumentationName(args ?? {}, INSTRUMENTATION_NAMES.EVE)
|
|
37836
|
+
)
|
|
37837
|
+
);
|
|
37838
|
+
try {
|
|
37839
|
+
context.state.set({
|
|
37840
|
+
exported: await span.export(),
|
|
37841
|
+
...rootSpanId ? { rootSpanId } : {}
|
|
37842
|
+
});
|
|
37843
|
+
} catch (error) {
|
|
37844
|
+
debugLogger.warn("Error exporting Eve provider span:", error);
|
|
37845
|
+
}
|
|
37846
|
+
return span;
|
|
37847
|
+
}
|
|
37848
|
+
drainActionsForTurn(sessionId, turnId, error) {
|
|
37849
|
+
const key = turnKey3(sessionId, turnId);
|
|
37850
|
+
for (const [idempotencyKey, active] of this.activeActions) {
|
|
37851
|
+
if (active.turnKey !== key) continue;
|
|
37852
|
+
if (error !== void 0) active.span.log({ error });
|
|
37853
|
+
active.span.end();
|
|
37854
|
+
this.activeActions.delete(idempotencyKey);
|
|
37855
|
+
}
|
|
37856
|
+
}
|
|
37857
|
+
forgetModel(attemptId, idempotencyKey) {
|
|
37858
|
+
this.activeModels.delete(idempotencyKey);
|
|
37859
|
+
const keys = this.modelsByAttempt.get(attemptId);
|
|
37860
|
+
keys?.delete(idempotencyKey);
|
|
37861
|
+
if (keys?.size === 0) this.modelsByAttempt.delete(attemptId);
|
|
37862
|
+
}
|
|
37863
|
+
spanMetadata(sessionId) {
|
|
37864
|
+
return {
|
|
37865
|
+
...this.metadata ?? {},
|
|
37866
|
+
"eve.session_id": sessionId
|
|
37867
|
+
};
|
|
37868
|
+
}
|
|
37869
|
+
async contain(operation, fn) {
|
|
37870
|
+
try {
|
|
37871
|
+
await fn();
|
|
37872
|
+
} catch (error) {
|
|
37873
|
+
debugLogger.warn(`Error in Eve provider ${operation}:`, error);
|
|
37874
|
+
}
|
|
37875
|
+
}
|
|
37876
|
+
};
|
|
37877
|
+
function storedSpan(context) {
|
|
37878
|
+
const value = context.state.get();
|
|
37879
|
+
if (!isObject(value)) return void 0;
|
|
37880
|
+
if (value["skip"] === true) return { skip: true };
|
|
37881
|
+
return typeof value["exported"] === "string" ? {
|
|
37882
|
+
exported: value["exported"],
|
|
37883
|
+
...typeof value["rootSpanId"] === "string" && value["rootSpanId"].length > 0 ? { rootSpanId: value["rootSpanId"] } : {}
|
|
37884
|
+
} : void 0;
|
|
37885
|
+
}
|
|
37886
|
+
function modelOutput(event) {
|
|
37887
|
+
const content = event.content ?? [];
|
|
37888
|
+
let text = "";
|
|
37889
|
+
const reasoning = [];
|
|
37890
|
+
const toolCalls = [];
|
|
37891
|
+
for (const part of content) {
|
|
37892
|
+
if (part.type === "text") {
|
|
37893
|
+
text += part.text;
|
|
37894
|
+
} else if (part.type === "reasoning" && part.text.trim().length > 0) {
|
|
37895
|
+
reasoning.push({ content: part.text });
|
|
37896
|
+
} else if (part.type === "tool-call") {
|
|
37897
|
+
toolCalls.push({
|
|
37898
|
+
function: {
|
|
37899
|
+
arguments: safeJsonStringify(part.input),
|
|
37900
|
+
name: part.toolName
|
|
37901
|
+
},
|
|
37902
|
+
id: part.callId,
|
|
37903
|
+
type: "function"
|
|
37904
|
+
});
|
|
37905
|
+
}
|
|
37906
|
+
}
|
|
37907
|
+
return [
|
|
37908
|
+
{
|
|
37909
|
+
finish_reason: normalizeFinishReason2(event.finishReason),
|
|
37910
|
+
index: 0,
|
|
37911
|
+
message: {
|
|
37912
|
+
content: text || null,
|
|
37913
|
+
...reasoning.length > 0 ? { reasoning } : {},
|
|
37914
|
+
role: "assistant",
|
|
37915
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
37916
|
+
}
|
|
37917
|
+
}
|
|
37918
|
+
];
|
|
37919
|
+
}
|
|
37920
|
+
function usageMetrics(usage) {
|
|
37921
|
+
const promptTokens = nonNegativeNumber(usage.inputTokens);
|
|
37922
|
+
const completionTokens = nonNegativeNumber(usage.outputTokens);
|
|
37923
|
+
const cachedTokens = nonNegativeNumber(
|
|
37924
|
+
usage.inputTokenDetails?.cacheReadTokens
|
|
37925
|
+
);
|
|
37926
|
+
const cacheCreationTokens = nonNegativeNumber(
|
|
37927
|
+
usage.inputTokenDetails?.cacheWriteTokens
|
|
37928
|
+
);
|
|
37929
|
+
return {
|
|
37930
|
+
...promptTokens !== void 0 ? { prompt_tokens: promptTokens } : {},
|
|
37931
|
+
...completionTokens !== void 0 ? { completion_tokens: completionTokens } : {},
|
|
37932
|
+
...promptTokens !== void 0 && completionTokens !== void 0 ? { tokens: promptTokens + completionTokens } : {},
|
|
37933
|
+
...cachedTokens !== void 0 ? { prompt_cached_tokens: cachedTokens } : {},
|
|
37934
|
+
...cacheCreationTokens !== void 0 ? { prompt_cache_creation_tokens: cacheCreationTokens } : {}
|
|
37935
|
+
};
|
|
37936
|
+
}
|
|
37937
|
+
function nonNegativeNumber(value) {
|
|
37938
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
37939
|
+
}
|
|
37940
|
+
function finiteTimestamp(value) {
|
|
37941
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
37942
|
+
}
|
|
37943
|
+
function normalizeFinishReason2(value) {
|
|
37944
|
+
if (value === "content-filter") return "content_filter";
|
|
37945
|
+
if (value === "tool-calls") return "tool_calls";
|
|
37946
|
+
return value;
|
|
37947
|
+
}
|
|
37948
|
+
function safeJsonStringify(value) {
|
|
37949
|
+
try {
|
|
37950
|
+
return JSON.stringify(value) ?? "null";
|
|
37951
|
+
} catch {
|
|
37952
|
+
return "null";
|
|
37953
|
+
}
|
|
37954
|
+
}
|
|
37955
|
+
function turnKey3(sessionId, turnId) {
|
|
37956
|
+
return `${sessionId}:${turnId}`;
|
|
37957
|
+
}
|
|
37958
|
+
function turnIdempotencyKey(sessionId, turnId) {
|
|
37959
|
+
return `turn:${sessionId}:${turnId}`;
|
|
37960
|
+
}
|
|
37961
|
+
function actionIdempotencyKey(sessionId, turnId, callId) {
|
|
37962
|
+
return `action:${sessionId}:${turnId}:${callId}`;
|
|
37963
|
+
}
|
|
37964
|
+
|
|
37965
|
+
// src/instrumentation/plugins/eve-instrumentation.ts
|
|
37966
|
+
var EVE_INSTRUMENTATION_PROVIDER = /* @__PURE__ */ Symbol.for("eve.instrumentation.provider");
|
|
37967
|
+
function braintrustEveInstrumentation(options) {
|
|
37968
|
+
const definition = "defineState" in options ? createLegacyEveInstrumentation(options) : createEveInstrumentationProvider(options);
|
|
37969
|
+
const declaration = {
|
|
37970
|
+
...definition,
|
|
37971
|
+
[EVE_INSTRUMENTATION_PROVIDER]: true
|
|
37972
|
+
};
|
|
37973
|
+
return declaration;
|
|
37974
|
+
}
|
|
37975
|
+
|
|
36171
37976
|
// src/instrumentation/config.ts
|
|
36172
37977
|
var envIntegrationAliases = {
|
|
36173
37978
|
openai: "openai",
|