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
|
@@ -653,8 +653,6 @@ function newGlobalTracingChannel(nameOrChannels) {
|
|
|
653
653
|
var DefaultAsyncLocalStorage = class {
|
|
654
654
|
constructor() {
|
|
655
655
|
}
|
|
656
|
-
enterWith(_) {
|
|
657
|
-
}
|
|
658
656
|
run(_, callback) {
|
|
659
657
|
return callback();
|
|
660
658
|
}
|
|
@@ -2576,7 +2574,9 @@ var AclObjectType = z6.union([
|
|
|
2576
2574
|
"project_log",
|
|
2577
2575
|
"org_project",
|
|
2578
2576
|
"org_audit_logs",
|
|
2579
|
-
"project_group"
|
|
2577
|
+
"project_group",
|
|
2578
|
+
"ai_secret",
|
|
2579
|
+
"org_ai_secret"
|
|
2580
2580
|
]),
|
|
2581
2581
|
z6.null()
|
|
2582
2582
|
]);
|
|
@@ -3409,7 +3409,7 @@ var PromptParserNullish = z6.union([
|
|
|
3409
3409
|
}),
|
|
3410
3410
|
z6.null()
|
|
3411
3411
|
]);
|
|
3412
|
-
var
|
|
3412
|
+
var PreprocessorId = z6.union([
|
|
3413
3413
|
z6.object({
|
|
3414
3414
|
type: z6.literal("function"),
|
|
3415
3415
|
id: z6.string(),
|
|
@@ -3420,6 +3420,7 @@ var PreprocessorSavedFunctionId = z6.union([
|
|
|
3420
3420
|
name: z6.string(),
|
|
3421
3421
|
function_type: z6.literal("preprocessor").optional().default("preprocessor")
|
|
3422
3422
|
}),
|
|
3423
|
+
z6.object({ type: z6.literal("inline"), code: z6.string().min(1) }),
|
|
3423
3424
|
z6.null()
|
|
3424
3425
|
]);
|
|
3425
3426
|
var PromptDataNullish = z6.union([
|
|
@@ -3427,7 +3428,7 @@ var PromptDataNullish = z6.union([
|
|
|
3427
3428
|
prompt: PromptBlockDataNullish,
|
|
3428
3429
|
options: PromptOptionsNullish,
|
|
3429
3430
|
parser: PromptParserNullish,
|
|
3430
|
-
preprocessor:
|
|
3431
|
+
preprocessor: PreprocessorId,
|
|
3431
3432
|
tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
|
|
3432
3433
|
template_format: z6.union([
|
|
3433
3434
|
z6.enum(["mustache", "nunjucks", "none"]),
|
|
@@ -3629,7 +3630,7 @@ var PromptData = z6.object({
|
|
|
3629
3630
|
prompt: PromptBlockDataNullish,
|
|
3630
3631
|
options: PromptOptionsNullish,
|
|
3631
3632
|
parser: PromptParserNullish,
|
|
3632
|
-
preprocessor:
|
|
3633
|
+
preprocessor: PreprocessorId,
|
|
3633
3634
|
tool_functions: z6.union([z6.array(SavedFunctionId), z6.null()]),
|
|
3634
3635
|
template_format: z6.union([
|
|
3635
3636
|
z6.enum(["mustache", "nunjucks", "none"]),
|
|
@@ -4573,6 +4574,7 @@ var View = z6.object({
|
|
|
4573
4574
|
]),
|
|
4574
4575
|
name: z6.string(),
|
|
4575
4576
|
description: z6.union([z6.string(), z6.null()]).optional(),
|
|
4577
|
+
starred: z6.boolean().optional(),
|
|
4576
4578
|
created: z6.union([z6.string(), z6.null()]).optional(),
|
|
4577
4579
|
updated_at: z6.union([z6.string(), z6.null()]).optional(),
|
|
4578
4580
|
view_data: ViewData.optional(),
|
|
@@ -4662,6 +4664,34 @@ var registerTemplatePlugin = templateRegistry.register.bind(templateRegistry);
|
|
|
4662
4664
|
var getTemplateRenderer = templateRegistry.get.bind(templateRegistry);
|
|
4663
4665
|
registerTemplatePlugin(mustachePlugin);
|
|
4664
4666
|
|
|
4667
|
+
// src/template/renderer.ts
|
|
4668
|
+
function isTemplateFormat(v) {
|
|
4669
|
+
return v === "mustache" || v === "nunjucks" || v === "none";
|
|
4670
|
+
}
|
|
4671
|
+
function parseTemplateFormat(value, defaultFormat = "mustache") {
|
|
4672
|
+
return isTemplateFormat(value) ? value : defaultFormat;
|
|
4673
|
+
}
|
|
4674
|
+
function renderTemplateContent(template, variables, escape, options) {
|
|
4675
|
+
const strict = !!options.strict;
|
|
4676
|
+
const templateFormat = parseTemplateFormat(options.templateFormat);
|
|
4677
|
+
if (templateFormat === "none") {
|
|
4678
|
+
return template;
|
|
4679
|
+
}
|
|
4680
|
+
const renderer = getTemplateRenderer(templateFormat);
|
|
4681
|
+
if (!renderer) {
|
|
4682
|
+
if (templateFormat === "nunjucks") {
|
|
4683
|
+
throw new Error(
|
|
4684
|
+
"Nunjucks templating requires @braintrust/template-nunjucks. Install and import it to enable templateFormat: 'nunjucks'."
|
|
4685
|
+
);
|
|
4686
|
+
}
|
|
4687
|
+
throw new Error(`No template renderer registered for ${templateFormat}`);
|
|
4688
|
+
}
|
|
4689
|
+
if (strict && renderer.lint) {
|
|
4690
|
+
renderer.lint(template, variables);
|
|
4691
|
+
}
|
|
4692
|
+
return renderer.render(template, variables, escape, strict);
|
|
4693
|
+
}
|
|
4694
|
+
|
|
4665
4695
|
// src/logger.ts
|
|
4666
4696
|
import { z as z8, ZodError } from "zod/v3";
|
|
4667
4697
|
|
|
@@ -5248,44 +5278,72 @@ function createCacheLayers({
|
|
|
5248
5278
|
}
|
|
5249
5279
|
|
|
5250
5280
|
// src/prompt-cache/prompt-cache.ts
|
|
5251
|
-
function createCacheKey(key) {
|
|
5281
|
+
function createCacheKey(key, namespace) {
|
|
5282
|
+
let cacheKey;
|
|
5252
5283
|
if (key.id) {
|
|
5253
|
-
|
|
5254
|
-
}
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5284
|
+
cacheKey = `id:${key.id}`;
|
|
5285
|
+
} else {
|
|
5286
|
+
const prefix = key.projectId ?? key.projectName;
|
|
5287
|
+
if (!prefix) {
|
|
5288
|
+
throw new Error("Either projectId or projectName must be provided");
|
|
5289
|
+
}
|
|
5290
|
+
if (!key.slug) {
|
|
5291
|
+
throw new Error("Slug must be provided when not using ID");
|
|
5292
|
+
}
|
|
5293
|
+
cacheKey = `${prefix}:${key.slug}:${key.version ?? "latest"}`;
|
|
5261
5294
|
}
|
|
5262
|
-
return `${
|
|
5295
|
+
return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
|
|
5263
5296
|
}
|
|
5264
|
-
var PromptCache = class {
|
|
5297
|
+
var PromptCache = class _PromptCache {
|
|
5265
5298
|
memoryCache;
|
|
5266
5299
|
diskCache;
|
|
5300
|
+
namespace;
|
|
5301
|
+
expectedResolvedOrgIdentity;
|
|
5267
5302
|
constructor(options) {
|
|
5268
5303
|
this.memoryCache = options.memoryCache;
|
|
5269
5304
|
this.diskCache = options.diskCache;
|
|
5305
|
+
this.namespace = options.namespace;
|
|
5306
|
+
this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
|
|
5307
|
+
}
|
|
5308
|
+
/**
|
|
5309
|
+
* Returns a cache view that shares the same storage layers but isolates all
|
|
5310
|
+
* entries under the provided namespace.
|
|
5311
|
+
*/
|
|
5312
|
+
withNamespace(namespace, expectedResolvedOrgIdentity) {
|
|
5313
|
+
return new _PromptCache({
|
|
5314
|
+
memoryCache: this.memoryCache,
|
|
5315
|
+
diskCache: this.diskCache,
|
|
5316
|
+
namespace,
|
|
5317
|
+
expectedResolvedOrgIdentity
|
|
5318
|
+
});
|
|
5270
5319
|
}
|
|
5271
5320
|
/**
|
|
5272
5321
|
* Retrieves a prompt from the cache.
|
|
5273
5322
|
* First checks the in-memory LRU cache, then falls back to checking the disk cache if available.
|
|
5274
5323
|
*/
|
|
5275
5324
|
async get(key) {
|
|
5276
|
-
const cacheKey = createCacheKey(key);
|
|
5325
|
+
const cacheKey = createCacheKey(key, this.namespace);
|
|
5277
5326
|
if (this.memoryCache) {
|
|
5278
|
-
const
|
|
5279
|
-
if (
|
|
5280
|
-
return
|
|
5327
|
+
const memoryEntry = this.memoryCache.get(cacheKey);
|
|
5328
|
+
if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
|
|
5329
|
+
return memoryEntry.value;
|
|
5281
5330
|
}
|
|
5282
5331
|
}
|
|
5283
5332
|
if (this.diskCache) {
|
|
5284
|
-
const
|
|
5285
|
-
if (!
|
|
5333
|
+
const diskEntry = await this.diskCache.get(cacheKey);
|
|
5334
|
+
if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
|
|
5286
5335
|
return void 0;
|
|
5287
5336
|
}
|
|
5288
|
-
|
|
5337
|
+
const serializedPrompt = diskEntry.value;
|
|
5338
|
+
const diskPrompt = new Prompt2(
|
|
5339
|
+
serializedPrompt.metadata,
|
|
5340
|
+
serializedPrompt.defaults,
|
|
5341
|
+
serializedPrompt.noTrace
|
|
5342
|
+
);
|
|
5343
|
+
this.memoryCache?.set(cacheKey, {
|
|
5344
|
+
value: diskPrompt,
|
|
5345
|
+
resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
|
|
5346
|
+
});
|
|
5289
5347
|
return diskPrompt;
|
|
5290
5348
|
}
|
|
5291
5349
|
return void 0;
|
|
@@ -5299,58 +5357,91 @@ var PromptCache = class {
|
|
|
5299
5357
|
* @throws If there is an error writing to the disk cache.
|
|
5300
5358
|
*/
|
|
5301
5359
|
async set(key, value) {
|
|
5302
|
-
const cacheKey = createCacheKey(key);
|
|
5303
|
-
|
|
5360
|
+
const cacheKey = createCacheKey(key, this.namespace);
|
|
5361
|
+
const memoryEntry = {
|
|
5362
|
+
value,
|
|
5363
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5364
|
+
};
|
|
5365
|
+
this.memoryCache?.set(cacheKey, memoryEntry);
|
|
5304
5366
|
if (this.diskCache) {
|
|
5305
|
-
await this.diskCache.set(cacheKey,
|
|
5367
|
+
await this.diskCache.set(cacheKey, {
|
|
5368
|
+
value: value._internalSerializeForCache(),
|
|
5369
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5370
|
+
});
|
|
5306
5371
|
}
|
|
5307
5372
|
}
|
|
5308
5373
|
};
|
|
5309
5374
|
|
|
5310
5375
|
// src/prompt-cache/parameters-cache.ts
|
|
5311
|
-
function createCacheKey2(key) {
|
|
5376
|
+
function createCacheKey2(key, namespace) {
|
|
5377
|
+
let cacheKey;
|
|
5312
5378
|
if (key.id) {
|
|
5313
|
-
|
|
5314
|
-
}
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5379
|
+
cacheKey = `parameters:id:${key.id}`;
|
|
5380
|
+
} else {
|
|
5381
|
+
const prefix = key.projectId ?? key.projectName;
|
|
5382
|
+
if (!prefix) {
|
|
5383
|
+
throw new Error("Either projectId or projectName must be provided");
|
|
5384
|
+
}
|
|
5385
|
+
if (!key.slug) {
|
|
5386
|
+
throw new Error("Slug must be provided when not using ID");
|
|
5387
|
+
}
|
|
5388
|
+
cacheKey = `parameters:${prefix}:${key.slug}:${key.version ?? "latest"}`;
|
|
5321
5389
|
}
|
|
5322
|
-
return
|
|
5390
|
+
return namespace === void 0 ? cacheKey : `${namespace.length}:${namespace}:${cacheKey}`;
|
|
5323
5391
|
}
|
|
5324
|
-
var ParametersCache = class {
|
|
5392
|
+
var ParametersCache = class _ParametersCache {
|
|
5325
5393
|
memoryCache;
|
|
5326
5394
|
diskCache;
|
|
5395
|
+
namespace;
|
|
5396
|
+
expectedResolvedOrgIdentity;
|
|
5327
5397
|
constructor(options) {
|
|
5328
5398
|
this.memoryCache = options.memoryCache;
|
|
5329
5399
|
this.diskCache = options.diskCache;
|
|
5400
|
+
this.namespace = options.namespace;
|
|
5401
|
+
this.expectedResolvedOrgIdentity = options.expectedResolvedOrgIdentity;
|
|
5402
|
+
}
|
|
5403
|
+
withNamespace(namespace, expectedResolvedOrgIdentity) {
|
|
5404
|
+
return new _ParametersCache({
|
|
5405
|
+
memoryCache: this.memoryCache,
|
|
5406
|
+
diskCache: this.diskCache,
|
|
5407
|
+
namespace,
|
|
5408
|
+
expectedResolvedOrgIdentity
|
|
5409
|
+
});
|
|
5330
5410
|
}
|
|
5331
5411
|
async get(key) {
|
|
5332
|
-
const cacheKey = createCacheKey2(key);
|
|
5412
|
+
const cacheKey = createCacheKey2(key, this.namespace);
|
|
5333
5413
|
if (this.memoryCache) {
|
|
5334
|
-
const
|
|
5335
|
-
if (
|
|
5336
|
-
return
|
|
5414
|
+
const memoryEntry = this.memoryCache.get(cacheKey);
|
|
5415
|
+
if (memoryEntry !== void 0 && (this.expectedResolvedOrgIdentity === void 0 || memoryEntry.resolvedOrgIdentity === this.expectedResolvedOrgIdentity)) {
|
|
5416
|
+
return memoryEntry.value;
|
|
5337
5417
|
}
|
|
5338
5418
|
}
|
|
5339
5419
|
if (this.diskCache) {
|
|
5340
|
-
const
|
|
5341
|
-
if (!
|
|
5420
|
+
const diskEntry = await this.diskCache.get(cacheKey);
|
|
5421
|
+
if (!diskEntry || this.expectedResolvedOrgIdentity !== void 0 && diskEntry.resolvedOrgIdentity !== this.expectedResolvedOrgIdentity) {
|
|
5342
5422
|
return void 0;
|
|
5343
5423
|
}
|
|
5344
|
-
|
|
5345
|
-
|
|
5424
|
+
const diskParameters = new RemoteEvalParameters(diskEntry.value.metadata);
|
|
5425
|
+
this.memoryCache?.set(cacheKey, {
|
|
5426
|
+
value: diskParameters,
|
|
5427
|
+
resolvedOrgIdentity: diskEntry.resolvedOrgIdentity
|
|
5428
|
+
});
|
|
5429
|
+
return diskParameters;
|
|
5346
5430
|
}
|
|
5347
5431
|
return void 0;
|
|
5348
5432
|
}
|
|
5349
5433
|
async set(key, value) {
|
|
5350
|
-
const cacheKey = createCacheKey2(key);
|
|
5351
|
-
|
|
5434
|
+
const cacheKey = createCacheKey2(key, this.namespace);
|
|
5435
|
+
const memoryEntry = {
|
|
5436
|
+
value,
|
|
5437
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5438
|
+
};
|
|
5439
|
+
this.memoryCache?.set(cacheKey, memoryEntry);
|
|
5352
5440
|
if (this.diskCache) {
|
|
5353
|
-
await this.diskCache.set(cacheKey,
|
|
5441
|
+
await this.diskCache.set(cacheKey, {
|
|
5442
|
+
value: value._internalSerializeForCache(),
|
|
5443
|
+
resolvedOrgIdentity: this.expectedResolvedOrgIdentity
|
|
5444
|
+
});
|
|
5354
5445
|
}
|
|
5355
5446
|
}
|
|
5356
5447
|
};
|
|
@@ -5654,6 +5745,7 @@ var INSTRUMENTATION_NAMES = {
|
|
|
5654
5745
|
CLOUDFLARE_THINK: "cloudflare-think",
|
|
5655
5746
|
COHERE: "cohere",
|
|
5656
5747
|
CURSOR_SDK: "cursor-sdk",
|
|
5748
|
+
DEEPSEEK_HARNESS: "deepseek-harness",
|
|
5657
5749
|
EVE: "eve",
|
|
5658
5750
|
FLUE: "flue",
|
|
5659
5751
|
GENKIT: "genkit",
|
|
@@ -5679,7 +5771,7 @@ var INSTRUMENTATION_NAMES = {
|
|
|
5679
5771
|
var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
|
|
5680
5772
|
"braintrust.spanInstrumentationName"
|
|
5681
5773
|
);
|
|
5682
|
-
var SDK_VERSION = true ? "3.
|
|
5774
|
+
var SDK_VERSION = true ? "3.30.0" : "0.0.0";
|
|
5683
5775
|
function withSpanInstrumentationName(args, instrumentationName) {
|
|
5684
5776
|
return {
|
|
5685
5777
|
...args,
|
|
@@ -5798,6 +5890,16 @@ var datasetSnapshotRegisterResponseSchema = z8.object({
|
|
|
5798
5890
|
dataset_snapshot: DatasetSnapshot,
|
|
5799
5891
|
found_existing: z8.boolean().optional()
|
|
5800
5892
|
});
|
|
5893
|
+
var datasetObjectInfoSchema = z8.object({
|
|
5894
|
+
object_id: z8.string(),
|
|
5895
|
+
object_name: z8.string(),
|
|
5896
|
+
parent_cols: z8.object({
|
|
5897
|
+
project: z8.object({
|
|
5898
|
+
id: z8.string(),
|
|
5899
|
+
name: z8.string()
|
|
5900
|
+
})
|
|
5901
|
+
})
|
|
5902
|
+
});
|
|
5801
5903
|
var datasetRestorePreviewResultSchema = z8.object({
|
|
5802
5904
|
rows_to_restore: z8.number(),
|
|
5803
5905
|
rows_to_delete: z8.number()
|
|
@@ -6011,12 +6113,53 @@ var loginSchema = z8.strictObject({
|
|
|
6011
6113
|
});
|
|
6012
6114
|
var stateNonce = 0;
|
|
6013
6115
|
var V1_PROXY_SUFFIX = "/v1/proxy";
|
|
6116
|
+
var LOADER_LOGIN_CACHE_MAX = 16;
|
|
6014
6117
|
function normalizeProxyConnUrl(proxyUrl) {
|
|
6015
6118
|
return proxyUrl.endsWith(V1_PROXY_SUFFIX) ? proxyUrl.slice(0, proxyUrl.length - V1_PROXY_SUFFIX.length) : proxyUrl;
|
|
6016
6119
|
}
|
|
6017
6120
|
var BraintrustState = class _BraintrustState {
|
|
6121
|
+
id;
|
|
6122
|
+
currentExperiment;
|
|
6123
|
+
// Note: the value of IsAsyncFlush doesn't really matter here, since we
|
|
6124
|
+
// (safely) dynamically cast it whenever retrieving the logger.
|
|
6125
|
+
currentLogger;
|
|
6126
|
+
currentParent;
|
|
6127
|
+
currentSpan;
|
|
6128
|
+
// Any time we re-log in, we directly update the apiConn inside the logger.
|
|
6129
|
+
// This is preferable to replacing the whole logger, which would create the
|
|
6130
|
+
// possibility of multiple loggers floating around, which may not log in a
|
|
6131
|
+
// deterministic order.
|
|
6132
|
+
_bgLogger;
|
|
6133
|
+
_overrideBgLogger = null;
|
|
6134
|
+
appUrl = null;
|
|
6135
|
+
appPublicUrl = null;
|
|
6136
|
+
loginToken = null;
|
|
6137
|
+
orgId = null;
|
|
6138
|
+
orgName = null;
|
|
6139
|
+
apiUrl = null;
|
|
6140
|
+
proxyUrl = null;
|
|
6141
|
+
loggedIn = false;
|
|
6142
|
+
gitMetadataSettings;
|
|
6143
|
+
debugLogLevel;
|
|
6144
|
+
debugLogLevelConfigured = false;
|
|
6145
|
+
fetch = globalThis.fetch;
|
|
6146
|
+
_appConn = null;
|
|
6147
|
+
_apiConn = null;
|
|
6148
|
+
_proxyConn = null;
|
|
6149
|
+
promptCache;
|
|
6150
|
+
parametersCache;
|
|
6151
|
+
spanCache;
|
|
6152
|
+
_idGenerator = null;
|
|
6153
|
+
_contextManager = null;
|
|
6154
|
+
_otelFlushCallback = null;
|
|
6155
|
+
spanOriginEnvironment;
|
|
6156
|
+
traceContextSigningSecret;
|
|
6157
|
+
loaderLoginCache = /* @__PURE__ */ new WeakMap();
|
|
6158
|
+
loginParams;
|
|
6159
|
+
activeLoginOrgNameSelector;
|
|
6018
6160
|
constructor(loginParams) {
|
|
6019
|
-
this.loginParams = loginParams;
|
|
6161
|
+
this.loginParams = { ...loginParams };
|
|
6162
|
+
this.activeLoginOrgNameSelector = loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
|
|
6020
6163
|
this.id = `${(/* @__PURE__ */ new Date()).toLocaleString()}-${stateNonce++}`;
|
|
6021
6164
|
this.currentExperiment = void 0;
|
|
6022
6165
|
this.currentLogger = void 0;
|
|
@@ -6053,12 +6196,14 @@ var BraintrustState = class _BraintrustState {
|
|
|
6053
6196
|
const {
|
|
6054
6197
|
memoryCache: parametersMemoryCache,
|
|
6055
6198
|
diskCache: parametersDiskCache
|
|
6056
|
-
} = createCacheLayers(
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6199
|
+
} = createCacheLayers(
|
|
6200
|
+
{
|
|
6201
|
+
memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
|
|
6202
|
+
diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
|
|
6203
|
+
diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
|
|
6204
|
+
getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
|
|
6205
|
+
}
|
|
6206
|
+
);
|
|
6062
6207
|
this.parametersCache = new ParametersCache({
|
|
6063
6208
|
memoryCache: parametersMemoryCache,
|
|
6064
6209
|
diskCache: parametersDiskCache
|
|
@@ -6067,43 +6212,6 @@ var BraintrustState = class _BraintrustState {
|
|
|
6067
6212
|
this.spanOriginEnvironment = detectSpanOriginEnvironment();
|
|
6068
6213
|
this._internalSetTraceContextSigningSecret(loginParams.apiKey);
|
|
6069
6214
|
}
|
|
6070
|
-
loginParams;
|
|
6071
|
-
id;
|
|
6072
|
-
currentExperiment;
|
|
6073
|
-
// Note: the value of IsAsyncFlush doesn't really matter here, since we
|
|
6074
|
-
// (safely) dynamically cast it whenever retrieving the logger.
|
|
6075
|
-
currentLogger;
|
|
6076
|
-
currentParent;
|
|
6077
|
-
currentSpan;
|
|
6078
|
-
// Any time we re-log in, we directly update the apiConn inside the logger.
|
|
6079
|
-
// This is preferable to replacing the whole logger, which would create the
|
|
6080
|
-
// possibility of multiple loggers floating around, which may not log in a
|
|
6081
|
-
// deterministic order.
|
|
6082
|
-
_bgLogger;
|
|
6083
|
-
_overrideBgLogger = null;
|
|
6084
|
-
appUrl = null;
|
|
6085
|
-
appPublicUrl = null;
|
|
6086
|
-
loginToken = null;
|
|
6087
|
-
orgId = null;
|
|
6088
|
-
orgName = null;
|
|
6089
|
-
apiUrl = null;
|
|
6090
|
-
proxyUrl = null;
|
|
6091
|
-
loggedIn = false;
|
|
6092
|
-
gitMetadataSettings;
|
|
6093
|
-
debugLogLevel;
|
|
6094
|
-
debugLogLevelConfigured = false;
|
|
6095
|
-
fetch = globalThis.fetch;
|
|
6096
|
-
_appConn = null;
|
|
6097
|
-
_apiConn = null;
|
|
6098
|
-
_proxyConn = null;
|
|
6099
|
-
promptCache;
|
|
6100
|
-
parametersCache;
|
|
6101
|
-
spanCache;
|
|
6102
|
-
_idGenerator = null;
|
|
6103
|
-
_contextManager = null;
|
|
6104
|
-
_otelFlushCallback = null;
|
|
6105
|
-
spanOriginEnvironment;
|
|
6106
|
-
traceContextSigningSecret;
|
|
6107
6215
|
/** @internal */
|
|
6108
6216
|
_internalSetTraceContextSigningSecret(secret) {
|
|
6109
6217
|
const normalizedSecret = secret?.trim();
|
|
@@ -6128,6 +6236,101 @@ var BraintrustState = class _BraintrustState {
|
|
|
6128
6236
|
this._appConn = null;
|
|
6129
6237
|
this._apiConn = null;
|
|
6130
6238
|
this._proxyConn = null;
|
|
6239
|
+
this.loaderLoginCache = /* @__PURE__ */ new WeakMap();
|
|
6240
|
+
}
|
|
6241
|
+
/** @internal */
|
|
6242
|
+
async _internalResolveLoaderLoginOptions({
|
|
6243
|
+
apiKey,
|
|
6244
|
+
appUrl,
|
|
6245
|
+
orgName,
|
|
6246
|
+
fetch: fetch2,
|
|
6247
|
+
forceLogin
|
|
6248
|
+
}) {
|
|
6249
|
+
const resolvedAppUrl = appUrl ?? (this.loggedIn ? this.appUrl ?? void 0 : void 0) ?? this.loginParams.appUrl ?? isomorph_default.getEnv("BRAINTRUST_APP_URL") ?? "https://www.braintrust.dev";
|
|
6250
|
+
const resolvedApiKey = apiKey ?? (this.loggedIn ? this.loginToken ?? void 0 : void 0) ?? this.loginParams.apiKey ?? await isomorph_default.getBraintrustApiKey();
|
|
6251
|
+
if (!resolvedApiKey) {
|
|
6252
|
+
throw new Error(
|
|
6253
|
+
"Please specify an api key (e.g. by setting BRAINTRUST_API_KEY)."
|
|
6254
|
+
);
|
|
6255
|
+
}
|
|
6256
|
+
const normalizedApiKey = HTTPConnection.sanitize_token(resolvedApiKey);
|
|
6257
|
+
const usesActiveCredential = this.loggedIn && normalizedApiKey === this.loginToken;
|
|
6258
|
+
const requestedOrgName = orgName ?? (usesActiveCredential ? this.activeLoginOrgNameSelector : void 0) ?? this.loginParams.orgName ?? isomorph_default.getEnv("BRAINTRUST_ORG_NAME");
|
|
6259
|
+
const resolvedOrgName = orgName ?? (usesActiveCredential ? this.orgName ?? void 0 : void 0) ?? requestedOrgName;
|
|
6260
|
+
const resolvedFetch = fetch2 ?? (this.loggedIn ? this.fetch : void 0) ?? this.loginParams.fetch ?? globalThis.fetch;
|
|
6261
|
+
const credentialCacheNamespace = JSON.stringify([
|
|
6262
|
+
"loader-credential",
|
|
6263
|
+
resolvedAppUrl,
|
|
6264
|
+
requestedOrgName,
|
|
6265
|
+
normalizedApiKey
|
|
6266
|
+
]);
|
|
6267
|
+
return {
|
|
6268
|
+
apiKey: normalizedApiKey,
|
|
6269
|
+
appUrl: resolvedAppUrl,
|
|
6270
|
+
orgName: resolvedOrgName,
|
|
6271
|
+
fetch: resolvedFetch,
|
|
6272
|
+
forceLogin,
|
|
6273
|
+
credentialCacheNamespace,
|
|
6274
|
+
existingState: !forceLogin && usesActiveCredential && resolvedAppUrl === this.appUrl && resolvedOrgName === this.orgName && resolvedFetch === this.fetch ? this : void 0
|
|
6275
|
+
};
|
|
6276
|
+
}
|
|
6277
|
+
/** @internal */
|
|
6278
|
+
_internalGetLoaderCacheViews(loginOptions, requestState) {
|
|
6279
|
+
const expectedResolvedOrgIdentity = requestState?.orgId && requestState.appUrl ? JSON.stringify([
|
|
6280
|
+
"loader-org",
|
|
6281
|
+
requestState.appUrl,
|
|
6282
|
+
requestState.orgId
|
|
6283
|
+
]) : void 0;
|
|
6284
|
+
return {
|
|
6285
|
+
promptCache: this.promptCache.withNamespace(
|
|
6286
|
+
loginOptions.credentialCacheNamespace,
|
|
6287
|
+
expectedResolvedOrgIdentity
|
|
6288
|
+
),
|
|
6289
|
+
parametersCache: this.parametersCache.withNamespace(
|
|
6290
|
+
loginOptions.credentialCacheNamespace,
|
|
6291
|
+
expectedResolvedOrgIdentity
|
|
6292
|
+
)
|
|
6293
|
+
};
|
|
6294
|
+
}
|
|
6295
|
+
/** @internal */
|
|
6296
|
+
async _internalGetLoaderState({
|
|
6297
|
+
apiKey,
|
|
6298
|
+
appUrl,
|
|
6299
|
+
orgName,
|
|
6300
|
+
fetch: fetch2,
|
|
6301
|
+
forceLogin,
|
|
6302
|
+
existingState
|
|
6303
|
+
}) {
|
|
6304
|
+
if (existingState) {
|
|
6305
|
+
return existingState;
|
|
6306
|
+
}
|
|
6307
|
+
let cache = this.loaderLoginCache.get(fetch2);
|
|
6308
|
+
if (!cache) {
|
|
6309
|
+
cache = new LRUCache({ max: LOADER_LOGIN_CACHE_MAX });
|
|
6310
|
+
this.loaderLoginCache.set(fetch2, cache);
|
|
6311
|
+
}
|
|
6312
|
+
const cacheKey = JSON.stringify([appUrl, orgName, apiKey]);
|
|
6313
|
+
if (!forceLogin) {
|
|
6314
|
+
const cachedState = cache.get(cacheKey);
|
|
6315
|
+
if (cachedState) {
|
|
6316
|
+
return cachedState;
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6319
|
+
const statePromise = loginToLoaderRequestState({
|
|
6320
|
+
orgName,
|
|
6321
|
+
apiKey,
|
|
6322
|
+
appUrl,
|
|
6323
|
+
fetch: fetch2
|
|
6324
|
+
});
|
|
6325
|
+
cache.set(cacheKey, statePromise);
|
|
6326
|
+
try {
|
|
6327
|
+
return await statePromise;
|
|
6328
|
+
} catch (error) {
|
|
6329
|
+
if (cache.get(cacheKey) === statePromise) {
|
|
6330
|
+
cache.delete(cacheKey);
|
|
6331
|
+
}
|
|
6332
|
+
throw error;
|
|
6333
|
+
}
|
|
6131
6334
|
}
|
|
6132
6335
|
resetIdGenState() {
|
|
6133
6336
|
this._idGenerator = null;
|
|
@@ -6176,6 +6379,8 @@ var BraintrustState = class _BraintrustState {
|
|
|
6176
6379
|
this.debugLogLevel = other.debugLogLevel;
|
|
6177
6380
|
this.debugLogLevelConfigured = other.debugLogLevelConfigured;
|
|
6178
6381
|
this.traceContextSigningSecret = other.traceContextSigningSecret;
|
|
6382
|
+
this.fetch = other.fetch;
|
|
6383
|
+
this.activeLoginOrgNameSelector = other.activeLoginOrgNameSelector;
|
|
6179
6384
|
setGlobalDebugLogLevel(
|
|
6180
6385
|
this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
|
|
6181
6386
|
);
|
|
@@ -6370,36 +6575,76 @@ var FailedHTTPResponse = class extends Error {
|
|
|
6370
6575
|
status;
|
|
6371
6576
|
text;
|
|
6372
6577
|
data;
|
|
6373
|
-
|
|
6578
|
+
cause;
|
|
6579
|
+
constructor(status, text, data, cause) {
|
|
6374
6580
|
super(`${status}: ${text} (${data})`);
|
|
6375
6581
|
this.status = status;
|
|
6376
6582
|
this.text = text;
|
|
6377
6583
|
this.data = data;
|
|
6584
|
+
this.cause = cause;
|
|
6378
6585
|
}
|
|
6379
6586
|
};
|
|
6587
|
+
var HTTPTransportError = class extends Error {
|
|
6588
|
+
cause;
|
|
6589
|
+
constructor(cause) {
|
|
6590
|
+
super(cause instanceof Error ? cause.message : String(cause));
|
|
6591
|
+
this.name = "HTTPTransportError";
|
|
6592
|
+
this.cause = cause;
|
|
6593
|
+
}
|
|
6594
|
+
};
|
|
6595
|
+
var httpTransportErrorCauses = /* @__PURE__ */ new WeakSet();
|
|
6596
|
+
function recordHTTPTransportError(error) {
|
|
6597
|
+
if (typeof error === "object" && error !== null || typeof error === "function") {
|
|
6598
|
+
httpTransportErrorCauses.add(error);
|
|
6599
|
+
}
|
|
6600
|
+
}
|
|
6601
|
+
function rethrowHTTPTransportError(error, classifyTransportErrors) {
|
|
6602
|
+
if (classifyTransportErrors) {
|
|
6603
|
+
throw new HTTPTransportError(error);
|
|
6604
|
+
}
|
|
6605
|
+
recordHTTPTransportError(error);
|
|
6606
|
+
throw error;
|
|
6607
|
+
}
|
|
6608
|
+
async function readJSONResponse(response, classifyTransportErrors = false) {
|
|
6609
|
+
let data;
|
|
6610
|
+
try {
|
|
6611
|
+
data = await response.text();
|
|
6612
|
+
} catch (error) {
|
|
6613
|
+
rethrowHTTPTransportError(error, classifyTransportErrors);
|
|
6614
|
+
}
|
|
6615
|
+
return JSON.parse(data);
|
|
6616
|
+
}
|
|
6380
6617
|
async function checkResponse(resp) {
|
|
6381
6618
|
if (resp.ok) {
|
|
6382
6619
|
return resp;
|
|
6383
|
-
}
|
|
6620
|
+
}
|
|
6621
|
+
let data;
|
|
6622
|
+
try {
|
|
6623
|
+
data = await resp.text();
|
|
6624
|
+
} catch (error) {
|
|
6384
6625
|
throw new FailedHTTPResponse(
|
|
6385
6626
|
resp.status,
|
|
6386
6627
|
resp.statusText,
|
|
6387
|
-
|
|
6628
|
+
"Unable to read response body",
|
|
6629
|
+
error
|
|
6388
6630
|
);
|
|
6389
6631
|
}
|
|
6632
|
+
throw new FailedHTTPResponse(resp.status, resp.statusText, data);
|
|
6390
6633
|
}
|
|
6391
6634
|
var HTTPConnection = class _HTTPConnection {
|
|
6392
|
-
base_url
|
|
6393
|
-
|
|
6394
|
-
headers;
|
|
6395
|
-
fetch;
|
|
6396
|
-
constructor(base_url, fetch2) {
|
|
6635
|
+
constructor(base_url, fetch2, classifyTransportErrors = false) {
|
|
6636
|
+
this.classifyTransportErrors = classifyTransportErrors;
|
|
6397
6637
|
this.base_url = base_url;
|
|
6398
6638
|
this.token = null;
|
|
6399
6639
|
this.headers = {};
|
|
6400
6640
|
this._reset();
|
|
6401
6641
|
this.fetch = fetch2;
|
|
6402
6642
|
}
|
|
6643
|
+
classifyTransportErrors;
|
|
6644
|
+
base_url;
|
|
6645
|
+
token;
|
|
6646
|
+
headers;
|
|
6647
|
+
fetch;
|
|
6403
6648
|
setFetch(fetch2) {
|
|
6404
6649
|
this.fetch = fetch2;
|
|
6405
6650
|
}
|
|
@@ -6439,9 +6684,9 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6439
6684
|
).toString();
|
|
6440
6685
|
const this_fetch = this.fetch;
|
|
6441
6686
|
const this_headers = this.headers;
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
await this_fetch(url.toString(), {
|
|
6687
|
+
let response;
|
|
6688
|
+
try {
|
|
6689
|
+
response = await this_fetch(url.toString(), {
|
|
6445
6690
|
headers: {
|
|
6446
6691
|
Accept: "application/json",
|
|
6447
6692
|
...this_headers,
|
|
@@ -6449,8 +6694,14 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6449
6694
|
},
|
|
6450
6695
|
keepalive: true,
|
|
6451
6696
|
...rest
|
|
6452
|
-
})
|
|
6453
|
-
)
|
|
6697
|
+
});
|
|
6698
|
+
} catch (error) {
|
|
6699
|
+
if (config?.signal?.aborted) {
|
|
6700
|
+
throw getAbortReason(config.signal);
|
|
6701
|
+
}
|
|
6702
|
+
rethrowHTTPTransportError(error, this.classifyTransportErrors);
|
|
6703
|
+
}
|
|
6704
|
+
return await checkResponse(response);
|
|
6454
6705
|
}
|
|
6455
6706
|
async post(path, params, config, retries = 0) {
|
|
6456
6707
|
const { headers, ...rest } = config || {};
|
|
@@ -6460,8 +6711,9 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6460
6711
|
const tries = retries + 1;
|
|
6461
6712
|
for (let i = 0; i < tries; i++) {
|
|
6462
6713
|
try {
|
|
6463
|
-
|
|
6464
|
-
|
|
6714
|
+
let response;
|
|
6715
|
+
try {
|
|
6716
|
+
response = await this_fetch(_urljoin(this_base_url, path), {
|
|
6465
6717
|
method: "POST",
|
|
6466
6718
|
headers: {
|
|
6467
6719
|
Accept: "application/json",
|
|
@@ -6472,8 +6724,14 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6472
6724
|
body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
|
|
6473
6725
|
keepalive: true,
|
|
6474
6726
|
...rest
|
|
6475
|
-
})
|
|
6476
|
-
)
|
|
6727
|
+
});
|
|
6728
|
+
} catch (error) {
|
|
6729
|
+
if (config?.signal?.aborted) {
|
|
6730
|
+
throw getAbortReason(config.signal);
|
|
6731
|
+
}
|
|
6732
|
+
rethrowHTTPTransportError(error, this.classifyTransportErrors);
|
|
6733
|
+
}
|
|
6734
|
+
return await checkResponse(response);
|
|
6477
6735
|
} catch (error) {
|
|
6478
6736
|
if (config?.signal?.aborted) {
|
|
6479
6737
|
throw getAbortReason(config.signal);
|
|
@@ -6498,7 +6756,7 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6498
6756
|
for (let i = 0; i < tries; i++) {
|
|
6499
6757
|
try {
|
|
6500
6758
|
const resp = await this.get(`${object_type}`, args);
|
|
6501
|
-
return await resp.
|
|
6759
|
+
return await readJSONResponse(resp, this.classifyTransportErrors);
|
|
6502
6760
|
} catch (e) {
|
|
6503
6761
|
if (i < tries - 1) {
|
|
6504
6762
|
debugLogger.debug(
|
|
@@ -6521,7 +6779,7 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
6521
6779
|
const resp = await this.post(`${object_type}`, args, {
|
|
6522
6780
|
headers: { "Content-Type": "application/json" }
|
|
6523
6781
|
});
|
|
6524
|
-
return await resp.
|
|
6782
|
+
return await readJSONResponse(resp, this.classifyTransportErrors);
|
|
6525
6783
|
}
|
|
6526
6784
|
// Custom inspect for Node.js console.log
|
|
6527
6785
|
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
@@ -8076,6 +8334,52 @@ function initLogger(options = {}) {
|
|
|
8076
8334
|
}
|
|
8077
8335
|
return ret;
|
|
8078
8336
|
}
|
|
8337
|
+
async function loginToLoaderRequestState({
|
|
8338
|
+
appUrl,
|
|
8339
|
+
apiKey,
|
|
8340
|
+
orgName,
|
|
8341
|
+
fetch: fetch2
|
|
8342
|
+
}) {
|
|
8343
|
+
let orgId;
|
|
8344
|
+
let apiUrl;
|
|
8345
|
+
if (apiKey === TEST_API_KEY) {
|
|
8346
|
+
orgId = "test-org-id";
|
|
8347
|
+
apiUrl = "https://braintrust.dev/fake-api-url";
|
|
8348
|
+
} else {
|
|
8349
|
+
let loginResponse;
|
|
8350
|
+
try {
|
|
8351
|
+
loginResponse = await fetch2(_urljoin(appUrl, `/api/apikey/login`), {
|
|
8352
|
+
method: "POST",
|
|
8353
|
+
headers: {
|
|
8354
|
+
"Content-Type": "application/json",
|
|
8355
|
+
Authorization: `Bearer ${apiKey}`
|
|
8356
|
+
}
|
|
8357
|
+
});
|
|
8358
|
+
} catch (error) {
|
|
8359
|
+
throw new HTTPTransportError(error);
|
|
8360
|
+
}
|
|
8361
|
+
const info = await readJSONResponse(
|
|
8362
|
+
await checkResponse(loginResponse),
|
|
8363
|
+
true
|
|
8364
|
+
);
|
|
8365
|
+
const org = selectLoginOrg(info.org_info, orgName);
|
|
8366
|
+
orgId = org.id;
|
|
8367
|
+
apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
|
|
8368
|
+
if (!apiUrl) {
|
|
8369
|
+
throw new Error(
|
|
8370
|
+
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."
|
|
8371
|
+
);
|
|
8372
|
+
}
|
|
8373
|
+
}
|
|
8374
|
+
const apiConnection = new HTTPConnection(apiUrl, fetch2, true);
|
|
8375
|
+
apiConnection.set_token(apiKey);
|
|
8376
|
+
apiConnection.make_long_lived();
|
|
8377
|
+
return {
|
|
8378
|
+
appUrl,
|
|
8379
|
+
orgId,
|
|
8380
|
+
apiConn: () => apiConnection
|
|
8381
|
+
};
|
|
8382
|
+
}
|
|
8079
8383
|
async function loginToState(options = {}) {
|
|
8080
8384
|
const {
|
|
8081
8385
|
appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
|
|
@@ -8107,16 +8411,18 @@ async function loginToState(options = {}) {
|
|
|
8107
8411
|
_saveOrgInfo(state, testOrgInfo, testOrgInfo[0].name);
|
|
8108
8412
|
return state;
|
|
8109
8413
|
} else {
|
|
8110
|
-
const
|
|
8111
|
-
|
|
8414
|
+
const loginResponse = await fetch2(
|
|
8415
|
+
_urljoin(state.appUrl, `/api/apikey/login`),
|
|
8416
|
+
{
|
|
8112
8417
|
method: "POST",
|
|
8113
8418
|
headers: {
|
|
8114
8419
|
"Content-Type": "application/json",
|
|
8115
8420
|
Authorization: `Bearer ${apiKey}`
|
|
8116
8421
|
}
|
|
8117
|
-
}
|
|
8422
|
+
}
|
|
8118
8423
|
);
|
|
8119
|
-
const
|
|
8424
|
+
const resp = await checkResponse(loginResponse);
|
|
8425
|
+
const info = await readJSONResponse(resp);
|
|
8120
8426
|
_saveOrgInfo(state, info.org_info, orgName);
|
|
8121
8427
|
if (!state.apiUrl) {
|
|
8122
8428
|
if (orgName) {
|
|
@@ -8181,6 +8487,9 @@ function getSpanParentObjectAndPropagatedState(options) {
|
|
|
8181
8487
|
}
|
|
8182
8488
|
return { parentObject: NOOP_SPAN, propagatedState: void 0 };
|
|
8183
8489
|
}
|
|
8490
|
+
function getSpanParentObject(options) {
|
|
8491
|
+
return getSpanParentObjectAndPropagatedState(options).parentObject;
|
|
8492
|
+
}
|
|
8184
8493
|
function currentBraintrustParent(state) {
|
|
8185
8494
|
const resolvedState = state ?? _globalState;
|
|
8186
8495
|
const experiment = currentExperiment({ state: resolvedState });
|
|
@@ -8427,6 +8736,15 @@ function _internalStartSpanWithInitialMerge(args) {
|
|
|
8427
8736
|
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
8428
8737
|
}).span;
|
|
8429
8738
|
}
|
|
8739
|
+
function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
|
|
8740
|
+
return startSpanAndIsLogger(
|
|
8741
|
+
{
|
|
8742
|
+
...args,
|
|
8743
|
+
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
8744
|
+
},
|
|
8745
|
+
{ useParentSpanIdsForObjectParent: true }
|
|
8746
|
+
).span;
|
|
8747
|
+
}
|
|
8430
8748
|
function _internalStartSpanWithContext(args, context) {
|
|
8431
8749
|
return startSpanAndIsLogger({
|
|
8432
8750
|
...args,
|
|
@@ -8437,7 +8755,7 @@ async function flush(options) {
|
|
|
8437
8755
|
const state = options?.state ?? _globalState;
|
|
8438
8756
|
return await state.bgLogger().flush();
|
|
8439
8757
|
}
|
|
8440
|
-
function startSpanAndIsLogger(args) {
|
|
8758
|
+
function startSpanAndIsLogger(args, internalOptions) {
|
|
8441
8759
|
const state = args?.state ?? _globalState;
|
|
8442
8760
|
const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
|
|
8443
8761
|
asyncFlush: args?.asyncFlush,
|
|
@@ -8451,7 +8769,7 @@ function startSpanAndIsLogger(args) {
|
|
|
8451
8769
|
) ? {
|
|
8452
8770
|
spanId: parentObject.data.span_id,
|
|
8453
8771
|
rootSpanId: parentObject.data.root_span_id
|
|
8454
|
-
} : void 0;
|
|
8772
|
+
} : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
|
|
8455
8773
|
const { parent: _ignoredParent, ...spanArgs } = args ?? {};
|
|
8456
8774
|
const span = new SpanImpl({
|
|
8457
8775
|
state,
|
|
@@ -8484,27 +8802,28 @@ function withCurrent(span, callback, state = void 0) {
|
|
|
8484
8802
|
const currentState = state ?? _globalState;
|
|
8485
8803
|
return currentState.contextManager.runInContext(span, () => callback(span));
|
|
8486
8804
|
}
|
|
8487
|
-
function _saveOrgInfo(state,
|
|
8488
|
-
|
|
8805
|
+
function _saveOrgInfo(state, orgInfo, orgName) {
|
|
8806
|
+
const org = selectLoginOrg(orgInfo, orgName);
|
|
8807
|
+
state.orgId = org.id;
|
|
8808
|
+
state.orgName = org.name;
|
|
8809
|
+
state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
|
|
8810
|
+
state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
|
|
8811
|
+
state.gitMetadataSettings = org.git_metadata || void 0;
|
|
8812
|
+
}
|
|
8813
|
+
function selectLoginOrg(orgInfo, orgName) {
|
|
8814
|
+
if (orgInfo.length === 0) {
|
|
8489
8815
|
throw new LoginInvalidOrgError(
|
|
8490
8816
|
"This user is not part of any organizations."
|
|
8491
8817
|
);
|
|
8492
8818
|
}
|
|
8493
|
-
for (const org of
|
|
8494
|
-
if (
|
|
8495
|
-
|
|
8496
|
-
state.orgName = org.name;
|
|
8497
|
-
state.apiUrl = isomorph_default.getEnv("BRAINTRUST_API_URL") ?? org.api_url;
|
|
8498
|
-
state.proxyUrl = isomorph_default.getEnv("BRAINTRUST_PROXY_URL") ?? org.proxy_url;
|
|
8499
|
-
state.gitMetadataSettings = org.git_metadata || void 0;
|
|
8500
|
-
break;
|
|
8819
|
+
for (const org of orgInfo) {
|
|
8820
|
+
if (orgName === void 0 || org.name === orgName) {
|
|
8821
|
+
return org;
|
|
8501
8822
|
}
|
|
8502
8823
|
}
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
);
|
|
8507
|
-
}
|
|
8824
|
+
throw new LoginInvalidOrgError(
|
|
8825
|
+
`Organization ${orgName} not found. Must be one of ${orgInfo.map((org) => org.name).join(", ")}`
|
|
8826
|
+
);
|
|
8508
8827
|
}
|
|
8509
8828
|
function validateTags(tags) {
|
|
8510
8829
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8669,6 +8988,19 @@ function enrichAttachments(event, state) {
|
|
|
8669
8988
|
}
|
|
8670
8989
|
return event;
|
|
8671
8990
|
}
|
|
8991
|
+
async function resolveAttachmentsToBase64(event, state) {
|
|
8992
|
+
for (const [key, value] of Object.entries(event)) {
|
|
8993
|
+
if (value instanceof ReadonlyAttachment) {
|
|
8994
|
+
event[key] = await value.asBase64Url();
|
|
8995
|
+
continue;
|
|
8996
|
+
}
|
|
8997
|
+
if (!(value instanceof Object)) {
|
|
8998
|
+
continue;
|
|
8999
|
+
}
|
|
9000
|
+
await resolveAttachmentsToBase64(value, state);
|
|
9001
|
+
}
|
|
9002
|
+
return event;
|
|
9003
|
+
}
|
|
8672
9004
|
function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
|
|
8673
9005
|
if ("input" in event && !isEmpty2(event.input) && "inputs" in event && !isEmpty2(event.inputs) || !("input" in event) && !("inputs" in event)) {
|
|
8674
9006
|
throw new Error(
|
|
@@ -9958,6 +10290,473 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
9958
10290
|
return typeof data === "object" && data !== null && "__braintrust_dataset_marker" in data;
|
|
9959
10291
|
}
|
|
9960
10292
|
};
|
|
10293
|
+
function isAttachmentObject(value) {
|
|
10294
|
+
return BraintrustAttachmentReference.safeParse(value).success || InlineAttachmentReferenceSchema.safeParse(value).success || ExternalAttachmentReference.safeParse(value).success;
|
|
10295
|
+
}
|
|
10296
|
+
function isURL(url) {
|
|
10297
|
+
try {
|
|
10298
|
+
const parsedUrl = new URL(url.trim());
|
|
10299
|
+
return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
|
|
10300
|
+
} catch {
|
|
10301
|
+
return false;
|
|
10302
|
+
}
|
|
10303
|
+
}
|
|
10304
|
+
function expandAttachmentArrayPreTemplate(content, variables) {
|
|
10305
|
+
if (typeof content !== "string") return null;
|
|
10306
|
+
const match = content.match(/^\{\{\s*([\w.]+)\s*\}\}$/);
|
|
10307
|
+
if (!match) return null;
|
|
10308
|
+
const varPath = match[1];
|
|
10309
|
+
const value = varPath.includes(".") ? getObjValueByPath(variables, varPath.split(".")) : variables[varPath];
|
|
10310
|
+
if (!Array.isArray(value)) return null;
|
|
10311
|
+
const allValid = value.every(
|
|
10312
|
+
(v) => isAttachmentObject(v) || typeof v === "string" && isURL(v)
|
|
10313
|
+
);
|
|
10314
|
+
if (!allValid) return null;
|
|
10315
|
+
return value.map((item) => ({
|
|
10316
|
+
type: "image_url",
|
|
10317
|
+
image_url: { url: item }
|
|
10318
|
+
}));
|
|
10319
|
+
}
|
|
10320
|
+
function renderMessageImpl(render, message, variables) {
|
|
10321
|
+
return {
|
|
10322
|
+
...message,
|
|
10323
|
+
..."content" in message ? {
|
|
10324
|
+
content: isEmpty2(message.content) ? void 0 : typeof message.content === "string" ? render(message.content) : message.content.flatMap((c) => {
|
|
10325
|
+
switch (c.type) {
|
|
10326
|
+
case "text":
|
|
10327
|
+
return [{ ...c, text: render(c.text) }];
|
|
10328
|
+
case "image_url":
|
|
10329
|
+
if (isObject(c.image_url.url)) {
|
|
10330
|
+
throw new Error(
|
|
10331
|
+
"Attachments must be replaced with URLs before calling `build()`"
|
|
10332
|
+
);
|
|
10333
|
+
}
|
|
10334
|
+
if (variables) {
|
|
10335
|
+
const expanded = expandAttachmentArrayPreTemplate(
|
|
10336
|
+
c.image_url.url,
|
|
10337
|
+
variables
|
|
10338
|
+
);
|
|
10339
|
+
if (expanded) {
|
|
10340
|
+
return expanded;
|
|
10341
|
+
}
|
|
10342
|
+
}
|
|
10343
|
+
return [
|
|
10344
|
+
{
|
|
10345
|
+
...c,
|
|
10346
|
+
image_url: {
|
|
10347
|
+
...c.image_url,
|
|
10348
|
+
url: render(c.image_url.url)
|
|
10349
|
+
}
|
|
10350
|
+
}
|
|
10351
|
+
];
|
|
10352
|
+
case "file":
|
|
10353
|
+
return [
|
|
10354
|
+
{
|
|
10355
|
+
...c,
|
|
10356
|
+
file: {
|
|
10357
|
+
...c.file.file_data && {
|
|
10358
|
+
file_data: render(c.file.file_data)
|
|
10359
|
+
},
|
|
10360
|
+
...c.file.file_id && {
|
|
10361
|
+
file_id: render(c.file.file_id)
|
|
10362
|
+
},
|
|
10363
|
+
...c.file.filename && {
|
|
10364
|
+
filename: render(c.file.filename)
|
|
10365
|
+
}
|
|
10366
|
+
}
|
|
10367
|
+
}
|
|
10368
|
+
];
|
|
10369
|
+
default:
|
|
10370
|
+
const _exhaustiveCheck = c;
|
|
10371
|
+
return _exhaustiveCheck;
|
|
10372
|
+
}
|
|
10373
|
+
})
|
|
10374
|
+
} : {},
|
|
10375
|
+
..."tool_calls" in message ? {
|
|
10376
|
+
tool_calls: isEmpty2(message.tool_calls) ? void 0 : message.tool_calls.map((t) => {
|
|
10377
|
+
return {
|
|
10378
|
+
type: t.type,
|
|
10379
|
+
id: render(t.id),
|
|
10380
|
+
function: {
|
|
10381
|
+
name: render(t.function.name),
|
|
10382
|
+
arguments: render(t.function.arguments)
|
|
10383
|
+
}
|
|
10384
|
+
};
|
|
10385
|
+
})
|
|
10386
|
+
} : {},
|
|
10387
|
+
..."tool_call_id" in message ? {
|
|
10388
|
+
tool_call_id: render(message.tool_call_id)
|
|
10389
|
+
} : {}
|
|
10390
|
+
};
|
|
10391
|
+
}
|
|
10392
|
+
function deserializePlainStringAsJSON(s) {
|
|
10393
|
+
if (s.trim() === "") {
|
|
10394
|
+
return { value: null, error: void 0 };
|
|
10395
|
+
}
|
|
10396
|
+
try {
|
|
10397
|
+
return { value: JSON.parse(s), error: void 0 };
|
|
10398
|
+
} catch (e) {
|
|
10399
|
+
return { value: s, error: e };
|
|
10400
|
+
}
|
|
10401
|
+
}
|
|
10402
|
+
function renderTemplatedObject(obj, args, options) {
|
|
10403
|
+
if (typeof obj === "string") {
|
|
10404
|
+
return renderTemplateContent(
|
|
10405
|
+
obj,
|
|
10406
|
+
args,
|
|
10407
|
+
(value) => typeof value === "string" ? value : JSON.stringify(value),
|
|
10408
|
+
{
|
|
10409
|
+
strict: options.strict,
|
|
10410
|
+
templateFormat: options.templateFormat
|
|
10411
|
+
}
|
|
10412
|
+
);
|
|
10413
|
+
} else if (isArray(obj)) {
|
|
10414
|
+
return obj.map((item) => renderTemplatedObject(item, args, options));
|
|
10415
|
+
} else if (isObject(obj)) {
|
|
10416
|
+
return Object.fromEntries(
|
|
10417
|
+
Object.entries(obj).map(([key, value]) => [
|
|
10418
|
+
key,
|
|
10419
|
+
renderTemplatedObject(value, args, options)
|
|
10420
|
+
])
|
|
10421
|
+
);
|
|
10422
|
+
}
|
|
10423
|
+
return obj;
|
|
10424
|
+
}
|
|
10425
|
+
function renderPromptParams(params, args, options = {}) {
|
|
10426
|
+
const templateFormat = parseTemplateFormat(options.templateFormat);
|
|
10427
|
+
const strict = !!options.strict;
|
|
10428
|
+
const schemaParsed = z8.object({
|
|
10429
|
+
response_format: z8.object({
|
|
10430
|
+
type: z8.literal("json_schema"),
|
|
10431
|
+
json_schema: ResponseFormatJsonSchema.omit({ schema: true }).extend({
|
|
10432
|
+
schema: z8.unknown()
|
|
10433
|
+
})
|
|
10434
|
+
})
|
|
10435
|
+
}).safeParse(params);
|
|
10436
|
+
if (schemaParsed.success) {
|
|
10437
|
+
const rawSchema = schemaParsed.data.response_format.json_schema.schema;
|
|
10438
|
+
const templatedSchema = renderTemplatedObject(rawSchema, args, {
|
|
10439
|
+
strict,
|
|
10440
|
+
templateFormat
|
|
10441
|
+
});
|
|
10442
|
+
const parsedSchema = typeof templatedSchema === "string" ? deserializePlainStringAsJSON(templatedSchema).value : templatedSchema;
|
|
10443
|
+
return {
|
|
10444
|
+
...params,
|
|
10445
|
+
response_format: {
|
|
10446
|
+
...schemaParsed.data.response_format,
|
|
10447
|
+
json_schema: {
|
|
10448
|
+
...schemaParsed.data.response_format.json_schema,
|
|
10449
|
+
schema: parsedSchema
|
|
10450
|
+
}
|
|
10451
|
+
}
|
|
10452
|
+
};
|
|
10453
|
+
}
|
|
10454
|
+
return params;
|
|
10455
|
+
}
|
|
10456
|
+
var Prompt2 = class _Prompt {
|
|
10457
|
+
constructor(metadata, defaults, noTrace) {
|
|
10458
|
+
this.metadata = metadata;
|
|
10459
|
+
this.defaults = defaults;
|
|
10460
|
+
this.noTrace = noTrace;
|
|
10461
|
+
void this.__braintrust_prompt_marker;
|
|
10462
|
+
}
|
|
10463
|
+
metadata;
|
|
10464
|
+
defaults;
|
|
10465
|
+
noTrace;
|
|
10466
|
+
parsedPromptData;
|
|
10467
|
+
hasParsedPromptData = false;
|
|
10468
|
+
__braintrust_prompt_marker = true;
|
|
10469
|
+
get id() {
|
|
10470
|
+
return this.metadata.id;
|
|
10471
|
+
}
|
|
10472
|
+
get projectId() {
|
|
10473
|
+
return this.metadata.project_id;
|
|
10474
|
+
}
|
|
10475
|
+
get name() {
|
|
10476
|
+
return "name" in this.metadata ? this.metadata.name : `Playground function ${this.metadata.id}`;
|
|
10477
|
+
}
|
|
10478
|
+
get slug() {
|
|
10479
|
+
return "slug" in this.metadata ? this.metadata.slug : this.metadata.id;
|
|
10480
|
+
}
|
|
10481
|
+
get prompt() {
|
|
10482
|
+
return this.getParsedPromptData()?.prompt;
|
|
10483
|
+
}
|
|
10484
|
+
get version() {
|
|
10485
|
+
return this.metadata[TRANSACTION_ID_FIELD];
|
|
10486
|
+
}
|
|
10487
|
+
get options() {
|
|
10488
|
+
return this.getParsedPromptData()?.options || {};
|
|
10489
|
+
}
|
|
10490
|
+
get templateFormat() {
|
|
10491
|
+
return this.getParsedPromptData()?.template_format;
|
|
10492
|
+
}
|
|
10493
|
+
get promptData() {
|
|
10494
|
+
return this.getParsedPromptData();
|
|
10495
|
+
}
|
|
10496
|
+
/**
|
|
10497
|
+
* Build the prompt with the given formatting options. The args you pass in will
|
|
10498
|
+
* be forwarded to the mustache template that defines the prompt and rendered with
|
|
10499
|
+
* the `mustache-js` library.
|
|
10500
|
+
*
|
|
10501
|
+
* @param buildArgs Args to forward along to the prompt template.
|
|
10502
|
+
*/
|
|
10503
|
+
build(buildArgs, options = {}) {
|
|
10504
|
+
return this.runBuild(buildArgs, {
|
|
10505
|
+
flavor: options.flavor ?? "chat",
|
|
10506
|
+
messages: options.messages,
|
|
10507
|
+
strict: options.strict,
|
|
10508
|
+
templateFormat: options.templateFormat
|
|
10509
|
+
});
|
|
10510
|
+
}
|
|
10511
|
+
/**
|
|
10512
|
+
* This is a special build method that first resolves attachment references, and then
|
|
10513
|
+
* calls the regular build method. You should use this if you are building prompts from
|
|
10514
|
+
* dataset rows that contain attachments.
|
|
10515
|
+
*
|
|
10516
|
+
* @param buildArgs Args to forward along to the prompt template.
|
|
10517
|
+
*/
|
|
10518
|
+
async buildWithAttachments(buildArgs, options = {}) {
|
|
10519
|
+
const hydrated = buildArgs instanceof Object ? await resolveAttachmentsToBase64(buildArgs, options.state) : buildArgs;
|
|
10520
|
+
return this.runBuild(hydrated, {
|
|
10521
|
+
flavor: options.flavor ?? "chat",
|
|
10522
|
+
messages: options.messages,
|
|
10523
|
+
strict: options.strict,
|
|
10524
|
+
templateFormat: options.templateFormat
|
|
10525
|
+
});
|
|
10526
|
+
}
|
|
10527
|
+
runBuild(buildArgs, options) {
|
|
10528
|
+
const { flavor } = options;
|
|
10529
|
+
const params = Object.fromEntries(
|
|
10530
|
+
Object.entries({
|
|
10531
|
+
...this.defaults,
|
|
10532
|
+
...Object.fromEntries(
|
|
10533
|
+
Object.entries(this.options.params || {}).filter(
|
|
10534
|
+
([k, _v]) => !BRAINTRUST_PARAMS.includes(k)
|
|
10535
|
+
)
|
|
10536
|
+
),
|
|
10537
|
+
...!isEmpty2(this.options.model) ? {
|
|
10538
|
+
model: this.options.model
|
|
10539
|
+
} : {}
|
|
10540
|
+
}).filter(([key, value]) => key !== "response_format" || value !== null)
|
|
10541
|
+
);
|
|
10542
|
+
if (!("model" in params) || isEmpty2(params.model)) {
|
|
10543
|
+
throw new Error(
|
|
10544
|
+
"No model specified. Either specify it in the prompt or as a default"
|
|
10545
|
+
);
|
|
10546
|
+
}
|
|
10547
|
+
const spanInfo = this.noTrace ? {} : {
|
|
10548
|
+
span_info: {
|
|
10549
|
+
metadata: {
|
|
10550
|
+
prompt: this.id ? {
|
|
10551
|
+
variables: buildArgs,
|
|
10552
|
+
id: this.id,
|
|
10553
|
+
project_id: this.projectId,
|
|
10554
|
+
version: this.version,
|
|
10555
|
+
..."prompt_session_id" in this.metadata ? { prompt_session_id: this.metadata.prompt_session_id } : {}
|
|
10556
|
+
} : void 0
|
|
10557
|
+
}
|
|
10558
|
+
}
|
|
10559
|
+
};
|
|
10560
|
+
const prompt = this.prompt;
|
|
10561
|
+
if (!prompt) {
|
|
10562
|
+
throw new Error("Empty prompt");
|
|
10563
|
+
}
|
|
10564
|
+
const dictArgParsed = z8.record(z8.unknown()).safeParse(buildArgs);
|
|
10565
|
+
const variables = {
|
|
10566
|
+
input: buildArgs,
|
|
10567
|
+
...dictArgParsed.success ? dictArgParsed.data : {}
|
|
10568
|
+
};
|
|
10569
|
+
const promptDataTemplateFormat = this.templateFormat;
|
|
10570
|
+
const resolvedTemplateFormat = parseTemplateFormat(
|
|
10571
|
+
options.templateFormat ?? promptDataTemplateFormat
|
|
10572
|
+
);
|
|
10573
|
+
const renderedPrompt = _Prompt.renderPrompt({
|
|
10574
|
+
prompt,
|
|
10575
|
+
buildArgs,
|
|
10576
|
+
options: { ...options, templateFormat: resolvedTemplateFormat }
|
|
10577
|
+
});
|
|
10578
|
+
if (flavor === "chat") {
|
|
10579
|
+
if (renderedPrompt.type !== "chat") {
|
|
10580
|
+
throw new Error(
|
|
10581
|
+
"Prompt is a completion prompt. Use buildCompletion() instead"
|
|
10582
|
+
);
|
|
10583
|
+
}
|
|
10584
|
+
return {
|
|
10585
|
+
...renderPromptParams(params, variables, {
|
|
10586
|
+
strict: options.strict,
|
|
10587
|
+
templateFormat: resolvedTemplateFormat
|
|
10588
|
+
}),
|
|
10589
|
+
...spanInfo,
|
|
10590
|
+
messages: renderedPrompt.messages,
|
|
10591
|
+
...renderedPrompt.tools ? {
|
|
10592
|
+
tools: ChatCompletionTool.array().parse(JSON.parse(renderedPrompt.tools))
|
|
10593
|
+
} : void 0
|
|
10594
|
+
};
|
|
10595
|
+
} else if (flavor === "completion") {
|
|
10596
|
+
if (renderedPrompt.type !== "completion") {
|
|
10597
|
+
throw new Error(`Prompt is a chat prompt. Use flavor: 'chat' instead`);
|
|
10598
|
+
}
|
|
10599
|
+
return {
|
|
10600
|
+
...renderPromptParams(params, variables, {
|
|
10601
|
+
strict: options.strict,
|
|
10602
|
+
templateFormat: resolvedTemplateFormat
|
|
10603
|
+
}),
|
|
10604
|
+
...spanInfo,
|
|
10605
|
+
prompt: renderedPrompt.content
|
|
10606
|
+
};
|
|
10607
|
+
} else {
|
|
10608
|
+
throw new Error("never!");
|
|
10609
|
+
}
|
|
10610
|
+
}
|
|
10611
|
+
static renderPrompt({
|
|
10612
|
+
prompt,
|
|
10613
|
+
buildArgs,
|
|
10614
|
+
options
|
|
10615
|
+
}) {
|
|
10616
|
+
const escape = (v) => {
|
|
10617
|
+
if (v === void 0) {
|
|
10618
|
+
throw new Error("Missing!");
|
|
10619
|
+
} else if (typeof v === "string") {
|
|
10620
|
+
return v;
|
|
10621
|
+
} else if (v instanceof ReadonlyAttachment) {
|
|
10622
|
+
throw new Error(
|
|
10623
|
+
"Use buildWithAttachments() to build prompts with attachments"
|
|
10624
|
+
);
|
|
10625
|
+
} else {
|
|
10626
|
+
return JSON.stringify(v);
|
|
10627
|
+
}
|
|
10628
|
+
};
|
|
10629
|
+
const dictArgParsed = z8.record(z8.unknown()).safeParse(buildArgs);
|
|
10630
|
+
const variables = {
|
|
10631
|
+
input: buildArgs,
|
|
10632
|
+
...dictArgParsed.success ? dictArgParsed.data : {}
|
|
10633
|
+
};
|
|
10634
|
+
const templateFormat = parseTemplateFormat(options.templateFormat);
|
|
10635
|
+
if (prompt.type === "chat") {
|
|
10636
|
+
const render = (template) => renderTemplateContent(template, variables, escape, {
|
|
10637
|
+
strict: options.strict,
|
|
10638
|
+
templateFormat
|
|
10639
|
+
});
|
|
10640
|
+
const baseMessages = (prompt.messages || []).map(
|
|
10641
|
+
(m) => renderMessageImpl(render, m, variables)
|
|
10642
|
+
);
|
|
10643
|
+
const hasSystemPrompt = baseMessages.some((m) => m.role === "system");
|
|
10644
|
+
const messages = [
|
|
10645
|
+
...baseMessages,
|
|
10646
|
+
...(options.messages ?? []).filter(
|
|
10647
|
+
(m) => !(hasSystemPrompt && m.role === "system")
|
|
10648
|
+
)
|
|
10649
|
+
];
|
|
10650
|
+
return {
|
|
10651
|
+
type: "chat",
|
|
10652
|
+
messages,
|
|
10653
|
+
...prompt.tools?.trim() ? {
|
|
10654
|
+
tools: render(prompt.tools)
|
|
10655
|
+
} : void 0
|
|
10656
|
+
};
|
|
10657
|
+
} else if (prompt.type === "completion") {
|
|
10658
|
+
if (options.messages) {
|
|
10659
|
+
throw new Error(
|
|
10660
|
+
"extra messages are not supported for completion prompts"
|
|
10661
|
+
);
|
|
10662
|
+
}
|
|
10663
|
+
const content = renderTemplateContent(prompt.content, variables, escape, {
|
|
10664
|
+
strict: options.strict,
|
|
10665
|
+
templateFormat
|
|
10666
|
+
});
|
|
10667
|
+
return {
|
|
10668
|
+
type: "completion",
|
|
10669
|
+
content
|
|
10670
|
+
};
|
|
10671
|
+
} else {
|
|
10672
|
+
const _ = prompt;
|
|
10673
|
+
throw new Error(`Invalid prompt type: ${_}`);
|
|
10674
|
+
}
|
|
10675
|
+
}
|
|
10676
|
+
getParsedPromptData() {
|
|
10677
|
+
if (!this.hasParsedPromptData) {
|
|
10678
|
+
this.parsedPromptData = PromptData.parse(this.metadata.prompt_data);
|
|
10679
|
+
this.hasParsedPromptData = true;
|
|
10680
|
+
}
|
|
10681
|
+
return this.parsedPromptData;
|
|
10682
|
+
}
|
|
10683
|
+
static isPrompt(data) {
|
|
10684
|
+
return typeof data === "object" && data !== null && "__braintrust_prompt_marker" in data;
|
|
10685
|
+
}
|
|
10686
|
+
/** @internal */
|
|
10687
|
+
_internalSerializeForCache() {
|
|
10688
|
+
return {
|
|
10689
|
+
metadata: this.metadata,
|
|
10690
|
+
defaults: this.defaults,
|
|
10691
|
+
noTrace: this.noTrace
|
|
10692
|
+
};
|
|
10693
|
+
}
|
|
10694
|
+
static fromPromptData(name, promptData) {
|
|
10695
|
+
return new _Prompt(
|
|
10696
|
+
{
|
|
10697
|
+
name,
|
|
10698
|
+
slug: name,
|
|
10699
|
+
prompt_data: promptData
|
|
10700
|
+
},
|
|
10701
|
+
{},
|
|
10702
|
+
false
|
|
10703
|
+
);
|
|
10704
|
+
}
|
|
10705
|
+
};
|
|
10706
|
+
var RemoteEvalParameters = class {
|
|
10707
|
+
constructor(metadata) {
|
|
10708
|
+
this.metadata = metadata;
|
|
10709
|
+
void this.__braintrust_parameters_marker;
|
|
10710
|
+
}
|
|
10711
|
+
metadata;
|
|
10712
|
+
__braintrust_parameters_marker = true;
|
|
10713
|
+
get id() {
|
|
10714
|
+
return this.metadata.id;
|
|
10715
|
+
}
|
|
10716
|
+
get projectId() {
|
|
10717
|
+
return this.metadata.project_id;
|
|
10718
|
+
}
|
|
10719
|
+
get name() {
|
|
10720
|
+
return this.metadata.name;
|
|
10721
|
+
}
|
|
10722
|
+
get slug() {
|
|
10723
|
+
return this.metadata.slug;
|
|
10724
|
+
}
|
|
10725
|
+
get version() {
|
|
10726
|
+
return this.metadata[TRANSACTION_ID_FIELD];
|
|
10727
|
+
}
|
|
10728
|
+
get schema() {
|
|
10729
|
+
return this.metadata.function_data.__schema;
|
|
10730
|
+
}
|
|
10731
|
+
get data() {
|
|
10732
|
+
return this.metadata.function_data.data ?? {};
|
|
10733
|
+
}
|
|
10734
|
+
/** @internal */
|
|
10735
|
+
_internalSerializeForCache() {
|
|
10736
|
+
return { metadata: this.metadata };
|
|
10737
|
+
}
|
|
10738
|
+
validate(data) {
|
|
10739
|
+
if (typeof data !== "object" || data === null) {
|
|
10740
|
+
return false;
|
|
10741
|
+
}
|
|
10742
|
+
const schemaProps = this.schema.properties;
|
|
10743
|
+
if (typeof schemaProps !== "object" || schemaProps === null) {
|
|
10744
|
+
return true;
|
|
10745
|
+
}
|
|
10746
|
+
for (const key of Object.keys(schemaProps)) {
|
|
10747
|
+
if (!(key in data)) {
|
|
10748
|
+
const required = Array.isArray(this.schema.required) ? this.schema.required : [];
|
|
10749
|
+
if (required.includes(key)) {
|
|
10750
|
+
return false;
|
|
10751
|
+
}
|
|
10752
|
+
}
|
|
10753
|
+
}
|
|
10754
|
+
return true;
|
|
10755
|
+
}
|
|
10756
|
+
static isParameters(x) {
|
|
10757
|
+
return typeof x === "object" && x !== null && "__braintrust_parameters_marker" in x && x.__braintrust_parameters_marker === true;
|
|
10758
|
+
}
|
|
10759
|
+
};
|
|
9961
10760
|
var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
|
|
9962
10761
|
|
|
9963
10762
|
// src/instrumentation/core/channel-tracing-utils.ts
|
|
@@ -10403,56 +11202,14 @@ function suppressionStore() {
|
|
|
10403
11202
|
autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
|
|
10404
11203
|
return autoInstrumentationSuppressionStore;
|
|
10405
11204
|
}
|
|
10406
|
-
function currentFrames() {
|
|
10407
|
-
return suppressionStore().getStore()?.frames ?? [];
|
|
10408
|
-
}
|
|
10409
11205
|
function isAutoInstrumentationSuppressed() {
|
|
10410
|
-
|
|
10411
|
-
return frames[frames.length - 1]?.mode === "suppress";
|
|
11206
|
+
return suppressionStore().getStore() === true;
|
|
10412
11207
|
}
|
|
10413
11208
|
function runWithAutoInstrumentationSuppressed(callback) {
|
|
10414
|
-
|
|
10415
|
-
id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
|
|
10416
|
-
mode: "suppress"
|
|
10417
|
-
};
|
|
10418
|
-
return suppressionStore().run(
|
|
10419
|
-
{ frames: [...currentFrames(), frame] },
|
|
10420
|
-
callback
|
|
10421
|
-
);
|
|
10422
|
-
}
|
|
10423
|
-
function bindAutoInstrumentationSuppressionToStart(tracingChannel) {
|
|
10424
|
-
const startChannel = tracingChannel.start;
|
|
10425
|
-
if (!startChannel) {
|
|
10426
|
-
return void 0;
|
|
10427
|
-
}
|
|
10428
|
-
const store = suppressionStore();
|
|
10429
|
-
startChannel.bindStore(store, () => ({
|
|
10430
|
-
frames: [
|
|
10431
|
-
...currentFrames(),
|
|
10432
|
-
{
|
|
10433
|
-
id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
|
|
10434
|
-
mode: "suppress"
|
|
10435
|
-
}
|
|
10436
|
-
]
|
|
10437
|
-
}));
|
|
10438
|
-
return () => {
|
|
10439
|
-
startChannel.unbindStore(store);
|
|
10440
|
-
};
|
|
11209
|
+
return suppressionStore().run(true, callback);
|
|
10441
11210
|
}
|
|
10442
|
-
function
|
|
10443
|
-
|
|
10444
|
-
id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
|
|
10445
|
-
mode: "allow"
|
|
10446
|
-
};
|
|
10447
|
-
suppressionStore().enterWith({
|
|
10448
|
-
frames: [...currentFrames(), frame]
|
|
10449
|
-
});
|
|
10450
|
-
return () => {
|
|
10451
|
-
const frames = currentFrames().filter(
|
|
10452
|
-
(candidate) => candidate.id !== frame.id
|
|
10453
|
-
);
|
|
10454
|
-
suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
|
|
10455
|
-
};
|
|
11211
|
+
function runWithAutoInstrumentationAllowed(callback) {
|
|
11212
|
+
return suppressionStore().run(void 0, callback);
|
|
10456
11213
|
}
|
|
10457
11214
|
|
|
10458
11215
|
// src/instrumentation/core/channel-tracing.ts
|
|
@@ -11042,6 +11799,131 @@ function unsubscribeAll(unsubscribers) {
|
|
|
11042
11799
|
return [];
|
|
11043
11800
|
}
|
|
11044
11801
|
|
|
11802
|
+
// src/instrumentation/core/channel-definitions.ts
|
|
11803
|
+
function channel(spec) {
|
|
11804
|
+
return spec;
|
|
11805
|
+
}
|
|
11806
|
+
function defineChannels(pkg, channels, options) {
|
|
11807
|
+
const { instrumentationName } = options;
|
|
11808
|
+
return Object.fromEntries(
|
|
11809
|
+
Object.entries(channels).map(([key, spec]) => {
|
|
11810
|
+
const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
|
|
11811
|
+
if (spec.kind === "async") {
|
|
11812
|
+
const asyncSpec = spec;
|
|
11813
|
+
const tracingChannel2 = () => isomorph_default.newTracingChannel(
|
|
11814
|
+
fullChannelName
|
|
11815
|
+
);
|
|
11816
|
+
const intercept2 = (interceptor) => {
|
|
11817
|
+
const hook = tracingChannel2();
|
|
11818
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
11819
|
+
};
|
|
11820
|
+
};
|
|
11821
|
+
return [
|
|
11822
|
+
key,
|
|
11823
|
+
{
|
|
11824
|
+
...asyncSpec,
|
|
11825
|
+
instrumentationName,
|
|
11826
|
+
intercept: intercept2,
|
|
11827
|
+
invoke: (target, thisArg, args, additional) => {
|
|
11828
|
+
const hook = tracingChannel2();
|
|
11829
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11830
|
+
},
|
|
11831
|
+
tracingChannel: tracingChannel2,
|
|
11832
|
+
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
11833
|
+
fn,
|
|
11834
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11835
|
+
context
|
|
11836
|
+
)
|
|
11837
|
+
}
|
|
11838
|
+
];
|
|
11839
|
+
}
|
|
11840
|
+
const syncSpec = spec;
|
|
11841
|
+
const tracingChannel = () => isomorph_default.newTracingChannel(
|
|
11842
|
+
fullChannelName
|
|
11843
|
+
);
|
|
11844
|
+
const intercept = (interceptor) => {
|
|
11845
|
+
const hook = tracingChannel();
|
|
11846
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
11847
|
+
};
|
|
11848
|
+
};
|
|
11849
|
+
return [
|
|
11850
|
+
key,
|
|
11851
|
+
{
|
|
11852
|
+
...syncSpec,
|
|
11853
|
+
instrumentationName,
|
|
11854
|
+
intercept,
|
|
11855
|
+
invoke: (target, thisArg, args, additional) => {
|
|
11856
|
+
const hook = tracingChannel();
|
|
11857
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11858
|
+
},
|
|
11859
|
+
tracingChannel,
|
|
11860
|
+
traceSync: (fn, context) => tracingChannel().traceSync(
|
|
11861
|
+
fn,
|
|
11862
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11863
|
+
context
|
|
11864
|
+
)
|
|
11865
|
+
}
|
|
11866
|
+
];
|
|
11867
|
+
})
|
|
11868
|
+
);
|
|
11869
|
+
}
|
|
11870
|
+
|
|
11871
|
+
// src/instrumentation/plugins/openai-channels.ts
|
|
11872
|
+
var openAIChannels = defineChannels(
|
|
11873
|
+
"openai",
|
|
11874
|
+
{
|
|
11875
|
+
filesCreateTraced: channel({
|
|
11876
|
+
channelName: "files.create-traced",
|
|
11877
|
+
kind: "async"
|
|
11878
|
+
}),
|
|
11879
|
+
batchesRetrieveTraced: channel({
|
|
11880
|
+
channelName: "batches.retrieve-traced",
|
|
11881
|
+
kind: "async"
|
|
11882
|
+
}),
|
|
11883
|
+
batchesCompleteTrace: channel({
|
|
11884
|
+
channelName: "batches.complete-trace",
|
|
11885
|
+
kind: "async"
|
|
11886
|
+
}),
|
|
11887
|
+
chatCompletionsCreate: channel({
|
|
11888
|
+
channelName: "chat.completions.create",
|
|
11889
|
+
kind: "async"
|
|
11890
|
+
}),
|
|
11891
|
+
embeddingsCreate: channel({
|
|
11892
|
+
channelName: "embeddings.create",
|
|
11893
|
+
kind: "async"
|
|
11894
|
+
}),
|
|
11895
|
+
betaChatCompletionsParse: channel({
|
|
11896
|
+
channelName: "beta.chat.completions.parse",
|
|
11897
|
+
kind: "async"
|
|
11898
|
+
}),
|
|
11899
|
+
betaChatCompletionsStream: channel({
|
|
11900
|
+
channelName: "beta.chat.completions.stream",
|
|
11901
|
+
kind: "sync-stream"
|
|
11902
|
+
}),
|
|
11903
|
+
moderationsCreate: channel({
|
|
11904
|
+
channelName: "moderations.create",
|
|
11905
|
+
kind: "async"
|
|
11906
|
+
}),
|
|
11907
|
+
responsesCreate: channel({
|
|
11908
|
+
channelName: "responses.create",
|
|
11909
|
+
kind: "async"
|
|
11910
|
+
}),
|
|
11911
|
+
responsesStream: channel({
|
|
11912
|
+
channelName: "responses.stream",
|
|
11913
|
+
kind: "sync-stream"
|
|
11914
|
+
}),
|
|
11915
|
+
responsesParse: channel({
|
|
11916
|
+
channelName: "responses.parse",
|
|
11917
|
+
kind: "async"
|
|
11918
|
+
}),
|
|
11919
|
+
responsesCompact: channel({
|
|
11920
|
+
channelName: "responses.compact",
|
|
11921
|
+
kind: "async"
|
|
11922
|
+
})
|
|
11923
|
+
},
|
|
11924
|
+
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
11925
|
+
);
|
|
11926
|
+
|
|
11045
11927
|
// src/wrappers/attachment-utils.ts
|
|
11046
11928
|
function getExtensionFromMediaType(mediaType) {
|
|
11047
11929
|
const extensionMap = {
|
|
@@ -11217,118 +12099,91 @@ function processInputAttachments(input) {
|
|
|
11217
12099
|
return processNode(input);
|
|
11218
12100
|
}
|
|
11219
12101
|
|
|
11220
|
-
// src/instrumentation/
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
...asyncSpec,
|
|
11243
|
-
instrumentationName,
|
|
11244
|
-
intercept: intercept2,
|
|
11245
|
-
invoke: (target, thisArg, args, additional) => {
|
|
11246
|
-
const hook = tracingChannel2();
|
|
11247
|
-
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11248
|
-
},
|
|
11249
|
-
tracingChannel: tracingChannel2,
|
|
11250
|
-
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
11251
|
-
fn,
|
|
11252
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11253
|
-
context
|
|
11254
|
-
)
|
|
11255
|
-
}
|
|
11256
|
-
];
|
|
12102
|
+
// src/instrumentation/plugins/openai-span-data.ts
|
|
12103
|
+
var OPENAI_METADATA_KEYS = [
|
|
12104
|
+
"model",
|
|
12105
|
+
"temperature",
|
|
12106
|
+
"top_p",
|
|
12107
|
+
"max_tokens",
|
|
12108
|
+
"frequency_penalty",
|
|
12109
|
+
"presence_penalty",
|
|
12110
|
+
"stop",
|
|
12111
|
+
"response_format",
|
|
12112
|
+
"tools",
|
|
12113
|
+
"tool_choice",
|
|
12114
|
+
"parallel_tool_calls",
|
|
12115
|
+
"max_tool_calls"
|
|
12116
|
+
];
|
|
12117
|
+
function batchMetadata(params) {
|
|
12118
|
+
const metadata = { provider: "openai" };
|
|
12119
|
+
for (const key of OPENAI_METADATA_KEYS) {
|
|
12120
|
+
try {
|
|
12121
|
+
const value = Reflect.get(params, key);
|
|
12122
|
+
if (value !== void 0) {
|
|
12123
|
+
metadata[key] = value;
|
|
11257
12124
|
}
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
12125
|
+
} catch {
|
|
12126
|
+
}
|
|
12127
|
+
}
|
|
12128
|
+
return metadata;
|
|
12129
|
+
}
|
|
12130
|
+
function extractOpenAIBatchInput(endpoint, params) {
|
|
12131
|
+
const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
|
|
12132
|
+
return {
|
|
12133
|
+
input: processInputAttachments(input),
|
|
12134
|
+
metadata: batchMetadata(params)
|
|
12135
|
+
};
|
|
12136
|
+
}
|
|
12137
|
+
function extractOpenAIChatInput(params) {
|
|
12138
|
+
const { messages, ...metadata } = params;
|
|
12139
|
+
return {
|
|
12140
|
+
input: processInputAttachments(messages),
|
|
12141
|
+
metadata: { ...metadata, provider: "openai" }
|
|
12142
|
+
};
|
|
12143
|
+
}
|
|
12144
|
+
function extractOpenAIResponsesInput(params) {
|
|
12145
|
+
const { input, ...metadata } = params;
|
|
12146
|
+
return {
|
|
12147
|
+
input: processInputAttachments(input),
|
|
12148
|
+
metadata: { ...metadata, provider: "openai" }
|
|
12149
|
+
};
|
|
12150
|
+
}
|
|
12151
|
+
function extractOpenAIResponsesMetadata(result) {
|
|
12152
|
+
if (!result) {
|
|
12153
|
+
return void 0;
|
|
12154
|
+
}
|
|
12155
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
12156
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12157
|
+
}
|
|
12158
|
+
function processImagesInOutput(output) {
|
|
12159
|
+
if (Array.isArray(output)) {
|
|
12160
|
+
return output.map(processImagesInOutput);
|
|
12161
|
+
}
|
|
12162
|
+
if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
|
|
12163
|
+
const fileExtension = output.output_format || "png";
|
|
12164
|
+
const contentType = `image/${fileExtension}`;
|
|
12165
|
+
const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
12166
|
+
let binaryString;
|
|
12167
|
+
try {
|
|
12168
|
+
binaryString = atob(output.result);
|
|
12169
|
+
} catch {
|
|
12170
|
+
return output;
|
|
12171
|
+
}
|
|
12172
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
12173
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
12174
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
12175
|
+
}
|
|
12176
|
+
return {
|
|
12177
|
+
...output,
|
|
12178
|
+
result: new Attachment({
|
|
12179
|
+
data: new Blob([bytes], { type: contentType }),
|
|
12180
|
+
filename: `${baseFilename}.${fileExtension}`,
|
|
12181
|
+
contentType
|
|
12182
|
+
})
|
|
12183
|
+
};
|
|
12184
|
+
}
|
|
12185
|
+
return output;
|
|
11287
12186
|
}
|
|
11288
|
-
|
|
11289
|
-
// src/instrumentation/plugins/openai-channels.ts
|
|
11290
|
-
var openAIChannels = defineChannels(
|
|
11291
|
-
"openai",
|
|
11292
|
-
{
|
|
11293
|
-
chatCompletionsCreate: channel({
|
|
11294
|
-
channelName: "chat.completions.create",
|
|
11295
|
-
kind: "async"
|
|
11296
|
-
}),
|
|
11297
|
-
embeddingsCreate: channel({
|
|
11298
|
-
channelName: "embeddings.create",
|
|
11299
|
-
kind: "async"
|
|
11300
|
-
}),
|
|
11301
|
-
betaChatCompletionsParse: channel({
|
|
11302
|
-
channelName: "beta.chat.completions.parse",
|
|
11303
|
-
kind: "async"
|
|
11304
|
-
}),
|
|
11305
|
-
betaChatCompletionsStream: channel({
|
|
11306
|
-
channelName: "beta.chat.completions.stream",
|
|
11307
|
-
kind: "sync-stream"
|
|
11308
|
-
}),
|
|
11309
|
-
moderationsCreate: channel({
|
|
11310
|
-
channelName: "moderations.create",
|
|
11311
|
-
kind: "async"
|
|
11312
|
-
}),
|
|
11313
|
-
responsesCreate: channel({
|
|
11314
|
-
channelName: "responses.create",
|
|
11315
|
-
kind: "async"
|
|
11316
|
-
}),
|
|
11317
|
-
responsesStream: channel({
|
|
11318
|
-
channelName: "responses.stream",
|
|
11319
|
-
kind: "sync-stream"
|
|
11320
|
-
}),
|
|
11321
|
-
responsesParse: channel({
|
|
11322
|
-
channelName: "responses.parse",
|
|
11323
|
-
kind: "async"
|
|
11324
|
-
}),
|
|
11325
|
-
responsesCompact: channel({
|
|
11326
|
-
channelName: "responses.compact",
|
|
11327
|
-
kind: "async"
|
|
11328
|
-
})
|
|
11329
|
-
},
|
|
11330
|
-
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
11331
|
-
);
|
|
11332
12187
|
|
|
11333
12188
|
// src/openai-utils.ts
|
|
11334
12189
|
var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
|
|
@@ -11385,23 +12240,573 @@ function getCachedMetricFromHeaders(headers) {
|
|
|
11385
12240
|
return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
|
|
11386
12241
|
}
|
|
11387
12242
|
|
|
12243
|
+
// src/instrumentation/plugins/openai-batch-instrumentation.ts
|
|
12244
|
+
var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
|
|
12245
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
12246
|
+
"completed",
|
|
12247
|
+
"failed",
|
|
12248
|
+
"expired",
|
|
12249
|
+
"cancelled"
|
|
12250
|
+
]);
|
|
12251
|
+
var pendingBatchTraces = /* @__PURE__ */ new Map();
|
|
12252
|
+
function read(value, key) {
|
|
12253
|
+
if (!isObject(value)) {
|
|
12254
|
+
return void 0;
|
|
12255
|
+
}
|
|
12256
|
+
try {
|
|
12257
|
+
return Reflect.get(value, key);
|
|
12258
|
+
} catch {
|
|
12259
|
+
return void 0;
|
|
12260
|
+
}
|
|
12261
|
+
}
|
|
12262
|
+
function isBatchRecordIterable(value) {
|
|
12263
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
12264
|
+
return false;
|
|
12265
|
+
}
|
|
12266
|
+
return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
|
|
12267
|
+
}
|
|
12268
|
+
function validCustomId(value) {
|
|
12269
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64;
|
|
12270
|
+
}
|
|
12271
|
+
function logBatchInstrumentationError(context, error) {
|
|
12272
|
+
debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
|
|
12273
|
+
}
|
|
12274
|
+
async function exportParent(parent) {
|
|
12275
|
+
if ("toStr" in parent && typeof parent.toStr === "function") {
|
|
12276
|
+
return parent.toStr();
|
|
12277
|
+
}
|
|
12278
|
+
if ("export" in parent && typeof parent.export === "function") {
|
|
12279
|
+
return await parent.export();
|
|
12280
|
+
}
|
|
12281
|
+
return void 0;
|
|
12282
|
+
}
|
|
12283
|
+
async function deterministicDigest(namespace, ...parts) {
|
|
12284
|
+
const encoded = new TextEncoder().encode(
|
|
12285
|
+
[namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
|
|
12286
|
+
);
|
|
12287
|
+
return new Uint8Array(
|
|
12288
|
+
await globalThis.crypto.subtle.digest("SHA-256", encoded)
|
|
12289
|
+
);
|
|
12290
|
+
}
|
|
12291
|
+
function digestHex(bytes, length) {
|
|
12292
|
+
return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
12293
|
+
}
|
|
12294
|
+
function digestUuid(bytes) {
|
|
12295
|
+
const hex = digestHex(bytes, 16);
|
|
12296
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
12297
|
+
}
|
|
12298
|
+
async function batchSpanIds(inputFileId) {
|
|
12299
|
+
const [row, span, root] = await Promise.all([
|
|
12300
|
+
deterministicDigest("openai:batch:row", inputFileId),
|
|
12301
|
+
deterministicDigest("openai:batch:span", inputFileId),
|
|
12302
|
+
deterministicDigest("openai:batch:root", inputFileId)
|
|
12303
|
+
]);
|
|
12304
|
+
return {
|
|
12305
|
+
rowId: digestUuid(row),
|
|
12306
|
+
spanId: digestHex(span, 8),
|
|
12307
|
+
rootSpanId: digestHex(root, 16)
|
|
12308
|
+
};
|
|
12309
|
+
}
|
|
12310
|
+
async function childSpanIds(inputFileId, customId) {
|
|
12311
|
+
const [row, span] = await Promise.all([
|
|
12312
|
+
deterministicDigest("openai:batch:child:row", inputFileId, customId),
|
|
12313
|
+
deterministicDigest("openai:batch:child:span", inputFileId, customId)
|
|
12314
|
+
]);
|
|
12315
|
+
return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
|
|
12316
|
+
}
|
|
12317
|
+
async function startBatchSpan(context) {
|
|
12318
|
+
const ids = await batchSpanIds(context.inputFileId);
|
|
12319
|
+
const parent = SpanComponentsV4.fromStr(context.parent);
|
|
12320
|
+
const hasParentSpan = Boolean(
|
|
12321
|
+
parent.data.row_id && parent.data.span_id && parent.data.root_span_id
|
|
12322
|
+
);
|
|
12323
|
+
return withCurrent(
|
|
12324
|
+
NOOP_SPAN,
|
|
12325
|
+
() => _internalStartSpanWithInitialMergeAndParentSpanIds(
|
|
12326
|
+
withSpanInstrumentationName(
|
|
12327
|
+
{
|
|
12328
|
+
name: "openai.batch",
|
|
12329
|
+
type: "task" /* TASK */,
|
|
12330
|
+
parent: context.parent,
|
|
12331
|
+
...!hasParentSpan ? {
|
|
12332
|
+
parentSpanIds: {
|
|
12333
|
+
parentSpanIds: [],
|
|
12334
|
+
rootSpanId: ids.rootSpanId
|
|
12335
|
+
}
|
|
12336
|
+
} : {},
|
|
12337
|
+
spanId: ids.spanId,
|
|
12338
|
+
startTime: context.taskStartTime,
|
|
12339
|
+
event: {
|
|
12340
|
+
id: ids.rowId,
|
|
12341
|
+
metadata: {
|
|
12342
|
+
endpoint: context.endpoint,
|
|
12343
|
+
input_file_id: context.inputFileId,
|
|
12344
|
+
provider: "openai"
|
|
12345
|
+
}
|
|
12346
|
+
}
|
|
12347
|
+
},
|
|
12348
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
12349
|
+
)
|
|
12350
|
+
)
|
|
12351
|
+
);
|
|
12352
|
+
}
|
|
12353
|
+
async function startBatchChild(context, taskParent, input) {
|
|
12354
|
+
const ids = await childSpanIds(context.inputFileId, input.customId);
|
|
12355
|
+
return withCurrent(
|
|
12356
|
+
NOOP_SPAN,
|
|
12357
|
+
() => _internalStartSpanWithInitialMerge(
|
|
12358
|
+
withSpanInstrumentationName(
|
|
12359
|
+
{
|
|
12360
|
+
name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
|
|
12361
|
+
type: "llm" /* LLM */,
|
|
12362
|
+
parent: taskParent,
|
|
12363
|
+
spanId: ids.spanId,
|
|
12364
|
+
startTime: context.childStartTime,
|
|
12365
|
+
event: {
|
|
12366
|
+
id: ids.rowId,
|
|
12367
|
+
...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
|
|
12368
|
+
metadata: {
|
|
12369
|
+
...input.spanData?.metadata,
|
|
12370
|
+
custom_id: input.customId,
|
|
12371
|
+
provider: "openai"
|
|
12372
|
+
}
|
|
12373
|
+
}
|
|
12374
|
+
},
|
|
12375
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
12376
|
+
)
|
|
12377
|
+
)
|
|
12378
|
+
);
|
|
12379
|
+
}
|
|
12380
|
+
async function* jsonlRecords(file, onIssue = () => {
|
|
12381
|
+
}) {
|
|
12382
|
+
const resolvedFile = await file;
|
|
12383
|
+
if (typeof resolvedFile === "string") {
|
|
12384
|
+
for (const line of resolvedFile.split("\n")) {
|
|
12385
|
+
if (!line.trim()) {
|
|
12386
|
+
continue;
|
|
12387
|
+
}
|
|
12388
|
+
try {
|
|
12389
|
+
yield JSON.parse(line.replace(/\r$/, ""));
|
|
12390
|
+
} catch (error) {
|
|
12391
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12392
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12393
|
+
}
|
|
12394
|
+
}
|
|
12395
|
+
return;
|
|
12396
|
+
}
|
|
12397
|
+
const body = read(resolvedFile, "body");
|
|
12398
|
+
const getReader = read(body, "getReader");
|
|
12399
|
+
if (isObject(body) && typeof getReader === "function") {
|
|
12400
|
+
let reader;
|
|
12401
|
+
try {
|
|
12402
|
+
reader = Reflect.apply(getReader, body, []);
|
|
12403
|
+
const decoder = new TextDecoder();
|
|
12404
|
+
let pending = "";
|
|
12405
|
+
while (true) {
|
|
12406
|
+
const readChunk = read(reader, "read");
|
|
12407
|
+
if (typeof readChunk !== "function") {
|
|
12408
|
+
throw new Error("Response body stream has no read method");
|
|
12409
|
+
}
|
|
12410
|
+
const chunk = await Reflect.apply(readChunk, reader, []);
|
|
12411
|
+
if (!isObject(chunk)) {
|
|
12412
|
+
throw new Error("Response body stream returned an invalid chunk");
|
|
12413
|
+
}
|
|
12414
|
+
if (chunk.done === true) {
|
|
12415
|
+
pending += decoder.decode();
|
|
12416
|
+
break;
|
|
12417
|
+
}
|
|
12418
|
+
if (!(chunk.value instanceof Uint8Array)) {
|
|
12419
|
+
throw new Error("Response body stream returned a non-byte chunk");
|
|
12420
|
+
}
|
|
12421
|
+
pending += decoder.decode(chunk.value, { stream: true });
|
|
12422
|
+
let newline = pending.indexOf("\n");
|
|
12423
|
+
while (newline !== -1) {
|
|
12424
|
+
const line = pending.slice(0, newline).replace(/\r$/, "");
|
|
12425
|
+
pending = pending.slice(newline + 1);
|
|
12426
|
+
if (line.trim()) {
|
|
12427
|
+
try {
|
|
12428
|
+
yield JSON.parse(line);
|
|
12429
|
+
} catch (error) {
|
|
12430
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12431
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12432
|
+
}
|
|
12433
|
+
}
|
|
12434
|
+
newline = pending.indexOf("\n");
|
|
12435
|
+
}
|
|
12436
|
+
}
|
|
12437
|
+
if (pending.trim()) {
|
|
12438
|
+
try {
|
|
12439
|
+
yield JSON.parse(pending.replace(/\r$/, ""));
|
|
12440
|
+
} catch (error) {
|
|
12441
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12442
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12443
|
+
}
|
|
12444
|
+
}
|
|
12445
|
+
} catch (error) {
|
|
12446
|
+
logBatchInstrumentationError("could not read JSONL response body", error);
|
|
12447
|
+
onIssue(new Error("OpenAI Batch response body could not be read"));
|
|
12448
|
+
} finally {
|
|
12449
|
+
const releaseLock = read(reader, "releaseLock");
|
|
12450
|
+
if (typeof releaseLock === "function") {
|
|
12451
|
+
try {
|
|
12452
|
+
Reflect.apply(releaseLock, reader, []);
|
|
12453
|
+
} catch (error) {
|
|
12454
|
+
logBatchInstrumentationError(
|
|
12455
|
+
"could not release stream reader",
|
|
12456
|
+
error
|
|
12457
|
+
);
|
|
12458
|
+
}
|
|
12459
|
+
}
|
|
12460
|
+
}
|
|
12461
|
+
return;
|
|
12462
|
+
}
|
|
12463
|
+
if (isBatchRecordIterable(resolvedFile)) {
|
|
12464
|
+
for await (const record of resolvedFile) {
|
|
12465
|
+
yield record;
|
|
12466
|
+
}
|
|
12467
|
+
return;
|
|
12468
|
+
}
|
|
12469
|
+
logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
|
|
12470
|
+
onIssue(new Error("OpenAI Batch file source is invalid"));
|
|
12471
|
+
}
|
|
12472
|
+
async function readBatchInputs(file) {
|
|
12473
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
12474
|
+
const issues = [];
|
|
12475
|
+
let endpoint;
|
|
12476
|
+
try {
|
|
12477
|
+
for await (const value of jsonlRecords(
|
|
12478
|
+
file,
|
|
12479
|
+
(issue) => issues.push(issue)
|
|
12480
|
+
)) {
|
|
12481
|
+
const customId = read(value, "custom_id");
|
|
12482
|
+
const url = read(value, "url");
|
|
12483
|
+
const body = read(value, "body");
|
|
12484
|
+
if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
|
|
12485
|
+
issues.push(new Error("OpenAI Batch input contains an invalid record"));
|
|
12486
|
+
continue;
|
|
12487
|
+
}
|
|
12488
|
+
endpoint = url;
|
|
12489
|
+
let spanData;
|
|
12490
|
+
try {
|
|
12491
|
+
spanData = extractOpenAIBatchInput(url, body);
|
|
12492
|
+
} catch (error) {
|
|
12493
|
+
logBatchInstrumentationError("could not extract batch input", error);
|
|
12494
|
+
}
|
|
12495
|
+
inputs.set(customId, { customId, spanData });
|
|
12496
|
+
}
|
|
12497
|
+
} catch (error) {
|
|
12498
|
+
logBatchInstrumentationError("could not process input file", error);
|
|
12499
|
+
issues.push(new Error("OpenAI Batch input file could not be processed"));
|
|
12500
|
+
}
|
|
12501
|
+
if (!endpoint || inputs.size === 0) {
|
|
12502
|
+
issues.push(new Error("OpenAI Batch input contains no supported records"));
|
|
12503
|
+
}
|
|
12504
|
+
return { endpoint, inputs, issues };
|
|
12505
|
+
}
|
|
12506
|
+
async function writePendingSpans(trace, endTime) {
|
|
12507
|
+
const task = await startBatchSpan(trace.context);
|
|
12508
|
+
const taskParent = await task.export();
|
|
12509
|
+
for (const input of trace.inputs.values()) {
|
|
12510
|
+
try {
|
|
12511
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
12512
|
+
if (endTime !== void 0) {
|
|
12513
|
+
child.end({ endTime });
|
|
12514
|
+
}
|
|
12515
|
+
} catch (error) {
|
|
12516
|
+
logBatchInstrumentationError("could not write batch request span", error);
|
|
12517
|
+
}
|
|
12518
|
+
}
|
|
12519
|
+
if (endTime !== void 0) {
|
|
12520
|
+
if (trace.status && trace.status !== "completed") {
|
|
12521
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12522
|
+
}
|
|
12523
|
+
task.end({ endTime });
|
|
12524
|
+
}
|
|
12525
|
+
}
|
|
12526
|
+
var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
|
|
12527
|
+
const startTime = getCurrentUnixTimestamp();
|
|
12528
|
+
const inputPromise = readBatchInputs(args[0].inputFileContent);
|
|
12529
|
+
const parentPromise = exportParent(args[0].parent);
|
|
12530
|
+
const file = await Reflect.apply(target, thisArg, args);
|
|
12531
|
+
try {
|
|
12532
|
+
const inputFileId = read(file, "id");
|
|
12533
|
+
const [inputData, exportedParent2] = await Promise.all([
|
|
12534
|
+
inputPromise,
|
|
12535
|
+
parentPromise
|
|
12536
|
+
]);
|
|
12537
|
+
if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
|
|
12538
|
+
if (inputData.issues[0]) {
|
|
12539
|
+
logBatchInstrumentationError(
|
|
12540
|
+
"skipped invalid input file",
|
|
12541
|
+
inputData.issues[0]
|
|
12542
|
+
);
|
|
12543
|
+
}
|
|
12544
|
+
return file;
|
|
12545
|
+
}
|
|
12546
|
+
const trace = {
|
|
12547
|
+
context: {
|
|
12548
|
+
inputFileId,
|
|
12549
|
+
endpoint: inputData.endpoint,
|
|
12550
|
+
parent: exportedParent2,
|
|
12551
|
+
taskStartTime: startTime,
|
|
12552
|
+
childStartTime: startTime
|
|
12553
|
+
},
|
|
12554
|
+
inputs: inputData.inputs
|
|
12555
|
+
};
|
|
12556
|
+
pendingBatchTraces.set(inputFileId, trace);
|
|
12557
|
+
await writePendingSpans(trace);
|
|
12558
|
+
} catch (error) {
|
|
12559
|
+
logBatchInstrumentationError("could not start batch spans", error);
|
|
12560
|
+
}
|
|
12561
|
+
return file;
|
|
12562
|
+
};
|
|
12563
|
+
function validTimestamp(value) {
|
|
12564
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
12565
|
+
}
|
|
12566
|
+
function terminalEndTime(batch, startTime) {
|
|
12567
|
+
let timestamp;
|
|
12568
|
+
switch (batch.status) {
|
|
12569
|
+
case "completed":
|
|
12570
|
+
timestamp = batch.completed_at;
|
|
12571
|
+
break;
|
|
12572
|
+
case "failed":
|
|
12573
|
+
timestamp = batch.failed_at;
|
|
12574
|
+
break;
|
|
12575
|
+
case "expired":
|
|
12576
|
+
timestamp = batch.expired_at;
|
|
12577
|
+
break;
|
|
12578
|
+
default:
|
|
12579
|
+
timestamp = batch.cancelled_at;
|
|
12580
|
+
}
|
|
12581
|
+
return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
|
|
12582
|
+
}
|
|
12583
|
+
async function updateBatchTimestamps(batch) {
|
|
12584
|
+
const trace = pendingBatchTraces.get(batch.input_file_id);
|
|
12585
|
+
if (!trace || trace.context.endpoint !== batch.endpoint) {
|
|
12586
|
+
return;
|
|
12587
|
+
}
|
|
12588
|
+
if (validTimestamp(batch.created_at)) {
|
|
12589
|
+
trace.context.taskStartTime = batch.created_at;
|
|
12590
|
+
}
|
|
12591
|
+
trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
|
|
12592
|
+
trace.status = batch.status;
|
|
12593
|
+
if (TERMINAL_STATUSES.has(batch.status)) {
|
|
12594
|
+
trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
|
|
12595
|
+
}
|
|
12596
|
+
await writePendingSpans(trace, trace.endTime);
|
|
12597
|
+
}
|
|
12598
|
+
var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
|
|
12599
|
+
try {
|
|
12600
|
+
await updateBatchTimestamps(batch);
|
|
12601
|
+
} catch (error) {
|
|
12602
|
+
logBatchInstrumentationError("could not update batch timestamps", error);
|
|
12603
|
+
}
|
|
12604
|
+
return batch;
|
|
12605
|
+
});
|
|
12606
|
+
function errorFromResult(result) {
|
|
12607
|
+
const error = read(result.value, "error");
|
|
12608
|
+
if (isObject(error)) {
|
|
12609
|
+
const message = read(error, "message");
|
|
12610
|
+
return new Error(
|
|
12611
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
12612
|
+
);
|
|
12613
|
+
}
|
|
12614
|
+
const response = read(result.value, "response");
|
|
12615
|
+
const statusCode = read(response, "status_code");
|
|
12616
|
+
if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
|
|
12617
|
+
const message = read(read(read(response, "body"), "error"), "message");
|
|
12618
|
+
return new Error(
|
|
12619
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
12620
|
+
);
|
|
12621
|
+
}
|
|
12622
|
+
return void 0;
|
|
12623
|
+
}
|
|
12624
|
+
async function completeBatchResult(context, taskParent, endTime, input, result) {
|
|
12625
|
+
const child = await startBatchChild(context, taskParent, input);
|
|
12626
|
+
try {
|
|
12627
|
+
const resultError = errorFromResult(result);
|
|
12628
|
+
const responseBody = read(read(result.value, "response"), "body");
|
|
12629
|
+
if (resultError) {
|
|
12630
|
+
child.log({ error: resultError });
|
|
12631
|
+
} else if (isObject(responseBody)) {
|
|
12632
|
+
const model = read(responseBody, "model");
|
|
12633
|
+
child.log({
|
|
12634
|
+
output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
|
|
12635
|
+
...typeof model === "string" ? { metadata: { model } } : {},
|
|
12636
|
+
metrics: parseMetricsFromUsage(read(responseBody, "usage"))
|
|
12637
|
+
});
|
|
12638
|
+
} else {
|
|
12639
|
+
child.log({ error: new Error("OpenAI Batch response body is missing") });
|
|
12640
|
+
}
|
|
12641
|
+
} catch (error) {
|
|
12642
|
+
child.log({ error });
|
|
12643
|
+
} finally {
|
|
12644
|
+
child.end({ endTime });
|
|
12645
|
+
}
|
|
12646
|
+
}
|
|
12647
|
+
async function completeResultFile({
|
|
12648
|
+
context,
|
|
12649
|
+
endTime,
|
|
12650
|
+
file,
|
|
12651
|
+
inputs,
|
|
12652
|
+
issues,
|
|
12653
|
+
seen,
|
|
12654
|
+
source,
|
|
12655
|
+
taskParent
|
|
12656
|
+
}) {
|
|
12657
|
+
if (file === void 0) {
|
|
12658
|
+
return;
|
|
12659
|
+
}
|
|
12660
|
+
for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
|
|
12661
|
+
const customId = read(value, "custom_id");
|
|
12662
|
+
if (!validCustomId(customId) || !isObject(value)) {
|
|
12663
|
+
issues.push(
|
|
12664
|
+
new Error("OpenAI Batch result is missing a valid custom_id")
|
|
12665
|
+
);
|
|
12666
|
+
continue;
|
|
12667
|
+
}
|
|
12668
|
+
if (seen.has(customId)) {
|
|
12669
|
+
issues.push(new Error("OpenAI Batch result contains a duplicate"));
|
|
12670
|
+
continue;
|
|
12671
|
+
}
|
|
12672
|
+
const input = inputs.get(customId);
|
|
12673
|
+
if (!input) {
|
|
12674
|
+
issues.push(
|
|
12675
|
+
new Error("OpenAI Batch result does not match an input record")
|
|
12676
|
+
);
|
|
12677
|
+
continue;
|
|
12678
|
+
}
|
|
12679
|
+
seen.add(customId);
|
|
12680
|
+
await completeBatchResult(context, taskParent, endTime, input, {
|
|
12681
|
+
value,
|
|
12682
|
+
source
|
|
12683
|
+
});
|
|
12684
|
+
}
|
|
12685
|
+
}
|
|
12686
|
+
function sameInputs(first, second) {
|
|
12687
|
+
return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
|
|
12688
|
+
}
|
|
12689
|
+
async function contextForCompletion(inputFileId, inputData) {
|
|
12690
|
+
if (!inputData.endpoint || inputData.issues.length > 0) {
|
|
12691
|
+
return void 0;
|
|
12692
|
+
}
|
|
12693
|
+
const existing = pendingBatchTraces.get(inputFileId);
|
|
12694
|
+
if (existing) {
|
|
12695
|
+
if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
|
|
12696
|
+
return void 0;
|
|
12697
|
+
}
|
|
12698
|
+
return { ...existing, inputs: inputData.inputs };
|
|
12699
|
+
}
|
|
12700
|
+
const parent = await exportParent(getSpanParentObject());
|
|
12701
|
+
if (!parent) {
|
|
12702
|
+
return void 0;
|
|
12703
|
+
}
|
|
12704
|
+
const startTime = getCurrentUnixTimestamp();
|
|
12705
|
+
return {
|
|
12706
|
+
context: {
|
|
12707
|
+
inputFileId,
|
|
12708
|
+
endpoint: inputData.endpoint,
|
|
12709
|
+
parent,
|
|
12710
|
+
taskStartTime: startTime,
|
|
12711
|
+
childStartTime: startTime
|
|
12712
|
+
},
|
|
12713
|
+
inputs: inputData.inputs
|
|
12714
|
+
};
|
|
12715
|
+
}
|
|
12716
|
+
async function completeBatch(args) {
|
|
12717
|
+
const inputData = await readBatchInputs(args.inputFileContent);
|
|
12718
|
+
const trace = await contextForCompletion(args.inputFileId, inputData);
|
|
12719
|
+
if (!trace) {
|
|
12720
|
+
logBatchInstrumentationError(
|
|
12721
|
+
"left batch spans pending",
|
|
12722
|
+
inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
|
|
12723
|
+
);
|
|
12724
|
+
return;
|
|
12725
|
+
}
|
|
12726
|
+
const endTime = trace.endTime ?? getCurrentUnixTimestamp();
|
|
12727
|
+
const task = await startBatchSpan(trace.context);
|
|
12728
|
+
const taskParent = await task.export();
|
|
12729
|
+
const issues = [];
|
|
12730
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12731
|
+
await Promise.all([
|
|
12732
|
+
completeResultFile({
|
|
12733
|
+
context: trace.context,
|
|
12734
|
+
endTime,
|
|
12735
|
+
file: args.outputFileContent,
|
|
12736
|
+
inputs: trace.inputs,
|
|
12737
|
+
issues,
|
|
12738
|
+
seen,
|
|
12739
|
+
source: "output",
|
|
12740
|
+
taskParent
|
|
12741
|
+
}),
|
|
12742
|
+
completeResultFile({
|
|
12743
|
+
context: trace.context,
|
|
12744
|
+
endTime,
|
|
12745
|
+
file: args.errorFileContent,
|
|
12746
|
+
inputs: trace.inputs,
|
|
12747
|
+
issues,
|
|
12748
|
+
seen,
|
|
12749
|
+
source: "error",
|
|
12750
|
+
taskParent
|
|
12751
|
+
})
|
|
12752
|
+
]);
|
|
12753
|
+
if (issues.length > 0) {
|
|
12754
|
+
logBatchInstrumentationError("left batch spans pending", issues[0]);
|
|
12755
|
+
return;
|
|
12756
|
+
}
|
|
12757
|
+
const missing = [...trace.inputs.values()].filter(
|
|
12758
|
+
({ customId }) => !seen.has(customId)
|
|
12759
|
+
);
|
|
12760
|
+
if (!trace.status || trace.status === "completed") {
|
|
12761
|
+
if (missing.length > 0) {
|
|
12762
|
+
logBatchInstrumentationError(
|
|
12763
|
+
"left batch spans pending",
|
|
12764
|
+
new Error("OpenAI Batch result files are incomplete")
|
|
12765
|
+
);
|
|
12766
|
+
return;
|
|
12767
|
+
}
|
|
12768
|
+
} else {
|
|
12769
|
+
for (const input of missing) {
|
|
12770
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
12771
|
+
child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12772
|
+
child.end({ endTime });
|
|
12773
|
+
}
|
|
12774
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12775
|
+
}
|
|
12776
|
+
task.end({ endTime });
|
|
12777
|
+
pendingBatchTraces.delete(args.inputFileId);
|
|
12778
|
+
}
|
|
12779
|
+
var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
|
|
12780
|
+
try {
|
|
12781
|
+
await completeBatch(args[0]);
|
|
12782
|
+
} catch (error) {
|
|
12783
|
+
logBatchInstrumentationError("could not complete batch", error);
|
|
12784
|
+
}
|
|
12785
|
+
return result;
|
|
12786
|
+
});
|
|
12787
|
+
|
|
11388
12788
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
11389
12789
|
var OpenAIPlugin = class extends BasePlugin {
|
|
11390
12790
|
constructor() {
|
|
11391
12791
|
super();
|
|
11392
12792
|
}
|
|
11393
12793
|
onEnable() {
|
|
12794
|
+
this.unsubscribers.push(
|
|
12795
|
+
openAIChannels.filesCreateTraced.intercept(
|
|
12796
|
+
interceptOpenAIFilesCreateTraced
|
|
12797
|
+
),
|
|
12798
|
+
openAIChannels.batchesRetrieveTraced.intercept(
|
|
12799
|
+
interceptOpenAIBatchesRetrieveTraced
|
|
12800
|
+
),
|
|
12801
|
+
openAIChannels.batchesCompleteTrace.intercept(
|
|
12802
|
+
interceptOpenAIBatchTraceComplete
|
|
12803
|
+
)
|
|
12804
|
+
);
|
|
11394
12805
|
this.unsubscribers.push(
|
|
11395
12806
|
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
11396
12807
|
name: "Chat Completion",
|
|
11397
12808
|
type: "llm" /* LLM */,
|
|
11398
|
-
extractInput: ([params]) =>
|
|
11399
|
-
const { messages, ...metadata } = params;
|
|
11400
|
-
return {
|
|
11401
|
-
input: processInputAttachments(messages),
|
|
11402
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11403
|
-
};
|
|
11404
|
-
},
|
|
12809
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
11405
12810
|
extractOutput: (result) => {
|
|
11406
12811
|
return result?.choices;
|
|
11407
12812
|
},
|
|
@@ -11447,13 +12852,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11447
12852
|
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
11448
12853
|
name: "Chat Completion",
|
|
11449
12854
|
type: "llm" /* LLM */,
|
|
11450
|
-
extractInput: ([params]) =>
|
|
11451
|
-
const { messages, ...metadata } = params;
|
|
11452
|
-
return {
|
|
11453
|
-
input: processInputAttachments(messages),
|
|
11454
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11455
|
-
};
|
|
11456
|
-
},
|
|
12855
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
11457
12856
|
extractOutput: (result) => {
|
|
11458
12857
|
return result?.choices;
|
|
11459
12858
|
},
|
|
@@ -11475,13 +12874,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11475
12874
|
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
11476
12875
|
name: "Chat Completion",
|
|
11477
12876
|
type: "llm" /* LLM */,
|
|
11478
|
-
extractInput: ([params]) =>
|
|
11479
|
-
const { messages, ...metadata } = params;
|
|
11480
|
-
return {
|
|
11481
|
-
input: processInputAttachments(messages),
|
|
11482
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11483
|
-
};
|
|
11484
|
-
}
|
|
12877
|
+
extractInput: ([params]) => extractOpenAIChatInput(params)
|
|
11485
12878
|
})
|
|
11486
12879
|
);
|
|
11487
12880
|
this.unsubscribers.push(
|
|
@@ -11511,23 +12904,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11511
12904
|
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
11512
12905
|
name: "openai.responses.create",
|
|
11513
12906
|
type: "llm" /* LLM */,
|
|
11514
|
-
extractInput: ([params]) =>
|
|
11515
|
-
const { input, ...metadata } = params;
|
|
11516
|
-
return {
|
|
11517
|
-
input: processInputAttachments(input),
|
|
11518
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11519
|
-
};
|
|
11520
|
-
},
|
|
12907
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11521
12908
|
extractOutput: (result) => {
|
|
11522
12909
|
return processImagesInOutput(result?.output);
|
|
11523
12910
|
},
|
|
11524
|
-
extractMetadata: (result) =>
|
|
11525
|
-
if (!result) {
|
|
11526
|
-
return void 0;
|
|
11527
|
-
}
|
|
11528
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
11529
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11530
|
-
},
|
|
12911
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
11531
12912
|
extractMetrics: (result, startTime, endEvent) => {
|
|
11532
12913
|
const metrics = withCachedMetric(
|
|
11533
12914
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -11546,13 +12927,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11546
12927
|
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
11547
12928
|
name: "openai.responses.create",
|
|
11548
12929
|
type: "llm" /* LLM */,
|
|
11549
|
-
extractInput: ([params]) =>
|
|
11550
|
-
const { input, ...metadata } = params;
|
|
11551
|
-
return {
|
|
11552
|
-
input: processInputAttachments(input),
|
|
11553
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11554
|
-
};
|
|
11555
|
-
},
|
|
12930
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11556
12931
|
extractFromEvent: (event) => {
|
|
11557
12932
|
if (event.type !== "response.completed" || !event.response) {
|
|
11558
12933
|
return {};
|
|
@@ -11575,23 +12950,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11575
12950
|
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
11576
12951
|
name: "openai.responses.parse",
|
|
11577
12952
|
type: "llm" /* LLM */,
|
|
11578
|
-
extractInput: ([params]) =>
|
|
11579
|
-
const { input, ...metadata } = params;
|
|
11580
|
-
return {
|
|
11581
|
-
input: processInputAttachments(input),
|
|
11582
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11583
|
-
};
|
|
11584
|
-
},
|
|
12953
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11585
12954
|
extractOutput: (result) => {
|
|
11586
12955
|
return processImagesInOutput(result?.output);
|
|
11587
12956
|
},
|
|
11588
|
-
extractMetadata: (result) =>
|
|
11589
|
-
if (!result) {
|
|
11590
|
-
return void 0;
|
|
11591
|
-
}
|
|
11592
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
11593
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11594
|
-
},
|
|
12957
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
11595
12958
|
extractMetrics: (result, startTime, endEvent) => {
|
|
11596
12959
|
const metrics = withCachedMetric(
|
|
11597
12960
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -11610,23 +12973,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
11610
12973
|
traceAsyncChannel(openAIChannels.responsesCompact, {
|
|
11611
12974
|
name: "openai.responses.compact",
|
|
11612
12975
|
type: "llm" /* LLM */,
|
|
11613
|
-
extractInput: ([params]) =>
|
|
11614
|
-
const { input, ...metadata } = params;
|
|
11615
|
-
return {
|
|
11616
|
-
input: processInputAttachments(input),
|
|
11617
|
-
metadata: { ...metadata, provider: "openai" }
|
|
11618
|
-
};
|
|
11619
|
-
},
|
|
12976
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
11620
12977
|
extractOutput: (result) => {
|
|
11621
12978
|
return processImagesInOutput(result?.output);
|
|
11622
12979
|
},
|
|
11623
|
-
extractMetadata: (result) =>
|
|
11624
|
-
if (!result) {
|
|
11625
|
-
return void 0;
|
|
11626
|
-
}
|
|
11627
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
11628
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11629
|
-
},
|
|
12980
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
11630
12981
|
extractMetrics: (result, startTime, endEvent) => {
|
|
11631
12982
|
const metrics = withCachedMetric(
|
|
11632
12983
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -11682,35 +13033,6 @@ function withCachedMetric(metrics, result, endEvent) {
|
|
|
11682
13033
|
cached
|
|
11683
13034
|
};
|
|
11684
13035
|
}
|
|
11685
|
-
function processImagesInOutput(output) {
|
|
11686
|
-
if (Array.isArray(output)) {
|
|
11687
|
-
return output.map(processImagesInOutput);
|
|
11688
|
-
}
|
|
11689
|
-
if (isObject(output)) {
|
|
11690
|
-
if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
|
|
11691
|
-
const fileExtension = output.output_format || "png";
|
|
11692
|
-
const contentType = `image/${fileExtension}`;
|
|
11693
|
-
const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
11694
|
-
const filename = `${baseFilename}.${fileExtension}`;
|
|
11695
|
-
const binaryString = atob(output.result);
|
|
11696
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
11697
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
11698
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
11699
|
-
}
|
|
11700
|
-
const blob = new Blob([bytes], { type: contentType });
|
|
11701
|
-
const attachment = new Attachment({
|
|
11702
|
-
data: blob,
|
|
11703
|
-
filename,
|
|
11704
|
-
contentType
|
|
11705
|
-
});
|
|
11706
|
-
return {
|
|
11707
|
-
...output,
|
|
11708
|
-
result: attachment
|
|
11709
|
-
};
|
|
11710
|
-
}
|
|
11711
|
-
}
|
|
11712
|
-
return output;
|
|
11713
|
-
}
|
|
11714
13036
|
function mergeLogprobTokens(existing, incoming) {
|
|
11715
13037
|
if (incoming === void 0) {
|
|
11716
13038
|
return existing;
|
|
@@ -11741,13 +13063,33 @@ function aggregateChatLogprobs(existing, incoming) {
|
|
|
11741
13063
|
}
|
|
11742
13064
|
return aggregated;
|
|
11743
13065
|
}
|
|
13066
|
+
function createAggregatedChatChoice(index) {
|
|
13067
|
+
return {
|
|
13068
|
+
index,
|
|
13069
|
+
role: void 0,
|
|
13070
|
+
content: void 0,
|
|
13071
|
+
refusal: void 0,
|
|
13072
|
+
toolCallsByIndex: /* @__PURE__ */ new Map(),
|
|
13073
|
+
logprobs: void 0,
|
|
13074
|
+
finish_reason: void 0
|
|
13075
|
+
};
|
|
13076
|
+
}
|
|
13077
|
+
function toChatChoice(choice) {
|
|
13078
|
+
const toolCalls = Array.from(choice.toolCallsByIndex.entries()).sort(([left], [right]) => left - right).map(([, toolCall]) => toolCall);
|
|
13079
|
+
return {
|
|
13080
|
+
index: choice.index,
|
|
13081
|
+
message: {
|
|
13082
|
+
role: choice.role,
|
|
13083
|
+
content: choice.content,
|
|
13084
|
+
...choice.refusal !== void 0 ? { refusal: choice.refusal } : {},
|
|
13085
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
13086
|
+
},
|
|
13087
|
+
logprobs: choice.logprobs ?? null,
|
|
13088
|
+
finish_reason: choice.finish_reason
|
|
13089
|
+
};
|
|
13090
|
+
}
|
|
11744
13091
|
function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
|
|
11745
|
-
|
|
11746
|
-
let content = void 0;
|
|
11747
|
-
let refusal = void 0;
|
|
11748
|
-
let tool_calls = void 0;
|
|
11749
|
-
let logprobs = void 0;
|
|
11750
|
-
let finish_reason = void 0;
|
|
13092
|
+
const choicesByIndex = /* @__PURE__ */ new Map();
|
|
11751
13093
|
let metrics = {};
|
|
11752
13094
|
for (const chunk of chunks) {
|
|
11753
13095
|
if (chunk.usage) {
|
|
@@ -11756,62 +13098,75 @@ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
|
|
|
11756
13098
|
...parseMetricsFromUsage(chunk.usage)
|
|
11757
13099
|
};
|
|
11758
13100
|
}
|
|
11759
|
-
const
|
|
11760
|
-
if (!
|
|
11761
|
-
continue;
|
|
11762
|
-
}
|
|
11763
|
-
if (choice.finish_reason) {
|
|
11764
|
-
finish_reason = choice.finish_reason;
|
|
11765
|
-
}
|
|
11766
|
-
logprobs = aggregateChatLogprobs(logprobs, choice.logprobs);
|
|
11767
|
-
const delta = choice.delta;
|
|
11768
|
-
if (!delta) {
|
|
13101
|
+
const choices = chunk.choices;
|
|
13102
|
+
if (!choices?.length) {
|
|
11769
13103
|
continue;
|
|
11770
13104
|
}
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
|
|
11790
|
-
|
|
11791
|
-
|
|
13105
|
+
for (const choice of choices) {
|
|
13106
|
+
const choiceIndex = choice.index;
|
|
13107
|
+
let aggregatedChoice = choicesByIndex.get(choiceIndex);
|
|
13108
|
+
if (!aggregatedChoice) {
|
|
13109
|
+
aggregatedChoice = createAggregatedChatChoice(choiceIndex);
|
|
13110
|
+
choicesByIndex.set(choiceIndex, aggregatedChoice);
|
|
13111
|
+
}
|
|
13112
|
+
if (choice.finish_reason) {
|
|
13113
|
+
aggregatedChoice.finish_reason = choice.finish_reason;
|
|
13114
|
+
}
|
|
13115
|
+
aggregatedChoice.logprobs = aggregateChatLogprobs(
|
|
13116
|
+
aggregatedChoice.logprobs,
|
|
13117
|
+
choice.logprobs
|
|
13118
|
+
);
|
|
13119
|
+
const delta = choice.delta;
|
|
13120
|
+
if (!delta) {
|
|
13121
|
+
continue;
|
|
13122
|
+
}
|
|
13123
|
+
if (delta.finish_reason) {
|
|
13124
|
+
aggregatedChoice.finish_reason = delta.finish_reason;
|
|
13125
|
+
}
|
|
13126
|
+
if (!aggregatedChoice.role && delta.role) {
|
|
13127
|
+
aggregatedChoice.role = delta.role;
|
|
13128
|
+
}
|
|
13129
|
+
if (delta.content) {
|
|
13130
|
+
aggregatedChoice.content = (aggregatedChoice.content || "") + delta.content;
|
|
13131
|
+
}
|
|
13132
|
+
if (delta.refusal) {
|
|
13133
|
+
aggregatedChoice.refusal = (aggregatedChoice.refusal || "") + delta.refusal;
|
|
13134
|
+
}
|
|
13135
|
+
if (delta.tool_calls) {
|
|
13136
|
+
for (const toolDelta of delta.tool_calls) {
|
|
13137
|
+
let aggregatedToolCall = aggregatedChoice.toolCallsByIndex.get(
|
|
13138
|
+
toolDelta.index
|
|
13139
|
+
);
|
|
13140
|
+
if (!aggregatedToolCall) {
|
|
13141
|
+
aggregatedToolCall = {
|
|
13142
|
+
function: { arguments: "" }
|
|
13143
|
+
};
|
|
13144
|
+
aggregatedChoice.toolCallsByIndex.set(
|
|
13145
|
+
toolDelta.index,
|
|
13146
|
+
aggregatedToolCall
|
|
13147
|
+
);
|
|
11792
13148
|
}
|
|
11793
|
-
|
|
11794
|
-
|
|
11795
|
-
|
|
13149
|
+
if (toolDelta.id !== void 0) {
|
|
13150
|
+
aggregatedToolCall.id = toolDelta.id;
|
|
13151
|
+
}
|
|
13152
|
+
if (toolDelta.type !== void 0) {
|
|
13153
|
+
aggregatedToolCall.type = toolDelta.type;
|
|
13154
|
+
}
|
|
13155
|
+
if (toolDelta.function?.name !== void 0) {
|
|
13156
|
+
aggregatedToolCall.function.name = toolDelta.function.name;
|
|
13157
|
+
}
|
|
13158
|
+
if (toolDelta.function?.arguments !== void 0) {
|
|
13159
|
+
aggregatedToolCall.function.arguments += toolDelta.function.arguments;
|
|
13160
|
+
}
|
|
13161
|
+
}
|
|
11796
13162
|
}
|
|
11797
13163
|
}
|
|
11798
13164
|
}
|
|
11799
13165
|
metrics = withCachedMetric(metrics, streamResult, endEvent);
|
|
13166
|
+
const output = Array.from(choicesByIndex.values()).sort((left, right) => left.index - right.index).map(toChatChoice);
|
|
11800
13167
|
return {
|
|
11801
13168
|
metrics,
|
|
11802
|
-
output: [
|
|
11803
|
-
{
|
|
11804
|
-
index: 0,
|
|
11805
|
-
message: {
|
|
11806
|
-
role,
|
|
11807
|
-
content,
|
|
11808
|
-
...refusal !== void 0 ? { refusal } : {},
|
|
11809
|
-
tool_calls
|
|
11810
|
-
},
|
|
11811
|
-
logprobs: logprobs ?? null,
|
|
11812
|
-
finish_reason
|
|
11813
|
-
}
|
|
11814
|
-
]
|
|
13169
|
+
output: output.length > 0 ? output : [toChatChoice(createAggregatedChatChoice(0))]
|
|
11815
13170
|
};
|
|
11816
13171
|
}
|
|
11817
13172
|
function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
|
|
@@ -13134,6 +14489,12 @@ function parseMetricsFromUsage2(usage) {
|
|
|
13134
14489
|
}
|
|
13135
14490
|
}
|
|
13136
14491
|
}
|
|
14492
|
+
if (isObject(usage.output_tokens_details)) {
|
|
14493
|
+
const thinkingTokens = usage.output_tokens_details.thinking_tokens;
|
|
14494
|
+
if (typeof thinkingTokens === "number") {
|
|
14495
|
+
metrics.completion_reasoning_tokens = thinkingTokens;
|
|
14496
|
+
}
|
|
14497
|
+
}
|
|
13137
14498
|
if (isObject(usage.server_tool_use)) {
|
|
13138
14499
|
for (const [name, value] of Object.entries(usage.server_tool_use)) {
|
|
13139
14500
|
if (typeof value === "number") {
|
|
@@ -14090,7 +15451,6 @@ function endHarnessTurn(parent) {
|
|
|
14090
15451
|
function braintrustAISDKTelemetry() {
|
|
14091
15452
|
const operations = /* @__PURE__ */ new Map();
|
|
14092
15453
|
const operationKeysByCallId = /* @__PURE__ */ new Map();
|
|
14093
|
-
const workflowOperationKeyStore = isomorph_default.newAsyncLocalStorage();
|
|
14094
15454
|
const modelSpans = /* @__PURE__ */ new Map();
|
|
14095
15455
|
const objectSpans = /* @__PURE__ */ new Map();
|
|
14096
15456
|
const embedSpans = /* @__PURE__ */ new Map();
|
|
@@ -14133,9 +15493,6 @@ function braintrustAISDKTelemetry() {
|
|
|
14133
15493
|
return;
|
|
14134
15494
|
}
|
|
14135
15495
|
operations.delete(operationKey);
|
|
14136
|
-
if (workflowOperationKeyStore.getStore() === operationKey) {
|
|
14137
|
-
workflowOperationKeyStore.enterWith(void 0);
|
|
14138
|
-
}
|
|
14139
15496
|
const keys = operationKeysByCallId.get(state.callId);
|
|
14140
15497
|
if (!keys) {
|
|
14141
15498
|
return;
|
|
@@ -14183,14 +15540,7 @@ function braintrustAISDKTelemetry() {
|
|
|
14183
15540
|
return key;
|
|
14184
15541
|
}
|
|
14185
15542
|
}
|
|
14186
|
-
|
|
14187
|
-
if (workflowOperationKey && keys.includes(workflowOperationKey)) {
|
|
14188
|
-
return workflowOperationKey;
|
|
14189
|
-
}
|
|
14190
|
-
if (callId === "workflow-agent") {
|
|
14191
|
-
return void 0;
|
|
14192
|
-
}
|
|
14193
|
-
return mode === "finish" ? keys[0] : keys[keys.length - 1];
|
|
15543
|
+
return callId === "workflow-agent" || mode === "active" ? keys[keys.length - 1] : keys[0];
|
|
14194
15544
|
};
|
|
14195
15545
|
const operationKeyFromEvent = (event, mode = "active") => {
|
|
14196
15546
|
const explicit = explicitOperationKey(event);
|
|
@@ -14204,17 +15554,13 @@ function braintrustAISDKTelemetry() {
|
|
|
14204
15554
|
if (operationKey) {
|
|
14205
15555
|
return operationKey;
|
|
14206
15556
|
}
|
|
14207
|
-
const
|
|
14208
|
-
if (
|
|
14209
|
-
return
|
|
15557
|
+
const workflowAgentKeys2 = operationKeysByCallId.get("workflow-agent");
|
|
15558
|
+
if (workflowAgentKeys2?.length) {
|
|
15559
|
+
return workflowAgentKeys2[workflowAgentKeys2.length - 1];
|
|
14210
15560
|
}
|
|
14211
15561
|
return callId === "workflow-agent" ? void 0 : callId;
|
|
14212
15562
|
}
|
|
14213
15563
|
}
|
|
14214
|
-
const workflowOperationKey = workflowOperationKeyStore.getStore();
|
|
14215
|
-
if (workflowOperationKey && operations.has(workflowOperationKey)) {
|
|
14216
|
-
return workflowOperationKey;
|
|
14217
|
-
}
|
|
14218
15564
|
const wrapperSpan = currentWorkflowAgentWrapperSpan();
|
|
14219
15565
|
if (wrapperSpan?.spanId) {
|
|
14220
15566
|
for (const [operationKey, state] of operations) {
|
|
@@ -14224,8 +15570,8 @@ function braintrustAISDKTelemetry() {
|
|
|
14224
15570
|
}
|
|
14225
15571
|
}
|
|
14226
15572
|
const workflowAgentKeys = operationKeysByCallId.get("workflow-agent");
|
|
14227
|
-
if (workflowAgentKeys?.length
|
|
14228
|
-
return workflowAgentKeys[
|
|
15573
|
+
if (workflowAgentKeys?.length) {
|
|
15574
|
+
return workflowAgentKeys[workflowAgentKeys.length - 1];
|
|
14229
15575
|
}
|
|
14230
15576
|
if (operations.size === 1) {
|
|
14231
15577
|
return operations.keys().next().value;
|
|
@@ -14428,9 +15774,6 @@ function braintrustAISDKTelemetry() {
|
|
|
14428
15774
|
if (!ownsSpan) {
|
|
14429
15775
|
return;
|
|
14430
15776
|
}
|
|
14431
|
-
if (workflowAgent) {
|
|
14432
|
-
workflowOperationKeyStore.enterWith(operationKey);
|
|
14433
|
-
}
|
|
14434
15777
|
let metadata = metadataFromEvent(event);
|
|
14435
15778
|
const logPayload = { metadata };
|
|
14436
15779
|
const workflowAgentCallInput = workflowAgent ? operationInput(event, operationName) : void 0;
|
|
@@ -14902,6 +16245,10 @@ var aiSDKChannels = defineChannels(
|
|
|
14902
16245
|
channelName: "generateText",
|
|
14903
16246
|
kind: "async"
|
|
14904
16247
|
}),
|
|
16248
|
+
generateImage: channel({
|
|
16249
|
+
channelName: "generateImage",
|
|
16250
|
+
kind: "async"
|
|
16251
|
+
}),
|
|
14905
16252
|
streamText: channel({
|
|
14906
16253
|
channelName: "streamText",
|
|
14907
16254
|
kind: "async"
|
|
@@ -15089,7 +16436,7 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
15089
16436
|
}
|
|
15090
16437
|
subscribeToAISDK() {
|
|
15091
16438
|
const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
|
|
15092
|
-
this.unsubscribers.push(
|
|
16439
|
+
this.unsubscribers.push(interceptAISDKV7TelemetryDispatcher());
|
|
15093
16440
|
this.unsubscribers.push(subscribeToHarnessAgentCreateSession());
|
|
15094
16441
|
this.unsubscribers.push(
|
|
15095
16442
|
subscribeToHarnessContinuation(
|
|
@@ -15117,6 +16464,18 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
15117
16464
|
aggregateChunks: aggregateAISDKChunks
|
|
15118
16465
|
})
|
|
15119
16466
|
);
|
|
16467
|
+
this.unsubscribers.push(
|
|
16468
|
+
traceAsyncChannel(aiSDKChannels.generateImage, {
|
|
16469
|
+
name: "generateImage",
|
|
16470
|
+
type: "llm" /* LLM */,
|
|
16471
|
+
extractInput: ([params], event) => prepareAISDKGenerateImageInput(params, event.self),
|
|
16472
|
+
extractOutput: (result, endEvent) => processAISDKGenerateImageOutput(
|
|
16473
|
+
result,
|
|
16474
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
16475
|
+
),
|
|
16476
|
+
extractMetrics: (result) => extractTokenMetrics(result)
|
|
16477
|
+
})
|
|
16478
|
+
);
|
|
15120
16479
|
this.unsubscribers.push(
|
|
15121
16480
|
traceStreamingChannel(aiSDKChannels.streamText, {
|
|
15122
16481
|
name: "streamText",
|
|
@@ -15606,26 +16965,29 @@ function subscribeToHarnessContinuation(continuationChannel, defaultDenyOutputPa
|
|
|
15606
16965
|
channel2.unsubscribe(handlers);
|
|
15607
16966
|
};
|
|
15608
16967
|
}
|
|
15609
|
-
function
|
|
15610
|
-
const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
|
|
16968
|
+
function interceptAISDKV7TelemetryDispatcher() {
|
|
15611
16969
|
const telemetry = braintrustAISDKTelemetry();
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
const
|
|
15615
|
-
|
|
15616
|
-
|
|
16970
|
+
return aiSDKChannels.v7CreateTelemetryDispatcher.intercept(
|
|
16971
|
+
(target, thisArg, args) => {
|
|
16972
|
+
const dispatcher = Reflect.apply(target, thisArg, args);
|
|
16973
|
+
const telemetryOptions = args[0]?.telemetry;
|
|
16974
|
+
if (telemetryOptions?.isEnabled !== false) {
|
|
16975
|
+
try {
|
|
16976
|
+
patchAISDKV7TelemetryDispatcher(
|
|
16977
|
+
dispatcher,
|
|
16978
|
+
telemetry,
|
|
16979
|
+
telemetryOptions
|
|
16980
|
+
);
|
|
16981
|
+
} catch (error) {
|
|
16982
|
+
debugLogger.error(
|
|
16983
|
+
"Error instrumenting AI SDK v7 telemetry dispatcher:",
|
|
16984
|
+
error
|
|
16985
|
+
);
|
|
16986
|
+
}
|
|
15617
16987
|
}
|
|
15618
|
-
|
|
15619
|
-
event.result,
|
|
15620
|
-
telemetry,
|
|
15621
|
-
telemetryOptions
|
|
15622
|
-
);
|
|
16988
|
+
return dispatcher;
|
|
15623
16989
|
}
|
|
15624
|
-
|
|
15625
|
-
channel2.subscribe(handlers);
|
|
15626
|
-
return () => {
|
|
15627
|
-
channel2.unsubscribe(handlers);
|
|
15628
|
-
};
|
|
16990
|
+
);
|
|
15629
16991
|
}
|
|
15630
16992
|
function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry, telemetryOptions) {
|
|
15631
16993
|
if (!isObject(dispatcher)) {
|
|
@@ -15950,16 +17312,10 @@ var convertImageToAttachment = (image, explicitMimeType) => {
|
|
|
15950
17312
|
}
|
|
15951
17313
|
}
|
|
15952
17314
|
if (explicitMimeType) {
|
|
15953
|
-
|
|
17315
|
+
const blob = convertDataToBlob(image, explicitMimeType);
|
|
17316
|
+
if (blob) {
|
|
15954
17317
|
return new Attachment({
|
|
15955
|
-
data:
|
|
15956
|
-
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
15957
|
-
contentType: explicitMimeType
|
|
15958
|
-
});
|
|
15959
|
-
}
|
|
15960
|
-
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
15961
|
-
return new Attachment({
|
|
15962
|
-
data: new Blob([image], { type: explicitMimeType }),
|
|
17318
|
+
data: blob,
|
|
15963
17319
|
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
15964
17320
|
contentType: explicitMimeType
|
|
15965
17321
|
});
|
|
@@ -16013,6 +17369,25 @@ var convertDataToAttachment = (data, mimeType, filename) => {
|
|
|
16013
17369
|
function processAISDKCallInput(params) {
|
|
16014
17370
|
return processInputAttachmentsSync(params);
|
|
16015
17371
|
}
|
|
17372
|
+
function processAISDKGenerateImageInput(params) {
|
|
17373
|
+
const prompt = params.prompt;
|
|
17374
|
+
if (!isObject(prompt) || Array.isArray(prompt)) {
|
|
17375
|
+
return processAISDKCallInput(params);
|
|
17376
|
+
}
|
|
17377
|
+
const processedPrompt = { ...prompt };
|
|
17378
|
+
if (Array.isArray(prompt.images)) {
|
|
17379
|
+
processedPrompt.images = prompt.images.map(
|
|
17380
|
+
(image) => convertImageToAttachment(image, "image/png") ?? image
|
|
17381
|
+
);
|
|
17382
|
+
}
|
|
17383
|
+
if (prompt.mask !== void 0) {
|
|
17384
|
+
processedPrompt.mask = convertImageToAttachment(prompt.mask, "image/png") ?? prompt.mask;
|
|
17385
|
+
}
|
|
17386
|
+
return processAISDKCallInput({
|
|
17387
|
+
...params,
|
|
17388
|
+
prompt: processedPrompt
|
|
17389
|
+
});
|
|
17390
|
+
}
|
|
16016
17391
|
function processAISDKWorkflowAgentCallInput(params) {
|
|
16017
17392
|
const processed = processAISDKCallInput(params);
|
|
16018
17393
|
return {
|
|
@@ -16151,6 +17526,12 @@ function prepareAISDKEmbedInput(params, self) {
|
|
|
16151
17526
|
metadata: extractMetadataFromEmbedParams(params, self)
|
|
16152
17527
|
};
|
|
16153
17528
|
}
|
|
17529
|
+
function prepareAISDKGenerateImageInput(params, self) {
|
|
17530
|
+
return {
|
|
17531
|
+
input: processAISDKGenerateImageInput(params).input,
|
|
17532
|
+
metadata: extractMetadataFromCallParams(params, self)
|
|
17533
|
+
};
|
|
17534
|
+
}
|
|
16154
17535
|
function prepareAISDKRerankInput(params, self) {
|
|
16155
17536
|
const { documents, query } = params;
|
|
16156
17537
|
return {
|
|
@@ -17526,6 +18907,57 @@ function processAISDKOutput(output, denyOutputPaths) {
|
|
|
17526
18907
|
}
|
|
17527
18908
|
return normalizeAISDKLoggedOutput(sanitized);
|
|
17528
18909
|
}
|
|
18910
|
+
function processAISDKGenerateImageOutput(output, denyOutputPaths) {
|
|
18911
|
+
if (!output || typeof output !== "object") {
|
|
18912
|
+
return output;
|
|
18913
|
+
}
|
|
18914
|
+
const summarized = {};
|
|
18915
|
+
for (const field of [
|
|
18916
|
+
"usage",
|
|
18917
|
+
"warnings",
|
|
18918
|
+
"providerMetadata",
|
|
18919
|
+
"experimental_providerMetadata",
|
|
18920
|
+
"responses"
|
|
18921
|
+
]) {
|
|
18922
|
+
const value = safeSerializableFieldRead(output, field);
|
|
18923
|
+
if (value !== void 0 && isSerializableOutputValue(value)) {
|
|
18924
|
+
summarized[field] = value;
|
|
18925
|
+
}
|
|
18926
|
+
}
|
|
18927
|
+
const images = safeSerializableFieldRead(output, "images");
|
|
18928
|
+
const image = safeSerializableFieldRead(output, "image");
|
|
18929
|
+
const generatedFiles = Array.isArray(images) && images.length > 0 ? images : image !== void 0 ? [image] : [];
|
|
18930
|
+
const loggedOutput = normalizeAISDKLoggedOutput(
|
|
18931
|
+
omit(summarized, denyOutputPaths)
|
|
18932
|
+
);
|
|
18933
|
+
if (generatedFiles.length > 0) {
|
|
18934
|
+
loggedOutput.images = generatedFiles.map(
|
|
18935
|
+
(file, index) => convertAISDKGeneratedFileToAttachment(file, index)
|
|
18936
|
+
);
|
|
18937
|
+
}
|
|
18938
|
+
return loggedOutput;
|
|
18939
|
+
}
|
|
18940
|
+
function convertAISDKGeneratedFileToAttachment(file, index) {
|
|
18941
|
+
if (!file || typeof file !== "object") {
|
|
18942
|
+
return file;
|
|
18943
|
+
}
|
|
18944
|
+
const generatedFile = file;
|
|
18945
|
+
const generatedMediaType = safeSerializableFieldRead(
|
|
18946
|
+
generatedFile,
|
|
18947
|
+
"mediaType"
|
|
18948
|
+
);
|
|
18949
|
+
const mediaType = typeof generatedMediaType === "string" ? generatedMediaType : "application/octet-stream";
|
|
18950
|
+
const data = safeSerializableFieldRead(generatedFile, "base64") ?? safeSerializableFieldRead(generatedFile, "uint8Array");
|
|
18951
|
+
const blob = convertDataToBlob(data, mediaType);
|
|
18952
|
+
if (blob) {
|
|
18953
|
+
return new Attachment({
|
|
18954
|
+
data: blob,
|
|
18955
|
+
filename: `generated_image_${index}.${getExtensionFromMediaType(mediaType)}`,
|
|
18956
|
+
contentType: mediaType
|
|
18957
|
+
});
|
|
18958
|
+
}
|
|
18959
|
+
return file;
|
|
18960
|
+
}
|
|
17529
18961
|
function processAISDKEmbeddingOutput(output, denyOutputPaths) {
|
|
17530
18962
|
if (!output || typeof output !== "object") {
|
|
17531
18963
|
return output;
|
|
@@ -18026,118 +19458,22 @@ var claudeAgentSDKChannels = defineChannels(
|
|
|
18026
19458
|
var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
|
|
18027
19459
|
|
|
18028
19460
|
// src/instrumentation/plugins/claude-agent-sdk-local-tool-context.ts
|
|
18029
|
-
var
|
|
18030
|
-
|
|
18031
|
-
)
|
|
18032
|
-
|
|
18033
|
-
const maybeIsoWithAsyncLocalStorage = isomorph_default;
|
|
18034
|
-
if (typeof maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage === "function") {
|
|
18035
|
-
return maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage();
|
|
18036
|
-
}
|
|
18037
|
-
let currentStore;
|
|
18038
|
-
return {
|
|
18039
|
-
enterWith(store) {
|
|
18040
|
-
currentStore = store;
|
|
18041
|
-
},
|
|
18042
|
-
getStore() {
|
|
18043
|
-
return currentStore;
|
|
18044
|
-
},
|
|
18045
|
-
run(store, callback) {
|
|
18046
|
-
const previousStore = currentStore;
|
|
18047
|
-
currentStore = store;
|
|
18048
|
-
try {
|
|
18049
|
-
return callback();
|
|
18050
|
-
} finally {
|
|
18051
|
-
currentStore = previousStore;
|
|
18052
|
-
}
|
|
18053
|
-
}
|
|
18054
|
-
};
|
|
18055
|
-
}
|
|
18056
|
-
var localToolContextStore = createLocalToolContextStore();
|
|
18057
|
-
var fallbackLocalToolParentResolver;
|
|
18058
|
-
function createClaudeLocalToolContext() {
|
|
18059
|
-
return {};
|
|
18060
|
-
}
|
|
18061
|
-
function runWithClaudeLocalToolContext(callback, context) {
|
|
18062
|
-
return localToolContextStore.run(
|
|
18063
|
-
context ?? createClaudeLocalToolContext(),
|
|
18064
|
-
callback
|
|
18065
|
-
);
|
|
19461
|
+
var localToolContextStore = isomorph_default.newAsyncLocalStorage();
|
|
19462
|
+
var localToolParentResolversByToolUseId = /* @__PURE__ */ new Map();
|
|
19463
|
+
function runWithClaudeLocalToolContext(callback, resolver) {
|
|
19464
|
+
return localToolContextStore.run(resolver, callback);
|
|
18066
19465
|
}
|
|
18067
|
-
function
|
|
18068
|
-
|
|
18069
|
-
if (existing) {
|
|
18070
|
-
return existing;
|
|
18071
|
-
}
|
|
18072
|
-
const created = {};
|
|
18073
|
-
localToolContextStore.enterWith(created);
|
|
18074
|
-
return created;
|
|
18075
|
-
}
|
|
18076
|
-
function setClaudeLocalToolParentResolver(resolver) {
|
|
18077
|
-
fallbackLocalToolParentResolver = resolver;
|
|
18078
|
-
const context = ensureClaudeLocalToolContext();
|
|
18079
|
-
if (!context) {
|
|
18080
|
-
return;
|
|
18081
|
-
}
|
|
18082
|
-
context.resolveLocalToolParent = resolver;
|
|
18083
|
-
}
|
|
18084
|
-
function getClaudeLocalToolParentResolver() {
|
|
18085
|
-
return localToolContextStore.getStore()?.resolveLocalToolParent ?? fallbackLocalToolParentResolver;
|
|
18086
|
-
}
|
|
18087
|
-
function isAsyncIterable3(value) {
|
|
18088
|
-
return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
19466
|
+
function registerClaudeLocalToolParentResolver(toolUseId, resolver) {
|
|
19467
|
+
localToolParentResolversByToolUseId.set(toolUseId, resolver);
|
|
18089
19468
|
}
|
|
18090
|
-
function
|
|
18091
|
-
|
|
18092
|
-
|
|
18093
|
-
|
|
18094
|
-
const stream = result;
|
|
18095
|
-
const originalAsyncIterator = stream[Symbol.asyncIterator];
|
|
18096
|
-
if (originalAsyncIterator[LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED]) {
|
|
18097
|
-
return result;
|
|
19469
|
+
function getClaudeLocalToolParentResolver(toolUseId) {
|
|
19470
|
+
const currentResolver = localToolContextStore.getStore();
|
|
19471
|
+
if (!toolUseId) {
|
|
19472
|
+
return currentResolver;
|
|
18098
19473
|
}
|
|
18099
|
-
const
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
if (!iterator || typeof iterator !== "object") {
|
|
18103
|
-
return iterator;
|
|
18104
|
-
}
|
|
18105
|
-
const patchMethod = (methodName) => {
|
|
18106
|
-
const originalMethod = Reflect.get(iterator, methodName);
|
|
18107
|
-
if (typeof originalMethod !== "function") {
|
|
18108
|
-
return;
|
|
18109
|
-
}
|
|
18110
|
-
Reflect.set(
|
|
18111
|
-
iterator,
|
|
18112
|
-
methodName,
|
|
18113
|
-
(...args) => runWithClaudeLocalToolContext(
|
|
18114
|
-
() => Reflect.apply(
|
|
18115
|
-
originalMethod,
|
|
18116
|
-
iterator,
|
|
18117
|
-
args
|
|
18118
|
-
),
|
|
18119
|
-
localToolContext
|
|
18120
|
-
)
|
|
18121
|
-
);
|
|
18122
|
-
};
|
|
18123
|
-
patchMethod("next");
|
|
18124
|
-
patchMethod("return");
|
|
18125
|
-
patchMethod("throw");
|
|
18126
|
-
return iterator;
|
|
18127
|
-
}, localToolContext);
|
|
18128
|
-
};
|
|
18129
|
-
Object.defineProperty(
|
|
18130
|
-
patchedAsyncIterator,
|
|
18131
|
-
LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED,
|
|
18132
|
-
{
|
|
18133
|
-
configurable: false,
|
|
18134
|
-
enumerable: false,
|
|
18135
|
-
value: true,
|
|
18136
|
-
writable: false
|
|
18137
|
-
}
|
|
18138
|
-
);
|
|
18139
|
-
Reflect.set(stream, Symbol.asyncIterator, patchedAsyncIterator);
|
|
18140
|
-
return result;
|
|
19474
|
+
const registeredResolver = localToolParentResolversByToolUseId.get(toolUseId);
|
|
19475
|
+
localToolParentResolversByToolUseId.delete(toolUseId);
|
|
19476
|
+
return currentResolver ?? registeredResolver;
|
|
18141
19477
|
}
|
|
18142
19478
|
|
|
18143
19479
|
// src/instrumentation/plugins/claude-agent-sdk-local-tool-spans.ts
|
|
@@ -18163,7 +19499,7 @@ function wrapLocalClaudeToolHandler(handler, getMetadata) {
|
|
|
18163
19499
|
const metadata = getMetadata();
|
|
18164
19500
|
const rawToolName = metadata.serverName ? `mcp__${metadata.serverName}__${metadata.toolName}` : metadata.toolName;
|
|
18165
19501
|
const toolUseId = getToolUseIdFromExtra(handlerArgs[1]);
|
|
18166
|
-
const localToolParentResolver = getClaudeLocalToolParentResolver();
|
|
19502
|
+
const localToolParentResolver = getClaudeLocalToolParentResolver(toolUseId);
|
|
18167
19503
|
const spanName = metadata.serverName ? `tool: ${metadata.serverName}/${metadata.toolName}` : `tool: ${metadata.toolName}`;
|
|
18168
19504
|
const runWithResolvedParent = async () => {
|
|
18169
19505
|
const parent = toolUseId && localToolParentResolver ? await localToolParentResolver(toolUseId).catch(() => void 0) : void 0;
|
|
@@ -18690,6 +20026,7 @@ function createToolTracingHooks(resolveParentSpan, taskIdToToolUseId, toolUseToP
|
|
|
18690
20026
|
}
|
|
18691
20027
|
}
|
|
18692
20028
|
if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
|
|
20029
|
+
registerClaudeLocalToolParentResolver(toolUseID, resolveParentSpan);
|
|
18693
20030
|
return {};
|
|
18694
20031
|
}
|
|
18695
20032
|
const parsed = parseToolName(input.tool_name);
|
|
@@ -19400,7 +20737,7 @@ async function finalizeQuerySpan(state) {
|
|
|
19400
20737
|
}
|
|
19401
20738
|
var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
19402
20739
|
onEnable() {
|
|
19403
|
-
this.
|
|
20740
|
+
this.interceptQuery();
|
|
19404
20741
|
}
|
|
19405
20742
|
onDisable() {
|
|
19406
20743
|
for (const unsubscribe of this.unsubscribers) {
|
|
@@ -19408,211 +20745,218 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
19408
20745
|
}
|
|
19409
20746
|
this.unsubscribers = [];
|
|
19410
20747
|
}
|
|
19411
|
-
|
|
19412
|
-
const
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
|
|
19416
|
-
|
|
19417
|
-
|
|
19418
|
-
|
|
19419
|
-
|
|
19420
|
-
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19426
|
-
|
|
19427
|
-
|
|
19428
|
-
|
|
19429
|
-
|
|
19430
|
-
|
|
19431
|
-
try {
|
|
19432
|
-
for await (const message of promptStream) {
|
|
19433
|
-
capturedPromptMessages.push(message);
|
|
19434
|
-
yield message;
|
|
19435
|
-
}
|
|
19436
|
-
} finally {
|
|
19437
|
-
resolvePromptDone?.();
|
|
20748
|
+
interceptQuery() {
|
|
20749
|
+
const startQuery = (params) => {
|
|
20750
|
+
const originalPrompt = params.prompt;
|
|
20751
|
+
const options = params.options ?? {};
|
|
20752
|
+
const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
|
|
20753
|
+
let promptStarted = false;
|
|
20754
|
+
let capturedPromptMessages;
|
|
20755
|
+
let resolvePromptDone;
|
|
20756
|
+
const promptDone = new Promise((resolve) => {
|
|
20757
|
+
resolvePromptDone = resolve;
|
|
20758
|
+
});
|
|
20759
|
+
if (promptIsAsyncIterable) {
|
|
20760
|
+
capturedPromptMessages = [];
|
|
20761
|
+
const promptStream = originalPrompt;
|
|
20762
|
+
params.prompt = (async function* () {
|
|
20763
|
+
promptStarted = true;
|
|
20764
|
+
try {
|
|
20765
|
+
for await (const message of promptStream) {
|
|
20766
|
+
capturedPromptMessages.push(message);
|
|
20767
|
+
yield message;
|
|
19438
20768
|
}
|
|
19439
|
-
}
|
|
19440
|
-
|
|
19441
|
-
const span = startSpan(
|
|
19442
|
-
withSpanInstrumentationName(
|
|
19443
|
-
{
|
|
19444
|
-
name: "Claude Agent",
|
|
19445
|
-
spanAttributes: {
|
|
19446
|
-
type: "task" /* TASK */
|
|
19447
|
-
}
|
|
19448
|
-
},
|
|
19449
|
-
INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
|
|
19450
|
-
)
|
|
19451
|
-
);
|
|
19452
|
-
const startTime = getCurrentUnixTimestamp();
|
|
19453
|
-
try {
|
|
19454
|
-
span.log({
|
|
19455
|
-
input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
|
|
19456
|
-
metadata: filterSerializableOptions(options)
|
|
19457
|
-
});
|
|
19458
|
-
} catch (error) {
|
|
19459
|
-
console.error("Error extracting input for Claude Agent SDK:", error);
|
|
19460
|
-
}
|
|
19461
|
-
const activeToolSpans = /* @__PURE__ */ new Map();
|
|
19462
|
-
const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
|
|
19463
|
-
const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
|
|
19464
|
-
const subAgentSpans = /* @__PURE__ */ new Map();
|
|
19465
|
-
const endedSubAgentSpans = /* @__PURE__ */ new Set();
|
|
19466
|
-
const toolUseToParent = /* @__PURE__ */ new Map();
|
|
19467
|
-
const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
|
|
19468
|
-
const latestRootLlmParentRef = {
|
|
19469
|
-
value: void 0
|
|
19470
|
-
};
|
|
19471
|
-
const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
|
|
19472
|
-
const taskIdToToolUseId = /* @__PURE__ */ new Map();
|
|
19473
|
-
const promptMessagesByParentKey = /* @__PURE__ */ new Map();
|
|
19474
|
-
const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
|
|
19475
|
-
const localToolContext = createClaudeLocalToolContext();
|
|
19476
|
-
const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
|
|
19477
|
-
const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
|
|
19478
|
-
const resolveToolUseParentSpan = async (toolUseID, context) => {
|
|
19479
|
-
const trackedParentToolUseId = toolUseToParent.get(toolUseID);
|
|
19480
|
-
const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
|
|
19481
|
-
const parentKey = llmParentKey(parentToolUseId);
|
|
19482
|
-
const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
|
|
19483
|
-
const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
|
|
19484
|
-
if (!activeLlmSpan && !latestLlmParent) {
|
|
19485
|
-
await ensureActiveLlmSpanForParentToolUse(
|
|
19486
|
-
span,
|
|
19487
|
-
activeLlmSpansByParentToolUse,
|
|
19488
|
-
subAgentDetailsByToolUseId,
|
|
19489
|
-
activeToolSpans,
|
|
19490
|
-
subAgentSpans,
|
|
19491
|
-
parentToolUseId,
|
|
19492
|
-
getCurrentUnixTimestamp()
|
|
19493
|
-
);
|
|
19494
|
-
}
|
|
19495
|
-
if (parentToolUseId) {
|
|
19496
|
-
const subAgentSpan = await ensureSubAgentSpan(
|
|
19497
|
-
subAgentDetailsByToolUseId,
|
|
19498
|
-
span,
|
|
19499
|
-
activeToolSpans,
|
|
19500
|
-
subAgentSpans,
|
|
19501
|
-
parentToolUseId
|
|
19502
|
-
);
|
|
19503
|
-
return subAgentSpan.export();
|
|
20769
|
+
} finally {
|
|
20770
|
+
resolvePromptDone?.();
|
|
19504
20771
|
}
|
|
19505
|
-
|
|
19506
|
-
|
|
19507
|
-
|
|
19508
|
-
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
|
|
19512
|
-
|
|
19513
|
-
|
|
19514
|
-
|
|
19515
|
-
|
|
19516
|
-
|
|
19517
|
-
|
|
19518
|
-
|
|
19519
|
-
|
|
19520
|
-
|
|
19521
|
-
|
|
19522
|
-
|
|
19523
|
-
spans.set(event, {
|
|
19524
|
-
activeLlmSpansByParentToolUse,
|
|
19525
|
-
activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
|
|
19526
|
-
activeToolSpans,
|
|
19527
|
-
conversationHistoryByParentKey,
|
|
19528
|
-
capturedPromptMessages,
|
|
19529
|
-
currentMessageId: void 0,
|
|
19530
|
-
currentMessageStartTime: startTime,
|
|
19531
|
-
currentMessages: [],
|
|
19532
|
-
endedSubAgentSpans,
|
|
19533
|
-
finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
|
|
19534
|
-
finalResults: [],
|
|
19535
|
-
options: optionsWithHooks,
|
|
19536
|
-
originalPrompt,
|
|
19537
|
-
processing: Promise.resolve(),
|
|
19538
|
-
promptDone,
|
|
19539
|
-
promptMessagesByParentKey,
|
|
19540
|
-
promptStarted: () => promptStarted,
|
|
19541
|
-
promptSourcePriorityByParentKey,
|
|
19542
|
-
span,
|
|
19543
|
-
subAgentDetailsByToolUseId,
|
|
19544
|
-
subAgentSpans,
|
|
19545
|
-
taskIdToToolUseId,
|
|
19546
|
-
latestLlmParentBySubAgentToolUse,
|
|
19547
|
-
latestRootLlmParentRef,
|
|
19548
|
-
toolUseToParent,
|
|
19549
|
-
usageByMessageId: /* @__PURE__ */ new Map(),
|
|
19550
|
-
localToolContext
|
|
20772
|
+
})();
|
|
20773
|
+
}
|
|
20774
|
+
const span = startSpan(
|
|
20775
|
+
withSpanInstrumentationName(
|
|
20776
|
+
{
|
|
20777
|
+
name: "Claude Agent",
|
|
20778
|
+
spanAttributes: {
|
|
20779
|
+
type: "task" /* TASK */
|
|
20780
|
+
}
|
|
20781
|
+
},
|
|
20782
|
+
INSTRUMENTATION_NAMES.CLAUDE_AGENT_SDK
|
|
20783
|
+
)
|
|
20784
|
+
);
|
|
20785
|
+
const startTime = getCurrentUnixTimestamp();
|
|
20786
|
+
try {
|
|
20787
|
+
span.log({
|
|
20788
|
+
input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
|
|
20789
|
+
metadata: filterSerializableOptions(options)
|
|
19551
20790
|
});
|
|
19552
|
-
}
|
|
19553
|
-
|
|
19554
|
-
|
|
19555
|
-
|
|
19556
|
-
|
|
19557
|
-
|
|
19558
|
-
|
|
19559
|
-
|
|
19560
|
-
|
|
19561
|
-
|
|
19562
|
-
|
|
19563
|
-
|
|
19564
|
-
|
|
19565
|
-
|
|
19566
|
-
|
|
19567
|
-
|
|
19568
|
-
|
|
19569
|
-
|
|
19570
|
-
|
|
19571
|
-
|
|
19572
|
-
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
|
|
19576
|
-
|
|
19577
|
-
|
|
19578
|
-
|
|
19579
|
-
|
|
19580
|
-
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
|
|
19587
|
-
})
|
|
19588
|
-
});
|
|
19589
|
-
return;
|
|
19590
|
-
}
|
|
19591
|
-
try {
|
|
19592
|
-
state.span.log({ output: eventResult });
|
|
19593
|
-
} catch (error) {
|
|
19594
|
-
console.error("Error extracting output for Claude Agent SDK:", error);
|
|
19595
|
-
} finally {
|
|
19596
|
-
state.span.end();
|
|
19597
|
-
spans.delete(event);
|
|
20791
|
+
} catch (error) {
|
|
20792
|
+
console.error("Error extracting input for Claude Agent SDK:", error);
|
|
20793
|
+
}
|
|
20794
|
+
const activeToolSpans = /* @__PURE__ */ new Map();
|
|
20795
|
+
const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
|
|
20796
|
+
const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
|
|
20797
|
+
const subAgentSpans = /* @__PURE__ */ new Map();
|
|
20798
|
+
const endedSubAgentSpans = /* @__PURE__ */ new Set();
|
|
20799
|
+
const toolUseToParent = /* @__PURE__ */ new Map();
|
|
20800
|
+
const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
|
|
20801
|
+
const latestRootLlmParentRef = {
|
|
20802
|
+
value: void 0
|
|
20803
|
+
};
|
|
20804
|
+
const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
|
|
20805
|
+
const taskIdToToolUseId = /* @__PURE__ */ new Map();
|
|
20806
|
+
const promptMessagesByParentKey = /* @__PURE__ */ new Map();
|
|
20807
|
+
const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
|
|
20808
|
+
const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
|
|
20809
|
+
const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
|
|
20810
|
+
const resolveToolUseParentSpan = async (toolUseID, context) => {
|
|
20811
|
+
const trackedParentToolUseId = toolUseToParent.get(toolUseID);
|
|
20812
|
+
const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
|
|
20813
|
+
const parentKey = llmParentKey(parentToolUseId);
|
|
20814
|
+
const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
|
|
20815
|
+
const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
|
|
20816
|
+
if (!activeLlmSpan && !latestLlmParent) {
|
|
20817
|
+
await ensureActiveLlmSpanForParentToolUse(
|
|
20818
|
+
span,
|
|
20819
|
+
activeLlmSpansByParentToolUse,
|
|
20820
|
+
subAgentDetailsByToolUseId,
|
|
20821
|
+
activeToolSpans,
|
|
20822
|
+
subAgentSpans,
|
|
20823
|
+
parentToolUseId,
|
|
20824
|
+
getCurrentUnixTimestamp()
|
|
20825
|
+
);
|
|
19598
20826
|
}
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
20827
|
+
if (parentToolUseId) {
|
|
20828
|
+
const subAgentSpan = await ensureSubAgentSpan(
|
|
20829
|
+
subAgentDetailsByToolUseId,
|
|
20830
|
+
span,
|
|
20831
|
+
activeToolSpans,
|
|
20832
|
+
subAgentSpans,
|
|
20833
|
+
parentToolUseId
|
|
20834
|
+
);
|
|
20835
|
+
return subAgentSpan.export();
|
|
19604
20836
|
}
|
|
19605
|
-
|
|
19606
|
-
|
|
20837
|
+
return span.export();
|
|
20838
|
+
};
|
|
20839
|
+
const optionsWithHooks = injectTracingHooks(
|
|
20840
|
+
options,
|
|
20841
|
+
resolveToolUseParentSpan,
|
|
20842
|
+
taskIdToToolUseId,
|
|
20843
|
+
toolUseToParent,
|
|
20844
|
+
activeToolSpans,
|
|
20845
|
+
localToolHookNames,
|
|
20846
|
+
skipLocalToolHooks,
|
|
20847
|
+
subAgentDetailsByToolUseId,
|
|
20848
|
+
subAgentSpans,
|
|
20849
|
+
endedSubAgentSpans
|
|
20850
|
+
);
|
|
20851
|
+
params.options = optionsWithHooks;
|
|
20852
|
+
return {
|
|
20853
|
+
activeLlmSpansByParentToolUse,
|
|
20854
|
+
activePartialMessageIdByParentKey: /* @__PURE__ */ new Map(),
|
|
20855
|
+
activeToolSpans,
|
|
20856
|
+
conversationHistoryByParentKey,
|
|
20857
|
+
capturedPromptMessages,
|
|
20858
|
+
currentMessageId: void 0,
|
|
20859
|
+
currentMessageStartTime: startTime,
|
|
20860
|
+
currentMessages: [],
|
|
20861
|
+
endedSubAgentSpans,
|
|
20862
|
+
finalOutputUsageMessageIds: /* @__PURE__ */ new Set(),
|
|
20863
|
+
finalResults: [],
|
|
20864
|
+
options: optionsWithHooks,
|
|
20865
|
+
originalPrompt,
|
|
20866
|
+
processing: Promise.resolve(),
|
|
20867
|
+
promptDone,
|
|
20868
|
+
promptMessagesByParentKey,
|
|
20869
|
+
promptStarted: () => promptStarted,
|
|
20870
|
+
promptSourcePriorityByParentKey,
|
|
20871
|
+
span,
|
|
20872
|
+
subAgentDetailsByToolUseId,
|
|
20873
|
+
subAgentSpans,
|
|
20874
|
+
taskIdToToolUseId,
|
|
20875
|
+
latestLlmParentBySubAgentToolUse,
|
|
20876
|
+
latestRootLlmParentRef,
|
|
20877
|
+
toolUseToParent,
|
|
20878
|
+
usageByMessageId: /* @__PURE__ */ new Map(),
|
|
20879
|
+
localToolParentResolver: resolveToolUseParentSpan
|
|
20880
|
+
};
|
|
20881
|
+
};
|
|
20882
|
+
const finishQuery = (state, result) => {
|
|
20883
|
+
if (isAsyncIterable(result)) {
|
|
20884
|
+
patchStreamIfNeeded(result, {
|
|
20885
|
+
aroundNext: (callback) => runWithClaudeLocalToolContext(
|
|
20886
|
+
callback,
|
|
20887
|
+
state.localToolParentResolver
|
|
20888
|
+
),
|
|
20889
|
+
onChunk: (message) => {
|
|
20890
|
+
maybeTrackToolUseContext(state, message);
|
|
20891
|
+
state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
|
|
20892
|
+
console.error(
|
|
20893
|
+
"Error processing Claude Agent SDK stream chunk:",
|
|
20894
|
+
error
|
|
20895
|
+
);
|
|
20896
|
+
});
|
|
20897
|
+
},
|
|
20898
|
+
onComplete: () => state.processing.then(() => finalizeQuerySpan(state)),
|
|
20899
|
+
onError: (error) => state.processing.then(() => {
|
|
20900
|
+
state.span.log({ error: error.message });
|
|
20901
|
+
}).then(() => finalizeQuerySpan(state))
|
|
19607
20902
|
});
|
|
20903
|
+
return;
|
|
20904
|
+
}
|
|
20905
|
+
try {
|
|
20906
|
+
state.span.log({ output: result });
|
|
20907
|
+
} catch (error) {
|
|
20908
|
+
console.error("Error extracting output for Claude Agent SDK:", error);
|
|
20909
|
+
} finally {
|
|
19608
20910
|
state.span.end();
|
|
19609
|
-
spans.delete(event);
|
|
19610
20911
|
}
|
|
19611
20912
|
};
|
|
19612
|
-
|
|
19613
|
-
|
|
19614
|
-
|
|
19615
|
-
|
|
20913
|
+
this.unsubscribers.push(
|
|
20914
|
+
claudeAgentSDKChannels.query.intercept((target, thisArg, args) => {
|
|
20915
|
+
let state;
|
|
20916
|
+
try {
|
|
20917
|
+
args[0] ??= {};
|
|
20918
|
+
state = startQuery(args[0]);
|
|
20919
|
+
} catch (error) {
|
|
20920
|
+
debugLogger.error(
|
|
20921
|
+
"Error starting Claude Agent SDK instrumentation:",
|
|
20922
|
+
error
|
|
20923
|
+
);
|
|
20924
|
+
}
|
|
20925
|
+
const invokeTarget = () => Reflect.apply(target, thisArg, args);
|
|
20926
|
+
try {
|
|
20927
|
+
const result = state ? runWithClaudeLocalToolContext(
|
|
20928
|
+
invokeTarget,
|
|
20929
|
+
state.localToolParentResolver
|
|
20930
|
+
) : invokeTarget();
|
|
20931
|
+
if (state) {
|
|
20932
|
+
try {
|
|
20933
|
+
finishQuery(state, result);
|
|
20934
|
+
} catch (error) {
|
|
20935
|
+
debugLogger.error(
|
|
20936
|
+
"Error finalizing Claude Agent SDK instrumentation:",
|
|
20937
|
+
error
|
|
20938
|
+
);
|
|
20939
|
+
}
|
|
20940
|
+
}
|
|
20941
|
+
return result;
|
|
20942
|
+
} catch (error) {
|
|
20943
|
+
if (state) {
|
|
20944
|
+
try {
|
|
20945
|
+
state.span.log({
|
|
20946
|
+
error: error instanceof Error ? error.message : String(error)
|
|
20947
|
+
});
|
|
20948
|
+
state.span.end();
|
|
20949
|
+
} catch (instrumentationError) {
|
|
20950
|
+
debugLogger.error(
|
|
20951
|
+
"Error handling Claude Agent SDK instrumentation failure:",
|
|
20952
|
+
instrumentationError
|
|
20953
|
+
);
|
|
20954
|
+
}
|
|
20955
|
+
}
|
|
20956
|
+
throw error;
|
|
20957
|
+
}
|
|
20958
|
+
})
|
|
20959
|
+
);
|
|
19616
20960
|
}
|
|
19617
20961
|
};
|
|
19618
20962
|
|
|
@@ -23726,7 +25070,7 @@ function patchOpenRouterCallModelResult(args) {
|
|
|
23726
25070
|
span,
|
|
23727
25071
|
() => originalMethod.apply(resultLike, args2)
|
|
23728
25072
|
);
|
|
23729
|
-
if (!
|
|
25073
|
+
if (!isAsyncIterable3(stream)) {
|
|
23730
25074
|
return stream;
|
|
23731
25075
|
}
|
|
23732
25076
|
return wrapAsyncIterableWithSpan({
|
|
@@ -23921,7 +25265,7 @@ function wrapAsyncIterableWithSpan(args) {
|
|
|
23921
25265
|
}
|
|
23922
25266
|
};
|
|
23923
25267
|
}
|
|
23924
|
-
function
|
|
25268
|
+
function isAsyncIterable3(value) {
|
|
23925
25269
|
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
23926
25270
|
}
|
|
23927
25271
|
function normalizeError(error) {
|
|
@@ -24799,7 +26143,7 @@ function patchOpenRouterCallModelResult2(args) {
|
|
|
24799
26143
|
span,
|
|
24800
26144
|
() => originalMethod.apply(resultLike, args2)
|
|
24801
26145
|
);
|
|
24802
|
-
if (!
|
|
26146
|
+
if (!isAsyncIterable4(stream)) {
|
|
24803
26147
|
return stream;
|
|
24804
26148
|
}
|
|
24805
26149
|
return wrapAsyncIterableWithSpan2({
|
|
@@ -24994,7 +26338,7 @@ function wrapAsyncIterableWithSpan2(args) {
|
|
|
24994
26338
|
}
|
|
24995
26339
|
};
|
|
24996
26340
|
}
|
|
24997
|
-
function
|
|
26341
|
+
function isAsyncIterable4(value) {
|
|
24998
26342
|
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
24999
26343
|
}
|
|
25000
26344
|
function normalizeError2(error) {
|
|
@@ -30986,12 +32330,14 @@ function getMetricsFromResponse(response) {
|
|
|
30986
32330
|
continue;
|
|
30987
32331
|
}
|
|
30988
32332
|
const inputTokenDetails = usageMetadata.input_token_details;
|
|
32333
|
+
const outputTokenDetails = usageMetadata.output_token_details;
|
|
30989
32334
|
return normalizeTokenMetrics({
|
|
30990
32335
|
total_tokens: usageMetadata.total_tokens,
|
|
30991
32336
|
prompt_tokens: usageMetadata.input_tokens,
|
|
30992
32337
|
completion_tokens: usageMetadata.output_tokens,
|
|
30993
32338
|
prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
|
|
30994
|
-
prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
|
|
32339
|
+
prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
|
|
32340
|
+
completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
|
|
30995
32341
|
});
|
|
30996
32342
|
}
|
|
30997
32343
|
const llmOutput = response.llmOutput || {};
|
|
@@ -31578,6 +32924,9 @@ var piCodingAgentChannels = defineChannels(
|
|
|
31578
32924
|
// src/instrumentation/plugins/pi-coding-agent-plugin.ts
|
|
31579
32925
|
var piAgentPatchStates = /* @__PURE__ */ new WeakMap();
|
|
31580
32926
|
var piAgentEventSubscriptions = /* @__PURE__ */ new WeakSet();
|
|
32927
|
+
var PI_TOOL_EXECUTE_WRAPPED = /* @__PURE__ */ Symbol.for(
|
|
32928
|
+
"braintrust.pi_coding_agent.tool_execute_wrapped"
|
|
32929
|
+
);
|
|
31581
32930
|
var piPromptContextStore;
|
|
31582
32931
|
var PiCodingAgentPlugin = class extends BasePlugin {
|
|
31583
32932
|
activePromptStates = /* @__PURE__ */ new Set();
|
|
@@ -31658,6 +33007,7 @@ function startPiPromptRun(event, onFinalize) {
|
|
|
31658
33007
|
return void 0;
|
|
31659
33008
|
}
|
|
31660
33009
|
installPiAgentInstrumentation(agent);
|
|
33010
|
+
wrapPiToolExecutors(agent.state?.tools);
|
|
31661
33011
|
const metadata = {
|
|
31662
33012
|
...extractSessionMetadata(session),
|
|
31663
33013
|
...extractPromptOptionsMetadata(event.arguments[1]),
|
|
@@ -31702,7 +33052,7 @@ function extractSession(event) {
|
|
|
31702
33052
|
return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
|
|
31703
33053
|
}
|
|
31704
33054
|
function isPiAgent(value) {
|
|
31705
|
-
return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
|
|
33055
|
+
return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
|
|
31706
33056
|
}
|
|
31707
33057
|
function promptContextStore() {
|
|
31708
33058
|
piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
|
|
@@ -31712,17 +33062,21 @@ function currentPiPromptState() {
|
|
|
31712
33062
|
return promptContextStore().getStore();
|
|
31713
33063
|
}
|
|
31714
33064
|
function installPiAgentInstrumentation(agent) {
|
|
33065
|
+
const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
|
|
33066
|
+
const streamFunction = agent[property];
|
|
31715
33067
|
const existing = piAgentPatchStates.get(agent);
|
|
31716
|
-
if (!existing ||
|
|
33068
|
+
if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
|
|
31717
33069
|
const patchState = {
|
|
31718
|
-
|
|
31719
|
-
|
|
33070
|
+
originalStreamFunction: streamFunction,
|
|
33071
|
+
property,
|
|
33072
|
+
wrappedStreamFunction: streamFunction
|
|
31720
33073
|
};
|
|
31721
|
-
patchState.
|
|
33074
|
+
patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
|
|
31722
33075
|
agent,
|
|
31723
|
-
patchState.
|
|
33076
|
+
patchState.originalStreamFunction,
|
|
33077
|
+
property
|
|
31724
33078
|
);
|
|
31725
|
-
agent
|
|
33079
|
+
agent[property] = patchState.wrappedStreamFunction;
|
|
31726
33080
|
piAgentPatchStates.set(agent, patchState);
|
|
31727
33081
|
}
|
|
31728
33082
|
if (piAgentEventSubscriptions.has(agent)) {
|
|
@@ -31747,14 +33101,21 @@ function installPiAgentInstrumentation(agent) {
|
|
|
31747
33101
|
logInstrumentationError4("Pi Coding Agent event subscription", error);
|
|
31748
33102
|
}
|
|
31749
33103
|
}
|
|
31750
|
-
function
|
|
31751
|
-
return async function
|
|
31752
|
-
const invokeOriginal = () => Reflect.apply(
|
|
33104
|
+
function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
|
|
33105
|
+
return async function instrumentedPiStreamFunction(model, context, options) {
|
|
33106
|
+
const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
|
|
31753
33107
|
const state = currentPiPromptState();
|
|
31754
33108
|
if (!state || state.agent !== agent || state.finalized) {
|
|
31755
33109
|
return invokeOriginal();
|
|
31756
33110
|
}
|
|
31757
|
-
|
|
33111
|
+
wrapPiToolExecutors(context.tools);
|
|
33112
|
+
const llmState = await startPiLlmSpan(
|
|
33113
|
+
state,
|
|
33114
|
+
model,
|
|
33115
|
+
context,
|
|
33116
|
+
property,
|
|
33117
|
+
options
|
|
33118
|
+
);
|
|
31758
33119
|
try {
|
|
31759
33120
|
const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
|
|
31760
33121
|
return patchAssistantMessageStream(stream, state, llmState);
|
|
@@ -31764,12 +33125,39 @@ function makeInstrumentedStreamFn(agent, originalStreamFn) {
|
|
|
31764
33125
|
}
|
|
31765
33126
|
};
|
|
31766
33127
|
}
|
|
31767
|
-
|
|
33128
|
+
function wrapPiToolExecutors(tools) {
|
|
33129
|
+
if (!tools) {
|
|
33130
|
+
return;
|
|
33131
|
+
}
|
|
33132
|
+
for (const tool of tools) {
|
|
33133
|
+
try {
|
|
33134
|
+
const execute = tool.execute;
|
|
33135
|
+
if (typeof execute !== "function" || execute[PI_TOOL_EXECUTE_WRAPPED]) {
|
|
33136
|
+
continue;
|
|
33137
|
+
}
|
|
33138
|
+
const wrappedExecute = function(...args) {
|
|
33139
|
+
return runWithAutoInstrumentationAllowed(
|
|
33140
|
+
() => Reflect.apply(execute, this, args)
|
|
33141
|
+
);
|
|
33142
|
+
};
|
|
33143
|
+
Object.defineProperty(wrappedExecute, PI_TOOL_EXECUTE_WRAPPED, {
|
|
33144
|
+
configurable: false,
|
|
33145
|
+
enumerable: false,
|
|
33146
|
+
value: true,
|
|
33147
|
+
writable: false
|
|
33148
|
+
});
|
|
33149
|
+
tool.execute = wrappedExecute;
|
|
33150
|
+
} catch (error) {
|
|
33151
|
+
logInstrumentationError4("Pi Coding Agent tool wrapping", error);
|
|
33152
|
+
}
|
|
33153
|
+
}
|
|
33154
|
+
}
|
|
33155
|
+
async function startPiLlmSpan(state, model, context, property, options) {
|
|
31768
33156
|
const metadata = {
|
|
31769
33157
|
...extractModelMetadata2(model),
|
|
31770
33158
|
...extractStreamOptionsMetadata(options),
|
|
31771
33159
|
...extractToolMetadata(context.tools),
|
|
31772
|
-
"pi_coding_agent.operation":
|
|
33160
|
+
"pi_coding_agent.operation": `agent.${property}`
|
|
31773
33161
|
};
|
|
31774
33162
|
const span = startSpan(
|
|
31775
33163
|
withSpanInstrumentationName(
|
|
@@ -31935,35 +33323,26 @@ async function startPiToolSpan(state, event) {
|
|
|
31935
33323
|
if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
|
|
31936
33324
|
return;
|
|
31937
33325
|
}
|
|
31938
|
-
const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
|
|
31939
33326
|
const metadata = {
|
|
31940
33327
|
"gen_ai.tool.call.id": event.toolCallId,
|
|
31941
33328
|
"gen_ai.tool.name": event.toolName,
|
|
31942
33329
|
"pi_coding_agent.tool.name": event.toolName
|
|
31943
33330
|
};
|
|
31944
|
-
|
|
31945
|
-
|
|
31946
|
-
|
|
31947
|
-
{
|
|
31948
|
-
|
|
31949
|
-
|
|
31950
|
-
metadata
|
|
31951
|
-
},
|
|
31952
|
-
name: event.toolName || "tool",
|
|
31953
|
-
parent: await state.span.export(),
|
|
31954
|
-
spanAttributes: { type: "tool" /* TOOL */ }
|
|
33331
|
+
const span = startSpan(
|
|
33332
|
+
withSpanInstrumentationName(
|
|
33333
|
+
{
|
|
33334
|
+
event: {
|
|
33335
|
+
input: event.args,
|
|
33336
|
+
metadata
|
|
31955
33337
|
},
|
|
31956
|
-
|
|
31957
|
-
|
|
31958
|
-
|
|
31959
|
-
|
|
31960
|
-
|
|
31961
|
-
|
|
31962
|
-
|
|
31963
|
-
|
|
31964
|
-
restoreAutoInstrumentation();
|
|
31965
|
-
throw error;
|
|
31966
|
-
}
|
|
33338
|
+
name: event.toolName || "tool",
|
|
33339
|
+
parent: await state.span.export(),
|
|
33340
|
+
spanAttributes: { type: "tool" /* TOOL */ }
|
|
33341
|
+
},
|
|
33342
|
+
INSTRUMENTATION_NAMES.PI_CODING_AGENT
|
|
33343
|
+
)
|
|
33344
|
+
);
|
|
33345
|
+
state.activeToolSpans.set(event.toolCallId, { span });
|
|
31967
33346
|
}
|
|
31968
33347
|
function finishPiToolSpan(state, event) {
|
|
31969
33348
|
const toolState = state.activeToolSpans.get(event.toolCallId);
|
|
@@ -31984,11 +33363,7 @@ function finishPiToolSpan(state, event) {
|
|
|
31984
33363
|
output: event.result
|
|
31985
33364
|
});
|
|
31986
33365
|
} finally {
|
|
31987
|
-
|
|
31988
|
-
toolState.span.end();
|
|
31989
|
-
} finally {
|
|
31990
|
-
toolState.restoreAutoInstrumentation?.();
|
|
31991
|
-
}
|
|
33366
|
+
toolState.span.end();
|
|
31992
33367
|
}
|
|
31993
33368
|
}
|
|
31994
33369
|
function finishPiPromptRun(state, error) {
|
|
@@ -32038,10 +33413,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
|
|
|
32038
33413
|
...cleanMetrics5(llmState.metrics),
|
|
32039
33414
|
...buildDurationMetrics3(llmState.startTime)
|
|
32040
33415
|
};
|
|
32041
|
-
const
|
|
32042
|
-
if (Object.keys(
|
|
33416
|
+
const usageMetrics2 = extractUsageMetrics2(message?.usage);
|
|
33417
|
+
if (Object.keys(usageMetrics2).length > 0) {
|
|
32043
33418
|
promptState.collectedLlmUsageMetrics = true;
|
|
32044
|
-
addMetrics(promptState.metrics,
|
|
33419
|
+
addMetrics(promptState.metrics, usageMetrics2);
|
|
32045
33420
|
}
|
|
32046
33421
|
try {
|
|
32047
33422
|
safeLog4(llmState.span, {
|
|
@@ -32059,14 +33434,10 @@ function finishPiLlmSpan(promptState, llmState, message, error) {
|
|
|
32059
33434
|
}
|
|
32060
33435
|
function finishOpenToolSpans(state, error) {
|
|
32061
33436
|
for (const [, toolState] of state.activeToolSpans) {
|
|
32062
|
-
|
|
32063
|
-
|
|
32064
|
-
|
|
32065
|
-
|
|
32066
|
-
toolState.span.end();
|
|
32067
|
-
} finally {
|
|
32068
|
-
toolState.restoreAutoInstrumentation?.();
|
|
32069
|
-
}
|
|
33437
|
+
safeLog4(toolState.span, {
|
|
33438
|
+
error: error ? toLoggedError(error) : "Pi tool did not complete"
|
|
33439
|
+
});
|
|
33440
|
+
toolState.span.end();
|
|
32070
33441
|
}
|
|
32071
33442
|
state.activeToolSpans.clear();
|
|
32072
33443
|
}
|
|
@@ -32385,12 +33756,12 @@ var MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES = 32;
|
|
|
32385
33756
|
var StrandsAgentSDKPlugin = class extends BasePlugin {
|
|
32386
33757
|
activeChildParents = /* @__PURE__ */ new WeakMap();
|
|
32387
33758
|
onEnable() {
|
|
32388
|
-
this.
|
|
32389
|
-
this.
|
|
33759
|
+
this.interceptAgentStream();
|
|
33760
|
+
this.interceptMultiAgentStream(
|
|
32390
33761
|
strandsAgentSDKChannels.graphStream,
|
|
32391
33762
|
"Graph.stream"
|
|
32392
33763
|
);
|
|
32393
|
-
this.
|
|
33764
|
+
this.interceptMultiAgentStream(
|
|
32394
33765
|
strandsAgentSDKChannels.swarmStream,
|
|
32395
33766
|
"Swarm.stream"
|
|
32396
33767
|
);
|
|
@@ -32401,122 +33772,92 @@ var StrandsAgentSDKPlugin = class extends BasePlugin {
|
|
|
32401
33772
|
}
|
|
32402
33773
|
this.unsubscribers = [];
|
|
32403
33774
|
}
|
|
32404
|
-
|
|
32405
|
-
|
|
32406
|
-
|
|
32407
|
-
|
|
32408
|
-
|
|
32409
|
-
|
|
32410
|
-
|
|
32411
|
-
|
|
32412
|
-
|
|
32413
|
-
|
|
32414
|
-
|
|
32415
|
-
|
|
32416
|
-
|
|
32417
|
-
|
|
32418
|
-
|
|
32419
|
-
|
|
32420
|
-
const result = event.result;
|
|
32421
|
-
if (isAsyncIterable(result)) {
|
|
32422
|
-
patchStreamIfNeeded(result, {
|
|
32423
|
-
aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
|
|
32424
|
-
onChunk: (chunk) => handleAgentStreamEvent(state, chunk),
|
|
32425
|
-
onComplete: () => {
|
|
32426
|
-
finalizeAgentStream(state);
|
|
32427
|
-
states.delete(event);
|
|
32428
|
-
},
|
|
32429
|
-
onError: (error) => {
|
|
32430
|
-
finalizeAgentStream(state, error);
|
|
32431
|
-
states.delete(event);
|
|
32432
|
-
}
|
|
32433
|
-
});
|
|
32434
|
-
return;
|
|
32435
|
-
}
|
|
32436
|
-
finalizeAgentStream(state, void 0, result);
|
|
32437
|
-
states.delete(event);
|
|
32438
|
-
},
|
|
32439
|
-
error: (event) => {
|
|
32440
|
-
const state = states.get(event);
|
|
32441
|
-
if (!state || !event.error) {
|
|
32442
|
-
return;
|
|
32443
|
-
}
|
|
32444
|
-
finalizeAgentStream(state, event.error);
|
|
32445
|
-
states.delete(event);
|
|
32446
|
-
}
|
|
32447
|
-
};
|
|
32448
|
-
channel2.subscribe(handlers);
|
|
32449
|
-
this.unsubscribers.push(() => {
|
|
32450
|
-
unbindAutoInstrumentationSuppression?.();
|
|
32451
|
-
channel2.unsubscribe(handlers);
|
|
32452
|
-
});
|
|
33775
|
+
interceptAgentStream() {
|
|
33776
|
+
this.unsubscribers.push(
|
|
33777
|
+
strandsAgentSDKChannels.agentStream.intercept(
|
|
33778
|
+
(target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
|
|
33779
|
+
finalize: finalizeAgentStream,
|
|
33780
|
+
handleChunk: handleAgentStreamEvent,
|
|
33781
|
+
invoke: () => Reflect.apply(target, thisArg, args),
|
|
33782
|
+
name: "Strands Agent SDK",
|
|
33783
|
+
start: () => startAgentStream(
|
|
33784
|
+
args[0],
|
|
33785
|
+
extractAgent(additional.agent, thisArg),
|
|
33786
|
+
this.activeChildParents
|
|
33787
|
+
)
|
|
33788
|
+
})
|
|
33789
|
+
)
|
|
33790
|
+
);
|
|
32453
33791
|
}
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
|
|
32458
|
-
|
|
32459
|
-
|
|
32460
|
-
|
|
32461
|
-
|
|
32462
|
-
|
|
32463
|
-
|
|
32464
|
-
|
|
32465
|
-
|
|
32466
|
-
|
|
32467
|
-
|
|
32468
|
-
|
|
32469
|
-
|
|
32470
|
-
|
|
32471
|
-
|
|
32472
|
-
|
|
32473
|
-
}
|
|
32474
|
-
|
|
32475
|
-
|
|
32476
|
-
|
|
32477
|
-
|
|
32478
|
-
|
|
32479
|
-
|
|
32480
|
-
|
|
32481
|
-
|
|
32482
|
-
|
|
32483
|
-
|
|
32484
|
-
|
|
32485
|
-
|
|
32486
|
-
|
|
32487
|
-
|
|
32488
|
-
|
|
32489
|
-
|
|
32490
|
-
|
|
32491
|
-
|
|
32492
|
-
|
|
32493
|
-
|
|
32494
|
-
|
|
32495
|
-
|
|
32496
|
-
this.activeChildParents,
|
|
32497
|
-
void 0,
|
|
32498
|
-
result
|
|
33792
|
+
interceptMultiAgentStream(channel2, operation) {
|
|
33793
|
+
this.unsubscribers.push(
|
|
33794
|
+
channel2.intercept(
|
|
33795
|
+
(target, thisArg, args, additional) => instrumentStrandsStreamInvocation({
|
|
33796
|
+
finalize: (state, error, output) => finalizeMultiAgentStream(
|
|
33797
|
+
state,
|
|
33798
|
+
this.activeChildParents,
|
|
33799
|
+
error,
|
|
33800
|
+
output
|
|
33801
|
+
),
|
|
33802
|
+
handleChunk: (state, chunk) => handleMultiAgentStreamEvent(state, chunk, this.activeChildParents),
|
|
33803
|
+
invoke: () => Reflect.apply(target, thisArg, args),
|
|
33804
|
+
name: "Strands multi-agent",
|
|
33805
|
+
start: () => startMultiAgentStream(
|
|
33806
|
+
args[0],
|
|
33807
|
+
extractOrchestrator(additional.orchestrator, thisArg),
|
|
33808
|
+
operation,
|
|
33809
|
+
this.activeChildParents
|
|
33810
|
+
)
|
|
33811
|
+
})
|
|
33812
|
+
)
|
|
33813
|
+
);
|
|
33814
|
+
}
|
|
33815
|
+
};
|
|
33816
|
+
function instrumentStrandsStreamInvocation(options) {
|
|
33817
|
+
let state;
|
|
33818
|
+
try {
|
|
33819
|
+
state = options.start();
|
|
33820
|
+
} catch (error) {
|
|
33821
|
+
debugLogger.error(`Error starting ${options.name} instrumentation:`, error);
|
|
33822
|
+
}
|
|
33823
|
+
let result;
|
|
33824
|
+
try {
|
|
33825
|
+
result = runWithAutoInstrumentationSuppressed(options.invoke);
|
|
33826
|
+
} catch (error) {
|
|
33827
|
+
if (state) {
|
|
33828
|
+
try {
|
|
33829
|
+
options.finalize(state, error);
|
|
33830
|
+
} catch (instrumentationError) {
|
|
33831
|
+
debugLogger.error(
|
|
33832
|
+
`Error handling ${options.name} instrumentation failure:`,
|
|
33833
|
+
instrumentationError
|
|
32499
33834
|
);
|
|
32500
|
-
states.delete(event);
|
|
32501
|
-
},
|
|
32502
|
-
error: (event) => {
|
|
32503
|
-
const state = states.get(event);
|
|
32504
|
-
if (!state || !event.error) {
|
|
32505
|
-
return;
|
|
32506
|
-
}
|
|
32507
|
-
finalizeMultiAgentStream(state, this.activeChildParents, event.error);
|
|
32508
|
-
states.delete(event);
|
|
32509
33835
|
}
|
|
32510
|
-
}
|
|
32511
|
-
|
|
32512
|
-
this.unsubscribers.push(() => {
|
|
32513
|
-
unbindAutoInstrumentationSuppression?.();
|
|
32514
|
-
tracingChannel.unsubscribe(handlers);
|
|
32515
|
-
});
|
|
33836
|
+
}
|
|
33837
|
+
throw error;
|
|
32516
33838
|
}
|
|
32517
|
-
|
|
32518
|
-
|
|
32519
|
-
|
|
33839
|
+
if (state) {
|
|
33840
|
+
try {
|
|
33841
|
+
if (isAsyncIterable(result)) {
|
|
33842
|
+
patchStreamIfNeeded(result, {
|
|
33843
|
+
aroundNext: (callback) => runWithAutoInstrumentationSuppressed(callback),
|
|
33844
|
+
onChunk: (chunk) => options.handleChunk(state, chunk),
|
|
33845
|
+
onComplete: () => options.finalize(state),
|
|
33846
|
+
onError: (error) => options.finalize(state, error)
|
|
33847
|
+
});
|
|
33848
|
+
} else {
|
|
33849
|
+
options.finalize(state, void 0, result);
|
|
33850
|
+
}
|
|
33851
|
+
} catch (error) {
|
|
33852
|
+
debugLogger.error(
|
|
33853
|
+
`Error finalizing ${options.name} instrumentation:`,
|
|
33854
|
+
error
|
|
33855
|
+
);
|
|
33856
|
+
}
|
|
33857
|
+
}
|
|
33858
|
+
return result;
|
|
33859
|
+
}
|
|
33860
|
+
function startAgentStream(input, agent, activeChildParents) {
|
|
32520
33861
|
const model = agent?.model;
|
|
32521
33862
|
const metadata = {
|
|
32522
33863
|
...extractAgentMetadata2(agent),
|
|
@@ -32526,17 +33867,14 @@ function startAgentStream(event, activeChildParents) {
|
|
|
32526
33867
|
};
|
|
32527
33868
|
const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
|
|
32528
33869
|
const attachmentCache = createStrandsAttachmentCache();
|
|
32529
|
-
const
|
|
32530
|
-
event.arguments[0],
|
|
32531
|
-
attachmentCache
|
|
32532
|
-
);
|
|
33870
|
+
const processedInput = processStrandsInputAttachments(input, attachmentCache);
|
|
32533
33871
|
const span = parentSpan ? withCurrent(
|
|
32534
33872
|
parentSpan,
|
|
32535
33873
|
() => startSpan(
|
|
32536
33874
|
withSpanInstrumentationName(
|
|
32537
33875
|
{
|
|
32538
33876
|
event: {
|
|
32539
|
-
input,
|
|
33877
|
+
input: processedInput,
|
|
32540
33878
|
metadata
|
|
32541
33879
|
},
|
|
32542
33880
|
name: formatAgentSpanName(agent),
|
|
@@ -32549,7 +33887,7 @@ function startAgentStream(event, activeChildParents) {
|
|
|
32549
33887
|
withSpanInstrumentationName(
|
|
32550
33888
|
{
|
|
32551
33889
|
event: {
|
|
32552
|
-
input,
|
|
33890
|
+
input: processedInput,
|
|
32553
33891
|
metadata
|
|
32554
33892
|
},
|
|
32555
33893
|
name: formatAgentSpanName(agent),
|
|
@@ -32567,22 +33905,21 @@ function startAgentStream(event, activeChildParents) {
|
|
|
32567
33905
|
startTime: getCurrentUnixTimestamp()
|
|
32568
33906
|
};
|
|
32569
33907
|
}
|
|
32570
|
-
function startMultiAgentStream(
|
|
32571
|
-
const orchestrator = extractOrchestrator(event);
|
|
33908
|
+
function startMultiAgentStream(input, orchestrator, operation, activeChildParents) {
|
|
32572
33909
|
const metadata = {
|
|
32573
33910
|
"strands.operation": operation,
|
|
32574
33911
|
provider: "strands",
|
|
32575
33912
|
...orchestrator?.id ? { "strands.orchestrator.id": orchestrator.id } : {}
|
|
32576
33913
|
};
|
|
32577
33914
|
const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
|
|
32578
|
-
const
|
|
33915
|
+
const processedInput = processStrandsInputAttachments(input);
|
|
32579
33916
|
const span = parentSpan ? withCurrent(
|
|
32580
33917
|
parentSpan,
|
|
32581
33918
|
() => startSpan(
|
|
32582
33919
|
withSpanInstrumentationName(
|
|
32583
33920
|
{
|
|
32584
33921
|
event: {
|
|
32585
|
-
input,
|
|
33922
|
+
input: processedInput,
|
|
32586
33923
|
metadata
|
|
32587
33924
|
},
|
|
32588
33925
|
name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
|
|
@@ -32595,7 +33932,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
|
|
|
32595
33932
|
withSpanInstrumentationName(
|
|
32596
33933
|
{
|
|
32597
33934
|
event: {
|
|
32598
|
-
input,
|
|
33935
|
+
input: processedInput,
|
|
32599
33936
|
metadata
|
|
32600
33937
|
},
|
|
32601
33938
|
name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
|
|
@@ -32966,12 +34303,12 @@ function finalizeMultiAgentStream(state, activeChildParents, error, output) {
|
|
|
32966
34303
|
});
|
|
32967
34304
|
state.span.end();
|
|
32968
34305
|
}
|
|
32969
|
-
function extractAgent(
|
|
32970
|
-
const candidate =
|
|
34306
|
+
function extractAgent(agent, self) {
|
|
34307
|
+
const candidate = agent ?? self;
|
|
32971
34308
|
return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
|
|
32972
34309
|
}
|
|
32973
|
-
function extractOrchestrator(
|
|
32974
|
-
const candidate =
|
|
34310
|
+
function extractOrchestrator(orchestrator, self) {
|
|
34311
|
+
const candidate = orchestrator ?? self;
|
|
32975
34312
|
return isObject(candidate) && typeof candidate.stream === "function" ? candidate : void 0;
|
|
32976
34313
|
}
|
|
32977
34314
|
function extractAgentMetadata2(agent) {
|
|
@@ -34491,7 +35828,7 @@ function braintrustEveHook(options) {
|
|
|
34491
35828
|
}
|
|
34492
35829
|
};
|
|
34493
35830
|
}
|
|
34494
|
-
function
|
|
35831
|
+
function createLegacyEveInstrumentation(options) {
|
|
34495
35832
|
const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
|
|
34496
35833
|
return {
|
|
34497
35834
|
events: {
|
|
@@ -35879,8 +37216,10 @@ function capturedModelInput(modelInput) {
|
|
|
35879
37216
|
const value = [];
|
|
35880
37217
|
if (typeof instructions === "string") {
|
|
35881
37218
|
value.push({ content: instructions, role: "system" });
|
|
35882
|
-
} else if (instructions) {
|
|
37219
|
+
} else if (Array.isArray(instructions)) {
|
|
35883
37220
|
value.push(...instructions.map(capturedEveModelMessage));
|
|
37221
|
+
} else if (instructions) {
|
|
37222
|
+
value.push(capturedEveModelMessage(instructions));
|
|
35884
37223
|
}
|
|
35885
37224
|
value.push(...messages.map(capturedEveModelMessage));
|
|
35886
37225
|
try {
|
|
@@ -36124,6 +37463,472 @@ async function deterministicEveId(...parts) {
|
|
|
36124
37463
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
36125
37464
|
}
|
|
36126
37465
|
|
|
37466
|
+
// src/instrumentation/plugins/eve-provider.ts
|
|
37467
|
+
var MAX_EVE_PROVIDER_CACHE_ENTRIES = 1e4;
|
|
37468
|
+
function createEveInstrumentationProvider(options = {}) {
|
|
37469
|
+
const bridge = new EveProviderBridge(options.metadata);
|
|
37470
|
+
return {
|
|
37471
|
+
// Eve versions before tracePolicy use capture to decide whether provider
|
|
37472
|
+
// events include content. Newer versions prefer tracePolicy when both are
|
|
37473
|
+
// present, so keep the deprecated field for backwards compatibility.
|
|
37474
|
+
capture: "content",
|
|
37475
|
+
tracePolicy: () => ({
|
|
37476
|
+
emit: true,
|
|
37477
|
+
recordInputs: true,
|
|
37478
|
+
recordOutputs: true
|
|
37479
|
+
}),
|
|
37480
|
+
events: {
|
|
37481
|
+
"action.completed": (event, context) => bridge.handleActionTerminal(event, context),
|
|
37482
|
+
"action.failed": (event, context) => bridge.handleActionTerminal(event, context),
|
|
37483
|
+
"action.started": (event, context) => bridge.handleActionStarted(event, context),
|
|
37484
|
+
"model.call.completed": (event, context) => bridge.handleModelTerminal(event, context),
|
|
37485
|
+
"model.call.failed": (event, context) => bridge.handleModelTerminal(event, context),
|
|
37486
|
+
"model.call.started": (event, context) => bridge.handleModelStarted(event, context),
|
|
37487
|
+
"step.attempt.completed": (event) => bridge.handleStepAttemptTerminal(event),
|
|
37488
|
+
"step.attempt.failed": (event) => bridge.handleStepAttemptTerminal(event),
|
|
37489
|
+
"turn.cancelled": (event, context) => bridge.handleTurnTerminal(event, context),
|
|
37490
|
+
"turn.completed": (event, context) => bridge.handleTurnTerminal(event, context),
|
|
37491
|
+
"turn.failed": (event, context) => bridge.handleTurnTerminal(event, context),
|
|
37492
|
+
"turn.started": (event, context) => bridge.handleTurnStarted(event, context)
|
|
37493
|
+
},
|
|
37494
|
+
flush,
|
|
37495
|
+
setup: options.setup
|
|
37496
|
+
};
|
|
37497
|
+
}
|
|
37498
|
+
var EveProviderBridge = class {
|
|
37499
|
+
constructor(metadata) {
|
|
37500
|
+
this.metadata = metadata;
|
|
37501
|
+
}
|
|
37502
|
+
metadata;
|
|
37503
|
+
activeActions = /* @__PURE__ */ new Map();
|
|
37504
|
+
activeModels = /* @__PURE__ */ new Map();
|
|
37505
|
+
modelsByAttempt = /* @__PURE__ */ new Map();
|
|
37506
|
+
settledOperations = new LRUCache({
|
|
37507
|
+
max: MAX_EVE_PROVIDER_CACHE_ENTRIES
|
|
37508
|
+
});
|
|
37509
|
+
turns = new LRUCache({
|
|
37510
|
+
max: MAX_EVE_PROVIDER_CACHE_ENTRIES
|
|
37511
|
+
});
|
|
37512
|
+
async handleTurnStarted(event, context) {
|
|
37513
|
+
await this.contain("turn start", async () => {
|
|
37514
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37515
|
+
context.state.set({ skip: true });
|
|
37516
|
+
return;
|
|
37517
|
+
}
|
|
37518
|
+
const { rowId, spanId } = await generateEveIds(
|
|
37519
|
+
"turn",
|
|
37520
|
+
event.idempotencyKey
|
|
37521
|
+
);
|
|
37522
|
+
const key = turnKey3(event.sessionId, event.turnId);
|
|
37523
|
+
const stored = storedSpan(context);
|
|
37524
|
+
if (stored && "exported" in stored && stored.rootSpanId) {
|
|
37525
|
+
this.turns.set(key, { rootSpanId: stored.rootSpanId, spanId });
|
|
37526
|
+
return;
|
|
37527
|
+
}
|
|
37528
|
+
let rootSpanId = spanId;
|
|
37529
|
+
let parentSpanId;
|
|
37530
|
+
if (event.parentLineage) {
|
|
37531
|
+
const parentTurnKey = turnKey3(
|
|
37532
|
+
event.parentLineage.sessionId,
|
|
37533
|
+
event.parentLineage.turnId
|
|
37534
|
+
);
|
|
37535
|
+
const parentTurn = this.turns.get(parentTurnKey);
|
|
37536
|
+
rootSpanId = parentTurn?.rootSpanId ?? // Eve propagates the root session through every nested subagent. Use
|
|
37537
|
+
// it instead of the immediate parent session when no ancestor ran
|
|
37538
|
+
// in-process.
|
|
37539
|
+
(await generateEveIds(
|
|
37540
|
+
"turn",
|
|
37541
|
+
turnIdempotencyKey(
|
|
37542
|
+
event.rootSessionId,
|
|
37543
|
+
event.parentLineage.turnId
|
|
37544
|
+
)
|
|
37545
|
+
)).spanId;
|
|
37546
|
+
parentSpanId = (await generateEveIds(
|
|
37547
|
+
"subagent",
|
|
37548
|
+
actionIdempotencyKey(
|
|
37549
|
+
event.parentLineage.sessionId,
|
|
37550
|
+
event.parentLineage.turnId,
|
|
37551
|
+
event.parentLineage.callId
|
|
37552
|
+
)
|
|
37553
|
+
)).spanId;
|
|
37554
|
+
}
|
|
37555
|
+
const metadata = this.spanMetadata(event.sessionId);
|
|
37556
|
+
const span = await this.startSpan(
|
|
37557
|
+
context,
|
|
37558
|
+
{
|
|
37559
|
+
event: { id: rowId, metadata },
|
|
37560
|
+
name: "eve.turn",
|
|
37561
|
+
parentSpanIds: parentSpanId ? { rootSpanId, spanId: parentSpanId } : { parentSpanIds: [], rootSpanId },
|
|
37562
|
+
spanAttributes: { type: "task" /* TASK */ },
|
|
37563
|
+
spanId
|
|
37564
|
+
},
|
|
37565
|
+
rootSpanId
|
|
37566
|
+
);
|
|
37567
|
+
span?.log({ metadata });
|
|
37568
|
+
this.turns.set(key, {
|
|
37569
|
+
rootSpanId,
|
|
37570
|
+
spanId
|
|
37571
|
+
});
|
|
37572
|
+
});
|
|
37573
|
+
}
|
|
37574
|
+
async handleTurnTerminal(event, context) {
|
|
37575
|
+
await this.contain("turn terminal", async () => {
|
|
37576
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37577
|
+
context.state.set(void 0);
|
|
37578
|
+
return;
|
|
37579
|
+
}
|
|
37580
|
+
const error = event.type === "turn.failed" ? event.error : void 0;
|
|
37581
|
+
this.drainActionsForTurn(event.sessionId, event.turnId, error);
|
|
37582
|
+
const stored = storedSpan(context);
|
|
37583
|
+
if (stored && "exported" in stored) {
|
|
37584
|
+
updateSpan({
|
|
37585
|
+
exported: stored.exported,
|
|
37586
|
+
...error !== void 0 ? { error } : {},
|
|
37587
|
+
metrics: { end: Date.now() / 1e3 }
|
|
37588
|
+
});
|
|
37589
|
+
}
|
|
37590
|
+
this.settledOperations.set(event.idempotencyKey, true);
|
|
37591
|
+
context.state.set(void 0);
|
|
37592
|
+
this.turns.delete(turnKey3(event.sessionId, event.turnId));
|
|
37593
|
+
});
|
|
37594
|
+
}
|
|
37595
|
+
async handleModelStarted(event, context) {
|
|
37596
|
+
await this.contain("model start", async () => {
|
|
37597
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37598
|
+
context.state.set({ skip: true });
|
|
37599
|
+
return;
|
|
37600
|
+
}
|
|
37601
|
+
const parent = await this.parentForScope(event.scope);
|
|
37602
|
+
const { rowId, spanId } = await generateEveIds(
|
|
37603
|
+
"step",
|
|
37604
|
+
event.idempotencyKey
|
|
37605
|
+
);
|
|
37606
|
+
const input = event.input ? capturedModelInput(event.input) : void 0;
|
|
37607
|
+
const metadata = {
|
|
37608
|
+
...this.spanMetadata(event.scope.sessionId),
|
|
37609
|
+
model: event.model.modelId,
|
|
37610
|
+
provider: event.model.provider
|
|
37611
|
+
};
|
|
37612
|
+
const span = await this.startSpan(context, {
|
|
37613
|
+
event: {
|
|
37614
|
+
id: rowId,
|
|
37615
|
+
...input !== void 0 ? { input } : {},
|
|
37616
|
+
metadata
|
|
37617
|
+
},
|
|
37618
|
+
name: "eve.step",
|
|
37619
|
+
parentSpanIds: parent,
|
|
37620
|
+
spanAttributes: { type: "llm" /* LLM */ },
|
|
37621
|
+
spanId
|
|
37622
|
+
});
|
|
37623
|
+
if (!span) return;
|
|
37624
|
+
span.log({ ...input !== void 0 ? { input } : {}, metadata });
|
|
37625
|
+
this.activeModels.set(event.idempotencyKey, {
|
|
37626
|
+
span,
|
|
37627
|
+
turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
|
|
37628
|
+
});
|
|
37629
|
+
const keys = this.modelsByAttempt.get(event.scope.attemptId) ?? /* @__PURE__ */ new Set();
|
|
37630
|
+
keys.add(event.idempotencyKey);
|
|
37631
|
+
this.modelsByAttempt.set(event.scope.attemptId, keys);
|
|
37632
|
+
});
|
|
37633
|
+
}
|
|
37634
|
+
async handleModelTerminal(event, context) {
|
|
37635
|
+
await this.contain("model terminal", async () => {
|
|
37636
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37637
|
+
context.state.set(void 0);
|
|
37638
|
+
return;
|
|
37639
|
+
}
|
|
37640
|
+
const active = this.activeModels.get(event.idempotencyKey);
|
|
37641
|
+
if (active) {
|
|
37642
|
+
const span = active.span;
|
|
37643
|
+
if (event.type === "model.call.failed") {
|
|
37644
|
+
if (event.error !== void 0) span.log({ error: event.error });
|
|
37645
|
+
} else {
|
|
37646
|
+
span.log({
|
|
37647
|
+
metrics: usageMetrics(event.usage),
|
|
37648
|
+
output: modelOutput(event)
|
|
37649
|
+
});
|
|
37650
|
+
}
|
|
37651
|
+
span.end();
|
|
37652
|
+
} else {
|
|
37653
|
+
const stored = storedSpan(context);
|
|
37654
|
+
if (stored && "exported" in stored) {
|
|
37655
|
+
updateSpan({
|
|
37656
|
+
exported: stored.exported,
|
|
37657
|
+
...event.type === "model.call.failed" ? event.error !== void 0 ? { error: event.error } : {} : { output: modelOutput(event) },
|
|
37658
|
+
metrics: {
|
|
37659
|
+
...event.type === "model.call.completed" ? usageMetrics(event.usage) : {},
|
|
37660
|
+
end: Date.now() / 1e3
|
|
37661
|
+
}
|
|
37662
|
+
});
|
|
37663
|
+
}
|
|
37664
|
+
}
|
|
37665
|
+
this.settledOperations.set(event.idempotencyKey, true);
|
|
37666
|
+
this.forgetModel(event.scope.attemptId, event.idempotencyKey);
|
|
37667
|
+
context.state.set(void 0);
|
|
37668
|
+
});
|
|
37669
|
+
}
|
|
37670
|
+
async handleActionStarted(event, context) {
|
|
37671
|
+
await this.contain("action start", async () => {
|
|
37672
|
+
if (event.kind === "load-skill" || this.settledOperations.has(event.idempotencyKey)) {
|
|
37673
|
+
context.state.set({ skip: true });
|
|
37674
|
+
return;
|
|
37675
|
+
}
|
|
37676
|
+
const parent = await this.parentForScope(event.scope);
|
|
37677
|
+
const { rowId, spanId } = await generateEveIds(
|
|
37678
|
+
event.kind === "subagent-call" ? "subagent" : "tool",
|
|
37679
|
+
event.idempotencyKey
|
|
37680
|
+
);
|
|
37681
|
+
const metadata = {
|
|
37682
|
+
...this.spanMetadata(event.scope.sessionId),
|
|
37683
|
+
"eve.action_kind": event.kind
|
|
37684
|
+
};
|
|
37685
|
+
const span = await this.startSpan(context, {
|
|
37686
|
+
event: {
|
|
37687
|
+
id: rowId,
|
|
37688
|
+
...event.input !== void 0 ? { input: event.input } : {},
|
|
37689
|
+
metadata
|
|
37690
|
+
},
|
|
37691
|
+
name: event.name,
|
|
37692
|
+
parentSpanIds: parent,
|
|
37693
|
+
spanAttributes: { type: "tool" /* TOOL */ },
|
|
37694
|
+
spanId
|
|
37695
|
+
});
|
|
37696
|
+
if (!span) return;
|
|
37697
|
+
span.log({
|
|
37698
|
+
...event.input !== void 0 ? { input: event.input } : {},
|
|
37699
|
+
metadata
|
|
37700
|
+
});
|
|
37701
|
+
this.activeActions.set(event.idempotencyKey, {
|
|
37702
|
+
span,
|
|
37703
|
+
turnKey: turnKey3(event.scope.sessionId, event.scope.turnId)
|
|
37704
|
+
});
|
|
37705
|
+
});
|
|
37706
|
+
}
|
|
37707
|
+
async handleActionTerminal(event, context) {
|
|
37708
|
+
await this.contain("action terminal", async () => {
|
|
37709
|
+
if (this.settledOperations.has(event.idempotencyKey)) {
|
|
37710
|
+
context.state.set(void 0);
|
|
37711
|
+
return;
|
|
37712
|
+
}
|
|
37713
|
+
const stored = storedSpan(context);
|
|
37714
|
+
if (stored?.skip) {
|
|
37715
|
+
context.state.set(void 0);
|
|
37716
|
+
return;
|
|
37717
|
+
}
|
|
37718
|
+
const active = this.activeActions.get(event.idempotencyKey);
|
|
37719
|
+
const end = finiteTimestamp(event.acceptedAtMs) ?? Date.now();
|
|
37720
|
+
if (active) {
|
|
37721
|
+
const span = active.span;
|
|
37722
|
+
if (event.type === "action.failed") {
|
|
37723
|
+
span.log({
|
|
37724
|
+
error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
|
|
37725
|
+
});
|
|
37726
|
+
} else if (event.output.type === "error") {
|
|
37727
|
+
span.log({
|
|
37728
|
+
error: event.output.error ?? new Error("Eve action returned an error")
|
|
37729
|
+
});
|
|
37730
|
+
} else {
|
|
37731
|
+
span.log({ output: event.output.output });
|
|
37732
|
+
}
|
|
37733
|
+
span.end({ endTime: end / 1e3 });
|
|
37734
|
+
} else {
|
|
37735
|
+
const stored2 = storedSpan(context);
|
|
37736
|
+
if (stored2 && "exported" in stored2) {
|
|
37737
|
+
updateSpan({
|
|
37738
|
+
exported: stored2.exported,
|
|
37739
|
+
...event.type === "action.failed" ? {
|
|
37740
|
+
error: event.error ?? new Error(event.errorCode ?? `Eve action ${event.outcome}`)
|
|
37741
|
+
} : event.output.type === "error" ? {
|
|
37742
|
+
error: event.output.error ?? new Error("Eve action returned an error")
|
|
37743
|
+
} : { output: event.output.output },
|
|
37744
|
+
metrics: { end: end / 1e3 }
|
|
37745
|
+
});
|
|
37746
|
+
}
|
|
37747
|
+
}
|
|
37748
|
+
this.settledOperations.set(event.idempotencyKey, true);
|
|
37749
|
+
this.activeActions.delete(event.idempotencyKey);
|
|
37750
|
+
context.state.set(void 0);
|
|
37751
|
+
});
|
|
37752
|
+
}
|
|
37753
|
+
handleStepAttemptTerminal(event) {
|
|
37754
|
+
void this.contain("step attempt terminal", () => {
|
|
37755
|
+
const keys = this.modelsByAttempt.get(event.scope.attemptId);
|
|
37756
|
+
if (!keys) return;
|
|
37757
|
+
for (const key of keys) {
|
|
37758
|
+
const active = this.activeModels.get(key);
|
|
37759
|
+
if (!active) continue;
|
|
37760
|
+
if (event.type === "step.attempt.failed" && event.error !== void 0) {
|
|
37761
|
+
active.span.log({ error: event.error });
|
|
37762
|
+
}
|
|
37763
|
+
active.span.end();
|
|
37764
|
+
this.activeModels.delete(key);
|
|
37765
|
+
}
|
|
37766
|
+
this.modelsByAttempt.delete(event.scope.attemptId);
|
|
37767
|
+
});
|
|
37768
|
+
}
|
|
37769
|
+
async parentForScope(scope) {
|
|
37770
|
+
const key = turnKey3(scope.sessionId, scope.turnId);
|
|
37771
|
+
const known = this.turns.get(key);
|
|
37772
|
+
if (known) {
|
|
37773
|
+
return { rootSpanId: known.rootSpanId, spanId: known.spanId };
|
|
37774
|
+
}
|
|
37775
|
+
const [{ spanId }, { spanId: rootSpanId }] = await Promise.all([
|
|
37776
|
+
generateEveIds("turn", turnIdempotencyKey(scope.sessionId, scope.turnId)),
|
|
37777
|
+
generateEveIds(
|
|
37778
|
+
"turn",
|
|
37779
|
+
turnIdempotencyKey(
|
|
37780
|
+
scope.rootSessionId ?? scope.sessionId,
|
|
37781
|
+
scope.turnId
|
|
37782
|
+
)
|
|
37783
|
+
)
|
|
37784
|
+
]);
|
|
37785
|
+
return { rootSpanId, spanId };
|
|
37786
|
+
}
|
|
37787
|
+
async startSpan(context, args, rootSpanId) {
|
|
37788
|
+
const span = withCurrent(
|
|
37789
|
+
NOOP_SPAN,
|
|
37790
|
+
() => _internalStartSpanWithInitialMerge(
|
|
37791
|
+
withSpanInstrumentationName(args ?? {}, INSTRUMENTATION_NAMES.EVE)
|
|
37792
|
+
)
|
|
37793
|
+
);
|
|
37794
|
+
try {
|
|
37795
|
+
context.state.set({
|
|
37796
|
+
exported: await span.export(),
|
|
37797
|
+
...rootSpanId ? { rootSpanId } : {}
|
|
37798
|
+
});
|
|
37799
|
+
} catch (error) {
|
|
37800
|
+
debugLogger.warn("Error exporting Eve provider span:", error);
|
|
37801
|
+
}
|
|
37802
|
+
return span;
|
|
37803
|
+
}
|
|
37804
|
+
drainActionsForTurn(sessionId, turnId, error) {
|
|
37805
|
+
const key = turnKey3(sessionId, turnId);
|
|
37806
|
+
for (const [idempotencyKey, active] of this.activeActions) {
|
|
37807
|
+
if (active.turnKey !== key) continue;
|
|
37808
|
+
if (error !== void 0) active.span.log({ error });
|
|
37809
|
+
active.span.end();
|
|
37810
|
+
this.activeActions.delete(idempotencyKey);
|
|
37811
|
+
}
|
|
37812
|
+
}
|
|
37813
|
+
forgetModel(attemptId, idempotencyKey) {
|
|
37814
|
+
this.activeModels.delete(idempotencyKey);
|
|
37815
|
+
const keys = this.modelsByAttempt.get(attemptId);
|
|
37816
|
+
keys?.delete(idempotencyKey);
|
|
37817
|
+
if (keys?.size === 0) this.modelsByAttempt.delete(attemptId);
|
|
37818
|
+
}
|
|
37819
|
+
spanMetadata(sessionId) {
|
|
37820
|
+
return {
|
|
37821
|
+
...this.metadata ?? {},
|
|
37822
|
+
"eve.session_id": sessionId
|
|
37823
|
+
};
|
|
37824
|
+
}
|
|
37825
|
+
async contain(operation, fn) {
|
|
37826
|
+
try {
|
|
37827
|
+
await fn();
|
|
37828
|
+
} catch (error) {
|
|
37829
|
+
debugLogger.warn(`Error in Eve provider ${operation}:`, error);
|
|
37830
|
+
}
|
|
37831
|
+
}
|
|
37832
|
+
};
|
|
37833
|
+
function storedSpan(context) {
|
|
37834
|
+
const value = context.state.get();
|
|
37835
|
+
if (!isObject(value)) return void 0;
|
|
37836
|
+
if (value["skip"] === true) return { skip: true };
|
|
37837
|
+
return typeof value["exported"] === "string" ? {
|
|
37838
|
+
exported: value["exported"],
|
|
37839
|
+
...typeof value["rootSpanId"] === "string" && value["rootSpanId"].length > 0 ? { rootSpanId: value["rootSpanId"] } : {}
|
|
37840
|
+
} : void 0;
|
|
37841
|
+
}
|
|
37842
|
+
function modelOutput(event) {
|
|
37843
|
+
const content = event.content ?? [];
|
|
37844
|
+
let text = "";
|
|
37845
|
+
const reasoning = [];
|
|
37846
|
+
const toolCalls = [];
|
|
37847
|
+
for (const part of content) {
|
|
37848
|
+
if (part.type === "text") {
|
|
37849
|
+
text += part.text;
|
|
37850
|
+
} else if (part.type === "reasoning" && part.text.trim().length > 0) {
|
|
37851
|
+
reasoning.push({ content: part.text });
|
|
37852
|
+
} else if (part.type === "tool-call") {
|
|
37853
|
+
toolCalls.push({
|
|
37854
|
+
function: {
|
|
37855
|
+
arguments: safeJsonStringify(part.input),
|
|
37856
|
+
name: part.toolName
|
|
37857
|
+
},
|
|
37858
|
+
id: part.callId,
|
|
37859
|
+
type: "function"
|
|
37860
|
+
});
|
|
37861
|
+
}
|
|
37862
|
+
}
|
|
37863
|
+
return [
|
|
37864
|
+
{
|
|
37865
|
+
finish_reason: normalizeFinishReason2(event.finishReason),
|
|
37866
|
+
index: 0,
|
|
37867
|
+
message: {
|
|
37868
|
+
content: text || null,
|
|
37869
|
+
...reasoning.length > 0 ? { reasoning } : {},
|
|
37870
|
+
role: "assistant",
|
|
37871
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
37872
|
+
}
|
|
37873
|
+
}
|
|
37874
|
+
];
|
|
37875
|
+
}
|
|
37876
|
+
function usageMetrics(usage) {
|
|
37877
|
+
const promptTokens = nonNegativeNumber(usage.inputTokens);
|
|
37878
|
+
const completionTokens = nonNegativeNumber(usage.outputTokens);
|
|
37879
|
+
const cachedTokens = nonNegativeNumber(
|
|
37880
|
+
usage.inputTokenDetails?.cacheReadTokens
|
|
37881
|
+
);
|
|
37882
|
+
const cacheCreationTokens = nonNegativeNumber(
|
|
37883
|
+
usage.inputTokenDetails?.cacheWriteTokens
|
|
37884
|
+
);
|
|
37885
|
+
return {
|
|
37886
|
+
...promptTokens !== void 0 ? { prompt_tokens: promptTokens } : {},
|
|
37887
|
+
...completionTokens !== void 0 ? { completion_tokens: completionTokens } : {},
|
|
37888
|
+
...promptTokens !== void 0 && completionTokens !== void 0 ? { tokens: promptTokens + completionTokens } : {},
|
|
37889
|
+
...cachedTokens !== void 0 ? { prompt_cached_tokens: cachedTokens } : {},
|
|
37890
|
+
...cacheCreationTokens !== void 0 ? { prompt_cache_creation_tokens: cacheCreationTokens } : {}
|
|
37891
|
+
};
|
|
37892
|
+
}
|
|
37893
|
+
function nonNegativeNumber(value) {
|
|
37894
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
37895
|
+
}
|
|
37896
|
+
function finiteTimestamp(value) {
|
|
37897
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
37898
|
+
}
|
|
37899
|
+
function normalizeFinishReason2(value) {
|
|
37900
|
+
if (value === "content-filter") return "content_filter";
|
|
37901
|
+
if (value === "tool-calls") return "tool_calls";
|
|
37902
|
+
return value;
|
|
37903
|
+
}
|
|
37904
|
+
function safeJsonStringify(value) {
|
|
37905
|
+
try {
|
|
37906
|
+
return JSON.stringify(value) ?? "null";
|
|
37907
|
+
} catch {
|
|
37908
|
+
return "null";
|
|
37909
|
+
}
|
|
37910
|
+
}
|
|
37911
|
+
function turnKey3(sessionId, turnId) {
|
|
37912
|
+
return `${sessionId}:${turnId}`;
|
|
37913
|
+
}
|
|
37914
|
+
function turnIdempotencyKey(sessionId, turnId) {
|
|
37915
|
+
return `turn:${sessionId}:${turnId}`;
|
|
37916
|
+
}
|
|
37917
|
+
function actionIdempotencyKey(sessionId, turnId, callId) {
|
|
37918
|
+
return `action:${sessionId}:${turnId}:${callId}`;
|
|
37919
|
+
}
|
|
37920
|
+
|
|
37921
|
+
// src/instrumentation/plugins/eve-instrumentation.ts
|
|
37922
|
+
var EVE_INSTRUMENTATION_PROVIDER = /* @__PURE__ */ Symbol.for("eve.instrumentation.provider");
|
|
37923
|
+
function braintrustEveInstrumentation(options) {
|
|
37924
|
+
const definition = "defineState" in options ? createLegacyEveInstrumentation(options) : createEveInstrumentationProvider(options);
|
|
37925
|
+
const declaration = {
|
|
37926
|
+
...definition,
|
|
37927
|
+
[EVE_INSTRUMENTATION_PROVIDER]: true
|
|
37928
|
+
};
|
|
37929
|
+
return declaration;
|
|
37930
|
+
}
|
|
37931
|
+
|
|
36127
37932
|
// src/instrumentation/config.ts
|
|
36128
37933
|
var envIntegrationAliases = {
|
|
36129
37934
|
openai: "openai",
|