@langchain/core 0.2.3 → 0.2.5

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/README.md CHANGED
@@ -83,7 +83,7 @@ Streaming (and streaming of intermediate steps) is needed to show the user that
83
83
  Async interfaces are nice when moving into production.
84
84
  Rather than having to write multiple implementations for all of those, LCEL allows you to write a runnable once and invoke it in many different ways.
85
85
 
86
- For more check out the [LCEL docs](https://js.langchain.com/docs/expression_language/).
86
+ For more check out the [LCEL docs](https://js.langchain.com/v0.2/docs/concepts#langchain-expression-language).
87
87
 
88
88
  ![LangChain Stack](../docs/core_docs/static/img/langchain_stack_feb_2024.webp)
89
89
 
@@ -617,7 +617,12 @@ class CallbackManager extends BaseCallbackManager {
617
617
  if (tracingEnabled &&
618
618
  !callbackManager.handlers.some((handler) => handler.name === "langchain_tracer")) {
619
619
  if (tracingV2Enabled) {
620
- callbackManager.addHandler(await (0, initialize_js_1.getTracingV2CallbackHandler)(), true);
620
+ const tracerV2 = await (0, initialize_js_1.getTracingV2CallbackHandler)();
621
+ callbackManager.addHandler(tracerV2, true);
622
+ // handoff between langchain and langsmith/traceable
623
+ // override the parent run ID
624
+ callbackManager._parentRunId =
625
+ tracerV2.getTraceableRunTree()?.id ?? callbackManager._parentRunId;
621
626
  }
622
627
  }
623
628
  }
@@ -120,7 +120,7 @@ export declare class CallbackManager extends BaseCallbackManager implements Base
120
120
  metadata: Record<string, unknown>;
121
121
  inheritableMetadata: Record<string, unknown>;
122
122
  name: string;
123
- readonly _parentRunId?: string;
123
+ _parentRunId?: string;
124
124
  constructor(parentRunId?: string, options?: {
125
125
  handlers?: BaseCallbackHandler[];
126
126
  inheritableHandlers?: BaseCallbackHandler[];
@@ -608,7 +608,12 @@ export class CallbackManager extends BaseCallbackManager {
608
608
  if (tracingEnabled &&
609
609
  !callbackManager.handlers.some((handler) => handler.name === "langchain_tracer")) {
610
610
  if (tracingV2Enabled) {
611
- callbackManager.addHandler(await getTracingV2CallbackHandler(), true);
611
+ const tracerV2 = await getTracingV2CallbackHandler();
612
+ callbackManager.addHandler(tracerV2, true);
613
+ // handoff between langchain and langsmith/traceable
614
+ // override the parent run ID
615
+ callbackManager._parentRunId =
616
+ tracerV2.getTraceableRunTree()?.id ?? callbackManager._parentRunId;
612
617
  }
613
618
  }
614
619
  }
@@ -76,11 +76,21 @@ class AIMessage extends base_js_1.BaseMessage {
76
76
  writable: true,
77
77
  value: []
78
78
  });
79
+ /**
80
+ * If provided, token usage information associated with the message.
81
+ */
82
+ Object.defineProperty(this, "usage_metadata", {
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true,
86
+ value: void 0
87
+ });
79
88
  if (typeof initParams !== "string") {
80
89
  this.tool_calls = initParams.tool_calls ?? this.tool_calls;
81
90
  this.invalid_tool_calls =
82
91
  initParams.invalid_tool_calls ?? this.invalid_tool_calls;
83
92
  }
93
+ this.usage_metadata = initParams.usage_metadata;
84
94
  }
85
95
  static lc_name() {
86
96
  return "AIMessage";
@@ -172,11 +182,21 @@ class AIMessageChunk extends base_js_1.BaseMessageChunk {
172
182
  writable: true,
173
183
  value: []
174
184
  });
185
+ /**
186
+ * If provided, token usage information associated with the message.
187
+ */
188
+ Object.defineProperty(this, "usage_metadata", {
189
+ enumerable: true,
190
+ configurable: true,
191
+ writable: true,
192
+ value: void 0
193
+ });
175
194
  this.tool_call_chunks =
176
- initParams?.tool_call_chunks ?? this.tool_call_chunks;
177
- this.tool_calls = initParams?.tool_calls ?? this.tool_calls;
195
+ initParams.tool_call_chunks ?? this.tool_call_chunks;
196
+ this.tool_calls = initParams.tool_calls ?? this.tool_calls;
178
197
  this.invalid_tool_calls =
179
- initParams?.invalid_tool_calls ?? this.invalid_tool_calls;
198
+ initParams.invalid_tool_calls ?? this.invalid_tool_calls;
199
+ this.usage_metadata = initParams.usage_metadata;
180
200
  }
181
201
  get lc_aliases() {
182
202
  // exclude snake case conversion to pascal case
@@ -207,6 +227,25 @@ class AIMessageChunk extends base_js_1.BaseMessageChunk {
207
227
  combinedFields.tool_call_chunks = rawToolCalls;
208
228
  }
209
229
  }
230
+ if (this.usage_metadata !== undefined ||
231
+ chunk.usage_metadata !== undefined) {
232
+ const left = this.usage_metadata ?? {
233
+ input_tokens: 0,
234
+ output_tokens: 0,
235
+ total_tokens: 0,
236
+ };
237
+ const right = chunk.usage_metadata ?? {
238
+ input_tokens: 0,
239
+ output_tokens: 0,
240
+ total_tokens: 0,
241
+ };
242
+ const usage_metadata = {
243
+ input_tokens: left.input_tokens + right.input_tokens,
244
+ output_tokens: left.output_tokens + right.output_tokens,
245
+ total_tokens: left.total_tokens + right.total_tokens,
246
+ };
247
+ combinedFields.usage_metadata = usage_metadata;
248
+ }
210
249
  return new AIMessageChunk(combinedFields);
211
250
  }
212
251
  }
