@masons/agent-network 0.3.7 → 0.3.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAa9D,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,oBAAoB,CAAC,CAAC;IAC9B,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAAC;IACvD,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IACpE,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IACjE,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;CAC/D;AAED,UAAU,sBAAsB;IAC9B,EAAE,EAAE,OAAO,CAAC;CACb;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,YAAY,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9C,QAAQ,CAAC,CAAC,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACzE;AAED,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAsDD,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,YAAY,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,WAAW,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,UAAU,yBAAyB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,mBAAmB,CAAC;IAClC,MAAM,EAAE,oBAAoB,CAAC,mBAAmB,CAAC,CAAC;IAClD,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;CACrD;AAwDD,eAAO,MAAM,mBAAmB,EAAE,yBAiTjC,CAAC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAa9D,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,oBAAoB,CAAC,CAAC;IAC9B,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAAC;IACvD,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IACpE,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IACjE,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;CAC/D;AAED,UAAU,sBAAsB;IAC9B,EAAE,EAAE,OAAO,CAAC;CACb;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,YAAY,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9C,QAAQ,CAAC,CAAC,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACzE;AAED,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAsDD,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,YAAY,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,WAAW,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,UAAU,yBAAyB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,mBAAmB,CAAC;IAClC,MAAM,EAAE,oBAAoB,CAAC,mBAAmB,CAAC,CAAC;IAClD,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;CACrD;AA0CD,eAAO,MAAM,mBAAmB,EAAE,yBAqWjC,CAAC"}
package/dist/channel.js CHANGED
@@ -5,22 +5,9 @@ import { ConnectorClient } from "./connector-client.js";
5
5
  import { checkForUpdate } from "./update-check.js";
6
6
  const dbg = createDebug("agent-network:channel");
7
7
  // --- Sender identity ---
