langsmith 0.5.12 → 0.5.14

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.
@@ -57,7 +57,7 @@ class StreamManager {
57
57
  return;
58
58
  if (message.type === "result") {
59
59
  if (message.modelUsage) {
60
- (0, usage_js_1.correctUsageFromResults)(message.modelUsage, Object.values(this.assistant));
60
+ (0, usage_js_1.correctUsageFromResults)(message.modelUsage, Object.values(this.assistant).filter((runTree) => runTree != null));
61
61
  }
62
62
  const usage = message.modelUsage
63
63
  ? (0, usage_js_1.aggregateUsageFromModelUsage)(message.modelUsage)
@@ -100,6 +100,8 @@ class StreamManager {
100
100
  },
101
101
  outputs: { output: { messages: [] } },
102
102
  });
103
+ if (this.assistant[messageId] == null)
104
+ return;
103
105
  this.assistant[messageId].outputs = (() => {
104
106
  const prevMessages = this.assistant[messageId].outputs?.output.messages ?? [];
105
107
  const newMessages = (0, messages_js_1.convertFromAnthropicMessage)([message]);
@@ -125,22 +127,24 @@ class StreamManager {
125
127
  ? block.input.description.split(" ")[0]
126
128
  : null) ||
127
129
  "unknown-agent";
128
- this.tools[block.id] ??= this.createChild("root", {
129
- name,
130
- run_type: "chain",
131
- inputs: block.input,
132
- start_time: eventTime,
133
- });
130
+ this.tools[block.id] ??=
131
+ this.createChild("root", {
132
+ name,
133
+ run_type: "chain",
134
+ inputs: block.input,
135
+ start_time: eventTime,
136
+ }) ?? this.tools[block.id];
134
137
  this.namespaces[block.id] ??= this.tools[block.id];
135
138
  }
136
139
  else {
137
140
  const name = block.name || "unknown-tool";
138
- this.tools[block.id] ??= this.createChild(namespace, {
139
- name,
140
- run_type: "tool",
141
- inputs: block.input ? { input: block.input } : {},
142
- start_time: eventTime,
143
- });
141
+ this.tools[block.id] ??=
142
+ this.createChild(namespace, {
143
+ name,
144
+ run_type: "tool",
145
+ inputs: block.input ? { input: block.input } : {},
146
+ start_time: eventTime,
147
+ }) ?? this.tools[block.id];
144
148
  }
145
149
  }
146
150
  }
@@ -174,14 +178,16 @@ class StreamManager {
174
178
  const toolError = "is_error" in block && block.is_error === true
175
179
  ? getToolError(result)
176
180
  : undefined;
177
- void this.tools[block.tool_use_id].end(toolOutput, toolError);
181
+ void this.tools[block.tool_use_id]?.end(toolOutput, toolError);
178
182
  }
179
183
  }
180
184
  }
181
185
  this.history[namespace].push(message);
182
186
  }
