openmausbot 0.1.78 → 0.1.79

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.
Files changed (47) hide show
  1. package/dist/assets/{index-BqDJqf2C.js → index-C2Je5jdF.js} +1 -1
  2. package/dist/assets/index-D_TFZLlo.js +305 -0
  3. package/dist/index.html +1 -1
  4. package/dist-server/container-mcp.js +11 -5
  5. package/dist-server/enterprise/server/index.js +0 -1
  6. package/dist-server/index.js +15451 -6812
  7. package/dist-server/local-computer.js +0 -1
  8. package/dist-server/mcp-server.js +8 -1
  9. package/dist-server/openmausbot.js +9190 -758
  10. package/dist-server/pair-cli.js +9190 -758
  11. package/dist-server/proxy-paths.js +0 -1
  12. package/dist-server/server/box.js +98 -41
  13. package/dist-server/server/browser-engine.js +1 -1
  14. package/dist-server/server/browser-runtime.js +11 -3
  15. package/dist-server/server/browser-tool-shape.js +72 -0
  16. package/dist-server/server/claude-accounts.js +1 -0
  17. package/dist-server/server/cli-setup.js +1 -1
  18. package/dist-server/server/composio.js +18 -0
  19. package/dist-server/server/config.js +16 -4
  20. package/dist-server/server/container-computer.js +0 -12
  21. package/dist-server/server/drivers/acp/core.js +4 -19
  22. package/dist-server/server/drivers/boxagent.js +48 -4
  23. package/dist-server/server/drivers/chat-mcp-tools.js +368 -0
  24. package/dist-server/server/drivers/chat-tool-approval.js +42 -0
  25. package/dist-server/server/drivers/claude.js +87 -32
  26. package/dist-server/server/drivers/codex.js +69 -31
  27. package/dist-server/server/drivers/grok.js +4 -0
  28. package/dist-server/server/drivers/minimax.js +11 -3
  29. package/dist-server/server/drivers/openai-chat-protocol.js +92 -0
  30. package/dist-server/server/drivers/openai-chat.js +332 -88
  31. package/dist-server/server/drivers/openai-compat.js +4 -0
  32. package/dist-server/server/drivers/pi.js +1 -9
  33. package/dist-server/server/index.js +64 -38
  34. package/dist-server/server/proxy-paths.js +0 -1
  35. package/dist-server/server/room-handoffs.js +47 -9
  36. package/dist-server/server/tts/chatterbox.js +83 -0
  37. package/dist-server/server/tts/index.js +45 -12
  38. package/dist-server/server/workspace.js +12 -2
  39. package/dist-server/shared/ask-question.js +28 -0
  40. package/dist-server/shared/computer-contention.js +17 -0
  41. package/dist-server/vps-container-mcp.js +11 -5
  42. package/enterprise/server/index.js +0 -1
  43. package/package.json +1 -1
  44. package/dist/assets/index-DjwAroIZ.js +0 -305
  45. package/dist-server/computer-proxy.js +0 -1196
  46. package/dist-server/server/computer-proxy.js +0 -1070
  47. package/dist-server/server/remote-computer.js +0 -170
@@ -16,6 +16,10 @@ import { redactSecretsInText } from "./redact.js";
16
16
  import { DATA_DIR } from "./config.js";
17
17
  export const WORKSPACES_DIR = join(DATA_DIR, "workspaces");
18
18
  export const TASK_WORKSPACES_DIR = join(DATA_DIR, "task-workspaces");
19
+ /** MCP support does not imply native filesystem tools or a local working directory. */
20
+ export function supportsWorkspaceFiles(driverKind) {
21
+ return !["grok", "openai-compat", "minimax", "boxAgent"].includes(driverKind);
22
+ }
19
23
  /** Default task files are private to the thread, outside the bot's shared
20
24
  * memory folder. This is directory organization, not a shell sandbox. */
