@steipete/oracle 0.9.0 → 0.10.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 (177) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -48
  3. package/dist/bin/oracle-cli.js +455 -402
  4. package/dist/bin/oracle-mcp.js +2 -2
  5. package/dist/bin/oracle.js +165 -279
  6. package/dist/scripts/agent-send.js +31 -31
  7. package/dist/scripts/check.js +6 -6
  8. package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
  9. package/dist/scripts/docs-list.js +30 -30
  10. package/dist/scripts/git-policy.js +25 -23
  11. package/dist/scripts/run-cli.js +8 -8
  12. package/dist/scripts/runner.js +203 -195
  13. package/dist/scripts/test-browser.js +21 -18
  14. package/dist/scripts/test-remote-chrome.js +20 -20
  15. package/dist/src/bridge/connection.js +18 -18
  16. package/dist/src/bridge/userConfigFile.js +7 -7
  17. package/dist/src/browser/actions/assistantResponse.js +149 -101
  18. package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
  19. package/dist/src/browser/actions/attachments.js +246 -150
  20. package/dist/src/browser/actions/domEvents.js +2 -2
  21. package/dist/src/browser/actions/modelSelection.js +275 -117
  22. package/dist/src/browser/actions/navigation.js +161 -137
  23. package/dist/src/browser/actions/promptComposer.js +100 -64
  24. package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
  25. package/dist/src/browser/actions/thinkingTime.js +207 -110
  26. package/dist/src/browser/chromeLifecycle.js +62 -60
  27. package/dist/src/browser/config.js +34 -15
  28. package/dist/src/browser/constants.js +17 -12
  29. package/dist/src/browser/cookies.js +19 -19
  30. package/dist/src/browser/detect.js +62 -62
  31. package/dist/src/browser/domDebug.js +1 -1
  32. package/dist/src/browser/index.js +390 -295
  33. package/dist/src/browser/modelStrategy.js +1 -1
  34. package/dist/src/browser/pageActions.js +5 -5
  35. package/dist/src/browser/policies.js +16 -13
  36. package/dist/src/browser/profileState.js +44 -39
  37. package/dist/src/browser/prompt.js +72 -42
  38. package/dist/src/browser/promptSummary.js +5 -5
  39. package/dist/src/browser/providerDomFlow.js +1 -1
  40. package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
  41. package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
  42. package/dist/src/browser/providers/index.js +2 -2
  43. package/dist/src/browser/reattach.js +67 -34
  44. package/dist/src/browser/reattachHelpers.js +31 -26
  45. package/dist/src/browser/sessionRunner.js +37 -25
  46. package/dist/src/browser/utils.js +9 -9
  47. package/dist/src/browserMode.js +1 -1
  48. package/dist/src/cli/bridge/claudeConfig.js +16 -16
  49. package/dist/src/cli/bridge/client.js +28 -20
  50. package/dist/src/cli/bridge/codexConfig.js +16 -16
  51. package/dist/src/cli/bridge/doctor.js +47 -39
  52. package/dist/src/cli/bridge/host.js +58 -56
  53. package/dist/src/cli/browserConfig.js +62 -48
  54. package/dist/src/cli/browserDefaults.js +27 -26
  55. package/dist/src/cli/bundleWarnings.js +1 -1
  56. package/dist/src/cli/clipboard.js +11 -2
  57. package/dist/src/cli/detach.js +2 -2
  58. package/dist/src/cli/dryRun.js +29 -25
  59. package/dist/src/cli/duplicatePromptGuard.js +3 -3
  60. package/dist/src/cli/engine.js +9 -9
  61. package/dist/src/cli/errorUtils.js +1 -1
  62. package/dist/src/cli/fileSize.js +3 -3
  63. package/dist/src/cli/format.js +2 -2
  64. package/dist/src/cli/help.js +28 -28
  65. package/dist/src/cli/hiddenAliases.js +3 -3
  66. package/dist/src/cli/markdownBundle.js +7 -7
  67. package/dist/src/cli/markdownRenderer.js +15 -15
  68. package/dist/src/cli/notifier.js +77 -67
  69. package/dist/src/cli/options.js +127 -106
  70. package/dist/src/cli/oscUtils.js +1 -1
  71. package/dist/src/cli/promptRequirement.js +2 -2
  72. package/dist/src/cli/renderOutput.js +1 -1
  73. package/dist/src/cli/rootAlias.js +1 -1
  74. package/dist/src/cli/runOptions.js +32 -28
  75. package/dist/src/cli/sessionCommand.js +31 -21
  76. package/dist/src/cli/sessionDisplay.js +95 -81
  77. package/dist/src/cli/sessionLineage.js +6 -2
  78. package/dist/src/cli/sessionRunner.js +103 -93
  79. package/dist/src/cli/sessionTable.js +26 -23
  80. package/dist/src/cli/stdin.js +22 -0
  81. package/dist/src/cli/tagline.js +121 -124
  82. package/dist/src/cli/tui/index.js +139 -128
  83. package/dist/src/cli/writeOutputPath.js +5 -5
  84. package/dist/src/config.js +7 -7
  85. package/dist/src/gemini-web/browserSessionManager.js +19 -15
  86. package/dist/src/gemini-web/client.js +76 -70
  87. package/dist/src/gemini-web/executionMode.js +6 -8
  88. package/dist/src/gemini-web/executor.js +98 -93
  89. package/dist/src/gemini-web/index.js +1 -1
  90. package/dist/src/mcp/server.js +16 -12
  91. package/dist/src/mcp/tools/consult.js +51 -47
  92. package/dist/src/mcp/tools/sessionResources.js +12 -12
  93. package/dist/src/mcp/tools/sessions.js +26 -17
  94. package/dist/src/mcp/types.js +5 -5
  95. package/dist/src/mcp/utils.js +15 -7
  96. package/dist/src/oracle/background.js +15 -15
  97. package/dist/src/oracle/claude.js +53 -25
  98. package/dist/src/oracle/client.js +50 -41
  99. package/dist/src/oracle/config.js +96 -66
  100. package/dist/src/oracle/errors.js +38 -38
  101. package/dist/src/oracle/files.js +55 -46
  102. package/dist/src/oracle/finishLine.js +10 -8
  103. package/dist/src/oracle/format.js +3 -3
  104. package/dist/src/oracle/gemini.js +37 -33
  105. package/dist/src/oracle/logging.js +7 -7
  106. package/dist/src/oracle/markdown.js +28 -28
  107. package/dist/src/oracle/modelResolver.js +16 -16
  108. package/dist/src/oracle/multiModelRunner.js +12 -12
  109. package/dist/src/oracle/oscProgress.js +8 -8
  110. package/dist/src/oracle/promptAssembly.js +6 -3
  111. package/dist/src/oracle/request.js +16 -13
  112. package/dist/src/oracle/run.js +156 -134
  113. package/dist/src/oracle/runUtils.js +8 -5
  114. package/dist/src/oracle/tokenEstimate.js +6 -6
  115. package/dist/src/oracle/tokenStats.js +5 -5
  116. package/dist/src/oracle/tokenStringifier.js +5 -5
  117. package/dist/src/oracle.js +12 -12
  118. package/dist/src/oracleHome.js +3 -3
  119. package/dist/src/remote/client.js +25 -25
  120. package/dist/src/remote/health.js +20 -20
  121. package/dist/src/remote/remoteServiceConfig.js +9 -9
  122. package/dist/src/remote/server.js +129 -118
  123. package/dist/src/sessionManager.js +77 -75
  124. package/dist/src/sessionStore.js +3 -3
  125. package/dist/src/version.js +10 -10
  126. package/dist/vendor/oracle-notifier/README.md +2 -0
  127. package/package.json +66 -62
  128. package/vendor/oracle-notifier/README.md +2 -0
  129. package/dist/markdansi/types/index.js +0 -4
  130. package/dist/oracle/bin/oracle-cli.js +0 -472
  131. package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
  132. package/dist/oracle/src/browser/actions/attachments.js +0 -82
  133. package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
  134. package/dist/oracle/src/browser/actions/navigation.js +0 -75
  135. package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
  136. package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
  137. package/dist/oracle/src/browser/config.js +0 -33
  138. package/dist/oracle/src/browser/constants.js +0 -40
  139. package/dist/oracle/src/browser/cookies.js +0 -210
  140. package/dist/oracle/src/browser/domDebug.js +0 -36
  141. package/dist/oracle/src/browser/index.js +0 -331
  142. package/dist/oracle/src/browser/pageActions.js +0 -5
  143. package/dist/oracle/src/browser/prompt.js +0 -88
  144. package/dist/oracle/src/browser/promptSummary.js +0 -20
  145. package/dist/oracle/src/browser/sessionRunner.js +0 -80
  146. package/dist/oracle/src/browser/types.js +0 -1
  147. package/dist/oracle/src/browser/utils.js +0 -62
  148. package/dist/oracle/src/browserMode.js +0 -1
  149. package/dist/oracle/src/cli/browserConfig.js +0 -44
  150. package/dist/oracle/src/cli/dryRun.js +0 -59
  151. package/dist/oracle/src/cli/engine.js +0 -17
  152. package/dist/oracle/src/cli/errorUtils.js +0 -9
  153. package/dist/oracle/src/cli/help.js +0 -70
  154. package/dist/oracle/src/cli/markdownRenderer.js +0 -15
  155. package/dist/oracle/src/cli/options.js +0 -103
  156. package/dist/oracle/src/cli/promptRequirement.js +0 -14
  157. package/dist/oracle/src/cli/rootAlias.js +0 -30
  158. package/dist/oracle/src/cli/sessionCommand.js +0 -77
  159. package/dist/oracle/src/cli/sessionDisplay.js +0 -270
  160. package/dist/oracle/src/cli/sessionRunner.js +0 -94
  161. package/dist/oracle/src/heartbeat.js +0 -43
  162. package/dist/oracle/src/oracle/client.js +0 -48
  163. package/dist/oracle/src/oracle/config.js +0 -29
  164. package/dist/oracle/src/oracle/errors.js +0 -101
  165. package/dist/oracle/src/oracle/files.js +0 -220
  166. package/dist/oracle/src/oracle/format.js +0 -33
  167. package/dist/oracle/src/oracle/fsAdapter.js +0 -7
  168. package/dist/oracle/src/oracle/oscProgress.js +0 -60
  169. package/dist/oracle/src/oracle/request.js +0 -48
  170. package/dist/oracle/src/oracle/run.js +0 -444
  171. package/dist/oracle/src/oracle/tokenStats.js +0 -39
  172. package/dist/oracle/src/oracle/types.js +0 -1
  173. package/dist/oracle/src/oracle.js +0 -9
  174. package/dist/oracle/src/sessionManager.js +0 -205
  175. package/dist/oracle/src/version.js +0 -39
  176. package/dist/scripts/chrome/browser-tools.js +0 -295
  177. package/dist/src/browser/profileSync.js +0 -141
