langsmith 0.4.8 → 0.4.10
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/experimental/anthropic/context.cjs +187 -0
- package/dist/experimental/anthropic/context.d.ts +5 -0
- package/dist/experimental/anthropic/context.js +183 -0
- package/dist/experimental/anthropic/index.cjs +82 -863
- package/dist/experimental/anthropic/index.d.ts +1 -1
- package/dist/experimental/anthropic/index.js +83 -864
- package/dist/experimental/anthropic/messages.cjs +102 -0
- package/dist/experimental/anthropic/messages.d.ts +6 -0
- package/dist/experimental/anthropic/messages.js +96 -0
- package/dist/experimental/anthropic/types.cjs +1 -0
- package/dist/experimental/anthropic/types.d.ts +50 -37
- package/dist/experimental/anthropic/types.js +1 -0
- package/dist/experimental/anthropic/usage.cjs +180 -0
- package/dist/experimental/anthropic/usage.d.ts +1 -0
- package/dist/experimental/anthropic/usage.js +175 -0
- package/dist/experimental/anthropic/utils.cjs +14 -0
- package/dist/experimental/anthropic/utils.d.ts +1 -1
- package/dist/experimental/anthropic/utils.js +13 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/schemas.d.ts +1 -0
- package/dist/utils/usage.cjs +6 -7
- package/dist/utils/usage.js +6 -7
- package/experimental/anthropic.cjs +1 -0
- package/experimental/anthropic.d.cts +1 -0
- package/experimental/anthropic.d.ts +1 -0
- package/experimental/anthropic.js +1 -0
- package/package.json +14 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamManager = void 0;
|
|
4
|
+
const messages_js_1 = require("./messages.cjs");
|
|
5
|
+
const traceable_js_1 = require("../../traceable.cjs");
|
|
6
|
+
const usage_js_1 = require("./usage.cjs");
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
class StreamManager {
|
|
11
|
+
constructor() {
|
|
12
|
+
Object.defineProperty(this, "namespaces", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: void 0
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(this, "history", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: void 0
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(this, "assistant", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
configurable: true,
|
|
27
|
+
writable: true,
|
|
28
|
+
value: {}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(this, "tools", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
configurable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
value: {}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(this, "postRunQueue", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: true,
|
|
39
|
+
writable: true,
|
|
40
|
+
value: []
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(this, "runTrees", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
configurable: true,
|
|
45
|
+
writable: true,
|
|
46
|
+
value: []
|
|
47
|
+
});
|
|
48
|
+
const rootRun = (0, traceable_js_1.getCurrentRunTree)(true);
|
|
49
|
+
this.namespaces = rootRun?.createChild ? { root: rootRun } : {};
|
|
50
|
+
this.history = { root: [] };
|
|
51
|
+
}
|
|
52
|
+
addMessage(message) {
|
|
53
|
+
const eventTime = Date.now();
|
|
54
|
+
// Short-circuit if no root run found
|
|
55
|
+
// This can happen if tracing is disabled globally
|
|
56
|
+
if (this.namespaces["root"] == null)
|
|
57
|
+
return;
|
|
58
|
+
if (message.type === "result") {
|
|
59
|
+
if (message.modelUsage) {
|
|
60
|
+
(0, usage_js_1.correctUsageFromResults)(message.modelUsage, Object.values(this.assistant));
|
|
61
|
+
}
|
|
62
|
+
const usage = message.modelUsage
|
|
63
|
+
? (0, usage_js_1.aggregateUsageFromModelUsage)(message.modelUsage)
|
|
64
|
+
: (0, usage_js_1.extractUsageFromMessage)(message);
|
|
65
|
+
if (message.total_cost_usd != null && usage != null) {
|
|
66
|
+
usage.total_cost = message.total_cost_usd;
|
|
67
|
+
}
|
|
68
|
+
this.namespaces["root"].extra ??= {};
|
|
69
|
+
this.namespaces["root"].extra.metadata ??= {};
|
|
70
|
+
this.namespaces["root"].extra.metadata.usage_metadata = usage;
|
|
71
|
+
this.namespaces["root"].extra.metadata.is_error = message.is_error;
|
|
72
|
+
this.namespaces["root"].extra.metadata.num_turns = message.num_turns;
|
|
73
|
+
this.namespaces["root"].extra.metadata.session_id = message.session_id;
|
|
74
|
+
this.namespaces["root"].extra.metadata.duration_ms = message.duration_ms;
|
|
75
|
+
this.namespaces["root"].extra.metadata.duration_api_ms =
|
|
76
|
+
message.duration_api_ms;
|
|
77
|
+
}
|
|
78
|
+
// Skip non-user / non-assistant messages
|
|
79
|
+
if (!("message" in message))
|
|
80
|
+
return;
|
|
81
|
+
const namespace = (() => {
|
|
82
|
+
if ("parent_tool_use_id" in message)
|
|
83
|
+
return message.parent_tool_use_id ?? "root";
|
|
84
|
+
return "root";
|
|
85
|
+
})();
|
|
86
|
+
// `eventTime` records the time we receive an event, which for `includePartialMessages: false`
|
|
87
|
+
// equals to the end time of an LLM block, so we need to use the first available end time within namespace.
|
|
88
|
+
const candidateStartTime = this.namespaces[namespace]?.child_runs?.at(-1)?.end_time ??
|
|
89
|
+
this.namespaces[namespace]?.start_time ??
|
|
90
|
+
eventTime;
|
|
91
|
+
this.history[namespace] ??= this.history["root"].slice();
|
|
92
|
+
if (message.type === "assistant") {
|
|
93
|
+
const messageId = message.message.id;
|
|
94
|
+
this.assistant[messageId] ??= this.createChild(namespace, {
|
|
95
|
+
name: "claude.assistant.turn",
|
|
96
|
+
run_type: "llm",
|
|
97
|
+
start_time: candidateStartTime,
|
|
98
|
+
inputs: {
|
|
99
|
+
messages: (0, messages_js_1.convertFromAnthropicMessage)(this.history[namespace]),
|
|
100
|
+
},
|
|
101
|
+
outputs: { output: { messages: [] } },
|
|
102
|
+
});
|
|
103
|
+
this.assistant[messageId].outputs = (() => {
|
|
104
|
+
const prevMessages = this.assistant[messageId].outputs?.output.messages ?? [];
|
|
105
|
+
const newMessages = (0, messages_js_1.convertFromAnthropicMessage)([message]);
|
|
106
|
+
return { output: { messages: [...prevMessages, ...newMessages] } };
|
|
107
|
+
})();
|
|
108
|
+
this.assistant[messageId].end_time = eventTime;
|
|
109
|
+
this.assistant[messageId].extra ??= {};
|
|
110
|
+
this.assistant[messageId].extra.metadata ??= {};
|
|
111
|
+
if (message.message.model != null) {
|
|
112
|
+
this.assistant[messageId].extra.metadata.ls_model_name =
|
|
113
|
+
message.message.model;
|
|
114
|
+
}
|
|
115
|
+
this.assistant[messageId].extra.metadata.usage_metadata =
|
|
116
|
+
(0, usage_js_1.extractUsageFromMessage)(message);
|
|
117
|
+
const tools = Array.isArray(message.message.content)
|
|
118
|
+
? message.message.content.filter((block) => (0, messages_js_1.isToolBlock)(block))
|
|
119
|
+
: [];
|
|
120
|
+
for (const block of tools) {
|
|
121
|
+
if ((0, messages_js_1.isTaskTool)(block)) {
|
|
122
|
+
const name = block.input.subagent_type ||
|
|
123
|
+
block.input.agent_type ||
|
|
124
|
+
(block.input.description
|
|
125
|
+
? block.input.description.split(" ")[0]
|
|
126
|
+
: null) ||
|
|
127
|
+
"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
|
+
});
|
|
134
|
+
this.namespaces[block.id] ??= this.tools[block.id];
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
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
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (message.type === "user") {
|
|
148
|
+
if (message.tool_use_result) {
|
|
149
|
+
const toolResult = Array.isArray(message.message.content)
|
|
150
|
+
? message.message.content.find((block) => "tool_use_id" in block)
|
|
151
|
+
: undefined;
|
|
152
|
+
if (toolResult?.tool_use_id &&
|
|
153
|
+
this.tools[toolResult.tool_use_id] != null) {
|
|
154
|
+
const toolOutput = Array.isArray(message.tool_use_result)
|
|
155
|
+
? { content: message.tool_use_result }
|
|
156
|
+
: message.tool_use_result;
|
|
157
|
+
const toolError = "is_error" in toolResult && toolResult.is_error === true
|
|
158
|
+
? ["string", "number", "boolean"].includes(typeof message.tool_use_result)
|
|
159
|
+
? String(message.tool_use_result)
|
|
160
|
+
: JSON.stringify(message.tool_use_result)
|
|
161
|
+
: undefined;
|
|
162
|
+
void this.tools[toolResult.tool_use_id].end(toolOutput, toolError);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
this.history[namespace].push(message);
|
|
167
|
+
}
|
|
168
|
+
createChild(namespace, args) {
|
|
169
|
+
const runTree = this.namespaces[namespace].createChild(args);
|
|
170
|
+
this.postRunQueue.push(runTree.postRun());
|
|
171
|
+
this.runTrees.push(runTree);
|
|
172
|
+
return runTree;
|
|
173
|
+
}
|
|
174
|
+
async finish() {
|
|
175
|
+
// Clean up incomplete tools and subagent calls
|
|
176
|
+
for (const tool of Object.values(this.tools)) {
|
|
177
|
+
if (tool.outputs == null && tool.error == null) {
|
|
178
|
+
void tool.end(undefined, "Run not completed (conversation ended)");
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// First make sure all the runs are created
|
|
182
|
+
await Promise.allSettled(this.postRunQueue);
|
|
183
|
+
// Then patch the runs
|
|
184
|
+
await Promise.allSettled(this.runTrees.map((runTree) => runTree.patchRun()));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
exports.StreamManager = StreamManager;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RunTreeConfig } from "../../run_trees.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for wrapping Claude Agent SDK with LangSmith tracing.
|
|
4
|
+
*/
|
|
5
|
+
export type WrapClaudeAgentSDKConfig = Partial<Omit<RunTreeConfig, "inputs" | "outputs" | "run_type" | "child_runs" | "parent_run" | "error">>;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { convertFromAnthropicMessage, isTaskTool, isToolBlock, } from "./messages.js";
|
|
2
|
+
import { getCurrentRunTree } from "../../traceable.js";
|
|
3
|
+
import { aggregateUsageFromModelUsage, correctUsageFromResults, extractUsageFromMessage, } from "./usage.js";
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export class StreamManager {
|
|
8
|
+
constructor() {
|
|
9
|
+
Object.defineProperty(this, "namespaces", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
writable: true,
|
|
13
|
+
value: void 0
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(this, "history", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: void 0
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, "assistant", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: {}
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "tools", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: {}
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(this, "postRunQueue", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
value: []
|
|
38
|
+
});
|
|
39
|
+
Object.defineProperty(this, "runTrees", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: []
|
|
44
|
+
});
|
|
45
|
+
const rootRun = getCurrentRunTree(true);
|
|
46
|
+
this.namespaces = rootRun?.createChild ? { root: rootRun } : {};
|
|
47
|
+
this.history = { root: [] };
|
|
48
|
+
}
|
|
49
|
+
addMessage(message) {
|
|
50
|
+
const eventTime = Date.now();
|
|
51
|
+
// Short-circuit if no root run found
|
|
52
|
+
// This can happen if tracing is disabled globally
|
|
53
|
+
if (this.namespaces["root"] == null)
|
|
54
|
+
return;
|
|
55
|
+
if (message.type === "result") {
|
|
56
|
+
if (message.modelUsage) {
|
|
57
|
+
correctUsageFromResults(message.modelUsage, Object.values(this.assistant));
|
|
58
|
+
}
|
|
59
|
+
const usage = message.modelUsage
|
|
60
|
+
? aggregateUsageFromModelUsage(message.modelUsage)
|
|
61
|
+
: extractUsageFromMessage(message);
|
|
62
|
+
if (message.total_cost_usd != null && usage != null) {
|
|
63
|
+
usage.total_cost = message.total_cost_usd;
|
|
64
|
+
}
|
|
65
|
+
this.namespaces["root"].extra ??= {};
|
|
66
|
+
this.namespaces["root"].extra.metadata ??= {};
|
|
67
|
+
this.namespaces["root"].extra.metadata.usage_metadata = usage;
|
|
68
|
+
this.namespaces["root"].extra.metadata.is_error = message.is_error;
|
|
69
|
+
this.namespaces["root"].extra.metadata.num_turns = message.num_turns;
|
|
70
|
+
this.namespaces["root"].extra.metadata.session_id = message.session_id;
|
|
71
|
+
this.namespaces["root"].extra.metadata.duration_ms = message.duration_ms;
|
|
72
|
+
this.namespaces["root"].extra.metadata.duration_api_ms =
|
|
73
|
+
message.duration_api_ms;
|
|
74
|
+
}
|
|
75
|
+
// Skip non-user / non-assistant messages
|
|
76
|
+
if (!("message" in message))
|
|
77
|
+
return;
|
|
78
|
+
const namespace = (() => {
|
|
79
|
+
if ("parent_tool_use_id" in message)
|
|
80
|
+
return message.parent_tool_use_id ?? "root";
|
|
81
|
+
return "root";
|
|
82
|
+
})();
|
|
83
|
+
// `eventTime` records the time we receive an event, which for `includePartialMessages: false`
|
|
84
|
+
// equals to the end time of an LLM block, so we need to use the first available end time within namespace.
|
|
85
|
+
const candidateStartTime = this.namespaces[namespace]?.child_runs?.at(-1)?.end_time ??
|
|
86
|
+
this.namespaces[namespace]?.start_time ??
|
|
87
|
+
eventTime;
|
|
88
|
+
this.history[namespace] ??= this.history["root"].slice();
|
|
89
|
+
if (message.type === "assistant") {
|
|
90
|
+
const messageId = message.message.id;
|
|
91
|
+
this.assistant[messageId] ??= this.createChild(namespace, {
|
|
92
|
+
name: "claude.assistant.turn",
|
|
93
|
+
run_type: "llm",
|
|
94
|
+
start_time: candidateStartTime,
|
|
95
|
+
inputs: {
|
|
96
|
+
messages: convertFromAnthropicMessage(this.history[namespace]),
|
|
97
|
+
},
|
|
98
|
+
outputs: { output: { messages: [] } },
|
|
99
|
+
});
|
|
100
|
+
this.assistant[messageId].outputs = (() => {
|
|
101
|
+
const prevMessages = this.assistant[messageId].outputs?.output.messages ?? [];
|
|
102
|
+
const newMessages = convertFromAnthropicMessage([message]);
|
|
103
|
+
return { output: { messages: [...prevMessages, ...newMessages] } };
|
|
104
|
+
})();
|
|
105
|
+
this.assistant[messageId].end_time = eventTime;
|
|
106
|
+
this.assistant[messageId].extra ??= {};
|
|
107
|
+
this.assistant[messageId].extra.metadata ??= {};
|
|
108
|
+
if (message.message.model != null) {
|
|
109
|
+
this.assistant[messageId].extra.metadata.ls_model_name =
|
|
110
|
+
message.message.model;
|
|
111
|
+
}
|
|
112
|
+
this.assistant[messageId].extra.metadata.usage_metadata =
|
|
113
|
+
extractUsageFromMessage(message);
|
|
114
|
+
const tools = Array.isArray(message.message.content)
|
|
115
|
+
? message.message.content.filter((block) => isToolBlock(block))
|
|
116
|
+
: [];
|
|
117
|
+
for (const block of tools) {
|
|
118
|
+
if (isTaskTool(block)) {
|
|
119
|
+
const name = block.input.subagent_type ||
|
|
120
|
+
block.input.agent_type ||
|
|
121
|
+
(block.input.description
|
|
122
|
+
? block.input.description.split(" ")[0]
|
|
123
|
+
: null) ||
|
|
124
|
+
"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
|
+
});
|
|
131
|
+
this.namespaces[block.id] ??= this.tools[block.id];
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
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
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (message.type === "user") {
|
|
145
|
+
if (message.tool_use_result) {
|
|
146
|
+
const toolResult = Array.isArray(message.message.content)
|
|
147
|
+
? message.message.content.find((block) => "tool_use_id" in block)
|
|
148
|
+
: undefined;
|
|
149
|
+
if (toolResult?.tool_use_id &&
|
|
150
|
+
this.tools[toolResult.tool_use_id] != null) {
|
|
151
|
+
const toolOutput = Array.isArray(message.tool_use_result)
|
|
152
|
+
? { content: message.tool_use_result }
|
|
153
|
+
: message.tool_use_result;
|
|
154
|
+
const toolError = "is_error" in toolResult && toolResult.is_error === true
|
|
155
|
+
? ["string", "number", "boolean"].includes(typeof message.tool_use_result)
|
|
156
|
+
? String(message.tool_use_result)
|
|
157
|
+
: JSON.stringify(message.tool_use_result)
|
|
158
|
+
: undefined;
|
|
159
|
+
void this.tools[toolResult.tool_use_id].end(toolOutput, toolError);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
this.history[namespace].push(message);
|
|
164
|
+
}
|
|
165
|
+
createChild(namespace, args) {
|
|
166
|
+
const runTree = this.namespaces[namespace].createChild(args);
|
|
167
|
+
this.postRunQueue.push(runTree.postRun());
|
|
168
|
+
this.runTrees.push(runTree);
|
|
169
|
+
return runTree;
|
|
170
|
+
}
|
|
171
|
+
async finish() {
|
|
172
|
+
// Clean up incomplete tools and subagent calls
|
|
173
|
+
for (const tool of Object.values(this.tools)) {
|
|
174
|
+
if (tool.outputs == null && tool.error == null) {
|
|
175
|
+
void tool.end(undefined, "Run not completed (conversation ended)");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// First make sure all the runs are created
|
|
179
|
+
await Promise.allSettled(this.postRunQueue);
|
|
180
|
+
// Then patch the runs
|
|
181
|
+
await Promise.allSettled(this.runTrees.map((runTree) => runTree.patchRun()));
|
|
182
|
+
}
|
|
183
|
+
}
|