@tritard/waterbrother 0.16.71 → 0.16.73
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-state.js +4 -1
- package/src/gateway.js +43 -2
- package/src/shared-project.js +27 -1
package/package.json
CHANGED
package/src/gateway-state.js
CHANGED
|
@@ -23,6 +23,9 @@ function normalizeGatewayState(parsed = {}) {
|
|
|
23
23
|
offset: Number.isFinite(Number(parsed?.offset)) ? Math.max(0, Math.floor(Number(parsed.offset))) : 0,
|
|
24
24
|
peers: parsed?.peers && typeof parsed.peers === "object" ? parsed.peers : {},
|
|
25
25
|
pendingPairings: parsed?.pendingPairings && typeof parsed.pendingPairings === "object" ? parsed.pendingPairings : {},
|
|
26
|
+
announcedEvents: Array.isArray(parsed?.announcedEvents)
|
|
27
|
+
? parsed.announcedEvents.map((value) => String(value || "").trim()).filter(Boolean).slice(-100)
|
|
28
|
+
: [],
|
|
26
29
|
continuations: Object.fromEntries(
|
|
27
30
|
Object.entries(continuations).map(([key, item]) => [
|
|
28
31
|
key,
|
|
@@ -135,7 +138,7 @@ export async function loadGatewayState(serviceId) {
|
|
|
135
138
|
return normalizeGatewayState(JSON.parse(raw));
|
|
136
139
|
} catch (error) {
|
|
137
140
|
if (error?.code === "ENOENT") {
|
|
138
|
-
return { offset: 0, peers: {}, pendingPairings: {}, continuations: {} };
|
|
141
|
+
return { offset: 0, peers: {}, pendingPairings: {}, announcedEvents: [], continuations: {} };
|
|
139
142
|
}
|
|
140
143
|
throw error;
|
|
141
144
|
}
|
package/src/gateway.js
CHANGED
|
@@ -334,6 +334,23 @@ function buildTelegramRoomGuidanceMarkup({ project = null, member = null, execut
|
|
|
334
334
|
].filter(Boolean).join("\n");
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
function buildTelegramAgentAnnouncementMarkup(event = {}) {
|
|
338
|
+
const meta = event?.meta && typeof event.meta === "object" ? event.meta : {};
|
|
339
|
+
const ownerName = String(meta.ownerName || "").trim() || String(meta.ownerId || "").trim() || "unknown";
|
|
340
|
+
const label = String(meta.label || meta.agentId || "").trim() || "terminal";
|
|
341
|
+
const runtime = meta.provider && meta.model ? `${meta.provider}/${meta.model}` : "";
|
|
342
|
+
const title = meta.isNew ? "Roundtable terminal joined" : "Roundtable terminal updated";
|
|
343
|
+
return [
|
|
344
|
+
`<b>${escapeTelegramHtml(title)}</b>`,
|
|
345
|
+
`owner: <code>${escapeTelegramHtml(ownerName)}</code>`,
|
|
346
|
+
`terminal: <code>${escapeTelegramHtml(label)}</code>`,
|
|
347
|
+
`role: <code>${escapeTelegramHtml(String(meta.role || "standby"))}</code>`,
|
|
348
|
+
`surface: <code>${escapeTelegramHtml(String(meta.surface || "unknown"))}</code>`,
|
|
349
|
+
runtime ? `runtime: <code>${escapeTelegramHtml(runtime)}</code>` : "",
|
|
350
|
+
meta.runtimeProfile ? `runtime profile: <code>${escapeTelegramHtml(String(meta.runtimeProfile || ""))}</code>` : ""
|
|
351
|
+
].filter(Boolean).join("\n");
|
|
352
|
+
}
|
|
353
|
+
|
|
337
354
|
function formatGatewaySessionStatus({ sessionId, userId, username, cwd, runtimeProfile, provider, model }) {
|
|
338
355
|
const bits = [
|
|
339
356
|
"<b>Telegram remote session</b>",
|
|
@@ -565,7 +582,9 @@ function parseTelegramAgentIntent(text = "") {
|
|
|
565
582
|
if (/^(how|what|why|when|where|who)\b/.test(lowered)) return null;
|
|
566
583
|
const reviewPatterns = [
|
|
567
584
|
/^(?:have|ask|use)\s+(.+?)['’]s\s+(?:bot|terminal)\s+(?:to\s+)?review(?:\s+this)?\s*$/i,
|
|
568
|
-
/^(?:have|ask|use)\s+(.+?)\s+(?:bot|terminal)\s+(?:to\s+)?review(?:\s+this)?\s*$/i
|
|
585
|
+
/^(?:have|ask|use)\s+(.+?)\s+(?:bot|terminal)\s+(?:to\s+)?review(?:\s+this)?\s*$/i,
|
|
586
|
+
/^(.+?),\s*review(?:\s+this)?\s+with\s+(?:your|ur)\s+(?:bot|terminal)\s*$/i,
|
|
587
|
+
/^(.+?)\s+should\s+review(?:\s+this)?\s+with\s+(?:their|his|her)\s+(?:bot|terminal)\s*$/i
|
|
569
588
|
];
|
|
570
589
|
for (const pattern of reviewPatterns) {
|
|
571
590
|
const match = value.match(pattern);
|
|
@@ -580,7 +599,9 @@ function parseTelegramAgentIntent(text = "") {
|
|
|
580
599
|
/^(?:have|ask|use)\s+(.+?)['’]s\s+(?:bot|terminal)\s+(?:to\s+)?(?:take execution|execute|handle execution|take this)\s*$/i,
|
|
581
600
|
/^(?:have|ask|use)\s+(.+?)\s+(?:bot|terminal)\s+(?:to\s+)?(?:take execution|execute|handle execution|take this)\s*$/i,
|
|
582
601
|
/^(.+?)['’]s\s+(?:bot|terminal)\s+should\s+(?:take execution|execute|handle execution)\s*$/i,
|
|
583
|
-
/^(.+?)\s+(?:bot|terminal)\s+should\s+(?:take execution|execute|handle execution)\s*$/i
|
|
602
|
+
/^(.+?)\s+(?:bot|terminal)\s+should\s+(?:take execution|execute|handle execution)\s*$/i,
|
|
603
|
+
/^(.+?),\s*(?:take execution|execute|handle execution|take this)\s+with\s+(?:your|ur)\s+(?:bot|terminal)\s*$/i,
|
|
604
|
+
/^(.+?)\s+should\s+(?:take execution|execute|handle execution)\s+with\s+(?:their|his|her)\s+(?:bot|terminal)\s*$/i
|
|
584
605
|
];
|
|
585
606
|
for (const pattern of executePatterns) {
|
|
586
607
|
const match = value.match(pattern);
|
|
@@ -1369,6 +1390,24 @@ class TelegramGateway {
|
|
|
1369
1390
|
};
|
|
1370
1391
|
}
|
|
1371
1392
|
|
|
1393
|
+
async maybeAnnounceRoomAgentEvents(message, project) {
|
|
1394
|
+
if (!this.isGroupChat(message) || !project?.enabled) return;
|
|
1395
|
+
if (String(project?.room?.chatId || "").trim() !== String(message?.chat?.id || "").trim()) return;
|
|
1396
|
+
const events = Array.isArray(project.recentEvents) ? project.recentEvents : [];
|
|
1397
|
+
const announced = new Set(Array.isArray(this.state.announcedEvents) ? this.state.announcedEvents : []);
|
|
1398
|
+
const pending = events
|
|
1399
|
+
.filter((event) => String(event?.type || "").trim() === "agent-upsert")
|
|
1400
|
+
.filter((event) => event?.id && !announced.has(String(event.id)))
|
|
1401
|
+
.slice(-3);
|
|
1402
|
+
if (!pending.length) return;
|
|
1403
|
+
for (const event of pending) {
|
|
1404
|
+
await this.sendMarkup(message.chat.id, buildTelegramAgentAnnouncementMarkup(event), message.message_id);
|
|
1405
|
+
announced.add(String(event.id));
|
|
1406
|
+
}
|
|
1407
|
+
this.state.announcedEvents = [...announced].slice(-100);
|
|
1408
|
+
await this.persistState();
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1372
1411
|
buildTrustedRoomIntroMarkup({ project, actor }) {
|
|
1373
1412
|
const participants = listProjectParticipants(project);
|
|
1374
1413
|
const agents = listProjectAgents(project);
|
|
@@ -2451,6 +2490,8 @@ class TelegramGateway {
|
|
|
2451
2490
|
const peer = this.getPeerState(userId);
|
|
2452
2491
|
const linkedSession = await loadSession(sessionId);
|
|
2453
2492
|
const sessionCwd = linkedSession.cwd || this.cwd;
|
|
2493
|
+
const linkedProject = await loadSharedProject(sessionCwd).catch(() => null);
|
|
2494
|
+
await this.maybeAnnounceRoomAgentEvents(message, linkedProject);
|
|
2454
2495
|
|
|
2455
2496
|
if (text === "/about") {
|
|
2456
2497
|
await this.sendMessage(
|
package/src/shared-project.js
CHANGED
|
@@ -71,6 +71,22 @@ function normalizeAgent(agent = {}) {
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
function areAgentsEquivalent(left = {}, right = {}) {
|
|
75
|
+
return [
|
|
76
|
+
"ownerId",
|
|
77
|
+
"ownerName",
|
|
78
|
+
"label",
|
|
79
|
+
"surface",
|
|
80
|
+
"role",
|
|
81
|
+
"provider",
|
|
82
|
+
"model",
|
|
83
|
+
"runtimeProfile",
|
|
84
|
+
"sessionId",
|
|
85
|
+
"cwd",
|
|
86
|
+
"chatId"
|
|
87
|
+
].every((key) => String(left?.[key] || "").trim() === String(right?.[key] || "").trim());
|
|
88
|
+
}
|
|
89
|
+
|
|
74
90
|
function buildProjectParticipants(project = {}) {
|
|
75
91
|
const members = Array.isArray(project.members) ? project.members.map(normalizeMember).filter((item) => item.id) : [];
|
|
76
92
|
const memberIds = new Set(members.map((member) => member.id));
|
|
@@ -615,6 +631,10 @@ export async function upsertSharedAgent(cwd, agent = {}, options = {}) {
|
|
|
615
631
|
}
|
|
616
632
|
const agents = Array.isArray(existing.agents) ? [...existing.agents] : [];
|
|
617
633
|
const index = agents.findIndex((item) => item.id === nextAgent.id);
|
|
634
|
+
const previousAgent = index >= 0 ? normalizeAgent(agents[index]) : null;
|
|
635
|
+
if (previousAgent && areAgentsEquivalent(previousAgent, nextAgent)) {
|
|
636
|
+
return existing;
|
|
637
|
+
}
|
|
618
638
|
if (index >= 0) {
|
|
619
639
|
agents[index] = normalizeAgent({ ...agents[index], ...nextAgent });
|
|
620
640
|
} else {
|
|
@@ -631,8 +651,14 @@ export async function upsertSharedAgent(cwd, agent = {}, options = {}) {
|
|
|
631
651
|
meta: {
|
|
632
652
|
agentId: nextAgent.id,
|
|
633
653
|
ownerId: nextAgent.ownerId,
|
|
654
|
+
ownerName: nextAgent.ownerName,
|
|
655
|
+
label: nextAgent.label,
|
|
634
656
|
role: nextAgent.role,
|
|
635
|
-
surface: nextAgent.surface
|
|
657
|
+
surface: nextAgent.surface,
|
|
658
|
+
provider: nextAgent.provider,
|
|
659
|
+
model: nextAgent.model,
|
|
660
|
+
runtimeProfile: nextAgent.runtimeProfile,
|
|
661
|
+
isNew: !previousAgent
|
|
636
662
|
}
|
|
637
663
|
})).project;
|
|
638
664
|
}
|