@@ -3,6 +3,24 @@ import { InvalidToolCall, ToolCall, ToolCallChunk } from "./tool.js";
3
3
  export type AIMessageFields = BaseMessageFields & {
4
4
  tool_calls?: ToolCall[];
5
5
  invalid_tool_calls?: InvalidToolCall[];
6
+ usage_metadata?: UsageMetadata;
7
+ };
8
+ /**
9
+ * Usage metadata for a message, such as token counts.
10
+ */
11
+ export type UsageMetadata = {
12
+ /**
13
+ * The count of input (or prompt) tokens.
14
+ */
15
+ input_tokens: number;
16
+ /**
17
+ * The count of output (or completion) tokens
18
+ */
19
+ output_tokens: number;
20
+ /**
21
+ * The total token count
22
+ */
23
+ total_tokens: number;
6
24
  };
7
25
  /**
8
26
  * Represents an AI message in a conversation.
@@ -10,6 +28,10 @@ export type AIMessageFields = BaseMessageFields & {
10
28
  export declare class AIMessage extends BaseMessage {
11
29
  tool_calls?: ToolCall[];
12
30
  invalid_tool_calls?: InvalidToolCall[];
31
+ /**
32
+ * If provided, token usage information associated with the message.
33
+ */
34
+ usage_metadata?: UsageMetadata;
13
35
  get lc_aliases(): Record<string, string>;
14
36
  constructor(fields: string | AIMessageFields,
15
37
  /** @deprecated */
@@ -29,6 +51,10 @@ export declare class AIMessageChunk extends BaseMessageChunk {
29
51
  tool_calls?: ToolCall[];
30
52
  invalid_tool_calls?: InvalidToolCall[];
31
53
  tool_call_chunks?: ToolCallChunk[];
54
+ /**
55
+ * If provided, token usage information associated with the message.
56
+ */
57
+ usage_metadata?: UsageMetadata;
32
58
  constructor(fields: string | AIMessageChunkFields);
33
59
  get lc_aliases(): Record<string, string>;
34
60
  static lc_name(): string;
@@ -73,11 +73,21 @@ export class AIMessage extends BaseMessage {
73
73
  writable: true,
74
74
  value: []
75
75
  });
76
+ /**
77
+ * If provided, token usage information associated with the message.
78
+ */
79
+ Object.defineProperty(this, "usage_metadata", {
80
+ enumerable: true,
81
+ configurable: true,
82
+ writable: true,
83
+ value: void 0
84
+ });
76
85
  if (typeof initParams !== "string") {
77
86
  this.tool_calls = initParams.tool_calls ?? this.tool_calls;
78
87
  this.invalid_tool_calls =
79
88
  initParams.invalid_tool_calls ?? this.invalid_tool_calls;
80
89
  }
90
+ this.usage_metadata = initParams.usage_metadata;
81
91
  }
82
92
  static lc_name() {
83
93
  return "AIMessage";
@@ -167,11 +177,21 @@ export class AIMessageChunk extends BaseMessageChunk {
167
177
  writable: true,
168
178
  value: []
169
179
  });
180
+ /**
181
+ * If provided, token usage information associated with the message.
182
+ */
183
+ Object.defineProperty(this, "usage_metadata", {
184
+ enumerable: true,
185
+ configurable: true,
186
+ writable: true,
187
+ value: void 0
188
+ });
170
189
  this.tool_call_chunks =
171
- initParams?.tool_call_chunks ?? this.tool_call_chunks;
172
- this.tool_calls = initParams?.tool_calls ?? this.tool_calls;
190
+ initParams.tool_call_chunks ?? this.tool_call_chunks;
191
+ this.tool_calls = initParams.tool_calls ?? this.tool_calls;
173
192
  this.invalid_tool_calls =
174
- initParams?.invalid_tool_calls ?? this.invalid_tool_calls;
193
+ initParams.invalid_tool_calls ?? this.invalid_tool_calls;
194
+ this.usage_metadata = initParams.usage_metadata;
175
195
  }
176
196
  get lc_aliases() {
177
197
  // exclude snake case conversion to pascal case
@@ -202,6 +222,25 @@ export class AIMessageChunk extends BaseMessageChunk {
202
222
  combinedFields.tool_call_chunks = rawToolCalls;
203
223
  }
204
224
  }
225
+ if (this.usage_metadata !== undefined ||
226
+ chunk.usage_metadata !== undefined) {
227
+ const left = this.usage_metadata ?? {
228
+ input_tokens: 0,
229
+ output_tokens: 0,
230
+ total_tokens: 0,
231
+ };
232
+ const right = chunk.usage_metadata ?? {
233
+ input_tokens: 0,
234
+ output_tokens: 0,
235
+ total_tokens: 0,
236
+ };
237
+ const usage_metadata = {
238
+ input_tokens: left.input_tokens + right.input_tokens,
239
+ output_tokens: left.output_tokens + right.output_tokens,
240
+ total_tokens: left.total_tokens + right.total_tokens,
241
+ };
242
+ combinedFields.usage_metadata = usage_metadata;
243
+ }
205
244
  return new AIMessageChunk(combinedFields);
206
245
  }
207
246
  }
@@ -3,10 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.RunnablePick = exports.RunnableAssign = exports._coerceToRunnable = exports.RunnableWithFallbacks = exports.RunnableParallel = exports.RunnableLambda = exports.RunnableMap = exports.RunnableSequence = exports.RunnableRetry = exports.RunnableEach = exports.RunnableBinding = exports.Runnable = exports._coerceToDict = void 0;
6
+ exports.RunnablePick = exports.RunnableAssign = exports._coerceToRunnable = exports.RunnableWithFallbacks = exports.RunnableParallel = exports.RunnableLambda = exports.RunnableTraceable = exports.RunnableMap = exports.RunnableSequence = exports.RunnableRetry = exports.RunnableEach = exports.RunnableBinding = exports.Runnable = exports._coerceToDict = void 0;
7
7
  const zod_1 = require("zod");
8
8
  const p_retry_1 = __importDefault(require("p-retry"));
9
9
  const uuid_1 = require("uuid");
