openmausbot 0.1.90 → 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-DUyXd0kL.js → abnfDiagram-O67JEVCF-Cd3X7Hxc.js} +1 -1
- package/dist/assets/{arc-q73qM-At.js → arc-DIYc7Ymx.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-D33O3Wur.js → architectureDiagram-NJMV4G6O-DBmRGVyP.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-DLsJeoXC.js → blockDiagram-BEXU5L5S-CPFePSEE.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-DnaljZnu.js → c4Diagram-YGBWAQC7-DD_DO1qy.js} +1 -1
- package/dist/assets/channel-Dtk5Mtic.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-Da0h2i79.js → chunk-2Q5K7J3B-BNEeNSjX.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-CfzHi54f.js → chunk-3FUC2YCW-BbinLaqH.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-LjE4d9Jf.js → chunk-5VM5RSS4-BBgYrgDR.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-DY-UGmvc.js → chunk-GTNCS2PH-ezXj-kA-.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-BqeGhyhP.js → chunk-GWA4HPMP-9FxZ3diV.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-BYa9EBAg.js → chunk-JWPE2WC7-CO-40JpI.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-vTrDtWyb.js → chunk-NETBCI7D-BEhjslYE.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-ic5tXadM.js → chunk-WEXAMYUT-CNeq4n7_.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-DvRCY-c6.js → chunk-XXDRQBXY-OsCY7KSi.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-DVbmgz_L.js → classDiagram-v2-NBCMYWYE-CloRUEtk.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-vdUs2n57.js → cose-bilkent-JH36ORCC-D1BGZhp4.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-BvLGlV3U.js → cynefin-OW5HDTMX-CUf4T2CN.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-C4GcJQDt.js → cynefinDiagram-VND7K2PF-DPEZrFGA.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-BMSaHpt_.js → dagre-6A5THRUB-bDe6GIv5.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-D5b9UBhC.js → diagram-22UHCM2B-CdcUQz55.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-CIKLlB7Y.js → diagram-3UASUU5V-BZpqGg7c.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-BzXb-7k7.js → diagram-ATOU4E4O-DvGM6ugp.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-HsTvJ7uT.js → diagram-CDSNMT55-DSTmMm0s.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-Db9ySNbQ.js → diagram-MLGK6HIB-15cucnMn.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-D6BKbpqY.js → diagram-MPIPVDR6-tMbuaE6n.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-Bq067L0t.js → ebnfDiagram-ZINNZB2B-BYxYzjHI.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-DhaD7fNJ.js → elk-276RUBZZ-v6bj852W.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-fwIhfz36.js → erDiagram-OPXOYQCR-5lBBlnd2.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-DygIyu0V.js → flowDiagram-KWPJA3E3-CZyl1zIj.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-DPYfSO96.js → ganttDiagram-FUAMR5RP-BiAI-ltZ.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-DhkHeCle.js → gitGraphDiagram-X574FWY7-BAZISkj3.js} +1 -1
- package/dist/assets/index-Cdmjrl28.css +1 -0
- package/dist/assets/{index-G1PHKGyh.js → index-DGBaEXrM.js} +1 -1
- package/dist/assets/index-DR7YPMkW.js +597 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-DstBLxME.js → infoDiagram-VRGFBTTK-B6ooOy-Z.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-CrIsGgch.js → ishikawaDiagram-OU5B5YK6-BZ9ksi-B.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-CYypGDbB.js → journeyDiagram-ZHPQQLJL-DWqlzIEe.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-DGjPt8E_.js → kanban-definition-PNTS6WVX-JX6piDwL.js} +1 -1
- package/dist/assets/{linear-Dwc3Hrru.js → linear-CmOWzX0P.js} +1 -1
- package/dist/assets/{mermaid.core-Dc4OePBL.js → mermaid.core-CF1zwoQ-.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-DV-vepj-.js → mindmap-definition-NLK3R4M7-CGh2K4fW.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-lx5Kj-n5.js → pegDiagram-GJSIUBJH-CDwYN0s7.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-Bq7Vmm15.js → pieDiagram-5QR66LMP-1rfjJocB.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-DeqeqOBj.js → quadrantDiagram-O4NWA36T-tKPvPiok.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-CXwRQzSC.js → railroadDiagram-XR7U4H2S-BHLm5vXR.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-8tAeoB88.js → requirementDiagram-PLB6GJNP-CB45STp7.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-BG5zjGWU.js → sankeyDiagram-IPEJSGJF-55QA_huC.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-DKF3iLcw.js → sequenceDiagram-PO4LG4MO-BckFmQHn.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-B-y1qUgT.js → sizeCapture-INFHLROL-BFCOJF11.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-MkzPgxAc.js → stateDiagram-v2-GCMORJYK-CZvmiVVN.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-DnbaOEwH.js → swimlanes-2SLR337P-BpDUCEKy.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-M0GYW9Y3.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-Bb4xG_Bt.js → timeline-definition-EJHVYXUP-BpxHq6IK.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-JgkR9pFf.js → usecaseDiagram-POWQR4AR-Cj66vm02.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-CIPIrAYe.js → vennDiagram-UO4OBE2U-C9nRkWE_.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-BjCLuUvJ.js → wardleyDiagram-VNRHLVJA-D-me_nWj.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-DKgiaYxT.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 +128 -15
- package/dist-server/container-mcp.js +277 -45
- package/dist-server/drivers/agents-proxy.js +16 -4
- package/dist-server/enterprise/server/index.js +5 -1
- package/dist-server/index.js +46703 -39955
- 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 +4099 -1217
- package/dist-server/pair-cli.js +4099 -1217
- package/dist-server/server/boat.js +67 -22
- package/dist-server/server/bot-overview.js +7 -4
- 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 +136 -26
- package/dist-server/server/cloud-home.js +64 -5
- package/dist-server/server/cloud-lending.js +167 -0
- package/dist-server/server/cloud-move-http.js +268 -0
- package/dist-server/server/cloud-move.js +418 -0
- 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 +215 -17
- package/dist-server/server/container-computer.js +3 -2
- package/dist-server/server/decider/index.js +238 -0
- package/dist-server/server/decider/jev.js +183 -0
- package/dist-server/server/decider/log.js +62 -0
- package/dist-server/server/decider/relay.js +52 -0
- package/dist-server/server/decider/room-routing.js +88 -0
- package/dist-server/server/decider/types.js +5 -0
- 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 +22 -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/boatagent.js +20 -12
- package/dist-server/server/drivers/chatgpt-plan-auth.js +481 -0
- package/dist-server/server/drivers/claude.js +313 -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/group-goal-run.js +6 -4
- package/dist-server/server/harness/registry.js +2 -2
- package/dist-server/server/harness-capabilities.js +2 -0
- package/dist-server/server/included-services.js +70 -0
- package/dist-server/server/index.js +1753 -263
- 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/model-context-window.js +4 -4
- package/dist-server/server/package-export.js +17 -10
- package/dist-server/server/package-import.js +6 -3
- package/dist-server/server/package-parts.js +3 -1
- 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 +25 -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/decider.js +19 -0
- 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/shared-computers.js +116 -30
- package/dist-server/server/skills.js +25 -10
- package/dist-server/server/store.js +79 -124
- package/dist-server/server/surface.js +13 -0
- package/dist-server/server/system-prompt.js +11 -0
- package/dist-server/server/team-backup.js +6 -2
- package/dist-server/server/team-manifest.js +11 -3
- 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/elevenlabs.js +11 -6
- package/dist-server/server/tts/fish.js +4 -5
- package/dist-server/server/tts/index.js +20 -11
- 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 +25 -3
- package/dist-server/server/workspace-backup.js +28 -8
- package/dist-server/server/workspace.js +65 -15
- package/dist-server/shared/cloud-home.js +4 -0
- package/dist-server/shared/package-format.js +30 -4
- package/dist-server/shared/team-backup.js +20 -3
- 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 +278 -45
- package/dist-server/workspace-backup.worker.js +184 -38
- package/enterprise/server/index.js +5 -1
- package/package.json +1 -1
- package/dist/assets/channel-BCuyHjFV.js +0 -1
- package/dist/assets/index-CRvo-DS2.css +0 -1
- package/dist/assets/index-CWYGlA63.js +0 -588
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BZQ07DGE.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
|
}
|
|
@@ -66,12 +66,14 @@ export function parseGroupGoalDecision(text) {
|
|
|
66
66
|
}
|
|
67
67
|
return { visibleText, decision: null };
|
|
68
68
|
}
|
|
69
|
-
/** Explicit room lead
|
|
70
|
-
* first active member. A goal run never recruits
|
|
69
|
+
/** Explicit room lead (or an Auto room's fallback) wins. Otherwise prefer
|
|
70
|
+
* an in-room Chief, then the first active member. A goal run never recruits
|
|
71
|
+
* somebody outside the room. */
|
|
71
72
|
export function selectGroupGoalCoordinator(members, responder) {
|
|
72
73
|
const active = members.filter((member) => !member.hidden);
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
const lead = responder.kind === "member" ? responder.botId : responder.kind === "auto" ? responder.fallbackBotId : undefined;
|
|
75
|
+
if (lead) {
|
|
76
|
+
const explicit = active.find((member) => member.id === lead);
|
|
75
77
|
if (explicit)
|
|
76
78
|
return explicit;
|
|
77
79
|
}
|
|
@@ -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
|
}
|
|
@@ -20,6 +20,8 @@ const ENVELOPE = {
|
|
|
20
20
|
skillAuthoring: true,
|
|
21
21
|
sharedComputers: true,
|
|
22
22
|
voiceNotes: true,
|
|
23
|
+
// Not a tool it adds: a Cloud home only hides its Local VM shell.
|
|
24
|
+
cloudHome: false,
|
|
23
25
|
botId: "",
|
|
24
26
|
};
|
|
25
27
|
/** Extra card lines for an engine switch, empty when nothing changes. */
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Boat cloud computers, ElevenLabs voice and the Jev decision model included
|
|
2
|
+
// with Cloud Pro (docs/cloud-pro.md, "Included Boat computers, voice and
|
|
3
|
+
// decisions").
|
|
4
|
+
// The Admin relays each on its own accounts, so its provider keys never reach
|
|
5
|
+
// this machine; each Cloud home gets its own relay tokens:
|
|
6
|
+
//
|
|
7
|
+
// OMB_CLOUD_BOAT_URL + OMB_CLOUD_BOAT_TOKEN the Boat relay, ending in /api/box/v1
|
|
8
|
+
// OMB_CLOUD_VOICE_URL + OMB_CLOUD_VOICE_TOKEN the ElevenLabs relay, ending in /v1
|
|
9
|
+
// OMB_CLOUD_DECIDER_URL + OMB_CLOUD_DECIDER_TOKEN the Jev relay, a Jev base URL
|
|
10
|
+
//
|
|
11
|
+
// An included token is only a fallback. The person's own key (Settings, or
|
|
12
|
+
// BOX_TOKEN / OMB_TTS_KEY / OMB_JEV_API_KEY) always wins, and removing it
|
|
13
|
+
// falls back again, so the credential is resolved on every request, never
|
|
14
|
+
// cached. The relay knows only our account, so each credential goes to one
|
|
15
|
+
// place: an own key to the provider (OMB_BOX_API / OMB_ELEVENLABS_API /
|
|
16
|
+
// decider.baseUrl when set, for dev and tests), an included token to its
|
|
17
|
+
// relay. An included token is never written to config.json, never reported
|
|
18
|
+
// to a client, and never the saved key Settings verifies, rotates or clears.
|
|
19
|
+
import { JEV_DEFAULT_BASE_URL } from "./decider/jev.js";
|
|
20
|
+
export const BOAT_API_DEFAULT = "https://ascii.dev/api/box/v1";
|
|
21
|
+
export const ELEVENLABS_API_DEFAULT = "https://api.elevenlabs.io/v1";
|
|
22
|
+
/** Also on WORKSPACE_CREDENTIAL_ENV (config.ts). */
|
|
23
|
+
export const INCLUDED_TOKEN_ENV = ["OMB_CLOUD_BOAT_TOKEN", "OMB_CLOUD_VOICE_TOKEN", "OMB_CLOUD_DECIDER_TOKEN"];
|
|
24
|
+
function includedService(url, token) {
|
|
25
|
+
const api = url?.trim().replace(/\/+$/, "");
|
|
26
|
+
const secret = token?.trim();
|
|
27
|
+
return api && secret ? { token: secret, api, included: true } : null;
|
|
28
|
+
}
|
|
29
|
+
const includedFrom = (env) => ({
|
|
30
|
+
boat: includedService(env.OMB_CLOUD_BOAT_URL, env.OMB_CLOUD_BOAT_TOKEN),
|
|
31
|
+
voice: includedService(env.OMB_CLOUD_VOICE_URL, env.OMB_CLOUD_VOICE_TOKEN),
|
|
32
|
+
// A Jev base URL as it is: the decider adds /v1/systemone, the relay's one route.
|
|
33
|
+
decider: includedService(env.OMB_CLOUD_DECIDER_URL, env.OMB_CLOUD_DECIDER_TOKEN),
|
|
34
|
+
});
|
|
35
|
+
let held = null;
|
|
36
|
+
/** At server startup: keep the included tokens in memory and drop them from
|
|
37
|
+
* the environment, as with the Cloud bootstrap secret, so nothing the server
|
|
38
|
+
* starts can inherit them. Before this (tests, scripts) they are read from
|
|
39
|
+
* the environment on each call. */
|
|
40
|
+
export function holdIncludedServices(env = process.env) {
|
|
41
|
+
held = includedFrom(env);
|
|
42
|
+
for (const name of INCLUDED_TOKEN_ENV)
|
|
43
|
+
delete env[name];
|
|
44
|
+
}
|
|
45
|
+
function resolve(own, providerApi, included) {
|
|
46
|
+
if (own) {
|
|
47
|
+
// A leased computer descriptor hands the token in use back as a plain
|
|
48
|
+
// token; the included one still goes only to its relay.
|
|
49
|
+
if (included && own === included.token)
|
|
50
|
+
return included;
|
|
51
|
+
return { token: own, api: providerApi, included: false };
|
|
52
|
+
}
|
|
53
|
+
return included;
|
|
54
|
+
}
|
|
55
|
+
export const boatProviderApi = (env = process.env) => env.OMB_BOX_API || BOAT_API_DEFAULT;
|
|
56
|
+
export const elevenLabsProviderApi = (env = process.env) => env.OMB_ELEVENLABS_API || ELEVENLABS_API_DEFAULT;
|
|
57
|
+
/** The Boat credential in use: the person's own token, else the included one. */
|
|
58
|
+
export function boatCredential(own, env = process.env) {
|
|
59
|
+
return resolve(own, boatProviderApi(env), (held ?? includedFrom(env)).boat);
|
|
60
|
+
}
|
|
61
|
+
/** The ElevenLabs credential in use: the person's own key, else the included one. */
|
|
62
|
+
export function voiceCredential(own, env = process.env) {
|
|
63
|
+
return resolve(own, elevenLabsProviderApi(env), (held ?? includedFrom(env)).voice);
|
|
64
|
+
}
|
|
65
|
+
/** The decision model's credential in use: the person's own Jev key (saved,
|
|
66
|
+
* or OMB_JEV_API_KEY) with their `decider.baseUrl` or Jev's own, else the
|
|
67
|
+
* included token with the relay. `api` is a Jev base URL. */
|
|
68
|
+
export function deciderCredential(own, ownBaseUrl, env = process.env) {
|
|
69
|
+
return resolve(own?.trim(), ownBaseUrl?.trim() || JEV_DEFAULT_BASE_URL, (held ?? includedFrom(env)).decider);
|
|
70
|
+
}
|