talon-agent 3.33.0 → 3.33.2

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 (31) hide show
  1. package/package.json +3 -3
  2. package/src/backend/kilo/factory.ts +39 -119
  3. package/src/backend/kilo/handler/index.ts +1 -11
  4. package/src/backend/kilo/handler/message.ts +20 -317
  5. package/src/backend/kilo/server.ts +55 -272
  6. package/src/backend/kilo/sessions.ts +5 -83
  7. package/src/backend/opencode/factory.ts +41 -118
  8. package/src/backend/opencode/handler/index.ts +1 -11
  9. package/src/backend/opencode/handler/message.ts +20 -321
  10. package/src/backend/opencode/server.ts +57 -217
  11. package/src/backend/opencode/sessions.ts +5 -83
  12. package/src/backend/remote-server/chat-turn.ts +359 -0
  13. package/src/backend/remote-server/factory.ts +150 -0
  14. package/src/backend/remote-server/index.ts +14 -19
  15. package/src/backend/remote-server/server-bindings.ts +232 -0
  16. package/src/backend/{kilo/handler → remote-server}/turn.ts +103 -67
  17. package/src/core/mesh/bridge-links.ts +319 -0
  18. package/src/core/mesh/common.ts +30 -0
  19. package/src/core/mesh/device-files.ts +710 -0
  20. package/src/core/mesh/service.ts +72 -894
  21. package/src/frontend/discord/handlers/access.ts +7 -56
  22. package/src/frontend/discord/handlers/state.ts +15 -8
  23. package/src/frontend/native/server.ts +391 -323
  24. package/src/frontend/shared/access.ts +152 -0
  25. package/src/frontend/telegram/handlers/access.ts +8 -25
  26. package/src/frontend/telegram/handlers/queue.ts +3 -35
  27. package/src/frontend/telegram/handlers/state.ts +15 -8
  28. package/src/backend/kilo/events.ts +0 -60
  29. package/src/backend/kilo/handler/state.ts +0 -9
  30. package/src/backend/opencode/handler/state.ts +0 -9
  31. package/src/backend/opencode/handler/turn.ts +0 -314
@@ -6,19 +6,13 @@
6
6
 
7
7
  import type { Client, Message } from "discord.js";
8
8
  import { ChannelType } from "discord.js";
9
- import { appendDailyLog } from "../../../storage/daily-log.js";
10
- import { log, logWarn, logDebug } from "../../../util/log.js";
9
+ import { logWarn } from "../../../util/log.js";
11
10
  import { escapeMarkdown } from "../formatting.js";
12
11
  import {
13
12
  accessState,
14
- knownDmUsers,
15
- KNOWN_DM_USERS_CAP,
16
- unauthorizedCooldown,
17
- UNAUTHORIZED_COOLDOWN_MS,
18
- MAX_UNAUTHORIZED_COOLDOWNS,
19
- userMessageTimestamps,
20
- RATE_LIMIT_WINDOW_MS,
21
- RATE_LIMIT_MAX_MESSAGES,
13
+ dmUsers,
14
+ unauthorizedNotices,
15
+ rateLimiter,
22
16
  } from "./state.js";
23
17
 