21
25
  export function ensureTaskWorkspace(botId, threadId) {
@@ -519,9 +523,15 @@ export function memorySystemPrompt(botId, opts = {}) {
519
523
  const memory = loadMemory(botId);
520
524
  const memoryFile = join(workspaceDir(botId), "MEMORY.md");
521
525
  const topicDir = join(workspaceDir(botId), "memory");
526
+ if (opts.fileTools === false && !opts.managedWrites) {
527
+ if (!memory)
528
+ return "";
529
+ return ` Your saved memory is supplied as context; this turn has no memory editing tools.\n\nYour memory (MEMORY.md):\n${memory.text}${memory.truncated ? " [Only the initial memory excerpt is visible.]" : ""}`;
530
+ }
522
531
  const writeGuidance = opts.managedWrites
523
532
  ? " This memory is shared across your independent threads. Use memory_update for every change to MEMORY.md, never direct file tools or whole-file overwrites." +
524
- " Append new facts, or replace/remove an exact unique old_text passage. If it conflicts, read the current file and retry only your intended change."
533
+ " Append new facts, or replace/remove an exact unique old_text passage. If it conflicts, " +
534
+ (opts.fileTools === false ? "use session_search to find the current passage" : "read the current file") + " and retry only your intended change."
525
535
  : " When you learn something worth keeping, update it with your file tools; remove notes that turn out to be wrong.";
526
536
  const guidance = ` Your private long-term memory file is ${JSON.stringify(memoryFile)}.` +
527
537
  " It stays separate from a custom project working folder." +
@@ -533,7 +543,7 @@ export function memorySystemPrompt(botId, opts = {}) {
533
543
  return guidance;
534
544
  const truncatedNote = memory.truncated
535
545
  ? ` [MEMORY.md is ${memory.lines} lines and ${memory.bytes} bytes; only the first ${MEMORY_MAX_LINES} lines / ${MEMORY_MAX_BYTES} bytes are shown above and the rest is not visible to you. ${opts.managedWrites
536
- ? "Consolidate it now with memory_update: replace or remove older entries, or move detail to a memory/<topic>.md file."
546
+ ? "Consolidate it now with memory_update: replace or remove older entries" + (opts.fileTools === false ? "." : ", or move detail to a memory/<topic>.md file.")
537
547
  : "Trim it with your file tools: merge or remove older entries, or move detail to a memory/<topic>.md file."}]`
538
548
  : "";
539
549
  return `${guidance}\n\nYour memory (MEMORY.md):\n${memory.text}${truncatedNote}`;
@@ -100,6 +100,34 @@ export function askQuestionSummary(questions) {
100
100
  const rest = questions.length - 1;
101
101
  return rest > 0 ? `${first} (+${rest} more question${rest > 1 ? "s" : ""})` : first;
102
102
  }
103
+ /** How many one-tap answers an `ask_user` card offers; the tool advertises
104
+ * "2-5 suggested answers". */
105
+ export const MAX_CHOICES = 5;
106
+ /**
107
+ * Flat labels from a bot-authored `ask_user` `choices` array.
108
+ *
109
+ * The tool schema says strings, but a model that has also seen Claude's
110
+ * AskUserQuestion will hand over `{ label, description }` rows instead
111
+ * (MiniMax M3 does). The label is the choice either way. Anything else is
112
+ * dropped: a non-string choice that reached the card was drawn as a React
113
+ * child, which React refuses, taking the whole chat page down with it.
114
+ */
115
+ export function parseChoices(input, limit = MAX_CHOICES) {
116
+ if (!Array.isArray(input))
117
+ return undefined;
118
+ const choices = [];
119
+ const seen = new Set();
120
+ for (const raw of input) {
121
+ const label = typeof raw === "string" ? text(raw, MAX_LABEL) : isRecord(raw) ? text(raw.label, MAX_LABEL) : undefined;
122
+ if (!label || seen.has(label))
123
+ continue;
124
+ seen.add(label);
125
+ choices.push(label);
126
+ if (choices.length === limit)
127
+ break;
128
+ }
129
+ return choices.length ? choices : undefined;
130
+ }
103
131
  /** Flat labels for clients that only know how to render a list of choices
104
132
  * (the phone companions, and any older desktop build). Only a single
105
133
  * question can be answered that way without losing which one was answered. */
@@ -0,0 +1,17 @@
1
+ /** One wording for "a turn already owns this bot's cloud computer", shared
2
+ * because two sides have to agree on it: the server sends it with 409 when
3
+ * provision or sleep arrives mid-turn, and the Computer panel recognises it
4
+ * to show the neutral busy state instead of a fault.
5
+ *
6
+ * Kept here rather than spelled out at each site: the panel used to match
7
+ * the server's prose with its own regex, so a copy-edit on the server would
8
+ * have silently turned the busy state back into "Couldn't reach the
9
+ * computer" — the exact bug the panel fix exists to prevent, and one no
10
+ * test would have caught. */
11
+ export const CLOUD_COMPUTER_BUSY_ERROR = "this bot's cloud computer is being used by an active turn — interrupt it first";
12
+ /** True when an error message carries that refusal, however it was wrapped.
13
+ * A substring test, not equality: the message reaches the client as the
14
+ * server wrote it today, but a future wrapper must not break recognition. */
15
+ export function isCloudComputerBusyMessage(message) {
16
+ return message.includes(CLOUD_COMPUTER_BUSY_ERROR);
17
+ }
@@ -15187,10 +15187,17 @@ var appConfigSchema = external_exports.object({
15187
15187
  vps: vpsConfigSchema.optional(),
15188
15188
  /** Optional OpenCode key; persisted write-only and passed only to its child. */
15189
15189
  opencodeGo: external_exports.object({ apiKey: optionalText }).optional(),
15190
- /** Voice credentials and the selected voice id. `provider` picks the
15191
- * engine: "elevenlabs" (default; needs a key) or "system" (the Mac's
15192
- * built-in voices, no key). */
15193
- tts: external_exports.object({ key: optionalText, voice: optionalText, provider: external_exports.enum(["elevenlabs", "system"]).optional() }).optional(),
15190
+ /** Voice settings and the selected voice id. `provider` picks the
15191
+ * engine: "elevenlabs" (default; needs a key), "system" (the Mac's
15192
+ * built-in voices, no key), or "chatterbox" (a local OpenAI-compatible
15193
+ * Chatterbox server; `baseUrl` and `model` are settings, not secrets). */
15194
+ tts: external_exports.object({
15195
+ key: optionalText,
15196
+ voice: optionalText,
15197
+ provider: external_exports.enum(["elevenlabs", "system", "chatterbox"]).optional(),
15198
+ baseUrl: external_exports.string().trim().max(2048).refine((value) => !value || /^https?:\/\//i.test(value), "the Chatterbox server address must start with http:// or https://").optional(),
15199
+ model: optionalText
15200
+ }).optional(),
15194
15201
  /** Avatar provider credentials stay separate; choosing a router never reuses a cloud key. */
15195
15202
  imageGen: external_exports.object({
15196
15203
  provider: external_exports.enum(["openai", "xai", "custom"]).optional(),
@@ -15249,7 +15256,6 @@ function resolveProxy(relative) {
15249
15256
  }
15250
15257
  var SPAWNED_PROXIES = {
15251
15258
  browser: resolveProxy("browser-proxy"),
15252
- computer: resolveProxy("computer-proxy"),
15253
15259
  localComputer: resolveProxy("local-computer-proxy"),
15254
15260
  permission: resolveProxy("permission-proxy"),
15255
15261
  containerMcp: resolveProxy("container-mcp"),
@@ -14593,7 +14593,6 @@ function resolveProxy(relative) {
14593
14593
  }
14594
14594
  var SPAWNED_PROXIES = {
14595
14595
  browser: resolveProxy("browser-proxy"),
14596
- computer: resolveProxy("computer-proxy"),
14597
14596
  localComputer: resolveProxy("local-computer-proxy"),
14598
14597
  permission: resolveProxy("permission-proxy"),
14599
14598
  containerMcp: resolveProxy("container-mcp"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmausbot",
3
- "version": "0.1.78",
3
+ "version": "0.1.79",
4
4
  "description": "Run the OpenMausBot server anywhere and pair your devices to it",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",