@librechat/agents 3.0.80 → 3.0.771
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/graphs/Graph.cjs +5 -19
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +25 -98
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +123 -32
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +1 -1
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/stream.cjs +2 -4
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +5 -9
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +5 -19
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +24 -97
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +123 -32
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +1 -1
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/stream.mjs +2 -4
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +5 -9
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/types/llm/bedrock/index.d.ts +7 -86
- package/dist/types/messages/cache.d.ts +6 -2
- package/dist/types/types/tools.d.ts +0 -2
- package/package.json +3 -6
- package/src/graphs/Graph.ts +5 -23
- package/src/llm/bedrock/index.ts +43 -180
- package/src/messages/cache.test.ts +215 -0
- package/src/messages/cache.ts +172 -43
- package/src/messages/core.ts +1 -1
- package/src/scripts/thinking.ts +18 -39
- package/src/scripts/tools.ts +3 -7
- package/src/stream.ts +2 -4
- package/src/tools/ToolNode.ts +5 -9
- package/src/types/tools.ts +0 -2
- package/dist/types/llm/bedrock/types.d.ts +0 -27
- package/dist/types/llm/bedrock/utils/index.d.ts +0 -5
- package/dist/types/llm/bedrock/utils/message_inputs.d.ts +0 -31
- package/dist/types/llm/bedrock/utils/message_outputs.d.ts +0 -33
- package/src/llm/bedrock/llm.spec.ts +0 -616
- package/src/llm/bedrock/types.ts +0 -51
- package/src/llm/bedrock/utils/index.ts +0 -18
- package/src/llm/bedrock/utils/message_inputs.ts +0 -563
- package/src/llm/bedrock/utils/message_outputs.ts +0 -310
- package/src/scripts/code_exec_multi_session.ts +0 -241
- package/src/scripts/thinking-bedrock.ts +0 -159
package/src/messages/cache.ts
CHANGED
|
@@ -7,13 +7,57 @@ type MessageWithContent = {
|
|
|
7
7
|
content?: string | MessageContentComplex[];
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Deep clones a message's content to prevent mutation of the original.
|
|
12
|
+
* Handles both string and array content types.
|
|
13
|
+
*/
|
|
14
|
+
function deepCloneContent<T extends string | MessageContentComplex[]>(
|
|
15
|
+
content: T
|
|
16
|
+
): T {
|
|
17
|
+
if (typeof content === 'string') {
|
|
18
|
+
return content;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(content)) {
|
|
21
|
+
return content.map((block) => ({ ...block })) as T;
|
|
22
|
+
}
|
|
23
|
+
return content;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Creates a shallow clone of a message with deep-cloned content.
|
|
28
|
+
* This ensures modifications to content don't affect the original message.
|
|
29
|
+
*/
|
|
30
|
+
function cloneMessageWithContent<T extends MessageWithContent>(message: T): T {
|
|
31
|
+
if (message.content === undefined) {
|
|
32
|
+
return { ...message };
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
...message,
|
|
36
|
+
content: deepCloneContent(message.content),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Checks if a message's content needs cache control stripping.
|
|
42
|
+
* Returns true if content has cachePoint blocks or cache_control fields.
|
|
43
|
+
*/
|
|
44
|
+
function needsCacheStripping(content: MessageContentComplex[]): boolean {
|
|
45
|
+
for (let i = 0; i < content.length; i++) {
|
|
46
|
+
const block = content[i];
|
|
47
|
+
if (isCachePoint(block)) return true;
|
|
48
|
+
if ('cache_control' in block) return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
10
53
|
/**
|
|
11
54
|
* Anthropic API: Adds cache control to the appropriate user messages in the payload.
|
|
12
55
|
* Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,
|
|
13
56
|
* then adds fresh cache control to the last 2 user messages in a single backward pass.
|
|
14
57
|
* This ensures we don't accumulate stale cache points across multiple turns.
|
|
58
|
+
* Returns a new array - only clones messages that require modification.
|
|
15
59
|
* @param messages - The array of message objects.
|
|
16
|
-
* @returns -
|
|
60
|
+
* @returns - A new array of message objects with cache control added.
|
|
17
61
|
*/
|
|
18
62
|
export function addCacheControl<T extends AnthropicMessage | BaseMessage>(
|
|
19
63
|
messages: T[]
|
|
@@ -22,22 +66,47 @@ export function addCacheControl<T extends AnthropicMessage | BaseMessage>(
|
|
|
22
66
|
return messages;
|
|
23
67
|
}
|
|
24
68
|
|
|
25
|
-
const updatedMessages = [...messages];
|
|
69
|
+
const updatedMessages: T[] = [...messages];
|
|
26
70
|
let userMessagesModified = 0;
|
|
27
71
|
|
|
28
72
|
for (let i = updatedMessages.length - 1; i >= 0; i--) {
|
|
29
|
-
const
|
|
73
|
+
const originalMessage = updatedMessages[i];
|
|
30
74
|
const isUserMessage =
|
|
31
|
-
('getType' in
|
|
32
|
-
('role' in
|
|
75
|
+
('getType' in originalMessage && originalMessage.getType() === 'human') ||
|
|
76
|
+
('role' in originalMessage && originalMessage.role === 'user');
|
|
77
|
+
|
|
78
|
+
const hasArrayContent = Array.isArray(originalMessage.content);
|
|
79
|
+
const needsStripping =
|
|
80
|
+
hasArrayContent &&
|
|
81
|
+
needsCacheStripping(originalMessage.content as MessageContentComplex[]);
|
|
82
|
+
const needsCacheAdd =
|
|
83
|
+
userMessagesModified < 2 &&
|
|
84
|
+
isUserMessage &&
|
|
85
|
+
(typeof originalMessage.content === 'string' || hasArrayContent);
|
|
86
|
+
|
|
87
|
+
if (!needsStripping && !needsCacheAdd) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
33
90
|
|
|
34
|
-
|
|
35
|
-
|
|
91
|
+
const message = cloneMessageWithContent(
|
|
92
|
+
originalMessage as MessageWithContent
|
|
93
|
+
) as T;
|
|
94
|
+
updatedMessages[i] = message;
|
|
95
|
+
|
|
96
|
+
if (hasArrayContent) {
|
|
97
|
+
message.content = (message.content as MessageContentComplex[]).filter(
|
|
36
98
|
(block) => !isCachePoint(block as MessageContentComplex)
|
|
37
99
|
) as typeof message.content;
|
|
38
100
|
|
|
39
|
-
for (
|
|
40
|
-
|
|
101
|
+
for (
|
|
102
|
+
let j = 0;
|
|
103
|
+
j < (message.content as MessageContentComplex[]).length;
|
|
104
|
+
j++
|
|
105
|
+
) {
|
|
106
|
+
const block = (message.content as MessageContentComplex[])[j] as Record<
|
|
107
|
+
string,
|
|
108
|
+
unknown
|
|
109
|
+
>;
|
|
41
110
|
if ('cache_control' in block) {
|
|
42
111
|
delete block.cache_control;
|
|
43
112
|
}
|
|
@@ -81,9 +150,20 @@ function isCachePoint(block: MessageContentComplex): boolean {
|
|
|
81
150
|
return 'cachePoint' in block && !('type' in block);
|
|
82
151
|
}
|
|
83
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Checks if a message's content has Anthropic cache_control fields.
|
|
155
|
+
*/
|
|
156
|
+
function hasAnthropicCacheControl(content: MessageContentComplex[]): boolean {
|
|
157
|
+
for (let i = 0; i < content.length; i++) {
|
|
158
|
+
if ('cache_control' in content[i]) return true;
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
84
163
|
/**
|
|
85
164
|
* Removes all Anthropic cache_control fields from messages
|
|
86
165
|
* Used when switching from Anthropic to Bedrock provider
|
|
166
|
+
* Returns a new array - only clones messages that require modification.
|
|
87
167
|
*/
|
|
88
168
|
export function stripAnthropicCacheControl<T extends MessageWithContent>(
|
|
89
169
|
messages: T[]
|
|
@@ -92,18 +172,30 @@ export function stripAnthropicCacheControl<T extends MessageWithContent>(
|
|
|
92
172
|
return messages;
|
|
93
173
|
}
|
|
94
174
|
|
|
95
|
-
const updatedMessages = [...messages];
|
|
175
|
+
const updatedMessages: T[] = [...messages];
|
|
96
176
|
|
|
97
177
|
for (let i = 0; i < updatedMessages.length; i++) {
|
|
98
|
-
const
|
|
99
|
-
const content =
|
|
178
|
+
const originalMessage = updatedMessages[i];
|
|
179
|
+
const content = originalMessage.content;
|
|
100
180
|
|
|
101
|
-
if (Array.isArray(content)) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
181
|
+
if (!Array.isArray(content) || !hasAnthropicCacheControl(content)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const message = cloneMessageWithContent(originalMessage);
|
|
186
|
+
updatedMessages[i] = message;
|
|
187
|
+
|
|
188
|
+
for (
|
|
189
|
+
let j = 0;
|
|
190
|
+
j < (message.content as MessageContentComplex[]).length;
|
|
191
|
+
j++
|
|
192
|
+
) {
|
|
193
|
+
const block = (message.content as MessageContentComplex[])[j] as Record<
|
|
194
|
+
string,
|
|
195
|
+
unknown
|
|
196
|
+
>;
|
|
197
|
+
if ('cache_control' in block) {
|
|
198
|
+
delete block.cache_control;
|
|
107
199
|
}
|
|
108
200
|
}
|
|
109
201
|
}
|
|
@@ -111,9 +203,20 @@ export function stripAnthropicCacheControl<T extends MessageWithContent>(
|
|
|
111
203
|
return updatedMessages;
|
|
112
204
|
}
|
|
113
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Checks if a message's content has Bedrock cachePoint blocks.
|
|
208
|
+
*/
|
|
209
|
+
function hasBedrockCachePoint(content: MessageContentComplex[]): boolean {
|
|
210
|
+
for (let i = 0; i < content.length; i++) {
|
|
211
|
+
if (isCachePoint(content[i])) return true;
|
|
212
|
+
}
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
|
|
114
216
|
/**
|
|
115
217
|
* Removes all Bedrock cachePoint blocks from messages
|
|
116
218
|
* Used when switching from Bedrock to Anthropic provider
|
|
219
|
+
* Returns a new array - only clones messages that require modification.
|
|
117
220
|
*/
|
|
118
221
|
export function stripBedrockCacheControl<T extends MessageWithContent>(
|
|
119
222
|
messages: T[]
|
|
@@ -122,17 +225,22 @@ export function stripBedrockCacheControl<T extends MessageWithContent>(
|
|
|
122
225
|
return messages;
|
|
123
226
|
}
|
|
124
227
|
|
|
125
|
-
const updatedMessages = [...messages];
|
|
228
|
+
const updatedMessages: T[] = [...messages];
|
|
126
229
|
|
|
127
230
|
for (let i = 0; i < updatedMessages.length; i++) {
|
|
128
|
-
const
|
|
129
|
-
const content =
|
|
231
|
+
const originalMessage = updatedMessages[i];
|
|
232
|
+
const content = originalMessage.content;
|
|
130
233
|
|
|
131
|
-
if (Array.isArray(content)) {
|
|
132
|
-
|
|
133
|
-
(block) => !isCachePoint(block as MessageContentComplex)
|
|
134
|
-
) as typeof content;
|
|
234
|
+
if (!Array.isArray(content) || !hasBedrockCachePoint(content)) {
|
|
235
|
+
continue;
|
|
135
236
|
}
|
|
237
|
+
|
|
238
|
+
const message = cloneMessageWithContent(originalMessage);
|
|
239
|
+
updatedMessages[i] = message;
|
|
240
|
+
|
|
241
|
+
message.content = (message.content as MessageContentComplex[]).filter(
|
|
242
|
+
(block) => !isCachePoint(block as MessageContentComplex)
|
|
243
|
+
) as typeof content;
|
|
136
244
|
}
|
|
137
245
|
|
|
138
246
|
return updatedMessages;
|
|
@@ -145,8 +253,9 @@ export function stripBedrockCacheControl<T extends MessageWithContent>(
|
|
|
145
253
|
* Strips ALL existing cache control (both Bedrock and Anthropic formats) from all messages,
|
|
146
254
|
* then adds fresh cache points to the last 2 messages in a single backward pass.
|
|
147
255
|
* This ensures we don't accumulate stale cache points across multiple turns.
|
|
256
|
+
* Returns a new array - only clones messages that require modification.
|
|
148
257
|
* @param messages - The array of message objects.
|
|
149
|
-
* @returns -
|
|
258
|
+
* @returns - A new array of message objects with cache points added.
|
|
150
259
|
*/
|
|
151
260
|
export function addBedrockCacheControl<
|
|
152
261
|
T extends Partial<BaseMessage> & MessageWithContent,
|
|
@@ -155,42 +264,62 @@ export function addBedrockCacheControl<
|
|
|
155
264
|
return messages;
|
|
156
265
|
}
|
|
157
266
|
|
|
158
|
-
const updatedMessages: T[] = messages
|
|
267
|
+
const updatedMessages: T[] = [...messages];
|
|
159
268
|
let messagesModified = 0;
|
|
160
269
|
|
|
161
270
|
for (let i = updatedMessages.length - 1; i >= 0; i--) {
|
|
162
|
-
const
|
|
271
|
+
const originalMessage = updatedMessages[i];
|
|
163
272
|
const isToolMessage =
|
|
164
|
-
'getType' in
|
|
165
|
-
typeof
|
|
166
|
-
|
|
273
|
+
'getType' in originalMessage &&
|
|
274
|
+
typeof originalMessage.getType === 'function' &&
|
|
275
|
+
originalMessage.getType() === 'tool';
|
|
276
|
+
|
|
277
|
+
const content = originalMessage.content;
|
|
278
|
+
const hasArrayContent = Array.isArray(content);
|
|
279
|
+
const needsStripping =
|
|
280
|
+
hasArrayContent &&
|
|
281
|
+
needsCacheStripping(content as MessageContentComplex[]);
|
|
282
|
+
const isEmptyString = typeof content === 'string' && content === '';
|
|
283
|
+
const needsCacheAdd =
|
|
284
|
+
messagesModified < 2 &&
|
|
285
|
+
!isToolMessage &&
|
|
286
|
+
!isEmptyString &&
|
|
287
|
+
(typeof content === 'string' || hasArrayContent);
|
|
288
|
+
|
|
289
|
+
if (!needsStripping && !needsCacheAdd) {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
167
292
|
|
|
168
|
-
const
|
|
293
|
+
const message = cloneMessageWithContent(originalMessage);
|
|
294
|
+
updatedMessages[i] = message;
|
|
169
295
|
|
|
170
|
-
if (
|
|
171
|
-
message.content = content.filter(
|
|
296
|
+
if (hasArrayContent) {
|
|
297
|
+
message.content = (message.content as MessageContentComplex[]).filter(
|
|
172
298
|
(block) => !isCachePoint(block)
|
|
173
299
|
) as typeof content;
|
|
174
300
|
|
|
175
|
-
for (
|
|
176
|
-
|
|
301
|
+
for (
|
|
302
|
+
let j = 0;
|
|
303
|
+
j < (message.content as MessageContentComplex[]).length;
|
|
304
|
+
j++
|
|
305
|
+
) {
|
|
306
|
+
const block = (message.content as MessageContentComplex[])[j] as Record<
|
|
307
|
+
string,
|
|
308
|
+
unknown
|
|
309
|
+
>;
|
|
177
310
|
if ('cache_control' in block) {
|
|
178
311
|
delete block.cache_control;
|
|
179
312
|
}
|
|
180
313
|
}
|
|
181
314
|
}
|
|
182
315
|
|
|
183
|
-
if (messagesModified >= 2 || isToolMessage) {
|
|
316
|
+
if (messagesModified >= 2 || isToolMessage || isEmptyString) {
|
|
184
317
|
continue;
|
|
185
318
|
}
|
|
186
319
|
|
|
187
|
-
if (typeof content === 'string'
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (typeof content === 'string') {
|
|
320
|
+
if (typeof message.content === 'string') {
|
|
192
321
|
message.content = [
|
|
193
|
-
{ type: ContentTypes.TEXT, text: content },
|
|
322
|
+
{ type: ContentTypes.TEXT, text: message.content },
|
|
194
323
|
{ cachePoint: { type: 'default' } },
|
|
195
324
|
] as MessageContentComplex[];
|
|
196
325
|
messagesModified++;
|
package/src/messages/core.ts
CHANGED
|
@@ -41,7 +41,7 @@ User: ${userMessage[1]}
|
|
|
41
41
|
const _allowedTypes = ['image_url', 'text', 'tool_use', 'tool_result'];
|
|
42
42
|
const allowedTypesByProvider: Record<string, string[]> = {
|
|
43
43
|
default: _allowedTypes,
|
|
44
|
-
[Providers.ANTHROPIC]: [..._allowedTypes, 'thinking'
|
|
44
|
+
[Providers.ANTHROPIC]: [..._allowedTypes, 'thinking'],
|
|
45
45
|
[Providers.BEDROCK]: [..._allowedTypes, 'reasoning_content'],
|
|
46
46
|
[Providers.OPENAI]: _allowedTypes,
|
|
47
47
|
};
|
package/src/scripts/thinking.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
// src/scripts/test-thinking.ts
|
|
2
2
|
import { config } from 'dotenv';
|
|
3
3
|
config();
|
|
4
|
-
import {
|
|
5
|
-
HumanMessage,
|
|
6
|
-
SystemMessage,
|
|
7
|
-
BaseMessage,
|
|
8
|
-
} from '@langchain/core/messages';
|
|
4
|
+
import { HumanMessage, SystemMessage, BaseMessage } from '@langchain/core/messages';
|
|
9
5
|
import type { UsageMetadata } from '@langchain/core/messages';
|
|
10
6
|
import * as t from '@/types';
|
|
11
7
|
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
@@ -25,23 +21,17 @@ async function testThinking(): Promise<void> {
|
|
|
25
21
|
const instructions = `You are a helpful AI assistant for ${userName}. When answering questions, be thorough in your reasoning.`;
|
|
26
22
|
const { contentParts, aggregateContent } = createContentAggregator();
|
|
27
23
|
_contentParts = contentParts as t.MessageContentComplex[];
|
|
28
|
-
|
|
24
|
+
|
|
29
25
|
// Set up event handlers
|
|
30
26
|
const customHandlers = {
|
|
31
27
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
32
28
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
33
29
|
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
34
30
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
35
|
-
handle: (
|
|
36
|
-
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
37
|
-
data: t.StreamEventData
|
|
38
|
-
): void => {
|
|
31
|
+
handle: (event: GraphEvents.ON_RUN_STEP_COMPLETED, data: t.StreamEventData): void => {
|
|
39
32
|
console.log('====== ON_RUN_STEP_COMPLETED ======');
|
|
40
|
-
aggregateContent({
|
|
41
|
-
|
|
42
|
-
data: data as unknown as { result: t.ToolEndEvent },
|
|
43
|
-
});
|
|
44
|
-
},
|
|
33
|
+
aggregateContent({ event, data: data as unknown as { result: t.ToolEndEvent } });
|
|
34
|
+
}
|
|
45
35
|
},
|
|
46
36
|
[GraphEvents.ON_RUN_STEP]: {
|
|
47
37
|
handle: (event: GraphEvents.ON_RUN_STEP, data: t.RunStep) => {
|
|
@@ -49,38 +39,29 @@ async function testThinking(): Promise<void> {
|
|
|
49
39
|
},
|
|
50
40
|
},
|
|
51
41
|
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
52
|
-
handle: (
|
|
53
|
-
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
54
|
-
data: t.RunStepDeltaEvent
|
|
55
|
-
) => {
|
|
42
|
+
handle: (event: GraphEvents.ON_RUN_STEP_DELTA, data: t.RunStepDeltaEvent) => {
|
|
56
43
|
aggregateContent({ event, data });
|
|
57
44
|
},
|
|
58
45
|
},
|
|
59
46
|
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
60
|
-
handle: (
|
|
61
|
-
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
62
|
-
data: t.MessageDeltaEvent
|
|
63
|
-
) => {
|
|
47
|
+
handle: (event: GraphEvents.ON_MESSAGE_DELTA, data: t.MessageDeltaEvent) => {
|
|
64
48
|
aggregateContent({ event, data });
|
|
65
49
|
},
|
|
66
50
|
},
|
|
67
51
|
[GraphEvents.ON_REASONING_DELTA]: {
|
|
68
|
-
handle: (
|
|
69
|
-
event: GraphEvents.ON_REASONING_DELTA,
|
|
70
|
-
data: t.ReasoningDeltaEvent
|
|
71
|
-
) => {
|
|
52
|
+
handle: (event: GraphEvents.ON_REASONING_DELTA, data: t.ReasoningDeltaEvent) => {
|
|
72
53
|
aggregateContent({ event, data });
|
|
73
54
|
},
|
|
74
55
|
},
|
|
75
56
|
};
|
|
76
57
|
|
|
77
58
|
const baseLlmConfig: t.LLMConfig = getLLMConfig(Providers.ANTHROPIC);
|
|
78
|
-
|
|
59
|
+
|
|
79
60
|
// Enable thinking with token budget
|
|
80
61
|
const llmConfig = {
|
|
81
62
|
...baseLlmConfig,
|
|
82
63
|
model: 'claude-3-7-sonnet-latest',
|
|
83
|
-
thinking: { type:
|
|
64
|
+
thinking: { type: "enabled", budget_tokens: 2000 }
|
|
84
65
|
};
|
|
85
66
|
|
|
86
67
|
const run = await Run.create<t.IState>({
|
|
@@ -112,7 +93,7 @@ async function testThinking(): Promise<void> {
|
|
|
112
93
|
console.log('Running first query with thinking enabled...');
|
|
113
94
|
const firstInputs = { messages: [...conversationHistory] };
|
|
114
95
|
await run.processStream(firstInputs, config);
|
|
115
|
-
|
|
96
|
+
|
|
116
97
|
// Extract and display thinking blocks
|
|
117
98
|
const finalMessages = run.getRunMessages();
|
|
118
99
|
|
|
@@ -120,32 +101,30 @@ async function testThinking(): Promise<void> {
|
|
|
120
101
|
console.log('\n\nTest 2: Multi-turn conversation with thinking enabled');
|
|
121
102
|
const userMessage2 = `Given your previous analysis, what would be the most significant technical challenges in making this transition?`;
|
|
122
103
|
conversationHistory.push(new HumanMessage(userMessage2));
|
|
123
|
-
|
|
104
|
+
|
|
124
105
|
console.log('Running second query with thinking enabled...');
|
|
125
106
|
const secondInputs = { messages: [...conversationHistory] };
|
|
126
107
|
await run.processStream(secondInputs, config);
|
|
127
|
-
|
|
108
|
+
|
|
128
109
|
// Display thinking blocks for second response
|
|
129
110
|
const finalMessages2 = run.getRunMessages();
|
|
130
111
|
|
|
131
112
|
// Test 3: Redacted thinking mode
|
|
132
113
|
console.log('\n\nTest 3: Redacted thinking mode');
|
|
133
|
-
const magicString =
|
|
134
|
-
'ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB';
|
|
114
|
+
const magicString = "ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB";
|
|
135
115
|
const userMessage3 = `${magicString}\n\nExplain how quantum computing works in simple terms.`;
|
|
136
|
-
|
|
116
|
+
|
|
137
117
|
// Reset conversation for clean test
|
|
138
118
|
conversationHistory.length = 0;
|
|
139
119
|
conversationHistory.push(new HumanMessage(userMessage3));
|
|
140
|
-
|
|
120
|
+
|
|
141
121
|
console.log('Running query with redacted thinking...');
|
|
142
122
|
const thirdInputs = { messages: [...conversationHistory] };
|
|
143
123
|
await run.processStream(thirdInputs, config);
|
|
144
|
-
|
|
124
|
+
|
|
145
125
|
// Display redacted thinking blocks
|
|
146
126
|
const finalMessages3 = run.getRunMessages();
|
|
147
127
|
console.log('\n\nThinking feature test completed!');
|
|
148
|
-
console.dir(finalMessages3, { depth: null });
|
|
149
128
|
}
|
|
150
129
|
|
|
151
130
|
process.on('unhandledRejection', (reason, promise) => {
|
|
@@ -168,4 +147,4 @@ testThinking().catch((err) => {
|
|
|
168
147
|
console.log('Content parts:');
|
|
169
148
|
console.dir(_contentParts, { depth: null });
|
|
170
149
|
process.exit(1);
|
|
171
|
-
});
|
|
150
|
+
});
|
package/src/scripts/tools.ts
CHANGED
|
@@ -18,13 +18,9 @@ async function testStandardStreaming(): Promise<void> {
|
|
|
18
18
|
const { userName, location, provider, currentDate } = await getArgs();
|
|
19
19
|
const { contentParts, aggregateContent } = createContentAggregator();
|
|
20
20
|
const customHandlers = {
|
|
21
|
-
[GraphEvents.TOOL_END]: new ToolEndHandler(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
(name?: string) => {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
),
|
|
21
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(undefined, (name?: string) => {
|
|
22
|
+
return true;
|
|
23
|
+
}),
|
|
28
24
|
[GraphEvents.CHAT_MODEL_END]: {
|
|
29
25
|
handle: (
|
|
30
26
|
_event: string,
|
package/src/stream.ts
CHANGED
|
@@ -339,8 +339,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
339
339
|
(c) =>
|
|
340
340
|
(c.type?.startsWith(ContentTypes.THINKING) ?? false) ||
|
|
341
341
|
(c.type?.startsWith(ContentTypes.REASONING) ?? false) ||
|
|
342
|
-
(c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false)
|
|
343
|
-
c.type === 'redacted_thinking'
|
|
342
|
+
(c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false)
|
|
344
343
|
)
|
|
345
344
|
) {
|
|
346
345
|
await graph.dispatchReasoningDelta(stepId, {
|
|
@@ -366,8 +365,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
366
365
|
Array.isArray(chunk.content) &&
|
|
367
366
|
(chunk.content[0]?.type === ContentTypes.THINKING ||
|
|
368
367
|
chunk.content[0]?.type === ContentTypes.REASONING ||
|
|
369
|
-
chunk.content[0]?.type === ContentTypes.REASONING_CONTENT
|
|
370
|
-
chunk.content[0]?.type === 'redacted_thinking')
|
|
368
|
+
chunk.content[0]?.type === ContentTypes.REASONING_CONTENT)
|
|
371
369
|
) {
|
|
372
370
|
reasoning_content = 'valid';
|
|
373
371
|
} else if (
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -145,9 +145,9 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
147
|
* Inject session context for code execution tools when available.
|
|
148
|
-
* Each file uses its own session_id (supporting multi-session file tracking).
|
|
149
148
|
* Both session_id and _injected_files are injected directly to invokeParams
|
|
150
149
|
* (not inside args) so they bypass Zod schema validation and reach config.toolCall.
|
|
150
|
+
* This avoids /files endpoint race conditions.
|
|
151
151
|
*/
|
|
152
152
|
if (
|
|
153
153
|
call.name === Constants.EXECUTE_CODE ||
|
|
@@ -156,18 +156,14 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
156
156
|
const codeSession = this.sessions?.get(Constants.EXECUTE_CODE) as
|
|
157
157
|
| t.CodeSessionContext
|
|
158
158
|
| undefined;
|
|
159
|
-
if (codeSession?.
|
|
160
|
-
/**
|
|
161
|
-
* Convert tracked files to CodeEnvFile format for the API.
|
|
162
|
-
* Each file uses its own session_id (set when file was created).
|
|
163
|
-
* This supports files from multiple parallel/sequential executions.
|
|
164
|
-
*/
|
|
159
|
+
if (codeSession?.session_id != null && codeSession.files.length > 0) {
|
|
160
|
+
/** Convert tracked files to CodeEnvFile format for the API */
|
|
165
161
|
const fileRefs: t.CodeEnvFile[] = codeSession.files.map((file) => ({
|
|
166
|
-
session_id:
|
|
162
|
+
session_id: codeSession.session_id,
|
|
167
163
|
id: file.id,
|
|
168
164
|
name: file.name,
|
|
169
165
|
}));
|
|
170
|
-
/** Inject
|
|
166
|
+
/** Inject session_id and files directly - bypasses Zod, reaches config.toolCall */
|
|
171
167
|
invokeParams = {
|
|
172
168
|
...invokeParams,
|
|
173
169
|
session_id: codeSession.session_id,
|
package/src/types/tools.ts
CHANGED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type definitions for Bedrock Converse utilities.
|
|
3
|
-
*/
|
|
4
|
-
import type { Message as BedrockMessage, SystemContentBlock as BedrockSystemContentBlock, ContentBlock as BedrockContentBlock, ConverseResponse, ContentBlockDeltaEvent, ConverseStreamMetadataEvent, ContentBlockStartEvent, ReasoningContentBlock, ReasoningContentBlockDelta } from '@aws-sdk/client-bedrock-runtime';
|
|
5
|
-
/**
|
|
6
|
-
* Reasoning content block type for LangChain messages.
|
|
7
|
-
*/
|
|
8
|
-
export interface MessageContentReasoningBlock {
|
|
9
|
-
type: 'reasoning_content';
|
|
10
|
-
reasoningText?: {
|
|
11
|
-
text?: string;
|
|
12
|
-
signature?: string;
|
|
13
|
-
};
|
|
14
|
-
redactedContent?: string;
|
|
15
|
-
}
|
|
16
|
-
export interface MessageContentReasoningBlockReasoningTextPartial {
|
|
17
|
-
type: 'reasoning_content';
|
|
18
|
-
reasoningText: {
|
|
19
|
-
text?: string;
|
|
20
|
-
signature?: string;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export interface MessageContentReasoningBlockRedacted {
|
|
24
|
-
type: 'reasoning_content';
|
|
25
|
-
redactedContent: string;
|
|
26
|
-
}
|
|
27
|
-
export type { BedrockMessage, BedrockSystemContentBlock, BedrockContentBlock, ConverseResponse, ContentBlockDeltaEvent, ConverseStreamMetadataEvent, ContentBlockStartEvent, ReasoningContentBlock, ReasoningContentBlockDelta, };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bedrock Converse utility exports.
|
|
3
|
-
*/
|
|
4
|
-
export { convertToConverseMessages, extractImageInfo, langchainReasoningBlockToBedrockReasoningBlock, concatenateLangchainReasoningBlocks, } from './message_inputs';
|
|
5
|
-
export { convertConverseMessageToLangChainMessage, handleConverseStreamContentBlockStart, handleConverseStreamContentBlockDelta, handleConverseStreamMetadata, bedrockReasoningBlockToLangchainReasoningBlock, bedrockReasoningDeltaToLangchainPartialReasoningBlock, } from './message_outputs';
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for converting LangChain messages to Bedrock Converse messages.
|
|
3
|
-
* Ported from @langchain/aws common.js
|
|
4
|
-
*/
|
|
5
|
-
import { type BaseMessage, MessageContentComplex } from '@langchain/core/messages';
|
|
6
|
-
import type { BedrockMessage, BedrockSystemContentBlock, BedrockContentBlock, MessageContentReasoningBlock } from '../types';
|
|
7
|
-
/**
|
|
8
|
-
* Convert a LangChain reasoning block to a Bedrock reasoning block.
|
|
9
|
-
*/
|
|
10
|
-
export declare function langchainReasoningBlockToBedrockReasoningBlock(content: MessageContentReasoningBlock): {
|
|
11
|
-
reasoningText?: {
|
|
12
|
-
text?: string;
|
|
13
|
-
signature?: string;
|
|
14
|
-
};
|
|
15
|
-
redactedContent?: Uint8Array;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Concatenate consecutive reasoning blocks in content array.
|
|
19
|
-
*/
|
|
20
|
-
export declare function concatenateLangchainReasoningBlocks(content: Array<MessageContentComplex | MessageContentReasoningBlock>): Array<MessageContentComplex | MessageContentReasoningBlock>;
|
|
21
|
-
/**
|
|
22
|
-
* Extract image info from a base64 string or URL.
|
|
23
|
-
*/
|
|
24
|
-
export declare function extractImageInfo(base64: string): BedrockContentBlock;
|
|
25
|
-
/**
|
|
26
|
-
* Convert LangChain messages to Bedrock Converse messages.
|
|
27
|
-
*/
|
|
28
|
-
export declare function convertToConverseMessages(messages: BaseMessage[]): {
|
|
29
|
-
converseMessages: BedrockMessage[];
|
|
30
|
-
converseSystem: BedrockSystemContentBlock[];
|
|
31
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for converting Bedrock Converse responses to LangChain messages.
|
|
3
|
-
* Ported from @langchain/aws common.js
|
|
4
|
-
*/
|
|
5
|
-
import { AIMessage } from '@langchain/core/messages';
|
|
6
|
-
import { ChatGenerationChunk } from '@langchain/core/outputs';
|
|
7
|
-
import type { BedrockMessage, ConverseResponse, ContentBlockDeltaEvent, ConverseStreamMetadataEvent, ContentBlockStartEvent, ReasoningContentBlock, ReasoningContentBlockDelta, MessageContentReasoningBlock, MessageContentReasoningBlockReasoningTextPartial, MessageContentReasoningBlockRedacted } from '../types';
|
|
8
|
-
/**
|
|
9
|
-
* Convert a Bedrock reasoning block delta to a LangChain partial reasoning block.
|
|
10
|
-
*/
|
|
11
|
-
export declare function bedrockReasoningDeltaToLangchainPartialReasoningBlock(reasoningContent: ReasoningContentBlockDelta): MessageContentReasoningBlockReasoningTextPartial | MessageContentReasoningBlockRedacted;
|
|
12
|
-
/**
|
|
13
|
-
* Convert a Bedrock reasoning block to a LangChain reasoning block.
|
|
14
|
-
*/
|
|
15
|
-
export declare function bedrockReasoningBlockToLangchainReasoningBlock(reasoningContent: ReasoningContentBlock): MessageContentReasoningBlock;
|
|
16
|
-
/**
|
|
17
|
-
* Convert a Bedrock Converse message to a LangChain message.
|
|
18
|
-
*/
|
|
19
|
-
export declare function convertConverseMessageToLangChainMessage(message: BedrockMessage, responseMetadata: Omit<ConverseResponse, 'output'>): AIMessage;
|
|
20
|
-
/**
|
|
21
|
-
* Handle a content block delta event from Bedrock Converse stream.
|
|
22
|
-
*/
|
|
23
|
-
export declare function handleConverseStreamContentBlockDelta(contentBlockDelta: ContentBlockDeltaEvent): ChatGenerationChunk;
|
|
24
|
-
/**
|
|
25
|
-
* Handle a content block start event from Bedrock Converse stream.
|
|
26
|
-
*/
|
|
27
|
-
export declare function handleConverseStreamContentBlockStart(contentBlockStart: ContentBlockStartEvent): ChatGenerationChunk | null;
|
|
28
|
-
/**
|
|
29
|
-
* Handle a metadata event from Bedrock Converse stream.
|
|
30
|
-
*/
|
|
31
|
-
export declare function handleConverseStreamMetadata(metadata: ConverseStreamMetadataEvent, extra: {
|
|
32
|
-
streamUsage: boolean;
|
|
33
|
-
}): ChatGenerationChunk;
|