browser-use 0.4.0 → 0.6.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 (58) hide show
  1. package/dist/agent/service.js +2 -0
  2. package/dist/agent/system_prompt.md +269 -0
  3. package/dist/agent/system_prompt_anthropic_flash.md +240 -0
  4. package/dist/agent/system_prompt_browser_use.md +18 -0
  5. package/dist/agent/system_prompt_browser_use_flash.md +15 -0
  6. package/dist/agent/system_prompt_browser_use_no_thinking.md +17 -0
  7. package/dist/agent/system_prompt_flash.md +16 -0
  8. package/dist/agent/system_prompt_flash_anthropic.md +30 -0
  9. package/dist/agent/system_prompt_no_thinking.md +245 -0
  10. package/dist/browser/cloud/index.d.ts +1 -0
  11. package/dist/browser/cloud/index.js +1 -0
  12. package/dist/browser/cloud/management.d.ts +130 -0
  13. package/dist/browser/cloud/management.js +140 -0
  14. package/dist/browser/events.d.ts +61 -3
  15. package/dist/browser/events.js +66 -0
  16. package/dist/browser/profile.d.ts +1 -0
  17. package/dist/browser/profile.js +25 -8
  18. package/dist/browser/session.d.ts +59 -2
  19. package/dist/browser/session.js +943 -131
  20. package/dist/browser/watchdogs/base.js +34 -1
  21. package/dist/browser/watchdogs/captcha-watchdog.d.ts +26 -0
  22. package/dist/browser/watchdogs/captcha-watchdog.js +151 -0
  23. package/dist/browser/watchdogs/index.d.ts +1 -0
  24. package/dist/browser/watchdogs/index.js +1 -0
  25. package/dist/browser/watchdogs/screenshot-watchdog.js +4 -3
  26. package/dist/cli.d.ts +120 -0
  27. package/dist/cli.js +1816 -4
  28. package/dist/controller/service.js +106 -362
  29. package/dist/controller/views.d.ts +9 -6
  30. package/dist/controller/views.js +8 -5
  31. package/dist/dom/dom_tree/index.js +24 -11
  32. package/dist/filesystem/file-system.js +1 -1
  33. package/dist/llm/litellm/chat.d.ts +11 -0
  34. package/dist/llm/litellm/chat.js +16 -0
  35. package/dist/llm/litellm/index.d.ts +1 -0
  36. package/dist/llm/litellm/index.js +1 -0
  37. package/dist/llm/models.js +29 -3
  38. package/dist/llm/oci-raw/chat.d.ts +64 -0
  39. package/dist/llm/oci-raw/chat.js +350 -0
  40. package/dist/llm/oci-raw/index.d.ts +2 -0
  41. package/dist/llm/oci-raw/index.js +2 -0
  42. package/dist/llm/oci-raw/serializer.d.ts +12 -0
  43. package/dist/llm/oci-raw/serializer.js +128 -0
  44. package/dist/mcp/server.d.ts +1 -0
  45. package/dist/mcp/server.js +62 -13
  46. package/dist/skill-cli/direct.d.ts +100 -0
  47. package/dist/skill-cli/direct.js +984 -0
  48. package/dist/skill-cli/index.d.ts +2 -0
  49. package/dist/skill-cli/index.js +2 -0
  50. package/dist/skill-cli/server.d.ts +2 -0
  51. package/dist/skill-cli/server.js +472 -11
  52. package/dist/skill-cli/tunnel.d.ts +61 -0
  53. package/dist/skill-cli/tunnel.js +257 -0
  54. package/dist/sync/auth.d.ts +8 -0
  55. package/dist/sync/auth.js +12 -0
  56. package/dist/utils.d.ts +1 -1
  57. package/dist/utils.js +2 -1
  58. package/package.json +22 -4