10
+ const traceable_1 = require("langsmith/singletons/traceable");
10
11
  const manager_js_1 = require("../callbacks/manager.cjs");
11
12
  const log_stream_js_1 = require("../tracers/log_stream.cjs");
12
13
  const event_stream_js_1 = require("../tracers/event_stream.cjs");
@@ -480,7 +481,7 @@ class Runnable extends serializable_js_1.Serializable {
480
481
  async *_streamEventsV2(input, options, streamOptions) {
481
482
  const eventStreamer = new event_stream_js_1.EventStreamCallbackHandler({
482
483
  ...streamOptions,
483
- autoClose: true,
484
+ autoClose: false,
484
485
  });
485
486
  const config = (0, config_js_1.ensureConfig)(options);
486
487
  const runId = config.runId ?? (0, uuid_1.v4)();
@@ -502,11 +503,16 @@ class Runnable extends serializable_js_1.Serializable {
502
503
  // add each chunk to the output stream
503
504
  const outerThis = this;
504
505
  async function consumeRunnableStream() {
505
- const runnableStream = await outerThis.stream(input, config);
506
- const tappedStream = eventStreamer.tapOutputIterable(runId, runnableStream);
507
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
508
- for await (const _ of tappedStream) {
509
- // Just iterate so that the callback handler picks up events
506
+ try {
507
+ const runnableStream = await outerThis.stream(input, config);
508
+ const tappedStream = eventStreamer.tapOutputIterable(runId, runnableStream);
509
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
510
+ for await (const _ of tappedStream) {
511
+ // Just iterate so that the callback handler picks up events
512
+ }
513
+ }
514
+ finally {
515
+ await eventStreamer.finish();
510
516
  }
511
517
  }
512
518
  const runnableStreamConsumePromise = consumeRunnableStream();
@@ -1385,6 +1391,69 @@ class RunnableMap extends Runnable {
1385
1391
  }
1386
1392
  }
1387
1393
  exports.RunnableMap = RunnableMap;
1394
+ /**
1395
+ * A runnable that wraps a traced LangSmith function.
1396
+ */
1397
+ class RunnableTraceable extends Runnable {
1398
+ constructor(fields) {
1399
+ super(fields);
1400
+ Object.defineProperty(this, "lc_serializable", {
1401
+ enumerable: true,
1402
+ configurable: true,
1403
+ writable: true,
1404
+ value: false
1405
+ });
1406
+ Object.defineProperty(this, "lc_namespace", {
1407
+ enumerable: true,
1408
+ configurable: true,
1409
+ writable: true,
1410
+ value: ["langchain_core", "runnables"]
1411
+ });
1412
+ Object.defineProperty(this, "func", {
1413
+ enumerable: true,
1414
+ configurable: true,
1415
+ writable: true,
1416
+ value: void 0
1417
+ });
1418
+ if (!(0, traceable_1.isTraceableFunction)(fields.func)) {
1419
+ throw new Error("RunnableTraceable requires a function that is wrapped in traceable higher-order function");
1420
+ }
1421
+ this.func = fields.func;
1422
+ }
1423
+ async invoke(input, options) {
1424
+ const [config] = this._getOptionsList(options ?? {}, 1);
1425
+ const callbacks = await (0, config_js_1.getCallbackManagerForConfig)(config);
1426
+ return (await this.func((0, config_js_1.patchConfig)(config, { callbacks }), input));
1427
+ }
1428
+ async *_streamIterator(input, options) {
1429
+ const result = await this.invoke(input, options);
1430
+ if ((0, iter_js_1.isAsyncIterable)(result)) {
1431
+ for await (const item of result) {
1432
+ yield item;
1433
+ }
1434
+ return;
1435
+ }
1436
+ if ((0, iter_js_1.isIterator)(result)) {
1437
+ while (true) {
1438
+ const state = result.next();
1439
+ if (state.done)
1440
+ break;
1441
+ yield state.value;
1442
+ }
1443
+ return;
1444
+ }
1445
+ yield result;
1446
+ }
1447
+ static from(func) {
1448
+ return new RunnableTraceable({ func });
1449
+ }
1450
+ }
1451
+ exports.RunnableTraceable = RunnableTraceable;
1452
+ function assertNonTraceableFunction(func) {
1453
+ if ((0, traceable_1.isTraceableFunction)(func)) {
1454
+ throw new Error("RunnableLambda requires a function that is not wrapped in traceable higher-order function. This shouldn't happen.");
1455
+ }
1456
+ }
1388
1457
  /**
1389
1458
  * A runnable that runs a callable.
1390
1459
  */
@@ -1393,6 +1462,10 @@ class RunnableLambda extends Runnable {
1393
1462
  return "RunnableLambda";
1394
1463
  }
1395
1464
  constructor(fields) {
1465
+ if ((0, traceable_1.isTraceableFunction)(fields.func)) {
1466
+ // eslint-disable-next-line no-constructor-return
1467
+ return RunnableTraceable.from(fields.func);
1468
+ }
1396
1469
  super(fields);
1397
1470
  Object.defineProperty(this, "lc_namespace", {
1398
1471
  enumerable: true,
@@ -1406,6 +1479,7 @@ class RunnableLambda extends Runnable {
1406
1479
  writable: true,
1407
1480
  value: void 0
1408
1481
  });
1482
+ assertNonTraceableFunction(fields.func);
1409
1483
  this.func = fields.func;
1410
1484
  }
1411
1485
  static from(func) {
@@ -1453,7 +1527,7 @@ class RunnableLambda extends Runnable {
1453
1527
  }
1454
1528
  output = finalOutput;
1455
1529
  }
1456
- else if ((0, iter_js_1.isIterator)(output)) {
1530
+ else if ((0, iter_js_1.isIterableIterator)(output)) {
1457
1531
  let finalOutput;
1458
1532
  for (const chunk of (0, iter_js_1.consumeIteratorInContext)(childConfig, output)) {
1459
1533
  if (finalOutput === undefined) {
@@ -1531,7 +1605,7 @@ class RunnableLambda extends Runnable {
1531
1605
  yield chunk;
1532
1606
  }
1533
1607
  }
1534
- else if ((0, iter_js_1.isIterator)(output)) {
1608
+ else if ((0, iter_js_1.isIterableIterator)(output)) {
1535
1609
  for (const chunk of (0, iter_js_1.consumeIteratorInContext)(config, output)) {
1536
1610
  yield chunk;
1537
1611
  }
@@ -1,3 +1,4 @@
1
+ import { type TraceableFunction } from "langsmith/singletons/traceable";
1
2
  import type { RunnableInterface, RunnableBatchOptions } from "./types.js";
2
3
  import { CallbackManagerForChainRun } from "../callbacks/manager.js";
3
4
  import { LogStreamCallbackHandler, LogStreamCallbackHandlerInput, RunLogPatch } from "../tracers/log_stream.js";
@@ -463,6 +464,21 @@ export declare class RunnableMap<RunInput = any, RunOutput extends Record<string
463
464
  transform(generator: AsyncGenerator<RunInput>, options?: Partial<RunnableConfig>): AsyncGenerator<RunOutput>;
464
465
  stream(input: RunInput, options?: Partial<RunnableConfig>): Promise<IterableReadableStream<RunOutput>>;
465
466
  }
467
+ type AnyTraceableFunction = TraceableFunction<(...any: any[]) => any>;
468
+ /**
469
+ * A runnable that wraps a traced LangSmith function.
470
+ */
471
+ export declare class RunnableTraceable<RunInput, RunOutput> extends Runnable<RunInput, RunOutput> {
472
+ lc_serializable: boolean;
473
+ lc_namespace: string[];
474
+ protected func: AnyTraceableFunction;
475
+ constructor(fields: {
476
+ func: AnyTraceableFunction;
477
+ });
478
+ invoke(input: RunInput, options?: Partial<RunnableConfig>): Promise<RunOutput>;
479
+ _streamIterator(input: RunInput, options?: Partial<RunnableConfig>): AsyncGenerator<RunOutput>;
480
+ static from(func: AnyTraceableFunction): RunnableTraceable<unknown, unknown>;
481
+ }
466
482
  /**
467
483
  * A runnable that runs a callable.
468
484
  */
@@ -471,9 +487,10 @@ export declare class RunnableLambda<RunInput, RunOutput> extends Runnable<RunInp
471
487
  lc_namespace: string[];
472
488
  protected func: RunnableFunc<RunInput, RunOutput | Runnable<RunInput, RunOutput>>;
473
489
  constructor(fields: {
474
- func: RunnableFunc<RunInput, RunOutput | Runnable<RunInput, RunOutput>>;
490
+ func: RunnableFunc<RunInput, RunOutput | Runnable<RunInput, RunOutput>> | TraceableFunction<RunnableFunc<RunInput, RunOutput | Runnable<RunInput, RunOutput>>>;
475
491
  });
476
492
  static from<RunInput, RunOutput>(func: RunnableFunc<RunInput, RunOutput | Runnable<RunInput, RunOutput>>): RunnableLambda<RunInput, RunOutput>;
493
+ static from<RunInput, RunOutput>(func: TraceableFunction<RunnableFunc<RunInput, RunOutput | Runnable<RunInput, RunOutput>>>): RunnableLambda<RunInput, RunOutput>;
477
494
  _invoke(input: RunInput, config?: Partial<RunnableConfig>, runManager?: CallbackManagerForChainRun): Promise<RunOutput>;
478
495
  invoke(input: RunInput, options?: Partial<RunnableConfig>): Promise<RunOutput>;
479
496
  _transform(generator: AsyncGenerator<RunInput>, runManager?: CallbackManagerForChainRun, config?: Partial<RunnableConfig>): AsyncGenerator<RunOutput>;
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import pRetry from "p-retry";
3
3
  import { v4 as uuidv4 } from "uuid";
4
+ import { isTraceableFunction, } from "langsmith/singletons/traceable";
4
5
  import { CallbackManager, } from "../callbacks/manager.js";
5
6
  import { LogStreamCallbackHandler, RunLog, RunLogPatch, isLogStreamHandler, } from "../tracers/log_stream.js";
6
7
  import { EventStreamCallbackHandler, isStreamEventsHandler, } from "../tracers/event_stream.js";
@@ -13,7 +14,7 @@ import { _RootEventFilter, isRunnableInterface } from "./utils.js";
13
14
  import { AsyncLocalStorageProviderSingleton } from "../singletons/index.js";
14
15
  import { Graph } from "./graph.js";
15
16
  import { convertToHttpEventStream } from "./wrappers.js";
16
- import { consumeAsyncIterableInContext, consumeIteratorInContext, isAsyncIterable, isIterator, } from "./iter.js";
17
+ import { consumeAsyncIterableInContext, consumeIteratorInContext, isAsyncIterable, isIterableIterator, isIterator, } from "./iter.js";
17
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
19
  export function _coerceToDict(value, defaultKey) {
19
20
  return value &&
@@ -473,7 +474,7 @@ export class Runnable extends Serializable {
473
474
  async *_streamEventsV2(input, options, streamOptions) {
474
475
  const eventStreamer = new EventStreamCallbackHandler({
475
476
  ...streamOptions,
476
- autoClose: true,
477
+ autoClose: false,
477
478
  });
478
479
  const config = ensureConfig(options);
479
480
  const runId = config.runId ?? uuidv4();
@@ -495,11 +496,16 @@ export class Runnable extends Serializable {
495
496
  // add each chunk to the output stream
496
497
  const outerThis = this;
497
498
  async function consumeRunnableStream() {
498
- const runnableStream = await outerThis.stream(input, config);
499
- const tappedStream = eventStreamer.tapOutputIterable(runId, runnableStream);
500
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
501
- for await (const _ of tappedStream) {
502
- // Just iterate so that the callback handler picks up events
499
+ try {
500
+ const runnableStream = await outerThis.stream(input, config);
501
+ const tappedStream = eventStreamer.tapOutputIterable(runId, runnableStream);
502
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
503
+ for await (const _ of tappedStream) {
504
+ // Just iterate so that the callback handler picks up events
505
+ }
506
+ }
507
+ finally {
508
+ await eventStreamer.finish();
503
509
  }
504
510
  }
505
511
  const runnableStreamConsumePromise = consumeRunnableStream();
@@ -1372,6 +1378,68 @@ export class RunnableMap extends Runnable {
1372
1378
  return IterableReadableStream.fromAsyncGenerator(wrappedGenerator);
1373
1379
  }
1374
1380
  }
1381
+ /**
1382
+ * A runnable that wraps a traced LangSmith function.
1383
+ */
1384
+ export class RunnableTraceable extends Runnable {
1385
+ constructor(fields) {
1386
+ super(fields);
1387
+ Object.defineProperty(this, "lc_serializable", {
1388
+ enumerable: true,
1389
+ configurable: true,
1390
+ writable: true,
1391
+ value: false
1392
+ });
1393
+ Object.defineProperty(this, "lc_namespace", {
1394
+ enumerable: true,
1395
+ configurable: true,
1396
+ writable: true,
1397
+ value: ["langchain_core", "runnables"]
1398
+ });
1399
+ Object.defineProperty(this, "func", {
1400
+ enumerable: true,
1401
+ configurable: true,
1402
+ writable: true,
1403
+ value: void 0
1404
+ });
1405
+ if (!isTraceableFunction(fields.func)) {
1406
+ throw new Error("RunnableTraceable requires a function that is wrapped in traceable higher-order function");
1407
+ }
1408
+ this.func = fields.func;
1409
+ }
1410
+ async invoke(input, options) {
1411
+ const [config] = this._getOptionsList(options ?? {}, 1);
1412
+ const callbacks = await getCallbackManagerForConfig(config);
1413
+ return (await this.func(patchConfig(config, { callbacks }), input));
1414
+ }
1415
+ async *_streamIterator(input, options) {
1416
+ const result = await this.invoke(input, options);
1417
+ if (isAsyncIterable(result)) {
1418
+ for await (const item of result) {
1419
+ yield item;
1420
+ }
1421
+ return;
1422
+ }
1423
+ if (isIterator(result)) {
1424
+ while (true) {
1425
+ const state = result.next();
1426
+ if (state.done)
1427
+ break;
1428
+ yield state.value;
1429
+ }
1430
+ return;
1431
+ }
1432
+ yield result;
1433
+ }
1434
+ static from(func) {
1435
+ return new RunnableTraceable({ func });
1436
+ }
1437
+ }
1438
+ function assertNonTraceableFunction(func) {
1439
+ if (isTraceableFunction(func)) {
1440
+ throw new Error("RunnableLambda requires a function that is not wrapped in traceable higher-order function. This shouldn't happen.");
1441
+ }
1442
+ }
1375
1443
  /**
1376
1444
  * A runnable that runs a callable.
1377
1445
  */
@@ -1380,6 +1448,10 @@ export class RunnableLambda extends Runnable {
1380
1448
  return "RunnableLambda";
1381
1449
  }
1382
1450
  constructor(fields) {
1451
+ if (isTraceableFunction(fields.func)) {
1452
+ // eslint-disable-next-line no-constructor-return
1453
+ return RunnableTraceable.from(fields.func);
1454
+ }
1383
1455
  super(fields);
1384
1456
  Object.defineProperty(this, "lc_namespace", {
1385
1457
  enumerable: true,
@@ -1393,6 +1465,7 @@ export class RunnableLambda extends Runnable {
1393
1465
  writable: true,
1394
1466
  value: void 0
1395
1467
  });
1468
+ assertNonTraceableFunction(fields.func);
1396
1469
  this.func = fields.func;
1397
1470
  }
1398
1471
  static from(func) {
@@ -1440,7 +1513,7 @@ export class RunnableLambda extends Runnable {
1440
1513
  }
1441
1514
  output = finalOutput;
1442
1515
  }
1443
- else if (isIterator(output)) {
1516
+ else if (isIterableIterator(output)) {
1444
1517
  let finalOutput;
1445
1518
  for (const chunk of consumeIteratorInContext(childConfig, output)) {
1446
1519
  if (finalOutput === undefined) {
@@ -1518,7 +1591,7 @@ export class RunnableLambda extends Runnable {
1518
1591
  yield chunk;
1519
1592
  }
1520
1593
  }
1521
- else if (isIterator(output)) {
1594
+ else if (isIterableIterator(output)) {
1522
1595
  for (const chunk of consumeIteratorInContext(config, output)) {
1523
1596
  yield chunk;
1524
1597
  }
@@ -1,14 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.consumeAsyncIterableInContext = exports.consumeIteratorInContext = exports.isAsyncIterable = exports.isIterator = void 0;
3
+ exports.consumeAsyncIterableInContext = exports.consumeIteratorInContext = exports.isAsyncIterable = exports.isIterator = exports.isIterableIterator = void 0;
4
4
  const index_js_1 = require("../singletons/index.cjs");
5
- function isIterator(thing) {
5
+ function isIterableIterator(thing) {
6
6
  return (typeof thing === "object" &&
7
7
  thing !== null &&
8
8
  typeof thing[Symbol.iterator] === "function" &&
9
9
  // avoid detecting array/set as iterator
10
10
  typeof thing.next === "function");
11
11
  }
12
+ exports.isIterableIterator = isIterableIterator;
13
+ const isIterator = (x) => x != null &&
14
+ typeof x === "object" &&
15
+ "next" in x &&
16
+ typeof x.next === "function";
12
17
  exports.isIterator = isIterator;
13
18
  function isAsyncIterable(thing) {
14
19
  return (typeof thing === "object" &&
@@ -1,5 +1,6 @@
1
1
  import { RunnableConfig } from "./config.js";
2
- export declare function isIterator(thing: unknown): thing is IterableIterator<unknown>;
2
+ export declare function isIterableIterator(thing: unknown): thing is IterableIterator<unknown>;
3
+ export declare const isIterator: (x: unknown) => x is Iterator<unknown, any, undefined>;
3
4
  export declare function isAsyncIterable(thing: unknown): thing is AsyncIterable<unknown>;
4
5
  export declare function consumeIteratorInContext<T>(context: Partial<RunnableConfig> | undefined, iter: IterableIterator<T>): IterableIterator<T>;
5
6
  export declare function consumeAsyncIterableInContext<T>(context: Partial<RunnableConfig> | undefined, iter: AsyncIterable<T>): AsyncIterableIterator<T>;
@@ -1,11 +1,15 @@
1
1
  import { AsyncLocalStorageProviderSingleton } from "../singletons/index.js";
2
- export function isIterator(thing) {
2
+ export function isIterableIterator(thing) {
3
3
  return (typeof thing === "object" &&
4
4
  thing !== null &&
5
5
  typeof thing[Symbol.iterator] === "function" &&
6
6
  // avoid detecting array/set as iterator
7
7
  typeof thing.next === "function");
8
8
  }
9
+ export const isIterator = (x) => x != null &&
10
+ typeof x === "object" &&
11
+ "next" in x &&
12
+ typeof x.next === "function";
9
13
  export function isAsyncIterable(thing) {
10
14
  return (typeof thing === "object" &&
11
15
  thing !== null &&
@@ -310,7 +310,8 @@ class RemoteRunnable extends base_js_1.Runnable {
310
310
  async *_streamIterator(input, options) {
311
311
  const [config, kwargs] = this._separateRunnableConfigFromCallOptions(options);
312
312
  const callbackManager_ = await (0, config_js_1.getCallbackManagerForConfig)(options);
313
- const runManager = await callbackManager_?.handleChainStart(this.toJSON(), (0, base_js_1._coerceToDict)(input, "input"), undefined, undefined, undefined, undefined, options?.runName);
313
+ const runManager = await callbackManager_?.handleChainStart(this.toJSON(), (0, base_js_1._coerceToDict)(input, "input"), config.runId, undefined, undefined, undefined, config.runName);
314
+ delete config.runId;
314
315
  let finalOutput;
315
316
  let finalOutputSupported = true;
316
317
  try {
@@ -360,7 +361,8 @@ class RemoteRunnable extends base_js_1.Runnable {
360
361
  async *streamLog(input, options, streamOptions) {
361
362
  const [config, kwargs] = this._separateRunnableConfigFromCallOptions(options);
362
363
  const callbackManager_ = await (0, config_js_1.getCallbackManagerForConfig)(options);
363
- const runManager = await callbackManager_?.handleChainStart(this.toJSON(), (0, base_js_1._coerceToDict)(input, "input"), undefined, undefined, undefined, undefined, options?.runName);
364
+ const runManager = await callbackManager_?.handleChainStart(this.toJSON(), (0, base_js_1._coerceToDict)(input, "input"), config.runId, undefined, undefined, undefined, config.runName);
365
+ delete config.runId;
364
366
  // The type is in camelCase but the API only accepts snake_case.
365
367
  const camelCaseStreamOptions = {
366
368
  include_names: streamOptions?.includeNames,
@@ -411,7 +413,8 @@ class RemoteRunnable extends base_js_1.Runnable {
411
413
  const generator = async function* () {
412
414
  const [config, kwargs] = outerThis._separateRunnableConfigFromCallOptions(options);
413
415
  const callbackManager_ = await (0, config_js_1.getCallbackManagerForConfig)(options);
414
- const runManager = await callbackManager_?.handleChainStart(outerThis.toJSON(), (0, base_js_1._coerceToDict)(input, "input"), undefined, undefined, undefined, undefined, options?.runName);
416
+ const runManager = await callbackManager_?.handleChainStart(outerThis.toJSON(), (0, base_js_1._coerceToDict)(input, "input"), config.runId, undefined, undefined, undefined, config.runName);
417
+ delete config.runId;
415
418
  // The type is in camelCase but the API only accepts snake_case.
416
419
  const camelCaseStreamOptions = {
417
420
  include_names: streamOptions?.includeNames,
@@ -307,7 +307,8 @@ export class RemoteRunnable extends Runnable {
307
307
  async *_streamIterator(input, options) {
308
308
  const [config, kwargs] = this._separateRunnableConfigFromCallOptions(options);
309
309
  const callbackManager_ = await getCallbackManagerForConfig(options);
310
- const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), undefined, undefined, undefined, undefined, options?.runName);
310
+ const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), config.runId, undefined, undefined, undefined, config.runName);
311
+ delete config.runId;
311
312
  let finalOutput;
312
313
  let finalOutputSupported = true;
313
314
  try {
@@ -357,7 +358,8 @@ export class RemoteRunnable extends Runnable {
357
358
  async *streamLog(input, options, streamOptions) {
358
359
  const [config, kwargs] = this._separateRunnableConfigFromCallOptions(options);
359
360
  const callbackManager_ = await getCallbackManagerForConfig(options);
360
- const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), undefined, undefined, undefined, undefined, options?.runName);
361
+ const runManager = await callbackManager_?.handleChainStart(this.toJSON(), _coerceToDict(input, "input"), config.runId, undefined, undefined, undefined, config.runName);
362
+ delete config.runId;
361
363
  // The type is in camelCase but the API only accepts snake_case.
362
364
  const camelCaseStreamOptions = {
363
365
  include_names: streamOptions?.includeNames,
@@ -408,7 +410,8 @@ export class RemoteRunnable extends Runnable {
408
410
  const generator = async function* () {
409
411
  const [config, kwargs] = outerThis._separateRunnableConfigFromCallOptions(options);
410
412
  const callbackManager_ = await getCallbackManagerForConfig(options);
411
- const runManager = await callbackManager_?.handleChainStart(outerThis.toJSON(), _coerceToDict(input, "input"), undefined, undefined, undefined, undefined, options?.runName);
413
+ const runManager = await callbackManager_?.handleChainStart(outerThis.toJSON(), _coerceToDict(input, "input"), config.runId, undefined, undefined, undefined, config.runName);
414
+ delete config.runId;
412
415
  // The type is in camelCase but the API only accepts snake_case.
413
416
  const camelCaseStreamOptions = {
414
417
  include_names: streamOptions?.includeNames,
@@ -70,12 +70,6 @@ class EventStreamCallbackHandler extends base_js_1.BaseTracer {
70
70
  writable: true,
71
71
  value: void 0
72
72
  });
73
- Object.defineProperty(this, "rootId", {
74
- enumerable: true,
75
- configurable: true,
76
- writable: true,
77
- value: void 0
78
- });
79
73
  Object.defineProperty(this, "runInfoMap", {
80
74
  enumerable: true,
81
75
  configurable: true,
@@ -164,7 +158,10 @@ class EventStreamCallbackHandler extends base_js_1.BaseTracer {
164
158
  return;
165
159
  }
166
160
  const runInfo = this.runInfoMap.get(runId);
167
- // run has finished, don't issue any stream events
161
+ // Run has finished, don't issue any stream events.
162
+ // An example of this is for runnables that use the default
163
+ // implementation of .stream(), which delegates to .invoke()
164
+ // and calls .onChainEnd() before passing it to the iterator.
168
165
  if (runInfo === undefined) {
169
166
  yield firstChunk.value;
170
167
  return;
@@ -207,7 +204,7 @@ class EventStreamCallbackHandler extends base_js_1.BaseTracer {
207
204
  finally {
208
205
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
209
206
  tappedPromiseResolver();
210
- // Don't delete from the map to keep track of which runs have been tapped.
207
+ // Don't delete from the promises map to keep track of which runs have been tapped.
211
208
  }
212
209
  }
213
210
  else {
@@ -492,18 +489,11 @@ class EventStreamCallbackHandler extends base_js_1.BaseTracer {
492
489
  metadata: runInfo.metadata,
493
490
  }, runInfo);
494
491
  }
495
- async onRunCreate(run) {
496
- if (this.rootId === undefined) {
497
- this.rootId = run.id;
498
- }
499
- }
500
- async onRunUpdate(run) {
501
- if (run.id === this.rootId && this.autoClose) {
502
- const pendingPromises = [...this.tappedPromises.values()];
503
- void Promise.all(pendingPromises).finally(() => {
504
- void this.writer.close();
505
- });
506
- }
492
+ async finish() {
493
+ const pendingPromises = [...this.tappedPromises.values()];
494
+ void Promise.all(pendingPromises).finally(() => {
495
+ void this.writer.close();
496
+ });
507
497
  }
508
498
  }
509
499
  exports.EventStreamCallbackHandler = EventStreamCallbackHandler;
@@ -109,7 +109,6 @@ export declare class EventStreamCallbackHandler extends BaseTracer {
109
109
  protected excludeNames?: string[];
110
110
  protected excludeTypes?: string[];
111
111
  protected excludeTags?: string[];
112
- protected rootId?: string;
113
112
  private runInfoMap;
114
113
  private tappedPromises;
115
114
  protected transformStream: TransformStream;
@@ -134,7 +133,6 @@ export declare class EventStreamCallbackHandler extends BaseTracer {
134
133
  onToolEnd(run: Run): Promise<void>;
135
134
  onRetrieverStart(run: Run): Promise<void>;
136
135
  onRetrieverEnd(run: Run): Promise<void>;
137
- onRunCreate(run: Run): Promise<void>;
138
- onRunUpdate(run: Run): Promise<void>;
136
+ finish(): Promise<void>;
139
137
  }
140
138
  export {};
@@ -66,12 +66,6 @@ export class EventStreamCallbackHandler extends BaseTracer {
66
66
  writable: true,
67
67
  value: void 0
68
68
  });
69
- Object.defineProperty(this, "rootId", {
70
- enumerable: true,
71
- configurable: true,
72
- writable: true,
73
- value: void 0
74
- });
75
69
  Object.defineProperty(this, "runInfoMap", {
76
70
  enumerable: true,
77
71
  configurable: true,
@@ -160,7 +154,10 @@ export class EventStreamCallbackHandler extends BaseTracer {
160
154
  return;
161
155
  }
162
156
  const runInfo = this.runInfoMap.get(runId);
163
- // run has finished, don't issue any stream events
157
+ // Run has finished, don't issue any stream events.
158
+ // An example of this is for runnables that use the default
159
+ // implementation of .stream(), which delegates to .invoke()
160
+ // and calls .onChainEnd() before passing it to the iterator.
164
161
  if (runInfo === undefined) {
165
162
  yield firstChunk.value;
166
163
  return;
@@ -203,7 +200,7 @@ export class EventStreamCallbackHandler extends BaseTracer {
203
200
  finally {
204
201
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
205
202
  tappedPromiseResolver();
206
- // Don't delete from the map to keep track of which runs have been tapped.
203
+ // Don't delete from the promises map to keep track of which runs have been tapped.
207
204
  }
208
205
  }
209
206
  else {
@@ -488,17 +485,10 @@ export class EventStreamCallbackHandler extends BaseTracer {
488
485
  metadata: runInfo.metadata,
489
486
  }, runInfo);
490
487
  }
491
- async onRunCreate(run) {
492
- if (this.rootId === undefined) {
493
- this.rootId = run.id;
494
- }
495
- }
496
- async onRunUpdate(run) {
497
- if (run.id === this.rootId && this.autoClose) {
498
- const pendingPromises = [...this.tappedPromises.values()];
499
- void Promise.all(pendingPromises).finally(() => {
500
- void this.writer.close();
501
- });
502
- }
488
+ async finish() {
489
+ const pendingPromises = [...this.tappedPromises.values()];
490
+ void Promise.all(pendingPromises).finally(() => {
491
+ void this.writer.close();
492
+ });
503
493
  }
504
494
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LangChainTracer = void 0;
4
4
  const langsmith_1 = require("langsmith");
5
+ const traceable_1 = require("langsmith/singletons/traceable");
5
6
  const env_js_1 = require("../utils/env.cjs");
6
7
  const base_js_1 = require("./base.cjs");
7
8
  class LangChainTracer extends base_js_1.BaseTracer {
@@ -38,6 +39,38 @@ class LangChainTracer extends base_js_1.BaseTracer {
38
39
  (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_SESSION");
39
40
  this.exampleId = exampleId;
40
41
  this.client = client ?? new langsmith_1.Client({});
42
+ // if we're inside traceable, we can obtain the traceable tree
43
+ // and populate the run map, which is used to correctly
44
+ // infer dotted order and execution order
45
+ const traceableTree = this.getTraceableRunTree();
46
+ if (traceableTree) {
47
+ let rootRun = traceableTree;
48
+ const visited = new Set();
49
+ while (rootRun.parent_run) {
50
+ if (visited.has(rootRun.id))
51
+ break;
52
+ visited.add(rootRun.id);
53
+ if (!rootRun.parent_run)
54
+ break;
55
+ rootRun = rootRun.parent_run;
56
+ }
57
+ visited.clear();
58
+ const queue = [rootRun];
59
+ while (queue.length > 0) {
60
+ const current = queue.shift();
61
+ if (!current || visited.has(current.id))
62
+ continue;
63
+ visited.add(current.id);
64
+ // @ts-expect-error Types of property 'events' are incompatible.
65
+ this.runMap.set(current.id, current);
66
+ if (current.child_runs) {
67
+ queue.push(...current.child_runs);
68
+ }
69
+ }
70
+ this.client = traceableTree.client ?? this.client;
71
+ this.projectName = traceableTree.project_name ?? this.projectName;
72
+ this.exampleId = traceableTree.reference_example_id ?? this.exampleId;
73
+ }
41
74
  }
42
75
  async _convertToCreate(run, example_id = undefined) {
43
76
  return {
@@ -72,5 +105,13 @@ class LangChainTracer extends base_js_1.BaseTracer {
72
105
  getRun(id) {
73
106
  return this.runMap.get(id);
74
107
  }
108
+ getTraceableRunTree() {
109
+ try {
110
+ return (0, traceable_1.getCurrentRunTree)();
111
+ }
112
+ catch {
113
+ return undefined;
114
+ }
115
+ }
75
116
  }
76
117
  exports.LangChainTracer = LangChainTracer;
@@ -1,4 +1,5 @@
1
1
  import { Client } from "langsmith";
2
+ import { RunTree } from "langsmith/run_trees";
2
3
  import { BaseRun, RunCreate, RunUpdate as BaseRunUpdate, KVMap } from "langsmith/schemas";
3
4
  import { BaseTracer } from "./base.js";
4
5
  import { BaseCallbackHandlerInput } from "../callbacks/base.js";
@@ -35,4 +36,5 @@ export declare class LangChainTracer extends BaseTracer implements LangChainTrac
35
36
  onRunCreate(run: Run): Promise<void>;
36
37
  onRunUpdate(run: Run): Promise<void>;
37
38
  getRun(id: string): Run | undefined;
39
+ getTraceableRunTree(): RunTree | undefined;
38
40
  }
@@ -1,4 +1,5 @@
1
1
  import { Client } from "langsmith";
2
+ import { getCurrentRunTree } from "langsmith/singletons/traceable";
2
3
  import { getEnvironmentVariable, getRuntimeEnvironment } from "../utils/env.js";
3
4
  import { BaseTracer } from "./base.js";
4
5
  export class LangChainTracer extends BaseTracer {
@@ -35,6 +36,38 @@ export class LangChainTracer extends BaseTracer {
35
36
  getEnvironmentVariable("LANGCHAIN_SESSION");
36
37
  this.exampleId = exampleId;
37
38
  this.client = client ?? new Client({});
39
+ // if we're inside traceable, we can obtain the traceable tree
40
+ // and populate the run map, which is used to correctly
41
+ // infer dotted order and execution order
42
+ const traceableTree = this.getTraceableRunTree();
43
+ if (traceableTree) {
44
+ let rootRun = traceableTree;
45
+ const visited = new Set();
46
+ while (rootRun.parent_run) {
47
+ if (visited.has(rootRun.id))
48
+ break;
49
+ visited.add(rootRun.id);
50
+ if (!rootRun.parent_run)
51
+ break;
52
+ rootRun = rootRun.parent_run;
53
+ }
54
+ visited.clear();
55
+ const queue = [rootRun];
56
+ while (queue.length > 0) {
57
+ const current = queue.shift();
58
+ if (!current || visited.has(current.id))
59
+ continue;
60
+ visited.add(current.id);
61
+ // @ts-expect-error Types of property 'events' are incompatible.
62
+ this.runMap.set(current.id, current);
63
+ if (current.child_runs) {
64
+ queue.push(...current.child_runs);
65
+ }
66
+ }
67
+ this.client = traceableTree.client ?? this.client;
68
+ this.projectName = traceableTree.project_name ?? this.projectName;
69
+ this.exampleId = traceableTree.reference_example_id ?? this.exampleId;
70
+ }
38
71
  }
39
72
  async _convertToCreate(run, example_id = undefined) {
40
73
  return {
@@ -69,4 +102,12 @@ export class LangChainTracer extends BaseTracer {
69
102
  getRun(id) {
70
103
  return this.runMap.get(id);
71
104
  }
105
+ getTraceableRunTree() {
106
+ try {
107
+ return getCurrentRunTree();
108
+ }
109
+ catch {
110
+ return undefined;
111
+ }
112
+ }
72
113
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/core",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Core LangChain.js abstractions and schemas",
5
5
  "type": "module",
6
6
  "engines": {
@@ -45,7 +45,7 @@
45
45
  "camelcase": "6",
46
46
  "decamelize": "1.2.0",
47
47
  "js-tiktoken": "^1.0.12",
48
- "langsmith": "~0.1.7",
48
+ "langsmith": "~0.1.30",
49
49
  "ml-distance": "^4.0.0",
50
50
  "mustache": "^4.2.0",
51
51
  "p-queue": "^6.6.2",