braintrust 3.6.0 → 3.7.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/dev/dist/index.js +1016 -317
- package/dev/dist/index.mjs +914 -215
- package/dist/auto-instrumentations/bundler/esbuild.cjs +34 -6
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/rollup.cjs +34 -6
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +34 -6
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +955 -0
- package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +53 -0
- package/dist/auto-instrumentations/bundler/webpack.cjs +34 -6
- package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
- package/dist/auto-instrumentations/{chunk-F7WAXFNM.mjs → chunk-AKEXR4AL.mjs} +34 -6
- package/dist/auto-instrumentations/{chunk-WOUC73KB.mjs → chunk-ZK2IYER2.mjs} +1 -1
- package/dist/auto-instrumentations/hook.mjs +65 -11
- package/dist/auto-instrumentations/index.cjs +34 -6
- package/dist/auto-instrumentations/index.mjs +1 -1
- package/dist/browser.js +926 -227
- package/dist/browser.mjs +926 -227
- package/dist/cli.js +919 -216
- package/dist/edge-light.js +955 -282
- package/dist/edge-light.mjs +955 -282
- package/dist/index.js +1184 -485
- package/dist/index.mjs +978 -279
- package/dist/instrumentation/index.js +883 -210
- package/dist/instrumentation/index.mjs +883 -210
- package/dist/workerd.js +955 -282
- package/dist/workerd.mjs +955 -282
- package/package.json +5 -1
package/dev/dist/index.mjs
CHANGED
|
@@ -24,25 +24,51 @@ function patchTracingChannel(tracingChannelFn) {
|
|
|
24
24
|
if (TracingChannel.prototype.tracePromise) {
|
|
25
25
|
TracingChannel.prototype.tracePromise = function(fn, context = {}, thisArg, ...args) {
|
|
26
26
|
const { start, end, asyncStart, asyncEnd, error } = this;
|
|
27
|
-
function
|
|
27
|
+
function publishRejected(err) {
|
|
28
28
|
context.error = err;
|
|
29
29
|
error?.publish(context);
|
|
30
30
|
asyncStart?.publish(context);
|
|
31
31
|
asyncEnd?.publish(context);
|
|
32
|
-
return Promise.reject(err);
|
|
33
32
|
}
|
|
34
|
-
function
|
|
33
|
+
function publishResolved(result) {
|
|
35
34
|
context.result = result;
|
|
36
35
|
asyncStart?.publish(context);
|
|
37
36
|
asyncEnd?.publish(context);
|
|
38
|
-
return result;
|
|
39
37
|
}
|
|
40
38
|
return start.runStores(context, () => {
|
|
41
39
|
try {
|
|
42
40
|
const result = Reflect.apply(fn, thisArg, args);
|
|
43
41
|
end?.publish(context);
|
|
44
42
|
if (result && (typeof result === "object" || typeof result === "function") && typeof result.then === "function") {
|
|
45
|
-
|
|
43
|
+
if (result.constructor === Promise) {
|
|
44
|
+
return result.then(
|
|
45
|
+
(res) => {
|
|
46
|
+
publishResolved(res);
|
|
47
|
+
return res;
|
|
48
|
+
},
|
|
49
|
+
(err) => {
|
|
50
|
+
publishRejected(err);
|
|
51
|
+
return Promise.reject(err);
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
void result.then(
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
(resolved) => {
|
|
58
|
+
try {
|
|
59
|
+
publishResolved(resolved);
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
(err) => {
|
|
65
|
+
try {
|
|
66
|
+
publishRejected(err);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
return result;
|
|
46
72
|
}
|
|
47
73
|
context.result = result;
|
|
48
74
|
asyncStart?.publish(context);
|
|
@@ -10468,7 +10494,7 @@ var AnthropicPlugin = class extends BasePlugin {
|
|
|
10468
10494
|
this.unsubscribers.push(
|
|
10469
10495
|
traceStreamingChannel(anthropicChannels.betaMessagesCreate, {
|
|
10470
10496
|
...anthropicConfig,
|
|
10471
|
-
name: "anthropic.
|
|
10497
|
+
name: "anthropic.messages.create"
|
|
10472
10498
|
})
|
|
10473
10499
|
);
|
|
10474
10500
|
}
|
|
@@ -10491,9 +10517,12 @@ function parseMetricsFromUsage2(usage) {
|
|
|
10491
10517
|
return metrics;
|
|
10492
10518
|
}
|
|
10493
10519
|
function aggregateAnthropicStreamChunks(chunks) {
|
|
10494
|
-
const
|
|
10520
|
+
const fallbackTextDeltas = [];
|
|
10521
|
+
const contentBlocks = {};
|
|
10522
|
+
const contentBlockDeltas = {};
|
|
10495
10523
|
let metrics = {};
|
|
10496
10524
|
let metadata = {};
|
|
10525
|
+
let role;
|
|
10497
10526
|
for (const event of chunks) {
|
|
10498
10527
|
switch (event?.type) {
|
|
10499
10528
|
case "message_start":
|
|
@@ -10501,15 +10530,43 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10501
10530
|
const initialMetrics = parseMetricsFromUsage2(event.message.usage);
|
|
10502
10531
|
metrics = { ...metrics, ...initialMetrics };
|
|
10503
10532
|
}
|
|
10533
|
+
if (typeof event.message?.role === "string") {
|
|
10534
|
+
role = event.message.role;
|
|
10535
|
+
}
|
|
10536
|
+
break;
|
|
10537
|
+
case "content_block_start":
|
|
10538
|
+
if (event.content_block) {
|
|
10539
|
+
contentBlocks[event.index] = event.content_block;
|
|
10540
|
+
contentBlockDeltas[event.index] = [];
|
|
10541
|
+
}
|
|
10504
10542
|
break;
|
|
10505
10543
|
case "content_block_delta":
|
|
10506
10544
|
if (event.delta?.type === "text_delta") {
|
|
10507
10545
|
const text = event.delta.text;
|
|
10508
10546
|
if (text) {
|
|
10509
|
-
|
|
10547
|
+
if (contentBlocks[event.index] !== void 0 || contentBlockDeltas[event.index] !== void 0) {
|
|
10548
|
+
contentBlockDeltas[event.index] ??= [];
|
|
10549
|
+
contentBlockDeltas[event.index].push(text);
|
|
10550
|
+
} else {
|
|
10551
|
+
fallbackTextDeltas.push(text);
|
|
10552
|
+
}
|
|
10553
|
+
}
|
|
10554
|
+
} else if (event.delta?.type === "input_json_delta") {
|
|
10555
|
+
const partialJson = event.delta.partial_json;
|
|
10556
|
+
if (partialJson) {
|
|
10557
|
+
contentBlockDeltas[event.index] ??= [];
|
|
10558
|
+
contentBlockDeltas[event.index].push(partialJson);
|
|
10510
10559
|
}
|
|
10511
10560
|
}
|
|
10512
10561
|
break;
|
|
10562
|
+
case "content_block_stop":
|
|
10563
|
+
finalizeContentBlock(
|
|
10564
|
+
event.index,
|
|
10565
|
+
contentBlocks,
|
|
10566
|
+
contentBlockDeltas,
|
|
10567
|
+
fallbackTextDeltas
|
|
10568
|
+
);
|
|
10569
|
+
break;
|
|
10513
10570
|
case "message_delta":
|
|
10514
10571
|
if (event.usage) {
|
|
10515
10572
|
const finalMetrics = parseMetricsFromUsage2(event.usage);
|
|
@@ -10521,7 +10578,21 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10521
10578
|
break;
|
|
10522
10579
|
}
|
|
10523
10580
|
}
|
|
10524
|
-
const
|
|
10581
|
+
const orderedContent = Object.entries(contentBlocks).map(([index, block]) => ({
|
|
10582
|
+
block,
|
|
10583
|
+
index: Number(index)
|
|
10584
|
+
})).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
|
|
10585
|
+
let output = fallbackTextDeltas.join("");
|
|
10586
|
+
if (orderedContent.length > 0) {
|
|
10587
|
+
if (orderedContent.every(isTextContentBlock)) {
|
|
10588
|
+
output = orderedContent.map((block) => block.text).join("");
|
|
10589
|
+
} else {
|
|
10590
|
+
output = {
|
|
10591
|
+
...role ? { role } : {},
|
|
10592
|
+
content: orderedContent
|
|
10593
|
+
};
|
|
10594
|
+
}
|
|
10595
|
+
}
|
|
10525
10596
|
const finalized = finalizeAnthropicTokens(metrics);
|
|
10526
10597
|
const filteredMetrics = Object.fromEntries(
|
|
10527
10598
|
Object.entries(finalized).filter(
|
|
@@ -10534,6 +10605,49 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10534
10605
|
metadata
|
|
10535
10606
|
};
|
|
10536
10607
|
}
|
|
10608
|
+
function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallbackTextDeltas) {
|
|
10609
|
+
const contentBlock = contentBlocks[index];
|
|
10610
|
+
if (!contentBlock) {
|
|
10611
|
+
return;
|
|
10612
|
+
}
|
|
10613
|
+
const text = contentBlockDeltas[index]?.join("") ?? "";
|
|
10614
|
+
if (isToolUseContentBlock(contentBlock)) {
|
|
10615
|
+
if (!text) {
|
|
10616
|
+
return;
|
|
10617
|
+
}
|
|
10618
|
+
try {
|
|
10619
|
+
contentBlocks[index] = {
|
|
10620
|
+
...contentBlock,
|
|
10621
|
+
input: JSON.parse(text)
|
|
10622
|
+
};
|
|
10623
|
+
} catch {
|
|
10624
|
+
fallbackTextDeltas.push(text);
|
|
10625
|
+
delete contentBlocks[index];
|
|
10626
|
+
}
|
|
10627
|
+
return;
|
|
10628
|
+
}
|
|
10629
|
+
if (isTextContentBlock(contentBlock)) {
|
|
10630
|
+
if (!text) {
|
|
10631
|
+
delete contentBlocks[index];
|
|
10632
|
+
return;
|
|
10633
|
+
}
|
|
10634
|
+
contentBlocks[index] = {
|
|
10635
|
+
...contentBlock,
|
|
10636
|
+
text
|
|
10637
|
+
};
|
|
10638
|
+
return;
|
|
10639
|
+
}
|
|
10640
|
+
if (text) {
|
|
10641
|
+
fallbackTextDeltas.push(text);
|
|
10642
|
+
}
|
|
10643
|
+
delete contentBlocks[index];
|
|
10644
|
+
}
|
|
10645
|
+
function isTextContentBlock(contentBlock) {
|
|
10646
|
+
return contentBlock.type === "text";
|
|
10647
|
+
}
|
|
10648
|
+
function isToolUseContentBlock(contentBlock) {
|
|
10649
|
+
return contentBlock.type === "tool_use";
|
|
10650
|
+
}
|
|
10537
10651
|
function isAnthropicBase64ContentBlock(input) {
|
|
10538
10652
|
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
10539
10653
|
}
|
|
@@ -11656,12 +11770,15 @@ var claudeAgentSDKChannels = defineChannels(
|
|
|
11656
11770
|
{
|
|
11657
11771
|
query: channel({
|
|
11658
11772
|
channelName: "query",
|
|
11659
|
-
kind: "
|
|
11773
|
+
kind: "sync-stream"
|
|
11660
11774
|
})
|
|
11661
11775
|
}
|
|
11662
11776
|
);
|
|
11663
11777
|
|
|
11664
11778
|
// src/instrumentation/plugins/claude-agent-sdk-plugin.ts
|
|
11779
|
+
function isSubAgentToolName(toolName) {
|
|
11780
|
+
return toolName === "Agent" || toolName === "Task";
|
|
11781
|
+
}
|
|
11665
11782
|
function filterSerializableOptions(options) {
|
|
11666
11783
|
const allowedKeys = [
|
|
11667
11784
|
"model",
|
|
@@ -11715,34 +11832,50 @@ function extractUsageFromMessage(message) {
|
|
|
11715
11832
|
const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
|
|
11716
11833
|
const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
|
|
11717
11834
|
if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
cacheCreationTokens
|
|
11835
|
+
Object.assign(
|
|
11836
|
+
metrics,
|
|
11837
|
+
extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
|
|
11721
11838
|
);
|
|
11722
|
-
Object.assign(metrics, cacheTokens);
|
|
11723
11839
|
}
|
|
11724
11840
|
if (Object.keys(metrics).length > 0) {
|
|
11725
11841
|
Object.assign(metrics, finalizeAnthropicTokens(metrics));
|
|
11726
11842
|
}
|
|
11727
11843
|
return metrics;
|
|
11728
11844
|
}
|
|
11729
|
-
function buildLLMInput(prompt, conversationHistory) {
|
|
11730
|
-
const
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11845
|
+
function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
|
|
11846
|
+
const promptMessages = [];
|
|
11847
|
+
if (typeof prompt === "string") {
|
|
11848
|
+
promptMessages.push({ content: prompt, role: "user" });
|
|
11849
|
+
} else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
|
|
11850
|
+
for (const msg of capturedPromptMessages) {
|
|
11851
|
+
const role = msg.message?.role;
|
|
11852
|
+
const content = msg.message?.content;
|
|
11853
|
+
if (role && content !== void 0) {
|
|
11854
|
+
promptMessages.push({ content, role });
|
|
11855
|
+
}
|
|
11856
|
+
}
|
|
11857
|
+
}
|
|
11858
|
+
const inputParts = [...promptMessages, ...conversationHistory];
|
|
11735
11859
|
return inputParts.length > 0 ? inputParts : void 0;
|
|
11736
11860
|
}
|
|
11737
|
-
|
|
11738
|
-
|
|
11861
|
+
function formatCapturedMessages(messages) {
|
|
11862
|
+
return messages.length > 0 ? messages : [];
|
|
11863
|
+
}
|
|
11864
|
+
async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan) {
|
|
11865
|
+
if (messages.length === 0) {
|
|
11866
|
+
return void 0;
|
|
11867
|
+
}
|
|
11739
11868
|
const lastMessage = messages[messages.length - 1];
|
|
11740
11869
|
if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
|
|
11741
11870
|
return void 0;
|
|
11742
11871
|
}
|
|
11743
11872
|
const model = lastMessage.message.model || options.model;
|
|
11744
11873
|
const usage = extractUsageFromMessage(lastMessage);
|
|
11745
|
-
const input = buildLLMInput(
|
|
11874
|
+
const input = buildLLMInput(
|
|
11875
|
+
prompt,
|
|
11876
|
+
conversationHistory,
|
|
11877
|
+
capturedPromptMessages
|
|
11878
|
+
);
|
|
11746
11879
|
const outputs = messages.map(
|
|
11747
11880
|
(m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
|
|
11748
11881
|
).filter(
|
|
@@ -11750,21 +11883,359 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
|
|
|
11750
11883
|
);
|
|
11751
11884
|
const span = startSpan({
|
|
11752
11885
|
name: "anthropic.messages.create",
|
|
11886
|
+
parent: parentSpan,
|
|
11753
11887
|
spanAttributes: {
|
|
11754
11888
|
type: "llm" /* LLM */
|
|
11755
11889
|
},
|
|
11756
|
-
startTime
|
|
11757
|
-
parent: parentSpan
|
|
11890
|
+
startTime
|
|
11758
11891
|
});
|
|
11759
11892
|
span.log({
|
|
11760
11893
|
input,
|
|
11761
|
-
output: outputs,
|
|
11762
11894
|
metadata: model ? { model } : void 0,
|
|
11763
|
-
metrics: usage
|
|
11895
|
+
metrics: usage,
|
|
11896
|
+
output: outputs
|
|
11764
11897
|
});
|
|
11765
11898
|
await span.end();
|
|
11766
11899
|
return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
|
|
11767
11900
|
}
|
|
11901
|
+
function getMcpServerMetadata(serverName, mcpServers) {
|
|
11902
|
+
if (!serverName || !mcpServers) {
|
|
11903
|
+
return {};
|
|
11904
|
+
}
|
|
11905
|
+
const serverConfig = mcpServers[serverName];
|
|
11906
|
+
if (!serverConfig) {
|
|
11907
|
+
return {};
|
|
11908
|
+
}
|
|
11909
|
+
const metadata = {};
|
|
11910
|
+
if (serverConfig.type) {
|
|
11911
|
+
metadata["mcp.type"] = serverConfig.type;
|
|
11912
|
+
} else if (typeof serverConfig === "object" && "transport" in serverConfig) {
|
|
11913
|
+
metadata["mcp.type"] = "sdk";
|
|
11914
|
+
}
|
|
11915
|
+
if (serverConfig.url) {
|
|
11916
|
+
metadata["mcp.url"] = serverConfig.url;
|
|
11917
|
+
}
|
|
11918
|
+
if (serverConfig.command) {
|
|
11919
|
+
metadata["mcp.command"] = serverConfig.command;
|
|
11920
|
+
if (serverConfig.args) {
|
|
11921
|
+
metadata["mcp.args"] = serverConfig.args.join(" ");
|
|
11922
|
+
}
|
|
11923
|
+
}
|
|
11924
|
+
return metadata;
|
|
11925
|
+
}
|
|
11926
|
+
function parseToolName(rawToolName) {
|
|
11927
|
+
const mcpMatch = rawToolName.match(/^mcp__([^_]+)__(.+)$/);
|
|
11928
|
+
if (mcpMatch) {
|
|
11929
|
+
const [, mcpServer, toolName] = mcpMatch;
|
|
11930
|
+
return {
|
|
11931
|
+
displayName: `tool: ${mcpServer}/${toolName}`,
|
|
11932
|
+
mcpServer,
|
|
11933
|
+
rawToolName,
|
|
11934
|
+
toolName
|
|
11935
|
+
};
|
|
11936
|
+
}
|
|
11937
|
+
return {
|
|
11938
|
+
displayName: `tool: ${rawToolName}`,
|
|
11939
|
+
rawToolName,
|
|
11940
|
+
toolName: rawToolName
|
|
11941
|
+
};
|
|
11942
|
+
}
|
|
11943
|
+
function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, subAgentSpans, endedSubAgentSpans) {
|
|
11944
|
+
const preToolUse = async (input, toolUseID) => {
|
|
11945
|
+
if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
|
|
11946
|
+
return {};
|
|
11947
|
+
}
|
|
11948
|
+
if (isSubAgentToolName(input.tool_name)) {
|
|
11949
|
+
return {};
|
|
11950
|
+
}
|
|
11951
|
+
const parsed = parseToolName(input.tool_name);
|
|
11952
|
+
const toolSpan = startSpan({
|
|
11953
|
+
event: {
|
|
11954
|
+
input: input.tool_input,
|
|
11955
|
+
metadata: {
|
|
11956
|
+
"claude_agent_sdk.cwd": input.cwd,
|
|
11957
|
+
"claude_agent_sdk.raw_tool_name": parsed.rawToolName,
|
|
11958
|
+
"claude_agent_sdk.session_id": input.session_id,
|
|
11959
|
+
"gen_ai.tool.call.id": toolUseID,
|
|
11960
|
+
"gen_ai.tool.name": parsed.toolName,
|
|
11961
|
+
...parsed.mcpServer && { "mcp.server": parsed.mcpServer },
|
|
11962
|
+
...getMcpServerMetadata(parsed.mcpServer, mcpServers)
|
|
11963
|
+
}
|
|
11964
|
+
},
|
|
11965
|
+
name: parsed.displayName,
|
|
11966
|
+
parent: await resolveParentSpan(toolUseID),
|
|
11967
|
+
spanAttributes: { type: "tool" /* TOOL */ }
|
|
11968
|
+
});
|
|
11969
|
+
activeToolSpans.set(toolUseID, toolSpan);
|
|
11970
|
+
return {};
|
|
11971
|
+
};
|
|
11972
|
+
const postToolUse = async (input, toolUseID) => {
|
|
11973
|
+
if (input.hook_event_name !== "PostToolUse" || !toolUseID) {
|
|
11974
|
+
return {};
|
|
11975
|
+
}
|
|
11976
|
+
const subAgentSpan = subAgentSpans.get(toolUseID);
|
|
11977
|
+
if (subAgentSpan) {
|
|
11978
|
+
try {
|
|
11979
|
+
const response = input.tool_response;
|
|
11980
|
+
const metadata = {};
|
|
11981
|
+
if (response?.status) {
|
|
11982
|
+
metadata["claude_agent_sdk.status"] = response.status;
|
|
11983
|
+
}
|
|
11984
|
+
if (response?.totalDurationMs) {
|
|
11985
|
+
metadata["claude_agent_sdk.duration_ms"] = response.totalDurationMs;
|
|
11986
|
+
}
|
|
11987
|
+
if (response?.totalToolUseCount !== void 0) {
|
|
11988
|
+
metadata["claude_agent_sdk.tool_use_count"] = response.totalToolUseCount;
|
|
11989
|
+
}
|
|
11990
|
+
subAgentSpan.log({
|
|
11991
|
+
metadata,
|
|
11992
|
+
output: response?.content
|
|
11993
|
+
});
|
|
11994
|
+
} finally {
|
|
11995
|
+
subAgentSpan.end();
|
|
11996
|
+
endedSubAgentSpans.add(toolUseID);
|
|
11997
|
+
}
|
|
11998
|
+
return {};
|
|
11999
|
+
}
|
|
12000
|
+
const toolSpan = activeToolSpans.get(toolUseID);
|
|
12001
|
+
if (!toolSpan) {
|
|
12002
|
+
return {};
|
|
12003
|
+
}
|
|
12004
|
+
try {
|
|
12005
|
+
toolSpan.log({ output: input.tool_response });
|
|
12006
|
+
} finally {
|
|
12007
|
+
toolSpan.end();
|
|
12008
|
+
activeToolSpans.delete(toolUseID);
|
|
12009
|
+
}
|
|
12010
|
+
return {};
|
|
12011
|
+
};
|
|
12012
|
+
const postToolUseFailure = async (input, toolUseID) => {
|
|
12013
|
+
if (input.hook_event_name !== "PostToolUseFailure" || !toolUseID) {
|
|
12014
|
+
return {};
|
|
12015
|
+
}
|
|
12016
|
+
const subAgentSpan = subAgentSpans.get(toolUseID);
|
|
12017
|
+
if (subAgentSpan) {
|
|
12018
|
+
try {
|
|
12019
|
+
subAgentSpan.log({ error: input.error });
|
|
12020
|
+
} finally {
|
|
12021
|
+
subAgentSpan.end();
|
|
12022
|
+
endedSubAgentSpans.add(toolUseID);
|
|
12023
|
+
}
|
|
12024
|
+
return {};
|
|
12025
|
+
}
|
|
12026
|
+
const toolSpan = activeToolSpans.get(toolUseID);
|
|
12027
|
+
if (!toolSpan) {
|
|
12028
|
+
return {};
|
|
12029
|
+
}
|
|
12030
|
+
const parsed = parseToolName(input.tool_name);
|
|
12031
|
+
try {
|
|
12032
|
+
toolSpan.log({
|
|
12033
|
+
error: input.error,
|
|
12034
|
+
metadata: {
|
|
12035
|
+
"claude_agent_sdk.is_interrupt": input.is_interrupt,
|
|
12036
|
+
"claude_agent_sdk.session_id": input.session_id,
|
|
12037
|
+
"gen_ai.tool.call.id": toolUseID,
|
|
12038
|
+
"gen_ai.tool.name": parsed.toolName,
|
|
12039
|
+
...parsed.mcpServer && { "mcp.server": parsed.mcpServer }
|
|
12040
|
+
}
|
|
12041
|
+
});
|
|
12042
|
+
} finally {
|
|
12043
|
+
toolSpan.end();
|
|
12044
|
+
activeToolSpans.delete(toolUseID);
|
|
12045
|
+
}
|
|
12046
|
+
return {};
|
|
12047
|
+
};
|
|
12048
|
+
return { postToolUse, postToolUseFailure, preToolUse };
|
|
12049
|
+
}
|
|
12050
|
+
function injectTracingHooks(options, resolveParentSpan, activeToolSpans, subAgentSpans, endedSubAgentSpans) {
|
|
12051
|
+
const { preToolUse, postToolUse, postToolUseFailure } = createToolTracingHooks(
|
|
12052
|
+
resolveParentSpan,
|
|
12053
|
+
activeToolSpans,
|
|
12054
|
+
options.mcpServers,
|
|
12055
|
+
subAgentSpans,
|
|
12056
|
+
endedSubAgentSpans
|
|
12057
|
+
);
|
|
12058
|
+
const existingHooks = options.hooks ?? {};
|
|
12059
|
+
return {
|
|
12060
|
+
...options,
|
|
12061
|
+
hooks: {
|
|
12062
|
+
...existingHooks,
|
|
12063
|
+
PostToolUse: [
|
|
12064
|
+
...existingHooks.PostToolUse ?? [],
|
|
12065
|
+
{ hooks: [postToolUse] }
|
|
12066
|
+
],
|
|
12067
|
+
PostToolUseFailure: [
|
|
12068
|
+
...existingHooks.PostToolUseFailure ?? [],
|
|
12069
|
+
{
|
|
12070
|
+
hooks: [postToolUseFailure]
|
|
12071
|
+
}
|
|
12072
|
+
],
|
|
12073
|
+
PreToolUse: [
|
|
12074
|
+
...existingHooks.PreToolUse ?? [],
|
|
12075
|
+
{ hooks: [preToolUse] }
|
|
12076
|
+
]
|
|
12077
|
+
}
|
|
12078
|
+
};
|
|
12079
|
+
}
|
|
12080
|
+
async function finalizeCurrentMessageGroup(state) {
|
|
12081
|
+
if (state.currentMessages.length === 0) {
|
|
12082
|
+
return;
|
|
12083
|
+
}
|
|
12084
|
+
const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
|
|
12085
|
+
let parentSpan = await state.span.export();
|
|
12086
|
+
if (parentToolUseId) {
|
|
12087
|
+
const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
|
|
12088
|
+
if (subAgentSpan) {
|
|
12089
|
+
parentSpan = await subAgentSpan.export();
|
|
12090
|
+
}
|
|
12091
|
+
}
|
|
12092
|
+
const finalMessage = await createLLMSpanForMessages(
|
|
12093
|
+
state.currentMessages,
|
|
12094
|
+
state.originalPrompt,
|
|
12095
|
+
state.finalResults,
|
|
12096
|
+
state.options,
|
|
12097
|
+
state.currentMessageStartTime,
|
|
12098
|
+
state.capturedPromptMessages,
|
|
12099
|
+
parentSpan
|
|
12100
|
+
);
|
|
12101
|
+
if (finalMessage) {
|
|
12102
|
+
state.finalResults.push(finalMessage);
|
|
12103
|
+
}
|
|
12104
|
+
const lastMessage = state.currentMessages[state.currentMessages.length - 1];
|
|
12105
|
+
if (lastMessage?.message?.usage) {
|
|
12106
|
+
state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
|
|
12107
|
+
}
|
|
12108
|
+
state.currentMessages.length = 0;
|
|
12109
|
+
}
|
|
12110
|
+
function maybeTrackToolUseContext(state, message) {
|
|
12111
|
+
if (message.type !== "assistant" || !Array.isArray(message.message?.content)) {
|
|
12112
|
+
return;
|
|
12113
|
+
}
|
|
12114
|
+
const parentToolUseId = message.parent_tool_use_id ?? null;
|
|
12115
|
+
for (const block of message.message.content) {
|
|
12116
|
+
if (typeof block !== "object" || block === null || !("type" in block) || block.type !== "tool_use" || !("id" in block) || typeof block.id !== "string") {
|
|
12117
|
+
continue;
|
|
12118
|
+
}
|
|
12119
|
+
state.toolUseToParent.set(block.id, parentToolUseId);
|
|
12120
|
+
if (block.name === "Task" && typeof block.input === "object" && block.input !== null && "subagent_type" in block.input && typeof block.input.subagent_type === "string") {
|
|
12121
|
+
state.pendingSubAgentNames.set(block.id, block.input.subagent_type);
|
|
12122
|
+
}
|
|
12123
|
+
}
|
|
12124
|
+
}
|
|
12125
|
+
async function maybeStartSubAgentSpan(state, message) {
|
|
12126
|
+
if (!("parent_tool_use_id" in message)) {
|
|
12127
|
+
return;
|
|
12128
|
+
}
|
|
12129
|
+
const parentToolUseId = message.parent_tool_use_id;
|
|
12130
|
+
if (!parentToolUseId) {
|
|
12131
|
+
return;
|
|
12132
|
+
}
|
|
12133
|
+
await ensureSubAgentSpan(
|
|
12134
|
+
state.pendingSubAgentNames,
|
|
12135
|
+
state.span,
|
|
12136
|
+
state.subAgentSpans,
|
|
12137
|
+
parentToolUseId
|
|
12138
|
+
);
|
|
12139
|
+
}
|
|
12140
|
+
async function ensureSubAgentSpan(pendingSubAgentNames, rootSpan, subAgentSpans, parentToolUseId) {
|
|
12141
|
+
const existingSpan = subAgentSpans.get(parentToolUseId);
|
|
12142
|
+
if (existingSpan) {
|
|
12143
|
+
return existingSpan;
|
|
12144
|
+
}
|
|
12145
|
+
const agentName = pendingSubAgentNames.get(parentToolUseId);
|
|
12146
|
+
const spanName = agentName ? `Agent: ${agentName}` : "Agent: sub-agent";
|
|
12147
|
+
const subAgentSpan = startSpan({
|
|
12148
|
+
event: {
|
|
12149
|
+
metadata: {
|
|
12150
|
+
...agentName && { "claude_agent_sdk.agent_type": agentName }
|
|
12151
|
+
}
|
|
12152
|
+
},
|
|
12153
|
+
name: spanName,
|
|
12154
|
+
parent: await rootSpan.export(),
|
|
12155
|
+
spanAttributes: { type: "task" /* TASK */ }
|
|
12156
|
+
});
|
|
12157
|
+
subAgentSpans.set(parentToolUseId, subAgentSpan);
|
|
12158
|
+
return subAgentSpan;
|
|
12159
|
+
}
|
|
12160
|
+
async function handleStreamMessage(state, message) {
|
|
12161
|
+
maybeTrackToolUseContext(state, message);
|
|
12162
|
+
await maybeStartSubAgentSpan(state, message);
|
|
12163
|
+
const messageId = message.message?.id;
|
|
12164
|
+
if (messageId && messageId !== state.currentMessageId) {
|
|
12165
|
+
await finalizeCurrentMessageGroup(state);
|
|
12166
|
+
state.currentMessageId = messageId;
|
|
12167
|
+
state.currentMessageStartTime = getCurrentUnixTimestamp();
|
|
12168
|
+
}
|
|
12169
|
+
if (message.type === "assistant" && message.message?.usage) {
|
|
12170
|
+
state.currentMessages.push(message);
|
|
12171
|
+
}
|
|
12172
|
+
if (message.type !== "result" || !message.usage) {
|
|
12173
|
+
return;
|
|
12174
|
+
}
|
|
12175
|
+
const finalUsageMetrics = extractUsageFromMessage(message);
|
|
12176
|
+
if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
|
|
12177
|
+
const lastMessage = state.currentMessages[state.currentMessages.length - 1];
|
|
12178
|
+
if (lastMessage?.message?.usage) {
|
|
12179
|
+
const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
|
|
12180
|
+
if (adjustedTokens >= 0) {
|
|
12181
|
+
lastMessage.message.usage.output_tokens = adjustedTokens;
|
|
12182
|
+
}
|
|
12183
|
+
const resultUsage = message.usage;
|
|
12184
|
+
if (resultUsage && typeof resultUsage === "object") {
|
|
12185
|
+
const cacheReadTokens = getNumberProperty(
|
|
12186
|
+
resultUsage,
|
|
12187
|
+
"cache_read_input_tokens"
|
|
12188
|
+
);
|
|
12189
|
+
if (cacheReadTokens !== void 0) {
|
|
12190
|
+
lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
|
|
12191
|
+
}
|
|
12192
|
+
const cacheCreationTokens = getNumberProperty(
|
|
12193
|
+
resultUsage,
|
|
12194
|
+
"cache_creation_input_tokens"
|
|
12195
|
+
);
|
|
12196
|
+
if (cacheCreationTokens !== void 0) {
|
|
12197
|
+
lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
|
|
12198
|
+
}
|
|
12199
|
+
}
|
|
12200
|
+
}
|
|
12201
|
+
}
|
|
12202
|
+
const metadata = {};
|
|
12203
|
+
if (message.num_turns !== void 0) {
|
|
12204
|
+
metadata.num_turns = message.num_turns;
|
|
12205
|
+
}
|
|
12206
|
+
if (message.session_id !== void 0) {
|
|
12207
|
+
metadata.session_id = message.session_id;
|
|
12208
|
+
}
|
|
12209
|
+
if (Object.keys(metadata).length > 0) {
|
|
12210
|
+
state.span.log({ metadata });
|
|
12211
|
+
}
|
|
12212
|
+
}
|
|
12213
|
+
async function finalizeQuerySpan(state) {
|
|
12214
|
+
try {
|
|
12215
|
+
await finalizeCurrentMessageGroup(state);
|
|
12216
|
+
state.span.log({
|
|
12217
|
+
output: state.finalResults.length > 0 ? state.finalResults[state.finalResults.length - 1] : void 0
|
|
12218
|
+
});
|
|
12219
|
+
if (state.capturedPromptMessages) {
|
|
12220
|
+
if (state.promptStarted()) {
|
|
12221
|
+
await state.promptDone;
|
|
12222
|
+
}
|
|
12223
|
+
if (state.capturedPromptMessages.length > 0) {
|
|
12224
|
+
state.span.log({
|
|
12225
|
+
input: formatCapturedMessages(state.capturedPromptMessages)
|
|
12226
|
+
});
|
|
12227
|
+
}
|
|
12228
|
+
}
|
|
12229
|
+
} finally {
|
|
12230
|
+
for (const [id, subAgentSpan] of state.subAgentSpans) {
|
|
12231
|
+
if (!state.endedSubAgentSpans.has(id)) {
|
|
12232
|
+
subAgentSpan.end();
|
|
12233
|
+
}
|
|
12234
|
+
}
|
|
12235
|
+
state.subAgentSpans.clear();
|
|
12236
|
+
state.span.end();
|
|
12237
|
+
}
|
|
12238
|
+
}
|
|
11768
12239
|
var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
11769
12240
|
onEnable() {
|
|
11770
12241
|
this.subscribeToQuery();
|
|
@@ -11775,19 +12246,36 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
11775
12246
|
}
|
|
11776
12247
|
this.unsubscribers = [];
|
|
11777
12248
|
}
|
|
11778
|
-
/**
|
|
11779
|
-
* Subscribe to the query channel for agent interactions.
|
|
11780
|
-
* Handles streaming responses and traces both the top-level agent task
|
|
11781
|
-
* and individual LLM calls.
|
|
11782
|
-
*/
|
|
11783
12249
|
subscribeToQuery() {
|
|
11784
12250
|
const channel2 = claudeAgentSDKChannels.query.tracingChannel();
|
|
11785
12251
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
11786
12252
|
const handlers = {
|
|
11787
12253
|
start: (event) => {
|
|
11788
|
-
const params = event.arguments[0];
|
|
11789
|
-
const
|
|
11790
|
-
const options = params
|
|
12254
|
+
const params = event.arguments[0] ?? {};
|
|
12255
|
+
const originalPrompt = params.prompt;
|
|
12256
|
+
const options = params.options ?? {};
|
|
12257
|
+
const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
|
|
12258
|
+
let promptStarted = false;
|
|
12259
|
+
let capturedPromptMessages;
|
|
12260
|
+
let resolvePromptDone;
|
|
12261
|
+
const promptDone = new Promise((resolve) => {
|
|
12262
|
+
resolvePromptDone = resolve;
|
|
12263
|
+
});
|
|
12264
|
+
if (promptIsAsyncIterable) {
|
|
12265
|
+
capturedPromptMessages = [];
|
|
12266
|
+
const promptStream = originalPrompt;
|
|
12267
|
+
params.prompt = (async function* () {
|
|
12268
|
+
promptStarted = true;
|
|
12269
|
+
try {
|
|
12270
|
+
for await (const message of promptStream) {
|
|
12271
|
+
capturedPromptMessages.push(message);
|
|
12272
|
+
yield message;
|
|
12273
|
+
}
|
|
12274
|
+
} finally {
|
|
12275
|
+
resolvePromptDone?.();
|
|
12276
|
+
}
|
|
12277
|
+
})();
|
|
12278
|
+
}
|
|
11791
12279
|
const span = startSpan({
|
|
11792
12280
|
name: "Claude Agent",
|
|
11793
12281
|
spanAttributes: {
|
|
@@ -11797,163 +12285,115 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
11797
12285
|
const startTime = getCurrentUnixTimestamp();
|
|
11798
12286
|
try {
|
|
11799
12287
|
span.log({
|
|
11800
|
-
input: typeof
|
|
11801
|
-
type: "streaming",
|
|
11802
|
-
description: "AsyncIterable<ClaudeAgentSDKMessage>"
|
|
11803
|
-
},
|
|
12288
|
+
input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
|
|
11804
12289
|
metadata: filterSerializableOptions(options)
|
|
11805
12290
|
});
|
|
11806
12291
|
} catch (error) {
|
|
11807
12292
|
console.error("Error extracting input for Claude Agent SDK:", error);
|
|
11808
12293
|
}
|
|
12294
|
+
const activeToolSpans = /* @__PURE__ */ new Map();
|
|
12295
|
+
const subAgentSpans = /* @__PURE__ */ new Map();
|
|
12296
|
+
const endedSubAgentSpans = /* @__PURE__ */ new Set();
|
|
12297
|
+
const toolUseToParent = /* @__PURE__ */ new Map();
|
|
12298
|
+
const pendingSubAgentNames = /* @__PURE__ */ new Map();
|
|
12299
|
+
const optionsWithHooks = injectTracingHooks(
|
|
12300
|
+
options,
|
|
12301
|
+
async (toolUseID) => {
|
|
12302
|
+
const parentToolUseId = toolUseToParent.get(toolUseID);
|
|
12303
|
+
if (parentToolUseId) {
|
|
12304
|
+
const subAgentSpan = await ensureSubAgentSpan(
|
|
12305
|
+
pendingSubAgentNames,
|
|
12306
|
+
span,
|
|
12307
|
+
subAgentSpans,
|
|
12308
|
+
parentToolUseId
|
|
12309
|
+
);
|
|
12310
|
+
return subAgentSpan.export();
|
|
12311
|
+
}
|
|
12312
|
+
return span.export();
|
|
12313
|
+
},
|
|
12314
|
+
activeToolSpans,
|
|
12315
|
+
subAgentSpans,
|
|
12316
|
+
endedSubAgentSpans
|
|
12317
|
+
);
|
|
12318
|
+
params.options = optionsWithHooks;
|
|
12319
|
+
event.arguments[0] = params;
|
|
11809
12320
|
spans.set(event, {
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
currentMessages: [],
|
|
12321
|
+
accumulatedOutputTokens: 0,
|
|
12322
|
+
activeToolSpans,
|
|
12323
|
+
capturedPromptMessages,
|
|
11814
12324
|
currentMessageId: void 0,
|
|
11815
12325
|
currentMessageStartTime: startTime,
|
|
11816
|
-
|
|
12326
|
+
currentMessages: [],
|
|
12327
|
+
endedSubAgentSpans,
|
|
12328
|
+
finalResults: [],
|
|
12329
|
+
options: optionsWithHooks,
|
|
12330
|
+
originalPrompt,
|
|
12331
|
+
pendingSubAgentNames,
|
|
12332
|
+
processing: Promise.resolve(),
|
|
12333
|
+
promptDone,
|
|
12334
|
+
promptStarted: () => promptStarted,
|
|
12335
|
+
span,
|
|
12336
|
+
subAgentSpans,
|
|
12337
|
+
toolUseToParent
|
|
11817
12338
|
});
|
|
11818
12339
|
},
|
|
11819
|
-
|
|
11820
|
-
const
|
|
11821
|
-
if (!
|
|
12340
|
+
end: (event) => {
|
|
12341
|
+
const state = spans.get(event);
|
|
12342
|
+
if (!state) {
|
|
11822
12343
|
return;
|
|
11823
12344
|
}
|
|
11824
12345
|
const eventResult = event.result;
|
|
11825
12346
|
if (eventResult === void 0) {
|
|
11826
|
-
|
|
12347
|
+
state.span.end();
|
|
11827
12348
|
spans.delete(event);
|
|
11828
12349
|
return;
|
|
11829
12350
|
}
|
|
11830
12351
|
if (isAsyncIterable(eventResult)) {
|
|
11831
12352
|
patchStreamIfNeeded(eventResult, {
|
|
11832
|
-
onChunk:
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
const prompt = params?.prompt;
|
|
11836
|
-
const options = params?.options ?? {};
|
|
11837
|
-
const messageId = message.message?.id;
|
|
11838
|
-
if (messageId && messageId !== spanData.currentMessageId) {
|
|
11839
|
-
if (spanData.currentMessages.length > 0) {
|
|
11840
|
-
const finalMessage = await createLLMSpanForMessages(
|
|
11841
|
-
spanData.currentMessages,
|
|
11842
|
-
prompt,
|
|
11843
|
-
spanData.conversationHistory,
|
|
11844
|
-
options,
|
|
11845
|
-
spanData.currentMessageStartTime,
|
|
11846
|
-
await spanData.span.export()
|
|
11847
|
-
);
|
|
11848
|
-
if (finalMessage) {
|
|
11849
|
-
spanData.conversationHistory.push(finalMessage);
|
|
11850
|
-
}
|
|
11851
|
-
const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
|
|
11852
|
-
if (lastMessage?.message?.usage) {
|
|
11853
|
-
const outputTokens = getNumberProperty(
|
|
11854
|
-
lastMessage.message.usage,
|
|
11855
|
-
"output_tokens"
|
|
11856
|
-
) || 0;
|
|
11857
|
-
spanData.accumulatedOutputTokens += outputTokens;
|
|
11858
|
-
}
|
|
11859
|
-
spanData.currentMessages = [];
|
|
11860
|
-
}
|
|
11861
|
-
spanData.currentMessageId = messageId;
|
|
11862
|
-
spanData.currentMessageStartTime = currentTime;
|
|
11863
|
-
}
|
|
11864
|
-
if (message.type === "assistant" && message.message?.usage) {
|
|
11865
|
-
spanData.currentMessages.push(message);
|
|
11866
|
-
}
|
|
11867
|
-
if (message.type === "result" && message.usage) {
|
|
11868
|
-
const finalUsageMetrics = extractUsageFromMessage(message);
|
|
11869
|
-
if (spanData.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
|
|
11870
|
-
const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
|
|
11871
|
-
if (lastMessage?.message?.usage) {
|
|
11872
|
-
const adjustedTokens = finalUsageMetrics.completion_tokens - spanData.accumulatedOutputTokens;
|
|
11873
|
-
if (adjustedTokens >= 0) {
|
|
11874
|
-
lastMessage.message.usage.output_tokens = adjustedTokens;
|
|
11875
|
-
}
|
|
11876
|
-
}
|
|
11877
|
-
}
|
|
11878
|
-
const result_metadata = {};
|
|
11879
|
-
if (message.num_turns !== void 0) {
|
|
11880
|
-
result_metadata.num_turns = message.num_turns;
|
|
11881
|
-
}
|
|
11882
|
-
if (message.session_id !== void 0) {
|
|
11883
|
-
result_metadata.session_id = message.session_id;
|
|
11884
|
-
}
|
|
11885
|
-
if (Object.keys(result_metadata).length > 0) {
|
|
11886
|
-
spanData.span.log({
|
|
11887
|
-
metadata: result_metadata
|
|
11888
|
-
});
|
|
11889
|
-
}
|
|
11890
|
-
}
|
|
11891
|
-
},
|
|
11892
|
-
onComplete: async () => {
|
|
11893
|
-
try {
|
|
11894
|
-
const params = event.arguments[0];
|
|
11895
|
-
const prompt = params?.prompt;
|
|
11896
|
-
const options = params?.options ?? {};
|
|
11897
|
-
if (spanData.currentMessages.length > 0) {
|
|
11898
|
-
const finalMessage = await createLLMSpanForMessages(
|
|
11899
|
-
spanData.currentMessages,
|
|
11900
|
-
prompt,
|
|
11901
|
-
spanData.conversationHistory,
|
|
11902
|
-
options,
|
|
11903
|
-
spanData.currentMessageStartTime,
|
|
11904
|
-
await spanData.span.export()
|
|
11905
|
-
);
|
|
11906
|
-
if (finalMessage) {
|
|
11907
|
-
spanData.conversationHistory.push(finalMessage);
|
|
11908
|
-
}
|
|
11909
|
-
}
|
|
11910
|
-
spanData.span.log({
|
|
11911
|
-
output: spanData.conversationHistory.length > 0 ? spanData.conversationHistory[spanData.conversationHistory.length - 1] : void 0
|
|
11912
|
-
});
|
|
11913
|
-
} catch (error) {
|
|
12353
|
+
onChunk: (message) => {
|
|
12354
|
+
maybeTrackToolUseContext(state, message);
|
|
12355
|
+
state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
|
|
11914
12356
|
console.error(
|
|
11915
|
-
"Error
|
|
12357
|
+
"Error processing Claude Agent SDK stream chunk:",
|
|
11916
12358
|
error
|
|
11917
12359
|
);
|
|
11918
|
-
}
|
|
11919
|
-
|
|
12360
|
+
});
|
|
12361
|
+
},
|
|
12362
|
+
onComplete: () => {
|
|
12363
|
+
void state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11920
12364
|
spans.delete(event);
|
|
11921
|
-
}
|
|
12365
|
+
});
|
|
11922
12366
|
},
|
|
11923
12367
|
onError: (error) => {
|
|
11924
|
-
|
|
11925
|
-
|
|
12368
|
+
void state.processing.then(() => {
|
|
12369
|
+
state.span.log({
|
|
12370
|
+
error: error.message
|
|
12371
|
+
});
|
|
12372
|
+
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
12373
|
+
spans.delete(event);
|
|
11926
12374
|
});
|
|
11927
|
-
spanData.span.end();
|
|
11928
|
-
spans.delete(event);
|
|
11929
12375
|
}
|
|
11930
12376
|
});
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
);
|
|
11941
|
-
} finally {
|
|
11942
|
-
spanData.span.end();
|
|
11943
|
-
spans.delete(event);
|
|
11944
|
-
}
|
|
12377
|
+
return;
|
|
12378
|
+
}
|
|
12379
|
+
try {
|
|
12380
|
+
state.span.log({ output: eventResult });
|
|
12381
|
+
} catch (error) {
|
|
12382
|
+
console.error("Error extracting output for Claude Agent SDK:", error);
|
|
12383
|
+
} finally {
|
|
12384
|
+
state.span.end();
|
|
12385
|
+
spans.delete(event);
|
|
11945
12386
|
}
|
|
11946
12387
|
},
|
|
11947
12388
|
error: (event) => {
|
|
11948
|
-
const
|
|
11949
|
-
if (!
|
|
12389
|
+
const state = spans.get(event);
|
|
12390
|
+
if (!state || !event.error) {
|
|
11950
12391
|
return;
|
|
11951
12392
|
}
|
|
11952
|
-
|
|
11953
|
-
span.log({
|
|
12393
|
+
state.span.log({
|
|
11954
12394
|
error: event.error.message
|
|
11955
12395
|
});
|
|
11956
|
-
span.end();
|
|
12396
|
+
state.span.end();
|
|
11957
12397
|
spans.delete(event);
|
|
11958
12398
|
}
|
|
11959
12399
|
};
|
|
@@ -11977,6 +12417,18 @@ var googleGenAIChannels = defineChannels("@google/genai", {
|
|
|
11977
12417
|
});
|
|
11978
12418
|
|
|
11979
12419
|
// src/instrumentation/plugins/google-genai-plugin.ts
|
|
12420
|
+
var GOOGLE_GENAI_INTERNAL_CONTEXT = {
|
|
12421
|
+
caller_filename: "<node-internal>",
|
|
12422
|
+
caller_functionname: "<node-internal>",
|
|
12423
|
+
caller_lineno: 0
|
|
12424
|
+
};
|
|
12425
|
+
function createWrapperParityEvent(args) {
|
|
12426
|
+
return {
|
|
12427
|
+
context: GOOGLE_GENAI_INTERNAL_CONTEXT,
|
|
12428
|
+
input: args.input,
|
|
12429
|
+
metadata: args.metadata
|
|
12430
|
+
};
|
|
12431
|
+
}
|
|
11980
12432
|
var GoogleGenAIPlugin = class extends BasePlugin {
|
|
11981
12433
|
onEnable() {
|
|
11982
12434
|
this.subscribeToGoogleGenAIChannels();
|
|
@@ -11985,51 +12437,282 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
11985
12437
|
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
11986
12438
|
}
|
|
11987
12439
|
subscribeToGoogleGenAIChannels() {
|
|
11988
|
-
this.
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
|
|
12002
|
-
|
|
12003
|
-
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
|
|
12440
|
+
this.subscribeToGenerateContentChannel();
|
|
12441
|
+
this.subscribeToGenerateContentStreamChannel();
|
|
12442
|
+
}
|
|
12443
|
+
subscribeToGenerateContentChannel() {
|
|
12444
|
+
const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
|
|
12445
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
12446
|
+
const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
|
|
12447
|
+
tracingChannel2,
|
|
12448
|
+
states,
|
|
12449
|
+
(event) => {
|
|
12450
|
+
const params = event.arguments[0];
|
|
12451
|
+
const input = serializeInput(params);
|
|
12452
|
+
const metadata = extractMetadata(params);
|
|
12453
|
+
const span = startSpan({
|
|
12454
|
+
name: "generate_content",
|
|
12455
|
+
spanAttributes: {
|
|
12456
|
+
type: "llm" /* LLM */
|
|
12457
|
+
},
|
|
12458
|
+
event: createWrapperParityEvent({ input, metadata })
|
|
12459
|
+
});
|
|
12460
|
+
return {
|
|
12461
|
+
span,
|
|
12462
|
+
startTime: getCurrentUnixTimestamp()
|
|
12463
|
+
};
|
|
12464
|
+
}
|
|
12007
12465
|
);
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
extractInput: ([params]) => {
|
|
12466
|
+
const handlers = {
|
|
12467
|
+
start: (event) => {
|
|
12468
|
+
ensureSpanState(states, event, () => {
|
|
12469
|
+
const params = event.arguments[0];
|
|
12013
12470
|
const input = serializeInput(params);
|
|
12014
12471
|
const metadata = extractMetadata(params);
|
|
12472
|
+
const span = startSpan({
|
|
12473
|
+
name: "generate_content",
|
|
12474
|
+
spanAttributes: {
|
|
12475
|
+
type: "llm" /* LLM */
|
|
12476
|
+
},
|
|
12477
|
+
event: createWrapperParityEvent({ input, metadata })
|
|
12478
|
+
});
|
|
12015
12479
|
return {
|
|
12016
|
-
|
|
12017
|
-
|
|
12480
|
+
span,
|
|
12481
|
+
startTime: getCurrentUnixTimestamp()
|
|
12018
12482
|
};
|
|
12019
|
-
}
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
return
|
|
12025
|
-
},
|
|
12026
|
-
aggregateChunks: (chunks, _result, _endEvent, startTime) => {
|
|
12027
|
-
return aggregateGenerateContentChunks(chunks, startTime);
|
|
12483
|
+
});
|
|
12484
|
+
},
|
|
12485
|
+
asyncEnd: (event) => {
|
|
12486
|
+
const spanState = states.get(event);
|
|
12487
|
+
if (!spanState) {
|
|
12488
|
+
return;
|
|
12028
12489
|
}
|
|
12029
|
-
|
|
12030
|
-
|
|
12490
|
+
try {
|
|
12491
|
+
spanState.span.log({
|
|
12492
|
+
metrics: cleanMetrics(
|
|
12493
|
+
extractGenerateContentMetrics(
|
|
12494
|
+
event.result,
|
|
12495
|
+
spanState.startTime
|
|
12496
|
+
)
|
|
12497
|
+
),
|
|
12498
|
+
output: event.result
|
|
12499
|
+
});
|
|
12500
|
+
} finally {
|
|
12501
|
+
spanState.span.end();
|
|
12502
|
+
states.delete(event);
|
|
12503
|
+
}
|
|
12504
|
+
},
|
|
12505
|
+
error: (event) => {
|
|
12506
|
+
logErrorAndEndSpan(states, event);
|
|
12507
|
+
}
|
|
12508
|
+
};
|
|
12509
|
+
tracingChannel2.subscribe(handlers);
|
|
12510
|
+
this.unsubscribers.push(() => {
|
|
12511
|
+
unbindCurrentSpanStore?.();
|
|
12512
|
+
tracingChannel2.unsubscribe(handlers);
|
|
12513
|
+
});
|
|
12514
|
+
}
|
|
12515
|
+
subscribeToGenerateContentStreamChannel() {
|
|
12516
|
+
const tracingChannel2 = googleGenAIChannels.generateContentStream.tracingChannel();
|
|
12517
|
+
const handlers = {
|
|
12518
|
+
start: (event) => {
|
|
12519
|
+
const streamEvent = event;
|
|
12520
|
+
const params = event.arguments[0];
|
|
12521
|
+
streamEvent.googleGenAIInput = serializeInput(params);
|
|
12522
|
+
streamEvent.googleGenAIMetadata = extractMetadata(params);
|
|
12523
|
+
},
|
|
12524
|
+
asyncEnd: (event) => {
|
|
12525
|
+
const streamEvent = event;
|
|
12526
|
+
patchGoogleGenAIStreamingResult({
|
|
12527
|
+
input: streamEvent.googleGenAIInput,
|
|
12528
|
+
metadata: streamEvent.googleGenAIMetadata,
|
|
12529
|
+
result: streamEvent.result
|
|
12530
|
+
});
|
|
12531
|
+
},
|
|
12532
|
+
error: () => {
|
|
12533
|
+
}
|
|
12534
|
+
};
|
|
12535
|
+
tracingChannel2.subscribe(handlers);
|
|
12536
|
+
this.unsubscribers.push(() => {
|
|
12537
|
+
tracingChannel2.unsubscribe(handlers);
|
|
12538
|
+
});
|
|
12031
12539
|
}
|
|
12032
12540
|
};
|
|
12541
|
+
function ensureSpanState(states, event, create) {
|
|
12542
|
+
const existing = states.get(event);
|
|
12543
|
+
if (existing) {
|
|
12544
|
+
return existing;
|
|
12545
|
+
}
|
|
12546
|
+
const created = create();
|
|
12547
|
+
states.set(event, created);
|
|
12548
|
+
return created;
|
|
12549
|
+
}
|
|
12550
|
+
function bindCurrentSpanStoreToStart2(tracingChannel2, states, create) {
|
|
12551
|
+
const state = _internalGetGlobalState();
|
|
12552
|
+
const startChannel = tracingChannel2.start;
|
|
12553
|
+
const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
|
|
12554
|
+
if (!startChannel?.bindStore || !currentSpanStore) {
|
|
12555
|
+
return void 0;
|
|
12556
|
+
}
|
|
12557
|
+
startChannel.bindStore(
|
|
12558
|
+
currentSpanStore,
|
|
12559
|
+
(event) => ensureSpanState(
|
|
12560
|
+
states,
|
|
12561
|
+
event,
|
|
12562
|
+
() => create(event)
|
|
12563
|
+
).span
|
|
12564
|
+
);
|
|
12565
|
+
return () => {
|
|
12566
|
+
startChannel.unbindStore?.(currentSpanStore);
|
|
12567
|
+
};
|
|
12568
|
+
}
|
|
12569
|
+
function logErrorAndEndSpan(states, event) {
|
|
12570
|
+
const spanState = states.get(event);
|
|
12571
|
+
if (!spanState) {
|
|
12572
|
+
return;
|
|
12573
|
+
}
|
|
12574
|
+
spanState.span.log({
|
|
12575
|
+
error: event.error.message
|
|
12576
|
+
});
|
|
12577
|
+
spanState.span.end();
|
|
12578
|
+
states.delete(event);
|
|
12579
|
+
}
|
|
12580
|
+
function patchGoogleGenAIStreamingResult(args) {
|
|
12581
|
+
const { input, metadata, result } = args;
|
|
12582
|
+
if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
|
|
12583
|
+
return false;
|
|
12584
|
+
}
|
|
12585
|
+
const chunks = [];
|
|
12586
|
+
let firstTokenTime = null;
|
|
12587
|
+
let finalized = false;
|
|
12588
|
+
let span = null;
|
|
12589
|
+
let startTime = null;
|
|
12590
|
+
const ensureSpan = () => {
|
|
12591
|
+
if (!span) {
|
|
12592
|
+
span = startSpan({
|
|
12593
|
+
name: "generate_content_stream",
|
|
12594
|
+
spanAttributes: {
|
|
12595
|
+
type: "llm" /* LLM */
|
|
12596
|
+
},
|
|
12597
|
+
event: {
|
|
12598
|
+
input,
|
|
12599
|
+
metadata
|
|
12600
|
+
}
|
|
12601
|
+
});
|
|
12602
|
+
startTime = getCurrentUnixTimestamp();
|
|
12603
|
+
}
|
|
12604
|
+
return span;
|
|
12605
|
+
};
|
|
12606
|
+
const finalize = (options) => {
|
|
12607
|
+
if (finalized || !span) {
|
|
12608
|
+
return;
|
|
12609
|
+
}
|
|
12610
|
+
finalized = true;
|
|
12611
|
+
if (options.result) {
|
|
12612
|
+
const { end, ...metricsWithoutEnd } = options.result.metrics;
|
|
12613
|
+
span.log({
|
|
12614
|
+
metrics: cleanMetrics(metricsWithoutEnd),
|
|
12615
|
+
output: options.result.aggregated
|
|
12616
|
+
});
|
|
12617
|
+
span.end(typeof end === "number" ? { endTime: end } : void 0);
|
|
12618
|
+
return;
|
|
12619
|
+
}
|
|
12620
|
+
if (options.error !== void 0) {
|
|
12621
|
+
span.log({
|
|
12622
|
+
error: options.error instanceof Error ? options.error.message : String(options.error)
|
|
12623
|
+
});
|
|
12624
|
+
}
|
|
12625
|
+
span.end();
|
|
12626
|
+
};
|
|
12627
|
+
const patchIterator = (iterator) => {
|
|
12628
|
+
if (typeof iterator !== "object" || iterator === null || "__braintrustGoogleGenAIPatched" in iterator) {
|
|
12629
|
+
return iterator;
|
|
12630
|
+
}
|
|
12631
|
+
const iteratorRecord = iterator;
|
|
12632
|
+
const originalNext = typeof iteratorRecord.next === "function" ? iteratorRecord.next.bind(iterator) : void 0;
|
|
12633
|
+
const originalReturn = typeof iteratorRecord.return === "function" ? iteratorRecord.return.bind(iterator) : void 0;
|
|
12634
|
+
const originalThrow = typeof iteratorRecord.throw === "function" ? iteratorRecord.throw.bind(iterator) : void 0;
|
|
12635
|
+
const asyncIteratorMethod = iteratorRecord[Symbol.asyncIterator];
|
|
12636
|
+
const originalAsyncIterator = typeof asyncIteratorMethod === "function" ? asyncIteratorMethod.bind(iterator) : void 0;
|
|
12637
|
+
Object.defineProperty(iteratorRecord, "__braintrustGoogleGenAIPatched", {
|
|
12638
|
+
configurable: true,
|
|
12639
|
+
enumerable: false,
|
|
12640
|
+
value: true,
|
|
12641
|
+
writable: false
|
|
12642
|
+
});
|
|
12643
|
+
if (originalNext) {
|
|
12644
|
+
iteratorRecord.next = async (...nextArgs) => {
|
|
12645
|
+
ensureSpan();
|
|
12646
|
+
try {
|
|
12647
|
+
const nextResult = await originalNext(
|
|
12648
|
+
...nextArgs
|
|
12649
|
+
);
|
|
12650
|
+
if (!nextResult.done && nextResult.value) {
|
|
12651
|
+
if (firstTokenTime === null) {
|
|
12652
|
+
firstTokenTime = getCurrentUnixTimestamp();
|
|
12653
|
+
}
|
|
12654
|
+
chunks.push(nextResult.value);
|
|
12655
|
+
}
|
|
12656
|
+
if (nextResult.done && startTime !== null) {
|
|
12657
|
+
finalize({
|
|
12658
|
+
result: aggregateGenerateContentChunks(
|
|
12659
|
+
chunks,
|
|
12660
|
+
startTime,
|
|
12661
|
+
firstTokenTime
|
|
12662
|
+
)
|
|
12663
|
+
});
|
|
12664
|
+
}
|
|
12665
|
+
return nextResult;
|
|
12666
|
+
} catch (error) {
|
|
12667
|
+
finalize({ error });
|
|
12668
|
+
throw error;
|
|
12669
|
+
}
|
|
12670
|
+
};
|
|
12671
|
+
}
|
|
12672
|
+
if (originalReturn) {
|
|
12673
|
+
iteratorRecord.return = async (...returnArgs) => {
|
|
12674
|
+
ensureSpan();
|
|
12675
|
+
try {
|
|
12676
|
+
return await originalReturn(
|
|
12677
|
+
...returnArgs
|
|
12678
|
+
);
|
|
12679
|
+
} finally {
|
|
12680
|
+
if (startTime !== null) {
|
|
12681
|
+
finalize({
|
|
12682
|
+
result: chunks.length > 0 ? aggregateGenerateContentChunks(
|
|
12683
|
+
chunks,
|
|
12684
|
+
startTime,
|
|
12685
|
+
firstTokenTime
|
|
12686
|
+
) : void 0
|
|
12687
|
+
});
|
|
12688
|
+
} else {
|
|
12689
|
+
finalize({});
|
|
12690
|
+
}
|
|
12691
|
+
}
|
|
12692
|
+
};
|
|
12693
|
+
}
|
|
12694
|
+
if (originalThrow) {
|
|
12695
|
+
iteratorRecord.throw = async (...throwArgs) => {
|
|
12696
|
+
ensureSpan();
|
|
12697
|
+
try {
|
|
12698
|
+
return await originalThrow(
|
|
12699
|
+
...throwArgs
|
|
12700
|
+
);
|
|
12701
|
+
} catch (error) {
|
|
12702
|
+
finalize({ error });
|
|
12703
|
+
throw error;
|
|
12704
|
+
}
|
|
12705
|
+
};
|
|
12706
|
+
}
|
|
12707
|
+
iteratorRecord[Symbol.asyncIterator] = () => {
|
|
12708
|
+
const asyncIterator = originalAsyncIterator ? originalAsyncIterator() : iterator;
|
|
12709
|
+
return patchIterator(asyncIterator);
|
|
12710
|
+
};
|
|
12711
|
+
return iterator;
|
|
12712
|
+
};
|
|
12713
|
+
patchIterator(result);
|
|
12714
|
+
return true;
|
|
12715
|
+
}
|
|
12033
12716
|
function serializeInput(params) {
|
|
12034
12717
|
const input = {
|
|
12035
12718
|
model: params.model,
|
|
@@ -12038,11 +12721,13 @@ function serializeInput(params) {
|
|
|
12038
12721
|
if (params.config) {
|
|
12039
12722
|
const config = tryToDict(params.config);
|
|
12040
12723
|
if (config) {
|
|
12041
|
-
const
|
|
12042
|
-
|
|
12043
|
-
|
|
12044
|
-
|
|
12045
|
-
|
|
12724
|
+
const filteredConfig = {};
|
|
12725
|
+
Object.keys(config).forEach((key) => {
|
|
12726
|
+
if (key !== "tools") {
|
|
12727
|
+
filteredConfig[key] = config[key];
|
|
12728
|
+
}
|
|
12729
|
+
});
|
|
12730
|
+
input.config = filteredConfig;
|
|
12046
12731
|
}
|
|
12047
12732
|
}
|
|
12048
12733
|
return input;
|
|
@@ -12129,12 +12814,18 @@ function extractMetadata(params) {
|
|
|
12129
12814
|
});
|
|
12130
12815
|
}
|
|
12131
12816
|
}
|
|
12817
|
+
const tools = serializeTools(params);
|
|
12818
|
+
if (tools) {
|
|
12819
|
+
metadata.tools = tools;
|
|
12820
|
+
}
|
|
12132
12821
|
return metadata;
|
|
12133
12822
|
}
|
|
12134
12823
|
function extractGenerateContentMetrics(response, startTime) {
|
|
12135
12824
|
const metrics = {};
|
|
12136
|
-
if (startTime) {
|
|
12825
|
+
if (startTime !== void 0) {
|
|
12137
12826
|
const end = getCurrentUnixTimestamp();
|
|
12827
|
+
metrics.start = startTime;
|
|
12828
|
+
metrics.end = end;
|
|
12138
12829
|
metrics.duration = end - startTime;
|
|
12139
12830
|
}
|
|
12140
12831
|
if (response?.usageMetadata) {
|
|
@@ -12159,19 +12850,18 @@ function populateUsageMetrics(metrics, usage) {
|
|
|
12159
12850
|
metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
|
|
12160
12851
|
}
|
|
12161
12852
|
}
|
|
12162
|
-
function aggregateGenerateContentChunks(chunks, startTime) {
|
|
12163
|
-
const
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
if (
|
|
12170
|
-
firstTokenTime = getCurrentUnixTimestamp();
|
|
12853
|
+
function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
|
|
12854
|
+
const end = getCurrentUnixTimestamp();
|
|
12855
|
+
const metrics = {
|
|
12856
|
+
start: startTime,
|
|
12857
|
+
end,
|
|
12858
|
+
duration: end - startTime
|
|
12859
|
+
};
|
|
12860
|
+
if (firstTokenTime !== null) {
|
|
12171
12861
|
metrics.time_to_first_token = firstTokenTime - startTime;
|
|
12172
12862
|
}
|
|
12173
12863
|
if (chunks.length === 0) {
|
|
12174
|
-
return {
|
|
12864
|
+
return { aggregated: {}, metrics };
|
|
12175
12865
|
}
|
|
12176
12866
|
let text = "";
|
|
12177
12867
|
let thoughtText = "";
|
|
@@ -12207,7 +12897,7 @@ function aggregateGenerateContentChunks(chunks, startTime) {
|
|
|
12207
12897
|
}
|
|
12208
12898
|
}
|
|
12209
12899
|
}
|
|
12210
|
-
const
|
|
12900
|
+
const aggregated = {};
|
|
12211
12901
|
const parts = [];
|
|
12212
12902
|
if (thoughtText) {
|
|
12213
12903
|
parts.push({ text: thoughtText, thought: true });
|
|
@@ -12233,16 +12923,25 @@ function aggregateGenerateContentChunks(chunks, startTime) {
|
|
|
12233
12923
|
}
|
|
12234
12924
|
candidates.push(candidateDict);
|
|
12235
12925
|
}
|
|
12236
|
-
|
|
12926
|
+
aggregated.candidates = candidates;
|
|
12237
12927
|
}
|
|
12238
12928
|
if (usageMetadata) {
|
|
12239
|
-
|
|
12929
|
+
aggregated.usageMetadata = usageMetadata;
|
|
12240
12930
|
populateUsageMetrics(metrics, usageMetadata);
|
|
12241
12931
|
}
|
|
12242
12932
|
if (text) {
|
|
12243
|
-
|
|
12933
|
+
aggregated.text = text;
|
|
12934
|
+
}
|
|
12935
|
+
return { aggregated, metrics };
|
|
12936
|
+
}
|
|
12937
|
+
function cleanMetrics(metrics) {
|
|
12938
|
+
const cleaned = {};
|
|
12939
|
+
for (const [key, value] of Object.entries(metrics)) {
|
|
12940
|
+
if (value !== null && value !== void 0) {
|
|
12941
|
+
cleaned[key] = value;
|
|
12942
|
+
}
|
|
12244
12943
|
}
|
|
12245
|
-
return
|
|
12944
|
+
return cleaned;
|
|
12246
12945
|
}
|
|
12247
12946
|
function tryToDict(obj) {
|
|
12248
12947
|
if (obj === null || obj === void 0) {
|