agent-relay 1.3.0 → 1.3.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 (240) hide show
  1. package/.trajectories/active/traj_3yx9dy148mge.json +42 -0
  2. package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.json +49 -0
  3. package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.md +31 -0
  4. package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.json +49 -0
  5. package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.md +31 -0
  6. package/.trajectories/completed/2026-01/traj_6unwwmgyj5sq.json +109 -0
  7. package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.json +49 -0
  8. package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.md +31 -0
  9. package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.json +66 -0
  10. package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.md +36 -0
  11. package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.json +49 -0
  12. package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.md +31 -0
  13. package/.trajectories/completed/2026-01/traj_cpn70dw066nt.json +65 -0
  14. package/.trajectories/completed/2026-01/traj_cpn70dw066nt.md +37 -0
  15. package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.json +36 -0
  16. package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.md +21 -0
  17. package/.trajectories/completed/2026-01/traj_he75f24d1xfm.json +101 -0
  18. package/.trajectories/completed/2026-01/traj_he75f24d1xfm.md +52 -0
  19. package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.json +61 -0
  20. package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.md +36 -0
  21. package/.trajectories/completed/2026-01/traj_oszg9flv74pk.json +73 -0
  22. package/.trajectories/completed/2026-01/traj_oszg9flv74pk.md +41 -0
  23. package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.json +77 -0
  24. package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.md +42 -0
  25. package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.json +109 -0
  26. package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.md +56 -0
  27. package/.trajectories/completed/2026-01/traj_x721m1j9rzup.json +113 -0
  28. package/.trajectories/completed/2026-01/traj_x721m1j9rzup.md +57 -0
  29. package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.json +61 -0
  30. package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.md +36 -0
  31. package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.json +49 -0
  32. package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.md +31 -0
  33. package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.json +49 -0
  34. package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.md +31 -0
  35. package/.trajectories/index.json +140 -1
  36. package/TRAIL_GIT_AUTH_FIX.md +113 -0
  37. package/deploy/workspace/codex.config.toml +1 -1
  38. package/deploy/workspace/entrypoint.sh +20 -79
  39. package/deploy/workspace/gh-relay +156 -0
  40. package/deploy/workspace/git-credential-relay +5 -1
  41. package/dist/bridge/multi-project-client.js +13 -10
  42. package/dist/bridge/spawner.d.ts +2 -0
  43. package/dist/bridge/spawner.js +19 -1
  44. package/dist/bridge/types.d.ts +2 -0
  45. package/dist/cli/index.d.ts +1 -1
  46. package/dist/cli/index.js +115 -69
  47. package/dist/cloud/api/admin.js +16 -3
  48. package/dist/cloud/api/codex-auth-helper.js +28 -8
  49. package/dist/cloud/api/consensus.d.ts +13 -0
  50. package/dist/cloud/api/consensus.js +259 -0
  51. package/dist/cloud/api/daemons.js +205 -1
  52. package/dist/cloud/api/git.js +37 -7
  53. package/dist/cloud/api/onboarding.js +4 -1
  54. package/dist/cloud/api/provider-env.d.ts +5 -0
  55. package/dist/cloud/api/provider-env.js +27 -0
  56. package/dist/cloud/api/providers.js +2 -0
  57. package/dist/cloud/api/test-helpers.js +130 -0
  58. package/dist/cloud/api/workspaces.js +38 -3
  59. package/dist/cloud/db/bulk-ingest.d.ts +88 -0
  60. package/dist/cloud/db/bulk-ingest.js +268 -0
  61. package/dist/cloud/db/drizzle.d.ts +33 -0
  62. package/dist/cloud/db/drizzle.js +174 -2
  63. package/dist/cloud/db/index.d.ts +24 -5
  64. package/dist/cloud/db/index.js +19 -4
  65. package/dist/cloud/db/schema.d.ts +397 -3
  66. package/dist/cloud/db/schema.js +75 -1
  67. package/dist/cloud/provisioner/index.d.ts +8 -0
  68. package/dist/cloud/provisioner/index.js +256 -50
  69. package/dist/cloud/server.js +47 -3
  70. package/dist/cloud/services/index.d.ts +1 -0
  71. package/dist/cloud/services/index.js +2 -0
  72. package/dist/cloud/services/nango.d.ts +3 -4
  73. package/dist/cloud/services/nango.js +11 -33
  74. package/dist/cloud/services/workspace-keepalive.d.ts +76 -0
  75. package/dist/cloud/services/workspace-keepalive.js +234 -0
  76. package/dist/config/relay-config.d.ts +23 -0
  77. package/dist/config/relay-config.js +23 -0
  78. package/dist/daemon/agent-manager.d.ts +20 -1
  79. package/dist/daemon/agent-manager.js +47 -0
  80. package/dist/daemon/agent-registry.js +4 -4
  81. package/dist/daemon/agent-signing.d.ts +158 -0
  82. package/dist/daemon/agent-signing.js +523 -0
  83. package/dist/daemon/api.js +18 -1
  84. package/dist/daemon/cli-auth.d.ts +4 -1
  85. package/dist/daemon/cli-auth.js +55 -11
  86. package/dist/daemon/cloud-sync.d.ts +47 -1
  87. package/dist/daemon/cloud-sync.js +152 -3
  88. package/dist/daemon/connection.d.ts +28 -0
  89. package/dist/daemon/connection.js +98 -15
  90. package/dist/daemon/consensus-integration.d.ts +167 -0
  91. package/dist/daemon/consensus-integration.js +371 -0
  92. package/dist/daemon/consensus.d.ts +271 -0
  93. package/dist/daemon/consensus.js +632 -0
  94. package/dist/daemon/delivery-tracker.d.ts +34 -0
  95. package/dist/daemon/delivery-tracker.js +104 -0
  96. package/dist/daemon/enhanced-features.d.ts +118 -0
  97. package/dist/daemon/enhanced-features.js +178 -0
  98. package/dist/daemon/index.d.ts +4 -0
  99. package/dist/daemon/index.js +5 -0
  100. package/dist/daemon/rate-limiter.d.ts +68 -0
  101. package/dist/daemon/rate-limiter.js +130 -0
  102. package/dist/daemon/router.d.ts +18 -11
  103. package/dist/daemon/router.js +55 -111
  104. package/dist/daemon/server.d.ts +13 -1
  105. package/dist/daemon/server.js +71 -9
  106. package/dist/daemon/sync-queue.d.ts +116 -0
  107. package/dist/daemon/sync-queue.js +361 -0
  108. package/dist/health-worker-manager.d.ts +62 -0
  109. package/dist/health-worker-manager.js +144 -0
  110. package/dist/health-worker.d.ts +9 -0
  111. package/dist/health-worker.js +79 -0
  112. package/dist/index.d.ts +2 -1
  113. package/dist/index.js +5 -1
  114. package/dist/memory/context-compaction.d.ts +156 -0
  115. package/dist/memory/context-compaction.js +453 -0
  116. package/dist/memory/index.d.ts +1 -0
  117. package/dist/memory/index.js +1 -0
  118. package/dist/protocol/channels.js +4 -4
  119. package/dist/protocol/framing.d.ts +72 -10
  120. package/dist/protocol/framing.js +194 -25
  121. package/dist/storage/adapter.d.ts +8 -1
  122. package/dist/storage/adapter.js +11 -0
  123. package/dist/storage/batched-sqlite-adapter.d.ts +71 -0
  124. package/dist/storage/batched-sqlite-adapter.js +183 -0
  125. package/dist/storage/dead-letter-queue.d.ts +196 -0
  126. package/dist/storage/dead-letter-queue.js +427 -0
  127. package/dist/storage/dlq-adapter.d.ts +195 -0
  128. package/dist/storage/dlq-adapter.js +664 -0
  129. package/dist/trajectory/config.d.ts +32 -14
  130. package/dist/trajectory/config.js +38 -16
  131. package/dist/trajectory/integration.js +217 -64
  132. package/dist/utils/git-remote.d.ts +47 -0
  133. package/dist/utils/git-remote.js +125 -0
  134. package/dist/utils/id-generator.d.ts +35 -0
  135. package/dist/utils/id-generator.js +60 -0
  136. package/dist/utils/index.d.ts +1 -0
  137. package/dist/utils/index.js +1 -0
  138. package/dist/utils/precompiled-patterns.d.ts +110 -0
  139. package/dist/utils/precompiled-patterns.js +322 -0
  140. package/dist/wrapper/auth-detection.js +1 -1
  141. package/dist/wrapper/base-wrapper.d.ts +36 -0
  142. package/dist/wrapper/base-wrapper.js +48 -2
  143. package/dist/wrapper/client.d.ts +14 -4
  144. package/dist/wrapper/client.js +84 -31
  145. package/dist/wrapper/idle-detector.d.ts +102 -0
  146. package/dist/wrapper/idle-detector.js +279 -0
  147. package/dist/wrapper/parser.d.ts +4 -0
  148. package/dist/wrapper/parser.js +19 -1
  149. package/dist/wrapper/pty-wrapper.d.ts +7 -1
  150. package/dist/wrapper/pty-wrapper.js +51 -27
  151. package/dist/wrapper/tmux-wrapper.d.ts +12 -1
  152. package/dist/wrapper/tmux-wrapper.js +65 -17
  153. package/package.json +5 -5
  154. package/scripts/run-migrations.js +43 -0
  155. package/scripts/verify-schema.js +134 -0
  156. package/tests/benchmarks/protocol.bench.ts +310 -0
  157. package/dist/dashboard/out/404.html +0 -1
  158. package/dist/dashboard/out/_next/static/T1tgCqVWHFIkV7ClEtzD7/_buildManifest.js +0 -1
  159. package/dist/dashboard/out/_next/static/T1tgCqVWHFIkV7ClEtzD7/_ssgManifest.js +0 -1
  160. package/dist/dashboard/out/_next/static/chunks/116-2502180def231162.js +0 -1
  161. package/dist/dashboard/out/_next/static/chunks/117-f7b8ab0809342e77.js +0 -2
  162. package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +0 -1
  163. package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +0 -9
  164. package/dist/dashboard/out/_next/static/chunks/648-5cc6e1921389a58a.js +0 -1
  165. package/dist/dashboard/out/_next/static/chunks/766-b54f0853794b78c3.js +0 -1
  166. package/dist/dashboard/out/_next/static/chunks/83-b51836037078006c.js +0 -1
  167. package/dist/dashboard/out/_next/static/chunks/891-6cd50de1224f70bb.js +0 -1
  168. package/dist/dashboard/out/_next/static/chunks/899-bb19a9b3d9b39ea6.js +0 -1
  169. package/dist/dashboard/out/_next/static/chunks/app/_not-found/page-53b8a69f76db17d0.js +0 -1
  170. package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-8939b0fc700f7eca.js +0 -1
  171. package/dist/dashboard/out/_next/static/chunks/app/app/page-5af1b6b439858aa6.js +0 -1
  172. package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-f45ecbc3e06134fc.js +0 -1
  173. package/dist/dashboard/out/_next/static/chunks/app/history/page-8c8bed33beb2bf1c.js +0 -1
  174. package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +0 -1
  175. package/dist/dashboard/out/_next/static/chunks/app/login/page-16f3b49e55b1e0ed.js +0 -1
  176. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-ac39dc0cc3c26fa7.js +0 -1
  177. package/dist/dashboard/out/_next/static/chunks/app/page-4a5938c18a11a654.js +0 -1
  178. package/dist/dashboard/out/_next/static/chunks/app/pricing/page-982a7000fee44014.js +0 -1
  179. package/dist/dashboard/out/_next/static/chunks/app/providers/page-ac3a6ac433fd6001.js +0 -1
  180. package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-09f9caae98a18c09.js +0 -1
  181. package/dist/dashboard/out/_next/static/chunks/app/signup/page-547dd0ca55ecd0ba.js +0 -1
  182. package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +0 -18
  183. package/dist/dashboard/out/_next/static/chunks/fd9d1056-609918ca7b6280bb.js +0 -1
  184. package/dist/dashboard/out/_next/static/chunks/framework-f66176bb897dc684.js +0 -1
  185. package/dist/dashboard/out/_next/static/chunks/main-2ee6beb2ae96d210.js +0 -1
  186. package/dist/dashboard/out/_next/static/chunks/main-app-5d692157a8eb1fd9.js +0 -1
  187. package/dist/dashboard/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
  188. package/dist/dashboard/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
  189. package/dist/dashboard/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  190. package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +0 -1
  191. package/dist/dashboard/out/_next/static/css/85d2af9c7ac74d62.css +0 -1
  192. package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.css +0 -1
  193. package/dist/dashboard/out/alt-logos/agent-relay-logo-128.png +0 -0
  194. package/dist/dashboard/out/alt-logos/agent-relay-logo-256.png +0 -0
  195. package/dist/dashboard/out/alt-logos/agent-relay-logo-32.png +0 -0
  196. package/dist/dashboard/out/alt-logos/agent-relay-logo-512.png +0 -0
  197. package/dist/dashboard/out/alt-logos/agent-relay-logo-64.png +0 -0
  198. package/dist/dashboard/out/alt-logos/agent-relay-logo.svg +0 -45
  199. package/dist/dashboard/out/alt-logos/logo.svg +0 -38
  200. package/dist/dashboard/out/alt-logos/monogram-logo-128.png +0 -0
  201. package/dist/dashboard/out/alt-logos/monogram-logo-256.png +0 -0
  202. package/dist/dashboard/out/alt-logos/monogram-logo-32.png +0 -0
  203. package/dist/dashboard/out/alt-logos/monogram-logo-512.png +0 -0
  204. package/dist/dashboard/out/alt-logos/monogram-logo-64.png +0 -0
  205. package/dist/dashboard/out/alt-logos/monogram-logo.svg +0 -38
  206. package/dist/dashboard/out/app/onboarding.html +0 -1
  207. package/dist/dashboard/out/app/onboarding.txt +0 -7
  208. package/dist/dashboard/out/app.html +0 -1
  209. package/dist/dashboard/out/app.txt +0 -7
  210. package/dist/dashboard/out/apple-icon.png +0 -0
  211. package/dist/dashboard/out/connect-repos.html +0 -1
  212. package/dist/dashboard/out/connect-repos.txt +0 -7
  213. package/dist/dashboard/out/history.html +0 -1
  214. package/dist/dashboard/out/history.txt +0 -7
  215. package/dist/dashboard/out/index.html +0 -1
  216. package/dist/dashboard/out/index.txt +0 -7
  217. package/dist/dashboard/out/login.html +0 -6
  218. package/dist/dashboard/out/login.txt +0 -7
  219. package/dist/dashboard/out/metrics.html +0 -1
  220. package/dist/dashboard/out/metrics.txt +0 -7
  221. package/dist/dashboard/out/pricing.html +0 -13
  222. package/dist/dashboard/out/pricing.txt +0 -7
  223. package/dist/dashboard/out/providers/setup/claude.html +0 -1
  224. package/dist/dashboard/out/providers/setup/claude.txt +0 -8
  225. package/dist/dashboard/out/providers/setup/codex.html +0 -1
  226. package/dist/dashboard/out/providers/setup/codex.txt +0 -8
  227. package/dist/dashboard/out/providers.html +0 -1
  228. package/dist/dashboard/out/providers.txt +0 -7
  229. package/dist/dashboard/out/signup.html +0 -6
  230. package/dist/dashboard/out/signup.txt +0 -7
  231. package/dist/dashboard-server/metrics.d.ts +0 -105
  232. package/dist/dashboard-server/metrics.js +0 -193
  233. package/dist/dashboard-server/needs-attention.d.ts +0 -24
  234. package/dist/dashboard-server/needs-attention.js +0 -78
  235. package/dist/dashboard-server/server.d.ts +0 -15
  236. package/dist/dashboard-server/server.js +0 -3776
  237. package/dist/dashboard-server/start.d.ts +0 -6
  238. package/dist/dashboard-server/start.js +0 -13
  239. package/dist/dashboard-server/user-bridge.d.ts +0 -103
  240. package/dist/dashboard-server/user-bridge.js +0 -189
