@tritard/waterbrother 0.16.68 → 0.16.69
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/package.json +1 -1
- package/src/gateway.js +90 -1
package/package.json
CHANGED
package/src/gateway.js
CHANGED
|
@@ -9,7 +9,7 @@ import { DEFAULT_PENDING_PAIRING_TTL_MINUTES, loadGatewayBridge, loadGatewayStat
|
|
|
9
9
|
import { getGatewayStatus, getChannelSpec } from "./channels.js";
|
|
10
10
|
import { getConfigPath, loadConfigLayers, saveConfig } from "./config.js";
|
|
11
11
|
import { canonicalizeLoosePath } from "./path-utils.js";
|
|
12
|
-
import { acceptSharedInvite, addSharedTask, approveSharedInvite, assignSharedTask, claimSharedOperator, claimSharedTask, commentSharedTask, createSharedInvite, enableSharedProject, getSharedTaskHistory, listSharedEvents, listSharedInvites, listSharedTasks, loadSharedProject, moveSharedTask, rejectSharedInvite, releaseSharedOperator, setSharedRoom, setSharedRoomMode, setSharedRuntimeProfile, removeSharedMember, upsertSharedMember } from "./shared-project.js";
|
|
12
|
+
import { acceptSharedInvite, addSharedTask, approveSharedInvite, assignSharedTask, claimSharedOperator, claimSharedTask, commentSharedTask, createSharedInvite, enableSharedProject, getSharedTaskHistory, listSharedEvents, listSharedInvites, listSharedTasks, loadSharedProject, moveSharedTask, rejectSharedInvite, releaseSharedOperator, setSharedRoom, setSharedRoomMode, setSharedRuntimeProfile, removeSharedMember, upsertSharedAgent, upsertSharedMember } from "./shared-project.js";
|
|
13
13
|
import { buildSelfAwarenessManifest, formatAboutWaterbrother, formatSelfState, resolveLocalConceptQuestion } from "./self-awareness.js";
|
|
14
14
|
|
|
15
15
|
const execFileAsync = promisify(execFile);
|
|
@@ -340,6 +340,23 @@ function chooseExecutorAgent(project, fallbackExecutor = {}) {
|
|
|
340
340
|
return null;
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
function memberRoleWeight(role = "") {
|
|
344
|
+
const normalized = String(role || "").trim().toLowerCase();
|
|
345
|
+
if (normalized === "owner") return 3;
|
|
346
|
+
if (normalized === "editor") return 2;
|
|
347
|
+
if (normalized === "observer") return 1;
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function memberHasAtLeastRole(project, memberId = "", role = "editor") {
|
|
352
|
+
const normalizedId = String(memberId || "").trim();
|
|
353
|
+
if (!normalizedId) return false;
|
|
354
|
+
const member = Array.isArray(project?.members)
|
|
355
|
+
? project.members.find((entry) => String(entry?.id || "").trim() === normalizedId) || null
|
|
356
|
+
: null;
|
|
357
|
+
return memberRoleWeight(member?.role) >= memberRoleWeight(role);
|
|
358
|
+
}
|
|
359
|
+
|
|
343
360
|
function formatAgentLabel(agent = {}) {
|
|
344
361
|
const label = String(agent?.label || agent?.name || "").trim();
|
|
345
362
|
const role = String(agent?.role || "").trim();
|
|
@@ -479,6 +496,33 @@ function parseTelegramPairingIntent(text = "") {
|
|
|
479
496
|
return null;
|
|
480
497
|
}
|
|
481
498
|
|
|
499
|
+
function parseTelegramAgentIntent(text = "") {
|
|
500
|
+
const value = normalizeTelegramProjectIntentText(text);
|
|
501
|
+
const lowered = value.toLowerCase();
|
|
502
|
+
if (!value) return null;
|
|
503
|
+
if (/^(how|what|why|when|where|who)\b/.test(lowered)) return null;
|
|
504
|
+
const roleMatch = lowered.match(/\b(executor|reviewer|standby)\b/);
|
|
505
|
+
const role = roleMatch?.[1] || "";
|
|
506
|
+
if (!role) return null;
|
|
507
|
+
|
|
508
|
+
const patterns = [
|
|
509
|
+
/^(?:have|make|set)\s+(.+?)['’]s\s+(?:bot|terminal)\s+(?:be|as|to)?\s*(?:the\s+)?(executor|reviewer|standby)\s*$/i,
|
|
510
|
+
/^(?:have|make|set)\s+(.+?)\s+(?:bot|terminal)\s+(?:be|as|to)?\s*(?:the\s+)?(executor|reviewer|standby)\s*$/i,
|
|
511
|
+
/^(.+?)['’]s\s+(?:bot|terminal)\s+should\s+(?:be\s+)?(?:the\s+)?(executor|reviewer|standby)\s*$/i,
|
|
512
|
+
/^(.+?)\s+(?:bot|terminal)\s+should\s+(?:be\s+)?(?:the\s+)?(executor|reviewer|standby)\s*$/i
|
|
513
|
+
];
|
|
514
|
+
for (const pattern of patterns) {
|
|
515
|
+
const match = value.match(pattern);
|
|
516
|
+
if (!match) continue;
|
|
517
|
+
const target = String(match[1] || "").trim();
|
|
518
|
+
const nextRole = String(match[2] || role).trim().toLowerCase();
|
|
519
|
+
if (target && nextRole) {
|
|
520
|
+
return { action: "agent-role", target, role: nextRole };
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
|
|
482
526
|
function parseTelegramStateIntent(text = "") {
|
|
483
527
|
const value = normalizeTelegramProjectIntentText(text);
|
|
484
528
|
const lower = value.toLowerCase();
|
|
@@ -1490,6 +1534,41 @@ class TelegramGateway {
|
|
|
1490
1534
|
};
|
|
1491
1535
|
}
|
|
1492
1536
|
|
|
1537
|
+
async handleConversationalAgentIntent(message, sessionId, intent) {
|
|
1538
|
+
const { session, project } = await this.bindSharedRoomForMessage(message, sessionId);
|
|
1539
|
+
if (!project?.enabled) {
|
|
1540
|
+
throw new Error("This project is not shared yet. Use /project share first.");
|
|
1541
|
+
}
|
|
1542
|
+
const actorId = String(message?.from?.id || "").trim();
|
|
1543
|
+
if (!memberHasAtLeastRole(project, actorId, "owner")) {
|
|
1544
|
+
throw new Error("Only a shared-project owner can change terminal roles.");
|
|
1545
|
+
}
|
|
1546
|
+
const actor = this.describeTelegramUser(message?.from || {});
|
|
1547
|
+
const targetAgent = resolveProjectAgent(project, intent.target);
|
|
1548
|
+
if (!targetAgent) {
|
|
1549
|
+
throw new Error(`No terminal found for ${intent.target}. Ask them to connect their Waterbrother bot/terminal first.`);
|
|
1550
|
+
}
|
|
1551
|
+
const nextProject = await upsertSharedAgent(session.cwd || this.cwd, {
|
|
1552
|
+
...targetAgent,
|
|
1553
|
+
role: intent.role
|
|
1554
|
+
}, {
|
|
1555
|
+
actorId,
|
|
1556
|
+
actorName: actor.displayName || actorId
|
|
1557
|
+
});
|
|
1558
|
+
return {
|
|
1559
|
+
kind: "agent",
|
|
1560
|
+
project: nextProject,
|
|
1561
|
+
markup: [
|
|
1562
|
+
"<b>Roundtable terminal updated</b>",
|
|
1563
|
+
`owner: <code>${escapeTelegramHtml(targetAgent.ownerName || targetAgent.ownerId || targetAgent.label || targetAgent.id || "-")}</code>`,
|
|
1564
|
+
`terminal: <code>${escapeTelegramHtml(targetAgent.label || targetAgent.id || "-")}</code>`,
|
|
1565
|
+
`role: <code>${escapeTelegramHtml(intent.role)}</code>`,
|
|
1566
|
+
`runtime: <code>${escapeTelegramHtml(targetAgent.provider && targetAgent.model ? `${targetAgent.provider}/${targetAgent.model}` : "unknown")}</code>`,
|
|
1567
|
+
`project: <code>${escapeTelegramHtml(nextProject.projectName || path.basename(session.cwd || this.cwd))}</code>`
|
|
1568
|
+
].join("\n")
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1493
1572
|
async handleStateIntent(message, sessionId, intent) {
|
|
1494
1573
|
const { session, project } = await this.bindSharedRoomForMessage(message, sessionId);
|
|
1495
1574
|
const cwd = session.cwd || this.cwd;
|
|
@@ -2962,6 +3041,16 @@ Ask them to run <code>/whoami</code> and then <code>/accept-invite ${escapeTeleg
|
|
|
2962
3041
|
}
|
|
2963
3042
|
return;
|
|
2964
3043
|
}
|
|
3044
|
+
const agentIntent = parseTelegramAgentIntent(promptText);
|
|
3045
|
+
if (agentIntent) {
|
|
3046
|
+
try {
|
|
3047
|
+
const result = await this.handleConversationalAgentIntent(message, sessionId, agentIntent);
|
|
3048
|
+
await this.sendMarkup(message.chat.id, result.markup, message.message_id);
|
|
3049
|
+
} catch (error) {
|
|
3050
|
+
await this.sendMessage(message.chat.id, escapeTelegramHtml(error instanceof Error ? error.message : String(error)), message.message_id);
|
|
3051
|
+
}
|
|
3052
|
+
return;
|
|
3053
|
+
}
|
|
2965
3054
|
const memberIntent = parseTelegramMemberIntent(promptText);
|
|
2966
3055
|
if (memberIntent) {
|
|
2967
3056
|
try {
|