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