openmausbot 0.1.75 → 0.1.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{index-BTlyRwLl.js → index-DeK-z9ld.js} +1 -1
- package/dist/assets/index-XdHJ-9CF.css +1 -0
- package/dist/assets/index-lhqE1umn.js +305 -0
- package/dist/index.html +2 -2
- package/dist-server/companion/src/routes.js +6 -2
- package/dist-server/container-mcp.js +5 -1
- package/dist-server/drivers/agents-proxy.js +184 -11
- package/dist-server/enterprise/server/index.js +387 -29
- package/dist-server/index.js +3786 -1135
- package/dist-server/mcp-gate.js +28 -18
- package/dist-server/openmausbot.js +927 -642
- package/dist-server/pair-cli.js +927 -642
- package/dist-server/server/agent-tool-policy.js +2 -0
- package/dist-server/server/atomic.js +37 -1
- package/dist-server/server/bot-overview.js +5 -1
- package/dist-server/server/browser-live.js +3 -0
- package/dist-server/server/chief-of-staff.js +17 -12
- package/dist-server/server/config.js +16 -0
- package/dist-server/server/delegations.js +177 -63
- package/dist-server/server/drivers/acp/core.js +3 -1
- package/dist-server/server/drivers/acp/hermes.js +21 -3
- package/dist-server/server/drivers/agents-proxy.js +169 -10
- package/dist-server/server/drivers/boxagent.js +1 -1
- package/dist-server/server/drivers/claude.js +34 -16
- package/dist-server/server/drivers/codex.js +3 -1
- package/dist-server/server/drivers/openai-chat.js +90 -67
- package/dist-server/server/drivers/openai-compat.js +9 -1
- package/dist-server/server/drivers/pi.js +22 -3
- package/dist-server/server/enterprise.js +38 -0
- package/dist-server/server/env-path.js +18 -17
- package/dist-server/server/environment.js +3 -0
- package/dist-server/server/fleet-agent.js +57 -13
- package/dist-server/server/fleet-cli.js +248 -31
- package/dist-server/server/fleet.js +88 -14
- package/dist-server/server/hosted-contract.js +16 -0
- package/dist-server/server/index.js +1777 -406
- package/dist-server/server/message-db.js +21 -0
- package/dist-server/server/message-file.js +4 -0
- package/dist-server/server/peer-roster.js +48 -9
- package/dist-server/server/procs.js +19 -3
- package/dist-server/server/provider-key-check.js +18 -1
- package/dist-server/server/request-auth.js +14 -5
- package/dist-server/server/room-handoffs.js +237 -0
- package/dist-server/server/section-context.js +64 -14
- package/dist-server/server/sessions.js +115 -8
- package/dist-server/server/shared-computer-control.js +24 -0
- package/dist-server/server/shared-computers.js +131 -0
- package/dist-server/server/steer-queue.js +2 -0
- package/dist-server/server/store.js +267 -15
- package/dist-server/server/surface.js +16 -5
- package/dist-server/server/team-backup.js +17 -1
- package/dist-server/server/team-computers.js +108 -0
- package/dist-server/server/team-setup-requests.js +252 -0
- package/dist-server/server/tool-summary.js +53 -1
- package/dist-server/server/turn-dispatch-guard.js +31 -3
- package/dist-server/server/workspace-backup.js +1 -0
- package/dist-server/shared/approval-mode.js +11 -1
- package/dist-server/shared/team-backup.js +1 -0
- package/dist-server/shared/team-computer.js +1 -0
- package/dist-server/shared/team-setup.js +1 -0
- package/dist-server/vps-container-mcp.js +5 -1
- package/enterprise/README.md +21 -3
- package/enterprise/server/index.js +387 -29
- package/package.json +1 -1
- package/dist/assets/index-CeMbvsgx.js +0 -305
- package/dist/assets/index-DH7Zax6L.css +0 -1
package/dist/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/app-icon.svg" />
|
|
7
7
|
<title>OpenMausBot</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-lhqE1umn.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-XdHJ-9CF.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -140,12 +140,16 @@ const ALLOWED = [
|
|
|
140
140
|
{ method: "POST", path: /^\/api\/routines\/[\w-]+\/run$/ },
|
|
141
141
|
{ method: "POST", path: /^\/api\/routine-runs\/[\w-]+\/(?:cancel|seen)$/ },
|
|
142
142
|
// Multi-account Composio management exposes opaque ids and aliases only.
|
|
143
|
-
//
|
|
144
|
-
//
|
|
143
|
+
// Account-level removal is allowed: the handler still proves the account
|
|
144
|
+
// belongs to the host's own user before revoking, and a paired client can
|
|
145
|
+
// already add accounts — connectable but not disconnectable is the bug
|
|
146
|
+
// being fixed here. The whole-service DELETE stays denied: it belongs to
|
|
147
|
+
// the host.
|
|
145
148
|
{ method: "GET", path: /^\/api\/connectors\/catalog$/ },
|
|
146
149
|
{ method: "GET", path: /^\/api\/connectors\/connected$/ },
|
|
147
150
|
{ method: "GET", path: /^\/api\/connectors$/ },
|
|
148
151
|
{ method: "POST", path: /^\/api\/connectors\/[\w-]+\/authorize$/ },
|
|
152
|
+
{ method: "DELETE", path: /^\/api\/connectors\/[\w-]+\/accounts\/[\w-]+$/ },
|
|
149
153
|
// Inline connector cards are scoped by bot, transcript message, and
|
|
150
154
|
// thread. They expose the same opaque OAuth authorization already allowed
|
|
151
155
|
// above, then only poll, resume, or dismiss that exact pending card.
|
|
@@ -14810,7 +14810,11 @@ var featureConfigSchema = external_exports.object({
|
|
|
14810
14810
|
showToolCalls: external_exports.boolean().optional(),
|
|
14811
14811
|
/** Experimental built-in browser. Off until explicitly enabled; each bot
|
|
14812
14812
|
* also has its own switch. */
|
|
14813
|
-
browser: external_exports.boolean().optional()
|
|
14813
|
+
browser: external_exports.boolean().optional(),
|
|
14814
|
+
/** Opt-in computer sharing (a desktop lending folders, a terminal or
|
|
14815
|
+
* computer control to a workspace). Off until explicitly enabled; there is
|
|
14816
|
+
* no Settings toggle — see sharedComputersEnabled. */
|
|
14817
|
+
sharedComputers: external_exports.boolean().optional()
|
|
14814
14818
|
});
|
|
14815
14819
|
var onboardingConfigSchema = external_exports.object({
|
|
14816
14820
|
/** ISO timestamp of finishing (or skipping to the end of) the welcome flow. */
|
|
@@ -41,6 +41,8 @@ function isCredentialTargetId(value) {
|
|
|
41
41
|
// server/agent-tool-policy.ts
|
|
42
42
|
var READ_ONLY_AGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
43
43
|
"list_bots",
|
|
44
|
+
"list_team_setup",
|
|
45
|
+
"list_shared_computers",
|
|
44
46
|
"list_rooms",
|
|
45
47
|
"list_threads",
|
|
46
48
|
"check_delegation",
|
|
@@ -63,6 +65,25 @@ function agentToolAnnotations(name) {
|
|
|
63
65
|
return isReadOnlyAgentTool(name) ? READ_ONLY_ANNOTATIONS : void 0;
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
// server/peer-roster.ts
|
|
69
|
+
var ROSTER_NAME_MAX = 80;
|
|
70
|
+
var oneLine = (value) => {
|
|
71
|
+
let flattened = "";
|
|
72
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
73
|
+
const code = value.charCodeAt(i);
|
|
74
|
+
const breaksOut = code < 32 || code >= 127 && code <= 159 || code === 8232 || code === 8233;
|
|
75
|
+
flattened += breaksOut ? " " : value[i];
|
|
76
|
+
}
|
|
77
|
+
return flattened.replace(/\s+/g, " ").trim();
|
|
78
|
+
};
|
|
79
|
+
var clip = (value, max) => {
|
|
80
|
+
const flat = oneLine(value);
|
|
81
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
82
|
+
};
|
|
83
|
+
function peerName(value) {
|
|
84
|
+
return clip(value.replace(/[[\]]/g, " "), ROSTER_NAME_MAX);
|
|
85
|
+
}
|
|
86
|
+
|
|
66
87
|
// server/drivers/agents-proxy.ts
|
|
67
88
|
var HARNESS = process.env.OMB_HARNESS_URL ?? "http://127.0.0.1:8799";
|
|
68
89
|
var BOT_ID = process.env.OMB_BOT_ID ?? "";
|
|
@@ -70,6 +91,7 @@ var THREAD_ID = process.env.OMB_THREAD_ID ?? "";
|
|
|
70
91
|
var TOKEN = process.env.OMB_COMMS_TOKEN ?? "";
|
|
71
92
|
var DEPTH = Number(process.env.OMB_TURN_DEPTH ?? "0") || 0;
|
|
72
93
|
var SKILL_AUTHORING_ENABLED = process.env.OMB_SKILL_AUTHORING_ENABLED === "1";
|
|
94
|
+
var SHARED_COMPUTERS_ENABLED = process.env.OMB_SHARED_COMPUTERS_ENABLED === "1";
|
|
73
95
|
var MAX_CREATED_PER_TURN = 4;
|
|
74
96
|
var createdThisTurn = 0;
|
|
75
97
|
var MAX_ROOM_POSTS_PER_TURN = 3;
|
|
@@ -313,14 +335,51 @@ var ROUTINE_FIELDS_SCHEMA = {
|
|
|
313
335
|
}
|
|
314
336
|
};
|
|
315
337
|
var TOOLS = [
|
|
338
|
+
{
|
|
339
|
+
name: "list_shared_computers",
|
|
340
|
+
description: "List online desktop computers explicitly shared with this workspace, and their allowed folders/capabilities. These are the user's computers, not this server. An offline or unshared computer cannot be accessed. Folder paths use opaque folder IDs and relative paths.",
|
|
341
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
name: "shared_computer",
|
|
345
|
+
description: "Use a desktop explicitly shared by the user. Discover computer_id and folder_id with list_shared_computers. list_files/read_file/write_file are confined to chosen folders; paths are relative. read_file returns sha256; overwriting requires expected_sha256. Binary files support base64 encoding. run_command requires a SEPARATE unrestricted terminal grant. computer_tools lists the native computer-control tools; computer_call invokes one with arguments and needs a SEPARATE computer-control grant. Never substitute the server's filesystem when this desktop is offline. Actions are not retried automatically; inspect an uncertain outcome before retrying.",
|
|
346
|
+
inputSchema: { type: "object", additionalProperties: false, properties: {
|
|
347
|
+
computer_id: { type: "string" },
|
|
348
|
+
action: { type: "string", enum: ["list_files", "read_file", "write_file", "run_command", "computer_tools", "computer_call"] },
|
|
349
|
+
folder_id: { type: "string" },
|
|
350
|
+
path: { type: "string" },
|
|
351
|
+
content: { type: "string" },
|
|
352
|
+
encoding: { type: "string", enum: ["utf8", "base64"] },
|
|
353
|
+
expected_sha256: { type: "string" },
|
|
354
|
+
command: { type: "string" },
|
|
355
|
+
tool_name: { type: "string" },
|
|
356
|
+
arguments: { type: "object", additionalProperties: true }
|
|
357
|
+
}, required: ["computer_id", "action"] }
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: "list_room_targets",
|
|
361
|
+
description: "Discover actual OpenMausBot teammates and rooms in your allowed teams. Works in a normal bot conversation too; no room is required. Returns bot and room IDs, roles and working folders, never other conversations' history. Use these bots, not native coding helpers with similar names, when the user asks their team to work together.",
|
|
362
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
name: "coordinate_bots",
|
|
366
|
+
description: "Ask existing OpenMausBot teammates for advice or assign concrete work. From normal chat each assignment gets a separate recipient conversation; from a room it defaults to this room. Use group_id from list_room_targets for a specific room. Name 1-4 bot_ids: they receive only your brief and use their own model, tools and permissions. Busy bots queue. They can consult their specialists; all results return here and resume you automatically. Include exact file paths, constraints and what must be verified. After sending all assignments, END your turn; do not poll or wait. On return, resolve tradeoffs, verify the requested outcome and request concrete corrections if necessary before giving one final answer. Do not send acknowledgements as new work.",
|
|
367
|
+
inputSchema: { type: "object", additionalProperties: false, properties: {
|
|
368
|
+
group_id: { type: "string", description: "Optional destination room. Omit for this room, or separate recipient tasks when chatting directly." },
|
|
369
|
+
bot_ids: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 4, uniqueItems: true },
|
|
370
|
+
message: { type: "string", minLength: 1, maxLength: 4e3, description: "Self-contained question or task for these teammates. Send separate requests when responsibilities differ." },
|
|
371
|
+
request_key: { type: "string", description: "A short unique assignment key. Reuse for an identical retry." },
|
|
372
|
+
rework: { type: "boolean", description: "True only for concrete additional work from someone who already completed a request." }
|
|
373
|
+
}, required: ["bot_ids", "message", "request_key"] }
|
|
374
|
+
},
|
|
316
375
|
{
|
|
317
376
|
name: "list_bots",
|
|
318
|
-
description: "List the other bots (agents) in your
|
|
377
|
+
description: "List the other bots (agents) you may contact in your own team and any additional teams the owner has explicitly allowed you to coordinate, with their team, model and current status. Call this to discover exact teammate IDs before assigning work or requesting advice through your available coordination tools.",
|
|
319
378
|
inputSchema: { type: "object", properties: {} }
|
|
320
379
|
},
|
|
321
380
|
{
|
|
322
381
|
name: "list_rooms",
|
|
323
|
-
description: "List the shared rooms (team channels) you belong to, with the other members of each. Call this before post_to_room
|
|
382
|
+
description: "List the shared rooms (team channels) you belong to, with the other members of each. Call this before post_to_room. One-to-one bot channels are never listed; discover individual teammates with list_bots. A room you are in but cannot post into is named without an id, together with the reason, so you can tell the user why.",
|
|
324
383
|
inputSchema: { type: "object", additionalProperties: false, properties: {} }
|
|
325
384
|
},
|
|
326
385
|
{
|
|
@@ -373,12 +432,12 @@ var TOOLS = [
|
|
|
373
432
|
},
|
|
374
433
|
{
|
|
375
434
|
name: "list_threads",
|
|
376
|
-
description: "See your own threads and the threads you opened on teammates, newest first: each with its bot, title, state (running, waiting on the person, queued, or
|
|
435
|
+
description: "See your own threads and the threads you opened on teammates, newest first: each with its bot, title, state (running, waiting on the person, queued, idle, or closed), whether the person has unread there, and the delegation id if it was a handoff. Use it to check how the threads you started are going before reporting to the person; write a thread's title as #Title when you mention it. A teammate's other threads are never listed \u2014 only the ones you opened. This is a read: it starts nothing and changes nothing.",
|
|
377
436
|
inputSchema: { type: "object", additionalProperties: false, properties: {} }
|
|
378
437
|
},
|
|
379
438
|
{
|
|
380
439
|
name: "close_thread",
|
|
381
|
-
description: "Mark a thread you opened (or one of your own) as finished once you have read its result: it
|
|
440
|
+
description: "Mark a thread you opened (or one of your own) as finished once you have read its result: it leaves the person's default sidebar list (still under all threads, with a note saying you closed it) and list_threads reports it as closed. Nothing is deleted \u2014 deleting stays the person's decision \u2014 and a thread that is still running cannot be closed; wait for it or leave it. Use the thread id from list_threads or from the start_thread result. If a close is refused, do not retry it.",
|
|
382
441
|
inputSchema: {
|
|
383
442
|
type: "object",
|
|
384
443
|
additionalProperties: false,
|
|
@@ -427,6 +486,54 @@ var TOOLS = [
|
|
|
427
486
|
required: ["name", "role", "instructions"]
|
|
428
487
|
}
|
|
429
488
|
},
|
|
489
|
+
{
|
|
490
|
+
name: "list_team_setup",
|
|
491
|
+
description: "Chief of Staff only: list authorized teams, teammate IDs, and exact engine/model choices for team setup. Call before proposing configuration; never invent model IDs. Existing thread models are independent of bot defaults.",
|
|
492
|
+
inputSchema: { type: "object", additionalProperties: false, properties: {} }
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
name: "propose_team_setup",
|
|
496
|
+
description: "Chief of Staff only: propose all requested specialist creation, profile/model configuration, and authorized team moves in ONE combined review card. Nothing changes until the user applies it. Use exact catalog engine/model IDs from list_team_setup. Combine all fields for each bot; use the same create key or botId to coalesce repeated entries. New teams must be named explicitly in newTeams and have a specialist in this plan; the card also asks to authorize your access to just those new teams. Existing unauthorized teams cannot be included. Models change bot defaults for groups/new threads; existing threads and execution permissions stay unchanged. After proposing, end your turn. The decision and structured result automatically resume you once; do not ask again, poll, or repeat the proposal.",
|
|
497
|
+
inputSchema: {
|
|
498
|
+
type: "object",
|
|
499
|
+
additionalProperties: false,
|
|
500
|
+
properties: {
|
|
501
|
+
reason: { type: "string", minLength: 1, maxLength: 500 },
|
|
502
|
+
newTeams: { type: "array", maxItems: 8, items: { type: "string", minLength: 1, maxLength: 60 } },
|
|
503
|
+
operations: { type: "array", minItems: 1, maxItems: 24, items: {
|
|
504
|
+
type: "object",
|
|
505
|
+
additionalProperties: false,
|
|
506
|
+
properties: {
|
|
507
|
+
action: { type: "string", enum: ["create", "update"] },
|
|
508
|
+
key: { type: "string", description: "For create: your stable short name for this new bot in this plan." },
|
|
509
|
+
botId: { type: "string", description: "For update: exact existing bot ID from list_team_setup." },
|
|
510
|
+
fields: { type: "object", additionalProperties: false, properties: {
|
|
511
|
+
name: { type: "string", maxLength: 100 },
|
|
512
|
+
title: { type: "string", maxLength: 200 },
|
|
513
|
+
description: { type: "string", maxLength: 4e3 },
|
|
514
|
+
soul: { type: "string", description: "Standing instructions; required with name/title/modelSelection for every new bot." },
|
|
515
|
+
section: { type: "string", maxLength: 60, description: "Exact authorized existing team, or a team explicitly named in newTeams. Empty string means General." },
|
|
516
|
+
modelSelection: { type: "object", additionalProperties: false, properties: {
|
|
517
|
+
instanceId: { type: "string" },
|
|
518
|
+
model: { type: "string" },
|
|
519
|
+
effort: { type: "string" }
|
|
520
|
+
}, required: ["instanceId", "model"] }
|
|
521
|
+
} }
|
|
522
|
+
},
|
|
523
|
+
required: ["action", "fields"]
|
|
524
|
+
} }
|
|
525
|
+
},
|
|
526
|
+
required: ["reason", "operations"]
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: "propose_bot_deletion",
|
|
531
|
+
description: "Chief of Staff only: when the user explicitly asks to delete a named teammate, create a separate confirmation card for that exact bot. Deletion removes its conversations, memory, instructions and skills; generated project files remain. Running work and owned computers can block deletion. Never delete yourself, substitute an archive, or put deletion into a setup batch. End your turn after proposing; the decision and result resume you once.",
|
|
532
|
+
inputSchema: { type: "object", additionalProperties: false, properties: {
|
|
533
|
+
bot_id: { type: "string", minLength: 1 },
|
|
534
|
+
reason: { type: "string", minLength: 1, maxLength: 500 }
|
|
535
|
+
}, required: ["bot_id", "reason"] }
|
|
536
|
+
},
|
|
430
537
|
{
|
|
431
538
|
name: "create_room",
|
|
432
539
|
description: "Create a room in your own section when the user asks for one (maximum four per turn). Chiefs only. Choose active peers from list_bots; you are included automatically as the default responder. This creates no turns or messages. Section moves stay with the user. If peer approval is enabled, ask the user to make the room change instead.",
|
|
@@ -665,7 +772,21 @@ var TOOLS = [
|
|
|
665
772
|
return annotations ? { ...tool, annotations } : tool;
|
|
666
773
|
});
|
|
667
774
|
var SKILL_TOOL_NAMES = /* @__PURE__ */ new Set(["skills_list", "skill_manage"]);
|
|
668
|
-
var
|
|
775
|
+
var AUTHORING_TOOLS = SKILL_AUTHORING_ENABLED ? TOOLS : TOOLS.filter((tool) => !SKILL_TOOL_NAMES.has(tool.name));
|
|
776
|
+
var SHARED_COMPUTER_TOOL_NAMES = /* @__PURE__ */ new Set(["list_shared_computers", "shared_computer"]);
|
|
777
|
+
var SHAREABLE_TOOLS = SHARED_COMPUTERS_ENABLED ? AUTHORING_TOOLS : AUTHORING_TOOLS.filter((tool) => !SHARED_COMPUTER_TOOL_NAMES.has(tool.name));
|
|
778
|
+
var ROOM_ONLY_TOOLS = /* @__PURE__ */ new Set(["list_room_targets", "coordinate_bots"]);
|
|
779
|
+
var ROOM_REPLACED_TOOLS = /* @__PURE__ */ new Set(["ask_bot", "delegate_bot", "check_delegation", "wait_delegation", "start_thread", "send_to_thread", "wait_thread"]);
|
|
780
|
+
var COORDINATING = process.env.OMB_ROOM_TURN === "1";
|
|
781
|
+
var OWN_THREAD_CREATION = process.env.OMB_OWN_THREAD_CREATION === "1";
|
|
782
|
+
var AVAILABLE_TOOLS = COORDINATING ? SHAREABLE_TOOLS.filter((tool) => !ROOM_REPLACED_TOOLS.has(tool.name) || tool.name === "start_thread" && OWN_THREAD_CREATION).map((tool) => tool.name === "start_thread" ? {
|
|
783
|
+
...tool,
|
|
784
|
+
description: "Open a separate job on yourself with its own history and run, without switching the person's selected conversation. Use only when the user requests independent jobs (for example one review per pull request). Give a short specific title and complete instructions; you can open at most five per turn. This is not a teammate handoff: use coordinate_bots for teammates and their automatic replies. Self-opened jobs cannot recursively open more jobs. If refused, do not retry; explain what remains.",
|
|
785
|
+
inputSchema: { ...tool.inputSchema, properties: {
|
|
786
|
+
...tool.inputSchema.properties,
|
|
787
|
+
bot_id: { type: "string", enum: [BOT_ID], description: "Leave out, or use your own bot ID. For teammates use coordinate_bots." }
|
|
788
|
+
} }
|
|
789
|
+
} : tool) : SHAREABLE_TOOLS.filter((tool) => !ROOM_ONLY_TOOLS.has(tool.name));
|
|
669
790
|
var send = (msg) => process.stdout.write(JSON.stringify(msg) + "\n");
|
|
670
791
|
var ok = (id, result) => send({ jsonrpc: "2.0", id, result });
|
|
671
792
|
var rpcErr = (id, code, message) => send({ jsonrpc: "2.0", id, error: { code, message } });
|
|
@@ -749,20 +870,36 @@ function recallSpeaker(hit) {
|
|
|
749
870
|
return hit.role === "user" ? "user" : "you";
|
|
750
871
|
}
|
|
751
872
|
async function callTool(name, args) {
|
|
873
|
+
if (name === "list_room_targets") {
|
|
874
|
+
const r = await api("/api/internal/room-targets");
|
|
875
|
+
return { text: JSON.stringify(r), ...r.error ? { isError: true } : {} };
|
|
876
|
+
}
|
|
877
|
+
if (name === "coordinate_bots") {
|
|
878
|
+
const r = await api("/api/internal/coordinate-bots", { method: "POST", body: JSON.stringify({
|
|
879
|
+
groupId: args.group_id,
|
|
880
|
+
botIds: args.bot_ids,
|
|
881
|
+
message: args.message,
|
|
882
|
+
requestKey: args.request_key,
|
|
883
|
+
rework: args.rework
|
|
884
|
+
}) });
|
|
885
|
+
return { text: JSON.stringify(r), ...r.error ? { isError: true } : {} };
|
|
886
|
+
}
|
|
752
887
|
if (name === "list_bots") {
|
|
753
888
|
const r = await api(`/api/internal/agents?self=${encodeURIComponent(BOT_ID)}`);
|
|
754
889
|
const bots = r.bots ?? [];
|
|
755
|
-
if (!bots.length) return { text: "No other bots
|
|
890
|
+
if (!bots.length) return { text: "No other reachable bots yet." };
|
|
756
891
|
const lines = bots.map((b) => {
|
|
757
892
|
const role = b.title ? ` \u2014 ${b.title}` : "";
|
|
758
893
|
const about = b.description ? ` (${String(b.description).slice(0, 120)})` : "";
|
|
759
|
-
|
|
894
|
+
const state = typeof b.statusText === "string" ? b.status === "available" ? "" : b.statusText : b.busy ? "busy" : "";
|
|
895
|
+
const team = typeof b.section === "string" ? `, team: ${peerName(b.section) || "General"}` : "";
|
|
896
|
+
return `- ${b.name}${role}${about} [id: ${b.id}, model: ${b.model}${team}${state ? `, ${state}` : ""}]`;
|
|
760
897
|
});
|
|
761
898
|
return {
|
|
762
|
-
text: `
|
|
899
|
+
text: `Reachable teammates:
|
|
763
900
|
${lines.join("\n")}
|
|
764
901
|
|
|
765
|
-
Assign work with delegate_bot. Use ask_bot only for a short answer you need inline
|
|
902
|
+
${COORDINATING ? "Use coordinate_bots for advice or concrete work, then end your turn. Busy teammates queue and results resume you automatically." : "Assign work with delegate_bot. Use ask_bot only for a short answer you need inline."}`
|
|
766
903
|
};
|
|
767
904
|
}
|
|
768
905
|
if (name === "list_rooms") {
|
|
@@ -880,7 +1017,10 @@ ${r.text ?? "(no reply)"}` };
|
|
|
880
1017
|
if (r.status === "done") return { text: `${who} finished task ${taskId}:
|
|
881
1018
|
${String(r.result || "(no reply text)")}` };
|
|
882
1019
|
if (r.status === "queued") {
|
|
883
|
-
|
|
1020
|
+
const why = r.targetStatus === "waiting-on-user" ? ` ${who} is waiting on the user, so it goes through after they answer.` : r.targetStatus === "working" ? ` ${who} is busy with other work.` : "";
|
|
1021
|
+
const expiresInMs = Number(r.expiresInMs);
|
|
1022
|
+
const expiry = !Number.isFinite(expiresInMs) ? "" : expiresInMs <= 0 ? " It is past its 24-hour limit and will expire the next time it cannot be delivered." : ` It expires if not picked up within ${Math.ceil(expiresInMs / 36e5)} hour${Math.ceil(expiresInMs / 36e5) === 1 ? "" : "s"}.`;
|
|
1023
|
+
return { text: `Task ${taskId} is still queued \u2014 ${who} hasn't picked it up yet${waitMs ? ` after ${timeout}s` : ""}.${why}${expiry} Keep working and check again later.` };
|
|
884
1024
|
}
|
|
885
1025
|
if (r.status === "running") {
|
|
886
1026
|
const elapsedMs = Number.isFinite(r.elapsedMs) ? Number(r.elapsedMs) : 0;
|
|
@@ -932,6 +1072,9 @@ ${lines.join("\n")}` };
|
|
|
932
1072
|
};
|
|
933
1073
|
}
|
|
934
1074
|
const toBotId = typeof args.bot_id === "string" ? args.bot_id.trim() : "";
|
|
1075
|
+
if (COORDINATING && toBotId && toBotId !== BOT_ID) {
|
|
1076
|
+
return { text: "Use coordinate_bots for teammates; start_thread only opens a separate job on yourself.", isError: true };
|
|
1077
|
+
}
|
|
935
1078
|
const folder = typeof args.folder === "string" ? args.folder.trim() : "";
|
|
936
1079
|
const body = { fromBotId: BOT_ID, fromThreadId: THREAD_ID, title, message, depth: DEPTH };
|
|
937
1080
|
if (toBotId) body.toBotId = toBotId;
|
|
@@ -962,6 +1105,21 @@ ${lines.join("\n")}` };
|
|
|
962
1105
|
text: `${opened}${timing}${approval} Its result will be delivered to this conversation automatically (delegation id: ${delegationId || "unknown"}). Acknowledge it, mention it to the person as #${threadTitle}, and finish your turn; do not check or wait for it in this turn.`
|
|
963
1106
|
};
|
|
964
1107
|
}
|
|
1108
|
+
if (name === "list_team_setup") {
|
|
1109
|
+
return { text: JSON.stringify(await api("/api/internal/team-setup-catalog")) };
|
|
1110
|
+
}
|
|
1111
|
+
if (name === "propose_team_setup" || name === "propose_bot_deletion") {
|
|
1112
|
+
const deleting = name === "propose_bot_deletion";
|
|
1113
|
+
const result = await api(deleting ? "/api/internal/bot-deletion-requests" : "/api/internal/team-setup-requests", {
|
|
1114
|
+
method: "POST",
|
|
1115
|
+
body: JSON.stringify({
|
|
1116
|
+
fromBotId: BOT_ID,
|
|
1117
|
+
fromThreadId: THREAD_ID,
|
|
1118
|
+
...deleting ? { targetBotId: args.bot_id, reason: args.reason } : { plan: args }
|
|
1119
|
+
})
|
|
1120
|
+
});
|
|
1121
|
+
return { text: `One review card is visible: ${String(result.title)}. Nothing has been applied. End this turn; the decision and structured result resume you automatically once. Do not ask again, poll, or repeat this proposal.` };
|
|
1122
|
+
}
|
|
965
1123
|
if (name === "create_bot") {
|
|
966
1124
|
const botName = String(args.name ?? "").trim();
|
|
967
1125
|
const role = String(args.role ?? "").trim();
|
|
@@ -984,7 +1142,7 @@ ${lines.join("\n")}` };
|
|
|
984
1142
|
});
|
|
985
1143
|
createdThisTurn += 1;
|
|
986
1144
|
return {
|
|
987
|
-
text: `Created @${r.name ?? botName} in ${r.section ?? "General"} [id: ${r.id}]. Assign work with delegate_bot.`
|
|
1145
|
+
text: `Created @${r.name ?? botName} in ${r.section ?? "General"} [id: ${r.id}]. Assign work with ${COORDINATING ? "coordinate_bots" : "delegate_bot"}.`
|
|
988
1146
|
};
|
|
989
1147
|
}
|
|
990
1148
|
if (name === "create_room") {
|
|
@@ -1342,6 +1500,21 @@ async function handle(msg) {
|
|
|
1342
1500
|
const name = params.name;
|
|
1343
1501
|
if (!AVAILABLE_TOOLS.some((t) => t.name === name)) return rpcErr(id, -32602, `Unknown tool: ${name}`);
|
|
1344
1502
|
try {
|
|
1503
|
+
if (SHARED_COMPUTER_TOOL_NAMES.has(name) && !SHARED_COMPUTERS_ENABLED) {
|
|
1504
|
+
textResult(id, "Computer sharing is turned off in this workspace. There are no shared computers to use.", true);
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
if (name === "list_shared_computers") {
|
|
1508
|
+
textResult(id, JSON.stringify(await api("/api/internal/shared-computers")));
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
if (name === "shared_computer") {
|
|
1512
|
+
const response = await api("/api/internal/shared-computers", { method: "POST", body: JSON.stringify(params.arguments ?? {}) });
|
|
1513
|
+
const result = response.result;
|
|
1514
|
+
if (Array.isArray(result?.content)) ok(id, result);
|
|
1515
|
+
else textResult(id, JSON.stringify(result));
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1345
1518
|
const { text, isError } = await callTool(name, params.arguments ?? {});
|
|
1346
1519
|
textResult(id, text, isError);
|
|
1347
1520
|
} catch (e) {
|