langsmith 0.5.24 → 0.5.26

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.
Files changed (60) hide show
  1. package/dist/client.cjs +9 -3
  2. package/dist/client.js +9 -3
  3. package/dist/experimental/anthropic/context.cjs +419 -49
  4. package/dist/experimental/anthropic/context.js +420 -50
  5. package/dist/experimental/anthropic/index.cjs +78 -10
  6. package/dist/experimental/anthropic/index.js +80 -12
  7. package/dist/experimental/anthropic/messages.cjs +53 -0
  8. package/dist/experimental/anthropic/messages.d.ts +6 -0
  9. package/dist/experimental/anthropic/messages.js +52 -0
  10. package/dist/experimental/anthropic/transcripts.cjs +144 -0
  11. package/dist/experimental/anthropic/transcripts.d.ts +22 -0
  12. package/dist/experimental/anthropic/transcripts.js +141 -0
  13. package/dist/experimental/anthropic/types.d.ts +1 -0
  14. package/dist/experimental/anthropic/usage.cjs +19 -20
  15. package/dist/experimental/anthropic/usage.d.ts +2 -1
  16. package/dist/experimental/anthropic/usage.js +18 -20
  17. package/dist/experimental/opencode/index.cjs +36 -0
  18. package/dist/experimental/opencode/index.d.ts +3 -0
  19. package/dist/experimental/opencode/index.js +32 -0
  20. package/dist/experimental/opencode/tracer.cjs +389 -0
  21. package/dist/experimental/opencode/tracer.d.ts +30 -0
  22. package/dist/experimental/opencode/tracer.js +385 -0
  23. package/dist/experimental/otel/setup.cjs +1 -1
  24. package/dist/experimental/otel/setup.js +1 -1
  25. package/dist/experimental/sandbox/sandbox.cjs +6 -2
  26. package/dist/experimental/sandbox/sandbox.d.ts +5 -1
  27. package/dist/experimental/sandbox/sandbox.js +6 -2
  28. package/dist/experimental/sandbox/types.d.ts +3 -1
  29. package/dist/experimental/vercel/index.cjs +1 -1
  30. package/dist/experimental/vercel/index.js +1 -1
  31. package/dist/experimental/vercel/middleware.cjs +2 -1
  32. package/dist/experimental/vercel/middleware.js +2 -1
  33. package/dist/index.cjs +1 -1
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.js +1 -1
  36. package/dist/schemas.d.ts +4 -0
  37. package/dist/singletons/traceable.cjs +1 -3
  38. package/dist/singletons/traceable.js +1 -3
  39. package/dist/traceable.cjs +1 -3
  40. package/dist/traceable.js +1 -3
  41. package/dist/utils/_git.cjs +2 -2
  42. package/dist/utils/_git.js +2 -2
  43. package/dist/utils/env.cjs +2 -2
  44. package/dist/utils/env.js +2 -2
  45. package/dist/utils/error.cjs +2 -2
  46. package/dist/utils/error.js +2 -2
  47. package/dist/utils/jestlike/reporter.cjs +1 -1
  48. package/dist/utils/jestlike/reporter.js +1 -1
  49. package/dist/utils/jestlike/vendor/chain.cjs +2 -3
  50. package/dist/utils/jestlike/vendor/chain.js +2 -3
  51. package/dist/vitest/utils/esm.mjs +4 -4
  52. package/dist/wrappers/gemini.cjs +1 -1
  53. package/dist/wrappers/gemini.js +1 -1
  54. package/dist/wrappers/openai.cjs +2 -6
  55. package/dist/wrappers/openai.js +2 -6
  56. package/experimental/opencode.cjs +1 -0
  57. package/experimental/opencode.d.cts +1 -0
  58. package/experimental/opencode.d.ts +1 -0
  59. package/experimental/opencode.js +1 -0
  60. package/package.json +24 -18
package/dist/client.cjs CHANGED
@@ -719,6 +719,10 @@ class Client {
719
719
  this.webUrl = "https://aws.smith.langchain.com";
720
720
  return this.webUrl;
721
721
  }
