@masons/agent-network 0.5.14 → 0.5.16
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/channel.d.ts +0 -7
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +3 -174
- package/dist/cli-setup.d.ts +0 -109
- package/dist/cli-setup.d.ts.map +1 -1
- package/dist/cli-setup.js +16 -570
- package/dist/config-fs.d.ts +4 -0
- package/dist/config-fs.d.ts.map +1 -0
- package/dist/config-fs.js +23 -0
- package/dist/config-schema.js +2 -2
- package/dist/config.d.ts +2 -210
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -334
- package/dist/connector-client.d.ts +0 -32
- package/dist/connector-client.d.ts.map +1 -1
- package/dist/connector-client.js +1 -89
- package/dist/constants.d.ts +0 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -3
- package/dist/conversation-manager.d.ts +0 -106
- package/dist/conversation-manager.d.ts.map +1 -1
- package/dist/conversation-manager.js +2 -131
- package/dist/environment-context.d.ts +0 -24
- package/dist/environment-context.d.ts.map +1 -1
- package/dist/environment-context.js +0 -42
- package/dist/handle-utils.d.ts +0 -14
- package/dist/handle-utils.d.ts.map +1 -1
- package/dist/handle-utils.js +0 -14
- package/dist/index.js +0 -9
- package/dist/owner-notes.d.ts +0 -33
- package/dist/owner-notes.d.ts.map +1 -1
- package/dist/owner-notes.js +2 -41
- package/dist/owner-session-state.d.ts +0 -26
- package/dist/owner-session-state.d.ts.map +1 -1
- package/dist/owner-session-state.js +0 -37
- package/dist/platform-client.d.ts +13 -202
- package/dist/platform-client.d.ts.map +1 -1
- package/dist/platform-client.js +22 -171
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +3 -167
- package/dist/sent-message-buffer.d.ts +0 -36
- package/dist/sent-message-buffer.d.ts.map +1 -1
- package/dist/sent-message-buffer.js +1 -45
- package/dist/tools.d.ts +0 -28
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +36 -240
- package/dist/turn-context.d.ts +0 -45
- package/dist/turn-context.d.ts.map +1 -1
- package/dist/turn-context.js +0 -57
- package/dist/types.d.ts +0 -67
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -7
- package/dist/update-cache.d.ts +0 -17
- package/dist/update-cache.d.ts.map +1 -1
- package/dist/update-cache.js +1 -21
- package/dist/update-check.d.ts +1 -40
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js +7 -66
- package/dist/version.d.ts +1 -2
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -2
- package/openclaw.plugin.json +94 -3
- package/package.json +11 -10
- package/skills/agent-network/SKILL.md +21 -47
- package/skills/agent-network/references/troubleshooting.md +5 -5
package/dist/connector-client.js
CHANGED
|
@@ -7,23 +7,12 @@ import { CURRENT_PROTOCOL_VERSION, isAddressedMessage, isDeliveryPending, isDeli
|
|
|
7
7
|
import { PLUGIN_VERSION } from "./version.js";
|
|
8
8
|
const dbg = createDebug("agent-network:connector");
|
|
9
9
|
const dbgMsg = createDebug("agent-network:connector:msg");
|
|
10
|
-
// --- Reconnection constants ---
|
|
11
10
|
const BACKOFF_INITIAL_MS = 1_000;
|
|
12
11
|
const BACKOFF_MAX_MS = 30_000;
|
|
13
12
|
const ALREADY_CONNECTED_RETRY_MS = 2_000;
|
|
14
13
|
const ALREADY_CONNECTED_MAX_RETRIES = 30;
|
|
15
|
-
// --- Single-driver Node semantic (#1264) ---
|
|
16
|
-
// The connector closes with WS code 4001 + this reason when a new Runtime
|
|
17
|
-
// REGISTERs for the same agentId. The current api_key may have been rotated
|
|
18
|
-
// by /runtime/v1/onboard select mode, so reconnecting with the cached token
|
|
19
|
-
// is futile (would 401 forever).
|
|
20
14
|
const REPLACED_BY_NEW_RUNTIME_REASON = "Replaced by new Runtime";
|
|
21
15
|
const REPLACED_BY_NEW_RUNTIME_CODE = 4001;
|
|
22
|
-
// --- Error class for structured errors ---
|
|
23
|
-
/**
|
|
24
|
-
* Error with machine-readable `code` from Connector structured errors.
|
|
25
|
-
* Thrown by `send()` when the Connector responds with ERROR { code }.
|
|
26
|
-
*/
|
|
27
16
|
export class ConnectorError extends Error {
|
|
28
17
|
code;
|
|
29
18
|
to;
|
|
@@ -34,7 +23,6 @@ export class ConnectorError extends Error {
|
|
|
34
23
|
this.to = to;
|
|
35
24
|
}
|
|
36
25
|
}
|
|
37
|
-
// --- ConnectorClient ---
|
|
38
26
|
export class ConnectorClient extends EventEmitter {
|
|
39
27
|
url;
|
|
40
28
|
token;
|
|
@@ -46,19 +34,13 @@ export class ConnectorClient extends EventEmitter {
|
|
|
46
34
|
registerResolve = null;
|
|
47
35
|
registerReject = null;
|
|
48
36
|
registerTimer = null;
|
|
49
|
-
/** Delivery cursor — highest recipientSeq received from Connector (#1133).
|
|
50
|
-
* Sent on REGISTER so the Connector can fill any gap. In-memory only —
|
|
51
|
-
* survives Connector restarts (Plugin stays alive), lost on Plugin restart
|
|
52
|
-
* (graceful degradation: no gap fill, same as pre-#1133 behavior). */
|
|
53
37
|
lastKnownSeq;
|
|
54
|
-
/** Pending SEND_ACK correlation map for address-based sends. */
|
|
55
38
|
pendingSends = new Map();
|
|
56
39
|
constructor(url, token) {
|
|
57
40
|
super();
|
|
58
41
|
this.url = url;
|
|
59
42
|
this.token = token;
|
|
60
43
|
}
|
|
61
|
-
// --- Public API ---
|
|
62
44
|
connect() {
|
|
63
45
|
if (this.ws) {
|
|
64
46
|
return Promise.reject(new Error("Already connecting or connected"));
|
|
@@ -79,14 +61,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
79
61
|
wsToClose.close(1000, "Client disconnect");
|
|
80
62
|
}
|
|
81
63
|
}
|
|
82
|
-
// --- Messaging ---
|
|
83
|
-
/**
|
|
84
|
-
* Send a message to a routable address. Returns a Promise that resolves
|
|
85
|
-
* with the SEND_ACK from the Connector, or rejects with a ConnectorError
|
|
86
|
-
* (structured error code) or a plain Error (timeout / disconnect).
|
|
87
|
-
*
|
|
88
|
-
* The messageId is generated internally and used for ACK correlation.
|
|
89
|
-
*/
|
|
90
64
|
send(to, content, contentType = "text", metadata) {
|
|
91
65
|
const messageId = randomUUID();
|
|
92
66
|
const event = {
|
|
@@ -111,18 +85,12 @@ export class ConnectorClient extends EventEmitter {
|
|
|
111
85
|
}
|
|
112
86
|
});
|
|
113
87
|
}
|
|
114
|
-
/**
|
|
115
|
-
* Send a typing indicator to a routable address.
|
|
116
|
-
*/
|
|
117
88
|
sendTyping(to, isTyping) {
|
|
118
89
|
const event = { event: "TYPING", to, isTyping };
|
|
119
90
|
const sent = this.sendEvent(event);
|
|
120
91
|
dbg("sendTyping to=%s isTyping=%s sent=%s", to, isTyping, sent);
|
|
121
92
|
return sent;
|
|
122
93
|
}
|
|
123
|
-
/**
|
|
124
|
-
* Acknowledge delivery of stored messages up to a timestamp.
|
|
125
|
-
*/
|
|
126
94
|
ackDelivery(upTo) {
|
|
127
95
|
const event = { event: "DELIVERY_ACK", upTo };
|
|
128
96
|
const sent = this.sendEvent(event);
|
|
@@ -141,7 +109,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
141
109
|
emit(event, ...args) {
|
|
142
110
|
return super.emit(event, ...args);
|
|
143
111
|
}
|
|
144
|
-
// --- Connection lifecycle ---
|
|
145
112
|
doConnect() {
|
|
146
113
|
return new Promise((resolve, reject) => {
|
|
147
114
|
this.registerResolve = resolve;
|
|
@@ -153,8 +120,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
153
120
|
this.startRegisterTimeout();
|
|
154
121
|
});
|
|
155
122
|
ws.on("message", this.handleMessage);
|
|
156
|
-
// ws's "close" event passes (code, reason) — handleClose accepts both.
|
|
157
|
-
// Pass the bound arrow reference so cleanupConnection can `off()` it.
|
|
158
123
|
ws.on("close", this.handleClose);
|
|
159
124
|
ws.on("error", this.handleError);
|
|
160
125
|
});
|
|
@@ -200,7 +165,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
200
165
|
this.registerReject = null;
|
|
201
166
|
}
|
|
202
167
|
}
|
|
203
|
-
// --- Message handling ---
|
|
204
168
|
handleMessage = (data) => {
|
|
205
169
|
let parsed;
|
|
206
170
|
try {
|
|
@@ -210,14 +174,12 @@ export class ConnectorClient extends EventEmitter {
|
|
|
210
174
|
this.emit("error", new Error("Received non-JSON message from Connector"));
|
|
211
175
|
return;
|
|
212
176
|
}
|
|
213
|
-
// REGISTER_ACK is version-agnostic — always handled first
|
|
214
177
|
if (isRegisterAck(parsed)) {
|
|
215
178
|
this.handleRegisterAck(parsed);
|
|
216
179
|
return;
|
|
217
180
|
}
|
|
218
181
|
this.dispatchAddressed(parsed);
|
|
219
182
|
};
|
|
220
|
-
/** Dispatch inbound address-based events. */
|
|
221
183
|
dispatchAddressed(parsed) {
|
|
222
184
|
if (isSendAck(parsed)) {
|
|
223
185
|
dbg("SEND_ACK messageId=%s status=%s", parsed.messageId, parsed.status);
|
|
@@ -226,7 +188,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
226
188
|
}
|
|
227
189
|
if (isAddressedMessage(parsed)) {
|
|
228
190
|
dbgMsg("MESSAGE_RECEIVED from=%s contentLength=%d seq=%s", parsed.from, parsed.content.length, parsed.seq ?? "none");
|
|
229
|
-
// Advance delivery cursor (#1133)
|
|
230
191
|
if (typeof parsed.seq === "number" &&
|
|
231
192
|
(this.lastKnownSeq === undefined || parsed.seq > this.lastKnownSeq)) {
|
|
232
193
|
this.lastKnownSeq = parsed.seq;
|
|
@@ -249,23 +210,14 @@ export class ConnectorClient extends EventEmitter {
|
|
|
249
210
|
this.handleStructuredError(parsed);
|
|
250
211
|
return;
|
|
251
212
|
}
|
|
252
|
-
// Unknown event type — silently ignore (forward compatibility)
|
|
253
213
|
}
|
|
254
214
|
handleRegisterAck(ack) {
|
|
255
215
|
dbg("REGISTER_ACK status=%s protocolVersion=%d", ack.status, ack.protocolVersion);
|
|
256
216
|
if (ack.status === "ok") {
|
|
257
|
-
// Defensive: verify the negotiated version matches what we requested.
|
|
258
|
-
// Current Connector rejects unsupported versions outright (no downgrade),
|
|
259
|
-
// so this check is future-proofing against silent protocol desync.
|
|
260
217
|
if (ack.protocolVersion !== CURRENT_PROTOCOL_VERSION) {
|
|
261
218
|
dbg("WARN: server negotiated protocolVersion=%d, expected=%d", ack.protocolVersion, CURRENT_PROTOCOL_VERSION);
|
|
262
219
|
}
|
|
263
|
-
// Store agent + owner identity from enriched REGISTER_ACK (#969).
|
|
264
|
-
// Old Connectors omit these fields — setEnvironmentContext handles undefined.
|
|
265
220
|
setEnvironmentContext(ack.agent, ack.owner);
|
|
266
|
-
// Initialize delivery cursor from server (#1133).
|
|
267
|
-
// Only set on first connect (lastKnownSeq === undefined). On reconnect,
|
|
268
|
-
// the Plugin already has a cursor from previous MESSAGE_RECEIVED events.
|
|
269
221
|
if (typeof ack.deliverySeq === "number" &&
|
|
270
222
|
this.lastKnownSeq === undefined) {
|
|
271
223
|
this.lastKnownSeq = ack.deliverySeq;
|
|
@@ -278,7 +230,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
278
230
|
}
|
|
279
231
|
else {
|
|
280
232
|
const reason = ack.reason ?? "Unknown registration error";
|
|
281
|
-
// "Unsupported protocol version" — do not reconnect
|
|
282
233
|
if (reason === "Unsupported protocol version") {
|
|
283
234
|
this.intentionalClose = true;
|
|
284
235
|
this.rejectRegister(new Error(reason));
|
|
@@ -286,13 +237,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
286
237
|
this.ws?.close(4001, reason);
|
|
287
238
|
return;
|
|
288
239
|
}
|
|
289
|
-
// "Already connected" — track retries for short backoff.
|
|
290
|
-
// As of connector #1264 the server flips this to single-driver
|
|
291
|
-
// eviction (close code 4001 + reason "Replaced by new Runtime",
|
|
292
|
-
// handled in handleClose). The REGISTER_ACK error path with this
|
|
293
|
-
// reason is now only reachable against pre-#1264 connector
|
|
294
|
-
// deployments during a rollout window — kept for that compat,
|
|
295
|
-
// safe to remove in 0.7.0 once preview/production are upgraded.
|
|
296
240
|
if (reason === "Already connected") {
|
|
297
241
|
this.alreadyConnectedRetries++;
|
|
298
242
|
}
|
|
@@ -300,11 +244,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
300
244
|
this.ws?.close(4001, reason);
|
|
301
245
|
}
|
|
302
246
|
}
|
|
303
|
-
// --- Address-based handlers ---
|
|
304
|
-
/**
|
|
305
|
-
* Resolve the pending send promise matching this SEND_ACK.
|
|
306
|
-
* Also emits `send_ack` for listeners that want to observe all ACKs.
|
|
307
|
-
*/
|
|
308
247
|
handleSendAck(ack) {
|
|
309
248
|
this.emit("send_ack", ack);
|
|
310
249
|
const pending = this.pendingSends.get(ack.messageId);
|
|
@@ -314,13 +253,8 @@ export class ConnectorClient extends EventEmitter {
|
|
|
314
253
|
pending.resolve(ack);
|
|
315
254
|
}
|
|
316
255
|
}
|
|
317
|
-
/**
|
|
318
|
-
* Structured ERROR: message-scoped errors reject pending sends,
|
|
319
|
-
* connection-scoped errors emit generic event.
|
|
320
|
-
*/
|
|
321
256
|
handleStructuredError(event) {
|
|
322
257
|
this.emit("structured_error", event);
|
|
323
|
-
// Message-scoped: reject the pending send for this messageId
|
|
324
258
|
if (event.messageId) {
|
|
325
259
|
const pending = this.pendingSends.get(event.messageId);
|
|
326
260
|
if (pending) {
|
|
@@ -330,10 +264,8 @@ export class ConnectorClient extends EventEmitter {
|
|
|
330
264
|
return;
|
|
331
265
|
}
|
|
332
266
|
}
|
|
333
|
-
// Connection-scoped: emit generic error
|
|
334
267
|
this.emit("error", new Error(`[${event.code}] ${event.message}`));
|
|
335
268
|
}
|
|
336
|
-
// --- Connection close ---
|
|
337
269
|
handleClose = (code, reason) => {
|
|
338
270
|
const reasonStr = reason
|
|
339
271
|
? typeof reason === "string"
|
|
@@ -343,18 +275,12 @@ export class ConnectorClient extends EventEmitter {
|
|
|
343
275
|
dbg("connection closed code=%s reason=%s intentional=%s", code ?? "?", reasonStr, this.intentionalClose);
|
|
344
276
|
const wasRegistering = this.registerReject !== null;
|
|
345
277
|
this.cleanupConnection();
|
|
346
|
-
// Single-driver eviction (#1264) — connector closes us with code 4001
|
|
347
|
-
// and reason "Replaced by new Runtime" when a new REGISTER claims our
|
|
348
|
-
// agentId. The api_key we hold may have been rotated by the new
|
|
349
|
-
// Runtime's /runtime/v1/onboard call; reconnecting would 401 forever.
|
|
350
|
-
// Treat as terminal: stop reconnects, surface an actionable message,
|
|
351
|
-
// emit a distinct event so consumers (channel.ts, etc.) can react.
|
|
352
278
|
const replacedByNewRuntime = code === REPLACED_BY_NEW_RUNTIME_CODE &&
|
|
353
279
|
reasonStr === REPLACED_BY_NEW_RUNTIME_REASON;
|
|
354
280
|
if (replacedByNewRuntime) {
|
|
355
281
|
this.intentionalClose = true;
|
|
356
282
|
const msg = "This agent was claimed by another Runtime " +
|
|
357
|
-
"(
|
|
283
|
+
"(this Runtime disconnected). " +
|
|
358
284
|
"Re-run `openclaw channels login --channel agent-network` " +
|
|
359
285
|
"to drive this agent from here again.";
|
|
360
286
|
this.emit("error", new Error(msg));
|
|
@@ -365,15 +291,10 @@ export class ConnectorClient extends EventEmitter {
|
|
|
365
291
|
return;
|
|
366
292
|
}
|
|
367
293
|
if (wasRegistering) {
|
|
368
|
-
// Connection closed during REGISTER — check for special retry logic
|
|
369
|
-
// (handled by rejectRegister which was already called if ACK error came first)
|
|
370
294
|
if (this.registerReject) {
|
|
371
295
|
this.rejectRegister(new Error("Connection closed during registration"));
|
|
372
296
|
}
|
|
373
297
|
}
|
|
374
|
-
// "disconnected" is emitted on every close, including intermediate closes
|
|
375
|
-
// during reconnect cycles. This is intentional — channel adapter uses this
|
|
376
|
-
// to clear stale session state before a fresh REGISTER re-creates sessions.
|
|
377
298
|
this.emit("disconnected");
|
|
378
299
|
if (!this.intentionalClose) {
|
|
379
300
|
this.scheduleReconnect();
|
|
@@ -381,10 +302,8 @@ export class ConnectorClient extends EventEmitter {
|
|
|
381
302
|
};
|
|
382
303
|
handleError = (err) => {
|
|
383
304
|
dbg("websocket error: %s", err.message);
|
|
384
|
-
// WebSocket errors are followed by a close event, so just emit
|
|
385
305
|
this.emit("error", err);
|
|
386
306
|
};
|
|
387
|
-
// --- Reconnection ---
|
|
388
307
|
scheduleReconnect() {
|
|
389
308
|
this.clearReconnectTimer();
|
|
390
309
|
const delay = this.calculateBackoff();
|
|
@@ -392,15 +311,12 @@ export class ConnectorClient extends EventEmitter {
|
|
|
392
311
|
this.reconnectTimer = setTimeout(() => {
|
|
393
312
|
this.reconnectTimer = null;
|
|
394
313
|
this.doConnect().catch(() => {
|
|
395
|
-
// connect rejection is expected during reconnect — handled by close event
|
|
396
314
|
});
|
|
397
315
|
}, delay);
|
|
398
316
|
}
|
|
399
317
|
calculateBackoff() {
|
|
400
|
-
// "Already connected" — short fixed retry with limit
|
|
401
318
|
if (this.alreadyConnectedRetries > 0) {
|
|
402
319
|
if (this.alreadyConnectedRetries >= ALREADY_CONNECTED_MAX_RETRIES) {
|
|
403
|
-
// Exceeded max retries, fall back to normal exponential backoff
|
|
404
320
|
this.alreadyConnectedRetries = 0;
|
|
405
321
|
return this.nextExponentialBackoff();
|
|
406
322
|
}
|
|
@@ -420,7 +336,6 @@ export class ConnectorClient extends EventEmitter {
|
|
|
420
336
|
this.reconnectTimer = null;
|
|
421
337
|
}
|
|
422
338
|
}
|
|
423
|
-
// --- Cleanup ---
|
|
424
339
|
cleanupConnection() {
|
|
425
340
|
if (this.ws) {
|
|
426
341
|
this.ws.off("message", this.handleMessage);
|
|
@@ -432,15 +347,12 @@ export class ConnectorClient extends EventEmitter {
|
|
|
432
347
|
clearTimeout(this.registerTimer);
|
|
433
348
|
this.registerTimer = null;
|
|
434
349
|
}
|
|
435
|
-
// Reject all pending address-based sends on disconnect
|
|
436
350
|
for (const [, pending] of this.pendingSends) {
|
|
437
351
|
clearTimeout(pending.timer);
|
|
438
352
|
pending.reject(new Error("Connection closed"));
|
|
439
353
|
}
|
|
440
354
|
this.pendingSends.clear();
|
|
441
355
|
}
|
|
442
|
-
// --- Wire helpers ---
|
|
443
|
-
/** Send an event over the WebSocket. */
|
|
444
356
|
sendEvent(event) {
|
|
445
357
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
446
358
|
this.ws.send(JSON.stringify(event));
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AACrE,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,QAAiB,CAAC;AAChD,eAAO,MAAM,uBAAuB,QAAiB,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
/** Unambiguous characters: A-H J-N P-Z 2-9 (excludes I/O/1/0) */
|
|
2
1
|
export const SETUP_CODE_CHARSET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
3
2
|
export const SETUP_CODE_LENGTH = 8;
|
|
4
|
-
export const SETUP_CODE_TTL_MS = 15 * 60 * 1000;
|
|
5
|
-
export const AUTHORIZED_TOKEN_TTL_MS = 60 * 60 * 1000;
|
|
3
|
+
export const SETUP_CODE_TTL_MS = 15 * 60 * 1000;
|
|
4
|
+
export const AUTHORIZED_TOKEN_TTL_MS = 60 * 60 * 1000;
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Conversation Manager — maps contacts to conversations.
|
|
3
|
-
*
|
|
4
|
-
* Owns the identity-based API that the Tool Interface and Inbound Dispatcher
|
|
5
|
-
* call. Sends messages directly to routable addresses via ConnectorClient.send().
|
|
6
|
-
*
|
|
7
|
-
* Contact resolution: handle → `mstps://${connectorHost}/${handle}`
|
|
8
|
-
* Address schemes: MSTP (`mstps://`), handle (bare), passport (`passport:@`)
|
|
9
|
-
* Internal key: routable address.
|
|
10
|
-
* One conversation per contact, in-memory only (D3).
|
|
11
|
-
*
|
|
12
|
-
* @see docs/connector/gateway-v2-consumer-adaptation-plan.md PR 2
|
|
13
|
-
*/
|
|
14
1
|
import { type ConnectorClient } from "./connector-client.js";
|
|
15
2
|
export interface SendResult {
|
|
16
3
|
status: "sent" | "failed";
|
|
17
4
|
error?: string;
|
|
18
|
-
/** Machine-readable error code from Connector (when status === "failed"). */
|
|
19
5
|
errorCode?: string;
|
|
20
6
|
}
|
|
21
7
|
export interface ConversationEntry {
|
|
@@ -23,19 +9,6 @@ export interface ConversationEntry {
|
|
|
23
9
|
address: string;
|
|
24
10
|
lastMessageAt: number;
|
|
25
11
|
initiatedBy: "local" | "remote";
|
|
26
|
-
/**
|
|
27
|
-
* Deferred deletion flag (#999).
|
|
28
|
-
*
|
|
29
|
-
* When `masons_end_conversation` runs during a dispatch cycle, the entry
|
|
30
|
-
* is marked `ended` but NOT removed from the Map. This keeps
|
|
31
|
-
* `hasConversation()` returning true so the deliver callback can still
|
|
32
|
-
* flush buffered text from the same LLM turn.
|
|
33
|
-
*
|
|
34
|
-
* Call `commitEndedConversations()` after the dispatch cycle completes
|
|
35
|
-
* to actually remove ended entries.
|
|
36
|
-
*
|
|
37
|
-
* @see https://github.com/MASONS-ai/masons.ai/issues/999
|
|
38
|
-
*/
|
|
39
12
|
ended?: boolean;
|
|
40
13
|
}
|
|
41
14
|
export interface ConversationSummary {
|
|
@@ -48,97 +21,18 @@ export interface ConversationSummary {
|
|
|
48
21
|
export declare class ConversationManager {
|
|
49
22
|
private readonly client;
|
|
50
23
|
private readonly connectorHost;
|
|
51
|
-
/** Conversations keyed by routable address */
|
|
52
24
|
private readonly conversations;
|
|
53
25
|
constructor(client: ConnectorClient, connectorHost: string);
|
|
54
|
-
/**
|
|
55
|
-
* Send a message to a contact. Sends directly to the resolved address —
|
|
56
|
-
* no session management needed.
|
|
57
|
-
*
|
|
58
|
-
* Returns a structured result with status and optional error.
|
|
59
|
-
* ConnectorError codes (ADDRESS_NOT_FOUND, ACCESS_DENIED, etc.) are
|
|
60
|
-
* mapped to human-readable messages for LLM tool results.
|
|
61
|
-
*
|
|
62
|
-
* @param contact - Handle, MSTP address, or passport address of the target.
|
|
63
|
-
* @param content - Message content to send.
|
|
64
|
-
*/
|
|
65
26
|
send(contact: string, content: string): Promise<SendResult>;
|
|
66
|
-
/**
|
|
67
|
-
* Register an inbound conversation (remote agent or visitor initiated).
|
|
68
|
-
* Called by the channel adapter when a message arrives from a new address.
|
|
69
|
-
*/
|
|
70
27
|
registerInbound(contact: string, address: string): void;
|
|
71
|
-
/**
|
|
72
|
-
* Resolve a routable address to a contact handle.
|
|
73
|
-
* Used by the inbound dispatcher to derive sender identity from MESSAGE_RECEIVED.from.
|
|
74
|
-
*/
|
|
75
28
|
getContactByAddress(address: string): string | undefined;
|
|
76
|
-
/**
|
|
77
|
-
* List all conversations with metadata.
|
|
78
|
-
* `active` is always true for address-based protocol — there is no session
|
|
79
|
-
* lifecycle. Conversations persist until explicitly ended or Plugin restarts.
|
|
80
|
-
*/
|
|
81
29
|
listConversations(): ConversationSummary[];
|
|
82
|
-
/**
|
|
83
|
-
* Check if a conversation entry exists for a contact.
|
|
84
|
-
*
|
|
85
|
-
* Returns true for entries that are marked `ended` but not yet committed —
|
|
86
|
-
* this allows the deliver callback to flush buffered text from the same
|
|
87
|
-
* dispatch cycle as end_conversation (#999).
|
|
88
|
-
*
|
|
89
|
-
* Straggler text from *subsequent* dispatch cycles is still suppressed
|
|
90
|
-
* because `commitEndedConversations()` removes entries between cycles.
|
|
91
|
-
*/
|
|
92
30
|
hasConversation(contact: string): boolean;
|
|
93
|
-
/**
|
|
94
|
-
* Mark the conversation with a contact as ended (deferred deletion).
|
|
95
|
-
*
|
|
96
|
-
* The entry is NOT removed immediately — it is flagged `ended` and stays
|
|
97
|
-
* in the Map until `commitEndedConversations()` is called after the
|
|
98
|
-
* current dispatch cycle completes. This prevents the "last-message-
|
|
99
|
-
* before-close" race where the dispatcher executes end_conversation
|
|
100
|
-
* before flushing buffered text (#999).
|
|
101
|
-
*
|
|
102
|
-
* No END_SESSION needed — the Connector manages connection lifecycle
|
|
103
|
-
* (idle timeout).
|
|
104
|
-
*/
|
|
105
31
|
endConversation(contact: string): void;
|
|
106
|
-
/**
|
|
107
|
-
* Remove all conversations marked as `ended`.
|
|
108
|
-
*
|
|
109
|
-
* Call this after the dispatch cycle completes (in the `finally` block
|
|
110
|
-
* of `handleAddressedMessage`). Deferred deletion ensures that text
|
|
111
|
-
* buffered in the same dispatch cycle as end_conversation is delivered
|
|
112
|
-
* before the entry disappears.
|
|
113
|
-
*
|
|
114
|
-
* Pattern: React 18 batched updates / Qt `deleteLater()` — mutations
|
|
115
|
-
* during a dispatch cycle are committed only when the cycle ends.
|
|
116
|
-
*
|
|
117
|
-
* @see https://github.com/MASONS-ai/masons.ai/issues/999
|
|
118
|
-
*/
|
|
119
32
|
commitEndedConversations(): void;
|
|
120
|
-
/**
|
|
121
|
-
* Resolve a contact (handle, MSTP address, or passport address) to a
|
|
122
|
-
* routable address.
|
|
123
|
-
*
|
|
124
|
-
* Resolution order:
|
|
125
|
-
* 1. MSTP address (starts with mstps:// or mstp://) → return as-is.
|
|
126
|
-
* 2. Passport address (starts with passport:) → return as-is (already routable).
|
|
127
|
-
* 3. Already a key in the conversations map → return as-is.
|
|
128
|
-
* 4. Reverse lookup: if any existing conversation has this handle as its
|
|
129
|
-
* contact, use that conversation's address. This ensures replies to a
|
|
130
|
-
* cross-Connector sender route to the sender's original address, not to
|
|
131
|
-
* a locally-constructed address.
|
|
132
|
-
* 5. Otherwise treat as handle → construct `mstps://${connectorHost}/${handle}`.
|
|
133
|
-
*/
|
|
134
33
|
resolveAddress(contact: string): string;
|
|
135
|
-
/**
|
|
136
|
-
* Extract a display-friendly handle from any address scheme.
|
|
137
|
-
* Delegates to shared utility — single source of truth.
|
|
138
|
-
*/
|
|
139
34
|
extractHandle(address: string): string;
|
|
140
35
|
private ensureConversationEntry;
|
|
141
|
-
/** @internal Reset for test isolation. */
|
|
142
36
|
_resetForTesting(): void;
|
|
143
37
|
}
|
|
144
38
|
//# sourceMappingURL=conversation-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-manager.d.ts","sourceRoot":"","sources":["../src/conversation-manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conversation-manager.d.ts","sourceRoot":"","sources":["../src/conversation-manager.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,uBAAuB,CAAC;AAS7E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,GAAG,QAAQ,CAAC;IAchC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,GAAG,QAAQ,CAAC;CACjC;AAwBD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAGvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;gBAE1D,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM;IAoBpD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAoCjE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IASvD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAkBxD,iBAAiB,IAAI,mBAAmB,EAAE;IAwB1C,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAiBzC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAwBtC,wBAAwB,IAAI,IAAI;IA+BhC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAwBvC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAQtC,OAAO,CAAC,uBAAuB;IA0B/B,gBAAgB,IAAI,IAAI;CAGzB"}
|