agent-relay-server 0.120.2 → 0.120.4

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 (141) hide show
  1. package/docs/openapi.json +1 -1
  2. package/package.json +3 -3
  3. package/public/assets/{MessageBubble-DazQ9Rn-.js → MessageBubble-Cqi3XsZ7.js} +2 -2
  4. package/public/assets/{MessageBubble-DazQ9Rn-.js.map → MessageBubble-Cqi3XsZ7.js.map} +1 -1
  5. package/public/assets/{PlanGraphPanel-DpTiGCkz.js → PlanGraphPanel-D6Um05oW.js} +2 -2
  6. package/public/assets/{PlanGraphPanel-DpTiGCkz.js.map → PlanGraphPanel-D6Um05oW.js.map} +1 -1
  7. package/public/assets/{activity-DReCE2mK.js → activity-B0LsQHEz.js} +2 -2
  8. package/public/assets/{activity-DReCE2mK.js.map → activity-B0LsQHEz.js.map} +1 -1
  9. package/public/assets/{agent-profiles-D3ba8Xpe.js → agent-profiles-O--pe5Ic.js} +2 -2
  10. package/public/assets/{agent-profiles-D3ba8Xpe.js.map → agent-profiles-O--pe5Ic.js.map} +1 -1
  11. package/public/assets/{agent-type-icon-BEz393ra.js → agent-type-icon-CeEoMouY.js} +2 -2
  12. package/public/assets/{agent-type-icon-BEz393ra.js.map → agent-type-icon-CeEoMouY.js.map} +1 -1
  13. package/public/assets/{agents-BcsIxadm.js → agents-Ii6XlVwR.js} +2 -2
  14. package/public/assets/{agents-BcsIxadm.js.map → agents-Ii6XlVwR.js.map} +1 -1
  15. package/public/assets/{analytics-0lOlkaib.js → analytics-BCzdYWRT.js} +2 -2
  16. package/public/assets/{analytics-0lOlkaib.js.map → analytics-BCzdYWRT.js.map} +1 -1
  17. package/public/assets/{automation-D66mthBn.js → automation-Crr3Xzui.js} +2 -2
  18. package/public/assets/{automation-D66mthBn.js.map → automation-Crr3Xzui.js.map} +1 -1
  19. package/public/assets/{badge-BhUZ1cAb.js → badge-DCIT3Irj.js} +2 -2
  20. package/public/assets/{badge-BhUZ1cAb.js.map → badge-DCIT3Irj.js.map} +1 -1
  21. package/public/assets/{branch-state-badge-NH-l2Eh3.js → branch-state-badge-Bhw2rloy.js} +2 -2
  22. package/public/assets/{branch-state-badge-NH-l2Eh3.js.map → branch-state-badge-Bhw2rloy.js.map} +1 -1
  23. package/public/assets/{button-C-V4oij1.js → button-CzdTkRIf.js} +2 -2
  24. package/public/assets/{button-C-V4oij1.js.map → button-CzdTkRIf.js.map} +1 -1
  25. package/public/assets/{card-Br1JLjTH.js → card-C3BGuVC6.js} +2 -2
  26. package/public/assets/{card-Br1JLjTH.js.map → card-C3BGuVC6.js.map} +1 -1
  27. package/public/assets/{channels-BlHLMQVk.js → channels-CKs9rvsn.js} +2 -2
  28. package/public/assets/{channels-BlHLMQVk.js.map → channels-CKs9rvsn.js.map} +1 -1
  29. package/public/assets/{chat-rwffRsPX.js → chat-BCwEUj5R.js} +2 -2
  30. package/public/assets/{chat-rwffRsPX.js.map → chat-BCwEUj5R.js.map} +1 -1
  31. package/public/assets/{connectors-CdsiaLD3.js → connectors-D_kQR_vw.js} +2 -2
  32. package/public/assets/{connectors-CdsiaLD3.js.map → connectors-D_kQR_vw.js.map} +1 -1
  33. package/public/assets/{copy-button-BStzXgtd.js → copy-button-B3o1jpLu.js} +2 -2
  34. package/public/assets/{copy-button-BStzXgtd.js.map → copy-button-B3o1jpLu.js.map} +1 -1
  35. package/public/assets/{dist-ChDX_t12.js → dist-B-T7lg0a.js} +2 -2
  36. package/public/assets/{dist-ChDX_t12.js.map → dist-B-T7lg0a.js.map} +1 -1
  37. package/public/assets/{dist-DV83j9tm.js → dist-B3e4B9pg.js} +2 -2
  38. package/public/assets/{dist-DV83j9tm.js.map → dist-B3e4B9pg.js.map} +1 -1
  39. package/public/assets/{dist-y03IwOrd.js → dist-B6woQ9Tb.js} +2 -2
  40. package/public/assets/{dist-y03IwOrd.js.map → dist-B6woQ9Tb.js.map} +1 -1
  41. package/public/assets/{dist-CQ0Z-TDi.js → dist-B9G83DXv.js} +2 -2
  42. package/public/assets/{dist-CQ0Z-TDi.js.map → dist-B9G83DXv.js.map} +1 -1
  43. package/public/assets/{dist-Cs8X0P1d.js → dist-BIjlN-xB.js} +2 -2
  44. package/public/assets/{dist-Cs8X0P1d.js.map → dist-BIjlN-xB.js.map} +1 -1
  45. package/public/assets/{dist-DyNJNwpi.js → dist-BInckSJC.js} +2 -2
  46. package/public/assets/{dist-DyNJNwpi.js.map → dist-BInckSJC.js.map} +1 -1
  47. package/public/assets/{dist-CmFeEXMe.js → dist-BlzVGRhh.js} +2 -2
  48. package/public/assets/{dist-CmFeEXMe.js.map → dist-BlzVGRhh.js.map} +1 -1
  49. package/public/assets/{dist-CDZZxxJq.js → dist-C7aTlosb.js} +2 -2
  50. package/public/assets/{dist-CDZZxxJq.js.map → dist-C7aTlosb.js.map} +1 -1
  51. package/public/assets/{dist-D2jvo5oA.js → dist-DGfp5dLz.js} +2 -2
  52. package/public/assets/{dist-D2jvo5oA.js.map → dist-DGfp5dLz.js.map} +1 -1
  53. package/public/assets/{dist-mm7c7nBt.js → dist-DT-OV6sQ.js} +2 -2
  54. package/public/assets/{dist-mm7c7nBt.js.map → dist-DT-OV6sQ.js.map} +1 -1
  55. package/public/assets/{dist-CBMWGhWc.js → dist-OUPTEP6q.js} +2 -2
  56. package/public/assets/{dist-CBMWGhWc.js.map → dist-OUPTEP6q.js.map} +1 -1
  57. package/public/assets/{es2015-VnZ2kVIz.js → es2015-CnKXYKpf.js} +2 -2
  58. package/public/assets/{es2015-VnZ2kVIz.js.map → es2015-CnKXYKpf.js.map} +1 -1
  59. package/public/assets/{formatted-body-impl-D_ZJQVNk.js → formatted-body-impl-CSRGuMcM.js} +2 -2
  60. package/public/assets/{formatted-body-impl-D_ZJQVNk.js.map → formatted-body-impl-CSRGuMcM.js.map} +1 -1
  61. package/public/assets/formatted-body-q_qzt1L-.js +3 -0
  62. package/public/assets/{formatted-body-C1AprxyU.js.map → formatted-body-q_qzt1L-.js.map} +1 -1
  63. package/public/assets/{index-DfPouNiV.js → index-Ceiwd02X.js} +6 -6
  64. package/public/assets/{index-DfPouNiV.js.map → index-Ceiwd02X.js.map} +1 -1
  65. package/public/assets/{input-CtLT7WXi.js → input-B6Q0NWCS.js} +2 -2
  66. package/public/assets/{input-CtLT7WXi.js.map → input-B6Q0NWCS.js.map} +1 -1
  67. package/public/assets/{insights-BJf1vwrf.js → insights-DUhXqZTZ.js} +2 -2
  68. package/public/assets/{insights-BJf1vwrf.js.map → insights-DUhXqZTZ.js.map} +1 -1
  69. package/public/assets/{integrations-BZSHasnY.js → integrations-lbg5CjtE.js} +2 -2
  70. package/public/assets/{integrations-BZSHasnY.js.map → integrations-lbg5CjtE.js.map} +1 -1
  71. package/public/assets/{lib-ByLQqcD1.js → lib-BHsWPMKB.js} +2 -2
  72. package/public/assets/{lib-ByLQqcD1.js.map → lib-BHsWPMKB.js.map} +1 -1
  73. package/public/assets/lucide-react-DuhlF2Sj.js +10 -0
  74. package/public/assets/lucide-react-DuhlF2Sj.js.map +1 -0
  75. package/public/assets/{maintenance-uEI1lArh.js → maintenance-CQgneSVf.js} +2 -2
  76. package/public/assets/{maintenance-uEI1lArh.js.map → maintenance-CQgneSVf.js.map} +1 -1
  77. package/public/assets/{managed-agents-mX3hHpOP.js → managed-agents-DsnYf6fm.js} +2 -2
  78. package/public/assets/{managed-agents-mX3hHpOP.js.map → managed-agents-DsnYf6fm.js.map} +1 -1
  79. package/public/assets/{markdown-preview-impl-ClNwMC48.js → markdown-preview-impl-C1ZtGJp6.js} +2 -2
  80. package/public/assets/{markdown-preview-impl-ClNwMC48.js.map → markdown-preview-impl-C1ZtGJp6.js.map} +1 -1
  81. package/public/assets/{memory-OfusEzGh.js → memory-SSLUTOI2.js} +2 -2
  82. package/public/assets/{memory-OfusEzGh.js.map → memory-SSLUTOI2.js.map} +1 -1
  83. package/public/assets/{messages-DsQGj0gU.js → messages-BY26OP4K.js} +2 -2
  84. package/public/assets/{messages-DsQGj0gU.js.map → messages-BY26OP4K.js.map} +1 -1
  85. package/public/assets/{orchestrators-BwWyl4mB.js → orchestrators-OY7yPzVI.js} +2 -2
  86. package/public/assets/{orchestrators-BwWyl4mB.js.map → orchestrators-OY7yPzVI.js.map} +1 -1
  87. package/public/assets/{overview-CED1SeTY.js → overview-Dj0u1tPG.js} +2 -2
  88. package/public/assets/{overview-CED1SeTY.js.map → overview-Dj0u1tPG.js.map} +1 -1
  89. package/public/assets/{pairs-BNu6ZWg4.js → pairs-CrUR50ou.js} +2 -2
  90. package/public/assets/{pairs-BNu6ZWg4.js.map → pairs-CrUR50ou.js.map} +1 -1
  91. package/public/assets/{projects-BmopRiUD.js → projects-B_AtxHtH.js} +2 -2
  92. package/public/assets/{projects-BmopRiUD.js.map → projects-B_AtxHtH.js.map} +1 -1
  93. package/public/assets/{prompt-settings-Ci2n1cFt.js → prompt-settings-CPtYSban.js} +2 -2
  94. package/public/assets/{prompt-settings-Ci2n1cFt.js.map → prompt-settings-CPtYSban.js.map} +1 -1
  95. package/public/assets/{react-dom-cLkVFBsS.js → react-dom-DWBmcawP.js} +2 -2
  96. package/public/assets/{react-dom-cLkVFBsS.js.map → react-dom-DWBmcawP.js.map} +1 -1
  97. package/public/assets/{registry-DwXnDIql.js → registry-BgUALWn5.js} +2 -2
  98. package/public/assets/{registry-DwXnDIql.js.map → registry-BgUALWn5.js.map} +1 -1
  99. package/public/assets/{security-AW5EbdOm.js → security-5lHfGk7g.js} +2 -2
  100. package/public/assets/{security-AW5EbdOm.js.map → security-5lHfGk7g.js.map} +1 -1
  101. package/public/assets/{select-CEeWX4hp.js → select-Cgx4QSLj.js} +2 -2
  102. package/public/assets/{select-CEeWX4hp.js.map → select-Cgx4QSLj.js.map} +1 -1
  103. package/public/assets/{settings-DYUdGz4G.js → settings-DFGgxyun.js} +2 -2
  104. package/public/assets/{settings-DYUdGz4G.js.map → settings-DFGgxyun.js.map} +1 -1
  105. package/public/assets/{store-BaslPLIP.js → store-BM4zM89B.js} +3 -3
  106. package/public/assets/store-BM4zM89B.js.map +1 -0
  107. package/public/assets/{task-chip-kxk4eNm1.js → task-chip-DXfvXBDx.js} +2 -2
  108. package/public/assets/{task-chip-kxk4eNm1.js.map → task-chip-DXfvXBDx.js.map} +1 -1
  109. package/public/assets/{tasks-DxCsrY4g.js → tasks-BvH5rluu.js} +2 -2
  110. package/public/assets/{tasks-DxCsrY4g.js.map → tasks-BvH5rluu.js.map} +1 -1
  111. package/public/assets/{teams-CF7vi-oM.js → teams-VZOIOdoE.js} +2 -2
  112. package/public/assets/{teams-CF7vi-oM.js.map → teams-VZOIOdoE.js.map} +1 -1
  113. package/public/assets/{terminal-viewer-impl-Dy3vqOnW.js → terminal-viewer-impl-DYY3Wmoe.js} +2 -2
  114. package/public/assets/{terminal-viewer-impl-Dy3vqOnW.js.map → terminal-viewer-impl-DYY3Wmoe.js.map} +1 -1
  115. package/public/assets/{use-keyboard-viewport-B06XtRUZ.js → use-keyboard-viewport-CP109w9y.js} +2 -2
  116. package/public/assets/{use-keyboard-viewport-B06XtRUZ.js.map → use-keyboard-viewport-CP109w9y.js.map} +1 -1
  117. package/public/assets/{user-avatar-DuwCFrER.js → user-avatar-Dw6mzWhv.js} +2 -2
  118. package/public/assets/{user-avatar-DuwCFrER.js.map → user-avatar-Dw6mzWhv.js.map} +1 -1
  119. package/public/assets/{work-queue-BPaGXrCE.js → work-queue-B6Xk7QNe.js} +2 -2
  120. package/public/assets/{work-queue-BPaGXrCE.js.map → work-queue-B6Xk7QNe.js.map} +1 -1
  121. package/public/assets/{workspaces-BLEXgnlj.js → workspaces-CPIzAHAe.js} +2 -2
  122. package/public/assets/{workspaces-BLEXgnlj.js.map → workspaces-CPIzAHAe.js.map} +1 -1
  123. package/public/index.html +23 -23
  124. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  125. package/src/branch-landed.ts +3 -7
  126. package/src/bus.ts +2 -2
  127. package/src/db/connection.ts +36 -12
  128. package/src/db/maintenance-worker.ts +23 -11
  129. package/src/db/message-reads.ts +17 -1
  130. package/src/maintenance/jobs.ts +18 -12
  131. package/src/maintenance/scheduler.ts +8 -3
  132. package/src/maintenance/types.ts +5 -1
  133. package/src/routes/sse.ts +2 -1
  134. package/src/services/git-process.ts +61 -0
  135. package/src/services/git-remote.ts +68 -17
  136. package/src/services/task-lifecycle.ts +2 -6
  137. package/src/sse.ts +110 -44
  138. package/public/assets/formatted-body-C1AprxyU.js +0 -3
  139. package/public/assets/lucide-react-Dc3ZwCBi.js +0 -9
  140. package/public/assets/lucide-react-Dc3ZwCBi.js.map +0 -1
  141. package/public/assets/store-BaslPLIP.js.map +0 -1
