langchain 0.0.182-rc.1 → 0.0.182

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.
@@ -7,6 +7,7 @@ const prompt_js_1 = require("./prompt.cjs");
7
7
  const chat_js_1 = require("../../prompts/chat.cjs");
8
8
  const llm_chain_js_1 = require("../../chains/llm_chain.cjs");
9
9
  const output_parser_js_1 = require("./output_parser.cjs");
10
+ const convert_to_openai_js_1 = require("../../tools/convert_to_openai.cjs");
10
11
  /**
11
12
  * Checks if the given action is a FunctionsAgentAction.
12
13
  * @param action The action to check.
@@ -140,7 +141,7 @@ class OpenAIAgent extends agent_js_1.Agent {
140
141
  const llm = this.llmChain.llm;
141
142
  const valuesForPrompt = { ...newInputs };
142
143
  const valuesForLLM = {
143
- tools: this.tools,
144
+ functions: this.tools.map(convert_to_openai_js_1.formatToOpenAIFunction),
144
145
  };
145
146
  for (const key of this.llmChain.llm.callKeys) {
146
147
  if (key in inputs) {
@@ -4,6 +4,7 @@ import { PREFIX } from "./prompt.js";
4
4
  import { ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate, } from "../../prompts/chat.js";
5
5
  import { LLMChain } from "../../chains/llm_chain.js";
6
6
  import { OpenAIFunctionsAgentOutputParser, } from "./output_parser.js";
7
+ import { formatToOpenAIFunction } from "../../tools/convert_to_openai.js";
7
8
  /**
8
9
  * Checks if the given action is a FunctionsAgentAction.
9
10
  * @param action The action to check.
@@ -136,7 +137,7 @@ export class OpenAIAgent extends Agent {
136
137
  const llm = this.llmChain.llm;
137
138
  const valuesForPrompt = { ...newInputs };
138
139
  const valuesForLLM = {
139
- tools: this.tools,
140
+ functions: this.tools.map(formatToOpenAIFunction),
140
141
  };
141
142
  for (const key of this.llmChain.llm.callKeys) {
142
143
  if (key in inputs) {
@@ -12,7 +12,7 @@ import { Generation, StoredGeneration } from "../schema/index.js";
12
12
  export declare const getCacheKey: (...strings: string[]) => string;
13
13
  export declare function deserializeStoredGeneration(storedGeneration: StoredGeneration): {
14
14
  text: string;
15
- message: import("../schema/index.js").ChatMessage | import("../schema/index.js").HumanMessage | import("../schema/index.js").AIMessage | import("../schema/index.js").SystemMessage | import("../schema/index.js").FunctionMessage;
15
+ message: import("../schema/index.js").ChatMessage | import("../schema/index.js").HumanMessage | import("../schema/index.js").AIMessage | import("../schema/index.js").SystemMessage | import("../schema/index.js").FunctionMessage | import("../schema/index.js").ToolMessage;
16
16
  } | {
17
17
  text: string;
18
18
  message?: undefined;
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ChatBedrock = exports.BedrockChat = exports.convertMessagesToPrompt = exports.convertMessagesToPromptAnthropic = void 0;
4
4
  const signature_v4_1 = require("@smithy/signature-v4");
5
- const credential_provider_node_1 = require("@aws-sdk/credential-provider-node");
6
5
  const protocol_http_1 = require("@smithy/protocol-http");
7
6
  const eventstream_codec_1 = require("@smithy/eventstream-codec");
8
7
  const util_utf8_1 = require("@smithy/util-utf8");
@@ -168,7 +167,7 @@ class BedrockChat extends base_js_1.SimpleChatModel {
168
167
  throw new Error("Please set the AWS_DEFAULT_REGION environment variable or pass it to the constructor as the region field.");
169
168
  }
170
169
  this.region = region;
171
- const credentials = fields?.credentials ?? (0, credential_provider_node_1.defaultProvider)();
170
+ const credentials = fields?.credentials;
172
171
  if (!credentials) {
173
172
  throw new Error("Please set the AWS credentials in the 'credentials' field.");
174
173
  }
@@ -1,5 +1,4 @@
1
1
  import { SignatureV4 } from "@smithy/signature-v4";
2
- import { defaultProvider } from "@aws-sdk/credential-provider-node";
3
2
  import { HttpRequest } from "@smithy/protocol-http";
4
3
  import { EventStreamCodec } from "@smithy/eventstream-codec";
5
4
  import { fromUtf8, toUtf8 } from "@smithy/util-utf8";
@@ -163,7 +162,7 @@ export class BedrockChat extends SimpleChatModel {
163
162
  throw new Error("Please set the AWS_DEFAULT_REGION environment variable or pass it to the constructor as the region field.");
164
163
  }
165
164
  this.region = region;
166
- const credentials = fields?.credentials ?? defaultProvider();
165
+ const credentials = fields?.credentials;
167
166
  if (!credentials) {
168
167
  throw new Error("Please set the AWS credentials in the 'credentials' field.");
169
168
  }
@@ -14,7 +14,8 @@ function extractGenericMessageCustomRole(message) {
14
14
  if (message.role !== "system" &&
15
15
  message.role !== "assistant" &&
16
16
  message.role !== "user" &&
17
- message.role !== "function") {
17
+ message.role !== "function" &&
18
+ message.role !== "tool") {
18
19
  console.warn(`Unknown message role: ${message.role}`);
19
20
  }
20
21
  return message.role;
@@ -30,6 +31,8 @@ function messageToOpenAIRole(message) {
30
31
  return "user";
31
32
  case "function":
32
33
  return "function";
34
+ case "tool":
35
+ return "tool";
33
36
  case "generic": {
34
37
  if (!index_js_1.ChatMessage.isInstance(message))
35
38
  throw new Error("Invalid generic chat message");
@@ -39,24 +42,12 @@ function messageToOpenAIRole(message) {
39
42
  throw new Error(`Unknown message type: ${type}`);
40
43
  }
41
44
  }
42
- function messageToOpenAIMessage(message) {
43
- const msg = {
44
- content: message.content || null,
45
- name: message.name,
46
- role: messageToOpenAIRole(message),
47
- function_call: message.additional_kwargs.function_call,
48
- };
49
- if (msg.function_call?.arguments) {
50
- // Remove spaces, new line characters etc.
51
- msg.function_call.arguments = JSON.stringify(JSON.parse(msg.function_call.arguments));
52
- }
53
- return msg;
54
- }
55
45
  function openAIResponseToChatMessage(message) {
56
46
  switch (message.role) {
57
47
  case "assistant":
58
48
  return new index_js_1.AIMessage(message.content || "", {
59
49
  function_call: message.function_call,
50
+ tool_calls: message.tool_calls,
60
51
  });
61
52
  default:
62
53
  return new index_js_1.ChatMessage(message.content || "", message.role ?? "unknown");
@@ -73,6 +64,11 @@ delta, defaultRole) {
73
64
  function_call: delta.function_call,
74
65
  };
75
66
  }
67
+ else if (delta.tool_calls) {
68
+ additional_kwargs = {
69
+ tool_calls: delta.tool_calls,
70
+ };
71
+ }
76
72
  else {
77
73
  additional_kwargs = {};
78
74
  }
@@ -92,10 +88,28 @@ delta, defaultRole) {
92
88
  name: delta.name,
93
89
  });
94
90
  }
91
+ else if (role === "tool") {
92
+ return new index_js_1.ToolMessageChunk({
93
+ content,
94
+ additional_kwargs,
95
+ tool_call_id: delta.tool_call_id,
96
+ });
97
+ }
95
98
  else {
96
99
  return new index_js_1.ChatMessageChunk({ content, role });
97
100
  }
98
101
  }
102
+ function convertMessagesToOpenAIParams(messages) {
103
+ // TODO: Function messages do not support array content, fix cast
104
+ return messages.map((message) => ({
105
+ role: messageToOpenAIRole(message),
106
+ content: message.content,
107
+ name: message.name,
108
+ function_call: message.additional_kwargs.function_call,
109
+ tool_calls: message.additional_kwargs.tool_calls,
110
+ tool_call_id: message.tool_call_id,
111
+ }));
112
+ }
99
113
  /**
100
114
  * Wrapper around OpenAI large language models that use the Chat endpoint.
101
115
  *
@@ -126,6 +140,7 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
126
140
  "function_call",
127
141
  "functions",
128
142
  "tools",
143
+ "tool_choice",
129
144
  "promptIndex",
130
145
  "response_format",
131
146
  "seed",
@@ -355,7 +370,11 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
355
370
  * Get the parameters used to invoke the model
356
371
  */
