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
|
@@ -29,7 +29,7 @@ function text(value, limit) {
|
|
|
29
29
|
if (typeof value !== "string")
|
|
30
30
|
return undefined;
|
|
31
31
|
const trimmed = value.trim();
|
|
32
|
-
return trimmed ? trimmed.slice(0, limit) : undefined;
|
|
32
|
+
return trimmed ? trimmed.slice(0, limit).trim() : undefined;
|
|
33
33
|
}
|
|
34
34
|
function isRecord(value) {
|
|
35
35
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -94,6 +94,36 @@ export function parseAskQuestions(input) {
|
|
|
94
94
|
}
|
|
95
95
|
return questions.length ? questions : null;
|
|
96
96
|
}
|
|
97
|
+
/** The fenced block a turn-boundary agent ends its run with when it wants
|
|
98
|
+
* to ask the person something (the BoxAgent transport): the harness cannot
|
|
99
|
+
* pause mid-run, so the questions ride the final output and OMB parses them
|
|
100
|
+
* at settle. The block is model-authored — untrusted input like any tool
|
|
101
|
+
* call — so its body runs through parseAskQuestions and the same caps. */
|
|
102
|
+
const OMB_ASK_FENCE = /(^|\n)[ \t]{0,3}(`{3,}|~{3,})[ \t]*omb-ask[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\2[ \t]*(?=\r?\n|$)/;
|
|
103
|
+
const OMB_ASK_FENCE_GLOBAL = new RegExp(OMB_ASK_FENCE.source, OMB_ASK_FENCE.flags + "g");
|
|
104
|
+
/** The questions inside the first fenced omb-ask block in an output, or
|
|
105
|
+
* null when there is nothing worth showing (no fence, invalid JSON, or no
|
|
106
|
+
* entry that parses as a question). The first fence wins: a second block
|
|
107
|
+
* in the same output is ignored, not merged. */
|
|
108
|
+
export function parseOmbAskQuestions(output) {
|
|
109
|
+
const match = OMB_ASK_FENCE.exec(output);
|
|
110
|
+
if (!match)
|
|
111
|
+
return null;
|
|
112
|
+
try {
|
|
113
|
+
return parseAskQuestions(JSON.parse(match[3]));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** The output with its omb-ask block(s) removed, for display: the person
|
|
120
|
+
* reads the prose around the ask, never the raw protocol JSON. Text
|
|
121
|
+
* without a block is returned untouched. */
|
|
122
|
+
export function stripOmbAskBlock(output) {
|
|
123
|
+
if (!OMB_ASK_FENCE.test(output))
|
|
124
|
+
return output;
|
|
125
|
+
return output.replace(OMB_ASK_FENCE_GLOBAL, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
126
|
+
}
|
|
97
127
|
/** The one line the card subtitle and a spoken prompt show. */
|
|
98
128
|
export function askQuestionSummary(questions) {
|
|
99
129
|
const first = questions[0]?.question ?? "";
|
|
@@ -139,6 +169,61 @@ export function questionChoices(questions) {
|
|
|
139
169
|
return undefined;
|
|
140
170
|
return only.options.map((option) => option.label);
|
|
141
171
|
}
|
|
172
|
+
/** The chat runtime's own ask tool: the OpenAI-compatible engines'
|
|
173
|
+
* counterpart of ASK_USER_QUESTION. Named ask_user so the ASKS_A_PERSON
|
|
174
|
+
* backstop already covers it — no auto mode may answer a question. */
|
|
175
|
+
export const ASK_USER_TOOL = "ask_user";
|
|
176
|
+
/** The ask_user definition shared by every chat-runtime engine, shaped for
|
|
177
|
+
* an OpenAI function-calling tool list. The schema states the caps; the
|
|
178
|
+
* parser enforces them again on arrival, because a model-authored argument
|
|
179
|
+
* is a request to follow the schema, not a guarantee that it did. */
|
|
180
|
+
export const ASK_USER_TOOL_DEFINITION = {
|
|
181
|
+
type: "function",
|
|
182
|
+
function: {
|
|
183
|
+
name: ASK_USER_TOOL,
|
|
184
|
+
description: "Ask the person questions when the decision is theirs. Offer concrete options where they exist; they can always answer in their own words. Ask up to six questions in one call rather than one at a time.",
|
|
185
|
+
parameters: {
|
|
186
|
+
type: "object",
|
|
187
|
+
properties: {
|
|
188
|
+
questions: {
|
|
189
|
+
type: "array",
|
|
190
|
+
minItems: 1,
|
|
191
|
+
maxItems: MAX_QUESTIONS,
|
|
192
|
+
items: {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: {
|
|
195
|
+
question: { type: "string", description: "The question to show the person." },
|
|
196
|
+
header: { type: "string", description: "A short label for the question's tab." },
|
|
197
|
+
multiSelect: { type: "boolean", description: "Whether several options may be picked." },
|
|
198
|
+
options: {
|
|
199
|
+
type: "array",
|
|
200
|
+
maxItems: MAX_OPTIONS,
|
|
201
|
+
description: "Suggested answers; the person may always write their own.",
|
|
202
|
+
items: {
|
|
203
|
+
type: "object",
|
|
204
|
+
properties: {
|
|
205
|
+
label: { type: "string" },
|
|
206
|
+
description: { type: "string" },
|
|
207
|
+
},
|
|
208
|
+
required: ["label"],
|
|
209
|
+
additionalProperties: false,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
required: ["question"],
|
|
214
|
+
additionalProperties: false,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
required: ["questions"],
|
|
219
|
+
additionalProperties: false,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
/** The synthetic tool string for an ask parsed out of model-authored final
|
|
224
|
+
* output (the BoxAgent turn-held transport): there is no tool call to name,
|
|
225
|
+
* but the event and the ASKS_A_PERSON backstop need one string. */
|
|
226
|
+
export const OMB_ASK_TOOL = "omb-ask";
|
|
142
227
|
/** The lead-in on a formatted answer. It exists for the model — the answer
|
|
143
228
|
* is delivered on the deny channel, so it has to say what it is — and the
|
|
144
229
|
* card strips it back off when it shows the person what they sent. */
|
|
@@ -164,6 +249,23 @@ export function formatQuestionAnswers(questions, answers) {
|
|
|
164
249
|
export function answerWithoutPreamble(answer) {
|
|
165
250
|
return answer.startsWith(`${ANSWER_PREAMBLE}\n\n`) ? answer.slice(ANSWER_PREAMBLE.length + 2) : answer;
|
|
166
251
|
}
|
|
252
|
+
/** The longest formatted answer OMB will echo back into a follow-up prompt
|
|
253
|
+
* (the BoxAgent continuation). formatQuestionAnswers itself does not
|
|
254
|
+
* truncate — the tool-result channel has no stated limit — but a prompt is
|
|
255
|
+
* not the place to find one: six answers at the custom-answer cap is the
|
|
256
|
+
* most a legitimate reply weighs, so that is the ceiling. */
|
|
257
|
+
export const MAX_ANSWER_ECHO = 6 * MAX_CUSTOM_ANSWER;
|
|
258
|
+
/** Cap a formatted answer for echoing into a follow-up prompt. An over-cap
|
|
259
|
+
* echo is cut back to the last whole block so no partial answer reads as
|
|
260
|
+
* one, and says it was truncated. */
|
|
261
|
+
export function capAnswerEcho(answer, limit = MAX_ANSWER_ECHO) {
|
|
262
|
+
if (answer.length <= limit)
|
|
263
|
+
return answer;
|
|
264
|
+
const cut = answer.slice(0, limit);
|
|
265
|
+
const boundary = cut.lastIndexOf("\n\nQ: ");
|
|
266
|
+
const kept = boundary > 0 ? cut.slice(0, boundary) : cut;
|
|
267
|
+
return kept + "\n\n[answer truncated]";
|
|
268
|
+
}
|
|
167
269
|
/**
|
|
168
270
|
* The answer text, read back as one value per question.
|
|
169
271
|
*
|
|
@@ -180,21 +282,95 @@ export function answerWithoutPreamble(answer) {
|
|
|
180
282
|
* With more than one there is, and nothing is filed.
|
|
181
283
|
*/
|
|
182
284
|
export function questionAnswersByQuestion(message, questions) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
285
|
+
return questionAnswersById(message, questions.map(question => ({ id: question.question, question })));
|
|
286
|
+
}
|
|
287
|
+
/** Longest protocol id accepted. Ids are harness-internal keys, never shown
|
|
288
|
+
* on the card, but they ride the reply — so they are capped like the rest. */
|
|
289
|
+
const MAX_QUESTION_ID = 200;
|
|
290
|
+
/** Parse a protocol questions array whose entries carry their own string
|
|
291
|
+
* ids (codex's item/tool/requestUserInput). The same caps and skip rules
|
|
292
|
+
* as parseAskQuestions; an entry without both a usable id and a usable
|
|
293
|
+
* question is skipped rather than fatal, and nothing answerable parses to
|
|
294
|
+
* null. */
|
|
295
|
+
export function parseProtocolAskQuestions(entries) {
|
|
296
|
+
if (!Array.isArray(entries))
|
|
297
|
+
return null;
|
|
298
|
+
const parsed = [];
|
|
299
|
+
const seenIds = new Set();
|
|
300
|
+
for (const raw of entries) {
|
|
301
|
+
if (!isRecord(raw))
|
|
302
|
+
continue;
|
|
303
|
+
const question = parseQuestion(raw);
|
|
304
|
+
// The id is opaque protocol data echoed back verbatim in the answer, so
|
|
305
|
+
// it is preserved exactly as sent — trimmed only to reject an
|
|
306
|
+
// all-whitespace id — and an overlong id is rejected whole rather than
|
|
307
|
+
// truncated. A duplicate id fails the whole request: two questions
|
|
308
|
+
// cannot share one answer slot, and silently dropping one would ask
|
|
309
|
+
// the person a question whose answer could never be delivered.
|
|
310
|
+
const id = raw.id;
|
|
311
|
+
if (!question || typeof id !== "string" || !id.trim() || id.length > MAX_QUESTION_ID)
|
|
312
|
+
continue;
|
|
313
|
+
if (seenIds.has(id))
|
|
314
|
+
return null;
|
|
315
|
+
seenIds.add(id);
|
|
316
|
+
parsed.push({ id, question });
|
|
317
|
+
if (parsed.length === MAX_QUESTIONS)
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
return parsed.length ? parsed : null;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* The id-keyed counterpart of questionAnswersByQuestion, for a protocol
|
|
324
|
+
* that answers by id (codex's requestUserInput) rather than by question
|
|
325
|
+
* text.
|
|
326
|
+
*
|
|
327
|
+
* Each protocol entry's id is paired with the AskQuestion parsed from that
|
|
328
|
+
* same entry, so a Q:/A: block the card wrote is matched against the text
|
|
329
|
+
* that produced it and filed under the id that asked. Only ids with a real
|
|
330
|
+
* block are answered — a question left unanswered gets no entry rather
|
|
331
|
+
* than a guess. When the reply carries no blocks at all, the flat path
|
|
332
|
+
* applies with exactly one question: the whole message is that question's
|
|
333
|
+
* answer, as it is for a phone or an older client. With more than one,
|
|
334
|
+
* nothing is filed.
|
|
335
|
+
*/
|
|
336
|
+
export function questionAnswersById(message, questions) {
|
|
337
|
+
const answers = Object.create(null);
|
|
338
|
+
const idByText = new Map();
|
|
339
|
+
const ambiguous = new Set();
|
|
340
|
+
for (const { id, question } of questions) {
|
|
341
|
+
if (idByText.has(question.question)) {
|
|
342
|
+
// Two questions with identical text cannot be told apart in a block;
|
|
343
|
+
// answering either id would be a guess, so neither is answered.
|
|
344
|
+
ambiguous.add(question.question);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
idByText.set(question.question, id);
|
|
348
|
+
}
|
|
349
|
+
// A block runs from one Q: header to the next (blank lines inside an
|
|
350
|
+
// answer are the answer's, not block boundaries), so the reply is scanned
|
|
351
|
+
// for header-to-header spans instead of split on every blank line.
|
|
352
|
+
const blocks = message.matchAll(/(?:^|\n\n)Q: ([\s\S]+?)\nA: ([\s\S]*?)(?=\n\nQ: |$)/g);
|
|
353
|
+
let sawBlock = false;
|
|
354
|
+
for (const match of blocks) {
|
|
355
|
+
sawBlock = true;
|
|
356
|
+
const asked = match[1].trim();
|
|
357
|
+
if (ambiguous.has(asked))
|
|
188
358
|
continue;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
359
|
+
const id = idByText.get(asked);
|
|
360
|
+
const answer = match[2].trim();
|
|
361
|
+
// A blank A: is no answer: the id stays unanswered rather than filed
|
|
362
|
+
// as an empty string.
|
|
363
|
+
if (id && answer)
|
|
364
|
+
answers[id] = answer;
|
|
194
365
|
}
|
|
195
366
|
if (Object.keys(answers).length)
|
|
196
367
|
return answers;
|
|
368
|
+
// A structured reply that matched a block is authoritative even when it
|
|
369
|
+
// answered nothing: falling through to the flat fallback would file the
|
|
370
|
+
// literal Q:/A: text as the person's answer.
|
|
371
|
+
if (sawBlock)
|
|
372
|
+
return {};
|
|
197
373
|
const only = questions.length === 1 ? questions[0] : undefined;
|
|
198
374
|
const flat = message.trim();
|
|
199
|
-
return only && flat ? { [only.
|
|
375
|
+
return only && flat ? { [only.id]: flat } : {};
|
|
200
376
|
}
|
|
@@ -9,3 +9,18 @@ export const BOT_PROFILE_LIMITS = {
|
|
|
9
9
|
voice: 200,
|
|
10
10
|
soul: 24_000,
|
|
11
11
|
};
|
|
12
|
+
/** A name or title is quoted inside prompts and cards as one line — a
|
|
13
|
+
* roster entry, a "Name: …" speaker line, the bracketed provenance note.
|
|
14
|
+
* Text that can break out of that line (a newline, a control byte, the
|
|
15
|
+
* Unicode separators) is refused at the door rather than flattened later,
|
|
16
|
+
* so what the person sees in the sidebar is what every prompt sees too.
|
|
17
|
+
* Written as a scan because a control-character class is the kind of
|
|
18
|
+
* literal the linter (rightly) refuses. */
|
|
19
|
+
export function fitsOnOneLine(value) {
|
|
20
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
21
|
+
const code = value.charCodeAt(i);
|
|
22
|
+
if (code < 0x20 || (code >= 0x7f && code <= 0x9f) || code === 0x2028 || code === 0x2029)
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -14,7 +14,7 @@ export const CREDENTIAL_TARGETS = {
|
|
|
14
14
|
label: "Box API key",
|
|
15
15
|
description: "Gives bots an isolated cloud computer when Box is selected.",
|
|
16
16
|
placeholder: "Paste your Box API key",
|
|
17
|
-
helpUrl: "https://docs.
|
|
17
|
+
helpUrl: "https://docs.boat.dev/api-keys",
|
|
18
18
|
},
|
|
19
19
|
opencodeGoApiKey: {
|
|
20
20
|
label: "OpenCode API key",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Keep mention recognition identical in the renderer and server routing.
|
|
2
|
+
// Deliberately allow only opening punctuation/Markdown markers here: `/@bot`
|
|
3
|
+
// remains a URL path, while `(@bot)`, `【@bot】`, and `**@bot**` are tags.
|
|
4
|
+
const OPENING_MENTION_BOUNDARY = /[(*_~[{<'"\u2018\u201c\u3008\u300a\u300c\u300e\u3010\uff08]/u;
|
|
5
|
+
/** Return whether an at-sign starts a standalone mention at this offset. */
|
|
6
|
+
export function isMentionBoundary(text, at) {
|
|
7
|
+
if (at === 0)
|
|
8
|
+
return true;
|
|
9
|
+
const before = text[at - 1];
|
|
10
|
+
return /\s/u.test(before) || OPENING_MENTION_BOUNDARY.test(before);
|
|
11
|
+
}
|
|
12
|
+
/** A matched name must not be the prefix of a longer Unicode word. */
|
|
13
|
+
export function isMentionNameContinuation(value) {
|
|
14
|
+
return value !== undefined && /^[\p{L}\p{N}\p{M}_]/u.test(value);
|
|
15
|
+
}
|