722
+ else if (this.apiUrl.split(".", 1)[0].includes("apac")) {
723
+ this.webUrl = "https://apac.smith.langchain.com";
724
+ return this.webUrl;
725
+ }
722
726
  else if (this.apiUrl.split(".", 1)[0].includes("beta")) {
723
727
  this.webUrl = "https://beta.smith.langchain.com";
724
728
  return this.webUrl;
@@ -1199,7 +1203,7 @@ class Client {
1199
1203
  const response = await this.caller.call(async () => {
1200
1204
  const res = await this._fetch(`${this.apiUrl}/info`, {
1201
1205
  method: "GET",
1202
- headers: { Accept: "application/json" },
1206
+ headers: { ...this._mergedHeaders, Accept: "application/json" },
1203
1207
  signal: AbortSignal.timeout(SERVER_INFO_REQUEST_TIMEOUT_MS),
1204
1208
  ...this.fetchOptions,
1205
1209
  });
@@ -2495,7 +2499,7 @@ class Client {
2495
2499
  // projectId querying
2496
2500
  return true;
2497
2501
  }
2498
- catch (e) {
2502
+ catch (_e) {
2499
2503
  return false;
2500
2504
  }
2501
2505
  }
@@ -4490,6 +4494,8 @@ class Client {
4490
4494
  commit_hash: result.commit_hash,
4491
4495
  manifest: result.manifest,
4492
4496
  examples: result.examples,
4497
+ hub_model_config: result.model_config,
4498
+ hub_model_provider: result.model_provider,
4493
4499
  };
4494
4500
  }
4495
4501
  async pullPromptCommit(promptIdentifier, options) {
@@ -4874,7 +4880,7 @@ class Client {
4874
4880
  throw new Error(`Invalid public ${kind} URL: ${urlOrToken}`);
4875
4881
  }
4876
4882
  }
4877
- catch (error) {
4883
+ catch (_error) {
4878
4884
  throw new Error(`Invalid public ${kind} URL or token: ${urlOrToken}`);
4879
4885
  }
4880
4886
  }
package/dist/client.js CHANGED
@@ -681,6 +681,10 @@ export class Client {
681
681
  this.webUrl = "https://aws.smith.langchain.com";
682
682
  return this.webUrl;
683
683
  }
684
+ else if (this.apiUrl.split(".", 1)[0].includes("apac")) {
685
+ this.webUrl = "https://apac.smith.langchain.com";
686
+ return this.webUrl;
687
+ }
684
688
  else if (this.apiUrl.split(".", 1)[0].includes("beta")) {
685
689
  this.webUrl = "https://beta.smith.langchain.com";
686
690
  return this.webUrl;
@@ -1161,7 +1165,7 @@ export class Client {
1161
1165
  const response = await this.caller.call(async () => {
1162
1166
  const res = await this._fetch(`${this.apiUrl}/info`, {
1163
1167
  method: "GET",
1164
- headers: { Accept: "application/json" },
1168
+ headers: { ...this._mergedHeaders, Accept: "application/json" },
1165
1169
  signal: AbortSignal.timeout(SERVER_INFO_REQUEST_TIMEOUT_MS),
1166
1170
  ...this.fetchOptions,
1167
1171
  });
@@ -2457,7 +2461,7 @@ export class Client {
2457
2461
  // projectId querying
2458
2462
  return true;
2459
2463
  }
2460
- catch (e) {
2464
+ catch (_e) {
2461
2465
  return false;
2462
2466
  }
2463
2467
  }
@@ -4452,6 +4456,8 @@ export class Client {
4452
4456
  commit_hash: result.commit_hash,
4453
4457
  manifest: result.manifest,
4454
4458
  examples: result.examples,
4459
+ hub_model_config: result.model_config,
4460
+ hub_model_provider: result.model_provider,
4455
4461
  };
4456
4462
  }
4457
4463
  async pullPromptCommit(promptIdentifier, options) {
@@ -4836,7 +4842,7 @@ export class Client {
4836
4842
  throw new Error(`Invalid public ${kind} URL: ${urlOrToken}`);
4837
4843
  }
4838
4844
  }
4839
- catch (error) {
4845
+ catch (_error) {
4840
4846
  throw new Error(`Invalid public ${kind} URL or token: ${urlOrToken}`);
4841
4847
  }
4842
4848
  }
@@ -4,11 +4,27 @@ exports.StreamManager = void 0;
4
4
  const messages_js_1 = require("./messages.cjs");
5
5
  const traceable_js_1 = require("../../traceable.cjs");
6
6
  const usage_js_1 = require("./usage.cjs");
7
+ const transcripts_js_1 = require("./transcripts.cjs");
8
+ function isRecord(value) {
9
+ return typeof value === "object" && value != null && !Array.isArray(value);
10
+ }
11
+ function isToolResultError(value) {
12
+ return isRecord(value) && (value.is_error === true || value.isError === true);
13
+ }
14
+ function makeSubagentTranscriptPathKey(path, toolUseId, agentType) {
15
+ return JSON.stringify([path, toolUseId ?? null, agentType ?? null]);
16
+ }
7
17
  /**
8
18
  * @internal
9
19
  */
10
20
  class StreamManager {
11
21
  constructor() {
22
+ Object.defineProperty(this, "rootRun", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
12
28
  Object.defineProperty(this, "namespaces", {
13
29
  enumerable: true,
14
30
  configurable: true,
@@ -33,6 +49,48 @@ class StreamManager {
33
49
  writable: true,
34
50
  value: {}
35
51
  });
52
+ Object.defineProperty(this, "subagents", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: {}
57
+ });
58
+ Object.defineProperty(this, "mainTranscriptPath", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: void 0
63
+ });
64
+ Object.defineProperty(this, "subagentTranscriptPaths", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: []
69
+ });
70
+ Object.defineProperty(this, "pendingAgentTools", {
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true,
74
+ value: new Map()
75
+ });
76
+ Object.defineProperty(this, "agentToToolUseId", {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: true,
80
+ value: new Map()
81
+ });
82
+ Object.defineProperty(this, "transcriptPathKeys", {
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true,
86
+ value: new Set()
87
+ });
88
+ Object.defineProperty(this, "resultModelUsage", {
89
+ enumerable: true,
90
+ configurable: true,
91
+ writable: true,
92
+ value: void 0
93
+ });
36
94
  Object.defineProperty(this, "postRunQueue", {
37
95
  enumerable: true,
38
96
  configurable: true,
@@ -46,10 +104,21 @@ class StreamManager {
46
104
  value: []
47
105
  });
48
106
  const rootRun = (0, traceable_js_1.getCurrentRunTree)(true);
107
+ this.rootRun = rootRun;
49
108
  this.namespaces = rootRun?.createChild ? { root: rootRun } : {};
50
109
  this.history = { root: [] };
110
+ if (rootRun != null) {
111
+ StreamManager.managersByRootRun.set(rootRun, this);
112
+ }
113
+ StreamManager.liveManagers.add(this);
51
114
  }
52
- addMessage(message) {
115
+ dispose() {
116
+ StreamManager.liveManagers.delete(this);
117
+ if (this.rootRun != null) {
118
+ StreamManager.managersByRootRun.delete(this.rootRun);
119
+ }
120
+ }
121
+ async addMessage(message) {
53
122
  const eventTime = Date.now();
54
123
  // Short-circuit if no root run found
55
124
  // This can happen if tracing is disabled globally
@@ -57,7 +126,7 @@ class StreamManager {
57
126
  return;
58
127
  if (message.type === "result") {
59
128
  if (message.modelUsage) {
60
- (0, usage_js_1.correctUsageFromResults)(message.modelUsage, Object.values(this.assistant).filter((runTree) => runTree != null));
129
+ this.resultModelUsage = message.modelUsage;
61
130
  }
62
131
  const usage = message.modelUsage
63
132
  ? (0, usage_js_1.aggregateUsageFromModelUsage)(message.modelUsage)
@@ -105,7 +174,11 @@ class StreamManager {
105
174
  this.assistant[messageId].outputs = (() => {
106
175
  const prevMessages = this.assistant[messageId].outputs?.output.messages ?? [];
107
176
  const newMessages = (0, messages_js_1.convertFromAnthropicMessage)([message]);
108
- return { output: { messages: [...prevMessages, ...newMessages] } };
177
+ return {
178
+ output: {
179
+ messages: (0, messages_js_1.mergeMessagesById)(prevMessages, newMessages),
180
+ },
181
+ };
109
182
  })();
110
183
  this.assistant[messageId].end_time = eventTime;
111
184
  this.assistant[messageId].extra ??= {};
@@ -121,35 +194,10 @@ class StreamManager {
121
194
  : [];
122
195
  for (const block of tools) {
123
196
  if ((0, messages_js_1.isTaskTool)(block)) {
124
- const name = block.input.subagent_type ||
125
- block.input.agent_type ||
126
- (block.input.description
127
- ? block.input.description.split(" ")[0]
128
- : null) ||
129
- "unknown-agent";
130
- this.tools[block.id] ??=
131
- this.createChild("root", {
132
- name,
133
- run_type: "chain",
134
- inputs: block.input,
135
- start_time: eventTime,
136
- extra: {
137
- metadata: {
138
- ls_agent_type: "subagent",
139
- },
140
- },
141
- }) ?? this.tools[block.id];
142
- this.namespaces[block.id] ??= this.tools[block.id];
197
+ this.createAgentToolRun(namespace, block, eventTime);
143
198
  }
144
199
  else {
145
- const name = block.name || "unknown-tool";
146
- this.tools[block.id] ??=
147
- this.createChild(namespace, {
148
- name,
149
- run_type: "tool",
150
- inputs: block.input ? { input: block.input } : {},
151
- start_time: eventTime,
152
- }) ?? this.tools[block.id];
200
+ this.createToolRun(namespace, block, eventTime);
153
201
  }
154
202
  }
155
203
  }
@@ -158,9 +206,7 @@ class StreamManager {
158
206
  ? message.message.content.filter((block) => "tool_use_id" in block)
159
207
  : [];
160
208
  const getToolOutput = (result) => {
161
- if (typeof result === "object" &&
162
- result != null &&
163
- !Array.isArray(result)) {
209
+ if (isRecord(result)) {
164
210
  return result;
165
211
  }
166
212
  return { content: result };
@@ -169,10 +215,23 @@ class StreamManager {
169
215
  if (["string", "number", "boolean"].includes(typeof result)) {
170
216
  return String(result);
171
217
  }
218
+ if (Array.isArray(result)) {
219
+ return result.map(getToolError).join("\n");
220
+ }
221
+ if (isRecord(result)) {
222
+ if (typeof result.error === "string")
223
+ return result.error;
224
+ if (typeof result.text === "string")
225
+ return result.text;
226
+ if ("content" in result)
227
+ return getToolError(result.content);
228
+ }
172
229
  return JSON.stringify(result);
173
230
  };
174
231
  for (const block of toolResultBlocks) {
175
- if (this.tools[block.tool_use_id] != null) {
232
+ const tool = this.tools[block.tool_use_id];
233
+ const subagent = this.subagents[block.tool_use_id];
234
+ if (tool != null || subagent != null) {
176
235
  // Previous versions of @anthropic-ai/claude-agent-sdk did provide
177
236
  // tool result in `message.tool_use_result`, but at least since 0.2.50 it disappeared,
178
237
  // so we rely on the last tool result block instead.
@@ -180,36 +239,347 @@ class StreamManager {
180
239
  ? message.tool_use_result
181
240
  : block.content;
182
241
  const toolOutput = getToolOutput(result);
183
- const toolError = "is_error" in block && block.is_error === true
184
- ? getToolError(result)
185
- : undefined;
186
- void this.tools[block.tool_use_id]?.end(toolOutput, toolError);
242
+ const isError = isToolResultError(block) || isToolResultError(result);
243
+ const toolError = isError ? getToolError(result) : undefined;
244
+ await tool?.end(toolOutput, toolError);
245
+ // Match Python's lifecycle: PostToolUse sets outputs on the
246
+ // subagent chain, but the subagent itself is not ended until after
247
+ // transcript reconciliation. Hidden transcript LLM/tool children can
248
+ // arrive after the Agent/Task tool result, so ending the chain here
249
+ // can make reconciled children appear outside their parent bounds.
250
+ if (subagent != null) {
251
+ subagent.outputs ??= toolOutput;
252
+ subagent.error ??= toolError;
253
+ }
187
254
  }
188
255
  }
189
256
  }
190
257
  this.history[namespace].push(message);
191
258
  }
259
+ addHookEvent(input, toolUseId) {
260
+ if (typeof input !== "object" || input == null)
261
+ return;
262
+ const data = input;
263
+ if (this.mainTranscriptPath == null &&
264
+ typeof data.transcript_path === "string") {
265
+ this.mainTranscriptPath = data.transcript_path;
266
+ }
267
+ if (data.hook_event_name === "PreToolUse" &&
268
+ typeof toolUseId === "string" &&
269
+ (data.tool_name === "Agent" || data.tool_name === "Task")) {
270
+ this.pendingAgentTools.set(toolUseId, typeof data.tool_input === "object" && data.tool_input != null
271
+ ? data.tool_input
272
+ : {});
273
+ return;
274
+ }
275
+ if (data.hook_event_name === "SubagentStart") {
276
+ const agentId = typeof data.agent_id === "string" ? data.agent_id : undefined;
277
+ if (agentId == null)
278
+ return;
279
+ const agentType = typeof data.agent_type === "string" ? data.agent_type : undefined;
280
+ let matchedToolUseId;
281
+ for (const [pendingToolUseId, toolInput] of this.pendingAgentTools) {
282
+ const pendingAgentType = typeof toolInput.subagent_type === "string"
283
+ ? toolInput.subagent_type
284
+ : typeof toolInput.agent_type === "string"
285
+ ? toolInput.agent_type
286
+ : undefined;
287
+ if (agentType == null ||
288
+ pendingAgentType == null ||
289
+ pendingAgentType === agentType) {
290
+ matchedToolUseId = pendingToolUseId;
291
+ break;
292
+ }
293
+ }
294
+ matchedToolUseId ??= this.pendingAgentTools.keys().next().value;
295
+ if (matchedToolUseId != null) {
296
+ this.agentToToolUseId.set(agentId, matchedToolUseId);
297
+ this.pendingAgentTools.delete(matchedToolUseId);
298
+ }
299
+ return;
300
+ }
301
+ if (data.hook_event_name === "SubagentStop") {
302
+ const transcriptPath = typeof data.agent_transcript_path === "string"
303
+ ? data.agent_transcript_path
304
+ : undefined;
305
+ if (!transcriptPath)
306
+ return;
307
+ const agentId = typeof data.agent_id === "string" ? data.agent_id : undefined;
308
+ const agentType = typeof data.agent_type === "string" ? data.agent_type : undefined;
309
+ const mappedToolUseId = agentId != null ? this.agentToToolUseId.get(agentId) : undefined;
310
+ if (agentId != null)
311
+ this.agentToToolUseId.delete(agentId);
312
+ this.addSubagentTranscriptPath(transcriptPath, mappedToolUseId, agentType);
313
+ }
314
+ }
315
+ addSubagentTranscriptPath(path, toolUseId, agentType) {
316
+ const key = makeSubagentTranscriptPathKey(path, toolUseId, agentType);
317
+ if (this.transcriptPathKeys.has(key))
318
+ return;
319
+ this.transcriptPathKeys.add(key);
320
+ this.subagentTranscriptPaths.push({ path, toolUseId, agentType });
321
+ }
322
+ static getActiveToolRun(toolName, input) {
323
+ const currentRun = (0, traceable_js_1.getCurrentRunTree)(true);
324
+ const currentManager = currentRun != null
325
+ ? StreamManager.managersByRootRun.get(currentRun)
326
+ : undefined;
327
+ const currentRunTree = currentManager?.getActiveToolRun(toolName, input);
328
+ if (currentRunTree != null)
329
+ return currentRunTree;
330
+ // Last resort: the SDK invoked an MCP handler from a detached async context
331
+ // that did not inherit the existing LangSmith AsyncLocalStorage. Require
332
+ // both tool name and input to match before scanning live managers to avoid
333
+ // cross-query attribution.
334
+ if (toolName == null || input === undefined)
335
+ return undefined;
336
+ for (const manager of Array.from(StreamManager.liveManagers).reverse()) {
337
+ if (manager === currentManager)
338
+ continue;
339
+ const runTree = manager.getActiveToolRun(toolName, input);
340
+ if (runTree != null)
341
+ return runTree;
342
+ }
343
+ return undefined;
344
+ }
345
+ getActiveToolRun(toolName, input) {
346
+ const toolEntries = Object.values(this.tools).filter((runTree) => runTree != null && runTree.end_time == null && runTree.error == null);
347
+ return toolEntries.find((runTree) => {
348
+ if (toolName != null) {
349
+ const runName = String(runTree.name);
350
+ const nameMatches = runName === toolName ||
351
+ runName.includes(toolName) ||
352
+ toolName.includes(runName);
353
+ if (!nameMatches)
354
+ return false;
355
+ }
356
+ if (input !== undefined) {
357
+ const recorded = runTree.inputs?.input ?? {};
358
+ try {
359
+ return JSON.stringify(recorded) === JSON.stringify(input ?? {});
360
+ }
361
+ catch {
362
+ return false;
363
+ }
364
+ }
365
+ return true;
366
+ });
367
+ }
192
368
  createChild(namespace, args) {
193
- const runTree = this.namespaces[namespace]?.createChild(args);
369
+ const parentRunTree = this.namespaces[namespace];
370
+ if (parentRunTree == null)
371
+ return undefined;
372
+ return this.createChildRun(parentRunTree, args);
373
+ }
374
+ createChildRun(parentRunTree, args) {
375
+ const runTree = parentRunTree.createChild(args);
194
376
  if (runTree == null)
195
377
  return undefined;
196
378
  this.postRunQueue.push(runTree.postRun());
197
379
  this.runTrees.push(runTree);
198
380
  return runTree;
199
381
  }
200
- async finish() {
201
- // Clean up incomplete tools and subagent calls
202
- for (const tool of Object.values(this.tools)) {
203
- if (tool == null)
382
+ getAgentName(block) {
383
+ const subagentType = block.input.subagent_type;
384
+ if (typeof subagentType === "string" && subagentType.length > 0) {
385
+ return subagentType;
386
+ }
387
+ const agentType = block.input.agent_type;
388
+ if (typeof agentType === "string" && agentType.length > 0) {
389
+ return agentType;
390
+ }
391
+ const description = block.input.description;
392
+ if (typeof description === "string" && description.length > 0) {
393
+ return description.split(" ")[0] || "unknown-agent";
394
+ }
395
+ return "unknown-agent";
396
+ }
397
+ createToolRun(namespace, block, startTime) {
398
+ if (typeof block.id !== "string")
399
+ return undefined;
400
+ const name = typeof block.name === "string" ? block.name : "unknown-tool";
401
+ this.tools[block.id] ??=
402
+ this.createChild(namespace, {
403
+ name,
404
+ run_type: "tool",
405
+ inputs: block.input ? { input: block.input } : {},
406
+ start_time: startTime,
407
+ }) ?? this.tools[block.id];
408
+ return this.tools[block.id];
409
+ }
410
+ createAgentToolRun(namespace, block, startTime) {
411
+ if (typeof block.id !== "string")
412
+ return;
413
+ if (typeof block.input !== "object" ||
414
+ block.input == null ||
415
+ Array.isArray(block.input)) {
416
+ return;
417
+ }
418
+ const input = block.input;
419
+ const agentToolRun = this.createToolRun(namespace, block, startTime);
420
+ if (agentToolRun == null)
421
+ return;
422
+ this.subagents[block.id] ??=
423
+ this.createChildRun(agentToolRun, {
424
+ name: this.getAgentName({ input }),
425
+ run_type: "chain",
426
+ inputs: input,
427
+ start_time: startTime,
428
+ extra: {
429
+ metadata: {
430
+ ls_agent_type: "subagent",
431
+ },
432
+ },
433
+ }) ?? this.subagents[block.id];
434
+ this.namespaces[block.id] ??= this.subagents[block.id];
435
+ }
436
+ resolveSubagentNamespace(agentType) {
437
+ const entries = Object.entries(this.namespaces);
438
+ if (agentType == null)
439
+ return undefined;
440
+ return entries.find(([, runTree]) => runTree?.name === agentType)?.[0];
441
+ }
442
+ createSyntheticAssistantRun(namespace, turn) {
443
+ let runTree = this.assistant[turn.messageId];
444
+ if (runTree == null) {
445
+ runTree = this.createChild(namespace, {
446
+ name: "claude.assistant.turn",
447
+ run_type: "llm",
448
+ start_time: turn.timestamp,
449
+ inputs: turn.inputMessages.length > 0 ? { messages: turn.inputMessages } : {},
450
+ outputs: {
451
+ output: { messages: (0, messages_js_1.convertFromAnthropicMessage)(turn.message) },
452
+ },
453
+ extra: {
454
+ metadata: {
455
+ ls_provider: "anthropic",
456
+ ...(turn.model != null ? { ls_model_name: turn.model } : {}),
457
+ ...(turn.usageMetadata != null
458
+ ? { usage_metadata: turn.usageMetadata }
459
+ : {}),
460
+ },
461
+ },
462
+ });
463
+ if (runTree == null)
464
+ return;
465
+ this.assistant[turn.messageId] = runTree;
466
+ }
467
+ else {
468
+ runTree.outputs = {
469
+ output: { messages: (0, messages_js_1.convertFromAnthropicMessage)(turn.message) },
470
+ };
471
+ runTree.extra ??= {};
472
+ runTree.extra.metadata ??= {};
473
+ if (turn.model != null)
474
+ runTree.extra.metadata.ls_model_name = turn.model;
475
+ if (turn.usageMetadata != null) {
476
+ runTree.extra.metadata.usage_metadata = turn.usageMetadata;
477
+ }
478
+ }
479
+ runTree.end_time = turn.timestamp;
480
+ const tools = Array.isArray(turn.message.message.content)
481
+ ? turn.message.message.content.filter((block) => (0, messages_js_1.isToolBlock)(block))
482
+ : [];
483
+ for (const block of tools) {
484
+ if ((0, messages_js_1.isTaskTool)(block)) {
485
+ this.createAgentToolRun(namespace, block, turn.timestamp);
486
+ }
487
+ else {
488
+ this.createToolRun(namespace, block, turn.timestamp);
489
+ }
490
+ }
491
+ }
492
+ async reconcileTranscripts() {
493
+ const usageByMessageId = {};
494
+ if (this.mainTranscriptPath != null) {
495
+ const transcript = await (0, transcripts_js_1.readTranscript)(this.mainTranscriptPath);
496
+ Object.assign(usageByMessageId, transcript.usageByMessageId);
497
+ }
498
+ for (const transcriptPath of this.subagentTranscriptPaths) {
499
+ const namespace = transcriptPath.toolUseId ??
500
+ this.resolveSubagentNamespace(transcriptPath.agentType);
501
+ if (namespace == null || this.namespaces[namespace] == null)
204
502
  continue;
205
- if (tool.outputs == null && tool.error == null) {
206
- void tool.end(undefined, "Run not completed (conversation ended)");
503
+ const transcript = await (0, transcripts_js_1.readTranscript)(transcriptPath.path);
504
+ Object.assign(usageByMessageId, transcript.usageByMessageId);
505
+ for (const turn of transcript.turns) {
506
+ this.createSyntheticAssistantRun(namespace, turn);
507
+ }
508
+ for (const toolResult of transcript.toolResults) {
509
+ const tool = this.tools[toolResult.toolUseId];
510
+ if (tool == null)
511
+ continue;
512
+ const output = isRecord(toolResult.content)
513
+ ? toolResult.content
514
+ : { content: toolResult.content };
515
+ const error = toolResult.isError
516
+ ? typeof toolResult.content === "string" ||
517
+ typeof toolResult.content === "number" ||
518
+ typeof toolResult.content === "boolean"
519
+ ? String(toolResult.content)
520
+ : JSON.stringify(toolResult.content)
521
+ : undefined;
522
+ await tool.end(output, error);
523
+ }
524
+ }
525
+ for (const [messageId, usage] of Object.entries(usageByMessageId)) {
526
+ const runTree = this.assistant[messageId];
527
+ if (runTree == null)
528
+ continue;
529
+ runTree.extra ??= {};
530
+ runTree.extra.metadata ??= {};
531
+ runTree.extra.metadata.usage_metadata = usage;
532
+ }
533
+ }
534
+ async finish() {
535
+ try {
536
+ await this.reconcileTranscripts();
537
+ if (this.resultModelUsage != null) {
538
+ (0, usage_js_1.correctUsageFromResults)(this.resultModelUsage, Object.values(this.assistant).filter((runTree) => runTree != null));
539
+ }
540
+ // Clean up incomplete tools and finalise subagent calls. This mirrors the
541
+ // Python integration: Agent/Task tool runs are ended when their tool result
542
+ // arrives, while subagent chain runs are finalised only after transcript
543
+ // reconciliation so hidden child LLM/tool runs are created first.
544
+ for (const tool of Object.values(this.tools)) {
545
+ if (tool == null)
546
+ continue;
547
+ if (tool.outputs == null && tool.error == null) {
548
+ await tool.end(undefined, "Run not completed (conversation ended)");
549
+ }
207
550
  }
551
+ for (const subagent of Object.values(this.subagents)) {
552
+ if (subagent == null)
553
+ continue;
554
+ if (subagent.end_time == null) {
555
+ if (subagent.outputs == null && subagent.error == null) {
556
+ await subagent.end(undefined, "Run not completed (conversation ended)");
557
+ }
558
+ else {
559
+ await subagent.end();
560
+ }
561
+ }
562
+ }
563
+ // First make sure all the runs are created
564
+ await Promise.allSettled(this.postRunQueue);
565
+ // Then patch the runs
566
+ await Promise.allSettled(this.runTrees.map((runTree) => runTree.patchRun()));
567
+ }
568
+ finally {
569
+ this.dispose();
208
570
  }
209
- // First make sure all the runs are created
210
- await Promise.allSettled(this.postRunQueue);
211
- // Then patch the runs
212
- await Promise.allSettled(this.runTrees.map((runTree) => runTree.patchRun()));
213
571
  }
214
572
  }
215
573
  exports.StreamManager = StreamManager;
574
+ Object.defineProperty(StreamManager, "liveManagers", {
575
+ enumerable: true,
576
+ configurable: true,
577
+ writable: true,
578
+ value: new Set()
579
+ });
580
+ Object.defineProperty(StreamManager, "managersByRootRun", {
581
+ enumerable: true,
582
+ configurable: true,
583
+ writable: true,
584
+ value: new WeakMap()
585
+ });