browser-use 0.2.0 → 0.3.0

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 (259) hide show
  1. package/README.md +295 -686
  2. package/dist/actor/element.d.ts +19 -0
  3. package/dist/actor/element.js +46 -0
  4. package/dist/actor/index.d.ts +4 -0
  5. package/dist/actor/index.js +4 -0
  6. package/dist/actor/mouse.d.ts +19 -0
  7. package/dist/actor/mouse.js +39 -0
  8. package/dist/actor/page.d.ts +29 -0
  9. package/dist/actor/page.js +88 -0
  10. package/dist/actor/utils.d.ts +4 -0
  11. package/dist/actor/utils.js +35 -0
  12. package/dist/agent/cloud-events.d.ts +18 -0
  13. package/dist/agent/cloud-events.js +65 -2
  14. package/dist/agent/gif.d.ts +1 -0
  15. package/dist/agent/gif.js +24 -2
  16. package/dist/agent/judge.d.ts +17 -0
  17. package/dist/agent/judge.js +197 -0
  18. package/dist/agent/message-manager/service.d.ts +12 -4
  19. package/dist/agent/message-manager/service.js +205 -39
  20. package/dist/agent/message-manager/utils.js +0 -1
  21. package/dist/agent/message-manager/views.d.ts +4 -0
  22. package/dist/agent/message-manager/views.js +11 -7
  23. package/dist/agent/prompts.d.ts +24 -3
  24. package/dist/agent/prompts.js +274 -59
  25. package/dist/agent/service.d.ts +99 -41
  26. package/dist/agent/service.js +2266 -472
  27. package/dist/agent/variable-detector.d.ts +12 -0
  28. package/dist/agent/variable-detector.js +211 -0
  29. package/dist/agent/views.d.ts +237 -18
  30. package/dist/agent/views.js +446 -33
  31. package/dist/browser/cloud/cloud.d.ts +20 -0
  32. package/dist/browser/cloud/cloud.js +129 -0
  33. package/dist/browser/cloud/index.d.ts +2 -0
  34. package/dist/browser/cloud/index.js +2 -0
  35. package/dist/browser/cloud/views.d.ts +41 -0
  36. package/dist/browser/cloud/views.js +35 -0
  37. package/dist/browser/events.d.ts +345 -0
  38. package/dist/browser/events.js +566 -0
  39. package/dist/browser/extensions.js +17 -17
  40. package/dist/browser/index.d.ts +4 -0
  41. package/dist/browser/index.js +4 -0
  42. package/dist/browser/profile.d.ts +8 -2
  43. package/dist/browser/profile.js +79 -12
  44. package/dist/browser/session-manager.d.ts +85 -0
  45. package/dist/browser/session-manager.js +208 -0
  46. package/dist/browser/session.d.ts +100 -8
  47. package/dist/browser/session.js +1097 -58
  48. package/dist/browser/types.d.ts +0 -2
  49. package/dist/browser/views.d.ts +39 -0
  50. package/dist/browser/views.js +32 -0
  51. package/dist/browser/watchdogs/aboutblank-watchdog.d.ts +12 -0
  52. package/dist/browser/watchdogs/aboutblank-watchdog.js +131 -0
  53. package/dist/browser/watchdogs/base.d.ts +21 -0
  54. package/dist/browser/watchdogs/base.js +81 -0
  55. package/dist/browser/watchdogs/cdp-session-watchdog.d.ts +14 -0
  56. package/dist/browser/watchdogs/cdp-session-watchdog.js +177 -0
  57. package/dist/browser/watchdogs/crash-watchdog.d.ts +38 -0
  58. package/dist/browser/watchdogs/crash-watchdog.js +296 -0
  59. package/dist/browser/watchdogs/default-action-watchdog.d.ts +49 -0
  60. package/dist/browser/watchdogs/default-action-watchdog.js +212 -0
  61. package/dist/browser/watchdogs/dom-watchdog.d.ts +8 -0
  62. package/dist/browser/watchdogs/dom-watchdog.js +31 -0
  63. package/dist/browser/watchdogs/downloads-watchdog.d.ts +77 -0
  64. package/dist/browser/watchdogs/downloads-watchdog.js +409 -0
  65. package/dist/browser/watchdogs/har-recording-watchdog.d.ts +19 -0
  66. package/dist/browser/watchdogs/har-recording-watchdog.js +317 -0
  67. package/dist/browser/watchdogs/index.d.ts +15 -0
  68. package/dist/browser/watchdogs/index.js +15 -0
  69. package/dist/browser/watchdogs/local-browser-watchdog.d.ts +10 -0
  70. package/dist/browser/watchdogs/local-browser-watchdog.js +32 -0
  71. package/dist/browser/watchdogs/permissions-watchdog.d.ts +8 -0
  72. package/dist/browser/watchdogs/permissions-watchdog.js +73 -0
  73. package/dist/browser/watchdogs/popups-watchdog.d.ts +13 -0
  74. package/dist/browser/watchdogs/popups-watchdog.js +77 -0
  75. package/dist/browser/watchdogs/recording-watchdog.d.ts +27 -0
  76. package/dist/browser/watchdogs/recording-watchdog.js +249 -0
  77. package/dist/browser/watchdogs/screenshot-watchdog.d.ts +6 -0
  78. package/dist/browser/watchdogs/screenshot-watchdog.js +13 -0
  79. package/dist/browser/watchdogs/security-watchdog.d.ts +10 -0
  80. package/dist/browser/watchdogs/security-watchdog.js +84 -0
  81. package/dist/browser/watchdogs/storage-state-watchdog.d.ts +24 -0
  82. package/dist/browser/watchdogs/storage-state-watchdog.js +288 -0
  83. package/dist/cli.d.ts +7 -2
  84. package/dist/cli.js +182 -25
  85. package/dist/code-use/formatting.d.ts +3 -0
  86. package/dist/code-use/formatting.js +18 -0
  87. package/dist/code-use/index.d.ts +6 -0
  88. package/dist/code-use/index.js +6 -0
  89. package/dist/code-use/namespace.d.ts +5 -0
  90. package/dist/code-use/namespace.js +81 -0
  91. package/dist/code-use/notebook-export.d.ts +3 -0
  92. package/dist/code-use/notebook-export.js +56 -0
  93. package/dist/code-use/service.d.ts +24 -0
  94. package/dist/code-use/service.js +104 -0
  95. package/dist/code-use/utils.d.ts +4 -0
  96. package/dist/code-use/utils.js +98 -0
  97. package/dist/code-use/views.d.ts +108 -0
  98. package/dist/code-use/views.js +165 -0
  99. package/dist/config.d.ts +13 -0
  100. package/dist/config.js +69 -3
  101. package/dist/controller/registry/service.d.ts +10 -1
  102. package/dist/controller/registry/service.js +266 -10
  103. package/dist/controller/registry/views.d.ts +4 -1
  104. package/dist/controller/registry/views.js +25 -2
  105. package/dist/controller/service.d.ts +10 -1
  106. package/dist/controller/service.js +1807 -268
  107. package/dist/controller/views.d.ts +78 -155
  108. package/dist/controller/views.js +61 -12
  109. package/dist/dom/history-tree-processor/service.d.ts +5 -0
  110. package/dist/dom/history-tree-processor/service.js +169 -14
  111. package/dist/dom/history-tree-processor/view.d.ts +7 -1
  112. package/dist/dom/history-tree-processor/view.js +10 -1
  113. package/dist/dom/markdown-extractor.d.ts +37 -0
  114. package/dist/dom/markdown-extractor.js +345 -0
  115. package/dist/dom/service.d.ts +3 -1
  116. package/dist/dom/service.js +76 -0
  117. package/dist/dom/views.d.ts +1 -0
  118. package/dist/dom/views.js +45 -0
  119. package/dist/event-bus.d.ts +107 -7
  120. package/dist/event-bus.js +313 -10
  121. package/dist/exceptions.d.ts +0 -3
  122. package/dist/exceptions.js +0 -7
  123. package/dist/filesystem/file-system.d.ts +18 -0
  124. package/dist/filesystem/file-system.js +503 -42
  125. package/dist/index.d.ts +7 -0
  126. package/dist/index.js +6 -0
  127. package/dist/integrations/gmail/actions.d.ts +3 -3
  128. package/dist/integrations/gmail/actions.js +4 -4
  129. package/dist/llm/anthropic/chat.d.ts +18 -1
  130. package/dist/llm/anthropic/chat.js +123 -55
  131. package/dist/llm/anthropic/serializer.d.ts +2 -0
  132. package/dist/llm/anthropic/serializer.js +81 -9
  133. package/dist/llm/aws/chat-anthropic.d.ts +17 -0
  134. package/dist/llm/aws/chat-anthropic.js +126 -26
  135. package/dist/llm/aws/chat-bedrock.d.ts +28 -1
  136. package/dist/llm/aws/chat-bedrock.js +161 -34
  137. package/dist/llm/aws/serializer.d.ts +13 -1
  138. package/dist/llm/aws/serializer.js +56 -17
  139. package/dist/llm/azure/chat.d.ts +53 -2
  140. package/dist/llm/azure/chat.js +366 -54
  141. package/dist/llm/base.d.ts +2 -0
  142. package/dist/llm/browser-use/chat.d.ts +40 -0
  143. package/dist/llm/browser-use/chat.js +305 -0
  144. package/dist/llm/browser-use/index.d.ts +1 -0
  145. package/dist/llm/browser-use/index.js +1 -0
  146. package/dist/llm/cerebras/chat.d.ts +39 -0
  147. package/dist/llm/cerebras/chat.js +178 -0
  148. package/dist/llm/cerebras/index.d.ts +2 -0
  149. package/dist/llm/cerebras/index.js +2 -0
  150. package/dist/llm/cerebras/serializer.d.ts +7 -0
  151. package/dist/llm/cerebras/serializer.js +82 -0
  152. package/dist/llm/deepseek/chat.d.ts +19 -2
  153. package/dist/llm/deepseek/chat.js +138 -25
  154. package/dist/llm/google/chat.d.ts +46 -2
  155. package/dist/llm/google/chat.js +267 -64
  156. package/dist/llm/google/serializer.d.ts +9 -1
  157. package/dist/llm/google/serializer.js +141 -34
  158. package/dist/llm/groq/chat.d.ts +21 -2
  159. package/dist/llm/groq/chat.js +125 -26
  160. package/dist/llm/groq/parser.js +3 -1
  161. package/dist/llm/mistral/chat.d.ts +43 -0
  162. package/dist/llm/mistral/chat.js +154 -0
  163. package/dist/llm/mistral/index.d.ts +2 -0
  164. package/dist/llm/mistral/index.js +2 -0
  165. package/dist/llm/mistral/schema.d.ts +8 -0
  166. package/dist/llm/mistral/schema.js +27 -0
  167. package/dist/llm/models.d.ts +2 -0
  168. package/dist/llm/models.js +317 -0
  169. package/dist/llm/ollama/chat.d.ts +13 -1
  170. package/dist/llm/ollama/chat.js +110 -19
  171. package/dist/llm/ollama/serializer.d.ts +1 -0
  172. package/dist/llm/ollama/serializer.js +34 -12
  173. package/dist/llm/openai/chat.d.ts +16 -0
  174. package/dist/llm/openai/chat.js +94 -44
  175. package/dist/llm/openai/like.d.ts +5 -3
  176. package/dist/llm/openai/like.js +7 -3
  177. package/dist/llm/openai/responses-serializer.d.ts +18 -0
  178. package/dist/llm/openai/responses-serializer.js +72 -0
  179. package/dist/llm/openrouter/chat.d.ts +28 -2
  180. package/dist/llm/openrouter/chat.js +115 -29
  181. package/dist/llm/schema.d.ts +11 -1
  182. package/dist/llm/schema.js +81 -1
  183. package/dist/llm/vercel/chat.d.ts +50 -0
  184. package/dist/llm/vercel/chat.js +276 -0
  185. package/dist/llm/vercel/index.d.ts +1 -0
  186. package/dist/llm/vercel/index.js +1 -0
  187. package/dist/llm/vercel/serializer.d.ts +5 -0
  188. package/dist/llm/vercel/serializer.js +7 -0
  189. package/dist/llm/views.d.ts +2 -1
  190. package/dist/llm/views.js +3 -1
  191. package/dist/logging-config.d.ts +2 -0
  192. package/dist/logging-config.js +82 -29
  193. package/dist/mcp/client.d.ts +10 -5
  194. package/dist/mcp/client.js +14 -9
  195. package/dist/mcp/controller.d.ts +42 -3
  196. package/dist/mcp/controller.js +56 -31
  197. package/dist/mcp/server.d.ts +14 -0
  198. package/dist/mcp/server.js +255 -52
  199. package/dist/observability.js +10 -4
  200. package/dist/sandbox/index.d.ts +2 -0
  201. package/dist/sandbox/index.js +2 -0
  202. package/dist/sandbox/sandbox.d.ts +19 -0
  203. package/dist/sandbox/sandbox.js +140 -0
  204. package/dist/sandbox/views.d.ts +67 -0
  205. package/dist/sandbox/views.js +121 -0
  206. package/dist/skill-cli/index.d.ts +3 -0
  207. package/dist/skill-cli/index.js +3 -0
  208. package/dist/skill-cli/protocol.d.ts +30 -0
  209. package/dist/skill-cli/protocol.js +48 -0
  210. package/dist/skill-cli/server.d.ts +11 -0
  211. package/dist/skill-cli/server.js +85 -0
  212. package/dist/skill-cli/sessions.d.ts +24 -0
  213. package/dist/skill-cli/sessions.js +47 -0
  214. package/dist/skills/index.d.ts +3 -0
  215. package/dist/skills/index.js +3 -0
  216. package/dist/skills/service.d.ts +27 -0
  217. package/dist/skills/service.js +266 -0
  218. package/dist/skills/utils.d.ts +6 -0
  219. package/dist/skills/utils.js +53 -0
  220. package/dist/skills/views.d.ts +40 -0
  221. package/dist/skills/views.js +10 -0
  222. package/dist/sync/auth.js +8 -3
  223. package/dist/sync/service.d.ts +6 -6
  224. package/dist/sync/service.js +54 -89
  225. package/dist/telemetry/views.d.ts +20 -6
  226. package/dist/telemetry/views.js +23 -5
  227. package/dist/tokens/custom-pricing.d.ts +2 -0
  228. package/dist/tokens/custom-pricing.js +22 -0
  229. package/dist/tokens/index.d.ts +2 -0
  230. package/dist/tokens/index.js +2 -0
  231. package/dist/tokens/mappings.d.ts +1 -0
  232. package/dist/tokens/mappings.js +3 -0
  233. package/dist/tokens/service.js +27 -8
  234. package/dist/tools/extraction/index.d.ts +2 -0
  235. package/dist/tools/extraction/index.js +2 -0
  236. package/dist/tools/extraction/schema-utils.d.ts +6 -0
  237. package/dist/tools/extraction/schema-utils.js +237 -0
  238. package/dist/tools/extraction/views.d.ts +7 -0
  239. package/dist/tools/index.d.ts +5 -0
  240. package/dist/tools/index.js +5 -0
  241. package/dist/tools/registry/index.d.ts +2 -0
  242. package/dist/tools/registry/index.js +2 -0
  243. package/dist/tools/registry/service.d.ts +1 -0
  244. package/dist/tools/registry/service.js +1 -0
  245. package/dist/tools/registry/views.d.ts +1 -0
  246. package/dist/tools/registry/views.js +1 -0
  247. package/dist/tools/service.d.ts +2 -0
  248. package/dist/tools/service.js +1 -0
  249. package/dist/tools/utils.d.ts +2 -0
  250. package/dist/tools/utils.js +57 -0
  251. package/dist/tools/views.d.ts +1 -0
  252. package/dist/tools/views.js +1 -0
  253. package/dist/utils.d.ts +10 -1
  254. package/dist/utils.js +70 -3
  255. package/package.json +87 -26
  256. package/dist/dom/playground/process-dom.js +0 -5
  257. package/dist/dom/playground/test-accessibility.d.ts +0 -44
  258. package/dist/dom/playground/test-accessibility.js +0 -111
  259. /package/dist/{dom/playground/process-dom.d.ts → tools/extraction/views.js} +0 -0
