@librechat/agents 3.1.75 → 3.1.77-dev.1

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.
Files changed (272) hide show
  1. package/dist/cjs/graphs/Graph.cjs +22 -3
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/hitl/askUserQuestion.cjs +67 -0
  4. package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -0
  5. package/dist/cjs/hooks/HookRegistry.cjs +54 -0
  6. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  7. package/dist/cjs/hooks/createToolPolicyHook.cjs +115 -0
  8. package/dist/cjs/hooks/createToolPolicyHook.cjs.map +1 -0
  9. package/dist/cjs/hooks/executeHooks.cjs +40 -1
  10. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  11. package/dist/cjs/hooks/types.cjs +1 -0
  12. package/dist/cjs/hooks/types.cjs.map +1 -1
  13. package/dist/cjs/langchain/google-common.cjs +3 -0
  14. package/dist/cjs/langchain/google-common.cjs.map +1 -0
  15. package/dist/cjs/langchain/index.cjs +86 -0
  16. package/dist/cjs/langchain/index.cjs.map +1 -0
  17. package/dist/cjs/langchain/language_models/chat_models.cjs +3 -0
  18. package/dist/cjs/langchain/language_models/chat_models.cjs.map +1 -0
  19. package/dist/cjs/langchain/messages/tool.cjs +3 -0
  20. package/dist/cjs/langchain/messages/tool.cjs.map +1 -0
  21. package/dist/cjs/langchain/messages.cjs +51 -0
  22. package/dist/cjs/langchain/messages.cjs.map +1 -0
  23. package/dist/cjs/langchain/openai.cjs +3 -0
  24. package/dist/cjs/langchain/openai.cjs.map +1 -0
  25. package/dist/cjs/langchain/prompts.cjs +11 -0
  26. package/dist/cjs/langchain/prompts.cjs.map +1 -0
  27. package/dist/cjs/langchain/runnables.cjs +19 -0
  28. package/dist/cjs/langchain/runnables.cjs.map +1 -0
  29. package/dist/cjs/langchain/tools.cjs +23 -0
  30. package/dist/cjs/langchain/tools.cjs.map +1 -0
  31. package/dist/cjs/langchain/utils/env.cjs +11 -0
  32. package/dist/cjs/langchain/utils/env.cjs.map +1 -0
  33. package/dist/cjs/llm/anthropic/index.cjs +145 -52
  34. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  35. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  36. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +21 -14
  37. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  38. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +84 -70
  39. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  40. package/dist/cjs/llm/bedrock/index.cjs +1 -1
  41. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  42. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +213 -3
  43. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  44. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +2 -1
  45. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  46. package/dist/cjs/llm/google/utils/common.cjs +5 -4
  47. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  48. package/dist/cjs/llm/openai/index.cjs +519 -655
  49. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  50. package/dist/cjs/llm/openai/utils/index.cjs +20 -458
  51. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  52. package/dist/cjs/llm/openrouter/index.cjs +57 -175
  53. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  54. package/dist/cjs/llm/vertexai/index.cjs +5 -3
  55. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  56. package/dist/cjs/main.cjs +112 -3
  57. package/dist/cjs/main.cjs.map +1 -1
  58. package/dist/cjs/messages/cache.cjs +2 -1
  59. package/dist/cjs/messages/cache.cjs.map +1 -1
  60. package/dist/cjs/messages/core.cjs +7 -6
  61. package/dist/cjs/messages/core.cjs.map +1 -1
  62. package/dist/cjs/messages/format.cjs +73 -15
  63. package/dist/cjs/messages/format.cjs.map +1 -1
  64. package/dist/cjs/messages/langchain.cjs +26 -0
  65. package/dist/cjs/messages/langchain.cjs.map +1 -0
  66. package/dist/cjs/messages/prune.cjs +7 -6
  67. package/dist/cjs/messages/prune.cjs.map +1 -1
  68. package/dist/cjs/run.cjs +400 -42
  69. package/dist/cjs/run.cjs.map +1 -1
  70. package/dist/cjs/tools/ToolNode.cjs +556 -56
  71. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  72. package/dist/cjs/tools/search/search.cjs +55 -66
  73. package/dist/cjs/tools/search/search.cjs.map +1 -1
  74. package/dist/cjs/tools/search/tavily-scraper.cjs +189 -0
  75. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -0
  76. package/dist/cjs/tools/search/tavily-search.cjs +372 -0
  77. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -0
  78. package/dist/cjs/tools/search/tool.cjs +26 -4
  79. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  80. package/dist/cjs/tools/search/utils.cjs +10 -3
  81. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  82. package/dist/esm/graphs/Graph.mjs +22 -3
  83. package/dist/esm/graphs/Graph.mjs.map +1 -1
  84. package/dist/esm/hitl/askUserQuestion.mjs +65 -0
  85. package/dist/esm/hitl/askUserQuestion.mjs.map +1 -0
  86. package/dist/esm/hooks/HookRegistry.mjs +54 -0
  87. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  88. package/dist/esm/hooks/createToolPolicyHook.mjs +113 -0
  89. package/dist/esm/hooks/createToolPolicyHook.mjs.map +1 -0
  90. package/dist/esm/hooks/executeHooks.mjs +40 -1
  91. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  92. package/dist/esm/hooks/types.mjs +1 -0
  93. package/dist/esm/hooks/types.mjs.map +1 -1
  94. package/dist/esm/langchain/google-common.mjs +2 -0
  95. package/dist/esm/langchain/google-common.mjs.map +1 -0
  96. package/dist/esm/langchain/index.mjs +5 -0
  97. package/dist/esm/langchain/index.mjs.map +1 -0
  98. package/dist/esm/langchain/language_models/chat_models.mjs +2 -0
  99. package/dist/esm/langchain/language_models/chat_models.mjs.map +1 -0
  100. package/dist/esm/langchain/messages/tool.mjs +2 -0
  101. package/dist/esm/langchain/messages/tool.mjs.map +1 -0
  102. package/dist/esm/langchain/messages.mjs +2 -0
  103. package/dist/esm/langchain/messages.mjs.map +1 -0
  104. package/dist/esm/langchain/openai.mjs +2 -0
  105. package/dist/esm/langchain/openai.mjs.map +1 -0
  106. package/dist/esm/langchain/prompts.mjs +2 -0
  107. package/dist/esm/langchain/prompts.mjs.map +1 -0
  108. package/dist/esm/langchain/runnables.mjs +2 -0
  109. package/dist/esm/langchain/runnables.mjs.map +1 -0
  110. package/dist/esm/langchain/tools.mjs +2 -0
  111. package/dist/esm/langchain/tools.mjs.map +1 -0
  112. package/dist/esm/langchain/utils/env.mjs +2 -0
  113. package/dist/esm/langchain/utils/env.mjs.map +1 -0
  114. package/dist/esm/llm/anthropic/index.mjs +146 -54
  115. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  116. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  117. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +21 -14
  118. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  119. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +84 -71
  120. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  121. package/dist/esm/llm/bedrock/index.mjs +1 -1
  122. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  123. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +214 -4
  124. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  125. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +2 -1
  126. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  127. package/dist/esm/llm/google/utils/common.mjs +5 -4
  128. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  129. package/dist/esm/llm/openai/index.mjs +520 -656
  130. package/dist/esm/llm/openai/index.mjs.map +1 -1
  131. package/dist/esm/llm/openai/utils/index.mjs +23 -459
  132. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  133. package/dist/esm/llm/openrouter/index.mjs +57 -175
  134. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  135. package/dist/esm/llm/vertexai/index.mjs +5 -3
  136. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  137. package/dist/esm/main.mjs +7 -0
  138. package/dist/esm/main.mjs.map +1 -1
  139. package/dist/esm/messages/cache.mjs +2 -1
  140. package/dist/esm/messages/cache.mjs.map +1 -1
  141. package/dist/esm/messages/core.mjs +7 -6
  142. package/dist/esm/messages/core.mjs.map +1 -1
  143. package/dist/esm/messages/format.mjs +73 -15
  144. package/dist/esm/messages/format.mjs.map +1 -1
  145. package/dist/esm/messages/langchain.mjs +23 -0
  146. package/dist/esm/messages/langchain.mjs.map +1 -0
  147. package/dist/esm/messages/prune.mjs +7 -6
  148. package/dist/esm/messages/prune.mjs.map +1 -1
  149. package/dist/esm/run.mjs +400 -42
  150. package/dist/esm/run.mjs.map +1 -1
  151. package/dist/esm/tools/ToolNode.mjs +557 -57
  152. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  153. package/dist/esm/tools/search/search.mjs +55 -66
  154. package/dist/esm/tools/search/search.mjs.map +1 -1
  155. package/dist/esm/tools/search/tavily-scraper.mjs +186 -0
  156. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -0
  157. package/dist/esm/tools/search/tavily-search.mjs +370 -0
  158. package/dist/esm/tools/search/tavily-search.mjs.map +1 -0
  159. package/dist/esm/tools/search/tool.mjs +26 -4
  160. package/dist/esm/tools/search/tool.mjs.map +1 -1
  161. package/dist/esm/tools/search/utils.mjs +10 -3
  162. package/dist/esm/tools/search/utils.mjs.map +1 -1
  163. package/dist/types/graphs/Graph.d.ts +7 -0
  164. package/dist/types/hitl/askUserQuestion.d.ts +55 -0
  165. package/dist/types/hitl/index.d.ts +6 -0
  166. package/dist/types/hooks/HookRegistry.d.ts +58 -0
  167. package/dist/types/hooks/createToolPolicyHook.d.ts +87 -0
  168. package/dist/types/hooks/index.d.ts +4 -1
  169. package/dist/types/hooks/types.d.ts +109 -3
  170. package/dist/types/index.d.ts +10 -0
  171. package/dist/types/langchain/google-common.d.ts +1 -0
  172. package/dist/types/langchain/index.d.ts +8 -0
  173. package/dist/types/langchain/language_models/chat_models.d.ts +1 -0
  174. package/dist/types/langchain/messages/tool.d.ts +1 -0
  175. package/dist/types/langchain/messages.d.ts +2 -0
  176. package/dist/types/langchain/openai.d.ts +1 -0
  177. package/dist/types/langchain/prompts.d.ts +1 -0
  178. package/dist/types/langchain/runnables.d.ts +2 -0
  179. package/dist/types/langchain/tools.d.ts +2 -0
  180. package/dist/types/langchain/utils/env.d.ts +1 -0
  181. package/dist/types/llm/anthropic/index.d.ts +22 -9
  182. package/dist/types/llm/anthropic/types.d.ts +5 -1
  183. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +13 -6
  184. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +1 -1
  185. package/dist/types/llm/openai/index.d.ts +21 -24
  186. package/dist/types/llm/openrouter/index.d.ts +11 -9
  187. package/dist/types/llm/vertexai/index.d.ts +1 -0
  188. package/dist/types/messages/cache.d.ts +4 -1
  189. package/dist/types/messages/format.d.ts +4 -1
  190. package/dist/types/messages/langchain.d.ts +27 -0
  191. package/dist/types/run.d.ts +117 -1
  192. package/dist/types/tools/ToolNode.d.ts +26 -1
  193. package/dist/types/tools/search/tavily-scraper.d.ts +19 -0
  194. package/dist/types/tools/search/tavily-search.d.ts +4 -0
  195. package/dist/types/tools/search/types.d.ts +99 -5
  196. package/dist/types/tools/search/utils.d.ts +2 -2
  197. package/dist/types/types/graph.d.ts +23 -37
  198. package/dist/types/types/hitl.d.ts +272 -0
  199. package/dist/types/types/index.d.ts +1 -0
  200. package/dist/types/types/llm.d.ts +3 -3
  201. package/dist/types/types/run.d.ts +33 -0
  202. package/dist/types/types/stream.d.ts +1 -1
  203. package/dist/types/types/tools.d.ts +19 -0
  204. package/package.json +80 -17
  205. package/src/graphs/Graph.ts +33 -4
  206. package/src/graphs/__tests__/composition.smoke.test.ts +188 -0
  207. package/src/hitl/askUserQuestion.ts +72 -0
  208. package/src/hitl/index.ts +7 -0
  209. package/src/hooks/HookRegistry.ts +71 -0
  210. package/src/hooks/__tests__/createToolPolicyHook.test.ts +259 -0
  211. package/src/hooks/createToolPolicyHook.ts +184 -0
  212. package/src/hooks/executeHooks.ts +50 -1
  213. package/src/hooks/index.ts +6 -0
  214. package/src/hooks/types.ts +112 -0
  215. package/src/index.ts +22 -0
  216. package/src/langchain/google-common.ts +1 -0
  217. package/src/langchain/index.ts +8 -0
  218. package/src/langchain/language_models/chat_models.ts +1 -0
  219. package/src/langchain/messages/tool.ts +5 -0
  220. package/src/langchain/messages.ts +21 -0
  221. package/src/langchain/openai.ts +1 -0
  222. package/src/langchain/prompts.ts +1 -0
  223. package/src/langchain/runnables.ts +7 -0
  224. package/src/langchain/tools.ts +8 -0
  225. package/src/langchain/utils/env.ts +1 -0
  226. package/src/llm/anthropic/index.ts +252 -84
  227. package/src/llm/anthropic/llm.spec.ts +751 -102
  228. package/src/llm/anthropic/types.ts +9 -1
  229. package/src/llm/anthropic/utils/message_inputs.ts +37 -19
  230. package/src/llm/anthropic/utils/message_outputs.ts +119 -101
  231. package/src/llm/bedrock/index.ts +2 -2
  232. package/src/llm/bedrock/llm.spec.ts +341 -0
  233. package/src/llm/bedrock/utils/message_inputs.ts +303 -4
  234. package/src/llm/bedrock/utils/message_outputs.ts +2 -1
  235. package/src/llm/custom-chat-models.smoke.test.ts +836 -0
  236. package/src/llm/google/llm.spec.ts +339 -57
  237. package/src/llm/google/utils/common.ts +53 -48
  238. package/src/llm/openai/contentBlocks.test.ts +346 -0
  239. package/src/llm/openai/index.ts +856 -833
  240. package/src/llm/openai/utils/index.ts +107 -78
  241. package/src/llm/openai/utils/messages.test.ts +159 -0
  242. package/src/llm/openrouter/index.ts +124 -247
  243. package/src/llm/openrouter/reasoning.test.ts +8 -1
  244. package/src/llm/vertexai/index.ts +11 -5
  245. package/src/llm/vertexai/llm.spec.ts +28 -1
  246. package/src/messages/cache.test.ts +4 -3
  247. package/src/messages/cache.ts +3 -2
  248. package/src/messages/core.ts +16 -9
  249. package/src/messages/format.ts +96 -16
  250. package/src/messages/formatAgentMessages.test.ts +166 -1
  251. package/src/messages/langchain.ts +39 -0
  252. package/src/messages/prune.ts +12 -8
  253. package/src/run.ts +456 -47
  254. package/src/scripts/caching.ts +2 -3
  255. package/src/specs/summarization.test.ts +51 -58
  256. package/src/tools/ToolNode.ts +706 -63
  257. package/src/tools/__tests__/hitl.test.ts +3593 -0
  258. package/src/tools/search/search.ts +83 -73
  259. package/src/tools/search/tavily-scraper.ts +235 -0
  260. package/src/tools/search/tavily-search.ts +424 -0
  261. package/src/tools/search/tavily.test.ts +965 -0
  262. package/src/tools/search/tool.ts +36 -26
  263. package/src/tools/search/types.ts +133 -8
  264. package/src/tools/search/utils.ts +13 -5
  265. package/src/types/graph.ts +32 -87
  266. package/src/types/hitl.ts +303 -0
  267. package/src/types/index.ts +1 -0
  268. package/src/types/llm.ts +3 -3
  269. package/src/types/run.ts +33 -0
  270. package/src/types/stream.ts +1 -1
  271. package/src/types/tools.ts +19 -0
  272. package/src/utils/llmConfig.ts +1 -6