@@ -0,0 +1,11 @@
1
+ import { ChatOpenAILike } from '../openai/like.js';
2
+ import type { ChatOpenAIOptions } from '../openai/chat.js';
3
+ export interface ChatLiteLLMOptions extends ChatOpenAIOptions {
4
+ model?: string;
5
+ apiKey?: string;
6
+ baseURL?: string;
7
+ }
8
+ export declare class ChatLiteLLM extends ChatOpenAILike {
9
+ provider: string;
10
+ constructor(options?: string | ChatLiteLLMOptions);
11
+ }
@@ -0,0 +1,16 @@
1
+ import { ChatOpenAILike } from '../openai/like.js';
2
+ export class ChatLiteLLM extends ChatOpenAILike {
3
+ provider = 'litellm';
4
+ constructor(options = {}) {
5
+ const normalizedOptions = typeof options === 'string' ? { model: options } : options;
6
+ super({
7
+ ...normalizedOptions,
8
+ model: normalizedOptions.model ?? 'gpt-4o-mini',
9
+ apiKey: normalizedOptions.apiKey ?? process.env.LITELLM_API_KEY,
10
+ baseURL: normalizedOptions.baseURL ??
11
+ process.env.LITELLM_API_BASE ??
12
+ process.env.LITELLM_BASE_URL ??
13
+ 'http://localhost:4000',
14
+ });
15
+ }
16
+ }
@@ -0,0 +1 @@
1
+ export * from './chat.js';
@@ -0,0 +1 @@
1
+ export * from './chat.js';
@@ -6,7 +6,9 @@ import { ChatCerebras } from './cerebras/chat.js';
6
6
  import { ChatDeepSeek } from './deepseek/chat.js';
7
7
  import { ChatGoogle } from './google/chat.js';
8
8
  import { ChatGroq } from './groq/chat.js';
9
+ import { ChatLiteLLM } from './litellm/chat.js';
9
10
  import { ChatMistral } from './mistral/chat.js';
11
+ import { ChatOCIRaw } from './oci-raw/chat.js';
10
12
  import { ChatOllama } from './ollama/chat.js';
11
13
  import { ChatOpenAI } from './openai/chat.js';
12
14
  import { ChatOpenRouter } from './openrouter/chat.js';
@@ -25,6 +27,8 @@ const AVAILABLE_PROVIDERS = [
25
27
  'mistral',
26
28
  'cerebras',
27
29
  'vercel',
30
+ 'litellm',
31
+ 'oci',
28
32
  ];
