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,53 @@
|
|
|
1
|
+
import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
|
|
2
|
+
export class OllamaMessageSerializer {
|
|
3
|
+
serialize(messages) {
|
|
4
|
+
return messages.map((message) => this.serializeMessage(message));
|
|
5
|
+
}
|
|
6
|
+
serializeMessage(message) {
|
|
7
|
+
if (message instanceof UserMessage) {
|
|
8
|
+
const images = [];
|
|
9
|
+
let content = '';
|
|
10
|
+
if (Array.isArray(message.content)) {
|
|
11
|
+
message.content.forEach((part) => {
|
|
12
|
+
if (part instanceof ContentPartTextParam) {
|
|
13
|
+
content += part.text;
|
|
14
|
+
}
|
|
15
|
+
else if (part instanceof ContentPartImageParam) {
|
|
16
|
+
// Ollama expects base64 string without header
|
|
17
|
+
const data = part.image_url.url.split(',')[1];
|
|
18
|
+
if (data)
|
|
19
|
+
images.push(data);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
content = message.content;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
role: 'user',
|
|
28
|
+
content: content,
|
|
29
|
+
images: images.length > 0 ? images : undefined,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (message instanceof SystemMessage) {
|
|
33
|
+
return {
|
|
34
|
+
role: 'system',
|
|
35
|
+
content: message.text,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (message instanceof AssistantMessage) {
|
|
39
|
+
const toolCalls = message.tool_calls?.map((toolCall) => ({
|
|
40
|
+
function: {
|
|
41
|
+
name: toolCall.functionCall.name,
|
|
42
|
+
arguments: JSON.parse(toolCall.functionCall.arguments),
|
|
43
|
+
},
|
|
44
|
+
}));
|
|
45
|
+
return {
|
|
46
|
+
role: 'assistant',
|
|
47
|
+
content: message.text,
|
|
48
|
+
tool_calls: toolCalls,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Unknown message type: ${message.constructor.name}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
|
|
2
|
+
import { ChatInvokeCompletion } from '../views.js';
|
|
3
|
+
import type { Message } from '../messages.js';
|
|
4
|
+
export interface ChatOpenAIOptions {
|
|
5
|
+
model?: string;
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
organization?: string;
|
|
8
|
+
baseURL?: string;
|
|
9
|
+
temperature?: number | null;
|
|
10
|
+
frequencyPenalty?: number | null;
|
|
11
|
+
reasoningEffort?: 'low' | 'medium' | 'high';
|
|
12
|
+
maxCompletionTokens?: number | null;
|
|
13
|
+
maxRetries?: number;
|
|
14
|
+
seed?: number | null;
|
|
15
|
+
topP?: number | null;
|
|
16
|
+
addSchemaToSystemPrompt?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class ChatOpenAI implements BaseChatModel {
|
|
19
|
+
model: string;
|
|
20
|
+
provider: string;
|
|
21
|
+
private client;
|
|
22
|
+
private temperature;
|
|
23
|
+
private frequencyPenalty;
|
|
24
|
+
private reasoningEffort;
|
|
25
|
+
private maxCompletionTokens;
|
|
26
|
+
private seed;
|
|
27
|
+
private topP;
|
|
28
|
+
private addSchemaToSystemPrompt;
|
|
29
|
+
constructor(options?: ChatOpenAIOptions);
|
|
30
|
+
get name(): string;
|
|
31
|
+
get model_name(): string;
|
|
32
|
+
private isReasoningModel;
|
|
33
|
+
private getUsage;
|
|
34
|
+
ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
|
|
35
|
+
ainvoke<T>(messages: Message[], output_format: {
|
|
36
|
+
parse: (input: string) => T;
|
|
37
|
+
} | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
|
|
38
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
import { ChatInvokeCompletion } from '../views.js';
|
|
4
|
+
import { OpenAIMessageSerializer } from './serializer.js';
|
|
5
|
+
import { ModelProviderError } from '../exceptions.js';
|
|
6
|
+
// Reasoning models that support reasoning_effort parameter
|
|
7
|
+
const ReasoningModels = [
|
|
8
|
+
'o4-mini',
|
|
9
|
+
'o3',
|
|
10
|
+
'o3-mini',
|
|
11
|
+
'o1',
|
|
12
|
+
'o1-pro',
|
|
13
|
+
'o3-pro',
|
|
14
|
+
'gpt-5',
|
|
15
|
+
'gpt-5-mini',
|
|
16
|
+
'gpt-5-nano',
|
|
17
|
+
];
|
|
18
|
+
export class ChatOpenAI {
|
|
19
|
+
model;
|
|
20
|
+
provider = 'openai';
|
|
21
|
+
client;
|
|
22
|
+
temperature;
|
|
23
|
+
frequencyPenalty;
|
|
24
|
+
reasoningEffort;
|
|
25
|
+
maxCompletionTokens;
|
|
26
|
+
seed;
|
|
27
|
+
topP;
|
|
28
|
+
addSchemaToSystemPrompt;
|
|
29
|
+
constructor(options = {}) {
|
|
30
|
+
const { model = 'gpt-4o', apiKey, organization, baseURL, temperature = 0.2, frequencyPenalty = 0.1, reasoningEffort = 'low', maxCompletionTokens = 8000, maxRetries = 10, seed = null, topP = null, addSchemaToSystemPrompt = false, } = options;
|
|
31
|
+
this.model = model;
|
|
32
|
+
this.temperature = temperature;
|
|
33
|
+
this.frequencyPenalty = frequencyPenalty;
|
|
34
|
+
this.reasoningEffort = reasoningEffort;
|
|
35
|
+
this.maxCompletionTokens = maxCompletionTokens;
|
|
36
|
+
this.seed = seed;
|
|
37
|
+
this.topP = topP;
|
|
38
|
+
this.addSchemaToSystemPrompt = addSchemaToSystemPrompt;
|
|
39
|
+
this.client = new OpenAI({
|
|
40
|
+
apiKey,
|
|
41
|
+
organization,
|
|
42
|
+
baseURL,
|
|
43
|
+
maxRetries,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
get name() {
|
|
47
|
+
return this.model;
|
|
48
|
+
}
|
|
49
|
+
get model_name() {
|
|
50
|
+
return this.model;
|
|
51
|
+
}
|
|
52
|
+
isReasoningModel() {
|
|
53
|
+
return ReasoningModels.some((m) => this.model.toLowerCase().includes(m.toLowerCase()));
|
|
54
|
+
}
|
|
55
|
+
getUsage(response) {
|
|
56
|
+
if (!response.usage)
|
|
57
|
+
return null;
|
|
58
|
+
let completionTokens = response.usage.completion_tokens;
|
|
59
|
+
const details = response.usage.completion_tokens_details;
|
|
60
|
+
if (details?.reasoning_tokens) {
|
|
61
|
+
completionTokens += details.reasoning_tokens;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
prompt_tokens: response.usage.prompt_tokens,
|
|
65
|
+
prompt_cached_tokens: response.usage.prompt_tokens_details?.cached_tokens ?? null,
|
|
66
|
+
prompt_cache_creation_tokens: null,
|
|
67
|
+
prompt_image_tokens: null,
|
|
68
|
+
completion_tokens: completionTokens,
|
|
69
|
+
total_tokens: response.usage.total_tokens,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async ainvoke(messages, output_format, options = {}) {
|
|
73
|
+
const serializer = new OpenAIMessageSerializer();
|
|
74
|
+
const openaiMessages = serializer.serialize(messages);
|
|
75
|
+
// Build model parameters
|
|
76
|
+
const modelParams = {};
|
|
77
|
+
if (!this.isReasoningModel()) {
|
|
78
|
+
// Regular models support temperature and frequency_penalty
|
|
79
|
+
if (this.temperature !== null) {
|
|
80
|
+
modelParams.temperature = this.temperature;
|
|
81
|
+
}
|
|
82
|
+
if (this.frequencyPenalty !== null) {
|
|
83
|
+
modelParams.frequency_penalty = this.frequencyPenalty;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Reasoning models use reasoning_effort instead
|
|
88
|
+
modelParams.reasoning_effort = this.reasoningEffort;
|
|
89
|
+
}
|
|
90
|
+
if (this.maxCompletionTokens !== null) {
|
|
91
|
+
modelParams.max_completion_tokens = this.maxCompletionTokens;
|
|
92
|
+
}
|
|
93
|
+
if (this.seed !== null) {
|
|
94
|
+
modelParams.seed = this.seed;
|
|
95
|
+
}
|
|
96
|
+
if (this.topP !== null) {
|
|
97
|
+
modelParams.top_p = this.topP;
|
|
98
|
+
}
|
|
99
|
+
let responseFormat = undefined;
|
|
100
|
+
if (output_format && 'schema' in output_format && output_format.schema) {
|
|
101
|
+
// Assuming output_format is a Zod schema wrapper or similar that has a schema property
|
|
102
|
+
// But the interface says { parse: ... }
|
|
103
|
+
// In the plan, it was passed as a Zod schema directly.
|
|
104
|
+
// However, the BaseChatModel interface I saw earlier has:
|
|
105
|
+
// ainvoke<T>(messages: Message[], output_format: { parse: (input: string) => T } | undefined): Promise<ChatInvokeCompletion<T>>;
|
|
106
|
+
// So I need to handle how to extract the schema if I want to use structured outputs.
|
|
107
|
+
// If output_format is just a Zod schema, it has a parse method.
|
|
108
|
+
// Let's assume it's a Zod schema for now, as that's what the plan implies.
|
|
109
|
+
// We need to cast it to any or check if it's a Zod schema to get the schema for JSON schema generation.
|
|
110
|
+
// For now, I'll try to use zodToJsonSchema on it if possible.
|
|
111
|
+
try {
|
|
112
|
+
const jsonSchema = zodToJsonSchema(output_format, {
|
|
113
|
+
name: 'Response',
|
|
114
|
+
target: 'jsonSchema7',
|
|
115
|
+
});
|
|
116
|
+
// OpenAI expects a specific format for json_schema
|
|
117
|
+
responseFormat = {
|
|
118
|
+
type: 'json_schema',
|
|
119
|
+
json_schema: {
|
|
120
|
+
name: 'Response',
|
|
121
|
+
schema: jsonSchema,
|
|
122
|
+
strict: true,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
// If it's not a Zod schema or fails, we might fallback or just not use response_format
|
|
128
|
+
console.warn('Failed to convert output_format to JSON schema', e);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const response = await this.client.chat.completions.create({
|
|
133
|
+
model: this.model,
|
|
134
|
+
messages: openaiMessages,
|
|
135
|
+
response_format: responseFormat,
|
|
136
|
+
...modelParams,
|
|
137
|
+
}, options.signal ? { signal: options.signal } : undefined);
|
|
138
|
+
const content = response.choices[0].message.content || '';
|
|
139
|
+
const usage = this.getUsage(response);
|
|
140
|
+
let completion = content;
|
|
141
|
+
if (output_format) {
|
|
142
|
+
try {
|
|
143
|
+
// If it's structured output, we need to parse the JSON first
|
|
144
|
+
if (responseFormat?.type === 'json_schema') {
|
|
145
|
+
const parsedJson = JSON.parse(content);
|
|
146
|
+
completion = output_format.parse(parsedJson);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// If it's not structured output but we have a parser (e.g. for simple types or manual parsing)
|
|
150
|
+
// But usually for OpenAI we want structured output if a schema is provided.
|
|
151
|
+
// If we didn't use json_schema, we might still try to parse if it looks like JSON?
|
|
152
|
+
// For now, let's trust the output_format.parse
|
|
153
|
+
completion = output_format.parse(content);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
console.error('Failed to parse completion', e);
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return new ChatInvokeCompletion(completion, usage);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
// Handle OpenAI-specific errors
|
|
165
|
+
if (error?.status === 429) {
|
|
166
|
+
throw new ModelProviderError(error?.message ?? 'Rate limit exceeded', 429, this.model);
|
|
167
|
+
}
|
|
168
|
+
if (error?.status >= 500) {
|
|
169
|
+
throw new ModelProviderError(error?.message ?? 'Server error', error.status, this.model);
|
|
170
|
+
}
|
|
171
|
+
throw new ModelProviderError(error?.message ?? String(error), error?.status ?? 500, this.model);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChatOpenAI } from './chat.js';
|
|
2
|
+
/**
|
|
3
|
+
* A class to interact with any provider using the OpenAI API schema.
|
|
4
|
+
*
|
|
5
|
+
* This allows using any OpenAI-compatible API provider by specifying a custom model name.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const llm = new ChatOpenAILike('custom-model-name');
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare class ChatOpenAILike extends ChatOpenAI {
|
|
13
|
+
/**
|
|
14
|
+
* @param model - The name of the model to use (any OpenAI-compatible model)
|
|
15
|
+
*/
|
|
16
|
+
constructor(model: string);
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ChatOpenAI } from './chat.js';
|
|
2
|
+
/**
|
|
3
|
+
* A class to interact with any provider using the OpenAI API schema.
|
|
4
|
+
*
|
|
5
|
+
* This allows using any OpenAI-compatible API provider by specifying a custom model name.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const llm = new ChatOpenAILike('custom-model-name');
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export class ChatOpenAILike extends ChatOpenAI {
|
|
13
|
+
/**
|
|
14
|
+
* @param model - The name of the model to use (any OpenAI-compatible model)
|
|
15
|
+
*/
|
|
16
|
+
constructor(model) {
|
|
17
|
+
super({ model });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
|
|
2
|
+
import { type Message } from '../messages.js';
|
|
3
|
+
export declare class OpenAIMessageSerializer {
|
|
4
|
+
serialize(messages: Message[]): ChatCompletionMessageParam[];
|
|
5
|
+
private serializeMessage;
|
|
6
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AssistantMessage, ContentPartImageParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
|
|
2
|
+
export class OpenAIMessageSerializer {
|
|
3
|
+
serialize(messages) {
|
|
4
|
+
return messages.map((message) => this.serializeMessage(message));
|
|
5
|
+
}
|
|
6
|
+
serializeMessage(message) {
|
|
7
|
+
if (message instanceof UserMessage) {
|
|
8
|
+
return {
|
|
9
|
+
role: 'user',
|
|
10
|
+
content: Array.isArray(message.content)
|
|
11
|
+
? message.content.map((part) => {
|
|
12
|
+
if (part instanceof ContentPartTextParam) {
|
|
13
|
+
return { type: 'text', text: part.text };
|
|
14
|
+
}
|
|
15
|
+
if (part instanceof ContentPartImageParam) {
|
|
16
|
+
return {
|
|
17
|
+
type: 'image_url',
|
|
18
|
+
image_url: {
|
|
19
|
+
url: part.image_url.url,
|
|
20
|
+
detail: part.image_url.detail,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return { type: 'text', text: '' }; // Fallback
|
|
25
|
+
})
|
|
26
|
+
: message.content,
|
|
27
|
+
name: message.name || undefined,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (message instanceof SystemMessage) {
|
|
31
|
+
return {
|
|
32
|
+
role: 'system',
|
|
33
|
+
content: Array.isArray(message.content)
|
|
34
|
+
? message.content.map((part) => part.text).join('\n')
|
|
35
|
+
: message.content,
|
|
36
|
+
name: message.name || undefined,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (message instanceof AssistantMessage) {
|
|
40
|
+
const toolCalls = message.tool_calls?.map((toolCall) => ({
|
|
41
|
+
id: toolCall.id,
|
|
42
|
+
type: 'function',
|
|
43
|
+
function: {
|
|
44
|
+
name: toolCall.functionCall.name,
|
|
45
|
+
arguments: toolCall.functionCall.arguments,
|
|
46
|
+
},
|
|
47
|
+
}));
|
|
48
|
+
return {
|
|
49
|
+
role: 'assistant',
|
|
50
|
+
content: typeof message.content === 'string' ? message.content : null, // OpenAI expects string or null for content in assistant message if tool_calls are present
|
|
51
|
+
tool_calls: toolCalls,
|
|
52
|
+
refusal: message.refusal || undefined,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Unknown message type: ${message.constructor.name}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
|
|
2
|
+
import { ChatInvokeCompletion } from '../views.js';
|
|
3
|
+
import type { Message } from '../messages.js';
|
|
4
|
+
export declare class ChatOpenRouter implements BaseChatModel {
|
|
5
|
+
model: string;
|
|
6
|
+
provider: string;
|
|
7
|
+
private client;
|
|
8
|
+
constructor(model?: string);
|
|
9
|
+
get name(): string;
|
|
10
|
+
get model_name(): string;
|
|
11
|
+
ainvoke(messages: Message[], output_format?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
|
|
12
|
+
ainvoke<T>(messages: Message[], output_format: {
|
|
13
|
+
parse: (input: string) => T;
|
|
14
|
+
} | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
import { ChatInvokeCompletion } from '../views.js';
|
|
4
|
+
import { OpenRouterMessageSerializer } from './serializer.js';
|
|
5
|
+
export class ChatOpenRouter {
|
|
6
|
+
model;
|
|
7
|
+
provider = 'openrouter';
|
|
8
|
+
client;
|
|
9
|
+
constructor(model = 'openai/gpt-4o') {
|
|
10
|
+
this.model = model;
|
|
11
|
+
this.client = new OpenAI({
|
|
12
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
13
|
+
baseURL: 'https://openrouter.ai/api/v1',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
get name() {
|
|
17
|
+
return this.model;
|
|
18
|
+
}
|
|
19
|
+
get model_name() {
|
|
20
|
+
return this.model;
|
|
21
|
+
}
|
|
22
|
+
async ainvoke(messages, output_format, options = {}) {
|
|
23
|
+
const serializer = new OpenRouterMessageSerializer();
|
|
24
|
+
const openRouterMessages = serializer.serialize(messages);
|
|
25
|
+
let responseFormat = undefined;
|
|
26
|
+
if (output_format && 'schema' in output_format && output_format.schema) {
|
|
27
|
+
// OpenRouter supports structured outputs for some models, but it depends on the underlying provider.
|
|
28
|
+
// We'll try to use json_schema if possible, or json_object.
|
|
29
|
+
try {
|
|
30
|
+
const jsonSchema = zodToJsonSchema(output_format, {
|
|
31
|
+
name: 'Response',
|
|
32
|
+
target: 'jsonSchema7',
|
|
33
|
+
});
|
|
34
|
+
responseFormat = {
|
|
35
|
+
type: 'json_schema',
|
|
36
|
+
json_schema: {
|
|
37
|
+
name: 'Response',
|
|
38
|
+
schema: jsonSchema,
|
|
39
|
+
strict: true,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.warn('Failed to convert output_format to JSON schema for OpenRouter', e);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const response = await this.client.chat.completions.create({
|
|
48
|
+
model: this.model,
|
|
49
|
+
messages: openRouterMessages,
|
|
50
|
+
response_format: responseFormat,
|
|
51
|
+
}, options.signal ? { signal: options.signal } : undefined);
|
|
52
|
+
const content = response.choices[0].message.content || '';
|
|
53
|
+
let completion = content;
|
|
54
|
+
if (output_format) {
|
|
55
|
+
try {
|
|
56
|
+
if (responseFormat?.type === 'json_schema') {
|
|
57
|
+
completion = output_format.parse(JSON.parse(content));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
completion = output_format.parse(content);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
console.error('Failed to parse completion', e);
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return new ChatInvokeCompletion(completion, {
|
|
69
|
+
prompt_tokens: response.usage?.prompt_tokens ?? 0,
|
|
70
|
+
completion_tokens: response.usage?.completion_tokens ?? 0,
|
|
71
|
+
total_tokens: response.usage?.total_tokens ?? 0,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export class SchemaOptimizer {
|
|
2
|
+
static createOptimizedJsonSchema(schema) {
|
|
3
|
+
const defsLookup = schema.$defs ?? {};
|
|
4
|
+
const optimize = (obj, inProperties = false) => {
|
|
5
|
+
if (Array.isArray(obj)) {
|
|
6
|
+
return obj.map((item) => optimize(item, inProperties));
|
|
7
|
+
}
|
|
8
|
+
if (obj && typeof obj === 'object') {
|
|
9
|
+
let flattenedRef = null;
|
|
10
|
+
const optimized = {};
|
|
11
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
12
|
+
if (key === '$defs' || key === 'additionalProperties')
|
|
13
|
+
continue;
|
|
14
|
+
if (key === 'title' && !inProperties)
|
|
15
|
+
continue;
|
|
16
|
+
if (key === '$ref' && typeof value === 'string') {
|
|
17
|
+
const refName = value.split('/').pop();
|
|
18
|
+
if (defsLookup[refName]) {
|
|
19
|
+
flattenedRef = optimize(defsLookup[refName], inProperties);
|
|
20
|
+
}
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (key === 'properties') {
|
|
24
|
+
optimized[key] = optimize(value, true);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (typeof value === 'object' && value !== null) {
|
|
28
|
+
optimized[key] = optimize(value, inProperties);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
optimized[key] = value;
|
|
32
|
+
}
|
|
33
|
+
const result = flattenedRef
|
|
34
|
+
? { ...flattenedRef, ...optimized }
|
|
35
|
+
: optimized;
|
|
36
|
+
if (result.type === 'object' &&
|
|
37
|
+
result.additionalProperties === undefined) {
|
|
38
|
+
result.additionalProperties = false;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
return obj;
|
|
43
|
+
};
|
|
44
|
+
const optimizedSchema = optimize(schema);
|
|
45
|
+
const ensureAdditionalProperties = (obj) => {
|
|
46
|
+
if (Array.isArray(obj)) {
|
|
47
|
+
obj.forEach(ensureAdditionalProperties);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (obj && typeof obj === 'object') {
|
|
51
|
+
if (obj.type === 'object' && obj.additionalProperties === undefined) {
|
|
52
|
+
obj.additionalProperties = false;
|
|
53
|
+
}
|
|
54
|
+
Object.values(obj).forEach(ensureAdditionalProperties);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
ensureAdditionalProperties(optimizedSchema);
|
|
58
|
+
SchemaOptimizer.makeStrictCompatible(optimizedSchema);
|
|
59
|
+
return optimizedSchema;
|
|
60
|
+
}
|
|
61
|
+
static makeStrictCompatible(schema) {
|
|
62
|
+
if (Array.isArray(schema)) {
|
|
63
|
+
schema.forEach(SchemaOptimizer.makeStrictCompatible);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (schema && typeof schema === 'object') {
|
|
67
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
68
|
+
if (key !== 'required' && value && typeof value === 'object') {
|
|
69
|
+
SchemaOptimizer.makeStrictCompatible(value);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (schema.type === 'object' && schema.properties) {
|
|
73
|
+
schema.required = Object.keys(schema.properties);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ChatInvokeUsage {
|
|
2
|
+
prompt_tokens: number;
|
|
3
|
+
prompt_cached_tokens?: number | null;
|
|
4
|
+
prompt_cache_creation_tokens?: number | null;
|
|
5
|
+
prompt_image_tokens?: number | null;
|
|
6
|
+
completion_tokens: number;
|
|
7
|
+
total_tokens: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class ChatInvokeCompletion<T = string> {
|
|
10
|
+
completion: T;
|
|
11
|
+
usage: ChatInvokeUsage | null;
|
|
12
|
+
thinking: string | null;
|
|
13
|
+
redacted_thinking: string | null;
|
|
14
|
+
constructor(completion: T, usage?: ChatInvokeUsage | null, thinking?: string | null, redacted_thinking?: string | null);
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class ChatInvokeCompletion {
|
|
2
|
+
completion;
|
|
3
|
+
usage;
|
|
4
|
+
thinking;
|
|
5
|
+
redacted_thinking;
|
|
6
|
+
constructor(completion, usage = null, thinking = null, redacted_thinking = null) {
|
|
7
|
+
this.completion = completion;
|
|
8
|
+
this.usage = usage;
|
|
9
|
+
this.thinking = thinking;
|
|
10
|
+
this.redacted_thinking = redacted_thinking;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
export type LogLevel = 'debug' | 'info' | 'result' | 'warning' | 'error';
|
|
3
|
+
interface SetupLoggingOptions {
|
|
4
|
+
stream?: Writable;
|
|
5
|
+
logLevel?: LogLevel;
|
|
6
|
+
forceSetup?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare class Logger {
|
|
9
|
+
private readonly name;
|
|
10
|
+
constructor(name: string);
|
|
11
|
+
private shouldLog;
|
|
12
|
+
get level(): LogLevel;
|
|
13
|
+
private emit;
|
|
14
|
+
debug(message: string, ...args: unknown[]): void;
|
|
15
|
+
info(message: string, ...args: unknown[]): void;
|
|
16
|
+
result(message: string, ...args: unknown[]): void;
|
|
17
|
+
warning(message: string, ...args: unknown[]): void;
|
|
18
|
+
warn(message: string, ...args: unknown[]): void;
|
|
19
|
+
error(message: string, ...args: unknown[]): void;
|
|
20
|
+
child(suffix: string): Logger;
|
|
21
|
+
}
|
|
22
|
+
export declare const createLogger: (name: string) => Logger;
|
|
23
|
+
export declare const setupLogging: (options?: SetupLoggingOptions) => Logger;
|
|
24
|
+
export declare const logger: Logger;
|
|
25
|
+
export {};
|