24
18
  export function setAccessControl(cfg: {
@@ -46,21 +40,7 @@ export function trackDmUser(
46
40
  senderName: string,
47
41
  tag?: string,
48
42
  ): void {
49
- if (knownDmUsers.has(senderId)) return;
50
- if (knownDmUsers.size >= KNOWN_DM_USERS_CAP) {
51
- const evictCount = Math.floor(KNOWN_DM_USERS_CAP * 0.1);
52
- const iter = knownDmUsers.values();
53
- for (let i = 0; i < evictCount; i++) {
54
- knownDmUsers.delete(iter.next().value as string);
55
- }
56
- }
57
- knownDmUsers.add(senderId);
58
- const tagStr = tag ? ` (${tag})` : "";
59
- log("users", `New DM user: ${senderName}${tagStr} [id:${senderId}]`);
60
- appendDailyLog(
61
- "System",
62
- `New DM user: ${senderName}${tagStr} [id:${senderId}]`,
63
- );
43
+ dmUsers.track(senderId, senderName, tag);
64
44
  }
65
45
 
66
46
  async function notifyUnauthorized(
@@ -77,13 +57,7 @@ async function notifyUnauthorized(
77
57
  : type === "guild"
78
58
  ? `guild:${guildId}`
79
59
  : `channel:${channelId}`;
80
- const now = Date.now();
81
- const last = unauthorizedCooldown.get(key);
82
- if (last && now - last < UNAUTHORIZED_COOLDOWN_MS) return;
83
- if (unauthorizedCooldown.size >= MAX_UNAUTHORIZED_COOLDOWNS) {
84
- unauthorizedCooldown.clear();
85
- }
86
- unauthorizedCooldown.set(key, now);
60
+ if (!unauthorizedNotices.shouldNotify(key)) return;
87
61
 
88
62
  const senderTag = msg.author.username ? ` (@${msg.author.username})` : "";
89
63
  const senderName = msg.author.globalName || msg.author.username || "User";
@@ -216,28 +190,5 @@ export function shouldHandleInGuild(client: Client, msg: Message): boolean {
216
190
  }
217
191
 
218
192
  export function isUserRateLimited(senderId: string): boolean {
219
- const now = Date.now();
220
- let timestamps = userMessageTimestamps.get(senderId);
221
- if (!timestamps) {
222
- timestamps = [];
223
- userMessageTimestamps.set(senderId, timestamps);
224
- }
225
- while (timestamps.length > 0 && timestamps[0] < now - RATE_LIMIT_WINDOW_MS) {
226
- timestamps.shift();
227
- }
228
- if (timestamps.length >= RATE_LIMIT_MAX_MESSAGES) {
229
- logDebug("bot", `Rate-limited user ${senderId}`);
230
- return true;
231
- }
232
- timestamps.push(now);
233
- if (userMessageTimestamps.size > 5_000) {
234
- const cutoff = now - 10 * 60_000;
235
- for (const [userId, ts] of userMessageTimestamps) {
236
- if (ts.length === 0 || ts[ts.length - 1] < cutoff) {
237
- userMessageTimestamps.delete(userId);
238
- }
239
- if (userMessageTimestamps.size <= 2_500) break;
240
- }
241
- }
242
- return false;
193
+ return rateLimiter.isLimited(senderId);
243
194
  }
@@ -7,6 +7,11 @@
7
7
 
8
8
  import type { TextBasedChannel } from "discord.js";
9
9
  import type { TalonConfig } from "../../../util/config.js";
10
+ import {
11
+ createDmUserTracker,
12
+ createNoticeCooldown,
13
+ createRateLimiter,
14
+ } from "../../shared/access.js";
10
15
 
11
16
  // ── Chat registry: numericChatId → Discord channel info ─────────────────────
12
17
  // The gateway/dispatcher uses numeric chatIds. Action handlers need to map
@@ -49,20 +54,22 @@ export const accessState: { access: AccessConfig } = {
49
54
 
50
55
  // ── First-time DM user tracking ──────────────────────────────────────────────
51
56
 
52
- export const knownDmUsers = new Set<string>();
53
- export const KNOWN_DM_USERS_CAP = 10_000;
57
+ export const dmUsers = createDmUserTracker<string>(10_000);
54
58
 
55
59
  // ── Unauthorized notification cooldown (10 min) ──────────────────────────────
56
60
 
57
- export const unauthorizedCooldown = new Map<string, number>();
58
- export const UNAUTHORIZED_COOLDOWN_MS = 10 * 60 * 1000;
59
- export const MAX_UNAUTHORIZED_COOLDOWNS = 5000;
61
+ export const unauthorizedNotices = createNoticeCooldown({
62
+ ttlMs: 10 * 60 * 1000,
63
+ cap: 5000,
64
+ });
60
65
 
61
66
  // ── Per-user rate limiting ───────────────────────────────────────────────────
62
67
 
63
- export const userMessageTimestamps = new Map<string, number[]>();
64
- export const RATE_LIMIT_WINDOW_MS = 60_000;
65
- export const RATE_LIMIT_MAX_MESSAGES = 15;
68
+ /** 15 messages per minute per user. */
69
+ export const rateLimiter = createRateLimiter<string>({
70
+ windowMs: 60_000,
71
+ maxMessages: 15,
72
+ });
66
73
 
67
74
  // ── Message queue (debounce rapid-fire messages per chat) ────────────────────
68
75