183
187
  createChild(namespace, args) {
184
- const runTree = this.namespaces[namespace].createChild(args);
188
+ const runTree = this.namespaces[namespace]?.createChild(args);
189
+ if (runTree == null)
190
+ return undefined;
185
191
  this.postRunQueue.push(runTree.postRun());
186
192
  this.runTrees.push(runTree);
187
193
  return runTree;
@@ -189,6 +195,8 @@ class StreamManager {
189
195
  async finish() {
190
196
  // Clean up incomplete tools and subagent calls
191
197
  for (const tool of Object.values(this.tools)) {
198
+ if (tool == null)
199
+ continue;
192
200
  if (tool.outputs == null && tool.error == null) {
193
201
  void tool.end(undefined, "Run not completed (conversation ended)");
194
202
  }
@@ -54,7 +54,7 @@ export class StreamManager {
54
54
  return;
55
55
  if (message.type === "result") {
56
56
  if (message.modelUsage) {
57
- correctUsageFromResults(message.modelUsage, Object.values(this.assistant));
57
+ correctUsageFromResults(message.modelUsage, Object.values(this.assistant).filter((runTree) => runTree != null));
58
58
  }
59
59
  const usage = message.modelUsage
60
60
  ? aggregateUsageFromModelUsage(message.modelUsage)
@@ -97,6 +97,8 @@ export class StreamManager {
97
97
  },
98
98
  outputs: { output: { messages: [] } },
99
99
  });
100
+ if (this.assistant[messageId] == null)
101
+ return;
100
102
  this.assistant[messageId].outputs = (() => {
101
103
  const prevMessages = this.assistant[messageId].outputs?.output.messages ?? [];
102
104
  const newMessages = convertFromAnthropicMessage([message]);
@@ -122,22 +124,24 @@ export class StreamManager {
122
124
  ? block.input.description.split(" ")[0]
123
125
  : null) ||
124
126
  "unknown-agent";
125
- this.tools[block.id] ??= this.createChild("root", {
126
- name,
127
- run_type: "chain",
128
- inputs: block.input,
129
- start_time: eventTime,
130
- });
127
+ this.tools[block.id] ??=
128
+ this.createChild("root", {
129
+ name,
130
+ run_type: "chain",
131
+ inputs: block.input,
132
+ start_time: eventTime,
133
+ }) ?? this.tools[block.id];
131
134
  this.namespaces[block.id] ??= this.tools[block.id];
132
135
  }
133
136
  else {
134
137
  const name = block.name || "unknown-tool";
135
- this.tools[block.id] ??= this.createChild(namespace, {
136
- name,
137
- run_type: "tool",
138
- inputs: block.input ? { input: block.input } : {},
139
- start_time: eventTime,
140
- });
138
+ this.tools[block.id] ??=
139
+ this.createChild(namespace, {
140
+ name,
141
+ run_type: "tool",
142
+ inputs: block.input ? { input: block.input } : {},
143
+ start_time: eventTime,
144
+ }) ?? this.tools[block.id];
141
145
  }
142
146
  }
143
147
  }
@@ -171,14 +175,16 @@ export class StreamManager {
171
175
  const toolError = "is_error" in block && block.is_error === true
172
176
  ? getToolError(result)
173
177
  : undefined;
174
- void this.tools[block.tool_use_id].end(toolOutput, toolError);
178
+ void this.tools[block.tool_use_id]?.end(toolOutput, toolError);
175
179
  }
176
180
  }
177
181
  }
178
182
  this.history[namespace].push(message);
179
183
  }
