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,52 @@
1
+ import Groq from 'groq-sdk';
2
+ import { ChatInvokeCompletion } from '../views.js';
3
+ import { GroqMessageSerializer } from './serializer.js';
4
+ export class ChatGroq {
5
+ model;
6
+ provider = 'groq';
7
+ client;
8
+ constructor(model = 'llama-3.1-70b-versatile') {
9
+ this.model = model;
10
+ this.client = new Groq({
11
+ apiKey: process.env.GROQ_API_KEY,
12
+ });
13
+ }
14
+ get name() {
15
+ return this.model;
16
+ }
17
+ get model_name() {
18
+ return this.model;
19
+ }
20
+ async ainvoke(messages, output_format, options = {}) {
21
+ const serializer = new GroqMessageSerializer();
22
+ const groqMessages = serializer.serialize(messages);
23
+ let responseFormat = undefined;
24
+ if (output_format && 'schema' in output_format && output_format.schema) {
25
+ // Groq supports JSON mode, but not full JSON schema validation in the same way as OpenAI yet (or maybe it does now).
26
+ // For now, we'll enforce JSON mode and prompt engineering or use tools if needed.
27
+ // But let's try to use json_object which is supported.
28
+ responseFormat = { type: 'json_object' };
29
+ }
30
+ const response = await this.client.chat.completions.create({
31
+ model: this.model,
32
+ messages: groqMessages,
33
+ response_format: responseFormat,
34
+ }, options.signal ? { signal: options.signal } : undefined);
35
+ const content = response.choices[0].message.content || '';
36
+ let completion = content;
37
+ if (output_format) {
38
+ try {
39
+ completion = output_format.parse(JSON.parse(content));
40
+ }
41
+ catch (e) {
42
+ console.error('Failed to parse completion', e);
43
+ throw e;
44
+ }
45
+ }
46
+ return new ChatInvokeCompletion(completion, {
47
+ prompt_tokens: response.usage?.prompt_tokens ?? 0,
48
+ completion_tokens: response.usage?.completion_tokens ?? 0,
49
+ total_tokens: response.usage?.total_tokens ?? 0,
50
+ });
51
+ }
52
+ }
@@ -0,0 +1,3 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
3
+ export * from './parser.js';
@@ -0,0 +1,3 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
3
+ export * from './parser.js';
@@ -0,0 +1,32 @@
1
+ import type { APIError } from 'groq-sdk';
2
+ export declare class ParseFailedGenerationError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Extract JSON from model output, handling both plain JSON and code-block-wrapped JSON.
7
+ * This is used to parse Groq's failed_generation field when an API error occurs.
8
+ *
9
+ * @param error - The Groq API error containing failed_generation
10
+ * @param outputFormat - An object with a parse method (typically a Zod schema)
11
+ * @returns The parsed output in the expected format
12
+ * @throws ParseFailedGenerationError if the failed_generation field is missing
13
+ * @throws Error if JSON parsing fails
14
+ */
15
+ export declare function tryParseGroqFailedGeneration<T>(error: APIError & {
16
+ body?: {
17
+ error?: {
18
+ failed_generation?: string;
19
+ };
20
+ };
21
+ }, outputFormat: {
22
+ parse: (input: string) => T;
23
+ }): T;
24
+ /**
25
+ * Fix control characters in JSON string values to make them valid JSON.
26
+ * This function escapes literal control characters (newlines, tabs, etc.) that
27
+ * appear inside JSON string values, while preserving the JSON structure.
28
+ *
29
+ * @param content - The JSON string to fix
30
+ * @returns The fixed JSON string
31
+ */
32
+ export declare function fixControlCharactersInJson(content: string): string;
@@ -0,0 +1,189 @@
1
+ import { logger } from '../../logging-config.js';
2
+ export class ParseFailedGenerationError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'ParseFailedGenerationError';
6
+ }
7
+ }
8
+ /**
9
+ * Extract JSON from model output, handling both plain JSON and code-block-wrapped JSON.
10
+ * This is used to parse Groq's failed_generation field when an API error occurs.
11
+ *
12
+ * @param error - The Groq API error containing failed_generation
13
+ * @param outputFormat - An object with a parse method (typically a Zod schema)
14
+ * @returns The parsed output in the expected format
15
+ * @throws ParseFailedGenerationError if the failed_generation field is missing
16
+ * @throws Error if JSON parsing fails
17
+ */
18
+ export function tryParseGroqFailedGeneration(error, outputFormat) {
19
+ try {
20
+ const failedGeneration = error.body?.error?.failed_generation;
21
+ if (!failedGeneration) {
22
+ throw new Error('No failed_generation field in error body');
23
+ }
24
+ let content = failedGeneration;
25
+ // If content is wrapped in code blocks, extract just the JSON part
26
+ if (content.includes('```')) {
27
+ // Find the JSON content between code blocks
28
+ const parts = content.split('```');
29
+ content = parts[1] || content;
30
+ // Remove language identifier if present (e.g., 'json\n')
31
+ if (content.includes('\n')) {
32
+ const [first, ...rest] = content.split('\n');
33
+ // Check if first line is just a language identifier
34
+ if (first.trim().length < 20) {
35
+ content = rest.join('\n');
36
+ }
37
+ }
38
+ }
39
+ // Remove html-like tags before the first { and after the last }
40
+ // This handles cases like <|header_start|>assistant<|header_end|> and <function=AgentOutput>
41
+ // Only remove content before { if content doesn't already start with {
42
+ if (!content.trim().startsWith('{')) {
43
+ content = content.replace(/^.*?(?=\{)/s, '');
44
+ }
45
+ // Remove common HTML-like tags and patterns at the end, but be more conservative
46
+ // Look for patterns like </function>, <|header_start|>, etc. after the JSON
47
+ content = content.replace(/\}(\s*<[^>]*>.*?$)/s, '}');
48
+ content = content.replace(/\}(\s*<\|[^|]*\|>.*?$)/s, '}');
49
+ // Handle extra characters after the JSON, including stray braces
50
+ // Find the position of the last } that would close the main JSON object
51
+ content = content.trim();
52
+ if (content.endsWith('}')) {
53
+ // Try to parse and see if we get valid JSON
54
+ try {
55
+ JSON.parse(content);
56
+ }
57
+ catch {
58
+ // If parsing fails, try to find the correct end of the JSON
59
+ // by counting braces and removing anything after the balanced JSON
60
+ let braceCount = 0;
61
+ let lastValidPos = -1;
62
+ for (let i = 0; i < content.length; i++) {
63
+ const char = content[i];
64
+ if (char === '{') {
65
+ braceCount++;
66
+ }
67
+ else if (char === '}') {
68
+ braceCount--;
69
+ if (braceCount === 0) {
70
+ lastValidPos = i + 1;
71
+ break;
72
+ }
73
+ }
74
+ }
75
+ if (lastValidPos > 0) {
76
+ content = content.substring(0, lastValidPos);
77
+ }
78
+ }
79
+ }
80
+ // Fix control characters in JSON strings before parsing
81
+ // This handles cases where literal control characters appear in JSON values
82
+ content = fixControlCharactersInJson(content);
83
+ // Parse the cleaned content
84
+ let resultDict = JSON.parse(content);
85
+ // Some models occasionally respond with a list containing one dict
86
+ if (Array.isArray(resultDict) &&
87
+ resultDict.length === 1 &&
88
+ typeof resultDict[0] === 'object') {
89
+ resultDict = resultDict[0];
90
+ }
91
+ logger.debug(`Successfully parsed model output: ${JSON.stringify(resultDict)}`);
92
+ return outputFormat.parse(JSON.stringify(resultDict));
93
+ }
94
+ catch (err) {
95
+ if (err instanceof Error &&
96
+ err.message.includes('No failed_generation field')) {
97
+ throw new ParseFailedGenerationError(err.message);
98
+ }
99
+ if (err instanceof SyntaxError) {
100
+ logger.warning(`Failed to parse model output: ${err.message}`);
101
+ throw new Error(`Could not parse response. ${err.message}`);
102
+ }
103
+ const errorMessage = error.message || String(error);
104
+ throw new ParseFailedGenerationError(errorMessage);
105
+ }
106
+ }
107
+ /**
108
+ * Fix control characters in JSON string values to make them valid JSON.
109
+ * This function escapes literal control characters (newlines, tabs, etc.) that
110
+ * appear inside JSON string values, while preserving the JSON structure.
111
+ *
112
+ * @param content - The JSON string to fix
113
+ * @returns The fixed JSON string
114
+ */
115
+ export function fixControlCharactersInJson(content) {
116
+ try {
117
+ // First try to parse as-is to see if it's already valid
118
+ JSON.parse(content);
119
+ return content;
120
+ }
121
+ catch {
122
+ // Continue to fix the content
123
+ }
124
+ // More sophisticated approach: only escape control characters inside string values
125
+ // while preserving JSON structure formatting
126
+ const result = [];
127
+ let i = 0;
128
+ let inString = false;
129
+ let escaped = false;
130
+ while (i < content.length) {
131
+ const char = content[i];
132
+ if (!inString) {
133
+ // Outside of string - check if we're entering a string
134
+ if (char === '"') {
135
+ inString = true;
136
+ }
137
+ result.push(char);
138
+ }
139
+ else {
140
+ // Inside string - handle escaping and control characters
141
+ if (escaped) {
142
+ // Previous character was backslash, so this character is escaped
143
+ result.push(char);
144
+ escaped = false;
145
+ }
146
+ else if (char === '\\') {
147
+ // This is an escape character
148
+ result.push(char);
149
+ escaped = true;
150
+ }
151
+ else if (char === '"') {
152
+ // End of string
153
+ result.push(char);
154
+ inString = false;
155
+ }
156
+ else if (char === '\n') {
157
+ // Literal newline inside string - escape it
158
+ result.push('\\n');
159
+ }
160
+ else if (char === '\r') {
161
+ // Literal carriage return inside string - escape it
162
+ result.push('\\r');
163
+ }
164
+ else if (char === '\t') {
165
+ // Literal tab inside string - escape it
166
+ result.push('\\t');
167
+ }
168
+ else if (char === '\b') {
169
+ // Literal backspace inside string - escape it
170
+ result.push('\\b');
171
+ }
172
+ else if (char === '\f') {
173
+ // Literal form feed inside string - escape it
174
+ result.push('\\f');
175
+ }
176
+ else if (char.charCodeAt(0) < 32) {
177
+ // Other control characters inside string - convert to unicode escape
178
+ const code = char.charCodeAt(0);
179
+ result.push(`\\u${code.toString(16).padStart(4, '0')}`);
180
+ }
181
+ else {
182
+ // Normal character inside string
183
+ result.push(char);
184
+ }
185
+ }
186
+ i++;
187
+ }
188
+ return result.join('');
189
+ }
@@ -0,0 +1,6 @@
1
+ import type { ChatCompletionMessageParam } from 'groq-sdk/resources/chat/completions.mjs';
2
+ import { type Message } from '../messages.js';
3
+ export declare class GroqMessageSerializer {
4
+ serialize(messages: Message[]): ChatCompletionMessageParam[];
5
+ private serializeMessage;
6
+ }
@@ -0,0 +1,56 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ export class GroqMessageSerializer {
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: '' };
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,
51
+ tool_calls: toolCalls,
52
+ };
53
+ }
54
+ throw new Error(`Unknown message type: ${message.constructor.name}`);
55
+ }
56
+ }
@@ -0,0 +1,77 @@
1
+ export type SupportedImageMediaType = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp';
2
+ export declare class ContentPartTextParam {
3
+ text: string;
4
+ type: 'text';
5
+ constructor(text: string);
6
+ toString(): string;
7
+ }
8
+ export declare class ContentPartRefusalParam {
9
+ refusal: string;
10
+ type: 'refusal';
11
+ constructor(refusal: string);
12
+ toString(): string;
13
+ }
14
+ export declare class ImageURL {
15
+ url: string;
16
+ detail: 'auto' | 'low' | 'high';
17
+ media_type: SupportedImageMediaType;
18
+ constructor(url: string, detail?: 'auto' | 'low' | 'high', media?: SupportedImageMediaType);
19
+ toString(): string;
20
+ }
21
+ export declare class ContentPartImageParam {
22
+ image_url: ImageURL;
23
+ type: 'image_url';
24
+ constructor(image_url: ImageURL);
25
+ toString(): string;
26
+ }
27
+ export declare class FunctionCall {
28
+ name: string;
29
+ arguments: string;
30
+ constructor(name: string, args: string);
31
+ toString(): string;
32
+ }
33
+ export declare class ToolCall {
34
+ id: string;
35
+ functionCall: FunctionCall;
36
+ type: 'function';
37
+ constructor(id: string, functionCall: FunctionCall);
38
+ toString(): string;
39
+ }
40
+ type ContentPart = ContentPartTextParam | ContentPartImageParam | ContentPartRefusalParam;
41
+ export type MessageRole = 'user' | 'system' | 'assistant';
42
+ export declare abstract class MessageBase {
43
+ cache: boolean;
44
+ abstract role: MessageRole;
45
+ constructor(init?: Partial<MessageBase>);
46
+ }
47
+ export declare class UserMessage extends MessageBase {
48
+ role: MessageRole;
49
+ content: string | ContentPart[];
50
+ name: string | null;
51
+ constructor(content: string | ContentPart[], name?: string | null);
52
+ get text(): string;
53
+ toString(): string;
54
+ }
55
+ export declare class SystemMessage extends MessageBase {
56
+ role: MessageRole;
57
+ content: string | ContentPartTextParam[];
58
+ name: string | null;
59
+ constructor(content: string | ContentPartTextParam[], name?: string | null);
60
+ get text(): string;
61
+ toString(): string;
62
+ }
63
+ export declare class AssistantMessage extends MessageBase {
64
+ role: MessageRole;
65
+ content: string | ContentPart[] | null;
66
+ tool_calls: ToolCall[] | null;
67
+ refusal: string | null;
68
+ constructor(init: {
69
+ content?: string | ContentPart[] | null;
70
+ tool_calls?: ToolCall[] | null;
71
+ refusal?: string | null;
72
+ });
73
+ get text(): string;
74
+ toString(): string;
75
+ }
76
+ export type Message = UserMessage | SystemMessage | AssistantMessage;
77
+ export {};
@@ -0,0 +1,157 @@
1
+ const truncate = (text, maxLength = 50) => {
2
+ if (text.length <= maxLength) {
3
+ return text;
4
+ }
5
+ return `${text.slice(0, maxLength - 3)}...`;
6
+ };
7
+ const formatImageUrl = (url, maxLength = 50) => {
8
+ if (url.startsWith('data:')) {
9
+ const mediaType = url.split(';')[0]?.split(':')[1] ?? 'image';
10
+ return `<base64 ${mediaType}>`;
11
+ }
12
+ return truncate(url, maxLength);
13
+ };
14
+ export class ContentPartTextParam {
15
+ text;
16
+ type = 'text';
17
+ constructor(text) {
18
+ this.text = text;
19
+ }
20
+ toString() {
21
+ return `Text: ${truncate(this.text)}`;
22
+ }
23
+ }
24
+ export class ContentPartRefusalParam {
25
+ refusal;
26
+ type = 'refusal';
27
+ constructor(refusal) {
28
+ this.refusal = refusal;
29
+ }
30
+ toString() {
31
+ return `Refusal: ${truncate(this.refusal)}`;
32
+ }
33
+ }
34
+ export class ImageURL {
35
+ url;
36
+ detail;
37
+ media_type;
38
+ constructor(url, detail = 'auto', media = 'image/png') {
39
+ this.url = url;
40
+ this.detail = detail;
41
+ this.media_type = media;
42
+ }
43
+ toString() {
44
+ return `🖼️ Image[${this.media_type}, detail=${this.detail}]: ${formatImageUrl(this.url)}`;
45
+ }
46
+ }
47
+ export class ContentPartImageParam {
48
+ image_url;
49
+ type = 'image_url';
50
+ constructor(image_url) {
51
+ this.image_url = image_url;
52
+ }
53
+ toString() {
54
+ return this.image_url.toString();
55
+ }
56
+ }
57
+ export class FunctionCall {
58
+ name;
59
+ // @ts-ignore - 'arguments' is a reserved keyword but valid as property name
60
+ arguments;
61
+ constructor(name, args) {
62
+ this.name = name;
63
+ // @ts-ignore
64
+ this.arguments = args;
65
+ }
66
+ toString() {
67
+ return `${this.name}(${truncate(this.arguments, 80)})`;
68
+ }
69
+ }
70
+ export class ToolCall {
71
+ id;
72
+ functionCall;
73
+ type = 'function';
74
+ constructor(id, functionCall) {
75
+ this.id = id;
76
+ this.functionCall = functionCall;
77
+ }
78
+ toString() {
79
+ return `ToolCall[${this.id}]: ${this.functionCall.toString()}`;
80
+ }
81
+ }
82
+ export class MessageBase {
83
+ cache = false;
84
+ constructor(init) {
85
+ if (init?.cache !== undefined) {
86
+ this.cache = init.cache;
87
+ }
88
+ }
89
+ }
90
+ export class UserMessage extends MessageBase {
91
+ role = 'user';
92
+ content;
93
+ name;
94
+ constructor(content, name = null) {
95
+ super();
96
+ this.content = content;
97
+ this.name = name;
98
+ }
99
+ get text() {
100
+ if (typeof this.content === 'string') {
101
+ return this.content;
102
+ }
103
+ return this.content
104
+ .filter((part) => part instanceof ContentPartTextParam)
105
+ .map((part) => part.text)
106
+ .join('\n');
107
+ }
108
+ toString() {
109
+ return `UserMessage(content=${this.text})`;
110
+ }
111
+ }
112
+ export class SystemMessage extends MessageBase {
113
+ role = 'system';
114
+ content;
115
+ name;
116
+ constructor(content, name = null) {
117
+ super();
118
+ this.content = content;
119
+ this.name = name;
120
+ }
121
+ get text() {
122
+ if (typeof this.content === 'string') {
123
+ return this.content;
124
+ }
125
+ return this.content.map((part) => part.text).join('\n');
126
+ }
127
+ toString() {
128
+ return `SystemMessage(content=${this.text})`;
129
+ }
130
+ }
131
+ export class AssistantMessage extends MessageBase {
132
+ role = 'assistant';
133
+ content;
134
+ tool_calls;
135
+ refusal;
136
+ constructor(init) {
137
+ super();
138
+ this.content = init.content ?? null;
139
+ this.tool_calls = init.tool_calls ?? null;
140
+ this.refusal = init.refusal ?? null;
141
+ }
142
+ get text() {
143
+ if (typeof this.content === 'string') {
144
+ return this.content;
145
+ }
146
+ if (Array.isArray(this.content)) {
147
+ return this.content
148
+ .filter((part) => part instanceof ContentPartTextParam)
149
+ .map((part) => part.text)
150
+ .join('\n');
151
+ }
152
+ return '';
153
+ }
154
+ toString() {
155
+ return `AssistantMessage(content=${this.text})`;
156
+ }
157
+ }
@@ -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 ChatOllama implements BaseChatModel {
5
+ model: string;
6
+ provider: string;
7
+ private client;
8
+ constructor(model?: string, host?: 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,77 @@
1
+ import { Ollama } from 'ollama';
2
+ import { ChatInvokeCompletion } from '../views.js';
3
+ import { OllamaMessageSerializer } from './serializer.js';
4
+ export class ChatOllama {
5
+ model;
6
+ provider = 'ollama';
7
+ client;
8
+ constructor(model = 'qwen2.5:latest', host = 'http://localhost:11434') {
9
+ this.model = model;
10
+ this.client = new Ollama({ host });
11
+ }
12
+ get name() {
13
+ return this.model;
14
+ }
15
+ get model_name() {
16
+ return this.model;
17
+ }
18
+ async ainvoke(messages, output_format, options = {}) {
19
+ const serializer = new OllamaMessageSerializer();
20
+ const ollamaMessages = serializer.serialize(messages);
21
+ let format = undefined;
22
+ if (output_format && 'schema' in output_format && output_format.schema) {
23
+ // Ollama supports 'json' format
24
+ format = 'json';
25
+ }
26
+ const requestPromise = this.client.chat({
27
+ model: this.model,
28
+ messages: ollamaMessages,
29
+ format: format,
30
+ stream: false,
31
+ });
32
+ const abortSignal = options.signal;
33
+ const response = abortSignal
34
+ ? await new Promise((resolve, reject) => {
35
+ const onAbort = () => {
36
+ cleanup();
37
+ const error = new Error('Operation aborted');
38
+ error.name = 'AbortError';
39
+ reject(error);
40
+ };
41
+ const cleanup = () => {
42
+ abortSignal.removeEventListener('abort', onAbort);
43
+ };
44
+ if (abortSignal.aborted) {
45
+ onAbort();
46
+ return;
47
+ }
48
+ abortSignal.addEventListener('abort', onAbort, { once: true });
49
+ requestPromise
50
+ .then((result) => {
51
+ cleanup();
52
+ resolve(result);
53
+ })
54
+ .catch((error) => {
55
+ cleanup();
56
+ reject(error);
57
+ });
58
+ })
59
+ : await requestPromise;
60
+ const content = response.message.content;
61
+ let completion = content;
62
+ if (output_format) {
63
+ try {
64
+ completion = output_format.parse(JSON.parse(content));
65
+ }
66
+ catch (e) {
67
+ console.error('Failed to parse completion', e);
68
+ throw e;
69
+ }
70
+ }
71
+ return new ChatInvokeCompletion(completion, {
72
+ prompt_tokens: response.prompt_eval_count ?? 0,
73
+ completion_tokens: response.eval_count ?? 0,
74
+ total_tokens: (response.prompt_eval_count ?? 0) + (response.eval_count ?? 0),
75
+ });
76
+ }
77
+ }
@@ -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';