@librechat/agents 1.9.4 → 1.9.6

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.
@@ -46,31 +46,70 @@ function cloneChunk(text, tokenType, chunk) {
46
46
  }
47
47
  class CustomAnthropic extends anthropic.ChatAnthropicMessages {
48
48
  _lc_stream_delay;
49
+ message_start;
50
+ message_delta;
51
+ tools_in_params;
52
+ emitted_usage;
49
53
  constructor(fields) {
50
54
  super(fields);
51
55
  this._lc_stream_delay = fields._lc_stream_delay ?? 25;
52
56
  }
53
- createGenerationChunk(text, chunk) {
57
+ /**
58
+ * Get stream usage as returned by this client's API response.
59
+ * @returns {AnthropicStreamUsage} The stream usage object.
60
+ */
61
+ getStreamUsage() {
62
+ if (this.emitted_usage === true) {
63
+ return;
64
+ }
65
+ const inputUsage = (this.message_start?.message)?.usage;
66
+ const outputUsage = this.message_delta?.usage;
67
+ if (!outputUsage) {
68
+ return;
69
+ }
70
+ const totalUsage = {
71
+ total_tokens: (inputUsage?.input_tokens ?? 0)
72
+ + (inputUsage?.output_tokens ?? 0)
73
+ + (inputUsage?.cache_creation_input_tokens ?? 0)
74
+ + (inputUsage?.cache_read_input_tokens ?? 0)
75
+ + (outputUsage.input_tokens ?? 0)
76
+ + (outputUsage.output_tokens ?? 0)
77
+ + (outputUsage.cache_creation_input_tokens ?? 0)
78
+ + (outputUsage.cache_read_input_tokens ?? 0),
79
+ };
80
+ this.emitted_usage = true;
81
+ return Object.assign(totalUsage, inputUsage, outputUsage);
82
+ }
83
+ resetTokenEvents() {
84
+ this.message_start = undefined;
85
+ this.message_delta = undefined;
86
+ this.emitted_usage = undefined;
87
+ this.tools_in_params = undefined;
88
+ }
89
+ createGenerationChunk({ token, chunk, usageMetadata, shouldStreamUsage, }) {
90
+ const usage_metadata = shouldStreamUsage ? usageMetadata ?? chunk.usage_metadata : undefined;
54
91
  return new outputs.ChatGenerationChunk({
55
92
  message: new messages.AIMessageChunk({
93
+ // Just yield chunk as it is and tool_use will be concat by BaseChatModel._generateUncached().
56
94
  content: chunk.content,
57
95
  additional_kwargs: chunk.additional_kwargs,
58
96
  tool_call_chunks: chunk.tool_call_chunks,
59
- usage_metadata: chunk.usage_metadata,
60
97
  response_metadata: chunk.response_metadata,
98
+ usage_metadata,
61
99
  id: chunk.id,
62
100
  }),
63
- text,
101
+ text: token ?? '',
64
102
  });
65
103
  }
66
104
  async *_streamResponseChunks(messages, options, runManager) {
67
105
  const params = this.invocationParams(options);
68
106
  const formattedMessages = message_inputs._convertMessagesToAnthropicPayload(messages);
69
- const coerceContentToString = !_toolsInParams({
107
+ this.tools_in_params = _toolsInParams({
70
108
  ...params,
71
109
  ...formattedMessages,
72
110
  stream: false,
73
111
  });
112
+ const coerceContentToString = !this.tools_in_params;
74
113
  const stream = await this.createStreamWithRetry({
75
114
  ...params,
76
115
  ...formattedMessages,
@@ -78,12 +117,23 @@ class CustomAnthropic extends anthropic.ChatAnthropicMessages {
78
117
  }, {
79
118
  headers: options.headers,
80
119
  });
120
+ const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
81
121
  for await (const data of stream) {
82
122
  if (options.signal?.aborted === true) {
83
123
  stream.controller.abort();
84
124
  throw new Error('AbortError: User aborted the request.');
85
125
  }
86
- const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
126
+ const type = data.type ?? '';
127
+ if (type === 'message_start') {
128
+ this.message_start = data;
129
+ }
130
+ else if (type === 'message_delta') {
131
+ this.message_delta = data;
132
+ }
133
+ let usageMetadata;
134
+ if (this.tools_in_params !== true && this.emitted_usage !== true) {
135
+ usageMetadata = this.getStreamUsage();
136
+ }
87
137
  const result = message_outputs._makeMessageChunkFromAnthropicEvent(data, {
88
138
  streamUsage: shouldStreamUsage,
89
139
  coerceContentToString,
@@ -92,8 +142,13 @@ class CustomAnthropic extends anthropic.ChatAnthropicMessages {
92
142
  continue;
93
143
  const { chunk } = result;
94
144
  const [token = '', tokenType] = extractToken(chunk);
95
- if (!tokenType || tokenType === 'input') {
96
- const generationChunk = this.createGenerationChunk(token, chunk);
145
+ if (!tokenType || tokenType === 'input' || (token === '' && usageMetadata)) {
146
+ const generationChunk = this.createGenerationChunk({
147
+ token,
148
+ chunk,
149
+ usageMetadata,
150
+ shouldStreamUsage,
151
+ });
97
152
  yield generationChunk;
98
153
  await runManager?.handleLLMNewToken(token, undefined, undefined, undefined, undefined, { chunk: generationChunk });
99
154
  continue;
@@ -106,9 +161,18 @@ class CustomAnthropic extends anthropic.ChatAnthropicMessages {
106
161
  });
107
162
  const generator = textStream.generateText();
108
163
  try {
164
+ let emittedUsage = false;
109
165
  for await (const currentToken of generator) {
110
166
  const newChunk = cloneChunk(currentToken, tokenType, chunk);
111
- const generationChunk = this.createGenerationChunk(currentToken, newChunk);
167
+ const generationChunk = this.createGenerationChunk({
168
+ token: currentToken,
169
+ chunk: newChunk,
170
+ usageMetadata: emittedUsage ? undefined : usageMetadata,
171
+ shouldStreamUsage,
172
+ });
173
+ if (usageMetadata && !emittedUsage) {
174
+ emittedUsage = true;
175
+ }
112
176
  yield generationChunk;
113
177
  await runManager?.handleLLMNewToken(token, undefined, undefined, undefined, undefined, { chunk: generationChunk });
114
178
  }
@@ -117,6 +181,7 @@ class CustomAnthropic extends anthropic.ChatAnthropicMessages {
117
181
  await generator.return();
118
182
  }
119
183
  }
184
+ this.resetTokenEvents();
120
185
  }
121
186
  }
122
187
 
@@ -1 +1 @@
1
- {"version":3,"file":"llm.cjs","sources":["../../../../src/llm/anthropic/llm.ts"],"sourcesContent":["import { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatAnthropicMessages } from '@langchain/anthropic';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { AnthropicInput } from '@langchain/anthropic';\nimport type { AnthropicMessageCreateParams } from '@/llm/anthropic/types';\nimport { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';\nimport { _convertMessagesToAnthropicPayload } from './utils/message_inputs';\nimport { TextStream } from '@/llm/text';\n\nfunction _toolsInParams(params: AnthropicMessageCreateParams): boolean {\n return !!(params.tools && params.tools.length > 0);\n}\n\nfunction extractToken(chunk: AIMessageChunk): [string, 'string' | 'input' | 'content'] | [undefined] {\n if (typeof chunk.content === 'string') {\n return [chunk.content, 'string'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'input' in chunk.content[0]\n ) {\n return typeof chunk.content[0].input === 'string'\n ? [chunk.content[0].input, 'input']\n : [JSON.stringify(chunk.content[0].input), 'input'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'text' in chunk.content[0]\n ) {\n return [chunk.content[0].text, 'content'];\n }\n return [undefined];\n}\n\nfunction cloneChunk(text: string, tokenType: string, chunk: AIMessageChunk): AIMessageChunk {\n if (tokenType === 'string') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: text }));\n } else if (tokenType === 'input') {\n return chunk;\n }\n const content = chunk.content[0] as MessageContentComplex;\n if (tokenType === 'content' && content.type === 'text') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n } else if (tokenType === 'content' && content.type === 'text_delta') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n }\n\n return chunk;\n}\n\nexport type CustomAnthropicInput = AnthropicInput & { _lc_stream_delay?: number };\n\nexport class CustomAnthropic extends ChatAnthropicMessages {\n _lc_stream_delay: number;\n constructor(fields: CustomAnthropicInput) {\n super(fields);\n this._lc_stream_delay = fields._lc_stream_delay ?? 25;\n }\n\n private createGenerationChunk(text: string, chunk: AIMessageChunk): ChatGenerationChunk {\n return new ChatGenerationChunk({\n message: new AIMessageChunk({\n content: chunk.content,\n additional_kwargs: chunk.additional_kwargs,\n tool_call_chunks: chunk.tool_call_chunks,\n usage_metadata: chunk.usage_metadata,\n response_metadata: chunk.response_metadata,\n id: chunk.id,\n }),\n text,\n });\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const params = this.invocationParams(options);\n const formattedMessages = _convertMessagesToAnthropicPayload(messages);\n const coerceContentToString = !_toolsInParams({\n ...params,\n ...formattedMessages,\n stream: false,\n });\n\n const stream = await this.createStreamWithRetry(\n {\n ...params,\n ...formattedMessages,\n stream: true,\n },\n {\n headers: options.headers,\n }\n );\n\n for await (const data of stream) {\n if (options.signal?.aborted === true) {\n stream.controller.abort();\n throw new Error('AbortError: User aborted the request.');\n }\n\n const shouldStreamUsage = this.streamUsage ?? options.streamUsage;\n const result = _makeMessageChunkFromAnthropicEvent(data, {\n streamUsage: shouldStreamUsage,\n coerceContentToString,\n });\n if (!result) continue;\n\n const { chunk } = result;\n const [token = '', tokenType] = extractToken(chunk);\n\n if (!tokenType || tokenType === 'input') {\n const generationChunk = this.createGenerationChunk(token, chunk);\n yield generationChunk;\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n continue;\n }\n\n const textStream = new TextStream(token, {\n delay: this._lc_stream_delay,\n firstWordChunk: true,\n minChunkSize: 4,\n maxChunkSize: 8,\n });\n\n const generator = textStream.generateText();\n try {\n for await (const currentToken of generator) {\n const newChunk = cloneChunk(currentToken, tokenType, chunk);\n const generationChunk = this.createGenerationChunk(currentToken, newChunk);\n yield generationChunk;\n\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n }\n } finally {\n await generator.return();\n }\n }\n }\n}"],"names":["AIMessageChunk","ChatAnthropicMessages","ChatGenerationChunk","_convertMessagesToAnthropicPayload","_makeMessageChunkFromAnthropicEvent","TextStream"],"mappings":"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"}
1
+ {"version":3,"file":"llm.cjs","sources":["../../../../src/llm/anthropic/llm.ts"],"sourcesContent":["import { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatAnthropicMessages } from '@langchain/anthropic';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { AnthropicInput } from '@langchain/anthropic';\nimport type { AnthropicMessageCreateParams, AnthropicStreamUsage, AnthropicMessageStartEvent, AnthropicMessageDeltaEvent } from '@/llm/anthropic/types';\nimport { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';\nimport { _convertMessagesToAnthropicPayload } from './utils/message_inputs';\nimport { TextStream } from '@/llm/text';\n\nfunction _toolsInParams(params: AnthropicMessageCreateParams): boolean {\n return !!(params.tools && params.tools.length > 0);\n}\n\nfunction extractToken(chunk: AIMessageChunk): [string, 'string' | 'input' | 'content'] | [undefined] {\n if (typeof chunk.content === 'string') {\n return [chunk.content, 'string'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'input' in chunk.content[0]\n ) {\n return typeof chunk.content[0].input === 'string'\n ? [chunk.content[0].input, 'input']\n : [JSON.stringify(chunk.content[0].input), 'input'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'text' in chunk.content[0]\n ) {\n return [chunk.content[0].text, 'content'];\n }\n return [undefined];\n}\n\nfunction cloneChunk(text: string, tokenType: string, chunk: AIMessageChunk): AIMessageChunk {\n if (tokenType === 'string') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: text }));\n } else if (tokenType === 'input') {\n return chunk;\n }\n const content = chunk.content[0] as MessageContentComplex;\n if (tokenType === 'content' && content.type === 'text') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n } else if (tokenType === 'content' && content.type === 'text_delta') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n }\n\n return chunk;\n}\n\nexport type CustomAnthropicInput = AnthropicInput & { _lc_stream_delay?: number };\n\nexport class CustomAnthropic extends ChatAnthropicMessages {\n _lc_stream_delay: number;\n private message_start: AnthropicMessageStartEvent | undefined;\n private message_delta: AnthropicMessageDeltaEvent | undefined;\n private tools_in_params?: boolean;\n private emitted_usage?: boolean;\n constructor(fields: CustomAnthropicInput) {\n super(fields);\n this._lc_stream_delay = fields._lc_stream_delay ?? 25;\n }\n\n /**\n * Get stream usage as returned by this client's API response.\n * @returns {AnthropicStreamUsage} The stream usage object.\n */\n getStreamUsage(): AnthropicStreamUsage | undefined {\n if (this.emitted_usage === true) {\n return;\n }\n const inputUsage = (this.message_start?.message)?.usage as undefined | AnthropicStreamUsage;\n const outputUsage = this.message_delta?.usage as undefined | Partial<AnthropicStreamUsage>;\n if (!outputUsage) {\n return;\n }\n const totalUsage = {\n total_tokens: (inputUsage?.input_tokens ?? 0)\n + (inputUsage?.output_tokens ?? 0)\n + (inputUsage?.cache_creation_input_tokens ?? 0)\n + (inputUsage?.cache_read_input_tokens ?? 0)\n + (outputUsage.input_tokens ?? 0)\n + (outputUsage.output_tokens ?? 0)\n + (outputUsage.cache_creation_input_tokens ?? 0)\n + (outputUsage.cache_read_input_tokens ?? 0),\n };\n\n this.emitted_usage = true;\n return Object.assign(totalUsage, inputUsage, outputUsage);\n }\n\n resetTokenEvents(): void {\n this.message_start = undefined;\n this.message_delta = undefined;\n this.emitted_usage = undefined;\n this.tools_in_params = undefined;\n }\n\n private createGenerationChunk({\n token,\n chunk,\n usageMetadata,\n shouldStreamUsage,\n }: {\n token?: string,\n chunk: AIMessageChunk,\n shouldStreamUsage: boolean\n usageMetadata?: AnthropicStreamUsage,\n }): ChatGenerationChunk {\n const usage_metadata = shouldStreamUsage ? usageMetadata ?? chunk.usage_metadata : undefined;\n return new ChatGenerationChunk({\n message: new AIMessageChunk({\n // Just yield chunk as it is and tool_use will be concat by BaseChatModel._generateUncached().\n content: chunk.content,\n additional_kwargs: chunk.additional_kwargs,\n tool_call_chunks: chunk.tool_call_chunks,\n response_metadata: chunk.response_metadata,\n usage_metadata,\n id: chunk.id,\n }),\n text: token ?? '',\n });\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const params = this.invocationParams(options);\n const formattedMessages = _convertMessagesToAnthropicPayload(messages);\n this.tools_in_params = _toolsInParams({\n ...params,\n ...formattedMessages,\n stream: false,\n });\n const coerceContentToString = !this.tools_in_params;\n\n const stream = await this.createStreamWithRetry(\n {\n ...params,\n ...formattedMessages,\n stream: true,\n },\n {\n headers: options.headers,\n }\n );\n\n const shouldStreamUsage = this.streamUsage ?? options.streamUsage;\n\n for await (const data of stream) {\n if (options.signal?.aborted === true) {\n stream.controller.abort();\n throw new Error('AbortError: User aborted the request.');\n }\n\n const type = data.type ?? '';\n if (type === 'message_start') {\n this.message_start = data as AnthropicMessageStartEvent;\n } else if (type === 'message_delta') {\n this.message_delta = data as AnthropicMessageDeltaEvent;\n }\n\n let usageMetadata: AnthropicStreamUsage | undefined;\n if (this.tools_in_params !== true && this.emitted_usage !== true) {\n usageMetadata = this.getStreamUsage();\n }\n\n const result = _makeMessageChunkFromAnthropicEvent(data, {\n streamUsage: shouldStreamUsage,\n coerceContentToString,\n });\n if (!result) continue;\n\n const { chunk } = result;\n const [token = '', tokenType] = extractToken(chunk);\n\n if (!tokenType || tokenType === 'input' || (token === '' && usageMetadata)) {\n const generationChunk = this.createGenerationChunk({\n token,\n chunk,\n usageMetadata,\n shouldStreamUsage,\n });\n yield generationChunk;\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n continue;\n }\n\n const textStream = new TextStream(token, {\n delay: this._lc_stream_delay,\n firstWordChunk: true,\n minChunkSize: 4,\n maxChunkSize: 8,\n });\n\n const generator = textStream.generateText();\n try {\n let emittedUsage = false;\n for await (const currentToken of generator) {\n const newChunk = cloneChunk(currentToken, tokenType, chunk);\n\n const generationChunk = this.createGenerationChunk({\n token: currentToken,\n chunk: newChunk,\n usageMetadata: emittedUsage ? undefined : usageMetadata,\n shouldStreamUsage,\n });\n\n if (usageMetadata && !emittedUsage) {\n emittedUsage = true;\n }\n yield generationChunk;\n\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n }\n } finally {\n await generator.return();\n }\n }\n\n this.resetTokenEvents();\n }\n}"],"names":["AIMessageChunk","ChatAnthropicMessages","ChatGenerationChunk","_convertMessagesToAnthropicPayload","_makeMessageChunkFromAnthropicEvent","TextStream"],"mappings":"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"}
@@ -44,31 +44,70 @@ function cloneChunk(text, tokenType, chunk) {
44
44
  }
45
45
  class CustomAnthropic extends ChatAnthropicMessages {
46
46
  _lc_stream_delay;
47
+ message_start;
48
+ message_delta;
49
+ tools_in_params;
50
+ emitted_usage;
47
51
  constructor(fields) {
48
52
  super(fields);
49
53
  this._lc_stream_delay = fields._lc_stream_delay ?? 25;
50
54
  }
51
- createGenerationChunk(text, chunk) {
55
+ /**
56
+ * Get stream usage as returned by this client's API response.
57
+ * @returns {AnthropicStreamUsage} The stream usage object.
58
+ */
59
+ getStreamUsage() {
60
+ if (this.emitted_usage === true) {
61
+ return;
62
+ }
63
+ const inputUsage = (this.message_start?.message)?.usage;
64
+ const outputUsage = this.message_delta?.usage;
65
+ if (!outputUsage) {
66
+ return;
67
+ }
68
+ const totalUsage = {
69
+ total_tokens: (inputUsage?.input_tokens ?? 0)
70
+ + (inputUsage?.output_tokens ?? 0)
71
+ + (inputUsage?.cache_creation_input_tokens ?? 0)
72
+ + (inputUsage?.cache_read_input_tokens ?? 0)
73
+ + (outputUsage.input_tokens ?? 0)
74
+ + (outputUsage.output_tokens ?? 0)
75
+ + (outputUsage.cache_creation_input_tokens ?? 0)
76
+ + (outputUsage.cache_read_input_tokens ?? 0),
77
+ };
78
+ this.emitted_usage = true;
79
+ return Object.assign(totalUsage, inputUsage, outputUsage);
80
+ }
81
+ resetTokenEvents() {
82
+ this.message_start = undefined;
83
+ this.message_delta = undefined;
84
+ this.emitted_usage = undefined;
85
+ this.tools_in_params = undefined;
86
+ }
87
+ createGenerationChunk({ token, chunk, usageMetadata, shouldStreamUsage, }) {
88
+ const usage_metadata = shouldStreamUsage ? usageMetadata ?? chunk.usage_metadata : undefined;
52
89
  return new ChatGenerationChunk({
53
90
  message: new AIMessageChunk({
91
+ // Just yield chunk as it is and tool_use will be concat by BaseChatModel._generateUncached().
54
92
  content: chunk.content,
55
93
  additional_kwargs: chunk.additional_kwargs,
56
94
  tool_call_chunks: chunk.tool_call_chunks,
57
- usage_metadata: chunk.usage_metadata,
58
95
  response_metadata: chunk.response_metadata,
96
+ usage_metadata,
59
97
  id: chunk.id,
60
98
  }),
61
- text,
99
+ text: token ?? '',
62
100
  });
63
101
  }
64
102
  async *_streamResponseChunks(messages, options, runManager) {
65
103
  const params = this.invocationParams(options);
66
104
  const formattedMessages = _convertMessagesToAnthropicPayload(messages);
67
- const coerceContentToString = !_toolsInParams({
105
+ this.tools_in_params = _toolsInParams({
68
106
  ...params,
69
107
  ...formattedMessages,
70
108
  stream: false,
71
109
  });
110
+ const coerceContentToString = !this.tools_in_params;
72
111
  const stream = await this.createStreamWithRetry({
73
112
  ...params,
74
113
  ...formattedMessages,
@@ -76,12 +115,23 @@ class CustomAnthropic extends ChatAnthropicMessages {
76
115
  }, {
77
116
  headers: options.headers,
78
117
  });
118
+ const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
79
119
  for await (const data of stream) {
80
120
  if (options.signal?.aborted === true) {
81
121
  stream.controller.abort();
82
122
  throw new Error('AbortError: User aborted the request.');
83
123
  }
84
- const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
124
+ const type = data.type ?? '';
125
+ if (type === 'message_start') {
126
+ this.message_start = data;
127
+ }
128
+ else if (type === 'message_delta') {
129
+ this.message_delta = data;
130
+ }
131
+ let usageMetadata;
132
+ if (this.tools_in_params !== true && this.emitted_usage !== true) {
133
+ usageMetadata = this.getStreamUsage();
134
+ }
85
135
  const result = _makeMessageChunkFromAnthropicEvent(data, {
86
136
  streamUsage: shouldStreamUsage,
87
137
  coerceContentToString,
@@ -90,8 +140,13 @@ class CustomAnthropic extends ChatAnthropicMessages {
90
140
  continue;
91
141
  const { chunk } = result;
92
142
  const [token = '', tokenType] = extractToken(chunk);
93
- if (!tokenType || tokenType === 'input') {
94
- const generationChunk = this.createGenerationChunk(token, chunk);
143
+ if (!tokenType || tokenType === 'input' || (token === '' && usageMetadata)) {
144
+ const generationChunk = this.createGenerationChunk({
145
+ token,
146
+ chunk,
147
+ usageMetadata,
148
+ shouldStreamUsage,
149
+ });
95
150
  yield generationChunk;
96
151
  await runManager?.handleLLMNewToken(token, undefined, undefined, undefined, undefined, { chunk: generationChunk });
97
152
  continue;
@@ -104,9 +159,18 @@ class CustomAnthropic extends ChatAnthropicMessages {
104
159
  });
105
160
  const generator = textStream.generateText();
106
161
  try {
162
+ let emittedUsage = false;
107
163
  for await (const currentToken of generator) {
108
164
  const newChunk = cloneChunk(currentToken, tokenType, chunk);
109
- const generationChunk = this.createGenerationChunk(currentToken, newChunk);
165
+ const generationChunk = this.createGenerationChunk({
166
+ token: currentToken,
167
+ chunk: newChunk,
168
+ usageMetadata: emittedUsage ? undefined : usageMetadata,
169
+ shouldStreamUsage,
170
+ });
171
+ if (usageMetadata && !emittedUsage) {
172
+ emittedUsage = true;
173
+ }
110
174
  yield generationChunk;
111
175
  await runManager?.handleLLMNewToken(token, undefined, undefined, undefined, undefined, { chunk: generationChunk });
112
176
  }
@@ -115,6 +179,7 @@ class CustomAnthropic extends ChatAnthropicMessages {
115
179
  await generator.return();
116
180
  }
117
181
  }
182
+ this.resetTokenEvents();
118
183
  }
119
184
  }
120
185
 
@@ -1 +1 @@
1
- {"version":3,"file":"llm.mjs","sources":["../../../../src/llm/anthropic/llm.ts"],"sourcesContent":["import { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatAnthropicMessages } from '@langchain/anthropic';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { AnthropicInput } from '@langchain/anthropic';\nimport type { AnthropicMessageCreateParams } from '@/llm/anthropic/types';\nimport { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';\nimport { _convertMessagesToAnthropicPayload } from './utils/message_inputs';\nimport { TextStream } from '@/llm/text';\n\nfunction _toolsInParams(params: AnthropicMessageCreateParams): boolean {\n return !!(params.tools && params.tools.length > 0);\n}\n\nfunction extractToken(chunk: AIMessageChunk): [string, 'string' | 'input' | 'content'] | [undefined] {\n if (typeof chunk.content === 'string') {\n return [chunk.content, 'string'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'input' in chunk.content[0]\n ) {\n return typeof chunk.content[0].input === 'string'\n ? [chunk.content[0].input, 'input']\n : [JSON.stringify(chunk.content[0].input), 'input'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'text' in chunk.content[0]\n ) {\n return [chunk.content[0].text, 'content'];\n }\n return [undefined];\n}\n\nfunction cloneChunk(text: string, tokenType: string, chunk: AIMessageChunk): AIMessageChunk {\n if (tokenType === 'string') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: text }));\n } else if (tokenType === 'input') {\n return chunk;\n }\n const content = chunk.content[0] as MessageContentComplex;\n if (tokenType === 'content' && content.type === 'text') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n } else if (tokenType === 'content' && content.type === 'text_delta') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n }\n\n return chunk;\n}\n\nexport type CustomAnthropicInput = AnthropicInput & { _lc_stream_delay?: number };\n\nexport class CustomAnthropic extends ChatAnthropicMessages {\n _lc_stream_delay: number;\n constructor(fields: CustomAnthropicInput) {\n super(fields);\n this._lc_stream_delay = fields._lc_stream_delay ?? 25;\n }\n\n private createGenerationChunk(text: string, chunk: AIMessageChunk): ChatGenerationChunk {\n return new ChatGenerationChunk({\n message: new AIMessageChunk({\n content: chunk.content,\n additional_kwargs: chunk.additional_kwargs,\n tool_call_chunks: chunk.tool_call_chunks,\n usage_metadata: chunk.usage_metadata,\n response_metadata: chunk.response_metadata,\n id: chunk.id,\n }),\n text,\n });\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const params = this.invocationParams(options);\n const formattedMessages = _convertMessagesToAnthropicPayload(messages);\n const coerceContentToString = !_toolsInParams({\n ...params,\n ...formattedMessages,\n stream: false,\n });\n\n const stream = await this.createStreamWithRetry(\n {\n ...params,\n ...formattedMessages,\n stream: true,\n },\n {\n headers: options.headers,\n }\n );\n\n for await (const data of stream) {\n if (options.signal?.aborted === true) {\n stream.controller.abort();\n throw new Error('AbortError: User aborted the request.');\n }\n\n const shouldStreamUsage = this.streamUsage ?? options.streamUsage;\n const result = _makeMessageChunkFromAnthropicEvent(data, {\n streamUsage: shouldStreamUsage,\n coerceContentToString,\n });\n if (!result) continue;\n\n const { chunk } = result;\n const [token = '', tokenType] = extractToken(chunk);\n\n if (!tokenType || tokenType === 'input') {\n const generationChunk = this.createGenerationChunk(token, chunk);\n yield generationChunk;\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n continue;\n }\n\n const textStream = new TextStream(token, {\n delay: this._lc_stream_delay,\n firstWordChunk: true,\n minChunkSize: 4,\n maxChunkSize: 8,\n });\n\n const generator = textStream.generateText();\n try {\n for await (const currentToken of generator) {\n const newChunk = cloneChunk(currentToken, tokenType, chunk);\n const generationChunk = this.createGenerationChunk(currentToken, newChunk);\n yield generationChunk;\n\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n }\n } finally {\n await generator.return();\n }\n }\n }\n}"],"names":[],"mappings":";;;;;;;AAWA,SAAS,cAAc,CAAC,MAAoC,EAAA;AAC1D,IAAA,OAAO,CAAC,EAAE,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,YAAY,CAAC,KAAqB,EAAA;AACzC,IAAA,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE;AACrC,QAAA,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;KAClC;AAAM,SAAA,IACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5B,QAAA,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAC3B;QACA,OAAO,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ;AAC/C,cAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC;AACnC,cAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;KACvD;AAAM,SAAA,IACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5B,QAAA,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAC1B;AACA,QAAA,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;KAC3C;IACD,OAAO,CAAC,SAAS,CAAC,CAAC;AACrB,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,SAAiB,EAAE,KAAqB,EAAA;AACxE,IAAA,IAAI,SAAS,KAAK,QAAQ,EAAE;AAC1B,QAAA,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;KACxE;AAAM,SAAA,IAAI,SAAS,KAAK,OAAO,EAAE;AAChC,QAAA,OAAO,KAAK,CAAC;KACd;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAA0B,CAAC;IAC1D,IAAI,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE;AACtD,QAAA,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAC1G;SAAM,IAAI,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,EAAE;AACnE,QAAA,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAC1G;AAED,IAAA,OAAO,KAAK,CAAC;AACf,CAAC;AAIK,MAAO,eAAgB,SAAQ,qBAAqB,CAAA;AACxD,IAAA,gBAAgB,CAAS;AACzB,IAAA,WAAA,CAAY,MAA4B,EAAA;QACtC,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC;KACvD;IAEO,qBAAqB,CAAC,IAAY,EAAE,KAAqB,EAAA;QAC/D,OAAO,IAAI,mBAAmB,CAAC;YAC7B,OAAO,EAAE,IAAI,cAAc,CAAC;gBAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;gBAC1C,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;gBACxC,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;gBAC1C,EAAE,EAAE,KAAK,CAAC,EAAE;aACb,CAAC;YACF,IAAI;AACL,SAAA,CAAC,CAAC;KACJ;IAED,OAAO,qBAAqB,CAC1B,QAAuB,EACvB,OAAkC,EAClC,UAAqC,EAAA;QAErC,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAC9C,QAAA,MAAM,iBAAiB,GAAG,kCAAkC,CAAC,QAAQ,CAAC,CAAC;AACvE,QAAA,MAAM,qBAAqB,GAAG,CAAC,cAAc,CAAC;AAC5C,YAAA,GAAG,MAAM;AACT,YAAA,GAAG,iBAAiB;AACpB,YAAA,MAAM,EAAE,KAAK;AACd,SAAA,CAAC,CAAC;AAEH,QAAA,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAC7C;AACE,YAAA,GAAG,MAAM;AACT,YAAA,GAAG,iBAAiB;AACpB,YAAA,MAAM,EAAE,IAAI;SACb,EACD;YACE,OAAO,EAAE,OAAO,CAAC,OAAO;AACzB,SAAA,CACF,CAAC;AAEF,QAAA,WAAW,MAAM,IAAI,IAAI,MAAM,EAAE;YAC/B,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE;AACpC,gBAAA,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;AAC1B,gBAAA,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;aAC1D;YAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;AAClE,YAAA,MAAM,MAAM,GAAG,mCAAmC,CAAC,IAAI,EAAE;AACvD,gBAAA,WAAW,EAAE,iBAAiB;gBAC9B,qBAAqB;AACtB,aAAA,CAAC,CAAC;AACH,YAAA,IAAI,CAAC,MAAM;gBAAE,SAAS;AAEtB,YAAA,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;AACzB,YAAA,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,SAAS,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;AAEpD,YAAA,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,OAAO,EAAE;gBACvC,MAAM,eAAe,GAAG,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACjE,gBAAA,MAAM,eAAe,CAAC;gBACtB,MAAM,UAAU,EAAE,iBAAiB,CACjC,KAAK,EACL,SAAS,EACT,SAAS,EACT,SAAS,EACT,SAAS,EACT,EAAE,KAAK,EAAE,eAAe,EAAE,CAC3B,CAAC;gBACF,SAAS;aACV;AAED,YAAA,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE;gBACvC,KAAK,EAAE,IAAI,CAAC,gBAAgB;AAC5B,gBAAA,cAAc,EAAE,IAAI;AACpB,gBAAA,YAAY,EAAE,CAAC;AACf,gBAAA,YAAY,EAAE,CAAC;AAChB,aAAA,CAAC,CAAC;AAEH,YAAA,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC;AAC5C,YAAA,IAAI;AACF,gBAAA,WAAW,MAAM,YAAY,IAAI,SAAS,EAAE;oBAC1C,MAAM,QAAQ,GAAG,UAAU,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;oBAC5D,MAAM,eAAe,GAAG,IAAI,CAAC,qBAAqB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;AAC3E,oBAAA,MAAM,eAAe,CAAC;oBAEtB,MAAM,UAAU,EAAE,iBAAiB,CACjC,KAAK,EACL,SAAS,EACT,SAAS,EACT,SAAS,EACT,SAAS,EACT,EAAE,KAAK,EAAE,eAAe,EAAE,CAC3B,CAAC;iBACH;aACF;oBAAS;AACR,gBAAA,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC;aAC1B;SACF;KACF;AACF;;;;"}
1
+ {"version":3,"file":"llm.mjs","sources":["../../../../src/llm/anthropic/llm.ts"],"sourcesContent":["import { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatAnthropicMessages } from '@langchain/anthropic';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { AnthropicInput } from '@langchain/anthropic';\nimport type { AnthropicMessageCreateParams, AnthropicStreamUsage, AnthropicMessageStartEvent, AnthropicMessageDeltaEvent } from '@/llm/anthropic/types';\nimport { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';\nimport { _convertMessagesToAnthropicPayload } from './utils/message_inputs';\nimport { TextStream } from '@/llm/text';\n\nfunction _toolsInParams(params: AnthropicMessageCreateParams): boolean {\n return !!(params.tools && params.tools.length > 0);\n}\n\nfunction extractToken(chunk: AIMessageChunk): [string, 'string' | 'input' | 'content'] | [undefined] {\n if (typeof chunk.content === 'string') {\n return [chunk.content, 'string'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'input' in chunk.content[0]\n ) {\n return typeof chunk.content[0].input === 'string'\n ? [chunk.content[0].input, 'input']\n : [JSON.stringify(chunk.content[0].input), 'input'];\n } else if (\n Array.isArray(chunk.content) &&\n chunk.content.length >= 1 &&\n 'text' in chunk.content[0]\n ) {\n return [chunk.content[0].text, 'content'];\n }\n return [undefined];\n}\n\nfunction cloneChunk(text: string, tokenType: string, chunk: AIMessageChunk): AIMessageChunk {\n if (tokenType === 'string') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: text }));\n } else if (tokenType === 'input') {\n return chunk;\n }\n const content = chunk.content[0] as MessageContentComplex;\n if (tokenType === 'content' && content.type === 'text') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n } else if (tokenType === 'content' && content.type === 'text_delta') {\n return new AIMessageChunk(Object.assign({}, chunk, { content: [Object.assign({}, content, { text })] }));\n }\n\n return chunk;\n}\n\nexport type CustomAnthropicInput = AnthropicInput & { _lc_stream_delay?: number };\n\nexport class CustomAnthropic extends ChatAnthropicMessages {\n _lc_stream_delay: number;\n private message_start: AnthropicMessageStartEvent | undefined;\n private message_delta: AnthropicMessageDeltaEvent | undefined;\n private tools_in_params?: boolean;\n private emitted_usage?: boolean;\n constructor(fields: CustomAnthropicInput) {\n super(fields);\n this._lc_stream_delay = fields._lc_stream_delay ?? 25;\n }\n\n /**\n * Get stream usage as returned by this client's API response.\n * @returns {AnthropicStreamUsage} The stream usage object.\n */\n getStreamUsage(): AnthropicStreamUsage | undefined {\n if (this.emitted_usage === true) {\n return;\n }\n const inputUsage = (this.message_start?.message)?.usage as undefined | AnthropicStreamUsage;\n const outputUsage = this.message_delta?.usage as undefined | Partial<AnthropicStreamUsage>;\n if (!outputUsage) {\n return;\n }\n const totalUsage = {\n total_tokens: (inputUsage?.input_tokens ?? 0)\n + (inputUsage?.output_tokens ?? 0)\n + (inputUsage?.cache_creation_input_tokens ?? 0)\n + (inputUsage?.cache_read_input_tokens ?? 0)\n + (outputUsage.input_tokens ?? 0)\n + (outputUsage.output_tokens ?? 0)\n + (outputUsage.cache_creation_input_tokens ?? 0)\n + (outputUsage.cache_read_input_tokens ?? 0),\n };\n\n this.emitted_usage = true;\n return Object.assign(totalUsage, inputUsage, outputUsage);\n }\n\n resetTokenEvents(): void {\n this.message_start = undefined;\n this.message_delta = undefined;\n this.emitted_usage = undefined;\n this.tools_in_params = undefined;\n }\n\n private createGenerationChunk({\n token,\n chunk,\n usageMetadata,\n shouldStreamUsage,\n }: {\n token?: string,\n chunk: AIMessageChunk,\n shouldStreamUsage: boolean\n usageMetadata?: AnthropicStreamUsage,\n }): ChatGenerationChunk {\n const usage_metadata = shouldStreamUsage ? usageMetadata ?? chunk.usage_metadata : undefined;\n return new ChatGenerationChunk({\n message: new AIMessageChunk({\n // Just yield chunk as it is and tool_use will be concat by BaseChatModel._generateUncached().\n content: chunk.content,\n additional_kwargs: chunk.additional_kwargs,\n tool_call_chunks: chunk.tool_call_chunks,\n response_metadata: chunk.response_metadata,\n usage_metadata,\n id: chunk.id,\n }),\n text: token ?? '',\n });\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const params = this.invocationParams(options);\n const formattedMessages = _convertMessagesToAnthropicPayload(messages);\n this.tools_in_params = _toolsInParams({\n ...params,\n ...formattedMessages,\n stream: false,\n });\n const coerceContentToString = !this.tools_in_params;\n\n const stream = await this.createStreamWithRetry(\n {\n ...params,\n ...formattedMessages,\n stream: true,\n },\n {\n headers: options.headers,\n }\n );\n\n const shouldStreamUsage = this.streamUsage ?? options.streamUsage;\n\n for await (const data of stream) {\n if (options.signal?.aborted === true) {\n stream.controller.abort();\n throw new Error('AbortError: User aborted the request.');\n }\n\n const type = data.type ?? '';\n if (type === 'message_start') {\n this.message_start = data as AnthropicMessageStartEvent;\n } else if (type === 'message_delta') {\n this.message_delta = data as AnthropicMessageDeltaEvent;\n }\n\n let usageMetadata: AnthropicStreamUsage | undefined;\n if (this.tools_in_params !== true && this.emitted_usage !== true) {\n usageMetadata = this.getStreamUsage();\n }\n\n const result = _makeMessageChunkFromAnthropicEvent(data, {\n streamUsage: shouldStreamUsage,\n coerceContentToString,\n });\n if (!result) continue;\n\n const { chunk } = result;\n const [token = '', tokenType] = extractToken(chunk);\n\n if (!tokenType || tokenType === 'input' || (token === '' && usageMetadata)) {\n const generationChunk = this.createGenerationChunk({\n token,\n chunk,\n usageMetadata,\n shouldStreamUsage,\n });\n yield generationChunk;\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n continue;\n }\n\n const textStream = new TextStream(token, {\n delay: this._lc_stream_delay,\n firstWordChunk: true,\n minChunkSize: 4,\n maxChunkSize: 8,\n });\n\n const generator = textStream.generateText();\n try {\n let emittedUsage = false;\n for await (const currentToken of generator) {\n const newChunk = cloneChunk(currentToken, tokenType, chunk);\n\n const generationChunk = this.createGenerationChunk({\n token: currentToken,\n chunk: newChunk,\n usageMetadata: emittedUsage ? undefined : usageMetadata,\n shouldStreamUsage,\n });\n\n if (usageMetadata && !emittedUsage) {\n emittedUsage = true;\n }\n yield generationChunk;\n\n await runManager?.handleLLMNewToken(\n token,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: generationChunk }\n );\n }\n } finally {\n await generator.return();\n }\n }\n\n this.resetTokenEvents();\n }\n}"],"names":[],"mappings":"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"}
@@ -3,12 +3,23 @@ import { ChatGenerationChunk } from '@langchain/core/outputs';
3
3
  import type { BaseMessage } from '@langchain/core/messages';
4
4
  import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
5
5
  import type { AnthropicInput } from '@langchain/anthropic';
6
+ import type { AnthropicStreamUsage } from '@/llm/anthropic/types';
6
7
  export type CustomAnthropicInput = AnthropicInput & {
7
8
  _lc_stream_delay?: number;
8
9
  };
9
10
  export declare class CustomAnthropic extends ChatAnthropicMessages {
10
11
  _lc_stream_delay: number;
12
+ private message_start;
13
+ private message_delta;
14
+ private tools_in_params?;
15
+ private emitted_usage?;
11
16
  constructor(fields: CustomAnthropicInput);
17
+ /**
18
+ * Get stream usage as returned by this client's API response.
19
+ * @returns {AnthropicStreamUsage} The stream usage object.
20
+ */
21
+ getStreamUsage(): AnthropicStreamUsage | undefined;
22
+ resetTokenEvents(): void;
12
23
  private createGenerationChunk;
13
24
  _streamResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
14
25
  }
@@ -8,6 +8,8 @@ export type AnthropicToolResponse = {
8
8
  input: Record<string, any>;
9
9
  };
10
10
  export type AnthropicMessageParam = Anthropic.MessageParam;
11
+ export type AnthropicMessageDeltaEvent = Anthropic.MessageDeltaEvent;
12
+ export type AnthropicMessageStartEvent = Anthropic.MessageStartEvent;
11
13
  export type AnthropicMessageResponse = Anthropic.ContentBlock | AnthropicToolResponse;
12
14
  export type AnthropicMessageCreateParams = Anthropic.MessageCreateParamsNonStreaming;
13
15
  export type AnthropicStreamingMessageCreateParams = Anthropic.MessageCreateParamsStreaming;
@@ -22,3 +24,29 @@ export type AnthropicTextBlockParam = Anthropic.Messages.TextBlockParam;
22
24
  export type AnthropicImageBlockParam = Anthropic.Messages.ImageBlockParam;
23
25
  export type AnthropicToolUseBlockParam = Anthropic.Messages.ToolUseBlockParam;
24
26
  export type AnthropicToolResultBlockParam = Anthropic.Messages.ToolResultBlockParam;
27
+ /**
28
+ * Stream usage information for Anthropic API calls
29
+ * @see https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching#pricing
30
+ */
31
+ export interface AnthropicStreamUsage {
32
+ /**
33
+ * The number of input tokens used in the request
34
+ */
35
+ input_tokens: number;
36
+ /**
37
+ * The number of cache creation input tokens used (write operations)
38
+ */
39
+ cache_creation_input_tokens?: number;
40
+ /**
41
+ * The number of cache input tokens used (read operations)
42
+ */
43
+ cache_read_input_tokens?: number;
44
+ /**
45
+ * The number of output tokens generated in the response
46
+ */
47
+ output_tokens: number;
48
+ /**
49
+ * The total number of tokens generated in the response
50
+ */
51
+ total_tokens: number;
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "1.9.4",
3
+ "version": "1.9.6",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -4,7 +4,7 @@ import { ChatGenerationChunk } from '@langchain/core/outputs';
4
4
  import type { BaseMessage, MessageContentComplex } from '@langchain/core/messages';
5
5
  import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
6
6
  import type { AnthropicInput } from '@langchain/anthropic';
7
- import type { AnthropicMessageCreateParams } from '@/llm/anthropic/types';
7
+ import type { AnthropicMessageCreateParams, AnthropicStreamUsage, AnthropicMessageStartEvent, AnthropicMessageDeltaEvent } from '@/llm/anthropic/types';
8
8
  import { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';
9
9
  import { _convertMessagesToAnthropicPayload } from './utils/message_inputs';
10
10
  import { TextStream } from '@/llm/text';
@@ -54,22 +54,73 @@ export type CustomAnthropicInput = AnthropicInput & { _lc_stream_delay?: number
54
54
 
55
55
  export class CustomAnthropic extends ChatAnthropicMessages {
56
56
  _lc_stream_delay: number;
57
+ private message_start: AnthropicMessageStartEvent | undefined;
58
+ private message_delta: AnthropicMessageDeltaEvent | undefined;
59
+ private tools_in_params?: boolean;
60
+ private emitted_usage?: boolean;
57
61
  constructor(fields: CustomAnthropicInput) {
58
62
  super(fields);
59
63
  this._lc_stream_delay = fields._lc_stream_delay ?? 25;
60
64
  }
61
65
 
62
- private createGenerationChunk(text: string, chunk: AIMessageChunk): ChatGenerationChunk {
66
+ /**
67
+ * Get stream usage as returned by this client's API response.
68
+ * @returns {AnthropicStreamUsage} The stream usage object.
69
+ */
70
+ getStreamUsage(): AnthropicStreamUsage | undefined {
71
+ if (this.emitted_usage === true) {
72
+ return;
73
+ }
74
+ const inputUsage = (this.message_start?.message)?.usage as undefined | AnthropicStreamUsage;
75
+ const outputUsage = this.message_delta?.usage as undefined | Partial<AnthropicStreamUsage>;
76
+ if (!outputUsage) {
77
+ return;
78
+ }
79
+ const totalUsage = {
80
+ total_tokens: (inputUsage?.input_tokens ?? 0)
81
+ + (inputUsage?.output_tokens ?? 0)
82
+ + (inputUsage?.cache_creation_input_tokens ?? 0)
83
+ + (inputUsage?.cache_read_input_tokens ?? 0)
84
+ + (outputUsage.input_tokens ?? 0)
85
+ + (outputUsage.output_tokens ?? 0)
86
+ + (outputUsage.cache_creation_input_tokens ?? 0)
87
+ + (outputUsage.cache_read_input_tokens ?? 0),
88
+ };
89
+
90
+ this.emitted_usage = true;
91
+ return Object.assign(totalUsage, inputUsage, outputUsage);
92
+ }
93
+
94
+ resetTokenEvents(): void {
95
+ this.message_start = undefined;
96
+ this.message_delta = undefined;
97
+ this.emitted_usage = undefined;
98
+ this.tools_in_params = undefined;
99
+ }
100
+
101
+ private createGenerationChunk({
102
+ token,
103
+ chunk,
104
+ usageMetadata,
105
+ shouldStreamUsage,
106
+ }: {
107
+ token?: string,
108
+ chunk: AIMessageChunk,
109
+ shouldStreamUsage: boolean
110
+ usageMetadata?: AnthropicStreamUsage,
111
+ }): ChatGenerationChunk {
112
+ const usage_metadata = shouldStreamUsage ? usageMetadata ?? chunk.usage_metadata : undefined;
63
113
  return new ChatGenerationChunk({
64
114
  message: new AIMessageChunk({
115
+ // Just yield chunk as it is and tool_use will be concat by BaseChatModel._generateUncached().
65
116
  content: chunk.content,
66
117
  additional_kwargs: chunk.additional_kwargs,
67
118
  tool_call_chunks: chunk.tool_call_chunks,
68
- usage_metadata: chunk.usage_metadata,
69
119
  response_metadata: chunk.response_metadata,
120
+ usage_metadata,
70
121
  id: chunk.id,
71
122
  }),
72
- text,
123
+ text: token ?? '',
73
124
  });
74
125
  }
75
126
 
@@ -80,11 +131,12 @@ export class CustomAnthropic extends ChatAnthropicMessages {
80
131
  ): AsyncGenerator<ChatGenerationChunk> {
81
132
  const params = this.invocationParams(options);
82
133
  const formattedMessages = _convertMessagesToAnthropicPayload(messages);
83
- const coerceContentToString = !_toolsInParams({
134
+ this.tools_in_params = _toolsInParams({
84
135
  ...params,
85
136
  ...formattedMessages,
86
137
  stream: false,
87
138
  });
139
+ const coerceContentToString = !this.tools_in_params;
88
140
 
89
141
  const stream = await this.createStreamWithRetry(
90
142
  {
@@ -97,13 +149,26 @@ export class CustomAnthropic extends ChatAnthropicMessages {
97
149
  }
98
150
  );
99
151
 
152
+ const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
153
+
100
154
  for await (const data of stream) {
101
155
  if (options.signal?.aborted === true) {
102
156
  stream.controller.abort();
103
157
  throw new Error('AbortError: User aborted the request.');
104
158
  }
105
159
 
106
- const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
160
+ const type = data.type ?? '';
161
+ if (type === 'message_start') {
162
+ this.message_start = data as AnthropicMessageStartEvent;
163
+ } else if (type === 'message_delta') {
164
+ this.message_delta = data as AnthropicMessageDeltaEvent;
165
+ }
166
+
167
+ let usageMetadata: AnthropicStreamUsage | undefined;
168
+ if (this.tools_in_params !== true && this.emitted_usage !== true) {
169
+ usageMetadata = this.getStreamUsage();
170
+ }
171
+
107
172
  const result = _makeMessageChunkFromAnthropicEvent(data, {
108
173
  streamUsage: shouldStreamUsage,
109
174
  coerceContentToString,
@@ -113,8 +178,13 @@ export class CustomAnthropic extends ChatAnthropicMessages {
113
178
  const { chunk } = result;
114
179
  const [token = '', tokenType] = extractToken(chunk);
115
180
 
116
- if (!tokenType || tokenType === 'input') {
117
- const generationChunk = this.createGenerationChunk(token, chunk);
181
+ if (!tokenType || tokenType === 'input' || (token === '' && usageMetadata)) {
182
+ const generationChunk = this.createGenerationChunk({
183
+ token,
184
+ chunk,
185
+ usageMetadata,
186
+ shouldStreamUsage,
187
+ });
118
188
  yield generationChunk;
119
189
  await runManager?.handleLLMNewToken(
120
190
  token,
@@ -136,9 +206,20 @@ export class CustomAnthropic extends ChatAnthropicMessages {
136
206
 
137
207
  const generator = textStream.generateText();
138
208
  try {
209
+ let emittedUsage = false;
139
210
  for await (const currentToken of generator) {
140
211
  const newChunk = cloneChunk(currentToken, tokenType, chunk);
141
- const generationChunk = this.createGenerationChunk(currentToken, newChunk);
212
+
213
+ const generationChunk = this.createGenerationChunk({
214
+ token: currentToken,
215
+ chunk: newChunk,
216
+ usageMetadata: emittedUsage ? undefined : usageMetadata,
217
+ shouldStreamUsage,
218
+ });
219
+
220
+ if (usageMetadata && !emittedUsage) {
221
+ emittedUsage = true;
222
+ }
142
223
  yield generationChunk;
143
224
 
144
225
  await runManager?.handleLLMNewToken(
@@ -154,5 +235,7 @@ export class CustomAnthropic extends ChatAnthropicMessages {
154
235
  await generator.return();
155
236
  }
156
237
  }
238
+
239
+ this.resetTokenEvents();
157
240
  }
158
241
  }
@@ -12,6 +12,8 @@ export type AnthropicToolResponse = {
12
12
  };
13
13
 
14
14
  export type AnthropicMessageParam = Anthropic.MessageParam;
15
+ export type AnthropicMessageDeltaEvent= Anthropic.MessageDeltaEvent;
16
+ export type AnthropicMessageStartEvent= Anthropic.MessageStartEvent;
15
17
  export type AnthropicMessageResponse =
16
18
  | Anthropic.ContentBlock
17
19
  | AnthropicToolResponse;
@@ -35,4 +37,34 @@ export type AnthropicTextBlockParam = Anthropic.Messages.TextBlockParam;
35
37
  export type AnthropicImageBlockParam = Anthropic.Messages.ImageBlockParam;
36
38
  export type AnthropicToolUseBlockParam = Anthropic.Messages.ToolUseBlockParam;
37
39
  export type AnthropicToolResultBlockParam =
38
- Anthropic.Messages.ToolResultBlockParam;
40
+ Anthropic.Messages.ToolResultBlockParam;
41
+
42
+ /**
43
+ * Stream usage information for Anthropic API calls
44
+ * @see https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching#pricing
45
+ */
46
+ export interface AnthropicStreamUsage {
47
+ /**
48
+ * The number of input tokens used in the request
49
+ */
50
+ input_tokens: number;
51
+
52
+ /**
53
+ * The number of cache creation input tokens used (write operations)
54
+ */
55
+ cache_creation_input_tokens?: number;
56
+
57
+ /**
58
+ * The number of cache input tokens used (read operations)
59
+ */
60
+ cache_read_input_tokens?: number;
61
+
62
+ /**
63
+ * The number of output tokens generated in the response
64
+ */
65
+ output_tokens: number;
66
+ /**
67
+ * The total number of tokens generated in the response
68
+ */
69
+ total_tokens: number;
70
+ }