braintrust 3.11.0 → 3.13.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 +8 -8
- package/dev/dist/index.d.mts +26 -7
- package/dev/dist/index.d.ts +26 -7
- package/dev/dist/index.js +2717 -335
- package/dev/dist/index.mjs +2499 -117
- package/dist/apply-auto-instrumentation.browser.d.mts +2 -0
- package/dist/apply-auto-instrumentation.browser.d.ts +2 -0
- package/dist/apply-auto-instrumentation.browser.js +18 -0
- package/dist/apply-auto-instrumentation.browser.mjs +0 -0
- package/dist/apply-auto-instrumentation.d.mts +2 -0
- package/dist/apply-auto-instrumentation.d.ts +2 -0
- package/dist/apply-auto-instrumentation.js +2534 -0
- package/dist/apply-auto-instrumentation.mjs +2534 -0
- package/dist/auto-instrumentations/bundler/esbuild.cjs +1803 -1283
- package/dist/auto-instrumentations/bundler/esbuild.d.mts +9 -5
- package/dist/auto-instrumentations/bundler/esbuild.d.ts +9 -5
- package/dist/auto-instrumentations/bundler/esbuild.mjs +10 -2
- package/dist/auto-instrumentations/bundler/next.cjs +3269 -0
- package/dist/auto-instrumentations/bundler/next.d.mts +3 -0
- package/dist/auto-instrumentations/bundler/next.d.ts +3 -0
- package/dist/auto-instrumentations/bundler/next.mjs +189 -0
- package/dist/auto-instrumentations/bundler/rollup.cjs +1803 -1283
- package/dist/auto-instrumentations/bundler/rollup.d.mts +9 -5
- package/dist/auto-instrumentations/bundler/rollup.d.ts +9 -5
- package/dist/auto-instrumentations/bundler/rollup.mjs +10 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +1803 -1283
- package/dist/auto-instrumentations/bundler/vite.d.mts +9 -5
- package/dist/auto-instrumentations/bundler/vite.d.ts +9 -5
- package/dist/auto-instrumentations/bundler/vite.mjs +10 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +1861 -1308
- package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +3 -3
- package/dist/auto-instrumentations/bundler/webpack.cjs +1803 -1283
- package/dist/auto-instrumentations/bundler/webpack.d.mts +9 -5
- package/dist/auto-instrumentations/bundler/webpack.d.ts +9 -5
- package/dist/auto-instrumentations/bundler/webpack.mjs +6 -6
- package/dist/auto-instrumentations/{chunk-DIV5TO4S.mjs → chunk-E5DUYJWK.mjs} +338 -1
- package/dist/auto-instrumentations/chunk-GJOO4ESL.mjs +300 -0
- package/dist/auto-instrumentations/chunk-WFEUJACP.mjs +18 -0
- package/dist/auto-instrumentations/hook.mjs +1713 -1460
- package/dist/auto-instrumentations/index.cjs +94 -0
- package/dist/auto-instrumentations/index.d.mts +5 -1
- package/dist/auto-instrumentations/index.d.ts +5 -1
- package/dist/auto-instrumentations/index.mjs +6 -247
- package/dist/auto-instrumentations/loader/esm-hook.mjs +19 -2
- package/dist/auto-instrumentations/plugin-D7nDswtC.d.mts +44 -0
- package/dist/auto-instrumentations/plugin-D7nDswtC.d.ts +44 -0
- package/dist/browser.d.mts +264 -47
- package/dist/browser.d.ts +264 -47
- package/dist/browser.js +2521 -159
- package/dist/browser.mjs +2521 -159
- package/dist/chunk-26JGOELH.js +817 -0
- package/dist/chunk-75IQCUB2.mjs +817 -0
- package/dist/cli.js +2510 -122
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +2521 -159
- package/dist/edge-light.mjs +2521 -159
- package/dist/index.d.mts +264 -47
- package/dist/index.d.ts +264 -47
- package/dist/index.js +3498 -1850
- package/dist/index.mjs +2635 -987
- package/dist/instrumentation/index.d.mts +7897 -48
- package/dist/instrumentation/index.d.ts +7897 -48
- package/dist/instrumentation/index.js +2408 -95
- package/dist/instrumentation/index.mjs +2407 -95
- package/dist/workerd.d.mts +1 -1
- package/dist/workerd.d.ts +1 -1
- package/dist/workerd.js +2521 -159
- package/dist/workerd.mjs +2521 -159
- package/package.json +23 -17
- package/util/dist/index.d.mts +3 -1
- package/util/dist/index.d.ts +3 -1
- package/util/dist/index.js +6 -0
- package/util/dist/index.mjs +6 -0
- package/dist/auto-instrumentations/chunk-G6ZWXGZB.mjs +0 -116
- package/dist/auto-instrumentations/plugin-Df3qKIl2.d.mts +0 -22
- package/dist/auto-instrumentations/plugin-Df3qKIl2.d.ts +0 -22
package/dist/workerd.mjs
CHANGED
|
@@ -89,6 +89,7 @@ var iso = {
|
|
|
89
89
|
getRepoInfo: async (_settings) => void 0,
|
|
90
90
|
getPastNAncestors: async () => [],
|
|
91
91
|
getEnv: (_name) => void 0,
|
|
92
|
+
getBraintrustApiKey: async () => void 0,
|
|
92
93
|
getCallerLocation: () => void 0,
|
|
93
94
|
newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
|
|
94
95
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -921,6 +922,11 @@ function isPromiseLike(value) {
|
|
|
921
922
|
|
|
922
923
|
// util/object_util.ts
|
|
923
924
|
var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
|
|
925
|
+
var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
|
|
926
|
+
"__proto__",
|
|
927
|
+
"constructor",
|
|
928
|
+
"prototype"
|
|
929
|
+
]);
|
|
924
930
|
function mergeDictsWithPaths({
|
|
925
931
|
mergeInto,
|
|
926
932
|
mergeFrom,
|
|
@@ -943,6 +949,7 @@ function mergeDictsWithPathsHelper({
|
|
|
943
949
|
mergePaths
|
|
944
950
|
}) {
|
|
945
951
|
Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
|
|
952
|
+
if (FORBIDDEN_MERGE_KEYS.has(k)) return;
|
|
946
953
|
const fullPath = path.concat([k]);
|
|
947
954
|
const fullPathSerialized = JSON.stringify(fullPath);
|
|
948
955
|
const mergeIntoV = recordFind(mergeInto, k);
|
|
@@ -5016,6 +5023,13 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
5016
5023
|
debugLogger.debug(
|
|
5017
5024
|
`Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
|
|
5018
5025
|
);
|
|
5026
|
+
const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
|
|
5027
|
+
debugLogger.info(
|
|
5028
|
+
`Sleeping for ${sleepTimeS}s before retrying API request`
|
|
5029
|
+
);
|
|
5030
|
+
await new Promise(
|
|
5031
|
+
(resolve) => setTimeout(resolve, sleepTimeS * 1e3)
|
|
5032
|
+
);
|
|
5019
5033
|
continue;
|
|
5020
5034
|
}
|
|
5021
5035
|
throw e;
|
|
@@ -5417,6 +5431,19 @@ var JSONAttachment = class extends Attachment {
|
|
|
5417
5431
|
*/
|
|
5418
5432
|
constructor(data, options) {
|
|
5419
5433
|
const { filename = "data.json", pretty = false, state } = options ?? {};
|
|
5434
|
+
const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
|
|
5435
|
+
if (deferredJsonAttachment) {
|
|
5436
|
+
super({
|
|
5437
|
+
data: new Blob([]),
|
|
5438
|
+
filename,
|
|
5439
|
+
contentType: "application/json",
|
|
5440
|
+
state
|
|
5441
|
+
});
|
|
5442
|
+
return deferredJsonAttachment(data, {
|
|
5443
|
+
filename,
|
|
5444
|
+
pretty
|
|
5445
|
+
});
|
|
5446
|
+
}
|
|
5420
5447
|
const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
5421
5448
|
const blob = new Blob([jsonString], { type: "application/json" });
|
|
5422
5449
|
super({
|
|
@@ -5665,20 +5692,7 @@ function startSpanParentArgs(args) {
|
|
|
5665
5692
|
`Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
|
|
5666
5693
|
);
|
|
5667
5694
|
}
|
|
5668
|
-
|
|
5669
|
-
args.state,
|
|
5670
|
-
parentComponents
|
|
5671
|
-
);
|
|
5672
|
-
const computeParentObjectId = async () => {
|
|
5673
|
-
const parentComponentsObjectId = await parentComponentsObjectIdLambda();
|
|
5674
|
-
if (await args.parentObjectId.get() !== parentComponentsObjectId) {
|
|
5675
|
-
throw new Error(
|
|
5676
|
-
`Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
|
|
5677
|
-
);
|
|
5678
|
-
}
|
|
5679
|
-
return await args.parentObjectId.get();
|
|
5680
|
-
};
|
|
5681
|
-
argParentObjectId = new LazyValue(computeParentObjectId);
|
|
5695
|
+
argParentObjectId = args.parentObjectId;
|
|
5682
5696
|
if (parentComponents.data.row_id) {
|
|
5683
5697
|
argParentSpanIds = {
|
|
5684
5698
|
spanId: parentComponents.data.span_id,
|
|
@@ -6064,6 +6078,7 @@ var TestBackgroundLogger = class {
|
|
|
6064
6078
|
}
|
|
6065
6079
|
};
|
|
6066
6080
|
var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
|
|
6081
|
+
var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
|
|
6067
6082
|
var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
|
|
6068
6083
|
apiConn;
|
|
6069
6084
|
queue;
|
|
@@ -6694,17 +6709,10 @@ function init(projectOrOptions, optionalOptions) {
|
|
|
6694
6709
|
if (repoInfo) {
|
|
6695
6710
|
return repoInfo;
|
|
6696
6711
|
}
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
};
|
|
6702
|
-
if (gitMetadataSettings) {
|
|
6703
|
-
mergedGitMetadataSettings = mergeGitMetadataSettings(
|
|
6704
|
-
mergedGitMetadataSettings,
|
|
6705
|
-
gitMetadataSettings
|
|
6706
|
-
);
|
|
6707
|
-
}
|
|
6712
|
+
const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
|
|
6713
|
+
state.gitMetadataSettings,
|
|
6714
|
+
gitMetadataSettings ?? { collect: "all" }
|
|
6715
|
+
);
|
|
6708
6716
|
return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
|
|
6709
6717
|
})();
|
|
6710
6718
|
if (repoInfoArg) {
|
|
@@ -7428,10 +7436,11 @@ async function login(options = {}) {
|
|
|
7428
7436
|
async function loginToState(options = {}) {
|
|
7429
7437
|
const {
|
|
7430
7438
|
appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
|
|
7431
|
-
apiKey
|
|
7439
|
+
apiKey: apiKeyArg,
|
|
7432
7440
|
orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
|
|
7433
7441
|
fetch: fetch2 = globalThis.fetch
|
|
7434
7442
|
} = options || {};
|
|
7443
|
+
const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
|
|
7435
7444
|
const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
|
|
7436
7445
|
const state = new BraintrustState(options);
|
|
7437
7446
|
state.resetLoginInfo();
|
|
@@ -8672,9 +8681,15 @@ var SpanImpl = class _SpanImpl {
|
|
|
8672
8681
|
const cachedSpan = {
|
|
8673
8682
|
input: partialRecord.input,
|
|
8674
8683
|
output: partialRecord.output,
|
|
8684
|
+
expected: partialRecord.expected,
|
|
8685
|
+
error: partialRecord.error,
|
|
8686
|
+
scores: partialRecord.scores,
|
|
8687
|
+
metrics: partialRecord.metrics,
|
|
8675
8688
|
metadata: partialRecord.metadata,
|
|
8689
|
+
tags: partialRecord.tags,
|
|
8676
8690
|
span_id: this._spanId,
|
|
8677
8691
|
span_parents: this._spanParents,
|
|
8692
|
+
is_root: this._spanId === this._rootSpanId,
|
|
8678
8693
|
span_attributes: partialRecord.span_attributes
|
|
8679
8694
|
};
|
|
8680
8695
|
this._state.spanCache.queueWrite(
|
|
@@ -9010,6 +9025,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
9010
9025
|
metadata,
|
|
9011
9026
|
tags,
|
|
9012
9027
|
output,
|
|
9028
|
+
origin,
|
|
9013
9029
|
isMerge
|
|
9014
9030
|
}) {
|
|
9015
9031
|
return new LazyValue(async () => {
|
|
@@ -9024,6 +9040,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
9024
9040
|
created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
|
|
9025
9041
|
//if we're merging/updating an event we will not add this ts
|
|
9026
9042
|
metadata,
|
|
9043
|
+
origin,
|
|
9027
9044
|
...!!isMerge ? {
|
|
9028
9045
|
[IS_MERGE_FIELD]: true
|
|
9029
9046
|
} : {}
|
|
@@ -9043,6 +9060,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
9043
9060
|
* about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
|
|
9044
9061
|
* `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
|
|
9045
9062
|
* JSON-serializable type, but its keys must be strings.
|
|
9063
|
+
* @param event.origin (Optional) a reference to the source object this dataset record was derived from.
|
|
9046
9064
|
* @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
|
|
9047
9065
|
* @param event.output: (Deprecated) The output of your application. Use `expected` instead.
|
|
9048
9066
|
* @returns The `id` of the logged record.
|
|
@@ -9053,7 +9071,8 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
9053
9071
|
metadata,
|
|
9054
9072
|
tags,
|
|
9055
9073
|
id,
|
|
9056
|
-
output
|
|
9074
|
+
output,
|
|
9075
|
+
origin
|
|
9057
9076
|
}) {
|
|
9058
9077
|
this.validateEvent({ metadata, expected, output, tags });
|
|
9059
9078
|
const rowId = id || uuidv42();
|
|
@@ -9065,6 +9084,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
9065
9084
|
metadata,
|
|
9066
9085
|
tags,
|
|
9067
9086
|
output,
|
|
9087
|
+
origin,
|
|
9068
9088
|
isMerge: false
|
|
9069
9089
|
})
|
|
9070
9090
|
);
|
|
@@ -13523,11 +13543,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
|
|
|
13523
13543
|
if (Array.isArray(event?.denyOutputPaths)) {
|
|
13524
13544
|
return event.denyOutputPaths;
|
|
13525
13545
|
}
|
|
13526
|
-
const
|
|
13527
|
-
if (!
|
|
13546
|
+
const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
|
|
13547
|
+
if (!firstArgument2 || typeof firstArgument2 !== "object") {
|
|
13528
13548
|
return defaultDenyOutputPaths;
|
|
13529
13549
|
}
|
|
13530
|
-
const runtimeDenyOutputPaths =
|
|
13550
|
+
const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
|
|
13531
13551
|
if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
|
|
13532
13552
|
return runtimeDenyOutputPaths;
|
|
13533
13553
|
}
|
|
@@ -17186,6 +17206,467 @@ function cleanMetrics2(metrics) {
|
|
|
17186
17206
|
return cleaned;
|
|
17187
17207
|
}
|
|
17188
17208
|
|
|
17209
|
+
// src/instrumentation/plugins/openai-agents-channels.ts
|
|
17210
|
+
var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
|
|
17211
|
+
onTraceStart: channel({
|
|
17212
|
+
channelName: "tracing.processor.onTraceStart",
|
|
17213
|
+
kind: "async"
|
|
17214
|
+
}),
|
|
17215
|
+
onTraceEnd: channel({
|
|
17216
|
+
channelName: "tracing.processor.onTraceEnd",
|
|
17217
|
+
kind: "async"
|
|
17218
|
+
}),
|
|
17219
|
+
onSpanStart: channel({
|
|
17220
|
+
channelName: "tracing.processor.onSpanStart",
|
|
17221
|
+
kind: "async"
|
|
17222
|
+
}),
|
|
17223
|
+
onSpanEnd: channel({
|
|
17224
|
+
channelName: "tracing.processor.onSpanEnd",
|
|
17225
|
+
kind: "async"
|
|
17226
|
+
})
|
|
17227
|
+
});
|
|
17228
|
+
|
|
17229
|
+
// src/instrumentation/plugins/openai-agents-trace-processor.ts
|
|
17230
|
+
function isSpanData(spanData, type) {
|
|
17231
|
+
return spanData.type === type;
|
|
17232
|
+
}
|
|
17233
|
+
function spanTypeFromAgents(span) {
|
|
17234
|
+
const spanType = span.spanData.type;
|
|
17235
|
+
if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
|
|
17236
|
+
return "tool" /* TOOL */;
|
|
17237
|
+
}
|
|
17238
|
+
if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
|
|
17239
|
+
return "llm" /* LLM */;
|
|
17240
|
+
}
|
|
17241
|
+
return "task" /* TASK */;
|
|
17242
|
+
}
|
|
17243
|
+
function spanNameFromAgents(span) {
|
|
17244
|
+
const spanData = span.spanData;
|
|
17245
|
+
if ("name" in spanData && spanData.name) {
|
|
17246
|
+
return spanData.name;
|
|
17247
|
+
}
|
|
17248
|
+
switch (spanData.type) {
|
|
17249
|
+
case "generation":
|
|
17250
|
+
return "Generation";
|
|
17251
|
+
case "response":
|
|
17252
|
+
return "Response";
|
|
17253
|
+
case "handoff":
|
|
17254
|
+
return "Handoff";
|
|
17255
|
+
case "mcp_tools":
|
|
17256
|
+
return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
|
|
17257
|
+
case "transcription":
|
|
17258
|
+
return "Transcription";
|
|
17259
|
+
case "speech":
|
|
17260
|
+
return "Speech";
|
|
17261
|
+
case "speech_group":
|
|
17262
|
+
return "Speech Group";
|
|
17263
|
+
default:
|
|
17264
|
+
return "Unknown";
|
|
17265
|
+
}
|
|
17266
|
+
}
|
|
17267
|
+
function getTimeElapsed(end, start) {
|
|
17268
|
+
if (!start || !end) {
|
|
17269
|
+
return void 0;
|
|
17270
|
+
}
|
|
17271
|
+
const startTime = new Date(start).getTime();
|
|
17272
|
+
const endTime = new Date(end).getTime();
|
|
17273
|
+
if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
|
|
17274
|
+
return void 0;
|
|
17275
|
+
}
|
|
17276
|
+
return (endTime - startTime) / 1e3;
|
|
17277
|
+
}
|
|
17278
|
+
function getNumberProperty2(obj, key) {
|
|
17279
|
+
if (!isObject(obj) || !(key in obj)) {
|
|
17280
|
+
return void 0;
|
|
17281
|
+
}
|
|
17282
|
+
const value = obj[key];
|
|
17283
|
+
return typeof value === "number" ? value : void 0;
|
|
17284
|
+
}
|
|
17285
|
+
function parseUsageMetrics(usage) {
|
|
17286
|
+
const metrics = {};
|
|
17287
|
+
if (!isObject(usage)) {
|
|
17288
|
+
return metrics;
|
|
17289
|
+
}
|
|
17290
|
+
const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
|
|
17291
|
+
const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
|
|
17292
|
+
const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
|
|
17293
|
+
if (promptTokens !== void 0) {
|
|
17294
|
+
metrics.prompt_tokens = promptTokens;
|
|
17295
|
+
}
|
|
17296
|
+
if (completionTokens !== void 0) {
|
|
17297
|
+
metrics.completion_tokens = completionTokens;
|
|
17298
|
+
}
|
|
17299
|
+
if (totalTokens !== void 0) {
|
|
17300
|
+
metrics.tokens = totalTokens;
|
|
17301
|
+
} else if (promptTokens !== void 0 && completionTokens !== void 0) {
|
|
17302
|
+
metrics.tokens = promptTokens + completionTokens;
|
|
17303
|
+
}
|
|
17304
|
+
const inputDetails = usage.input_tokens_details;
|
|
17305
|
+
const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
|
|
17306
|
+
const cacheWriteTokens = getNumberProperty2(
|
|
17307
|
+
inputDetails,
|
|
17308
|
+
"cache_write_tokens"
|
|
17309
|
+
);
|
|
17310
|
+
if (cachedTokens !== void 0) {
|
|
17311
|
+
metrics.prompt_cached_tokens = cachedTokens;
|
|
17312
|
+
}
|
|
17313
|
+
if (cacheWriteTokens !== void 0) {
|
|
17314
|
+
metrics.prompt_cache_creation_tokens = cacheWriteTokens;
|
|
17315
|
+
}
|
|
17316
|
+
return metrics;
|
|
17317
|
+
}
|
|
17318
|
+
var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
|
|
17319
|
+
static DEFAULT_MAX_TRACES = 1e4;
|
|
17320
|
+
logger;
|
|
17321
|
+
maxTraces;
|
|
17322
|
+
traceSpans = /* @__PURE__ */ new Map();
|
|
17323
|
+
traceOrder = [];
|
|
17324
|
+
_traceSpans = this.traceSpans;
|
|
17325
|
+
constructor(options = {}) {
|
|
17326
|
+
this.logger = options.logger;
|
|
17327
|
+
this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
|
|
17328
|
+
}
|
|
17329
|
+
evictOldestTrace() {
|
|
17330
|
+
const oldestTraceId = this.traceOrder.shift();
|
|
17331
|
+
if (oldestTraceId) {
|
|
17332
|
+
this.traceSpans.delete(oldestTraceId);
|
|
17333
|
+
}
|
|
17334
|
+
}
|
|
17335
|
+
onTraceStart(trace) {
|
|
17336
|
+
if (!trace?.traceId) {
|
|
17337
|
+
return Promise.resolve();
|
|
17338
|
+
}
|
|
17339
|
+
if (this.traceOrder.length >= this.maxTraces) {
|
|
17340
|
+
this.evictOldestTrace();
|
|
17341
|
+
}
|
|
17342
|
+
const current = currentSpan();
|
|
17343
|
+
const span = current && current !== NOOP_SPAN ? current.startSpan({
|
|
17344
|
+
name: trace.name,
|
|
17345
|
+
type: "task" /* TASK */
|
|
17346
|
+
}) : this.logger ? this.logger.startSpan({
|
|
17347
|
+
name: trace.name,
|
|
17348
|
+
type: "task" /* TASK */
|
|
17349
|
+
}) : startSpan({
|
|
17350
|
+
name: trace.name,
|
|
17351
|
+
type: "task" /* TASK */
|
|
17352
|
+
});
|
|
17353
|
+
span.log({
|
|
17354
|
+
input: "Agent workflow started",
|
|
17355
|
+
metadata: {
|
|
17356
|
+
group_id: trace.groupId,
|
|
17357
|
+
...trace.metadata || {}
|
|
17358
|
+
}
|
|
17359
|
+
});
|
|
17360
|
+
this.traceSpans.set(trace.traceId, {
|
|
17361
|
+
rootSpan: span,
|
|
17362
|
+
childSpans: /* @__PURE__ */ new Map(),
|
|
17363
|
+
metadata: {
|
|
17364
|
+
firstInput: null,
|
|
17365
|
+
lastOutput: null
|
|
17366
|
+
}
|
|
17367
|
+
});
|
|
17368
|
+
this.traceOrder.push(trace.traceId);
|
|
17369
|
+
return Promise.resolve();
|
|
17370
|
+
}
|
|
17371
|
+
async onTraceEnd(trace) {
|
|
17372
|
+
const traceData = this.traceSpans.get(trace?.traceId);
|
|
17373
|
+
if (!traceData) {
|
|
17374
|
+
return;
|
|
17375
|
+
}
|
|
17376
|
+
try {
|
|
17377
|
+
traceData.rootSpan.log({
|
|
17378
|
+
input: traceData.metadata.firstInput,
|
|
17379
|
+
output: traceData.metadata.lastOutput
|
|
17380
|
+
});
|
|
17381
|
+
traceData.rootSpan.end();
|
|
17382
|
+
await traceData.rootSpan.flush();
|
|
17383
|
+
} finally {
|
|
17384
|
+
this.traceSpans.delete(trace.traceId);
|
|
17385
|
+
const orderIndex = this.traceOrder.indexOf(trace.traceId);
|
|
17386
|
+
if (orderIndex > -1) {
|
|
17387
|
+
this.traceOrder.splice(orderIndex, 1);
|
|
17388
|
+
}
|
|
17389
|
+
}
|
|
17390
|
+
}
|
|
17391
|
+
onSpanStart(span) {
|
|
17392
|
+
if (!span?.spanId || !span.traceId) {
|
|
17393
|
+
return Promise.resolve();
|
|
17394
|
+
}
|
|
17395
|
+
const traceData = this.traceSpans.get(span.traceId);
|
|
17396
|
+
if (!traceData) {
|
|
17397
|
+
return Promise.resolve();
|
|
17398
|
+
}
|
|
17399
|
+
const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
|
|
17400
|
+
if (!parentSpan) {
|
|
17401
|
+
return Promise.resolve();
|
|
17402
|
+
}
|
|
17403
|
+
const childSpan = parentSpan.startSpan({
|
|
17404
|
+
name: spanNameFromAgents(span),
|
|
17405
|
+
type: spanTypeFromAgents(span)
|
|
17406
|
+
});
|
|
17407
|
+
traceData.childSpans.set(span.spanId, childSpan);
|
|
17408
|
+
return Promise.resolve();
|
|
17409
|
+
}
|
|
17410
|
+
onSpanEnd(span) {
|
|
17411
|
+
if (!span?.spanId || !span.traceId) {
|
|
17412
|
+
return Promise.resolve();
|
|
17413
|
+
}
|
|
17414
|
+
const traceData = this.traceSpans.get(span.traceId);
|
|
17415
|
+
if (!traceData) {
|
|
17416
|
+
return Promise.resolve();
|
|
17417
|
+
}
|
|
17418
|
+
const braintrustSpan = traceData.childSpans.get(span.spanId);
|
|
17419
|
+
if (!braintrustSpan) {
|
|
17420
|
+
return Promise.resolve();
|
|
17421
|
+
}
|
|
17422
|
+
const logData = this.extractLogData(span);
|
|
17423
|
+
braintrustSpan.log({
|
|
17424
|
+
error: span.error,
|
|
17425
|
+
...logData
|
|
17426
|
+
});
|
|
17427
|
+
braintrustSpan.end();
|
|
17428
|
+
traceData.childSpans.delete(span.spanId);
|
|
17429
|
+
const input = logData.input;
|
|
17430
|
+
const output = logData.output;
|
|
17431
|
+
if (traceData.metadata.firstInput === null && input != null) {
|
|
17432
|
+
traceData.metadata.firstInput = input;
|
|
17433
|
+
}
|
|
17434
|
+
if (output != null) {
|
|
17435
|
+
traceData.metadata.lastOutput = output;
|
|
17436
|
+
}
|
|
17437
|
+
return Promise.resolve();
|
|
17438
|
+
}
|
|
17439
|
+
async shutdown() {
|
|
17440
|
+
if (this.logger && typeof this.logger.flush === "function") {
|
|
17441
|
+
await this.logger.flush();
|
|
17442
|
+
}
|
|
17443
|
+
}
|
|
17444
|
+
async forceFlush() {
|
|
17445
|
+
if (this.logger && typeof this.logger.flush === "function") {
|
|
17446
|
+
await this.logger.flush();
|
|
17447
|
+
}
|
|
17448
|
+
}
|
|
17449
|
+
extractLogData(span) {
|
|
17450
|
+
const spanData = span.spanData;
|
|
17451
|
+
switch (spanData.type) {
|
|
17452
|
+
case "agent":
|
|
17453
|
+
return this.extractAgentLogData(spanData);
|
|
17454
|
+
case "response":
|
|
17455
|
+
return this.extractResponseLogData(spanData, span);
|
|
17456
|
+
case "function":
|
|
17457
|
+
return this.extractFunctionLogData(spanData);
|
|
17458
|
+
case "handoff":
|
|
17459
|
+
return this.extractHandoffLogData(spanData);
|
|
17460
|
+
case "guardrail":
|
|
17461
|
+
return this.extractGuardrailLogData(spanData);
|
|
17462
|
+
case "generation":
|
|
17463
|
+
return this.extractGenerationLogData(spanData, span);
|
|
17464
|
+
case "custom":
|
|
17465
|
+
return this.extractCustomLogData(spanData);
|
|
17466
|
+
case "mcp_tools":
|
|
17467
|
+
return this.extractMCPListToolsLogData(spanData);
|
|
17468
|
+
case "transcription":
|
|
17469
|
+
return this.extractTranscriptionLogData(spanData);
|
|
17470
|
+
case "speech":
|
|
17471
|
+
return this.extractSpeechLogData(spanData);
|
|
17472
|
+
case "speech_group":
|
|
17473
|
+
return this.extractSpeechGroupLogData(spanData);
|
|
17474
|
+
default:
|
|
17475
|
+
return {};
|
|
17476
|
+
}
|
|
17477
|
+
}
|
|
17478
|
+
extractAgentLogData(spanData) {
|
|
17479
|
+
return {
|
|
17480
|
+
metadata: {
|
|
17481
|
+
tools: spanData.tools,
|
|
17482
|
+
handoffs: spanData.handoffs,
|
|
17483
|
+
output_type: spanData.output_type
|
|
17484
|
+
}
|
|
17485
|
+
};
|
|
17486
|
+
}
|
|
17487
|
+
extractResponseLogData(spanData, span) {
|
|
17488
|
+
const response = spanData._response;
|
|
17489
|
+
const output = isObject(response) ? response.output : void 0;
|
|
17490
|
+
const usage = isObject(response) ? response.usage : void 0;
|
|
17491
|
+
const metrics = {
|
|
17492
|
+
...this.extractTimingMetrics(span),
|
|
17493
|
+
...parseUsageMetrics(usage)
|
|
17494
|
+
};
|
|
17495
|
+
return {
|
|
17496
|
+
input: spanData._input,
|
|
17497
|
+
output,
|
|
17498
|
+
metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
|
|
17499
|
+
metrics
|
|
17500
|
+
};
|
|
17501
|
+
}
|
|
17502
|
+
extractFunctionLogData(spanData) {
|
|
17503
|
+
return {
|
|
17504
|
+
input: spanData.input,
|
|
17505
|
+
output: spanData.output
|
|
17506
|
+
};
|
|
17507
|
+
}
|
|
17508
|
+
extractHandoffLogData(spanData) {
|
|
17509
|
+
return {
|
|
17510
|
+
metadata: {
|
|
17511
|
+
from_agent: spanData.from_agent,
|
|
17512
|
+
to_agent: spanData.to_agent
|
|
17513
|
+
}
|
|
17514
|
+
};
|
|
17515
|
+
}
|
|
17516
|
+
extractGuardrailLogData(spanData) {
|
|
17517
|
+
return {
|
|
17518
|
+
metadata: {
|
|
17519
|
+
triggered: spanData.triggered
|
|
17520
|
+
}
|
|
17521
|
+
};
|
|
17522
|
+
}
|
|
17523
|
+
extractGenerationLogData(spanData, span) {
|
|
17524
|
+
return {
|
|
17525
|
+
input: spanData.input,
|
|
17526
|
+
output: spanData.output,
|
|
17527
|
+
metadata: {
|
|
17528
|
+
model: spanData.model,
|
|
17529
|
+
model_config: spanData.model_config
|
|
17530
|
+
},
|
|
17531
|
+
metrics: {
|
|
17532
|
+
...this.extractTimingMetrics(span),
|
|
17533
|
+
...parseUsageMetrics(spanData.usage)
|
|
17534
|
+
}
|
|
17535
|
+
};
|
|
17536
|
+
}
|
|
17537
|
+
extractCustomLogData(spanData) {
|
|
17538
|
+
return spanData.data || {};
|
|
17539
|
+
}
|
|
17540
|
+
extractMCPListToolsLogData(spanData) {
|
|
17541
|
+
return {
|
|
17542
|
+
output: spanData.result,
|
|
17543
|
+
metadata: {
|
|
17544
|
+
server: spanData.server
|
|
17545
|
+
}
|
|
17546
|
+
};
|
|
17547
|
+
}
|
|
17548
|
+
extractTranscriptionLogData(spanData) {
|
|
17549
|
+
return {
|
|
17550
|
+
input: spanData.input,
|
|
17551
|
+
output: spanData.output,
|
|
17552
|
+
metadata: {
|
|
17553
|
+
model: spanData.model,
|
|
17554
|
+
model_config: spanData.model_config
|
|
17555
|
+
}
|
|
17556
|
+
};
|
|
17557
|
+
}
|
|
17558
|
+
extractSpeechLogData(spanData) {
|
|
17559
|
+
return {
|
|
17560
|
+
input: spanData.input,
|
|
17561
|
+
output: spanData.output,
|
|
17562
|
+
metadata: {
|
|
17563
|
+
model: spanData.model,
|
|
17564
|
+
model_config: spanData.model_config
|
|
17565
|
+
}
|
|
17566
|
+
};
|
|
17567
|
+
}
|
|
17568
|
+
extractSpeechGroupLogData(spanData) {
|
|
17569
|
+
return {
|
|
17570
|
+
input: spanData.input
|
|
17571
|
+
};
|
|
17572
|
+
}
|
|
17573
|
+
extractTimingMetrics(span) {
|
|
17574
|
+
const timeToFirstToken = getTimeElapsed(
|
|
17575
|
+
span.endedAt ?? void 0,
|
|
17576
|
+
span.startedAt ?? void 0
|
|
17577
|
+
);
|
|
17578
|
+
return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
|
|
17579
|
+
}
|
|
17580
|
+
omitKeys(value, keys) {
|
|
17581
|
+
const result = {};
|
|
17582
|
+
for (const [key, fieldValue] of Object.entries(value)) {
|
|
17583
|
+
if (!keys.includes(key)) {
|
|
17584
|
+
result[key] = fieldValue;
|
|
17585
|
+
}
|
|
17586
|
+
}
|
|
17587
|
+
return result;
|
|
17588
|
+
}
|
|
17589
|
+
};
|
|
17590
|
+
|
|
17591
|
+
// src/instrumentation/plugins/openai-agents-plugin.ts
|
|
17592
|
+
function firstArgument(args) {
|
|
17593
|
+
if (Array.isArray(args)) {
|
|
17594
|
+
return args[0];
|
|
17595
|
+
}
|
|
17596
|
+
if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
|
|
17597
|
+
return Array.from(args)[0];
|
|
17598
|
+
}
|
|
17599
|
+
return void 0;
|
|
17600
|
+
}
|
|
17601
|
+
function isOpenAIAgentsTrace(value) {
|
|
17602
|
+
return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
|
|
17603
|
+
}
|
|
17604
|
+
function isOpenAIAgentsSpan(value) {
|
|
17605
|
+
return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
|
|
17606
|
+
}
|
|
17607
|
+
var OpenAIAgentsPlugin = class extends BasePlugin {
|
|
17608
|
+
processor = new OpenAIAgentsTraceProcessor();
|
|
17609
|
+
onEnable() {
|
|
17610
|
+
this.subscribeToTraceLifecycle();
|
|
17611
|
+
}
|
|
17612
|
+
onDisable() {
|
|
17613
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
17614
|
+
void this.processor.shutdown();
|
|
17615
|
+
}
|
|
17616
|
+
subscribeToTraceLifecycle() {
|
|
17617
|
+
const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
|
|
17618
|
+
const traceStartHandlers = {
|
|
17619
|
+
start: (event) => {
|
|
17620
|
+
const trace = firstArgument(event.arguments);
|
|
17621
|
+
if (isOpenAIAgentsTrace(trace)) {
|
|
17622
|
+
void this.processor.onTraceStart(trace);
|
|
17623
|
+
}
|
|
17624
|
+
}
|
|
17625
|
+
};
|
|
17626
|
+
traceStartChannel.subscribe(traceStartHandlers);
|
|
17627
|
+
this.unsubscribers.push(
|
|
17628
|
+
() => traceStartChannel.unsubscribe(traceStartHandlers)
|
|
17629
|
+
);
|
|
17630
|
+
const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
|
|
17631
|
+
const traceEndHandlers = {
|
|
17632
|
+
start: (event) => {
|
|
17633
|
+
const trace = firstArgument(event.arguments);
|
|
17634
|
+
if (isOpenAIAgentsTrace(trace)) {
|
|
17635
|
+
void this.processor.onTraceEnd(trace);
|
|
17636
|
+
}
|
|
17637
|
+
}
|
|
17638
|
+
};
|
|
17639
|
+
traceEndChannel.subscribe(traceEndHandlers);
|
|
17640
|
+
this.unsubscribers.push(
|
|
17641
|
+
() => traceEndChannel.unsubscribe(traceEndHandlers)
|
|
17642
|
+
);
|
|
17643
|
+
const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
|
|
17644
|
+
const spanStartHandlers = {
|
|
17645
|
+
start: (event) => {
|
|
17646
|
+
const span = firstArgument(event.arguments);
|
|
17647
|
+
if (isOpenAIAgentsSpan(span)) {
|
|
17648
|
+
void this.processor.onSpanStart(span);
|
|
17649
|
+
}
|
|
17650
|
+
}
|
|
17651
|
+
};
|
|
17652
|
+
spanStartChannel.subscribe(spanStartHandlers);
|
|
17653
|
+
this.unsubscribers.push(
|
|
17654
|
+
() => spanStartChannel.unsubscribe(spanStartHandlers)
|
|
17655
|
+
);
|
|
17656
|
+
const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
|
|
17657
|
+
const spanEndHandlers = {
|
|
17658
|
+
start: (event) => {
|
|
17659
|
+
const span = firstArgument(event.arguments);
|
|
17660
|
+
if (isOpenAIAgentsSpan(span)) {
|
|
17661
|
+
void this.processor.onSpanEnd(span);
|
|
17662
|
+
}
|
|
17663
|
+
}
|
|
17664
|
+
};
|
|
17665
|
+
spanEndChannel.subscribe(spanEndHandlers);
|
|
17666
|
+
this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
|
|
17667
|
+
}
|
|
17668
|
+
};
|
|
17669
|
+
|
|
17189
17670
|
// src/instrumentation/plugins/google-genai-channels.ts
|
|
17190
17671
|
var googleGenAIChannels = defineChannels("@google/genai", {
|
|
17191
17672
|
generateContent: channel({
|
|
@@ -23478,58 +23959,1794 @@ var GitHubCopilotPlugin = class extends BasePlugin {
|
|
|
23478
23959
|
}
|
|
23479
23960
|
};
|
|
23480
23961
|
|
|
23481
|
-
// src/instrumentation/
|
|
23482
|
-
|
|
23483
|
-
|
|
23962
|
+
// src/instrumentation/plugins/flue-channels.ts
|
|
23963
|
+
var flueChannels = defineChannels("@flue/runtime", {
|
|
23964
|
+
createContext: channel({
|
|
23965
|
+
channelName: "createFlueContext",
|
|
23966
|
+
kind: "sync-stream"
|
|
23967
|
+
}),
|
|
23968
|
+
openSession: channel({
|
|
23969
|
+
channelName: "Harness.openSession",
|
|
23970
|
+
kind: "async"
|
|
23971
|
+
}),
|
|
23972
|
+
contextEvent: channel({
|
|
23973
|
+
channelName: "context.event",
|
|
23974
|
+
kind: "sync-stream"
|
|
23975
|
+
}),
|
|
23976
|
+
prompt: channel({
|
|
23977
|
+
channelName: "session.prompt",
|
|
23978
|
+
kind: "async"
|
|
23979
|
+
}),
|
|
23980
|
+
skill: channel({
|
|
23981
|
+
channelName: "session.skill",
|
|
23982
|
+
kind: "async"
|
|
23983
|
+
}),
|
|
23984
|
+
task: channel({
|
|
23985
|
+
channelName: "session.task",
|
|
23986
|
+
kind: "async"
|
|
23987
|
+
}),
|
|
23988
|
+
compact: channel({
|
|
23989
|
+
channelName: "session.compact",
|
|
23990
|
+
kind: "async"
|
|
23991
|
+
})
|
|
23992
|
+
});
|
|
23993
|
+
|
|
23994
|
+
// src/wrappers/flue.ts
|
|
23995
|
+
var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
|
|
23996
|
+
var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
|
|
23997
|
+
var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
|
|
23998
|
+
var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
|
|
23999
|
+
"braintrust.flue.subscribed-context-events"
|
|
24000
|
+
);
|
|
24001
|
+
function wrapFlueContext(ctx) {
|
|
24002
|
+
if (!isPlausibleFlueContext(ctx)) {
|
|
24003
|
+
console.warn("Unsupported Flue context. Not wrapping.");
|
|
24004
|
+
return ctx;
|
|
24005
|
+
}
|
|
24006
|
+
const context = ctx;
|
|
24007
|
+
subscribeFlueContextEvents(context, { captureTurnSpans: true });
|
|
24008
|
+
return patchFlueContextInPlace(context);
|
|
23484
24009
|
}
|
|
23485
|
-
|
|
23486
|
-
|
|
23487
|
-
|
|
23488
|
-
|
|
23489
|
-
anthropicPlugin = null;
|
|
23490
|
-
aiSDKPlugin = null;
|
|
23491
|
-
claudeAgentSDKPlugin = null;
|
|
23492
|
-
cursorSDKPlugin = null;
|
|
23493
|
-
googleGenAIPlugin = null;
|
|
23494
|
-
huggingFacePlugin = null;
|
|
23495
|
-
openRouterPlugin = null;
|
|
23496
|
-
openRouterAgentPlugin = null;
|
|
23497
|
-
mistralPlugin = null;
|
|
23498
|
-
googleADKPlugin = null;
|
|
23499
|
-
coherePlugin = null;
|
|
23500
|
-
groqPlugin = null;
|
|
23501
|
-
genkitPlugin = null;
|
|
23502
|
-
gitHubCopilotPlugin = null;
|
|
23503
|
-
constructor(config = {}) {
|
|
23504
|
-
super();
|
|
23505
|
-
this.config = config;
|
|
24010
|
+
function patchFlueContextInPlace(ctx) {
|
|
24011
|
+
const context = ctx;
|
|
24012
|
+
if (context[WRAPPED_FLUE_CONTEXT]) {
|
|
24013
|
+
return ctx;
|
|
23506
24014
|
}
|
|
23507
|
-
|
|
23508
|
-
|
|
23509
|
-
|
|
23510
|
-
|
|
23511
|
-
|
|
23512
|
-
|
|
23513
|
-
|
|
23514
|
-
|
|
23515
|
-
|
|
23516
|
-
|
|
23517
|
-
|
|
23518
|
-
|
|
23519
|
-
|
|
23520
|
-
|
|
23521
|
-
|
|
23522
|
-
|
|
23523
|
-
|
|
23524
|
-
|
|
23525
|
-
|
|
23526
|
-
|
|
24015
|
+
const originalInit = context.init.bind(context);
|
|
24016
|
+
try {
|
|
24017
|
+
Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
|
|
24018
|
+
configurable: false,
|
|
24019
|
+
enumerable: false,
|
|
24020
|
+
value: true
|
|
24021
|
+
});
|
|
24022
|
+
Object.defineProperty(context, "init", {
|
|
24023
|
+
configurable: true,
|
|
24024
|
+
value: async function wrappedFlueInit(options) {
|
|
24025
|
+
const harness = await originalInit(options);
|
|
24026
|
+
return wrapFlueHarness(harness);
|
|
24027
|
+
},
|
|
24028
|
+
writable: true
|
|
24029
|
+
});
|
|
24030
|
+
} catch {
|
|
24031
|
+
}
|
|
24032
|
+
return ctx;
|
|
24033
|
+
}
|
|
24034
|
+
function wrapFlueSession(session) {
|
|
24035
|
+
if (!isPlausibleFlueSession(session)) {
|
|
24036
|
+
console.warn("Unsupported Flue session. Not wrapping.");
|
|
24037
|
+
return session;
|
|
24038
|
+
}
|
|
24039
|
+
return patchFlueSessionInPlace(session);
|
|
24040
|
+
}
|
|
24041
|
+
function subscribeFlueContextEvents(ctx, options = {}) {
|
|
24042
|
+
if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
|
|
24043
|
+
return void 0;
|
|
24044
|
+
}
|
|
24045
|
+
const context = ctx;
|
|
24046
|
+
const captureTurnSpans = options.captureTurnSpans ?? true;
|
|
24047
|
+
const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
|
|
24048
|
+
if (existingSubscription) {
|
|
24049
|
+
if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
|
|
24050
|
+
return void 0;
|
|
24051
|
+
}
|
|
24052
|
+
try {
|
|
24053
|
+
existingSubscription.unsubscribe();
|
|
24054
|
+
} catch {
|
|
24055
|
+
}
|
|
24056
|
+
}
|
|
24057
|
+
try {
|
|
24058
|
+
const unsubscribe = ctx.subscribeEvent((event) => {
|
|
24059
|
+
flueChannels.contextEvent.traceSync(() => void 0, {
|
|
24060
|
+
arguments: [event],
|
|
24061
|
+
captureTurnSpans,
|
|
24062
|
+
context: ctx
|
|
24063
|
+
});
|
|
24064
|
+
});
|
|
24065
|
+
if (existingSubscription) {
|
|
24066
|
+
existingSubscription.captureTurnSpans = captureTurnSpans;
|
|
24067
|
+
existingSubscription.unsubscribe = unsubscribe;
|
|
24068
|
+
} else {
|
|
24069
|
+
Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
|
|
24070
|
+
configurable: false,
|
|
24071
|
+
enumerable: false,
|
|
24072
|
+
value: {
|
|
24073
|
+
captureTurnSpans,
|
|
24074
|
+
unsubscribe
|
|
24075
|
+
}
|
|
24076
|
+
});
|
|
24077
|
+
}
|
|
24078
|
+
return unsubscribe;
|
|
24079
|
+
} catch {
|
|
24080
|
+
return void 0;
|
|
24081
|
+
}
|
|
24082
|
+
}
|
|
24083
|
+
function wrapFlueHarness(harness) {
|
|
24084
|
+
if (!isPlausibleFlueHarness(harness)) {
|
|
24085
|
+
return harness;
|
|
24086
|
+
}
|
|
24087
|
+
const target = harness;
|
|
24088
|
+
if (target[WRAPPED_FLUE_HARNESS]) {
|
|
24089
|
+
return harness;
|
|
24090
|
+
}
|
|
24091
|
+
const originalSession = target.session.bind(target);
|
|
24092
|
+
try {
|
|
24093
|
+
Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
|
|
24094
|
+
configurable: false,
|
|
24095
|
+
enumerable: false,
|
|
24096
|
+
value: true
|
|
24097
|
+
});
|
|
24098
|
+
Object.defineProperty(target, "session", {
|
|
24099
|
+
configurable: true,
|
|
24100
|
+
value: async function wrappedFlueHarnessSession(name, options) {
|
|
24101
|
+
const session = await originalSession(name, options);
|
|
24102
|
+
return patchFlueSessionInPlace(session);
|
|
24103
|
+
},
|
|
24104
|
+
writable: true
|
|
24105
|
+
});
|
|
24106
|
+
const sessions = target.sessions;
|
|
24107
|
+
if (sessions && typeof sessions === "object") {
|
|
24108
|
+
patchFlueSessionFactory(sessions, "get");
|
|
24109
|
+
patchFlueSessionFactory(sessions, "create");
|
|
24110
|
+
}
|
|
24111
|
+
} catch {
|
|
24112
|
+
}
|
|
24113
|
+
return harness;
|
|
24114
|
+
}
|
|
24115
|
+
function patchFlueSessionInPlace(session) {
|
|
24116
|
+
if (session[WRAPPED_FLUE_SESSION]) {
|
|
24117
|
+
return session;
|
|
24118
|
+
}
|
|
24119
|
+
try {
|
|
24120
|
+
Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
|
|
24121
|
+
configurable: false,
|
|
24122
|
+
enumerable: false,
|
|
24123
|
+
value: true
|
|
24124
|
+
});
|
|
24125
|
+
patchCallHandleMethod(session, "prompt", flueChannels.prompt);
|
|
24126
|
+
patchCallHandleMethod(session, "skill", flueChannels.skill);
|
|
24127
|
+
patchCallHandleMethod(session, "task", flueChannels.task);
|
|
24128
|
+
patchCompact(session);
|
|
24129
|
+
} catch {
|
|
24130
|
+
}
|
|
24131
|
+
return session;
|
|
24132
|
+
}
|
|
24133
|
+
function patchFlueSessionFactory(sessions, method) {
|
|
24134
|
+
const original = sessions[method];
|
|
24135
|
+
if (typeof original !== "function") {
|
|
24136
|
+
return;
|
|
24137
|
+
}
|
|
24138
|
+
const bound = original.bind(sessions);
|
|
24139
|
+
Object.defineProperty(sessions, method, {
|
|
24140
|
+
configurable: true,
|
|
24141
|
+
value: async function wrappedFlueSessionFactory(name, options) {
|
|
24142
|
+
const session = await bound(name, options);
|
|
24143
|
+
return patchFlueSessionInPlace(session);
|
|
24144
|
+
},
|
|
24145
|
+
writable: true
|
|
24146
|
+
});
|
|
24147
|
+
}
|
|
24148
|
+
function patchCallHandleMethod(session, method, channel2) {
|
|
24149
|
+
const original = session[method];
|
|
24150
|
+
if (typeof original !== "function") {
|
|
24151
|
+
return;
|
|
24152
|
+
}
|
|
24153
|
+
const bound = original.bind(session);
|
|
24154
|
+
Object.defineProperty(session, method, {
|
|
24155
|
+
configurable: true,
|
|
24156
|
+
value(input, options) {
|
|
24157
|
+
const args = [input, options];
|
|
24158
|
+
const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
|
|
24159
|
+
context: {
|
|
24160
|
+
arguments: args,
|
|
24161
|
+
operation: method,
|
|
24162
|
+
session
|
|
24163
|
+
},
|
|
24164
|
+
run: () => bound(input, options)
|
|
24165
|
+
});
|
|
24166
|
+
return preserveCallHandle(originalResult, traced2);
|
|
24167
|
+
},
|
|
24168
|
+
writable: true
|
|
24169
|
+
});
|
|
24170
|
+
}
|
|
24171
|
+
function patchCompact(session) {
|
|
24172
|
+
const original = session.compact;
|
|
24173
|
+
if (typeof original !== "function") {
|
|
24174
|
+
return;
|
|
24175
|
+
}
|
|
24176
|
+
const bound = original.bind(session);
|
|
24177
|
+
Object.defineProperty(session, "compact", {
|
|
24178
|
+
configurable: true,
|
|
24179
|
+
value() {
|
|
24180
|
+
const context = {
|
|
24181
|
+
arguments: [],
|
|
24182
|
+
operation: "compact",
|
|
24183
|
+
session
|
|
24184
|
+
};
|
|
24185
|
+
return flueChannels.compact.tracePromise(() => bound(), context);
|
|
24186
|
+
},
|
|
24187
|
+
writable: true
|
|
24188
|
+
});
|
|
24189
|
+
}
|
|
24190
|
+
function traceFlueOperation(channel2, args) {
|
|
24191
|
+
const tracingChannel2 = channel2.tracingChannel();
|
|
24192
|
+
const context = args.context;
|
|
24193
|
+
let originalResult;
|
|
24194
|
+
let traced2;
|
|
24195
|
+
const run = () => {
|
|
24196
|
+
try {
|
|
24197
|
+
originalResult = args.run();
|
|
24198
|
+
tracingChannel2.end?.publish(context);
|
|
24199
|
+
} catch (error) {
|
|
24200
|
+
context.error = normalizeError3(error);
|
|
24201
|
+
tracingChannel2.error?.publish(context);
|
|
24202
|
+
tracingChannel2.end?.publish(context);
|
|
24203
|
+
throw error;
|
|
24204
|
+
}
|
|
24205
|
+
traced2 = Promise.resolve(originalResult).then(
|
|
24206
|
+
(result) => {
|
|
24207
|
+
context.result = result;
|
|
24208
|
+
tracingChannel2.asyncStart?.publish(context);
|
|
24209
|
+
tracingChannel2.asyncEnd?.publish(context);
|
|
24210
|
+
return result;
|
|
24211
|
+
},
|
|
24212
|
+
(error) => {
|
|
24213
|
+
context.error = normalizeError3(error);
|
|
24214
|
+
tracingChannel2.error?.publish(context);
|
|
24215
|
+
tracingChannel2.asyncStart?.publish(context);
|
|
24216
|
+
tracingChannel2.asyncEnd?.publish(context);
|
|
24217
|
+
throw error;
|
|
24218
|
+
}
|
|
24219
|
+
);
|
|
24220
|
+
};
|
|
24221
|
+
if (tracingChannel2.start?.runStores) {
|
|
24222
|
+
tracingChannel2.start.runStores(context, run);
|
|
24223
|
+
} else {
|
|
24224
|
+
tracingChannel2.start?.publish(context);
|
|
24225
|
+
run();
|
|
24226
|
+
}
|
|
24227
|
+
return { originalResult, traced: traced2 };
|
|
24228
|
+
}
|
|
24229
|
+
function normalizeError3(error) {
|
|
24230
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
24231
|
+
}
|
|
24232
|
+
function preserveCallHandle(originalHandle, traced2) {
|
|
24233
|
+
if (!isFlueCallHandle(originalHandle)) {
|
|
24234
|
+
return traced2;
|
|
24235
|
+
}
|
|
24236
|
+
const handle = originalHandle;
|
|
24237
|
+
const wrapped = {
|
|
24238
|
+
get signal() {
|
|
24239
|
+
return handle.signal;
|
|
24240
|
+
},
|
|
24241
|
+
abort(reason) {
|
|
24242
|
+
return handle.abort(reason);
|
|
24243
|
+
},
|
|
24244
|
+
then(onfulfilled, onrejected) {
|
|
24245
|
+
return traced2.then(onfulfilled, onrejected);
|
|
24246
|
+
}
|
|
24247
|
+
};
|
|
24248
|
+
return wrapped;
|
|
24249
|
+
}
|
|
24250
|
+
function isPlausibleFlueContext(value) {
|
|
24251
|
+
return !!value && typeof value === "object" && typeof value.init === "function";
|
|
24252
|
+
}
|
|
24253
|
+
function isPlausibleFlueHarness(value) {
|
|
24254
|
+
return !!value && typeof value === "object" && typeof value.session === "function";
|
|
24255
|
+
}
|
|
24256
|
+
function isPlausibleFlueSession(value) {
|
|
24257
|
+
return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
|
|
24258
|
+
}
|
|
24259
|
+
function isFlueCallHandle(value) {
|
|
24260
|
+
return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
|
|
24261
|
+
}
|
|
24262
|
+
|
|
24263
|
+
// src/instrumentation/plugins/flue-plugin.ts
|
|
24264
|
+
var FluePlugin = class extends BasePlugin {
|
|
24265
|
+
activeOperationsById = /* @__PURE__ */ new Map();
|
|
24266
|
+
activeOperationsByScope = /* @__PURE__ */ new Map();
|
|
24267
|
+
compactionsByScope = /* @__PURE__ */ new Map();
|
|
24268
|
+
pendingOperationsByKey = /* @__PURE__ */ new Map();
|
|
24269
|
+
tasksById = /* @__PURE__ */ new Map();
|
|
24270
|
+
toolsById = /* @__PURE__ */ new Map();
|
|
24271
|
+
turnsByScope = /* @__PURE__ */ new Map();
|
|
24272
|
+
onEnable() {
|
|
24273
|
+
this.subscribeToContextCreation();
|
|
24274
|
+
this.subscribeToSessionCreation();
|
|
24275
|
+
this.subscribeToContextEvents();
|
|
24276
|
+
this.subscribeToSessionOperations();
|
|
24277
|
+
}
|
|
24278
|
+
onDisable() {
|
|
24279
|
+
for (const unsubscribe of this.unsubscribers) {
|
|
24280
|
+
unsubscribe();
|
|
24281
|
+
}
|
|
24282
|
+
this.unsubscribers = [];
|
|
24283
|
+
this.activeOperationsById.clear();
|
|
24284
|
+
this.activeOperationsByScope.clear();
|
|
24285
|
+
this.compactionsByScope.clear();
|
|
24286
|
+
this.pendingOperationsByKey.clear();
|
|
24287
|
+
this.tasksById.clear();
|
|
24288
|
+
this.toolsById.clear();
|
|
24289
|
+
this.turnsByScope.clear();
|
|
24290
|
+
}
|
|
24291
|
+
subscribeToContextCreation() {
|
|
24292
|
+
const channel2 = flueChannels.createContext.tracingChannel();
|
|
24293
|
+
const handlers = {
|
|
24294
|
+
end: (event) => {
|
|
24295
|
+
const ctx = event.result;
|
|
24296
|
+
if (!ctx) {
|
|
24297
|
+
return;
|
|
24298
|
+
}
|
|
24299
|
+
subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
|
|
24300
|
+
patchFlueContextInPlace(ctx);
|
|
24301
|
+
},
|
|
24302
|
+
error: () => {
|
|
24303
|
+
}
|
|
24304
|
+
};
|
|
24305
|
+
channel2.subscribe(handlers);
|
|
24306
|
+
this.unsubscribers.push(() => {
|
|
24307
|
+
channel2.unsubscribe(handlers);
|
|
24308
|
+
});
|
|
24309
|
+
}
|
|
24310
|
+
subscribeToSessionCreation() {
|
|
24311
|
+
const channel2 = flueChannels.openSession.tracingChannel();
|
|
24312
|
+
const handlers = {
|
|
24313
|
+
asyncEnd: (event) => {
|
|
24314
|
+
if (event.result) {
|
|
24315
|
+
patchFlueSessionInPlace(
|
|
24316
|
+
event.result
|
|
24317
|
+
);
|
|
24318
|
+
}
|
|
24319
|
+
if (event.harness) {
|
|
24320
|
+
wrapFlueHarness(event.harness);
|
|
24321
|
+
}
|
|
24322
|
+
},
|
|
24323
|
+
error: () => {
|
|
24324
|
+
}
|
|
24325
|
+
};
|
|
24326
|
+
channel2.subscribe(handlers);
|
|
24327
|
+
this.unsubscribers.push(() => {
|
|
24328
|
+
channel2.unsubscribe(handlers);
|
|
24329
|
+
});
|
|
24330
|
+
}
|
|
24331
|
+
subscribeToSessionOperations() {
|
|
24332
|
+
this.subscribeToSessionOperation(flueChannels.prompt);
|
|
24333
|
+
this.subscribeToSessionOperation(flueChannels.skill);
|
|
24334
|
+
this.subscribeToSessionOperation(flueChannels.task);
|
|
24335
|
+
this.subscribeToCompact();
|
|
24336
|
+
}
|
|
24337
|
+
subscribeToSessionOperation(channel2) {
|
|
24338
|
+
const tracingChannel2 = channel2.tracingChannel();
|
|
24339
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
24340
|
+
const ensureState2 = (event) => {
|
|
24341
|
+
const existing = states.get(event);
|
|
24342
|
+
if (existing) {
|
|
24343
|
+
return existing;
|
|
24344
|
+
}
|
|
24345
|
+
const state = this.startOperationState({
|
|
24346
|
+
args: event.arguments,
|
|
24347
|
+
moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
|
|
24348
|
+
operation: event.operation,
|
|
24349
|
+
session: event.session
|
|
24350
|
+
});
|
|
24351
|
+
states.set(event, state);
|
|
24352
|
+
return state;
|
|
24353
|
+
};
|
|
24354
|
+
const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
|
|
24355
|
+
tracingChannel2,
|
|
24356
|
+
ensureState2
|
|
24357
|
+
);
|
|
24358
|
+
const handlers = {
|
|
24359
|
+
start: (event) => {
|
|
24360
|
+
ensureState2(event);
|
|
24361
|
+
},
|
|
24362
|
+
asyncEnd: (event) => {
|
|
24363
|
+
this.endOperationState(states.get(event), event.result);
|
|
24364
|
+
states.delete(event);
|
|
24365
|
+
},
|
|
24366
|
+
error: (event) => {
|
|
24367
|
+
const state = states.get(event);
|
|
24368
|
+
if (state && event.error) {
|
|
24369
|
+
safeLog3(state.span, { error: errorToString(event.error) });
|
|
24370
|
+
this.finishOperationState(state);
|
|
24371
|
+
}
|
|
24372
|
+
states.delete(event);
|
|
24373
|
+
}
|
|
24374
|
+
};
|
|
24375
|
+
tracingChannel2.subscribe(handlers);
|
|
24376
|
+
this.unsubscribers.push(() => {
|
|
24377
|
+
unbindCurrentSpanStore?.();
|
|
24378
|
+
tracingChannel2.unsubscribe(handlers);
|
|
24379
|
+
});
|
|
24380
|
+
}
|
|
24381
|
+
subscribeToCompact() {
|
|
24382
|
+
const tracingChannel2 = flueChannels.compact.tracingChannel();
|
|
24383
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
24384
|
+
const ensureState2 = (event) => {
|
|
24385
|
+
const existing = states.get(event);
|
|
24386
|
+
if (existing) {
|
|
24387
|
+
return existing;
|
|
24388
|
+
}
|
|
24389
|
+
const state = this.startOperationState({
|
|
24390
|
+
args: [],
|
|
24391
|
+
moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
|
|
24392
|
+
operation: event.operation,
|
|
24393
|
+
session: event.session
|
|
24394
|
+
});
|
|
24395
|
+
states.set(event, state);
|
|
24396
|
+
return state;
|
|
24397
|
+
};
|
|
24398
|
+
const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
|
|
24399
|
+
tracingChannel2,
|
|
24400
|
+
ensureState2
|
|
24401
|
+
);
|
|
24402
|
+
const handlers = {
|
|
24403
|
+
start: (event) => {
|
|
24404
|
+
ensureState2(event);
|
|
24405
|
+
},
|
|
24406
|
+
asyncEnd: (event) => {
|
|
24407
|
+
this.endOperationState(states.get(event), void 0);
|
|
24408
|
+
states.delete(event);
|
|
24409
|
+
},
|
|
24410
|
+
error: (event) => {
|
|
24411
|
+
const state = states.get(event);
|
|
24412
|
+
if (state && event.error) {
|
|
24413
|
+
safeLog3(state.span, { error: errorToString(event.error) });
|
|
24414
|
+
this.finishOperationState(state);
|
|
24415
|
+
}
|
|
24416
|
+
states.delete(event);
|
|
24417
|
+
}
|
|
24418
|
+
};
|
|
24419
|
+
tracingChannel2.subscribe(handlers);
|
|
24420
|
+
this.unsubscribers.push(() => {
|
|
24421
|
+
unbindCurrentSpanStore?.();
|
|
24422
|
+
tracingChannel2.unsubscribe(handlers);
|
|
24423
|
+
});
|
|
24424
|
+
}
|
|
24425
|
+
subscribeToContextEvents() {
|
|
24426
|
+
const channel2 = flueChannels.contextEvent.tracingChannel();
|
|
24427
|
+
const handlers = {
|
|
24428
|
+
start: (event) => {
|
|
24429
|
+
const flueEvent = event.arguments[0];
|
|
24430
|
+
if (!flueEvent) {
|
|
24431
|
+
return;
|
|
24432
|
+
}
|
|
24433
|
+
try {
|
|
24434
|
+
this.handleFlueEvent(flueEvent, {
|
|
24435
|
+
captureTurnSpans: event.captureTurnSpans !== false
|
|
24436
|
+
});
|
|
24437
|
+
} catch (error) {
|
|
24438
|
+
logInstrumentationError3("Flue event", error);
|
|
24439
|
+
}
|
|
24440
|
+
},
|
|
24441
|
+
error: () => {
|
|
24442
|
+
}
|
|
24443
|
+
};
|
|
24444
|
+
channel2.subscribe(handlers);
|
|
24445
|
+
this.unsubscribers.push(() => {
|
|
24446
|
+
channel2.unsubscribe(handlers);
|
|
24447
|
+
});
|
|
24448
|
+
}
|
|
24449
|
+
bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
|
|
24450
|
+
const state = _internalGetGlobalState();
|
|
24451
|
+
const startChannel = tracingChannel2.start;
|
|
24452
|
+
const contextManager = state?.contextManager;
|
|
24453
|
+
const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
|
|
24454
|
+
if (!currentSpanStore || !startChannel) {
|
|
24455
|
+
return void 0;
|
|
24456
|
+
}
|
|
24457
|
+
startChannel.bindStore(currentSpanStore, (event) => {
|
|
24458
|
+
const operationState = ensureState2(event);
|
|
24459
|
+
return contextManager.wrapSpanForStore(operationState.span);
|
|
24460
|
+
});
|
|
24461
|
+
return () => {
|
|
24462
|
+
startChannel.unbindStore(currentSpanStore);
|
|
24463
|
+
};
|
|
24464
|
+
}
|
|
24465
|
+
startOperationState(args) {
|
|
24466
|
+
const sessionName = getSessionName(args.session);
|
|
24467
|
+
const metadata = {
|
|
24468
|
+
...extractOperationInputMetadata(args.operation, args.args),
|
|
24469
|
+
...extractSessionMetadata(args.session),
|
|
24470
|
+
"flue.operation": args.operation,
|
|
24471
|
+
provider: "flue",
|
|
24472
|
+
...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
|
|
24473
|
+
};
|
|
24474
|
+
const span = startSpan({
|
|
24475
|
+
name: `flue.session.${args.operation}`,
|
|
24476
|
+
spanAttributes: { type: "task" /* TASK */ }
|
|
24477
|
+
});
|
|
24478
|
+
const state = {
|
|
24479
|
+
metadata,
|
|
24480
|
+
operation: args.operation,
|
|
24481
|
+
sessionName,
|
|
24482
|
+
span,
|
|
24483
|
+
startTime: getCurrentUnixTimestamp()
|
|
24484
|
+
};
|
|
24485
|
+
safeLog3(span, {
|
|
24486
|
+
input: extractOperationInput(args.operation, args.args),
|
|
24487
|
+
metadata
|
|
24488
|
+
});
|
|
24489
|
+
this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
|
|
24490
|
+
state
|
|
24491
|
+
);
|
|
24492
|
+
addOperationToScope(
|
|
24493
|
+
this.activeOperationsByScope,
|
|
24494
|
+
sessionName ?? "unknown",
|
|
24495
|
+
state
|
|
24496
|
+
);
|
|
24497
|
+
return state;
|
|
24498
|
+
}
|
|
24499
|
+
endOperationState(state, result) {
|
|
24500
|
+
if (!state) {
|
|
24501
|
+
return;
|
|
24502
|
+
}
|
|
24503
|
+
const metadata = {
|
|
24504
|
+
...state.metadata,
|
|
24505
|
+
...extractPromptResponseMetadata(result)
|
|
24506
|
+
};
|
|
24507
|
+
const metrics = {
|
|
24508
|
+
...buildDurationMetrics3(state.startTime),
|
|
24509
|
+
...metricsFromUsage(result?.usage)
|
|
24510
|
+
};
|
|
24511
|
+
safeLog3(state.span, {
|
|
24512
|
+
metadata,
|
|
24513
|
+
metrics,
|
|
24514
|
+
output: extractOperationOutput(result)
|
|
24515
|
+
});
|
|
24516
|
+
this.finishCompactionsForOperation(state);
|
|
24517
|
+
this.finishOperationState(state);
|
|
24518
|
+
}
|
|
24519
|
+
finishOperationState(state) {
|
|
24520
|
+
removePendingOperation(this.pendingOperationsByKey, state);
|
|
24521
|
+
if (state.operationId) {
|
|
24522
|
+
this.activeOperationsById.delete(state.operationId);
|
|
24523
|
+
}
|
|
24524
|
+
removeScopedOperation(this.activeOperationsByScope, state);
|
|
24525
|
+
state.span.end();
|
|
24526
|
+
}
|
|
24527
|
+
handleFlueEvent(event, options) {
|
|
24528
|
+
switch (event.type) {
|
|
24529
|
+
case "operation_start":
|
|
24530
|
+
this.handleOperationStart(event);
|
|
24531
|
+
return;
|
|
24532
|
+
case "operation":
|
|
24533
|
+
this.handleOperation(event);
|
|
24534
|
+
return;
|
|
24535
|
+
case "text_delta":
|
|
24536
|
+
if (!options.captureTurnSpans) {
|
|
24537
|
+
return;
|
|
24538
|
+
}
|
|
24539
|
+
this.ensureTurnState(event).text.push(
|
|
24540
|
+
typeof event.text === "string" ? event.text : ""
|
|
24541
|
+
);
|
|
24542
|
+
return;
|
|
24543
|
+
case "thinking_start":
|
|
24544
|
+
if (!options.captureTurnSpans) {
|
|
24545
|
+
return;
|
|
24546
|
+
}
|
|
24547
|
+
this.handleThinkingStart(event);
|
|
24548
|
+
return;
|
|
24549
|
+
case "thinking_delta":
|
|
24550
|
+
if (!options.captureTurnSpans) {
|
|
24551
|
+
return;
|
|
24552
|
+
}
|
|
24553
|
+
this.handleThinkingDelta(event);
|
|
24554
|
+
return;
|
|
24555
|
+
case "thinking_end":
|
|
24556
|
+
if (!options.captureTurnSpans) {
|
|
24557
|
+
return;
|
|
24558
|
+
}
|
|
24559
|
+
this.handleThinkingEnd(event);
|
|
24560
|
+
return;
|
|
24561
|
+
case "turn":
|
|
24562
|
+
if (!options.captureTurnSpans) {
|
|
24563
|
+
return;
|
|
24564
|
+
}
|
|
24565
|
+
this.handleTurn(event);
|
|
24566
|
+
return;
|
|
24567
|
+
case "tool_start":
|
|
24568
|
+
this.handleToolStart(event, options);
|
|
24569
|
+
return;
|
|
24570
|
+
case "tool_call":
|
|
24571
|
+
this.handleToolCall(event);
|
|
24572
|
+
return;
|
|
24573
|
+
case "task_start":
|
|
24574
|
+
this.handleTaskStart(event);
|
|
24575
|
+
return;
|
|
24576
|
+
case "task":
|
|
24577
|
+
this.handleTask(event);
|
|
24578
|
+
return;
|
|
24579
|
+
case "compaction_start":
|
|
24580
|
+
this.handleCompactionStart(event);
|
|
24581
|
+
return;
|
|
24582
|
+
case "compaction":
|
|
24583
|
+
this.handleCompaction(event);
|
|
24584
|
+
return;
|
|
24585
|
+
default:
|
|
24586
|
+
return;
|
|
24587
|
+
}
|
|
24588
|
+
}
|
|
24589
|
+
handleOperationStart(event) {
|
|
24590
|
+
if (!isInstrumentedOperation(event.operationKind)) {
|
|
24591
|
+
return;
|
|
24592
|
+
}
|
|
24593
|
+
const state = this.takePendingOperationForEvent(event);
|
|
24594
|
+
if (!state) {
|
|
24595
|
+
return;
|
|
24596
|
+
}
|
|
24597
|
+
state.operationId = event.operationId;
|
|
24598
|
+
this.activeOperationsById.set(event.operationId, state);
|
|
24599
|
+
addScopedOperation(this.activeOperationsByScope, event, state);
|
|
24600
|
+
state.metadata = {
|
|
24601
|
+
...state.metadata,
|
|
24602
|
+
...extractEventMetadata(event),
|
|
24603
|
+
"flue.operation_id": event.operationId
|
|
24604
|
+
};
|
|
24605
|
+
safeLog3(state.span, { metadata: state.metadata });
|
|
24606
|
+
}
|
|
24607
|
+
handleOperation(event) {
|
|
24608
|
+
const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
|
|
24609
|
+
if (!state) {
|
|
24610
|
+
return;
|
|
24611
|
+
}
|
|
24612
|
+
const metadata = {
|
|
24613
|
+
...state.metadata,
|
|
24614
|
+
...extractEventMetadata(event),
|
|
24615
|
+
...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
|
|
24616
|
+
...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
|
|
24617
|
+
};
|
|
24618
|
+
const metrics = metricsFromUsage(event.usage);
|
|
24619
|
+
safeLog3(state.span, {
|
|
24620
|
+
...event.error ? { error: errorToString(event.error) } : {},
|
|
24621
|
+
metadata,
|
|
24622
|
+
...Object.keys(metrics).length ? { metrics } : {}
|
|
24623
|
+
});
|
|
24624
|
+
}
|
|
24625
|
+
ensureTurnState(event) {
|
|
24626
|
+
const scope = scopeKey(event);
|
|
24627
|
+
const existing = this.turnsByScope.get(scope);
|
|
24628
|
+
if (existing) {
|
|
24629
|
+
return existing;
|
|
24630
|
+
}
|
|
24631
|
+
const parent = this.parentSpanForEvent(event);
|
|
24632
|
+
const metadata = {
|
|
24633
|
+
...extractEventMetadata(event),
|
|
24634
|
+
provider: "flue"
|
|
24635
|
+
};
|
|
24636
|
+
const span = startFlueSpan(parent, {
|
|
24637
|
+
name: "flue.turn",
|
|
24638
|
+
spanAttributes: { type: "llm" /* LLM */ }
|
|
24639
|
+
});
|
|
24640
|
+
const state = {
|
|
24641
|
+
metadata,
|
|
24642
|
+
span,
|
|
24643
|
+
hasThinking: false,
|
|
24644
|
+
startTime: getCurrentUnixTimestamp(),
|
|
24645
|
+
text: [],
|
|
24646
|
+
thinking: [],
|
|
24647
|
+
toolCalls: []
|
|
24648
|
+
};
|
|
24649
|
+
safeLog3(span, { metadata });
|
|
24650
|
+
this.turnsByScope.set(scope, state);
|
|
24651
|
+
return state;
|
|
24652
|
+
}
|
|
24653
|
+
handleTurn(event) {
|
|
24654
|
+
const scope = scopeKey(event);
|
|
24655
|
+
const state = this.ensureTurnState(event);
|
|
24656
|
+
const text = state.text.join("");
|
|
24657
|
+
const reasoning = state.finalThinking ?? state.thinking.join("");
|
|
24658
|
+
const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
|
|
24659
|
+
const metadata = {
|
|
24660
|
+
...state.metadata,
|
|
24661
|
+
...extractEventMetadata(event),
|
|
24662
|
+
...event.model ? { model: event.model, "flue.model": event.model } : {},
|
|
24663
|
+
...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
|
|
24664
|
+
...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
|
|
24665
|
+
provider: "flue"
|
|
24666
|
+
};
|
|
24667
|
+
safeLog3(state.span, {
|
|
24668
|
+
...event.error ? { error: errorToString(event.error) } : {},
|
|
24669
|
+
metadata,
|
|
24670
|
+
metrics: {
|
|
24671
|
+
...durationMsMetrics(event.durationMs),
|
|
24672
|
+
...metricsFromUsage(event.usage)
|
|
24673
|
+
},
|
|
24674
|
+
output: toAssistantOutput(
|
|
24675
|
+
text,
|
|
24676
|
+
event.stopReason,
|
|
24677
|
+
outputReasoning,
|
|
24678
|
+
state.toolCalls
|
|
24679
|
+
)
|
|
24680
|
+
});
|
|
24681
|
+
state.span.end();
|
|
24682
|
+
this.turnsByScope.delete(scope);
|
|
24683
|
+
}
|
|
24684
|
+
handleThinkingDelta(event) {
|
|
24685
|
+
const delta = event.delta;
|
|
24686
|
+
if (typeof delta !== "string" || !delta) {
|
|
24687
|
+
return;
|
|
24688
|
+
}
|
|
24689
|
+
const state = this.ensureTurnState(event);
|
|
24690
|
+
state.hasThinking = true;
|
|
24691
|
+
state.metadata["flue.thinking"] = true;
|
|
24692
|
+
state.thinking.push(delta);
|
|
24693
|
+
}
|
|
24694
|
+
handleThinkingStart(event) {
|
|
24695
|
+
const state = this.ensureTurnState(event);
|
|
24696
|
+
state.hasThinking = true;
|
|
24697
|
+
state.metadata["flue.thinking"] = true;
|
|
24698
|
+
}
|
|
24699
|
+
handleThinkingEnd(event) {
|
|
24700
|
+
const state = this.ensureTurnState(event);
|
|
24701
|
+
state.hasThinking = true;
|
|
24702
|
+
state.metadata["flue.thinking"] = true;
|
|
24703
|
+
if (typeof event.content === "string" && event.content) {
|
|
24704
|
+
state.finalThinking = event.content;
|
|
24705
|
+
}
|
|
24706
|
+
}
|
|
24707
|
+
handleToolStart(event, options) {
|
|
24708
|
+
const toolCallId = event.toolCallId;
|
|
24709
|
+
if (!toolCallId) {
|
|
24710
|
+
return;
|
|
24711
|
+
}
|
|
24712
|
+
const parent = this.parentSpanForEvent(event);
|
|
24713
|
+
const scope = scopeKey(event);
|
|
24714
|
+
let turnState = this.turnsByScope.get(scope);
|
|
24715
|
+
if (!turnState && parent && options.captureTurnSpans) {
|
|
24716
|
+
turnState = this.ensureTurnState(event);
|
|
24717
|
+
}
|
|
24718
|
+
const metadata = {
|
|
24719
|
+
...extractEventMetadata(event),
|
|
24720
|
+
...event.toolName ? { "flue.tool_name": event.toolName } : {},
|
|
24721
|
+
"flue.tool_call_id": toolCallId,
|
|
24722
|
+
provider: "flue"
|
|
24723
|
+
};
|
|
24724
|
+
const span = startFlueSpan(parent, {
|
|
24725
|
+
name: `tool: ${event.toolName ?? "unknown"}`,
|
|
24726
|
+
spanAttributes: { type: "tool" /* TOOL */ }
|
|
24727
|
+
});
|
|
24728
|
+
if (turnState) {
|
|
24729
|
+
turnState.toolCalls.push({
|
|
24730
|
+
args: event.args,
|
|
24731
|
+
toolCallId,
|
|
24732
|
+
toolName: event.toolName
|
|
24733
|
+
});
|
|
24734
|
+
}
|
|
24735
|
+
safeLog3(span, {
|
|
24736
|
+
input: event.args,
|
|
24737
|
+
metadata
|
|
24738
|
+
});
|
|
24739
|
+
this.toolsById.set(toolKey(event), {
|
|
24740
|
+
metadata,
|
|
24741
|
+
span,
|
|
24742
|
+
startTime: getCurrentUnixTimestamp()
|
|
24743
|
+
});
|
|
24744
|
+
}
|
|
24745
|
+
handleToolCall(event) {
|
|
24746
|
+
const key = toolKey(event);
|
|
24747
|
+
const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
|
|
24748
|
+
const metadata = {
|
|
24749
|
+
...state.metadata,
|
|
24750
|
+
...extractEventMetadata(event),
|
|
24751
|
+
...event.toolName ? { "flue.tool_name": event.toolName } : {},
|
|
24752
|
+
...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
|
|
24753
|
+
...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
|
|
24754
|
+
};
|
|
24755
|
+
safeLog3(state.span, {
|
|
24756
|
+
...event.isError ? { error: errorToString(event.result) } : {},
|
|
24757
|
+
metadata,
|
|
24758
|
+
metrics: durationMsMetrics(event.durationMs),
|
|
24759
|
+
output: event.result
|
|
24760
|
+
});
|
|
24761
|
+
state.span.end();
|
|
24762
|
+
this.toolsById.delete(key);
|
|
24763
|
+
}
|
|
24764
|
+
handleTaskStart(event) {
|
|
24765
|
+
const parent = this.parentSpanForEvent(event);
|
|
24766
|
+
const metadata = {
|
|
24767
|
+
...extractEventMetadata(event),
|
|
24768
|
+
...event.role ? { "flue.role": event.role } : {},
|
|
24769
|
+
...event.cwd ? { "flue.cwd": event.cwd } : {},
|
|
24770
|
+
"flue.task_id": event.taskId,
|
|
24771
|
+
provider: "flue"
|
|
24772
|
+
};
|
|
24773
|
+
const span = startFlueSpan(parent, {
|
|
24774
|
+
name: "flue.task",
|
|
24775
|
+
spanAttributes: { type: "task" /* TASK */ }
|
|
24776
|
+
});
|
|
24777
|
+
safeLog3(span, {
|
|
24778
|
+
input: event.prompt,
|
|
24779
|
+
metadata
|
|
24780
|
+
});
|
|
24781
|
+
this.tasksById.set(event.taskId, {
|
|
24782
|
+
metadata,
|
|
24783
|
+
span,
|
|
24784
|
+
startTime: getCurrentUnixTimestamp()
|
|
24785
|
+
});
|
|
24786
|
+
}
|
|
24787
|
+
handleTask(event) {
|
|
24788
|
+
const state = this.tasksById.get(event.taskId);
|
|
24789
|
+
if (!state) {
|
|
24790
|
+
return;
|
|
24791
|
+
}
|
|
24792
|
+
safeLog3(state.span, {
|
|
24793
|
+
...event.isError ? { error: errorToString(event.result) } : {},
|
|
24794
|
+
metadata: {
|
|
24795
|
+
...state.metadata,
|
|
24796
|
+
...extractEventMetadata(event),
|
|
24797
|
+
...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
|
|
24798
|
+
},
|
|
24799
|
+
metrics: durationMsMetrics(event.durationMs),
|
|
24800
|
+
output: event.result
|
|
24801
|
+
});
|
|
24802
|
+
state.span.end();
|
|
24803
|
+
this.tasksById.delete(event.taskId);
|
|
24804
|
+
}
|
|
24805
|
+
handleCompactionStart(event) {
|
|
24806
|
+
const operationState = this.operationStateForEvent(event);
|
|
24807
|
+
const parent = operationState?.span ?? this.parentSpanForEvent(event);
|
|
24808
|
+
const metadata = {
|
|
24809
|
+
...extractEventMetadata(event),
|
|
24810
|
+
...event.reason ? { "flue.compaction_reason": event.reason } : {},
|
|
24811
|
+
provider: "flue"
|
|
24812
|
+
};
|
|
24813
|
+
const input = {
|
|
24814
|
+
...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
|
|
24815
|
+
...event.reason ? { reason: event.reason } : {}
|
|
24816
|
+
};
|
|
24817
|
+
const span = startFlueSpan(parent, {
|
|
24818
|
+
name: "flue.compaction",
|
|
24819
|
+
spanAttributes: { type: "task" /* TASK */ }
|
|
24820
|
+
});
|
|
24821
|
+
safeLog3(span, {
|
|
24822
|
+
input,
|
|
24823
|
+
metadata
|
|
24824
|
+
});
|
|
24825
|
+
this.compactionsByScope.set(scopeKey(event), {
|
|
24826
|
+
input,
|
|
24827
|
+
metadata,
|
|
24828
|
+
operationState,
|
|
24829
|
+
span,
|
|
24830
|
+
startTime: getCurrentUnixTimestamp()
|
|
24831
|
+
});
|
|
24832
|
+
}
|
|
24833
|
+
handleCompaction(event) {
|
|
24834
|
+
const key = scopeKey(event);
|
|
24835
|
+
const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
|
|
24836
|
+
if (!state) {
|
|
24837
|
+
return;
|
|
24838
|
+
}
|
|
24839
|
+
safeLog3(state.span, {
|
|
24840
|
+
metadata: {
|
|
24841
|
+
...state.metadata,
|
|
24842
|
+
...extractEventMetadata(event),
|
|
24843
|
+
...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
|
|
24844
|
+
...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
|
|
24845
|
+
},
|
|
24846
|
+
metrics: {
|
|
24847
|
+
...durationMsMetrics(event.durationMs),
|
|
24848
|
+
...metricsFromUsage(event.usage)
|
|
24849
|
+
},
|
|
24850
|
+
output: {
|
|
24851
|
+
messagesAfter: event.messagesAfter,
|
|
24852
|
+
messagesBefore: event.messagesBefore
|
|
24853
|
+
}
|
|
24854
|
+
});
|
|
24855
|
+
state.span.end();
|
|
24856
|
+
this.deleteCompactionState(state);
|
|
24857
|
+
}
|
|
24858
|
+
findCompactionState(event) {
|
|
24859
|
+
const operationState = this.operationStateForEvent(event);
|
|
24860
|
+
for (const state of this.compactionsByScope.values()) {
|
|
24861
|
+
if (operationState && state.operationState === operationState) {
|
|
24862
|
+
return state;
|
|
24863
|
+
}
|
|
24864
|
+
}
|
|
24865
|
+
return void 0;
|
|
24866
|
+
}
|
|
24867
|
+
finishCompactionsForOperation(operationState) {
|
|
24868
|
+
for (const state of [...this.compactionsByScope.values()]) {
|
|
24869
|
+
if (state.operationState !== operationState) {
|
|
24870
|
+
continue;
|
|
24871
|
+
}
|
|
24872
|
+
safeLog3(state.span, {
|
|
24873
|
+
input: state.input,
|
|
24874
|
+
metadata: state.metadata,
|
|
24875
|
+
metrics: {
|
|
24876
|
+
...buildDurationMetrics3(state.startTime)
|
|
24877
|
+
},
|
|
24878
|
+
output: { completed: true }
|
|
24879
|
+
});
|
|
24880
|
+
state.span.end();
|
|
24881
|
+
this.deleteCompactionState(state);
|
|
24882
|
+
}
|
|
24883
|
+
}
|
|
24884
|
+
deleteCompactionState(state) {
|
|
24885
|
+
for (const [key, candidate] of this.compactionsByScope) {
|
|
24886
|
+
if (candidate !== state) {
|
|
24887
|
+
continue;
|
|
24888
|
+
}
|
|
24889
|
+
this.compactionsByScope.delete(key);
|
|
24890
|
+
return;
|
|
24891
|
+
}
|
|
24892
|
+
}
|
|
24893
|
+
startSyntheticToolState(event, toolName) {
|
|
24894
|
+
const parent = this.parentSpanForEvent(event);
|
|
24895
|
+
const metadata = {
|
|
24896
|
+
...extractEventMetadata(event),
|
|
24897
|
+
...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
|
|
24898
|
+
"flue.tool_name": toolName,
|
|
24899
|
+
provider: "flue"
|
|
24900
|
+
};
|
|
24901
|
+
const span = startFlueSpan(parent, {
|
|
24902
|
+
name: `tool: ${toolName}`,
|
|
24903
|
+
spanAttributes: { type: "tool" /* TOOL */ }
|
|
24904
|
+
});
|
|
24905
|
+
safeLog3(span, { metadata });
|
|
24906
|
+
return { metadata, span, startTime: getCurrentUnixTimestamp() };
|
|
24907
|
+
}
|
|
24908
|
+
operationStateForEvent(event) {
|
|
24909
|
+
if (event.operationId) {
|
|
24910
|
+
const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
|
|
24911
|
+
if (operation) {
|
|
24912
|
+
return operation;
|
|
24913
|
+
}
|
|
24914
|
+
}
|
|
24915
|
+
return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
|
|
24916
|
+
}
|
|
24917
|
+
parentSpanForEvent(event) {
|
|
24918
|
+
if (event.operationId) {
|
|
24919
|
+
const operation = this.operationStateForEvent(event);
|
|
24920
|
+
if (operation) {
|
|
24921
|
+
return operation.span;
|
|
24922
|
+
}
|
|
24923
|
+
}
|
|
24924
|
+
if (event.taskId) {
|
|
24925
|
+
return this.tasksById.get(event.taskId)?.span;
|
|
24926
|
+
}
|
|
24927
|
+
return this.operationStateForEvent(event)?.span;
|
|
24928
|
+
}
|
|
24929
|
+
promotePendingOperationForEvent(event) {
|
|
24930
|
+
if (!event.operationId) {
|
|
24931
|
+
return void 0;
|
|
24932
|
+
}
|
|
24933
|
+
const scopePrefixes = operationScopePrefixes(event);
|
|
24934
|
+
for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
|
|
24935
|
+
if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
|
|
24936
|
+
continue;
|
|
24937
|
+
}
|
|
24938
|
+
const state = candidateQueue.shift();
|
|
24939
|
+
if (!state) {
|
|
24940
|
+
return void 0;
|
|
24941
|
+
}
|
|
24942
|
+
state.operationId = event.operationId;
|
|
24943
|
+
this.activeOperationsById.set(event.operationId, state);
|
|
24944
|
+
addScopedOperation(this.activeOperationsByScope, event, state);
|
|
24945
|
+
state.metadata = {
|
|
24946
|
+
...state.metadata,
|
|
24947
|
+
...extractEventMetadata(event),
|
|
24948
|
+
"flue.operation_id": event.operationId
|
|
24949
|
+
};
|
|
24950
|
+
safeLog3(state.span, { metadata: state.metadata });
|
|
24951
|
+
return state;
|
|
24952
|
+
}
|
|
24953
|
+
return void 0;
|
|
24954
|
+
}
|
|
24955
|
+
activeOperationForEventScope(event) {
|
|
24956
|
+
for (const scope of operationScopeNames(event)) {
|
|
24957
|
+
const operations = this.activeOperationsByScope.get(scope);
|
|
24958
|
+
if (operations?.length) {
|
|
24959
|
+
return operations[operations.length - 1];
|
|
24960
|
+
}
|
|
24961
|
+
}
|
|
24962
|
+
return void 0;
|
|
24963
|
+
}
|
|
24964
|
+
pendingOperationForEventScope(event) {
|
|
24965
|
+
const scopePrefixes = operationScopePrefixes(event);
|
|
24966
|
+
for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
|
|
24967
|
+
if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
|
|
24968
|
+
continue;
|
|
24969
|
+
}
|
|
24970
|
+
return candidateQueue[0];
|
|
24971
|
+
}
|
|
24972
|
+
return void 0;
|
|
24973
|
+
}
|
|
24974
|
+
takePendingOperationForEvent(event) {
|
|
24975
|
+
const key = operationKey(event.session, event.operationKind);
|
|
24976
|
+
const queue2 = this.pendingOperationsByKey.get(key);
|
|
24977
|
+
if (queue2?.length) {
|
|
24978
|
+
return queue2.shift();
|
|
24979
|
+
}
|
|
24980
|
+
for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
|
|
24981
|
+
if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
|
|
24982
|
+
return candidateQueue.shift();
|
|
24983
|
+
}
|
|
24984
|
+
}
|
|
24985
|
+
return void 0;
|
|
24986
|
+
}
|
|
24987
|
+
pendingOperationQueue(key) {
|
|
24988
|
+
const existing = this.pendingOperationsByKey.get(key);
|
|
24989
|
+
if (existing) {
|
|
24990
|
+
return existing;
|
|
24991
|
+
}
|
|
24992
|
+
const queue2 = [];
|
|
24993
|
+
this.pendingOperationsByKey.set(key, queue2);
|
|
24994
|
+
return queue2;
|
|
24995
|
+
}
|
|
24996
|
+
};
|
|
24997
|
+
function isInstrumentedOperation(operation) {
|
|
24998
|
+
return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
|
|
24999
|
+
}
|
|
25000
|
+
function getSessionName(session) {
|
|
25001
|
+
return typeof session?.name === "string" ? session.name : void 0;
|
|
25002
|
+
}
|
|
25003
|
+
function operationKey(sessionName, operation) {
|
|
25004
|
+
return `${sessionName ?? "unknown"}::${operation}`;
|
|
25005
|
+
}
|
|
25006
|
+
function operationScopePrefixes(event) {
|
|
25007
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
25008
|
+
for (const scope of operationScopeNames(event)) {
|
|
25009
|
+
scopes.add(`${scope}::`);
|
|
25010
|
+
}
|
|
25011
|
+
return scopes;
|
|
25012
|
+
}
|
|
25013
|
+
function operationKeyMatchesScopes(key, scopes) {
|
|
25014
|
+
for (const scope of scopes) {
|
|
25015
|
+
if (key.startsWith(scope)) {
|
|
25016
|
+
return true;
|
|
25017
|
+
}
|
|
25018
|
+
}
|
|
25019
|
+
return false;
|
|
25020
|
+
}
|
|
25021
|
+
function operationScopeNames(event) {
|
|
25022
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
25023
|
+
if (event.session) {
|
|
25024
|
+
scopes.add(event.session);
|
|
25025
|
+
}
|
|
25026
|
+
if (event.parentSession) {
|
|
25027
|
+
scopes.add(event.parentSession);
|
|
25028
|
+
}
|
|
25029
|
+
if (!scopes.size) {
|
|
25030
|
+
scopes.add("unknown");
|
|
25031
|
+
}
|
|
25032
|
+
return scopes;
|
|
25033
|
+
}
|
|
25034
|
+
function addScopedOperation(operationsByScope, event, state) {
|
|
25035
|
+
for (const scope of operationScopeNames(event)) {
|
|
25036
|
+
addOperationToScope(operationsByScope, scope, state);
|
|
25037
|
+
}
|
|
25038
|
+
}
|
|
25039
|
+
function addOperationToScope(operationsByScope, scope, state) {
|
|
25040
|
+
const operations = operationsByScope.get(scope);
|
|
25041
|
+
if (operations) {
|
|
25042
|
+
if (!operations.includes(state)) {
|
|
25043
|
+
operations.push(state);
|
|
25044
|
+
}
|
|
25045
|
+
} else {
|
|
25046
|
+
operationsByScope.set(scope, [state]);
|
|
25047
|
+
}
|
|
25048
|
+
}
|
|
25049
|
+
function removeScopedOperation(operationsByScope, state) {
|
|
25050
|
+
for (const [scope, operations] of operationsByScope) {
|
|
25051
|
+
const index = operations.indexOf(state);
|
|
25052
|
+
if (index === -1) {
|
|
25053
|
+
continue;
|
|
25054
|
+
}
|
|
25055
|
+
operations.splice(index, 1);
|
|
25056
|
+
if (operations.length === 0) {
|
|
25057
|
+
operationsByScope.delete(scope);
|
|
25058
|
+
}
|
|
25059
|
+
}
|
|
25060
|
+
}
|
|
25061
|
+
function removePendingOperation(pendingOperationsByKey, state) {
|
|
25062
|
+
for (const [key, queue2] of pendingOperationsByKey) {
|
|
25063
|
+
const index = queue2.indexOf(state);
|
|
25064
|
+
if (index === -1) {
|
|
25065
|
+
continue;
|
|
25066
|
+
}
|
|
25067
|
+
queue2.splice(index, 1);
|
|
25068
|
+
if (queue2.length === 0) {
|
|
25069
|
+
pendingOperationsByKey.delete(key);
|
|
25070
|
+
}
|
|
25071
|
+
return;
|
|
25072
|
+
}
|
|
25073
|
+
}
|
|
25074
|
+
function extractSessionMetadata(session) {
|
|
25075
|
+
const sessionName = getSessionName(session);
|
|
25076
|
+
return sessionName ? { "flue.session": sessionName } : {};
|
|
25077
|
+
}
|
|
25078
|
+
function extractEventMetadata(event) {
|
|
25079
|
+
return {
|
|
25080
|
+
...event.runId ? { "flue.run_id": event.runId } : {},
|
|
25081
|
+
...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
|
|
25082
|
+
...event.session ? { "flue.session": event.session } : {},
|
|
25083
|
+
...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
|
|
25084
|
+
...event.harness ? { "flue.harness": event.harness } : {},
|
|
25085
|
+
...event.taskId ? { "flue.task_id": event.taskId } : {},
|
|
25086
|
+
...event.operationId ? { "flue.operation_id": event.operationId } : {}
|
|
25087
|
+
};
|
|
25088
|
+
}
|
|
25089
|
+
function extractOperationInput(operation, args) {
|
|
25090
|
+
switch (operation) {
|
|
25091
|
+
case "prompt":
|
|
25092
|
+
case "task":
|
|
25093
|
+
return args[0];
|
|
25094
|
+
case "skill":
|
|
25095
|
+
return {
|
|
25096
|
+
args: getOptionObject(args[1])?.args,
|
|
25097
|
+
name: args[0]
|
|
25098
|
+
};
|
|
25099
|
+
case "compact":
|
|
25100
|
+
return void 0;
|
|
25101
|
+
}
|
|
25102
|
+
}
|
|
25103
|
+
function extractOperationInputMetadata(operation, args) {
|
|
25104
|
+
const options = getOptionObject(args[1]);
|
|
25105
|
+
return {
|
|
25106
|
+
...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
|
|
25107
|
+
...options?.model ? { model: options.model, "flue.model": options.model } : {},
|
|
25108
|
+
...options?.role ? { "flue.role": options.role } : {},
|
|
25109
|
+
...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
|
|
25110
|
+
...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
|
|
25111
|
+
...Array.isArray(options?.tools) ? {
|
|
25112
|
+
"flue.tools_count": options.tools.length,
|
|
25113
|
+
tools: summarizeTools(options.tools)
|
|
25114
|
+
} : {},
|
|
25115
|
+
...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
|
|
25116
|
+
...options?.result || options?.schema ? { "flue.result_schema": true } : {}
|
|
25117
|
+
};
|
|
25118
|
+
}
|
|
25119
|
+
function getOptionObject(value) {
|
|
25120
|
+
return isObject(value) ? value : void 0;
|
|
25121
|
+
}
|
|
25122
|
+
function summarizeTools(tools) {
|
|
25123
|
+
return tools.flatMap((tool) => {
|
|
25124
|
+
if (!isObject(tool)) {
|
|
25125
|
+
return [];
|
|
25126
|
+
}
|
|
25127
|
+
const name = typeof tool.name === "string" ? tool.name : void 0;
|
|
25128
|
+
if (!name) {
|
|
25129
|
+
return [];
|
|
25130
|
+
}
|
|
25131
|
+
return [
|
|
25132
|
+
{
|
|
25133
|
+
function: {
|
|
25134
|
+
description: typeof tool.description === "string" ? tool.description : void 0,
|
|
25135
|
+
name,
|
|
25136
|
+
parameters: tool.parameters
|
|
25137
|
+
},
|
|
25138
|
+
type: "function"
|
|
25139
|
+
}
|
|
25140
|
+
];
|
|
25141
|
+
});
|
|
25142
|
+
}
|
|
25143
|
+
function extractPromptResponseMetadata(result) {
|
|
25144
|
+
const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
|
|
25145
|
+
return modelId ? {
|
|
25146
|
+
model: modelId,
|
|
25147
|
+
"flue.model": modelId
|
|
25148
|
+
} : {};
|
|
25149
|
+
}
|
|
25150
|
+
function extractOperationOutput(result) {
|
|
25151
|
+
if (!result) {
|
|
25152
|
+
return void 0;
|
|
25153
|
+
}
|
|
25154
|
+
if ("data" in result) {
|
|
25155
|
+
return result.data;
|
|
25156
|
+
}
|
|
25157
|
+
if ("text" in result) {
|
|
25158
|
+
return result.text;
|
|
25159
|
+
}
|
|
25160
|
+
return result;
|
|
25161
|
+
}
|
|
25162
|
+
function metricsFromUsage(usage) {
|
|
25163
|
+
return {
|
|
25164
|
+
...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
|
|
25165
|
+
...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
|
|
25166
|
+
...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
|
|
25167
|
+
...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
|
|
25168
|
+
...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
|
|
25169
|
+
...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
|
|
25170
|
+
};
|
|
25171
|
+
}
|
|
25172
|
+
function buildDurationMetrics3(startTime) {
|
|
25173
|
+
return {
|
|
25174
|
+
duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
|
|
25175
|
+
};
|
|
25176
|
+
}
|
|
25177
|
+
function durationMsMetrics(durationMs) {
|
|
25178
|
+
return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
|
|
25179
|
+
}
|
|
25180
|
+
function scopeKey(event) {
|
|
25181
|
+
if (event.operationId) {
|
|
25182
|
+
return `operation:${event.operationId}`;
|
|
25183
|
+
}
|
|
25184
|
+
if (event.taskId) {
|
|
25185
|
+
return `task:${event.taskId}`;
|
|
25186
|
+
}
|
|
25187
|
+
if (event.session) {
|
|
25188
|
+
return `session:${event.session}`;
|
|
25189
|
+
}
|
|
25190
|
+
return "flue:unknown";
|
|
25191
|
+
}
|
|
25192
|
+
function toolKey(event) {
|
|
25193
|
+
return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
|
|
25194
|
+
}
|
|
25195
|
+
function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
|
|
25196
|
+
return [
|
|
25197
|
+
{
|
|
25198
|
+
finish_reason: finishReason ?? "stop",
|
|
25199
|
+
index: 0,
|
|
25200
|
+
message: {
|
|
25201
|
+
content: text,
|
|
25202
|
+
...reasoning ? { reasoning } : {},
|
|
25203
|
+
role: "assistant",
|
|
25204
|
+
...toolCalls?.length ? {
|
|
25205
|
+
tool_calls: toolCalls.map((toolCall) => ({
|
|
25206
|
+
function: {
|
|
25207
|
+
arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
|
|
25208
|
+
name: toolCall.toolName ?? "unknown"
|
|
25209
|
+
},
|
|
25210
|
+
...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
|
|
25211
|
+
type: "function"
|
|
25212
|
+
}))
|
|
25213
|
+
} : {}
|
|
25214
|
+
}
|
|
25215
|
+
}
|
|
25216
|
+
];
|
|
25217
|
+
}
|
|
25218
|
+
function startFlueSpan(parent, args) {
|
|
25219
|
+
return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
|
|
25220
|
+
}
|
|
25221
|
+
function safeLog3(span, event) {
|
|
25222
|
+
try {
|
|
25223
|
+
span.log(event);
|
|
25224
|
+
} catch (error) {
|
|
25225
|
+
logInstrumentationError3("Flue span log", error);
|
|
25226
|
+
}
|
|
25227
|
+
}
|
|
25228
|
+
function errorToString(error) {
|
|
25229
|
+
if (error instanceof Error) {
|
|
25230
|
+
return error.message;
|
|
25231
|
+
}
|
|
25232
|
+
if (typeof error === "string") {
|
|
25233
|
+
return error;
|
|
25234
|
+
}
|
|
25235
|
+
try {
|
|
25236
|
+
return JSON.stringify(error);
|
|
25237
|
+
} catch {
|
|
25238
|
+
return String(error);
|
|
25239
|
+
}
|
|
25240
|
+
}
|
|
25241
|
+
function logInstrumentationError3(label, error) {
|
|
25242
|
+
console.error(`Error in ${label} instrumentation:`, error);
|
|
25243
|
+
}
|
|
25244
|
+
|
|
25245
|
+
// src/wrappers/langchain/callback-handler.ts
|
|
25246
|
+
var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
|
|
25247
|
+
var BraintrustLangChainCallbackHandler = class {
|
|
25248
|
+
name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
|
|
25249
|
+
spans = /* @__PURE__ */ new Map();
|
|
25250
|
+
skippedRuns = /* @__PURE__ */ new Set();
|
|
25251
|
+
parent;
|
|
25252
|
+
rootRunId;
|
|
25253
|
+
options;
|
|
25254
|
+
startTimes = /* @__PURE__ */ new Map();
|
|
25255
|
+
firstTokenTimes = /* @__PURE__ */ new Map();
|
|
25256
|
+
ttftMs = /* @__PURE__ */ new Map();
|
|
25257
|
+
constructor(options) {
|
|
25258
|
+
this.parent = options?.parent;
|
|
25259
|
+
this.options = {
|
|
25260
|
+
debug: options?.debug ?? false,
|
|
25261
|
+
excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
|
|
25262
|
+
logger: options?.logger
|
|
25263
|
+
};
|
|
25264
|
+
}
|
|
25265
|
+
startSpan({
|
|
25266
|
+
runId,
|
|
25267
|
+
parentRunId,
|
|
25268
|
+
...args
|
|
25269
|
+
}) {
|
|
25270
|
+
if (this.spans.has(runId)) {
|
|
25271
|
+
return;
|
|
25272
|
+
}
|
|
25273
|
+
if (!parentRunId) {
|
|
25274
|
+
this.rootRunId = runId;
|
|
25275
|
+
}
|
|
25276
|
+
const tags = args.event?.tags;
|
|
25277
|
+
const spanAttributes = args.spanAttributes || {};
|
|
25278
|
+
spanAttributes.type = args.type || spanAttributes.type || "task";
|
|
25279
|
+
args.type = spanAttributes.type;
|
|
25280
|
+
const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
|
|
25281
|
+
let parentSpan;
|
|
25282
|
+
if (parentRunId && this.spans.has(parentRunId)) {
|
|
25283
|
+
parentSpan = this.spans.get(parentRunId);
|
|
25284
|
+
} else if (!Object.is(currentParent, NOOP_SPAN)) {
|
|
25285
|
+
parentSpan = currentParent;
|
|
25286
|
+
} else if (this.options.logger) {
|
|
25287
|
+
parentSpan = this.options.logger;
|
|
25288
|
+
} else {
|
|
25289
|
+
parentSpan = { startSpan };
|
|
25290
|
+
}
|
|
25291
|
+
args.event = {
|
|
25292
|
+
...args.event,
|
|
25293
|
+
tags: void 0,
|
|
25294
|
+
metadata: {
|
|
25295
|
+
...tags ? { tags } : {},
|
|
25296
|
+
...args.event?.metadata,
|
|
25297
|
+
braintrust: {
|
|
25298
|
+
integration_name: "langchain-js",
|
|
25299
|
+
sdk_language: "javascript"
|
|
25300
|
+
},
|
|
25301
|
+
run_id: runId,
|
|
25302
|
+
parent_run_id: parentRunId,
|
|
25303
|
+
...this.options.debug ? { runId, parentRunId } : {}
|
|
25304
|
+
}
|
|
25305
|
+
};
|
|
25306
|
+
let span = parentSpan.startSpan(args);
|
|
25307
|
+
if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
|
|
25308
|
+
span = initLogger().startSpan(args);
|
|
25309
|
+
}
|
|
25310
|
+
this.spans.set(runId, span);
|
|
25311
|
+
}
|
|
25312
|
+
endSpan({
|
|
25313
|
+
runId,
|
|
25314
|
+
parentRunId,
|
|
25315
|
+
tags,
|
|
25316
|
+
metadata,
|
|
25317
|
+
...args
|
|
25318
|
+
}) {
|
|
25319
|
+
if (!this.spans.has(runId)) {
|
|
25320
|
+
return;
|
|
25321
|
+
}
|
|
25322
|
+
if (this.skippedRuns.has(runId)) {
|
|
25323
|
+
this.skippedRuns.delete(runId);
|
|
25324
|
+
return;
|
|
25325
|
+
}
|
|
25326
|
+
const span = this.spans.get(runId);
|
|
25327
|
+
this.spans.delete(runId);
|
|
25328
|
+
if (runId === this.rootRunId) {
|
|
25329
|
+
this.rootRunId = void 0;
|
|
25330
|
+
}
|
|
25331
|
+
span.log({ ...args, metadata: { tags, ...metadata } });
|
|
25332
|
+
span.end();
|
|
25333
|
+
}
|
|
25334
|
+
async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
25335
|
+
this.startSpan({
|
|
25336
|
+
runId,
|
|
25337
|
+
parentRunId,
|
|
25338
|
+
name: runName ?? getSerializedName(llm) ?? "LLM",
|
|
25339
|
+
type: "llm",
|
|
25340
|
+
event: {
|
|
25341
|
+
input: prompts,
|
|
25342
|
+
tags,
|
|
25343
|
+
metadata: {
|
|
25344
|
+
serialized: llm,
|
|
25345
|
+
name: runName,
|
|
25346
|
+
metadata,
|
|
25347
|
+
...extraParams
|
|
25348
|
+
}
|
|
25349
|
+
}
|
|
25350
|
+
});
|
|
25351
|
+
}
|
|
25352
|
+
async handleLLMError(err, runId, parentRunId, tags) {
|
|
25353
|
+
this.endSpan({ runId, parentRunId, error: err, tags });
|
|
25354
|
+
}
|
|
25355
|
+
async handleLLMEnd(output, runId, parentRunId, tags) {
|
|
25356
|
+
const metrics = getMetricsFromResponse(output);
|
|
25357
|
+
const modelName2 = getModelNameFromResponse(output);
|
|
25358
|
+
const ttft = this.ttftMs.get(runId);
|
|
25359
|
+
if (ttft !== void 0) {
|
|
25360
|
+
metrics.time_to_first_token = ttft;
|
|
25361
|
+
}
|
|
25362
|
+
this.startTimes.delete(runId);
|
|
25363
|
+
this.firstTokenTimes.delete(runId);
|
|
25364
|
+
this.ttftMs.delete(runId);
|
|
25365
|
+
this.endSpan({
|
|
25366
|
+
runId,
|
|
25367
|
+
parentRunId,
|
|
25368
|
+
output,
|
|
25369
|
+
metrics,
|
|
25370
|
+
tags,
|
|
25371
|
+
metadata: {
|
|
25372
|
+
model: modelName2
|
|
25373
|
+
}
|
|
25374
|
+
});
|
|
25375
|
+
}
|
|
25376
|
+
async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
|
|
25377
|
+
this.startTimes.set(runId, Date.now());
|
|
25378
|
+
this.firstTokenTimes.delete(runId);
|
|
25379
|
+
this.ttftMs.delete(runId);
|
|
25380
|
+
this.startSpan({
|
|
25381
|
+
runId,
|
|
25382
|
+
parentRunId,
|
|
25383
|
+
name: runName ?? getSerializedName(llm) ?? "Chat Model",
|
|
25384
|
+
type: "llm",
|
|
25385
|
+
event: {
|
|
25386
|
+
input: messages,
|
|
25387
|
+
tags,
|
|
25388
|
+
metadata: {
|
|
25389
|
+
serialized: llm,
|
|
25390
|
+
name: runName,
|
|
25391
|
+
metadata,
|
|
25392
|
+
...extraParams
|
|
25393
|
+
}
|
|
25394
|
+
}
|
|
25395
|
+
});
|
|
25396
|
+
}
|
|
25397
|
+
async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
|
|
25398
|
+
if (tags?.includes("langsmith:hidden")) {
|
|
25399
|
+
this.skippedRuns.add(runId);
|
|
25400
|
+
return;
|
|
25401
|
+
}
|
|
25402
|
+
this.startSpan({
|
|
25403
|
+
runId,
|
|
25404
|
+
parentRunId,
|
|
25405
|
+
name: runName ?? getSerializedName(chain) ?? "Chain",
|
|
25406
|
+
event: {
|
|
25407
|
+
input: inputs,
|
|
25408
|
+
tags,
|
|
25409
|
+
metadata: {
|
|
25410
|
+
serialized: chain,
|
|
25411
|
+
name: runName,
|
|
25412
|
+
metadata,
|
|
25413
|
+
run_type: runType
|
|
25414
|
+
}
|
|
25415
|
+
}
|
|
25416
|
+
});
|
|
25417
|
+
}
|
|
25418
|
+
async handleChainError(err, runId, parentRunId, tags, kwargs) {
|
|
25419
|
+
this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
|
|
25420
|
+
}
|
|
25421
|
+
async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
|
|
25422
|
+
this.endSpan({
|
|
25423
|
+
runId,
|
|
25424
|
+
parentRunId,
|
|
25425
|
+
tags,
|
|
25426
|
+
output: outputs,
|
|
25427
|
+
metadata: { ...kwargs }
|
|
25428
|
+
});
|
|
25429
|
+
}
|
|
25430
|
+
async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
|
|
25431
|
+
this.startSpan({
|
|
25432
|
+
runId,
|
|
25433
|
+
parentRunId,
|
|
25434
|
+
name: runName ?? getSerializedName(tool) ?? "Tool",
|
|
25435
|
+
type: "llm",
|
|
25436
|
+
event: {
|
|
25437
|
+
input: safeJsonParse(input),
|
|
25438
|
+
tags,
|
|
25439
|
+
metadata: {
|
|
25440
|
+
metadata,
|
|
25441
|
+
serialized: tool,
|
|
25442
|
+
input_str: input,
|
|
25443
|
+
input: safeJsonParse(input),
|
|
25444
|
+
name: runName
|
|
25445
|
+
}
|
|
25446
|
+
}
|
|
25447
|
+
});
|
|
25448
|
+
}
|
|
25449
|
+
async handleToolError(err, runId, parentRunId, tags) {
|
|
25450
|
+
this.endSpan({ runId, parentRunId, error: err, tags });
|
|
25451
|
+
}
|
|
25452
|
+
async handleToolEnd(output, runId, parentRunId, tags) {
|
|
25453
|
+
this.endSpan({ runId, parentRunId, output, tags });
|
|
25454
|
+
}
|
|
25455
|
+
async handleAgentAction(action, runId, parentRunId, tags) {
|
|
25456
|
+
this.startSpan({
|
|
25457
|
+
runId,
|
|
25458
|
+
parentRunId,
|
|
25459
|
+
type: "llm",
|
|
25460
|
+
name: typeof action.tool === "string" ? action.tool : "Agent",
|
|
25461
|
+
event: {
|
|
25462
|
+
input: action,
|
|
25463
|
+
tags
|
|
25464
|
+
}
|
|
25465
|
+
});
|
|
25466
|
+
}
|
|
25467
|
+
async handleAgentEnd(action, runId, parentRunId, tags) {
|
|
25468
|
+
this.endSpan({ runId, parentRunId, output: action, tags });
|
|
25469
|
+
}
|
|
25470
|
+
async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
|
|
25471
|
+
this.startSpan({
|
|
25472
|
+
runId,
|
|
25473
|
+
parentRunId,
|
|
25474
|
+
name: name ?? getSerializedName(retriever) ?? "Retriever",
|
|
25475
|
+
type: "function",
|
|
25476
|
+
event: {
|
|
25477
|
+
input: query,
|
|
25478
|
+
tags,
|
|
25479
|
+
metadata: {
|
|
25480
|
+
serialized: retriever,
|
|
25481
|
+
metadata,
|
|
25482
|
+
name
|
|
25483
|
+
}
|
|
25484
|
+
}
|
|
25485
|
+
});
|
|
25486
|
+
}
|
|
25487
|
+
async handleRetrieverEnd(documents, runId, parentRunId, tags) {
|
|
25488
|
+
this.endSpan({ runId, parentRunId, output: documents, tags });
|
|
25489
|
+
}
|
|
25490
|
+
async handleRetrieverError(err, runId, parentRunId, tags) {
|
|
25491
|
+
this.endSpan({ runId, parentRunId, error: err, tags });
|
|
25492
|
+
}
|
|
25493
|
+
async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
|
|
25494
|
+
if (!this.firstTokenTimes.has(runId)) {
|
|
25495
|
+
const now2 = Date.now();
|
|
25496
|
+
this.firstTokenTimes.set(runId, now2);
|
|
25497
|
+
const start = this.startTimes.get(runId);
|
|
25498
|
+
if (start !== void 0) {
|
|
25499
|
+
this.ttftMs.set(runId, (now2 - start) / 1e3);
|
|
25500
|
+
}
|
|
25501
|
+
}
|
|
25502
|
+
}
|
|
25503
|
+
};
|
|
25504
|
+
function getSerializedName(serialized) {
|
|
25505
|
+
if (typeof serialized.name === "string") {
|
|
25506
|
+
return serialized.name;
|
|
25507
|
+
}
|
|
25508
|
+
const lastIdPart = serialized.id?.at(-1);
|
|
25509
|
+
return typeof lastIdPart === "string" ? lastIdPart : void 0;
|
|
25510
|
+
}
|
|
25511
|
+
function cleanObject(obj) {
|
|
25512
|
+
return Object.fromEntries(
|
|
25513
|
+
Object.entries(obj).filter(([, value]) => {
|
|
25514
|
+
if (typeof value !== "number") {
|
|
25515
|
+
return false;
|
|
25516
|
+
}
|
|
25517
|
+
return Number.isFinite(value);
|
|
25518
|
+
})
|
|
25519
|
+
);
|
|
25520
|
+
}
|
|
25521
|
+
function walkGenerations(response) {
|
|
25522
|
+
const result = [];
|
|
25523
|
+
const generations = response.generations || [];
|
|
25524
|
+
for (const batch of generations) {
|
|
25525
|
+
if (Array.isArray(batch)) {
|
|
25526
|
+
for (const generation of batch) {
|
|
25527
|
+
if (isRecord(generation)) {
|
|
25528
|
+
result.push(generation);
|
|
25529
|
+
}
|
|
25530
|
+
}
|
|
25531
|
+
} else if (isRecord(batch)) {
|
|
25532
|
+
result.push(batch);
|
|
25533
|
+
}
|
|
25534
|
+
}
|
|
25535
|
+
return result;
|
|
25536
|
+
}
|
|
25537
|
+
function getModelNameFromResponse(response) {
|
|
25538
|
+
for (const generation of walkGenerations(response)) {
|
|
25539
|
+
const message = generation.message;
|
|
25540
|
+
if (!isRecord(message)) {
|
|
25541
|
+
continue;
|
|
25542
|
+
}
|
|
25543
|
+
const responseMetadata = message.response_metadata;
|
|
25544
|
+
if (!isRecord(responseMetadata)) {
|
|
25545
|
+
continue;
|
|
25546
|
+
}
|
|
25547
|
+
const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
|
|
25548
|
+
if (typeof modelName3 === "string") {
|
|
25549
|
+
return modelName3;
|
|
25550
|
+
}
|
|
25551
|
+
}
|
|
25552
|
+
const llmOutput = response.llmOutput || {};
|
|
25553
|
+
const modelName2 = llmOutput.model_name ?? llmOutput.model;
|
|
25554
|
+
return typeof modelName2 === "string" ? modelName2 : void 0;
|
|
25555
|
+
}
|
|
25556
|
+
function getMetricsFromResponse(response) {
|
|
25557
|
+
for (const generation of walkGenerations(response)) {
|
|
25558
|
+
const message = generation.message;
|
|
25559
|
+
if (!isRecord(message)) {
|
|
25560
|
+
continue;
|
|
25561
|
+
}
|
|
25562
|
+
const usageMetadata = message.usage_metadata;
|
|
25563
|
+
if (!isRecord(usageMetadata)) {
|
|
25564
|
+
continue;
|
|
25565
|
+
}
|
|
25566
|
+
const inputTokenDetails = usageMetadata.input_token_details;
|
|
25567
|
+
return cleanObject({
|
|
25568
|
+
total_tokens: usageMetadata.total_tokens,
|
|
25569
|
+
prompt_tokens: usageMetadata.input_tokens,
|
|
25570
|
+
completion_tokens: usageMetadata.output_tokens,
|
|
25571
|
+
prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
|
|
25572
|
+
prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
|
|
25573
|
+
});
|
|
25574
|
+
}
|
|
25575
|
+
const llmOutput = response.llmOutput || {};
|
|
25576
|
+
const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
|
|
25577
|
+
return cleanObject({
|
|
25578
|
+
total_tokens: tokenUsage.totalTokens,
|
|
25579
|
+
prompt_tokens: tokenUsage.promptTokens,
|
|
25580
|
+
completion_tokens: tokenUsage.completionTokens
|
|
25581
|
+
});
|
|
25582
|
+
}
|
|
25583
|
+
function safeJsonParse(input) {
|
|
25584
|
+
try {
|
|
25585
|
+
return JSON.parse(input);
|
|
25586
|
+
} catch {
|
|
25587
|
+
return input;
|
|
25588
|
+
}
|
|
25589
|
+
}
|
|
25590
|
+
function isRecord(value) {
|
|
25591
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25592
|
+
}
|
|
25593
|
+
|
|
25594
|
+
// src/instrumentation/plugins/langchain-channels.ts
|
|
25595
|
+
var langChainChannels = defineChannels("@langchain/core", {
|
|
25596
|
+
configure: channel({
|
|
25597
|
+
channelName: "CallbackManager.configure",
|
|
25598
|
+
kind: "sync-stream"
|
|
25599
|
+
}),
|
|
25600
|
+
configureSync: channel({
|
|
25601
|
+
channelName: "CallbackManager._configureSync",
|
|
25602
|
+
kind: "sync-stream"
|
|
25603
|
+
})
|
|
25604
|
+
});
|
|
25605
|
+
|
|
25606
|
+
// src/instrumentation/plugins/langchain-plugin.ts
|
|
25607
|
+
var LangChainPlugin = class extends BasePlugin {
|
|
25608
|
+
injectedManagers = /* @__PURE__ */ new WeakSet();
|
|
25609
|
+
onEnable() {
|
|
25610
|
+
this.subscribeToConfigure(langChainChannels.configure);
|
|
25611
|
+
this.subscribeToConfigure(langChainChannels.configureSync);
|
|
25612
|
+
}
|
|
25613
|
+
onDisable() {
|
|
25614
|
+
for (const unsubscribe of this.unsubscribers) {
|
|
25615
|
+
unsubscribe();
|
|
25616
|
+
}
|
|
25617
|
+
this.unsubscribers = [];
|
|
25618
|
+
this.injectedManagers = /* @__PURE__ */ new WeakSet();
|
|
25619
|
+
}
|
|
25620
|
+
subscribeToConfigure(channel2) {
|
|
25621
|
+
const tracingChannel2 = channel2.tracingChannel();
|
|
25622
|
+
const handlers = {
|
|
25623
|
+
start: (event) => {
|
|
25624
|
+
injectHandlerIntoArguments(event.arguments);
|
|
25625
|
+
},
|
|
25626
|
+
end: (event) => {
|
|
25627
|
+
this.injectHandler(event.result);
|
|
25628
|
+
}
|
|
25629
|
+
};
|
|
25630
|
+
tracingChannel2.subscribe(handlers);
|
|
25631
|
+
this.unsubscribers.push(() => {
|
|
25632
|
+
tracingChannel2.unsubscribe(handlers);
|
|
25633
|
+
});
|
|
25634
|
+
}
|
|
25635
|
+
injectHandler(result) {
|
|
25636
|
+
if (!isCallbackManager(result)) {
|
|
25637
|
+
return;
|
|
25638
|
+
}
|
|
25639
|
+
if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
|
|
25640
|
+
return;
|
|
25641
|
+
}
|
|
25642
|
+
try {
|
|
25643
|
+
result.addHandler(new BraintrustLangChainCallbackHandler(), true);
|
|
25644
|
+
this.injectedManagers.add(result);
|
|
25645
|
+
} catch {
|
|
25646
|
+
}
|
|
25647
|
+
}
|
|
25648
|
+
};
|
|
25649
|
+
function isCallbackManager(value) {
|
|
25650
|
+
if (typeof value !== "object" || value === null) {
|
|
25651
|
+
return false;
|
|
25652
|
+
}
|
|
25653
|
+
const maybeManager = value;
|
|
25654
|
+
return typeof maybeManager.addHandler === "function";
|
|
25655
|
+
}
|
|
25656
|
+
function hasBraintrustHandler(manager) {
|
|
25657
|
+
return manager.handlers?.some((handler) => {
|
|
25658
|
+
if (typeof handler !== "object" || handler === null) {
|
|
25659
|
+
return false;
|
|
25660
|
+
}
|
|
25661
|
+
const name = Reflect.get(handler, "name");
|
|
25662
|
+
return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
|
|
25663
|
+
}) ?? false;
|
|
25664
|
+
}
|
|
25665
|
+
function injectHandlerIntoArguments(args) {
|
|
25666
|
+
if (!isWritableArgumentsObject(args)) {
|
|
25667
|
+
return;
|
|
25668
|
+
}
|
|
25669
|
+
const inheritedHandlers = Reflect.get(args, "0");
|
|
25670
|
+
const handler = new BraintrustLangChainCallbackHandler();
|
|
25671
|
+
if (inheritedHandlers === void 0 || inheritedHandlers === null) {
|
|
25672
|
+
Reflect.set(args, "0", [handler]);
|
|
25673
|
+
return;
|
|
25674
|
+
}
|
|
25675
|
+
if (Array.isArray(inheritedHandlers)) {
|
|
25676
|
+
if (!inheritedHandlers.some(isBraintrustHandler)) {
|
|
25677
|
+
inheritedHandlers.push(handler);
|
|
25678
|
+
}
|
|
25679
|
+
}
|
|
25680
|
+
}
|
|
25681
|
+
function isWritableArgumentsObject(args) {
|
|
25682
|
+
return typeof args === "object" && args !== null;
|
|
25683
|
+
}
|
|
25684
|
+
function isBraintrustHandler(handler) {
|
|
25685
|
+
if (typeof handler !== "object" || handler === null) {
|
|
25686
|
+
return false;
|
|
25687
|
+
}
|
|
25688
|
+
return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
|
|
25689
|
+
}
|
|
25690
|
+
|
|
25691
|
+
// src/instrumentation/braintrust-plugin.ts
|
|
25692
|
+
function getIntegrationConfig(integrations, key) {
|
|
25693
|
+
return integrations[key];
|
|
25694
|
+
}
|
|
25695
|
+
var BraintrustPlugin = class extends BasePlugin {
|
|
25696
|
+
config;
|
|
25697
|
+
openaiPlugin = null;
|
|
25698
|
+
openAICodexPlugin = null;
|
|
25699
|
+
anthropicPlugin = null;
|
|
25700
|
+
aiSDKPlugin = null;
|
|
25701
|
+
claudeAgentSDKPlugin = null;
|
|
25702
|
+
cursorSDKPlugin = null;
|
|
25703
|
+
openAIAgentsPlugin = null;
|
|
25704
|
+
googleGenAIPlugin = null;
|
|
25705
|
+
huggingFacePlugin = null;
|
|
25706
|
+
openRouterPlugin = null;
|
|
25707
|
+
openRouterAgentPlugin = null;
|
|
25708
|
+
mistralPlugin = null;
|
|
25709
|
+
googleADKPlugin = null;
|
|
25710
|
+
coherePlugin = null;
|
|
25711
|
+
groqPlugin = null;
|
|
25712
|
+
genkitPlugin = null;
|
|
25713
|
+
gitHubCopilotPlugin = null;
|
|
25714
|
+
fluePlugin = null;
|
|
25715
|
+
langChainPlugin = null;
|
|
25716
|
+
constructor(config = {}) {
|
|
25717
|
+
super();
|
|
25718
|
+
this.config = config;
|
|
25719
|
+
}
|
|
25720
|
+
onEnable() {
|
|
25721
|
+
const integrations = this.config.integrations || {};
|
|
25722
|
+
if (integrations.openai !== false) {
|
|
25723
|
+
this.openaiPlugin = new OpenAIPlugin();
|
|
25724
|
+
this.openaiPlugin.enable();
|
|
25725
|
+
}
|
|
25726
|
+
if (integrations.openaiCodexSDK !== false) {
|
|
25727
|
+
this.openAICodexPlugin = new OpenAICodexPlugin();
|
|
25728
|
+
this.openAICodexPlugin.enable();
|
|
25729
|
+
}
|
|
25730
|
+
if (integrations.anthropic !== false) {
|
|
25731
|
+
this.anthropicPlugin = new AnthropicPlugin();
|
|
25732
|
+
this.anthropicPlugin.enable();
|
|
25733
|
+
}
|
|
25734
|
+
if (integrations.aisdk !== false && integrations.vercel !== false) {
|
|
25735
|
+
this.aiSDKPlugin = new AISDKPlugin();
|
|
25736
|
+
this.aiSDKPlugin.enable();
|
|
25737
|
+
}
|
|
25738
|
+
if (integrations.claudeAgentSDK !== false) {
|
|
25739
|
+
this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
|
|
23527
25740
|
this.claudeAgentSDKPlugin.enable();
|
|
23528
25741
|
}
|
|
23529
25742
|
if (integrations.cursorSDK !== false && integrations.cursor !== false) {
|
|
23530
25743
|
this.cursorSDKPlugin = new CursorSDKPlugin();
|
|
23531
25744
|
this.cursorSDKPlugin.enable();
|
|
23532
25745
|
}
|
|
25746
|
+
if (integrations.openAIAgents !== false) {
|
|
25747
|
+
this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
|
|
25748
|
+
this.openAIAgentsPlugin.enable();
|
|
25749
|
+
}
|
|
23533
25750
|
if (integrations.googleGenAI !== false && integrations.google !== false) {
|
|
23534
25751
|
this.googleGenAIPlugin = new GoogleGenAIPlugin();
|
|
23535
25752
|
this.googleGenAIPlugin.enable();
|
|
@@ -23570,6 +25787,14 @@ var BraintrustPlugin = class extends BasePlugin {
|
|
|
23570
25787
|
this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
|
|
23571
25788
|
this.gitHubCopilotPlugin.enable();
|
|
23572
25789
|
}
|
|
25790
|
+
if (getIntegrationConfig(integrations, "flue") !== false) {
|
|
25791
|
+
this.fluePlugin = new FluePlugin();
|
|
25792
|
+
this.fluePlugin.enable();
|
|
25793
|
+
}
|
|
25794
|
+
if (integrations.langchain !== false && integrations.langgraph !== false) {
|
|
25795
|
+
this.langChainPlugin = new LangChainPlugin();
|
|
25796
|
+
this.langChainPlugin.enable();
|
|
25797
|
+
}
|
|
23573
25798
|
}
|
|
23574
25799
|
onDisable() {
|
|
23575
25800
|
if (this.openaiPlugin) {
|
|
@@ -23596,6 +25821,10 @@ var BraintrustPlugin = class extends BasePlugin {
|
|
|
23596
25821
|
this.cursorSDKPlugin.disable();
|
|
23597
25822
|
this.cursorSDKPlugin = null;
|
|
23598
25823
|
}
|
|
25824
|
+
if (this.openAIAgentsPlugin) {
|
|
25825
|
+
this.openAIAgentsPlugin.disable();
|
|
25826
|
+
this.openAIAgentsPlugin = null;
|
|
25827
|
+
}
|
|
23599
25828
|
if (this.googleGenAIPlugin) {
|
|
23600
25829
|
this.googleGenAIPlugin.disable();
|
|
23601
25830
|
this.googleGenAIPlugin = null;
|
|
@@ -23636,9 +25865,104 @@ var BraintrustPlugin = class extends BasePlugin {
|
|
|
23636
25865
|
this.gitHubCopilotPlugin.disable();
|
|
23637
25866
|
this.gitHubCopilotPlugin = null;
|
|
23638
25867
|
}
|
|
25868
|
+
if (this.fluePlugin) {
|
|
25869
|
+
this.fluePlugin.disable();
|
|
25870
|
+
this.fluePlugin = null;
|
|
25871
|
+
}
|
|
25872
|
+
if (this.langChainPlugin) {
|
|
25873
|
+
this.langChainPlugin.disable();
|
|
25874
|
+
this.langChainPlugin = null;
|
|
25875
|
+
}
|
|
23639
25876
|
}
|
|
23640
25877
|
};
|
|
23641
25878
|
|
|
25879
|
+
// src/instrumentation/config.ts
|
|
25880
|
+
var envIntegrationAliases = {
|
|
25881
|
+
openai: "openai",
|
|
25882
|
+
"openai-codex": "openaiCodexSDK",
|
|
25883
|
+
"openai-codex-sdk": "openaiCodexSDK",
|
|
25884
|
+
openaicodexsdk: "openaiCodexSDK",
|
|
25885
|
+
codex: "openaiCodexSDK",
|
|
25886
|
+
"codex-sdk": "openaiCodexSDK",
|
|
25887
|
+
anthropic: "anthropic",
|
|
25888
|
+
aisdk: "aisdk",
|
|
25889
|
+
"ai-sdk": "aisdk",
|
|
25890
|
+
"vercel-ai": "aisdk",
|
|
25891
|
+
vercel: "vercel",
|
|
25892
|
+
claudeagentsdk: "claudeAgentSDK",
|
|
25893
|
+
"claude-agent-sdk": "claudeAgentSDK",
|
|
25894
|
+
cursor: "cursor",
|
|
25895
|
+
"cursor-sdk": "cursorSDK",
|
|
25896
|
+
cursorsdk: "cursorSDK",
|
|
25897
|
+
flue: "flue",
|
|
25898
|
+
"flue-runtime": "flue",
|
|
25899
|
+
"openai-agents": "openAIAgents",
|
|
25900
|
+
openaiagents: "openAIAgents",
|
|
25901
|
+
"openai-agents-core": "openAIAgents",
|
|
25902
|
+
openaiagentscore: "openAIAgents",
|
|
25903
|
+
google: "google",
|
|
25904
|
+
"google-genai": "googleGenAI",
|
|
25905
|
+
googlegenai: "googleGenAI",
|
|
25906
|
+
huggingface: "huggingface",
|
|
25907
|
+
openrouter: "openrouter",
|
|
25908
|
+
openrouteragent: "openrouterAgent",
|
|
25909
|
+
"openrouter-agent": "openrouterAgent",
|
|
25910
|
+
mistral: "mistral",
|
|
25911
|
+
googleadk: "googleADK",
|
|
25912
|
+
"google-adk": "googleADK",
|
|
25913
|
+
cohere: "cohere",
|
|
25914
|
+
groq: "groq",
|
|
25915
|
+
"groq-sdk": "groq",
|
|
25916
|
+
genkit: "genkit",
|
|
25917
|
+
"firebase-genkit": "genkit",
|
|
25918
|
+
githubcopilot: "gitHubCopilot",
|
|
25919
|
+
"github-copilot": "gitHubCopilot",
|
|
25920
|
+
"copilot-sdk": "gitHubCopilot",
|
|
25921
|
+
langchain: "langchain",
|
|
25922
|
+
"langchain-js": "langchain",
|
|
25923
|
+
"@langchain": "langchain",
|
|
25924
|
+
langgraph: "langgraph"
|
|
25925
|
+
};
|
|
25926
|
+
function getDefaultInstrumentationIntegrations() {
|
|
25927
|
+
return {
|
|
25928
|
+
openai: true,
|
|
25929
|
+
openaiCodexSDK: true,
|
|
25930
|
+
anthropic: true,
|
|
25931
|
+
vercel: true,
|
|
25932
|
+
aisdk: true,
|
|
25933
|
+
google: true,
|
|
25934
|
+
googleGenAI: true,
|
|
25935
|
+
googleADK: true,
|
|
25936
|
+
huggingface: true,
|
|
25937
|
+
claudeAgentSDK: true,
|
|
25938
|
+
cursor: true,
|
|
25939
|
+
cursorSDK: true,
|
|
25940
|
+
flue: true,
|
|
25941
|
+
openAIAgents: true,
|
|
25942
|
+
openrouter: true,
|
|
25943
|
+
openrouterAgent: true,
|
|
25944
|
+
mistral: true,
|
|
25945
|
+
cohere: true,
|
|
25946
|
+
groq: true,
|
|
25947
|
+
genkit: true,
|
|
25948
|
+
gitHubCopilot: true,
|
|
25949
|
+
langchain: true,
|
|
25950
|
+
langgraph: true
|
|
25951
|
+
};
|
|
25952
|
+
}
|
|
25953
|
+
function readDisabledInstrumentationEnvConfig(disabledList) {
|
|
25954
|
+
const integrations = {};
|
|
25955
|
+
if (disabledList) {
|
|
25956
|
+
for (const value of disabledList.split(",")) {
|
|
25957
|
+
const sdk = value.trim().toLowerCase();
|
|
25958
|
+
if (sdk.length > 0) {
|
|
25959
|
+
integrations[envIntegrationAliases[sdk] ?? sdk] = false;
|
|
25960
|
+
}
|
|
25961
|
+
}
|
|
25962
|
+
}
|
|
25963
|
+
return { integrations };
|
|
25964
|
+
}
|
|
25965
|
+
|
|
23642
25966
|
// src/instrumentation/registry.ts
|
|
23643
25967
|
var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
|
|
23644
25968
|
function getSharedState() {
|
|
@@ -23717,50 +26041,16 @@ var PluginRegistry = class {
|
|
|
23717
26041
|
* Get default configuration (all integrations enabled).
|
|
23718
26042
|
*/
|
|
23719
26043
|
getDefaultConfig() {
|
|
23720
|
-
return
|
|
23721
|
-
openai: true,
|
|
23722
|
-
openaiCodexSDK: true,
|
|
23723
|
-
anthropic: true,
|
|
23724
|
-
vercel: true,
|
|
23725
|
-
aisdk: true,
|
|
23726
|
-
google: true,
|
|
23727
|
-
googleGenAI: true,
|
|
23728
|
-
googleADK: true,
|
|
23729
|
-
huggingface: true,
|
|
23730
|
-
claudeAgentSDK: true,
|
|
23731
|
-
cursor: true,
|
|
23732
|
-
cursorSDK: true,
|
|
23733
|
-
openrouter: true,
|
|
23734
|
-
openrouterAgent: true,
|
|
23735
|
-
mistral: true,
|
|
23736
|
-
cohere: true,
|
|
23737
|
-
groq: true,
|
|
23738
|
-
genkit: true,
|
|
23739
|
-
gitHubCopilot: true
|
|
23740
|
-
};
|
|
26044
|
+
return getDefaultInstrumentationIntegrations();
|
|
23741
26045
|
}
|
|
23742
26046
|
/**
|
|
23743
26047
|
* Read configuration from environment variables.
|
|
23744
26048
|
* Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
|
|
23745
26049
|
*/
|
|
23746
26050
|
readEnvConfig() {
|
|
23747
|
-
|
|
23748
|
-
|
|
23749
|
-
|
|
23750
|
-
const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
|
|
23751
|
-
for (const sdk of disabled) {
|
|
23752
|
-
if (sdk === "cursor-sdk") {
|
|
23753
|
-
integrations.cursorSDK = false;
|
|
23754
|
-
} else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
|
|
23755
|
-
integrations.gitHubCopilot = false;
|
|
23756
|
-
} else if (sdk === "openai-codex-sdk") {
|
|
23757
|
-
integrations.openaiCodexSDK = false;
|
|
23758
|
-
} else {
|
|
23759
|
-
integrations[sdk] = false;
|
|
23760
|
-
}
|
|
23761
|
-
}
|
|
23762
|
-
}
|
|
23763
|
-
return { integrations };
|
|
26051
|
+
return readDisabledInstrumentationEnvConfig(
|
|
26052
|
+
isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
|
|
26053
|
+
);
|
|
23764
26054
|
}
|
|
23765
26055
|
};
|
|
23766
26056
|
var registry = new PluginRegistry();
|
|
@@ -23790,6 +26080,10 @@ function configureWorkerd() {
|
|
|
23790
26080
|
}
|
|
23791
26081
|
return process.env[name];
|
|
23792
26082
|
};
|
|
26083
|
+
isomorph_default.getBraintrustApiKey = async () => {
|
|
26084
|
+
const value = isomorph_default.getEnv("BRAINTRUST_API_KEY");
|
|
26085
|
+
return value?.trim() ? value : void 0;
|
|
26086
|
+
};
|
|
23793
26087
|
isomorph_default.hash = (data) => {
|
|
23794
26088
|
let hash = 0;
|
|
23795
26089
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -23811,8 +26105,10 @@ __export(exports_exports, {
|
|
|
23811
26105
|
Attachment: () => Attachment,
|
|
23812
26106
|
AttachmentReference: () => AttachmentReference,
|
|
23813
26107
|
BRAINTRUST_CURRENT_SPAN_STORE: () => BRAINTRUST_CURRENT_SPAN_STORE,
|
|
26108
|
+
BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME: () => BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
|
|
23814
26109
|
BaseAttachment: () => BaseAttachment,
|
|
23815
26110
|
BaseExperiment: () => BaseExperiment,
|
|
26111
|
+
BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
|
|
23816
26112
|
BraintrustMiddleware: () => BraintrustMiddleware,
|
|
23817
26113
|
BraintrustState: () => BraintrustState,
|
|
23818
26114
|
BraintrustStream: () => BraintrustStream,
|
|
@@ -23823,6 +26119,7 @@ __export(exports_exports, {
|
|
|
23823
26119
|
DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
|
|
23824
26120
|
DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
|
|
23825
26121
|
Dataset: () => Dataset2,
|
|
26122
|
+
DatasetPipeline: () => DatasetPipeline,
|
|
23826
26123
|
ERR_PERMALINK: () => ERR_PERMALINK,
|
|
23827
26124
|
Eval: () => Eval,
|
|
23828
26125
|
EvalResultWithSummary: () => EvalResultWithSummary,
|
|
@@ -23938,6 +26235,8 @@ __export(exports_exports, {
|
|
|
23938
26235
|
wrapCohere: () => wrapCohere,
|
|
23939
26236
|
wrapCopilotClient: () => wrapCopilotClient,
|
|
23940
26237
|
wrapCursorSDK: () => wrapCursorSDK,
|
|
26238
|
+
wrapFlueContext: () => wrapFlueContext,
|
|
26239
|
+
wrapFlueSession: () => wrapFlueSession,
|
|
23941
26240
|
wrapGenkit: () => wrapGenkit,
|
|
23942
26241
|
wrapGoogleADK: () => wrapGoogleADK,
|
|
23943
26242
|
wrapGoogleGenAI: () => wrapGoogleGenAI,
|
|
@@ -25037,7 +27336,7 @@ function extractModelParameters(params, excludeKeys) {
|
|
|
25037
27336
|
}
|
|
25038
27337
|
return modelParams;
|
|
25039
27338
|
}
|
|
25040
|
-
function
|
|
27339
|
+
function getNumberProperty3(obj, key) {
|
|
25041
27340
|
if (!obj || typeof obj !== "object" || !(key in obj)) {
|
|
25042
27341
|
return void 0;
|
|
25043
27342
|
}
|
|
@@ -25046,31 +27345,31 @@ function getNumberProperty2(obj, key) {
|
|
|
25046
27345
|
}
|
|
25047
27346
|
function normalizeUsageMetrics(usage, provider, providerMetadata) {
|
|
25048
27347
|
const metrics = {};
|
|
25049
|
-
const inputTokens =
|
|
27348
|
+
const inputTokens = getNumberProperty3(usage, "inputTokens");
|
|
25050
27349
|
if (inputTokens !== void 0) {
|
|
25051
27350
|
metrics.prompt_tokens = inputTokens;
|
|
25052
27351
|
}
|
|
25053
|
-
const outputTokens =
|
|
27352
|
+
const outputTokens = getNumberProperty3(usage, "outputTokens");
|
|
25054
27353
|
if (outputTokens !== void 0) {
|
|
25055
27354
|
metrics.completion_tokens = outputTokens;
|
|
25056
27355
|
}
|
|
25057
|
-
const totalTokens =
|
|
27356
|
+
const totalTokens = getNumberProperty3(usage, "totalTokens");
|
|
25058
27357
|
if (totalTokens !== void 0) {
|
|
25059
27358
|
metrics.tokens = totalTokens;
|
|
25060
27359
|
}
|
|
25061
|
-
const reasoningTokens =
|
|
27360
|
+
const reasoningTokens = getNumberProperty3(usage, "reasoningTokens");
|
|
25062
27361
|
if (reasoningTokens !== void 0) {
|
|
25063
27362
|
metrics.completion_reasoning_tokens = reasoningTokens;
|
|
25064
27363
|
}
|
|
25065
|
-
const cachedInputTokens =
|
|
27364
|
+
const cachedInputTokens = getNumberProperty3(usage, "cachedInputTokens");
|
|
25066
27365
|
if (cachedInputTokens !== void 0) {
|
|
25067
27366
|
metrics.prompt_cached_tokens = cachedInputTokens;
|
|
25068
27367
|
}
|
|
25069
27368
|
if (provider === "anthropic") {
|
|
25070
27369
|
const anthropicMetadata = providerMetadata?.anthropic;
|
|
25071
27370
|
if (anthropicMetadata) {
|
|
25072
|
-
const cacheReadTokens =
|
|
25073
|
-
const cacheCreationTokens =
|
|
27371
|
+
const cacheReadTokens = getNumberProperty3(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
|
|
27372
|
+
const cacheCreationTokens = getNumberProperty3(
|
|
25074
27373
|
anthropicMetadata.usage,
|
|
25075
27374
|
"cache_creation_input_tokens"
|
|
25076
27375
|
) || 0;
|
|
@@ -26045,17 +28344,17 @@ function wrapGenkit(genkit) {
|
|
|
26045
28344
|
console.warn("Unsupported Genkit object. Not wrapping.");
|
|
26046
28345
|
return genkit;
|
|
26047
28346
|
}
|
|
26048
|
-
function
|
|
28347
|
+
function isRecord2(value) {
|
|
26049
28348
|
return typeof value === "object" && value !== null;
|
|
26050
28349
|
}
|
|
26051
28350
|
function isPropertyBag(value) {
|
|
26052
|
-
return
|
|
28351
|
+
return isRecord2(value) || typeof value === "function";
|
|
26053
28352
|
}
|
|
26054
28353
|
function hasFunction(value, methodName) {
|
|
26055
28354
|
return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
|
|
26056
28355
|
}
|
|
26057
28356
|
function isGenkitInstance(value) {
|
|
26058
|
-
return
|
|
28357
|
+
return isRecord2(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
|
|
26059
28358
|
}
|
|
26060
28359
|
function isGenkitModule(value) {
|
|
26061
28360
|
return hasFunction(value, "genkit");
|
|
@@ -26109,7 +28408,7 @@ function patchGenkitRegistry(instance) {
|
|
|
26109
28408
|
patchGenkitRegistryConstructor(registry2);
|
|
26110
28409
|
}
|
|
26111
28410
|
function patchGenkitRegistryLookup(registry2) {
|
|
26112
|
-
if (!
|
|
28411
|
+
if (!isRecord2(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
|
|
26113
28412
|
return;
|
|
26114
28413
|
}
|
|
26115
28414
|
const originalLookupAction = registry2.lookupAction;
|
|
@@ -26135,7 +28434,7 @@ function patchGenkitRegistryLookup(registry2) {
|
|
|
26135
28434
|
}
|
|
26136
28435
|
}
|
|
26137
28436
|
function patchGenkitRegistryConstructor(registry2) {
|
|
26138
|
-
if (!
|
|
28437
|
+
if (!isRecord2(registry2)) {
|
|
26139
28438
|
return;
|
|
26140
28439
|
}
|
|
26141
28440
|
const constructor = registry2.constructor;
|
|
@@ -26151,7 +28450,7 @@ function patchGenkitRegistryConstructor(registry2) {
|
|
|
26151
28450
|
configurable: true,
|
|
26152
28451
|
value: (...args) => {
|
|
26153
28452
|
const childRegistry = originalWithParent.apply(constructor, args);
|
|
26154
|
-
if (args.some((arg) =>
|
|
28453
|
+
if (args.some((arg) => isRecord2(arg) && hasRegistryPatchedFlag(arg))) {
|
|
26155
28454
|
patchGenkitRegistryLookup(childRegistry);
|
|
26156
28455
|
patchGenkitRegistryConstructor(childRegistry);
|
|
26157
28456
|
}
|
|
@@ -26250,7 +28549,7 @@ function hasRegistryConstructorPatchedFlag(value) {
|
|
|
26250
28549
|
);
|
|
26251
28550
|
}
|
|
26252
28551
|
function isPromiseLike2(value) {
|
|
26253
|
-
return
|
|
28552
|
+
return isRecord2(value) && "then" in value && typeof value.then === "function";
|
|
26254
28553
|
}
|
|
26255
28554
|
|
|
26256
28555
|
// src/wrappers/huggingface.ts
|
|
@@ -26613,14 +28912,14 @@ function wrapMistral(mistral) {
|
|
|
26613
28912
|
console.warn("Unsupported Mistral library. Not wrapping.");
|
|
26614
28913
|
return mistral;
|
|
26615
28914
|
}
|
|
26616
|
-
function
|
|
28915
|
+
function isRecord3(value) {
|
|
26617
28916
|
return typeof value === "object" && value !== null;
|
|
26618
28917
|
}
|
|
26619
28918
|
function hasFunction3(value, methodName) {
|
|
26620
|
-
return
|
|
28919
|
+
return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
|
|
26621
28920
|
}
|
|
26622
28921
|
function isSupportedMistralClient(value) {
|
|
26623
|
-
if (!
|
|
28922
|
+
if (!isRecord3(value)) {
|
|
26624
28923
|
return false;
|
|
26625
28924
|
}
|
|
26626
28925
|
return value.chat !== void 0 && hasChat(value.chat) || value.embeddings !== void 0 && hasEmbeddings(value.embeddings) || value.fim !== void 0 && hasFim(value.fim) || value.agents !== void 0 && hasAgents(value.agents) || value.classifiers !== void 0 && hasClassifiers(value.classifiers);
|
|
@@ -26804,14 +29103,14 @@ function wrapCohere(cohere) {
|
|
|
26804
29103
|
return cohere;
|
|
26805
29104
|
}
|
|
26806
29105
|
var cohereProxyCache = /* @__PURE__ */ new WeakMap();
|
|
26807
|
-
function
|
|
29106
|
+
function isRecord4(value) {
|
|
26808
29107
|
return typeof value === "object" && value !== null;
|
|
26809
29108
|
}
|
|
26810
29109
|
function hasFunction4(value, methodName) {
|
|
26811
|
-
return
|
|
29110
|
+
return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
|
|
26812
29111
|
}
|
|
26813
29112
|
function isSupportedCohereClient(value) {
|
|
26814
|
-
if (!
|
|
29113
|
+
if (!isRecord4(value)) {
|
|
26815
29114
|
return false;
|
|
26816
29115
|
}
|
|
26817
29116
|
return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
|
|
@@ -26871,20 +29170,20 @@ function wrapGroq(groq) {
|
|
|
26871
29170
|
console.warn("Unsupported Groq library. Not wrapping.");
|
|
26872
29171
|
return groq;
|
|
26873
29172
|
}
|
|
26874
|
-
function
|
|
29173
|
+
function isRecord5(value) {
|
|
26875
29174
|
return typeof value === "object" && value !== null;
|
|
26876
29175
|
}
|
|
26877
29176
|
function hasFunction5(value, methodName) {
|
|
26878
|
-
return
|
|
29177
|
+
return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
|
|
26879
29178
|
}
|
|
26880
29179
|
function hasChat2(value) {
|
|
26881
|
-
return
|
|
29180
|
+
return isRecord5(value) && isRecord5(value.completions) && hasFunction5(value.completions, "create");
|
|
26882
29181
|
}
|
|
26883
29182
|
function hasEmbeddings2(value) {
|
|
26884
29183
|
return hasFunction5(value, "create");
|
|
26885
29184
|
}
|
|
26886
29185
|
function isSupportedGroqClient(value) {
|
|
26887
|
-
return
|
|
29186
|
+
return isRecord5(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
|
|
26888
29187
|
}
|
|
26889
29188
|
function groqProxy(groq) {
|
|
26890
29189
|
const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -27079,10 +29378,12 @@ function formatExperimentSummary(summary) {
|
|
|
27079
29378
|
// src/wrappers/shared/flush.ts
|
|
27080
29379
|
async function summarizeAndFlush(experiment, options) {
|
|
27081
29380
|
const shouldDisplay = options.displaySummary ?? true;
|
|
27082
|
-
|
|
27083
|
-
|
|
27084
|
-
|
|
29381
|
+
if (!shouldDisplay) {
|
|
29382
|
+
await experiment.flush();
|
|
29383
|
+
return;
|
|
27085
29384
|
}
|
|
29385
|
+
const summary = await experiment.summarize();
|
|
29386
|
+
console.log(formatExperimentSummary(summary));
|
|
27086
29387
|
}
|
|
27087
29388
|
|
|
27088
29389
|
// src/wrappers/vitest/flush-manager.ts
|
|
@@ -28946,8 +31247,12 @@ var waterfall$1 = awaitify(waterfall);
|
|
|
28946
31247
|
|
|
28947
31248
|
// src/trace.ts
|
|
28948
31249
|
var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
|
|
28949
|
-
constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
|
|
28950
|
-
const filterExpr = _SpanFetcher.buildFilter(
|
|
31250
|
+
constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
|
|
31251
|
+
const filterExpr = _SpanFetcher.buildFilter(
|
|
31252
|
+
rootSpanId,
|
|
31253
|
+
spanTypeFilter,
|
|
31254
|
+
includeScorers
|
|
31255
|
+
);
|
|
28951
31256
|
super(objectType, void 0, void 0, {
|
|
28952
31257
|
filter: filterExpr
|
|
28953
31258
|
});
|
|
@@ -28956,16 +31261,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
|
|
|
28956
31261
|
this._state = _state;
|
|
28957
31262
|
this.spanTypeFilter = spanTypeFilter;
|
|
28958
31263
|
}
|
|
28959
|
-
static buildFilter(rootSpanId, spanTypeFilter) {
|
|
31264
|
+
static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
|
|
28960
31265
|
const children = [
|
|
28961
31266
|
// Base filter: root_span_id = 'value'
|
|
28962
31267
|
{
|
|
28963
31268
|
op: "eq",
|
|
28964
31269
|
left: { op: "ident", name: ["root_span_id"] },
|
|
28965
31270
|
right: { op: "literal", value: rootSpanId }
|
|
28966
|
-
}
|
|
28967
|
-
|
|
28968
|
-
|
|
31271
|
+
}
|
|
31272
|
+
];
|
|
31273
|
+
if (!includeScorers) {
|
|
31274
|
+
children.push({
|
|
28969
31275
|
op: "or",
|
|
28970
31276
|
children: [
|
|
28971
31277
|
{
|
|
@@ -28978,8 +31284,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
|
|
|
28978
31284
|
right: { op: "literal", value: "scorer" }
|
|
28979
31285
|
}
|
|
28980
31286
|
]
|
|
28981
|
-
}
|
|
28982
|
-
|
|
31287
|
+
});
|
|
31288
|
+
}
|
|
28983
31289
|
if (spanTypeFilter && spanTypeFilter.length > 0) {
|
|
28984
31290
|
children.push({
|
|
28985
31291
|
op: "in",
|
|
@@ -29005,35 +31311,49 @@ var CachedSpanFetcher = class {
|
|
|
29005
31311
|
fetchFn;
|
|
29006
31312
|
constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
|
|
29007
31313
|
if (typeof objectTypeOrFetchFn === "function") {
|
|
29008
|
-
this.fetchFn = objectTypeOrFetchFn;
|
|
31314
|
+
this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
|
|
29009
31315
|
} else {
|
|
29010
31316
|
const objectType = objectTypeOrFetchFn;
|
|
29011
|
-
this.fetchFn = async (spanType) => {
|
|
31317
|
+
this.fetchFn = async (spanType, includeScorers) => {
|
|
29012
31318
|
const state = await getState();
|
|
29013
31319
|
const fetcher = new SpanFetcher(
|
|
29014
31320
|
objectType,
|
|
29015
31321
|
objectId,
|
|
29016
31322
|
rootSpanId,
|
|
29017
31323
|
state,
|
|
29018
|
-
spanType
|
|
31324
|
+
spanType,
|
|
31325
|
+
includeScorers
|
|
29019
31326
|
);
|
|
29020
31327
|
const rows = await fetcher.fetchedData();
|
|
29021
|
-
return rows.
|
|
31328
|
+
return rows.map((row) => ({
|
|
29022
31329
|
input: row.input,
|
|
29023
31330
|
output: row.output,
|
|
31331
|
+
expected: row.expected,
|
|
31332
|
+
error: row.error,
|
|
31333
|
+
scores: row.scores,
|
|
31334
|
+
metrics: row.metrics,
|
|
29024
31335
|
metadata: row.metadata,
|
|
29025
31336
|
span_id: row.span_id,
|
|
29026
31337
|
span_parents: row.span_parents,
|
|
31338
|
+
is_root: row.is_root,
|
|
29027
31339
|
span_attributes: row.span_attributes,
|
|
29028
31340
|
id: row.id,
|
|
29029
31341
|
_xact_id: row._xact_id,
|
|
29030
31342
|
_pagination_key: row._pagination_key,
|
|
29031
|
-
root_span_id: row.root_span_id
|
|
31343
|
+
root_span_id: row.root_span_id,
|
|
31344
|
+
created: row.created,
|
|
31345
|
+
tags: row.tags
|
|
29032
31346
|
}));
|
|
29033
31347
|
};
|
|
29034
31348
|
}
|
|
29035
31349
|
}
|
|
29036
|
-
async getSpans({
|
|
31350
|
+
async getSpans({
|
|
31351
|
+
spanType,
|
|
31352
|
+
includeScorers = false
|
|
31353
|
+
} = {}) {
|
|
31354
|
+
if (includeScorers) {
|
|
31355
|
+
return this.fetchFn(spanType, true);
|
|
31356
|
+
}
|
|
29037
31357
|
if (this.allFetched) {
|
|
29038
31358
|
return this.getFromCache(spanType);
|
|
29039
31359
|
}
|
|
@@ -29050,7 +31370,7 @@ var CachedSpanFetcher = class {
|
|
|
29050
31370
|
return this.getFromCache(spanType);
|
|
29051
31371
|
}
|
|
29052
31372
|
async fetchSpans(spanType) {
|
|
29053
|
-
const spans = await this.fetchFn(spanType);
|
|
31373
|
+
const spans = await this.fetchFn(spanType, false);
|
|
29054
31374
|
for (const span of spans) {
|
|
29055
31375
|
const type = span.span_attributes?.type ?? "";
|
|
29056
31376
|
const existing = this.spanCache.get(type) ?? [];
|
|
@@ -29128,10 +31448,13 @@ var LocalTrace = class {
|
|
|
29128
31448
|
* First checks the local span cache for recently logged spans, then falls
|
|
29129
31449
|
* back to CachedSpanFetcher which handles BTQL fetching and caching.
|
|
29130
31450
|
*/
|
|
29131
|
-
async getSpans({
|
|
31451
|
+
async getSpans({
|
|
31452
|
+
spanType,
|
|
31453
|
+
includeScorers = false
|
|
31454
|
+
} = {}) {
|
|
29132
31455
|
const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
|
|
29133
31456
|
if (cachedSpans && cachedSpans.length > 0) {
|
|
29134
|
-
let spans = cachedSpans.filter(
|
|
31457
|
+
let spans = includeScorers ? cachedSpans : cachedSpans.filter(
|
|
29135
31458
|
(span) => span.span_attributes?.purpose !== "scorer"
|
|
29136
31459
|
);
|
|
29137
31460
|
if (spanType && spanType.length > 0) {
|
|
@@ -29142,13 +31465,19 @@ var LocalTrace = class {
|
|
|
29142
31465
|
return spans.map((span) => ({
|
|
29143
31466
|
input: span.input,
|
|
29144
31467
|
output: span.output,
|
|
31468
|
+
expected: span.expected,
|
|
31469
|
+
error: span.error,
|
|
31470
|
+
scores: span.scores,
|
|
31471
|
+
metrics: span.metrics,
|
|
29145
31472
|
metadata: span.metadata,
|
|
29146
31473
|
span_id: span.span_id,
|
|
29147
31474
|
span_parents: span.span_parents,
|
|
29148
|
-
|
|
31475
|
+
is_root: span.is_root,
|
|
31476
|
+
span_attributes: span.span_attributes,
|
|
31477
|
+
tags: span.tags
|
|
29149
31478
|
}));
|
|
29150
31479
|
}
|
|
29151
|
-
return this.cachedFetcher.getSpans({ spanType });
|
|
31480
|
+
return this.cachedFetcher.getSpans({ spanType, includeScorers });
|
|
29152
31481
|
}
|
|
29153
31482
|
/**
|
|
29154
31483
|
* Get the thread (preprocessed messages) for this trace.
|
|
@@ -30337,6 +32666,34 @@ var defaultReporter = {
|
|
|
30337
32666
|
}
|
|
30338
32667
|
};
|
|
30339
32668
|
|
|
32669
|
+
// src/dataset-pipeline.ts
|
|
32670
|
+
function DatasetPipeline(definition) {
|
|
32671
|
+
if (!globalThis.__braintrust_dataset_pipelines) {
|
|
32672
|
+
globalThis.__braintrust_dataset_pipelines = [];
|
|
32673
|
+
}
|
|
32674
|
+
const storedDefinition = {
|
|
32675
|
+
name: definition.name,
|
|
32676
|
+
source: {
|
|
32677
|
+
projectId: definition.source.projectId,
|
|
32678
|
+
projectName: definition.source.projectName,
|
|
32679
|
+
orgName: definition.source.orgName,
|
|
32680
|
+
filter: definition.source.filter,
|
|
32681
|
+
scope: definition.source.scope ?? "span"
|
|
32682
|
+
},
|
|
32683
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
|
32684
|
+
transform: definition.transform,
|
|
32685
|
+
target: {
|
|
32686
|
+
projectId: definition.target.projectId,
|
|
32687
|
+
projectName: definition.target.projectName,
|
|
32688
|
+
orgName: definition.target.orgName,
|
|
32689
|
+
datasetName: definition.target.datasetName,
|
|
32690
|
+
description: definition.target.description,
|
|
32691
|
+
metadata: definition.target.metadata
|
|
32692
|
+
}
|
|
32693
|
+
};
|
|
32694
|
+
globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
|
|
32695
|
+
}
|
|
32696
|
+
|
|
30340
32697
|
// src/framework2.ts
|
|
30341
32698
|
import { z as z12 } from "zod/v3";
|
|
30342
32699
|
var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";
|
|
@@ -30862,8 +33219,10 @@ export {
|
|
|
30862
33219
|
Attachment,
|
|
30863
33220
|
AttachmentReference,
|
|
30864
33221
|
BRAINTRUST_CURRENT_SPAN_STORE,
|
|
33222
|
+
BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
|
|
30865
33223
|
BaseAttachment,
|
|
30866
33224
|
BaseExperiment,
|
|
33225
|
+
BraintrustLangChainCallbackHandler,
|
|
30867
33226
|
BraintrustMiddleware,
|
|
30868
33227
|
BraintrustState,
|
|
30869
33228
|
BraintrustStream,
|
|
@@ -30874,6 +33233,7 @@ export {
|
|
|
30874
33233
|
DEFAULT_FETCH_BATCH_SIZE,
|
|
30875
33234
|
DEFAULT_MAX_REQUEST_SIZE,
|
|
30876
33235
|
Dataset2 as Dataset,
|
|
33236
|
+
DatasetPipeline,
|
|
30877
33237
|
ERR_PERMALINK,
|
|
30878
33238
|
Eval,
|
|
30879
33239
|
EvalResultWithSummary,
|
|
@@ -30990,6 +33350,8 @@ export {
|
|
|
30990
33350
|
wrapCohere,
|
|
30991
33351
|
wrapCopilotClient,
|
|
30992
33352
|
wrapCursorSDK,
|
|
33353
|
+
wrapFlueContext,
|
|
33354
|
+
wrapFlueSession,
|
|
30993
33355
|
wrapGenkit,
|
|
30994
33356
|
wrapGoogleADK,
|
|
30995
33357
|
wrapGoogleGenAI,
|