180
184
  createChild(namespace, args) {
181
- const runTree = this.namespaces[namespace].createChild(args);
185
+ const runTree = this.namespaces[namespace]?.createChild(args);
186
+ if (runTree == null)
187
+ return undefined;
182
188
  this.postRunQueue.push(runTree.postRun());
183
189
  this.runTrees.push(runTree);
184
190
  return runTree;
@@ -186,6 +192,8 @@ export class StreamManager {
186
192
  async finish() {
187
193
  // Clean up incomplete tools and subagent calls
188
194
  for (const tool of Object.values(this.tools)) {
195
+ if (tool == null)
196
+ continue;
189
197
  if (tool.outputs == null && tool.error == null) {
190
198
  void tool.end(undefined, "Run not completed (conversation ended)");
191
199
  }
@@ -89,7 +89,7 @@ function isToolResultBlock(block) {
89
89
  * @internal
90
90
  */
91
91
  function isTaskTool(tool) {
92
- return tool.type === "tool_use" && tool.name === "Task";
92
+ return (tool.type === "tool_use" && (tool.name === "Task" || tool.name === "Agent"));
93
93
  }
94
94
  /**
95
95
  * Type-assertion to check for tool blocks
@@ -83,7 +83,7 @@ function isToolResultBlock(block) {
83
83
  * @internal
84
84
  */
85
85
  export function isTaskTool(tool) {
86
- return tool.type === "tool_use" && tool.name === "Task";
86
+ return (tool.type === "tool_use" && (tool.name === "Task" || tool.name === "Agent"));
87
87
  }
88
88
  /**
89
89
  * Type-assertion to check for tool blocks
@@ -192,23 +192,33 @@ function LangSmithMiddleware(config) {
192
192
  try {
193
193
  const output = chunks.reduce((aggregated, chunk) => {
194
194
  if (chunk.type === "text-delta") {
195
+ if (aggregated.content.at(-1)?.type !== "text") {
196
+ aggregated.content.push({ type: "text", text: "" });
197
+ }
198
+ const contentBlock = aggregated.content.at(-1);
195
199
  if (chunk.delta != null) {
196
- return {
197
- ...aggregated,
198
- content: aggregated.content + chunk.delta,
199
- };
200
+ contentBlock.text += chunk.delta;
200
201
  }
201
202
  else if ("textDelta" in chunk &&
202
203
  chunk.textDelta != null) {
203
204
  // AI SDK 4 shim
204
- return {
205
- ...aggregated,
206
- content: aggregated.content + chunk.textDelta,
207
- };
205
+ contentBlock.text += chunk.textDelta;
208
206
  }
209
- else {
210
- return aggregated;
207
+ return aggregated;
208
+ }
209
+ else if (chunk.type === "reasoning-delta") {
210
+ if (aggregated.content.at(-1)?.type !== "reasoning") {
211
+ aggregated.content.push({
212
+ type: "reasoning",
213
+ reasoning: "",
214
+ extras: chunk.providerMetadata,
215
+ });
211
216
  }
217
+ const reasoningBlock = aggregated.content.at(-1);
218
+ if (chunk.delta != null) {
219
+ reasoningBlock.reasoning += chunk.delta;
220
+ }
221
+ return aggregated;
212
222
  }
213
223
  else if (chunk.type === "tool-call") {
214
224
  const matchingToolCall = aggregated.tool_calls.find((call) => call.id === chunk.toolCallId);
@@ -250,7 +260,7 @@ function LangSmithMiddleware(config) {
250
260
  return aggregated;
251
261
  }
252
262
  }, {
253
- content: "",
263
+ content: [],
254
264
  role: "assistant",
255
265
  tool_calls: [],
256
266
  });
@@ -260,6 +270,12 @@ function LangSmithMiddleware(config) {
260
270
  request: rest.request,
261
271
  response: rest.response,
262
272
  };
273
+ if ("content" in outputForTracing &&
274
+ Array.isArray(outputForTracing.content) &&
275
+ outputForTracing.content.length === 1 &&
276
+ outputForTracing.content[0].type === "text") {
277
+ outputForTracing.content = outputForTracing.content[0].text;
278
+ }
263
279
  let formattedOutputs;
264
280
  if (lsConfig?.processOutputs) {
265
281
  formattedOutputs = await lsConfig.processOutputs(outputForTracing);
@@ -1,7 +1,16 @@
1
1
  import type { LanguageModelV2Middleware, SharedV2ProviderMetadata, LanguageModelV2FinishReason } from "@ai-sdk/provider";
2
2
  import type { RunTreeConfig } from "../../run_trees.js";
3
+ type StandardTextBlock = {
4
+ type: "text";
5
+ text: string;
6
+ };
7
+ type StandardReasoningBlock = {
8
+ type: "reasoning";
9
+ reasoning: string;
10
+ extras?: Record<string, unknown>;
11
+ };
3
12
  export type AggregatedDoStreamOutput = {
4
- content: string;
13
+ content: (StandardReasoningBlock | StandardTextBlock)[];
5
14
  role: "assistant";
6
15
  tool_calls: {
7
16
  id: string;
@@ -26,3 +35,4 @@ export declare function LangSmithMiddleware(config?: {
26
35
  traceRawHttp?: boolean;
27
36
  };
28
37
  }): LanguageModelV2Middleware;
38
+ export {};
@@ -189,23 +189,33 @@ export function LangSmithMiddleware(config) {
189
189
  try {
190
190
  const output = chunks.reduce((aggregated, chunk) => {
191
191
  if (chunk.type === "text-delta") {
192
+ if (aggregated.content.at(-1)?.type !== "text") {
193
+ aggregated.content.push({ type: "text", text: "" });
194
+ }
195
+ const contentBlock = aggregated.content.at(-1);
192
196
  if (chunk.delta != null) {
193
- return {
194
- ...aggregated,
195
- content: aggregated.content + chunk.delta,
196
- };
197
+ contentBlock.text += chunk.delta;
197
198
  }
198
199
  else if ("textDelta" in chunk &&
199
200
  chunk.textDelta != null) {
200
201
  // AI SDK 4 shim
201
- return {
202
- ...aggregated,
203
- content: aggregated.content + chunk.textDelta,
204
- };
202
+ contentBlock.text += chunk.textDelta;
205
203
  }
206
- else {
207
- return aggregated;
204
+ return aggregated;
205
+ }
206
+ else if (chunk.type === "reasoning-delta") {
207
+ if (aggregated.content.at(-1)?.type !== "reasoning") {
208
+ aggregated.content.push({
209
+ type: "reasoning",
210
+ reasoning: "",
211
+ extras: chunk.providerMetadata,
212
+ });
208
213
  }
214
+ const reasoningBlock = aggregated.content.at(-1);
215
+ if (chunk.delta != null) {
216
+ reasoningBlock.reasoning += chunk.delta;
217
+ }
218
+ return aggregated;
209
219
  }
210
220
  else if (chunk.type === "tool-call") {
211
221
  const matchingToolCall = aggregated.tool_calls.find((call) => call.id === chunk.toolCallId);
@@ -247,7 +257,7 @@ export function LangSmithMiddleware(config) {
247
257
  return aggregated;
248
258
  }
249
259
  }, {
250
- content: "",
260
+ content: [],
251
261
  role: "assistant",
252
262
  tool_calls: [],
253
263
  });
@@ -257,6 +267,12 @@ export function LangSmithMiddleware(config) {
257
267
  request: rest.request,
258
268
  response: rest.response,
259
269
  };
270
+ if ("content" in outputForTracing &&
271
+ Array.isArray(outputForTracing.content) &&
272
+ outputForTracing.content.length === 1 &&
273
+ outputForTracing.content[0].type === "text") {
274
+ outputForTracing.content = outputForTracing.content[0].text;
275
+ }
260
276
  let formattedOutputs;
261
277
  if (lsConfig?.processOutputs) {
262
278
  formattedOutputs = await lsConfig.processOutputs(outputForTracing);
package/dist/index.cjs CHANGED
@@ -18,4 +18,4 @@ Object.defineProperty(exports, "PromptCache", { enumerable: true, get: function
18
18
  Object.defineProperty(exports, "configureGlobalPromptCache", { enumerable: true, get: function () { return index_js_1.configureGlobalPromptCache; } });
19
19
  Object.defineProperty(exports, "promptCacheSingleton", { enumerable: true, get: function () { return index_js_1.promptCacheSingleton; } });
20
20
  // Update using yarn bump-version
21
- exports.__version__ = "0.5.12";
21
+ exports.__version__ = "0.5.14";
package/dist/index.d.ts CHANGED
@@ -5,4 +5,4 @@ export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
6
  export { uuid7, uuid7FromTime } from "./uuid.js";
7
7
  export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
8
- export declare const __version__ = "0.5.12";
8
+ export declare const __version__ = "0.5.14";
package/dist/index.js CHANGED
@@ -5,4 +5,4 @@ export { getDefaultProjectName } from "./utils/project.js";
5
5
  export { uuid7, uuid7FromTime } from "./uuid.js";
6
6
  export { Cache, PromptCache, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
7
7
  // Update using yarn bump-version
8
- export const __version__ = "0.5.12";
8
+ export const __version__ = "0.5.14";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.5.12",
3
+ "version": "0.5.14",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "yarn@1.22.19",
6
6
  "files": [
@@ -156,7 +156,7 @@
156
156
  "@ai-sdk/anthropic": "^3.0.0",
157
157
  "@ai-sdk/openai": "^3.0.0",
158
158
  "@ai-sdk/provider": "^3.0.0",
159
- "@anthropic-ai/claude-agent-sdk": "^0.2.34",
159
+ "@anthropic-ai/claude-agent-sdk": "^0.2.83",
160
160
  "@anthropic-ai/sdk": "^0.78.0",
161
161
  "@babel/preset-env": "^7.22.4",
162
162
  "@faker-js/faker": "^8.4.1",