@@ -1,11 +1,11 @@
1
- const DEFAULT_CLAUDE_ENDPOINT = 'https://api.anthropic.com/v1/messages';
2
- const ANTHROPIC_VERSION = '2023-06-01';
1
+ const DEFAULT_CLAUDE_ENDPOINT = "https://api.anthropic.com/v1/messages";
2
+ const ANTHROPIC_VERSION = "2023-06-01";
3
3
  function extractPrompt(body) {
4
4
  const first = body.input?.[0]?.content?.[0];
5
- if (first && first.type === 'input_text') {
6
- return first.text ?? '';
5
+ if (first && first.type === "input_text") {
6
+ return first.text ?? "";
7
7
  }
8
- return '';
8
+ return "";
9
9
  }
10
10
  async function callClaude({ apiKey, model, prompt, endpoint, stream = false, }) {
11
11
  const url = endpoint?.trim() || DEFAULT_CLAUDE_ENDPOINT;
@@ -14,34 +14,45 @@ async function callClaude({ apiKey, model, prompt, endpoint, stream = false, })
14
14
  max_tokens: 2048,
15
15
  messages: [
16
16
  {
17
- role: 'user',
17
+ role: "user",
18
18
  content: prompt,
19
19
  },
20
20
  ],
21
21
  stream,
22
22
  };
23
23
  return fetch(url, {
24
- method: 'POST',
24
+ method: "POST",
25
25
  headers: {
26
- 'content-type': 'application/json',
27
- 'x-api-key': apiKey,
28
- 'anthropic-version': ANTHROPIC_VERSION,
26
+ "content-type": "application/json",
27
+ "x-api-key": apiKey,
28
+ "anthropic-version": ANTHROPIC_VERSION,
29
29
  },
30
30
  body: JSON.stringify(payload),
31
31
  });
32
32
  }