357
372
  invocationParams(options) {
358
- return {
373
+ function isStructuredToolArray(tools) {
374
+ return (tools !== undefined &&
375
+ tools.every((tool) => Array.isArray(tool.lc_namespace)));
376
+ }
377
+ const params = {
359
378
  model: this.modelName,
360
379
  temperature: this.temperature,
361
380
  top_p: this.topP,
@@ -367,15 +386,17 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
367
386
  stop: options?.stop ?? this.stop,
368
387
  user: this.user,
369
388
  stream: this.streaming,
370
- functions: options?.functions ??
371
- (options?.tools
372
- ? options?.tools.map(convert_to_openai_js_1.formatToOpenAIFunction)
373
- : undefined),
389
+ functions: options?.functions,
374
390
  function_call: options?.function_call,
391
+ tools: isStructuredToolArray(options?.tools)
392
+ ? options?.tools.map(convert_to_openai_js_1.formatToOpenAITool)
393
+ : options?.tools,
394
+ tool_choice: options?.tool_choice,
375
395
  response_format: options?.response_format,
376
396
  seed: options?.seed,
377
397
  ...this.modelKwargs,
378
398
  };
399
+ return params;
379
400
  }
380
401
  /** @ignore */
381
402
  _identifyingParams() {
@@ -386,13 +407,7 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
386
407
  };
387
408
  }
