@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.
- package/dist/cjs/llm/anthropic/llm.cjs +73 -8
- package/dist/cjs/llm/anthropic/llm.cjs.map +1 -1
- package/dist/esm/llm/anthropic/llm.mjs +73 -8
- package/dist/esm/llm/anthropic/llm.mjs.map +1 -1
- package/dist/types/llm/anthropic/llm.d.ts +11 -0
- package/dist/types/llm/anthropic/types.d.ts +28 -0
- package/package.json +1 -1
- package/src/llm/anthropic/llm.ts +92 -9
- package/src/llm/anthropic/types.ts +33 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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":"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"}
|
|
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
package/src/llm/anthropic/llm.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
+
}
|