33
33
  async function parseClaudeResponse(raw) {
34
- const json = (await raw.json());
34
+ const body = await raw.text();
35
+ if (!body.trim()) {
36
+ throw new Error(`Claude request failed (${raw.status} ${raw.statusText || "unknown status"}): empty response`);
37
+ }
38
+ let json;
39
+ try {
40
+ json = JSON.parse(body);
41
+ }
42
+ catch (error) {
43
+ const snippet = body.slice(0, 160).replace(/\s+/g, " ").trim();
44
+ throw new Error(`Claude request failed (${raw.status} ${raw.statusText || "unknown status"}): invalid JSON response${snippet ? `: ${snippet}` : ""}`, { cause: error });
45
+ }
35
46
  if (json.error) {
36
- throw new Error(json.error.message || 'Claude request failed');
47
+ throw new Error(json.error.message || "Claude request failed");
37
48
  }
38
- const textParts = json.content?.map((part) => part.text ?? '').filter(Boolean) ?? [];
39
- const outputText = textParts.join('');
49
+ const textParts = json.content?.map((part) => part.text ?? "").filter(Boolean) ?? [];
50
+ const outputText = textParts.join("");
40
51
  return {
41
52
  id: json.id ?? `claude-${Date.now()}`,
42
- status: 'completed',
53
+ status: "completed",
43
54
  output_text: [outputText],
44
- output: [{ type: 'text', text: outputText }],
55
+ output: [{ type: "text", text: outputText }],
45
56
  usage: {
46
57
  input_tokens: json.usage?.input_tokens ?? 0,
47
58
  output_tokens: json.usage?.output_tokens ?? 0,
@@ -53,11 +64,17 @@ export function createClaudeClient(apiKey, modelName, resolvedModelId, baseUrl)
53
64
  const modelId = resolveClaudeModelId(resolvedModelId ?? modelName);
54
65
  const stream = async (body) => {
55
66
  const prompt = extractPrompt(body);
56
- const resp = await callClaude({ apiKey, model: modelId, prompt, stream: false, endpoint: baseUrl });
67
+ const resp = await callClaude({
68
+ apiKey,
69
+ model: modelId,
70
+ prompt,
71
+ stream: false,
72
+ endpoint: baseUrl,
73
+ });
57
74
  const parsed = await parseClaudeResponse(resp);
58
75
  const iterator = async function* () {
59
76
  if (parsed.output_text?.[0]) {
60
- yield { type: 'response.output_text.delta', delta: parsed.output_text[0] };
77
+ yield { type: "response.output_text.delta", delta: parsed.output_text[0] };
61
78
  }
62
79
  return;
63
80
  };
@@ -68,13 +85,19 @@ export function createClaudeClient(apiKey, modelName, resolvedModelId, baseUrl)
68
85
  };
69
86
  const create = async (body) => {
70
87
  const prompt = extractPrompt(body);
71
- const resp = await callClaude({ apiKey, model: modelId, prompt, stream: false, endpoint: baseUrl });
88
+ const resp = await callClaude({
89
+ apiKey,
90
+ model: modelId,
91
+ prompt,
92
+ stream: false,
93
+ endpoint: baseUrl,
94
+ });
72
95
  return parseClaudeResponse(resp);
73
96
  };
74
97
  const retrieve = async (id) => ({
75
98
  id,
76
- status: 'error',
77
- error: { message: 'Retrieve by ID not supported for Claude API yet.' },
99
+ status: "error",
100
+ error: { message: "Retrieve by ID not supported for Claude API yet." },
78
101
  });
79
102
  return {
80
103
  responses: {
@@ -85,11 +108,16 @@ export function createClaudeClient(apiKey, modelName, resolvedModelId, baseUrl)
85
108
  };
86
109
  }
87
110
  export function resolveClaudeModelId(modelName) {
88
- if (modelName === 'claude-4.5-sonnet' || modelName === 'claude-sonnet-4-5-20241022') {
89
- return 'claude-sonnet-4-5';
111
+ if (modelName === "claude-4.6-sonnet" || modelName === "claude-sonnet-4-6") {
112
+ return "claude-sonnet-4-6";
113
+ }
114
+ if (modelName === "claude-4.5-sonnet" ||
115
+ modelName === "claude-sonnet-4-5" ||
116
+ modelName === "claude-sonnet-4-5-20250929") {
117
+ return "claude-sonnet-4-5";
90
118
  }
91
- if (modelName === 'claude-4.1-opus' || modelName === 'claude-opus-4-1-20240808') {
92
- return 'claude-opus-4-1';
119
+ if (modelName === "claude-4.1-opus" || modelName === "claude-opus-4-1-20240808") {
120
+ return "claude-opus-4-1";
93
121
  }
94
122
  return modelName;
95
123
  }
@@ -1,19 +1,19 @@
1
- import OpenAI from 'openai';
2
- import path from 'node:path';
3
- import { createRequire } from 'node:module';
4
- import { createGeminiClient } from './gemini.js';
5
- import { createClaudeClient } from './claude.js';
6
- import { isOpenRouterBaseUrl } from './modelResolver.js';
1
+ import OpenAI from "openai";
2
+ import path from "node:path";
3
+ import { createRequire } from "node:module";
4
+ import { createGeminiClient } from "./gemini.js";
5
+ import { createClaudeClient } from "./claude.js";
6
+ import { isOpenRouterBaseUrl } from "./modelResolver.js";
7
7
  /**
8
8
  * Known native API base URLs that should still use their dedicated SDKs.
9
9
  * Any other custom base URL is treated as an OpenAI-compatible proxy and
10
10
  * all models are routed through the chat/completions adapter.
11
11
  */
12
12
  const NATIVE_API_HOSTS = [
13
- 'api.openai.com',
14
- 'api.anthropic.com',
15
- 'generativelanguage.googleapis.com',
16
- 'api.x.ai',
13
+ "api.openai.com",
14
+ "api.anthropic.com",
15
+ "generativelanguage.googleapis.com",
16
+ "api.x.ai",
17
17
  ];
18
18
  export function isCustomBaseUrl(baseUrl) {
19
19
  if (!baseUrl)
@@ -27,7 +27,7 @@ export function isCustomBaseUrl(baseUrl) {
27
27
  }
28
28
  }
29
29
  export function buildAzureResponsesBaseUrl(endpoint) {
30
- return `${endpoint.replace(/\/+$/, '')}/openai/v1`;
30
+ return `${endpoint.replace(/\/+$/, "")}/openai/v1`;
31
31
  }
32
32
  export function createDefaultClientFactory() {
33
33
  const customFactory = loadCustomClientFactory();
@@ -40,17 +40,21 @@ export function createDefaultClientFactory() {
40
40
  // route ALL models through the OpenAI chat/completions adapter instead of native SDKs
41
41
  // which would reject the proxy's API key.
42
42
  if (!openRouter && !customProxy) {
43
- if (options?.model?.startsWith('gemini')) {
43
+ if (options?.model?.startsWith("gemini")) {
44
44
  // Gemini client uses its own SDK; allow passing the already-resolved id for transparency/logging.
45
45
  return createGeminiClient(key, options.model, options.resolvedModelId);
46
46
  }
47
- if (options?.model?.startsWith('claude')) {
47
+ if (options?.model?.startsWith("claude")) {
48
48
  return createClaudeClient(key, options.model, options.resolvedModelId, options.baseUrl);
49
49
  }
50
50
  }
51
51
  let instance;
52
- const defaultHeaders = openRouter ? buildOpenRouterHeaders() : undefined;
53
- const httpTimeoutMs = typeof options?.httpTimeoutMs === 'number' && Number.isFinite(options.httpTimeoutMs) && options.httpTimeoutMs > 0
52
+ const defaultHeaders = openRouter
53
+ ? buildOpenRouterHeaders()
54
+ : undefined;
55
+ const httpTimeoutMs = typeof options?.httpTimeoutMs === "number" &&
56
+ Number.isFinite(options.httpTimeoutMs) &&
57
+ options.httpTimeoutMs > 0
54
58
  ? options.httpTimeoutMs
55
59
  : 20 * 60 * 1000;
56
60
  if (options?.azure?.endpoint) {
@@ -82,13 +86,15 @@ export function createDefaultClientFactory() {
82
86
  }
83
87
  function buildOpenRouterHeaders() {
84
88
  const headers = {};
85
- const referer = process.env.OPENROUTER_REFERER ?? process.env.OPENROUTER_HTTP_REFERER ?? 'https://github.com/steipete/oracle';
86
- const title = process.env.OPENROUTER_TITLE ?? 'Oracle CLI';
89
+ const referer = process.env.OPENROUTER_REFERER ??
90
+ process.env.OPENROUTER_HTTP_REFERER ??
91
+ "https://github.com/steipete/oracle";
92
+ const title = process.env.OPENROUTER_TITLE ?? "Oracle CLI";
87
93
  if (referer) {
88
- headers['HTTP-Referer'] = referer;
94
+ headers["HTTP-Referer"] = referer;
89
95
  }
90
96
  if (title) {
91
- headers['X-Title'] = title;
97
+ headers["X-Title"] = title;
92
98
  }
93
99
  return headers;
94
100
  }
@@ -97,19 +103,19 @@ function loadCustomClientFactory() {
97
103
  if (!override) {
98
104
  return null;
99
105
  }
100
- if (override === 'INLINE_TEST_FACTORY') {
106
+ if (override === "INLINE_TEST_FACTORY") {
101
107
  return () => ({
102
108
  responses: {
103
- create: async () => ({ id: 'inline-test', status: 'completed' }),
109
+ create: async () => ({ id: "inline-test", status: "completed" }),
104
110
  stream: async () => ({
105
111
  [Symbol.asyncIterator]: () => ({
106
112
  async next() {
107
113
  return { done: true, value: undefined };
108
114
  },
109
115
  }),
110
- finalResponse: async () => ({ id: 'inline-test', status: 'completed' }),
116
+ finalResponse: async () => ({ id: "inline-test", status: "completed" }),
111
117
  }),
112
- retrieve: async (id) => ({ id, status: 'completed' }),
118
+ retrieve: async (id) => ({ id, status: "completed" }),
113
119
  },
114
120
  });
115
121
  }
@@ -117,14 +123,14 @@ function loadCustomClientFactory() {
117
123
  const require = createRequire(import.meta.url);
118
124
  const resolved = path.isAbsolute(override) ? override : path.resolve(process.cwd(), override);
119
125
  const moduleExports = require(resolved);
120
- const factory = typeof moduleExports === 'function'
126
+ const factory = typeof moduleExports === "function"
121
127
  ? moduleExports
122
- : typeof moduleExports?.default === 'function'
128
+ : typeof moduleExports?.default === "function"
123
129
  ? moduleExports.default
124
- : typeof moduleExports?.createClientFactory === 'function'
130
+ : typeof moduleExports?.createClientFactory === "function"
125
131
  ? moduleExports.createClientFactory
126
132
  : null;
127
- if (typeof factory === 'function') {
133
+ if (typeof factory === "function") {
128
134
  return factory;
129
135
  }
130
136
  console.warn(`Custom client factory at ${resolved} did not export a function.`);
@@ -140,14 +146,17 @@ function buildOpenRouterCompletionClient(instance) {
140
146
  const adaptRequest = (body) => {
141
147
  const messages = [];
142
148
  if (body.instructions) {
143
- messages.push({ role: 'system', content: body.instructions });
149
+ messages.push({ role: "system", content: body.instructions });
144
150
  }
145
151
  for (const entry of body.input) {
146
152
  const textParts = entry.content
147
- .map((c) => (c.type === 'input_text' ? c.text : ''))
153
+ .map((c) => (c.type === "input_text" ? c.text : ""))
148
154
  .filter((t) => t)
149
- .join('\n\n');
150
- messages.push({ role: entry.role ?? 'user', content: textParts });
155
+ .join("\n\n");
156
+ messages.push({
157
+ role: entry.role ?? "user",
158
+ content: textParts,
159
+ });
151
160
  }
152
161
  const base = {
153
162
  model: body.model,
@@ -159,7 +168,7 @@ function buildOpenRouterCompletionClient(instance) {
159
168
  return { streaming, nonStreaming };
160
169
  };
161
170
  const adaptResponse = (response) => {
162
- const text = response.choices?.[0]?.message?.content ?? '';
171
+ const text = response.choices?.[0]?.message?.content ?? "";
163
172
  const usage = {
164
173
  input_tokens: response.usage?.prompt_tokens ?? 0,
165
174
  output_tokens: response.usage?.completion_tokens ?? 0,
@@ -167,9 +176,9 @@ function buildOpenRouterCompletionClient(instance) {
167
176
  };
168
177
  return {
169
178
  id: response.id ?? `openrouter-${Date.now()}`,
170
- status: 'completed',
179
+ status: "completed",
171
180
  output_text: [text],
172
- output: [{ type: 'text', text }],
181
+ output: [{ type: "text", text }],
173
182
  usage,
174
183
  };
175
184
  };
@@ -177,15 +186,15 @@ function buildOpenRouterCompletionClient(instance) {
177
186
  const { streaming } = adaptRequest(body);
178
187
  let finalUsage;
179
188
  let finalId;
180
- let aggregated = '';
189
+ let aggregated = "";
181
190
  async function* iterator() {
182
191
  const completion = await instance.chat.completions.create(streaming);
183
192
  for await (const chunk of completion) {
184
193
  finalId = chunk.id ?? finalId;
185
- const delta = chunk.choices?.[0]?.delta?.content ?? '';
194
+ const delta = chunk.choices?.[0]?.delta?.content ?? "";
186
195
  if (delta) {
187
196
  aggregated += delta;
188
- yield { type: 'chunk', delta };
197
+ yield { type: "chunk", delta };
189
198
  }
190
199
  if (chunk.usage) {
191
200
  finalUsage = chunk.usage;
@@ -200,11 +209,11 @@ function buildOpenRouterCompletionClient(instance) {
200
209
  async finalResponse() {
201
210
  return adaptResponse({
202
211
  id: finalId ?? `openrouter-${Date.now()}`,
203
- choices: [{ message: { role: 'assistant', content: aggregated } }],
212
+ choices: [{ message: { role: "assistant", content: aggregated } }],
204
213
  usage: finalUsage ?? { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
205
214
  created: Math.floor(Date.now() / 1000),
206
- model: '',
207
- object: 'chat.completion',
215
+ model: "",
216
+ object: "chat.completion",
208
217
  });
209
218
  },
210
219
  };
@@ -219,7 +228,7 @@ function buildOpenRouterCompletionClient(instance) {
219
228
  stream,
220
229
  create,
221
230
  retrieve: async () => {
222
- throw new Error('retrieve is not supported for OpenRouter chat/completions fallback.');
231
+ throw new Error("retrieve is not supported for OpenRouter chat/completions fallback.");
223
232
  },
224
233
  },
225
234
  };
@@ -1,15 +1,45 @@
1
- import { countTokens as countTokensGpt5 } from 'gpt-tokenizer/model/gpt-5';
2
- import { countTokens as countTokensGpt5Pro } from 'gpt-tokenizer/model/gpt-5-pro';
3
- import { countTokens as countTokensAnthropicRaw } from '@anthropic-ai/tokenizer';
4
- import { stringifyTokenizerInput } from './tokenStringifier.js';
5
- export const DEFAULT_MODEL = 'gpt-5.4-pro';
6
- export const PRO_MODELS = new Set(['gpt-5.4-pro', 'gpt-5.1-pro', 'gpt-5-pro', 'gpt-5.2-pro', 'claude-4.5-sonnet', 'claude-4.1-opus']);
1
+ import { countTokens as countTokensGpt5 } from "gpt-tokenizer/model/gpt-5";
2
+ import { countTokens as countTokensGpt5Pro } from "gpt-tokenizer/model/gpt-5-pro";
3
+ import { countTokens as countTokensAnthropicRaw } from "@anthropic-ai/tokenizer";
4
+ import { stringifyTokenizerInput } from "./tokenStringifier.js";
5
+ export const DEFAULT_MODEL = "gpt-5.5-pro";
6
+ export const PRO_MODELS = new Set([
7
+ "gpt-5.5-pro",
8
+ "gpt-5.4-pro",
9
+ "gpt-5.1-pro",
10
+ "gpt-5-pro",
11
+ "gpt-5.2-pro",
12
+ "claude-4.6-sonnet",
13
+ "claude-4.1-opus",
14
+ ]);
7
15
  const countTokensAnthropic = (input) => countTokensAnthropicRaw(stringifyTokenizerInput(input));
8
16
  export const MODEL_CONFIGS = {
9
- 'gpt-5.1-pro': {
10
- model: 'gpt-5.1-pro',
11
- apiModel: 'gpt-5.4-pro',
12
- provider: 'openai',
17
+ "gpt-5.5-pro": {
18
+ model: "gpt-5.5-pro",
19
+ provider: "openai",
20
+ tokenizer: countTokensGpt5Pro,
21
+ inputLimit: 1_050_000,
22
+ pricing: {
23
+ inputPerToken: 30 / 1_000_000,
24
+ outputPerToken: 180 / 1_000_000,
25
+ },
26
+ reasoning: { effort: "xhigh" },
27
+ },
28
+ "gpt-5.5": {
29
+ model: "gpt-5.5",
30
+ provider: "openai",
31
+ tokenizer: countTokensGpt5,
32
+ inputLimit: 1_050_000,
33
+ pricing: {
34
+ inputPerToken: 5 / 1_000_000,
35
+ outputPerToken: 30 / 1_000_000,
36
+ },
37
+ reasoning: { effort: "xhigh" },
38
+ },
39
+ "gpt-5.1-pro": {
40
+ model: "gpt-5.1-pro",
41
+ apiModel: "gpt-5.5-pro",
42
+ provider: "openai",
13
43
  tokenizer: countTokensGpt5Pro,
14
44
  inputLimit: 196000,
15
45
  pricing: {
@@ -18,9 +48,9 @@ export const MODEL_CONFIGS = {
18
48
  },
19
49
  reasoning: null,
20
50
  },
21
- 'gpt-5-pro': {
22
- model: 'gpt-5-pro',
23
- provider: 'openai',
51
+ "gpt-5-pro": {
52
+ model: "gpt-5-pro",
53
+ provider: "openai",
24
54
  tokenizer: countTokensGpt5Pro,
25
55
  inputLimit: 196000,
26
56
  pricing: {
@@ -29,65 +59,65 @@ export const MODEL_CONFIGS = {
29
59
  },
30
60
  reasoning: null,
31
61
  },
32
- 'gpt-5.1': {
33
- model: 'gpt-5.1',
34
- provider: 'openai',
62
+ "gpt-5.1": {
63
+ model: "gpt-5.1",
64
+ provider: "openai",
35
65
  tokenizer: countTokensGpt5,
36
66
  inputLimit: 196000,
37
67
  pricing: {
38
68
  inputPerToken: 1.25 / 1_000_000,
39
69
  outputPerToken: 10 / 1_000_000,
40
70
  },
41
- reasoning: { effort: 'high' },
71
+ reasoning: { effort: "high" },
42
72
  },
43
- 'gpt-5.1-codex': {
44
- model: 'gpt-5.1-codex',
45
- provider: 'openai',
73
+ "gpt-5.1-codex": {
74
+ model: "gpt-5.1-codex",
75
+ provider: "openai",
46
76
  tokenizer: countTokensGpt5,
47
77
  inputLimit: 196000,
48
78
  pricing: {
49
79
  inputPerToken: 1.25 / 1_000_000,
50
80
  outputPerToken: 10 / 1_000_000,
51
81
  },
52
- reasoning: { effort: 'high' },
82
+ reasoning: { effort: "high" },
53
83
  },
54
- 'gpt-5.4': {
55
- model: 'gpt-5.4',
56
- provider: 'openai',
84
+ "gpt-5.4": {
85
+ model: "gpt-5.4",
86
+ provider: "openai",
57
87
  tokenizer: countTokensGpt5,
58
88
  inputLimit: 196000,
59
89
  pricing: {
60
90
  inputPerToken: 2.5 / 1_000_000,
61
91
  outputPerToken: 15 / 1_000_000,
62
92
  },
63
- reasoning: { effort: 'xhigh' },
93
+ reasoning: { effort: "xhigh" },
64
94
  },
65
- 'gpt-5.4-pro': {
66
- model: 'gpt-5.4-pro',
67
- provider: 'openai',
95
+ "gpt-5.4-pro": {
96
+ model: "gpt-5.4-pro",
97
+ provider: "openai",
68
98
  tokenizer: countTokensGpt5Pro,
69
99
  inputLimit: 196000,
70
100
  pricing: {
71
101
  inputPerToken: 30 / 1_000_000,
72
102
  outputPerToken: 180 / 1_000_000,
73
103
  },
74
- reasoning: { effort: 'xhigh' },
104
+ reasoning: { effort: "xhigh" },
75
105
  },
76
- 'gpt-5.2': {
77
- model: 'gpt-5.2',
78
- provider: 'openai',
106
+ "gpt-5.2": {
107
+ model: "gpt-5.2",
108
+ provider: "openai",
79
109
  tokenizer: countTokensGpt5,
80
110
  inputLimit: 196000,
81
111
  pricing: {
82
112
  inputPerToken: 1.75 / 1_000_000,
83
113
  outputPerToken: 14 / 1_000_000,
84
114
  },
85
- reasoning: { effort: 'xhigh' },
115
+ reasoning: { effort: "xhigh" },
86
116
  },
87
- 'gpt-5.2-instant': {
88
- model: 'gpt-5.2-instant',
89
- apiModel: 'gpt-5.2-chat-latest',
90
- provider: 'openai',
117
+ "gpt-5.2-instant": {
118
+ model: "gpt-5.2-instant",
119
+ apiModel: "gpt-5.2-chat-latest",
120
+ provider: "openai",
91
121
  tokenizer: countTokensGpt5,
92
122
  inputLimit: 196000,
93
123
  pricing: {
@@ -96,21 +126,21 @@ export const MODEL_CONFIGS = {
96
126
  },
97
127
  reasoning: null,
98
128
  },
99
- 'gpt-5.2-pro': {
100
- model: 'gpt-5.2-pro',
101
- apiModel: 'gpt-5.4-pro',
102
- provider: 'openai',
129
+ "gpt-5.2-pro": {
130
+ model: "gpt-5.2-pro",
131
+ apiModel: "gpt-5.5-pro",
132
+ provider: "openai",
103
133
  tokenizer: countTokensGpt5Pro,
104
134
  inputLimit: 196000,
105
135
  pricing: {
106
136
  inputPerToken: 30 / 1_000_000,
107
137
  outputPerToken: 180 / 1_000_000,
108
138
  },
109
- reasoning: { effort: 'xhigh' },
139
+ reasoning: { effort: "xhigh" },
110
140
  },
111
- 'gemini-3.1-pro': {
112
- model: 'gemini-3.1-pro',
113
- provider: 'google',
141
+ "gemini-3.1-pro": {
142
+ model: "gemini-3.1-pro",
143
+ provider: "google",
114
144
  tokenizer: countTokensGpt5Pro,
115
145
  inputLimit: 200000,
116
146
  pricing: {
@@ -121,9 +151,9 @@ export const MODEL_CONFIGS = {
121
151
  supportsBackground: false,
122
152
  supportsSearch: true,
123
153
  },
124
- 'gemini-3-pro': {
125
- model: 'gemini-3-pro',
126
- provider: 'google',
154
+ "gemini-3-pro": {
155
+ model: "gemini-3-pro",
156
+ provider: "google",
127
157
  tokenizer: countTokensGpt5Pro,
128
158
  inputLimit: 200000,
129
159
  pricing: {
@@ -134,10 +164,10 @@ export const MODEL_CONFIGS = {
134
164
  supportsBackground: false,
135
165
  supportsSearch: true,
136
166
  },
137
- 'claude-4.5-sonnet': {
138
- model: 'claude-4.5-sonnet',
139
- apiModel: 'claude-sonnet-4-5',
140
- provider: 'anthropic',
167
+ "claude-4.6-sonnet": {
168
+ model: "claude-4.6-sonnet",
169
+ apiModel: "claude-sonnet-4-6",
170
+ provider: "anthropic",
141
171
  tokenizer: countTokensAnthropic,
142
172
  inputLimit: 200000,
143
173
  pricing: {
@@ -148,24 +178,24 @@ export const MODEL_CONFIGS = {
148
178
  supportsBackground: false,
149
179
  supportsSearch: false,
150
180
  },
151
- 'claude-4.1-opus': {
152
- model: 'claude-4.1-opus',
153
- apiModel: 'claude-opus-4-1',
154
- provider: 'anthropic',
181
+ "claude-4.1-opus": {
182
+ model: "claude-4.1-opus",
183
+ apiModel: "claude-opus-4-1",
184
+ provider: "anthropic",
155
185
  tokenizer: countTokensAnthropic,
156
186
  inputLimit: 200000,
157
187
  pricing: {
158
188
  inputPerToken: 15 / 1_000_000,
159
189
  outputPerToken: 75 / 1_000_000,
160
190
  },
161
- reasoning: { effort: 'high' },
191
+ reasoning: { effort: "high" },
162
192
  supportsBackground: false,
163
193
  supportsSearch: false,
164
194
  },
165
- 'grok-4.1': {
166
- model: 'grok-4.1',
167
- apiModel: 'grok-4-1-fast-reasoning',
168
- provider: 'xai',
195
+ "grok-4.1": {
196
+ model: "grok-4.1",
197
+ apiModel: "grok-4-1-fast-reasoning",
198
+ provider: "xai",
169
199
  tokenizer: countTokensGpt5Pro,
170
200
  inputLimit: 2_000_000,
171
201
  pricing: {
@@ -175,11 +205,11 @@ export const MODEL_CONFIGS = {
175
205
  reasoning: null,
176
206
  supportsBackground: false,
177
207
  supportsSearch: true,
178
- searchToolType: 'web_search',
208
+ searchToolType: "web_search",
179
209
  },
180
210
  };
181
211
  export const DEFAULT_SYSTEM_PROMPT = [
182
- 'You are Oracle, a focused one-shot problem solver.',
183
- 'Emphasize direct answers and cite any files referenced.',
184
- ].join(' ');
185
- export const TOKENIZER_OPTIONS = { allowedSpecial: 'all' };
212
+ "You are Oracle, a focused one-shot problem solver.",
213
+ "Emphasize direct answers and cite any files referenced.",
214
+ ].join(" ");
215
+ export const TOKENIZER_OPTIONS = { allowedSpecial: "all" };