8
- /**
9
- * Use sessionId as the sender identifier for OpenClaw routing.
10
- *
11
- * OpenClaw Gateway sets `ctx.recipient = senderId` when the LLM replies.
12
- * Our `sendText()` uses `ctx.recipient` as a sessionId to look up the
13
- * MSTP session. So senderId MUST equal sessionId for reply routing to work.
14
- *
15
- * Each MSTP session maps to a separate OpenClaw conversation — correct
16
- * semantics since sessions are independent, ephemeral exchanges.
17
- *
18
- * The remote Agent's MSTP address (from `metadata.from`) is preserved in
19
- * `senderName` and the envelope's `metadata` field — identity is not lost.
20
- */
21
- function deriveSenderId(event) {
22
- return event.sessionId;
23
- }
8
+ // Identity resolution uses session state (remoteAddress from SESSION_CREATED),
9
+ // not per-message metadata. See the message_received handler for details.
10
+ // See: docs/openclaw/research/session-identity-mapping.md §5
24
11
  /**
25
12
  * Extract a human-readable name from the remote Agent's MSTP address.
26
13
  *
@@ -97,15 +84,24 @@ export const agentNetworkChannel = {
97
84
  outbound: {
98
85
  deliveryMode: "direct",
99
86
  async sendText(ctx) {
100
- // ctx.recipient = sessionId Gateway echoes back SenderId from finalizeInboundContext
87
+ // ctx.recipient is now an MSTP address (senderId = address from deriveSenderId).
88
+ // Resolve to the active sessionId via the reverse index.
101
89
  const state = accounts.get(ctx.accountId);
102
- if (!state?.sessions.has(ctx.recipient)) {
90
+ if (!state)
103
91
  return { ok: false };
92
+ let sessionId = state.activeSession.get(ctx.recipient);
93
+ // Fallback: ctx.recipient might be a raw sessionId (direct MSTP client
94
+ // without metadata.from — deriveSenderId fell back to sessionId).
95
+ if (!sessionId && state.sessions.has(ctx.recipient)) {
96
+ sessionId = ctx.recipient;
104
97
  }
105
- const sent = state.client.sendMessage(ctx.recipient, ctx.text, {
98
+ if (!sessionId || !state.sessions.has(sessionId)) {
99
+ return { ok: false };
100
+ }
101
+ const sent = state.client.sendMessage(sessionId, ctx.text, {
106
102
  contentType: "text",
107
103
  });
108
- dbg("sendText sessionId=%s contentLength=%d sent=%s", ctx.recipient, ctx.text.length, sent);
104
+ dbg("sendText recipient=%s sessionId=%s contentLength=%d sent=%s", ctx.recipient, sessionId, ctx.text.length, sent);
109
105
  return { ok: sent };
110
106
  },
111
107
  },
@@ -117,6 +113,7 @@ export const agentNetworkChannel = {
117
113
  const state = {
118
114
  client,
119
115
  sessions: new Map(),
116
+ activeSession: new Map(),
120
117
  };
121
118
  accounts.set(ctx.accountId, state);
122
119
  // --- Inbound message routing (4-step channelRuntime dispatch) ---
@@ -146,8 +143,21 @@ export const agentNetworkChannel = {
146
143
  dbg("channelRuntime not available, dropping message sessionId=%s", event.sessionId);
147
144
  return;
148
145
  }
149
- const senderId = deriveSenderId(event);
150
- const senderName = deriveSenderName(event);
146
+ // Resolve sender identity from session state, NOT from per-message metadata.
147
+ // metadata.from is reliably present on SESSION_CREATED (Connector sets it
148
+ // server-side) but NOT on MESSAGE_RECEIVED (per-message metadata is
149
+ // pass-through from the remote plugin, which doesn't include `from`).
150
+ // The session_created handler already stored the remoteAddress.
151
+ const sessionMeta = state.sessions.get(event.sessionId);
152
+ const senderId = sessionMeta?.remoteAddress ?? event.sessionId;
153
+ // Derive sender name from the resolved address, not per-message metadata.
154
+ // Build a synthetic event with the session's address for deriveSenderName.
155
+ const senderName = sessionMeta?.remoteAddress
156
+ ? deriveSenderName({
157
+ ...event,
158
+ metadata: { ...event.metadata, from: sessionMeta.remoteAddress },
159
+ })
160
+ : deriveSenderName(event);
151
161
  try {
152
162
  // Step 1 — Resolve agent route (await defensively — may be sync or async)
153
163
  const route = await runtime.channel.routing.resolveAgentRoute({
@@ -195,16 +205,19 @@ export const agentNetworkChannel = {
195
205
  const text = payload.text;
196
206
  if (!text)
197
207
  return;
208
+ // senderId is now an MSTP address. Resolve to sessionId.
209
+ let deliverSessionId = state.activeSession.get(senderId);
210
+ // Fallback: senderId might be a raw sessionId (direct client).
211
+ if (!deliverSessionId && state.sessions.has(senderId)) {
212
+ deliverSessionId = senderId;
213
+ }
198
214
  // Session may have ended while LLM was processing.
199
- // Skip the send to avoid a needless Connector round-trip.
200
- if (!state.sessions.has(senderId))
215
+ if (!deliverSessionId || !state.sessions.has(deliverSessionId))
201
216
  return;
202
- // Send LLM reply back through the MSTP session.
203
- // senderId === sessionId (deriveSenderId invariant).
204
- const sent = state.client.sendMessage(senderId, text, {
217
+ const sent = state.client.sendMessage(deliverSessionId, text, {
205
218
  contentType: "text",
206
219
  });
207
- dbg("deliver reply sessionId=%s contentLength=%d sent=%s", senderId, text.length, sent);
220
+ dbg("deliver reply address=%s sessionId=%s contentLength=%d sent=%s", senderId, deliverSessionId, text.length, sent);
208
221
  },
209
222
  onError: (err) => {
210
223
  console.error(`[agent-network:${ctx.accountId}] dispatch error:`, err);
@@ -220,13 +233,27 @@ export const agentNetworkChannel = {
220
233
  client.on("session_created", (event) => {
221
234
  dbg("session created sessionId=%s direction=%s", event.sessionId, event.direction);
222
235
  const from = event.metadata?.from;
223
- state.sessions.set(event.sessionId, {
224
- remoteAddress: typeof from === "string" && from.length > 0 ? from : null,
225
- });
236
+ const remoteAddress = typeof from === "string" && from.length > 0 ? from : null;
237
+ state.sessions.set(event.sessionId, { remoteAddress });
238
+ // Update reverse index: this address is now reachable via this session.
239
+ // Last-write-wins: if a new session arrives from the same address,
240
+ // replies go to the newest session (same as XMPP resource binding).
241
+ if (remoteAddress) {
242
+ state.activeSession.set(remoteAddress, event.sessionId);
243
+ }
226
244
  });
227
245
  client.on("session_ended", (event) => {
228
246
  dbg("session ended sessionId=%s", event.sessionId);
247
+ const sessionMeta = state.sessions.get(event.sessionId);
229
248
  state.sessions.delete(event.sessionId);
249
+ // Only clear reverse index if this session was the active one.
250
+ // If a newer session replaced it, the index already points elsewhere.
251
+ if (sessionMeta?.remoteAddress) {
252
+ const currentActive = state.activeSession.get(sessionMeta.remoteAddress);
253
+ if (currentActive === event.sessionId) {
254
+ state.activeSession.delete(sessionMeta.remoteAddress);
255
+ }
256
+ }
230
257
  });
231
258
  // --- Error handling ---
232
259
  // Must register before connect() — unhandled "error" events crash the process.
@@ -237,6 +264,7 @@ export const agentNetworkChannel = {
237
264
  client.on("disconnected", () => {
238
265
  dbg("disconnected, cleared %d sessions", state.sessions.size);
239
266
  state.sessions.clear();
267
+ state.activeSession.clear();
240
268
  });
241
269
  // --- Abort signal ---
242
270
  ctx.abortSignal.addEventListener("abort", () => {
@@ -275,6 +303,7 @@ export const agentNetworkChannel = {
275
303
  state.client.removeAllListeners();
276
304
  state.client.disconnect();
277
305
  state.sessions.clear();
306
+ state.activeSession.clear();
278
307
  accounts.delete(ctx.accountId);
279
308
  }
280
309
  },
@@ -120,6 +120,10 @@ export interface ListConnectionsResponse {
120
120
  address: string;
121
121
  }>;
122
122
  }
123
+ export interface ConnectionStatusResponse {
124
+ status: "connected" | "pending" | "not_connected";
125
+ canCreateSession: boolean;
126
+ }
123
127
  /**
124
128
  * `POST /setup/init` — Start Device Code Flow.
125
129
  *
@@ -207,4 +211,13 @@ export declare function updateProfile(cfg: PlatformClientConfig, apiKey: string,
207
211
  * Returns name + MSTP address for each connected agent.
208
212
  */
