@librechat/agents 3.0.79 → 3.0.81
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/bedrock/index.cjs +35 -74
- 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/esm/llm/bedrock/index.mjs +35 -74
- 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/types/llm/bedrock/index.d.ts +7 -4
- package/dist/types/messages/cache.d.ts +6 -2
- package/package.json +2 -1
- package/src/llm/bedrock/index.ts +42 -96
- package/src/llm/bedrock/utils/message_outputs.ts +34 -20
- package/src/messages/cache.test.ts +215 -0
- package/src/messages/cache.ts +172 -43
- package/src/scripts/thinking-bedrock.ts +159 -0
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +0 -465
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +0 -1
- package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +0 -238
- package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +0 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +0 -460
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +0 -1
- package/dist/esm/llm/bedrock/utils/message_outputs.mjs +0 -231
- package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +0 -1
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++;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// src/scripts/thinking-bedrock.ts
|
|
2
|
+
import { config } from 'dotenv';
|
|
3
|
+
config();
|
|
4
|
+
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
5
|
+
import type { UsageMetadata } from '@langchain/core/messages';
|
|
6
|
+
import * as t from '@/types';
|
|
7
|
+
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
8
|
+
import { createCodeExecutionTool } from '@/tools/CodeExecutor';
|
|
9
|
+
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
10
|
+
import { GraphEvents, Providers } from '@/common';
|
|
11
|
+
import { getLLMConfig } from '@/utils/llmConfig';
|
|
12
|
+
import { getArgs } from '@/scripts/args';
|
|
13
|
+
import { Run } from '@/run';
|
|
14
|
+
|
|
15
|
+
const conversationHistory: BaseMessage[] = [];
|
|
16
|
+
let _contentParts: t.MessageContentComplex[] = [];
|
|
17
|
+
const collectedUsage: UsageMetadata[] = [];
|
|
18
|
+
|
|
19
|
+
async function testBedrockThinking(): Promise<void> {
|
|
20
|
+
const { userName } = await getArgs();
|
|
21
|
+
const instructions = `You are a helpful AI assistant for ${userName}. When answering questions, be thorough in your reasoning.`;
|
|
22
|
+
const { contentParts, aggregateContent } = createContentAggregator();
|
|
23
|
+
_contentParts = contentParts as t.MessageContentComplex[];
|
|
24
|
+
|
|
25
|
+
// Set up event handlers
|
|
26
|
+
const customHandlers = {
|
|
27
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
28
|
+
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
29
|
+
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
30
|
+
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
31
|
+
handle: (
|
|
32
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
33
|
+
data: t.StreamEventData
|
|
34
|
+
): void => {
|
|
35
|
+
console.log('====== ON_RUN_STEP_COMPLETED ======');
|
|
36
|
+
aggregateContent({
|
|
37
|
+
event,
|
|
38
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
[GraphEvents.ON_RUN_STEP]: {
|
|
43
|
+
handle: (event: GraphEvents.ON_RUN_STEP, data: t.RunStep) => {
|
|
44
|
+
aggregateContent({ event, data });
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
48
|
+
handle: (
|
|
49
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
50
|
+
data: t.RunStepDeltaEvent
|
|
51
|
+
) => {
|
|
52
|
+
aggregateContent({ event, data });
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
56
|
+
handle: (
|
|
57
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
58
|
+
data: t.MessageDeltaEvent
|
|
59
|
+
) => {
|
|
60
|
+
aggregateContent({ event, data });
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
[GraphEvents.ON_REASONING_DELTA]: {
|
|
64
|
+
handle: (
|
|
65
|
+
event: GraphEvents.ON_REASONING_DELTA,
|
|
66
|
+
data: t.ReasoningDeltaEvent
|
|
67
|
+
) => {
|
|
68
|
+
aggregateContent({ event, data });
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const baseLlmConfig = getLLMConfig(Providers.BEDROCK);
|
|
74
|
+
|
|
75
|
+
// Enable thinking with token budget for Bedrock
|
|
76
|
+
const llmConfig = {
|
|
77
|
+
...baseLlmConfig,
|
|
78
|
+
model: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
|
|
79
|
+
maxTokens: 5000,
|
|
80
|
+
additionalModelRequestFields: {
|
|
81
|
+
thinking: { type: 'enabled', budget_tokens: 2000 },
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const run = await Run.create<t.IState>({
|
|
86
|
+
runId: 'test-bedrock-thinking-id',
|
|
87
|
+
graphConfig: {
|
|
88
|
+
instructions,
|
|
89
|
+
type: 'standard',
|
|
90
|
+
tools: [createCodeExecutionTool()],
|
|
91
|
+
llmConfig,
|
|
92
|
+
},
|
|
93
|
+
returnContent: true,
|
|
94
|
+
customHandlers: customHandlers as t.RunConfig['customHandlers'],
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const config = {
|
|
98
|
+
configurable: {
|
|
99
|
+
thread_id: 'bedrock-thinking-test-thread',
|
|
100
|
+
},
|
|
101
|
+
streamMode: 'values',
|
|
102
|
+
version: 'v2' as const,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Test 1: Regular thinking mode
|
|
106
|
+
console.log('\n\nTest 1: Bedrock Regular thinking mode');
|
|
107
|
+
const userMessage1 = `Please print 'hello world' in python`;
|
|
108
|
+
conversationHistory.push(new HumanMessage(userMessage1));
|
|
109
|
+
|
|
110
|
+
console.log('Running first query with Bedrock thinking enabled...');
|
|
111
|
+
const firstInputs = { messages: [...conversationHistory] };
|
|
112
|
+
await run.processStream(firstInputs, config);
|
|
113
|
+
|
|
114
|
+
// Extract and display thinking blocks
|
|
115
|
+
const finalMessages = run.getRunMessages();
|
|
116
|
+
console.log('\n\nFinal messages after Test 1:');
|
|
117
|
+
console.dir(finalMessages, { depth: null });
|
|
118
|
+
|
|
119
|
+
// Test 2: Try multi-turn conversation
|
|
120
|
+
console.log(
|
|
121
|
+
'\n\nTest 2: Multi-turn conversation with Bedrock thinking enabled'
|
|
122
|
+
);
|
|
123
|
+
const userMessage2 = `Given your previous analysis, what would be the most significant technical challenges in making this transition?`;
|
|
124
|
+
conversationHistory.push(new HumanMessage(userMessage2));
|
|
125
|
+
|
|
126
|
+
console.log('Running second query with Bedrock thinking enabled...');
|
|
127
|
+
const secondInputs = { messages: [...conversationHistory] };
|
|
128
|
+
await run.processStream(secondInputs, config);
|
|
129
|
+
|
|
130
|
+
// Display thinking blocks for second response
|
|
131
|
+
const finalMessages2 = run.getRunMessages();
|
|
132
|
+
console.log('\n\nBedrock thinking feature test completed!');
|
|
133
|
+
console.dir(finalMessages2, { depth: null });
|
|
134
|
+
|
|
135
|
+
console.log('\n\nContent parts:');
|
|
136
|
+
console.dir(_contentParts, { depth: null });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
140
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
141
|
+
console.log('Conversation history:');
|
|
142
|
+
console.dir(conversationHistory, { depth: null });
|
|
143
|
+
console.log('Content parts:');
|
|
144
|
+
console.dir(_contentParts, { depth: null });
|
|
145
|
+
process.exit(1);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
process.on('uncaughtException', (err) => {
|
|
149
|
+
console.error('Uncaught Exception:', err);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
testBedrockThinking().catch((err) => {
|
|
153
|
+
console.error(err);
|
|
154
|
+
console.log('Conversation history:');
|
|
155
|
+
console.dir(conversationHistory, { depth: null });
|
|
156
|
+
console.log('Content parts:');
|
|
157
|
+
console.dir(_contentParts, { depth: null });
|
|
158
|
+
process.exit(1);
|
|
159
|
+
});
|