@creatornader/agent-bridge 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -4
- package/README.md +567 -55
- package/ROADMAP.md +114 -0
- package/SECURITY.md +90 -0
- package/SKILL.md +68 -2
- package/bin/agent-bridge +2 -2
- package/clients/claude-desktop.json +3 -1
- package/dist/archive.d.ts +163 -0
- package/dist/archive.js +50 -0
- package/dist/archive.js.map +1 -0
- package/dist/bridge-domain-CBX3IVqC.d.ts +153 -0
- package/dist/{bridge-service-CfqMcMAn.d.ts → bridge-service-hX1ZQp4W.d.ts} +15 -5
- package/dist/bridge-store-DPVSCwfs.d.ts +102 -0
- package/dist/bridge.d.ts +76 -17
- package/dist/bridge.js +52 -24
- package/dist/chunk-2DFNOLMO.js +618 -0
- package/dist/chunk-2DFNOLMO.js.map +1 -0
- package/dist/{chunk-KVR4JBRF.js → chunk-2EVLG3YA.js} +2 -2
- package/dist/{chunk-KVR4JBRF.js.map → chunk-2EVLG3YA.js.map} +1 -1
- package/dist/chunk-45BZGB77.js +709 -0
- package/dist/chunk-45BZGB77.js.map +1 -0
- package/dist/chunk-4VB44KJU.js +230 -0
- package/dist/chunk-4VB44KJU.js.map +1 -0
- package/dist/chunk-5GMB3A77.js +1013 -0
- package/dist/chunk-5GMB3A77.js.map +1 -0
- package/dist/chunk-A6W4QALF.js +1258 -0
- package/dist/chunk-A6W4QALF.js.map +1 -0
- package/dist/chunk-BZLMF5O5.js +328 -0
- package/dist/chunk-BZLMF5O5.js.map +1 -0
- package/dist/{chunk-AXL2I7FH.js → chunk-CEXBMOI5.js} +240 -79
- package/dist/chunk-CEXBMOI5.js.map +1 -0
- package/dist/chunk-GADH244D.js +527 -0
- package/dist/chunk-GADH244D.js.map +1 -0
- package/dist/chunk-MBPZXTJA.js +2428 -0
- package/dist/chunk-MBPZXTJA.js.map +1 -0
- package/dist/chunk-NCO7RLBM.js +146 -0
- package/dist/chunk-NCO7RLBM.js.map +1 -0
- package/dist/chunk-Q6PPMXJC.js +1050 -0
- package/dist/chunk-Q6PPMXJC.js.map +1 -0
- package/dist/{chunk-4KAOBC5X.js → chunk-SPSMZOCJ.js} +190 -165
- package/dist/chunk-SPSMZOCJ.js.map +1 -0
- package/dist/chunk-UAHMP6GC.js +54 -0
- package/dist/chunk-UAHMP6GC.js.map +1 -0
- package/dist/{chunk-YD6YJATN.js → chunk-VOQIDTCJ.js} +4 -2
- package/dist/chunk-VOQIDTCJ.js.map +1 -0
- package/dist/chunk-WAI2IYIQ.js +554 -0
- package/dist/chunk-WAI2IYIQ.js.map +1 -0
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +3555 -214
- package/dist/cli.js.map +1 -1
- package/dist/client-config.d.ts +1 -1
- package/dist/client-config.js +1 -1
- package/dist/client-runtime.d.ts +10 -6
- package/dist/client-runtime.js +9 -6
- package/dist/contracts/generate.d.ts +2 -0
- package/dist/contracts/generate.js +247 -0
- package/dist/contracts/generate.js.map +1 -0
- package/dist/dr.d.ts +324 -0
- package/dist/dr.js +124 -0
- package/dist/dr.js.map +1 -0
- package/dist/gateway-CggQ8vTC.d.ts +78 -0
- package/dist/gateway-main.js +190 -8
- package/dist/gateway-main.js.map +1 -1
- package/dist/gateway.d.ts +4 -3
- package/dist/gateway.js +4 -3
- package/dist/index.js +11 -8
- package/dist/index.js.map +1 -1
- package/dist/postgres-bridge-store-Bfd3hRId.d.ts +49 -0
- package/dist/server.d.ts +3 -2
- package/dist/server.js +13 -8
- package/dist/sqlite.d.ts +94 -12
- package/dist/sqlite.js +7 -4
- package/docs/architecture-v2.md +394 -0
- package/docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md +85 -0
- package/docs/decisions/0002-canonical-operation-contract-registry.md +46 -0
- package/docs/decisions/0003-host-adapters-and-consumer-instance-keys.md +88 -0
- package/docs/ecosystem.md +86 -0
- package/docs/postmortems/2026-07-08-wrapper-source-drift.md +82 -0
- package/docs/troubleshooting.md +89 -0
- package/llms.txt +107 -6
- package/openapi/agent-bridge-v2.openapi.json +9610 -0
- package/package.json +24 -4
- package/schemas/agent-bridge-v2.capabilities.json +1829 -0
- package/schemas/agent-bridge-v2.mcp.json +2074 -0
- package/schemas/agent-bridge-v2.schema.json +4560 -0
- package/sql/migrations/008_message_projects.sql +36 -0
- package/sql/migrations/009_mailbox_query_indexes.sql +28 -0
- package/sql/migrations/010_publisher_delivery_policy.sql +210 -0
- package/sql/migrations/011_credential_security.sql +875 -0
- package/sql/migrations/012_request_authority.sql +177 -0
- package/sql/migrations/013_row_isolation.sql +495 -0
- package/sql/migrations/014_owner_control_plane.sql +1641 -0
- package/sql/migrations/015_portable_archives.sql +1813 -0
- package/sql/migrations/016_native_dr_fence.sql +1005 -0
- package/bin/CLAUDE.md +0 -11
- package/dist/bridge-domain-BcnBeHOn.d.ts +0 -97
- package/dist/bridge-store-BuGjxTn4.d.ts +0 -61
- package/dist/chunk-4KAOBC5X.js.map +0 -1
- package/dist/chunk-6MAZ6YLZ.js +0 -146
- package/dist/chunk-6MAZ6YLZ.js.map +0 -1
- package/dist/chunk-AXL2I7FH.js.map +0 -1
- package/dist/chunk-BV6W4AJK.js +0 -211
- package/dist/chunk-BV6W4AJK.js.map +0 -1
- package/dist/chunk-CKSKUBDQ.js +0 -153
- package/dist/chunk-CKSKUBDQ.js.map +0 -1
- package/dist/chunk-JOUBDRYX.js +0 -272
- package/dist/chunk-JOUBDRYX.js.map +0 -1
- package/dist/chunk-JTC5YURG.js +0 -49
- package/dist/chunk-JTC5YURG.js.map +0 -1
- package/dist/chunk-O26W5QHS.js +0 -409
- package/dist/chunk-O26W5QHS.js.map +0 -1
- package/dist/chunk-WEULPMUY.js +0 -988
- package/dist/chunk-WEULPMUY.js.map +0 -1
- package/dist/chunk-YD6YJATN.js.map +0 -1
- package/dist/gateway-BULozv3K.d.ts +0 -54
package/dist/chunk-O26W5QHS.js
DELETED
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
assertIdempotentReplay
|
|
4
|
-
} from "./chunk-YD6YJATN.js";
|
|
5
|
-
import {
|
|
6
|
-
decodeCursor,
|
|
7
|
-
encodeCursor
|
|
8
|
-
} from "./chunk-BV6W4AJK.js";
|
|
9
|
-
|
|
10
|
-
// src/postgres-bridge-store.ts
|
|
11
|
-
import { randomUUID } from "crypto";
|
|
12
|
-
function json(value) {
|
|
13
|
-
return value === void 0 ? null : JSON.stringify(value);
|
|
14
|
-
}
|
|
15
|
-
function parse(value) {
|
|
16
|
-
return typeof value === "string" ? JSON.parse(value) : value;
|
|
17
|
-
}
|
|
18
|
-
function asTimestamp(value) {
|
|
19
|
-
if (value === void 0 || value === null) return void 0;
|
|
20
|
-
if (value instanceof Date) return value.toISOString();
|
|
21
|
-
return String(value);
|
|
22
|
-
}
|
|
23
|
-
function asMessage(row) {
|
|
24
|
-
return {
|
|
25
|
-
id: String(row.id),
|
|
26
|
-
workspace: String(row.workspace),
|
|
27
|
-
source: String(row.source),
|
|
28
|
-
sequence: String(row.sequence),
|
|
29
|
-
type: String(row.type),
|
|
30
|
-
content: String(row.content),
|
|
31
|
-
contentType: String(row.content_type),
|
|
32
|
-
data: parse(row.data),
|
|
33
|
-
targets: parse(row.targets) ?? [],
|
|
34
|
-
threadId: row.thread_id ?? void 0,
|
|
35
|
-
replyToId: row.reply_to_id ?? void 0,
|
|
36
|
-
correlationId: row.correlation_id ?? void 0,
|
|
37
|
-
causationId: row.causation_id ?? void 0,
|
|
38
|
-
priority: row.priority,
|
|
39
|
-
expiresAt: asTimestamp(row.expires_at),
|
|
40
|
-
idempotencyKey: row.idempotency_key ?? void 0,
|
|
41
|
-
atribReceiptId: row.atrib_receipt_id ?? void 0,
|
|
42
|
-
informedBy: parse(row.informed_by),
|
|
43
|
-
metadata: parse(row.metadata),
|
|
44
|
-
createdAt: asTimestamp(row.created_at) ?? ""
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function asDelivery(row) {
|
|
48
|
-
return {
|
|
49
|
-
id: String(row.id),
|
|
50
|
-
messageId: String(row.message_id),
|
|
51
|
-
workspace: String(row.workspace),
|
|
52
|
-
recipient: String(row.recipient),
|
|
53
|
-
state: row.state,
|
|
54
|
-
attempt: Number(row.attempt),
|
|
55
|
-
availableAt: asTimestamp(row.available_at) ?? "",
|
|
56
|
-
leaseToken: row.lease_token ?? void 0,
|
|
57
|
-
leaseOwner: row.lease_owner ?? void 0,
|
|
58
|
-
leaseExpiresAt: asTimestamp(row.lease_expires_at),
|
|
59
|
-
lastError: row.last_error ?? void 0
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
function asPresence(row) {
|
|
63
|
-
return {
|
|
64
|
-
workspace: String(row.workspace),
|
|
65
|
-
agent: String(row.agent),
|
|
66
|
-
instance: String(row.instance),
|
|
67
|
-
runtimeType: row.runtime_type ?? void 0,
|
|
68
|
-
capabilities: parse(row.capabilities) ?? [],
|
|
69
|
-
leaseExpiresAt: asTimestamp(row.lease_expires_at) ?? "",
|
|
70
|
-
lastSeenAt: asTimestamp(row.last_seen_at) ?? ""
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
function asDeliveryEvent(row) {
|
|
74
|
-
return {
|
|
75
|
-
sequence: String(row.sequence),
|
|
76
|
-
deliveryId: String(row.delivery_id),
|
|
77
|
-
messageId: String(row.message_id),
|
|
78
|
-
workspace: String(row.workspace),
|
|
79
|
-
recipient: String(row.recipient),
|
|
80
|
-
fromState: row.from_state,
|
|
81
|
-
toState: row.to_state,
|
|
82
|
-
attempt: Number(row.attempt),
|
|
83
|
-
leaseOwner: row.lease_owner ?? void 0,
|
|
84
|
-
error: row.error ?? void 0,
|
|
85
|
-
createdAt: asTimestamp(row.created_at) ?? ""
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
var PostgresBridgeStore = class {
|
|
89
|
-
constructor(db) {
|
|
90
|
-
this.db = db;
|
|
91
|
-
}
|
|
92
|
-
async initialize() {
|
|
93
|
-
}
|
|
94
|
-
async insertMessage(input) {
|
|
95
|
-
const values = [
|
|
96
|
-
input.id,
|
|
97
|
-
input.workspace,
|
|
98
|
-
input.source,
|
|
99
|
-
input.type,
|
|
100
|
-
input.content,
|
|
101
|
-
input.contentType,
|
|
102
|
-
json(input.data),
|
|
103
|
-
json(input.targets),
|
|
104
|
-
input.threadId ?? null,
|
|
105
|
-
input.replyToId ?? null,
|
|
106
|
-
input.correlationId ?? null,
|
|
107
|
-
input.causationId ?? null,
|
|
108
|
-
input.priority,
|
|
109
|
-
input.expiresAt ?? null,
|
|
110
|
-
input.idempotencyKey ?? null,
|
|
111
|
-
input.atribReceiptId ?? null,
|
|
112
|
-
json(input.informedBy),
|
|
113
|
-
json(input.metadata)
|
|
114
|
-
];
|
|
115
|
-
const result = await this.db.query(
|
|
116
|
-
`WITH inserted AS (
|
|
117
|
-
INSERT INTO agent_bridge.messages (
|
|
118
|
-
id, workspace, source, type, content, content_type, data, targets,
|
|
119
|
-
thread_id, reply_to_id, correlation_id, causation_id, priority,
|
|
120
|
-
expires_at, idempotency_key, atrib_receipt_id, informed_by, metadata
|
|
121
|
-
)
|
|
122
|
-
VALUES (
|
|
123
|
-
$1, $2, $3, $4, $5, $6, $7::jsonb, $8::jsonb,
|
|
124
|
-
$9, $10, $11, $12, $13, $14, $15, $16, $17::jsonb, $18::jsonb
|
|
125
|
-
)
|
|
126
|
-
ON CONFLICT (workspace, source, idempotency_key)
|
|
127
|
-
WHERE idempotency_key IS NOT NULL
|
|
128
|
-
DO NOTHING
|
|
129
|
-
RETURNING *, true AS created
|
|
130
|
-
), selected AS (
|
|
131
|
-
SELECT * FROM inserted
|
|
132
|
-
UNION ALL
|
|
133
|
-
SELECT existing.*, false AS created
|
|
134
|
-
FROM agent_bridge.messages existing
|
|
135
|
-
WHERE $15::text IS NOT NULL
|
|
136
|
-
AND existing.workspace = $2
|
|
137
|
-
AND existing.source = $3
|
|
138
|
-
AND existing.idempotency_key = $15
|
|
139
|
-
AND NOT EXISTS (SELECT 1 FROM inserted)
|
|
140
|
-
LIMIT 1
|
|
141
|
-
), delivery_rows AS (
|
|
142
|
-
INSERT INTO agent_bridge.deliveries (
|
|
143
|
-
id, message_id, workspace, recipient, state, available_at
|
|
144
|
-
)
|
|
145
|
-
SELECT gen_random_uuid(), inserted.id, inserted.workspace, target, 'pending', now()
|
|
146
|
-
FROM inserted
|
|
147
|
-
CROSS JOIN LATERAL jsonb_array_elements_text(inserted.targets) AS target
|
|
148
|
-
ON CONFLICT (message_id, recipient) DO NOTHING
|
|
149
|
-
)
|
|
150
|
-
SELECT * FROM selected`,
|
|
151
|
-
values
|
|
152
|
-
);
|
|
153
|
-
let row = result.rows[0];
|
|
154
|
-
if (!row && input.idempotencyKey) {
|
|
155
|
-
const existing = await this.db.query(
|
|
156
|
-
`SELECT *, false AS created
|
|
157
|
-
FROM agent_bridge.messages
|
|
158
|
-
WHERE workspace=$1 AND source=$2 AND idempotency_key=$3`,
|
|
159
|
-
[input.workspace, input.source, input.idempotencyKey]
|
|
160
|
-
);
|
|
161
|
-
row = existing.rows[0];
|
|
162
|
-
}
|
|
163
|
-
if (!row) throw new Error("message insert did not return a row");
|
|
164
|
-
const message = asMessage(row);
|
|
165
|
-
if (row.created !== true) assertIdempotentReplay(message, input);
|
|
166
|
-
return { message, created: row.created === true };
|
|
167
|
-
}
|
|
168
|
-
async listMessages(principal, query = {}) {
|
|
169
|
-
const cursor = decodeCursor(query.cursor) ?? "0";
|
|
170
|
-
const limit = Math.min(Math.max(Math.trunc(query.limit ?? 50), 1), 200);
|
|
171
|
-
const boundary = query.latest ? void 0 : await this.db.query(
|
|
172
|
-
"SELECT max(sequence)::text AS sequence FROM agent_bridge.messages WHERE workspace=$1",
|
|
173
|
-
[principal.workspace]
|
|
174
|
-
);
|
|
175
|
-
const highWater = boundary?.rows[0]?.sequence;
|
|
176
|
-
const values = query.latest ? [principal.workspace, principal.agent] : [principal.workspace, cursor, principal.agent];
|
|
177
|
-
let sql = `SELECT * FROM agent_bridge.messages WHERE workspace=$1 ${query.latest ? "" : "AND sequence>$2::bigint "}AND (targets='[]'::jsonb OR targets ? $${query.latest ? 2 : 3})`;
|
|
178
|
-
if (highWater) {
|
|
179
|
-
values.push(highWater);
|
|
180
|
-
sql += ` AND sequence <= $${values.length}::bigint`;
|
|
181
|
-
}
|
|
182
|
-
if (!query.includeExpired) {
|
|
183
|
-
sql += " AND (expires_at IS NULL OR expires_at > now())";
|
|
184
|
-
}
|
|
185
|
-
if (query.types?.length) {
|
|
186
|
-
values.push(query.types);
|
|
187
|
-
sql += ` AND type = ANY($${values.length})`;
|
|
188
|
-
}
|
|
189
|
-
if (query.source) {
|
|
190
|
-
values.push(query.source);
|
|
191
|
-
sql += ` AND source = $${values.length}`;
|
|
192
|
-
}
|
|
193
|
-
if (query.since) {
|
|
194
|
-
values.push(query.since);
|
|
195
|
-
sql += ` AND created_at >= $${values.length}::timestamptz`;
|
|
196
|
-
}
|
|
197
|
-
if (query.unacknowledgedBy) {
|
|
198
|
-
values.push(query.unacknowledgedBy);
|
|
199
|
-
sql += ` AND NOT EXISTS (
|
|
200
|
-
SELECT 1 FROM agent_bridge.receipts receipt
|
|
201
|
-
WHERE receipt.workspace=agent_bridge.messages.workspace
|
|
202
|
-
AND receipt.message_id=agent_bridge.messages.id
|
|
203
|
-
AND receipt.principal=$${values.length}
|
|
204
|
-
)`;
|
|
205
|
-
}
|
|
206
|
-
if (query.threadId) {
|
|
207
|
-
values.push(query.threadId);
|
|
208
|
-
sql += ` AND thread_id = $${values.length}`;
|
|
209
|
-
}
|
|
210
|
-
values.push(limit);
|
|
211
|
-
const result = await this.db.query(
|
|
212
|
-
`${sql} ORDER BY sequence ${query.latest ? "DESC" : "ASC"} LIMIT $${values.length}`,
|
|
213
|
-
values
|
|
214
|
-
);
|
|
215
|
-
const messages = result.rows.map(asMessage);
|
|
216
|
-
const last = messages[messages.length - 1];
|
|
217
|
-
if (query.latest) return { messages, cursor: messages[0] ? encodeCursor(messages[0].sequence) : query.cursor };
|
|
218
|
-
if (messages.length === limit) return { messages, cursor: encodeCursor(last.sequence) };
|
|
219
|
-
return { messages, cursor: highWater ? encodeCursor(highWater) : query.cursor };
|
|
220
|
-
}
|
|
221
|
-
async recordReceipt(workspace, ids, principal, readAt = /* @__PURE__ */ new Date()) {
|
|
222
|
-
const result = await this.db.query(
|
|
223
|
-
`INSERT INTO agent_bridge.receipts (workspace, message_id, principal, read_at)
|
|
224
|
-
SELECT message.workspace, message.id, $3, $4
|
|
225
|
-
FROM agent_bridge.messages message
|
|
226
|
-
WHERE message.workspace = $1 AND message.id = ANY($2::uuid[])
|
|
227
|
-
AND (message.targets='[]'::jsonb OR message.targets ? $3)
|
|
228
|
-
ON CONFLICT DO NOTHING`,
|
|
229
|
-
[workspace, ids, principal, readAt]
|
|
230
|
-
);
|
|
231
|
-
return result.rowCount ?? 0;
|
|
232
|
-
}
|
|
233
|
-
async claimDelivery(principal, options) {
|
|
234
|
-
const owner = principal.instance ?? principal.agent;
|
|
235
|
-
const token = randomUUID();
|
|
236
|
-
const result = await this.db.query(
|
|
237
|
-
`WITH expired AS (
|
|
238
|
-
UPDATE agent_bridge.deliveries delivery
|
|
239
|
-
SET state='dead', last_error='message expired', lease_token=NULL,
|
|
240
|
-
lease_owner=NULL, lease_expires_at=NULL
|
|
241
|
-
FROM agent_bridge.messages message
|
|
242
|
-
WHERE delivery.workspace=$1 AND delivery.recipient=$2
|
|
243
|
-
AND delivery.state IN ('pending', 'retrying', 'claimed')
|
|
244
|
-
AND message.workspace=delivery.workspace AND message.id=delivery.message_id
|
|
245
|
-
AND message.expires_at IS NOT NULL AND message.expires_at <= now()
|
|
246
|
-
RETURNING delivery.id
|
|
247
|
-
), exhausted AS (
|
|
248
|
-
UPDATE agent_bridge.deliveries delivery
|
|
249
|
-
SET state='dead', last_error='maximum attempts reached', lease_token=NULL,
|
|
250
|
-
lease_owner=NULL, lease_expires_at=NULL
|
|
251
|
-
WHERE delivery.workspace=$1 AND delivery.recipient=$2 AND delivery.attempt >= $6
|
|
252
|
-
AND (
|
|
253
|
-
delivery.state IN ('pending', 'retrying')
|
|
254
|
-
OR (delivery.state='claimed' AND delivery.lease_expires_at <= now())
|
|
255
|
-
)
|
|
256
|
-
RETURNING delivery.id
|
|
257
|
-
), candidate AS (
|
|
258
|
-
SELECT delivery.id
|
|
259
|
-
FROM agent_bridge.deliveries delivery
|
|
260
|
-
JOIN agent_bridge.messages message
|
|
261
|
-
ON message.workspace=delivery.workspace AND message.id=delivery.message_id
|
|
262
|
-
WHERE delivery.workspace=$1 AND delivery.recipient=$2
|
|
263
|
-
AND (
|
|
264
|
-
(delivery.state IN ('pending', 'retrying') AND delivery.available_at <= now())
|
|
265
|
-
OR (delivery.state='claimed' AND delivery.lease_expires_at <= now())
|
|
266
|
-
)
|
|
267
|
-
AND delivery.attempt < $6
|
|
268
|
-
AND (message.expires_at IS NULL OR message.expires_at > now())
|
|
269
|
-
ORDER BY delivery.available_at, delivery.id
|
|
270
|
-
FOR UPDATE OF delivery SKIP LOCKED
|
|
271
|
-
LIMIT 1
|
|
272
|
-
)
|
|
273
|
-
UPDATE agent_bridge.deliveries delivery
|
|
274
|
-
SET state='claimed', attempt=delivery.attempt+1, lease_token=$3,
|
|
275
|
-
lease_owner=$4, lease_expires_at=now() + ($5 * interval '1 millisecond')
|
|
276
|
-
FROM candidate
|
|
277
|
-
WHERE delivery.id=candidate.id
|
|
278
|
-
RETURNING delivery.*`,
|
|
279
|
-
[principal.workspace, principal.agent, token, owner, options.leaseMs, options.maxAttempts ?? 5]
|
|
280
|
-
);
|
|
281
|
-
return result.rows[0] ? asDelivery(result.rows[0]) : null;
|
|
282
|
-
}
|
|
283
|
-
async renewDelivery(principal, id, token, leaseMs) {
|
|
284
|
-
const result = await this.db.query(
|
|
285
|
-
`UPDATE agent_bridge.deliveries
|
|
286
|
-
SET lease_expires_at=now() + ($1 * interval '1 millisecond')
|
|
287
|
-
WHERE workspace=$2 AND recipient=$3 AND lease_owner=$4 AND id=$5 AND lease_token=$6
|
|
288
|
-
AND state='claimed' AND lease_expires_at>now()
|
|
289
|
-
RETURNING *`,
|
|
290
|
-
[leaseMs, principal.workspace, principal.agent, principal.instance ?? principal.agent, id, token]
|
|
291
|
-
);
|
|
292
|
-
return result.rows[0] ? asDelivery(result.rows[0]) : null;
|
|
293
|
-
}
|
|
294
|
-
async settleDelivery(principal, id, token, state, error, retryPolicy) {
|
|
295
|
-
if (!retryPolicy) throw new Error("retry policy is required");
|
|
296
|
-
const result = await this.db.query(
|
|
297
|
-
`UPDATE agent_bridge.deliveries
|
|
298
|
-
SET state=CASE
|
|
299
|
-
WHEN $1='retrying' AND attempt >= $6 THEN 'dead'
|
|
300
|
-
ELSE $1
|
|
301
|
-
END,
|
|
302
|
-
available_at=CASE
|
|
303
|
-
WHEN $1='retrying' AND attempt < $6 THEN
|
|
304
|
-
now() + (
|
|
305
|
-
LEAST($8::double precision, $7::double precision * power(2, GREATEST(attempt - 1, 0)))
|
|
306
|
-
* (1 + ((random() * 2) - 1) * $9::double precision)
|
|
307
|
-
* interval '1 millisecond'
|
|
308
|
-
)
|
|
309
|
-
ELSE available_at
|
|
310
|
-
END,
|
|
311
|
-
last_error=$2, lease_token=NULL, lease_owner=NULL, lease_expires_at=NULL
|
|
312
|
-
WHERE workspace=$3 AND recipient=$4 AND lease_owner=$5
|
|
313
|
-
AND id=$10 AND lease_token=$11 AND state='claimed' AND lease_expires_at>now()
|
|
314
|
-
RETURNING *`,
|
|
315
|
-
[
|
|
316
|
-
state,
|
|
317
|
-
error?.slice(0, 1024) ?? null,
|
|
318
|
-
principal.workspace,
|
|
319
|
-
principal.agent,
|
|
320
|
-
principal.instance ?? principal.agent,
|
|
321
|
-
retryPolicy.maxAttempts,
|
|
322
|
-
retryPolicy.baseDelayMs,
|
|
323
|
-
retryPolicy.maxDelayMs,
|
|
324
|
-
retryPolicy.jitterRatio,
|
|
325
|
-
id,
|
|
326
|
-
token
|
|
327
|
-
]
|
|
328
|
-
);
|
|
329
|
-
return result.rows[0] ? asDelivery(result.rows[0]) : null;
|
|
330
|
-
}
|
|
331
|
-
async diagnostics(principal) {
|
|
332
|
-
const result = await this.db.query(
|
|
333
|
-
`SELECT state, count(*)::integer AS count, min(available_at) AS oldest
|
|
334
|
-
FROM agent_bridge.deliveries
|
|
335
|
-
WHERE workspace=$1 AND recipient=$2
|
|
336
|
-
GROUP BY state`,
|
|
337
|
-
[principal.workspace, principal.agent]
|
|
338
|
-
);
|
|
339
|
-
const counts = new Map(result.rows.map((row) => [String(row.state), Number(row.count)]));
|
|
340
|
-
const oldest = result.rows.filter((row) => row.state === "pending" || row.state === "retrying").map((row) => asTimestamp(row.oldest)).filter((value) => Boolean(value)).sort()[0];
|
|
341
|
-
return {
|
|
342
|
-
schemaVersion: "postgres-v2",
|
|
343
|
-
deliverySupported: true,
|
|
344
|
-
pending: counts.get("pending") ?? 0,
|
|
345
|
-
claimed: counts.get("claimed") ?? 0,
|
|
346
|
-
retrying: counts.get("retrying") ?? 0,
|
|
347
|
-
dead: counts.get("dead") ?? 0,
|
|
348
|
-
oldestAvailableAt: oldest
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
async heartbeat(principal, leaseMs, runtimeType, capabilities = []) {
|
|
352
|
-
await this.db.query(
|
|
353
|
-
"DELETE FROM agent_bridge.agent_instances WHERE workspace=$1 AND lease_expires_at<=now()",
|
|
354
|
-
[principal.workspace]
|
|
355
|
-
);
|
|
356
|
-
const result = await this.db.query(
|
|
357
|
-
`WITH locked AS (
|
|
358
|
-
SELECT pg_advisory_xact_lock(hashtextextended($1, 0))
|
|
359
|
-
)
|
|
360
|
-
INSERT INTO agent_bridge.agent_instances (workspace,agent,instance,runtime_type,capabilities,lease_expires_at,last_seen_at)
|
|
361
|
-
SELECT $1,$2,$3,$4,$5::jsonb,now() + ($6 * interval '1 millisecond'),now()
|
|
362
|
-
FROM locked
|
|
363
|
-
WHERE EXISTS (
|
|
364
|
-
SELECT 1 FROM agent_bridge.agent_instances
|
|
365
|
-
WHERE workspace=$1 AND agent=$2 AND instance=$3
|
|
366
|
-
) OR ((
|
|
367
|
-
SELECT count(*) < 128 FROM agent_bridge.agent_instances
|
|
368
|
-
WHERE workspace=$1 AND agent=$2
|
|
369
|
-
) AND (
|
|
370
|
-
SELECT count(*) < 4096 FROM agent_bridge.agent_instances
|
|
371
|
-
WHERE workspace=$1
|
|
372
|
-
)
|
|
373
|
-
)
|
|
374
|
-
ON CONFLICT (workspace,agent,instance) DO UPDATE SET runtime_type=excluded.runtime_type,capabilities=excluded.capabilities,lease_expires_at=excluded.lease_expires_at,last_seen_at=excluded.last_seen_at
|
|
375
|
-
RETURNING *`,
|
|
376
|
-
[principal.workspace, principal.agent, principal.instance, runtimeType ?? null, JSON.stringify(capabilities), leaseMs]
|
|
377
|
-
);
|
|
378
|
-
if (!result.rows[0]) {
|
|
379
|
-
throw Object.assign(new Error("active instance limit reached"), {
|
|
380
|
-
status: 429,
|
|
381
|
-
code: "presence_limit"
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
return asPresence(result.rows[0]);
|
|
385
|
-
}
|
|
386
|
-
async listPresence(principal) {
|
|
387
|
-
await this.db.query(
|
|
388
|
-
"DELETE FROM agent_bridge.agent_instances WHERE workspace=$1 AND lease_expires_at<=now()",
|
|
389
|
-
[principal.workspace]
|
|
390
|
-
);
|
|
391
|
-
const result = await this.db.query(
|
|
392
|
-
"SELECT * FROM agent_bridge.agent_instances WHERE workspace=$1 ORDER BY agent,instance",
|
|
393
|
-
[principal.workspace]
|
|
394
|
-
);
|
|
395
|
-
return result.rows.map(asPresence);
|
|
396
|
-
}
|
|
397
|
-
async listDeliveryEvents(deliveryId) {
|
|
398
|
-
const result = await this.db.query(
|
|
399
|
-
"SELECT * FROM agent_bridge.delivery_events WHERE delivery_id=$1 ORDER BY sequence",
|
|
400
|
-
[deliveryId]
|
|
401
|
-
);
|
|
402
|
-
return result.rows.map(asDeliveryEvent);
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
export {
|
|
407
|
-
PostgresBridgeStore
|
|
408
|
-
};
|
|
409
|
-
//# sourceMappingURL=chunk-O26W5QHS.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/postgres-bridge-store.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n decodeCursor,\n encodeCursor,\n type AgentPresence,\n type BridgeDelivery,\n type BridgeDeliveryEvent,\n type BridgeMessage,\n type BridgePrincipal,\n type RetryPolicy,\n} from \"./bridge-domain.js\";\nimport type {\n BridgeStore,\n BridgeDiagnostics,\n ClaimOptions,\n InsertMessageResult,\n MessagePage,\n MessageQuery,\n} from \"./bridge-store.js\";\nimport { assertIdempotentReplay } from \"./idempotency.js\";\n\nexport interface PgQueryable {\n query<T extends Record<string, unknown> = Record<string, unknown>>(\n sql: string,\n values?: unknown[],\n ): Promise<{ rows: T[]; rowCount: number | null }>;\n}\n\ntype Row = Record<string, any>;\n\nfunction json(value: unknown): string | null {\n return value === undefined ? null : JSON.stringify(value);\n}\n\nfunction parse(value: unknown): any {\n return typeof value === \"string\" ? JSON.parse(value) : value;\n}\n\nfunction asTimestamp(value: unknown): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (value instanceof Date) return value.toISOString();\n return String(value);\n}\n\nfunction asMessage(row: Row): BridgeMessage {\n return {\n id: String(row.id),\n workspace: String(row.workspace),\n source: String(row.source),\n sequence: String(row.sequence),\n type: String(row.type),\n content: String(row.content),\n contentType: String(row.content_type),\n data: parse(row.data),\n targets: parse(row.targets) ?? [],\n threadId: row.thread_id ?? undefined,\n replyToId: row.reply_to_id ?? undefined,\n correlationId: row.correlation_id ?? undefined,\n causationId: row.causation_id ?? undefined,\n priority: row.priority,\n expiresAt: asTimestamp(row.expires_at),\n idempotencyKey: row.idempotency_key ?? undefined,\n atribReceiptId: row.atrib_receipt_id ?? undefined,\n informedBy: parse(row.informed_by),\n metadata: parse(row.metadata),\n createdAt: asTimestamp(row.created_at) ?? \"\",\n };\n}\n\nfunction asDelivery(row: Row): BridgeDelivery {\n return {\n id: String(row.id),\n messageId: String(row.message_id),\n workspace: String(row.workspace),\n recipient: String(row.recipient),\n state: row.state,\n attempt: Number(row.attempt),\n availableAt: asTimestamp(row.available_at) ?? \"\",\n leaseToken: row.lease_token ?? undefined,\n leaseOwner: row.lease_owner ?? undefined,\n leaseExpiresAt: asTimestamp(row.lease_expires_at),\n lastError: row.last_error ?? undefined,\n };\n}\n\nfunction asPresence(row: Row): AgentPresence {\n return {\n workspace: String(row.workspace), agent: String(row.agent), instance: String(row.instance),\n runtimeType: row.runtime_type ?? undefined, capabilities: parse(row.capabilities) ?? [],\n leaseExpiresAt: asTimestamp(row.lease_expires_at) ?? \"\", lastSeenAt: asTimestamp(row.last_seen_at) ?? \"\",\n };\n}\n\nfunction asDeliveryEvent(row: Row): BridgeDeliveryEvent {\n return {\n sequence: String(row.sequence), deliveryId: String(row.delivery_id),\n messageId: String(row.message_id), workspace: String(row.workspace),\n recipient: String(row.recipient), fromState: row.from_state as BridgeDeliveryEvent[\"fromState\"],\n toState: row.to_state as BridgeDeliveryEvent[\"toState\"], attempt: Number(row.attempt),\n leaseOwner: row.lease_owner ?? undefined, error: row.error ?? undefined,\n createdAt: asTimestamp(row.created_at) ?? \"\",\n };\n}\n\nexport class PostgresBridgeStore implements BridgeStore {\n constructor(private readonly db: PgQueryable) {}\n\n async initialize(): Promise<void> {\n // Deployments apply ordered migrations before starting the service.\n }\n\n async insertMessage(\n input: Omit<BridgeMessage, \"sequence\" | \"createdAt\">,\n ): Promise<InsertMessageResult> {\n const values = [\n input.id,\n input.workspace,\n input.source,\n input.type,\n input.content,\n input.contentType,\n json(input.data),\n json(input.targets),\n input.threadId ?? null,\n input.replyToId ?? null,\n input.correlationId ?? null,\n input.causationId ?? null,\n input.priority,\n input.expiresAt ?? null,\n input.idempotencyKey ?? null,\n input.atribReceiptId ?? null,\n json(input.informedBy),\n json(input.metadata),\n ];\n\n const result = await this.db.query<Row>(\n `WITH inserted AS (\n INSERT INTO agent_bridge.messages (\n id, workspace, source, type, content, content_type, data, targets,\n thread_id, reply_to_id, correlation_id, causation_id, priority,\n expires_at, idempotency_key, atrib_receipt_id, informed_by, metadata\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7::jsonb, $8::jsonb,\n $9, $10, $11, $12, $13, $14, $15, $16, $17::jsonb, $18::jsonb\n )\n ON CONFLICT (workspace, source, idempotency_key)\n WHERE idempotency_key IS NOT NULL\n DO NOTHING\n RETURNING *, true AS created\n ), selected AS (\n SELECT * FROM inserted\n UNION ALL\n SELECT existing.*, false AS created\n FROM agent_bridge.messages existing\n WHERE $15::text IS NOT NULL\n AND existing.workspace = $2\n AND existing.source = $3\n AND existing.idempotency_key = $15\n AND NOT EXISTS (SELECT 1 FROM inserted)\n LIMIT 1\n ), delivery_rows AS (\n INSERT INTO agent_bridge.deliveries (\n id, message_id, workspace, recipient, state, available_at\n )\n SELECT gen_random_uuid(), inserted.id, inserted.workspace, target, 'pending', now()\n FROM inserted\n CROSS JOIN LATERAL jsonb_array_elements_text(inserted.targets) AS target\n ON CONFLICT (message_id, recipient) DO NOTHING\n )\n SELECT * FROM selected`,\n values,\n );\n\n let row = result.rows[0];\n if (!row && input.idempotencyKey) {\n const existing = await this.db.query<Row>(\n `SELECT *, false AS created\n FROM agent_bridge.messages\n WHERE workspace=$1 AND source=$2 AND idempotency_key=$3`,\n [input.workspace, input.source, input.idempotencyKey],\n );\n row = existing.rows[0];\n }\n if (!row) throw new Error(\"message insert did not return a row\");\n const message = asMessage(row);\n if (row.created !== true) assertIdempotentReplay(message, input);\n return { message, created: row.created === true };\n }\n\n async listMessages(\n principal: BridgePrincipal,\n query: MessageQuery = {},\n ): Promise<MessagePage> {\n const cursor = decodeCursor(query.cursor) ?? \"0\";\n const limit = Math.min(Math.max(Math.trunc(query.limit ?? 50), 1), 200);\n const boundary = query.latest ? undefined : await this.db.query<{ sequence: string | null }>(\n \"SELECT max(sequence)::text AS sequence FROM agent_bridge.messages WHERE workspace=$1\",\n [principal.workspace],\n );\n const highWater = boundary?.rows[0]?.sequence;\n const values: unknown[] = query.latest\n ? [principal.workspace, principal.agent]\n : [principal.workspace, cursor, principal.agent];\n let sql =\n `SELECT * FROM agent_bridge.messages WHERE workspace=$1 ${query.latest ? \"\" : \"AND sequence>$2::bigint \"}` +\n `AND (targets='[]'::jsonb OR targets ? $${query.latest ? 2 : 3})`;\n\n if (highWater) {\n values.push(highWater);\n sql += ` AND sequence <= $${values.length}::bigint`;\n }\n\n if (!query.includeExpired) {\n sql += \" AND (expires_at IS NULL OR expires_at > now())\";\n }\n if (query.types?.length) {\n values.push(query.types);\n sql += ` AND type = ANY($${values.length})`;\n }\n if (query.source) {\n values.push(query.source);\n sql += ` AND source = $${values.length}`;\n }\n if (query.since) {\n values.push(query.since);\n sql += ` AND created_at >= $${values.length}::timestamptz`;\n }\n if (query.unacknowledgedBy) {\n values.push(query.unacknowledgedBy);\n sql += ` AND NOT EXISTS (\n SELECT 1 FROM agent_bridge.receipts receipt\n WHERE receipt.workspace=agent_bridge.messages.workspace\n AND receipt.message_id=agent_bridge.messages.id\n AND receipt.principal=$${values.length}\n )`;\n }\n if (query.threadId) {\n values.push(query.threadId);\n sql += ` AND thread_id = $${values.length}`;\n }\n\n values.push(limit);\n const result = await this.db.query<Row>(\n `${sql} ORDER BY sequence ${query.latest ? \"DESC\" : \"ASC\"} LIMIT $${values.length}`,\n values,\n );\n const messages = result.rows.map(asMessage);\n const last = messages[messages.length - 1];\n if (query.latest) return { messages, cursor: messages[0] ? encodeCursor(messages[0].sequence) : query.cursor };\n if (messages.length === limit) return { messages, cursor: encodeCursor(last!.sequence) };\n return { messages, cursor: highWater ? encodeCursor(highWater) : query.cursor };\n }\n\n async recordReceipt(\n workspace: string,\n ids: string[],\n principal: string,\n readAt = new Date(),\n ): Promise<number> {\n const result = await this.db.query(\n `INSERT INTO agent_bridge.receipts (workspace, message_id, principal, read_at)\n SELECT message.workspace, message.id, $3, $4\n FROM agent_bridge.messages message\n WHERE message.workspace = $1 AND message.id = ANY($2::uuid[])\n AND (message.targets='[]'::jsonb OR message.targets ? $3)\n ON CONFLICT DO NOTHING`,\n [workspace, ids, principal, readAt],\n );\n return result.rowCount ?? 0;\n }\n\n async claimDelivery(\n principal: BridgePrincipal,\n options: ClaimOptions,\n ): Promise<BridgeDelivery | null> {\n const owner = principal.instance ?? principal.agent;\n const token = randomUUID();\n const result = await this.db.query<Row>(\n `WITH expired AS (\n UPDATE agent_bridge.deliveries delivery\n SET state='dead', last_error='message expired', lease_token=NULL,\n lease_owner=NULL, lease_expires_at=NULL\n FROM agent_bridge.messages message\n WHERE delivery.workspace=$1 AND delivery.recipient=$2\n AND delivery.state IN ('pending', 'retrying', 'claimed')\n AND message.workspace=delivery.workspace AND message.id=delivery.message_id\n AND message.expires_at IS NOT NULL AND message.expires_at <= now()\n RETURNING delivery.id\n ), exhausted AS (\n UPDATE agent_bridge.deliveries delivery\n SET state='dead', last_error='maximum attempts reached', lease_token=NULL,\n lease_owner=NULL, lease_expires_at=NULL\n WHERE delivery.workspace=$1 AND delivery.recipient=$2 AND delivery.attempt >= $6\n AND (\n delivery.state IN ('pending', 'retrying')\n OR (delivery.state='claimed' AND delivery.lease_expires_at <= now())\n )\n RETURNING delivery.id\n ), candidate AS (\n SELECT delivery.id\n FROM agent_bridge.deliveries delivery\n JOIN agent_bridge.messages message\n ON message.workspace=delivery.workspace AND message.id=delivery.message_id\n WHERE delivery.workspace=$1 AND delivery.recipient=$2\n AND (\n (delivery.state IN ('pending', 'retrying') AND delivery.available_at <= now())\n OR (delivery.state='claimed' AND delivery.lease_expires_at <= now())\n )\n AND delivery.attempt < $6\n AND (message.expires_at IS NULL OR message.expires_at > now())\n ORDER BY delivery.available_at, delivery.id\n FOR UPDATE OF delivery SKIP LOCKED\n LIMIT 1\n )\n UPDATE agent_bridge.deliveries delivery\n SET state='claimed', attempt=delivery.attempt+1, lease_token=$3,\n lease_owner=$4, lease_expires_at=now() + ($5 * interval '1 millisecond')\n FROM candidate\n WHERE delivery.id=candidate.id\n RETURNING delivery.*`,\n [principal.workspace, principal.agent, token, owner, options.leaseMs, options.maxAttempts ?? 5],\n );\n return result.rows[0] ? asDelivery(result.rows[0]) : null;\n }\n\n async renewDelivery(\n principal: BridgePrincipal,\n id: string,\n token: string,\n leaseMs: number,\n ): Promise<BridgeDelivery | null> {\n const result = await this.db.query<Row>(\n `UPDATE agent_bridge.deliveries\n SET lease_expires_at=now() + ($1 * interval '1 millisecond')\n WHERE workspace=$2 AND recipient=$3 AND lease_owner=$4 AND id=$5 AND lease_token=$6\n AND state='claimed' AND lease_expires_at>now()\n RETURNING *`,\n [leaseMs, principal.workspace, principal.agent, principal.instance ?? principal.agent, id, token],\n );\n return result.rows[0] ? asDelivery(result.rows[0]) : null;\n }\n\n async settleDelivery(\n principal: BridgePrincipal,\n id: string,\n token: string,\n state: \"acked\" | \"retrying\" | \"dead\",\n error?: string,\n retryPolicy?: RetryPolicy,\n ): Promise<BridgeDelivery | null> {\n if (!retryPolicy) throw new Error(\"retry policy is required\");\n const result = await this.db.query<Row>(\n `UPDATE agent_bridge.deliveries\n SET state=CASE\n WHEN $1='retrying' AND attempt >= $6 THEN 'dead'\n ELSE $1\n END,\n available_at=CASE\n WHEN $1='retrying' AND attempt < $6 THEN\n now() + (\n LEAST($8::double precision, $7::double precision * power(2, GREATEST(attempt - 1, 0)))\n * (1 + ((random() * 2) - 1) * $9::double precision)\n * interval '1 millisecond'\n )\n ELSE available_at\n END,\n last_error=$2, lease_token=NULL, lease_owner=NULL, lease_expires_at=NULL\n WHERE workspace=$3 AND recipient=$4 AND lease_owner=$5\n AND id=$10 AND lease_token=$11 AND state='claimed' AND lease_expires_at>now()\n RETURNING *`,\n [\n state,\n error?.slice(0, 1024) ?? null,\n principal.workspace,\n principal.agent,\n principal.instance ?? principal.agent,\n retryPolicy.maxAttempts,\n retryPolicy.baseDelayMs,\n retryPolicy.maxDelayMs,\n retryPolicy.jitterRatio,\n id,\n token,\n ],\n );\n return result.rows[0] ? asDelivery(result.rows[0]) : null;\n }\n\n async diagnostics(principal: BridgePrincipal): Promise<BridgeDiagnostics> {\n const result = await this.db.query<Row>(\n `SELECT state, count(*)::integer AS count, min(available_at) AS oldest\n FROM agent_bridge.deliveries\n WHERE workspace=$1 AND recipient=$2\n GROUP BY state`,\n [principal.workspace, principal.agent],\n );\n const counts = new Map(result.rows.map((row) => [String(row.state), Number(row.count)]));\n const oldest = result.rows\n .filter((row) => row.state === \"pending\" || row.state === \"retrying\")\n .map((row) => asTimestamp(row.oldest))\n .filter((value): value is string => Boolean(value))\n .sort()[0];\n return {\n schemaVersion: \"postgres-v2\",\n deliverySupported: true,\n pending: counts.get(\"pending\") ?? 0,\n claimed: counts.get(\"claimed\") ?? 0,\n retrying: counts.get(\"retrying\") ?? 0,\n dead: counts.get(\"dead\") ?? 0,\n oldestAvailableAt: oldest,\n };\n }\n\n async heartbeat(principal: BridgePrincipal, leaseMs: number, runtimeType?: string, capabilities: string[] = []): Promise<AgentPresence> {\n await this.db.query(\n \"DELETE FROM agent_bridge.agent_instances WHERE workspace=$1 AND lease_expires_at<=now()\",\n [principal.workspace],\n );\n const result = await this.db.query<Row>(\n `WITH locked AS (\n SELECT pg_advisory_xact_lock(hashtextextended($1, 0))\n )\n INSERT INTO agent_bridge.agent_instances (workspace,agent,instance,runtime_type,capabilities,lease_expires_at,last_seen_at)\n SELECT $1,$2,$3,$4,$5::jsonb,now() + ($6 * interval '1 millisecond'),now()\n FROM locked\n WHERE EXISTS (\n SELECT 1 FROM agent_bridge.agent_instances\n WHERE workspace=$1 AND agent=$2 AND instance=$3\n ) OR ((\n SELECT count(*) < 128 FROM agent_bridge.agent_instances\n WHERE workspace=$1 AND agent=$2\n ) AND (\n SELECT count(*) < 4096 FROM agent_bridge.agent_instances\n WHERE workspace=$1\n )\n )\n ON CONFLICT (workspace,agent,instance) DO UPDATE SET runtime_type=excluded.runtime_type,capabilities=excluded.capabilities,lease_expires_at=excluded.lease_expires_at,last_seen_at=excluded.last_seen_at\n RETURNING *`,\n [principal.workspace, principal.agent, principal.instance, runtimeType ?? null, JSON.stringify(capabilities), leaseMs],\n );\n if (!result.rows[0]) {\n throw Object.assign(new Error(\"active instance limit reached\"), {\n status: 429,\n code: \"presence_limit\",\n });\n }\n return asPresence(result.rows[0]!);\n }\n\n async listPresence(principal: BridgePrincipal): Promise<AgentPresence[]> {\n await this.db.query(\n \"DELETE FROM agent_bridge.agent_instances WHERE workspace=$1 AND lease_expires_at<=now()\",\n [principal.workspace],\n );\n const result = await this.db.query<Row>(\n \"SELECT * FROM agent_bridge.agent_instances WHERE workspace=$1 ORDER BY agent,instance\",\n [principal.workspace],\n );\n return result.rows.map(asPresence);\n }\n\n async listDeliveryEvents(deliveryId: string): Promise<BridgeDeliveryEvent[]> {\n const result = await this.db.query<Row>(\n \"SELECT * FROM agent_bridge.delivery_events WHERE delivery_id=$1 ORDER BY sequence\",\n [deliveryId],\n );\n return result.rows.map(asDeliveryEvent);\n }\n}\n"],"mappings":"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","names":[]}
|