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
@@ -1,10 +1,10 @@
1
1
  import OpenAI from 'openai';
2
- import { zodToJsonSchema } from 'zod-to-json-schema';
3
2
  import { ChatInvokeCompletion } from '../views.js';
4
3
  import { OpenAIMessageSerializer } from './serializer.js';
5
- import { ModelProviderError } from '../exceptions.js';
4
+ import { ModelProviderError, ModelRateLimitError } from '../exceptions.js';
5
+ import { SchemaOptimizer, zodSchemaToJsonSchema } from '../schema.js';
6
6
  // Reasoning models that support reasoning_effort parameter
7
- const ReasoningModels = [
7
+ const DEFAULT_REASONING_MODELS = [
8
8
  'o4-mini',
9
9
  'o3',
10
10
  'o3-mini',
@@ -22,25 +22,43 @@ export class ChatOpenAI {
22
22
  temperature;
23
23
  frequencyPenalty;
24
24
  reasoningEffort;
25
+ serviceTier;
25
26
  maxCompletionTokens;
26
27
  seed;
27
28
  topP;
28
29
  addSchemaToSystemPrompt;
30
+ dontForceStructuredOutput;
31
+ removeMinItemsFromSchema;
32
+ removeDefaultsFromSchema;
33
+ reasoningModels;
29
34
  constructor(options = {}) {
30
- const { model = 'gpt-4o', apiKey, organization, baseURL, temperature = 0.2, frequencyPenalty = 0.1, reasoningEffort = 'low', maxCompletionTokens = 8000, maxRetries = 10, seed = null, topP = null, addSchemaToSystemPrompt = false, } = options;
35
+ const { model = 'gpt-4o', apiKey, organization, project, baseURL, timeout = null, temperature = 0.2, frequencyPenalty = 0.3, reasoningEffort = 'low', serviceTier = null, maxCompletionTokens = 4096, maxRetries = 5, defaultHeaders = null, defaultQuery = null, fetchImplementation, fetchOptions = null, seed = null, topP = null, addSchemaToSystemPrompt = false, dontForceStructuredOutput = false, removeMinItemsFromSchema = false, removeDefaultsFromSchema = false, reasoningModels = DEFAULT_REASONING_MODELS, } = options;
31
36
  this.model = model;
32
37
  this.temperature = temperature;
33
38
  this.frequencyPenalty = frequencyPenalty;
34
39
  this.reasoningEffort = reasoningEffort;
40
+ this.serviceTier = serviceTier;
35
41
  this.maxCompletionTokens = maxCompletionTokens;
36
42
  this.seed = seed;
37
43
  this.topP = topP;
38
44
  this.addSchemaToSystemPrompt = addSchemaToSystemPrompt;
45
+ this.dontForceStructuredOutput = dontForceStructuredOutput;
46
+ this.removeMinItemsFromSchema = removeMinItemsFromSchema;
47
+ this.removeDefaultsFromSchema = removeDefaultsFromSchema;
48
+ this.reasoningModels = reasoningModels
49
+ ? [...reasoningModels]
50
+ : reasoningModels;
39
51
  this.client = new OpenAI({
40
52
  apiKey,
41
53
  organization,
54
+ project,
42
55
  baseURL,
56
+ timeout: timeout ?? undefined,
43
57
  maxRetries,
58
+ defaultHeaders: defaultHeaders ?? undefined,
59
+ defaultQuery: defaultQuery ?? undefined,
60
+ fetch: fetchImplementation,
61
+ fetchOptions: (fetchOptions ?? undefined),
44
62
  });
45
63
  }
46
64
  get name() {
@@ -50,7 +68,7 @@ export class ChatOpenAI {
50
68
  return this.model;
51
69
  }
52
70
  isReasoningModel() {
53
- return ReasoningModels.some((m) => this.model.toLowerCase().includes(m.toLowerCase()));
71
+ return (this.reasoningModels ?? []).some((m) => this.model.toLowerCase().includes(m.toLowerCase()));
54
72
  }
55
73
  getUsage(response) {
56
74
  if (!response.usage)
@@ -96,36 +114,69 @@ export class ChatOpenAI {
96
114
  if (this.topP !== null) {
97
115
  modelParams.top_p = this.topP;
98
116
  }
117
+ if (this.serviceTier !== null) {
118
+ modelParams.service_tier = this.serviceTier;
119
+ }
120
+ const zodSchemaCandidate = (() => {
121
+ const output = output_format;
122
+ if (output &&
123
+ typeof output === 'object' &&
124
+ typeof output.safeParse === 'function' &&
125
+ typeof output.parse === 'function') {
126
+ return output;
127
+ }
128
+ if (output &&
129
+ typeof output === 'object' &&
130
+ output.schema &&
131
+ typeof output.schema.safeParse === 'function' &&
132
+ typeof output.schema.parse === 'function') {
133
+ return output.schema;
134
+ }
135
+ return null;
136
+ })();
99
137
  let responseFormat = undefined;
100
- if (output_format && 'schema' in output_format && output_format.schema) {
101
- // Assuming output_format is a Zod schema wrapper or similar that has a schema property
102
- // But the interface says { parse: ... }
103
- // In the plan, it was passed as a Zod schema directly.
104
- // However, the BaseChatModel interface I saw earlier has:
105
- // ainvoke<T>(messages: Message[], output_format: { parse: (input: string) => T } | undefined): Promise<ChatInvokeCompletion<T>>;
106
- // So I need to handle how to extract the schema if I want to use structured outputs.
107
- // If output_format is just a Zod schema, it has a parse method.
108
- // Let's assume it's a Zod schema for now, as that's what the plan implies.
109
- // We need to cast it to any or check if it's a Zod schema to get the schema for JSON schema generation.
110
- // For now, I'll try to use zodToJsonSchema on it if possible.
138
+ if (zodSchemaCandidate) {
111
139
  try {
112
- const jsonSchema = zodToJsonSchema(output_format, {
113
- name: 'Response',
140
+ const rawJsonSchema = zodSchemaToJsonSchema(zodSchemaCandidate, {
141
+ name: 'agent_output',
114
142
  target: 'jsonSchema7',
115
143
  });
116
- // OpenAI expects a specific format for json_schema
117
- responseFormat = {
118
- type: 'json_schema',
119
- json_schema: {
120
- name: 'Response',
121
- schema: jsonSchema,
122
- strict: true,
123
- },
144
+ const optimizedJsonSchema = SchemaOptimizer.createOptimizedJsonSchema(rawJsonSchema, {
145
+ removeMinItems: this.removeMinItemsFromSchema,
146
+ removeDefaults: this.removeDefaultsFromSchema,
147
+ });
148
+ const responseJsonSchema = {
149
+ name: 'agent_output',
150
+ schema: optimizedJsonSchema,
151
+ strict: true,
124
152
  };
153
+ if (this.addSchemaToSystemPrompt && openaiMessages.length > 0) {
154
+ const firstMessage = openaiMessages[0];
155
+ const schemaText = `\n<json_schema>\n` +
156
+ `${JSON.stringify(responseJsonSchema, null, 2)}\n` +
157
+ `</json_schema>`;
158
+ if (firstMessage?.role === 'system') {
159
+ if (typeof firstMessage.content === 'string') {
160
+ firstMessage.content =
161
+ (firstMessage.content ?? '') + schemaText;
162
+ }
163
+ else if (Array.isArray(firstMessage.content)) {
164
+ firstMessage.content = [
165
+ ...firstMessage.content,
166
+ { type: 'text', text: schemaText },
167
+ ];
168
+ }
169
+ }
170
+ }
171
+ if (!this.dontForceStructuredOutput) {
172
+ responseFormat = {
173
+ type: 'json_schema',
174
+ json_schema: responseJsonSchema,
175
+ };
176
+ }
125
177
  }
126
- catch (e) {
127
- // If it's not a Zod schema or fails, we might fallback or just not use response_format
128
- console.warn('Failed to convert output_format to JSON schema', e);
178
+ catch {
179
+ responseFormat = undefined;
129
180
  }
130
181
  }
131
182
  try {
@@ -137,33 +188,32 @@ export class ChatOpenAI {
137
188
  }, options.signal ? { signal: options.signal } : undefined);
138
189
  const content = response.choices[0].message.content || '';
139
190
  const usage = this.getUsage(response);
191
+ const stopReason = response.choices[0].finish_reason ?? null;
140
192
  let completion = content;
141
193
  if (output_format) {
142
- try {
143
- // If it's structured output, we need to parse the JSON first
144
- if (responseFormat?.type === 'json_schema') {
145
- const parsedJson = JSON.parse(content);
146
- completion = output_format.parse(parsedJson);
194
+ if (zodSchemaCandidate) {
195
+ const parsedJson = JSON.parse(content);
196
+ const output = output_format;
197
+ if (output &&
198
+ typeof output === 'object' &&
199
+ output.schema &&
200
+ typeof output.schema.parse === 'function') {
201
+ completion = output.schema.parse(parsedJson);
147
202
  }
148
203
  else {
149
- // If it's not structured output but we have a parser (e.g. for simple types or manual parsing)
150
- // But usually for OpenAI we want structured output if a schema is provided.
151
- // If we didn't use json_schema, we might still try to parse if it looks like JSON?
152
- // For now, let's trust the output_format.parse
153
- completion = output_format.parse(content);
204
+ completion = output_format.parse(parsedJson);
154
205
  }
155
206
  }
156
- catch (e) {
157
- console.error('Failed to parse completion', e);
158
- throw e;
207
+ else {
208
+ completion = output_format.parse(content);
159
209
  }
160
210
  }
161
- return new ChatInvokeCompletion(completion, usage);
211
+ return new ChatInvokeCompletion(completion, usage, null, null, stopReason);
162
212
  }
163
213
  catch (error) {
164
214
  // Handle OpenAI-specific errors
165
215
  if (error?.status === 429) {
166
- throw new ModelProviderError(error?.message ?? 'Rate limit exceeded', 429, this.model);
216
+ throw new ModelRateLimitError(error?.message ?? 'Rate limit exceeded', 429, this.model);
167
217
  }
168
218
  if (error?.status >= 500) {
169
219
  throw new ModelProviderError(error?.message ?? 'Server error', error.status, this.model);
@@ -1,4 +1,4 @@
1
- import { ChatOpenAI } from './chat.js';
1
+ import { ChatOpenAI, type ChatOpenAIOptions } from './chat.js';
2
2
  /**
3
3
  * A class to interact with any provider using the OpenAI API schema.
4
4
  *
@@ -11,7 +11,9 @@ import { ChatOpenAI } from './chat.js';
11
11
  */
12
12
  export declare class ChatOpenAILike extends ChatOpenAI {
13
13
  /**
14
- * @param model - The name of the model to use (any OpenAI-compatible model)
14
+ * @param options - A model name or ChatOpenAI-compatible options
15
15
  */
16
- constructor(model: string);
16
+ constructor(options: string | (ChatOpenAIOptions & {
17
+ model: string;
18
+ }));
17
19
  }
@@ -11,9 +11,13 @@ import { ChatOpenAI } from './chat.js';
11
11
  */
12
12
  export class ChatOpenAILike extends ChatOpenAI {
13
13
  /**
14
- * @param model - The name of the model to use (any OpenAI-compatible model)
14
+ * @param options - A model name or ChatOpenAI-compatible options
15
15
  */
16
- constructor(model) {
17
- super({ model });
16
+ constructor(options) {
17
+ if (typeof options === 'string') {
18
+ super({ model: options });
19
+ return;
20
+ }
21
+ super(options);
18
22
  }
19
23
  }
@@ -0,0 +1,18 @@
1
+ import { type Message } from '../messages.js';
2
+ type ResponsesInputPart = {
3
+ type: 'input_text';
4
+ text: string;
5
+ } | {
6
+ type: 'input_image';
7
+ image_url: string;
8
+ detail?: 'auto' | 'low' | 'high';
9
+ };
10
+ export type ResponsesInputMessage = {
11
+ role: 'user' | 'system' | 'assistant';
12
+ content: string | ResponsesInputPart[];
13
+ };
14
+ export declare class ResponsesAPIMessageSerializer {
15
+ serialize(messages: Message[]): ResponsesInputMessage[];
16
+ private serializeMessage;
17
+ }
18
+ export {};
@@ -0,0 +1,72 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartRefusalParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ export class ResponsesAPIMessageSerializer {
3
+ serialize(messages) {
4
+ return messages.map((message) => this.serializeMessage(message));
5
+ }
6
+ serializeMessage(message) {
7
+ if (message instanceof UserMessage) {
8
+ if (typeof message.content === 'string') {
9
+ return { role: 'user', content: message.content };
10
+ }
11
+ const content = message.content
12
+ .map((part) => {
13
+ if (part instanceof ContentPartTextParam) {
14
+ return { type: 'input_text', text: part.text };
15
+ }
16
+ if (part instanceof ContentPartImageParam) {
17
+ return {
18
+ type: 'input_image',
19
+ image_url: part.image_url.url,
20
+ detail: part.image_url.detail,
21
+ };
22
+ }
23
+ return null;
24
+ })
25
+ .filter((part) => part !== null);
26
+ return { role: 'user', content };
27
+ }
28
+ if (message instanceof SystemMessage) {
29
+ if (typeof message.content === 'string') {
30
+ return { role: 'system', content: message.content };
31
+ }
32
+ return {
33
+ role: 'system',
34
+ content: message.content.map((part) => ({
35
+ type: 'input_text',
36
+ text: part.text,
37
+ })),
38
+ };
39
+ }
40
+ if (message instanceof AssistantMessage) {
41
+ if (message.content == null) {
42
+ if (Array.isArray(message.tool_calls) &&
43
+ message.tool_calls.length > 0) {
44
+ const toolCallText = message.tool_calls
45
+ .map((toolCall) => `[Tool call: ${toolCall.functionCall.name}(${toolCall.functionCall.arguments})]`)
46
+ .join('\n');
47
+ return { role: 'assistant', content: toolCallText };
48
+ }
49
+ return { role: 'assistant', content: '' };
50
+ }
51
+ if (typeof message.content === 'string') {
52
+ return { role: 'assistant', content: message.content };
53
+ }
54
+ const content = message.content
55
+ .map((part) => {
56
+ if (part instanceof ContentPartTextParam) {
57
+ return { type: 'input_text', text: part.text };
58
+ }
59
+ if (part instanceof ContentPartRefusalParam) {
60
+ return {
61
+ type: 'input_text',
62
+ text: `[Refusal: ${part.refusal}]`,
63
+ };
64
+ }
65
+ return null;
66
+ })
67
+ .filter((part) => part !== null);
68
+ return { role: 'assistant', content };
69
+ }
70
+ throw new Error(`Unknown message type: ${message?.constructor?.name ?? typeof message}`);
71
+ }
72
+ }
@@ -1,13 +1,39 @@
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 ChatOpenRouterOptions {
5
+ model?: string;
6
+ apiKey?: string;
7
+ baseURL?: string;
8
+ timeout?: number | null;
9
+ temperature?: number | null;
10
+ topP?: number | null;
11
+ seed?: number | null;
12
+ maxRetries?: number;
13
+ defaultHeaders?: Record<string, string> | null;
14
+ defaultQuery?: Record<string, string | undefined> | null;
15
+ fetchImplementation?: typeof fetch;
16
+ fetchOptions?: RequestInit | null;
17
+ httpReferer?: string | null;
18
+ extraBody?: Record<string, unknown> | null;
19
+ removeMinItemsFromSchema?: boolean;
20
+ removeDefaultsFromSchema?: boolean;
21
+ }
4
22
  export declare class ChatOpenRouter implements BaseChatModel {
5
23
  model: string;
6
24
  provider: string;
7
25
  private client;
8
- constructor(model?: string);
26
+ private temperature;
27
+ private topP;
28
+ private seed;
29
+ private httpReferer;
30
+ private extraBody;
31
+ private removeMinItemsFromSchema;
32
+ private removeDefaultsFromSchema;
33
+ constructor(options?: string | ChatOpenRouterOptions);
9
34
  get name(): string;
10
35
  get model_name(): string;
36
+ private getUsage;
11
37
  ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
12
38
  ainvoke<T>(messages: Message[], output_format: {
13
39
  parse: (input: string) => T;
@@ -1,16 +1,39 @@
1
1
  import OpenAI from 'openai';
2
- import { zodToJsonSchema } from 'zod-to-json-schema';
2
+ import { ModelProviderError } from '../exceptions.js';
3
+ import { SchemaOptimizer, zodSchemaToJsonSchema } from '../schema.js';
3
4
  import { ChatInvokeCompletion } from '../views.js';
4
5
  import { OpenRouterMessageSerializer } from './serializer.js';
5
6
  export class ChatOpenRouter {
6
7
  model;
7
8
  provider = 'openrouter';
8
9
  client;
9
- constructor(model = 'openai/gpt-4o') {
10
+ temperature;
11
+ topP;
12
+ seed;
13
+ httpReferer;
14
+ extraBody;
15
+ removeMinItemsFromSchema;
16
+ removeDefaultsFromSchema;
17
+ constructor(options = {}) {
18
+ const normalizedOptions = typeof options === 'string' ? { model: options } : options;
19
+ const { model = 'openai/gpt-4o', apiKey = process.env.OPENROUTER_API_KEY, baseURL = 'https://openrouter.ai/api/v1', timeout = null, temperature = null, topP = null, seed = null, maxRetries = 10, defaultHeaders = null, defaultQuery = null, fetchImplementation, fetchOptions = null, httpReferer = null, extraBody = null, removeMinItemsFromSchema = false, removeDefaultsFromSchema = false, } = normalizedOptions;
10
20
  this.model = model;
21
+ this.temperature = temperature;
22
+ this.topP = topP;
23
+ this.seed = seed;
24
+ this.httpReferer = httpReferer;
25
+ this.extraBody = extraBody;
26
+ this.removeMinItemsFromSchema = removeMinItemsFromSchema;
27
+ this.removeDefaultsFromSchema = removeDefaultsFromSchema;
11
28
  this.client = new OpenAI({
12
- apiKey: process.env.OPENROUTER_API_KEY,
13
- baseURL: 'https://openrouter.ai/api/v1',
29
+ apiKey,
30
+ baseURL,
31
+ timeout: timeout ?? undefined,
32
+ maxRetries,
33
+ defaultHeaders: defaultHeaders ?? undefined,
34
+ defaultQuery: defaultQuery ?? undefined,
35
+ fetch: fetchImplementation,
36
+ fetchOptions: (fetchOptions ?? undefined),
14
37
  });
15
38
  }
16
39
  get name() {
@@ -19,56 +42,119 @@ export class ChatOpenRouter {
19
42
  get model_name() {
20
43
  return this.model;
21
44
  }
45
+ getUsage(response) {
46
+ if (!response.usage) {
47
+ return null;
48
+ }
49
+ return {
50
+ prompt_tokens: response.usage.prompt_tokens,
51
+ prompt_cached_tokens: response.usage.prompt_tokens_details?.cached_tokens ?? null,
52
+ prompt_cache_creation_tokens: null,
53
+ prompt_image_tokens: null,
54
+ completion_tokens: response.usage.completion_tokens,
55
+ total_tokens: response.usage.total_tokens,
56
+ };
57
+ }
22
58
  async ainvoke(messages, output_format, options = {}) {
23
59
  const serializer = new OpenRouterMessageSerializer();
24
60
  const openRouterMessages = serializer.serialize(messages);
61
+ const modelParams = {};
62
+ if (this.temperature !== null) {
63
+ modelParams.temperature = this.temperature;
64
+ }
65
+ if (this.topP !== null) {
66
+ modelParams.top_p = this.topP;
67
+ }
68
+ if (this.seed !== null) {
69
+ modelParams.seed = this.seed;
70
+ }
71
+ const zodSchemaCandidate = (() => {
72
+ const output = output_format;
73
+ if (output &&
74
+ typeof output === 'object' &&
75
+ typeof output.safeParse === 'function' &&
76
+ typeof output.parse === 'function') {
77
+ return output;
78
+ }
79
+ if (output &&
80
+ typeof output === 'object' &&
81
+ output.schema &&
82
+ typeof output.schema.safeParse === 'function' &&
83
+ typeof output.schema.parse === 'function') {
84
+ return output.schema;
85
+ }
86
+ return null;
87
+ })();
25
88
  let responseFormat = undefined;
26
- if (output_format && 'schema' in output_format && output_format.schema) {
27
- // OpenRouter supports structured outputs for some models, but it depends on the underlying provider.
28
- // We'll try to use json_schema if possible, or json_object.
89
+ if (zodSchemaCandidate) {
29
90
  try {
30
- const jsonSchema = zodToJsonSchema(output_format, {
31
- name: 'Response',
91
+ const rawJsonSchema = zodSchemaToJsonSchema(zodSchemaCandidate, {
92
+ name: 'agent_output',
32
93
  target: 'jsonSchema7',
33
94
  });
95
+ const optimizedJsonSchema = SchemaOptimizer.createOptimizedJsonSchema(rawJsonSchema, {
96
+ removeMinItems: this.removeMinItemsFromSchema,
97
+ removeDefaults: this.removeDefaultsFromSchema,
98
+ });
34
99
  responseFormat = {
35
100
  type: 'json_schema',
36
101
  json_schema: {
37
- name: 'Response',
38
- schema: jsonSchema,
102
+ name: 'agent_output',
103
+ schema: optimizedJsonSchema,
39
104
  strict: true,
40
105
  },
41
106
  };
42
107
  }
43
- catch (e) {
44
- console.warn('Failed to convert output_format to JSON schema for OpenRouter', e);
108
+ catch {
109
+ responseFormat = undefined;
45
110
  }
46
111
  }
47
- const response = await this.client.chat.completions.create({
112
+ const request = {
48
113
  model: this.model,
49
114
  messages: openRouterMessages,
50
115
  response_format: responseFormat,
51
- }, options.signal ? { signal: options.signal } : undefined);
52
- const content = response.choices[0].message.content || '';
53
- let completion = content;
54
- if (output_format) {
55
- try {
56
- if (responseFormat?.type === 'json_schema') {
57
- completion = output_format.parse(JSON.parse(content));
116
+ ...modelParams,
117
+ ...(this.extraBody ?? {}),
118
+ };
119
+ if (this.httpReferer) {
120
+ request.extra_headers = {
121
+ 'HTTP-Referer': this.httpReferer,
122
+ };
123
+ }
124
+ try {
125
+ const response = await this.client.chat.completions.create(request, options.signal ? { signal: options.signal } : undefined);
126
+ const content = response.choices[0].message.content || '';
127
+ const usage = this.getUsage(response);
128
+ const stopReason = response.choices[0].finish_reason ?? null;
129
+ let completion = content;
130
+ if (output_format) {
131
+ if (zodSchemaCandidate) {
132
+ const parsedJson = JSON.parse(content);
133
+ const output = output_format;
134
+ if (output &&
135
+ typeof output === 'object' &&
136
+ output.schema &&
137
+ typeof output.schema.parse === 'function') {
138
+ completion = output.schema.parse(parsedJson);
139
+ }
140
+ else {
141
+ completion = output_format.parse(parsedJson);
142
+ }
58
143
  }
59
144
  else {
60
145
  completion = output_format.parse(content);
61
146
  }
62
147
  }
63
- catch (e) {
64
- console.error('Failed to parse completion', e);
65
- throw e;
148
+ return new ChatInvokeCompletion(completion, usage, null, null, stopReason);
149
+ }
150
+ catch (error) {
151
+ if (error?.status === 429) {
152
+ throw new ModelProviderError(error?.message ?? 'Rate limit exceeded', 429, this.model);
153
+ }
154
+ if (error?.status >= 500) {
155
+ throw new ModelProviderError(error?.message ?? 'Server error', error.status, this.model);
66
156
  }
157
+ throw new ModelProviderError(error?.message ?? String(error), error?.status ?? 500, this.model);
67
158
  }
68
- return new ChatInvokeCompletion(completion, {
69
- prompt_tokens: response.usage?.prompt_tokens ?? 0,
70
- completion_tokens: response.usage?.completion_tokens ?? 0,
71
- total_tokens: response.usage?.total_tokens ?? 0,
72
- });
73
159
  }
74
160
  }
@@ -1,6 +1,16 @@
1
1
  type JsonSchema = Record<string, unknown>;
2
+ interface ZodJsonSchemaOptions {
3
+ name?: string;
4
+ target?: string;
5
+ [key: string]: unknown;
6
+ }
7
+ export declare const zodSchemaToJsonSchema: (schema: unknown, options?: ZodJsonSchemaOptions) => JsonSchema;
2
8
  export declare class SchemaOptimizer {
3
- static createOptimizedJsonSchema(schema: JsonSchema): JsonSchema;
9
+ static createOptimizedJsonSchema(schema: JsonSchema, options?: {
10
+ removeMinItems?: boolean;
11
+ removeDefaults?: boolean;
12
+ }): JsonSchema;
13
+ static createGeminiOptimizedSchema(schema: JsonSchema): JsonSchema;
4
14
  static makeStrictCompatible(schema: any): void;
5
15
  }
6
16
  export {};