29
33
  const MISTRAL_ALIAS_MAP = {
30
34
  large: 'mistral-large-latest',
@@ -132,6 +136,12 @@ const inferProviderFromModel = (model) => {
132
136
  if (lower.startsWith('vercel:')) {
133
137
  return 'vercel';
134
138
  }
139
+ if (lower.startsWith('litellm:')) {
140
+ return 'litellm';
141
+ }
142
+ if (lower.startsWith('oci:')) {
143
+ return 'oci';
144
+ }
135
145
  if (lower.startsWith('mistral-') ||
136
146
  lower.startsWith('codestral') ||
137
147
  lower.startsWith('pixtral')) {
@@ -182,6 +192,12 @@ const normalizeModelForProvider = (provider, model) => {
182
192
  if (provider === 'vercel' && lower.startsWith('vercel:')) {
183
193
  return model.slice('vercel:'.length);
184
194
  }
195
+ if (provider === 'litellm' && lower.startsWith('litellm:')) {
196
+ return model.slice('litellm:'.length);
197
+ }
198
+ if (provider === 'oci' && lower.startsWith('oci:')) {
199
+ return model.slice('oci:'.length);
200
+ }
185
201
  if (provider === 'aws' && lower.startsWith('bedrock:')) {
186
202
  return model.slice('bedrock:'.length);
187
203
  }
@@ -248,6 +264,16 @@ const buildProviderModel = (provider, model) => {
248
264
  apiKey: process.env.VERCEL_API_KEY,
249
265
  baseURL: process.env.VERCEL_BASE_URL,
250
266
  });
267
+ case 'litellm':
268
+ return new ChatLiteLLM({
269
+ model,
270
+ apiKey: process.env.LITELLM_API_KEY,
271
+ baseURL: process.env.LITELLM_API_BASE ?? process.env.LITELLM_BASE_URL,
272
+ });
273
+ case 'oci':
274
+ return new ChatOCIRaw({
275
+ model,
276
+ });
251
277
  case 'aws':
252
278
  return new ChatBedrockConverse({
253
279
  model,
@@ -294,13 +320,13 @@ export const getLlmByName = (modelName) => {
294
320
  const separator = normalizedName.indexOf('_');
295
321
  if (separator > 0) {
296
322
  const provider = normalizedName.slice(0, separator);
297
- if (provider === 'oci') {
298
- throw new Error('OCI models require manual configuration. Use ChatOCIRaw directly with your OCI credentials.');
299
- }
300
323
  const modelPart = normalizedName.slice(separator + 1);
301
324
  if (provider === 'bu') {
302
325
  return buildProviderModel('browser-use', `bu-${modelPart.replace(/_/g, '-')}`);
303
326
  }
327
+ if (provider === 'oci') {
328
+ return buildProviderModel('oci', modelPart);
329
+ }
304
330
  if (provider === 'browser-use') {
305
331
  return buildProviderModel('browser-use', modelPart.replace(/_/g, '/'));
306
332
  }
@@ -0,0 +1,64 @@
1
+ import type { BaseChatModel, ChatInvokeOptions } from '../base.js';
2
+ import type { Message } from '../messages.js';
3
+ import { ChatInvokeCompletion } from '../views.js';
4
+ export interface ChatOCIRawOptions {
5
+ model?: string;
6
+ modelId?: string;
7
+ serviceEndpoint?: string;
8
+ compartmentId?: string;
9
+ provider?: string;
10
+ temperature?: number | null;
11
+ maxTokens?: number | null;
12
+ frequencyPenalty?: number | null;
13
+ presencePenalty?: number | null;
14
+ topP?: number | null;
15
+ topK?: number | null;
16
+ authType?: 'API_KEY' | 'INSTANCE_PRINCIPAL' | 'RESOURCE_PRINCIPAL' | string;
17
+ authProfile?: string;
18
+ configFilePath?: string;
19
+ tenancyId?: string;
20
+ userId?: string;
21
+ fingerprint?: string;
22
+ privateKey?: string;
23
+ passphrase?: string | null;
24
+ responseSchemaName?: string;
25
+ }
26
+ export declare class ChatOCIRaw implements BaseChatModel {
27
+ model: string;
28
+ provider: string;
29
+ private readonly serviceEndpoint;
30
+ private readonly compartmentId;
31
+ private readonly ociProvider;
32
+ private readonly temperature;
33
+ private readonly maxTokens;
34
+ private readonly frequencyPenalty;
35
+ private readonly presencePenalty;
36
+ private readonly topP;
37
+ private readonly topK;
38
+ private readonly authType;
39
+ private readonly authProfile;
40
+ private readonly configFilePath?;
41
+ private readonly tenancyId?;
42
+ private readonly userId?;
43
+ private readonly fingerprint?;
44
+ private readonly privateKey?;
45
+ private readonly passphrase;
46
+ private readonly responseSchemaName;
47
+ private clientPromise;
48
+ constructor(options?: ChatOCIRawOptions);
49
+ get name(): string;
50
+ get model_name(): string;
51
+ private usesCohereFormat;
52
+ private createAuthProvider;
53
+ private getClient;
54
+ private getUsage;
55
+ private buildGenericRequest;
56
+ private buildCohereRequest;
57
+ private buildChatRequest;
58
+ private extractText;
59
+ private mapError;
60
+ ainvoke(messages: Message[], outputFormat?: undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<string>>;
61
+ ainvoke<T>(messages: Message[], outputFormat: {
62
+ parse: (input: unknown) => T;
63
+ } | undefined, options?: ChatInvokeOptions): Promise<ChatInvokeCompletion<T>>;
64
+ }
@@ -0,0 +1,350 @@
1
+ import { ConfigFileAuthenticationDetailsProvider, InstancePrincipalsAuthenticationDetailsProviderBuilder, ResourcePrincipalAuthenticationDetailsProvider, SimpleAuthenticationDetailsProvider, } from 'oci-common';
2
+ import { GenerativeAiInferenceClient } from 'oci-generativeaiinference';
3
+ import { ModelProviderError, ModelRateLimitError } from '../exceptions.js';
4
+ import { SchemaOptimizer, zodSchemaToJsonSchema } from '../schema.js';
5
+ import { ChatInvokeCompletion } from '../views.js';
6
+ import { OCIRawMessageSerializer } from './serializer.js';
7
+ const parseStructuredJson = (text) => {
8
+ let jsonText = String(text ?? '').trim();
9
+ if (jsonText.startsWith('```json') && jsonText.endsWith('```')) {
10
+ jsonText = jsonText.slice(7, -3).trim();
11
+ }
12
+ else if (jsonText.startsWith('```') && jsonText.endsWith('```')) {
13
+ jsonText = jsonText.slice(3, -3).trim();
14
+ }
15
+ return JSON.parse(jsonText);
16
+ };
17
+ const extractZodSchema = (outputFormat) => {
18
+ const direct = outputFormat;
19
+ if (direct &&
20
+ typeof direct === 'object' &&
21
+ typeof direct.safeParse === 'function' &&
22
+ typeof direct.parse === 'function') {
23
+ return direct;
24
+ }
25
+ const nested = outputFormat?.schema;
26
+ if (nested &&
27
+ typeof nested === 'object' &&
28
+ typeof nested.safeParse === 'function' &&
29
+ typeof nested.parse === 'function') {
30
+ return nested;
31
+ }
32
+ return null;
33
+ };
34
+ const parseOutput = (outputFormat, payload) => {
35
+ const maybeWrapped = outputFormat;
36
+ if (maybeWrapped &&
37
+ typeof maybeWrapped === 'object' &&
38
+ maybeWrapped.schema &&
39
+ typeof maybeWrapped.schema.parse === 'function') {
40
+ return maybeWrapped.schema.parse(payload);
41
+ }
42
+ return outputFormat.parse(payload);
43
+ };
44
+ const appendJsonInstruction = (messages, schema) => {
45
+ const instruction = '\n\nIMPORTANT: You must respond with ONLY a valid JSON object ' +
46
+ '(no markdown, no code blocks, no explanations)' +
47
+ (schema
48
+ ? ` that exactly matches this schema:\n${JSON.stringify(schema, null, 2)}`
49
+ : '.');
50
+ const target = [...messages]
51
+ .reverse()
52
+ .find((message) => message.role === 'USER' || message.role === 'SYSTEM') ?? null;
53
+ if (target) {
54
+ const content = Array.isArray(target.content)
55
+ ? [...target.content]
56
+ : [];
57
+ content.push({
58
+ type: 'TEXT',
59
+ text: instruction,
60
+ });
61
+ target.content = content;
62
+ return messages;
63
+ }
64
+ return [
65
+ {
66
+ role: 'SYSTEM',
67
+ content: [
68
+ {
69
+ type: 'TEXT',
70
+ text: instruction,
71
+ },
72
+ ],
73
+ },
74
+ ...messages,
75
+ ];
76
+ };
77
+ export class ChatOCIRaw {
78
+ model;
79
+ provider = 'oci-raw';
80
+ serviceEndpoint;
81
+ compartmentId;
82
+ ociProvider;
83
+ temperature;
84
+ maxTokens;
85
+ frequencyPenalty;
86
+ presencePenalty;
87
+ topP;
88
+ topK;
89
+ authType;
90
+ authProfile;
91
+ configFilePath;
92
+ tenancyId;
93
+ userId;
94
+ fingerprint;
95
+ privateKey;
96
+ passphrase;
97
+ responseSchemaName;
98
+ clientPromise = null;
99
+ constructor(options = {}) {
100
+ this.model =
101
+ options.model ??
102
+ options.modelId ??
103
+ process.env.OCI_MODEL_ID ??
104
+ (() => {
105
+ throw new Error('ChatOCIRaw requires model or OCI_MODEL_ID');
106
+ })();
107
+ this.serviceEndpoint =
108
+ options.serviceEndpoint ??
109
+ process.env.OCI_SERVICE_ENDPOINT ??
110
+ (() => {
111
+ throw new Error('ChatOCIRaw requires serviceEndpoint or OCI_SERVICE_ENDPOINT');
112
+ })();
113
+ this.compartmentId =
114
+ options.compartmentId ??
115
+ process.env.OCI_COMPARTMENT_ID ??
116
+ (() => {
117
+ throw new Error('ChatOCIRaw requires compartmentId or OCI_COMPARTMENT_ID');
118
+ })();
119
+ this.ociProvider = options.provider ?? process.env.OCI_PROVIDER ?? 'meta';
120
+ this.temperature = options.temperature ?? 1.0;
121
+ this.maxTokens = options.maxTokens ?? 600;
122
+ this.frequencyPenalty = options.frequencyPenalty ?? 0.0;
123
+ this.presencePenalty = options.presencePenalty ?? 0.0;
124
+ this.topP = options.topP ?? 0.75;
125
+ this.topK = options.topK ?? 0;
126
+ this.authType = options.authType ?? process.env.OCI_AUTH_TYPE ?? 'API_KEY';
127
+ this.authProfile =
128
+ options.authProfile ??
129
+ process.env.OCI_AUTH_PROFILE ??
130
+ process.env.OCI_CONFIG_PROFILE ??
131
+ 'DEFAULT';
132
+ this.configFilePath = options.configFilePath ?? process.env.OCI_CONFIG_FILE;
133
+ this.tenancyId = options.tenancyId ?? process.env.OCI_TENANCY_ID;
134
+ this.userId = options.userId ?? process.env.OCI_USER_ID;
135
+ this.fingerprint = options.fingerprint ?? process.env.OCI_FINGERPRINT;
136
+ this.privateKey = options.privateKey ?? process.env.OCI_PRIVATE_KEY;
137
+ this.passphrase =
138
+ options.passphrase ?? process.env.OCI_PRIVATE_KEY_PASSPHRASE ?? null;
139
+ this.responseSchemaName =
140
+ options.responseSchemaName ?? 'browser_use_response';
141
+ }
142
+ get name() {
143
+ if (this.model.length <= 90) {
144
+ return this.model;
145
+ }
146
+ const parts = this.model.split('.');
147
+ if (parts.length >= 4) {
148
+ return `oci-${this.ociProvider}-${parts[3]}`;
149
+ }
150
+ return `oci-${this.ociProvider}-model`;
151
+ }
152
+ get model_name() {
153
+ return this.name;
154
+ }
155
+ usesCohereFormat() {
156
+ return this.ociProvider.toLowerCase() === 'cohere';
157
+ }
158
+ async createAuthProvider() {
159
+ const authType = this.authType.toUpperCase();
160
+ if (authType === 'INSTANCE_PRINCIPAL') {
161
+ return new InstancePrincipalsAuthenticationDetailsProviderBuilder().build();
162
+ }
163
+ if (authType === 'RESOURCE_PRINCIPAL') {
164
+ return ResourcePrincipalAuthenticationDetailsProvider.builder();
165
+ }
166
+ if (this.tenancyId && this.userId && this.fingerprint && this.privateKey) {
167
+ return new SimpleAuthenticationDetailsProvider(this.tenancyId, this.userId, this.fingerprint, this.privateKey, this.passphrase);
168
+ }
169
+ return new ConfigFileAuthenticationDetailsProvider(this.configFilePath, this.authProfile);
170
+ }
171
+ async getClient() {
172
+ if (!this.clientPromise) {
173
+ this.clientPromise = (async () => {
174
+ const authenticationDetailsProvider = await this.createAuthProvider();
175
+ const client = new GenerativeAiInferenceClient({
176
+ authenticationDetailsProvider,
177
+ });
178
+ client.endpoint = this.serviceEndpoint;
179
+ return client;
180
+ })();
181
+ }
182
+ return this.clientPromise;
183
+ }
184
+ getUsage(payload) {
185
+ const usage = payload?.usage;
186
+ if (!usage) {
187
+ return null;
188
+ }
189
+ const reasoningTokens = usage.completionTokensDetails?.reasoningTokens ?? 0;
190
+ const completionTokens = (usage.completionTokens ?? 0) + reasoningTokens;
191
+ return {
192
+ prompt_tokens: usage.promptTokens ?? 0,
193
+ prompt_cached_tokens: usage.promptTokensDetails?.cachedTokens ?? null,
194
+ prompt_cache_creation_tokens: null,
195
+ prompt_image_tokens: null,
196
+ completion_tokens: completionTokens,
197
+ total_tokens: usage.totalTokens ?? (usage.promptTokens ?? 0) + completionTokens,
198
+ };
199
+ }
200
+ buildGenericRequest(messages, outputFormat) {
201
+ const zodSchema = extractZodSchema(outputFormat);
202
+ const serializedMessages = OCIRawMessageSerializer.serializeMessages(messages);
203
+ const optimizedSchema = zodSchema
204
+ ? SchemaOptimizer.createOptimizedJsonSchema(zodSchemaToJsonSchema(zodSchema))
205
+ : null;
206
+ const requestMessages = outputFormat && !zodSchema
207
+ ? appendJsonInstruction(serializedMessages, null)
208
+ : serializedMessages;
209
+ const request = {
210
+ apiFormat: 'GENERIC',
211
+ messages: requestMessages,
212
+ };
213
+ if (this.temperature !== null) {
214
+ request.temperature = this.temperature;
215
+ }
216
+ if (this.maxTokens !== null) {
217
+ request.maxTokens = this.maxTokens;
218
+ }
219
+ if (this.frequencyPenalty !== null) {
220
+ request.frequencyPenalty = this.frequencyPenalty;
221
+ }
222
+ if (this.presencePenalty !== null) {
223
+ request.presencePenalty = this.presencePenalty;
224
+ }
225
+ if (this.topP !== null) {
226
+ request.topP = this.topP;
227
+ }
228
+ if (this.topK !== null) {
229
+ request.topK = this.topK;
230
+ }
231
+ if (optimizedSchema) {
232
+ request.responseFormat = {
233
+ type: 'JSON_SCHEMA',
234
+ jsonSchema: {
235
+ name: this.responseSchemaName,
236
+ schema: optimizedSchema,
237
+ isStrict: true,
238
+ },
239
+ };
240
+ }
241
+ return request;
242
+ }
243
+ buildCohereRequest(messages, outputFormat) {
244
+ const zodSchema = extractZodSchema(outputFormat);
245
+ const optimizedSchema = zodSchema
246
+ ? SchemaOptimizer.createOptimizedJsonSchema(zodSchemaToJsonSchema(zodSchema))
247
+ : null;
248
+ let conversation = OCIRawMessageSerializer.serializeMessagesForCohere(messages);
249
+ if (outputFormat) {
250
+ conversation +=
251
+ '\n\nIMPORTANT: You must respond with ONLY a valid JSON object (no markdown, no code blocks, no explanations)' +
252
+ (optimizedSchema
253
+ ? ` that exactly matches this schema:\n${JSON.stringify(optimizedSchema, null, 2)}`
254
+ : '.');
255
+ }
256
+ const request = {
257
+ apiFormat: 'COHERE',
258
+ message: conversation,
259
+ };
260
+ if (this.temperature !== null) {
261
+ request.temperature = this.temperature;
262
+ }
263
+ if (this.maxTokens !== null) {
264
+ request.maxTokens = this.maxTokens;
265
+ }
266
+ if (this.frequencyPenalty !== null) {
267
+ request.frequencyPenalty = this.frequencyPenalty;
268
+ }
269
+ if (this.presencePenalty !== null) {
270
+ request.presencePenalty = this.presencePenalty;
271
+ }
272
+ if (this.topP !== null) {
273
+ request.topP = this.topP;
274
+ }
275
+ if (this.topK !== null) {
276
+ request.topK = this.topK;
277
+ }
278
+ return request;
279
+ }
280
+ buildChatRequest(messages, outputFormat) {
281
+ const chatRequest = this.usesCohereFormat()
282
+ ? this.buildCohereRequest(messages, outputFormat)
283
+ : this.buildGenericRequest(messages, outputFormat);
284
+ return {
285
+ chatDetails: {
286
+ compartmentId: this.compartmentId,
287
+ servingMode: {
288
+ servingType: 'ON_DEMAND',
289
+ modelId: this.model,
290
+ },
291
+ chatRequest,
292
+ },
293
+ };
294
+ }
295
+ extractText(payload) {
296
+ if (!payload) {
297
+ throw new ModelProviderError('OCI response did not include chatResponse payload', 502, this.name);
298
+ }
299
+ if (payload.apiFormat === 'COHERE') {
300
+ const coherePayload = payload;
301
+ return {
302
+ text: coherePayload.text ?? '',
303
+ thinking: null,
304
+ stopReason: coherePayload.finishReason ?? null,
305
+ };
306
+ }
307
+ const genericPayload = payload;
308
+ const choice = genericPayload.choices?.[0];
309
+ const text = choice?.message?.content
310
+ ?.filter((part) => part.type === 'TEXT')
311
+ .map((part) => part.text ?? '')
312
+ .join('\n')
313
+ .trim();
314
+ return {
315
+ text: text ?? '',
316
+ thinking: choice?.message?.reasoningContent ?? null,
317
+ stopReason: choice?.finishReason ?? null,
318
+ };
319
+ }
320
+ mapError(error) {
321
+ const statusCode = typeof error?.statusCode === 'number'
322
+ ? error.statusCode
323
+ : 502;
324
+ const message = String(error?.message ?? error ?? 'OCI request failed');
325
+ if (statusCode === 429) {
326
+ throw new ModelRateLimitError(message, statusCode, this.name);
327
+ }
328
+ throw new ModelProviderError(message, statusCode, this.name);
329
+ }
330
+ async ainvoke(messages, outputFormat, _options = {}) {
331
+ try {
332
+ const client = await this.getClient();
333
+ const response = (await client.chat(this.buildChatRequest(messages, outputFormat)));
334
+ if (!response || typeof response !== 'object') {
335
+ throw new ModelProviderError('OCI chat request returned an empty response', 502, this.name);
336
+ }
337
+ const payload = response.chatResult?.chatResponse;
338
+ const usage = this.getUsage(payload);
339
+ const { text, thinking, stopReason } = this.extractText(payload);
340
+ if (!outputFormat) {
341
+ return new ChatInvokeCompletion(text, usage, thinking, null, stopReason);
342
+ }
343
+ const parsed = parseOutput(outputFormat, parseStructuredJson(text));
344
+ return new ChatInvokeCompletion(parsed, usage, thinking, null, stopReason);
345
+ }
346
+ catch (error) {
347
+ this.mapError(error);
348
+ }
349
+ }
350
+ }
@@ -0,0 +1,2 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
@@ -0,0 +1,2 @@
1
+ export * from './chat.js';
2
+ export * from './serializer.js';
@@ -0,0 +1,12 @@
1
+ import { type Message } from '../messages.js';
2
+ type OciChatContent = Record<string, unknown>;
3
+ type OciMessage = {
4
+ role: string;
5
+ name?: string;
6
+ content: OciChatContent[];
7
+ };
8
+ export declare class OCIRawMessageSerializer {
9
+ static serializeMessages(messages: Message[]): OciMessage[];
10
+ static serializeMessagesForCohere(messages: Message[]): string;
11
+ }
12
+ export {};
@@ -0,0 +1,128 @@
1
+ import { AssistantMessage, ContentPartImageParam, ContentPartRefusalParam, ContentPartTextParam, SystemMessage, UserMessage, } from '../messages.js';
2
+ const textContent = (text) => ({
3
+ type: 'TEXT',
4
+ text,
5
+ });
6
+ const imageContent = (url) => ({
7
+ type: 'IMAGE',
8
+ imageUrl: {
9
+ url,
10
+ },
11
+ });
12
+ const contentPartsToOci = (content) => {
13
+ if (typeof content === 'string') {
14
+ return [textContent(content)];
15
+ }
16
+ if (!Array.isArray(content)) {
17
+ return [];
18
+ }
19
+ const parts = [];
20
+ for (const part of content) {
21
+ if (part instanceof ContentPartTextParam) {
22
+ parts.push(textContent(part.text));
23
+ continue;
24
+ }
25
+ if (part instanceof ContentPartImageParam) {
26
+ parts.push(imageContent(part.image_url.url));
27
+ continue;
28
+ }
29
+ if (part instanceof ContentPartRefusalParam) {
30
+ parts.push(textContent(`[Refusal] ${part.refusal}`));
31
+ }
32
+ }
33
+ return parts;
34
+ };
35
+ const serializeRole = (message) => {
36
+ if (message instanceof SystemMessage) {
37
+ return 'SYSTEM';
38
+ }
39
+ if (message instanceof AssistantMessage) {
40
+ return 'ASSISTANT';
41
+ }
42
+ return 'USER';
43
+ };
44
+ const serializeName = (message) => {
45
+ if (message instanceof UserMessage || message instanceof SystemMessage) {
46
+ return message.name ?? undefined;
47
+ }
48
+ return undefined;
49
+ };
50
+ export class OCIRawMessageSerializer {
51
+ static serializeMessages(messages) {
52
+ const serialized = [];
53
+ for (const message of messages) {
54
+ const content = message instanceof AssistantMessage
55
+ ? contentPartsToOci(message.content)
56
+ : contentPartsToOci(message.content);
57
+ if (content.length === 0) {
58
+ continue;
59
+ }
60
+ serialized.push({
61
+ role: serializeRole(message),
62
+ name: serializeName(message),
63
+ content,
64
+ });
65
+ }
66
+ return serialized;
67
+ }
68
+ static serializeMessagesForCohere(messages) {
69
+ const conversationParts = [];
70
+ for (const message of messages) {
71
+ let text = '';
72
+ if (message instanceof UserMessage || message instanceof SystemMessage) {
73
+ const content = message.content;
74
+ if (typeof content === 'string') {
75
+ text = content;
76
+ }
77
+ else {
78
+ text = content
79
+ .map((part) => {
80
+ if (part instanceof ContentPartTextParam) {
81
+ return part.text;
82
+ }
83
+ if (part instanceof ContentPartImageParam) {
84
+ return part.image_url.url.startsWith('data:image/')
85
+ ? '[Image: base64_data]'
86
+ : '[Image: external_url]';
87
+ }
88
+ return '';
89
+ })
90
+ .filter(Boolean)
91
+ .join(' ');
92
+ }
93
+ }
94
+ else if (message instanceof AssistantMessage) {
95
+ if (typeof message.content === 'string') {
96
+ text = message.content;
97
+ }
98
+ else if (Array.isArray(message.content)) {
99
+ text = message.content
100
+ .map((part) => {
101
+ if (part instanceof ContentPartTextParam) {
102
+ return part.text;
103
+ }
104
+ if (part instanceof ContentPartRefusalParam) {
105
+ return `[Refusal] ${part.refusal}`;
106
+ }
107
+ return '';
108
+ })
109
+ .filter(Boolean)
110
+ .join(' ');
111
+ }
112
+ else if (message.refusal) {
113
+ text = `[Refusal] ${message.refusal}`;
114
+ }
115
+ }
116
+ if (!text) {
117
+ continue;
118
+ }
119
+ const prefix = message instanceof SystemMessage
120
+ ? 'System'
121
+ : message instanceof AssistantMessage
122
+ ? 'Assistant'
123
+ : 'User';
124
+ conversationParts.push(`${prefix}: ${text}`);
125
+ }
126
+ return conversationParts.join('\n\n');
127
+ }
128
+ }
@@ -75,6 +75,7 @@ export declare class MCPServer {
75
75
  private cleanupExpiredSessions;
76
76
  private startSessionCleanupLoop;
77
77
  private stopSessionCleanupLoop;
78
+ private formatToolResult;
78
79
  private setupHandlers;
79
80
  private ensureController;
80
81
  private ensureBrowserSession;