browser-use 0.0.1 → 0.1.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 (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +761 -0
  3. package/dist/agent/cloud-events.d.ts +264 -0
  4. package/dist/agent/cloud-events.js +318 -0
  5. package/dist/agent/gif.d.ts +15 -0
  6. package/dist/agent/gif.js +215 -0
  7. package/dist/agent/index.d.ts +8 -0
  8. package/dist/agent/index.js +8 -0
  9. package/dist/agent/message-manager/service.d.ts +30 -0
  10. package/dist/agent/message-manager/service.js +208 -0
  11. package/dist/agent/message-manager/utils.d.ts +2 -0
  12. package/dist/agent/message-manager/utils.js +41 -0
  13. package/dist/agent/message-manager/views.d.ts +26 -0
  14. package/dist/agent/message-manager/views.js +73 -0
  15. package/dist/agent/prompts.d.ts +52 -0
  16. package/dist/agent/prompts.js +259 -0
  17. package/dist/agent/service.d.ts +290 -0
  18. package/dist/agent/service.js +2200 -0
  19. package/dist/agent/views.d.ts +741 -0
  20. package/dist/agent/views.js +537 -0
  21. package/dist/browser/browser.d.ts +7 -0
  22. package/dist/browser/browser.js +5 -0
  23. package/dist/browser/context.d.ts +8 -0
  24. package/dist/browser/context.js +4 -0
  25. package/dist/browser/dvd-screensaver.d.ts +101 -0
  26. package/dist/browser/dvd-screensaver.js +270 -0
  27. package/dist/browser/extensions.d.ts +63 -0
  28. package/dist/browser/extensions.js +359 -0
  29. package/dist/browser/index.d.ts +10 -0
  30. package/dist/browser/index.js +9 -0
  31. package/dist/browser/playwright-manager.d.ts +47 -0
  32. package/dist/browser/playwright-manager.js +146 -0
  33. package/dist/browser/profile.d.ts +196 -0
  34. package/dist/browser/profile.js +815 -0
  35. package/dist/browser/session.d.ts +505 -0
  36. package/dist/browser/session.js +3409 -0
  37. package/dist/browser/types.d.ts +1184 -0
  38. package/dist/browser/types.js +1 -0
  39. package/dist/browser/utils.d.ts +1 -0
  40. package/dist/browser/utils.js +19 -0
  41. package/dist/browser/views.d.ts +78 -0
  42. package/dist/browser/views.js +72 -0
  43. package/dist/cli.d.ts +2 -0
  44. package/dist/cli.js +44 -0
  45. package/dist/config.d.ts +108 -0
  46. package/dist/config.js +430 -0
  47. package/dist/controller/index.d.ts +3 -0
  48. package/dist/controller/index.js +3 -0
  49. package/dist/controller/registry/index.d.ts +2 -0
  50. package/dist/controller/registry/index.js +2 -0
  51. package/dist/controller/registry/service.d.ts +45 -0
  52. package/dist/controller/registry/service.js +184 -0
  53. package/dist/controller/registry/views.d.ts +55 -0
  54. package/dist/controller/registry/views.js +174 -0
  55. package/dist/controller/service.d.ts +49 -0
  56. package/dist/controller/service.js +1176 -0
  57. package/dist/controller/views.d.ts +241 -0
  58. package/dist/controller/views.js +88 -0
  59. package/dist/dom/clickable-element-processor/service.d.ts +11 -0
  60. package/dist/dom/clickable-element-processor/service.js +60 -0
  61. package/dist/dom/dom_tree/index.js +1400 -0
  62. package/dist/dom/history-tree-processor/service.d.ts +14 -0
  63. package/dist/dom/history-tree-processor/service.js +75 -0
  64. package/dist/dom/history-tree-processor/view.d.ts +54 -0
  65. package/dist/dom/history-tree-processor/view.js +56 -0
  66. package/dist/dom/playground/extraction.d.ts +19 -0
  67. package/dist/dom/playground/extraction.js +187 -0
  68. package/dist/dom/playground/process-dom.d.ts +1 -0
  69. package/dist/dom/playground/process-dom.js +5 -0
  70. package/dist/dom/playground/test-accessibility.d.ts +44 -0
  71. package/dist/dom/playground/test-accessibility.js +111 -0
  72. package/dist/dom/service.d.ts +19 -0
  73. package/dist/dom/service.js +227 -0
  74. package/dist/dom/utils.d.ts +1 -0
  75. package/dist/dom/utils.js +6 -0
  76. package/dist/dom/views.d.ts +61 -0
  77. package/dist/dom/views.js +247 -0
  78. package/dist/event-bus.d.ts +11 -0
  79. package/dist/event-bus.js +19 -0
  80. package/dist/exceptions.d.ts +10 -0
  81. package/dist/exceptions.js +22 -0
  82. package/dist/filesystem/file-system.d.ts +68 -0
  83. package/dist/filesystem/file-system.js +412 -0
  84. package/dist/filesystem/index.d.ts +1 -0
  85. package/dist/filesystem/index.js +1 -0
  86. package/dist/index.d.ts +31 -0
  87. package/dist/index.js +33 -0
  88. package/dist/integrations/gmail/actions.d.ts +12 -0
  89. package/dist/integrations/gmail/actions.js +113 -0
  90. package/dist/integrations/gmail/index.d.ts +2 -0
  91. package/dist/integrations/gmail/index.js +2 -0
  92. package/dist/integrations/gmail/service.d.ts +61 -0
  93. package/dist/integrations/gmail/service.js +260 -0
  94. package/dist/llm/anthropic/chat.d.ts +28 -0
  95. package/dist/llm/anthropic/chat.js +126 -0
  96. package/dist/llm/anthropic/index.d.ts +2 -0
  97. package/dist/llm/anthropic/index.js +2 -0
  98. package/dist/llm/anthropic/serializer.d.ts +68 -0
  99. package/dist/llm/anthropic/serializer.js +285 -0
  100. package/dist/llm/aws/chat-anthropic.d.ts +61 -0
  101. package/dist/llm/aws/chat-anthropic.js +176 -0
  102. package/dist/llm/aws/chat-bedrock.d.ts +15 -0
  103. package/dist/llm/aws/chat-bedrock.js +80 -0
  104. package/dist/llm/aws/index.d.ts +3 -0
  105. package/dist/llm/aws/index.js +3 -0
  106. package/dist/llm/aws/serializer.d.ts +5 -0
  107. package/dist/llm/aws/serializer.js +68 -0
  108. package/dist/llm/azure/chat.d.ts +15 -0
  109. package/dist/llm/azure/chat.js +83 -0
  110. package/dist/llm/azure/index.d.ts +1 -0
  111. package/dist/llm/azure/index.js +1 -0
  112. package/dist/llm/base.d.ts +16 -0
  113. package/dist/llm/base.js +1 -0
  114. package/dist/llm/deepseek/chat.d.ts +15 -0
  115. package/dist/llm/deepseek/chat.js +51 -0
  116. package/dist/llm/deepseek/index.d.ts +2 -0
  117. package/dist/llm/deepseek/index.js +2 -0
  118. package/dist/llm/deepseek/serializer.d.ts +6 -0
  119. package/dist/llm/deepseek/serializer.js +57 -0
  120. package/dist/llm/exceptions.d.ts +10 -0
  121. package/dist/llm/exceptions.js +18 -0
  122. package/dist/llm/google/chat.d.ts +20 -0
  123. package/dist/llm/google/chat.js +144 -0
  124. package/dist/llm/google/index.d.ts +2 -0
  125. package/dist/llm/google/index.js +2 -0
  126. package/dist/llm/google/serializer.d.ts +6 -0
  127. package/dist/llm/google/serializer.js +64 -0
  128. package/dist/llm/groq/chat.d.ts +15 -0
  129. package/dist/llm/groq/chat.js +52 -0
  130. package/dist/llm/groq/index.d.ts +3 -0
  131. package/dist/llm/groq/index.js +3 -0
  132. package/dist/llm/groq/parser.d.ts +32 -0
  133. package/dist/llm/groq/parser.js +189 -0
  134. package/dist/llm/groq/serializer.d.ts +6 -0
  135. package/dist/llm/groq/serializer.js +56 -0
  136. package/dist/llm/messages.d.ts +77 -0
  137. package/dist/llm/messages.js +157 -0
  138. package/dist/llm/ollama/chat.d.ts +15 -0
  139. package/dist/llm/ollama/chat.js +77 -0
  140. package/dist/llm/ollama/index.d.ts +2 -0
  141. package/dist/llm/ollama/index.js +2 -0
  142. package/dist/llm/ollama/serializer.d.ts +6 -0
  143. package/dist/llm/ollama/serializer.js +53 -0
  144. package/dist/llm/openai/chat.d.ts +38 -0
  145. package/dist/llm/openai/chat.js +174 -0
  146. package/dist/llm/openai/index.d.ts +3 -0
  147. package/dist/llm/openai/index.js +3 -0
  148. package/dist/llm/openai/like.d.ts +17 -0
  149. package/dist/llm/openai/like.js +19 -0
  150. package/dist/llm/openai/serializer.d.ts +6 -0
  151. package/dist/llm/openai/serializer.js +57 -0
  152. package/dist/llm/openrouter/chat.d.ts +15 -0
  153. package/dist/llm/openrouter/chat.js +74 -0
  154. package/dist/llm/openrouter/index.d.ts +2 -0
  155. package/dist/llm/openrouter/index.js +2 -0
  156. package/dist/llm/openrouter/serializer.d.ts +3 -0
  157. package/dist/llm/openrouter/serializer.js +3 -0
  158. package/dist/llm/schema.d.ts +6 -0
  159. package/dist/llm/schema.js +77 -0
  160. package/dist/llm/views.d.ts +15 -0
  161. package/dist/llm/views.js +12 -0
  162. package/dist/logging-config.d.ts +25 -0
  163. package/dist/logging-config.js +89 -0
  164. package/dist/mcp/client.d.ts +142 -0
  165. package/dist/mcp/client.js +638 -0
  166. package/dist/mcp/controller.d.ts +6 -0
  167. package/dist/mcp/controller.js +38 -0
  168. package/dist/mcp/index.d.ts +3 -0
  169. package/dist/mcp/index.js +3 -0
  170. package/dist/mcp/server.d.ts +134 -0
  171. package/dist/mcp/server.js +759 -0
  172. package/dist/observability-decorators.d.ts +158 -0
  173. package/dist/observability-decorators.js +286 -0
  174. package/dist/observability.d.ts +23 -0
  175. package/dist/observability.js +58 -0
  176. package/dist/screenshots/index.d.ts +1 -0
  177. package/dist/screenshots/index.js +1 -0
  178. package/dist/screenshots/service.d.ts +6 -0
  179. package/dist/screenshots/service.js +28 -0
  180. package/dist/sync/auth.d.ts +27 -0
  181. package/dist/sync/auth.js +205 -0
  182. package/dist/sync/index.d.ts +2 -0
  183. package/dist/sync/index.js +2 -0
  184. package/dist/sync/service.d.ts +21 -0
  185. package/dist/sync/service.js +146 -0
  186. package/dist/telemetry/index.d.ts +2 -0
  187. package/dist/telemetry/index.js +2 -0
  188. package/dist/telemetry/service.d.ts +12 -0
  189. package/dist/telemetry/service.js +85 -0
  190. package/dist/telemetry/views.d.ts +112 -0
  191. package/dist/telemetry/views.js +112 -0
  192. package/dist/tokens/index.d.ts +2 -0
  193. package/dist/tokens/index.js +2 -0
  194. package/dist/tokens/service.d.ts +35 -0
  195. package/dist/tokens/service.js +423 -0
  196. package/dist/tokens/views.d.ts +58 -0
  197. package/dist/tokens/views.js +1 -0
  198. package/dist/utils.d.ts +128 -0
  199. package/dist/utils.js +529 -0
  200. package/package.json +94 -5
@@ -0,0 +1,6 @@
1
+ import type { Message as OllamaMessage } from 'ollama';
2
+ import { type Message } from '../messages.js';
3
+ export declare class OllamaMessageSerializer {
4
+ serialize(messages: Message[]): OllamaMessage[];
5
+ private serializeMessage;
6
+ }
@@ -0,0 +1,53 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ export class OllamaMessageSerializer {
3
+ serialize(messages) {
4
+ return messages.map((message) => this.serializeMessage(message));
5
+ }
6
+ serializeMessage(message) {
7
+ if (message instanceof UserMessage) {
8
+ const images = [];
9
+ let content = '';
10
+ if (Array.isArray(message.content)) {
11
+ message.content.forEach((part) => {
12
+ if (part instanceof ContentPartTextParam) {
13
+ content += part.text;
14
+ }
15
+ else if (part instanceof ContentPartImageParam) {
16
+ // Ollama expects base64 string without header
17
+ const data = part.image_url.url.split(',')[1];
18
+ if (data)
19
+ images.push(data);
20
+ }
21
+ });
22
+ }
23
+ else {
24
+ content = message.content;
25
+ }
26
+ return {
27
+ role: 'user',
28
+ content: content,
29
+ images: images.length > 0 ? images : undefined,
30
+ };
31
+ }
32
+ if (message instanceof SystemMessage) {
33
+ return {
34
+ role: 'system',
35
+ content: message.text,
36
+ };
37
+ }
38
+ if (message instanceof AssistantMessage) {
39
+ const toolCalls = message.tool_calls?.map((toolCall) => ({
40
+ function: {
41
+ name: toolCall.functionCall.name,
42
+ arguments: JSON.parse(toolCall.functionCall.arguments),
43
+ },
44
+ }));
45
+ return {
46
+ role: 'assistant',
47
+ content: message.text,
48
+ tool_calls: toolCalls,
49
+ };
50
+ }
51
+ throw new Error(`Unknown message type: ${message.constructor.name}`);
52
+ }
53
+ }
@@ -0,0 +1,38 @@
1
+ import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
2
+ import { ChatInvokeCompletion } from '../views.js';
3
+ import type { Message } from '../messages.js';
4
+ export interface ChatOpenAIOptions {
5
+ model?: string;
6
+ apiKey?: string;
7
+ organization?: string;
8
+ baseURL?: string;
9
+ temperature?: number | null;
10
+ frequencyPenalty?: number | null;
11
+ reasoningEffort?: 'low' | 'medium' | 'high';
12
+ maxCompletionTokens?: number | null;
13
+ maxRetries?: number;
14
+ seed?: number | null;
15
+ topP?: number | null;
16
+ addSchemaToSystemPrompt?: boolean;
17
+ }
18
+ export declare class ChatOpenAI implements BaseChatModel {
19
+ model: string;
20
+ provider: string;
21
+ private client;
22
+ private temperature;
23
+ private frequencyPenalty;
24
+ private reasoningEffort;
25
+ private maxCompletionTokens;
26
+ private seed;
27
+ private topP;
28
+ private addSchemaToSystemPrompt;
29
+ constructor(options?: ChatOpenAIOptions);
30
+ get name(): string;
31
+ get model_name(): string;
32
+ private isReasoningModel;
33
+ private getUsage;
34
+ ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
35
+ ainvoke<T>(messages: Message[], output_format: {
36
+ parse: (input: string) => T;
37
+ } | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
38
+ }
@@ -0,0 +1,174 @@
1
+ import OpenAI from 'openai';
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ import { ChatInvokeCompletion } from '../views.js';
4
+ import { OpenAIMessageSerializer } from './serializer.js';
5
+ import { ModelProviderError } from '../exceptions.js';
6
+ // Reasoning models that support reasoning_effort parameter
7
+ const ReasoningModels = [
8
+ 'o4-mini',
9
+ 'o3',
10
+ 'o3-mini',
11
+ 'o1',
12
+ 'o1-pro',
13
+ 'o3-pro',
14
+ 'gpt-5',
15
+ 'gpt-5-mini',
16
+ 'gpt-5-nano',
17
+ ];
18
+ export class ChatOpenAI {
19
+ model;
20
+ provider = 'openai';
21
+ client;
22
+ temperature;
23
+ frequencyPenalty;
24
+ reasoningEffort;
25
+ maxCompletionTokens;
26
+ seed;
27
+ topP;
28
+ addSchemaToSystemPrompt;
29
+ 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;
31
+ this.model = model;
32
+ this.temperature = temperature;
33
+ this.frequencyPenalty = frequencyPenalty;
34
+ this.reasoningEffort = reasoningEffort;
35
+ this.maxCompletionTokens = maxCompletionTokens;
36
+ this.seed = seed;
37
+ this.topP = topP;
38
+ this.addSchemaToSystemPrompt = addSchemaToSystemPrompt;
39
+ this.client = new OpenAI({
40
+ apiKey,
41
+ organization,
42
+ baseURL,
43
+ maxRetries,
44
+ });
45
+ }
46
+ get name() {
47
+ return this.model;
48
+ }
49
+ get model_name() {
50
+ return this.model;
51
+ }
52
+ isReasoningModel() {
53
+ return ReasoningModels.some((m) => this.model.toLowerCase().includes(m.toLowerCase()));
54
+ }
55
+ getUsage(response) {
56
+ if (!response.usage)
57
+ return null;
58
+ let completionTokens = response.usage.completion_tokens;
59
+ const details = response.usage.completion_tokens_details;
60
+ if (details?.reasoning_tokens) {
61
+ completionTokens += details.reasoning_tokens;
62
+ }
63
+ return {
64
+ prompt_tokens: response.usage.prompt_tokens,
65
+ prompt_cached_tokens: response.usage.prompt_tokens_details?.cached_tokens ?? null,
66
+ prompt_cache_creation_tokens: null,
67
+ prompt_image_tokens: null,
68
+ completion_tokens: completionTokens,
69
+ total_tokens: response.usage.total_tokens,
70
+ };
71
+ }
72
+ async ainvoke(messages, output_format, options = {}) {
73
+ const serializer = new OpenAIMessageSerializer();
74
+ const openaiMessages = serializer.serialize(messages);
75
+ // Build model parameters
76
+ const modelParams = {};
77
+ if (!this.isReasoningModel()) {
78
+ // Regular models support temperature and frequency_penalty
79
+ if (this.temperature !== null) {
80
+ modelParams.temperature = this.temperature;
81
+ }
82
+ if (this.frequencyPenalty !== null) {
83
+ modelParams.frequency_penalty = this.frequencyPenalty;
84
+ }
85
+ }
86
+ else {
87
+ // Reasoning models use reasoning_effort instead
88
+ modelParams.reasoning_effort = this.reasoningEffort;
89
+ }
90
+ if (this.maxCompletionTokens !== null) {
91
+ modelParams.max_completion_tokens = this.maxCompletionTokens;
92
+ }
93
+ if (this.seed !== null) {
94
+ modelParams.seed = this.seed;
95
+ }
96
+ if (this.topP !== null) {
97
+ modelParams.top_p = this.topP;
98
+ }
99
+ 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.
111
+ try {
112
+ const jsonSchema = zodToJsonSchema(output_format, {
113
+ name: 'Response',
114
+ target: 'jsonSchema7',
115
+ });
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
+ },
124
+ };
125
+ }
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);
129
+ }
130
+ }
131
+ try {
132
+ const response = await this.client.chat.completions.create({
133
+ model: this.model,
134
+ messages: openaiMessages,
135
+ response_format: responseFormat,
136
+ ...modelParams,
137
+ }, options.signal ? { signal: options.signal } : undefined);
138
+ const content = response.choices[0].message.content || '';
139
+ const usage = this.getUsage(response);
140
+ let completion = content;
141
+ 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);
147
+ }
148
+ 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);
154
+ }
155
+ }
156
+ catch (e) {
157
+ console.error('Failed to parse completion', e);
158
+ throw e;
159
+ }
160
+ }
161
+ return new ChatInvokeCompletion(completion, usage);
162
+ }
163
+ catch (error) {
164
+ // Handle OpenAI-specific errors
165
+ if (error?.status === 429) {
166
+ throw new ModelProviderError(error?.message ?? 'Rate limit exceeded', 429, this.model);
167
+ }
168
+ if (error?.status >= 500) {
169
+ throw new ModelProviderError(error?.message ?? 'Server error', error.status, this.model);
170
+ }
171
+ throw new ModelProviderError(error?.message ?? String(error), error?.status ?? 500, this.model);
172
+ }
173
+ }
174
+ }
@@ -0,0 +1,3 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
3
+ export * from './like.js';
@@ -0,0 +1,3 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
3
+ export * from './like.js';
@@ -0,0 +1,17 @@
1
+ import { ChatOpenAI } from './chat.js';
2
+ /**
3
+ * A class to interact with any provider using the OpenAI API schema.
4
+ *
5
+ * This allows using any OpenAI-compatible API provider by specifying a custom model name.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const llm = new ChatOpenAILike('custom-model-name');
10
+ * ```
11
+ */
12
+ export declare class ChatOpenAILike extends ChatOpenAI {
13
+ /**
14
+ * @param model - The name of the model to use (any OpenAI-compatible model)
15
+ */
16
+ constructor(model: string);
17
+ }
@@ -0,0 +1,19 @@
1
+ import { ChatOpenAI } from './chat.js';
2
+ /**
3
+ * A class to interact with any provider using the OpenAI API schema.
4
+ *
5
+ * This allows using any OpenAI-compatible API provider by specifying a custom model name.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const llm = new ChatOpenAILike('custom-model-name');
10
+ * ```
11
+ */
12
+ export class ChatOpenAILike extends ChatOpenAI {
13
+ /**
14
+ * @param model - The name of the model to use (any OpenAI-compatible model)
15
+ */
16
+ constructor(model) {
17
+ super({ model });
18
+ }
19
+ }
@@ -0,0 +1,6 @@
1
+ import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
2
+ import { type Message } from '../messages.js';
3
+ export declare class OpenAIMessageSerializer {
4
+ serialize(messages: Message[]): ChatCompletionMessageParam[];
5
+ private serializeMessage;
6
+ }
@@ -0,0 +1,57 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ export class OpenAIMessageSerializer {
3
+ serialize(messages) {
4
+ return messages.map((message) => this.serializeMessage(message));
5
+ }
6
+ serializeMessage(message) {
7
+ if (message instanceof UserMessage) {
8
+ return {
9
+ role: 'user',
10
+ content: Array.isArray(message.content)
11
+ ? message.content.map((part) => {
12
+ if (part instanceof ContentPartTextParam) {
13
+ return { type: 'text', text: part.text };
14
+ }
15
+ if (part instanceof ContentPartImageParam) {
16
+ return {
17
+ type: 'image_url',
18
+ image_url: {
19
+ url: part.image_url.url,
20
+ detail: part.image_url.detail,
21
+ },
22
+ };
23
+ }
24
+ return { type: 'text', text: '' }; // Fallback
25
+ })
26
+ : message.content,
27
+ name: message.name || undefined,
28
+ };
29
+ }
30
+ if (message instanceof SystemMessage) {
31
+ return {
32
+ role: 'system',
33
+ content: Array.isArray(message.content)
34
+ ? message.content.map((part) => part.text).join('\n')
35
+ : message.content,
36
+ name: message.name || undefined,
37
+ };
38
+ }
39
+ if (message instanceof AssistantMessage) {
40
+ const toolCalls = message.tool_calls?.map((toolCall) => ({
41
+ id: toolCall.id,
42
+ type: 'function',
43
+ function: {
44
+ name: toolCall.functionCall.name,
45
+ arguments: toolCall.functionCall.arguments,
46
+ },
47
+ }));
48
+ return {
49
+ role: 'assistant',
50
+ content: typeof message.content === 'string' ? message.content : null, // OpenAI expects string or null for content in assistant message if tool_calls are present
51
+ tool_calls: toolCalls,
52
+ refusal: message.refusal || undefined,
53
+ };
54
+ }
55
+ throw new Error(`Unknown message type: ${message.constructor.name}`);
56
+ }
57
+ }
@@ -0,0 +1,15 @@
1
+ import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
2
+ import { ChatInvokeCompletion } from '../views.js';
3
+ import type { Message } from '../messages.js';
4
+ export declare class ChatOpenRouter implements BaseChatModel {
5
+ model: string;
6
+ provider: string;
7
+ private client;
8
+ constructor(model?: string);
9
+ get name(): string;
10
+ get model_name(): string;
11
+ ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
12
+ ainvoke<T>(messages: Message[], output_format: {
13
+ parse: (input: string) => T;
14
+ } | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
15
+ }
@@ -0,0 +1,74 @@
1
+ import OpenAI from 'openai';
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ import { ChatInvokeCompletion } from '../views.js';
4
+ import { OpenRouterMessageSerializer } from './serializer.js';
5
+ export class ChatOpenRouter {
6
+ model;
7
+ provider = 'openrouter';
8
+ client;
9
+ constructor(model = 'openai/gpt-4o') {
10
+ this.model = model;
11
+ this.client = new OpenAI({
12
+ apiKey: process.env.OPENROUTER_API_KEY,
13
+ baseURL: 'https://openrouter.ai/api/v1',
14
+ });
15
+ }
16
+ get name() {
17
+ return this.model;
18
+ }
19
+ get model_name() {
20
+ return this.model;
21
+ }
22
+ async ainvoke(messages, output_format, options = {}) {
23
+ const serializer = new OpenRouterMessageSerializer();
24
+ const openRouterMessages = serializer.serialize(messages);
25
+ 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.
29
+ try {
30
+ const jsonSchema = zodToJsonSchema(output_format, {
31
+ name: 'Response',
32
+ target: 'jsonSchema7',
33
+ });
34
+ responseFormat = {
35
+ type: 'json_schema',
36
+ json_schema: {
37
+ name: 'Response',
38
+ schema: jsonSchema,
39
+ strict: true,
40
+ },
41
+ };
42
+ }
43
+ catch (e) {
44
+ console.warn('Failed to convert output_format to JSON schema for OpenRouter', e);
45
+ }
46
+ }
47
+ const response = await this.client.chat.completions.create({
48
+ model: this.model,
49
+ messages: openRouterMessages,
50
+ 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));
58
+ }
59
+ else {
60
+ completion = output_format.parse(content);
61
+ }
62
+ }
63
+ catch (e) {
64
+ console.error('Failed to parse completion', e);
65
+ throw e;
66
+ }
67
+ }
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
+ }
74
+ }
@@ -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,3 @@
1
+ import { OpenAIMessageSerializer } from '../openai/serializer.js';
2
+ export declare class OpenRouterMessageSerializer extends OpenAIMessageSerializer {
3
+ }
@@ -0,0 +1,3 @@
1
+ import { OpenAIMessageSerializer } from '../openai/serializer.js';
2
+ export class OpenRouterMessageSerializer extends OpenAIMessageSerializer {
3
+ }
@@ -0,0 +1,6 @@
1
+ type JsonSchema = Record<string, unknown>;
2
+ export declare class SchemaOptimizer {
3
+ static createOptimizedJsonSchema(schema: JsonSchema): JsonSchema;
4
+ static makeStrictCompatible(schema: any): void;
5
+ }
6
+ export {};
@@ -0,0 +1,77 @@
1
+ export class SchemaOptimizer {
2
+ static createOptimizedJsonSchema(schema) {
3
+ const defsLookup = schema.$defs ?? {};
4
+ const optimize = (obj, inProperties = false) => {
5
+ if (Array.isArray(obj)) {
6
+ return obj.map((item) => optimize(item, inProperties));
7
+ }
8
+ if (obj && typeof obj === 'object') {
9
+ let flattenedRef = null;
10
+ const optimized = {};
11
+ for (const [key, value] of Object.entries(obj)) {
12
+ if (key === '$defs' || key === 'additionalProperties')
13
+ continue;
14
+ if (key === 'title' && !inProperties)
15
+ continue;
16
+ if (key === '$ref' && typeof value === 'string') {
17
+ const refName = value.split('/').pop();
18
+ if (defsLookup[refName]) {
19
+ flattenedRef = optimize(defsLookup[refName], inProperties);
20
+ }
21
+ continue;
22
+ }
23
+ if (key === 'properties') {
24
+ optimized[key] = optimize(value, true);
25
+ continue;
26
+ }
27
+ if (typeof value === 'object' && value !== null) {
28
+ optimized[key] = optimize(value, inProperties);
29
+ continue;
30
+ }
31
+ optimized[key] = value;
32
+ }
33
+ const result = flattenedRef
34
+ ? { ...flattenedRef, ...optimized }
35
+ : optimized;
36
+ if (result.type === 'object' &&
37
+ result.additionalProperties === undefined) {
38
+ result.additionalProperties = false;
39
+ }
40
+ return result;
41
+ }
42
+ return obj;
43
+ };
44
+ const optimizedSchema = optimize(schema);
45
+ const ensureAdditionalProperties = (obj) => {
46
+ if (Array.isArray(obj)) {
47
+ obj.forEach(ensureAdditionalProperties);
48
+ return;
49
+ }
50
+ if (obj && typeof obj === 'object') {
51
+ if (obj.type === 'object' && obj.additionalProperties === undefined) {
52
+ obj.additionalProperties = false;
53
+ }
54
+ Object.values(obj).forEach(ensureAdditionalProperties);
55
+ }
56
+ };
57
+ ensureAdditionalProperties(optimizedSchema);
58
+ SchemaOptimizer.makeStrictCompatible(optimizedSchema);
59
+ return optimizedSchema;
60
+ }
61
+ static makeStrictCompatible(schema) {
62
+ if (Array.isArray(schema)) {
63
+ schema.forEach(SchemaOptimizer.makeStrictCompatible);
64
+ return;
65
+ }
66
+ if (schema && typeof schema === 'object') {
67
+ for (const [key, value] of Object.entries(schema)) {
68
+ if (key !== 'required' && value && typeof value === 'object') {
69
+ SchemaOptimizer.makeStrictCompatible(value);
70
+ }
71
+ }
72
+ if (schema.type === 'object' && schema.properties) {
73
+ schema.required = Object.keys(schema.properties);
74
+ }
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,15 @@
1
+ export interface ChatInvokeUsage {
2
+ prompt_tokens: number;
3
+ prompt_cached_tokens?: number | null;
4
+ prompt_cache_creation_tokens?: number | null;
5
+ prompt_image_tokens?: number | null;
6
+ completion_tokens: number;
7
+ total_tokens: number;
8
+ }
9
+ export declare class ChatInvokeCompletion<T = string> {
10
+ completion: T;
11
+ usage: ChatInvokeUsage | null;
12
+ thinking: string | null;
13
+ redacted_thinking: string | null;
14
+ constructor(completion: T, usage?: ChatInvokeUsage | null, thinking?: string | null, redacted_thinking?: string | null);
15
+ }
@@ -0,0 +1,12 @@
1
+ export class ChatInvokeCompletion {
2
+ completion;
3
+ usage;
4
+ thinking;
5
+ redacted_thinking;
6
+ constructor(completion, usage = null, thinking = null, redacted_thinking = null) {
7
+ this.completion = completion;
8
+ this.usage = usage;
9
+ this.thinking = thinking;
10
+ this.redacted_thinking = redacted_thinking;
11
+ }
12
+ }
@@ -0,0 +1,25 @@
1
+ import { Writable } from 'node:stream';
2
+ export type LogLevel = 'debug' | 'info' | 'result' | 'warning' | 'error';
3
+ interface SetupLoggingOptions {
4
+ stream?: Writable;
5
+ logLevel?: LogLevel;
6
+ forceSetup?: boolean;
7
+ }
8
+ export declare class Logger {
9
+ private readonly name;
10
+ constructor(name: string);
11
+ private shouldLog;
12
+ get level(): LogLevel;
13
+ private emit;
14
+ debug(message: string, ...args: unknown[]): void;
15
+ info(message: string, ...args: unknown[]): void;
16
+ result(message: string, ...args: unknown[]): void;
17
+ warning(message: string, ...args: unknown[]): void;
18
+ warn(message: string, ...args: unknown[]): void;
19
+ error(message: string, ...args: unknown[]): void;
20
+ child(suffix: string): Logger;
21
+ }
22
+ export declare const createLogger: (name: string) => Logger;
23
+ export declare const setupLogging: (options?: SetupLoggingOptions) => Logger;
24
+ export declare const logger: Logger;
25
+ export {};