browser-use 0.2.0 → 0.4.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 +103 -41
  26. package/dist/agent/service.js +2336 -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 +10 -4
  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 +105 -9
  47. package/dist/browser/session.js +1166 -95
  48. package/dist/browser/types.d.ts +153 -156
  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 +15 -0
  100. package/dist/config.js +109 -7
  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 +1814 -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 +109 -4
  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 +15 -0
  198. package/dist/mcp/server.js +261 -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 +116 -49
  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
@@ -0,0 +1,305 @@
1
+ import { setTimeout as sleep } from 'node:timers/promises';
2
+ import { CONFIG } from '../../config.js';
3
+ import { ModelProviderError, ModelRateLimitError } from '../exceptions.js';
4
+ import { zodSchemaToJsonSchema } from '../schema.js';
5
+ import { ChatInvokeCompletion } from '../views.js';
6
+ const RETRYABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);
7
+ const VALID_MODELS = new Set(['bu-latest', 'bu-1-0', 'bu-2-0']);
8
+ class HttpStatusError extends Error {
9
+ statusCode;
10
+ detail;
11
+ constructor(statusCode, detail) {
12
+ super(`HTTP ${statusCode}: ${detail}`);
13
+ this.statusCode = statusCode;
14
+ this.detail = detail;
15
+ this.name = 'HttpStatusError';
16
+ }
17
+ }
18
+ const isAbortError = (error) => error instanceof Error && error.name === 'AbortError';
19
+ const getJsonErrorDetail = (value) => {
20
+ if (!value || typeof value !== 'object') {
21
+ return '';
22
+ }
23
+ const detail = value.detail ?? value.error ?? value.message;
24
+ if (typeof detail === 'string') {
25
+ return detail;
26
+ }
27
+ try {
28
+ return JSON.stringify(value);
29
+ }
30
+ catch {
31
+ return '';
32
+ }
33
+ };
34
+ export class ChatBrowserUse {
35
+ model;
36
+ provider = 'browser-use';
37
+ apiKey;
38
+ baseUrl;
39
+ timeoutMs;
40
+ maxRetries;
41
+ retryBaseDelay;
42
+ retryMaxDelay;
43
+ fast;
44
+ fetchImplementation;
45
+ constructor(options = {}) {
46
+ const { model = 'bu-latest', apiKey = process.env.BROWSER_USE_API_KEY, baseUrl = process.env.BROWSER_USE_LLM_URL ??
47
+ 'https://llm.api.browser-use.com', timeout = 120, maxRetries = 5, retryBaseDelay = 1.0, retryMaxDelay = 60.0, fast = false, fetchImplementation = fetch, } = options;
48
+ const isValidModel = VALID_MODELS.has(model) || model.startsWith('browser-use/');
49
+ if (!isValidModel) {
50
+ throw new Error(`Invalid model: '${model}'. Must be one of bu-latest, bu-1-0, bu-2-0 or start with 'browser-use/'`);
51
+ }
52
+ this.model = model === 'bu-latest' ? 'bu-1-0' : model;
53
+ if (!apiKey) {
54
+ throw new Error('You need to set the BROWSER_USE_API_KEY environment variable. Get your key at https://cloud.browser-use.com/new-api-key');
55
+ }
56
+ this.apiKey = apiKey;
57
+ this.baseUrl = baseUrl.replace(/\/+$/, '');
58
+ this.timeoutMs = Math.max(1, Math.round(timeout * 1000));
59
+ this.maxRetries = Math.max(1, Math.trunc(maxRetries));
60
+ this.retryBaseDelay = Math.max(0.001, retryBaseDelay);
61
+ this.retryMaxDelay = Math.max(this.retryBaseDelay, retryMaxDelay);
62
+ this.fast = fast;
63
+ this.fetchImplementation = fetchImplementation;
64
+ }
65
+ get name() {
66
+ return this.model;
67
+ }
68
+ get model_name() {
69
+ return this.model;
70
+ }
71
+ getOutputSchema(output_format) {
72
+ const output = output_format;
73
+ if (!output || typeof output !== 'object') {
74
+ return null;
75
+ }
76
+ if (typeof output.model_json_schema === 'function') {
77
+ const schema = output.model_json_schema();
78
+ if (schema && typeof schema === 'object') {
79
+ return schema;
80
+ }
81
+ }
82
+ if (typeof output.safeParse === 'function' &&
83
+ typeof output.parse === 'function') {
84
+ return zodSchemaToJsonSchema(output, {
85
+ name: 'Response',
86
+ target: 'jsonSchema7',
87
+ });
88
+ }
89
+ if (output.schema &&
90
+ typeof output.schema.safeParse === 'function' &&
91
+ typeof output.schema.parse === 'function') {
92
+ return zodSchemaToJsonSchema(output.schema, {
93
+ name: 'Response',
94
+ target: 'jsonSchema7',
95
+ });
96
+ }
97
+ if (output.schema && typeof output.schema === 'object') {
98
+ const schemaCandidate = output.schema;
99
+ const schema = typeof schemaCandidate.toJSON === 'function'
100
+ ? schemaCandidate.toJSON()
101
+ : schemaCandidate;
102
+ if (schema && typeof schema === 'object') {
103
+ return schema;
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+ parseOutput(output_format, payload) {
109
+ const output = output_format;
110
+ if (output &&
111
+ typeof output === 'object' &&
112
+ output.schema &&
113
+ typeof output.schema.parse === 'function') {
114
+ return output.schema.parse(payload);
115
+ }
116
+ return output.parse(payload);
117
+ }
118
+ serializeMessage(message) {
119
+ return {
120
+ role: message.role,
121
+ content: message.content,
122
+ };
123
+ }
124
+ getUsage(payload) {
125
+ if (!payload || typeof payload !== 'object') {
126
+ return null;
127
+ }
128
+ const usage = payload.usage;
129
+ if (!usage || typeof usage !== 'object') {
130
+ return null;
131
+ }
132
+ return {
133
+ prompt_tokens: Number(usage.prompt_tokens ?? 0) || 0,
134
+ prompt_cached_tokens: usage.prompt_cached_tokens == null
135
+ ? null
136
+ : Number(usage.prompt_cached_tokens),
137
+ prompt_cache_creation_tokens: usage.prompt_cache_creation_tokens == null
138
+ ? null
139
+ : Number(usage.prompt_cache_creation_tokens),
140
+ prompt_image_tokens: usage.prompt_image_tokens == null
141
+ ? null
142
+ : Number(usage.prompt_image_tokens),
143
+ completion_tokens: Number(usage.completion_tokens ?? 0) || 0,
144
+ total_tokens: Number(usage.total_tokens ?? 0) || 0,
145
+ };
146
+ }
147
+ raiseHttpError(statusCode, detail) {
148
+ const errorDetail = detail || `HTTP ${statusCode}`;
149
+ if (statusCode === 401) {
150
+ throw new ModelProviderError(`Invalid API key. ${errorDetail}`, 401, this.model);
151
+ }
152
+ if (statusCode === 402) {
153
+ throw new ModelProviderError(`Insufficient credits. ${errorDetail}`, 402, this.model);
154
+ }
155
+ if (statusCode === 429) {
156
+ throw new ModelRateLimitError(`Rate limit exceeded. ${errorDetail}`, 429, this.model);
157
+ }
158
+ if (RETRYABLE_STATUS_CODES.has(statusCode)) {
159
+ throw new ModelProviderError(`Server error. ${errorDetail}`, statusCode, this.model);
160
+ }
161
+ throw new ModelProviderError(`API request failed: ${errorDetail}`, statusCode, this.model);
162
+ }
163
+ isRetryableNetworkError(error) {
164
+ if (!(error instanceof Error)) {
165
+ return false;
166
+ }
167
+ if (isAbortError(error)) {
168
+ return false;
169
+ }
170
+ const message = error.message.toLowerCase();
171
+ return (message.includes('fetch failed') ||
172
+ message.includes('networkerror') ||
173
+ message.includes('econnreset') ||
174
+ message.includes('econnrefused') ||
175
+ message.includes('enotfound') ||
176
+ message.includes('etimedout') ||
177
+ message.includes('timeout'));
178
+ }
179
+ async makeRequest(payload, signal) {
180
+ const controller = new AbortController();
181
+ const timeoutHandle = setTimeout(() => controller.abort(), this.timeoutMs);
182
+ const onAbort = () => controller.abort();
183
+ if (signal) {
184
+ if (signal.aborted) {
185
+ controller.abort();
186
+ }
187
+ else {
188
+ signal.addEventListener('abort', onAbort, { once: true });
189
+ }
190
+ }
191
+ try {
192
+ const response = await this.fetchImplementation(`${this.baseUrl}/v1/chat/completions`, {
193
+ method: 'POST',
194
+ headers: {
195
+ Authorization: `Bearer ${this.apiKey}`,
196
+ 'Content-Type': 'application/json',
197
+ },
198
+ body: JSON.stringify(payload),
199
+ signal: controller.signal,
200
+ });
201
+ if (!response.ok) {
202
+ let detail = '';
203
+ try {
204
+ const errorJson = await response.json();
205
+ detail = getJsonErrorDetail(errorJson);
206
+ }
207
+ catch {
208
+ try {
209
+ detail = await response.text();
210
+ }
211
+ catch {
212
+ detail = '';
213
+ }
214
+ }
215
+ throw new HttpStatusError(response.status, detail);
216
+ }
217
+ const result = await response.json();
218
+ return result && typeof result === 'object'
219
+ ? result
220
+ : {};
221
+ }
222
+ catch (error) {
223
+ if (isAbortError(error) && !signal?.aborted) {
224
+ throw new ModelProviderError(`Request timed out after ${Math.round(this.timeoutMs / 1000)}s`, 408, this.model);
225
+ }
226
+ throw error;
227
+ }
228
+ finally {
229
+ clearTimeout(timeoutHandle);
230
+ signal?.removeEventListener('abort', onAbort);
231
+ }
232
+ }
233
+ async ainvoke(messages, output_format, options = {}) {
234
+ const payload = {
235
+ model: this.model,
236
+ messages: messages.map((message) => this.serializeMessage(message)),
237
+ fast: this.fast,
238
+ request_type: options.request_type ?? 'browser_agent',
239
+ anonymized_telemetry: CONFIG.ANONYMIZED_TELEMETRY,
240
+ };
241
+ if (typeof options.session_id === 'string') {
242
+ payload.session_id = options.session_id;
243
+ }
244
+ const schema = this.getOutputSchema(output_format);
245
+ if (schema) {
246
+ payload.output_format = schema;
247
+ }
248
+ let result = null;
249
+ for (let attempt = 0; attempt < this.maxRetries; attempt += 1) {
250
+ try {
251
+ result = await this.makeRequest(payload, options.signal);
252
+ break;
253
+ }
254
+ catch (error) {
255
+ if (isAbortError(error)) {
256
+ throw error;
257
+ }
258
+ const statusCode = error instanceof HttpStatusError
259
+ ? error.statusCode
260
+ : (error?.statusCode ?? null);
261
+ const retryableHttp = typeof statusCode === 'number' &&
262
+ RETRYABLE_STATUS_CODES.has(statusCode);
263
+ const retryableNetwork = this.isRetryableNetworkError(error);
264
+ if (attempt < this.maxRetries - 1 &&
265
+ (retryableHttp || retryableNetwork)) {
266
+ const delaySeconds = Math.min(this.retryBaseDelay * 2 ** attempt, this.retryMaxDelay);
267
+ const jitter = Math.random() * delaySeconds * 0.1;
268
+ const sleepMs = Math.max(1, Math.round((delaySeconds + jitter) * 1000));
269
+ await sleep(sleepMs);
270
+ continue;
271
+ }
272
+ if (error instanceof HttpStatusError) {
273
+ this.raiseHttpError(error.statusCode, error.detail);
274
+ }
275
+ if (error instanceof ModelProviderError) {
276
+ throw error;
277
+ }
278
+ throw new ModelProviderError(`Failed to connect to browser-use API: ${error instanceof Error ? error.message : String(error)}`, 502, this.model);
279
+ }
280
+ }
281
+ if (result == null) {
282
+ throw new ModelProviderError('Request failed without a response payload.', 502, this.model);
283
+ }
284
+ const usage = this.getUsage(result);
285
+ const completionPayload = result.completion;
286
+ if (!output_format) {
287
+ const textCompletion = typeof completionPayload === 'string'
288
+ ? completionPayload
289
+ : JSON.stringify(completionPayload ?? '');
290
+ return new ChatInvokeCompletion(textCompletion, usage);
291
+ }
292
+ const parsedPayload = typeof completionPayload === 'string'
293
+ ? (() => {
294
+ try {
295
+ return JSON.parse(completionPayload);
296
+ }
297
+ catch {
298
+ return completionPayload;
299
+ }
300
+ })()
301
+ : completionPayload;
302
+ const completion = this.parseOutput(output_format, parsedPayload);
303
+ return new ChatInvokeCompletion(completion, usage);
304
+ }
305
+ }
@@ -0,0 +1 @@
1
+ export * from './chat.js';
@@ -0,0 +1 @@
1
+ export * from './chat.js';
@@ -0,0 +1,39 @@
1
+ import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
2
+ import type { Message } from '../messages.js';
3
+ import { ChatInvokeCompletion } from '../views.js';
4
+ export interface ChatCerebrasOptions {
5
+ model?: string;
6
+ apiKey?: string;
7
+ baseURL?: string;
8
+ timeout?: number | null;
9
+ clientParams?: Record<string, unknown> | null;
10
+ temperature?: number | null;
11
+ maxTokens?: number | null;
12
+ topP?: number | null;
13
+ seed?: number | null;
14
+ maxRetries?: number;
15
+ removeMinItemsFromSchema?: boolean;
16
+ removeDefaultsFromSchema?: boolean;
17
+ }
18
+ export declare class ChatCerebras implements BaseChatModel {
19
+ model: string;
20
+ provider: string;
21
+ private client;
22
+ private temperature;
23
+ private maxTokens;
24
+ private topP;
25
+ private seed;
26
+ private removeMinItemsFromSchema;
27
+ private removeDefaultsFromSchema;
28
+ constructor(options?: string | ChatCerebrasOptions);
29
+ get name(): string;
30
+ get model_name(): string;
31
+ private getUsage;
32
+ private getSchemaCandidate;
33
+ private extractJsonFromContent;
34
+ private appendJsonInstruction;
35
+ ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
36
+ ainvoke<T>(messages: Message[], output_format: {
37
+ parse: (input: string) => T;
38
+ } | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
39
+ }
@@ -0,0 +1,178 @@
1
+ import OpenAI from 'openai';
2
+ import { ModelProviderError, ModelRateLimitError } from '../exceptions.js';
3
+ import { SchemaOptimizer, zodSchemaToJsonSchema } from '../schema.js';
4
+ import { ChatInvokeCompletion } from '../views.js';
5
+ import { CerebrasMessageSerializer, } from './serializer.js';
6
+ export class ChatCerebras {
7
+ model;
8
+ provider = 'cerebras';
9
+ client;
10
+ temperature;
11
+ maxTokens;
12
+ topP;
13
+ seed;
14
+ removeMinItemsFromSchema;
15
+ removeDefaultsFromSchema;
16
+ constructor(options = {}) {
17
+ const normalizedOptions = typeof options === 'string' ? { model: options } : options;
18
+ const { model = 'llama3.1-8b', apiKey = process.env.CEREBRAS_API_KEY, baseURL = process.env.CEREBRAS_BASE_URL || 'https://api.cerebras.ai/v1', timeout = null, clientParams = null, temperature = 0.2, maxTokens = 4096, topP = null, seed = null, maxRetries = 5, removeMinItemsFromSchema = false, removeDefaultsFromSchema = false, } = normalizedOptions;
19
+ this.model = model;
20
+ this.temperature = temperature;
21
+ this.maxTokens = maxTokens;
22
+ this.topP = topP;
23
+ this.seed = seed;
24
+ this.removeMinItemsFromSchema = removeMinItemsFromSchema;
25
+ this.removeDefaultsFromSchema = removeDefaultsFromSchema;
26
+ this.client = new OpenAI({
27
+ apiKey,
28
+ baseURL,
29
+ ...(timeout !== null ? { timeout } : {}),
30
+ maxRetries,
31
+ ...(clientParams ?? {}),
32
+ });
33
+ }
34
+ get name() {
35
+ return this.model;
36
+ }
37
+ get model_name() {
38
+ return this.model;
39
+ }
40
+ getUsage(response) {
41
+ if (!response.usage) {
42
+ return null;
43
+ }
44
+ return {
45
+ prompt_tokens: response.usage.prompt_tokens,
46
+ prompt_cached_tokens: response.usage.prompt_tokens_details?.cached_tokens ?? null,
47
+ prompt_cache_creation_tokens: null,
48
+ prompt_image_tokens: null,
49
+ completion_tokens: response.usage.completion_tokens,
50
+ total_tokens: response.usage.total_tokens,
51
+ };
52
+ }
53
+ getSchemaCandidate(output_format) {
54
+ const output = output_format;
55
+ if (output &&
56
+ typeof output === 'object' &&
57
+ typeof output.safeParse === 'function' &&
58
+ typeof output.parse === 'function') {
59
+ return output;
60
+ }
61
+ if (output &&
62
+ typeof output === 'object' &&
63
+ output.schema &&
64
+ typeof output.schema.safeParse === 'function' &&
65
+ typeof output.schema.parse === 'function') {
66
+ return output.schema;
67
+ }
68
+ return null;
69
+ }
70
+ extractJsonFromContent(content) {
71
+ const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
72
+ const normalized = (fenced ? fenced[1] : content).trim();
73
+ const firstBrace = normalized.indexOf('{');
74
+ if (firstBrace < 0) {
75
+ return normalized;
76
+ }
77
+ let depth = 0;
78
+ for (let idx = firstBrace; idx < normalized.length; idx += 1) {
79
+ const char = normalized[idx];
80
+ if (char === '{') {
81
+ depth += 1;
82
+ }
83
+ else if (char === '}') {
84
+ depth -= 1;
85
+ if (depth === 0) {
86
+ return normalized.slice(firstBrace, idx + 1);
87
+ }
88
+ }
89
+ }
90
+ return normalized.slice(firstBrace);
91
+ }
92
+ appendJsonInstruction(serializedMessages, schemaText) {
93
+ const instruction = `\n\nPlease respond with a JSON object that follows this exact schema:\n` +
94
+ `${schemaText}\n\n` +
95
+ `Your response must be valid JSON only, no other text.`;
96
+ if (serializedMessages.length === 0) {
97
+ return [{ role: 'user', content: instruction }];
98
+ }
99
+ const cloned = [...serializedMessages];
100
+ const last = cloned[cloned.length - 1];
101
+ if (last?.role === 'user') {
102
+ if (typeof last.content === 'string') {
103
+ last.content = `${last.content}${instruction}`;
104
+ return cloned;
105
+ }
106
+ if (Array.isArray(last.content)) {
107
+ last.content = [...last.content, { type: 'text', text: instruction }];
108
+ return cloned;
109
+ }
110
+ }
111
+ cloned.push({ role: 'user', content: instruction });
112
+ return cloned;
113
+ }
114
+ async ainvoke(messages, output_format, options = {}) {
115
+ const serializer = new CerebrasMessageSerializer();
116
+ const cerebrasMessages = serializer.serialize(messages);
117
+ const modelParams = {};
118
+ if (this.temperature !== null) {
119
+ modelParams.temperature = this.temperature;
120
+ }
121
+ if (this.maxTokens !== null) {
122
+ modelParams.max_tokens = this.maxTokens;
123
+ }
124
+ if (this.topP !== null) {
125
+ modelParams.top_p = this.topP;
126
+ }
127
+ if (this.seed !== null) {
128
+ modelParams.seed = this.seed;
129
+ }
130
+ const zodSchemaCandidate = this.getSchemaCandidate(output_format);
131
+ let requestMessages = cerebrasMessages;
132
+ if (zodSchemaCandidate) {
133
+ const rawSchema = zodSchemaToJsonSchema(zodSchemaCandidate, {
134
+ name: 'agent_output',
135
+ target: 'jsonSchema7',
136
+ });
137
+ const optimizedSchema = SchemaOptimizer.createOptimizedJsonSchema(rawSchema, {
138
+ removeMinItems: this.removeMinItemsFromSchema,
139
+ removeDefaults: this.removeDefaultsFromSchema,
140
+ });
141
+ requestMessages = this.appendJsonInstruction(cerebrasMessages, JSON.stringify(optimizedSchema, null, 2));
142
+ }
143
+ try {
144
+ const response = await this.client.chat.completions.create({
145
+ model: this.model,
146
+ messages: requestMessages,
147
+ ...modelParams,
148
+ }, options.signal ? { signal: options.signal } : undefined);
149
+ const content = response.choices[0].message.content || '';
150
+ const usage = this.getUsage(response);
151
+ const stopReason = response.choices[0].finish_reason ?? null;
152
+ let completion = content;
153
+ if (output_format) {
154
+ const jsonSource = zodSchemaCandidate
155
+ ? this.extractJsonFromContent(content)
156
+ : content;
157
+ const parsedJson = JSON.parse(jsonSource);
158
+ const output = output_format;
159
+ if (output &&
160
+ typeof output === 'object' &&
161
+ output.schema &&
162
+ typeof output.schema.parse === 'function') {
163
+ completion = output.schema.parse(parsedJson);
164
+ }
165
+ else {
166
+ completion = output.parse(parsedJson);
167
+ }
168
+ }
169
+ return new ChatInvokeCompletion(completion, usage, null, null, stopReason);
170
+ }
171
+ catch (error) {
172
+ if (error?.status === 429) {
173
+ throw new ModelRateLimitError(error?.message ?? 'Rate limit exceeded', 429, this.model);
174
+ }
175
+ throw new ModelProviderError(error?.message ?? String(error), error?.status ?? 500, this.model);
176
+ }
177
+ }
178
+ }
@@ -0,0 +1,2 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
@@ -0,0 +1,2 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
@@ -0,0 +1,7 @@
1
+ import { type Message } from '../messages.js';
2
+ export type CerebrasMessage = Record<string, unknown>;
3
+ export declare class CerebrasMessageSerializer {
4
+ private serializeContent;
5
+ private serializeToolCalls;
6
+ serialize(messages: Message[]): CerebrasMessage[];
7
+ }
@@ -0,0 +1,82 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartRefusalParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ export class CerebrasMessageSerializer {
3
+ serializeContent(content) {
4
+ if (content == null) {
5
+ return '';
6
+ }
7
+ if (typeof content === 'string') {
8
+ return content;
9
+ }
10
+ if (!Array.isArray(content)) {
11
+ return String(content);
12
+ }
13
+ const parts = [];
14
+ for (const part of content) {
15
+ if (part instanceof ContentPartTextParam) {
16
+ parts.push({ type: 'text', text: part.text });
17
+ }
18
+ else if (part instanceof ContentPartImageParam) {
19
+ parts.push({
20
+ type: 'image_url',
21
+ image_url: {
22
+ url: part.image_url.url,
23
+ },
24
+ });
25
+ }
26
+ else if (part instanceof ContentPartRefusalParam) {
27
+ parts.push({ type: 'text', text: `[Refusal] ${part.refusal}` });
28
+ }
29
+ }
30
+ return parts;
31
+ }
32
+ serializeToolCalls(toolCalls) {
33
+ if (!toolCalls || !toolCalls.length) {
34
+ return undefined;
35
+ }
36
+ return toolCalls.map((toolCall) => {
37
+ let argumentsPayload;
38
+ try {
39
+ argumentsPayload = JSON.parse(toolCall.functionCall.arguments);
40
+ }
41
+ catch {
42
+ argumentsPayload = { arguments: toolCall.functionCall.arguments };
43
+ }
44
+ return {
45
+ id: toolCall.id,
46
+ type: 'function',
47
+ function: {
48
+ name: toolCall.functionCall.name,
49
+ arguments: argumentsPayload,
50
+ },
51
+ };
52
+ });
53
+ }
54
+ serialize(messages) {
55
+ return messages.map((message) => {
56
+ if (message instanceof UserMessage) {
57
+ return {
58
+ role: 'user',
59
+ content: this.serializeContent(message.content),
60
+ };
61
+ }
62
+ if (message instanceof SystemMessage) {
63
+ return {
64
+ role: 'system',
65
+ content: this.serializeContent(message.content),
66
+ };
67
+ }
68
+ if (message instanceof AssistantMessage) {
69
+ const payload = {
70
+ role: 'assistant',
71
+ content: this.serializeContent(message.content),
72
+ };
73
+ const toolCalls = this.serializeToolCalls(message.tool_calls);
74
+ if (toolCalls) {
75
+ payload.tool_calls = toolCalls;
76
+ }
77
+ return payload;
78
+ }
79
+ throw new Error(`Unknown message type: ${message?.constructor?.name ?? typeof message}`);
80
+ });
81
+ }
82
+ }
@@ -1,13 +1,30 @@
1
1
  import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
2
- import { ChatInvokeCompletion } from '../views.js';
3
2
  import type { Message } from '../messages.js';
3
+ import { ChatInvokeCompletion } from '../views.js';
4
+ export interface ChatDeepSeekOptions {
5
+ model?: string;
6
+ apiKey?: string;
7
+ baseURL?: string;
8
+ timeout?: number | null;
9
+ clientParams?: Record<string, unknown> | null;
10
+ temperature?: number | null;
11
+ maxTokens?: number | null;
12
+ topP?: number | null;
13
+ seed?: number | null;
14
+ maxRetries?: number;
15
+ }
4
16
  export declare class ChatDeepSeek implements BaseChatModel {
5
17
  model: string;
6
18
  provider: string;
7
19
  private client;
8
- constructor(model?: string);
20
+ private temperature;
21
+ private maxTokens;
22
+ private topP;
23
+ private seed;
24
+ constructor(options?: string | ChatDeepSeekOptions);
9
25
  get name(): string;
10
26
  get model_name(): string;
27
+ private getUsage;
11
28
  ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
12
29
  ainvoke<T>(messages: Message[], output_format: {
13
30
  parse: (input: string) => T;