browser-use 0.5.0 → 0.6.1

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 (61) hide show
  1. package/README.md +22 -17
  2. package/dist/agent/service.js +13 -2
  3. package/dist/agent/system_prompt.md +269 -0
  4. package/dist/agent/system_prompt_anthropic_flash.md +240 -0
  5. package/dist/agent/system_prompt_browser_use.md +18 -0
  6. package/dist/agent/system_prompt_browser_use_flash.md +15 -0
  7. package/dist/agent/system_prompt_browser_use_no_thinking.md +17 -0
  8. package/dist/agent/system_prompt_flash.md +16 -0
  9. package/dist/agent/system_prompt_flash_anthropic.md +30 -0
  10. package/dist/agent/system_prompt_no_thinking.md +245 -0
  11. package/dist/browser/cloud/index.d.ts +1 -0
  12. package/dist/browser/cloud/index.js +1 -0
  13. package/dist/browser/cloud/management.d.ts +130 -0
  14. package/dist/browser/cloud/management.js +140 -0
  15. package/dist/browser/events.d.ts +61 -3
  16. package/dist/browser/events.js +66 -0
  17. package/dist/browser/profile.d.ts +1 -0
  18. package/dist/browser/profile.js +1 -0
  19. package/dist/browser/session.d.ts +56 -2
  20. package/dist/browser/session.js +596 -24
  21. package/dist/browser/watchdogs/base.js +34 -1
  22. package/dist/browser/watchdogs/captcha-watchdog.d.ts +26 -0
  23. package/dist/browser/watchdogs/captcha-watchdog.js +151 -0
  24. package/dist/browser/watchdogs/index.d.ts +1 -0
  25. package/dist/browser/watchdogs/index.js +1 -0
  26. package/dist/browser/watchdogs/screenshot-watchdog.js +4 -3
  27. package/dist/cli.d.ts +120 -0
  28. package/dist/cli.js +1817 -5
  29. package/dist/config.js +1 -1
  30. package/dist/controller/registry/views.d.ts +2 -0
  31. package/dist/controller/registry/views.js +44 -17
  32. package/dist/controller/service.js +106 -362
  33. package/dist/controller/views.d.ts +9 -6
  34. package/dist/controller/views.js +8 -5
  35. package/dist/filesystem/file-system.js +1 -1
  36. package/dist/llm/litellm/chat.d.ts +11 -0
  37. package/dist/llm/litellm/chat.js +16 -0
  38. package/dist/llm/litellm/index.d.ts +1 -0
  39. package/dist/llm/litellm/index.js +1 -0
  40. package/dist/llm/models.js +29 -3
  41. package/dist/llm/oci-raw/chat.d.ts +64 -0
  42. package/dist/llm/oci-raw/chat.js +350 -0
  43. package/dist/llm/oci-raw/index.d.ts +2 -0
  44. package/dist/llm/oci-raw/index.js +2 -0
  45. package/dist/llm/oci-raw/serializer.d.ts +12 -0
  46. package/dist/llm/oci-raw/serializer.js +128 -0
  47. package/dist/mcp/server.d.ts +1 -0
  48. package/dist/mcp/server.js +62 -13
  49. package/dist/observability.js +1 -1
  50. package/dist/skill-cli/direct.d.ts +100 -0
  51. package/dist/skill-cli/direct.js +984 -0
  52. package/dist/skill-cli/index.d.ts +2 -0
  53. package/dist/skill-cli/index.js +2 -0
  54. package/dist/skill-cli/server.d.ts +2 -0
  55. package/dist/skill-cli/server.js +472 -11
  56. package/dist/skill-cli/tunnel.d.ts +61 -0
  57. package/dist/skill-cli/tunnel.js +257 -0
  58. package/dist/sync/auth.d.ts +8 -0
  59. package/dist/sync/auth.js +12 -0
  60. package/dist/utils.js +1 -1
  61. package/package.json +31 -12
@@ -77,6 +77,14 @@ export declare const ScreenshotActionSchema: z.ZodObject<{
77
77
  file_name: z.ZodOptional<z.ZodString>;
78
78
  }, z.core.$strip>;
79
79
  export type ScreenshotAction = z.infer<typeof ScreenshotActionSchema>;