package/src/sse.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { getAgent, getOrchestrator, matchingDeliveryAgents, onWorkspaceChange, sendMessageWithResult, setChannelSubscriberProbe } from "./db";
2
+ import { getOldestOutboxCursor, getOutboxCursor, replayEvents, type BusEvent } from "./bus-outbox";
2
3
  import { projectAgentStatusData } from "./agent-card-projection";
3
4
  import { emitRelayEvent, subscribeRelayEvents, type RelayEvent } from "./events";
4
5
  import { messageMatchesAgent, targetMatchesAgent } from "./agent-ref";
@@ -15,7 +16,7 @@ interface Connection {
15
16
  // Pending backpressure re-check. Set when a stream crosses the byte floor; cleared
16
17
  // once it drains or is closed after making no progress during the grace interval.
17
18
  drainCheck?: Timer;
18
- drainCheckDesiredSize?: number | null;
19
+ drainCheckQueuedBytes?: number;
19
20
  }
20
21
 
21
22
  const connections = new Map<string, Connection>();
@@ -43,28 +44,36 @@ export function hasActiveSubscriber(agentId: string): boolean {
43
44
  }
44
45
  setChannelSubscriberProbe(hasActiveSubscriber);
45
46
 
46
- export function createSSEStream(agentId: string | null): Response {
47
+ export function createSSEStream(agentId: string | null, lastEventId = 0): Response {
47
48
  let connId: string;
48
49
 
49
- const stream = new ReadableStream<Uint8Array>({
50
- start(controller) {
51
- connId = crypto.randomUUID();
52
- const keepalive = setInterval(() => {
53
- const conn = connections.get(connId);
54
- if (!conn) return;
55
- sendEncoded(conn, encoder.encode(": keepalive\n\n"));
56
- }, SSE_KEEPALIVE_MS);
57
-
58
- connections.set(connId, { id: connId, agentId, controller, keepalive, queuedBytes: 0 });
59
-
60
- controller.enqueue(encoder.encode(
61
- `retry: ${SSE_RETRY_MS}\nevent: connected\ndata: ${JSON.stringify({ connectionId: connId })}\n\n`
62
- ));
50
+ const stream = new ReadableStream<Uint8Array>(
51
+ {
52
+ start(controller) {
53
+ connId = crypto.randomUUID();
54
+ const keepalive = setInterval(() => {
55
+ const conn = connections.get(connId);
56
+ if (!conn) return;
57
+ sendEncoded(conn, encoder.encode(": keepalive\n\n"));
58
+ }, SSE_KEEPALIVE_MS);
59
+
60
+ connections.set(connId, { id: connId, agentId, controller, keepalive, queuedBytes: 0 });
61
+
62
+ const replay = replayPlan(lastEventId);
63
+ controller.enqueue(encoder.encode(
64
+ `retry: ${SSE_RETRY_MS}\nevent: connected\ndata: ${JSON.stringify({ connectionId: connId, replay })}\n\n`
65
+ ));
66
+ replayEventsToConnection(connections.get(connId), replay);
67
+ },
68
+ cancel() {
69
+ removeConnection(connId);
70
+ },
63
71
  },
64
- cancel() {
65
- removeConnection(connId);
72
+ {
73
+ highWaterMark: 0,
74
+ size: (chunk) => chunk?.byteLength ?? 0,
66
75
  },
67
- });
76
+ );
68
77
 
69
78
  return new Response(stream, {
70
79
  headers: {
@@ -92,12 +101,19 @@ function closeConnection(id: string) {
92
101
  try { conn?.controller.close(); } catch {}
93
102
  }
94
103
 
95
- function sseFrame(event: string, data: unknown): Uint8Array {
96
- return encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
104
+ function sseFrame(event: string, data: unknown, id?: number): Uint8Array {
105
+ const idLine = id !== undefined ? `id: ${id}\n` : "";
106
+ return encoder.encode(`${idLine}event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
107
+ }
108
+
109
+ function bufferedBytes(conn: Connection): number {
110
+ const desiredSize = conn.controller.desiredSize;
111
+ if (desiredSize === null) return conn.queuedBytes;
112
+ return Math.max(0, -desiredSize);
97
113
  }
98
114
 
99
115
  function isBackpressured(conn: Connection): boolean {
100
- return conn.queuedBytes >= SSE_MAX_QUEUED_BYTES && conn.controller.desiredSize !== null && conn.controller.desiredSize < 0;
116
+ return bufferedBytes(conn) >= SSE_MAX_QUEUED_BYTES;
101
117
  }
102
118
 
103
119
  function sendEncoded(conn: Connection, chunk: Uint8Array) {
@@ -108,31 +124,27 @@ function sendEncoded(conn: Connection, chunk: Uint8Array) {
108
124
  removeConnection(conn.id);
109
125
  return;
110
126
  }
111
- if (conn.controller.desiredSize !== null && conn.controller.desiredSize >= 0) conn.queuedBytes = 0;
112
- else conn.queuedBytes += chunk.byteLength;
127
+ conn.queuedBytes = bufferedBytes(conn);
113
128
  if (isBackpressured(conn)) scheduleDrainCheck(conn);
114
129
  }
115
130
 
116
131
  function scheduleDrainCheck(conn: Connection) {
117
132
  if (conn.drainCheck) return; // one deferred verdict per stream is enough
118
- conn.drainCheckDesiredSize = conn.controller.desiredSize;
133
+ conn.drainCheckQueuedBytes = bufferedBytes(conn);
119
134
  conn.drainCheck = setTimeout(() => {
120
135
  conn.drainCheck = undefined;
121
136
  // The connection may already have been removed (cancel/close) during the grace —
122
137
  // closeConnection is idempotent, but bail early so we never touch a stale ref.
123
138
  if (connections.get(conn.id) !== conn) return;
124
- const desiredSize = conn.controller.desiredSize;
125
- if (desiredSize !== null && desiredSize >= 0) {
126
- conn.queuedBytes = 0;
127
- conn.drainCheckDesiredSize = undefined;
139
+ const queuedBytes = bufferedBytes(conn);
140
+ conn.queuedBytes = queuedBytes;
141
+ if (queuedBytes < SSE_MAX_QUEUED_BYTES) {
142
+ conn.drainCheckQueuedBytes = undefined;
128
143
  return;
129
144
  }
130
- const improved = desiredSize !== null
131
- && conn.drainCheckDesiredSize !== null
132
- && conn.drainCheckDesiredSize !== undefined
133
- && desiredSize > conn.drainCheckDesiredSize;
134
- conn.drainCheckDesiredSize = undefined;
135
- if (improved) {
145
+ const drained = conn.drainCheckQueuedBytes !== undefined && queuedBytes < conn.drainCheckQueuedBytes;
146
+ conn.drainCheckQueuedBytes = undefined;
147
+ if (drained) {
136
148
  scheduleDrainCheck(conn);
137
149
  return;
138
150
  }
@@ -140,30 +152,30 @@ function scheduleDrainCheck(conn: Connection) {
140
152
  }, SSE_DRAIN_GRACE_MS);
141
153
  }
142
154
 
143
- function send(conn: Connection, event: string, data: unknown) {
144
- sendEncoded(conn, sseFrame(event, data));
155
+ function send(conn: Connection, event: string, data: unknown, id?: number) {
156
+ sendEncoded(conn, sseFrame(event, data, id));
145
157
  }
146
158
 
147
159
  function fanout(event: RelayEvent): void {
148
160
  if (event.type === "message.new") {
149
- sendNewMessage(event.data as unknown as Message);
161
+ sendNewMessage(event.data as unknown as Message, event.seq);
150
162
  return;
151
163
  }
152
164
  if (event.type === "task.updated" || event.type === "task.created" || event.type === "task.claimed" || event.type === "task.status") {
153
- sendTaskChanged(event.data as unknown as Task, event.type);
165
+ sendTaskChanged(event.data as unknown as Task, event.type, event.seq);
154
166
  return;
155
167
  }
156
- const chunk = sseFrame(event.type, event.data);
168
+ const chunk = sseFrame(event.type, event.data, event.seq);
157
169
  for (const conn of connections.values()) {
158
170
  sendEncoded(conn, chunk);
159
171
  }
160
172
  }
161
173
 
162
- function sendNewMessage(msg: Message): void {
174
+ function sendNewMessage(msg: Message, seq?: number): void {
163
175
  const scopedBroadcastAgentIds = msg.to === "broadcast"
164
176
  ? new Set(matchingDeliveryAgents("broadcast", { from: msg.from, channel: msg.channel }).map((agent) => agent.id))
165
177
  : null;
166
- const chunk = sseFrame("message.new", msg);
178
+ const chunk = sseFrame("message.new", msg, seq);
167
179
  const agentCache = new Map<string, AgentCard | null>();
168
180
  for (const conn of connections.values()) {
169
181
  if (!conn.agentId) {
@@ -279,8 +291,8 @@ export function emitMessageReactionUpdated(msg: Message) {
279
291
  emitRelayEvent({ type: "message.reaction_updated", source: "server", subject: String(msg.id), data: msg as unknown as Record<string, unknown> });
280
292
  }
281
293
 
282
- function sendTaskChanged(task: Task, eventType = "task.updated"): void {
283
- const chunk = sseFrame(eventType, task);
294
+ function sendTaskChanged(task: Task, eventType = "task.updated", seq?: number): void {
295
+ const chunk = sseFrame(eventType, task, seq);
284
296
  const agentCache = new Map<string, AgentCard | null>();
285
297
  for (const conn of connections.values()) {
286
298
  if (conn.agentId && !targetMatchesAgent(task.target, conn.agentId, fanoutAgent(conn.agentId, agentCache))) continue;
@@ -288,6 +300,60 @@ function sendTaskChanged(task: Task, eventType = "task.updated"): void {
288
300
  }
289
301
  }
290
302
 
303
+ interface ReplayPlan {
304
+ requested: boolean;
305
+ since: number;
306
+ available: boolean;
307
+ gap: boolean;
308
+ }
309
+
310
+ function replayPlan(lastEventId: number): ReplayPlan {
311
+ const since = Number.isSafeInteger(lastEventId) && lastEventId > 0 ? lastEventId : 0;
312
+ if (since === 0) return { requested: false, since: 0, available: false, gap: false };
313
+ const oldest = getOldestOutboxCursor();
314
+ const gap = oldest > 0 && oldest > since + 1;
315
+ return { requested: true, since, available: !gap, gap };
316
+ }
317
+
318
+ function replayEventsToConnection(conn: Connection | undefined, plan: ReplayPlan): void {
319
+ if (!conn || !plan.requested) return;
320
+ if (plan.gap) {
321
+ send(conn, "replay.gap", { since: plan.since }, getOutboxCursor());
322
+ return;
323
+ }
324
+ const agentCache = new Map<string, AgentCard | null>();
325
+ for (const event of replayEvents(plan.since)) {
326
+ sendReplayEvent(conn, outboxToRelayEvent(event), agentCache);
327
+ }
328
+ }
329
+
330
+ function sendReplayEvent(conn: Connection, event: RelayEvent, agentCache: Map<string, AgentCard | null>): void {
331
+ if (event.type === "message.new" && conn.agentId) {
332
+ const msg = event.data as unknown as Message;
333
+ if (!messageMatchesAgent(msg, conn.agentId, fanoutAgent(conn.agentId, agentCache))) return;
334
+ send(conn, "message.new", msg, event.seq);
335
+ return;
336
+ }
337
+ if (event.type.startsWith("task.") && conn.agentId) {
338
+ const task = event.data as unknown as Task;
339
+ if (!targetMatchesAgent(task.target, conn.agentId, fanoutAgent(conn.agentId, agentCache))) return;
340
+ send(conn, event.type, task, event.seq);
341
+ return;
342
+ }
343
+ send(conn, event.type, event.data, event.seq);
344
+ }
345
+
346
+ function outboxToRelayEvent(event: BusEvent): RelayEvent {
347
+ return {
348
+ seq: event.seq,
349
+ type: event.eventType,
350
+ source: event.source,
351
+ subject: event.subject,
352
+ data: event.data,
353
+ timestamp: event.timestamp,
354
+ };
355
+ }
356
+
291
357
  export function emitTaskChanged(task: Task, eventType = "task.updated") {
292
358
  emitRelayEvent({ type: eventType, source: task.source, subject: String(task.id), data: task as unknown as Record<string, unknown> });
293
359
  }
@@ -1,3 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./formatted-body-impl-D_ZJQVNk.js","./chunk-CilyBKbf.js","./index-DfPouNiV.js","./preload-helper-C_JMBXql.js","./dist-DV83j9tm.js","./dist-ChDX_t12.js","./lucide-react-Dc3ZwCBi.js","./dist-Cs8X0P1d.js","./dist-CQ0Z-TDi.js","./react-dom-cLkVFBsS.js","./dist-mm7c7nBt.js","./dist-CDZZxxJq.js","./dist-BiLuYU6G.js","./dist-DyNJNwpi.js","./dist-D2jvo5oA.js","./es2015-VnZ2kVIz.js","./dist-CmFeEXMe.js","./dist-CBMWGhWc.js","./dist-y03IwOrd.js","./store-BaslPLIP.js","./display-exQDWum3.js","./types-uVOXgvMT.js","./agent-type-icon-BEz393ra.js","./copy-button-BStzXgtd.js","./button-C-V4oij1.js","./task-chip-kxk4eNm1.js","./badge-BhUZ1cAb.js","./input-CtLT7WXi.js","./themes-DjSwmAZN.js","./index-DcmG5gLR.css","./lib-ByLQqcD1.js","./lib-Cc7Il-6i.js"])))=>i.map(i=>d[i]);
2
- import{r as e}from"./chunk-CilyBKbf.js";import{hr as t,nr as n}from"./lucide-react-Dc3ZwCBi.js";import{t as r}from"./preload-helper-C_JMBXql.js";var i=e(t(),1),a=n(),o=(0,i.lazy)(()=>r(()=>import(`./formatted-body-impl-D_ZJQVNk.js`).then(e=>({default:e.FormattedBody})),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]),import.meta.url));function s(e){return(0,a.jsx)(i.Suspense,{fallback:(0,a.jsx)(`span`,{className:e.className,children:e.text}),children:(0,a.jsx)(o,{...e})})}export{s as t};
3
- //# sourceMappingURL=formatted-body-C1AprxyU.js.map