@@ -9,12 +9,14 @@ import {
9
9
  HumanMessage,
10
10
  SystemMessage,
11
11
  AIMessageChunk,
12
+ type MessageContentComplex,
12
13
  } from '@langchain/core/messages';
13
14
  import { concat } from '@langchain/core/utils/stream';
14
15
  import { ChatGenerationChunk } from '@langchain/core/outputs';
15
16
  import {
16
17
  BedrockRuntimeClient,
17
18
  ConverseCommand,
19
+ ConverseStreamCommand,
18
20
  } from '@aws-sdk/client-bedrock-runtime';
19
21
  import type { ConverseResponse } from '@aws-sdk/client-bedrock-runtime';
20
22
  import {
@@ -22,6 +24,7 @@ import {
22
24
  handleConverseStreamMetadata,
23
25
  convertToConverseMessages,
24
26
  } from './utils';
27
+ import { toLangChainContent } from '@/messages/langchain';
25
28
  import { CustomChatBedrockConverse, ServiceTierType } from './index';
26
29
 
27
30
  jest.setTimeout(120000);
@@ -35,6 +38,53 @@ const baseConstructorArgs = {
35
38
  },
36
39
  };
37
40
 
41
+ type ConverseContentBlock = NonNullable<
42
+ ReturnType<
43
+ typeof convertToConverseMessages
44
+ >['converseMessages'][number]['content']
45
+ >[number];
46
+ type BedrockVideoBlock = ConverseContentBlock & {
47
+ video: {
48
+ format?: string;
49
+ source?: { bytes?: Uint8Array; s3Location?: { uri?: string } };
50
+ };
51
+ };
52
+ type BedrockAudioBlock = ConverseContentBlock & {
53
+ audio: {
54
+ format?: string;
55
+ source?: { bytes?: Uint8Array; s3Location?: { uri?: string } };
56
+ };
57
+ };
58
+ type BedrockDocumentBlock = ConverseContentBlock & {
59
+ document: {
60
+ format?: string;
61
+ name?: string;
62
+ };
63
+ };
64
+
65
+ function expectVideoBlock(block: ConverseContentBlock): BedrockVideoBlock {
66
+ expect(block).toHaveProperty('video');
67
+ return block as BedrockVideoBlock;
68
+ }
69
+
70
+ function expectAudioBlock(block: ConverseContentBlock): BedrockAudioBlock {
71
+ expect(block).toHaveProperty('audio');
72
+ return block as BedrockAudioBlock;
73
+ }
74
+
75
+ function expectDocumentBlock(
76
+ block: ConverseContentBlock
77
+ ): BedrockDocumentBlock {
78
+ expect(block).toHaveProperty('document');
79
+ return block as BedrockDocumentBlock;
80
+ }
81
+
82
+ function humanMessageWithContent(
83
+ content: MessageContentComplex[]
84
+ ): HumanMessage {
85
+ return new HumanMessage({ content: toLangChainContent(content) });
86
+ }
87
+
38
88
  describe('CustomChatBedrockConverse', () => {
39
89
  describe('applicationInferenceProfile parameter', () => {
40
90
  test('should initialize applicationInferenceProfile from constructor', () => {
@@ -135,6 +185,59 @@ describe('CustomChatBedrockConverse', () => {
135
185
  'anthropic.claude-3-haiku-20240307-v1:0'
136
186
  );
137
187
  });
188
+
189
+ test('should send applicationInferenceProfile as modelId in ConverseStreamCommand when provided', async () => {
190
+ const testArn =
191
+ 'arn:aws:bedrock:eu-west-1:123456789012:application-inference-profile/test-profile';
192
+ const mockSend = jest
193
+ .fn<
194
+ (command: ConverseStreamCommand) => Promise<{
195
+ stream: AsyncIterable<{
196
+ contentBlockDelta: {
197
+ contentBlockIndex: number;
198
+ delta: { text: string };
199
+ };
200
+ }>;
201
+ }>
202
+ >()
203
+ .mockResolvedValue({
204
+ stream: (async function* streamChunks() {
205
+ yield {
206
+ contentBlockDelta: {
207
+ contentBlockIndex: 0,
208
+ delta: { text: 'Test response' },
209
+ },
210
+ };
211
+ })(),
212
+ });
213
+
214
+ const mockClient = {
215
+ send: mockSend,
216
+ } as unknown as BedrockRuntimeClient;
217
+
218
+ const model = new CustomChatBedrockConverse({
219
+ ...baseConstructorArgs,
220
+ model: 'anthropic.claude-3-haiku-20240307-v1:0',
221
+ applicationInferenceProfile: testArn,
222
+ client: mockClient,
223
+ });
224
+
225
+ let chunks = 0;
226
+ for await (const _chunk of await model.stream([
227
+ new HumanMessage('Hello'),
228
+ ])) {
229
+ chunks += 1;
230
+ }
231
+
232
+ expect(mockSend).toHaveBeenCalledTimes(1);
233
+ expect(chunks).toBe(1);
234
+ const commandArg = mockSend.mock.calls[0][0] as ConverseStreamCommand;
235
+ expect(commandArg).toBeInstanceOf(ConverseStreamCommand);
236
+ expect(commandArg.input.modelId).toBe(testArn);
237
+ expect(commandArg.input.modelId).not.toBe(
238
+ 'anthropic.claude-3-haiku-20240307-v1:0'
239
+ );
240
+ });
138
241
  });
139
242
 
140
243
  describe('serviceTier configuration', () => {
@@ -753,6 +856,244 @@ describe('convertToConverseMessages', () => {
753
856
  'call_2'
754
857
  );
755
858
  });
859
+
860
+ describe('video content block conversion', () => {
861
+ test('converts multimodal video block with base64 data', () => {
862
+ const videoData = btoa('fake-video-bytes');
863
+ const result = convertToConverseMessages([
864
+ humanMessageWithContent([
865
+ { type: 'text', text: 'Describe this video' },
866
+ {
867
+ type: 'video',
868
+ mimeType: 'video/mp4',
869
+ data: videoData,
870
+ } as MessageContentComplex,
871
+ ]),
872
+ ]);
873
+
874
+ const content = result.converseMessages[0].content!;
875
+ expect(content).toHaveLength(2);
876
+ expect(content[0]).toEqual({ text: 'Describe this video' });
877
+ const videoBlock = expectVideoBlock(content[1]);
878
+ expect(videoBlock.video.format).toBe('mp4');
879
+ expect(videoBlock.video.source?.bytes).toBeInstanceOf(Uint8Array);
880
+ });
881
+
882
+ test('converts multimodal video block with Uint8Array data', () => {
883
+ const videoBytes = new Uint8Array([1, 2, 3, 4]);
884
+ const result = convertToConverseMessages([
885
+ humanMessageWithContent([
886
+ {
887
+ type: 'video',
888
+ mimeType: 'video/webm',
889
+ data: videoBytes,
890
+ } as MessageContentComplex,
891
+ ]),
892
+ ]);
893
+
894
+ const content = result.converseMessages[0].content!;
895
+ const videoBlock = expectVideoBlock(content[0]);
896
+ expect(videoBlock.video.format).toBe('webm');
897
+ expect(videoBlock.video.source?.bytes).toBe(videoBytes);
898
+ });
899
+
900
+ test('passes through native Bedrock video block', () => {
901
+ const videoSource = {
902
+ bytes: new Uint8Array([1, 2, 3]),
903
+ };
904
+ const result = convertToConverseMessages([
905
+ humanMessageWithContent([
906
+ {
907
+ type: 'video',
908
+ video: {
909
+ format: 'mp4',
910
+ source: videoSource,
911
+ },
912
+ } as MessageContentComplex,
913
+ ]),
914
+ ]);
915
+
916
+ const content = result.converseMessages[0].content!;
917
+ const videoBlock = expectVideoBlock(content[0]);
918
+ expect(videoBlock.video.format).toBe('mp4');
919
+ expect(videoBlock.video.source).toBe(videoSource);
920
+ });
921
+
922
+ test('converts video block with S3 fileId', () => {
923
+ const result = convertToConverseMessages([
924
+ humanMessageWithContent([
925
+ {
926
+ type: 'video',
927
+ mimeType: 'video/mp4',
928
+ fileId: 's3://my-bucket/my-video.mp4',
929
+ } as MessageContentComplex,
930
+ ]),
931
+ ]);
932
+
933
+ const content = result.converseMessages[0].content!;
934
+ const videoBlock = expectVideoBlock(content[0]);
935
+ expect(videoBlock.video.format).toBe('mp4');
936
+ expect(videoBlock.video.source?.s3Location?.uri).toBe(
937
+ 's3://my-bucket/my-video.mp4'
938
+ );
939
+ });
940
+ });
941
+
942
+ describe('audio content block conversion', () => {
943
+ test('converts multimodal audio block with base64 data', () => {
944
+ const audioData = btoa('fake-audio-bytes');
945
+ const result = convertToConverseMessages([
946
+ humanMessageWithContent([
947
+ { type: 'text', text: 'Transcribe this audio' },
948
+ {
949
+ type: 'audio',
950
+ mimeType: 'audio/mp3',
951
+ data: audioData,
952
+ } as MessageContentComplex,
953
+ ]),
954
+ ]);
955
+
956
+ const content = result.converseMessages[0].content!;
957
+ expect(content).toHaveLength(2);
958
+ expect(content[0]).toEqual({ text: 'Transcribe this audio' });
959
+ const audioBlock = expectAudioBlock(content[1]);
960
+ expect(audioBlock.audio.format).toBe('mp3');
961
+ expect(audioBlock.audio.source?.bytes).toBeInstanceOf(Uint8Array);
962
+ });
963
+
964
+ test('converts multimodal audio block with Uint8Array data', () => {
965
+ const audioBytes = new Uint8Array([1, 2, 3, 4]);
966
+ const result = convertToConverseMessages([
967
+ humanMessageWithContent([
968
+ {
969
+ type: 'audio',
970
+ mimeType: 'audio/wav',
971
+ data: audioBytes,
972
+ } as MessageContentComplex,
973
+ ]),
974
+ ]);
975
+
976
+ const content = result.converseMessages[0].content!;
977
+ const audioBlock = expectAudioBlock(content[0]);
978
+ expect(audioBlock.audio.format).toBe('wav');
979
+ expect(audioBlock.audio.source?.bytes).toBe(audioBytes);
980
+ });
981
+
982
+ test('passes through native Bedrock audio block', () => {
983
+ const audioSource = {
984
+ bytes: new Uint8Array([1, 2, 3]),
985
+ };
986
+ const result = convertToConverseMessages([
987
+ humanMessageWithContent([
988
+ {
989
+ type: 'audio',
990
+ audio: {
991
+ format: 'flac',
992
+ source: audioSource,
993
+ },
994
+ } as MessageContentComplex,
995
+ ]),
996
+ ]);
997
+
998
+ const content = result.converseMessages[0].content!;
999
+ const audioBlock = expectAudioBlock(content[0]);
1000
+ expect(audioBlock.audio.format).toBe('flac');
1001
+ expect(audioBlock.audio.source).toBe(audioSource);
1002
+ });
1003
+
1004
+ test('converts audio block with S3 fileId', () => {
1005
+ const result = convertToConverseMessages([
1006
+ humanMessageWithContent([
1007
+ {
1008
+ type: 'audio',
1009
+ mimeType: 'audio/mp3',
1010
+ fileId: 's3://my-bucket/my-audio.mp3',
1011
+ } as MessageContentComplex,
1012
+ ]),
1013
+ ]);
1014
+
1015
+ const content = result.converseMessages[0].content!;
1016
+ const audioBlock = expectAudioBlock(content[0]);
1017
+ expect(audioBlock.audio.format).toBe('mp3');
1018
+ expect(audioBlock.audio.source?.s3Location?.uri).toBe(
1019
+ 's3://my-bucket/my-audio.mp3'
1020
+ );
1021
+ });
1022
+ });
1023
+
1024
+ describe('document content block conversion', () => {
1025
+ test('imputes placeholder filename when no name is provided', () => {
1026
+ const pdfData = btoa('fake-pdf-bytes');
1027
+ const result = convertToConverseMessages([
1028
+ humanMessageWithContent([
1029
+ {
1030
+ type: 'file',
1031
+ source_type: 'base64',
1032
+ mime_type: 'application/pdf',
1033
+ data: pdfData,
1034
+ } as MessageContentComplex,
1035
+ ]),
1036
+ ]);
1037
+
1038
+ const content = result.converseMessages[0].content!;
1039
+ expect(content).toHaveLength(1);
1040
+ const documentBlock = expectDocumentBlock(content[0]);
1041
+ expect(documentBlock.document.format).toBe('pdf');
1042
+ expect(documentBlock.document.name).toBeDefined();
1043
+ expect(typeof documentBlock.document.name).toBe('string');
1044
+ expect(documentBlock.document.name?.length).toBe(12);
1045
+ });
1046
+
1047
+ test('uses provided filename from metadata', () => {
1048
+ const pdfData = btoa('fake-pdf-bytes');
1049
+ const result = convertToConverseMessages([
1050
+ humanMessageWithContent([
1051
+ {
1052
+ type: 'file',
1053
+ source_type: 'base64',
1054
+ mime_type: 'application/pdf',
1055
+ data: pdfData,
1056
+ metadata: { filename: 'my-report.pdf' },
1057
+ } as MessageContentComplex,
1058
+ ]),
1059
+ ]);
1060
+
1061
+ const content = result.converseMessages[0].content!;
1062
+ expect(expectDocumentBlock(content[0]).document.name).toBe(
1063
+ 'my-report.pdf'
1064
+ );
1065
+ });
1066
+
1067
+ test('generates unique placeholder filenames for multiple files', () => {
1068
+ const pdfData = btoa('fake-pdf-bytes');
1069
+ const result = convertToConverseMessages([
1070
+ humanMessageWithContent([
1071
+ {
1072
+ type: 'file',
1073
+ source_type: 'base64',
1074
+ mime_type: 'application/pdf',
1075
+ data: pdfData,
1076
+ } as MessageContentComplex,
1077
+ {
1078
+ type: 'file',
1079
+ source_type: 'base64',
1080
+ mime_type: 'application/pdf',
1081
+ data: pdfData,
1082
+ } as MessageContentComplex,
1083
+ ]),
1084
+ ]);
1085
+
1086
+ const content = result.converseMessages[0].content!;
1087
+ expect(content).toHaveLength(2);
1088
+ const firstDocument = expectDocumentBlock(content[0]);
1089
+ const secondDocument = expectDocumentBlock(content[1]);
1090
+ expect(firstDocument.document.name).toBeDefined();
1091
+ expect(secondDocument.document.name).toBeDefined();
1092
+ expect(firstDocument.document.name).not.toBe(
1093
+ secondDocument.document.name
1094
+ );
1095
+ });
1096
+ });
756
1097
  });
757
1098
 
758
1099
  // Integration tests (require AWS credentials)