@relaycast/engine 8.15.0 → 9.0.0

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 (70) hide show
  1. package/dist/db/migrations/0062_direct_dm_idempotency.sql +20 -0
  2. package/dist/db/migrations/0063_node_rotation_recovery.sql +13 -0
  3. package/dist/db/schema.d.ts +200 -0
  4. package/dist/db/schema.d.ts.map +1 -1
  5. package/dist/db/schema.js +29 -0
  6. package/dist/db/schema.js.map +1 -1
  7. package/dist/engine/a2aEgress.d.ts +10 -0
  8. package/dist/engine/a2aEgress.d.ts.map +1 -1
  9. package/dist/engine/a2aEgress.js +35 -3
  10. package/dist/engine/a2aEgress.js.map +1 -1
  11. package/dist/engine/attachments.d.ts.map +1 -1
  12. package/dist/engine/attachments.js +5 -3
  13. package/dist/engine/attachments.js.map +1 -1
  14. package/dist/engine/dm.d.ts +5 -1
  15. package/dist/engine/dm.d.ts.map +1 -1
  16. package/dist/engine/dm.js +131 -20
  17. package/dist/engine/dm.js.map +1 -1
  18. package/dist/engine/dmAll.d.ts +6 -0
  19. package/dist/engine/dmAll.d.ts.map +1 -1
  20. package/dist/engine/dmAll.js +51 -2
  21. package/dist/engine/dmAll.js.map +1 -1
  22. package/dist/engine/inboundWebhook.d.ts +4 -0
  23. package/dist/engine/inboundWebhook.d.ts.map +1 -1
  24. package/dist/engine/inboundWebhook.js +5 -0
  25. package/dist/engine/inboundWebhook.js.map +1 -1
  26. package/dist/engine/messageMetadata.d.ts +4 -0
  27. package/dist/engine/messageMetadata.d.ts.map +1 -1
  28. package/dist/engine/messageMetadata.js +7 -1
  29. package/dist/engine/messageMetadata.js.map +1 -1
  30. package/dist/engine/node.d.ts +37 -7
  31. package/dist/engine/node.d.ts.map +1 -1
  32. package/dist/engine/node.js +107 -19
  33. package/dist/engine/node.js.map +1 -1
  34. package/dist/engine/sessionEvent.d.ts.map +1 -1
  35. package/dist/engine/sessionEvent.js +2 -0
  36. package/dist/engine/sessionEvent.js.map +1 -1
  37. package/dist/engine/workspace.d.ts +3 -0
  38. package/dist/engine/workspace.d.ts.map +1 -1
  39. package/dist/engine/workspace.js +45 -1
  40. package/dist/engine/workspace.js.map +1 -1
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/lib/serverTelemetry.d.ts +13 -2
  46. package/dist/lib/serverTelemetry.d.ts.map +1 -1
  47. package/dist/lib/serverTelemetry.js +4 -0
  48. package/dist/lib/serverTelemetry.js.map +1 -1
  49. package/dist/middleware/idempotency.d.ts +15 -9
  50. package/dist/middleware/idempotency.d.ts.map +1 -1
  51. package/dist/middleware/idempotency.js +104 -58
  52. package/dist/middleware/idempotency.js.map +1 -1
  53. package/dist/routes/a2a.js +6 -1
  54. package/dist/routes/a2a.js.map +1 -1
  55. package/dist/routes/agent.js +1 -1
  56. package/dist/routes/agent.js.map +1 -1
  57. package/dist/routes/dm.d.ts.map +1 -1
  58. package/dist/routes/dm.js +70 -42
  59. package/dist/routes/dm.js.map +1 -1
  60. package/dist/routes/node.d.ts.map +1 -1
  61. package/dist/routes/node.js +38 -3
  62. package/dist/routes/node.js.map +1 -1
  63. package/dist/routes/webhookOutbox.d.ts +1 -0
  64. package/dist/routes/webhookOutbox.d.ts.map +1 -1
  65. package/dist/routes/webhookOutbox.js +9 -5
  66. package/dist/routes/webhookOutbox.js.map +1 -1
  67. package/dist/routes/workspace.d.ts.map +1 -1
  68. package/dist/routes/workspace.js +46 -17
  69. package/dist/routes/workspace.js.map +1 -1
  70. package/package.json +3 -3
@@ -1,6 +1,7 @@
1
1
  import { type EngineDb } from '../ports/database.js';
