@paintenzero/orchestra-bus 0.1.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/dist/bus.d.ts +120 -0
- package/dist/bus.d.ts.map +1 -0
- package/dist/bus.js +535 -0
- package/dist/bus.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +27 -0
package/dist/bus.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type Envelope, type ObservabilityEvent, type ControlMessage, type AgentRegistration, type AgentStatus, type PresenceEvent, type SessionEvent } from "@paintenzero/orchestra-protocol";
|
|
2
|
+
import type { BusOptions, RequestOptions, RequestHandler, Unsubscribe } from "./types.js";
|
|
3
|
+
export declare class RequestTimeoutError extends Error {
|
|
4
|
+
target: string;
|
|
5
|
+
correlationId: string;
|
|
6
|
+
constructor(target: string, correlationId: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class RemoteError extends Error {
|
|
9
|
+
target: string;
|
|
10
|
+
constructor(target: string, message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* One bus client per participant. Every agent, the orchestrator, and each UI
|
|
14
|
+
* session constructs one of these. The transport (Redis) is fully hidden behind
|
|
15
|
+
* publishEvent / subscribeEvents / request / onRequest / control / presence.
|
|
16
|
+
*/
|
|
17
|
+
export declare class Bus {
|
|
18
|
+
readonly clientId: string;
|
|
19
|
+
private readonly url;
|
|
20
|
+
private readonly redis;
|
|
21
|
+
private readonly auxConns;
|
|
22
|
+
private running;
|
|
23
|
+
private heartbeat?;
|
|
24
|
+
private registration?;
|
|
25
|
+
private readonly redisOpts;
|
|
26
|
+
constructor(opts: BusOptions);
|
|
27
|
+
private aux;
|
|
28
|
+
/** Append an event to a session's replayable stream. */
|
|
29
|
+
publishEvent(sessionId: string, event: ObservabilityEvent, opts?: {
|
|
30
|
+
causationId?: string;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Tail a session's event stream. `from`: "now" (default, only new), "start"
|
|
34
|
+
* (replay full history then tail), or a specific stream id to resume from.
|
|
35
|
+
*/
|
|
36
|
+
subscribeEvents(sessionId: string, handler: (event: ObservabilityEvent, env: Envelope<ObservabilityEvent>) => void, opts?: {
|
|
37
|
+
from?: "now" | "start" | string;
|
|
38
|
+
}): Unsubscribe;
|
|
39
|
+
/**
|
|
40
|
+
* One-shot read of a session's full event history (XRANGE - +). Used by
|
|
41
|
+
* persisters to archive the trace and by the orchestrator to serve a durable
|
|
42
|
+
* transcript when the S3 archive isn't there yet. Returns full envelopes so
|
|
43
|
+
* callers keep messageId / ts / source.
|
|
44
|
+
*/
|
|
45
|
+
readEvents(sessionId: string): Promise<Envelope<ObservabilityEvent>[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Claim a message id exactly once (Phase 6, WS3). Returns true the first time a
|
|
48
|
+
* key is seen, false on every repeat within the TTL window — so a redelivered
|
|
49
|
+
* request/control message executes at most once. Namespaced per client.
|
|
50
|
+
*/
|
|
51
|
+
dedupe(key: string, ttlMs?: number): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Snapshot a task's working memory (e.g. an agent's per-task conversation) so the
|
|
54
|
+
* task survives idle-eviction and process restarts. Keyed per client + task and
|
|
55
|
+
* TTL'd. `messages` is opaque JSON to the bus (the agent owns its shape).
|
|
56
|
+
*/
|
|
57
|
+
saveTaskContext(taskId: string, messages: unknown[]): Promise<void>;
|
|
58
|
+
/** Load a previously snapshotted task working memory, or undefined if none. */
|
|
59
|
+
loadTaskContext(taskId: string): Promise<unknown[] | undefined>;
|
|
60
|
+
/** Liveness check for the Redis connection (Phase 6, WS8 /readyz). */
|
|
61
|
+
ping(): Promise<boolean>;
|
|
62
|
+
/** Length of a stream (e.g. a DLQ depth), 0 if it doesn't exist. */
|
|
63
|
+
streamLen(key: string): Promise<number>;
|
|
64
|
+
/** Count of pending (delivered, un-acked) requests for an agent's worker group. */
|
|
65
|
+
pendingCount(agentId: string, group?: string): Promise<number>;
|
|
66
|
+
/** Announce a newly allocated session so recorders can persist + tail it. */
|
|
67
|
+
announceSession(ev: SessionEvent): Promise<void>;
|
|
68
|
+
/** React to sessions being opened in real time (mirrors watchPresence). */
|
|
69
|
+
watchSessions(handler: (event: SessionEvent) => void): Unsubscribe;
|
|
70
|
+
/** Send a directed request to an agent and await its correlated reply. */
|
|
71
|
+
request<R = unknown>(target: string, payload: unknown, opts?: RequestOptions): Promise<R>;
|
|
72
|
+
/**
|
|
73
|
+
* Register a handler for inbound requests addressed to this client. Uses a
|
|
74
|
+
* consumer group so multiple instances of the same agent load-balance work.
|
|
75
|
+
* NOTE: delivery is at-least-once — make handlers idempotent or dedupe on
|
|
76
|
+
* meta.messageId.
|
|
77
|
+
*/
|
|
78
|
+
onRequest(handler: RequestHandler, opts?: {
|
|
79
|
+
group?: string;
|
|
80
|
+
consumer?: string;
|
|
81
|
+
}): Unsubscribe;
|
|
82
|
+
private reclaimStuck;
|
|
83
|
+
private handleRequest;
|
|
84
|
+
/** Write a correlated reply onto the request's replyTo stream. */
|
|
85
|
+
private sendReply;
|
|
86
|
+
/**
|
|
87
|
+
* Fire a control signal at an agent's current run (chat / steer / cancel / …).
|
|
88
|
+
* `opts.sessionId` rides on the envelope so the agent knows which conversation
|
|
89
|
+
* the message belongs to. WS5: this goes to a **durable, replayable stream**, not
|
|
90
|
+
* fire-and-forget pub/sub — so a message sent while the agent is briefly offline
|
|
91
|
+
* is delivered when it reconnects (a blocking XREAD is still instant when live).
|
|
92
|
+
*/
|
|
93
|
+
publishControl(agentId: string, msg: ControlMessage, opts?: {
|
|
94
|
+
sessionId?: string;
|
|
95
|
+
}): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Listen for control signals addressed to this client (WS5). Tails the durable
|
|
98
|
+
* control stream with a blocking XREAD, resuming from the last id this client
|
|
99
|
+
* processed (persisted in Redis), so a process that was briefly down catches up on
|
|
100
|
+
* messages it missed. Incompatible-schema envelopes are dropped with a warning.
|
|
101
|
+
*/
|
|
102
|
+
subscribeControl(handler: (msg: ControlMessage, env: Envelope<ControlMessage>) => void): Unsubscribe;
|
|
103
|
+
/** Announce this agent and start the heartbeat that keeps it "online". */
|
|
104
|
+
register(reg: Omit<AgentRegistration, "startedAt"> & {
|
|
105
|
+
startedAt?: number;
|
|
106
|
+
}): Promise<void>;
|
|
107
|
+
updateStatus(status: AgentStatus): Promise<void>;
|
|
108
|
+
deregister(): Promise<void>;
|
|
109
|
+
/** Snapshot of all agents currently online. */
|
|
110
|
+
listAgents(): Promise<AgentRegistration[]>;
|
|
111
|
+
/** Agents currently online that advertise a given capability. */
|
|
112
|
+
findAgents(capability: string): Promise<AgentRegistration[]>;
|
|
113
|
+
/** React to agents coming and going in real time. */
|
|
114
|
+
watchPresence(handler: (event: PresenceEvent) => void): Unsubscribe;
|
|
115
|
+
private writePresence;
|
|
116
|
+
private announce;
|
|
117
|
+
private dropAux;
|
|
118
|
+
close(): Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../src/bus.ts"],"names":[],"mappings":"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"}
|
package/dist/bus.js
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
import { Redis } from "ioredis";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { channels, makeEnvelope, uuidv7, isSchemaCompatible, SCHEMA_VERSION, } from "@paintenzero/orchestra-protocol";
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
5
|
+
const PRESENCE_TTL_S = 15;
|
|
6
|
+
const HEARTBEAT_MS = 5_000;
|
|
7
|
+
const OBS_MAXLEN = Number(process.env.OBS_MAXLEN ?? 10_000); // cap on a session's live stream
|
|
8
|
+
const REPLY_TTL_S = 60; // safety net so abandoned reply streams self-clean
|
|
9
|
+
const CONTROL_MAXLEN = 1_000; // cap on a durable control stream
|
|
10
|
+
const DEDUPE_TTL_MS = Number(process.env.DEDUPE_TTL_MS ?? 86_400_000); // 24h idempotency window
|
|
11
|
+
const RECLAIM_IDLE_MS = Number(process.env.RECLAIM_IDLE_MS ?? 30_000); // reclaim pending idle this long
|
|
12
|
+
const RECLAIM_EVERY_MS = Number(process.env.RECLAIM_EVERY_MS ?? 10_000); // how often to sweep for stuck requests
|
|
13
|
+
const MAX_DELIVERIES = Number(process.env.MAX_DELIVERIES ?? 5); // attempts before dead-lettering
|
|
14
|
+
const TASK_CONTEXT_TTL_MS = Number(process.env.TASK_CONTEXT_TTL_MS ?? 7 * 86_400_000); // task snapshot retention
|
|
15
|
+
export class RequestTimeoutError extends Error {
|
|
16
|
+
target;
|
|
17
|
+
correlationId;
|
|
18
|
+
constructor(target, correlationId) {
|
|
19
|
+
super(`request to "${target}" timed out (correlationId=${correlationId})`);
|
|
20
|
+
this.target = target;
|
|
21
|
+
this.correlationId = correlationId;
|
|
22
|
+
this.name = "RequestTimeoutError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class RemoteError extends Error {
|
|
26
|
+
target;
|
|
27
|
+
constructor(target, message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.target = target;
|
|
30
|
+
this.name = "RemoteError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function safeJson(raw) {
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(raw);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Extract the JSON envelope from a stream entry's field array (["e", "<json>"]). */
|
|
42
|
+
function parseEntry(fields) {
|
|
43
|
+
const i = fields.indexOf("e");
|
|
44
|
+
if (i < 0 || i + 1 >= fields.length)
|
|
45
|
+
return undefined;
|
|
46
|
+
return safeJson(fields[i + 1]);
|
|
47
|
+
}
|
|
48
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
49
|
+
/**
|
|
50
|
+
* One bus client per participant. Every agent, the orchestrator, and each UI
|
|
51
|
+
* session constructs one of these. The transport (Redis) is fully hidden behind
|
|
52
|
+
* publishEvent / subscribeEvents / request / onRequest / control / presence.
|
|
53
|
+
*/
|
|
54
|
+
export class Bus {
|
|
55
|
+
clientId;
|
|
56
|
+
url;
|
|
57
|
+
redis; // command connection (non-blocking)
|
|
58
|
+
auxConns = new Set(); // blocking reads + pub/sub
|
|
59
|
+
running = true;
|
|
60
|
+
heartbeat;
|
|
61
|
+
registration;
|
|
62
|
+
redisOpts;
|
|
63
|
+
constructor(opts) {
|
|
64
|
+
this.clientId = opts.clientId;
|
|
65
|
+
this.url = opts.redisUrl ?? process.env.REDIS_URL ?? "redis://localhost:6379";
|
|
66
|
+
// Phase 6: authenticate to Redis. A dev user keeps the local stack runnable;
|
|
67
|
+
// a deployment sets REDIS_USERNAME/REDIS_PASSWORD per role (and per agent, so a
|
|
68
|
+
// compromised agent's ACL can't touch another's keys/channels). Options are kept
|
|
69
|
+
// so every duplicate() (blocking reads, pub/sub) inherits the same credentials.
|
|
70
|
+
this.redisOpts = {
|
|
71
|
+
maxRetriesPerRequest: null,
|
|
72
|
+
lazyConnect: false,
|
|
73
|
+
// Our ACL intentionally withholds INFO; skip ioredis's INFO-based ready check
|
|
74
|
+
// (the connection is ready after AUTH/HELLO) so least-privilege users are quiet.
|
|
75
|
+
enableReadyCheck: false,
|
|
76
|
+
username: opts.username ?? process.env.REDIS_USERNAME ?? "dev",
|
|
77
|
+
password: opts.password ?? process.env.REDIS_PASSWORD ?? "orchestra-dev",
|
|
78
|
+
};
|
|
79
|
+
// TLS to Redis: enable via rediss:// or REDIS_TLS=1; REDIS_TLS_CA points at a
|
|
80
|
+
// CA bundle for a self-signed dev cert (else system roots / rejectUnauthorized).
|
|
81
|
+
if (this.url.startsWith("rediss://") || process.env.REDIS_TLS === "1") {
|
|
82
|
+
const ca = process.env.REDIS_TLS_CA;
|
|
83
|
+
this.redisOpts.tls = ca ? { ca: readFileSync(ca) } : {};
|
|
84
|
+
}
|
|
85
|
+
this.redis = new Redis(this.url, this.redisOpts);
|
|
86
|
+
// WS6: ioredis auto-reconnects the socket and the blocking loops resume from
|
|
87
|
+
// their last id; on every (re)connect re-assert our presence so a Redis restart
|
|
88
|
+
// (which drops the TTL'd key) or a blip doesn't make us vanish from the roster.
|
|
89
|
+
this.redis.on("ready", () => {
|
|
90
|
+
if (!this.registration)
|
|
91
|
+
return;
|
|
92
|
+
void this.writePresence().catch(() => { });
|
|
93
|
+
void this.announce({ event: "register", registration: this.registration }).catch(() => { });
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
aux() {
|
|
97
|
+
const c = this.redis.duplicate();
|
|
98
|
+
this.auxConns.add(c);
|
|
99
|
+
return c;
|
|
100
|
+
}
|
|
101
|
+
// ---- observability ------------------------------------------------------
|
|
102
|
+
/** Append an event to a session's replayable stream. */
|
|
103
|
+
async publishEvent(sessionId, event, opts = {}) {
|
|
104
|
+
const env = makeEnvelope({
|
|
105
|
+
type: "event",
|
|
106
|
+
source: this.clientId,
|
|
107
|
+
sessionId,
|
|
108
|
+
causationId: opts.causationId,
|
|
109
|
+
payload: event,
|
|
110
|
+
});
|
|
111
|
+
await this.redis.xadd(channels.observability(sessionId), "MAXLEN", "~", String(OBS_MAXLEN), "*", "e", JSON.stringify(env));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Tail a session's event stream. `from`: "now" (default, only new), "start"
|
|
115
|
+
* (replay full history then tail), or a specific stream id to resume from.
|
|
116
|
+
*/
|
|
117
|
+
subscribeEvents(sessionId, handler, opts = {}) {
|
|
118
|
+
const conn = this.aux();
|
|
119
|
+
let lastId = opts.from === "start" ? "0" : opts.from && opts.from !== "now" ? opts.from : "$";
|
|
120
|
+
let active = true;
|
|
121
|
+
void (async () => {
|
|
122
|
+
while (active && this.running) {
|
|
123
|
+
try {
|
|
124
|
+
const res = (await conn.xread("BLOCK", 0, "COUNT", 100, "STREAMS", channels.observability(sessionId), lastId));
|
|
125
|
+
if (!res)
|
|
126
|
+
continue;
|
|
127
|
+
for (const [, entries] of res) {
|
|
128
|
+
for (const [id, fields] of entries) {
|
|
129
|
+
lastId = id;
|
|
130
|
+
const env = parseEntry(fields);
|
|
131
|
+
if (env)
|
|
132
|
+
handler(env.payload, env);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
if (active)
|
|
138
|
+
await sleep(200);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
})();
|
|
142
|
+
return () => {
|
|
143
|
+
active = false;
|
|
144
|
+
this.dropAux(conn);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* One-shot read of a session's full event history (XRANGE - +). Used by
|
|
149
|
+
* persisters to archive the trace and by the orchestrator to serve a durable
|
|
150
|
+
* transcript when the S3 archive isn't there yet. Returns full envelopes so
|
|
151
|
+
* callers keep messageId / ts / source.
|
|
152
|
+
*/
|
|
153
|
+
async readEvents(sessionId) {
|
|
154
|
+
const entries = (await this.redis.xrange(channels.observability(sessionId), "-", "+"));
|
|
155
|
+
const out = [];
|
|
156
|
+
for (const [, fields] of entries) {
|
|
157
|
+
const env = parseEntry(fields);
|
|
158
|
+
if (env)
|
|
159
|
+
out.push(env);
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
// ---- idempotency & introspection ---------------------------------------
|
|
164
|
+
/**
|
|
165
|
+
* Claim a message id exactly once (Phase 6, WS3). Returns true the first time a
|
|
166
|
+
* key is seen, false on every repeat within the TTL window — so a redelivered
|
|
167
|
+
* request/control message executes at most once. Namespaced per client.
|
|
168
|
+
*/
|
|
169
|
+
async dedupe(key, ttlMs = DEDUPE_TTL_MS) {
|
|
170
|
+
const res = await this.redis.set(channels.dedupe(this.clientId, key), "1", "PX", ttlMs, "NX");
|
|
171
|
+
return res === "OK";
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Snapshot a task's working memory (e.g. an agent's per-task conversation) so the
|
|
175
|
+
* task survives idle-eviction and process restarts. Keyed per client + task and
|
|
176
|
+
* TTL'd. `messages` is opaque JSON to the bus (the agent owns its shape).
|
|
177
|
+
*/
|
|
178
|
+
async saveTaskContext(taskId, messages) {
|
|
179
|
+
await this.redis.set(channels.taskContext(this.clientId, taskId), JSON.stringify(messages), "PX", TASK_CONTEXT_TTL_MS);
|
|
180
|
+
}
|
|
181
|
+
/** Load a previously snapshotted task working memory, or undefined if none. */
|
|
182
|
+
async loadTaskContext(taskId) {
|
|
183
|
+
const raw = await this.redis.get(channels.taskContext(this.clientId, taskId));
|
|
184
|
+
if (!raw)
|
|
185
|
+
return undefined;
|
|
186
|
+
return safeJson(raw);
|
|
187
|
+
}
|
|
188
|
+
/** Liveness check for the Redis connection (Phase 6, WS8 /readyz). */
|
|
189
|
+
async ping() {
|
|
190
|
+
try {
|
|
191
|
+
return (await this.redis.ping()) === "PONG";
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/** Length of a stream (e.g. a DLQ depth), 0 if it doesn't exist. */
|
|
198
|
+
async streamLen(key) {
|
|
199
|
+
return (await this.redis.xlen(key).catch(() => 0));
|
|
200
|
+
}
|
|
201
|
+
/** Count of pending (delivered, un-acked) requests for an agent's worker group. */
|
|
202
|
+
async pendingCount(agentId, group = "workers") {
|
|
203
|
+
try {
|
|
204
|
+
const summary = (await this.redis.xpending(channels.request(agentId), group));
|
|
205
|
+
return Array.isArray(summary) ? Number(summary[0] ?? 0) : 0;
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return 0; // no group yet
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ---- sessions -----------------------------------------------------------
|
|
212
|
+
/** Announce a newly allocated session so recorders can persist + tail it. */
|
|
213
|
+
async announceSession(ev) {
|
|
214
|
+
await this.redis.publish(channels.sessionEvents, JSON.stringify(ev));
|
|
215
|
+
}
|
|
216
|
+
/** React to sessions being opened in real time (mirrors watchPresence). */
|
|
217
|
+
watchSessions(handler) {
|
|
218
|
+
const conn = this.aux();
|
|
219
|
+
void conn.subscribe(channels.sessionEvents);
|
|
220
|
+
conn.on("message", (_ch, raw) => {
|
|
221
|
+
const e = safeJson(raw);
|
|
222
|
+
if (e)
|
|
223
|
+
handler(e);
|
|
224
|
+
});
|
|
225
|
+
return () => this.dropAux(conn);
|
|
226
|
+
}
|
|
227
|
+
// ---- request / reply ----------------------------------------------------
|
|
228
|
+
/** Send a directed request to an agent and await its correlated reply. */
|
|
229
|
+
async request(target, payload, opts = {}) {
|
|
230
|
+
const correlationId = uuidv7();
|
|
231
|
+
const replyTo = channels.reply(this.clientId, correlationId);
|
|
232
|
+
const env = makeEnvelope({
|
|
233
|
+
type: "request",
|
|
234
|
+
source: this.clientId,
|
|
235
|
+
target,
|
|
236
|
+
correlationId,
|
|
237
|
+
replyTo,
|
|
238
|
+
sessionId: opts.sessionId,
|
|
239
|
+
causationId: opts.causationId,
|
|
240
|
+
payload,
|
|
241
|
+
});
|
|
242
|
+
await this.redis.xadd(channels.request(target), "*", "e", JSON.stringify(env));
|
|
243
|
+
const conn = this.aux();
|
|
244
|
+
try {
|
|
245
|
+
// Read from "0": if the reply already landed we get it immediately,
|
|
246
|
+
// otherwise BLOCK waits for the first entry on this unique stream.
|
|
247
|
+
const res = (await conn.xread("BLOCK", opts.timeoutMs ?? DEFAULT_TIMEOUT_MS, "COUNT", 1, "STREAMS", replyTo, "0"));
|
|
248
|
+
if (!res)
|
|
249
|
+
throw new RequestTimeoutError(target, correlationId);
|
|
250
|
+
const env2 = parseEntry(res[0][1][0][1]);
|
|
251
|
+
if (!env2)
|
|
252
|
+
throw new RemoteError(target, "malformed reply");
|
|
253
|
+
if (!env2.payload.ok)
|
|
254
|
+
throw new RemoteError(target, env2.payload.error);
|
|
255
|
+
return env2.payload.result;
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
this.dropAux(conn);
|
|
259
|
+
await this.redis.del(replyTo).catch(() => { });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Register a handler for inbound requests addressed to this client. Uses a
|
|
264
|
+
* consumer group so multiple instances of the same agent load-balance work.
|
|
265
|
+
* NOTE: delivery is at-least-once — make handlers idempotent or dedupe on
|
|
266
|
+
* meta.messageId.
|
|
267
|
+
*/
|
|
268
|
+
onRequest(handler, opts = {}) {
|
|
269
|
+
const stream = channels.request(this.clientId);
|
|
270
|
+
const group = opts.group ?? "workers";
|
|
271
|
+
const consumer = opts.consumer ?? `${this.clientId}#${process.pid}`;
|
|
272
|
+
const conn = this.aux();
|
|
273
|
+
let active = true;
|
|
274
|
+
void (async () => {
|
|
275
|
+
try {
|
|
276
|
+
await conn.xgroup("CREATE", stream, group, "$", "MKSTREAM");
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
/* BUSYGROUP: group already exists */
|
|
280
|
+
}
|
|
281
|
+
while (active && this.running) {
|
|
282
|
+
try {
|
|
283
|
+
const res = (await conn.xreadgroup("GROUP", group, consumer, "BLOCK", 5000, "COUNT", 10, "STREAMS", stream, ">"));
|
|
284
|
+
if (!res)
|
|
285
|
+
continue;
|
|
286
|
+
for (const [, entries] of res) {
|
|
287
|
+
for (const [id, fields] of entries) {
|
|
288
|
+
await this.handleRequest(stream, group, id, fields, handler);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
if (active)
|
|
294
|
+
await sleep(200);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
})();
|
|
298
|
+
// WS4: sweep for requests a dead worker left pending — reclaim them to this
|
|
299
|
+
// consumer (re-process; the dedupe guard prevents a double run), or after too
|
|
300
|
+
// many delivery attempts dead-letter the poison message rather than loop forever.
|
|
301
|
+
const reclaim = setInterval(() => {
|
|
302
|
+
if (active && this.running)
|
|
303
|
+
void this.reclaimStuck(stream, group, consumer, handler);
|
|
304
|
+
}, RECLAIM_EVERY_MS);
|
|
305
|
+
reclaim.unref?.(); // a background sweep must not keep the process alive on its own
|
|
306
|
+
return () => {
|
|
307
|
+
active = false;
|
|
308
|
+
clearInterval(reclaim);
|
|
309
|
+
this.dropAux(conn);
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async reclaimStuck(stream, group, consumer, handler) {
|
|
313
|
+
try {
|
|
314
|
+
// [count, [[id, consumer, idleMs, deliveries], ...]] — pending entries idle long enough.
|
|
315
|
+
const pending = (await this.redis.xpending(stream, group, "IDLE", RECLAIM_IDLE_MS, "-", "+", 50));
|
|
316
|
+
if (!Array.isArray(pending))
|
|
317
|
+
return;
|
|
318
|
+
for (const [id, , , deliveries] of pending) {
|
|
319
|
+
const claimed = (await this.redis.xclaim(stream, group, consumer, RECLAIM_IDLE_MS, id));
|
|
320
|
+
if (!claimed?.length)
|
|
321
|
+
continue; // someone else got it, or it was acked
|
|
322
|
+
const [, fields] = claimed[0];
|
|
323
|
+
if (Number(deliveries) > MAX_DELIVERIES) {
|
|
324
|
+
await this.redis.xadd(channels.requestDlq(this.clientId), "*", ...fields);
|
|
325
|
+
await this.redis.xack(stream, group, id).catch(() => { });
|
|
326
|
+
console.warn(`[bus] dead-lettered ${id} after ${deliveries} attempts → ${channels.requestDlq(this.clientId)}`);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
await this.handleRequest(stream, group, id, fields, handler);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
/* transient; the next sweep retries */
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async handleRequest(stream, group, id, fields, handler) {
|
|
338
|
+
const env = parseEntry(fields);
|
|
339
|
+
if (!env || !env.correlationId) {
|
|
340
|
+
await this.redis.xack(stream, group, id).catch(() => { });
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// WS7: reject an envelope from an incompatible schema rather than mis-parsing —
|
|
344
|
+
// reply with a clear error so the caller isn't left hanging, then ack.
|
|
345
|
+
if (!isSchemaCompatible(env)) {
|
|
346
|
+
const error = `unsupported schemaVersion ${env.schemaVersion} (expected ${SCHEMA_VERSION})`;
|
|
347
|
+
if (env.replyTo)
|
|
348
|
+
await this.sendReply(env, { ok: false, error });
|
|
349
|
+
await this.redis.xack(stream, group, id).catch(() => { });
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// WS3: claim this messageId once. A redelivery (e.g. after a worker died before
|
|
353
|
+
// acking) is skipped here so an expensive handler never runs twice.
|
|
354
|
+
if (!(await this.dedupe(`req:${env.messageId}`))) {
|
|
355
|
+
await this.redis.xack(stream, group, id).catch(() => { });
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
let body;
|
|
359
|
+
try {
|
|
360
|
+
const result = await handler(env.payload, {
|
|
361
|
+
messageId: env.messageId,
|
|
362
|
+
source: env.source,
|
|
363
|
+
correlationId: env.correlationId,
|
|
364
|
+
sessionId: env.sessionId,
|
|
365
|
+
causationId: env.causationId,
|
|
366
|
+
});
|
|
367
|
+
body = { ok: true, result };
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
body = { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
371
|
+
}
|
|
372
|
+
if (env.replyTo)
|
|
373
|
+
await this.sendReply(env, body);
|
|
374
|
+
await this.redis.xack(stream, group, id);
|
|
375
|
+
}
|
|
376
|
+
/** Write a correlated reply onto the request's replyTo stream. */
|
|
377
|
+
async sendReply(env, body) {
|
|
378
|
+
if (!env.replyTo)
|
|
379
|
+
return;
|
|
380
|
+
const reply = makeEnvelope({
|
|
381
|
+
type: "response",
|
|
382
|
+
source: this.clientId,
|
|
383
|
+
target: env.source,
|
|
384
|
+
correlationId: env.correlationId,
|
|
385
|
+
causationId: env.messageId,
|
|
386
|
+
sessionId: env.sessionId,
|
|
387
|
+
payload: body,
|
|
388
|
+
});
|
|
389
|
+
await this.redis.xadd(env.replyTo, "*", "e", JSON.stringify(reply));
|
|
390
|
+
await this.redis.expire(env.replyTo, REPLY_TTL_S);
|
|
391
|
+
}
|
|
392
|
+
// ---- control ------------------------------------------------------------
|
|
393
|
+
/**
|
|
394
|
+
* Fire a control signal at an agent's current run (chat / steer / cancel / …).
|
|
395
|
+
* `opts.sessionId` rides on the envelope so the agent knows which conversation
|
|
396
|
+
* the message belongs to. WS5: this goes to a **durable, replayable stream**, not
|
|
397
|
+
* fire-and-forget pub/sub — so a message sent while the agent is briefly offline
|
|
398
|
+
* is delivered when it reconnects (a blocking XREAD is still instant when live).
|
|
399
|
+
*/
|
|
400
|
+
async publishControl(agentId, msg, opts = {}) {
|
|
401
|
+
const env = makeEnvelope({
|
|
402
|
+
type: "control",
|
|
403
|
+
source: this.clientId,
|
|
404
|
+
target: agentId,
|
|
405
|
+
sessionId: opts.sessionId,
|
|
406
|
+
payload: msg,
|
|
407
|
+
});
|
|
408
|
+
await this.redis.xadd(channels.controlStream(agentId), "MAXLEN", "~", String(CONTROL_MAXLEN), "*", "e", JSON.stringify(env));
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Listen for control signals addressed to this client (WS5). Tails the durable
|
|
412
|
+
* control stream with a blocking XREAD, resuming from the last id this client
|
|
413
|
+
* processed (persisted in Redis), so a process that was briefly down catches up on
|
|
414
|
+
* messages it missed. Incompatible-schema envelopes are dropped with a warning.
|
|
415
|
+
*/
|
|
416
|
+
subscribeControl(handler) {
|
|
417
|
+
const conn = this.aux();
|
|
418
|
+
const stream = channels.controlStream(this.clientId);
|
|
419
|
+
const posKey = channels.controlPos(this.clientId);
|
|
420
|
+
let active = true;
|
|
421
|
+
void (async () => {
|
|
422
|
+
// Resume from the persisted position; first-ever start tails only new ("$").
|
|
423
|
+
let lastId = (await this.redis.get(posKey).catch(() => null)) ?? "$";
|
|
424
|
+
while (active && this.running) {
|
|
425
|
+
try {
|
|
426
|
+
const res = (await conn.xread("BLOCK", 0, "COUNT", 50, "STREAMS", stream, lastId));
|
|
427
|
+
if (!res)
|
|
428
|
+
continue;
|
|
429
|
+
for (const [, entries] of res) {
|
|
430
|
+
for (const [id, fields] of entries) {
|
|
431
|
+
lastId = id;
|
|
432
|
+
const env = parseEntry(fields);
|
|
433
|
+
if (env && !isSchemaCompatible(env)) {
|
|
434
|
+
console.warn(`[bus] dropped control with schemaVersion ${env.schemaVersion}`);
|
|
435
|
+
}
|
|
436
|
+
else if (env) {
|
|
437
|
+
handler(env.payload, env);
|
|
438
|
+
}
|
|
439
|
+
await this.redis.set(posKey, id).catch(() => { });
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
catch {
|
|
444
|
+
if (active)
|
|
445
|
+
await sleep(200);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
})();
|
|
449
|
+
return () => {
|
|
450
|
+
active = false;
|
|
451
|
+
this.dropAux(conn);
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
// ---- presence -----------------------------------------------------------
|
|
455
|
+
/** Announce this agent and start the heartbeat that keeps it "online". */
|
|
456
|
+
async register(reg) {
|
|
457
|
+
this.registration = { startedAt: Date.now(), ...reg };
|
|
458
|
+
await this.writePresence();
|
|
459
|
+
this.heartbeat = setInterval(() => void this.writePresence().catch(() => { }), HEARTBEAT_MS);
|
|
460
|
+
await this.announce({ event: "register", registration: this.registration });
|
|
461
|
+
}
|
|
462
|
+
async updateStatus(status) {
|
|
463
|
+
if (!this.registration)
|
|
464
|
+
return;
|
|
465
|
+
this.registration.status = status;
|
|
466
|
+
await this.writePresence();
|
|
467
|
+
await this.announce({ event: "update", registration: this.registration });
|
|
468
|
+
}
|
|
469
|
+
async deregister() {
|
|
470
|
+
if (this.heartbeat)
|
|
471
|
+
clearInterval(this.heartbeat);
|
|
472
|
+
if (!this.registration)
|
|
473
|
+
return;
|
|
474
|
+
const id = this.registration.id;
|
|
475
|
+
await this.redis.del(channels.presenceKey(id)).catch(() => { });
|
|
476
|
+
await this.announce({ event: "deregister", id });
|
|
477
|
+
this.registration = undefined;
|
|
478
|
+
}
|
|
479
|
+
/** Snapshot of all agents currently online. */
|
|
480
|
+
async listAgents() {
|
|
481
|
+
const keys = [];
|
|
482
|
+
let cursor = "0";
|
|
483
|
+
do {
|
|
484
|
+
const [next, batch] = await this.redis.scan(cursor, "MATCH", channels.presenceScan, "COUNT", 100);
|
|
485
|
+
cursor = next;
|
|
486
|
+
keys.push(...batch);
|
|
487
|
+
} while (cursor !== "0");
|
|
488
|
+
if (keys.length === 0)
|
|
489
|
+
return [];
|
|
490
|
+
const vals = (await this.redis.mget(keys));
|
|
491
|
+
return vals
|
|
492
|
+
.filter((v) => Boolean(v))
|
|
493
|
+
.map((v) => safeJson(v))
|
|
494
|
+
.filter((r) => Boolean(r));
|
|
495
|
+
}
|
|
496
|
+
/** Agents currently online that advertise a given capability. */
|
|
497
|
+
async findAgents(capability) {
|
|
498
|
+
const all = await this.listAgents();
|
|
499
|
+
return all.filter((a) => a.capabilities.includes(capability));
|
|
500
|
+
}
|
|
501
|
+
/** React to agents coming and going in real time. */
|
|
502
|
+
watchPresence(handler) {
|
|
503
|
+
const conn = this.aux();
|
|
504
|
+
void conn.subscribe(channels.presenceEvents);
|
|
505
|
+
conn.on("message", (_ch, raw) => {
|
|
506
|
+
const e = safeJson(raw);
|
|
507
|
+
if (e)
|
|
508
|
+
handler(e);
|
|
509
|
+
});
|
|
510
|
+
return () => this.dropAux(conn);
|
|
511
|
+
}
|
|
512
|
+
async writePresence() {
|
|
513
|
+
if (!this.registration)
|
|
514
|
+
return;
|
|
515
|
+
await this.redis.set(channels.presenceKey(this.registration.id), JSON.stringify(this.registration), "EX", PRESENCE_TTL_S);
|
|
516
|
+
}
|
|
517
|
+
async announce(event) {
|
|
518
|
+
await this.redis.publish(channels.presenceEvents, JSON.stringify(event));
|
|
519
|
+
}
|
|
520
|
+
// ---- lifecycle ----------------------------------------------------------
|
|
521
|
+
dropAux(conn) {
|
|
522
|
+
this.auxConns.delete(conn);
|
|
523
|
+
conn.disconnect();
|
|
524
|
+
}
|
|
525
|
+
async close() {
|
|
526
|
+
this.running = false;
|
|
527
|
+
if (this.heartbeat)
|
|
528
|
+
clearInterval(this.heartbeat);
|
|
529
|
+
for (const c of this.auxConns)
|
|
530
|
+
c.disconnect();
|
|
531
|
+
this.auxConns.clear();
|
|
532
|
+
this.redis.disconnect();
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
//# sourceMappingURL=bus.js.map
|
package/dist/bus.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bus.js","sourceRoot":"","sources":["../src/bus.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Envelope } from "@paintenzero/orchestra-protocol";
|
|
2
|
+
export interface BusOptions {
|
|
3
|
+
/** This participant's stable id (agent id, "orchestrator", "ui:<session>"). */
|
|
4
|
+
clientId: string;
|
|
5
|
+
/** Defaults to env REDIS_URL or redis://localhost:6379. */
|
|
6
|
+
redisUrl?: string;
|
|
7
|
+
/** Redis ACL user (Phase 6). Defaults to env REDIS_USERNAME, else the dev user. */
|
|
8
|
+
username?: string;
|
|
9
|
+
/** Redis ACL password (Phase 6). Defaults to env REDIS_PASSWORD, else the dev password. */
|
|
10
|
+
password?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RequestOptions {
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
sessionId?: string;
|
|
15
|
+
causationId?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RequestMeta {
|
|
18
|
+
messageId: string;
|
|
19
|
+
source: string;
|
|
20
|
+
correlationId: string;
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
causationId?: string;
|
|
23
|
+
}
|
|
24
|
+
export type RequestHandler = (payload: unknown, meta: RequestMeta) => Promise<unknown> | unknown;
|
|
25
|
+
export type Unsubscribe = () => void;
|
|
26
|
+
export type EnvelopeOf<P> = Envelope<P>;
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAEjG,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@paintenzero/orchestra-bus",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json",
|
|
21
|
+
"prepublishOnly": "tsc -p tsconfig.json"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@paintenzero/orchestra-protocol": "workspace:^",
|
|
25
|
+
"ioredis": "^5.4.0"
|
|
26
|
+
}
|
|
27
|
+
}
|