openmausbot 0.1.91 → 0.1.92
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/dist/assets/DesktopViewer-Do6lBa4C.js +5 -0
- package/dist/assets/{abnfDiagram-O67JEVCF-yP-w8pRq.js → abnfDiagram-O67JEVCF-Cd3X7Hxc.js} +1 -1
- package/dist/assets/{arc-DsivfZEh.js → arc-DIYc7Ymx.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-CILw7lzT.js → architectureDiagram-NJMV4G6O-DBmRGVyP.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-DEQUV3HF.js → blockDiagram-BEXU5L5S-CPFePSEE.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-lSXCZoKA.js → c4Diagram-YGBWAQC7-DD_DO1qy.js} +1 -1
- package/dist/assets/channel-Dtk5Mtic.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-QCD5bgWP.js → chunk-2Q5K7J3B-BNEeNSjX.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-C5-iZJuL.js → chunk-3FUC2YCW-BbinLaqH.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-cxsawMpY.js → chunk-5VM5RSS4-BBgYrgDR.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-DV8tV8H7.js → chunk-GTNCS2PH-ezXj-kA-.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-CJFZyfbW.js → chunk-GWA4HPMP-9FxZ3diV.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-BigbMXco.js → chunk-JWPE2WC7-CO-40JpI.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-oVxTfpDy.js → chunk-NETBCI7D-BEhjslYE.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-CH4BiroW.js → chunk-WEXAMYUT-CNeq4n7_.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-KEDa6gax.js → chunk-XXDRQBXY-OsCY7KSi.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-BiPjfqVv.js → classDiagram-v2-NBCMYWYE-CloRUEtk.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-Caxew3OY.js → cose-bilkent-JH36ORCC-D1BGZhp4.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-B_Pui369.js → cynefin-OW5HDTMX-CUf4T2CN.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-X64ydIhP.js → cynefinDiagram-VND7K2PF-DPEZrFGA.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-TqYCI1E1.js → dagre-6A5THRUB-bDe6GIv5.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-TeOt3rAQ.js → diagram-22UHCM2B-CdcUQz55.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-D70BLhDA.js → diagram-3UASUU5V-BZpqGg7c.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-BbQDLwUC.js → diagram-ATOU4E4O-DvGM6ugp.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-ChNJZ1u-.js → diagram-CDSNMT55-DSTmMm0s.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-DMBl2APa.js → diagram-MLGK6HIB-15cucnMn.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-CEqDchOp.js → diagram-MPIPVDR6-tMbuaE6n.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-BVDKRp_-.js → ebnfDiagram-ZINNZB2B-BYxYzjHI.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-CRkofO9B.js → elk-276RUBZZ-v6bj852W.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-DruOMh5e.js → erDiagram-OPXOYQCR-5lBBlnd2.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-8GMQeB7t.js → flowDiagram-KWPJA3E3-CZyl1zIj.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-ORE9jcsM.js → ganttDiagram-FUAMR5RP-BiAI-ltZ.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-BmsedsWh.js → gitGraphDiagram-X574FWY7-BAZISkj3.js} +1 -1
- package/dist/assets/index-Cdmjrl28.css +1 -0
- package/dist/assets/{index-DKNEM8Q6.js → index-DGBaEXrM.js} +1 -1
- package/dist/assets/index-DR7YPMkW.js +597 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-E_p7AooJ.js → infoDiagram-VRGFBTTK-B6ooOy-Z.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-Y-B2mKda.js → ishikawaDiagram-OU5B5YK6-BZ9ksi-B.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-eA8RELcK.js → journeyDiagram-ZHPQQLJL-DWqlzIEe.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-DqIL2e8e.js → kanban-definition-PNTS6WVX-JX6piDwL.js} +1 -1
- package/dist/assets/{linear-yC_29R6e.js → linear-CmOWzX0P.js} +1 -1
- package/dist/assets/{mermaid.core-VhEMkSND.js → mermaid.core-CF1zwoQ-.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-oJ7kyQZy.js → mindmap-definition-NLK3R4M7-CGh2K4fW.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-BmfYcY0O.js → pegDiagram-GJSIUBJH-CDwYN0s7.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-DKvgP7w9.js → pieDiagram-5QR66LMP-1rfjJocB.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-BEKL3W0L.js → quadrantDiagram-O4NWA36T-tKPvPiok.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-BEsiqR5s.js → railroadDiagram-XR7U4H2S-BHLm5vXR.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-DWBcWvAP.js → requirementDiagram-PLB6GJNP-CB45STp7.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-rpZ2_O4s.js → sankeyDiagram-IPEJSGJF-55QA_huC.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-B99HQdJR.js → sequenceDiagram-PO4LG4MO-BckFmQHn.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-BjN0qT5T.js → sizeCapture-INFHLROL-BFCOJF11.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-BbsVgGsC.js → stateDiagram-v2-GCMORJYK-CZvmiVVN.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-DG3gKkeR.js → swimlanes-2SLR337P-BpDUCEKy.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-M0GYW9Y3.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-BTHOdtF_.js → timeline-definition-EJHVYXUP-BpxHq6IK.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-acLSLFwc.js → usecaseDiagram-POWQR4AR-Cj66vm02.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-C5JzNX9G.js → vennDiagram-UO4OBE2U-C9nRkWE_.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-DL1-PrR_.js → wardleyDiagram-VNRHLVJA-D-me_nWj.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-Bvr1477p.js → xychartDiagram-PMCCYNJV-Dc_fL4mk.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/novnc-NOTICE.txt +118 -0
- package/dist-server/cloud-home-start.js +112 -14
- package/dist-server/container-mcp.js +195 -15
- package/dist-server/drivers/agents-proxy.js +5 -4
- package/dist-server/enterprise/server/index.js +5 -1
- package/dist-server/index.js +9300 -4155
- package/dist-server/local-computer-proxy.js +128 -7
- package/dist-server/mcp-gate.js +11 -5
- package/dist-server/model-catalog/models-dev.snapshot.json +7299 -0
- package/dist-server/openmausbot.js +3910 -1182
- package/dist-server/pair-cli.js +3910 -1182
- package/dist-server/server/boat.js +2 -2
- package/dist-server/server/browser-engine.js +10 -1
- package/dist-server/server/browser-live.js +46 -2
- package/dist-server/server/browser-runtime.js +74 -8
- package/dist-server/server/browser-tool-shape.js +6 -4
- package/dist-server/server/chief-of-staff.js +1 -1
- package/dist-server/server/cloud-home-start.js +118 -26
- package/dist-server/server/cloud-home.js +39 -3
- package/dist-server/server/cloud-lending.js +74 -10
- package/dist-server/server/cloud-owner.js +196 -0
- package/dist-server/server/cloud-secrets-boot.js +6 -0
- package/dist-server/server/cloud-secrets.js +65 -0
- package/dist-server/server/config.js +174 -14
- package/dist-server/server/container-computer.js +3 -2
- package/dist-server/server/desktop-viewer-targets.js +26 -0
- package/dist-server/server/drivers/acp/core.js +167 -21
- package/dist-server/server/drivers/acp/opencode-go.js +614 -85
- package/dist-server/server/drivers/agents-catalog.js +6 -6
- package/dist-server/server/drivers/antigravity-acp.js +69 -11
- package/dist-server/server/drivers/antigravity-temp.js +360 -0
- package/dist-server/server/drivers/antigravity.js +21 -0
- package/dist-server/server/drivers/chatgpt-plan-auth.js +481 -0
- package/dist-server/server/drivers/claude.js +312 -34
- package/dist-server/server/drivers/codex.js +228 -18
- package/dist-server/server/drivers/grok.js +2 -2
- package/dist-server/server/drivers/mistral.js +4 -3
- package/dist-server/server/drivers/openai-chat-protocol.js +4 -3
- package/dist-server/server/drivers/openai-chat.js +41 -3
- package/dist-server/server/drivers/openai-compat.js +73 -23
- package/dist-server/server/engine-install.js +46 -12
- package/dist-server/server/env-path.js +15 -3
- package/dist-server/server/harness/registry.js +2 -2
- package/dist-server/server/index.js +1338 -184
- package/dist-server/server/lending-memory.js +479 -0
- package/dist-server/server/local-vm-idle.js +24 -6
- package/dist-server/server/managed-desktop.js +3 -0
- package/dist-server/server/mcp-bridge.js +5 -3
- package/dist-server/server/mcp-http.js +6 -3
- package/dist-server/server/mcp-oauth-discovery.js +133 -0
- package/dist-server/server/mcp-oauth-store.js +70 -0
- package/dist-server/server/mcp-oauth.js +550 -0
- package/dist-server/server/mcp-probe.js +14 -1
- package/dist-server/server/mcp-registry.js +43 -0
- package/dist-server/server/memory-upkeep.js +94 -84
- package/dist-server/server/model-catalog/catalog.js +374 -0
- package/dist-server/server/model-catalog/presets.js +176 -0
- package/dist-server/server/model-catalog/trim.js +219 -0
- package/dist-server/server/provider-key-check.js +4 -2
- package/dist-server/server/recent-work.js +1 -1
- package/dist-server/server/request-auth.js +23 -0
- package/dist-server/server/routes/antigravity-leftovers.js +45 -0
- package/dist-server/server/routes/bot-memory.js +31 -6
- package/dist-server/server/routes/desktop-viewer.js +194 -0
- package/dist-server/server/routine-requests.js +1 -1
- package/dist-server/server/routines.js +1 -1
- package/dist-server/server/sessions.js +56 -9
- package/dist-server/server/skills.js +25 -10
- package/dist-server/server/store.js +62 -122
- package/dist-server/server/thread-events.js +2 -0
- package/dist-server/server/thread-starters.js +33 -0
- package/dist-server/server/thread-title.js +46 -0
- package/dist-server/server/tts/fish.js +4 -5
- package/dist-server/server/tts/index.js +5 -3
- package/dist-server/server/vps-computer.js +79 -12
- package/dist-server/server/webhooks.js +18 -1
- package/dist-server/server/workspace-backup-policy.js +3 -0
- package/dist-server/server/workspace-backup.js +3 -0
- package/dist-server/server/workspace.js +65 -15
- package/dist-server/shared/workspace-backup-client.js +1 -0
- package/dist-server/src/lib/citations.js +177 -0
- package/dist-server/src/lib/composer-attachments.js +7 -1
- package/dist-server/vps-container-mcp.js +196 -15
- package/dist-server/workspace-backup.worker.js +73 -9
- package/enterprise/server/index.js +5 -1
- package/package.json +1 -1
- package/dist/assets/channel-DrfGMu7X.js +0 -1
- package/dist/assets/index-BlnCEcU6.js +0 -588
- package/dist/assets/index-DVxjOvID.css +0 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BCZhxl7e.js +0 -8
|
@@ -15,6 +15,27 @@ const DEFAULT_MODELS = {
|
|
|
15
15
|
{ id: "llama-3.3-70b-versatile", label: "Llama 3.3 70B (Groq)", custom: true },
|
|
16
16
|
],
|
|
17
17
|
};
|
|
18
|
+
const DEFAULT_KEY_ENV = "OPENAI_COMPAT_API_KEY";
|
|
19
|
+
/** A provider's own key (the built-in OpenAI and OpenRouter instances). An
|
|
20
|
+
* instance reading one of these never falls back to the workspace
|
|
21
|
+
* OpenAI-compatible key, URL, model or routing. */
|
|
22
|
+
const OWN_KEY_ENVS = new Set(["OMB_OPENAI_API_KEY", "OMB_OPENROUTER_API_KEY"]);
|
|
23
|
+
/** OpenAI's own API, seeded until its live catalog loads. */
|
|
24
|
+
const OPENAI_MODELS = {
|
|
25
|
+
default: "gpt-5",
|
|
26
|
+
options: [
|
|
27
|
+
{ id: "gpt-5", label: "gpt-5" },
|
|
28
|
+
{ id: "gpt-5-mini", label: "gpt-5-mini" },
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
/** OpenAI's /models lists every model the key can reach: embeddings, speech,
|
|
32
|
+
* images, moderation and Responses-only models too. Only chat models belong
|
|
33
|
+
* in a chat picker. */
|
|
34
|
+
export function isOpenAIChatModel(id) {
|
|
35
|
+
if (!/^(gpt-|chatgpt-|o\d)/i.test(id))
|
|
36
|
+
return false;
|
|
37
|
+
return !/(audio|realtime|tts|transcribe|search|image|embedding|moderation|instruct|codex|computer-use|deep-research|-pro\b)/i.test(id);
|
|
38
|
+
}
|
|
18
39
|
function isOpenRouterUrl(url) {
|
|
19
40
|
try {
|
|
20
41
|
const host = new URL(url).hostname.toLowerCase();
|
|
@@ -30,7 +51,11 @@ function decodeConfig(raw) {
|
|
|
30
51
|
throw new Error("tools must be a boolean");
|
|
31
52
|
if (config.managedModels !== undefined && (!Array.isArray(config.managedModels) || !config.managedModels.length || config.managedModels.some(model => typeof model !== "string" || !model.trim())))
|
|
32
53
|
throw new Error("Invalid managed models.");
|
|
33
|
-
const
|
|
54
|
+
const ownKey = typeof config.apiKeyEnv === "string" && OWN_KEY_ENVS.has(config.apiKeyEnv);
|
|
55
|
+
if (config.catalog !== undefined && config.catalog !== "openai")
|
|
56
|
+
throw new Error("catalog must be \"openai\"");
|
|
57
|
+
// Workspace defaults belong to the shared OpenAI-compatible connection only.
|
|
58
|
+
const envUrl = ownKey ? undefined : process.env.OPENAI_COMPAT_URL;
|
|
34
59
|
return {
|
|
35
60
|
...(config.tools !== undefined ? { tools: config.tools } : {}),
|
|
36
61
|
...(config.managedModels ? { managedModels: config.managedModels } : {}),
|
|
@@ -38,55 +63,65 @@ function decodeConfig(raw) {
|
|
|
38
63
|
.replace(/\/+$/, ""),
|
|
39
64
|
apiKeyEnv: typeof config.apiKeyEnv === "string" && config.apiKeyEnv
|
|
40
65
|
? config.apiKeyEnv
|
|
41
|
-
:
|
|
66
|
+
: DEFAULT_KEY_ENV,
|
|
67
|
+
...(config.catalog === "openai" ? { catalog: "openai" } : {}),
|
|
42
68
|
key: typeof config.key === "string" && config.key ? config.key : undefined,
|
|
43
69
|
model: typeof config.model === "string" && config.model
|
|
44
70
|
? config.model
|
|
45
|
-
: process.env.OPENAI_COMPAT_MODEL || undefined,
|
|
71
|
+
: ownKey ? undefined : process.env.OPENAI_COMPAT_MODEL || undefined,
|
|
46
72
|
// An explicit empty override disables inherited routing for an isolated
|
|
47
73
|
// connection (CLI setup uses this). Absent still inherits the global pin.
|
|
48
74
|
provider: typeof config.provider === "string"
|
|
49
75
|
? config.provider || undefined
|
|
50
|
-
: process.env.OPENAI_COMPAT_PROVIDER || undefined,
|
|
76
|
+
: ownKey ? undefined : process.env.OPENAI_COMPAT_PROVIDER || undefined,
|
|
51
77
|
};
|
|
52
78
|
}
|
|
53
79
|
export const OpenAICompatDriver = {
|
|
54
80
|
driverKind: DRIVER_KIND,
|
|
55
81
|
metadata: {
|
|
56
|
-
displayName: "OpenAI-compatible
|
|
82
|
+
displayName: "Other (OpenAI-compatible)",
|
|
57
83
|
supportsMultipleInstances: true,
|
|
58
|
-
access: "
|
|
84
|
+
access: "api",
|
|
59
85
|
},
|
|
60
86
|
models: DEFAULT_MODELS,
|
|
87
|
+
// Nothing to install: the key and base URL are saved in the app. The old
|
|
88
|
+
// descriptor offered a config.json sentence as an "Open install in
|
|
89
|
+
// Terminal" command.
|
|
61
90
|
install: {
|
|
62
91
|
docsUrl: "https://openrouter.ai/keys",
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
darwin: "Get a free key at https://openrouter.ai/keys (or https://console.groq.com) then add it to ~/.openmausbot/config.json under openaiCompat.key",
|
|
66
|
-
linux: "Get a free key at https://openrouter.ai/keys (or https://console.groq.com) then add it to ~/.openmausbot/config.json under openaiCompat.key",
|
|
67
|
-
win32: "Get a free key at https://openrouter.ai/keys (or https://console.groq.com) then add it to %USERPROFILE%\\.openmausbot\\config.json under openaiCompat.key",
|
|
68
|
-
},
|
|
92
|
+
settings: "connections",
|
|
93
|
+
signInCommand: "Save an OpenAI-compatible API key in Settings → API keys, or set OPENAI_COMPAT_API_KEY on the server.",
|
|
69
94
|
},
|
|
70
95
|
decodeConfig,
|
|
71
96
|
defaultConfig: () => decodeConfig({}),
|
|
72
97
|
async create(input) {
|
|
73
98
|
const { config } = input;
|
|
99
|
+
// An instance that names its own key variable reads only that one: the
|
|
100
|
+
// workspace key (OPENAI_COMPAT_API_KEY) belongs to the workspace's
|
|
101
|
+
// endpoint and must not reach this instance's host.
|
|
102
|
+
const ownKeyVariable = config.apiKeyEnv !== DEFAULT_KEY_ENV;
|
|
74
103
|
const apiKey = config.key ??
|
|
75
104
|
input.environment[config.apiKeyEnv] ??
|
|
76
|
-
input.environment
|
|
105
|
+
(ownKeyVariable ? undefined : input.environment[DEFAULT_KEY_ENV]) ??
|
|
77
106
|
process.env[config.apiKeyEnv] ??
|
|
78
|
-
process.env
|
|
107
|
+
(ownKeyVariable ? undefined : process.env[DEFAULT_KEY_ENV]) ??
|
|
79
108
|
"";
|
|
109
|
+
// The default key and the built-in providers' keys are saved in
|
|
110
|
+
// Settings → API keys; any other variable is configured where it was written.
|
|
111
|
+
const missingKey = !ownKeyVariable || OWN_KEY_ENVS.has(config.apiKeyEnv)
|
|
112
|
+
? "No API key — open Settings → API keys."
|
|
113
|
+
: `no API key — set ${config.apiKeyEnv} or add it to the instance config`;
|
|
114
|
+
const seeded = config.catalog === "openai" ? OPENAI_MODELS : DEFAULT_MODELS;
|
|
80
115
|
let catalog = config.managedModels
|
|
81
116
|
? { default: config.managedModels[0], options: config.managedModels.map(id => ({ id, label: id })) }
|
|
82
117
|
: config.model
|
|
83
118
|
? {
|
|
84
119
|
default: config.model,
|
|
85
|
-
options:
|
|
86
|
-
?
|
|
87
|
-
: [{ id: config.model, label: config.model, custom: true }, ...
|
|
120
|
+
options: seeded.options.some((model) => model.id === config.model)
|
|
121
|
+
? seeded.options
|
|
122
|
+
: [{ id: config.model, label: config.model, custom: true }, ...seeded.options],
|
|
88
123
|
}
|
|
89
|
-
:
|
|
124
|
+
: seeded;
|
|
90
125
|
const fetchModels = async () => {
|
|
91
126
|
if (config.managedModels)
|
|
92
127
|
return;
|
|
@@ -100,7 +135,14 @@ export const OpenAICompatDriver = {
|
|
|
100
135
|
if (!response.ok)
|
|
101
136
|
return;
|
|
102
137
|
const json = await response.json();
|
|
103
|
-
|
|
138
|
+
let rows = Array.isArray(json) ? json : Array.isArray(json.data) ? json.data : [];
|
|
139
|
+
// OpenAI lists its catalog unordered and mixed with non-chat models:
|
|
140
|
+
// keep chat models, newest first.
|
|
141
|
+
if (config.catalog === "openai") {
|
|
142
|
+
rows = rows
|
|
143
|
+
.filter((row) => typeof row.id === "string" && isOpenAIChatModel(row.id))
|
|
144
|
+
.sort((a, b) => (typeof b.created === "number" ? b.created : 0) - (typeof a.created === "number" ? a.created : 0));
|
|
145
|
+
}
|
|
104
146
|
const seen = new Set();
|
|
105
147
|
const options = [];
|
|
106
148
|
for (const row of rows) {
|
|
@@ -111,7 +153,8 @@ export const OpenAICompatDriver = {
|
|
|
111
153
|
options.push({
|
|
112
154
|
id,
|
|
113
155
|
label: typeof row.name === "string" && row.name.trim() ? row.name : id,
|
|
114
|
-
custom
|
|
156
|
+
// A provider's own catalog is its official list, not a custom model.
|
|
157
|
+
...(config.catalog === "openai" ? {} : { custom: true }),
|
|
115
158
|
});
|
|
116
159
|
}
|
|
117
160
|
if (!options.length)
|
|
@@ -146,15 +189,22 @@ export const OpenAICompatDriver = {
|
|
|
146
189
|
: {}),
|
|
147
190
|
}),
|
|
148
191
|
httpErrorLabel: "upstream",
|
|
149
|
-
missingKeyError:
|
|
150
|
-
unavailableReason:
|
|
192
|
+
missingKeyError: missingKey,
|
|
193
|
+
unavailableReason: missingKey,
|
|
151
194
|
timeoutMs: idleTimeoutMs(),
|
|
152
195
|
reasoning: true,
|
|
153
196
|
billing: "metered",
|
|
154
197
|
includeUsageInCompleted: true,
|
|
155
198
|
nativeLog: {
|
|
156
199
|
source: "openai-compat.chat.completions",
|
|
157
|
-
|
|
200
|
+
// Tool names are the answer to "did the harness send them?" — the
|
|
201
|
+
// LiteLLM/proxy hop after this point is what drops tools silently,
|
|
202
|
+
// and until now the tee held no record either side could compare.
|
|
203
|
+
outgoing: (_turn, messages, model, tools) => ({
|
|
204
|
+
model,
|
|
205
|
+
messageCount: messages.length,
|
|
206
|
+
tools: tools.map(tool => tool.function.name),
|
|
207
|
+
}),
|
|
158
208
|
incoming: ({ text, reasoning, usage }) => ({
|
|
159
209
|
textLength: text.length,
|
|
160
210
|
reasoningLength: reasoning.length,
|
|
@@ -9,9 +9,10 @@ import { join } from "node:path";
|
|
|
9
9
|
import { stripVTControlCharacters } from "node:util";
|
|
10
10
|
import { DATA_DIR, stripWorkspaceCredentialEnv } from "./config.js";
|
|
11
11
|
import { augmentedPath, findCliCandidates, registerPathDir, resetPathCache } from "./env-path.js";
|
|
12
|
-
import { killCliTree, spawnCli } from "./procs.js";
|
|
12
|
+
import { execCli, killCliTree, spawnCli } from "./procs.js";
|
|
13
13
|
const MAX_OUTPUT = 64 * 1024;
|
|
14
14
|
const DEFAULT_TIMEOUT_MS = 10 * 60_000;
|
|
15
|
+
const PROBE_TIMEOUT_MS = 30_000;
|
|
15
16
|
/** npm's global prefix for engines the app installs itself. */
|
|
16
17
|
export function enginesPrefix(baseDir = DATA_DIR) {
|
|
17
18
|
return join(baseDir, "tools", "npm");
|
|
@@ -68,21 +69,54 @@ async function installOnce(pkg, options) {
|
|
|
68
69
|
stripWorkspaceCredentialEnv(env);
|
|
69
70
|
// npm 11 skips a dependency's install script unless the package is named
|
|
70
71
|
// here; the engines that need one (Claude Code) are exactly these.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
// Engines like Codex ship their native binary as a platform optional
|
|
73
|
+
// dependency, so a user-level `omit=optional` must not leave it out.
|
|
74
|
+
const args = ["install", "-g", "--prefix", prefix, "--loglevel=error", "--include=optional", `--allow-scripts=${pkg}`, `${pkg}@latest`];
|
|
75
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
76
|
+
await runInstall(pkg, args, env, prefix, timeoutMs);
|
|
76
77
|
// Whatever the boot registration did, the directory we just filled must
|
|
77
78
|
// be on the engines' PATH from here on.
|
|
78
|
-
|
|
79
|
+
const binDir = enginesBinDir(options.baseDir);
|
|
80
|
+
registerPathDir(binDir);
|
|
79
81
|
resetPathCache();
|
|
80
|
-
if (options.cli)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
82
|
+
if (!options.cli)
|
|
83
|
+
return;
|
|
84
|
+
const installed = findCliCandidates(options.cli).find((path) => path.startsWith(binDir));
|
|
85
|
+
if (!installed) {
|
|
86
|
+
throw new Error(`${pkg} installed, but it did not provide a \`${options.cli}\` command. Check the package name in this engine's install descriptor.`);
|
|
85
87
|
}
|
|
88
|
+
// npm exits 0 even when it drops an optional dependency it failed to
|
|
89
|
+
// download, which leaves a launcher without its platform binary (#2064).
|
|
90
|
+
// A copy here shadows every other one on PATH, so prove it starts; a
|
|
91
|
+
// second run fetches what the first one dropped.
|
|
92
|
+
let failure = await probeCli(installed, env);
|
|
93
|
+
if (failure === null)
|
|
94
|
+
return;
|
|
95
|
+
await runInstall(pkg, args, env, prefix, timeoutMs);
|
|
96
|
+
failure = await probeCli(installed, env);
|
|
97
|
+
if (failure === null)
|
|
98
|
+
return;
|
|
99
|
+
throw new Error(`npm installed ${pkg}, but \`${options.cli}\` does not start: ${failure}\nnpm can leave out a platform package when its download fails, even after a retry. Check this server's network connection, then install again from Settings.`);
|
|
100
|
+
}
|
|
101
|
+
async function runInstall(pkg, args, env, prefix, timeoutMs) {
|
|
102
|
+
const result = await runNpm(args, env, prefix, timeoutMs);
|
|
103
|
+
if (result.code !== 0) {
|
|
104
|
+
throw new Error(`npm could not install ${pkg} on this server.${tail(result.output)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Null when `<cli> --version` succeeds, else why it did not. A Node
|
|
108
|
+
* launcher that throws prints its source line first, so its `Error:` line
|
|
109
|
+
* is the one worth showing. */
|
|
110
|
+
function probeCli(cli, env) {
|
|
111
|
+
return new Promise((resolveProbe) => {
|
|
112
|
+
execCli(cli, ["--version"], { env: { ...env, PATH: augmentedPath() }, timeout: PROBE_TIMEOUT_MS, killSignal: "SIGKILL", maxBuffer: MAX_OUTPUT }, (error, stdout, stderr) => {
|
|
113
|
+
if (!error)
|
|
114
|
+
return resolveProbe(null);
|
|
115
|
+
const lines = stripVTControlCharacters(`${stderr ?? ""}\n${stdout}`).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
116
|
+
const said = lines.find((line) => /^\w*Error: /.test(line)) ?? lines[0] ?? error.message;
|
|
117
|
+
resolveProbe(said.slice(0, 400));
|
|
118
|
+
});
|
|
119
|
+
});
|
|
86
120
|
}
|
|
87
121
|
function tail(output) {
|
|
88
122
|
const clean = stripVTControlCharacters(output).trim();
|
|
@@ -27,6 +27,15 @@ function nvmBinDirs() {
|
|
|
27
27
|
return [];
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
/** A sealed test fixture finds CLIs only where it was granted them: its own
|
|
31
|
+
* PATH, OMB_EXTRA_PATH, app-managed dirs, and install dirs under its own
|
|
32
|
+
* temporary home. The machine-wide install dirs and the login shell's PATH
|
|
33
|
+
* would hand it this computer's real CLIs — a Homebrew `codex` made the
|
|
34
|
+
* fixture's ChatGPT plan engine "available" on a developer Mac (#2035).
|
|
35
|
+
* Only the verification launcher (scripts/control-omb.ts) sets it. */
|
|
36
|
+
function sealedFixture() {
|
|
37
|
+
return process.env.OMB_TEST_SEALED_PATH === "1";
|
|
38
|
+
}
|
|
30
39
|
function knownDirs() {
|
|
31
40
|
const home = homedir();
|
|
32
41
|
return [
|
|
@@ -36,8 +45,11 @@ function knownDirs() {
|
|
|
36
45
|
join(home, ".grok", "bin"), // x.ai installer
|
|
37
46
|
join(home, ".opencode", "bin"), // opencode installer
|
|
38
47
|
join(home, ".claude", "local"), // claude "local install"
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
// Machine-wide rather than under the (possibly temporary) home.
|
|
49
|
+
...(sealedFixture() ? [] : [
|
|
50
|
+
"/opt/homebrew/bin", // brew, Apple silicon
|
|
51
|
+
"/usr/local/bin", // brew Intel / classic installs
|
|
52
|
+
]),
|
|
41
53
|
join(home, ".volta", "bin"),
|
|
42
54
|
join(home, ".bun", "bin"),
|
|
43
55
|
join(home, ".asdf", "shims"),
|
|
@@ -115,7 +127,7 @@ export function augmentedPath() {
|
|
|
115
127
|
// belt-and-braces: fold in the login shell's PATH once, in the
|
|
116
128
|
// background — catches anything the known-dirs list doesn't (custom
|
|
117
129
|
// rc exports). Never blocks a spawn; the next one benefits.
|
|
118
|
-
if (!probed && !process.env.VITEST && process.platform !== "win32") {
|
|
130
|
+
if (!probed && !process.env.VITEST && !sealedFixture() && process.platform !== "win32") {
|
|
119
131
|
probed = true;
|
|
120
132
|
probeLoginShellPath();
|
|
121
133
|
}
|
|
@@ -235,11 +235,11 @@ export class ProviderRegistry {
|
|
|
235
235
|
install: withServerInstall(driver?.install, npmPresent),
|
|
236
236
|
authentication: inst.startAuthentication
|
|
237
237
|
? {
|
|
238
|
-
method: inst.getAuthentication && inst.completeAuthentication
|
|
238
|
+
method: inst.authenticationMethod ?? (inst.getAuthentication && inst.completeAuthentication
|
|
239
239
|
? "paste-code" // a link to open, then a code pasted back (Claude)
|
|
240
240
|
: inst.getAuthentication
|
|
241
241
|
? "device-code" // a code to enter at the provider's page (Codex)
|
|
242
|
-
: "browser", // a link and a callback URL (managed engines)
|
|
242
|
+
: "browser"), // a link and a callback URL (managed engines)
|
|
243
243
|
// the browser may remove the stored sign-in to switch accounts
|
|
244
244
|
signOut: inst.signOut !== undefined,
|
|
245
245
|
}
|