2
2
  /** Same finite retry horizon as HTTP idempotency; payloads never dispatch after it. */
3
3
  export declare const A2A_EGRESS_RETRY_WINDOW_MS: number;
4
+ export declare const DIRECT_DM_IDEMPOTENCY_CLEANUP_BATCH_SIZE = 500;
4
5
  /** Durable admission and a lease exclude concurrent senders. A crash after remote
5
6
  * acceptance can replay the same message_id and HTTP Idempotency-Key; receivers
6
7
  * must deduplicate them. Arbitrary receivers still have at-least-once delivery.
@@ -11,6 +12,15 @@ export declare function dispatchA2aEgress(db: EngineDb, id: string): Promise<voi
11
12
  * After deletion a key is fresh, as with the existing HTTP idempotency contract.
12
13
  */
13
14
  export declare function cleanupA2aEgress(db: EngineDb, limit?: number): Promise<number>;
15
+ /** Remove one expired request identity before the caller admits a fresh use of
16
+ * its key. A live transport lease wins the race and keeps the row until a
17
+ * later retry or maintenance pass.
18
+ */
19
+ export declare function expireA2aEgressForReuse(db: EngineDb, id: string, now?: Date): Promise<boolean>;
20
+ /** Bounded cleanup for transport-independent DM request claims. Once the
21
+ * 24-hour replay window ends, the same caller key is intentionally fresh.
22
+ */
23
+ export declare function cleanupDirectDmIdempotency(db: EngineDb, limit?: number, now?: Date): Promise<number>;
14
24
  /** Existing Node/HOST maintenance entrypoint includes bounded retention cleanup. */