80
+ export declare const SaveAsPdfActionSchema: z.ZodObject<{
81
+ file_name: z.ZodOptional<z.ZodString>;
82
+ print_background: z.ZodDefault<z.ZodBoolean>;
83
+ landscape: z.ZodDefault<z.ZodBoolean>;
84
+ scale: z.ZodDefault<z.ZodNumber>;
85
+ paper_format: z.ZodDefault<z.ZodString>;
86
+ }, z.core.$strip>;
87
+ export type SaveAsPdfAction = z.infer<typeof SaveAsPdfActionSchema>;
80
88
  export declare const EvaluateActionSchema: z.ZodObject<{
81
89
  code: z.ZodString;
82
90
  }, z.core.$strip>;
@@ -90,6 +98,7 @@ export declare const ExtractStructuredDataActionSchema: z.ZodObject<{
90
98
  extract_links: z.ZodDefault<z.ZodBoolean>;
91
99
  start_from_char: z.ZodDefault<z.ZodNumber>;
92
100
  output_schema: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
101
+ already_collected: z.ZodDefault<z.ZodArray<z.ZodString>>;
93
102
  }, z.core.$strip>;
94
103
  export type ExtractStructuredDataAction = z.infer<typeof ExtractStructuredDataActionSchema>;
95
104
  export declare const SearchPageActionSchema: z.ZodObject<{
@@ -112,12 +121,6 @@ export declare const ReadFileActionSchema: z.ZodObject<{
112
121
  file_name: z.ZodString;
113
122
  }, z.core.$strip>;
114
123
  export type ReadFileAction = z.infer<typeof ReadFileActionSchema>;
115
- export declare const ReadLongContentActionSchema: z.ZodObject<{
116
- goal: z.ZodString;
117
- source: z.ZodDefault<z.ZodString>;
118
- context: z.ZodDefault<z.ZodString>;
119
- }, z.core.$strip>;
120
- export type ReadLongContentAction = z.infer<typeof ReadLongContentActionSchema>;
121
124
  export declare const WriteFileActionSchema: z.ZodObject<{
122
125
  file_name: z.ZodString;
123
126
  content: z.ZodString;
@@ -64,6 +64,13 @@ export const UploadFileActionSchema = z.object({
64
64
  export const ScreenshotActionSchema = z.object({
65
65
  file_name: z.string().optional(),
66
66
  });
67
+ export const SaveAsPdfActionSchema = z.object({
68
+ file_name: z.string().optional(),
69
+ print_background: z.boolean().default(true),
70
+ landscape: z.boolean().default(false),
71
+ scale: z.number().min(0.1).max(2.0).default(1.0),
72
+ paper_format: z.string().default('Letter'),
73
+ });
67
74
  export const EvaluateActionSchema = z.object({
68
75
  code: z.string(),
69
76
  });
@@ -75,6 +82,7 @@ export const ExtractStructuredDataActionSchema = z.object({
75
82
  extract_links: z.boolean().default(false),
76
83
  start_from_char: z.number().int().default(0),
77
84
  output_schema: z.record(z.string(), z.unknown()).nullable().optional(),
85
+ already_collected: z.array(z.string()).default([]),
78
86
  });
79
87
  export const SearchPageActionSchema = z.object({
80
88
  pattern: z.string(),
@@ -93,11 +101,6 @@ export const FindElementsActionSchema = z.object({
93
101
  export const ReadFileActionSchema = z.object({
94
102
  file_name: z.string(),
95
103
  });
96
- export const ReadLongContentActionSchema = z.object({
97
- goal: z.string(),
98
- source: z.string().default('page'),
99
- context: z.string().default(''),
100
- });
101
104
  export const WriteFileActionSchema = z.object({
102
105
  file_name: z.string(),
103
106
  content: z.string(),
@@ -638,7 +638,7 @@ export class FileSystem {
638
638
  truncationNote =
639
639
  `\n\n[Showing ${pagesIncluded.length} of ${numPages} pages. ` +
640
640
  `Skipped pages: [${skippedPreview}${skippedSuffix}]. ` +
641
- 'Use read_long_content with a specific goal to find relevant sections.]';
641
+ 'Use extract with start_from_char to read further into the file.]';
642
642
  }
643
643
  result.message =
644
644
  `Read from file ${filename} (${numPages} pages, ${totalChars.toLocaleString()} chars total).\n` +
@@ -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 {};