langsmith 0.5.26 → 0.6.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.
@@ -1,389 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OpenCodeSessionTracer = void 0;
4
- // import type { Event, FilePart, Message, Model, Part } from "@opencode-ai/sdk";
5
- const run_trees_js_1 = require("../../run_trees.cjs");
6
- const index_js_1 = require("../../index.cjs");
7
- const dedupeParts = (parts) => {
8
- const partById = {};
9
- for (const part of parts) {
10
- partById[part.id] = { ...partById[part.id], ...part };
11
- }
12
- return Object.values(partById);
13
- };
14
- const convertToStandardContentBlock = (part) => {
15
- // Ignore AI SDK specific parts
16
- if (part.type === "step-start" || part.type === "step-finish") {
17
- return [];
18
- }
19
- if (part.type === "text") {
20
- return {
21
- type: "text",
22
- text: part.text,
23
- extras: part.metadata,
24
- };
25
- }
26
- if (part.type === "reasoning") {
27
- return {
28
- type: "thinking",
29
- thinking: part.text,
30
- };
31
- }
32
- if (part.type === "file") {
33
- return {
34
- type: "file",
35
- id: part.filename ?? part.id,
36
- url: part.url,
37
- mime_type: part.mime,
38
- };
39
- }
40
- if (part.type === "tool") {
41
- return {
42
- type: "tool_use",
43
- name: part.tool,
44
- input: part.state.input,
45
- id: part.callID,
46
- };
47
- }
48
- if (part.type === "compaction") {
49
- return {
50
- type: "compaction",
51
- data: { auto: part.auto },
52
- };
53
- }
54
- return {
55
- type: "non_standard",
56
- value: part,
57
- };
58
- };
59
- const convertToStandardMessages = (messages) => {
60
- return messages.flatMap((message) => {
61
- const parts = dedupeParts(message.parts);
62
- if (message.info?.role === "assistant") {
63
- // split out into "model message"
64
- return [
65
- {
66
- role: "assistant",
67
- content: parts.flatMap(convertToStandardContentBlock),
68
- },
69
- ...parts.flatMap((part) => {
70
- if (part.type !== "tool")
71
- return [];
72
- if (part.state.status === "completed") {
73
- return {
74
- role: "tool",
75
- content: part.state.output,
76
- name: part.tool,
77
- id: part.id,
78
- tool_call_id: part.callID,
79
- };
80
- }
81
- if (part.state.status === "error") {
82
- return {
83
- role: "tool",
84
- content: part.state.error,
85
- name: part.tool,
86
- id: part.id,
87
- tool_call_id: part.callID,
88
- };
89
- }
90
- return [];
91
- }),
92
- ];
93
- }
94
- if (message.info?.role === "user") {
95
- return {
96
- role: "user",
97
- content: parts.flatMap(convertToStandardContentBlock),
98
- };
99
- }
100
- return [];
101
- });
102
- };
103
- class OpenCodeSessionTracer {
104
- constructor(inputConfig) {
105
- Object.defineProperty(this, "sessions", {
106
- enumerable: true,
107
- configurable: true,
108
- writable: true,
109
- value: {}
110
- });
111
- Object.defineProperty(this, "client", {
112
- enumerable: true,
113
- configurable: true,
114
- writable: true,
115
- value: void 0
116
- });
117
- Object.defineProperty(this, "inputConfig", {
118
- enumerable: true,
119
- configurable: true,
120
- writable: true,
121
- value: void 0
122
- });
123
- this.inputConfig = inputConfig ?? {};
124
- this.client = inputConfig?.client ?? new index_js_1.Client();
125
- }
126
- getSession(sessionID) {
127
- this.sessions[sessionID] ??= {
128
- messages: {},
129
- traces: {},
130
- history: undefined,
131
- pendingSystem: undefined,
132
- postRunQueue: [],
133
- parentID: undefined,
134
- };
135
- return this.sessions[sessionID];
136
- }
137
- getMessage(sessionID, messageID) {
138
- const session = this.getSession(sessionID);
139
- session.messages[messageID] ??= {
140
- info: undefined,
141
- parts: [],
142
- complete: false,
143
- system: undefined,
144
- };
145
- // Attach pending system to assistant messages
146
- if (session.pendingSystem != null &&
147
- session.messages[messageID]?.info?.role === "assistant") {
148
- session.messages[messageID].system = session.pendingSystem;
149
- session.pendingSystem = undefined;
150
- }
151
- return session.messages[messageID];
152
- }
153
- getProviderMetadata(run) {
154
- const info = run.info;
155
- if (!info || info.role !== "assistant")
156
- return {};
157
- const model = run.system?.model;
158
- const modelId = model?.id ?? info.modelID;
159
- const providerId = model?.providerID ?? info.providerID;
160
- const ls_invocation_params = {
161
- model: modelId,
162
- providerID: providerId,
163
- };
164
- if (model?.name)
165
- ls_invocation_params.model_display_name = model.name;
166
- if (model?.api?.id)
167
- ls_invocation_params.api_model_id = model.api.id;
168
- if (model?.api?.url)
169
- ls_invocation_params.api_url = model.api.url;
170
- if (model?.api?.npm)
171
- ls_invocation_params.api_npm_package = model.api.npm;
172
- const stepFinish = run.parts.find((part) => part.type === "step-finish");
173
- return {
174
- ls_model_name: modelId,
175
- ls_provider: providerId,
176
- ls_model_type: "chat",
177
- ls_invocation_params,
178
- usage_metadata: stepFinish
179
- ? {
180
- input_tokens: stepFinish.tokens.input,
181
- output_tokens: stepFinish.tokens.output + stepFinish.tokens.reasoning,
182
- total_tokens: stepFinish.tokens.input +
183
- stepFinish.tokens.output +
184
- stepFinish.tokens.reasoning,
185
- input_token_details: {
186
- cache_read: stepFinish.tokens.cache.read,
187
- cache_creation: stepFinish.tokens.cache.write,
188
- },
189
- }
190
- : undefined,
191
- };
192
- }
193
- async sendTrace(sessionID, runs, options) {
194
- const session = this.getSession(sessionID);
195
- const userRunIdx = runs.findIndex(({ info }) => info?.role === "user");
196
- const userRun = runs.at(userRunIdx);
197
- const agentRuns = runs.slice(userRunIdx + 1);
198
- if (userRunIdx === -1 || userRun == null)
199
- return;
200
- const parentStartTime = userRun?.info?.time?.created ?? Date.now();
201
- const parentEndTime = agentRuns
202
- .flatMap((run) => run.parts)
203
- .reduce((acc, part) => {
204
- if (!("time" in part) || part.time == null)
205
- return acc;
206
- if (!("end" in part.time) || typeof part.time.end !== "number")
207
- return acc;
208
- return Math.max(acc, part.time.end);
209
- }, parentStartTime);
210
- if (userRun?.info) {
211
- session.history ??= [];
212
- session.history.push({ info: userRun.info, parts: userRun.parts });
213
- }
214
- const parentConfig = {
215
- name: "opencode.session",
216
- run_type: "chain",
217
- start_time: parentStartTime,
218
- end_time: parentEndTime,
219
- extra: {
220
- metadata: {
221
- ls_integration: "opencode-js",
222
- ls_agent_type: "root",
223
- thread_id: sessionID,
224
- },
225
- },
226
- inputs: { messages: convertToStandardMessages([userRun]) },
227
- outputs: { messages: convertToStandardMessages(agentRuns) },
228
- ...this.inputConfig,
229
- client: this.client,
230
- };
231
- const parent = options?.parentRunTree?.createChild(parentConfig) ??
232
- new run_trees_js_1.RunTree(parentConfig);
233
- session.postRunQueue.push(parent.postRun());
234
- for (const run of agentRuns) {
235
- const startTime = run.info?.time?.created ?? Date.now();
236
- const endTime = run.parts.reduce((acc, part) => {
237
- if (!("time" in part) || part.time == null)
238
- return acc;
239
- if (!("end" in part.time) || typeof part.time.end !== "number")
240
- return acc;
241
- return Math.max(acc, part.time.end);
242
- }, startTime);
243
- const parts = dedupeParts(run.parts);
244
- // Create child runs for tool parts
245
- const child = parent.createChild({
246
- name: "opencode.assistant.turn",
247
- run_type: "llm",
248
- start_time: startTime,
249
- end_time: endTime,
250
- inputs: {
251
- messages: [
252
- ...(run.system?.system
253
- ? [{ role: "system", content: run.system.system.join("\n") }]
254
- : []),
255
- ...convertToStandardMessages(session.history ?? []),
256
- ],
257
- },
258
- outputs: { messages: convertToStandardMessages([run]) },
259
- extra: { metadata: this.getProviderMetadata(run) },
260
- });
261
- session.postRunQueue.push(child.postRun());
262
- for (const toolPart of parts) {
263
- if (toolPart.type !== "tool")
264
- continue;
265
- const state = toolPart.state;
266
- // Try looking for subgraph
267
- let toolHandled = false;
268
- if (state.metadata?.sessionId) {
269
- const session = this.getSession(state.metadata.sessionId);
270
- for (const trace of Object.values(session.traces)) {
271
- if (trace.state !== "subgraph")
272
- continue;
273
- await this.sendTrace(state.metadata.sessionId, trace.runs, {
274
- parentRunTree: child,
275
- });
276
- toolHandled = true;
277
- }
278
- }
279
- if (toolHandled)
280
- continue;
281
- const tool = child.createChild({
282
- name: toolPart.tool,
283
- run_type: "tool",
284
- inputs: state.input ?? {},
285
- outputs: {
286
- output: state.output,
287
- attachments: state.attachments?.map(convertToStandardContentBlock) ??
288
- undefined,
289
- },
290
- start_time: state.time?.start ?? startTime,
291
- end_time: state.time?.end ?? endTime,
292
- error: state.error,
293
- extra: { metadata: state.metadata },
294
- });
295
- session.postRunQueue.push(tool.postRun());
296
- }
297
- if (run.info) {
298
- session.history ??= [];
299
- session.history.push({ info: run.info, parts });
300
- }
301
- }
302
- }
303
- async flush() {
304
- await Promise.all(Object.values(this.sessions).flatMap((session) => session.postRunQueue));
305
- await this.client.flush();
306
- await this.client.awaitPendingTraceBatches();
307
- }
308
- async handleSystem(input, output) {
309
- if (!input.sessionID)
310
- return;
311
- const session = this.getSession(input.sessionID);
312
- session.pendingSystem = { model: input.model, system: output.system };
313
- }
314
- async handleSessionLoad(sessionID, history) {
315
- const session = this.getSession(sessionID);
316
- if (session.history)
317
- return;
318
- session.history = await history(sessionID);
319
- }
320
- async handleEvent({ event: { properties, type } }) {
321
- if (type === "server.instance.disposed") {
322
- await this.flush();
323
- return;
324
- }
325
- const sessionID = "sessionID" in properties && typeof properties.sessionID === "string"
326
- ? properties.sessionID
327
- : undefined;
328
- if (!sessionID)
329
- return;
330
- const session = this.getSession(sessionID);
331
- let updatedID;
332
- if (type === "session.created" || type === "session.updated") {
333
- session.parentID = properties.info.parentID;
334
- }
335
- if (type === "message.updated") {
336
- const message = this.getMessage(sessionID, properties.info.id);
337
- message.info = properties.info;
338
- updatedID = properties.info.id;
339
- }
340
- if (type === "message.part.updated") {
341
- const message = this.getMessage(sessionID, properties.part.messageID);
342
- message.parts.push(properties.part);
343
- updatedID = properties.part.messageID;
344
- }
345
- if (type === "message.part.removed") {
346
- const message = this.getMessage(sessionID, properties.messageID);
347
- message.parts = message.parts.filter((part) => part.id !== properties.partID);
348
- updatedID = properties.messageID;
349
- }
350
- if (type === "message.removed") {
351
- const session = this.getSession(sessionID);
352
- delete session.messages[properties.messageID];
353
- }
354
- // Message consolidation logic
355
- const message = updatedID ? session.messages[updatedID] : undefined;
356
- if (message?.info?.role == null)
357
- return;
358
- // Skip if message is already marked as complete
359
- if (message.complete)
360
- return;
361
- message.complete =
362
- (message.info?.role === "user" && message.parts.length > 0) ||
363
- (message.info?.role === "assistant" &&
364
- message.parts.some((part) => part.type === "step-finish"));
365
- // Now we're complete, add to a trace
366
- if (message.complete) {
367
- const traceId = message.info.role === "user" ? message.info.id : message.info.parentID;
368
- session.traces[traceId] ??= { runs: [], state: false };
369
- const trace = session.traces[traceId];
370
- trace.runs.push(message);
371
- // Skip if trace is already marked as complete
372
- if (trace.state !== false)
373
- return;
374
- trace.state = trace.runs.some((run) => run.parts.some(
375
- // trace is marked complete when there's a step-finish part with reason "stop"
376
- (part) => part.type === "step-finish" && part.reason === "stop"));
377
- if (trace.state) {
378
- // If trace is part of a subagent call, mark it as a subgraph and submit
379
- // when parent is being submitted (to preserve correct dotted order)
380
- if (session.parentID) {
381
- trace.state = "subgraph";
382
- return;
383
- }
384
- await this.sendTrace(sessionID, trace.runs);
385
- }
386
- }
387
- }
388
- }
389
- exports.OpenCodeSessionTracer = OpenCodeSessionTracer;
@@ -1,30 +0,0 @@
1
- import { type RunTreeConfig } from "../../run_trees.js";
2
- type Event = any;
3
- type Message = any;
4
- type Model = any;
5
- type Part = any;
6
- export declare class OpenCodeSessionTracer {
7
- private sessions;
8
- private client;
9
- private inputConfig;
10
- constructor(inputConfig?: Partial<RunTreeConfig>);
11
- private getSession;
12
- private getMessage;
13
- private getProviderMetadata;
14
- private sendTrace;
15
- flush(): Promise<void>;
16
- handleSystem(input: {
17
- model: Model;
18
- sessionID?: string | undefined;
19
- }, output: {
20
- system: string[];
21
- }): Promise<void>;
22
- handleSessionLoad(sessionID: string, history: (sessionID: string) => Promise<{
23
- info: Message;
24
- parts: Part[];
25
- }[]>): Promise<void>;
26
- handleEvent({ event: { properties, type } }: {
27
- event: Event;
28
- }): Promise<void>;
29
- }
30
- export {};