15
25
  export declare function sweepPendingA2aEgress(db: EngineDb, limit?: number): Promise<{
16
26
  attempted: number;
@@ -1 +1 @@
1
- {"version":3,"file":"a2aEgress.d.ts","sourceRoot":"","sources":["../../src/engine/a2aEgress.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKtE,uFAAuF;AACvF,eAAO,MAAM,0BAA0B,QAAsB,CAAC;AAe9D;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D/E;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAShF;AAED,oFAAoF;AACpF,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAepH"}
1
+ {"version":3,"file":"a2aEgress.d.ts","sourceRoot":"","sources":["../../src/engine/a2aEgress.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKtE,uFAAuF;AACvF,eAAO,MAAM,0BAA0B,QAAsB,CAAC;AAC9D,eAAO,MAAM,wCAAwC,MAAM,CAAC;AA2B5D;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D/E;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAKhF;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,QAAQ,EACZ,EAAE,EAAE,MAAM,EACV,GAAG,OAAa,GACf,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,QAAQ,EACZ,KAAK,SAA2C,EAChD,GAAG,OAAa,GACf,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED,oFAAoF;AACpF,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBpH"}
@@ -1,16 +1,21 @@
1
1
  import { and, eq, or, sql, lte, inArray, asc } from 'drizzle-orm';
2
- import { a2aAgents, a2aEgress, a2aInbound, messages, agents } from '../db/schema.js';
2
+ import { a2aAgents, a2aEgress, a2aInbound, directDmIdempotency, messages, agents } from '../db/schema.js';
3
3
  import { runAtomicWrites } from '../ports/database.js';
4
4
  import { randomUuid } from '../lib/crypto.js';
5
5
  import { codedError } from '../lib/httpError.js';
6
6
  import { sendToExternalAgent } from './a2a.js';
7
7
  /** Same finite retry horizon as HTTP idempotency; payloads never dispatch after it. */
8
8
  export const A2A_EGRESS_RETRY_WINDOW_MS = 24 * 60 * 60 * 1000;
9
+ export const DIRECT_DM_IDEMPOTENCY_CLEANUP_BATCH_SIZE = 500;
9
10
  const batchLimit = (limit) => Number.isFinite(limit) ? Math.max(1, Math.min(100, Math.floor(limit))) : 20;
11
+ const directClaimBatchLimit = (limit) => Number.isFinite(limit)
12
+ ? Math.max(1, Math.min(1_000, Math.floor(limit)))
13
+ : DIRECT_DM_IDEMPOTENCY_CLEANUP_BATCH_SIZE;
10
14
  const expired = (intent) => intent.createdAt.getTime() + A2A_EGRESS_RETRY_WINDOW_MS <= Date.now();
11
15
  const notRetained = () => codedError('Accepted A2A message is no longer retained', 'a2a_message_not_retained', 410);
12
16
  const targetGone = () => codedError('Accepted A2A target no longer registered at its original endpoint', 'a2a_target_gone', 410);
13
17
  const windowExpired = () => codedError('Accepted A2A retry window expired', 'a2a_egress_expired', 410);
18
+ const cleanupEligible = (now) => and(lte(a2aEgress.createdAt, new Date(now.getTime() - A2A_EGRESS_RETRY_WINDOW_MS)), or(sql `${a2aEgress.leaseUntil} IS NULL`, lte(a2aEgress.leaseUntil, now), sql `${a2aEgress.status} != 'sending'`));
14
19
  async function validateSource(db, intent) {
15
20
  if (expired(intent))
16
21
  throw windowExpired();
@@ -90,12 +95,35 @@ export async function dispatchA2aEgress(db, id) {
90
95
  * After deletion a key is fresh, as with the existing HTTP idempotency contract.
91
96
  */
92
97
  export async function cleanupA2aEgress(db, limit = 20) {
93
- const eligible = and(lte(a2aEgress.createdAt, new Date(Date.now() - A2A_EGRESS_RETRY_WINDOW_MS)), or(sql `${a2aEgress.leaseUntil} IS NULL`, lte(a2aEgress.leaseUntil, new Date()), sql `${a2aEgress.status} != 'sending'`));
94
- const candidates = db.select({ id: a2aEgress.id }).from(a2aEgress).where(eligible)
98
+ const candidates = db.select({ id: a2aEgress.id }).from(a2aEgress).where(cleanupEligible(new Date()))
95
99
  .orderBy(asc(a2aEgress.createdAt), asc(a2aEgress.id)).limit(batchLimit(limit));
96
100
  const deleted = await db.delete(a2aEgress).where(inArray(a2aEgress.id, candidates)).returning({ id: a2aEgress.id });
97
101
  return deleted.length;
98
102
  }
103
+ /** Remove one expired request identity before the caller admits a fresh use of
104
+ * its key. A live transport lease wins the race and keeps the row until a
105
+ * later retry or maintenance pass.
106
+ */
107
+ export async function expireA2aEgressForReuse(db, id, now = new Date()) {
108
+ const deleted = await db.delete(a2aEgress)
109
+ .where(and(eq(a2aEgress.id, id), cleanupEligible(now)))
110
+ .returning({ id: a2aEgress.id });
111
+ return deleted.length > 0;
112
+ }
113
+ /** Bounded cleanup for transport-independent DM request claims. Once the
114
+ * 24-hour replay window ends, the same caller key is intentionally fresh.
115
+ */
116
+ export async function cleanupDirectDmIdempotency(db, limit = DIRECT_DM_IDEMPOTENCY_CLEANUP_BATCH_SIZE, now = new Date()) {
117
+ const expired = db.select({ id: directDmIdempotency.id })
118
+ .from(directDmIdempotency)
119
+ .where(lte(directDmIdempotency.createdAt, new Date(now.getTime() - A2A_EGRESS_RETRY_WINDOW_MS)))
120
+ .orderBy(asc(directDmIdempotency.createdAt), asc(directDmIdempotency.id))
121
+ .limit(directClaimBatchLimit(limit));
122
+ const deleted = await db.delete(directDmIdempotency)
123
+ .where(inArray(directDmIdempotency.id, expired))
124
+ .returning({ id: directDmIdempotency.id });
125
+ return deleted.length;
126
+ }
99
127
  /** Existing Node/HOST maintenance entrypoint includes bounded retention cleanup. */
100
128
  export async function sweepPendingA2aEgress(db, limit = 20) {
101
129
  const due = await db.select({ id: a2aEgress.id }).from(a2aEgress).where(and(or(eq(a2aEgress.status, 'pending'), eq(a2aEgress.status, 'sending')), or(sql `${a2aEgress.leaseUntil} IS NULL`, lte(a2aEgress.leaseUntil, new Date())))).limit(batchLimit(limit));
@@ -109,6 +137,10 @@ export async function sweepPendingA2aEgress(db, limit = 20) {
109
137
  }
110
138
  }
111
139
  await cleanupA2aEgress(db, limit);
140
+ // Direct request claims arrive on every keyed /v1/dm call and are unrelated
141
+ // to the small transport retry budget. Give them their own bounded batch so
142
+ // a rotating hosted cron cannot accumulate snapshots beyond message retention.
143
+ await cleanupDirectDmIdempotency(db, DIRECT_DM_IDEMPOTENCY_CLEANUP_BATCH_SIZE);
112
144
  const inboundExpired = db.select({ id: a2aInbound.id }).from(a2aInbound)
113
145
  .where(lte(a2aInbound.createdAt, new Date(Date.now() - A2A_EGRESS_RETRY_WINDOW_MS)))
114
146
  .orderBy(asc(a2aInbound.createdAt), asc(a2aInbound.id)).limit(batchLimit(limit));
@@ -1 +1 @@
1
- {"version":3,"file":"a2aEgress.js","sourceRoot":"","sources":["../../src/engine/a2aEgress.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"a2aEgress.js","sourceRoot":"","sources":["../../src/engine/a2aEgress.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../../src/engine/attachments.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAI5C,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AAEnC,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,EAAE,EACN,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,aAAa,EAAE,CAAC,CAuC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,EAAE,EACN,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,CA4BvC"}
1
+ {"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../../src/engine/attachments.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAK5C,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AAEnC,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,EAAE,EACN,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,aAAa,EAAE,CAAC,CAuC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,EAAE,EACN,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,CA6BvC"}
@@ -1,6 +1,7 @@
1
1
  import { and, asc, eq, inArray } from 'drizzle-orm';
2
2
  import { messageAttachments, files } from '../db/schema.js';
3
3
  import { codedError } from '../lib/httpError.js';
4
+ import { queryInChunks } from '../lib/queryChunks.js';
4
5
  /**
5
6
  * Validate attachment ids for a send path and hydrate the details needed for
6
7
  * response payloads and logs. Unknown, foreign-workspace, incomplete, and
@@ -49,7 +50,8 @@ export async function fetchAttachmentsBatch(db, workspaceId, msgIds) {
49
50
  const map = new Map();
50
51
  if (msgIds.length === 0)
51
52
  return map;
52
- const rows = await db
53
+ const uniqueMsgIds = [...new Set(msgIds)];
54
+ const rows = await queryInChunks(uniqueMsgIds, (chunk) => db
53
55
  .select({
54
56
  messageId: messageAttachments.messageId,
55
57
  fileId: messageAttachments.fileId,
@@ -59,8 +61,8 @@ export async function fetchAttachmentsBatch(db, workspaceId, msgIds) {
59
61
  })
60
62
  .from(messageAttachments)
61
63
  .innerJoin(files, eq(messageAttachments.fileId, files.id))
62
- .where(and(inArray(messageAttachments.messageId, msgIds), eq(files.workspaceId, workspaceId)))
63
- .orderBy(asc(messageAttachments.messageId), asc(messageAttachments.position));
64
+ .where(and(inArray(messageAttachments.messageId, chunk), eq(files.workspaceId, workspaceId)))
65
+ .orderBy(asc(messageAttachments.messageId), asc(messageAttachments.position)));
64
66
  for (const row of rows) {
65
67
  const list = map.get(row.messageId) || [];
66
68
  list.push({
@@ -1 +1 @@
1
- {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../src/engine/attachments.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../src/engine/attachments.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,8 @@ interface SendDmOptions {
10
10
  skipA2aIntercept?: boolean;
11
11
  /** Stable request identity for resuming already admitted outbound A2A. */
12
12
  idempotencyKey?: string;
13
+ /** Whether durable webhook fanout has any subscriber to receive it. */
14
+ hasWebhookSubscriptions?: boolean;
13
15
  /** Count an authenticated inbound peer in the same transaction as its DM. */
14
16
  receivedA2aAgentId?: string;
15
17
  /** Token hash authenticated by the route; checked with registration at SQL admission. */
@@ -28,7 +30,7 @@ interface SendDmOptions {
28
30
  seq: number;
29
31
  payload: Record<string, unknown>;
30
32
  data: Record<string, unknown>;
31
- outboxId: string;
33
+ outboxId?: string;
32
34
  }) => void;
33
35
  mailbox?: MailboxConfig;
34
36
  /** Server-resolved workspace growth policy; absent => no workspace guard. */
@@ -105,6 +107,8 @@ export type SendDmResult = AcceptedDmResult & {
105
107
  _delivery: DeliveryOutcomeRecords['deliveries'][number] | null;
106
108
  _delivery_rejections: DeliveryOutcomeRecords['rejections'];
107
109
  _notifications_durable?: boolean;
110
+ _idempotency_replayed?: boolean;
111
+ _idempotency_ttl_seconds?: number;
108
112
  };
109
113
  export declare function sendDm(db: Db, workspaceId: string, fromAgentId: string, data: {
110
114
  to: string;
@@ -1 +1 @@
1
- {"version":3,"file":"dm.d.ts","sourceRoot":"","sources":["../../src/engine/dm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dm.d.ts","sourceRoot":"","sources":["../../src/engine/dm.ts"],"names":[],"mappings":"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"}
package/dist/engine/dm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { eq, and, sql, lt, lte, gt, isNull, inArray, desc } from 'drizzle-orm';
3
- import { messages, channels, agents, dmConversations, dmConversationReservations, dmParticipants, messageAttachments, a2aEgress, a2aEgressContext, a2aInbound, a2aAgents, pendingEvents, messageLogs, nodes, } from '../db/schema.js';
3
+ import { messages, channels, agents, dmConversations, dmConversationReservations, dmParticipants, messageAttachments, a2aEgress, a2aEgressContext, a2aInbound, a2aAgents, pendingEvents, messageLogs, nodes, directDmIdempotency, } from '../db/schema.js';
4
4
  import { sha256Hex } from '../lib/crypto.js';
5
5
  import { runAtomicWrites, databaseConstraintKind } from '../ports/database.js';
6
6
  import { generateId } from './snowflake.js';
@@ -8,7 +8,7 @@ import * as a2aEngine from './a2a.js';
8
8
  import { buildMessageLogWrite } from './console.js';
9
9
  import { buildDirectDeliveryWrite, fetchDirectDeliveryOutcomes, } from './deliveryWrites.js';
10
10
  import { DEFAULT_MAILBOX_DEPTH_CAP, DEFAULT_MAILBOX_TTL_MS } from './mailboxConfig.js';
11
- import { dispatchA2aEgress } from './a2aEgress.js';
11
+ import { A2A_EGRESS_RETRY_WINDOW_MS, dispatchA2aEgress, expireA2aEgressForReuse } from './a2aEgress.js';
12
12
  import { buildDmReceivedEventData } from './deliveryWire.js';
13
13
  import { buildWorkspaceEventWrite } from './workspaceEvents.js';
14
14
  import { transformForClient } from './wsTransform.js';
@@ -16,8 +16,9 @@ import { codedError } from '../lib/httpError.js';
16
16
  import { addressNodeSelection, addressNotFound, addressSplits, formatAgentAddress, selectAddressedRecipient, SENDER_ADDRESS_METADATA_KEY, senderAddressField, } from './address.js';
17
17
  import { buildMessageSessionWrite, requireSessionRefFromMetadata } from './sessionMessages.js';
18
18
  import { fetchAttachmentsBatch, resolveSendAttachments } from './attachments.js';
19
- import { canonicalUserMessageMetadata, publicMessageMetadata, sanitizeUserMessageMetadata } from './messageMetadata.js';
19
+ import { canonicalJson, canonicalUserMessageMetadata, publicMessageMetadata, sanitizeUserMessageMetadata } from './messageMetadata.js';
20
20
  import { queryInChunks } from '../lib/queryChunks.js';
21
+ const DIRECT_DM_IDEMPOTENCY_TTL_MS = 24 * 60 * 60 * 1000;
21
22
  /**
22
23
  * Derivation only: this digest does not resolve or claim a conversation.
23
24
  * Callers must atomically reserve the derived id before using it.
@@ -336,19 +337,90 @@ async function promoteLegacyInbound(db, workspaceId, fromAgentId, inboundId, fin
336
337
  throw codedError('Accepted A2A message is no longer retained', 'a2a_message_not_retained', 410);
337
338
  return { ...retained.response, _delivery: null, _delivery_rejections: [], _notifications_durable: true };
338
339
  }
340
+ async function replayAcceptedA2aEgress(db, id) {
341
+ try {
342
+ await dispatchA2aEgress(db, id);
343
+ }
344
+ catch (error) {
345
+ // The durable receipt is stable only while another sender or retry lease
346
+ // owns transport. Retention, target, expiry, and upstream errors still
347
+ // preserve their original typed replay contract.
348
+ if (error.code !== 'a2a_egress_in_progress')
349
+ throw error;
350
+ }
351
+ }
339
352
  export async function sendDm(db, workspaceId, fromAgentId, data, options = {}) {
340
353
  const startedAtMs = Date.now();
341
- // Resolve durable request identity before mutable recipient/attachment metadata.
342
- // A removed/recreated target must never turn an accepted retry into a new send.
354
+ const directRequestId = options.idempotencyKey
355
+ ? `dmid_${await sha256Hex(JSON.stringify([workspaceId, fromAgentId, options.idempotencyKey]))}`
356
+ : null;
357
+ const directFingerprint = directRequestId
358
+ ? await sha256Hex(canonicalJson({ data, address: options.address ?? null }))
359
+ : '';
360
+ // The request claim is transport-independent. If the recipient changes
361
+ // between direct and A2A routing, both attempts still contend on one ID.
343
362
  const requestEgressId = !options.skipA2aIntercept && options.idempotencyKey
344
363
  ? `a2ae_${await sha256Hex(JSON.stringify([workspaceId, fromAgentId, options.idempotencyKey]))}`
345
364
  : null;
346
- const [accepted] = requestEgressId ? await db.select().from(a2aEgress).where(eq(a2aEgress.id, requestEgressId)) : [];
365
+ const requestEgressFingerprint = requestEgressId
366
+ ? await sha256Hex(canonicalJson(data))
367
+ : '';
368
+ const legacyRequestEgressFingerprint = requestEgressId
369
+ ? await sha256Hex(JSON.stringify(data))
370
+ : '';
371
+ const idempotencyNow = new Date();
372
+ let [acceptedDirect] = directRequestId
373
+ ? await db.select().from(directDmIdempotency).where(eq(directDmIdempotency.id, directRequestId))
374
+ : [];
375
+ if (acceptedDirect
376
+ && acceptedDirect.createdAt.getTime() + DIRECT_DM_IDEMPOTENCY_TTL_MS <= idempotencyNow.getTime()) {
377
+ await db.delete(directDmIdempotency).where(and(eq(directDmIdempotency.id, acceptedDirect.id), lte(directDmIdempotency.createdAt, new Date(idempotencyNow.getTime() - DIRECT_DM_IDEMPOTENCY_TTL_MS))));
378
+ [acceptedDirect] = await db
379
+ .select()
380
+ .from(directDmIdempotency)
381
+ .where(eq(directDmIdempotency.id, directRequestId));
382
+ }
383
+ if (acceptedDirect) {
384
+ if (acceptedDirect.fingerprint !== directFingerprint) {
385
+ throw codedError('Idempotency-Key was reused with a different request payload', 'idempotency_key_reused', 409);
386
+ }
387
+ const [acceptedEgress] = requestEgressId
388
+ ? await db.select().from(a2aEgress).where(eq(a2aEgress.id, requestEgressId))
389
+ : [];
390
+ if (acceptedEgress)
391
+ await replayAcceptedA2aEgress(db, acceptedEgress.id);
392
+ return {
393
+ ...acceptedDirect.response,
394
+ _delivery: null,
395
+ _delivery_rejections: [],
396
+ _notifications_durable: true,
397
+ _idempotency_replayed: true,
398
+ _idempotency_ttl_seconds: Math.max(0, Math.floor((acceptedDirect.createdAt.getTime() + DIRECT_DM_IDEMPOTENCY_TTL_MS - Date.now()) / 1000)),
399
+ };
400
+ }
401
+ // Resolve durable request identity before mutable recipient/attachment metadata.
402
+ // A removed/recreated target must never turn an accepted retry into a new send.
403
+ let accepted = requestEgressId
404
+ ? (await db.select().from(a2aEgress).where(eq(a2aEgress.id, requestEgressId)))[0]
405
+ : undefined;
406
+ if (accepted
407
+ && accepted.createdAt.getTime() + A2A_EGRESS_RETRY_WINDOW_MS <= idempotencyNow.getTime()) {
408
+ const deleted = await expireA2aEgressForReuse(db, accepted.id, idempotencyNow);
409
+ if (deleted) {
410
+ accepted = undefined;
411
+ }
412
+ else {
413
+ // A live transport lease may have won between the read and conditional
414
+ // delete. Re-read the row rather than admitting a competing identity.
415
+ [accepted] = await db.select().from(a2aEgress).where(eq(a2aEgress.id, requestEgressId));
416
+ }
417
+ }
347
418
  if (accepted) {
348
- if (accepted.fingerprint !== await sha256Hex(JSON.stringify(data))) {
419
+ if (accepted.fingerprint !== requestEgressFingerprint
420
+ && accepted.fingerprint !== legacyRequestEgressFingerprint) {
349
421
  throw codedError('Idempotency-Key was reused with a different request payload', 'idempotency_key_reused', 409);
350
422
  }
351
- await dispatchA2aEgress(db, accepted.id);
423
+ await replayAcceptedA2aEgress(db, accepted.id);
352
424
  let [context] = await db.select().from(a2aEgressContext).where(eq(a2aEgressContext.id, accepted.id));
353
425
  if (!context) {
354
426
  // Upgrade compatibility for admissions predating 0058: recover only from
@@ -430,7 +502,9 @@ export async function sendDm(db, workspaceId, fromAgentId, data, options = {}) {
430
502
  const egressId = a2aTarget
431
503
  ? `a2ae_${await sha256Hex(JSON.stringify([workspaceId, fromAgentId, options.idempotencyKey ?? generateId()]))}`
432
504
  : null;
433
- const fingerprint = egressId ? await sha256Hex(JSON.stringify(data)) : '';
505
+ const fingerprint = egressId
506
+ ? requestEgressFingerprint || await sha256Hex(canonicalJson(data))
507
+ : '';
434
508
  const messageId = generateId();
435
509
  // Match SQLite timestamp precision so live, retained response and delivery replay agree.
436
510
  const createdAt = new Date(Math.floor(Date.now() / 1000) * 1000);
@@ -471,10 +545,26 @@ export async function sendDm(db, workspaceId, fromAgentId, data, options = {}) {
471
545
  const workspacePayload = transformForClient({
472
546
  type: 'dm.received', workspace_id: workspaceId, data: eventData, timestamp: createdAt.toISOString(),
473
547
  });
474
- // The outbox, observer cursor log, response context and delivery share admission.
475
- // None can escape a capacity rollback, or depend on external transport success.
548
+ const directClaimId = directRequestId;
549
+ const notificationsDurable = Boolean(egressId || options.receivedA2aAgentId || inboundId || directClaimId);
550
+ const persistWebhookOutbox = notificationsDurable && options.hasWebhookSubscriptions !== false;
551
+ // The optional webhook outbox, observer cursor log, response context and
552
+ // delivery share admission. None can escape a capacity rollback, or depend
553
+ // on external transport success.
476
554
  const persist = () => runAtomicWrites(db, (writeDb) => {
477
555
  const writes = buildDmMessageWrites(writeDb, workspaceId, fromAgentId, conv.channelId, data, attachments, messageId, createdAt, options.receivedA2aAgentId ? { id: options.receivedA2aAgentId, tokenHash: options.receivedA2aTokenHash } : undefined, senderAddress, addressedRecipient);
556
+ if (directClaimId) {
557
+ // The unique claim is the first statement in the atomic admission. A
558
+ // concurrent loser rolls back before any message or delivery can escape.
559
+ writes.unshift(writeDb.insert(directDmIdempotency).values({
560
+ id: directClaimId,
561
+ workspaceId,
562
+ messageId,
563
+ fingerprint: directFingerprint,
564
+ response: publicResult,
565
+ createdAt,
566
+ }));
567
+ }
478
568
  if (egressId && a2aTarget && egressPayload) {
479
569
  // First statement owns the request identity; a competing attempt rolls
480
570
  // back before it can consume capacity or invoke the external transport.
@@ -522,15 +612,18 @@ export async function sendDm(db, workspaceId, fromAgentId, data, options = {}) {
522
612
  writes.push(writeDb.insert(a2aInbound).values({ id: inboundId, workspaceId, messageId, fingerprint: inboundFingerprint, response: publicResult }));
523
613
  if (egressId)
524
614
  writes.push(writeDb.insert(a2aEgressContext).values({ id: egressId, messageId, response: publicResult }));
525
- if (egressId || options.receivedA2aAgentId || inboundId) {
526
- writes.push(writeDb.insert(pendingEvents).values({ id: messageId, workspaceId, eventType: 'dm.received', payload: eventData }), buildWorkspaceEventWrite(writeDb, workspaceId, { type: 'dm.received', payload: workspacePayload }));
615
+ if (persistWebhookOutbox) {
616
+ writes.push(writeDb.insert(pendingEvents).values({ id: messageId, workspaceId, eventType: 'dm.received', payload: eventData }));
617
+ }
618
+ if (notificationsDurable) {
619
+ writes.push(buildWorkspaceEventWrite(writeDb, workspaceId, { type: 'dm.received', payload: workspacePayload }));
527
620
  }
528
621
  return writes;
529
- }, { requireAtomic: Boolean(workspacePolicy || a2aTarget || options.receivedA2aAgentId || inboundId) });
622
+ }, { requireAtomic: Boolean(workspacePolicy || a2aTarget || options.receivedA2aAgentId || inboundId || directClaimId) });
530
623
  let admittedEventSeq;
531
624
  try {
532
625
  const results = await persist();
533
- if (egressId || options.receivedA2aAgentId || inboundId)
626
+ if (notificationsDurable)
534
627
  admittedEventSeq = results[results.length - 1][0].seq;
535
628
  }
536
629
  catch (error) {
@@ -548,11 +641,21 @@ export async function sendDm(db, workspaceId, fromAgentId, data, options = {}) {
548
641
  return sendDm(db, workspaceId, fromAgentId, data, options);
549
642
  }
550
643
  }
644
+ if (directClaimId) {
645
+ const [winner] = await db.select().from(directDmIdempotency).where(eq(directDmIdempotency.id, directClaimId));
646
+ if (winner) {
647
+ if (winner.fingerprint !== directFingerprint) {
648
+ throw codedError('Idempotency-Key was reused with a different request payload', 'idempotency_key_reused', 409);
649
+ }
650
+ return sendDm(db, workspaceId, fromAgentId, data, options);
651
+ }
652
+ }
551
653
  // Inspect the actual committed winner after the losing atomic batch rolls back.
552
654
  const [winner] = egressId ? await db.select().from(a2aEgress).where(eq(a2aEgress.id, egressId)) : [];
553
655
  if (!winner)
554
656
  throw error;
555
- if (winner.fingerprint !== fingerprint) {
657
+ if (winner.fingerprint !== fingerprint
658
+ && winner.fingerprint !== legacyRequestEgressFingerprint) {
556
659
  throw codedError('Idempotency-Key was reused with a different request payload', 'idempotency_key_reused', 409);
557
660
  }
558
661
  return sendDm(db, workspaceId, fromAgentId, data, options);
@@ -565,15 +668,23 @@ export async function sendDm(db, workspaceId, fromAgentId, data, options = {}) {
565
668
  ...publicResult,
566
669
  _delivery: dmDelivery,
567
670
  _delivery_rejections: deliveryOutcomes.rejections,
568
- ...((egressId || options.receivedA2aAgentId || inboundId) ? { _notifications_durable: true } : {}),
671
+ ...(notificationsDurable ? { _notifications_durable: true } : {}),
569
672
  };
570
- if (egressId || options.receivedA2aAgentId || inboundId) {
673
+ if (notificationsDurable) {
571
674
  // Local fast paths run independently of transport. A crash here still leaves
572
- // the webhook outbox, workspace cursor log and queued delivery recoverable.
573
- options.afterAdmission?.(result, { seq: admittedEventSeq, payload: workspacePayload, data: eventData, outboxId: messageId });
675
+ // any needed webhook outbox, workspace cursor log and queued delivery recoverable.
676
+ options.afterAdmission?.(result, {
677
+ seq: admittedEventSeq, payload: workspacePayload, data: eventData,
678
+ ...(persistWebhookOutbox ? { outboxId: messageId } : {}),
679
+ });
574
680
  }
575
681
  if (egressId)
576
682
  await dispatchA2aEgress(db, egressId);
683
+ if (directClaimId) {
684
+ // Compute this after transport work so a slow A2A dispatch cannot refill KV
685
+ // beyond the authoritative claim's absolute 24-hour lifetime.
686
+ result._idempotency_ttl_seconds = Math.max(0, Math.floor((createdAt.getTime() + DIRECT_DM_IDEMPOTENCY_TTL_MS - Date.now()) / 1000));
687
+ }
577
688
  return result;
578
689
  }
579
690
  export async function listConversations(db, workspaceId, agentId, opts = {}) {