@@ -19,9 +19,10 @@
19
19
  * ```
20
20
  */
21
21
  import { BedrockRuntimeClient, ConverseCommand, } from '@aws-sdk/client-bedrock-runtime';
22
+ import { ModelProviderError, ModelRateLimitError } from '../exceptions.js';
22
23
  import { ChatInvokeCompletion } from '../views.js';
23
24
  import { AnthropicMessageSerializer } from '../anthropic/serializer.js';
24
- import { zodToJsonSchema } from 'zod-to-json-schema';
25
+ import { SchemaOptimizer, zodSchemaToJsonSchema } from '../schema.js';
25
26
  export class ChatAnthropicBedrock {
26
27
  model;
27
28
  provider = 'anthropic_bedrock';
@@ -31,6 +32,8 @@ export class ChatAnthropicBedrock {
31
32
  top_p;
32
33
  top_k;
33
34
  stop_sequences;
35
+ removeMinItemsFromSchema;
36
+ removeDefaultsFromSchema;
34
37
  constructor(config = {}) {
35
38
  // Anthropic Claude specific defaults
36
39
  this.model = config.model || 'anthropic.claude-3-5-sonnet-20241022-v2:0';
@@ -41,8 +44,24 @@ export class ChatAnthropicBedrock {
41
44
  this.top_k = config.top_k === undefined ? null : config.top_k;
42
45
  this.stop_sequences =
43
46
  config.stop_sequences === undefined ? null : config.stop_sequences;
47
+ this.removeMinItemsFromSchema = config.removeMinItemsFromSchema ?? false;
48
+ this.removeDefaultsFromSchema = config.removeDefaultsFromSchema ?? false;
44
49
  const region = config.region || process.env.AWS_REGION || 'us-east-1';
45
- this.client = new BedrockRuntimeClient({ region });
50
+ const awsSessionToken = config.awsSessionToken || process.env.AWS_SESSION_TOKEN;
51
+ const credentials = config.awsAccessKeyId && config.awsSecretAccessKey
52
+ ? {
53
+ accessKeyId: config.awsAccessKeyId,
54
+ secretAccessKey: config.awsSecretAccessKey,
55
+ ...(awsSessionToken ? { sessionToken: awsSessionToken } : {}),
56
+ }
57
+ : undefined;
58
+ this.client = new BedrockRuntimeClient({
59
+ region,
60
+ ...(credentials ? { credentials } : {}),
61
+ ...(config.maxRetries !== undefined
62
+ ? { maxAttempts: config.maxRetries }
63
+ : {}),
64
+ });
46
65
  }
47
66
  get name() {
48
67
  return this.model;
@@ -65,6 +84,43 @@ export class ChatAnthropicBedrock {
65
84
  }
66
85
  return params;
67
86
  }
87
+ getZodSchemaCandidate(output_format) {
88
+ const output = output_format;
89
+ if (output &&
90
+ typeof output === 'object' &&
91
+ typeof output.safeParse === 'function' &&
92
+ typeof output.parse === 'function') {
93
+ return output;
94
+ }
95
+ if (output &&
96
+ typeof output === 'object' &&
97
+ output.schema &&
98
+ typeof output.schema.safeParse === 'function' &&
99
+ typeof output.schema.parse === 'function') {
100
+ return output.schema;
101
+ }
102
+ return null;
103
+ }
104
+ parseOutput(output_format, payload) {
105
+ const output = output_format;
106
+ if (output &&
107
+ typeof output === 'object' &&
108
+ output.schema &&
109
+ typeof output.schema.parse === 'function') {
110
+ return output.schema.parse(payload);
111
+ }
112
+ return output.parse(payload);
113
+ }
114
+ getTextCompletion(response) {
115
+ const contentBlocks = response?.output?.message?.content;
116
+ if (!Array.isArray(contentBlocks)) {
117
+ return '';
118
+ }
119
+ return contentBlocks
120
+ .filter((block) => typeof block?.text === 'string')
121
+ .map((block) => block.text)
122
+ .join('\n');
123
+ }
68
124
  async ainvoke(messages, output_format, options = {}) {
69
125
  // Use Anthropic-specific message serializer
70
126
  const serializer = new AnthropicMessageSerializer();
@@ -76,8 +132,26 @@ export class ChatAnthropicBedrock {
76
132
  if (block.type === 'text') {
77
133
  return { text: block.text };
78
134
  }
135
+ else if (block.type === 'tool_use') {
136
+ return {
137
+ toolUse: {
138
+ toolUseId: block.id,
139
+ name: block.name,
140
+ input: block.input,
141
+ },
142
+ };
143
+ }
79
144
  else if (block.type === 'image') {
80
- // Handle image blocks if needed
145
+ if (block.source?.type === 'base64') {
146
+ return {
147
+ image: {
148
+ format: String(block.source.media_type || 'image/jpeg').split('/')[1] ?? 'jpeg',
149
+ source: {
150
+ bytes: Buffer.from(block.source.data ?? '', 'base64'),
151
+ },
152
+ },
153
+ };
154
+ }
81
155
  return { text: '[Image]' };
82
156
  }
83
157
  return { text: String(block) };
@@ -98,15 +172,18 @@ export class ChatAnthropicBedrock {
98
172
  },
99
173
  ]
100
174
  : undefined;
101
- let tools = undefined;
102
175
  let toolConfig = undefined;
103
- if (output_format && 'schema' in output_format) {
176
+ const zodSchemaCandidate = this.getZodSchemaCandidate(output_format);
177
+ if (output_format && zodSchemaCandidate) {
104
178
  // Structured output using tools
105
179
  try {
106
- const schema = output_format.schema?.shape
107
- ? this._zodToJsonSchema(output_format.schema)
108
- : {};
109
- tools = [
180
+ const rawSchema = this._zodToJsonSchema(zodSchemaCandidate);
181
+ const schema = SchemaOptimizer.createOptimizedJsonSchema(rawSchema, {
182
+ removeMinItems: this.removeMinItemsFromSchema,
183
+ removeDefaults: this.removeDefaultsFromSchema,
184
+ });
185
+ delete schema.title;
186
+ const tools = [
110
187
  {
111
188
  toolSpec: {
112
189
  name: 'extract_structured_data',
@@ -118,7 +195,7 @@ export class ChatAnthropicBedrock {
118
195
  },
119
196
  ];
120
197
  toolConfig = {
121
- tools: tools,
198
+ tools,
122
199
  toolChoice: { tool: { name: 'extract_structured_data' } },
123
200
  };
124
201
  }
@@ -133,31 +210,54 @@ export class ChatAnthropicBedrock {
133
210
  toolConfig: toolConfig,
134
211
  inferenceConfig: this._getInferenceParams(),
135
212
  });
136
- const response = await this.client.send(command, options.signal ? { abortSignal: options.signal } : undefined);
137
- let completion = '';
138
- if (response.output?.message?.content) {
139
- // Check for tool use (structured output)
140
- const toolUseBlock = response.output.message.content.find((block) => block.toolUse);
141
- if (toolUseBlock && toolUseBlock.toolUse && output_format) {
142
- completion = output_format.parse(toolUseBlock.toolUse.input);
213
+ try {
214
+ const response = await this.client.send(command, options.signal ? { abortSignal: options.signal } : undefined);
215
+ let completion = this.getTextCompletion(response);
216
+ const contentBlocks = response?.output?.message?.content;
217
+ const toolUseBlock = Array.isArray(contentBlocks)
218
+ ? contentBlocks.find((block) => block?.toolUse)
219
+ : undefined;
220
+ if (toolUseBlock?.toolUse && output_format) {
221
+ const input = toolUseBlock.toolUse.input;
222
+ if (typeof input === 'string') {
223
+ completion = this.parseOutput(output_format, JSON.parse(input));
224
+ }
225
+ else {
226
+ completion = this.parseOutput(output_format, input);
227
+ }
228
+ }
229
+ else if (output_format && toolConfig) {
230
+ throw new ModelProviderError('Expected tool use in response but none found', 502, this.model);
231
+ }
232
+ else if (output_format) {
233
+ completion = this.parseOutput(output_format, completion);
143
234
  }
144
235
  else {
145
- // Fallback to text
146
- const textBlock = response.output.message.content.find((block) => block.text);
147
- completion = textBlock?.text || '';
236
+ completion = this.getTextCompletion(response);
148
237
  }
238
+ const stopReason = response?.stopReason ?? null;
239
+ return new ChatInvokeCompletion(completion, {
240
+ prompt_tokens: response.usage?.inputTokens ?? 0,
241
+ completion_tokens: response.usage?.outputTokens ?? 0,
242
+ total_tokens: response.usage?.totalTokens ?? 0,
243
+ }, null, null, stopReason);
244
+ }
245
+ catch (error) {
246
+ const errorName = String(error?.name ?? '');
247
+ const statusCode = error?.$metadata?.httpStatusCode ?? 502;
248
+ if (statusCode === 429 ||
249
+ errorName.includes('Throttling') ||
250
+ errorName.includes('TooManyRequests')) {
251
+ throw new ModelRateLimitError(error?.message ?? 'Rate limit exceeded', 429, this.model);
252
+ }
253
+ throw new ModelProviderError(error?.message ?? String(error), statusCode, this.model);
149
254
  }
150
- return new ChatInvokeCompletion(completion, {
151
- prompt_tokens: response.usage?.inputTokens ?? 0,
152
- completion_tokens: response.usage?.outputTokens ?? 0,
153
- total_tokens: response.usage?.totalTokens ?? 0,
154
- });
155
255
  }
156
256
  /**
157
257
  * Simple Zod to JSON Schema conversion for structured output
158
258
  */
159
259
  _zodToJsonSchema(schema) {
160
- return zodToJsonSchema(schema, {
260
+ return zodSchemaToJsonSchema(schema, {
161
261
  name: 'Response',
162
262
  target: 'jsonSchema7',
163
263
  });
@@ -1,13 +1,40 @@
1
1
  import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
2
2
  import { ChatInvokeCompletion } from '../views.js';
3
3
  import { type Message } from '../messages.js';
4
+ export interface ChatBedrockConverseOptions {
5
+ model?: string;
6
+ region?: string;
7
+ awsAccessKeyId?: string;
8
+ awsSecretAccessKey?: string;
9
+ awsSessionToken?: string;
10
+ maxTokens?: number | null;
11
+ temperature?: number | null;
12
+ topP?: number | null;
13
+ seed?: number | null;
14
+ stopSequences?: string[] | null;
15
+ maxRetries?: number;
16
+ removeMinItemsFromSchema?: boolean;
17
+ removeDefaultsFromSchema?: boolean;
18
+ }
4
19
  export declare class ChatBedrockConverse implements BaseChatModel {
5
20
  model: string;
6
21
  provider: string;
7
22
  private client;
8
- constructor(model?: string, region?: string);
23
+ private maxTokens;
24
+ private temperature;
25
+ private topP;
26
+ private seed;
27
+ private stopSequences;
28
+ private removeMinItemsFromSchema;
29
+ private removeDefaultsFromSchema;
30
+ constructor(modelOrOptions?: string | ChatBedrockConverseOptions, region?: string);
9
31
  get name(): string;
10
32
  get model_name(): string;
33
+ private getInferenceConfig;
34
+ private getUsage;
35
+ private getZodSchemaCandidate;
36
+ private parseOutput;
37
+ private getTextCompletion;
11
38
  ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
12
39
  ainvoke<T>(messages: Message[], output_format: {
13
40
  parse: (input: string) => T;
@@ -1,15 +1,44 @@
1
1
  import { BedrockRuntimeClient, ConverseCommand, } from '@aws-sdk/client-bedrock-runtime';
2
- import { zodToJsonSchema } from 'zod-to-json-schema';
2
+ import { ModelProviderError, ModelRateLimitError } from '../exceptions.js';
3
3
  import { ChatInvokeCompletion } from '../views.js';
4
- import { SystemMessage } from '../messages.js';
4
+ import { SchemaOptimizer, zodSchemaToJsonSchema } from '../schema.js';
5
5
  import { AWSBedrockMessageSerializer } from './serializer.js';
6
6
  export class ChatBedrockConverse {
7
7
  model;
8
8
  provider = 'aws';
9
9
  client;
10
- constructor(model = 'anthropic.claude-3-5-sonnet-20240620-v1:0', region = process.env.AWS_REGION || 'us-east-1') {
10
+ maxTokens;
11
+ temperature;
12
+ topP;
13
+ seed;
14
+ stopSequences;
15
+ removeMinItemsFromSchema;
16
+ removeDefaultsFromSchema;
17
+ constructor(modelOrOptions = {}, region) {
18
+ const normalizedOptions = typeof modelOrOptions === 'string'
19
+ ? { model: modelOrOptions, region }
20
+ : modelOrOptions;
21
+ const { model = 'anthropic.claude-3-5-sonnet-20240620-v1:0', region: bedrockRegion = process.env.AWS_REGION || 'us-east-1', awsAccessKeyId, awsSecretAccessKey, awsSessionToken = process.env.AWS_SESSION_TOKEN, maxTokens = 4096, temperature = null, topP = null, seed = null, stopSequences = null, maxRetries, removeMinItemsFromSchema = false, removeDefaultsFromSchema = false, } = normalizedOptions;
11
22
  this.model = model;
12
- this.client = new BedrockRuntimeClient({ region });
23
+ this.maxTokens = maxTokens;
24
+ this.temperature = temperature;
25
+ this.topP = topP;
26
+ this.seed = seed;
27
+ this.stopSequences = stopSequences;
28
+ this.removeMinItemsFromSchema = removeMinItemsFromSchema;
29
+ this.removeDefaultsFromSchema = removeDefaultsFromSchema;
30
+ const credentials = awsAccessKeyId && awsSecretAccessKey
31
+ ? {
32
+ accessKeyId: awsAccessKeyId,
33
+ secretAccessKey: awsSecretAccessKey,
34
+ ...(awsSessionToken ? { sessionToken: awsSessionToken } : {}),
35
+ }
36
+ : undefined;
37
+ this.client = new BedrockRuntimeClient({
38
+ region: bedrockRegion,
39
+ ...(credentials ? { credentials } : {}),
40
+ ...(maxRetries !== undefined ? { maxAttempts: maxRetries } : {}),
41
+ });
13
42
  }
14
43
  get name() {
15
44
  return this.model;
@@ -17,32 +46,102 @@ export class ChatBedrockConverse {
17
46
  get model_name() {
18
47
  return this.model;
19
48
  }
49
+ getInferenceConfig() {
50
+ const config = {};
51
+ if (this.maxTokens !== null) {
52
+ config.maxTokens = this.maxTokens;
53
+ }
54
+ if (this.temperature !== null) {
55
+ config.temperature = this.temperature;
56
+ }
57
+ if (this.topP !== null) {
58
+ config.topP = this.topP;
59
+ }
60
+ if (this.seed !== null) {
61
+ config.seed = this.seed;
62
+ }
63
+ if (this.stopSequences !== null) {
64
+ config.stopSequences = this.stopSequences;
65
+ }
66
+ return config;
67
+ }
68
+ getUsage(response) {
69
+ const usage = response?.usage ?? {};
70
+ return {
71
+ prompt_tokens: usage.inputTokens ?? 0,
72
+ completion_tokens: usage.outputTokens ?? 0,
73
+ total_tokens: usage.totalTokens ?? 0,
74
+ prompt_cached_tokens: null,
75
+ prompt_cache_creation_tokens: null,
76
+ prompt_image_tokens: null,
77
+ };
78
+ }
79
+ getZodSchemaCandidate(output_format) {
80
+ const output = output_format;
81
+ if (output &&
82
+ typeof output === 'object' &&
83
+ typeof output.safeParse === 'function' &&
84
+ typeof output.parse === 'function') {
85
+ return output;
86
+ }
87
+ if (output &&
88
+ typeof output === 'object' &&
89
+ output.schema &&
90
+ typeof output.schema.safeParse === 'function' &&
91
+ typeof output.schema.parse === 'function') {
92
+ return output.schema;
93
+ }
94
+ return null;
95
+ }
96
+ parseOutput(output_format, payload) {
97
+ const output = output_format;
98
+ if (output &&
99
+ typeof output === 'object' &&
100
+ output.schema &&
101
+ typeof output.schema.parse === 'function') {
102
+ return output.schema.parse(payload);
103
+ }
104
+ return output.parse(payload);
105
+ }
106
+ getTextCompletion(response) {
107
+ const contentBlocks = response?.output?.message?.content;
108
+ if (!Array.isArray(contentBlocks)) {
109
+ return '';
110
+ }
111
+ return contentBlocks
112
+ .filter((block) => typeof block?.text === 'string')
113
+ .map((block) => block.text)
114
+ .join('\n');
115
+ }
20
116
  async ainvoke(messages, output_format, options = {}) {
21
117
  const serializer = new AWSBedrockMessageSerializer();
22
- const bedrockMessages = serializer.serialize(messages);
23
- const systemMessage = messages.find((msg) => msg instanceof SystemMessage);
24
- const system = systemMessage ? [{ text: systemMessage.text }] : undefined;
25
- let tools = undefined;
118
+ const [bedrockMessages, systemMessage] = serializer.serializeMessages(messages);
119
+ const zodSchemaCandidate = this.getZodSchemaCandidate(output_format);
26
120
  let toolConfig = undefined;
27
- if (output_format && 'schema' in output_format && output_format.schema) {
121
+ if (output_format && zodSchemaCandidate) {
28
122
  try {
29
- const jsonSchema = zodToJsonSchema(output_format, {
123
+ const rawJsonSchema = zodSchemaToJsonSchema(zodSchemaCandidate, {
30
124
  name: 'Response',
31
125
  target: 'jsonSchema7',
32
126
  });
33
- tools = [
127
+ const optimizedJsonSchema = SchemaOptimizer.createOptimizedJsonSchema(rawJsonSchema, {
128
+ removeMinItems: this.removeMinItemsFromSchema,
129
+ removeDefaults: this.removeDefaultsFromSchema,
130
+ });
131
+ delete optimizedJsonSchema.title;
132
+ const tools = [
34
133
  {
35
134
  toolSpec: {
36
135
  name: 'response',
37
- description: 'The response to the user request',
136
+ description: 'Extract information in the format of response',
38
137
  inputSchema: {
39
- json: jsonSchema,
138
+ json: optimizedJsonSchema,
40
139
  },
41
140
  },
42
141
  },
43
142
  ];
44
143
  toolConfig = {
45
- tools: tools,
144
+ tools,
46
145
  toolChoice: { tool: { name: 'response' } },
47
146
  };
48
147
  }
@@ -50,31 +149,59 @@ export class ChatBedrockConverse {
50
149
  console.warn('Failed to convert output_format to JSON schema for AWS Bedrock', e);
51
150
  }
52
151
  }
53
- const command = new ConverseCommand({
152
+ const requestPayload = {
54
153
  modelId: this.model,
55
154
  messages: bedrockMessages,
56
- system: system,
57
- toolConfig: toolConfig,
58
- });
59
- const response = await this.client.send(command, options.signal ? { abortSignal: options.signal } : undefined);
60
- let completion = '';
61
- if (response.output?.message?.content) {
62
- // Check for tool use
63
- const toolUseBlock = response.output.message.content.find((block) => block.toolUse);
64
- if (toolUseBlock && toolUseBlock.toolUse && output_format) {
65
- completion = output_format.parse(toolUseBlock.toolUse.input);
155
+ };
156
+ if (systemMessage) {
157
+ requestPayload.system = systemMessage;
158
+ }
159
+ const inferenceConfig = this.getInferenceConfig();
160
+ if (Object.keys(inferenceConfig).length) {
161
+ requestPayload.inferenceConfig = inferenceConfig;
162
+ }
163
+ if (toolConfig) {
164
+ requestPayload.toolConfig = toolConfig;
165
+ }
166
+ try {
167
+ const response = await this.client.send(new ConverseCommand(requestPayload), options.signal ? { abortSignal: options.signal } : undefined);
168
+ let completion = this.getTextCompletion(response);
169
+ if (output_format) {
170
+ const contentBlocks = response?.output?.message?.content;
171
+ const toolUseBlock = Array.isArray(contentBlocks)
172
+ ? contentBlocks.find((block) => block?.toolUse)
173
+ : undefined;
174
+ if (toolUseBlock?.toolUse) {
175
+ const input = toolUseBlock.toolUse.input;
176
+ if (typeof input === 'string') {
177
+ completion = this.parseOutput(output_format, JSON.parse(input));
178
+ }
179
+ else {
180
+ completion = this.parseOutput(output_format, input);
181
+ }
182
+ }
183
+ else if (toolConfig) {
184
+ throw new ModelProviderError('Expected tool use in response but none found', 502, this.model);
185
+ }
186
+ else {
187
+ completion = this.parseOutput(output_format, completion);
188
+ }
66
189
  }
67
190
  else {
68
- // Fallback to text
69
- const textBlock = response.output.message.content.find((block) => block.text);
70
- completion = textBlock?.text || '';
191
+ completion = this.getTextCompletion(response);
71
192
  }
193
+ const stopReason = response?.stopReason ?? null;
194
+ return new ChatInvokeCompletion(completion, this.getUsage(response), null, null, stopReason);
195
+ }
196
+ catch (error) {
197
+ const errorName = String(error?.name ?? '');
198
+ const statusCode = error?.$metadata?.httpStatusCode ?? 502;
199
+ if (statusCode === 429 ||
200
+ errorName.includes('Throttling') ||
201
+ errorName.includes('TooManyRequests')) {
202
+ throw new ModelRateLimitError(error?.message ?? 'Rate limit exceeded', 429, this.model);
203
+ }
204
+ throw new ModelProviderError(error?.message ?? String(error), statusCode, this.model);
72
205
  }
73
- const usage = response.usage || {};
74
- return new ChatInvokeCompletion(completion, {
75
- prompt_tokens: usage.inputTokens || 0,
76
- completion_tokens: usage.outputTokens || 0,
77
- total_tokens: usage.totalTokens || 0,
78
- });
79
206
  }
80
207
  }
@@ -1,5 +1,17 @@
1
1
  import { type Message } from '../messages.js';
2
+ type BedrockContentBlock = Record<string, unknown>;
3
+ type BedrockMessage = {
4
+ role: 'user' | 'assistant';
5
+ content: BedrockContentBlock[];
6
+ };
7
+ type BedrockSystemMessage = {
8
+ text: string;
9
+ }[];
2
10
  export declare class AWSBedrockMessageSerializer {
3
- serialize(messages: Message[]): any[];
11
+ serialize(messages: Message[]): BedrockMessage[];
12
+ serializeMessages(messages: Message[]): [BedrockMessage[], BedrockSystemMessage?];
13
+ private serializeSystemContent;
14
+ private serializeImageContent;
4
15
  private serializeMessage;
5
16
  }
17
+ export {};
@@ -1,11 +1,44 @@
1
- import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
- // AWS Bedrock types are a bit complex and vary by model.
3
- // We will define a generic structure that fits most Bedrock models (like Claude on Bedrock).
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartRefusalParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
4
2
  export class AWSBedrockMessageSerializer {
5
3
  serialize(messages) {
6
- return messages
7
- .filter((msg) => !(msg instanceof SystemMessage)) // System messages are handled separately usually
8
- .map((message) => this.serializeMessage(message));
4
+ return this.serializeMessages(messages)[0];
5
+ }
6
+ serializeMessages(messages) {
7
+ const bedrockMessages = [];
8
+ let systemMessage = undefined;
9
+ for (const message of messages) {
10
+ if (message instanceof SystemMessage) {
11
+ systemMessage = this.serializeSystemContent(message.content);
12
+ }
13
+ else {
14
+ bedrockMessages.push(this.serializeMessage(message));
15
+ }
16
+ }
17
+ return [bedrockMessages, systemMessage];
18
+ }
19
+ serializeSystemContent(content) {
20
+ if (typeof content === 'string') {
21
+ return [{ text: content }];
22
+ }
23
+ return content
24
+ .filter((part) => part instanceof ContentPartTextParam)
25
+ .map((part) => ({ text: part.text }));
26
+ }
27
+ serializeImageContent(part) {
28
+ const url = part.image_url.url;
29
+ if (!url.startsWith('data:')) {
30
+ throw new Error(`Unsupported image URL format: ${url}`);
31
+ }
32
+ const [, payload = ''] = url.split(',', 2);
33
+ const format = part.image_url.media_type.split('/')[1] ?? 'jpeg';
34
+ return {
35
+ image: {
36
+ format,
37
+ source: {
38
+ bytes: Buffer.from(payload, 'base64'),
39
+ },
40
+ },
41
+ };
9
42
  }
10
43
  serializeMessage(message) {
11
44
  if (message instanceof UserMessage) {
@@ -17,16 +50,7 @@ export class AWSBedrockMessageSerializer {
17
50
  return { text: part.text };
18
51
  }
19
52
  if (part instanceof ContentPartImageParam) {
20
- const mediaType = part.image_url.media_type;
21
- const data = part.image_url.url.split(',')[1];
22
- return {
23
- image: {
24
- format: mediaType.split('/')[1], // e.g. 'png' from 'image/png'
25
- source: {
26
- bytes: Buffer.from(data, 'base64'),
27
- },
28
- },
29
- };
53
+ return this.serializeImageContent(part);
30
54
  }
31
55
  return { text: '' };
32
56
  })
@@ -44,20 +68,35 @@ export class AWSBedrockMessageSerializer {
44
68
  if (part instanceof ContentPartTextParam) {
45
69
  content.push({ text: part.text });
46
70
  }
71
+ else if (part instanceof ContentPartRefusalParam) {
72
+ content.push({ text: `[Refusal] ${part.refusal}` });
73
+ }
47
74
  });
48
75
  }
49
76
  }
50
77
  if (message.tool_calls) {
51
78
  message.tool_calls.forEach((toolCall) => {
79
+ let parsedArguments;
80
+ try {
81
+ parsedArguments = JSON.parse(toolCall.functionCall.arguments);
82
+ }
83
+ catch {
84
+ parsedArguments = {
85
+ arguments: toolCall.functionCall.arguments,
86
+ };
87
+ }
52
88
  content.push({
53
89
  toolUse: {
54
90
  toolUseId: toolCall.id,
55
91
  name: toolCall.functionCall.name,
56
- input: JSON.parse(toolCall.functionCall.arguments),
92
+ input: parsedArguments,
57
93
  },
58
94
  });
59
95
  });
60
96
  }
97
+ if (!content.length) {
98
+ content.push({ text: '' });
99
+ }
61
100
  return {
62
101
  role: 'assistant',
63
102
  content: content,