openmausbot 0.1.88 → 0.1.90
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/README.md +1 -1
- package/dist/assets/{abnfDiagram-O67JEVCF-qd9VD3GV.js → abnfDiagram-O67JEVCF-DUyXd0kL.js} +1 -1
- package/dist/assets/{arc-3RwkUjRe.js → arc-q73qM-At.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-CFKSJS7a.js → architectureDiagram-NJMV4G6O-D33O3Wur.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-CG1rEfWD.js → blockDiagram-BEXU5L5S-DLsJeoXC.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-CBW9N664.js → c4Diagram-YGBWAQC7-DnaljZnu.js} +1 -1
- package/dist/assets/channel-BCuyHjFV.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-2mRfTksB.js → chunk-2Q5K7J3B-Da0h2i79.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-Cv1dpErj.js → chunk-3FUC2YCW-CfzHi54f.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-B7IACJp-.js → chunk-5VM5RSS4-LjE4d9Jf.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-An0hZtYa.js → chunk-GTNCS2PH-DY-UGmvc.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-BcJB2nEm.js → chunk-GWA4HPMP-BqeGhyhP.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-CV_W7TN7.js → chunk-JWPE2WC7-BYa9EBAg.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-Bcs_kwnA.js → chunk-NETBCI7D-vTrDtWyb.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-lrx_DxFP.js → chunk-WEXAMYUT-ic5tXadM.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-DabHlLGM.js → chunk-XXDRQBXY-DvRCY-c6.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-BnHj6P7d.js → classDiagram-v2-NBCMYWYE-DVbmgz_L.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-CfLp6UDi.js → cose-bilkent-JH36ORCC-vdUs2n57.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-Dm4dbVA1.js → cynefin-OW5HDTMX-BvLGlV3U.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-B9mH-PID.js → cynefinDiagram-VND7K2PF-C4GcJQDt.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-DDc_NVQJ.js → dagre-6A5THRUB-BMSaHpt_.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-lwr8Ip8-.js → diagram-22UHCM2B-D5b9UBhC.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-BLLe6dmI.js → diagram-3UASUU5V-CIKLlB7Y.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-6eUIq4lz.js → diagram-ATOU4E4O-BzXb-7k7.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-O-pRN7VQ.js → diagram-CDSNMT55-HsTvJ7uT.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-BietvGAI.js → diagram-MLGK6HIB-Db9ySNbQ.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-Bd2Cl62X.js → diagram-MPIPVDR6-D6BKbpqY.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-B6iDy69W.js → ebnfDiagram-ZINNZB2B-Bq067L0t.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-DQVHfKe0.js → elk-276RUBZZ-DhaD7fNJ.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-BWdVp2tQ.js → erDiagram-OPXOYQCR-fwIhfz36.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-WLE6rKB4.js → flowDiagram-KWPJA3E3-DygIyu0V.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-BbjS-4gn.js → ganttDiagram-FUAMR5RP-DPYfSO96.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-Dpy2QSGq.js → gitGraphDiagram-X574FWY7-DhkHeCle.js} +1 -1
- package/dist/assets/index-CRvo-DS2.css +1 -0
- package/dist/assets/index-CWYGlA63.js +588 -0
- package/dist/assets/{index-CIaHn5NS.js → index-G1PHKGyh.js} +1 -1
- package/dist/assets/{infoDiagram-VRGFBTTK-D_jKWlKe.js → infoDiagram-VRGFBTTK-DstBLxME.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-DLJohSuK.js → ishikawaDiagram-OU5B5YK6-CrIsGgch.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-DPOFj0qN.js → journeyDiagram-ZHPQQLJL-CYypGDbB.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-BI7v-xpK.js → kanban-definition-PNTS6WVX-DGjPt8E_.js} +1 -1
- package/dist/assets/{linear-C2pWPSxO.js → linear-Dwc3Hrru.js} +1 -1
- package/dist/assets/{mermaid.core-CR-j5WQU.js → mermaid.core-Dc4OePBL.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-lz9GvXRh.js → mindmap-definition-NLK3R4M7-DV-vepj-.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-Dl4_ia61.js → pegDiagram-GJSIUBJH-lx5Kj-n5.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-DWuT3n88.js → pieDiagram-5QR66LMP-Bq7Vmm15.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-DXWe9Jx7.js → quadrantDiagram-O4NWA36T-DeqeqOBj.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-COY1IBVY.js → railroadDiagram-XR7U4H2S-CXwRQzSC.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-DnyVuhsQ.js → requirementDiagram-PLB6GJNP-8tAeoB88.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-BSc4NdGK.js → sankeyDiagram-IPEJSGJF-BG5zjGWU.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-kqEU2EGq.js → sequenceDiagram-PO4LG4MO-DKF3iLcw.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-BvB4bkWD.js → sizeCapture-INFHLROL-B-y1qUgT.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-BIrqNv7y.js → stateDiagram-v2-GCMORJYK-MkzPgxAc.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-CFnalQUE.js → swimlanes-2SLR337P-DnbaOEwH.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BZQ07DGE.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-CsSWJnSQ.js → timeline-definition-EJHVYXUP-Bb4xG_Bt.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-DkAmJ1EE.js → usecaseDiagram-POWQR4AR-JgkR9pFf.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-C3vd9drL.js → vennDiagram-UO4OBE2U-CIPIrAYe.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-j26CM-pi.js → wardleyDiagram-VNRHLVJA-BjCLuUvJ.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-BYu1Q_at.js → xychartDiagram-PMCCYNJV-DKgiaYxT.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/cloud-home-start.js +14795 -0
- package/dist-server/container-mcp.js +60 -4
- package/dist-server/drivers/agents-proxy.js +20 -10
- package/dist-server/index.js +48924 -46153
- package/dist-server/openmausbot.js +544 -253
- package/dist-server/pair-cli.js +544 -253
- package/dist-server/permission-proxy.js +1 -1
- package/dist-server/server/admission.js +46 -0
- package/dist-server/server/automatic-recovery.js +15 -0
- package/dist-server/server/{box-create-idempotency.js → boat-create-idempotency.js} +32 -31
- package/dist-server/server/{box-delete-journal.js → boat-delete-journal.js} +26 -25
- package/dist-server/server/{box.js → boat.js} +330 -328
- package/dist-server/server/bot-profile.js +7 -1
- package/dist-server/server/channel-queue.js +58 -18
- package/dist-server/server/checkpoints.js +98 -52
- package/dist-server/server/claim-idle.js +33 -0
- package/dist-server/server/cli-api-setup.js +0 -1
- package/dist-server/server/cloud-backend.js +5 -5
- package/dist-server/server/cloud-home-start.js +103 -0
- package/dist-server/server/cloud-home.js +218 -0
- package/dist-server/server/cloud-overflow.js +167 -0
- package/dist-server/server/composio.js +5 -0
- package/dist-server/server/computer-observation.js +2 -2
- package/dist-server/server/config.js +124 -6
- package/dist-server/server/container-computer.js +23 -0
- package/dist-server/server/contracts.js +10 -0
- package/dist-server/server/control-client.js +2 -2
- package/dist-server/server/delegations.js +11 -3
- package/dist-server/server/drivers/acp/core.js +129 -21
- package/dist-server/server/drivers/acp/qwen.js +3 -0
- package/dist-server/server/drivers/agents-call.js +5 -1
- package/dist-server/server/drivers/agents-catalog.js +9 -3
- package/dist-server/server/drivers/{boxagent.js → boatagent.js} +14 -13
- package/dist-server/server/drivers/builtIn.js +2 -2
- package/dist-server/server/drivers/{chat-box-tools.js → chat-boat-tools.js} +3 -3
- package/dist-server/server/drivers/chat-mcp-tools.js +2 -2
- package/dist-server/server/drivers/claude.js +177 -13
- package/dist-server/server/drivers/native.js +1 -1
- package/dist-server/server/drivers/openai-chat.js +19 -4
- package/dist-server/server/drivers/pi.js +3 -3
- package/dist-server/server/harness-capabilities.js +18 -3
- package/dist-server/server/hosted-models.js +6 -1
- package/dist-server/server/index.js +1163 -530
- package/dist-server/server/local-vm-inventory.js +11 -1
- package/dist-server/server/local-vm-seat-pool.js +141 -0
- package/dist-server/server/managed-policy.js +4 -1
- package/dist-server/server/memory-capture.js +194 -0
- package/dist-server/server/memory-entries.js +76 -0
- package/dist-server/server/memory-organize.js +102 -0
- package/dist-server/server/memory-tidy.js +144 -0
- package/dist-server/server/memory-topics.js +169 -0
- package/dist-server/server/memory-upkeep.js +452 -0
- package/dist-server/server/message-db.js +49 -5
- package/dist-server/server/permission-proxy.js +3 -3
- package/dist-server/server/profile-learned.js +98 -0
- package/dist-server/server/profile-versions.js +45 -11
- package/dist-server/server/recall.js +172 -0
- package/dist-server/server/redact.js +1 -1
- package/dist-server/server/room-cwd.js +1 -1
- package/dist-server/server/room-handoffs.js +61 -6
- package/dist-server/server/routes/bot-memory.js +215 -0
- package/dist-server/server/routine-requests.js +27 -16
- package/dist-server/server/routines.js +10 -6
- package/dist-server/server/steer-queue.js +41 -10
- package/dist-server/server/store.js +25 -1
- package/dist-server/server/surface.js +1 -1
- package/dist-server/server/system-prompt.js +16 -5
- package/dist-server/server/team-computers.js +2 -2
- package/dist-server/server/tightening-requests.js +34 -4
- package/dist-server/server/tool-summary.js +2 -2
- package/dist-server/server/tts/elevenlabs.js +1 -1
- package/dist-server/server/turn-resources.js +87 -11
- package/dist-server/server/vps-computer.js +1 -1
- package/dist-server/server/webhooks.js +21 -3
- package/dist-server/server/workspace.js +57 -22
- package/dist-server/shared/ask-question.js +7 -5
- package/dist-server/shared/bot-avatar.js +19 -0
- package/dist-server/shared/credential-request.js +3 -3
- package/dist-server/shared/tool-surface.js +1 -1
- package/dist-server/src/lib/composer-attachments.js +26 -0
- package/dist-server/vps-container-mcp.js +60 -4
- package/dist-server/workspace-backup.worker.js +60 -4
- package/package.json +1 -1
- package/dist/assets/channel-CnRnO3tF.js +0 -1
- package/dist/assets/index-BIMdIbaw.css +0 -1
- package/dist/assets/index-CHnODCr2.js +0 -583
- package/dist/assets/swimlanesDiagram-TC7HE7FX-C4a8qNGj.js +0 -8
|
@@ -13,6 +13,7 @@ import { isModelVariant } from "./contracts.js";
|
|
|
13
13
|
import { PROVIDER_ICON_PRESETS, providerIconError } from "../shared/provider-icon.js";
|
|
14
14
|
import { isRemoteMcpServer, parseStoredMcpServer } from "./mcp-registry.js";
|
|
15
15
|
import { parseJson, schemaIssue } from "./schema.js";
|
|
16
|
+
import { CLOUD_SEAT_IDLE_STOP_MS } from "./cloud-overflow.js";
|
|
16
17
|
const optionalText = z.string().optional();
|
|
17
18
|
const SSH_ALIAS = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/;
|
|
18
19
|
const LEGACY_BROWSER_PROFILE_ID = /^[A-Za-z0-9_-]{1,40}$/;
|
|
@@ -87,7 +88,8 @@ const roomConfigSchema = z.object({
|
|
|
87
88
|
.min(MIN_ROOM_TURN_TIMEOUT_MINUTES)
|
|
88
89
|
.max(MAX_ROOM_TURN_TIMEOUT_MINUTES),
|
|
89
90
|
/** Room handoff tree lifetime. Active execution pauses this clock; the
|
|
90
|
-
* hard cap is
|
|
91
|
+
* hard cap is the maximum stall window, measured wall-clock from the
|
|
92
|
+
* tree's last durable progress. */
|
|
91
93
|
handoffLifetimeMinutes: z.number().int().min(1).max(MAX_ROOM_TURN_TIMEOUT_MINUTES).optional(),
|
|
92
94
|
handoffMinRunwayMinutes: z.number().int().min(1).max(MAX_ROOM_TURN_TIMEOUT_MINUTES).optional(),
|
|
93
95
|
handoffHardCapMinutes: z.number().int().min(1).max(7 * MAX_ROOM_TURN_TIMEOUT_MINUTES).optional(),
|
|
@@ -95,8 +97,14 @@ const roomConfigSchema = z.object({
|
|
|
95
97
|
(rooms.handoffLifetimeMinutes ?? DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES) &&
|
|
96
98
|
(rooms.handoffLifetimeMinutes ?? DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES) <=
|
|
97
99
|
(rooms.handoffHardCapMinutes ?? DEFAULT_ROOM_HANDOFF_HARD_CAP_MINUTES), { message: "rooms handoff bounds must satisfy handoffMinRunwayMinutes <= handoffLifetimeMinutes <= handoffHardCapMinutes" });
|
|
100
|
+
/** Isolation for bot desktops. Migration note (issue #1654): switching
|
|
101
|
+
* modes changes lease keys and vm-home directories, so desktops cold-start
|
|
102
|
+
* under the new mode — a pool seat lives in vm-homes/pool-N — while the old
|
|
103
|
+
* mode's workspaces stay on disk until removed. maxInstances caps per-bot
|
|
104
|
+
* desktops in per-bot mode, or the pool's seat count in pool mode; it is
|
|
105
|
+
* not a total across modes. Default stays "shared". */
|
|
98
106
|
const localVmConfigSchema = z.object({
|
|
99
|
-
mode: z.enum(["shared", "per-bot"]).optional(),
|
|
107
|
+
mode: z.enum(["shared", "per-bot", "pool"]).optional(),
|
|
100
108
|
maxInstances: z
|
|
101
109
|
.number()
|
|
102
110
|
.int()
|
|
@@ -247,6 +255,10 @@ const featureConfigSchema = z.object({
|
|
|
247
255
|
skillAuthoring: z.boolean().optional(),
|
|
248
256
|
/** Show each tool run in the transcript. Off unless explicitly enabled. */
|
|
249
257
|
showToolCalls: z.boolean().optional(),
|
|
258
|
+
/** Run a routine inside the conversation it reports to, instead of a hidden
|
|
259
|
+
* thread. Off unless explicitly enabled. The run still starts from its own
|
|
260
|
+
* instructions, but the messages stay in that chat. */
|
|
261
|
+
routinesInConversation: z.boolean().optional(),
|
|
250
262
|
/** Experimental built-in browser. Off until explicitly enabled; each bot
|
|
251
263
|
* also has its own switch. */
|
|
252
264
|
browser: z.boolean().optional(),
|
|
@@ -260,8 +272,23 @@ const featureConfigSchema = z.object({
|
|
|
260
272
|
claudeUserMcp: z.boolean().optional(),
|
|
261
273
|
/** LLM-generated titles for new bot threads. Off until explicitly
|
|
262
274
|
* enabled; a one-shot that fails or answers junk leaves the first-message
|
|
263
|
-
|
|
275
|
+
* snippet in place — see llmThreadTitlesEnabled. */
|
|
264
276
|
llmThreadTitles: z.boolean().optional(),
|
|
277
|
+
/** Before each turn, passages from the bot's own memory files and earlier
|
|
278
|
+
* conversations that share words with the message ride into the turn.
|
|
279
|
+
* Read-only; on unless explicitly switched off — see autoRecallEnabled. */
|
|
280
|
+
autoRecall: z.boolean().optional(),
|
|
281
|
+
/** Idle release for computer claims (#1653): a desktop seat that stays
|
|
282
|
+
* screen-quiet for 90 seconds is released to waiting turns while its
|
|
283
|
+
* holder's turn still lives; the previous holder re-claims directly
|
|
284
|
+
* for 10 minutes and yields to an occupied seat. Off until baked; see
|
|
285
|
+
* computerClaimIdleReleaseEnabled for how to enable it by hand. */
|
|
286
|
+
computerClaimIdleRelease: z.boolean().optional(),
|
|
287
|
+
/** Consented cloud overflow for local computer waits (#1655): a wait
|
|
288
|
+
* may offer a per-second-billed cloud seat, but only through an explicit
|
|
289
|
+
* consent card or a configured allowlist — never a silent Auto default.
|
|
290
|
+
* Off until baked; see cloudOverflowEnabled for how to enable it by hand. */
|
|
291
|
+
cloudOverflow: z.boolean().optional(),
|
|
265
292
|
});
|
|
266
293
|
/** First-run progress. Kept in the workspace config rather than a browser so
|
|
267
294
|
* it survives cleared site data and is shared by every paired client. Hint
|
|
@@ -295,6 +322,10 @@ const defaultModelSelectionSchema = z.object({
|
|
|
295
322
|
effort: z.enum(EFFORT_LEVELS).optional(),
|
|
296
323
|
variant: z.string().refine(isModelVariant, "invalid model variant").optional(),
|
|
297
324
|
}).refine((selection) => selection.variant === undefined || selection.effort === undefined, "choose either a model variant or an effort level");
|
|
325
|
+
const automaticRecoverySchema = z.object({
|
|
326
|
+
enabled: z.boolean(),
|
|
327
|
+
backup: defaultModelSelectionSchema.optional(),
|
|
328
|
+
}).strict().refine((recovery) => !recovery.enabled || recovery.backup !== undefined, { message: "Choose a backup model before enabling automatic recovery", path: ["backup"] });
|
|
298
329
|
const threadsConfigSchema = z.object({
|
|
299
330
|
maxConcurrentPerBot: z.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS),
|
|
300
331
|
/** Cap each per-thread events/ and native/ NDJSON log at this many
|
|
@@ -327,6 +358,7 @@ const appConfigSchema = z.object({
|
|
|
327
358
|
* addresses or `@domain` entries; admins get every scope, members chat only. */
|
|
328
359
|
signIn: z.object({ admins: z.array(z.string().max(320)).max(500).optional(), members: z.array(z.string().max(320)).max(5000).optional() }).optional(),
|
|
329
360
|
defaultModelSelection: defaultModelSelectionSchema.optional(),
|
|
361
|
+
automaticRecovery: automaticRecoverySchema.optional(),
|
|
330
362
|
newBotDefaults: newBotDefaultsSchema.optional(),
|
|
331
363
|
newBots: newBotsConfigSchema.optional(),
|
|
332
364
|
/** CLI-only launch preferences. Never enable remote access implicitly. */
|
|
@@ -371,6 +403,8 @@ const appConfigSchema = z.object({
|
|
|
371
403
|
/** Project key used for Sessions, catalog and agent tools. userId/sessionId
|
|
372
404
|
* are non-secret local identifiers used to reuse one Composio Session. */
|
|
373
405
|
composio: z.object({ apiKey: optionalText, userId: optionalText, sessionId: optionalText }).optional(),
|
|
406
|
+
/** Historical config section name "box" (the persisted config.json key); the
|
|
407
|
+
* provider is Boat now and the key is kept for compatibility. */
|
|
374
408
|
box: z.object({ token: optionalText }).optional(),
|
|
375
409
|
vps: vpsConfigSchema.optional(),
|
|
376
410
|
/** Optional OpenCode key; persisted write-only and passed only to its child. */
|
|
@@ -424,10 +458,26 @@ const appConfigSchema = z.object({
|
|
|
424
458
|
compactAt: z.number().positive().max(10_000_000).optional(),
|
|
425
459
|
autoCompact: z.boolean().optional(),
|
|
426
460
|
}).optional(),
|
|
461
|
+
/** Memory upkeep timing, for bots with Memory upkeep switched on. */
|
|
462
|
+
memory: z.object({
|
|
463
|
+
/** Quiet time after a turn before its facts are captured (ms). */
|
|
464
|
+
captureQuietMs: z.number().int().min(1_000).max(24 * 60 * 60_000).optional(),
|
|
465
|
+
/** Local hour (0-23) after which the nightly tidy-up runs. */
|
|
466
|
+
tidyHour: z.number().int().min(0).max(23).optional(),
|
|
467
|
+
}).strict().optional(),
|
|
427
468
|
threads: threadsConfigSchema.optional(),
|
|
428
469
|
/** The authorization decision log (server/decision-log.ts): days of month
|
|
429
470
|
* files kept, at least; OMB_DECISION_RETENTION_DAYS wins when set. */
|
|
430
471
|
decisions: z.object({ retentionDays: z.number().int().min(1).max(3650).optional() }).strict().optional(),
|
|
472
|
+
/** #1655 cloud-overflow settings. perSecondCostUsd is the operator's own
|
|
473
|
+
* verified rate: with no price configured the feature stays inert rather
|
|
474
|
+
* than show an invented one. allowlistedThreads carries standing consent
|
|
475
|
+
* for exact thread ids. */
|
|
476
|
+
cloudOverflow: z.object({
|
|
477
|
+
perSecondCostUsd: z.number().positive().max(10).optional(),
|
|
478
|
+
idleStopMs: z.number().int().positive().max(24 * 60 * 60_000).optional(),
|
|
479
|
+
allowlistedThreads: z.array(z.string().min(1)).max(1000).optional(),
|
|
480
|
+
}).strict().optional(),
|
|
431
481
|
localVm: localVmConfigSchema.optional(),
|
|
432
482
|
features: featureConfigSchema.optional(),
|
|
433
483
|
onboarding: onboardingConfigSchema.optional(),
|
|
@@ -536,8 +586,9 @@ export function roomTurnTimeoutMinutes(cfg) {
|
|
|
536
586
|
return cfg.rooms?.turnTimeoutMinutes ?? DEFAULT_ROOM_TURN_TIMEOUT_MINUTES;
|
|
537
587
|
}
|
|
538
588
|
/** Room handoff tree budgets in milliseconds. The tree lifetime pauses
|
|
539
|
-
* while a node is actively executing; the hard cap is
|
|
540
|
-
*
|
|
589
|
+
* while a node is actively executing; the hard cap is the maximum stall
|
|
590
|
+
* window, measured wall-clock from the tree's last durable progress. Read
|
|
591
|
+
* when the server starts. */
|
|
541
592
|
export function roomHandoffLimits(cfg) {
|
|
542
593
|
return {
|
|
543
594
|
lifetimeMs: (cfg.rooms?.handoffLifetimeMinutes ?? DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES) * 60_000,
|
|
@@ -573,9 +624,26 @@ export function localVmMaxInstances(cfg) {
|
|
|
573
624
|
export function skillAuthoringEnabled(cfg) {
|
|
574
625
|
return cfg.features?.skillAuthoring !== false;
|
|
575
626
|
}
|
|
627
|
+
/** Automatic recall is read-only, so it is on unless switched off. */
|
|
628
|
+
export function autoRecallEnabled(cfg) {
|
|
629
|
+
return cfg.features?.autoRecall !== false;
|
|
630
|
+
}
|
|
631
|
+
export const DEFAULT_CAPTURE_QUIET_MS = 2 * 60_000;
|
|
632
|
+
export const DEFAULT_TIDY_HOUR = 3;
|
|
633
|
+
export function captureQuietMs(cfg) {
|
|
634
|
+
return cfg.memory?.captureQuietMs ?? DEFAULT_CAPTURE_QUIET_MS;
|
|
635
|
+
}
|
|
636
|
+
export function tidyHour(cfg) {
|
|
637
|
+
return cfg.memory?.tidyHour ?? DEFAULT_TIDY_HOUR;
|
|
638
|
+
}
|
|
576
639
|
export function showToolCallsEnabled(cfg) {
|
|
577
640
|
return cfg.features?.showToolCalls === true;
|
|
578
641
|
}
|
|
642
|
+
/** A routine's turns are posted in the conversation that receives its card.
|
|
643
|
+
* Off by default, so scheduled work stays in a hidden thread. */
|
|
644
|
+
export function routinesInConversationEnabled(cfg) {
|
|
645
|
+
return cfg.features?.routinesInConversation === true;
|
|
646
|
+
}
|
|
579
647
|
/** Workspace-level gate for the experimental built-in browser. A bot's own
|
|
580
648
|
* switch sits under it, so either can withhold the browser. */
|
|
581
649
|
export function builtInBrowserEnabled(cfg) {
|
|
@@ -609,6 +677,43 @@ export function claudeUserMcpEnabled(cfg) {
|
|
|
609
677
|
export function llmThreadTitlesEnabled(cfg) {
|
|
610
678
|
return cfg.features?.llmThreadTitles === true;
|
|
611
679
|
}
|
|
680
|
+
/** Idle release for computer claims (#1653): a whole-turn desktop hold
|
|
681
|
+
* ends after a screen-quiet window (default 90 seconds, screen-poller
|
|
682
|
+
* frames excluded) instead of at turn settle, and the previous holder
|
|
683
|
+
* re-claims directly inside a reclaim window (default 10 minutes) while
|
|
684
|
+
* yielding to a seat another turn already holds. Off unless an explicit
|
|
685
|
+
* `true` — bake it as a maintainer-only flag first, exactly like
|
|
686
|
+
* sharedComputers: enable by hand in ~/.openmausbot/config.json
|
|
687
|
+
* (`{"features": {"computerClaimIdleRelease": true}}`) and restart. */
|
|
688
|
+
export function computerClaimIdleReleaseEnabled(cfg) {
|
|
689
|
+
return cfg.features?.computerClaimIdleRelease === true;
|
|
690
|
+
}
|
|
691
|
+
/** Consented cloud overflow for local computer waits (#1655): while a turn
|
|
692
|
+
* waits for a local desktop, it may offer overflow to a per-second-billed
|
|
693
|
+
* cloud seat — never silently: the card names the cost, and only an
|
|
694
|
+
* explicit per-conversation consent or a configured allowlist thread may
|
|
695
|
+
* start the machine, which then hard-stops after an idle window. Off
|
|
696
|
+
* unless an explicit `true`, like computerClaimIdleRelease: enable by
|
|
697
|
+
* hand in ~/.openmausbot/config.json
|
|
698
|
+
* (`{"features": {"cloudOverflow": true}, "cloudOverflow": {"perSecondCostUsd": 0.0004}}`)
|
|
699
|
+
* and restart. */
|
|
700
|
+
export function cloudOverflowEnabled(cfg) {
|
|
701
|
+
return cfg.features?.cloudOverflow === true;
|
|
702
|
+
}
|
|
703
|
+
/** The per-second rate shown on the card, or null when the operator has
|
|
704
|
+
* not set one: the offer fails closed rather than guess a price. */
|
|
705
|
+
export function cloudOverflowPerSecondCostUsd(cfg) {
|
|
706
|
+
const cost = cfg.cloudOverflow?.perSecondCostUsd;
|
|
707
|
+
return typeof cost === "number" && Number.isFinite(cost) && cost > 0 ? cost : null;
|
|
708
|
+
}
|
|
709
|
+
/** How long a cloud seat may stay screen-quiet before it is stopped. */
|
|
710
|
+
export function cloudOverflowIdleStopMs(cfg) {
|
|
711
|
+
return cfg.cloudOverflow?.idleStopMs ?? CLOUD_SEAT_IDLE_STOP_MS;
|
|
712
|
+
}
|
|
713
|
+
/** Threads with standing consent, by exact thread id. */
|
|
714
|
+
export function cloudOverflowAllowlistedThreads(cfg) {
|
|
715
|
+
return new Set(cfg.cloudOverflow?.allowlistedThreads ?? []);
|
|
716
|
+
}
|
|
612
717
|
/** Config sections no provider driver reads. A write that touches only
|
|
613
718
|
* these must not rebuild the fleet: rebuilding disposes every engine child
|
|
614
719
|
* and reloads it, seconds of work that would also interrupt in-flight
|
|
@@ -622,9 +727,12 @@ export const FLEET_NEUTRAL_KEYS = new Set([
|
|
|
622
727
|
"vps",
|
|
623
728
|
"rooms",
|
|
624
729
|
"threads",
|
|
730
|
+
"automaticRecovery",
|
|
625
731
|
"context",
|
|
732
|
+
"memory",
|
|
626
733
|
"localVm",
|
|
627
734
|
"features",
|
|
735
|
+
"cloudOverflow",
|
|
628
736
|
"browserProfiles",
|
|
629
737
|
"onboarding",
|
|
630
738
|
]);
|
|
@@ -746,6 +854,7 @@ export function loadConfig() {
|
|
|
746
854
|
cfg.composio = { ...cfg.composio };
|
|
747
855
|
if (process.env.COMPOSIO_API_KEY !== undefined)
|
|
748
856
|
cfg.composio.apiKey = process.env.COMPOSIO_API_KEY;
|
|
857
|
+
// BOX_TOKEN keeps its historical name; the provider is Boat.
|
|
749
858
|
cfg.box = { ...cfg.box };
|
|
750
859
|
if (process.env.BOX_TOKEN !== undefined)
|
|
751
860
|
cfg.box.token = process.env.BOX_TOKEN;
|
|
@@ -755,6 +864,11 @@ export function loadConfig() {
|
|
|
755
864
|
cfg.tts = { ...cfg.tts };
|
|
756
865
|
if (process.env.OMB_TTS_KEY !== undefined)
|
|
757
866
|
cfg.tts.key = process.env.OMB_TTS_KEY;
|
|
867
|
+
// A preset ElevenLabs voice (Cloud Pro sets one) is only a default: a voice or
|
|
868
|
+
// another speech provider the person picked in Settings always wins.
|
|
869
|
+
const presetVoice = process.env.OMB_TTS_DEFAULT_VOICE?.trim();
|
|
870
|
+
if (presetVoice && !cfg.tts.voice?.trim() && (cfg.tts.provider ?? "elevenlabs") === "elevenlabs")
|
|
871
|
+
cfg.tts.voice = presetVoice;
|
|
758
872
|
if (process.env.OMB_FISH_AUDIO_API_KEY !== undefined)
|
|
759
873
|
cfg.tts.fishKey = process.env.OMB_FISH_AUDIO_API_KEY;
|
|
760
874
|
cfg.imageGen = { ...cfg.imageGen };
|
|
@@ -923,7 +1037,7 @@ export function saveConfig(patch, options = {}) {
|
|
|
923
1037
|
const storedProfiles = storedBrowserProfilesSchema.safeParse(disk.browserProfiles);
|
|
924
1038
|
if (storedProfiles.success)
|
|
925
1039
|
disk.browserProfiles = storedProfiles.data;
|
|
926
|
-
for (const key of ["xai", "anthropic", "mistral", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "context", "localVm", "features", "budgets", "billing", "decisions", "onboarding", "browserEngine", "newBots"]) {
|
|
1040
|
+
for (const key of ["xai", "anthropic", "mistral", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "context", "memory", "localVm", "features", "cloudOverflow", "budgets", "billing", "decisions", "onboarding", "browserEngine", "newBots"]) {
|
|
927
1041
|
const section = checkedPatch[key];
|
|
928
1042
|
if (!section)
|
|
929
1043
|
continue;
|
|
@@ -953,6 +1067,9 @@ export function saveConfig(patch, options = {}) {
|
|
|
953
1067
|
disk.customDomain = checkedPatch.customDomain;
|
|
954
1068
|
if (checkedPatch.signIn !== undefined)
|
|
955
1069
|
disk.signIn = checkedPatch.signIn;
|
|
1070
|
+
// Replace the section so clearing a backup cannot revive the old selection.
|
|
1071
|
+
if (checkedPatch.automaticRecovery !== undefined)
|
|
1072
|
+
disk.automaticRecovery = checkedPatch.automaticRecovery;
|
|
956
1073
|
// A selection is replaced as one value, so changing engines also clears
|
|
957
1074
|
// an effort level omitted from the new selection.
|
|
958
1075
|
if (checkedPatch.defaultModelSelection !== undefined) {
|
|
@@ -1129,6 +1246,7 @@ function injectedEnvironment(cfg, driver) {
|
|
|
1129
1246
|
environment.set("OPENAI_COMPAT_API_KEY", cfg.openaiCompat.key);
|
|
1130
1247
|
if (driver === "openai-compat" && cfg.openaiCompat?.url)
|
|
1131
1248
|
environment.set("OPENAI_COMPAT_URL", cfg.openaiCompat.url);
|
|
1249
|
+
// driverKind "boxAgent" and env BOX_TOKEN keep their historical names.
|
|
1132
1250
|
if (driver === "boxAgent" && cfg.box?.token)
|
|
1133
1251
|
environment.set("BOX_TOKEN", cfg.box.token);
|
|
1134
1252
|
if (driver === "opencodeGo" && cfg.opencodeGo?.apiKey)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// typing, screenshots, accessibility, or window discovery.
|
|
8
8
|
import { execFile } from "node:child_process";
|
|
9
9
|
import { createHash, randomBytes } from "node:crypto";
|
|
10
|
+
import { lstatSync } from "node:fs";
|
|
10
11
|
import { chmod, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
11
12
|
import { tmpdir } from "node:os";
|
|
12
13
|
import { join, resolve } from "node:path";
|
|
@@ -68,6 +69,28 @@ export function perBotLocalVmTarget(botId) {
|
|
|
68
69
|
label: digest,
|
|
69
70
|
};
|
|
70
71
|
}
|
|
72
|
+
/** A pool-mode seat (issue #1654): one of N desktops shared by every
|
|
73
|
+
* conversation, addressed by seat index. Identities stay disjoint from the
|
|
74
|
+
* shared singleton and from per-bot digests, so discovery, labels, and lease
|
|
75
|
+
* lanes never confuse the three modes. */
|
|
76
|
+
export function poolLocalVmTarget(seat) {
|
|
77
|
+
return {
|
|
78
|
+
key: `pool:${seat}`,
|
|
79
|
+
containerName: `${CONTAINER}-p${seat}`,
|
|
80
|
+
workspaceDir: join(DATA_DIR, "vm-homes", `pool-${seat}`),
|
|
81
|
+
viewerPort: null,
|
|
82
|
+
label: `pool-${seat}`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Only provisioning creates this durable directory; idle removal keeps it. */
|
|
86
|
+
export function localVmWorkspaceExists(target) {
|
|
87
|
+
try {
|
|
88
|
+
return lstatSync(target.workspaceDir, { throwIfNoEntry: false })?.isDirectory() === true;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
71
94
|
const LINUX_WHEELS = {
|
|
72
95
|
x86_64: {
|
|
73
96
|
url: "https://files.pythonhosted.org/packages/fa/d7/a43008a328a40c85e7bc706fc20235b9abedc75e28b413817655153157ff/cua_driver-0.20.0-py3-none-manylinux_2_31_x86_64.whl",
|
|
@@ -12,6 +12,16 @@ export class ProviderError extends Error {
|
|
|
12
12
|
this.code = code;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
/** The driver proved this attempt never reached a prompt or client-side action,
|
|
16
|
+
* and its owned process has stopped. The harness may safely recover it. */
|
|
17
|
+
export class TurnNotStartedError extends Error {
|
|
18
|
+
turnId;
|
|
19
|
+
constructor(turnId, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "TurnNotStartedError";
|
|
22
|
+
this.turnId = turnId;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
15
25
|
/** Variants are opaque provider IDs, not the cross-engine effort enum. */
|
|
16
26
|
export function isModelVariant(value) {
|
|
17
27
|
return typeof value === "string" && value.length > 0 && value.length <= 256 &&
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// The proxy-side half of computer control. The harness keeps the record of
|
|
2
2
|
// who is driving (server/computer-control.ts); the per-turn computer
|
|
3
3
|
// processes consult it through this client before acting, because the
|
|
4
|
-
// action paths themselves never traverse the harness — a
|
|
5
|
-
// straight to the
|
|
4
|
+
// action paths themselves never traverse the harness — a boat click goes
|
|
5
|
+
// straight to the boat's REST API, and a Local VM / VPS click rides a
|
|
6
6
|
// transparent stdio bridge into Cua Driver.
|
|
7
7
|
//
|
|
8
8
|
// Failure posture: CLOSED once configured. A missing/expired turn capability
|
|
@@ -259,8 +259,10 @@ export function pendingDelegationSnapshot() {
|
|
|
259
259
|
})));
|
|
260
260
|
}
|
|
261
261
|
/** How many handoffs one turn may queue. Small on purpose: this is the only
|
|
262
|
-
* thing standing between a confused bot and a fan-out of real turns.
|
|
263
|
-
|
|
262
|
+
* thing standing between a confused bot and a fan-out of real turns. Six,
|
|
263
|
+
* not four: a lead running a weekly check-in over a five-member team is the
|
|
264
|
+
* ordinary case, and hitting the cap there silently dropped one teammate. */
|
|
265
|
+
const MAX_QUEUED_PER_THREAD = 6;
|
|
264
266
|
/** Validate and enqueue a delegation. Pushes a "Delegated to @B: reason"
|
|
265
267
|
* chip to the source thread so the user can see what was queued. */
|
|
266
268
|
export function queueDelegation(bus, from, item, maxDepth, sourceThreadId = from.threadId) {
|
|
@@ -838,7 +840,13 @@ export function buildDelegationFailurePrompt(targetName, reason) {
|
|
|
838
840
|
"Take over: tell the user what failed in plain terms, then decide the next step — retry with a narrower task, do the work yourself, or propose an alternative. Do not re-delegate the exact same task unchanged.",
|
|
839
841
|
].join("\n\n");
|
|
840
842
|
}
|
|
841
|
-
|
|
843
|
+
// Must not be smaller than MAX_QUEUED_PER_THREAD: every delegate reply is
|
|
844
|
+
// one wake, so a fan-out that the queue cap allows has to be resumable
|
|
845
|
+
// within the window. Three failed a five-member weekly check-in whose
|
|
846
|
+
// replies all landed inside four minutes ("Delegation follow-up limit
|
|
847
|
+
// reached"), while the same routine passed a week earlier only because the
|
|
848
|
+
// replies happened to spread over twenty.
|
|
849
|
+
export const DELEGATION_WAKE_MAX_PER_WINDOW = 6;
|
|
842
850
|
export const DELEGATION_WAKE_WINDOW_MS = 5 * 60 * 1000;
|
|
843
851
|
/** Bounded auto-wake budget per source thread. A delegation completion
|
|
844
852
|
* wakes the source; if that source re-delegates and the new completion
|