langsmith 0.3.83-rc.0 → 0.3.83
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 +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/usage.cjs +29 -0
- package/dist/utils/usage.d.ts +1 -0
- package/dist/utils/usage.js +25 -0
- package/dist/utils/vercel.cjs +3 -22
- package/dist/utils/vercel.js +3 -22
- package/dist/wrappers/anthropic.cjs +45 -50
- package/dist/wrappers/anthropic.d.ts +1 -15
- package/dist/wrappers/anthropic.js +45 -50
- package/dist/wrappers/index.cjs +0 -1
- package/dist/wrappers/index.d.ts +0 -1
- package/dist/wrappers/index.js +0 -1
- package/package.json +14 -1
- package/wrappers/anthropic.cjs +1 -0
- package/wrappers/anthropic.d.cts +1 -0
- package/wrappers/anthropic.d.ts +1 -0
- package/wrappers/anthropic.js +1 -0
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.83
|
|
16
|
+
exports.__version__ = "0.3.83";
|
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.83
|
|
7
|
+
export declare const __version__ = "0.3.83";
|
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.83
|
|
7
|
+
export const __version__ = "0.3.83";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertAnthropicUsageToInputTokenDetails = void 0;
|
|
4
|
+
const convertAnthropicUsageToInputTokenDetails = (usage) => {
|
|
5
|
+
const inputTokenDetails = {};
|
|
6
|
+
if (usage.cache_creation != null &&
|
|
7
|
+
typeof usage.cache_creation === "object") {
|
|
8
|
+
const cacheCreation = usage.cache_creation;
|
|
9
|
+
if (typeof cacheCreation.ephemeral_5m_input_tokens === "number") {
|
|
10
|
+
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
11
|
+
cacheCreation.ephemeral_5m_input_tokens;
|
|
12
|
+
}
|
|
13
|
+
if (typeof cacheCreation.ephemeral_1h_input_tokens === "number") {
|
|
14
|
+
inputTokenDetails.ephemeral_1hr_input_tokens =
|
|
15
|
+
cacheCreation.ephemeral_1h_input_tokens;
|
|
16
|
+
}
|
|
17
|
+
// If cache_creation not returned (no beta header passed),
|
|
18
|
+
// fallback to assuming 5m cache tokens
|
|
19
|
+
}
|
|
20
|
+
else if (typeof usage.cache_creation_input_tokens === "number") {
|
|
21
|
+
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
22
|
+
usage.cache_creation_input_tokens;
|
|
23
|
+
}
|
|
24
|
+
if (typeof usage.cache_read_input_tokens === "number") {
|
|
25
|
+
inputTokenDetails.cache_read = usage.cache_read_input_tokens;
|
|
26
|
+
}
|
|
27
|
+
return inputTokenDetails;
|
|
28
|
+
};
|
|
29
|
+
exports.convertAnthropicUsageToInputTokenDetails = convertAnthropicUsageToInputTokenDetails;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const convertAnthropicUsageToInputTokenDetails: (usage: Record<string, unknown>) => Record<string, number>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const convertAnthropicUsageToInputTokenDetails = (usage) => {
|
|
2
|
+
const inputTokenDetails = {};
|
|
3
|
+
if (usage.cache_creation != null &&
|
|
4
|
+
typeof usage.cache_creation === "object") {
|
|
5
|
+
const cacheCreation = usage.cache_creation;
|
|
6
|
+
if (typeof cacheCreation.ephemeral_5m_input_tokens === "number") {
|
|
7
|
+
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
8
|
+
cacheCreation.ephemeral_5m_input_tokens;
|
|
9
|
+
}
|
|
10
|
+
if (typeof cacheCreation.ephemeral_1h_input_tokens === "number") {
|
|
11
|
+
inputTokenDetails.ephemeral_1hr_input_tokens =
|
|
12
|
+
cacheCreation.ephemeral_1h_input_tokens;
|
|
13
|
+
}
|
|
14
|
+
// If cache_creation not returned (no beta header passed),
|
|
15
|
+
// fallback to assuming 5m cache tokens
|
|
16
|
+
}
|
|
17
|
+
else if (typeof usage.cache_creation_input_tokens === "number") {
|
|
18
|
+
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
19
|
+
usage.cache_creation_input_tokens;
|
|
20
|
+
}
|
|
21
|
+
if (typeof usage.cache_read_input_tokens === "number") {
|
|
22
|
+
inputTokenDetails.cache_read = usage.cache_read_input_tokens;
|
|
23
|
+
}
|
|
24
|
+
return inputTokenDetails;
|
|
25
|
+
};
|
package/dist/utils/vercel.cjs
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.extractOutputTokenDetails = extractOutputTokenDetails;
|
|
4
4
|
exports.extractInputTokenDetails = extractInputTokenDetails;
|
|
5
5
|
exports.extractUsageMetadata = extractUsageMetadata;
|
|
6
|
+
const usage_js_1 = require("./usage.cjs");
|
|
6
7
|
function extractTraceableServiceTier(providerMetadata) {
|
|
7
8
|
if (providerMetadata?.openai != null &&
|
|
8
9
|
typeof providerMetadata.openai === "object") {
|
|
@@ -35,34 +36,14 @@ function extractOutputTokenDetails(usage, providerMetadata) {
|
|
|
35
36
|
return outputTokenDetails;
|
|
36
37
|
}
|
|
37
38
|
function extractInputTokenDetails(usage, providerMetadata) {
|
|
38
|
-
|
|
39
|
+
let inputTokenDetails = {};
|
|
39
40
|
if (providerMetadata?.anthropic != null &&
|
|
40
41
|
typeof providerMetadata?.anthropic === "object") {
|
|
41
42
|
const anthropic = providerMetadata.anthropic;
|
|
42
43
|
if (anthropic.usage != null && typeof anthropic.usage === "object") {
|
|
43
44
|
// Raw usage from Anthropic returned in AI SDK 5
|
|
44
45
|
const usage = anthropic.usage;
|
|
45
|
-
|
|
46
|
-
typeof usage.cache_creation === "object") {
|
|
47
|
-
const cacheCreation = usage.cache_creation;
|
|
48
|
-
if (typeof cacheCreation.ephemeral_5m_input_tokens === "number") {
|
|
49
|
-
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
50
|
-
cacheCreation.ephemeral_5m_input_tokens;
|
|
51
|
-
}
|
|
52
|
-
if (typeof cacheCreation.ephemeral_1h_input_tokens === "number") {
|
|
53
|
-
inputTokenDetails.ephemeral_1hr_input_tokens =
|
|
54
|
-
cacheCreation.ephemeral_1h_input_tokens;
|
|
55
|
-
}
|
|
56
|
-
// If cache_creation not returned (no beta header passed),
|
|
57
|
-
// fallback to assuming 5m cache tokens
|
|
58
|
-
}
|
|
59
|
-
else if (typeof usage.cache_creation_input_tokens === "number") {
|
|
60
|
-
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
61
|
-
usage.cache_creation_input_tokens;
|
|
62
|
-
}
|
|
63
|
-
if (typeof usage.cache_read_input_tokens === "number") {
|
|
64
|
-
inputTokenDetails.cache_read = usage.cache_read_input_tokens;
|
|
65
|
-
}
|
|
46
|
+
inputTokenDetails = (0, usage_js_1.convertAnthropicUsageToInputTokenDetails)(usage);
|
|
66
47
|
}
|
|
67
48
|
else {
|
|
68
49
|
// AI SDK 4 fields
|
package/dist/utils/vercel.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { convertAnthropicUsageToInputTokenDetails } from "./usage.js";
|
|
1
2
|
function extractTraceableServiceTier(providerMetadata) {
|
|
2
3
|
if (providerMetadata?.openai != null &&
|
|
3
4
|
typeof providerMetadata.openai === "object") {
|
|
@@ -30,34 +31,14 @@ export function extractOutputTokenDetails(usage, providerMetadata) {
|
|
|
30
31
|
return outputTokenDetails;
|
|
31
32
|
}
|
|
32
33
|
export function extractInputTokenDetails(usage, providerMetadata) {
|
|
33
|
-
|
|
34
|
+
let inputTokenDetails = {};
|
|
34
35
|
if (providerMetadata?.anthropic != null &&
|
|
35
36
|
typeof providerMetadata?.anthropic === "object") {
|
|
36
37
|
const anthropic = providerMetadata.anthropic;
|
|
37
38
|
if (anthropic.usage != null && typeof anthropic.usage === "object") {
|
|
38
39
|
// Raw usage from Anthropic returned in AI SDK 5
|
|
39
40
|
const usage = anthropic.usage;
|
|
40
|
-
|
|
41
|
-
typeof usage.cache_creation === "object") {
|
|
42
|
-
const cacheCreation = usage.cache_creation;
|
|
43
|
-
if (typeof cacheCreation.ephemeral_5m_input_tokens === "number") {
|
|
44
|
-
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
45
|
-
cacheCreation.ephemeral_5m_input_tokens;
|
|
46
|
-
}
|
|
47
|
-
if (typeof cacheCreation.ephemeral_1h_input_tokens === "number") {
|
|
48
|
-
inputTokenDetails.ephemeral_1hr_input_tokens =
|
|
49
|
-
cacheCreation.ephemeral_1h_input_tokens;
|
|
50
|
-
}
|
|
51
|
-
// If cache_creation not returned (no beta header passed),
|
|
52
|
-
// fallback to assuming 5m cache tokens
|
|
53
|
-
}
|
|
54
|
-
else if (typeof usage.cache_creation_input_tokens === "number") {
|
|
55
|
-
inputTokenDetails.ephemeral_5m_input_tokens =
|
|
56
|
-
usage.cache_creation_input_tokens;
|
|
57
|
-
}
|
|
58
|
-
if (typeof usage.cache_read_input_tokens === "number") {
|
|
59
|
-
inputTokenDetails.cache_read = usage.cache_read_input_tokens;
|
|
60
|
-
}
|
|
41
|
+
inputTokenDetails = convertAnthropicUsageToInputTokenDetails(usage);
|
|
61
42
|
}
|
|
62
43
|
else {
|
|
63
44
|
// AI SDK 4 fields
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.wrapAnthropic = void 0;
|
|
4
4
|
const traceable_js_1 = require("../traceable.cjs");
|
|
5
|
+
const usage_js_1 = require("../utils/usage.cjs");
|
|
5
6
|
const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
|
|
6
7
|
/**
|
|
7
8
|
* Create usage metadata from Anthropic's token usage format.
|
|
@@ -10,16 +11,16 @@ function createUsageMetadata(anthropicUsage) {
|
|
|
10
11
|
if (!anthropicUsage) {
|
|
11
12
|
return undefined;
|
|
12
13
|
}
|
|
13
|
-
const inputTokens = anthropicUsage.input_tokens
|
|
14
|
-
|
|
14
|
+
const inputTokens = typeof anthropicUsage.input_tokens === "number"
|
|
15
|
+
? anthropicUsage.input_tokens
|
|
16
|
+
: 0;
|
|
17
|
+
const outputTokens = typeof anthropicUsage.output_tokens === "number"
|
|
18
|
+
? anthropicUsage.output_tokens
|
|
19
|
+
: 0;
|
|
15
20
|
const totalTokens = inputTokens + outputTokens;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const inputTokenDetails = {};
|
|
20
|
-
if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
|
|
21
|
-
inputTokenDetails.cache_read = cacheReadTokens + cacheCreationTokens;
|
|
22
|
-
}
|
|
21
|
+
const inputTokenDetails = (0, usage_js_1.convertAnthropicUsageToInputTokenDetails)(
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
anthropicUsage);
|
|
23
24
|
return {
|
|
24
25
|
input_tokens: inputTokens,
|
|
25
26
|
output_tokens: outputTokens,
|
|
@@ -96,12 +97,7 @@ const messageAggregator = (chunks) => {
|
|
|
96
97
|
};
|
|
97
98
|
// Capture initial usage
|
|
98
99
|
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
|
-
};
|
|
100
|
+
usage = chunk.message.usage;
|
|
105
101
|
}
|
|
106
102
|
break;
|
|
107
103
|
case "content_block_start":
|
|
@@ -141,7 +137,12 @@ const messageAggregator = (chunks) => {
|
|
|
141
137
|
message.stop_reason = chunk.delta.stop_reason;
|
|
142
138
|
message.stop_sequence = chunk.delta.stop_sequence ?? null;
|
|
143
139
|
if (chunk.usage) {
|
|
144
|
-
|
|
140
|
+
// Override only non-null keys
|
|
141
|
+
for (const [key, value] of Object.entries(chunk.usage)) {
|
|
142
|
+
if (value != null) {
|
|
143
|
+
usage[key] = value;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
145
146
|
}
|
|
146
147
|
break;
|
|
147
148
|
case "message_stop":
|
|
@@ -181,26 +182,12 @@ const messageAggregator = (chunks) => {
|
|
|
181
182
|
* messages: [{ role: "user", content: "Hello!" }],
|
|
182
183
|
* });
|
|
183
184
|
*
|
|
184
|
-
* // Streaming
|
|
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()
|
|
185
|
+
* // Streaming
|
|
196
186
|
* const messageStream = anthropic.messages.stream({
|
|
197
187
|
* model: "claude-sonnet-4-20250514",
|
|
198
188
|
* max_tokens: 1024,
|
|
199
189
|
* messages: [{ role: "user", content: "Hello!" }],
|
|
200
190
|
* });
|
|
201
|
-
* for await (const event of messageStream) {
|
|
202
|
-
* // process events
|
|
203
|
-
* }
|
|
204
191
|
* const finalMessage = await messageStream.finalMessage();
|
|
205
192
|
* ```
|
|
206
193
|
*/
|
|
@@ -248,25 +235,33 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
248
235
|
Object.assign(tracedAnthropicClient.messages, anthropic.messages);
|
|
249
236
|
// Wrap messages.create
|
|
250
237
|
tracedAnthropicClient.messages.create = (0, traceable_js_1.traceable)(anthropic.messages.create.bind(anthropic.messages), messagesCreateConfig);
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
stream
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
238
|
+
// Shared function to wrap stream methods
|
|
239
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
240
|
+
const wrapStreamMethod = (originalStreamFn) => {
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
242
|
+
return function (...args) {
|
|
243
|
+
const stream = originalStreamFn(...args);
|
|
244
|
+
if ("finalMessage" in stream &&
|
|
245
|
+
typeof stream.finalMessage === "function") {
|
|
246
|
+
const originalFinalMessage = stream.finalMessage.bind(stream);
|
|
247
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
248
|
+
stream.finalMessage = async (...args) => {
|
|
249
|
+
if ("done" in stream && typeof stream.done === "function") {
|
|
250
|
+
await stream.done();
|
|
251
|
+
}
|
|
252
|
+
for await (const _ of stream) {
|
|
253
|
+
// Finish consuming the stream if it has not already been consumed
|
|
254
|
+
// It should be relatively uncommon to consume an iterator after calling
|
|
255
|
+
// .finalMessage()
|
|
256
|
+
}
|
|
257
|
+
return originalFinalMessage(...args);
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
return stream;
|
|
261
|
+
};
|
|
268
262
|
};
|
|
269
|
-
|
|
263
|
+
// Wrap messages.stream
|
|
264
|
+
tracedAnthropicClient.messages.stream = (0, traceable_js_1.traceable)(wrapStreamMethod(anthropic.messages.stream.bind(anthropic.messages)), {
|
|
270
265
|
name: "ChatAnthropic",
|
|
271
266
|
run_type: "llm",
|
|
272
267
|
aggregator: messageAggregator,
|
|
@@ -287,7 +282,7 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
287
282
|
tracedBeta.messages.create = (0, traceable_js_1.traceable)(anthropic.beta.messages.create.bind(anthropic.beta.messages), messagesCreateConfig);
|
|
288
283
|
// Wrap beta.messages.stream if it exists
|
|
289
284
|
if (typeof anthropic.beta.messages.stream === "function") {
|
|
290
|
-
tracedBeta.messages.stream = (0, traceable_js_1.traceable)(anthropic.beta.messages.stream.bind(anthropic.beta.messages), {
|
|
285
|
+
tracedBeta.messages.stream = (0, traceable_js_1.traceable)(wrapStreamMethod(anthropic.beta.messages.stream.bind(anthropic.beta.messages)), {
|
|
291
286
|
name: "ChatAnthropic",
|
|
292
287
|
run_type: "llm",
|
|
293
288
|
aggregator: messageAggregator,
|
|
@@ -54,26 +54,12 @@ type PatchedAnthropicClient<T extends AnthropicType> = T & {
|
|
|
54
54
|
* messages: [{ role: "user", content: "Hello!" }],
|
|
55
55
|
* });
|
|
56
56
|
*
|
|
57
|
-
* // Streaming
|
|
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()
|
|
57
|
+
* // Streaming
|
|
69
58
|
* const messageStream = anthropic.messages.stream({
|
|
70
59
|
* model: "claude-sonnet-4-20250514",
|
|
71
60
|
* max_tokens: 1024,
|
|
72
61
|
* messages: [{ role: "user", content: "Hello!" }],
|
|
73
62
|
* });
|
|
74
|
-
* for await (const event of messageStream) {
|
|
75
|
-
* // process events
|
|
76
|
-
* }
|
|
77
63
|
* const finalMessage = await messageStream.finalMessage();
|
|
78
64
|
* ```
|
|
79
65
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isTraceableFunction, traceable, } from "../traceable.js";
|
|
2
|
+
import { convertAnthropicUsageToInputTokenDetails } from "../utils/usage.js";
|
|
2
3
|
const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
|
|
3
4
|
/**
|
|
4
5
|
* Create usage metadata from Anthropic's token usage format.
|
|
@@ -7,16 +8,16 @@ function createUsageMetadata(anthropicUsage) {
|
|
|
7
8
|
if (!anthropicUsage) {
|
|
8
9
|
return undefined;
|
|
9
10
|
}
|
|
10
|
-
const inputTokens = anthropicUsage.input_tokens
|
|
11
|
-
|
|
11
|
+
const inputTokens = typeof anthropicUsage.input_tokens === "number"
|
|
12
|
+
? anthropicUsage.input_tokens
|
|
13
|
+
: 0;
|
|
14
|
+
const outputTokens = typeof anthropicUsage.output_tokens === "number"
|
|
15
|
+
? anthropicUsage.output_tokens
|
|
16
|
+
: 0;
|
|
12
17
|
const totalTokens = inputTokens + outputTokens;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const inputTokenDetails = {};
|
|
17
|
-
if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
|
|
18
|
-
inputTokenDetails.cache_read = cacheReadTokens + cacheCreationTokens;
|
|
19
|
-
}
|
|
18
|
+
const inputTokenDetails = convertAnthropicUsageToInputTokenDetails(
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
anthropicUsage);
|
|
20
21
|
return {
|
|
21
22
|
input_tokens: inputTokens,
|
|
22
23
|
output_tokens: outputTokens,
|
|
@@ -93,12 +94,7 @@ const messageAggregator = (chunks) => {
|
|
|
93
94
|
};
|
|
94
95
|
// Capture initial usage
|
|
95
96
|
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
|
-
};
|
|
97
|
+
usage = chunk.message.usage;
|
|
102
98
|
}
|
|
103
99
|
break;
|
|
104
100
|
case "content_block_start":
|
|
@@ -138,7 +134,12 @@ const messageAggregator = (chunks) => {
|
|
|
138
134
|
message.stop_reason = chunk.delta.stop_reason;
|
|
139
135
|
message.stop_sequence = chunk.delta.stop_sequence ?? null;
|
|
140
136
|
if (chunk.usage) {
|
|
141
|
-
|
|
137
|
+
// Override only non-null keys
|
|
138
|
+
for (const [key, value] of Object.entries(chunk.usage)) {
|
|
139
|
+
if (value != null) {
|
|
140
|
+
usage[key] = value;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
142
143
|
}
|
|
143
144
|
break;
|
|
144
145
|
case "message_stop":
|
|
@@ -178,26 +179,12 @@ const messageAggregator = (chunks) => {
|
|
|
178
179
|
* messages: [{ role: "user", content: "Hello!" }],
|
|
179
180
|
* });
|
|
180
181
|
*
|
|
181
|
-
* // Streaming
|
|
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()
|
|
182
|
+
* // Streaming
|
|
193
183
|
* const messageStream = anthropic.messages.stream({
|
|
194
184
|
* model: "claude-sonnet-4-20250514",
|
|
195
185
|
* max_tokens: 1024,
|
|
196
186
|
* messages: [{ role: "user", content: "Hello!" }],
|
|
197
187
|
* });
|
|
198
|
-
* for await (const event of messageStream) {
|
|
199
|
-
* // process events
|
|
200
|
-
* }
|
|
201
188
|
* const finalMessage = await messageStream.finalMessage();
|
|
202
189
|
* ```
|
|
203
190
|
*/
|
|
@@ -245,25 +232,33 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
245
232
|
Object.assign(tracedAnthropicClient.messages, anthropic.messages);
|
|
246
233
|
// Wrap messages.create
|
|
247
234
|
tracedAnthropicClient.messages.create = traceable(anthropic.messages.create.bind(anthropic.messages), messagesCreateConfig);
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
stream
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
235
|
+
// Shared function to wrap stream methods
|
|
236
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
237
|
+
const wrapStreamMethod = (originalStreamFn) => {
|
|
238
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
239
|
+
return function (...args) {
|
|
240
|
+
const stream = originalStreamFn(...args);
|
|
241
|
+
if ("finalMessage" in stream &&
|
|
242
|
+
typeof stream.finalMessage === "function") {
|
|
243
|
+
const originalFinalMessage = stream.finalMessage.bind(stream);
|
|
244
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
245
|
+
stream.finalMessage = async (...args) => {
|
|
246
|
+
if ("done" in stream && typeof stream.done === "function") {
|
|
247
|
+
await stream.done();
|
|
248
|
+
}
|
|
249
|
+
for await (const _ of stream) {
|
|
250
|
+
// Finish consuming the stream if it has not already been consumed
|
|
251
|
+
// It should be relatively uncommon to consume an iterator after calling
|
|
252
|
+
// .finalMessage()
|
|
253
|
+
}
|
|
254
|
+
return originalFinalMessage(...args);
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return stream;
|
|
258
|
+
};
|
|
265
259
|
};
|
|
266
|
-
|
|
260
|
+
// Wrap messages.stream
|
|
261
|
+
tracedAnthropicClient.messages.stream = traceable(wrapStreamMethod(anthropic.messages.stream.bind(anthropic.messages)), {
|
|
267
262
|
name: "ChatAnthropic",
|
|
268
263
|
run_type: "llm",
|
|
269
264
|
aggregator: messageAggregator,
|
|
@@ -284,7 +279,7 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
284
279
|
tracedBeta.messages.create = traceable(anthropic.beta.messages.create.bind(anthropic.beta.messages), messagesCreateConfig);
|
|
285
280
|
// Wrap beta.messages.stream if it exists
|
|
286
281
|
if (typeof anthropic.beta.messages.stream === "function") {
|
|
287
|
-
tracedBeta.messages.stream = traceable(anthropic.beta.messages.stream.bind(anthropic.beta.messages), {
|
|
282
|
+
tracedBeta.messages.stream = traceable(wrapStreamMethod(anthropic.beta.messages.stream.bind(anthropic.beta.messages)), {
|
|
288
283
|
name: "ChatAnthropic",
|
|
289
284
|
run_type: "llm",
|
|
290
285
|
aggregator: messageAggregator,
|
package/dist/wrappers/index.cjs
CHANGED
|
@@ -16,6 +16,5 @@ 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);
|
|
20
19
|
var generic_js_1 = require("./generic.cjs");
|
|
21
20
|
Object.defineProperty(exports, "wrapSDK", { enumerable: true, get: function () { return generic_js_1.wrapSDK; } });
|
package/dist/wrappers/index.d.ts
CHANGED
package/dist/wrappers/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "langsmith",
|
|
3
|
-
"version": "0.3.83
|
|
3
|
+
"version": "0.3.83",
|
|
4
4
|
"description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
|
|
5
5
|
"packageManager": "yarn@1.22.19",
|
|
6
6
|
"files": [
|
|
@@ -61,6 +61,10 @@
|
|
|
61
61
|
"anonymizer.js",
|
|
62
62
|
"anonymizer.d.ts",
|
|
63
63
|
"anonymizer.d.cts",
|
|
64
|
+
"wrappers/anthropic.cjs",
|
|
65
|
+
"wrappers/anthropic.js",
|
|
66
|
+
"wrappers/anthropic.d.ts",
|
|
67
|
+
"wrappers/anthropic.d.cts",
|
|
64
68
|
"wrappers/openai.cjs",
|
|
65
69
|
"wrappers/openai.js",
|
|
66
70
|
"wrappers/openai.d.ts",
|
|
@@ -353,6 +357,15 @@
|
|
|
353
357
|
"import": "./anonymizer.js",
|
|
354
358
|
"require": "./anonymizer.cjs"
|
|
355
359
|
},
|
|
360
|
+
"./wrappers/anthropic": {
|
|
361
|
+
"types": {
|
|
362
|
+
"import": "./wrappers/anthropic.d.ts",
|
|
363
|
+
"require": "./wrappers/anthropic.d.cts",
|
|
364
|
+
"default": "./wrappers/anthropic.d.ts"
|
|
365
|
+
},
|
|
366
|
+
"import": "./wrappers/anthropic.js",
|
|
367
|
+
"require": "./wrappers/anthropic.cjs"
|
|
368
|
+
},
|
|
356
369
|
"./wrappers/openai": {
|
|
357
370
|
"types": {
|
|
358
371
|
"import": "./wrappers/openai.d.ts",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../dist/wrappers/anthropic.cjs');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/wrappers/anthropic.js'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/wrappers/anthropic.js'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/wrappers/anthropic.js'
|