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,68 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ // AWS Bedrock types are a bit complex and vary by model.
3
+ // We will define a generic structure that fits most Bedrock models (like Claude on Bedrock).
4
+ export class AWSBedrockMessageSerializer {
5
+ serialize(messages) {
6
+ return messages
7
+ .filter((msg) => !(msg instanceof SystemMessage)) // System messages are handled separately usually
8
+ .map((message) => this.serializeMessage(message));
9
+ }
10
+ serializeMessage(message) {
11
+ if (message instanceof UserMessage) {
12
+ return {
13
+ role: 'user',
14
+ content: Array.isArray(message.content)
15
+ ? message.content.map((part) => {
16
+ if (part instanceof ContentPartTextParam) {
17
+ return { text: part.text };
18
+ }
19
+ if (part instanceof ContentPartImageParam) {
20
+ const mediaType = part.image_url.media_type;
21
+ const data = part.image_url.url.split(',')[1];
22
+ return {
23
+ image: {
24
+ format: mediaType.split('/')[1], // e.g. 'png' from 'image/png'
25
+ source: {
26
+ bytes: Buffer.from(data, 'base64'),
27
+ },
28
+ },
29
+ };
30
+ }
31
+ return { text: '' };
32
+ })
33
+ : [{ text: message.content }],
34
+ };
35
+ }
36
+ if (message instanceof AssistantMessage) {
37
+ const content = [];
38
+ if (message.content) {
39
+ if (typeof message.content === 'string') {
40
+ content.push({ text: message.content });
41
+ }
42
+ else if (Array.isArray(message.content)) {
43
+ message.content.forEach((part) => {
44
+ if (part instanceof ContentPartTextParam) {
45
+ content.push({ text: part.text });
46
+ }
47
+ });
48
+ }
49
+ }
50
+ if (message.tool_calls) {
51
+ message.tool_calls.forEach((toolCall) => {
52
+ content.push({
53
+ toolUse: {
54
+ toolUseId: toolCall.id,
55
+ name: toolCall.functionCall.name,
56
+ input: JSON.parse(toolCall.functionCall.arguments),
57
+ },
58
+ });
59
+ });
60
+ }
61
+ return {
62
+ role: 'assistant',
63
+ content: content,
64
+ };
65
+ }
66
+ throw new Error(`Unknown message type: ${message.constructor.name}`);
67
+ }
68
+ }
@@ -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 ChatAzure 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,83 @@
1
+ import { AzureOpenAI } from 'openai';
2
+ import { ChatInvokeCompletion } from '../views.js';
3
+ import { OpenAIMessageSerializer } from '../openai/serializer.js';
4
+ export class ChatAzure {
5
+ model;
6
+ provider = 'azure';
7
+ client;
8
+ constructor(model = 'gpt-4o') {
9
+ this.model = model;
10
+ this.client = new AzureOpenAI({
11
+ apiKey: process.env.AZURE_OPENAI_API_KEY,
12
+ endpoint: process.env.AZURE_OPENAI_ENDPOINT,
13
+ apiVersion: process.env.AZURE_OPENAI_API_VERSION || '2024-05-01-preview',
14
+ deployment: model,
15
+ });
16
+ }
17
+ get name() {
18
+ return this.model;
19
+ }
20
+ get model_name() {
21
+ return this.model;
22
+ }
23
+ async ainvoke(messages, output_format, options = {}) {
24
+ const serializer = new OpenAIMessageSerializer();
25
+ const openaiMessages = serializer.serialize(messages);
26
+ // Use simple json_object format for better compatibility with Azure
27
+ // json_schema format may not be supported on all Azure API versions/deployments
28
+ const responseFormat = output_format
29
+ ? { type: 'json_object' }
30
+ : undefined;
31
+ const response = await this.client.chat.completions.create({
32
+ model: this.model,
33
+ messages: openaiMessages,
34
+ response_format: responseFormat,
35
+ }, options.signal ? { signal: options.signal } : undefined);
36
+ const content = response.choices[0].message.content || '';
37
+ let completion = content;
38
+ if (output_format) {
39
+ try {
40
+ // Extract JSON from the response
41
+ let jsonText = content.trim();
42
+ // Handle markdown fenced code blocks
43
+ const fencedMatch = jsonText.match(/```(?:json)?\s*([\s\S]*?)```/);
44
+ if (fencedMatch && fencedMatch[1]) {
45
+ jsonText = fencedMatch[1].trim();
46
+ }
47
+ // Extract JSON object/array from the text
48
+ const firstBrace = jsonText.indexOf('{');
49
+ const firstBracket = jsonText.indexOf('[');
50
+ const lastBrace = jsonText.lastIndexOf('}');
51
+ const lastBracket = jsonText.lastIndexOf(']');
52
+ // Determine if it's an object or array
53
+ let startIdx = -1;
54
+ let endIdx = -1;
55
+ if (firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket)) {
56
+ // It's an object
57
+ startIdx = firstBrace;
58
+ endIdx = lastBrace;
59
+ }
60
+ else if (firstBracket !== -1) {
61
+ // It's an array
62
+ startIdx = firstBracket;
63
+ endIdx = lastBracket;
64
+ }
65
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
66
+ jsonText = jsonText.slice(startIdx, endIdx + 1);
67
+ }
68
+ const parsedJson = JSON.parse(jsonText);
69
+ completion = output_format.parse(parsedJson);
70
+ }
71
+ catch (e) {
72
+ console.error('Failed to parse Azure completion:', e);
73
+ console.error('Raw content:', content.substring(0, 500));
74
+ throw new Error(`Failed to parse LLM completion as JSON: ${e}`);
75
+ }
76
+ }
77
+ return new ChatInvokeCompletion(completion, {
78
+ prompt_tokens: response.usage?.prompt_tokens ?? 0,
79
+ completion_tokens: response.usage?.completion_tokens ?? 0,
80
+ total_tokens: response.usage?.total_tokens ?? 0,
81
+ });
82
+ }
83
+ }
@@ -0,0 +1 @@
1
+ export * from './chat.js';
@@ -0,0 +1 @@
1
+ export * from './chat.js';
@@ -0,0 +1,16 @@
1
+ import type { ChatInvokeCompletion } from './views.js';
2
+ import type { Message } from './messages.js';
3
+ export interface ChatInvokeOptions {
4
+ signal?: AbortSignal;
5
+ }
6
+ export interface BaseChatModel {
7
+ model: string;
8
+ _verified_api_keys?: boolean;
9
+ get provider(): string;
10
+ get name(): string;
11
+ get model_name(): string;
12
+ ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
13
+ ainvoke<T>(messages: Message[], output_format: {
14
+ parse: (input: string) => T;
15
+ } | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -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 ChatDeepSeek 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,51 @@
1
+ import OpenAI from 'openai';
2
+ import { ChatInvokeCompletion } from '../views.js';
3
+ import { DeepSeekMessageSerializer } from './serializer.js';
4
+ export class ChatDeepSeek {
5
+ model;
6
+ provider = 'deepseek';
7
+ client;
8
+ constructor(model = 'deepseek-chat') {
9
+ this.model = model;
10
+ this.client = new OpenAI({
11
+ apiKey: process.env.DEEPSEEK_API_KEY,
12
+ baseURL: 'https://api.deepseek.com',
13
+ });
14
+ }
15
+ get name() {
16
+ return this.model;
17
+ }
18
+ get model_name() {
19
+ return this.model;
20
+ }
21
+ async ainvoke(messages, output_format, options = {}) {
22
+ const serializer = new DeepSeekMessageSerializer();
23
+ const deepseekMessages = serializer.serialize(messages);
24
+ let responseFormat = undefined;
25
+ if (output_format && 'schema' in output_format && output_format.schema) {
26
+ // DeepSeek supports json_object
27
+ responseFormat = { type: 'json_object' };
28
+ }
29
+ const response = await this.client.chat.completions.create({
30
+ model: this.model,
31
+ messages: deepseekMessages,
32
+ response_format: responseFormat,
33
+ }, options.signal ? { signal: options.signal } : undefined);
34
+ const content = response.choices[0].message.content || '';
35
+ let completion = content;
36
+ if (output_format) {
37
+ try {
38
+ completion = output_format.parse(JSON.parse(content));
39
+ }
40
+ catch (e) {
41
+ console.error('Failed to parse completion', e);
42
+ throw e;
43
+ }
44
+ }
45
+ return new ChatInvokeCompletion(completion, {
46
+ prompt_tokens: response.usage?.prompt_tokens ?? 0,
47
+ completion_tokens: response.usage?.completion_tokens ?? 0,
48
+ total_tokens: response.usage?.total_tokens ?? 0,
49
+ });
50
+ }
51
+ }
@@ -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,6 @@
1
+ import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
2
+ import { type Message } from '../messages.js';
3
+ export declare class DeepSeekMessageSerializer {
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 DeepSeekMessageSerializer {
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
+ // DeepSeek might not support images in all models, but we'll include it for now
16
+ if (part instanceof ContentPartImageParam) {
17
+ return {
18
+ type: 'image_url',
19
+ image_url: {
20
+ url: part.image_url.url,
21
+ detail: part.image_url.detail,
22
+ },
23
+ };
24
+ }
25
+ return { type: 'text', text: '' };
26
+ })
27
+ : message.content,
28
+ name: message.name || undefined,
29
+ };
30
+ }
31
+ if (message instanceof SystemMessage) {
32
+ return {
33
+ role: 'system',
34
+ content: Array.isArray(message.content)
35
+ ? message.content.map((part) => part.text).join('\n')
36
+ : message.content,
37
+ name: message.name || undefined,
38
+ };
39
+ }
40
+ if (message instanceof AssistantMessage) {
41
+ return {
42
+ role: 'assistant',
43
+ content: typeof message.content === 'string' ? message.content : null,
44
+ // DeepSeek supports tool calls in newer models
45
+ tool_calls: message.tool_calls?.map((toolCall) => ({
46
+ id: toolCall.id,
47
+ type: 'function',
48
+ function: {
49
+ name: toolCall.functionCall.name,
50
+ arguments: toolCall.functionCall.arguments,
51
+ },
52
+ })),
53
+ };
54
+ }
55
+ throw new Error(`Unknown message type: ${message.constructor.name}`);
56
+ }
57
+ }
@@ -0,0 +1,10 @@
1
+ export declare class ModelError extends Error {
2
+ }
3
+ export declare class ModelProviderError extends ModelError {
4
+ statusCode: number;
5
+ model: string | null;
6
+ constructor(message: string, statusCode?: number, model?: string | null);
7
+ }
8
+ export declare class ModelRateLimitError extends ModelProviderError {
9
+ constructor(message: string, statusCode?: number, model?: string | null);
10
+ }
@@ -0,0 +1,18 @@
1
+ export class ModelError extends Error {
2
+ }
3
+ export class ModelProviderError extends ModelError {
4
+ statusCode;
5
+ model;
6
+ constructor(message, statusCode = 502, model = null) {
7
+ super(message);
8
+ this.statusCode = statusCode;
9
+ this.model = model;
10
+ this.name = 'ModelProviderError';
11
+ }
12
+ }
13
+ export class ModelRateLimitError extends ModelProviderError {
14
+ constructor(message, statusCode = 429, model = null) {
15
+ super(message, statusCode, model);
16
+ this.name = 'ModelRateLimitError';
17
+ }
18
+ }
@@ -0,0 +1,20 @@
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 ChatGoogle 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
+ /**
12
+ * Clean up JSON schema for Google's format
13
+ * Google API has specific requirements for responseSchema
14
+ */
15
+ private _cleanSchemaForGoogle;
16
+ ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
17
+ ainvoke<T>(messages: Message[], output_format: {
18
+ parse: (input: string) => T;
19
+ } | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
20
+ }
@@ -0,0 +1,144 @@
1
+ import { GoogleGenAI, } from '@google/genai';
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ import { ChatInvokeCompletion } from '../views.js';
4
+ import { SystemMessage } from '../messages.js';
5
+ import { GoogleMessageSerializer } from './serializer.js';
6
+ export class ChatGoogle {
7
+ model;
8
+ provider = 'google';
9
+ client;
10
+ constructor(model = 'gemini-2.5-flash') {
11
+ this.model = model;
12
+ const apiVersion = process.env.GOOGLE_API_VERSION || 'v1';
13
+ const baseUrl = process.env.GOOGLE_API_BASE_URL;
14
+ this.client = new GoogleGenAI({
15
+ apiKey: process.env.GOOGLE_API_KEY || '',
16
+ ...(baseUrl ? { baseUrl } : {}),
17
+ ...(apiVersion ? { apiVersion } : {}),
18
+ });
19
+ }
20
+ get name() {
21
+ return this.model;
22
+ }
23
+ get model_name() {
24
+ return this.model;
25
+ }
26
+ /**
27
+ * Clean up JSON schema for Google's format
28
+ * Google API has specific requirements for responseSchema
29
+ */
30
+ _cleanSchemaForGoogle(schema) {
31
+ if (!schema || typeof schema !== 'object') {
32
+ return schema;
33
+ }
34
+ const cleaned = {};
35
+ for (const [key, value] of Object.entries(schema)) {
36
+ // Skip unsupported keys
37
+ if (key === '$schema' ||
38
+ key === 'additionalProperties' ||
39
+ key === '$ref' ||
40
+ key === 'definitions') {
41
+ continue;
42
+ }
43
+ if (key === 'properties' && typeof value === 'object') {
44
+ cleaned.properties = {};
45
+ for (const [propKey, propValue] of Object.entries(value)) {
46
+ cleaned.properties[propKey] = this._cleanSchemaForGoogle(propValue);
47
+ }
48
+ }
49
+ else if (key === 'items' && typeof value === 'object') {
50
+ cleaned.items = this._cleanSchemaForGoogle(value);
51
+ }
52
+ else if (typeof value === 'object' && !Array.isArray(value)) {
53
+ cleaned[key] = this._cleanSchemaForGoogle(value);
54
+ }
55
+ else {
56
+ cleaned[key] = value;
57
+ }
58
+ }
59
+ return cleaned;
60
+ }
61
+ async ainvoke(messages, output_format, options = {}) {
62
+ const serializer = new GoogleMessageSerializer();
63
+ const contents = serializer.serialize(messages);
64
+ const systemMessage = messages.find((msg) => msg instanceof SystemMessage);
65
+ const systemInstruction = systemMessage ? systemMessage.text : undefined;
66
+ let tools = undefined;
67
+ let toolConfig = undefined;
68
+ // For Google, we need to be more explicit about JSON output
69
+ // The generationConfig with responseSchema helps enforce JSON structure
70
+ const generationConfig = {
71
+ responseMimeType: 'application/json',
72
+ };
73
+ // Try to get schema from output_format
74
+ const schemaForJson = output_format && 'schema' in output_format && output_format.schema
75
+ ? output_format.schema
76
+ : null;
77
+ if (schemaForJson) {
78
+ try {
79
+ const jsonSchema = zodToJsonSchema(schemaForJson);
80
+ // Clean up the schema for Google's format
81
+ const cleanSchema = this._cleanSchemaForGoogle(jsonSchema);
82
+ generationConfig.responseSchema = cleanSchema;
83
+ }
84
+ catch (e) {
85
+ console.warn('Failed to set responseSchema', e);
86
+ }
87
+ }
88
+ const request = {
89
+ model: this.model,
90
+ contents,
91
+ };
92
+ if (systemInstruction) {
93
+ request.systemInstruction = {
94
+ role: 'system',
95
+ parts: [{ text: systemInstruction }],
96
+ };
97
+ }
98
+ if (Object.keys(generationConfig).length > 0) {
99
+ request.generationConfig = generationConfig;
100
+ }
101
+ const result = await this.client.models.generateContent(request, options.signal ? { signal: options.signal } : undefined);
102
+ // Extract text from first candidate
103
+ const candidate = result.candidates?.[0];
104
+ const textParts = candidate?.content?.parts?.filter((p) => p.text) || [];
105
+ const text = textParts.map((p) => p.text).join('');
106
+ let completion = text;
107
+ if (output_format) {
108
+ try {
109
+ let parsed = text;
110
+ if (generationConfig.responseMimeType === 'application/json') {
111
+ let jsonText = text.trim();
112
+ // Handle markdown code fences like ```json ... ```
113
+ const fencedMatch = jsonText.match(/```(?:json)?\s*([\s\S]*?)```/i);
114
+ if (fencedMatch && fencedMatch[1]) {
115
+ jsonText = fencedMatch[1].trim();
116
+ }
117
+ // Try to extract JSON object from text
118
+ const firstBrace = jsonText.indexOf('{');
119
+ const lastBrace = jsonText.lastIndexOf('}');
120
+ if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
121
+ jsonText = jsonText.slice(firstBrace, lastBrace + 1);
122
+ }
123
+ else {
124
+ // If no JSON object found, the model returned plain text
125
+ // Try to wrap it in a minimal valid structure
126
+ console.warn('Google LLM returned plain text instead of JSON. Raw response:', text.slice(0, 200));
127
+ throw new Error(`Expected JSON response but got plain text: "${text.slice(0, 50)}..."`);
128
+ }
129
+ parsed = JSON.parse(jsonText);
130
+ }
131
+ completion = output_format.parse(parsed);
132
+ }
133
+ catch (e) {
134
+ console.error('Failed to parse completion', e);
135
+ throw e;
136
+ }
137
+ }
138
+ return new ChatInvokeCompletion(completion, {
139
+ prompt_tokens: result.usageMetadata?.promptTokenCount ?? 0,
140
+ completion_tokens: result.usageMetadata?.candidatesTokenCount ?? 0,
141
+ total_tokens: result.usageMetadata?.totalTokenCount ?? 0,
142
+ });
143
+ }
144
+ }
@@ -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,6 @@
1
+ import type { Content } from '@google/genai';
2
+ import { type Message } from '../messages.js';
3
+ export declare class GoogleMessageSerializer {
4
+ serialize(messages: Message[]): Content[];
5
+ private serializeMessage;
6
+ }
@@ -0,0 +1,64 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ export class GoogleMessageSerializer {
3
+ serialize(messages) {
4
+ return messages
5
+ .filter((msg) => !(msg instanceof SystemMessage)) // System instructions are passed separately
6
+ .map((message) => this.serializeMessage(message));
7
+ }
8
+ serializeMessage(message) {
9
+ if (message instanceof UserMessage) {
10
+ return {
11
+ role: 'user',
12
+ parts: Array.isArray(message.content)
13
+ ? message.content.map((part) => {
14
+ if (part instanceof ContentPartTextParam) {
15
+ return { text: part.text };
16
+ }
17
+ if (part instanceof ContentPartImageParam) {
18
+ // Google GenAI expects inlineData for images usually
19
+ const data = part.image_url.url.split(',')[1];
20
+ const mimeType = part.image_url.media_type;
21
+ return {
22
+ inlineData: {
23
+ mimeType: mimeType,
24
+ data: data,
25
+ },
26
+ };
27
+ }
28
+ return { text: '' };
29
+ })
30
+ : [{ text: message.content }],
31
+ };
32
+ }
33
+ if (message instanceof AssistantMessage) {
34
+ const parts = [];
35
+ if (message.content) {
36
+ if (typeof message.content === 'string') {
37
+ parts.push({ text: message.content });
38
+ }
39
+ else if (Array.isArray(message.content)) {
40
+ message.content.forEach((part) => {
41
+ if (part instanceof ContentPartTextParam) {
42
+ parts.push({ text: part.text });
43
+ }
44
+ });
45
+ }
46
+ }
47
+ if (message.tool_calls) {
48
+ message.tool_calls.forEach((toolCall) => {
49
+ parts.push({
50
+ functionCall: {
51
+ name: toolCall.functionCall.name,
52
+ args: JSON.parse(toolCall.functionCall.arguments),
53
+ },
54
+ });
55
+ });
56
+ }
57
+ return {
58
+ role: 'model',
59
+ parts: parts,
60
+ };
61
+ }
62
+ throw new Error(`Unknown message type: ${message.constructor.name}`);
63
+ }
64
+ }
@@ -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 ChatGroq 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
+ }