@@ -0,0 +1,104 @@
1
+ import { routerLog } from '../utils/logger.js';
2
+ export const DEFAULT_DELIVERY_OPTIONS = {
3
+ ackTimeoutMs: 5000,
4
+ maxAttempts: 5,
5
+ deliveryTtlMs: 60_000,
6
+ };
7
+ export class DeliveryTracker {
8
+ pendingDeliveries = new Map();
9
+ deliveryOptions;
10
+ storage;
11
+ getConnection;
12
+ constructor(options) {
13
+ this.storage = options.storage;
14
+ this.deliveryOptions = { ...DEFAULT_DELIVERY_OPTIONS, ...options.delivery };
15
+ this.getConnection = options.getConnection;
16
+ }
17
+ get pendingCount() {
18
+ return this.pendingDeliveries.size;
19
+ }
20
+ track(target, deliver) {
21
+ const pending = {
22
+ envelope: deliver,
23
+ connectionId: target.id,
24
+ attempts: 1,
25
+ firstSentAt: Date.now(),
26
+ };
27
+ pending.timer = this.scheduleRetry(deliver.id);
28
+ this.pendingDeliveries.set(deliver.id, pending);
29
+ }
30
+ handleAck(connectionId, ackId) {
31
+ const pending = this.pendingDeliveries.get(ackId);
32
+ if (!pending)
33
+ return;
34
+ // Only accept ACKs from the same connection that received the deliver
35
+ if (pending.connectionId !== connectionId)
36
+ return;
37
+ if (pending.timer) {
38
+ clearTimeout(pending.timer);
39
+ }
40
+ this.pendingDeliveries.delete(ackId);
41
+ const statusUpdate = this.storage?.updateMessageStatus?.(ackId, 'acked');
42
+ if (statusUpdate instanceof Promise) {
43
+ statusUpdate.catch(err => {
44
+ routerLog.error('Failed to record ACK status', { error: String(err) });
45
+ });
46
+ }
47
+ routerLog.debug(`ACK received for ${ackId}`);
48
+ }
49
+ clearPendingForConnection(connectionId) {
50
+ for (const [id, pending] of this.pendingDeliveries.entries()) {
51
+ if (pending.connectionId === connectionId) {
52
+ if (pending.timer)
53
+ clearTimeout(pending.timer);
54
+ this.pendingDeliveries.delete(id);
55
+ }
56
+ }
57
+ }
58
+ scheduleRetry(deliverId) {
59
+ return setTimeout(() => {
60
+ const pending = this.pendingDeliveries.get(deliverId);
61
+ if (!pending)
62
+ return;
63
+ const now = Date.now();
64
+ const elapsed = now - pending.firstSentAt;
65
+ if (elapsed > this.deliveryOptions.deliveryTtlMs) {
66
+ routerLog.warn(`Dropping ${deliverId} after TTL`, { ttlMs: this.deliveryOptions.deliveryTtlMs });
67
+ this.pendingDeliveries.delete(deliverId);
68
+ this.markFailed(deliverId);
69
+ return;
70
+ }
71
+ if (pending.attempts >= this.deliveryOptions.maxAttempts) {
72
+ routerLog.warn(`Dropping ${deliverId} after max attempts`, { maxAttempts: this.deliveryOptions.maxAttempts });
73
+ this.pendingDeliveries.delete(deliverId);
74
+ this.markFailed(deliverId);
75
+ return;
76
+ }
77
+ const target = this.getConnection(pending.connectionId);
78
+ if (!target) {
79
+ routerLog.warn(`Dropping ${deliverId} - connection unavailable`);
80
+ this.pendingDeliveries.delete(deliverId);
81
+ this.markFailed(deliverId);
82
+ return;
83
+ }
84
+ pending.attempts++;
85
+ const sent = target.send(pending.envelope);
86
+ if (!sent) {
87
+ routerLog.warn(`Retry failed for ${deliverId}`, { attempt: pending.attempts });
88
+ }
89
+ else {
90
+ routerLog.debug(`Retried ${deliverId}`, { attempt: pending.attempts });
91
+ }
92
+ pending.timer = this.scheduleRetry(deliverId);
93
+ }, this.deliveryOptions.ackTimeoutMs);
94
+ }
95
+ markFailed(deliverId) {
96
+ const statusUpdate = this.storage?.updateMessageStatus?.(deliverId, 'failed');
97
+ if (statusUpdate instanceof Promise) {
98
+ statusUpdate.catch(err => {
99
+ routerLog.error(`Failed to update status for ${deliverId}`, { error: String(err) });
100
+ });
101
+ }
102
+ }
103
+ }
104
+ //# sourceMappingURL=delivery-tracker.js.map
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Enhanced Features Integration Module
3
+ *
4
+ * Wires together the new performance and reliability features:
5
+ * - Precompiled regex patterns
6
+ * - Agent authentication with signing
7
+ * - Dead Letter Queue
8
+ * - Context compaction
9
+ * - Consensus mechanism
10
+ *
11
+ * This module provides a unified interface for integrating
12
+ * these features into the existing daemon and router.
13
+ */
14
+ import type { Database as BetterSqlite3Database } from 'better-sqlite3';
15
+ import type { Pool as PgPool } from 'pg';
16
+ import { getCompiledPatterns, isInstructionalTextFast, isPlaceholderTargetFast, stripAnsiFast, StaticPatterns } from '../utils/precompiled-patterns.js';
17
+ import { AgentSigningManager, loadSigningConfig, attachSignature, extractSignature, type AgentSigningConfig, type SignedMessage } from './agent-signing.js';
18
+ import { SQLiteDLQAdapter, PostgresDLQAdapter, InMemoryDLQAdapter, createDLQAdapter, DEFAULT_DLQ_CONFIG, type DLQStorageAdapter, type DLQConfig, type DeadLetter, type DLQStats } from '../storage/dlq-adapter.js';
19
+ import { ContextCompactor, createContextCompactor, estimateTokens, estimateContextTokens, formatTokenCount, type Message, type CompactionConfig, type CompactionResult } from '../memory/context-compaction.js';
20
+ import { ConsensusEngine, createConsensusEngine, formatProposalMessage, parseVoteCommand, formatResultMessage, type Proposal, type ConsensusResult, type ConsensusConfig, type VoteValue } from './consensus.js';
21
+ export interface EnhancedFeaturesConfig {
22
+ /** Pattern matching configuration */
23
+ patterns?: {
24
+ relayPrefix?: string;
25
+ thinkingPrefix?: string;
26
+ };
27
+ /** Signing configuration (or path to config file) */
28
+ signing?: Partial<AgentSigningConfig> | string;
29
+ /** DLQ configuration */
30
+ dlq?: Partial<DLQConfig> & {
31
+ /** Storage type */
32
+ type?: 'sqlite' | 'postgres' | 'memory';
33
+ /** SQLite database (if type is sqlite) */
34
+ sqlite?: BetterSqlite3Database;
35
+ /** PostgreSQL pool (if type is postgres) */
36
+ postgres?: PgPool;
37
+ };
38
+ /** Context compaction configuration */
39
+ compaction?: Partial<CompactionConfig>;
40
+ /** Consensus configuration */
41
+ consensus?: Partial<ConsensusConfig>;
42
+ }
43
+ export interface EnhancedFeatures {
44
+ /** Precompiled pattern matching */
45
+ patterns: {
46
+ compiled: ReturnType<typeof getCompiledPatterns>;
47
+ isInstructionalText: typeof isInstructionalTextFast;
48
+ isPlaceholderTarget: typeof isPlaceholderTargetFast;
49
+ stripAnsi: typeof stripAnsiFast;
50
+ static: typeof StaticPatterns;
51
+ };
52
+ /** Agent signing manager */
53
+ signing: AgentSigningManager;
54
+ /** Dead Letter Queue */
55
+ dlq: DLQStorageAdapter;
56
+ /** Context compactor */
57
+ compaction: ContextCompactor;
58
+ /** Consensus engine */
59
+ consensus: ConsensusEngine;
60
+ /** Cleanup function */
61
+ cleanup: () => Promise<void>;
62
+ }
63
+ /**
64
+ * Initialize all enhanced features.
65
+ */
66
+ export declare function initEnhancedFeatures(config?: EnhancedFeaturesConfig): Promise<EnhancedFeatures>;
67
+ /**
68
+ * Handle failed message delivery by adding to DLQ.
69
+ */
70
+ export declare function handleDeliveryFailure(dlq: DLQStorageAdapter, envelope: {
71
+ id: string;
72
+ from: string;
73
+ to: string;
74
+ topic?: string;
75
+ payload: {
76
+ kind: string;
77
+ body: string;
78
+ data?: Record<string, unknown>;
79
+ thread?: string;
80
+ };
81
+ ts: number;
82
+ }, reason: 'max_retries_exceeded' | 'ttl_expired' | 'connection_lost' | 'target_not_found', attemptCount: number, errorMessage?: string): Promise<DeadLetter>;
83
+ /**
84
+ * Sign an outgoing envelope if signing is enabled.
85
+ */
86
+ export declare function signEnvelope<T extends Record<string, unknown>>(signing: AgentSigningManager, envelope: T, agentName: string): T;
87
+ /**
88
+ * Verify an incoming envelope signature.
89
+ */
90
+ export declare function verifyEnvelope(signing: AgentSigningManager, envelope: Record<string, unknown>): {
91
+ valid: boolean;
92
+ error?: string;
93
+ };
94
+ /**
95
+ * Process a potential vote command from a relay message.
96
+ */
97
+ export declare function processVoteMessage(consensus: ConsensusEngine, from: string, body: string): {
98
+ processed: boolean;
99
+ result?: ReturnType<ConsensusEngine['vote']>;
100
+ };
101
+ /**
102
+ * Create a proposal and format it for broadcast.
103
+ */
104
+ export declare function createAndBroadcastProposal(consensus: ConsensusEngine, options: Parameters<ConsensusEngine['createProposal']>[0]): {
105
+ proposal: Proposal;
106
+ message: string;
107
+ };
108
+ /**
109
+ * Check if context needs compaction and compact if necessary.
110
+ */
111
+ export declare function manageContext(compactor: ContextCompactor, messages: Message[]): {
112
+ messages: Message[];
113
+ compacted: boolean;
114
+ result?: CompactionResult;
115
+ budget: ReturnType<ContextCompactor['getTokenBudget']>;
116
+ };
117
+ export { getCompiledPatterns, isInstructionalTextFast, isPlaceholderTargetFast, stripAnsiFast, StaticPatterns, AgentSigningManager, loadSigningConfig, attachSignature, extractSignature, type AgentSigningConfig, type SignedMessage, SQLiteDLQAdapter, PostgresDLQAdapter, InMemoryDLQAdapter, createDLQAdapter, DEFAULT_DLQ_CONFIG, type DLQStorageAdapter, type DLQConfig, type DeadLetter, type DLQStats, ContextCompactor, createContextCompactor, estimateTokens, estimateContextTokens, formatTokenCount, type Message, type CompactionConfig, type CompactionResult, ConsensusEngine, createConsensusEngine, formatProposalMessage, parseVoteCommand, formatResultMessage, type Proposal, type ConsensusResult, type ConsensusConfig, type VoteValue, };
118
+ //# sourceMappingURL=enhanced-features.d.ts.map
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Enhanced Features Integration Module
3
+ *
4
+ * Wires together the new performance and reliability features:
5
+ * - Precompiled regex patterns
6
+ * - Agent authentication with signing
7
+ * - Dead Letter Queue
8
+ * - Context compaction
9
+ * - Consensus mechanism
10
+ *
11
+ * This module provides a unified interface for integrating
12
+ * these features into the existing daemon and router.
13
+ */
14
+ // Import new modules
15
+ import { getCompiledPatterns, isInstructionalTextFast, isPlaceholderTargetFast, stripAnsiFast, StaticPatterns, } from '../utils/precompiled-patterns.js';
16
+ import { AgentSigningManager, loadSigningConfig, attachSignature, extractSignature, } from './agent-signing.js';
17
+ import { SQLiteDLQAdapter, PostgresDLQAdapter, InMemoryDLQAdapter, createDLQAdapter, DEFAULT_DLQ_CONFIG, } from '../storage/dlq-adapter.js';
18
+ import { ContextCompactor, createContextCompactor, estimateTokens, estimateContextTokens, formatTokenCount, } from '../memory/context-compaction.js';
19
+ import { ConsensusEngine, createConsensusEngine, formatProposalMessage, parseVoteCommand, formatResultMessage, } from './consensus.js';
20
+ // =============================================================================
21
+ // Factory Function
22
+ // =============================================================================
23
+ /**
24
+ * Initialize all enhanced features.
25
+ */
26
+ export async function initEnhancedFeatures(config = {}) {
27
+ // Initialize pattern matching
28
+ const patterns = {
29
+ compiled: getCompiledPatterns(config.patterns?.relayPrefix ?? '->relay:', config.patterns?.thinkingPrefix ?? '->thinking:'),
30
+ isInstructionalText: isInstructionalTextFast,
31
+ isPlaceholderTarget: isPlaceholderTargetFast,
32
+ stripAnsi: stripAnsiFast,
33
+ static: StaticPatterns,
34
+ };
35
+ // Initialize signing
36
+ const signingConfig = typeof config.signing === 'string'
37
+ ? loadSigningConfig(config.signing)
38
+ : { ...loadSigningConfig(), ...config.signing };
39
+ const signing = new AgentSigningManager(signingConfig);
40
+ // Initialize DLQ
41
+ let dlq;
42
+ const dlqConfig = config.dlq ?? {};
43
+ if (dlqConfig.type === 'postgres' && dlqConfig.postgres) {
44
+ dlq = new PostgresDLQAdapter(dlqConfig.postgres);
45
+ }
46
+ else if (dlqConfig.type === 'sqlite' && dlqConfig.sqlite) {
47
+ dlq = new SQLiteDLQAdapter(dlqConfig.sqlite);
48
+ }
49
+ else if (dlqConfig.type === 'memory' || (!dlqConfig.sqlite && !dlqConfig.postgres)) {
50
+ dlq = new InMemoryDLQAdapter();
51
+ }
52
+ else {
53
+ dlq = new InMemoryDLQAdapter();
54
+ }
55
+ await dlq.init();
56
+ // Initialize context compaction
57
+ const compaction = createContextCompactor(config.compaction);
58
+ // Initialize consensus
59
+ const consensus = createConsensusEngine(config.consensus);
60
+ // Cleanup function
61
+ const cleanup = async () => {
62
+ await dlq.close();
63
+ consensus.cleanup();
64
+ };
65
+ return {
66
+ patterns,
67
+ signing,
68
+ dlq,
69
+ compaction,
70
+ consensus,
71
+ cleanup,
72
+ };
73
+ }
74
+ // =============================================================================
75
+ // Router Integration Helpers
76
+ // =============================================================================
77
+ /**
78
+ * Handle failed message delivery by adding to DLQ.
79
+ */
80
+ export async function handleDeliveryFailure(dlq, envelope, reason, attemptCount, errorMessage) {
81
+ return dlq.add(envelope.id, {
82
+ from: envelope.from,
83
+ to: envelope.to,
84
+ topic: envelope.topic,
85
+ kind: envelope.payload.kind,
86
+ body: envelope.payload.body,
87
+ data: envelope.payload.data,
88
+ thread: envelope.payload.thread,
89
+ ts: envelope.ts,
90
+ }, reason, attemptCount, errorMessage);
91
+ }
92
+ /**
93
+ * Sign an outgoing envelope if signing is enabled.
94
+ */
95
+ export function signEnvelope(signing, envelope, agentName) {
96
+ if (!signing.enabled) {
97
+ return envelope;
98
+ }
99
+ const content = JSON.stringify(envelope);
100
+ const signed = signing.sign(agentName, content);
101
+ if (!signed) {
102
+ return envelope;
103
+ }
104
+ return attachSignature(envelope, signed);
105
+ }
106
+ /**
107
+ * Verify an incoming envelope signature.
108
+ */
109
+ export function verifyEnvelope(signing, envelope) {
110
+ if (!signing.enabled) {
111
+ return { valid: true };
112
+ }
113
+ const signed = extractSignature(envelope);
114
+ if (!signed) {
115
+ const from = typeof envelope.from === 'string' ? envelope.from : 'unknown';
116
+ if (signing.requiresVerification(from)) {
117
+ return { valid: false, error: 'Missing signature' };
118
+ }
119
+ return { valid: true };
120
+ }
121
+ return signing.verify(signed);
122
+ }
123
+ // =============================================================================
124
+ // Consensus Integration Helpers
125
+ // =============================================================================
126
+ /**
127
+ * Process a potential vote command from a relay message.
128
+ */
129
+ export function processVoteMessage(consensus, from, body) {
130
+ const vote = parseVoteCommand(body);
131
+ if (!vote) {
132
+ return { processed: false };
133
+ }
134
+ const result = consensus.vote(vote.proposalId, from, vote.value, vote.reason);
135
+ return { processed: true, result };
136
+ }
137
+ /**
138
+ * Create a proposal and format it for broadcast.
139
+ */
140
+ export function createAndBroadcastProposal(consensus, options) {
141
+ const proposal = consensus.createProposal(options);
142
+ const message = formatProposalMessage(proposal);
143
+ return { proposal, message };
144
+ }
145
+ // =============================================================================
146
+ // Context Management Helpers
147
+ // =============================================================================
148
+ /**
149
+ * Check if context needs compaction and compact if necessary.
150
+ */
151
+ export function manageContext(compactor, messages) {
152
+ const budget = compactor.getTokenBudget(messages);
153
+ if (!compactor.needsCompaction(messages)) {
154
+ return { messages, compacted: false, budget };
155
+ }
156
+ const result = compactor.compact(messages);
157
+ return {
158
+ messages: result.messages,
159
+ compacted: true,
160
+ result,
161
+ budget: compactor.getTokenBudget(result.messages),
162
+ };
163
+ }
164
+ // =============================================================================
165
+ // Re-exports for convenience
166
+ // =============================================================================
167
+ export {
168
+ // Patterns
169
+ getCompiledPatterns, isInstructionalTextFast, isPlaceholderTargetFast, stripAnsiFast, StaticPatterns,
170
+ // Signing
171
+ AgentSigningManager, loadSigningConfig, attachSignature, extractSignature,
172
+ // DLQ
173
+ SQLiteDLQAdapter, PostgresDLQAdapter, InMemoryDLQAdapter, createDLQAdapter, DEFAULT_DLQ_CONFIG,
174
+ // Compaction
175
+ ContextCompactor, createContextCompactor, estimateTokens, estimateContextTokens, formatTokenCount,
176
+ // Consensus
177
+ ConsensusEngine, createConsensusEngine, formatProposalMessage, parseVoteCommand, formatResultMessage, };
178
+ //# sourceMappingURL=enhanced-features.js.map
@@ -7,4 +7,8 @@ export * from './types.js';
7
7
  export * from './orchestrator.js';
