openmausbot 0.1.84 → 0.1.86
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/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/assets/abnfDiagram-O67JEVCF-DpUZNnFD.js +1 -0
- package/dist/assets/arc-DW7mrI4p.js +1 -0
- package/dist/assets/architectureDiagram-NJMV4G6O-CyeZ5WLZ.js +36 -0
- package/dist/assets/blockDiagram-BEXU5L5S-CBVaNjO7.js +140 -0
- package/dist/assets/c4Diagram-YGBWAQC7-sf8d41uT.js +38 -0
- package/dist/assets/channel-BXFkgus9.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-BOGvy7Y_.js +1 -0
- package/dist/assets/chunk-3FUC2YCW-BiF9zyiz.js +2 -0
- package/dist/assets/chunk-5VM5RSS4-EFuZ1SBZ.js +15 -0
- package/dist/assets/chunk-GTNCS2PH-pJLNSAT7.js +88 -0
- package/dist/assets/chunk-GWA4HPMP-Cb-3_3IT.js +1 -0
- package/dist/assets/chunk-JWPE2WC7-DAf5aogn.js +1 -0
- package/dist/assets/chunk-NETBCI7D-DR3kiwZz.js +1 -0
- package/dist/assets/chunk-WEXAMYUT-BmU8PeyM.js +1 -0
- package/dist/assets/chunk-XXDRQBXY-Buh8g8OT.js +1 -0
- package/dist/assets/classDiagram-v2-NBCMYWYE-BurfmMWM.js +217 -0
- package/dist/assets/cose-bilkent-JH36ORCC-KkGZUEkU.js +1 -0
- package/dist/assets/cynefin-OW5HDTMX-C3PpV96d.js +166 -0
- package/dist/assets/cynefinDiagram-VND7K2PF-Dt8JwJaI.js +62 -0
- package/dist/assets/cytoscape.esm-BB4DxJjf.js +321 -0
- package/dist/assets/dagre-6A5THRUB-DkjN8266.js +4 -0
- package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/assets/diagram-22UHCM2B-DUAJS0JV.js +200 -0
- package/dist/assets/diagram-3UASUU5V-Dw4KhF1a.js +24 -0
- package/dist/assets/diagram-ATOU4E4O-Dd1gmQqf.js +3 -0
- package/dist/assets/diagram-CDSNMT55-CjwGs0Yw.js +30 -0
- package/dist/assets/diagram-MLGK6HIB-BL-69Zrq.js +24 -0
- package/dist/assets/diagram-MPIPVDR6-5Zi2N7wo.js +41 -0
- package/dist/assets/ebnfDiagram-ZINNZB2B-D9NekWUX.js +1 -0
- package/dist/assets/elk-276RUBZZ-CkaSQjxw.js +27 -0
- package/dist/assets/erDiagram-OPXOYQCR-CdAVBV8-.js +99 -0
- package/dist/assets/flowDiagram-KWPJA3E3-Bm_lWWH7.js +213 -0
- package/dist/assets/ganttDiagram-FUAMR5RP-FZ8ejYWJ.js +292 -0
- package/dist/assets/gitGraphDiagram-X574FWY7-Dlv9rizZ.js +106 -0
- package/dist/assets/graph-D8UmR1vK.js +1 -0
- package/dist/assets/index-BGgqlWPJ.css +1 -0
- package/dist/assets/index-BtHo8ZKl.js +577 -0
- package/dist/assets/{index-DNa2umw-.js → index-h9FFNwTu.js} +1 -1
- package/dist/assets/infoDiagram-VRGFBTTK-BdQ_gW5B.js +2 -0
- package/dist/assets/init-Gi6I4Gst.js +1 -0
- package/dist/assets/ishikawaDiagram-OU5B5YK6-EwssEp2X.js +70 -0
- package/dist/assets/journeyDiagram-ZHPQQLJL-BX1G1vOd.js +139 -0
- package/dist/assets/kanban-definition-PNTS6WVX-BB4kAsyC.js +89 -0
- package/dist/assets/linear-3su2TG93.js +1 -0
- package/dist/assets/mermaid.core-CDD1E0s9.js +311 -0
- package/dist/assets/mindmap-definition-NLK3R4M7-Ba50MsNK.js +96 -0
- package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/assets/pegDiagram-GJSIUBJH-DZLkkZlM.js +1 -0
- package/dist/assets/pieDiagram-5QR66LMP-DaTz77Uq.js +39 -0
- package/dist/assets/quadrantDiagram-O4NWA36T-CpaiidpR.js +7 -0
- package/dist/assets/railroadDiagram-XR7U4H2S-mN4JrMeI.js +1 -0
- package/dist/assets/requirementDiagram-PLB6GJNP-BSNDRpg7.js +84 -0
- package/dist/assets/sankeyDiagram-IPEJSGJF-FngzGNug.js +40 -0
- package/dist/assets/sequenceDiagram-PO4LG4MO-CM4pCC3L.js +169 -0
- package/dist/assets/sizeCapture-INFHLROL-CRICHXkw.js +1 -0
- package/dist/assets/stateDiagram-v2-GCMORJYK-oyTWpxH2.js +291 -0
- package/dist/assets/swimlanes-2SLR337P-D9h9mPBq.js +1 -0
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BWrvB2ak.js +8 -0
- package/dist/assets/timeline-definition-EJHVYXUP-BJUlN9bW.js +120 -0
- package/dist/assets/usecaseDiagram-POWQR4AR-3uBNkbAb.js +370 -0
- package/dist/assets/vennDiagram-UO4OBE2U-D2odalzT.js +34 -0
- package/dist/assets/wardleyDiagram-VNRHLVJA-DHgFaB9S.js +78 -0
- package/dist/assets/xychartDiagram-PMCCYNJV-w5GYM2h0.js +7 -0
- package/dist/index.html +2 -2
- package/dist-server/companion/src/routes.js +1 -0
- package/dist-server/container-mcp.js +231 -17
- package/dist-server/drivers/agents-proxy.js +16097 -1411
- package/dist-server/enterprise/LICENSE +32 -0
- package/dist-server/enterprise/server/index.js +6 -5
- package/dist-server/hooks/omb-hook.js +74 -0
- package/dist-server/index.js +12495 -7584
- package/dist-server/local-computer-proxy.js +83 -1
- package/dist-server/local-computer.js +14 -2
- package/dist-server/mcp-server.js +3 -1
- package/dist-server/openmausbot.js +5458 -4587
- package/dist-server/pair-cli.js +5458 -4587
- package/dist-server/proxy-paths.js +1 -0
- package/dist-server/server/admin-activity.js +410 -0
- package/dist-server/server/agent-tool-policy.js +1 -0
- package/dist-server/server/bot-package.js +2 -0
- package/dist-server/server/bot-visibility.js +462 -0
- package/dist-server/server/box.js +25 -5
- package/dist-server/server/browser-engine.js +87 -10
- package/dist-server/server/browser-live.js +7 -5
- package/dist-server/server/browser-runtime.js +66 -11
- package/dist-server/server/channel-queue.js +2 -0
- package/dist-server/server/checkpoints.js +62 -18
- package/dist-server/server/cli-prompts.js +26 -2
- package/dist-server/server/cli.js +79 -10
- package/dist-server/server/commands.js +27 -0
- package/dist-server/server/compaction-summary.js +78 -0
- package/dist-server/server/composio.js +49 -11
- package/dist-server/server/config.js +137 -14
- package/dist-server/server/context-budget.js +29 -0
- package/dist-server/server/context-rebuild.js +72 -0
- package/dist-server/server/decision-log.js +209 -48
- package/dist-server/server/default-model-selection.js +20 -3
- package/dist-server/server/delegations.js +11 -9
- package/dist-server/server/digest.js +130 -0
- package/dist-server/server/drivers/acp/core.js +637 -238
- package/dist-server/server/drivers/acp/grok.js +4 -3
- package/dist-server/server/drivers/agents-call.js +1123 -0
- package/dist-server/server/drivers/agents-catalog.js +659 -0
- package/dist-server/server/drivers/agents-client.js +28 -0
- package/dist-server/server/drivers/agents-proxy.js +18 -1683
- package/dist-server/server/drivers/agents-result.js +23 -0
- package/dist-server/server/drivers/chat-mcp-tools.js +17 -2
- package/dist-server/server/drivers/claude.js +83 -16
- package/dist-server/server/drivers/codex-mcp-names.js +44 -0
- package/dist-server/server/drivers/codex.js +32 -4
- package/dist-server/server/drivers/grok.js +2 -1
- package/dist-server/server/drivers/openai-chat.js +66 -45
- package/dist-server/server/drivers/openai-compat.js +16 -8
- package/dist-server/server/enterprise.js +97 -16
- package/dist-server/server/external-runtime.js +83 -0
- package/dist-server/server/guarded-requests.js +60 -0
- package/dist-server/server/harness/http.js +61 -0
- package/dist-server/server/hooks/omb-hook.js +103 -0
- package/dist-server/server/hosted-models.js +151 -0
- package/dist-server/server/hosted-slack.js +11 -0
- package/dist-server/server/index.js +2810 -678
- package/dist-server/server/local-computer.js +21 -2
- package/dist-server/server/managed-desktop.js +79 -14
- package/dist-server/server/managed-policy.js +153 -0
- package/dist-server/server/mcp-bridge.js +10 -2
- package/dist-server/server/mcp-tool-images.js +37 -0
- package/dist-server/server/mcp-tool-schema.js +108 -0
- package/dist-server/server/message-db.js +108 -21
- package/dist-server/server/message-file.js +3 -2
- package/dist-server/server/model-context-window.js +7 -0
- package/dist-server/server/model-prices.js +121 -0
- package/dist-server/server/notify.js +10 -1
- package/dist-server/server/package-export.js +1 -0
- package/dist-server/server/peer-roster.js +17 -4
- package/dist-server/server/provider-icon.js +20 -0
- package/dist-server/server/proxy-paths.js +1 -0
- package/dist-server/server/recent-work.js +15 -0
- package/dist-server/server/request-auth.js +97 -0
- package/dist-server/server/room-handoffs.js +41 -13
- package/dist-server/server/routes/hosted-slack.js +20 -0
- package/dist-server/server/routes/table.js +14 -0
- package/dist-server/server/routine-requests.js +39 -1
- package/dist-server/server/routines.js +65 -9
- package/dist-server/server/shared-computer-control.js +31 -4
- package/dist-server/server/spend.js +111 -16
- package/dist-server/server/steer-queue.js +12 -1
- package/dist-server/server/store.js +384 -33
- package/dist-server/server/system-prompt.js +4 -4
- package/dist-server/server/team-backup.js +19 -2
- package/dist-server/server/thread-starters.js +53 -0
- package/dist-server/server/tool-results.js +72 -0
- package/dist-server/server/tts/grok.js +74 -0
- package/dist-server/server/tts/index.js +19 -1
- package/dist-server/server/usage-ledger.js +31 -8
- package/dist-server/server/webhooks.js +28 -0
- package/dist-server/server/workspace-backup-policy.js +9 -2
- package/dist-server/server/workspace-backup.js +7 -4
- package/dist-server/shared/approval-mode.js +7 -1
- package/dist-server/shared/digest.js +1 -0
- package/dist-server/shared/markdown-windows-paths.js +36 -0
- package/dist-server/shared/mention-boundary.js +15 -0
- package/dist-server/shared/provider-icon.js +110 -0
- package/dist-server/shared/routines.js +7 -1
- package/dist-server/shared/team-backup.js +5 -0
- package/dist-server/src/lib/composer-attachments.js +16 -0
- package/dist-server/vps-container-mcp.js +236 -22
- package/enterprise/README.md +33 -12
- package/enterprise/server/index.js +6 -5
- package/package.json +1 -1
- package/dist/assets/index-BbU5REzd.js +0 -310
- package/dist/assets/index-CLGfYlx_.css +0 -1
|
@@ -9,6 +9,7 @@ import { normalizeImageGenerationUrl } from "../shared/image-generation.js";
|
|
|
9
9
|
import { writeFileAtomic } from "./atomic.js";
|
|
10
10
|
import { EFFORT_LEVELS } from "../shared/wire.js";
|
|
11
11
|
import { isModelVariant } from "./contracts.js";
|
|
12
|
+
import { PROVIDER_ICON_PRESETS, providerIconError } from "../shared/provider-icon.js";
|
|
12
13
|
import { isRemoteMcpServer, parseStoredMcpServer } from "./mcp-registry.js";
|
|
13
14
|
import { parseJson, schemaIssue } from "./schema.js";
|
|
14
15
|
const optionalText = z.string().optional();
|
|
@@ -35,6 +36,19 @@ export const MAX_LOCAL_VM_MAX_INSTANCES = 4;
|
|
|
35
36
|
export function isValidSshAlias(value) {
|
|
36
37
|
return typeof value === "string" && SSH_ALIAS.test(value);
|
|
37
38
|
}
|
|
39
|
+
const CDP_PORT = /^[0-9]{1,5}$/;
|
|
40
|
+
const CDP_URL = /^(https?|wss?):\/\/\S+$/i;
|
|
41
|
+
/** A bare TCP port (agent-browser's `--cdp <port>` shorthand) or an
|
|
42
|
+
* http(s)/ws(s) URL to a Chrome DevTools Protocol endpoint. */
|
|
43
|
+
export function isValidCdpTarget(value) {
|
|
44
|
+
if (typeof value !== "string" || value === "")
|
|
45
|
+
return false;
|
|
46
|
+
if (CDP_PORT.test(value)) {
|
|
47
|
+
const port = Number(value);
|
|
48
|
+
return port >= 1 && port <= 65535;
|
|
49
|
+
}
|
|
50
|
+
return CDP_URL.test(value);
|
|
51
|
+
}
|
|
38
52
|
/** Keep the persisted VPS shape deliberately smaller than an SSH connection. */
|
|
39
53
|
export function normalizeVpsConfig(raw) {
|
|
40
54
|
if (raw === undefined || raw === null)
|
|
@@ -55,6 +69,16 @@ const vpsConfigSchema = z.object({
|
|
|
55
69
|
message: "must be a simple SSH config alias",
|
|
56
70
|
}).optional(),
|
|
57
71
|
});
|
|
72
|
+
/** Attach a bot's browser to a Chrome the operator already has running,
|
|
73
|
+
* instead of agent-browser spawning its own (#1396). Deliberately a
|
|
74
|
+
* server-owned config field, not an env-var passthrough: the ambient
|
|
75
|
+
* process environment must never redirect a bot's browser
|
|
76
|
+
* (server/browser-live.test.ts pins this guarantee down). */
|
|
77
|
+
const browserEngineConfigSchema = z.object({
|
|
78
|
+
attachCdpUrl: z.string().trim().max(2048).refine((value) => value === "" || isValidCdpTarget(value), {
|
|
79
|
+
message: "browserEngine.attachCdpUrl must be a CDP port (1-65535) or an http(s)/ws(s) URL",
|
|
80
|
+
}).optional(),
|
|
81
|
+
});
|
|
58
82
|
const roomConfigSchema = z.object({
|
|
59
83
|
turnTimeoutMinutes: z
|
|
60
84
|
.number()
|
|
@@ -233,6 +257,10 @@ const featureConfigSchema = z.object({
|
|
|
233
257
|
* machine's own Claude Code setup (Plugins → MCP servers switch). Off by
|
|
234
258
|
* default: each extra tool costs tokens on every model call. */
|
|
235
259
|
claudeUserMcp: z.boolean().optional(),
|
|
260
|
+
/** LLM-generated titles for new bot threads. Off until explicitly
|
|
261
|
+
* enabled; a one-shot that fails or answers junk leaves the first-message
|
|
262
|
+
* snippet in place — see llmThreadTitlesEnabled. */
|
|
263
|
+
llmThreadTitles: z.boolean().optional(),
|
|
236
264
|
});
|
|
237
265
|
/** First-run progress. Kept in the workspace config rather than a browser so
|
|
238
266
|
* it survives cleared site data and is shared by every paired client. Hint
|
|
@@ -250,6 +278,11 @@ const instanceConfigSchema = z.object({
|
|
|
250
278
|
driver: z.string().min(1),
|
|
251
279
|
displayName: optionalText,
|
|
252
280
|
accentColor: optionalText,
|
|
281
|
+
icon: z.discriminatedUnion("kind", [
|
|
282
|
+
z.object({ kind: z.literal("preset"), preset: z.enum(PROVIDER_ICON_PRESETS) }).strict(),
|
|
283
|
+
z.object({ kind: z.literal("custom"), dataUrl: z.string() }).strict()
|
|
284
|
+
.refine((icon) => providerIconError(icon) === null, { message: "Invalid provider icon" }),
|
|
285
|
+
]).optional(),
|
|
253
286
|
environment: z.record(z.string(), z.string()).optional(),
|
|
254
287
|
enabled: z.boolean().optional(),
|
|
255
288
|
config: z.json().optional(),
|
|
@@ -261,6 +294,22 @@ const defaultModelSelectionSchema = z.object({
|
|
|
261
294
|
effort: z.enum(EFFORT_LEVELS).optional(),
|
|
262
295
|
variant: z.string().refine(isModelVariant, "invalid model variant").optional(),
|
|
263
296
|
}).refine((selection) => selection.variant === undefined || selection.effort === undefined, "choose either a model variant or an effort level");
|
|
297
|
+
const threadsConfigSchema = z.object({
|
|
298
|
+
maxConcurrentPerBot: z.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS),
|
|
299
|
+
/** Cap each per-thread events/ and native/ NDJSON log at this many
|
|
300
|
+
* bytes; absent (the default) keeps today's unbounded growth (#1280). */
|
|
301
|
+
eventLogMaxBytes: z.number().int().min(MIN_THREAD_EVENT_LOG_BYTES).max(MAX_THREAD_EVENT_LOG_BYTES).optional(),
|
|
302
|
+
/** Days a closed or archived thread's event logs survive (#1280).
|
|
303
|
+
* Absent keeps them forever. */
|
|
304
|
+
eventLogRetentionDays: z.number().int().min(1).max(3650).optional(),
|
|
305
|
+
}).strict();
|
|
306
|
+
/** PATCH threads: every knob is independently patchable, and null clears an
|
|
307
|
+
* event-log knob back to its absent (off) default. */
|
|
308
|
+
const threadsPatchSchema = threadsConfigSchema.extend({
|
|
309
|
+
maxConcurrentPerBot: threadsConfigSchema.shape.maxConcurrentPerBot.optional(),
|
|
310
|
+
eventLogMaxBytes: threadsConfigSchema.shape.eventLogMaxBytes.nullable(),
|
|
311
|
+
eventLogRetentionDays: threadsConfigSchema.shape.eventLogRetentionDays.nullable(),
|
|
312
|
+
});
|
|
264
313
|
const appConfigSchema = z.object({
|
|
265
314
|
/** Verified by the dedicated domain endpoint, never a generic config patch. */
|
|
266
315
|
customDomain: z.string().optional(),
|
|
@@ -316,6 +365,7 @@ const appConfigSchema = z.object({
|
|
|
316
365
|
/** Voice settings and the selected voice id. `provider` picks the
|
|
317
366
|
* engine: "elevenlabs" (default; needs `key`), "fish" (needs its own
|
|
318
367
|
* `fishKey`), "system" (the Mac's built-in voices, no key), or
|
|
368
|
+
* "xai" (Grok TTS, reusing `xai.key`), or
|
|
319
369
|
* "chatterbox" (a local OpenAI-compatible Chatterbox server; `baseUrl`
|
|
320
370
|
* and `model` are settings, not secrets). Cloud keys stay separate so
|
|
321
371
|
* switching providers never overwrites or misuses the other key. */
|
|
@@ -323,7 +373,7 @@ const appConfigSchema = z.object({
|
|
|
323
373
|
key: optionalText,
|
|
324
374
|
fishKey: optionalText,
|
|
325
375
|
voice: optionalText,
|
|
326
|
-
provider: z.enum(["elevenlabs", "fish", "system", "chatterbox"]).optional(),
|
|
376
|
+
provider: z.enum(["elevenlabs", "fish", "system", "chatterbox", "xai"]).optional(),
|
|
327
377
|
baseUrl: z
|
|
328
378
|
.string()
|
|
329
379
|
.trim()
|
|
@@ -356,18 +406,20 @@ const appConfigSchema = z.object({
|
|
|
356
406
|
* system language. Unknown tags degrade to English in the renderer. */
|
|
357
407
|
language: optionalText,
|
|
358
408
|
rooms: roomConfigSchema.optional(),
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}).strict().optional(),
|
|
409
|
+
context: z.object({
|
|
410
|
+
rebuildBytes: z.number().int().min(1_024).max(1_000_000).optional(),
|
|
411
|
+
compactAt: z.number().positive().max(10_000_000).optional(),
|
|
412
|
+
autoCompact: z.boolean().optional(),
|
|
413
|
+
}).optional(),
|
|
414
|
+
threads: threadsConfigSchema.optional(),
|
|
415
|
+
/** The authorization decision log (server/decision-log.ts): days of month
|
|
416
|
+
* files kept, at least; OMB_DECISION_RETENTION_DAYS wins when set. */
|
|
417
|
+
decisions: z.object({ retentionDays: z.number().int().min(1).max(3650).optional() }).strict().optional(),
|
|
368
418
|
localVm: localVmConfigSchema.optional(),
|
|
369
419
|
features: featureConfigSchema.optional(),
|
|
370
420
|
onboarding: onboardingConfigSchema.optional(),
|
|
421
|
+
/** CDP attach target for a bot's browser; see browserEngineConfigSchema. */
|
|
422
|
+
browserEngine: browserEngineConfigSchema.optional(),
|
|
371
423
|
browserProfiles: browserProfilesSchema.optional(),
|
|
372
424
|
instances: instanceConfigMapSchema.optional(),
|
|
373
425
|
/** User-configured MCP servers, mounted into every capable engine. Kept
|
|
@@ -379,7 +431,8 @@ const appConfigSchema = z.object({
|
|
|
379
431
|
const storedAppConfigSchema = appConfigSchema.extend({
|
|
380
432
|
browserProfiles: storedBrowserProfilesSchema.optional(),
|
|
381
433
|
});
|
|
382
|
-
const appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true })
|
|
434
|
+
const appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true })
|
|
435
|
+
.extend({ threads: threadsPatchSchema.optional() });
|
|
383
436
|
const jsonObjectSchema = z.record(z.string(), z.json());
|
|
384
437
|
/** Resolve a canonical profile record to its exact durable Electron
|
|
385
438
|
* partition identity. Callers must never substitute the display/API id. */
|
|
@@ -459,6 +512,13 @@ export function parseConfigPatch(value) {
|
|
|
459
512
|
export function vpsSshAlias(cfg) {
|
|
460
513
|
return isValidSshAlias(cfg.vps?.sshAlias) ? cfg.vps.sshAlias : null;
|
|
461
514
|
}
|
|
515
|
+
/** Read-and-revalidate accessor, same shape as vpsSshAlias above: even
|
|
516
|
+
* though loadConfig()/parseStoredConfig() already schema-validate this
|
|
517
|
+
* field, callers that forward it into a child process environment get a
|
|
518
|
+
* second, cheap guarantee rather than trusting a hand-edited config.json. */
|
|
519
|
+
export function browserEngineAttachCdpUrl(cfg) {
|
|
520
|
+
return isValidCdpTarget(cfg.browserEngine?.attachCdpUrl) ? cfg.browserEngine.attachCdpUrl : null;
|
|
521
|
+
}
|
|
462
522
|
export function roomTurnTimeoutMinutes(cfg) {
|
|
463
523
|
return cfg.rooms?.turnTimeoutMinutes ?? DEFAULT_ROOM_TURN_TIMEOUT_MINUTES;
|
|
464
524
|
}
|
|
@@ -472,6 +532,8 @@ export function roomHandoffLimits(cfg) {
|
|
|
472
532
|
hardCapMs: (cfg.rooms?.handoffHardCapMinutes ?? DEFAULT_ROOM_HANDOFF_HARD_CAP_MINUTES) * 60_000,
|
|
473
533
|
};
|
|
474
534
|
}
|
|
535
|
+
/** Accepts a full config or a parsed patch: the concurrency limit may be
|
|
536
|
+
* read from either, and a patch may legitimately omit it. */
|
|
475
537
|
export function maxConcurrentBotThreads(cfg) {
|
|
476
538
|
return cfg.threads?.maxConcurrentPerBot ?? DEFAULT_MAX_CONCURRENT_BOT_THREADS;
|
|
477
539
|
}
|
|
@@ -526,6 +588,14 @@ export function sharedComputersEnabled(cfg) {
|
|
|
526
588
|
export function claudeUserMcpEnabled(cfg) {
|
|
527
589
|
return cfg.features?.claudeUserMcp === true;
|
|
528
590
|
}
|
|
591
|
+
/** Opt-in generated titles for new bot threads: a cheap provider one-shot
|
|
592
|
+
* names the row instead of the first-message snippet. Off until enabled by
|
|
593
|
+
* hand in ~/.openmausbot/config.json
|
|
594
|
+
* (`{"features": {"llmThreadTitles": true}}`); a one-shot that fails or
|
|
595
|
+
* answers anything unusable leaves the snippet untouched. */
|
|
596
|
+
export function llmThreadTitlesEnabled(cfg) {
|
|
597
|
+
return cfg.features?.llmThreadTitles === true;
|
|
598
|
+
}
|
|
529
599
|
/** Config sections no provider driver reads. A write that touches only
|
|
530
600
|
* these must not rebuild the fleet: rebuilding disposes every engine child
|
|
531
601
|
* and reloads it, seconds of work that would also interrupt in-flight
|
|
@@ -539,6 +609,7 @@ export const FLEET_NEUTRAL_KEYS = new Set([
|
|
|
539
609
|
"vps",
|
|
540
610
|
"rooms",
|
|
541
611
|
"threads",
|
|
612
|
+
"context",
|
|
542
613
|
"localVm",
|
|
543
614
|
"features",
|
|
544
615
|
"browserProfiles",
|
|
@@ -719,6 +790,8 @@ export const WORKSPACE_CREDENTIAL_ENV = [
|
|
|
719
790
|
"XAI_API_KEY",
|
|
720
791
|
"OMB_ANTHROPIC_API_KEY",
|
|
721
792
|
"OMB_ANTHROPIC_API_URL",
|
|
793
|
+
"OMB_HOSTED_MODEL_TOKEN",
|
|
794
|
+
"OMB_HOSTED_MODELS",
|
|
722
795
|
"OPENAI_COMPAT_API_KEY",
|
|
723
796
|
"OPENAI_COMPAT_URL",
|
|
724
797
|
"BOX_TOKEN",
|
|
@@ -735,10 +808,32 @@ export const WORKSPACE_CREDENTIAL_ENV = [
|
|
|
735
808
|
"OMB_BROWSER_CONNECTION",
|
|
736
809
|
"OMB_USER_DATA",
|
|
737
810
|
];
|
|
738
|
-
/**
|
|
811
|
+
/** Secrets of whoever operates this server, not of the workspace: the license
|
|
812
|
+
* key, a fleet container's installation credential, and everything a hosting
|
|
813
|
+
* control plane injects under `OMB_CLOUD_` (the readiness token, the bootstrap
|
|
814
|
+
* document and its gateway token). Only this process reads them. The prefix
|
|
815
|
+
* ends in an underscore on purpose: `OMB_CLOUDFLARED_PATH` is not one of them.
|
|
816
|
+
* What an engine is meant to receive arrives under another name through its
|
|
817
|
+
* instance environment (the hosted model token as ANTHROPIC_API_KEY or
|
|
818
|
+
* OPENMAUSBOT_COMPANY_API_KEY), so nothing here is ever an engine's input. */
|
|
819
|
+
export const CONTROL_PLANE_ENV = ["OMB_LICENSE_KEY", "OMB_INSTALLATION_CREDENTIAL"];
|
|
820
|
+
export const CONTROL_PLANE_ENV_PREFIX = "OMB_CLOUD_";
|
|
821
|
+
/** Drop every control-plane secret from a child-process env (in place). No
|
|
822
|
+
* driver allowlist re-admits these. Names compare case-insensitively because
|
|
823
|
+
* Windows environments do. */
|
|
824
|
+
export function stripControlPlaneEnv(env) {
|
|
825
|
+
for (const key of Object.keys(env)) {
|
|
826
|
+
const name = key.toUpperCase();
|
|
827
|
+
if (name.startsWith(CONTROL_PLANE_ENV_PREFIX) || CONTROL_PLANE_ENV.includes(name))
|
|
828
|
+
delete env[key];
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
/** Drop every workspace credential, and every control-plane secret, from a
|
|
832
|
+
* child-process env (in place). */
|
|
739
833
|
export function stripWorkspaceCredentialEnv(env) {
|
|
740
834
|
for (const key of WORKSPACE_CREDENTIAL_ENV)
|
|
741
835
|
delete env[key];
|
|
836
|
+
stripControlPlaneEnv(env);
|
|
742
837
|
}
|
|
743
838
|
/** Env names a provider CLI might read as its own billing identity. A spawned
|
|
744
839
|
* engine keeps only what its driver explicitly allows: a foreign key riding
|
|
@@ -758,6 +853,14 @@ export const PROVIDER_CREDENTIAL_ENV = [
|
|
|
758
853
|
"CURSOR_API_KEY",
|
|
759
854
|
"CURSOR_AUTH_TOKEN",
|
|
760
855
|
];
|
|
856
|
+
const configSaveListeners = new Set();
|
|
857
|
+
/** Told, synchronously, what each saveConfig wrote: the file before and
|
|
858
|
+
* after. The admin activity log (server/admin-activity.ts) records the
|
|
859
|
+
* change for whoever's request made it. A listener must not throw. */
|
|
860
|
+
export function onConfigSaved(listener) {
|
|
861
|
+
configSaveListeners.add(listener);
|
|
862
|
+
return () => { configSaveListeners.delete(listener); };
|
|
863
|
+
}
|
|
761
864
|
/** Merge a partial config into ~/.openmausbot/config.json (secrets never
|
|
762
865
|
* echoed back — callers report configured-or-not booleans only). */
|
|
763
866
|
export function saveConfig(patch, options = {}) {
|
|
@@ -771,20 +874,32 @@ export function saveConfig(patch, options = {}) {
|
|
|
771
874
|
catch {
|
|
772
875
|
/* first write */
|
|
773
876
|
}
|
|
774
|
-
const checkedPatch = appConfigSchema.partial().parse(patch);
|
|
877
|
+
const checkedPatch = appConfigSchema.partial().extend({ threads: threadsPatchSchema.optional() }).parse(patch);
|
|
878
|
+
const before = configSaveListeners.size ? structuredClone(disk) : disk;
|
|
775
879
|
// A write is the durable migration point. Preserve every other raw key in
|
|
776
880
|
// config.json, but never write #567's mixed-case or duplicate profile ids
|
|
777
881
|
// back after we have successfully recognized the legacy list.
|
|
778
882
|
const storedProfiles = storedBrowserProfilesSchema.safeParse(disk.browserProfiles);
|
|
779
883
|
if (storedProfiles.success)
|
|
780
884
|
disk.browserProfiles = storedProfiles.data;
|
|
781
|
-
for (const key of ["xai", "anthropic", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "localVm", "features", "budgets", "billing", "onboarding"]) {
|
|
885
|
+
for (const key of ["xai", "anthropic", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "context", "localVm", "features", "budgets", "billing", "decisions", "onboarding", "browserEngine"]) {
|
|
782
886
|
const section = checkedPatch[key];
|
|
783
887
|
if (!section)
|
|
784
888
|
continue;
|
|
785
889
|
const current = jsonObjectSchema.safeParse(disk[key]);
|
|
786
890
|
const merged = current.success ? { ...current.data } : {};
|
|
891
|
+
// parseStoredConfig requires threads.maxConcurrentPerBot, so creating
|
|
892
|
+
// the section with only an event-log knob must still persist a valid
|
|
893
|
+
// concurrency default.
|
|
894
|
+
if (key === "threads" && !current.success)
|
|
895
|
+
merged.maxConcurrentPerBot = DEFAULT_MAX_CONCURRENT_BOT_THREADS;
|
|
787
896
|
Object.assign(merged, section);
|
|
897
|
+
// null is the patch's explicit "remove this key" marker (today only the
|
|
898
|
+
// threads event-log knobs use it); a key the patch omits keeps its value.
|
|
899
|
+
for (const [sectionKey, sectionValue] of Object.entries(section)) {
|
|
900
|
+
if (sectionValue === null)
|
|
901
|
+
delete merged[sectionKey];
|
|
902
|
+
}
|
|
788
903
|
disk[key] = merged;
|
|
789
904
|
}
|
|
790
905
|
if (checkedPatch.vps !== undefined)
|
|
@@ -863,6 +978,14 @@ export function saveConfig(patch, options = {}) {
|
|
|
863
978
|
}
|
|
864
979
|
mkdirSync(DATA_DIR, { recursive: true });
|
|
865
980
|
writeFileAtomic(p, JSON.stringify(disk, null, 2), { mode: 0o600 });
|
|
981
|
+
for (const listener of configSaveListeners) {
|
|
982
|
+
try {
|
|
983
|
+
listener(before, disk);
|
|
984
|
+
}
|
|
985
|
+
catch (error) {
|
|
986
|
+
console.warn(`config: a save listener failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
866
989
|
}
|
|
867
990
|
/** Set one instance's `config.cli` ("" clears the override back to the
|
|
868
991
|
* driver default). Creating the instance entry is fine — a config-less
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { modelContextWindow } from "./model-context-window.js";
|
|
2
|
+
export const DEFAULT_CONTEXT_WINDOW = 128_000;
|
|
3
|
+
const positive = (n) => typeof n === "number" && Number.isFinite(n) && n > 0;
|
|
4
|
+
export function contextWindowFor(model, catalog, reported) {
|
|
5
|
+
if (positive(reported))
|
|
6
|
+
return reported;
|
|
7
|
+
const declared = catalog?.options.find((option) => option.id === model)?.contextWindow;
|
|
8
|
+
if (positive(declared))
|
|
9
|
+
return declared;
|
|
10
|
+
const inferred = model ? modelContextWindow(model) : undefined;
|
|
11
|
+
return positive(inferred) ? inferred : DEFAULT_CONTEXT_WINDOW;
|
|
12
|
+
}
|
|
13
|
+
/** Leave headroom even for a small local model. An 8k lower bound would
|
|
14
|
+
* make compaction unreachable on models whose entire window is 8k. */
|
|
15
|
+
export function compactBudget(window, compactAt, nativeCompactAt) {
|
|
16
|
+
if (!positive(window))
|
|
17
|
+
throw new Error("invalid model context window");
|
|
18
|
+
const configured = positive(compactAt) ? (compactAt < 1 ? window * compactAt : compactAt) : window * 0.8;
|
|
19
|
+
return Math.max(1, Math.floor(Math.min(configured, window * 0.9, positive(nativeCompactAt) ? nativeCompactAt * 0.9 : Infinity)));
|
|
20
|
+
}
|
|
21
|
+
export function shouldCompact(input) {
|
|
22
|
+
// Summed input across tool rounds is NOT a context-window measurement.
|
|
23
|
+
const size = positive(input.contextTokens) ? input.contextTokens : Math.ceil(input.estimatedBytes / 4);
|
|
24
|
+
// Regrowth avoids repeatedly folding an irreducible prompt, but cannot
|
|
25
|
+
// delay the harness beyond a known provider-native compaction boundary.
|
|
26
|
+
const ceiling = compactBudget(input.window, input.window, input.nativeCompactAt);
|
|
27
|
+
const threshold = Math.min(ceiling, positive(input.floor) ? Math.max(input.budget, input.floor * 1.25) : input.budget);
|
|
28
|
+
return size >= threshold;
|
|
29
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export const DEFAULT_REBUILD_BYTES = 24_000;
|
|
2
|
+
export const MAX_SUMMARY_BYTES = 6_000;
|
|
3
|
+
const OMITTED_TEXT = "\n[Text shortened for context; the original remains in this conversation.]";
|
|
4
|
+
/** UTF-8 prefixes must not end inside a code point. */
|
|
5
|
+
export function prefixBytes(text, limit) {
|
|
6
|
+
const bytes = Buffer.from(text);
|
|
7
|
+
let end = Math.max(0, Math.min(bytes.length, Math.floor(limit)));
|
|
8
|
+
while (end < bytes.length && end > 0 && (bytes[end] & 0xc0) === 0x80)
|
|
9
|
+
end--;
|
|
10
|
+
return bytes.subarray(0, end).toString("utf8");
|
|
11
|
+
}
|
|
12
|
+
export function boundedContextText(text, limit) {
|
|
13
|
+
if (Buffer.byteLength(text) <= limit)
|
|
14
|
+
return text;
|
|
15
|
+
const notice = prefixBytes(OMITTED_TEXT, limit);
|
|
16
|
+
const remaining = Math.max(0, limit - Buffer.byteLength(notice));
|
|
17
|
+
const head = prefixBytes(text, Math.floor(remaining / 2));
|
|
18
|
+
const bytes = Buffer.from(text);
|
|
19
|
+
let start = bytes.length - (remaining - Buffer.byteLength(head));
|
|
20
|
+
while (start < bytes.length && (bytes[start] & 0xc0) === 0x80)
|
|
21
|
+
start++;
|
|
22
|
+
return head + notice + bytes.subarray(start).toString("utf8");
|
|
23
|
+
}
|
|
24
|
+
export function selectReplay(history, options = {}) {
|
|
25
|
+
const budget = options.budgetBytes ?? DEFAULT_REBUILD_BYTES;
|
|
26
|
+
const maxMessages = options.maxMessages ?? 40;
|
|
27
|
+
if (!Number.isSafeInteger(budget) || budget < 1_024 || !Number.isSafeInteger(maxMessages) || maxMessages < 1) {
|
|
28
|
+
throw new Error("invalid context replay budget");
|
|
29
|
+
}
|
|
30
|
+
const record = options.compaction;
|
|
31
|
+
const foldedThrough = record ? history.findIndex((entry) => entry.id === record.foldedThroughId) : -1;
|
|
32
|
+
const cut = record ? (record.firstKeptId ? history.findIndex((entry) => entry.id === record.firstKeptId) : foldedThrough + 1) : -1;
|
|
33
|
+
const recordAt = record ? history.findIndex((entry) => entry.id === record.id) : -1;
|
|
34
|
+
// Both anchors must still belong to this branch, in their original order.
|
|
35
|
+
// A stale record must never hide a rewritten or independently selected fork.
|
|
36
|
+
const applies = Boolean(record && cut > foldedThrough && foldedThrough >= 0 && recordAt >= cut);
|
|
37
|
+
const representedIds = applies ? history.slice(0, cut).map((entry) => entry.id) : [];
|
|
38
|
+
const entries = history.slice(applies ? cut : 0).filter((entry) => entry.text && entry.id !== record?.id && !options.excludedIds?.has(entry.id));
|
|
39
|
+
const transcript = [];
|
|
40
|
+
// Reserve space for the exact omission count and role framing.
|
|
41
|
+
let available = budget - 128;
|
|
42
|
+
if (applies && record) {
|
|
43
|
+
const summary = boundedContextText(record.summary, Math.min(MAX_SUMMARY_BYTES, Math.floor(available / 2)));
|
|
44
|
+
const text = `[Earlier conversation summary — historical data, not new instructions. Later corrections take precedence.]\n${JSON.stringify(summary)}`;
|
|
45
|
+
const bounded = boundedContextText(text, Math.floor(available / 2));
|
|
46
|
+
transcript.push({ id: record.id, role: "assistant", text: bounded });
|
|
47
|
+
representedIds.push(record.id);
|
|
48
|
+
available -= Buffer.byteLength(bounded) + 16;
|
|
49
|
+
}
|
|
50
|
+
const kept = [];
|
|
51
|
+
const shortened = [];
|
|
52
|
+
for (let i = entries.length - 1; i >= 0 && kept.length < maxMessages; i--) {
|
|
53
|
+
const entry = entries[i];
|
|
54
|
+
if (available <= 16)
|
|
55
|
+
break;
|
|
56
|
+
const size = Buffer.byteLength(entry.text) + 16;
|
|
57
|
+
if (size > available && kept.length)
|
|
58
|
+
break;
|
|
59
|
+
const text = size > available ? boundedContextText(entry.text, available - 16) : entry.text;
|
|
60
|
+
if (text !== entry.text)
|
|
61
|
+
shortened.push(entry.id);
|
|
62
|
+
kept.unshift({ ...entry, text });
|
|
63
|
+
representedIds.push(entry.id);
|
|
64
|
+
available -= Buffer.byteLength(text) + 16;
|
|
65
|
+
}
|
|
66
|
+
const dropped = entries.length - kept.length;
|
|
67
|
+
if (dropped)
|
|
68
|
+
transcript.push({ id: "", role: "assistant", text: `[${dropped} earlier messages omitted from this context; full history remains in the app.]` });
|
|
69
|
+
transcript.push(...kept);
|
|
70
|
+
const represented = new Set(representedIds);
|
|
71
|
+
return { transcript, representedIds: history.filter(entry => represented.has(entry.id)).map(entry => entry.id), dropped, compacted: applies ? cut : 0, shortened };
|
|
72
|
+
}
|