langsmith 0.3.82 → 0.3.83-rc.1

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/dist/index.cjs CHANGED
@@ -13,4 +13,4 @@ var uuid_js_1 = require("./uuid.cjs");
13
13
  Object.defineProperty(exports, "uuid7", { enumerable: true, get: function () { return uuid_js_1.uuid7; } });
14
14
  Object.defineProperty(exports, "uuid7FromTime", { enumerable: true, get: function () { return uuid_js_1.uuid7FromTime; } });
15
15
  // Update using yarn bump-version
16
- exports.__version__ = "0.3.82";
16
+ exports.__version__ = "0.3.83-rc.1";
package/dist/index.d.ts CHANGED
@@ -4,4 +4,4 @@ export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
4
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
6
  export { uuid7, uuid7FromTime } from "./uuid.js";
7
- export declare const __version__ = "0.3.82";
7
+ export declare const __version__ = "0.3.83-rc.1";
package/dist/index.js CHANGED
@@ -4,4 +4,4 @@ export { overrideFetchImplementation } from "./singletons/fetch.js";
4
4
  export { getDefaultProjectName } from "./utils/project.js";
5
5
  export { uuid7, uuid7FromTime } from "./uuid.js";
6
6
  // Update using yarn bump-version
7
- export const __version__ = "0.3.82";
7
+ export const __version__ = "0.3.83-rc.1";
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wrapAnthropic = void 0;
4
+ const traceable_js_1 = require("../traceable.cjs");
5
+ const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
6
+ /**
7
+ * Create usage metadata from Anthropic's token usage format.
8
+ */
9
+ function createUsageMetadata(anthropicUsage) {
10
+ if (!anthropicUsage) {
11
+ return undefined;
12
+ }
13
+ const inputTokens = anthropicUsage.input_tokens ?? 0;
14
+ const outputTokens = anthropicUsage.output_tokens ?? 0;
15
+ const totalTokens = inputTokens + outputTokens;
16
+ // Anthropic provides cache tokens separately
17
+ const cacheReadTokens = anthropicUsage.cache_read_input_tokens ?? 0;
18
+ const cacheCreationTokens = anthropicUsage.cache_creation_input_tokens ?? 0;
19
+ const inputTokenDetails = {};
20
+ if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
21
+ inputTokenDetails.cache_read = cacheReadTokens + cacheCreationTokens;
22
+ }
23
+ return {
24
+ input_tokens: inputTokens,
25
+ output_tokens: outputTokens,
26
+ total_tokens: totalTokens,
27
+ ...(Object.keys(inputTokenDetails).length > 0 && {
28
+ input_token_details: inputTokenDetails,
29
+ }),
30
+ };
31
+ }
32
+ /**
33
+ * Process Anthropic message outputs
34
+ */
35
+ function processMessageOutput(outputs) {
36
+ const message = outputs;
37
+ const result = { ...message };
38
+ delete result.type;
39
+ if (message.usage) {
40
+ result.usage_metadata = createUsageMetadata(message.usage);
41
+ delete result.usage;
42
+ }
43
+ return result;
44
+ }
45
+ /**
46
+ * Accumulate a single content block delta into the content array.
47
+ */
48
+ function accumulateContentBlockDelta(content, event) {
49
+ const block = content[event.index];
50
+ if (!block)
51
+ return;
52
+ if (block.type === "text" && event.delta.type === "text_delta") {
53
+ block.text += event.delta.text;
54
+ }
55
+ else if (block.type === "tool_use" &&
56
+ event.delta.type === "input_json_delta") {
57
+ // Accumulate JSON input for tool use
58
+ const toolBlock = block;
59
+ toolBlock._partial_json =
60
+ (toolBlock._partial_json ?? "") + event.delta.partial_json;
61
+ }
62
+ }
63
+ /**
64
+ * Aggregate streaming chunks into a complete message response
65
+ */
66
+ const messageAggregator = (chunks) => {
67
+ if (!chunks || chunks.length === 0) {
68
+ return {
69
+ role: "assistant",
70
+ content: [],
71
+ };
72
+ }
73
+ let message = {
74
+ role: "assistant",
75
+ content: [],
76
+ model: "",
77
+ stop_reason: null,
78
+ stop_sequence: null,
79
+ };
80
+ // Track usage
81
+ let usage = {
82
+ input_tokens: 0,
83
+ output_tokens: 0,
84
+ };
85
+ for (const chunk of chunks) {
86
+ switch (chunk.type) {
87
+ case "message_start":
88
+ // Initialize message
89
+ message = {
90
+ id: chunk.message.id,
91
+ role: chunk.message.role,
92
+ content: [],
93
+ model: chunk.message.model,
94
+ stop_reason: chunk.message.stop_reason,
95
+ stop_sequence: chunk.message.stop_sequence,
96
+ };
97
+ // Capture initial usage
98
+ if (chunk.message.usage) {
99
+ usage = {
100
+ input_tokens: chunk.message.usage.input_tokens,
101
+ output_tokens: chunk.message.usage.output_tokens,
102
+ cache_read_input_tokens: chunk.message.usage.cache_read_input_tokens,
103
+ cache_creation_input_tokens: chunk.message.usage.cache_creation_input_tokens,
104
+ };
105
+ }
106
+ break;
107
+ case "content_block_start":
108
+ // Add new content block
109
+ if (message.content) {
110
+ message.content[chunk.index] =
111
+ chunk.content_block;
112
+ }
113
+ break;
114
+ case "content_block_delta":
115
+ // Accumulate delta
116
+ if (message.content) {
117
+ accumulateContentBlockDelta(message.content, chunk);
118
+ }
119
+ break;
120
+ case "content_block_stop":
121
+ // Finalize content block
122
+ if (message.content) {
123
+ const block = message.content[chunk.index];
124
+ if (block?.type === "tool_use") {
125
+ const toolBlock = block;
126
+ if (toolBlock._partial_json) {
127
+ try {
128
+ toolBlock.input = JSON.parse(toolBlock._partial_json);
129
+ }
130
+ catch {
131
+ // Keep partial JSON as-is if parsing fails
132
+ toolBlock.input = toolBlock._partial_json;
133
+ }
134
+ delete toolBlock._partial_json;
135
+ }
136
+ }
137
+ }
138
+ break;
139
+ case "message_delta":
140
+ // Update message metadata
141
+ message.stop_reason = chunk.delta.stop_reason;
142
+ message.stop_sequence = chunk.delta.stop_sequence ?? null;
143
+ if (chunk.usage) {
144
+ usage.output_tokens = chunk.usage.output_tokens;
145
+ }
146
+ break;
147
+ case "message_stop":
148
+ // Message complete
149
+ break;
150
+ }
151
+ }
152
+ // Build final output
153
+ const result = {
154
+ ...message,
155
+ };
156
+ delete result.type;
157
+ // Add usage metadata
158
+ result.usage_metadata = createUsageMetadata(usage);
159
+ return result;
160
+ };
161
+ /**
162
+ * Wraps an Anthropic client's completion methods, enabling automatic LangSmith
163
+ * tracing. Method signatures are unchanged, with the exception that you can pass
164
+ * an additional and optional "langsmithExtra" field within the second parameter.
165
+ *
166
+ * @param anthropic An Anthropic client instance.
167
+ * @param options LangSmith options.
168
+ * @returns The wrapped client.
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * import Anthropic from "@anthropic-ai/sdk";
173
+ * import { wrapAnthropic } from "langsmith/wrappers/anthropic";
174
+ *
175
+ * const anthropic = wrapAnthropic(new Anthropic());
176
+ *
177
+ * // Non-streaming
178
+ * const message = await anthropic.messages.create({
179
+ * model: "claude-sonnet-4-20250514",
180
+ * max_tokens: 1024,
181
+ * messages: [{ role: "user", content: "Hello!" }],
182
+ * });
183
+ *
184
+ * // Streaming with create()
185
+ * const stream = await anthropic.messages.create({
186
+ * model: "claude-sonnet-4-20250514",
187
+ * max_tokens: 1024,
188
+ * messages: [{ role: "user", content: "Hello!" }],
189
+ * stream: true,
190
+ * });
191
+ * for await (const event of stream) {
192
+ * // process events
193
+ * }
194
+ *
195
+ * // Streaming with stream()
196
+ * const messageStream = anthropic.messages.stream({
197
+ * model: "claude-sonnet-4-20250514",
198
+ * max_tokens: 1024,
199
+ * messages: [{ role: "user", content: "Hello!" }],
200
+ * });
201
+ * for await (const event of messageStream) {
202
+ * // process events
203
+ * }
204
+ * const finalMessage = await messageStream.finalMessage();
205
+ * ```
206
+ */
207
+ const wrapAnthropic = (anthropic, options) => {
208
+ if ((0, traceable_js_1.isTraceableFunction)(anthropic.messages.create) ||
209
+ (0, traceable_js_1.isTraceableFunction)(anthropic.messages.stream)) {
210
+ throw new Error("This instance of Anthropic client has been already wrapped once.");
211
+ }
212
+ const tracedAnthropicClient = { ...anthropic };
213
+ // Common configuration for messages.create
214
+ const messagesCreateConfig = {
215
+ name: "ChatAnthropic",
216
+ run_type: "llm",
217
+ aggregator: messageAggregator,
218
+ argsConfigPath: [1, "langsmithExtra"],
219
+ getInvocationParams: (payload) => {
220
+ if (typeof payload !== "object" || payload == null)
221
+ return undefined;
222
+ const params = payload;
223
+ const ls_stop = (typeof params.stop_sequences === "string"
224
+ ? [params.stop_sequences]
225
+ : params.stop_sequences) ?? undefined;
226
+ const ls_invocation_params = {};
227
+ for (const [key, value] of Object.entries(params)) {
228
+ if (TRACED_INVOCATION_KEYS.includes(key)) {
229
+ ls_invocation_params[key] = value;
230
+ }
231
+ }
232
+ return {
233
+ ls_provider: "anthropic",
234
+ ls_model_type: "chat",
235
+ ls_model_name: params.model,
236
+ ls_max_tokens: params.max_tokens ?? undefined,
237
+ ls_temperature: params.temperature ?? undefined,
238
+ ls_stop,
239
+ ls_invocation_params,
240
+ };
241
+ },
242
+ processOutputs: processMessageOutput,
243
+ ...options,
244
+ };
245
+ // Create a new messages object preserving the prototype
246
+ tracedAnthropicClient.messages = Object.create(Object.getPrototypeOf(anthropic.messages));
247
+ // Copy all own properties
248
+ Object.assign(tracedAnthropicClient.messages, anthropic.messages);
249
+ // Wrap messages.create
250
+ tracedAnthropicClient.messages.create = (0, traceable_js_1.traceable)(anthropic.messages.create.bind(anthropic.messages), messagesCreateConfig);
251
+ // Wrap messages.stream
252
+ const originalStream = anthropic.messages.stream.bind(anthropic.messages);
253
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
+ const streamMethod = function (...args) {
255
+ const stream = originalStream(...args);
256
+ if ("finalMessage" in stream && typeof stream.finalMessage === "function") {
257
+ const originalFinalMessage = stream.finalMessage.bind(stream);
258
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
259
+ stream.finalMessage = async (...args) => {
260
+ for await (const _ of stream) {
261
+ // consume chunks
262
+ }
263
+ return originalFinalMessage(...args);
264
+ };
265
+ }
266
+ return stream;
267
+ };
268
+ tracedAnthropicClient.messages.stream = (0, traceable_js_1.traceable)(streamMethod, {
269
+ name: "ChatAnthropic",
270
+ run_type: "llm",
271
+ aggregator: messageAggregator,
272
+ argsConfigPath: [1, "langsmithExtra"],
273
+ getInvocationParams: messagesCreateConfig.getInvocationParams,
274
+ processOutputs: processMessageOutput,
275
+ ...options,
276
+ });
277
+ // Wrap beta.messages if it exists
278
+ if (anthropic.beta &&
279
+ anthropic.beta.messages &&
280
+ typeof anthropic.beta.messages.create === "function") {
281
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
282
+ const tracedBeta = { ...anthropic.beta };
283
+ tracedBeta.messages = Object.create(Object.getPrototypeOf(anthropic.beta.messages));
284
+ Object.assign(tracedBeta.messages, anthropic.beta.messages);
285
+ // Wrap beta.messages.create
286
+ tracedBeta.messages.create = (0, traceable_js_1.traceable)(anthropic.beta.messages.create.bind(anthropic.beta.messages), messagesCreateConfig);
287
+ // Wrap beta.messages.stream if it exists
288
+ if (typeof anthropic.beta.messages.stream === "function") {
289
+ tracedBeta.messages.stream = (0, traceable_js_1.traceable)(anthropic.beta.messages.stream.bind(anthropic.beta.messages), {
290
+ name: "ChatAnthropic",
291
+ run_type: "llm",
292
+ aggregator: messageAggregator,
293
+ argsConfigPath: [1, "langsmithExtra"],
294
+ getInvocationParams: messagesCreateConfig.getInvocationParams,
295
+ processOutputs: processMessageOutput,
296
+ ...options,
297
+ });
298
+ }
299
+ tracedAnthropicClient.beta = tracedBeta;
300
+ }
301
+ return tracedAnthropicClient;
302
+ };
303
+ exports.wrapAnthropic = wrapAnthropic;
@@ -0,0 +1,81 @@
1
+ import type Anthropic from "@anthropic-ai/sdk";
2
+ import type { Stream } from "@anthropic-ai/sdk/streaming";
3
+ import type { MessageStream } from "@anthropic-ai/sdk/lib/MessageStream";
4
+ import type { RunTreeConfig } from "../index.js";
5
+ type ExtraRunTreeConfig = Pick<Partial<RunTreeConfig>, "name" | "metadata" | "tags">;
6
+ type MessagesNamespace = {
7
+ create: (...args: any[]) => any;
8
+ stream: (...args: any[]) => any;
9
+ };
10
+ type AnthropicType = {
11
+ messages: MessagesNamespace;
12
+ beta?: {
13
+ messages?: MessagesNamespace;
14
+ };
15
+ };
16
+ type PatchedAnthropicClient<T extends AnthropicType> = T & {
17
+ messages: T["messages"] & {
18
+ create: {
19
+ (arg: Anthropic.MessageCreateParamsStreaming, arg2?: Anthropic.RequestOptions & {
20
+ langsmithExtra?: ExtraRunTreeConfig;
21
+ }): Promise<Stream<Anthropic.MessageStreamEvent>>;
22
+ } & {
23
+ (arg: Anthropic.MessageCreateParamsNonStreaming, arg2?: Anthropic.RequestOptions & {
24
+ langsmithExtra?: ExtraRunTreeConfig;
25
+ }): Promise<Anthropic.Message>;
26
+ };
27
+ stream: {
28
+ (arg: Anthropic.MessageStreamParams, arg2?: Anthropic.RequestOptions & {
29
+ langsmithExtra?: ExtraRunTreeConfig;
30
+ }): MessageStream;
31
+ };
32
+ };
33
+ };
34
+ /**
35
+ * Wraps an Anthropic client's completion methods, enabling automatic LangSmith
36
+ * tracing. Method signatures are unchanged, with the exception that you can pass
37
+ * an additional and optional "langsmithExtra" field within the second parameter.
38
+ *
39
+ * @param anthropic An Anthropic client instance.
40
+ * @param options LangSmith options.
41
+ * @returns The wrapped client.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import Anthropic from "@anthropic-ai/sdk";
46
+ * import { wrapAnthropic } from "langsmith/wrappers/anthropic";
47
+ *
48
+ * const anthropic = wrapAnthropic(new Anthropic());
49
+ *
50
+ * // Non-streaming
51
+ * const message = await anthropic.messages.create({
52
+ * model: "claude-sonnet-4-20250514",
53
+ * max_tokens: 1024,
54
+ * messages: [{ role: "user", content: "Hello!" }],
55
+ * });
56
+ *
57
+ * // Streaming with create()
58
+ * const stream = await anthropic.messages.create({
59
+ * model: "claude-sonnet-4-20250514",
60
+ * max_tokens: 1024,
61
+ * messages: [{ role: "user", content: "Hello!" }],
62
+ * stream: true,
63
+ * });
64
+ * for await (const event of stream) {
65
+ * // process events
66
+ * }
67
+ *
68
+ * // Streaming with stream()
69
+ * const messageStream = anthropic.messages.stream({
70
+ * model: "claude-sonnet-4-20250514",
71
+ * max_tokens: 1024,
72
+ * messages: [{ role: "user", content: "Hello!" }],
73
+ * });
74
+ * for await (const event of messageStream) {
75
+ * // process events
76
+ * }
77
+ * const finalMessage = await messageStream.finalMessage();
78
+ * ```
79
+ */
80
+ export declare const wrapAnthropic: <T extends AnthropicType>(anthropic: T, options?: Partial<RunTreeConfig>) => PatchedAnthropicClient<T>;
81
+ export {};
@@ -0,0 +1,299 @@
1
+ import { isTraceableFunction, traceable, } from "../traceable.js";
2
+ const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
3
+ /**
4
+ * Create usage metadata from Anthropic's token usage format.
5
+ */
6
+ function createUsageMetadata(anthropicUsage) {
7
+ if (!anthropicUsage) {
8
+ return undefined;
9
+ }
10
+ const inputTokens = anthropicUsage.input_tokens ?? 0;
11
+ const outputTokens = anthropicUsage.output_tokens ?? 0;
12
+ const totalTokens = inputTokens + outputTokens;
13
+ // Anthropic provides cache tokens separately
14
+ const cacheReadTokens = anthropicUsage.cache_read_input_tokens ?? 0;
15
+ const cacheCreationTokens = anthropicUsage.cache_creation_input_tokens ?? 0;
16
+ const inputTokenDetails = {};
17
+ if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
18
+ inputTokenDetails.cache_read = cacheReadTokens + cacheCreationTokens;
19
+ }
20
+ return {
21
+ input_tokens: inputTokens,
22
+ output_tokens: outputTokens,
23
+ total_tokens: totalTokens,
24
+ ...(Object.keys(inputTokenDetails).length > 0 && {
25
+ input_token_details: inputTokenDetails,
26
+ }),
27
+ };
28
+ }
29
+ /**
30
+ * Process Anthropic message outputs
31
+ */
32
+ function processMessageOutput(outputs) {
33
+ const message = outputs;
34
+ const result = { ...message };
35
+ delete result.type;
36
+ if (message.usage) {
37
+ result.usage_metadata = createUsageMetadata(message.usage);
38
+ delete result.usage;
39
+ }
40
+ return result;
41
+ }
42
+ /**
43
+ * Accumulate a single content block delta into the content array.
44
+ */
45
+ function accumulateContentBlockDelta(content, event) {
46
+ const block = content[event.index];
47
+ if (!block)
48
+ return;
49
+ if (block.type === "text" && event.delta.type === "text_delta") {
50
+ block.text += event.delta.text;
51
+ }
52
+ else if (block.type === "tool_use" &&
53
+ event.delta.type === "input_json_delta") {
54
+ // Accumulate JSON input for tool use
55
+ const toolBlock = block;
56
+ toolBlock._partial_json =
57
+ (toolBlock._partial_json ?? "") + event.delta.partial_json;
58
+ }
59
+ }
60
+ /**
61
+ * Aggregate streaming chunks into a complete message response
62
+ */
63
+ const messageAggregator = (chunks) => {
64
+ if (!chunks || chunks.length === 0) {
65
+ return {
66
+ role: "assistant",
67
+ content: [],
68
+ };
69
+ }
70
+ let message = {
71
+ role: "assistant",
72
+ content: [],
73
+ model: "",
74
+ stop_reason: null,
75
+ stop_sequence: null,
76
+ };
77
+ // Track usage
78
+ let usage = {
79
+ input_tokens: 0,
80
+ output_tokens: 0,
81
+ };
82
+ for (const chunk of chunks) {
83
+ switch (chunk.type) {
84
+ case "message_start":
85
+ // Initialize message
86
+ message = {
87
+ id: chunk.message.id,
88
+ role: chunk.message.role,
89
+ content: [],
90
+ model: chunk.message.model,
91
+ stop_reason: chunk.message.stop_reason,
92
+ stop_sequence: chunk.message.stop_sequence,
93
+ };
94
+ // Capture initial usage
95
+ if (chunk.message.usage) {
96
+ usage = {
97
+ input_tokens: chunk.message.usage.input_tokens,
98
+ output_tokens: chunk.message.usage.output_tokens,
99
+ cache_read_input_tokens: chunk.message.usage.cache_read_input_tokens,
100
+ cache_creation_input_tokens: chunk.message.usage.cache_creation_input_tokens,
101
+ };
102
+ }
103
+ break;
104
+ case "content_block_start":
105
+ // Add new content block
106
+ if (message.content) {
107
+ message.content[chunk.index] =
108
+ chunk.content_block;
109
+ }
110
+ break;
111
+ case "content_block_delta":
112
+ // Accumulate delta
113
+ if (message.content) {
114
+ accumulateContentBlockDelta(message.content, chunk);
115
+ }
116
+ break;
117
+ case "content_block_stop":
118
+ // Finalize content block
119
+ if (message.content) {
120
+ const block = message.content[chunk.index];
121
+ if (block?.type === "tool_use") {
122
+ const toolBlock = block;
123
+ if (toolBlock._partial_json) {
124
+ try {
125
+ toolBlock.input = JSON.parse(toolBlock._partial_json);
126
+ }
127
+ catch {
128
+ // Keep partial JSON as-is if parsing fails
129
+ toolBlock.input = toolBlock._partial_json;
130
+ }
131
+ delete toolBlock._partial_json;
132
+ }
133
+ }
134
+ }
135
+ break;
136
+ case "message_delta":
137
+ // Update message metadata
138
+ message.stop_reason = chunk.delta.stop_reason;
139
+ message.stop_sequence = chunk.delta.stop_sequence ?? null;
140
+ if (chunk.usage) {
141
+ usage.output_tokens = chunk.usage.output_tokens;
142
+ }
143
+ break;
144
+ case "message_stop":
145
+ // Message complete
146
+ break;
147
+ }
148
+ }
149
+ // Build final output
150
+ const result = {
151
+ ...message,
152
+ };
153
+ delete result.type;
154
+ // Add usage metadata
155
+ result.usage_metadata = createUsageMetadata(usage);
156
+ return result;
157
+ };
158
+ /**
159
+ * Wraps an Anthropic client's completion methods, enabling automatic LangSmith
160
+ * tracing. Method signatures are unchanged, with the exception that you can pass
161
+ * an additional and optional "langsmithExtra" field within the second parameter.
162
+ *
163
+ * @param anthropic An Anthropic client instance.
164
+ * @param options LangSmith options.
165
+ * @returns The wrapped client.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * import Anthropic from "@anthropic-ai/sdk";
170
+ * import { wrapAnthropic } from "langsmith/wrappers/anthropic";
171
+ *
172
+ * const anthropic = wrapAnthropic(new Anthropic());
173
+ *
174
+ * // Non-streaming
175
+ * const message = await anthropic.messages.create({
176
+ * model: "claude-sonnet-4-20250514",
177
+ * max_tokens: 1024,
178
+ * messages: [{ role: "user", content: "Hello!" }],
179
+ * });
180
+ *
181
+ * // Streaming with create()
182
+ * const stream = await anthropic.messages.create({
183
+ * model: "claude-sonnet-4-20250514",
184
+ * max_tokens: 1024,
185
+ * messages: [{ role: "user", content: "Hello!" }],
186
+ * stream: true,
187
+ * });
188
+ * for await (const event of stream) {
189
+ * // process events
190
+ * }
191
+ *
192
+ * // Streaming with stream()
193
+ * const messageStream = anthropic.messages.stream({
194
+ * model: "claude-sonnet-4-20250514",
195
+ * max_tokens: 1024,
196
+ * messages: [{ role: "user", content: "Hello!" }],
197
+ * });
198
+ * for await (const event of messageStream) {
199
+ * // process events
200
+ * }
201
+ * const finalMessage = await messageStream.finalMessage();
202
+ * ```
203
+ */
204
+ export const wrapAnthropic = (anthropic, options) => {
205
+ if (isTraceableFunction(anthropic.messages.create) ||
206
+ isTraceableFunction(anthropic.messages.stream)) {
207
+ throw new Error("This instance of Anthropic client has been already wrapped once.");
208
+ }
209
+ const tracedAnthropicClient = { ...anthropic };
210
+ // Common configuration for messages.create
211
+ const messagesCreateConfig = {
212
+ name: "ChatAnthropic",
213
+ run_type: "llm",
214
+ aggregator: messageAggregator,
215
+ argsConfigPath: [1, "langsmithExtra"],
216
+ getInvocationParams: (payload) => {
217
+ if (typeof payload !== "object" || payload == null)
218
+ return undefined;
219
+ const params = payload;
220
+ const ls_stop = (typeof params.stop_sequences === "string"
221
+ ? [params.stop_sequences]
222
+ : params.stop_sequences) ?? undefined;
223
+ const ls_invocation_params = {};
224
+ for (const [key, value] of Object.entries(params)) {
225
+ if (TRACED_INVOCATION_KEYS.includes(key)) {
226
+ ls_invocation_params[key] = value;
227
+ }
228
+ }
229
+ return {
230
+ ls_provider: "anthropic",
231
+ ls_model_type: "chat",
232
+ ls_model_name: params.model,
233
+ ls_max_tokens: params.max_tokens ?? undefined,
234
+ ls_temperature: params.temperature ?? undefined,
235
+ ls_stop,
236
+ ls_invocation_params,
237
+ };
238
+ },
239
+ processOutputs: processMessageOutput,
240
+ ...options,
241
+ };
242
+ // Create a new messages object preserving the prototype
243
+ tracedAnthropicClient.messages = Object.create(Object.getPrototypeOf(anthropic.messages));
244
+ // Copy all own properties
245
+ Object.assign(tracedAnthropicClient.messages, anthropic.messages);
246
+ // Wrap messages.create
247
+ tracedAnthropicClient.messages.create = traceable(anthropic.messages.create.bind(anthropic.messages), messagesCreateConfig);
248
+ // Wrap messages.stream
249
+ const originalStream = anthropic.messages.stream.bind(anthropic.messages);
250
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
251
+ const streamMethod = function (...args) {
252
+ const stream = originalStream(...args);
253
+ if ("finalMessage" in stream && typeof stream.finalMessage === "function") {
254
+ const originalFinalMessage = stream.finalMessage.bind(stream);
255
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
+ stream.finalMessage = async (...args) => {
257
+ for await (const _ of stream) {
258
+ // consume chunks
259
+ }
260
+ return originalFinalMessage(...args);
261
+ };
262
+ }
263
+ return stream;
264
+ };
265
+ tracedAnthropicClient.messages.stream = traceable(streamMethod, {
266
+ name: "ChatAnthropic",
267
+ run_type: "llm",
268
+ aggregator: messageAggregator,
269
+ argsConfigPath: [1, "langsmithExtra"],
270
+ getInvocationParams: messagesCreateConfig.getInvocationParams,
271
+ processOutputs: processMessageOutput,
272
+ ...options,
273
+ });
274
+ // Wrap beta.messages if it exists
275
+ if (anthropic.beta &&
276
+ anthropic.beta.messages &&
277
+ typeof anthropic.beta.messages.create === "function") {
278
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
279
+ const tracedBeta = { ...anthropic.beta };
280
+ tracedBeta.messages = Object.create(Object.getPrototypeOf(anthropic.beta.messages));
281
+ Object.assign(tracedBeta.messages, anthropic.beta.messages);
282
+ // Wrap beta.messages.create
283
+ tracedBeta.messages.create = traceable(anthropic.beta.messages.create.bind(anthropic.beta.messages), messagesCreateConfig);
284
+ // Wrap beta.messages.stream if it exists
285
+ if (typeof anthropic.beta.messages.stream === "function") {
286
+ tracedBeta.messages.stream = traceable(anthropic.beta.messages.stream.bind(anthropic.beta.messages), {
287
+ name: "ChatAnthropic",
288
+ run_type: "llm",
289
+ aggregator: messageAggregator,
290
+ argsConfigPath: [1, "langsmithExtra"],
291
+ getInvocationParams: messagesCreateConfig.getInvocationParams,
292
+ processOutputs: processMessageOutput,
293
+ ...options,
294
+ });
295
+ }
296
+ tracedAnthropicClient.beta = tracedBeta;
297
+ }
298
+ return tracedAnthropicClient;
299
+ };
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.wrapSDK = void 0;
18
18
  __exportStar(require("./openai.cjs"), exports);
19
+ __exportStar(require("./anthropic.cjs"), exports);
19
20
  var generic_js_1 = require("./generic.cjs");
20
21
  Object.defineProperty(exports, "wrapSDK", { enumerable: true, get: function () { return generic_js_1.wrapSDK; } });
@@ -1,2 +1,3 @@
1
1
  export * from "./openai.js";
2
+ export * from "./anthropic.js";
2
3
  export { wrapSDK } from "./generic.js";
@@ -1,2 +1,3 @@
1
1
  export * from "./openai.js";
2
+ export * from "./anthropic.js";
2
3
  export { wrapSDK } from "./generic.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.82",
3
+ "version": "0.3.83-rc.1",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "yarn@1.22.19",
6
6
  "files": [
@@ -150,6 +150,7 @@
150
150
  "devDependencies": {
151
151
  "@ai-sdk/anthropic": "^2.0.17",
152
152
  "@ai-sdk/openai": "^2.0.23",
153
+ "@anthropic-ai/sdk": "^0.71.2",
153
154
  "@babel/preset-env": "^7.22.4",
154
155
  "@faker-js/faker": "^8.4.1",
155
156
  "@jest/globals": "^29.5.0",