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.
- package/LICENSE +21 -0
- package/README.md +761 -0
- package/dist/agent/cloud-events.d.ts +264 -0
- package/dist/agent/cloud-events.js +318 -0
- package/dist/agent/gif.d.ts +15 -0
- package/dist/agent/gif.js +215 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/message-manager/service.d.ts +30 -0
- package/dist/agent/message-manager/service.js +208 -0
- package/dist/agent/message-manager/utils.d.ts +2 -0
- package/dist/agent/message-manager/utils.js +41 -0
- package/dist/agent/message-manager/views.d.ts +26 -0
- package/dist/agent/message-manager/views.js +73 -0
- package/dist/agent/prompts.d.ts +52 -0
- package/dist/agent/prompts.js +259 -0
- package/dist/agent/service.d.ts +290 -0
- package/dist/agent/service.js +2200 -0
- package/dist/agent/views.d.ts +741 -0
- package/dist/agent/views.js +537 -0
- package/dist/browser/browser.d.ts +7 -0
- package/dist/browser/browser.js +5 -0
- package/dist/browser/context.d.ts +8 -0
- package/dist/browser/context.js +4 -0
- package/dist/browser/dvd-screensaver.d.ts +101 -0
- package/dist/browser/dvd-screensaver.js +270 -0
- package/dist/browser/extensions.d.ts +63 -0
- package/dist/browser/extensions.js +359 -0
- package/dist/browser/index.d.ts +10 -0
- package/dist/browser/index.js +9 -0
- package/dist/browser/playwright-manager.d.ts +47 -0
- package/dist/browser/playwright-manager.js +146 -0
- package/dist/browser/profile.d.ts +196 -0
- package/dist/browser/profile.js +815 -0
- package/dist/browser/session.d.ts +505 -0
- package/dist/browser/session.js +3409 -0
- package/dist/browser/types.d.ts +1184 -0
- package/dist/browser/types.js +1 -0
- package/dist/browser/utils.d.ts +1 -0
- package/dist/browser/utils.js +19 -0
- package/dist/browser/views.d.ts +78 -0
- package/dist/browser/views.js +72 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +44 -0
- package/dist/config.d.ts +108 -0
- package/dist/config.js +430 -0
- package/dist/controller/index.d.ts +3 -0
- package/dist/controller/index.js +3 -0
- package/dist/controller/registry/index.d.ts +2 -0
- package/dist/controller/registry/index.js +2 -0
- package/dist/controller/registry/service.d.ts +45 -0
- package/dist/controller/registry/service.js +184 -0
- package/dist/controller/registry/views.d.ts +55 -0
- package/dist/controller/registry/views.js +174 -0
- package/dist/controller/service.d.ts +49 -0
- package/dist/controller/service.js +1176 -0
- package/dist/controller/views.d.ts +241 -0
- package/dist/controller/views.js +88 -0
- package/dist/dom/clickable-element-processor/service.d.ts +11 -0
- package/dist/dom/clickable-element-processor/service.js +60 -0
- package/dist/dom/dom_tree/index.js +1400 -0
- package/dist/dom/history-tree-processor/service.d.ts +14 -0
- package/dist/dom/history-tree-processor/service.js +75 -0
- package/dist/dom/history-tree-processor/view.d.ts +54 -0
- package/dist/dom/history-tree-processor/view.js +56 -0
- package/dist/dom/playground/extraction.d.ts +19 -0
- package/dist/dom/playground/extraction.js +187 -0
- package/dist/dom/playground/process-dom.d.ts +1 -0
- package/dist/dom/playground/process-dom.js +5 -0
- package/dist/dom/playground/test-accessibility.d.ts +44 -0
- package/dist/dom/playground/test-accessibility.js +111 -0
- package/dist/dom/service.d.ts +19 -0
- package/dist/dom/service.js +227 -0
- package/dist/dom/utils.d.ts +1 -0
- package/dist/dom/utils.js +6 -0
- package/dist/dom/views.d.ts +61 -0
- package/dist/dom/views.js +247 -0
- package/dist/event-bus.d.ts +11 -0
- package/dist/event-bus.js +19 -0
- package/dist/exceptions.d.ts +10 -0
- package/dist/exceptions.js +22 -0
- package/dist/filesystem/file-system.d.ts +68 -0
- package/dist/filesystem/file-system.js +412 -0
- package/dist/filesystem/index.d.ts +1 -0
- package/dist/filesystem/index.js +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +33 -0
- package/dist/integrations/gmail/actions.d.ts +12 -0
- package/dist/integrations/gmail/actions.js +113 -0
- package/dist/integrations/gmail/index.d.ts +2 -0
- package/dist/integrations/gmail/index.js +2 -0
- package/dist/integrations/gmail/service.d.ts +61 -0
- package/dist/integrations/gmail/service.js +260 -0
- package/dist/llm/anthropic/chat.d.ts +28 -0
- package/dist/llm/anthropic/chat.js +126 -0
- package/dist/llm/anthropic/index.d.ts +2 -0
- package/dist/llm/anthropic/index.js +2 -0
- package/dist/llm/anthropic/serializer.d.ts +68 -0
- package/dist/llm/anthropic/serializer.js +285 -0
- package/dist/llm/aws/chat-anthropic.d.ts +61 -0
- package/dist/llm/aws/chat-anthropic.js +176 -0
- package/dist/llm/aws/chat-bedrock.d.ts +15 -0
- package/dist/llm/aws/chat-bedrock.js +80 -0
- package/dist/llm/aws/index.d.ts +3 -0
- package/dist/llm/aws/index.js +3 -0
- package/dist/llm/aws/serializer.d.ts +5 -0
- package/dist/llm/aws/serializer.js +68 -0
- package/dist/llm/azure/chat.d.ts +15 -0
- package/dist/llm/azure/chat.js +83 -0
- package/dist/llm/azure/index.d.ts +1 -0
- package/dist/llm/azure/index.js +1 -0
- package/dist/llm/base.d.ts +16 -0
- package/dist/llm/base.js +1 -0
- package/dist/llm/deepseek/chat.d.ts +15 -0
- package/dist/llm/deepseek/chat.js +51 -0
- package/dist/llm/deepseek/index.d.ts +2 -0
- package/dist/llm/deepseek/index.js +2 -0
- package/dist/llm/deepseek/serializer.d.ts +6 -0
- package/dist/llm/deepseek/serializer.js +57 -0
- package/dist/llm/exceptions.d.ts +10 -0
- package/dist/llm/exceptions.js +18 -0
- package/dist/llm/google/chat.d.ts +20 -0
- package/dist/llm/google/chat.js +144 -0
- package/dist/llm/google/index.d.ts +2 -0
- package/dist/llm/google/index.js +2 -0
- package/dist/llm/google/serializer.d.ts +6 -0
- package/dist/llm/google/serializer.js +64 -0
- package/dist/llm/groq/chat.d.ts +15 -0
- package/dist/llm/groq/chat.js +52 -0
- package/dist/llm/groq/index.d.ts +3 -0
- package/dist/llm/groq/index.js +3 -0
- package/dist/llm/groq/parser.d.ts +32 -0
- package/dist/llm/groq/parser.js +189 -0
- package/dist/llm/groq/serializer.d.ts +6 -0
- package/dist/llm/groq/serializer.js +56 -0
- package/dist/llm/messages.d.ts +77 -0
- package/dist/llm/messages.js +157 -0
- package/dist/llm/ollama/chat.d.ts +15 -0
- package/dist/llm/ollama/chat.js +77 -0
- package/dist/llm/ollama/index.d.ts +2 -0
- package/dist/llm/ollama/index.js +2 -0
- package/dist/llm/ollama/serializer.d.ts +6 -0
- package/dist/llm/ollama/serializer.js +53 -0
- package/dist/llm/openai/chat.d.ts +38 -0
- package/dist/llm/openai/chat.js +174 -0
- package/dist/llm/openai/index.d.ts +3 -0
- package/dist/llm/openai/index.js +3 -0
- package/dist/llm/openai/like.d.ts +17 -0
- package/dist/llm/openai/like.js +19 -0
- package/dist/llm/openai/serializer.d.ts +6 -0
- package/dist/llm/openai/serializer.js +57 -0
- package/dist/llm/openrouter/chat.d.ts +15 -0
- package/dist/llm/openrouter/chat.js +74 -0
- package/dist/llm/openrouter/index.d.ts +2 -0
- package/dist/llm/openrouter/index.js +2 -0
- package/dist/llm/openrouter/serializer.d.ts +3 -0
- package/dist/llm/openrouter/serializer.js +3 -0
- package/dist/llm/schema.d.ts +6 -0
- package/dist/llm/schema.js +77 -0
- package/dist/llm/views.d.ts +15 -0
- package/dist/llm/views.js +12 -0
- package/dist/logging-config.d.ts +25 -0
- package/dist/logging-config.js +89 -0
- package/dist/mcp/client.d.ts +142 -0
- package/dist/mcp/client.js +638 -0
- package/dist/mcp/controller.d.ts +6 -0
- package/dist/mcp/controller.js +38 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/server.d.ts +134 -0
- package/dist/mcp/server.js +759 -0
- package/dist/observability-decorators.d.ts +158 -0
- package/dist/observability-decorators.js +286 -0
- package/dist/observability.d.ts +23 -0
- package/dist/observability.js +58 -0
- package/dist/screenshots/index.d.ts +1 -0
- package/dist/screenshots/index.js +1 -0
- package/dist/screenshots/service.d.ts +6 -0
- package/dist/screenshots/service.js +28 -0
- package/dist/sync/auth.d.ts +27 -0
- package/dist/sync/auth.js +205 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.js +2 -0
- package/dist/sync/service.d.ts +21 -0
- package/dist/sync/service.js +146 -0
- package/dist/telemetry/index.d.ts +2 -0
- package/dist/telemetry/index.js +2 -0
- package/dist/telemetry/service.d.ts +12 -0
- package/dist/telemetry/service.js +85 -0
- package/dist/telemetry/views.d.ts +112 -0
- package/dist/telemetry/views.js +112 -0
- package/dist/tokens/index.d.ts +2 -0
- package/dist/tokens/index.js +2 -0
- package/dist/tokens/service.d.ts +35 -0
- package/dist/tokens/service.js +423 -0
- package/dist/tokens/views.d.ts +58 -0
- package/dist/tokens/views.js +1 -0
- package/dist/utils.d.ts +128 -0
- package/dist/utils.js +529 -0
- 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
|
+
}
|
package/dist/llm/base.js
ADDED
|
@@ -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,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,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
|
+
}
|