openmausbot 0.1.85 → 0.1.87
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 +2 -2
- 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-BTiuL79F.js +1 -0
- package/dist/assets/arc-C88Blc2v.js +1 -0
- package/dist/assets/architectureDiagram-NJMV4G6O-BZsJIZrb.js +36 -0
- package/dist/assets/blockDiagram-BEXU5L5S-CVeMe9Ah.js +140 -0
- package/dist/assets/c4Diagram-YGBWAQC7-Cedk3Bhx.js +38 -0
- package/dist/assets/channel-taCNRlUU.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-D-VRqzTB.js +1 -0
- package/dist/assets/chunk-3FUC2YCW-BChov01Y.js +2 -0
- package/dist/assets/chunk-5VM5RSS4-C-TfwvHy.js +15 -0
- package/dist/assets/chunk-GTNCS2PH-Db7CGj5Y.js +88 -0
- package/dist/assets/chunk-GWA4HPMP-CNvIfqKT.js +1 -0
- package/dist/assets/chunk-JWPE2WC7-C_bEp5tq.js +1 -0
- package/dist/assets/chunk-NETBCI7D-Coi4BOls.js +1 -0
- package/dist/assets/chunk-WEXAMYUT-CzylEuL3.js +1 -0
- package/dist/assets/chunk-XXDRQBXY-m7p7ztaD.js +1 -0
- package/dist/assets/classDiagram-v2-NBCMYWYE-BMy6o9x2.js +217 -0
- package/dist/assets/cose-bilkent-JH36ORCC-BDQ__0_J.js +1 -0
- package/dist/assets/cynefin-OW5HDTMX-Djv4ghUb.js +166 -0
- package/dist/assets/cynefinDiagram-VND7K2PF-BULrlGYH.js +62 -0
- package/dist/assets/cytoscape.esm-BB4DxJjf.js +321 -0
- package/dist/assets/dagre-6A5THRUB-D-jrT_hU.js +4 -0
- package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/assets/diagram-22UHCM2B-p2UhQmfL.js +200 -0
- package/dist/assets/diagram-3UASUU5V-DHvGWZ7q.js +24 -0
- package/dist/assets/diagram-ATOU4E4O-ChhKDot-.js +3 -0
- package/dist/assets/diagram-CDSNMT55-B-T7A43R.js +30 -0
- package/dist/assets/diagram-MLGK6HIB-CJm8ENNY.js +24 -0
- package/dist/assets/diagram-MPIPVDR6-510tlza8.js +41 -0
- package/dist/assets/ebnfDiagram-ZINNZB2B-PkvRPHel.js +1 -0
- package/dist/assets/elk-276RUBZZ-BVBVPoX3.js +27 -0
- package/dist/assets/erDiagram-OPXOYQCR-BgYMVm7L.js +99 -0
- package/dist/assets/flowDiagram-KWPJA3E3-BGqsnc_3.js +213 -0
- package/dist/assets/ganttDiagram-FUAMR5RP-D_-UeReH.js +292 -0
- package/dist/assets/gitGraphDiagram-X574FWY7-D0uooONx.js +106 -0
- package/dist/assets/graph-D8UmR1vK.js +1 -0
- package/dist/assets/index-BwdMAQ6p.css +1 -0
- package/dist/assets/index-ByJennr7.js +581 -0
- package/dist/assets/{index-CTNNoqSJ.js → index-zRsJERGJ.js} +1 -1
- package/dist/assets/infoDiagram-VRGFBTTK-B9e1z77f.js +2 -0
- package/dist/assets/init-Gi6I4Gst.js +1 -0
- package/dist/assets/ishikawaDiagram-OU5B5YK6-BB4vNwvD.js +70 -0
- package/dist/assets/journeyDiagram-ZHPQQLJL-DpkosOTB.js +139 -0
- package/dist/assets/kanban-definition-PNTS6WVX-DbDP4kUu.js +89 -0
- package/dist/assets/linear-DBJGPmjT.js +1 -0
- package/dist/assets/mermaid.core-DWPRi-ue.js +311 -0
- package/dist/assets/mindmap-definition-NLK3R4M7-nszBbJmx.js +96 -0
- package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/assets/pegDiagram-GJSIUBJH-CWykJWu_.js +1 -0
- package/dist/assets/pieDiagram-5QR66LMP-g3Da-Vnv.js +39 -0
- package/dist/assets/quadrantDiagram-O4NWA36T-Wzrlpzgh.js +7 -0
- package/dist/assets/railroadDiagram-XR7U4H2S-moHTFMC0.js +1 -0
- package/dist/assets/requirementDiagram-PLB6GJNP-CwfXdFH8.js +84 -0
- package/dist/assets/sankeyDiagram-IPEJSGJF-3ZROYvnq.js +40 -0
- package/dist/assets/sequenceDiagram-PO4LG4MO-E1TBebP8.js +169 -0
- package/dist/assets/sizeCapture-INFHLROL-DHKEU5pu.js +1 -0
- package/dist/assets/stateDiagram-v2-GCMORJYK-BguEj09D.js +291 -0
- package/dist/assets/swimlanes-2SLR337P-C7IDYnhd.js +1 -0
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BpEdoB2e.js +8 -0
- package/dist/assets/timeline-definition-EJHVYXUP-DCW-F5PW.js +120 -0
- package/dist/assets/usecaseDiagram-POWQR4AR-xBMFtWYV.js +370 -0
- package/dist/assets/vennDiagram-UO4OBE2U-B5nIkuH8.js +34 -0
- package/dist/assets/wardleyDiagram-VNRHLVJA-DYFAhdbr.js +78 -0
- package/dist/assets/xychartDiagram-PMCCYNJV-DeXwX6Cz.js +7 -0
- package/dist/index.html +2 -2
- package/dist-server/browser-proxy.js +2 -1
- package/dist-server/container-mcp.js +1047 -173
- package/dist-server/drivers/agents-proxy.js +16121 -1504
- package/dist-server/drivers/phone-proxy.js +33 -2
- package/dist-server/enterprise/LICENSE +32 -0
- package/dist-server/enterprise/server/index.js +5 -5
- package/dist-server/index.js +16134 -7446
- package/dist-server/local-computer-proxy.js +3 -3
- package/dist-server/local-computer.js +53 -17
- package/dist-server/mcp-server.js +3 -1
- package/dist-server/openmausbot.js +9353 -6124
- package/dist-server/pair-cli.js +9353 -6124
- package/dist-server/permission-proxy.js +29 -9
- package/dist-server/server/admin-activity.js +410 -0
- package/dist-server/server/attachments.js +55 -0
- package/dist-server/server/auto-approve.js +4 -3
- package/dist-server/server/auto-vm-claims.js +1 -0
- package/dist-server/server/bot-package.js +18 -292
- package/dist-server/server/bot-profile.js +5 -17
- package/dist-server/server/bot-visibility.js +462 -0
- package/dist-server/server/box-create-idempotency.js +3 -3
- package/dist-server/server/box.js +59 -56
- package/dist-server/server/browser-proxy.js +3 -2
- package/dist-server/server/browser-runtime.js +38 -2
- package/dist-server/server/channel-queue.js +2 -0
- package/dist-server/server/cli-prompts.js +24 -2
- package/dist-server/server/cli.js +81 -12
- package/dist-server/server/command-allowlist.js +154 -0
- package/dist-server/server/composio.js +49 -11
- package/dist-server/server/computer-wait.js +22 -9
- package/dist-server/server/config.js +133 -17
- package/dist-server/server/connector-verdict.js +141 -0
- package/dist-server/server/container-computer.js +1 -1
- package/dist-server/server/decision-log.js +209 -48
- package/dist-server/server/default-model-selection.js +29 -3
- package/dist-server/server/delegations.js +97 -44
- package/dist-server/server/drivers/acp/core.js +163 -33
- package/dist-server/server/drivers/acp/grok.js +4 -3
- package/dist-server/server/drivers/agents-call.js +1162 -0
- package/dist-server/server/drivers/agents-catalog.js +689 -0
- package/dist-server/server/drivers/agents-client.js +28 -0
- package/dist-server/server/drivers/agents-proxy.js +18 -1722
- package/dist-server/server/drivers/boxagent.js +174 -36
- package/dist-server/server/drivers/builtIn.js +2 -0
- package/dist-server/server/drivers/chat-box-tools.js +90 -0
- package/dist-server/server/drivers/chat-images.js +54 -0
- package/dist-server/server/drivers/chat-mcp-tools.js +55 -10
- package/dist-server/server/drivers/chat-tool-approval.js +70 -18
- package/dist-server/server/drivers/claude.js +28 -8
- package/dist-server/server/drivers/codex-instructions.js +48 -6
- package/dist-server/server/drivers/codex-mcp-names.js +44 -0
- package/dist-server/server/drivers/codex-tool-surface.js +20 -0
- package/dist-server/server/drivers/codex.js +121 -34
- package/dist-server/server/drivers/grok.js +2 -1
- package/dist-server/server/drivers/mistral.js +115 -0
- package/dist-server/server/drivers/openai-chat.js +155 -32
- package/dist-server/server/drivers/openai-compat.js +16 -8
- package/dist-server/server/drivers/permission-command.js +35 -0
- package/dist-server/server/drivers/phone-proxy.js +47 -2
- package/dist-server/server/drivers/pi.js +75 -4
- package/dist-server/server/drivers/prompt-split.js +87 -0
- package/dist-server/server/enterprise.js +97 -16
- package/dist-server/server/external-runtime.js +83 -0
- package/dist-server/server/fleet.js +1 -1
- package/dist-server/server/group-thread-usage.js +103 -0
- package/dist-server/server/guarded-requests.js +60 -0
- package/dist-server/server/harness/http.js +61 -0
- package/dist-server/server/harness/registry.js +1 -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 +3091 -658
- package/dist-server/server/local-computer.js +72 -23
- 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 +6 -6
- package/dist-server/server/message-db.js +28 -0
- package/dist-server/server/model-context-window.js +7 -0
- package/dist-server/server/model-prices.js +121 -0
- package/dist-server/server/new-bot-defaults.js +115 -0
- package/dist-server/server/notify.js +10 -1
- package/dist-server/server/org-library.js +1051 -0
- package/dist-server/server/package-export.js +627 -39
- package/dist-server/server/package-import.js +458 -0
- package/dist-server/server/package-parts.js +87 -0
- package/dist-server/server/peer-approval.js +16 -7
- package/dist-server/server/peer-roster.js +23 -2
- package/dist-server/server/presets.js +492 -0
- package/dist-server/server/provider-key-check.js +3 -2
- package/dist-server/server/published-teams.js +80 -0
- package/dist-server/server/recent-work.js +15 -0
- package/dist-server/server/request-auth.js +96 -0
- package/dist-server/server/room-handoffs.js +44 -14
- package/dist-server/server/routes/bot-presets.js +25 -0
- 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 +6 -3
- package/dist-server/server/routines.js +63 -1
- package/dist-server/server/section-context.js +10 -0
- package/dist-server/server/skills.js +34 -61
- package/dist-server/server/spend.js +111 -16
- package/dist-server/server/steer-queue.js +9 -3
- package/dist-server/server/store.js +550 -35
- package/dist-server/server/surface.js +10 -4
- package/dist-server/server/system-prompt.js +12 -4
- package/dist-server/server/team-backup.js +16 -3
- package/dist-server/server/team-computers.js +10 -0
- package/dist-server/server/team-library.js +6 -2
- package/dist-server/server/team-manifest.js +4 -3
- package/dist-server/server/team-setup-requests.js +16 -5
- package/dist-server/server/thread-events.js +17 -1
- package/dist-server/server/thread-starters.js +53 -0
- package/dist-server/server/turn-context.js +2 -0
- package/dist-server/server/turn-watchdog.js +12 -3
- package/dist-server/server/usage-ledger.js +43 -9
- package/dist-server/server/vps-computer.js +139 -51
- package/dist-server/server/vps-container-mcp.js +7 -0
- package/dist-server/server/vps-ssh.js +36 -7
- package/dist-server/server/workspace-backup-policy.js +21 -2
- package/dist-server/server/workspace-backup.js +7 -4
- package/dist-server/server/workspace.js +1 -1
- package/dist-server/shared/approval-mode.js +1 -1
- package/dist-server/shared/ask-question.js +188 -12
- package/dist-server/shared/bot-profile.js +15 -0
- package/dist-server/shared/command-allowlist.js +1 -0
- package/dist-server/shared/credential-request.js +1 -1
- package/dist-server/shared/mention-boundary.js +15 -0
- package/dist-server/shared/package-format.js +967 -0
- package/dist-server/shared/routines.js +7 -1
- package/dist-server/shared/skill-md.js +64 -0
- package/dist-server/shared/team-backup.js +9 -0
- package/dist-server/shared/wire.js +4 -0
- package/dist-server/src/lib/composer-attachments.js +16 -0
- package/dist-server/vps-container-mcp.js +1147 -179
- package/enterprise/README.md +33 -12
- package/enterprise/server/index.js +5 -5
- package/package.json +1 -1
- package/dist/assets/index-Ba9G44HI.js +0 -310
- package/dist/assets/index-CkRNp7wX.css +0 -1
|
@@ -7,6 +7,7 @@ import { join } from "node:path";
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { normalizeImageGenerationUrl } from "../shared/image-generation.js";
|
|
9
9
|
import { writeFileAtomic } from "./atomic.js";
|
|
10
|
+
import { newBotDefaultsSchema } from "./new-bot-defaults.js";
|
|
10
11
|
import { EFFORT_LEVELS } from "../shared/wire.js";
|
|
11
12
|
import { isModelVariant } from "./contracts.js";
|
|
12
13
|
import { PROVIDER_ICON_PRESETS, providerIconError } from "../shared/provider-icon.js";
|
|
@@ -289,11 +290,36 @@ const instanceConfigSchema = z.object({
|
|
|
289
290
|
});
|
|
290
291
|
const instanceConfigMapSchema = z.record(z.string(), instanceConfigSchema);
|
|
291
292
|
const defaultModelSelectionSchema = z.object({
|
|
292
|
-
instanceId: z.string().trim().min(1),
|
|
293
|
-
model: z.string().trim().min(1),
|
|
293
|
+
instanceId: z.string().trim().min(1).max(200),
|
|
294
|
+
model: z.string().trim().min(1).max(500),
|
|
294
295
|
effort: z.enum(EFFORT_LEVELS).optional(),
|
|
295
296
|
variant: z.string().refine(isModelVariant, "invalid model variant").optional(),
|
|
296
297
|
}).refine((selection) => selection.variant === undefined || selection.effort === undefined, "choose either a model variant or an effort level");
|
|
298
|
+
const threadsConfigSchema = z.object({
|
|
299
|
+
maxConcurrentPerBot: z.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS),
|
|
300
|
+
/** Cap each per-thread events/ and native/ NDJSON log at this many
|
|
301
|
+
* bytes; absent (the default) keeps today's unbounded growth (#1280). */
|
|
302
|
+
eventLogMaxBytes: z.number().int().min(MIN_THREAD_EVENT_LOG_BYTES).max(MAX_THREAD_EVENT_LOG_BYTES).optional(),
|
|
303
|
+
/** Days a closed or archived thread's event logs survive (#1280).
|
|
304
|
+
* Absent keeps them forever. */
|
|
305
|
+
eventLogRetentionDays: z.number().int().min(1).max(3650).optional(),
|
|
306
|
+
}).strict();
|
|
307
|
+
/** Workspace-wide defaults every new bot starts with (Store.createBot). */
|
|
308
|
+
const newBotsConfigSchema = z.object({
|
|
309
|
+
/** Effort for a new bot whose model selection names none. */
|
|
310
|
+
effort: z.enum(EFFORT_LEVELS).optional(),
|
|
311
|
+
}).strict();
|
|
312
|
+
/** PATCH newBots: null clears a default back to absent (no level is sent). */
|
|
313
|
+
const newBotsPatchSchema = z.object({
|
|
314
|
+
effort: newBotsConfigSchema.shape.effort.nullable(),
|
|
315
|
+
}).strict();
|
|
316
|
+
/** PATCH threads: every knob is independently patchable, and null clears an
|
|
317
|
+
* event-log knob back to its absent (off) default. */
|
|
318
|
+
const threadsPatchSchema = threadsConfigSchema.extend({
|
|
319
|
+
maxConcurrentPerBot: threadsConfigSchema.shape.maxConcurrentPerBot.optional(),
|
|
320
|
+
eventLogMaxBytes: threadsConfigSchema.shape.eventLogMaxBytes.nullable(),
|
|
321
|
+
eventLogRetentionDays: threadsConfigSchema.shape.eventLogRetentionDays.nullable(),
|
|
322
|
+
});
|
|
297
323
|
const appConfigSchema = z.object({
|
|
298
324
|
/** Verified by the dedicated domain endpoint, never a generic config patch. */
|
|
299
325
|
customDomain: z.string().optional(),
|
|
@@ -301,12 +327,15 @@ const appConfigSchema = z.object({
|
|
|
301
327
|
* addresses or `@domain` entries; admins get every scope, members chat only. */
|
|
302
328
|
signIn: z.object({ admins: z.array(z.string().max(320)).max(500).optional(), members: z.array(z.string().max(320)).max(5000).optional() }).optional(),
|
|
303
329
|
defaultModelSelection: defaultModelSelectionSchema.optional(),
|
|
330
|
+
newBotDefaults: newBotDefaultsSchema.optional(),
|
|
331
|
+
newBots: newBotsConfigSchema.optional(),
|
|
304
332
|
/** CLI-only launch preferences. Never enable remote access implicitly. */
|
|
305
333
|
cliStartup: z.object({
|
|
306
334
|
access: z.enum(["local", "tunnel", "tailscale", "public-url"]),
|
|
307
335
|
publicUrl: z.string().url().optional(),
|
|
308
336
|
phone: z.enum(["ios", "android"]).optional(),
|
|
309
337
|
}).optional(),
|
|
338
|
+
mistral: z.object({ key: optionalText }).optional(),
|
|
310
339
|
xai: z.object({ key: optionalText, url: optionalText }).optional(),
|
|
311
340
|
/** Anthropic API key for Claude Code billed per token, handed only to
|
|
312
341
|
* Claude instances; `url` only for a proxy or a test double. Never a
|
|
@@ -384,8 +413,8 @@ const appConfigSchema = z.object({
|
|
|
384
413
|
}).optional(),
|
|
385
414
|
customModel: z.string().trim().max(200).refine((value) => !["\r", "\n", "\0"].some((character) => value.includes(character)), "Use a model ID without control characters").optional(),
|
|
386
415
|
}).optional(),
|
|
387
|
-
/** Non-secret profile details
|
|
388
|
-
profile: z.object({ name: optionalText, email: optionalText }).optional(),
|
|
416
|
+
/** Non-secret profile details; aboutMe is shared with every bot. */
|
|
417
|
+
profile: z.object({ name: optionalText, email: optionalText, aboutMe: z.string().max(24_000).optional() }).optional(),
|
|
389
418
|
/** UI language override (BCP-47, lowercase). Empty/absent = follow the
|
|
390
419
|
* system language. Unknown tags degrade to English in the renderer. */
|
|
391
420
|
language: optionalText,
|
|
@@ -395,15 +424,10 @@ const appConfigSchema = z.object({
|
|
|
395
424
|
compactAt: z.number().positive().max(10_000_000).optional(),
|
|
396
425
|
autoCompact: z.boolean().optional(),
|
|
397
426
|
}).optional(),
|
|
398
|
-
threads:
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
eventLogMaxBytes: z.number().int().min(MIN_THREAD_EVENT_LOG_BYTES).max(MAX_THREAD_EVENT_LOG_BYTES).optional(),
|
|
403
|
-
/** Days a closed or archived thread's event logs survive (#1280).
|
|
404
|
-
* Absent keeps them forever. */
|
|
405
|
-
eventLogRetentionDays: z.number().int().min(1).max(3650).optional(),
|
|
406
|
-
}).strict().optional(),
|
|
427
|
+
threads: threadsConfigSchema.optional(),
|
|
428
|
+
/** The authorization decision log (server/decision-log.ts): days of month
|
|
429
|
+
* files kept, at least; OMB_DECISION_RETENTION_DAYS wins when set. */
|
|
430
|
+
decisions: z.object({ retentionDays: z.number().int().min(1).max(3650).optional() }).strict().optional(),
|
|
407
431
|
localVm: localVmConfigSchema.optional(),
|
|
408
432
|
features: featureConfigSchema.optional(),
|
|
409
433
|
onboarding: onboardingConfigSchema.optional(),
|
|
@@ -420,7 +444,8 @@ const appConfigSchema = z.object({
|
|
|
420
444
|
const storedAppConfigSchema = appConfigSchema.extend({
|
|
421
445
|
browserProfiles: storedBrowserProfilesSchema.optional(),
|
|
422
446
|
});
|
|
423
|
-
const appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true })
|
|
447
|
+
const appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true })
|
|
448
|
+
.extend({ threads: threadsPatchSchema.optional(), newBots: newBotsPatchSchema.optional() });
|
|
424
449
|
const jsonObjectSchema = z.record(z.string(), z.json());
|
|
425
450
|
/** Resolve a canonical profile record to its exact durable Electron
|
|
426
451
|
* partition identity. Callers must never substitute the display/API id. */
|
|
@@ -520,6 +545,8 @@ export function roomHandoffLimits(cfg) {
|
|
|
520
545
|
hardCapMs: (cfg.rooms?.handoffHardCapMinutes ?? DEFAULT_ROOM_HANDOFF_HARD_CAP_MINUTES) * 60_000,
|
|
521
546
|
};
|
|
522
547
|
}
|
|
548
|
+
/** Accepts a full config or a parsed patch: the concurrency limit may be
|
|
549
|
+
* read from either, and a patch may legitimately omit it. */
|
|
523
550
|
export function maxConcurrentBotThreads(cfg) {
|
|
524
551
|
return cfg.threads?.maxConcurrentPerBot ?? DEFAULT_MAX_CONCURRENT_BOT_THREADS;
|
|
525
552
|
}
|
|
@@ -671,6 +698,9 @@ export function loadConfig() {
|
|
|
671
698
|
// Anything that saves a credential mid-session must keep process.env in
|
|
672
699
|
// step (syncCredentialEnv below), or the value injected at boot would
|
|
673
700
|
// shadow the save until the next launch.
|
|
701
|
+
cfg.mistral = { ...cfg.mistral };
|
|
702
|
+
if (process.env.MISTRAL_API_KEY !== undefined)
|
|
703
|
+
cfg.mistral.key = process.env.MISTRAL_API_KEY;
|
|
674
704
|
cfg.xai = { ...cfg.xai };
|
|
675
705
|
if (process.env.XAI_API_KEY !== undefined)
|
|
676
706
|
cfg.xai.key = process.env.XAI_API_KEY;
|
|
@@ -732,6 +762,7 @@ export function loadConfig() {
|
|
|
732
762
|
export function syncCredentialEnv(patch) {
|
|
733
763
|
const secrets = [
|
|
734
764
|
[patch.xai?.key, "XAI_API_KEY"],
|
|
765
|
+
[patch.mistral?.key, "MISTRAL_API_KEY"],
|
|
735
766
|
[patch.anthropic?.key, "OMB_ANTHROPIC_API_KEY"],
|
|
736
767
|
[patch.openaiCompat?.key, "OPENAI_COMPAT_API_KEY"],
|
|
737
768
|
[patch.composio?.apiKey, "COMPOSIO_API_KEY"],
|
|
@@ -774,8 +805,11 @@ export function syncCredentialEnv(patch) {
|
|
|
774
805
|
* child these are someone else's keys riding along in `...process.env`. */
|
|
775
806
|
export const WORKSPACE_CREDENTIAL_ENV = [
|
|
776
807
|
"XAI_API_KEY",
|
|
808
|
+
"MISTRAL_API_KEY",
|
|
777
809
|
"OMB_ANTHROPIC_API_KEY",
|
|
778
810
|
"OMB_ANTHROPIC_API_URL",
|
|
811
|
+
"OMB_HOSTED_MODEL_TOKEN",
|
|
812
|
+
"OMB_HOSTED_MODELS",
|
|
779
813
|
"OPENAI_COMPAT_API_KEY",
|
|
780
814
|
"OPENAI_COMPAT_URL",
|
|
781
815
|
"BOX_TOKEN",
|
|
@@ -792,10 +826,32 @@ export const WORKSPACE_CREDENTIAL_ENV = [
|
|
|
792
826
|
"OMB_BROWSER_CONNECTION",
|
|
793
827
|
"OMB_USER_DATA",
|
|
794
828
|
];
|
|
795
|
-
/**
|
|
829
|
+
/** Secrets of whoever operates this server, not of the workspace: the license
|
|
830
|
+
* key, a fleet container's installation credential, and everything a hosting
|
|
831
|
+
* control plane injects under `OMB_CLOUD_` (the readiness token, the bootstrap
|
|
832
|
+
* document and its gateway token). Only this process reads them. The prefix
|
|
833
|
+
* ends in an underscore on purpose: `OMB_CLOUDFLARED_PATH` is not one of them.
|
|
834
|
+
* What an engine is meant to receive arrives under another name through its
|
|
835
|
+
* instance environment (the hosted model token as ANTHROPIC_API_KEY or
|
|
836
|
+
* OPENMAUSBOT_COMPANY_API_KEY), so nothing here is ever an engine's input. */
|
|
837
|
+
export const CONTROL_PLANE_ENV = ["OMB_LICENSE_KEY", "OMB_INSTALLATION_CREDENTIAL"];
|
|
838
|
+
export const CONTROL_PLANE_ENV_PREFIX = "OMB_CLOUD_";
|
|
839
|
+
/** Drop every control-plane secret from a child-process env (in place). No
|
|
840
|
+
* driver allowlist re-admits these. Names compare case-insensitively because
|
|
841
|
+
* Windows environments do. */
|
|
842
|
+
export function stripControlPlaneEnv(env) {
|
|
843
|
+
for (const key of Object.keys(env)) {
|
|
844
|
+
const name = key.toUpperCase();
|
|
845
|
+
if (name.startsWith(CONTROL_PLANE_ENV_PREFIX) || CONTROL_PLANE_ENV.includes(name))
|
|
846
|
+
delete env[key];
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
/** Drop every workspace credential, and every control-plane secret, from a
|
|
850
|
+
* child-process env (in place). */
|
|
796
851
|
export function stripWorkspaceCredentialEnv(env) {
|
|
797
852
|
for (const key of WORKSPACE_CREDENTIAL_ENV)
|
|
798
853
|
delete env[key];
|
|
854
|
+
stripControlPlaneEnv(env);
|
|
799
855
|
}
|
|
800
856
|
/** Env names a provider CLI might read as its own billing identity. A spawned
|
|
801
857
|
* engine keeps only what its driver explicitly allows: a foreign key riding
|
|
@@ -812,9 +868,18 @@ export const PROVIDER_CREDENTIAL_ENV = [
|
|
|
812
868
|
"OPENAI_API_KEY",
|
|
813
869
|
"OPENCODE_API_KEY",
|
|
814
870
|
"XAI_API_KEY",
|
|
871
|
+
"MISTRAL_API_KEY",
|
|
815
872
|
"CURSOR_API_KEY",
|
|
816
873
|
"CURSOR_AUTH_TOKEN",
|
|
817
874
|
];
|
|
875
|
+
const configSaveListeners = new Set();
|
|
876
|
+
/** Told, synchronously, what each saveConfig wrote: the file before and
|
|
877
|
+
* after. The admin activity log (server/admin-activity.ts) records the
|
|
878
|
+
* change for whoever's request made it. A listener must not throw. */
|
|
879
|
+
export function onConfigSaved(listener) {
|
|
880
|
+
configSaveListeners.add(listener);
|
|
881
|
+
return () => { configSaveListeners.delete(listener); };
|
|
882
|
+
}
|
|
818
883
|
/** Merge a partial config into ~/.openmausbot/config.json (secrets never
|
|
819
884
|
* echoed back — callers report configured-or-not booleans only). */
|
|
820
885
|
export function saveConfig(patch, options = {}) {
|
|
@@ -828,20 +893,33 @@ export function saveConfig(patch, options = {}) {
|
|
|
828
893
|
catch {
|
|
829
894
|
/* first write */
|
|
830
895
|
}
|
|
831
|
-
const checkedPatch = appConfigSchema.partial().parse(patch);
|
|
896
|
+
const checkedPatch = appConfigSchema.partial().extend({ threads: threadsPatchSchema.optional(), newBots: newBotsPatchSchema.optional() }).parse(patch);
|
|
897
|
+
const before = configSaveListeners.size ? structuredClone(disk) : disk;
|
|
832
898
|
// A write is the durable migration point. Preserve every other raw key in
|
|
833
899
|
// config.json, but never write #567's mixed-case or duplicate profile ids
|
|
834
900
|
// back after we have successfully recognized the legacy list.
|
|
835
901
|
const storedProfiles = storedBrowserProfilesSchema.safeParse(disk.browserProfiles);
|
|
836
902
|
if (storedProfiles.success)
|
|
837
903
|
disk.browserProfiles = storedProfiles.data;
|
|
838
|
-
for (const key of ["xai", "anthropic", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "context", "localVm", "features", "budgets", "billing", "onboarding", "browserEngine"]) {
|
|
904
|
+
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"]) {
|
|
839
905
|
const section = checkedPatch[key];
|
|
840
906
|
if (!section)
|
|
841
907
|
continue;
|
|
842
908
|
const current = jsonObjectSchema.safeParse(disk[key]);
|
|
843
909
|
const merged = current.success ? { ...current.data } : {};
|
|
910
|
+
// parseStoredConfig requires threads.maxConcurrentPerBot, so creating
|
|
911
|
+
// the section with only an event-log knob must still persist a valid
|
|
912
|
+
// concurrency default.
|
|
913
|
+
if (key === "threads" && !current.success)
|
|
914
|
+
merged.maxConcurrentPerBot = DEFAULT_MAX_CONCURRENT_BOT_THREADS;
|
|
844
915
|
Object.assign(merged, section);
|
|
916
|
+
// null is the patch's explicit "remove this key" marker (the threads
|
|
917
|
+
// event-log knobs and newBots.effort use it); a key the patch omits
|
|
918
|
+
// keeps its value.
|
|
919
|
+
for (const [sectionKey, sectionValue] of Object.entries(section)) {
|
|
920
|
+
if (sectionValue === null)
|
|
921
|
+
delete merged[sectionKey];
|
|
922
|
+
}
|
|
845
923
|
disk[key] = merged;
|
|
846
924
|
}
|
|
847
925
|
if (checkedPatch.vps !== undefined)
|
|
@@ -857,6 +935,24 @@ export function saveConfig(patch, options = {}) {
|
|
|
857
935
|
// an effort level omitted from the new selection.
|
|
858
936
|
if (checkedPatch.defaultModelSelection !== undefined) {
|
|
859
937
|
disk.defaultModelSelection = checkedPatch.defaultModelSelection;
|
|
938
|
+
if (disk.newBotDefaults) {
|
|
939
|
+
const previousDefaults = newBotDefaultsSchema.parse(disk.newBotDefaults);
|
|
940
|
+
disk.newBotDefaults = newBotDefaultsSchema.parse({
|
|
941
|
+
...previousDefaults,
|
|
942
|
+
profile: { ...previousDefaults.profile, modelSelection: checkedPatch.defaultModelSelection },
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
// Replace the complete template so clearing a field, file or routine
|
|
947
|
+
// cannot revive an old value through the general section merge above.
|
|
948
|
+
if (checkedPatch.newBotDefaults !== undefined) {
|
|
949
|
+
disk.newBotDefaults = checkedPatch.newBotDefaults;
|
|
950
|
+
if (checkedPatch.newBotDefaults.profile.modelSelection) {
|
|
951
|
+
disk.defaultModelSelection = checkedPatch.newBotDefaults.profile.modelSelection;
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
delete disk.defaultModelSelection;
|
|
955
|
+
}
|
|
860
956
|
}
|
|
861
957
|
if (checkedPatch.cliStartup !== undefined)
|
|
862
958
|
disk.cliStartup = checkedPatch.cliStartup;
|
|
@@ -880,6 +976,14 @@ export function saveConfig(patch, options = {}) {
|
|
|
880
976
|
if (routingConflict)
|
|
881
977
|
throw Object.assign(new Error(routingConflict), { status: 409 });
|
|
882
978
|
disk.browserProfiles = nextProfiles;
|
|
979
|
+
if (disk.newBotDefaults) {
|
|
980
|
+
const defaults = newBotDefaultsSchema.parse(disk.newBotDefaults);
|
|
981
|
+
const profileId = defaults.profile.browserProfile;
|
|
982
|
+
if (profileId && profileId !== "guest" && !nextProfiles.some(profile => profile.id === profileId)) {
|
|
983
|
+
delete defaults.profile.browserProfile;
|
|
984
|
+
disk.newBotDefaults = defaults;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
883
987
|
}
|
|
884
988
|
if (checkedPatch.instances) {
|
|
885
989
|
const currentInstances = jsonObjectSchema.safeParse(disk.instances);
|
|
@@ -920,6 +1024,14 @@ export function saveConfig(patch, options = {}) {
|
|
|
920
1024
|
}
|
|
921
1025
|
mkdirSync(DATA_DIR, { recursive: true });
|
|
922
1026
|
writeFileAtomic(p, JSON.stringify(disk, null, 2), { mode: 0o600 });
|
|
1027
|
+
for (const listener of configSaveListeners) {
|
|
1028
|
+
try {
|
|
1029
|
+
listener(before, disk);
|
|
1030
|
+
}
|
|
1031
|
+
catch (error) {
|
|
1032
|
+
console.warn(`config: a save listener failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
923
1035
|
}
|
|
924
1036
|
/** Set one instance's `config.cli` ("" clears the override back to the
|
|
925
1037
|
* driver default). Creating the instance entry is fine — a config-less
|
|
@@ -980,6 +1092,8 @@ export function persistableInstanceConfigs(cfg) {
|
|
|
980
1092
|
* environment of an unrelated child process. */
|
|
981
1093
|
function injectedEnvironment(cfg, driver) {
|
|
982
1094
|
const environment = new Map();
|
|
1095
|
+
if (driver === "mistral" && cfg.mistral?.key)
|
|
1096
|
+
environment.set("MISTRAL_API_KEY", cfg.mistral.key);
|
|
983
1097
|
if (driver === "grok" && cfg.xai?.key)
|
|
984
1098
|
environment.set("XAI_API_KEY", cfg.xai.key);
|
|
985
1099
|
// The workspace Anthropic key reaches Claude Code as the variable it
|
|
@@ -1030,6 +1144,7 @@ export function instanceConfigs(cfg) {
|
|
|
1030
1144
|
opencodeGo: { driver: "opencodeGo" },
|
|
1031
1145
|
computer: { driver: "boxAgent" },
|
|
1032
1146
|
openaiCompat: { driver: "openai-compat" },
|
|
1147
|
+
mistral: { driver: "mistral" },
|
|
1033
1148
|
qwen: { driver: "qwenAgent" },
|
|
1034
1149
|
hermes: { driver: "hermesAgent" },
|
|
1035
1150
|
pi: { driver: "piAgent" },
|
|
@@ -1045,6 +1160,7 @@ export function instanceConfigs(cfg) {
|
|
|
1045
1160
|
const PRODUCT_FLEET_ADDITIONS = {
|
|
1046
1161
|
cursor: { driver: "cursorAgent" },
|
|
1047
1162
|
openaiCompat: { driver: "openai-compat" },
|
|
1163
|
+
mistral: { driver: "mistral" },
|
|
1048
1164
|
...CUSTOM_ONLY,
|
|
1049
1165
|
};
|
|
1050
1166
|
const configured = cfg.instances && Object.keys(cfg.instances).length ? cfg.instances : null;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// The harness-side verdict for connected-app tool calls (issue #1736, part
|
|
2
|
+
// of the per-bot Composio tool grants umbrella #1734).
|
|
3
|
+
//
|
|
4
|
+
// Every Composio tool call crosses POST /api/internal/connectors/mcp: the
|
|
5
|
+
// provider CLIs talk to the stdio bridge, and the bridge forwards each
|
|
6
|
+
// JSON-RPC frame there. So the grants verdict lives on the harness side,
|
|
7
|
+
// where the loopback token already names the bot and the decision log is
|
|
8
|
+
// native — the bridge never sees a key it could have to enforce with.
|
|
9
|
+
//
|
|
10
|
+
// Three shapes reach this module:
|
|
11
|
+
//
|
|
12
|
+
// * a direct per-toolkit call — params.name is the tool itself, e.g.
|
|
13
|
+
// GMAIL_SEND_EMAIL;
|
|
14
|
+
// * the executor meta-tool — COMPOSIO_MULTI_EXECUTE_TOOL, whose
|
|
15
|
+
// arguments name one or many target tools;
|
|
16
|
+
// * everything else — connection cards, discovery, notifications —
|
|
17
|
+
// which passes through untouched (advertisement filtering is slice 3).
|
|
18
|
+
//
|
|
19
|
+
// Unrecognized argument shapes are denied by default: a call whose target
|
|
20
|
+
// tools cannot be read is a call whose tools cannot be checked, and the
|
|
21
|
+
// grants promise — "this bot may call exactly these tools" — must hold
|
|
22
|
+
// even against a model that garbles the protocol.
|
|
23
|
+
import { CONNECTOR_TOOL_NAME_PATTERN } from "../shared/wire.js";
|
|
24
|
+
/** The executor meta-tool: the only meta-tool whose arguments name target
|
|
25
|
+
* tools. Discovery and connection meta-tools keep their existing flows. */
|
|
26
|
+
export const COMPOSIO_MULTI_EXECUTE_TOOL = "COMPOSIO_MULTI_EXECUTE_TOOL";
|
|
27
|
+
/** The service a Composio tool name belongs to: the upper-snake prefix
|
|
28
|
+
* before the first underscore, lowercased (GMAIL_SEND_EMAIL to gmail). A
|
|
29
|
+
* name with no underscore names no service, so no grant can cover it. */
|
|
30
|
+
export function serviceSlugFor(tool) {
|
|
31
|
+
const underscore = tool.indexOf("_");
|
|
32
|
+
if (underscore <= 0)
|
|
33
|
+
return null;
|
|
34
|
+
return tool.slice(0, underscore).toLowerCase();
|
|
35
|
+
}
|
|
36
|
+
/** Classify one relayed JSON-RPC frame. Anything that is not a tools/call,
|
|
37
|
+
* or is a discovery/connection/platform meta-tool, passes through. */
|
|
38
|
+
export function connectorCallFromFrame(payload) {
|
|
39
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
40
|
+
return { kind: "passthrough" };
|
|
41
|
+
const frame = payload;
|
|
42
|
+
if (frame.method !== "tools/call")
|
|
43
|
+
return { kind: "passthrough" };
|
|
44
|
+
const params = frame.params;
|
|
45
|
+
if (!params || typeof params !== "object" || Array.isArray(params)) {
|
|
46
|
+
return { kind: "unrecognized", invoked: "tools/call", reason: "the call carried no params object" };
|
|
47
|
+
}
|
|
48
|
+
const name = params.name;
|
|
49
|
+
if (typeof name !== "string" || !name) {
|
|
50
|
+
return { kind: "unrecognized", invoked: "tools/call", reason: "the call named no tool" };
|
|
51
|
+
}
|
|
52
|
+
if (name === COMPOSIO_MULTI_EXECUTE_TOOL) {
|
|
53
|
+
return multiExecuteCall(name, params.arguments);
|
|
54
|
+
}
|
|
55
|
+
// Platform meta-tools (search, schemas, remote workbench) are not
|
|
56
|
+
// connected-app tools; grants are keyed by service slug, and slice 3
|
|
57
|
+
// owns what the model is even shown.
|
|
58
|
+
if (name.startsWith("COMPOSIO_"))
|
|
59
|
+
return { kind: "passthrough" };
|
|
60
|
+
// Per-service connection cards keep their card flow in any spelling.
|
|
61
|
+
if (name.endsWith("_MANAGE_CONNECTIONS") || name.endsWith("_WAIT_FOR_CONNECTIONS")) {
|
|
62
|
+
return { kind: "passthrough" };
|
|
63
|
+
}
|
|
64
|
+
if (!CONNECTOR_TOOL_NAME_PATTERN.test(name)) {
|
|
65
|
+
return { kind: "unrecognized", invoked: name, reason: "the tool name is not a Composio tool name" };
|
|
66
|
+
}
|
|
67
|
+
return { kind: "tools", invoked: name, names: [name] };
|
|
68
|
+
}
|
|
69
|
+
/** Read the target tools out of COMPOSIO_MULTI_EXECUTE_TOOL arguments:
|
|
70
|
+
* the upstream schema is a 1-50 item tools array of { tool_slug,
|
|
71
|
+
* arguments }; a legacy single { tool_slug } object is accepted too.
|
|
72
|
+
* Anything else cannot be checked, so it is denied. */
|
|
73
|
+
function multiExecuteCall(invoked, args) {
|
|
74
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) {
|
|
75
|
+
return { kind: "unrecognized", invoked, reason: "the arguments were not an object" };
|
|
76
|
+
}
|
|
77
|
+
const tools = args.tools;
|
|
78
|
+
const singleSlug = args.tool_slug;
|
|
79
|
+
if (Array.isArray(tools)) {
|
|
80
|
+
if (tools.length === 0) {
|
|
81
|
+
return { kind: "unrecognized", invoked, reason: "the tools list was empty" };
|
|
82
|
+
}
|
|
83
|
+
const names = [];
|
|
84
|
+
for (const item of tools) {
|
|
85
|
+
const slug = item && typeof item === "object" && !Array.isArray(item)
|
|
86
|
+
? item.tool_slug
|
|
87
|
+
: undefined;
|
|
88
|
+
if (typeof slug !== "string" || !slug) {
|
|
89
|
+
return { kind: "unrecognized", invoked, reason: "an entry in the tools list named no tool_slug" };
|
|
90
|
+
}
|
|
91
|
+
names.push(slug);
|
|
92
|
+
}
|
|
93
|
+
return { kind: "tools", invoked, names };
|
|
94
|
+
}
|
|
95
|
+
if (typeof singleSlug === "string" && singleSlug) {
|
|
96
|
+
return { kind: "tools", invoked, names: [singleSlug] };
|
|
97
|
+
}
|
|
98
|
+
return { kind: "unrecognized", invoked, reason: "the arguments named no tools to execute" };
|
|
99
|
+
}
|
|
100
|
+
/** Judge distinct target names against a bot's grants. grants undefined
|
|
101
|
+
* is the legacy all-tools bot and passes everything; an explicit record —
|
|
102
|
+
* including the empty one — allows only what it names. */
|
|
103
|
+
export function evaluateConnectorTools(names, grants) {
|
|
104
|
+
if (grants === undefined) {
|
|
105
|
+
return { allowed: true, legacy: true, denials: [], rule: "composio" };
|
|
106
|
+
}
|
|
107
|
+
const denials = [];
|
|
108
|
+
let rule = "";
|
|
109
|
+
for (const tool of new Set(names)) {
|
|
110
|
+
const service = serviceSlugFor(tool);
|
|
111
|
+
const grant = service === null ? undefined : grants[service];
|
|
112
|
+
if (grant && (grant.tools === "*" || grant.tools.includes(tool))) {
|
|
113
|
+
if (!rule)
|
|
114
|
+
rule = "connectorTools." + service;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
denials.push({ tool, service, onGrantedService: Boolean(grant) });
|
|
118
|
+
}
|
|
119
|
+
return { allowed: denials.length === 0, legacy: false, denials, rule };
|
|
120
|
+
}
|
|
121
|
+
/** Safe to hand straight to the model: names the refused tool and says who
|
|
122
|
+
* can change it. It never lists what the bot could have called instead —
|
|
123
|
+
* a refusal that enumerates adjacent grants teaches the model to probe. */
|
|
124
|
+
export function connectorRefusalText(denials) {
|
|
125
|
+
const named = denials.map((denial) => '"' + denial.tool + '"').join(", ");
|
|
126
|
+
const one = denials.length === 1;
|
|
127
|
+
return [
|
|
128
|
+
named + " " + (one ? "is" : "are") + " not granted to this bot.",
|
|
129
|
+
"This call was not performed.",
|
|
130
|
+
"Ask the person to grant " + (one ? "it" : "these tools") + " in OpenMausBot if they want " + (one ? "it" : "them") + " run.",
|
|
131
|
+
].join(" ");
|
|
132
|
+
}
|
|
133
|
+
/** The unrecognized-shape refusal: names the meta-tool and what could not
|
|
134
|
+
* be read, and still points at the person rather than at any tool list. */
|
|
135
|
+
export function connectorUnrecognizedText(invoked, reason) {
|
|
136
|
+
return [
|
|
137
|
+
"A " + invoked + " call arrived in a shape OpenMausBot could not read (" + reason + "), so it was not performed.",
|
|
138
|
+
"Send a well-formed call that names the tools to execute.",
|
|
139
|
+
"Ask the person to grant any tool this bot needs.",
|
|
140
|
+
].join(" ");
|
|
141
|
+
}
|
|
@@ -310,7 +310,7 @@ function statusProblem(status) {
|
|
|
310
310
|
if (status.security === "unsafe")
|
|
311
311
|
return "The existing Local VM is missing safety limits; recreate it";
|
|
312
312
|
if (status.persistence === "unsafe")
|
|
313
|
-
return "The existing Local VM is missing its durable
|
|
313
|
+
return "The existing Local VM is missing its durable folder; recreate it";
|
|
314
314
|
if (status.container === "stopped")
|
|
315
315
|
return "This desktop image cannot safely resume; recreate the Local VM";
|
|
316
316
|
if (status.desktop_error)
|