209
213
  export declare function listConnections(cfg: PlatformClientConfig, apiKey: string): Promise<ListConnectionsResponse>;
214
+ /**
215
+ * `GET /connections/status?target={handle}` — Check connection status.
216
+ *
217
+ * Requires API Key in Authorization header.
218
+ * Returns connection status and whether session creation is possible.
219
+ *
220
+ * Returns null if the request fails (advisory — caller should degrade gracefully).
221
+ */
222
+ export declare function getConnectionStatus(cfg: PlatformClientConfig, apiKey: string, targetHandle: string): Promise<ConnectionStatusResponse | null>;
210
223
  //# sourceMappingURL=platform-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../src/platform-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../src/platform-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,wBAAwB;AACxB,eAAO,MAAM,gBAAgB,+BAA+B,CAAC;AAE7D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,qBAAa,gBAAiB,SAAQ,KAAK;aAEvB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAED,0EAA0E;AAC1E,qBAAa,iBAAkB,SAAQ,gBAAgB;gBACzC,OAAO,SAA0B;CAI9C;AAED,oEAAoE;AACpE,qBAAa,iBAAkB,SAAQ,gBAAgB;gBACzC,OAAO,SAAwB;CAI5C;AAMD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qCAAqC;AACrC,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;IACnC,sEAAsE;IACtE,SAAS,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,yEAAyE;IACzE,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,eAAe,CAAC;IAClD,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AA0BD;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAO5B;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC,CAQ5B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,kBAAkB,CAAC,CAM7B;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,eAAe,CAAC,CAW1B;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,YAAY,GAAG,SAAS,CAAC,EAAE,CAAA;CAAE,GACvE,OAAO,CAAC,yBAAyB,CAAC,CAWpC;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,oBAAoB,CAAC,CAc/B;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC,CAUhC;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,CAAC,CAUjC;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,uBAAuB,CAAC,CAMlC;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,oBAAoB,EACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAiB1C"}