388
409
  async *_streamResponseChunks(messages, options, runManager) {
389
- const messagesMapped = messages.map((message) => ({
390
- role: messageToOpenAIRole(message),
391
- content: message.content,
392
- name: message.name,
393
- function_call: message.additional_kwargs
394
- .function_call,
395
- }));
410
+ const messagesMapped = convertMessagesToOpenAIParams(messages);
396
411
  const params = {
397
412
  ...this.invocationParams(options),
398
413
  messages: messagesMapped,
@@ -412,6 +427,10 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
412
427
  prompt: options.promptIndex ?? 0,
413
428
  completion: choice.index ?? 0,
414
429
  };
430
+ if (typeof chunk.content !== "string") {
431
+ console.log("[WARNING]: Received non-string content from OpenAI. This is currently not supported.");
432
+ continue;
433
+ }
415
434
  const generationChunk = new index_js_1.ChatGenerationChunk({
416
435
  message: chunk,
417
436
  text: chunk.content,
@@ -436,13 +455,7 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
436
455
  async _generate(messages, options, runManager) {
437
456
  const tokenUsage = {};
438
457
  const params = this.invocationParams(options);
439
- const messagesMapped = messages.map((message) => ({
440
- role: messageToOpenAIRole(message),
441
- content: message.content,
442
- name: message.name,
443
- function_call: message.additional_kwargs
444
- .function_call,
445
- }));
458
+ const messagesMapped = convertMessagesToOpenAIParams(messages);
446
459
  if (params.stream) {
447
460
  const stream = this._streamResponseChunks(messages, options, runManager);
448
461
  const finalChunks = {};
@@ -461,7 +474,7 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
461
474
  const { functions, function_call } = this.invocationParams(options);
462
475
  // OpenAI does not support token usage report under stream mode,
463
476
  // fallback to estimation.
464
- const promptTokenUsage = await this.getNumTokensFromPrompt(messages, functions, function_call);
477
+ const promptTokenUsage = await this.getEstimatedTokenCountFromPrompt(messages, functions, function_call);
465
478
  const completionTokenUsage = await this.getNumTokensFromGenerations(generations);
466
479
  tokenUsage.promptTokens = promptTokenUsage;
467
480
  tokenUsage.completionTokens = completionTokenUsage;
@@ -510,11 +523,9 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
510
523
  * Estimate the number of tokens a prompt will use.
511
524
  * Modified from: https://github.com/hmarr/openai-chat-tokens/blob/main/src/index.ts
512
525
  */
513
- async getNumTokensFromPrompt(messages, functions, function_call) {
526
+ async getEstimatedTokenCountFromPrompt(messages, functions, function_call) {
514
527
  // It appears that if functions are present, the first system message is padded with a trailing newline. This
515
528
  // was inferred by trying lots of combinations of messages and functions and seeing what the token counts were.
516
- // let paddedSystem = false;
517
- const openaiMessages = messages.map((m) => messageToOpenAIMessage(m));
518
529
  let tokens = (await this.getNumTokensFromMessages(messages)).totalCount;
519
530
  // If there are functions, add the function definitions as they count towards token usage
520
531
  if (functions && function_call !== "auto") {
@@ -525,7 +536,7 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
525
536
  // If there's a system message _and_ functions are present, subtract four tokens. I assume this is because
526
537
  // functions typically add a system message, but reuse the first one if it's already there. This offsets
527
538
  // the extra 9 tokens added by the function definitions.
528
- if (functions && openaiMessages.find((m) => m.role === "system")) {
539
+ if (functions && messages.find((m) => m._getType() === "system")) {
529
540
  tokens -= 4;
530
541
  }
531
542
  // If function_call is 'none', add one token.
@@ -544,8 +555,7 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
544
555
  */
545
556
  async getNumTokensFromGenerations(generations) {
546
557
  const generationUsages = await Promise.all(generations.map(async (generation) => {
547
- const openAIMessage = messageToOpenAIMessage(generation.message);
548
- if (openAIMessage.function_call) {
558
+ if (generation.message.additional_kwargs?.function_call) {
549
559
  return (await this.getNumTokensFromMessages([generation.message]))
550
560
  .countPerMessage[0];
551
561
  }
@@ -576,19 +586,20 @@ class ChatOpenAI extends base_js_1.BaseChatModel {
576
586
  : 0;
577
587
  let count = textCount + tokensPerMessage + roleCount + nameCount;
578
588
  // From: https://github.com/hmarr/openai-chat-tokens/blob/main/src/index.ts messageTokenEstimate
579
- const openAIMessage = messageToOpenAIMessage(message);
580
- if (openAIMessage.role === "function" ||
581
- openAIMessage.role === "tool") {
589
+ const openAIMessage = message;
590
+ if (openAIMessage._getType() === "function") {
582
591
  count -= 2;
583
592
  }
584
- if (openAIMessage.function_call) {
593
+ if (openAIMessage.additional_kwargs?.function_call) {
585
594
  count += 3;
586
595
  }
587
- if (openAIMessage.function_call?.name) {
588
- count += await this.getNumTokens(openAIMessage.function_call?.name);
596
+ if (openAIMessage?.additional_kwargs.function_call?.name) {
597
+ count += await this.getNumTokens(openAIMessage.additional_kwargs.function_call?.name);
589
598
  }
590
- if (openAIMessage.function_call?.arguments) {
591
- count += await this.getNumTokens(openAIMessage.function_call?.arguments);
599
+ if (openAIMessage.additional_kwargs.function_call?.arguments) {
600
+ count += await this.getNumTokens(
601
+ // Remove newlines and spaces
602
+ JSON.stringify(JSON.parse(openAIMessage.additional_kwargs.function_call?.arguments)));
592
603
  }
593
604
  totalCount += count;
594
605
  return count;
@@ -15,7 +15,8 @@ interface OpenAILLMOutput {
15
15
  tokenUsage: TokenUsage;
16
16
  }
17
17
  export interface ChatOpenAICallOptions extends OpenAICallOptions, BaseFunctionCallOptions {
18
- tools?: StructuredTool[];
18
+ tools?: StructuredTool[] | OpenAIClient.ChatCompletionTool[];
19
+ tool_choice?: OpenAIClient.ChatCompletionToolChoiceOption;
19
20
  promptIndex?: number;
20
21
  response_format?: {
21
22
  type: "json_object";
@@ -98,7 +99,7 @@ export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = Chat
98
99
  * Estimate the number of tokens a prompt will use.
99
100
  * Modified from: https://github.com/hmarr/openai-chat-tokens/blob/main/src/index.ts
100
101
  */
101
- private getNumTokensFromPrompt;
102
+ private getEstimatedTokenCountFromPrompt;
102
103
  /**
103
104
  * Estimate the number of tokens an array of generations have used.
104
105
  */
@@ -1,6 +1,6 @@
1
1
  import { OpenAI as OpenAIClient } from "openai";
2
- import { AIMessage, AIMessageChunk, ChatGenerationChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, } from "../schema/index.js";
3
- import { formatToOpenAIFunction } from "../tools/convert_to_openai.js";
2
+ import { AIMessage, AIMessageChunk, ChatGenerationChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, } from "../schema/index.js";
3
+ import { formatToOpenAITool } from "../tools/convert_to_openai.js";
4
4
  import { getEndpoint } from "../util/azure.js";
5
5
  import { getEnvironmentVariable } from "../util/env.js";
6
6
  import { promptLayerTrackRequest } from "../util/prompt-layer.js";
@@ -11,7 +11,8 @@ function extractGenericMessageCustomRole(message) {
11
11
  if (message.role !== "system" &&
12
12
  message.role !== "assistant" &&
13
13
  message.role !== "user" &&
14
- message.role !== "function") {
14
+ message.role !== "function" &&
15
+ message.role !== "tool") {
15
16
  console.warn(`Unknown message role: ${message.role}`);
16
17
  }
17
18
  return message.role;
@@ -27,6 +28,8 @@ function messageToOpenAIRole(message) {
27
28
  return "user";
28
29
  case "function":
29
30
  return "function";
31
+ case "tool":
32
+ return "tool";
30
33
  case "generic": {
31
34
  if (!ChatMessage.isInstance(message))
32
35
  throw new Error("Invalid generic chat message");
@@ -36,24 +39,12 @@ function messageToOpenAIRole(message) {
36
39
  throw new Error(`Unknown message type: ${type}`);
37
40
  }
38
41
  }
39
- function messageToOpenAIMessage(message) {
40
- const msg = {
41
- content: message.content || null,
42
- name: message.name,
43
- role: messageToOpenAIRole(message),
44
- function_call: message.additional_kwargs.function_call,
45
- };
46
- if (msg.function_call?.arguments) {
47
- // Remove spaces, new line characters etc.
48
- msg.function_call.arguments = JSON.stringify(JSON.parse(msg.function_call.arguments));
49
- }
50
- return msg;
51
- }
52
42
  function openAIResponseToChatMessage(message) {
53
43
  switch (message.role) {
54
44
  case "assistant":
55
45
  return new AIMessage(message.content || "", {
56
46
  function_call: message.function_call,
47
+ tool_calls: message.tool_calls,
57
48
  });
58
49
  default:
59
50
  return new ChatMessage(message.content || "", message.role ?? "unknown");
@@ -70,6 +61,11 @@ delta, defaultRole) {
70
61
  function_call: delta.function_call,
71
62
  };
72
63
  }
64
+ else if (delta.tool_calls) {
65
+ additional_kwargs = {
66
+ tool_calls: delta.tool_calls,
67
+ };
68
+ }
73
69
  else {
74
70
  additional_kwargs = {};
75
71
  }
@@ -89,10 +85,28 @@ delta, defaultRole) {
89
85
  name: delta.name,
90
86
  });
91
87
  }
88
+ else if (role === "tool") {
89
+ return new ToolMessageChunk({
90
+ content,
91
+ additional_kwargs,
92
+ tool_call_id: delta.tool_call_id,
93
+ });
94
+ }
92
95
  else {
93
96
  return new ChatMessageChunk({ content, role });
94
97
  }
95
98
  }
99
+ function convertMessagesToOpenAIParams(messages) {
100
+ // TODO: Function messages do not support array content, fix cast
101
+ return messages.map((message) => ({
102
+ role: messageToOpenAIRole(message),
103
+ content: message.content,
104
+ name: message.name,
105
+ function_call: message.additional_kwargs.function_call,
106
+ tool_calls: message.additional_kwargs.tool_calls,
107
+ tool_call_id: message.tool_call_id,
108
+ }));
109
+ }
96
110
  /**
97
111
  * Wrapper around OpenAI large language models that use the Chat endpoint.
98
112
  *
@@ -123,6 +137,7 @@ export class ChatOpenAI extends BaseChatModel {
123
137
  "function_call",
124
138
  "functions",
125
139
  "tools",
140
+ "tool_choice",
126
141
  "promptIndex",
127
142
  "response_format",
128
143
  "seed",
@@ -352,7 +367,11 @@ export class ChatOpenAI extends BaseChatModel {
352
367
  * Get the parameters used to invoke the model
353
368
  */
354
369
  invocationParams(options) {
355
- return {
370
+ function isStructuredToolArray(tools) {
371
+ return (tools !== undefined &&
372
+ tools.every((tool) => Array.isArray(tool.lc_namespace)));
373
+ }
374
+ const params = {
356
375
  model: this.modelName,
357
376
  temperature: this.temperature,
358
377
  top_p: this.topP,
@@ -364,15 +383,17 @@ export class ChatOpenAI extends BaseChatModel {
364
383
  stop: options?.stop ?? this.stop,
365
384
  user: this.user,
366
385
  stream: this.streaming,
367
- functions: options?.functions ??
368
- (options?.tools
369
- ? options?.tools.map(formatToOpenAIFunction)
370
- : undefined),
386
+ functions: options?.functions,
371
387
  function_call: options?.function_call,
388
+ tools: isStructuredToolArray(options?.tools)
389
+ ? options?.tools.map(formatToOpenAITool)
390
+ : options?.tools,
391
+ tool_choice: options?.tool_choice,
372
392
  response_format: options?.response_format,
373
393
  seed: options?.seed,
374
394
  ...this.modelKwargs,
375
395
  };
396
+ return params;
376
397
  }
377
398
  /** @ignore */
378
399
  _identifyingParams() {
@@ -383,13 +404,7 @@ export class ChatOpenAI extends BaseChatModel {
383
404
  };
384
405
  }
385
406
  async *_streamResponseChunks(messages, options, runManager) {
386
- const messagesMapped = messages.map((message) => ({
387
- role: messageToOpenAIRole(message),
388
- content: message.content,
389
- name: message.name,
390
- function_call: message.additional_kwargs
391
- .function_call,
392
- }));
407
+ const messagesMapped = convertMessagesToOpenAIParams(messages);
393
408
  const params = {
394
409
  ...this.invocationParams(options),
395
410
  messages: messagesMapped,
@@ -409,6 +424,10 @@ export class ChatOpenAI extends BaseChatModel {
409
424
  prompt: options.promptIndex ?? 0,
410
425
  completion: choice.index ?? 0,
411
426
  };
427
+ if (typeof chunk.content !== "string") {
428
+ console.log("[WARNING]: Received non-string content from OpenAI. This is currently not supported.");
429
+ continue;
430
+ }
412
431
  const generationChunk = new ChatGenerationChunk({
413
432
  message: chunk,
414
433
  text: chunk.content,
@@ -433,13 +452,7 @@ export class ChatOpenAI extends BaseChatModel {
433
452
  async _generate(messages, options, runManager) {
434
453
  const tokenUsage = {};
435
454
  const params = this.invocationParams(options);
436
- const messagesMapped = messages.map((message) => ({
437
- role: messageToOpenAIRole(message),
438
- content: message.content,
439
- name: message.name,
440
- function_call: message.additional_kwargs
441
- .function_call,
442
- }));
455
+ const messagesMapped = convertMessagesToOpenAIParams(messages);
443
456
  if (params.stream) {
444
457
  const stream = this._streamResponseChunks(messages, options, runManager);
445
458
  const finalChunks = {};
@@ -458,7 +471,7 @@ export class ChatOpenAI extends BaseChatModel {
458
471
  const { functions, function_call } = this.invocationParams(options);
459
472
  // OpenAI does not support token usage report under stream mode,
460
473
  // fallback to estimation.
461
- const promptTokenUsage = await this.getNumTokensFromPrompt(messages, functions, function_call);
474
+ const promptTokenUsage = await this.getEstimatedTokenCountFromPrompt(messages, functions, function_call);
462
475
  const completionTokenUsage = await this.getNumTokensFromGenerations(generations);
463
476
  tokenUsage.promptTokens = promptTokenUsage;
464
477
  tokenUsage.completionTokens = completionTokenUsage;
@@ -507,11 +520,9 @@ export class ChatOpenAI extends BaseChatModel {
507
520
  * Estimate the number of tokens a prompt will use.
508
521
  * Modified from: https://github.com/hmarr/openai-chat-tokens/blob/main/src/index.ts
509
522
  */
510
- async getNumTokensFromPrompt(messages, functions, function_call) {
523
+ async getEstimatedTokenCountFromPrompt(messages, functions, function_call) {
511
524
  // It appears that if functions are present, the first system message is padded with a trailing newline. This
512
525
  // was inferred by trying lots of combinations of messages and functions and seeing what the token counts were.
513
- // let paddedSystem = false;
514
- const openaiMessages = messages.map((m) => messageToOpenAIMessage(m));
515
526
  let tokens = (await this.getNumTokensFromMessages(messages)).totalCount;
516
527
  // If there are functions, add the function definitions as they count towards token usage
517
528
  if (functions && function_call !== "auto") {
@@ -522,7 +533,7 @@ export class ChatOpenAI extends BaseChatModel {
522
533
  // If there's a system message _and_ functions are present, subtract four tokens. I assume this is because
523
534
  // functions typically add a system message, but reuse the first one if it's already there. This offsets
524
535
  // the extra 9 tokens added by the function definitions.
525
- if (functions && openaiMessages.find((m) => m.role === "system")) {
536
+ if (functions && messages.find((m) => m._getType() === "system")) {
526
537
  tokens -= 4;
527
538
  }
528
539
  // If function_call is 'none', add one token.
@@ -541,8 +552,7 @@ export class ChatOpenAI extends BaseChatModel {
541
552
  */
542
553
  async getNumTokensFromGenerations(generations) {
543
554
  const generationUsages = await Promise.all(generations.map(async (generation) => {
544
- const openAIMessage = messageToOpenAIMessage(generation.message);
545
- if (openAIMessage.function_call) {
555
+ if (generation.message.additional_kwargs?.function_call) {
546
556
  return (await this.getNumTokensFromMessages([generation.message]))
547
557
  .countPerMessage[0];
548
558
  }
@@ -573,19 +583,20 @@ export class ChatOpenAI extends BaseChatModel {
573
583
  : 0;
574
584
  let count = textCount + tokensPerMessage + roleCount + nameCount;
575
585
  // From: https://github.com/hmarr/openai-chat-tokens/blob/main/src/index.ts messageTokenEstimate
576
- const openAIMessage = messageToOpenAIMessage(message);
577
- if (openAIMessage.role === "function" ||
578
- openAIMessage.role === "tool") {
586
+ const openAIMessage = message;
587
+ if (openAIMessage._getType() === "function") {
579
588
  count -= 2;
580
589
  }
581
- if (openAIMessage.function_call) {
590
+ if (openAIMessage.additional_kwargs?.function_call) {
582
591
  count += 3;
583
592
  }
584
- if (openAIMessage.function_call?.name) {
585
- count += await this.getNumTokens(openAIMessage.function_call?.name);
593
+ if (openAIMessage?.additional_kwargs.function_call?.name) {
594
+ count += await this.getNumTokens(openAIMessage.additional_kwargs.function_call?.name);
586
595
  }
587
- if (openAIMessage.function_call?.arguments) {
588
- count += await this.getNumTokens(openAIMessage.function_call?.arguments);
596
+ if (openAIMessage.additional_kwargs.function_call?.arguments) {
597
+ count += await this.getNumTokens(
598
+ // Remove newlines and spaces
599
+ JSON.stringify(JSON.parse(openAIMessage.additional_kwargs.function_call?.arguments)));
589
600
  }
590
601
  totalCount += count;
591
602
  return count;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.ApifyDatasetLoader = void 0;
4
5
  const apify_client_1 = require("apify-client");
@@ -1,22 +1,22 @@
1
- import { ApifyClient, ApifyClientOptions, ActorCallOptions, TaskCallOptions } from "apify-client";
2
- import { Document } from "../../document.js";
1
+ import { ActorCallOptions, ApifyClient, ApifyClientOptions, TaskCallOptions } from "apify-client";
3
2
  import { BaseDocumentLoader, DocumentLoader } from "../base.js";
3
+ import { Document } from "../../document.js";
4
4
  /**
5
5
  * A type that represents a function that takes a single object (an Apify
6
6
  * dataset item) and converts it to an instance of the Document class.
7
7
  */
8
- export type ApifyDatasetMappingFunction = (item: Record<string | number, unknown>) => Document;
8
+ export type ApifyDatasetMappingFunction<Metadata extends Record<string, any>> = (item: Record<string | number, unknown>) => Document<Metadata>;
9
9
  /**
10
10
  * A class that extends the BaseDocumentLoader and implements the
11
11
  * DocumentLoader interface. It represents a document loader that loads
12
12
  * documents from an Apify dataset.
13
13
  */
14
- export declare class ApifyDatasetLoader extends BaseDocumentLoader implements DocumentLoader {
14
+ export declare class ApifyDatasetLoader<Metadata extends Record<string, any>> extends BaseDocumentLoader implements DocumentLoader {
15
15
  protected apifyClient: ApifyClient;
16
16
  protected datasetId: string;
17
- protected datasetMappingFunction: (item: Record<string | number, unknown>) => Document;
17
+ protected datasetMappingFunction: (item: Record<string | number, unknown>) => Document<Metadata>;
18
18
  constructor(datasetId: string, config: {
19
- datasetMappingFunction: ApifyDatasetMappingFunction;
19
+ datasetMappingFunction: ApifyDatasetMappingFunction<Metadata>;
20
20
  clientOptions?: ApifyClientOptions;
21
21
  });
22
22
  private static _getApifyApiToken;
@@ -26,7 +26,7 @@ export declare class ApifyDatasetLoader extends BaseDocumentLoader implements Do
26
26
  * instances.
27
27
  * @returns An array of Document instances.
28
28
  */
29
- load(): Promise<Document[]>;
29
+ load(): Promise<Document<Metadata>[]>;
30
30
  /**
31
31
  * Create an ApifyDatasetLoader by calling an Actor on the Apify platform and waiting for its results to be ready.
32
32
  * @param actorId The ID or name of the Actor on the Apify platform.
@@ -35,11 +35,11 @@ export declare class ApifyDatasetLoader extends BaseDocumentLoader implements Do
35
35
  * @param options.datasetMappingFunction A function that takes a single object (an Apify dataset item) and converts it to an instance of the Document class.
36
36
  * @returns An instance of `ApifyDatasetLoader` with the results from the Actor run.
37
37
  */
38
- static fromActorCall(actorId: string, input: Record<string | number, unknown>, config: {
38
+ static fromActorCall<Metadata extends Record<string, any>>(actorId: string, input: Record<string | number, unknown>, config: {
39
39
  callOptions?: ActorCallOptions;
40
40
  clientOptions?: ApifyClientOptions;
41
- datasetMappingFunction: ApifyDatasetMappingFunction;
42
- }): Promise<ApifyDatasetLoader>;
41
+ datasetMappingFunction: ApifyDatasetMappingFunction<Metadata>;
42
+ }): Promise<ApifyDatasetLoader<Metadata>>;
43
43
  /**
44
44
  * Create an ApifyDatasetLoader by calling a saved Actor task on the Apify platform and waiting for its results to be ready.
45
45
  * @param taskId The ID or name of the task on the Apify platform.
@@ -48,9 +48,9 @@ export declare class ApifyDatasetLoader extends BaseDocumentLoader implements Do
48
48
  * @param options.datasetMappingFunction A function that takes a single object (an Apify dataset item) and converts it to an instance of the Document class.
49
49
  * @returns An instance of `ApifyDatasetLoader` with the results from the task's run.
50
50
  */
51
- static fromActorTaskCall(taskId: string, input: Record<string | number, unknown>, config: {
51
+ static fromActorTaskCall<Metadata extends Record<string, any>>(taskId: string, input: Record<string | number, unknown>, config: {
52
52
  callOptions?: TaskCallOptions;
53
53
  clientOptions?: ApifyClientOptions;
54
- datasetMappingFunction: ApifyDatasetMappingFunction;
55
- }): Promise<ApifyDatasetLoader>;
54
+ datasetMappingFunction: ApifyDatasetMappingFunction<Metadata>;
55
+ }): Promise<ApifyDatasetLoader<Metadata>>;
56
56
  }
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import { ApifyClient, } from "apify-client";
2
3
  import { BaseDocumentLoader } from "../base.js";
3
4
  import { getEnvironmentVariable } from "../../util/env.js";
@@ -52,6 +52,12 @@ function revive(obj) {
52
52
  name: obj.name,
53
53
  });
54
54
  }
55
+ if (obj.type === "tool") {
56
+ return new index_js_2.ToolMessage({
57
+ content: obj.content,
58
+ tool_call_id: obj.tool_call_id,
59
+ });
60
+ }
55
61
  if (obj.type === "ai") {
56
62
  return new index_js_2.AIMessage({
57
63
  content: obj.content,
@@ -81,6 +87,12 @@ function revive(obj) {
81
87
  name: obj.name,
82
88
  });
83
89
  }
90
+ if (obj.type === "tool") {
91
+ return new index_js_2.ToolMessageChunk({
92
+ content: obj.content,
93
+ tool_call_id: obj.tool_call_id,
94
+ });
95
+ }
84
96
  if (obj.type === "ai") {
85
97
  return new index_js_2.AIMessageChunk({
86
98
  content: obj.content,
@@ -1,7 +1,7 @@
1
1
  import { Runnable } from "../schema/runnable/index.js";
2
2
  import { getBytes, getLines, getMessages } from "../util/event-source-parse.js";
3
3
  import { Document } from "../document.js";
4
- import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessage, FunctionMessageChunk, HumanMessage, HumanMessageChunk, SystemMessage, SystemMessageChunk, } from "../schema/index.js";
4
+ import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessage, FunctionMessageChunk, HumanMessage, HumanMessageChunk, SystemMessage, SystemMessageChunk, ToolMessage, ToolMessageChunk, } from "../schema/index.js";
5
5
  import { StringPromptValue } from "../prompts/base.js";
6
6
  import { ChatPromptValue } from "../prompts/chat.js";
7
7
  import { IterableReadableStream } from "../util/stream.js";
@@ -49,6 +49,12 @@ function revive(obj) {
49
49
  name: obj.name,
50
50
  });
51
51
  }
52
+ if (obj.type === "tool") {
53
+ return new ToolMessage({
54
+ content: obj.content,
55
+ tool_call_id: obj.tool_call_id,
56
+ });
57
+ }
52
58
  if (obj.type === "ai") {
53
59
  return new AIMessage({
54
60
  content: obj.content,
@@ -78,6 +84,12 @@ function revive(obj) {
78
84
  name: obj.name,
79
85
  });
80
86
  }
87
+ if (obj.type === "tool") {
88
+ return new ToolMessageChunk({
89
+ content: obj.content,
90
+ tool_call_id: obj.tool_call_id,
91
+ });
92
+ }
81
93
  if (obj.type === "ai") {
82
94
  return new AIMessageChunk({
83
95
  content: obj.content,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Docstore = exports.BaseEntityStore = exports.BaseFileStore = exports.BaseCache = exports.BaseListChatMessageHistory = exports.BaseChatMessageHistory = exports.BasePromptValue = exports.mapStoredMessageToChatMessage = exports.ChatGenerationChunk = exports.ChatMessageChunk = exports.coerceMessageLikeToMessage = exports.isBaseMessageChunk = exports.isBaseMessage = exports.ChatMessage = exports.FunctionMessageChunk = exports.FunctionMessage = exports.SystemChatMessage = exports.AIChatMessage = exports.HumanChatMessage = exports.BaseChatMessage = exports.SystemMessageChunk = exports.SystemMessage = exports.AIMessageChunk = exports.AIMessage = exports.HumanMessageChunk = exports.HumanMessage = exports.BaseMessageChunk = exports.BaseMessage = exports.GenerationChunk = exports.RUN_KEY = void 0;
3
+ exports.Docstore = exports.BaseEntityStore = exports.BaseFileStore = exports.BaseCache = exports.BaseListChatMessageHistory = exports.BaseChatMessageHistory = exports.BasePromptValue = exports.mapStoredMessageToChatMessage = exports.ChatGenerationChunk = exports.ChatMessageChunk = exports.coerceMessageLikeToMessage = exports.isBaseMessageChunk = exports.isBaseMessage = exports.ChatMessage = exports.ToolMessageChunk = exports.ToolMessage = exports.FunctionMessageChunk = exports.FunctionMessage = exports.SystemChatMessage = exports.AIChatMessage = exports.HumanChatMessage = exports.BaseChatMessage = exports.SystemMessageChunk = exports.SystemMessage = exports.AIMessageChunk = exports.AIMessage = exports.HumanMessageChunk = exports.HumanMessage = exports.BaseMessageChunk = exports.BaseMessage = exports.GenerationChunk = exports.RUN_KEY = void 0;
4
4
  const serializable_js_1 = require("../load/serializable.cjs");
5
5
  exports.RUN_KEY = "__run";
6
6
  /**
@@ -154,6 +154,10 @@ class BaseMessage extends serializable_js_1.Serializable {
154
154
  }
155
155
  }
156
156
  exports.BaseMessage = BaseMessage;
157
+ function isOpenAIToolCallArray(value) {
158
+ return (Array.isArray(value) &&
159
+ value.every((v) => typeof v.index === "number"));
160
+ }
157
161
  /**
158
162
  * Represents a chunk of a message, which can be concatenated with other
159
163
  * message chunks. It includes a method `_merge_kwargs_dict()` for merging
@@ -178,6 +182,31 @@ class BaseMessageChunk extends BaseMessage {
178
182
  typeof merged[key] === "object") {
179
183
  merged[key] = this._mergeAdditionalKwargs(merged[key], value);
180
184
  }
185
+ else if (key === "tool_calls" &&
186
+ isOpenAIToolCallArray(merged[key]) &&
187
+ isOpenAIToolCallArray(value)) {
188
+ for (const toolCall of value) {
189
+ if (merged[key]?.[toolCall.index] !== undefined) {
190
+ merged[key] = merged[key]?.map((value, i) => {
191
+ if (i !== toolCall.index) {
192
+ return value;
193
+ }
194
+ return {
195
+ ...value,
196
+ ...toolCall,
197
+ function: {
198
+ name: toolCall.function.name ?? value.function.name,
199
+ arguments: (value.function.arguments ?? "") +
200
+ (toolCall.function.arguments ?? ""),
201
+ },
202
+ };
203
+ });
204
+ }
205
+ else {
206
+ merged[key][toolCall.index] = toolCall;
207
+ }
208
+ }
209
+ }
181
210
  else {
182
211
  throw new Error(`additional_kwargs[${key}] already exists in this message chunk.`);
183
212
  }
@@ -340,6 +369,62 @@ class FunctionMessageChunk extends BaseMessageChunk {
340
369
  }
341
370
  }
342
371
  exports.FunctionMessageChunk = FunctionMessageChunk;
372
+ /**
373
+ * Represents a tool message in a conversation.
374
+ */
375
+ class ToolMessage extends BaseMessage {
376
+ static lc_name() {
377
+ return "ToolMessage";
378
+ }
379
+ constructor(fields, tool_call_id, name) {
380
+ if (typeof fields === "string") {
381
+ // eslint-disable-next-line no-param-reassign, @typescript-eslint/no-non-null-assertion
382
+ fields = { content: fields, name, tool_call_id: tool_call_id };
383
+ }
384
+ super(fields);
385
+ Object.defineProperty(this, "tool_call_id", {
386
+ enumerable: true,
387
+ configurable: true,
388
+ writable: true,
389
+ value: void 0
390
+ });
391
+ this.tool_call_id = fields.tool_call_id;
392
+ }
393
+ _getType() {
394
+ return "tool";
395
+ }
396
+ }
397
+ exports.ToolMessage = ToolMessage;
398
+ /**
399
+ * Represents a chunk of a function message, which can be concatenated
400
+ * with other function message chunks.
401
+ */
402
+ class ToolMessageChunk extends BaseMessageChunk {
403
+ constructor(fields) {
404
+ super(fields);
405
+ Object.defineProperty(this, "tool_call_id", {
406
+ enumerable: true,
407
+ configurable: true,
408
+ writable: true,
409
+ value: void 0
410
+ });
411
+ this.tool_call_id = fields.tool_call_id;
412
+ }
413
+ static lc_name() {
414
+ return "ToolMessageChunk";
415
+ }
416
+ _getType() {
417
+ return "tool";
418
+ }
419
+ concat(chunk) {
420
+ return new ToolMessageChunk({
421
+ content: mergeContent(this.content, chunk.content),
422
+ additional_kwargs: ToolMessageChunk._mergeAdditionalKwargs(this.additional_kwargs, chunk.additional_kwargs),
423
+ tool_call_id: this.tool_call_id,
424
+ });
425
+ }
426
+ }
427
+ exports.ToolMessageChunk = ToolMessageChunk;
343
428
  /**
344
429
  * Represents a chat message in a conversation.
345
430
  */
@@ -477,6 +562,7 @@ function mapV1MessageToStoredMessage(message) {
477
562
  content: v1Message.text,
478
563
  role: v1Message.role,
479
564
  name: undefined,
565
+ tool_call_id: undefined,
480
566
  },
481
567
  };
482
568
  }
@@ -495,6 +581,11 @@ function mapStoredMessageToChatMessage(message) {
495
581
  throw new Error("Name must be defined for function messages");
496
582
  }
497
583
  return new FunctionMessage(storedMessage.data);
584
+ case "tool":
585
+ if (storedMessage.data.tool_call_id === undefined) {
586
+ throw new Error("Tool call ID must be defined for tool messages");
587
+ }
588
+ return new ToolMessage(storedMessage.data);
498
589
  case "chat": {
499
590
  if (storedMessage.data.role === undefined) {
500
591
  throw new Error("Role must be defined for chat messages");
@@ -53,6 +53,7 @@ export interface StoredMessageData {
53
53
  content: string;
54
54
  role: string | undefined;
55
55
  name: string | undefined;
56
+ tool_call_id: string | undefined;
56
57
  additional_kwargs?: Record<string, any>;
57
58
  }
58
59
  export interface StoredMessage {
@@ -63,7 +64,7 @@ export interface StoredGeneration {
63
64
  text: string;
64
65
  message?: StoredMessage;
65
66
  }
66
- export type MessageType = "human" | "ai" | "generic" | "system" | "function";
67
+ export type MessageType = "human" | "ai" | "generic" | "system" | "function" | "tool";
67
68
  export type MessageContent = string | {
68
69
  type: "text" | "image_url";
69
70
  text?: string;
@@ -76,6 +77,7 @@ export interface BaseMessageFields {
76
77
  name?: string;
77
78
  additional_kwargs?: {
78
79
  function_call?: OpenAIClient.Chat.ChatCompletionMessage.FunctionCall;
80
+ tool_calls?: OpenAIClient.Chat.ChatCompletionMessageToolCall[];
79
81
  [key: string]: unknown;
80
82
  };
81
83
  }
@@ -85,6 +87,9 @@ export interface ChatMessageFieldsWithRole extends BaseMessageFields {
85
87
  export interface FunctionMessageFieldsWithName extends BaseMessageFields {
86
88
  name: string;
87
89
  }
90
+ export interface ToolMessageFieldsWithToolCallId extends BaseMessageFields {
91
+ tool_call_id: string;
92
+ }
88
93
  /**
89
94
  * Base class for all types of messages in a conversation. It includes
90
95
  * properties like `content`, `name`, and `additional_kwargs`. It also
@@ -112,6 +117,9 @@ export declare abstract class BaseMessage extends Serializable implements BaseMe
112
117
  toDict(): StoredMessage;
113
118
  toChunk(): BaseMessageChunk;
114
119
  }
120
+ export type OpenAIToolCall = OpenAIClient.ChatCompletionMessageToolCall & {
121
+ index: number;
122
+ };
115
123
  /**
116
124
  * Represents a chunk of a message, which can be concatenated with other
117
125
  * message chunks. It includes a method `_merge_kwargs_dict()` for merging
@@ -211,6 +219,27 @@ export declare class FunctionMessageChunk extends BaseMessageChunk {
211
219
  _getType(): MessageType;
212
220
  concat(chunk: FunctionMessageChunk): FunctionMessageChunk;
213
221
  }
222
+ /**
223
+ * Represents a tool message in a conversation.
224
+ */
225
+ export declare class ToolMessage extends BaseMessage {
226
+ static lc_name(): string;
227
+ tool_call_id: string;
228
+ constructor(fields: ToolMessageFieldsWithToolCallId);
229
+ constructor(fields: string | BaseMessageFields, tool_call_id: string, name?: string);
230
+ _getType(): MessageType;
231
+ }
232
+ /**
233
+ * Represents a chunk of a function message, which can be concatenated
234
+ * with other function message chunks.
235
+ */
236
+ export declare class ToolMessageChunk extends BaseMessageChunk {
237
+ tool_call_id: string;
238
+ constructor(fields: ToolMessageFieldsWithToolCallId);
239
+ static lc_name(): string;
240
+ _getType(): MessageType;
241
+ concat(chunk: ToolMessageChunk): ToolMessageChunk;
242
+ }
214
243
  /**
215
244
  * Represents a chat message in a conversation.
216
245
  */
@@ -252,7 +281,7 @@ export declare class ChatGenerationChunk extends GenerationChunk implements Chat
252
281
  constructor(fields: ChatGenerationChunkFields);
253
282
  concat(chunk: ChatGenerationChunk): ChatGenerationChunk;
254
283
  }
255
- export declare function mapStoredMessageToChatMessage(message: StoredMessage): ChatMessage | HumanMessage | AIMessage | SystemMessage | FunctionMessage;
284
+ export declare function mapStoredMessageToChatMessage(message: StoredMessage): ChatMessage | HumanMessage | AIMessage | SystemMessage | FunctionMessage | ToolMessage;
256
285
  export interface ChatResult {
257
286
  generations: ChatGeneration[];
258
287
  llmOutput?: Record<string, any>;
@@ -149,6 +149,10 @@ export class BaseMessage extends Serializable {
149
149
  }
150
150
  }
151
151
  }
152
+ function isOpenAIToolCallArray(value) {
153
+ return (Array.isArray(value) &&
154
+ value.every((v) => typeof v.index === "number"));
155
+ }
152
156
  /**
153
157
  * Represents a chunk of a message, which can be concatenated with other
154
158
  * message chunks. It includes a method `_merge_kwargs_dict()` for merging
@@ -173,6 +177,31 @@ export class BaseMessageChunk extends BaseMessage {
173
177
  typeof merged[key] === "object") {
174
178
  merged[key] = this._mergeAdditionalKwargs(merged[key], value);
175
179
  }
180
+ else if (key === "tool_calls" &&
181
+ isOpenAIToolCallArray(merged[key]) &&
182
+ isOpenAIToolCallArray(value)) {
183
+ for (const toolCall of value) {
184
+ if (merged[key]?.[toolCall.index] !== undefined) {
185
+ merged[key] = merged[key]?.map((value, i) => {
186
+ if (i !== toolCall.index) {
187
+ return value;
188
+ }
189
+ return {
190
+ ...value,
191
+ ...toolCall,
192
+ function: {
193
+ name: toolCall.function.name ?? value.function.name,
194
+ arguments: (value.function.arguments ?? "") +
195
+ (toolCall.function.arguments ?? ""),
196
+ },
197
+ };
198
+ });
199
+ }
200
+ else {
201
+ merged[key][toolCall.index] = toolCall;
202
+ }
203
+ }
204
+ }
176
205
  else {
177
206
  throw new Error(`additional_kwargs[${key}] already exists in this message chunk.`);
178
207
  }
@@ -326,6 +355,60 @@ export class FunctionMessageChunk extends BaseMessageChunk {
326
355
  });
327
356
  }
328
357
  }
358
+ /**
359
+ * Represents a tool message in a conversation.
360
+ */
361
+ export class ToolMessage extends BaseMessage {
362
+ static lc_name() {
363
+ return "ToolMessage";
364
+ }
365
+ constructor(fields, tool_call_id, name) {
366
+ if (typeof fields === "string") {
367
+ // eslint-disable-next-line no-param-reassign, @typescript-eslint/no-non-null-assertion
368
+ fields = { content: fields, name, tool_call_id: tool_call_id };
369
+ }
370
+ super(fields);
371
+ Object.defineProperty(this, "tool_call_id", {
372
+ enumerable: true,
373
+ configurable: true,
374
+ writable: true,
375
+ value: void 0
376
+ });
377
+ this.tool_call_id = fields.tool_call_id;
378
+ }
379
+ _getType() {
380
+ return "tool";
381
+ }
382
+ }
383
+ /**
384
+ * Represents a chunk of a function message, which can be concatenated
385
+ * with other function message chunks.
386
+ */
387
+ export class ToolMessageChunk extends BaseMessageChunk {
388
+ constructor(fields) {
389
+ super(fields);
390
+ Object.defineProperty(this, "tool_call_id", {
391
+ enumerable: true,
392
+ configurable: true,
393
+ writable: true,
394
+ value: void 0
395
+ });
396
+ this.tool_call_id = fields.tool_call_id;
397
+ }
398
+ static lc_name() {
399
+ return "ToolMessageChunk";
400
+ }
401
+ _getType() {
402
+ return "tool";
403
+ }
404
+ concat(chunk) {
405
+ return new ToolMessageChunk({
406
+ content: mergeContent(this.content, chunk.content),
407
+ additional_kwargs: ToolMessageChunk._mergeAdditionalKwargs(this.additional_kwargs, chunk.additional_kwargs),
408
+ tool_call_id: this.tool_call_id,
409
+ });
410
+ }
411
+ }
329
412
  /**
330
413
  * Represents a chat message in a conversation.
331
414
  */
@@ -457,6 +540,7 @@ function mapV1MessageToStoredMessage(message) {
457
540
  content: v1Message.text,
458
541
  role: v1Message.role,
459
542
  name: undefined,
543
+ tool_call_id: undefined,
460
544
  },
461
545
  };
462
546
  }
@@ -475,6 +559,11 @@ export function mapStoredMessageToChatMessage(message) {
475
559
  throw new Error("Name must be defined for function messages");
476
560
  }
477
561
  return new FunctionMessage(storedMessage.data);
562
+ case "tool":
563
+ if (storedMessage.data.tool_call_id === undefined) {
564
+ throw new Error("Tool call ID must be defined for tool messages");
565
+ }
566
+ return new ToolMessage(storedMessage.data);
478
567
  case "chat": {
479
568
  if (storedMessage.data.role === undefined) {
480
569
  throw new Error("Role must be defined for chat messages");
@@ -1,11 +1,11 @@
1
- import { DocumentByName, FieldPaths, FunctionReference, GenericActionCtx, GenericDataModel, NamedTableInfo, TableNamesInDataModel, VectorIndexNames } from "convex/server";
1
+ import { DocumentByName, FieldPaths, FunctionReference, GenericActionCtx, GenericDataModel, NamedTableInfo, TableNamesInDataModel, IndexNames } from "convex/server";
2
2
  import { BaseMessage, BaseListChatMessageHistory } from "../../schema/index.js";
3
3
  /**
4
4
  * Type that defines the config required to initialize the
5
5
  * ConvexChatMessageHistory class. At minimum it needs a sessionId
6
6
  * and an ActionCtx.
7
7
  */
8
- export type ConvexChatMessageHistoryInput<DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel> = "messages", IndexName extends VectorIndexNames<NamedTableInfo<DataModel, TableName>> = "bySessionId", SessionIdFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "sessionId", MessageTextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "message", InsertMutation extends FunctionReference<"mutation", "internal", {
8
+ export type ConvexChatMessageHistoryInput<DataModel extends GenericDataModel, TableName extends TableNamesInDataModel<DataModel> = "messages", IndexName extends IndexNames<NamedTableInfo<DataModel, TableName>> = "bySessionId", SessionIdFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "sessionId", MessageTextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "message", InsertMutation extends FunctionReference<"mutation", "internal", {
9
9
  table: string;
10
10
  document: object;
11
11
  }> = any, LookupQuery extends FunctionReference<"query", "internal", {
@@ -50,7 +50,7 @@ export type ConvexChatMessageHistoryInput<DataModel extends GenericDataModel, Ta
50
50
  */
51
51
  readonly deleteMany?: DeleteManyMutation;
52
52
  };
53
- export declare class ConvexChatMessageHistory<DataModel extends GenericDataModel, SessionIdFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "sessionId", TableName extends TableNamesInDataModel<DataModel> = "messages", IndexName extends VectorIndexNames<NamedTableInfo<DataModel, TableName>> = "bySessionId", MessageTextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "message", InsertMutation extends FunctionReference<"mutation", "internal", {
53
+ export declare class ConvexChatMessageHistory<DataModel extends GenericDataModel, SessionIdFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "sessionId", TableName extends TableNamesInDataModel<DataModel> = "messages", IndexName extends IndexNames<NamedTableInfo<DataModel, TableName>> = "bySessionId", MessageTextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>> = "message", InsertMutation extends FunctionReference<"mutation", "internal", {
54
54
  table: string;
55
55
  document: object;
56
56
  }> = any, LookupQuery extends FunctionReference<"query", "internal", {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatToOpenAIFunction = void 0;
3
+ exports.formatToOpenAITool = exports.formatToOpenAIFunction = void 0;
4
4
  const zod_to_json_schema_1 = require("zod-to-json-schema");
5
5
  /**
6
6
  * Formats a `StructuredTool` instance into a format that is compatible
@@ -16,3 +16,14 @@ function formatToOpenAIFunction(tool) {
16
16
  };
17
17
  }
18
18
  exports.formatToOpenAIFunction = formatToOpenAIFunction;
19
+ function formatToOpenAITool(tool) {
20
+ return {
21
+ type: "function",
22
+ function: {
23
+ name: tool.name,
24
+ description: tool.description,
25
+ parameters: (0, zod_to_json_schema_1.zodToJsonSchema)(tool.schema),
26
+ },
27
+ };
28
+ }
29
+ exports.formatToOpenAITool = formatToOpenAITool;
@@ -7,3 +7,4 @@ import { StructuredTool } from "./base.js";
7
7
  * schema, which is then used as the parameters for the OpenAI function.
8
8
  */
9
9
  export declare function formatToOpenAIFunction(tool: StructuredTool): OpenAIClient.Chat.ChatCompletionCreateParams.Function;
10
+ export declare function formatToOpenAITool(tool: StructuredTool): OpenAIClient.Chat.ChatCompletionTool;
@@ -12,3 +12,13 @@ export function formatToOpenAIFunction(tool) {
12
12
  parameters: zodToJsonSchema(tool.schema),
13
13
  };
14
14
  }
15
+ export function formatToOpenAITool(tool) {
16
+ return {
17
+ type: "function",
18
+ function: {
19
+ name: tool.name,
20
+ description: tool.description,
21
+ parameters: zodToJsonSchema(tool.schema),
22
+ },
23
+ };
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langchain",
3
- "version": "0.0.182-rc.1",
3
+ "version": "0.0.182",
4
4
  "description": "Typescript bindings for langchain",
5
5
  "type": "module",
6
6
  "engines": {
@@ -796,10 +796,11 @@
796
796
  "url": "git@github.com:langchain-ai/langchainjs.git"
797
797
  },
798
798
  "scripts": {
799
- "build": "yarn clean && yarn build:esm && yarn build:cjs && node scripts/create-entrypoints.js && node scripts/check-tree-shaking.js",
799
+ "build": "yarn clean && yarn build:esm && yarn build:cjs && yarn build:scripts",
800
800
  "build:esm": "NODE_OPTIONS=--max-old-space-size=4096 tsc --outDir dist/ && rimraf dist/tests dist/**/tests",
801
801
  "build:cjs": "NODE_OPTIONS=--max-old-space-size=4096 tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rimraf dist-cjs",
802
802
  "build:watch": "node scripts/create-entrypoints.js && tsc --outDir dist/ --watch",
803
+ "build:scripts": "node scripts/create-entrypoints.js && node scripts/check-tree-shaking.js",
803
804
  "lint": "NODE_OPTIONS=--max-old-space-size=4096 eslint src && dpdm --exit-code circular:1 --no-warning --no-tree src/*.ts src/**/*.ts",
804
805
  "lint:fix": "yarn lint --fix",
805
806
  "precommit": "lint-staged",
@@ -1360,7 +1361,7 @@
1360
1361
  "langchainhub": "~0.0.6",
1361
1362
  "langsmith": "~0.0.48",
1362
1363
  "ml-distance": "^4.0.0",
1363
- "openai": "~4.16.0",
1364
+ "openai": "^4.16.1",
1364
1365
  "openapi-types": "^12.1.3",
1365
1366
  "p-queue": "^6.6.2",
1366
1367
  "p-retry": "4",