@creatornader/agent-bridge 0.2.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.
- package/CHANGELOG.md +60 -0
- package/LICENSE +216 -0
- package/README.md +338 -0
- package/SKILL.md +24 -0
- package/bin/CLAUDE.md +11 -0
- package/bin/agent-bridge +7 -0
- package/clients/claude-code.json +20 -0
- package/clients/claude-desktop.json +20 -0
- package/clients/codex.json +20 -0
- package/clients/generic-mcp.json +13 -0
- package/clients/openclaw.json +13 -0
- package/dist/bridge-domain-BcnBeHOn.d.ts +97 -0
- package/dist/bridge-service-CfqMcMAn.d.ts +28 -0
- package/dist/bridge-store-BuGjxTn4.d.ts +61 -0
- package/dist/bridge.d.ts +102 -0
- package/dist/bridge.js +83 -0
- package/dist/bridge.js.map +1 -0
- package/dist/chunk-4KAOBC5X.js +773 -0
- package/dist/chunk-4KAOBC5X.js.map +1 -0
- package/dist/chunk-6MAZ6YLZ.js +146 -0
- package/dist/chunk-6MAZ6YLZ.js.map +1 -0
- package/dist/chunk-AXL2I7FH.js +423 -0
- package/dist/chunk-AXL2I7FH.js.map +1 -0
- package/dist/chunk-BV6W4AJK.js +211 -0
- package/dist/chunk-BV6W4AJK.js.map +1 -0
- package/dist/chunk-CKSKUBDQ.js +153 -0
- package/dist/chunk-CKSKUBDQ.js.map +1 -0
- package/dist/chunk-JOUBDRYX.js +272 -0
- package/dist/chunk-JOUBDRYX.js.map +1 -0
- package/dist/chunk-JTC5YURG.js +49 -0
- package/dist/chunk-JTC5YURG.js.map +1 -0
- package/dist/chunk-KVR4JBRF.js +80 -0
- package/dist/chunk-KVR4JBRF.js.map +1 -0
- package/dist/chunk-O26W5QHS.js +409 -0
- package/dist/chunk-O26W5QHS.js.map +1 -0
- package/dist/chunk-WEULPMUY.js +988 -0
- package/dist/chunk-WEULPMUY.js.map +1 -0
- package/dist/chunk-YD6YJATN.js +48 -0
- package/dist/chunk-YD6YJATN.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +670 -0
- package/dist/cli.js.map +1 -0
- package/dist/client-config.d.ts +30 -0
- package/dist/client-config.js +10 -0
- package/dist/client-config.js.map +1 -0
- package/dist/client-runtime.d.ts +15 -0
- package/dist/client-runtime.js +15 -0
- package/dist/client-runtime.js.map +1 -0
- package/dist/gateway-BULozv3K.d.ts +54 -0
- package/dist/gateway-main.d.ts +2 -0
- package/dist/gateway-main.js +105 -0
- package/dist/gateway-main.js.map +1 -0
- package/dist/gateway.d.ts +4 -0
- package/dist/gateway.js +10 -0
- package/dist/gateway.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +34 -0
- package/dist/server.js +19 -0
- package/dist/server.js.map +1 -0
- package/dist/sqlite.d.ts +156 -0
- package/dist/sqlite.js +24 -0
- package/dist/sqlite.js.map +1 -0
- package/llms.txt +39 -0
- package/package.json +104 -0
- package/sql/migrations/001_schema_state.sql +34 -0
- package/sql/migrations/002_workspaces_agents_credentials.sql +77 -0
- package/sql/migrations/003_messages_receipts_deliveries.sql +116 -0
- package/sql/migrations/004_message_query_indexes.sql +31 -0
- package/sql/migrations/005_delivery_events_presence.sql +79 -0
- package/sql/migrations/006_legacy_shared_context_import.sql +139 -0
- package/sql/migrations/007_runtime_role.sql +59 -0
- package/sql/setup.sql +68 -0
package/dist/sqlite.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { b as BridgeMessage, c as BridgePrincipal, B as BridgeDelivery, D as DeliveryState, R as RetryPolicy, A as AgentPresence, a as BridgeDeliveryEvent } from './bridge-domain-BcnBeHOn.js';
|
|
2
|
+
import { b as MessageQuery, M as MessagePage, B as BridgeDiagnostics, I as InsertMessageResult, a as BridgeStore, C as ClaimOptions } from './bridge-store-BuGjxTn4.js';
|
|
3
|
+
|
|
4
|
+
type PendingMessage = Omit<BridgeMessage, "sequence" | "createdAt">;
|
|
5
|
+
interface EdgeScope {
|
|
6
|
+
endpoint: string;
|
|
7
|
+
principal: BridgePrincipal;
|
|
8
|
+
}
|
|
9
|
+
interface EdgeOutboxRecord {
|
|
10
|
+
position: number;
|
|
11
|
+
draft: PendingMessage;
|
|
12
|
+
payloadHash: string;
|
|
13
|
+
attempts: number;
|
|
14
|
+
leaseToken: string;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
}
|
|
17
|
+
interface EdgeEnqueueResult {
|
|
18
|
+
draft: PendingMessage;
|
|
19
|
+
created: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface EdgeStats {
|
|
22
|
+
pending: number;
|
|
23
|
+
blocked: number;
|
|
24
|
+
cached: number;
|
|
25
|
+
pullCursor?: string;
|
|
26
|
+
lastSyncAt?: string;
|
|
27
|
+
lastError?: string;
|
|
28
|
+
}
|
|
29
|
+
declare class EdgeConflictError extends Error {
|
|
30
|
+
readonly code = "edge_idempotency_conflict";
|
|
31
|
+
}
|
|
32
|
+
declare function edgeMessageFingerprint(message: PendingMessage | BridgeMessage): string;
|
|
33
|
+
declare function stableIdempotency(message: PendingMessage): PendingMessage;
|
|
34
|
+
declare function edgeScopeKey(scope: EdgeScope): string;
|
|
35
|
+
declare class SQLiteEdgeStore {
|
|
36
|
+
private readonly path;
|
|
37
|
+
private readonly scope;
|
|
38
|
+
private readonly busyTimeoutMs;
|
|
39
|
+
private readonly db;
|
|
40
|
+
private readonly key;
|
|
41
|
+
private initialized;
|
|
42
|
+
constructor(path: string, scope: EdgeScope, busyTimeoutMs?: number);
|
|
43
|
+
private restrictFiles;
|
|
44
|
+
get scopeKey(): string;
|
|
45
|
+
initialize(): Promise<void>;
|
|
46
|
+
private ready;
|
|
47
|
+
enqueue(input: PendingMessage, now?: Date): Promise<EdgeEnqueueResult>;
|
|
48
|
+
claimNext(now?: Date, leaseMs?: number): Promise<EdgeOutboxRecord | undefined>;
|
|
49
|
+
retry(record: EdgeOutboxRecord, error: string, availableAt: Date): Promise<void>;
|
|
50
|
+
block(record: EdgeOutboxRecord, error: string): Promise<void>;
|
|
51
|
+
commit(record: EdgeOutboxRecord, message: BridgeMessage, cacheVisible: boolean, now?: Date): Promise<void>;
|
|
52
|
+
private cacheOne;
|
|
53
|
+
cachePage(messages: BridgeMessage[], cursor: string | undefined, now?: Date): Promise<void>;
|
|
54
|
+
cacheLatest(messages: BridgeMessage[], now?: Date): Promise<void>;
|
|
55
|
+
list(query?: MessageQuery): Promise<MessagePage>;
|
|
56
|
+
pullCursor(): Promise<string | undefined>;
|
|
57
|
+
noteError(error: string): Promise<void>;
|
|
58
|
+
stats(): Promise<EdgeStats>;
|
|
59
|
+
close(): Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface SyncInsertResult extends InsertMessageResult {
|
|
63
|
+
disposition: "committed" | "queued";
|
|
64
|
+
authoritative: boolean;
|
|
65
|
+
}
|
|
66
|
+
interface CachedMessagePage extends MessagePage {
|
|
67
|
+
source: "remote" | "cache";
|
|
68
|
+
stale: boolean;
|
|
69
|
+
lastSyncedAt?: string;
|
|
70
|
+
}
|
|
71
|
+
interface SyncReport {
|
|
72
|
+
online: boolean;
|
|
73
|
+
pushed: number;
|
|
74
|
+
deduplicated: number;
|
|
75
|
+
pulled: number;
|
|
76
|
+
pending: number;
|
|
77
|
+
blocked: number;
|
|
78
|
+
cached: number;
|
|
79
|
+
cursor?: string;
|
|
80
|
+
lastSyncedAt?: string;
|
|
81
|
+
lastError?: string;
|
|
82
|
+
failureRetryable?: boolean;
|
|
83
|
+
}
|
|
84
|
+
interface SyncDiagnostics extends BridgeDiagnostics {
|
|
85
|
+
remoteReachable: boolean;
|
|
86
|
+
outboxPending: number;
|
|
87
|
+
outboxBlocked: number;
|
|
88
|
+
cachedMessages: number;
|
|
89
|
+
lastSyncAt?: string;
|
|
90
|
+
lastSyncError?: string;
|
|
91
|
+
}
|
|
92
|
+
interface SyncingBridgeStoreOptions {
|
|
93
|
+
now?: () => Date;
|
|
94
|
+
random?: () => number;
|
|
95
|
+
baseDelayMs?: number;
|
|
96
|
+
maxDelayMs?: number;
|
|
97
|
+
leaseMs?: number;
|
|
98
|
+
}
|
|
99
|
+
declare function isRetryableSyncError(error: unknown): boolean;
|
|
100
|
+
declare class SyncingBridgeStore implements BridgeStore {
|
|
101
|
+
private readonly edge;
|
|
102
|
+
private readonly remote;
|
|
103
|
+
private readonly principal;
|
|
104
|
+
private readonly now;
|
|
105
|
+
private readonly random;
|
|
106
|
+
private readonly baseDelayMs;
|
|
107
|
+
private readonly maxDelayMs;
|
|
108
|
+
private readonly leaseMs;
|
|
109
|
+
private remoteReady;
|
|
110
|
+
constructor(edge: SQLiteEdgeStore, remote: BridgeStore, principal: BridgePrincipal, options?: SyncingBridgeStoreOptions);
|
|
111
|
+
initialize(): Promise<void>;
|
|
112
|
+
verifyRemote(): Promise<void>;
|
|
113
|
+
private ensureRemote;
|
|
114
|
+
private assertPrincipal;
|
|
115
|
+
private delay;
|
|
116
|
+
private flushOne;
|
|
117
|
+
insertMessage(message: PendingMessage): Promise<SyncInsertResult>;
|
|
118
|
+
private pull;
|
|
119
|
+
sync(options?: {
|
|
120
|
+
maxPush?: number;
|
|
121
|
+
maxPages?: number;
|
|
122
|
+
}): Promise<SyncReport>;
|
|
123
|
+
listMessages(principal: BridgePrincipal, query?: MessageQuery): Promise<CachedMessagePage>;
|
|
124
|
+
recordReceipt(workspace: string, messageIds: string[], principal: string, readAt?: Date): Promise<number>;
|
|
125
|
+
claimDelivery(principal: BridgePrincipal, options: ClaimOptions): Promise<BridgeDelivery | null>;
|
|
126
|
+
renewDelivery(principal: BridgePrincipal, deliveryId: string, leaseToken: string, leaseMs: number): Promise<BridgeDelivery | null>;
|
|
127
|
+
settleDelivery(principal: BridgePrincipal, deliveryId: string, leaseToken: string, state: Extract<DeliveryState, "acked" | "retrying" | "dead">, error: string | undefined, retryPolicy: RetryPolicy): Promise<BridgeDelivery | null>;
|
|
128
|
+
diagnostics(principal: BridgePrincipal): Promise<SyncDiagnostics>;
|
|
129
|
+
heartbeat(principal: BridgePrincipal, leaseMs: number, runtimeType?: string, capabilities?: string[]): Promise<AgentPresence>;
|
|
130
|
+
listPresence(principal: BridgePrincipal): Promise<AgentPresence[]>;
|
|
131
|
+
close(): Promise<void>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
declare class SQLiteBridgeStore implements BridgeStore {
|
|
135
|
+
private readonly path;
|
|
136
|
+
private readonly busyTimeoutMs;
|
|
137
|
+
private readonly db;
|
|
138
|
+
private initialized;
|
|
139
|
+
constructor(path?: string, busyTimeoutMs?: number);
|
|
140
|
+
private restrictFiles;
|
|
141
|
+
initialize(): Promise<void>;
|
|
142
|
+
private ready;
|
|
143
|
+
insertMessage(input: Omit<BridgeMessage, "sequence" | "createdAt">): Promise<InsertMessageResult>;
|
|
144
|
+
listMessages(principal: BridgePrincipal, query?: MessageQuery): Promise<MessagePage>;
|
|
145
|
+
recordReceipt(workspace: string, messageIds: string[], principal: string, readAt?: Date): Promise<number>;
|
|
146
|
+
claimDelivery(principal: BridgePrincipal, options: ClaimOptions): Promise<BridgeDelivery | null>;
|
|
147
|
+
renewDelivery(principal: BridgePrincipal, id: string, token: string, leaseMs: number): Promise<BridgeDelivery | null>;
|
|
148
|
+
settleDelivery(principal: BridgePrincipal, id: string, token: string, state: "acked" | "retrying" | "dead", error: string | undefined, retryPolicy: RetryPolicy): Promise<BridgeDelivery | null>;
|
|
149
|
+
diagnostics(principal: BridgePrincipal): Promise<BridgeDiagnostics>;
|
|
150
|
+
heartbeat(principal: BridgePrincipal, leaseMs: number, runtimeType?: string, capabilities?: string[]): Promise<AgentPresence>;
|
|
151
|
+
listPresence(principal: BridgePrincipal): Promise<AgentPresence[]>;
|
|
152
|
+
listDeliveryEvents(deliveryId: string): Promise<BridgeDeliveryEvent[]>;
|
|
153
|
+
close(): Promise<void>;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { type CachedMessagePage, EdgeConflictError, type EdgeEnqueueResult, type EdgeOutboxRecord, type EdgeScope, type EdgeStats, type PendingMessage, SQLiteBridgeStore, SQLiteEdgeStore, type SyncDiagnostics, type SyncInsertResult, type SyncReport, SyncingBridgeStore, type SyncingBridgeStoreOptions, edgeMessageFingerprint, edgeScopeKey, isRetryableSyncError, stableIdempotency };
|
package/dist/sqlite.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
EdgeConflictError,
|
|
4
|
+
SQLiteBridgeStore,
|
|
5
|
+
SQLiteEdgeStore,
|
|
6
|
+
SyncingBridgeStore,
|
|
7
|
+
edgeMessageFingerprint,
|
|
8
|
+
edgeScopeKey,
|
|
9
|
+
isRetryableSyncError,
|
|
10
|
+
stableIdempotency
|
|
11
|
+
} from "./chunk-WEULPMUY.js";
|
|
12
|
+
import "./chunk-YD6YJATN.js";
|
|
13
|
+
import "./chunk-BV6W4AJK.js";
|
|
14
|
+
export {
|
|
15
|
+
EdgeConflictError,
|
|
16
|
+
SQLiteBridgeStore,
|
|
17
|
+
SQLiteEdgeStore,
|
|
18
|
+
SyncingBridgeStore,
|
|
19
|
+
edgeMessageFingerprint,
|
|
20
|
+
edgeScopeKey,
|
|
21
|
+
isRetryableSyncError,
|
|
22
|
+
stableIdempotency
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Agent Bridge
|
|
2
|
+
|
|
3
|
+
Repository: https://github.com/creatornader/agent-bridge
|
|
4
|
+
Package: @creatornader/agent-bridge
|
|
5
|
+
|
|
6
|
+
Agent Bridge carries durable context and executable work between AI agents in different clients, processes, sessions, and machines.
|
|
7
|
+
|
|
8
|
+
## Modes
|
|
9
|
+
|
|
10
|
+
- local: SQLite WAL, no account or daemon
|
|
11
|
+
- gateway: authenticated HTTPS, PostgreSQL authority, SQLite edge outbox and cache
|
|
12
|
+
- legacy-supabase: compatibility with the v1 shared_context schema
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
- agent-bridge init --provider local
|
|
17
|
+
- agent-bridge demo
|
|
18
|
+
- agent-bridge doctor
|
|
19
|
+
- agent-bridge pending
|
|
20
|
+
- agent-bridge send, inbox, history, acknowledge
|
|
21
|
+
- agent-bridge claim, extend, ack, nack
|
|
22
|
+
- agent-bridge sync, watch, join, presence
|
|
23
|
+
- agent-bridge clients install <runtime> --identity <principal>
|
|
24
|
+
|
|
25
|
+
## MCP tools
|
|
26
|
+
|
|
27
|
+
Compatibility: post_context, get_context, ack_context.
|
|
28
|
+
Reliable messaging: send, history, claim, extend, acknowledge, negative_acknowledge, heartbeat, presence.
|
|
29
|
+
|
|
30
|
+
## Identity rule
|
|
31
|
+
|
|
32
|
+
The active runtime supplies AGENT_BRIDGE_AGENT and AGENT_BRIDGE_INSTANCE. Do not hardcode another client name and do not store agent identity in the shared backend config. Gateway installations use a separate principal-bound token and owner-only backend file for each client.
|
|
33
|
+
|
|
34
|
+
## References
|
|
35
|
+
|
|
36
|
+
- README.md: setup, commands, security, and provider behavior
|
|
37
|
+
- docs/architecture-v2.md: protocol, storage, identity, delivery, and acceptance decisions
|
|
38
|
+
- clients/*.json: runtime adapter manifests
|
|
39
|
+
- SKILL.md: concise agent operating instructions
|
package/package.json
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@creatornader/agent-bridge",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Shared context MCP server for heterogeneous AI agent coordination",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"author": "Nader Helmy",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/creatornader/agent-bridge.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/creatornader/agent-bridge#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/creatornader/agent-bridge/issues"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22.23.1"
|
|
18
|
+
},
|
|
19
|
+
"main": "dist/bridge.js",
|
|
20
|
+
"bin": {
|
|
21
|
+
"agent-bridge": "bin/agent-bridge",
|
|
22
|
+
"agent-bridge-mcp": "dist/index.js",
|
|
23
|
+
"agent-bridge-gateway": "dist/gateway-main.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"bin",
|
|
28
|
+
"clients",
|
|
29
|
+
"sql/migrations",
|
|
30
|
+
"sql/setup.sql",
|
|
31
|
+
"llms.txt",
|
|
32
|
+
"SKILL.md",
|
|
33
|
+
"README.md",
|
|
34
|
+
"CHANGELOG.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/bridge.d.ts",
|
|
40
|
+
"import": "./dist/bridge.js"
|
|
41
|
+
},
|
|
42
|
+
"./server": {
|
|
43
|
+
"types": "./dist/server.d.ts",
|
|
44
|
+
"import": "./dist/server.js"
|
|
45
|
+
},
|
|
46
|
+
"./bridge": {
|
|
47
|
+
"types": "./dist/bridge.d.ts",
|
|
48
|
+
"import": "./dist/bridge.js"
|
|
49
|
+
},
|
|
50
|
+
"./gateway": {
|
|
51
|
+
"types": "./dist/gateway.d.ts",
|
|
52
|
+
"import": "./dist/gateway.js"
|
|
53
|
+
},
|
|
54
|
+
"./sqlite": {
|
|
55
|
+
"types": "./dist/sqlite.d.ts",
|
|
56
|
+
"import": "./dist/sqlite.js"
|
|
57
|
+
},
|
|
58
|
+
"./client": {
|
|
59
|
+
"types": "./dist/client-runtime.d.ts",
|
|
60
|
+
"import": "./dist/client-runtime.js"
|
|
61
|
+
},
|
|
62
|
+
"./config": {
|
|
63
|
+
"types": "./dist/client-config.d.ts",
|
|
64
|
+
"import": "./dist/client-config.js"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "tsup",
|
|
69
|
+
"dev": "tsup --watch",
|
|
70
|
+
"start": "node dist/index.js",
|
|
71
|
+
"start:gateway": "node dist/gateway-main.js",
|
|
72
|
+
"migrate": "node dist/gateway-main.js --migrate-only",
|
|
73
|
+
"prepack": "npm run build",
|
|
74
|
+
"pretest": "npm run build",
|
|
75
|
+
"test": "vitest run",
|
|
76
|
+
"typecheck": "tsc --noEmit",
|
|
77
|
+
"check": "npm run typecheck && npm test"
|
|
78
|
+
},
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
81
|
+
"pg": "^8.22.0"
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"@types/node": "^26.1.0",
|
|
85
|
+
"@types/pg": "^8.20.0",
|
|
86
|
+
"tsup": "^8.4.0",
|
|
87
|
+
"typescript": "^6.0.3",
|
|
88
|
+
"vitest": "^4.1.9"
|
|
89
|
+
},
|
|
90
|
+
"overrides": {
|
|
91
|
+
"esbuild": "0.28.1"
|
|
92
|
+
},
|
|
93
|
+
"directories": {
|
|
94
|
+
"doc": "docs",
|
|
95
|
+
"test": "test"
|
|
96
|
+
},
|
|
97
|
+
"keywords": [
|
|
98
|
+
"agents",
|
|
99
|
+
"mcp",
|
|
100
|
+
"messaging",
|
|
101
|
+
"coordination"
|
|
102
|
+
],
|
|
103
|
+
"types": "./dist/bridge.d.ts"
|
|
104
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pg_advisory_xact_lock(1646705660);
|
|
4
|
+
|
|
5
|
+
create schema if not exists agent_bridge;
|
|
6
|
+
revoke all on schema agent_bridge from public;
|
|
7
|
+
|
|
8
|
+
create table if not exists agent_bridge.schema_migrations (
|
|
9
|
+
version integer primary key,
|
|
10
|
+
name text not null unique,
|
|
11
|
+
checksum char(64) not null,
|
|
12
|
+
applied_at timestamptz not null default now(),
|
|
13
|
+
constraint schema_migrations_checksum check (checksum ~ '^[0-9a-f]{64}$')
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
insert into agent_bridge.schema_migrations (version, name, checksum)
|
|
17
|
+
values (1, 'schema_state', '__AGENT_BRIDGE_MIGRATION_CHECKSUM__')
|
|
18
|
+
on conflict (version) do update set applied_at=agent_bridge.schema_migrations.applied_at
|
|
19
|
+
where agent_bridge.schema_migrations.name=excluded.name
|
|
20
|
+
and agent_bridge.schema_migrations.checksum=excluded.checksum;
|
|
21
|
+
|
|
22
|
+
do $migration$
|
|
23
|
+
begin
|
|
24
|
+
if not exists (
|
|
25
|
+
select 1 from agent_bridge.schema_migrations
|
|
26
|
+
where version=1 and name='schema_state'
|
|
27
|
+
and checksum='__AGENT_BRIDGE_MIGRATION_CHECKSUM__'
|
|
28
|
+
) then
|
|
29
|
+
raise exception 'migration 1_schema_state conflicts with recorded schema state';
|
|
30
|
+
end if;
|
|
31
|
+
end
|
|
32
|
+
$migration$;
|
|
33
|
+
|
|
34
|
+
commit;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pg_advisory_xact_lock(1646705660);
|
|
4
|
+
|
|
5
|
+
create table if not exists agent_bridge.workspaces (
|
|
6
|
+
id text primary key,
|
|
7
|
+
name text not null,
|
|
8
|
+
disabled_at timestamptz,
|
|
9
|
+
created_at timestamptz not null default now()
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
create table if not exists agent_bridge.agents (
|
|
13
|
+
id uuid primary key default gen_random_uuid(),
|
|
14
|
+
workspace_id text not null references agent_bridge.workspaces(id),
|
|
15
|
+
principal text not null,
|
|
16
|
+
display_name text,
|
|
17
|
+
runtime_type text,
|
|
18
|
+
disabled_at timestamptz,
|
|
19
|
+
created_at timestamptz not null default now(),
|
|
20
|
+
unique (workspace_id, principal),
|
|
21
|
+
unique (workspace_id, id)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
create table if not exists agent_bridge.credentials (
|
|
25
|
+
id uuid primary key default gen_random_uuid(),
|
|
26
|
+
workspace_id text not null,
|
|
27
|
+
agent_id uuid not null,
|
|
28
|
+
token_hash char(64) not null unique,
|
|
29
|
+
label text,
|
|
30
|
+
expires_at timestamptz,
|
|
31
|
+
revoked_at timestamptz,
|
|
32
|
+
created_at timestamptz not null default now(),
|
|
33
|
+
last_used_at timestamptz,
|
|
34
|
+
foreign key (workspace_id, agent_id)
|
|
35
|
+
references agent_bridge.agents(workspace_id, id),
|
|
36
|
+
constraint credentials_hash check (token_hash ~ '^[0-9a-f]{64}$')
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
create index if not exists credentials_active_hash
|
|
40
|
+
on agent_bridge.credentials(token_hash)
|
|
41
|
+
where revoked_at is null;
|
|
42
|
+
|
|
43
|
+
revoke all on all tables in schema agent_bridge from public;
|
|
44
|
+
revoke all on all sequences in schema agent_bridge from public;
|
|
45
|
+
|
|
46
|
+
do $roles$
|
|
47
|
+
declare role_name text;
|
|
48
|
+
begin
|
|
49
|
+
foreach role_name in array array['anon', 'authenticated'] loop
|
|
50
|
+
if exists (select 1 from pg_roles where rolname=role_name) then
|
|
51
|
+
execute format('revoke all on schema agent_bridge from %I', role_name);
|
|
52
|
+
execute format('revoke all on all tables in schema agent_bridge from %I', role_name);
|
|
53
|
+
execute format('revoke all on all sequences in schema agent_bridge from %I', role_name);
|
|
54
|
+
end if;
|
|
55
|
+
end loop;
|
|
56
|
+
end
|
|
57
|
+
$roles$;
|
|
58
|
+
|
|
59
|
+
insert into agent_bridge.schema_migrations (version, name, checksum)
|
|
60
|
+
values (2, 'workspaces_agents_credentials', '__AGENT_BRIDGE_MIGRATION_CHECKSUM__')
|
|
61
|
+
on conflict (version) do update set applied_at=agent_bridge.schema_migrations.applied_at
|
|
62
|
+
where agent_bridge.schema_migrations.name=excluded.name
|
|
63
|
+
and agent_bridge.schema_migrations.checksum=excluded.checksum;
|
|
64
|
+
|
|
65
|
+
do $migration$
|
|
66
|
+
begin
|
|
67
|
+
if not exists (
|
|
68
|
+
select 1 from agent_bridge.schema_migrations
|
|
69
|
+
where version=2 and name='workspaces_agents_credentials'
|
|
70
|
+
and checksum='__AGENT_BRIDGE_MIGRATION_CHECKSUM__'
|
|
71
|
+
) then
|
|
72
|
+
raise exception 'migration 2_workspaces_agents_credentials conflicts with recorded schema state';
|
|
73
|
+
end if;
|
|
74
|
+
end
|
|
75
|
+
$migration$;
|
|
76
|
+
|
|
77
|
+
commit;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pg_advisory_xact_lock(1646705660);
|
|
4
|
+
|
|
5
|
+
create table if not exists agent_bridge.messages (
|
|
6
|
+
sequence bigint generated always as identity primary key,
|
|
7
|
+
id uuid not null unique,
|
|
8
|
+
workspace text not null references agent_bridge.workspaces(id),
|
|
9
|
+
source text not null,
|
|
10
|
+
type text not null,
|
|
11
|
+
content text not null,
|
|
12
|
+
content_type text not null default 'text/plain',
|
|
13
|
+
data jsonb,
|
|
14
|
+
targets jsonb not null default '[]'::jsonb,
|
|
15
|
+
thread_id text,
|
|
16
|
+
reply_to_id text,
|
|
17
|
+
correlation_id text,
|
|
18
|
+
causation_id text,
|
|
19
|
+
priority text not null default 'info',
|
|
20
|
+
expires_at timestamptz,
|
|
21
|
+
idempotency_key text,
|
|
22
|
+
atrib_receipt_id text,
|
|
23
|
+
informed_by jsonb,
|
|
24
|
+
metadata jsonb,
|
|
25
|
+
created_at timestamptz not null default now(),
|
|
26
|
+
unique (workspace, id),
|
|
27
|
+
check (jsonb_typeof(targets)='array'),
|
|
28
|
+
check (priority in ('info','high','urgent'))
|
|
29
|
+
);
|
|
30
|
+
create unique index if not exists messages_idempotency
|
|
31
|
+
on agent_bridge.messages(workspace, source, idempotency_key)
|
|
32
|
+
where idempotency_key is not null;
|
|
33
|
+
create index if not exists messages_cursor on agent_bridge.messages(workspace, sequence);
|
|
34
|
+
create index if not exists messages_expiry on agent_bridge.messages(workspace, expires_at)
|
|
35
|
+
where expires_at is not null;
|
|
36
|
+
|
|
37
|
+
create table if not exists agent_bridge.receipts (
|
|
38
|
+
workspace text not null,
|
|
39
|
+
message_id uuid not null,
|
|
40
|
+
principal text not null,
|
|
41
|
+
read_at timestamptz not null default now(),
|
|
42
|
+
primary key (workspace, message_id, principal),
|
|
43
|
+
foreign key (workspace, message_id)
|
|
44
|
+
references agent_bridge.messages(workspace, id) on delete cascade
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
create table if not exists agent_bridge.deliveries (
|
|
48
|
+
id uuid primary key,
|
|
49
|
+
message_id uuid not null,
|
|
50
|
+
workspace text not null,
|
|
51
|
+
recipient text not null,
|
|
52
|
+
state text not null,
|
|
53
|
+
attempt integer not null default 0,
|
|
54
|
+
available_at timestamptz not null default now(),
|
|
55
|
+
lease_token uuid,
|
|
56
|
+
lease_owner text,
|
|
57
|
+
lease_expires_at timestamptz,
|
|
58
|
+
last_error text,
|
|
59
|
+
unique (message_id, recipient),
|
|
60
|
+
foreign key (workspace, message_id)
|
|
61
|
+
references agent_bridge.messages(workspace, id) on delete cascade,
|
|
62
|
+
check (state in ('pending','claimed','acked','retrying','dead')),
|
|
63
|
+
check (attempt >= 0),
|
|
64
|
+
check ((state='claimed' and lease_token is not null and lease_expires_at is not null)
|
|
65
|
+
or (state<>'claimed' and lease_token is null and lease_owner is null and lease_expires_at is null))
|
|
66
|
+
);
|
|
67
|
+
create index if not exists deliveries_claim
|
|
68
|
+
on agent_bridge.deliveries(workspace, recipient, state, available_at);
|
|
69
|
+
|
|
70
|
+
create or replace function agent_bridge.reject_message_mutation() returns trigger
|
|
71
|
+
language plpgsql set search_path = '' as $$
|
|
72
|
+
begin
|
|
73
|
+
raise exception 'bridge messages are immutable';
|
|
74
|
+
end
|
|
75
|
+
$$;
|
|
76
|
+
drop trigger if exists messages_immutable on agent_bridge.messages;
|
|
77
|
+
create trigger messages_immutable before update or delete on agent_bridge.messages
|
|
78
|
+
for each row execute function agent_bridge.reject_message_mutation();
|
|
79
|
+
|
|
80
|
+
revoke all on all tables in schema agent_bridge from public;
|
|
81
|
+
revoke all on all sequences in schema agent_bridge from public;
|
|
82
|
+
revoke all on all functions in schema agent_bridge from public;
|
|
83
|
+
|
|
84
|
+
do $roles$
|
|
85
|
+
declare role_name text;
|
|
86
|
+
begin
|
|
87
|
+
foreach role_name in array array['anon', 'authenticated'] loop
|
|
88
|
+
if exists (select 1 from pg_roles where rolname=role_name) then
|
|
89
|
+
execute format('revoke all on schema agent_bridge from %I', role_name);
|
|
90
|
+
execute format('revoke all on all tables in schema agent_bridge from %I', role_name);
|
|
91
|
+
execute format('revoke all on all sequences in schema agent_bridge from %I', role_name);
|
|
92
|
+
execute format('revoke all on all functions in schema agent_bridge from %I', role_name);
|
|
93
|
+
end if;
|
|
94
|
+
end loop;
|
|
95
|
+
end
|
|
96
|
+
$roles$;
|
|
97
|
+
|
|
98
|
+
insert into agent_bridge.schema_migrations (version, name, checksum)
|
|
99
|
+
values (3, 'messages_receipts_deliveries', '__AGENT_BRIDGE_MIGRATION_CHECKSUM__')
|
|
100
|
+
on conflict (version) do update set applied_at=agent_bridge.schema_migrations.applied_at
|
|
101
|
+
where agent_bridge.schema_migrations.name=excluded.name
|
|
102
|
+
and agent_bridge.schema_migrations.checksum=excluded.checksum;
|
|
103
|
+
|
|
104
|
+
do $migration$
|
|
105
|
+
begin
|
|
106
|
+
if not exists (
|
|
107
|
+
select 1 from agent_bridge.schema_migrations
|
|
108
|
+
where version=3 and name='messages_receipts_deliveries'
|
|
109
|
+
and checksum='__AGENT_BRIDGE_MIGRATION_CHECKSUM__'
|
|
110
|
+
) then
|
|
111
|
+
raise exception 'migration 3_messages_receipts_deliveries conflicts with recorded schema state';
|
|
112
|
+
end if;
|
|
113
|
+
end
|
|
114
|
+
$migration$;
|
|
115
|
+
|
|
116
|
+
commit;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pg_advisory_xact_lock(1646705660);
|
|
4
|
+
|
|
5
|
+
create index if not exists messages_source
|
|
6
|
+
on agent_bridge.messages(workspace, source, sequence);
|
|
7
|
+
create index if not exists messages_thread
|
|
8
|
+
on agent_bridge.messages(workspace, thread_id, sequence)
|
|
9
|
+
where thread_id is not null;
|
|
10
|
+
create index if not exists messages_created
|
|
11
|
+
on agent_bridge.messages(workspace, created_at, sequence);
|
|
12
|
+
|
|
13
|
+
insert into agent_bridge.schema_migrations (version, name, checksum)
|
|
14
|
+
values (4, 'message_query_indexes', '__AGENT_BRIDGE_MIGRATION_CHECKSUM__')
|
|
15
|
+
on conflict (version) do update set applied_at=agent_bridge.schema_migrations.applied_at
|
|
16
|
+
where agent_bridge.schema_migrations.name=excluded.name
|
|
17
|
+
and agent_bridge.schema_migrations.checksum=excluded.checksum;
|
|
18
|
+
|
|
19
|
+
do $migration$
|
|
20
|
+
begin
|
|
21
|
+
if not exists (
|
|
22
|
+
select 1 from agent_bridge.schema_migrations
|
|
23
|
+
where version=4 and name='message_query_indexes'
|
|
24
|
+
and checksum='__AGENT_BRIDGE_MIGRATION_CHECKSUM__'
|
|
25
|
+
) then
|
|
26
|
+
raise exception 'migration 4_message_query_indexes conflicts with recorded schema state';
|
|
27
|
+
end if;
|
|
28
|
+
end
|
|
29
|
+
$migration$;
|
|
30
|
+
|
|
31
|
+
commit;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pg_advisory_xact_lock(1646705660);
|
|
4
|
+
|
|
5
|
+
create table if not exists agent_bridge.delivery_events (
|
|
6
|
+
sequence bigint generated always as identity primary key,
|
|
7
|
+
delivery_id uuid not null,
|
|
8
|
+
message_id uuid not null,
|
|
9
|
+
workspace text not null,
|
|
10
|
+
recipient text not null,
|
|
11
|
+
from_state text,
|
|
12
|
+
to_state text not null,
|
|
13
|
+
attempt integer not null,
|
|
14
|
+
lease_owner text,
|
|
15
|
+
error text,
|
|
16
|
+
created_at timestamptz not null default now()
|
|
17
|
+
);
|
|
18
|
+
create index if not exists delivery_events_lookup
|
|
19
|
+
on agent_bridge.delivery_events(workspace, delivery_id, sequence);
|
|
20
|
+
|
|
21
|
+
create or replace function agent_bridge.record_delivery_event() returns trigger
|
|
22
|
+
language plpgsql set search_path = '' as $$
|
|
23
|
+
begin
|
|
24
|
+
if tg_op = 'INSERT' or old.state is distinct from new.state or old.attempt is distinct from new.attempt then
|
|
25
|
+
insert into agent_bridge.delivery_events (
|
|
26
|
+
delivery_id, message_id, workspace, recipient, from_state, to_state,
|
|
27
|
+
attempt, lease_owner, error
|
|
28
|
+
) values (
|
|
29
|
+
new.id, new.message_id, new.workspace, new.recipient,
|
|
30
|
+
case when tg_op = 'INSERT' then null else old.state end,
|
|
31
|
+
new.state, new.attempt, new.lease_owner, new.last_error
|
|
32
|
+
);
|
|
33
|
+
end if;
|
|
34
|
+
return new;
|
|
35
|
+
end
|
|
36
|
+
$$;
|
|
37
|
+
drop trigger if exists deliveries_record_event on agent_bridge.deliveries;
|
|
38
|
+
create trigger deliveries_record_event
|
|
39
|
+
after insert or update on agent_bridge.deliveries
|
|
40
|
+
for each row execute function agent_bridge.record_delivery_event();
|
|
41
|
+
|
|
42
|
+
create table if not exists agent_bridge.agent_instances (
|
|
43
|
+
workspace text not null,
|
|
44
|
+
agent text not null,
|
|
45
|
+
instance text not null,
|
|
46
|
+
runtime_type text,
|
|
47
|
+
capabilities jsonb not null default '[]'::jsonb,
|
|
48
|
+
lease_expires_at timestamptz not null,
|
|
49
|
+
last_seen_at timestamptz not null default now(),
|
|
50
|
+
primary key (workspace, agent, instance),
|
|
51
|
+
foreign key (workspace) references agent_bridge.workspaces(id) on delete cascade,
|
|
52
|
+
check (jsonb_typeof(capabilities)='array')
|
|
53
|
+
);
|
|
54
|
+
create index if not exists agent_instances_active
|
|
55
|
+
on agent_bridge.agent_instances(workspace, lease_expires_at);
|
|
56
|
+
|
|
57
|
+
revoke all on all tables in schema agent_bridge from public;
|
|
58
|
+
revoke all on all sequences in schema agent_bridge from public;
|
|
59
|
+
revoke all on all functions in schema agent_bridge from public;
|
|
60
|
+
|
|
61
|
+
insert into agent_bridge.schema_migrations (version, name, checksum)
|
|
62
|
+
values (5, 'delivery_events_presence', '__AGENT_BRIDGE_MIGRATION_CHECKSUM__')
|
|
63
|
+
on conflict (version) do update set applied_at=agent_bridge.schema_migrations.applied_at
|
|
64
|
+
where agent_bridge.schema_migrations.name=excluded.name
|
|
65
|
+
and agent_bridge.schema_migrations.checksum=excluded.checksum;
|
|
66
|
+
|
|
67
|
+
do $migration$
|
|
68
|
+
begin
|
|
69
|
+
if not exists (
|
|
70
|
+
select 1 from agent_bridge.schema_migrations
|
|
71
|
+
where version=5 and name='delivery_events_presence'
|
|
72
|
+
and checksum='__AGENT_BRIDGE_MIGRATION_CHECKSUM__'
|
|
73
|
+
) then
|
|
74
|
+
raise exception 'migration 5_delivery_events_presence conflicts with recorded schema state';
|
|
75
|
+
end if;
|
|
76
|
+
end
|
|
77
|
+
$migration$;
|
|
78
|
+
|
|
79
|
+
commit;
|