@@ -247,3 +247,28 @@ export async function listConnections(cfg, apiKey) {
247
247
  return handleError(res);
248
248
  return (await res.json());
249
249
  }
250
+ /**
251
+ * `GET /connections/status?target={handle}` — Check connection status.
252
+ *
253
+ * Requires API Key in Authorization header.
254
+ * Returns connection status and whether session creation is possible.
255
+ *
256
+ * Returns null if the request fails (advisory — caller should degrade gracefully).
257
+ */
258
+ export async function getConnectionStatus(cfg, apiKey, targetHandle) {
259
+ try {
260
+ const controller = new AbortController();
261
+ const timeout = setTimeout(() => controller.abort(), 3000);
262
+ const res = await fetch(`${baseUrl(cfg)}/connections/status?target=${encodeURIComponent(targetHandle)}`, {
263
+ headers: { Authorization: `Bearer ${apiKey}` },
264
+ signal: controller.signal,
265
+ });
266
+ clearTimeout(timeout);
267
+ if (!res.ok)
268
+ return null; // Advisory — degrade gracefully
269
+ return (await res.json());
270
+ }
271
+ catch {
272
+ return null; // Network error or timeout — degrade gracefully
273
+ }
274
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoCH,UAAU,WAAW;IACnB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,CACP,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,WAAW,CAAC,CAAC;CAC3B;AAED,UAAU,OAAO;IACf,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACzE;AAmBD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAED,6DAA6D;AAC7D,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7D;AAuID;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA6pBhD"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAqCH,UAAU,WAAW;IACnB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,CACP,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,WAAW,CAAC,CAAC;CAC3B;AAED,UAAU,OAAO;IACf,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACzE;AAmBD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAED,6DAA6D;AAC7D,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7D;AAwJD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAurBhD"}
package/dist/tools.js CHANGED
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { clearTargetHandle, getPendingTarget, markProfileComplete, markProfileNeeded, requireApiKey, requireConnectorClient, requirePlatformConfig, writeCredentials, } from "./config.js";
18
- import { acceptRequest, declineRequest, initSetup, listConnections, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
18
+ import { acceptRequest, declineRequest, getConnectionStatus, initSetup, listConnections, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
19
19
  import { getUpdateInfo } from "./update-check.js";
20
20
  // ---------------------------------------------------------------------------
21
21
  // Constants
@@ -63,8 +63,9 @@ function maybeAppendUpdateNotice(result) {
63
63
  if (last?.type === "text") {
64
64
  last.text +=
65
65
  `\n\n[Update available: v${info.latestVersion} (current: v${info.currentVersion}).` +
66
- ` To update, use the exec tool to run: openclaw plugins update agent-network` +
67
- ` — then restart using the gateway tool.]`;
66
+ ` To update, run exactly: openclaw plugins update agent-network` +
67
+ ` — then restart using the gateway tool.` +
68
+ ` IMPORTANT: "plugins" is plural. Do NOT use "plugin" (singular), "install", or "npm install".]`;
68
69
  }
69
70
  return result;
70
71
  }
@@ -131,19 +132,33 @@ function formatSessionCreated(sessionId, target) {
131
132
  function waitForSessionCreated(client, requestId) {
132
133
  return new Promise((resolve) => {
133
134
  const timer = setTimeout(() => {
134
- client.off("session_created", onSessionCreated);
135
+ cleanup();
135
136
  resolve({
136
137
  error: "Session creation timed out. The remote agent may be unavailable.",
137
138
  });
138
139
  }, sessionTimeoutMs);
140
+ function cleanup() {
141
+ clearTimeout(timer);
142
+ client.off("session_created", onSessionCreated);
143
+ client.off("error", onError);
144
+ }
139
145
  function onSessionCreated(event) {
140
146
  if (event.requestId === requestId && event.direction === "outbound") {
141
- clearTimeout(timer);
142
- client.off("session_created", onSessionCreated);
147
+ cleanup();
143
148
  resolve({ sessionId: event.sessionId });
144
149
  }
145
150
  }
151
+ // Listen for ERROR events from the Connector (e.g., access control rejection).
152
+ // The Connector sends { event: "ERROR", requestId, message } as a global error
153
+ // when CREATE_SESSION is rejected.
154
+ function onError(err) {
155
+ // ConnectorClient emits Error objects with the server message as err.message.
156
+ // Match by checking if the error message is actionable (not a generic WS error).
157
+ cleanup();
158
+ resolve({ error: err.message });
159
+ }
146
160
  client.on("session_created", onSessionCreated);
161
+ client.on("error", onError);
147
162
  });
148
163
  }
149
164
  // ---------------------------------------------------------------------------
@@ -603,6 +618,28 @@ export function registerTools(api) {
603
618
  execute: withUpdateNotice(async (_id, params) => {
604
619
  const client = requireConnectorClient();
605
620
  const target = params.target;
621
+ // --- Pre-flight: check connection status (advisory, not gate) ---
622
+ // If the check fails (network error, API down), proceed anyway —
623
+ // the Connector gate (Layer 2) is the authoritative enforcement.
624
+ try {
625
+ const handle = target
626
+ .replace(/^mstps?:\/\/[^/]+\//, "")
627
+ .replace(/\/+$/, "");
628
+ if (handle) {
629
+ const cfg = requirePlatformConfig();
630
+ const apiKey = requireApiKey();
631
+ const status = await getConnectionStatus(cfg, apiKey, handle);
632
+ if (status && !status.canCreateSession) {
633
+ if (status.status === "pending") {
634
+ return textResult(`Connection request to @${handle} is pending. Wait for the other agent to accept your request.`);
635
+ }
636
+ return textResult(`You are not connected to @${handle}. Send a connection request first using masons_send_connection_request.`);
637
+ }
638
+ }
639
+ }
640
+ catch {
641
+ // Advisory check failed — proceed to Connector gate
642
+ }
606
643
  const { requestId, sent } = client.createSession(target);
607
644
  if (!sent) {
608
645
  return textResult("Failed to create session. The network connection may be temporarily unavailable. Try again in a moment.");
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
- export declare const PLUGIN_VERSION = "0.3.7";
2
+ export declare const PLUGIN_VERSION = "0.3.9";
3
3
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
- export const PLUGIN_VERSION = "0.3.7";
2
+ export const PLUGIN_VERSION = "0.3.9";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "MASONS plugin for OpenClaw — connect your agent to the agent network",
5
5
  "license": "MIT",
6
6
  "author": "MASONS.ai <hello@masons.ai> (https://masons.ai)",
@@ -285,10 +285,15 @@ When a tool output mentions an update is available:
285
285
 
286
286
  **If they agree:**
287
287
 
288
- 1. Run `openclaw plugins update agent-network` (use the `exec` tool, or tell the user to run it in Terminal)
288
+ 1. Run exactly: `openclaw plugins update agent-network` (use the `exec` tool, or tell the user to run it in Terminal)
289
289
  2. Restart the gateway (use the `gateway` tool with `action: "restart"`, or tell the user to run `openclaw gateway restart`)
290
290
 
291
- **Important:** Use `plugins update`, NOT `plugins install`. `plugins install` may not replace the running code. `plugins update` does a full replacement.
291
+ **Common mistakes do NOT use any of these:**
292
+ - `openclaw plugin update` — wrong: `plugin` must be **`plugins`** (plural)
293
+ - `openclaw plugins install` — wrong: `install` may reject with "already exists"
294
+ - `npm install -g @masons/agent-network` — wrong: npm global install does not register with OpenClaw
295
+
296
+ **If the command fails:** Re-read this section and verify the exact spelling. Do NOT guess alternative commands.
292
297
 
293
298
  Your configuration, credentials, agent identity, and connections are all preserved — no setup needed after upgrade.
294
299