8
8
  export * from './workspace-manager.js';
9
9
  export * from './agent-manager.js';
10
+ export * from './enhanced-features.js';
11
+ export * from './agent-signing.js';
12
+ export * from './consensus.js';
13
+ export * from './consensus-integration.js';
10
14
  //# sourceMappingURL=index.d.ts.map
@@ -9,4 +9,9 @@ export * from './types.js';
9
9
  export * from './orchestrator.js';
10
10
  export * from './workspace-manager.js';
11
11
  export * from './agent-manager.js';
12
+ // Enhanced features (performance, reliability, coordination)
13
+ export * from './enhanced-features.js';
14
+ export * from './agent-signing.js';
15
+ export * from './consensus.js';
16
+ export * from './consensus-integration.js';
12
17
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Token bucket rate limiter for per-agent message throttling.
3
+ *
4
+ * Uses a token bucket algorithm that allows bursting while enforcing
5
+ * an average rate limit. Generous defaults to avoid blocking legitimate
6
+ * agent communication.
7
+ */
8
+ export interface RateLimitConfig {
9
+ /** Messages allowed per second (sustained rate). Default: 500 */
10
+ messagesPerSecond: number;
11
+ /** Maximum burst size (tokens in bucket). Default: 1000 */
12
+ burstSize: number;
13
+ /** Whether to log rate limit events. Default: true */
14
+ logEvents: boolean;
15
+ }
16
+ export declare const DEFAULT_RATE_LIMIT_CONFIG: RateLimitConfig;
17
+ export interface RateLimitResult {
18
+ allowed: boolean;
19
+ remainingTokens: number;
20
+ retryAfterMs?: number;
21
+ }
22
+ export declare class RateLimiter {
23
+ private buckets;
24
+ private config;
25
+ constructor(config?: Partial<RateLimitConfig>);
26
+ /**
27
+ * Try to acquire a token for the given agent.
28
+ * Returns true if the message should be allowed, false if rate limited.
29
+ */
30
+ tryAcquire(agentName: string): boolean;
31
+ /**
32
+ * Try to acquire a token with detailed result.
33
+ */
34
+ tryAcquireWithResult(agentName: string): RateLimitResult;
35
+ /**
36
+ * Get remaining tokens for an agent (for monitoring/debugging).
37
+ */
38
+ getRemainingTokens(agentName: string): number;
39
+ /**
40
+ * Reset rate limit for an agent (useful for testing or admin override).
41
+ */
42
+ reset(agentName: string): void;
43
+ /**
44
+ * Reset all rate limits.
45
+ */
46
+ resetAll(): void;
47
+ /**
48
+ * Get rate limiter statistics.
49
+ */
50
+ getStats(): {
51
+ agentCount: number;
52
+ config: RateLimitConfig;
53
+ };
54
+ /**
55
+ * Clean up stale buckets (agents that haven't sent messages in a while).
56
+ * Call periodically to prevent memory growth.
57
+ */
58
+ cleanup(maxAgeMs?: number): number;
59
+ }
60
+ /**
61
+ * No-op rate limiter for when rate limiting is disabled.
62
+ */
63
+ export declare class NoOpRateLimiter extends RateLimiter {
64
+ constructor();
65
+ tryAcquire(_agentName: string): boolean;
66
+ tryAcquireWithResult(_agentName: string): RateLimitResult;
67
+ }
68
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Token bucket rate limiter for per-agent message throttling.
3
+ *
4
+ * Uses a token bucket algorithm that allows bursting while enforcing
5
+ * an average rate limit. Generous defaults to avoid blocking legitimate
6
+ * agent communication.
7
+ */
8
+ export const DEFAULT_RATE_LIMIT_CONFIG = {
9
+ // Very generous defaults - 500/sec sustained, 1000 burst
10
+ // This allows agents to send in bursts without being throttled
11
+ messagesPerSecond: 500,
12
+ burstSize: 1000,
13
+ logEvents: true,
14
+ };
15
+ export class RateLimiter {
16
+ buckets = new Map();
17
+ config;
18
+ constructor(config = {}) {
19
+ this.config = { ...DEFAULT_RATE_LIMIT_CONFIG, ...config };
20
+ }
21
+ /**
22
+ * Try to acquire a token for the given agent.
23
+ * Returns true if the message should be allowed, false if rate limited.
24
+ */
25
+ tryAcquire(agentName) {
26
+ return this.tryAcquireWithResult(agentName).allowed;
27
+ }
28
+ /**
29
+ * Try to acquire a token with detailed result.
30
+ */
31
+ tryAcquireWithResult(agentName) {
32
+ const now = Date.now();
33
+ let bucket = this.buckets.get(agentName);
34
+ if (!bucket) {
35
+ // New agent - start with full bucket
36
+ bucket = {
37
+ tokens: this.config.burstSize,
38
+ lastRefill: now,
39
+ };
40
+ this.buckets.set(agentName, bucket);
41
+ }
42
+ // Refill tokens based on time elapsed
43
+ const elapsedMs = now - bucket.lastRefill;
44
+ const tokensToAdd = (elapsedMs / 1000) * this.config.messagesPerSecond;
45
+ bucket.tokens = Math.min(this.config.burstSize, bucket.tokens + tokensToAdd);
46
+ bucket.lastRefill = now;
47
+ if (bucket.tokens >= 1) {
48
+ bucket.tokens -= 1;
49
+ return {
50
+ allowed: true,
51
+ remainingTokens: Math.floor(bucket.tokens),
52
+ };
53
+ }
54
+ // Rate limited - calculate retry time
55
+ const tokensNeeded = 1 - bucket.tokens;
56
+ const retryAfterMs = Math.ceil((tokensNeeded / this.config.messagesPerSecond) * 1000);
57
+ if (this.config.logEvents) {
58
+ console.warn(`[rate-limiter] Agent ${agentName} rate limited, retry in ${retryAfterMs}ms`);
59
+ }
60
+ return {
61
+ allowed: false,
62
+ remainingTokens: 0,
63
+ retryAfterMs,
64
+ };
65
+ }
66
+ /**
67
+ * Get remaining tokens for an agent (for monitoring/debugging).
68
+ */
69
+ getRemainingTokens(agentName) {
70
+ const bucket = this.buckets.get(agentName);
71
+ if (!bucket)
72
+ return this.config.burstSize;
73
+ // Calculate current tokens with refill
74
+ const now = Date.now();
75
+ const elapsedMs = now - bucket.lastRefill;
76
+ const tokensToAdd = (elapsedMs / 1000) * this.config.messagesPerSecond;
77
+ return Math.min(this.config.burstSize, Math.floor(bucket.tokens + tokensToAdd));
78
+ }
79
+ /**
80
+ * Reset rate limit for an agent (useful for testing or admin override).
81
+ */
82
+ reset(agentName) {
83
+ this.buckets.delete(agentName);
84
+ }
85
+ /**
86
+ * Reset all rate limits.
87
+ */
88
+ resetAll() {
89
+ this.buckets.clear();
90
+ }
91
+ /**
92
+ * Get rate limiter statistics.
93
+ */
94
+ getStats() {
95
+ return {
96
+ agentCount: this.buckets.size,
97
+ config: this.config,
98
+ };
99
+ }
100
+ /**
101
+ * Clean up stale buckets (agents that haven't sent messages in a while).
102
+ * Call periodically to prevent memory growth.
103
+ */
104
+ cleanup(maxAgeMs = 60 * 60 * 1000) {
105
+ const now = Date.now();
106
+ let cleaned = 0;
107
+ for (const [agentName, bucket] of this.buckets) {
108
+ if (now - bucket.lastRefill > maxAgeMs) {
109
+ this.buckets.delete(agentName);
110
+ cleaned++;
111
+ }
112
+ }
113
+ return cleaned;
114
+ }
115
+ }
116
+ /**
117
+ * No-op rate limiter for when rate limiting is disabled.
118
+ */
119
+ export class NoOpRateLimiter extends RateLimiter {
120
+ constructor() {
121
+ super({ messagesPerSecond: Infinity, burstSize: Infinity, logEvents: false });
122
+ }
123
+ tryAcquire(_agentName) {
124
+ return true;
125
+ }
126
+ tryAcquireWithResult(_agentName) {
127
+ return { allowed: true, remainingTokens: Infinity };
128
+ }
129
+ }
130
+ //# sourceMappingURL=rate-limiter.js.map