@tritard/waterbrother 0.16.71 → 0.16.72
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 +37 -0
- 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>",
|
|
@@ -1369,6 +1386,24 @@ class TelegramGateway {
|
|
|
1369
1386
|
};
|
|
1370
1387
|
}
|
|
1371
1388
|
|
|
1389
|
+
async maybeAnnounceRoomAgentEvents(message, project) {
|
|
1390
|
+
if (!this.isGroupChat(message) || !project?.enabled) return;
|
|
1391
|
+
if (String(project?.room?.chatId || "").trim() !== String(message?.chat?.id || "").trim()) return;
|
|
1392
|
+
const events = Array.isArray(project.recentEvents) ? project.recentEvents : [];
|
|
1393
|
+
const announced = new Set(Array.isArray(this.state.announcedEvents) ? this.state.announcedEvents : []);
|
|
1394
|
+
const pending = events
|
|
1395
|
+
.filter((event) => String(event?.type || "").trim() === "agent-upsert")
|
|
1396
|
+
.filter((event) => event?.id && !announced.has(String(event.id)))
|
|
1397
|
+
.slice(-3);
|
|
1398
|
+
if (!pending.length) return;
|
|
1399
|
+
for (const event of pending) {
|
|
1400
|
+
await this.sendMarkup(message.chat.id, buildTelegramAgentAnnouncementMarkup(event), message.message_id);
|
|
1401
|
+
announced.add(String(event.id));
|
|
1402
|
+
}
|
|
1403
|
+
this.state.announcedEvents = [...announced].slice(-100);
|
|
1404
|
+
await this.persistState();
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1372
1407
|
buildTrustedRoomIntroMarkup({ project, actor }) {
|
|
1373
1408
|
const participants = listProjectParticipants(project);
|
|
1374
1409
|
const agents = listProjectAgents(project);
|
|
@@ -2451,6 +2486,8 @@ class TelegramGateway {
|
|
|
2451
2486
|
const peer = this.getPeerState(userId);
|
|
2452
2487
|
const linkedSession = await loadSession(sessionId);
|
|
2453
2488
|
const sessionCwd = linkedSession.cwd || this.cwd;
|
|
2489
|
+
const linkedProject = await loadSharedProject(sessionCwd).catch(() => null);
|
|
2490
|
+
await this.maybeAnnounceRoomAgentEvents(message, linkedProject);
|
|
2454
2491
|
|
|
2455
2492
|
if (text === "/about") {
|
|
2456
2493
|
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
|
}
|