@masons/agent-network 0.3.7 → 0.3.8

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;AAiED,eAAO,MAAM,mBAAmB,EAAE,yBAqWjC,CAAC"}
package/dist/channel.js CHANGED
@@ -6,19 +6,26 @@ import { checkForUpdate } from "./update-check.js";
6
6
  const dbg = createDebug("agent-network:channel");
7
7
  // --- Sender identity ---
8
8
  /**
9
- * Use sessionId as the sender identifier for OpenClaw routing.
9
+ * Derive a persistent sender identifier from the MSTP address.
10
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.
11
+ * Uses `metadata.from` (the remote agent's MSTP address, e.g.
12
+ * `mstps://masons.ai/alice`) as the conversation key. This ensures
13
+ * all messages from the same agent land in the same OpenClaw conversation,
14
+ * regardless of how many MSTP sessions are created.
14
15
  *
15
- * Each MSTP session maps to a separate OpenClaw conversation correct
16
- * semantics since sessions are independent, ephemeral exchanges.
16
+ * Falls back to `sessionId` for direct MSTP clients that connect without
17
+ * a Connector (no `metadata.from`). These get ephemeral conversations.
17
18
  *
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.
19
+ * The `activeSession` reverse index in AccountState maps the MSTP address
20
+ * back to the current sessionId for outbound routing (sendText, deliver).
21
+ *
22
+ * See: docs/openclaw/research/session-identity-mapping.md §5
20
23
  */
21
24
  function deriveSenderId(event) {
25
+ const from = event.metadata?.from;
26
+ if (typeof from === "string" && from.length > 0) {
27
+ return from;
28
+ }
22
29
  return event.sessionId;
23
30
  }
24
31
  /**
@@ -97,15 +104,24 @@ export const agentNetworkChannel = {
97
104
  outbound: {
98
105
  deliveryMode: "direct",
99
106
  async sendText(ctx) {
100
- // ctx.recipient = sessionId Gateway echoes back SenderId from finalizeInboundContext
107
+ // ctx.recipient is now an MSTP address (senderId = address from deriveSenderId).
108
+ // Resolve to the active sessionId via the reverse index.
101
109
  const state = accounts.get(ctx.accountId);
102
- if (!state?.sessions.has(ctx.recipient)) {
110
+ if (!state)
111
+ return { ok: false };
112
+ let sessionId = state.activeSession.get(ctx.recipient);
113
+ // Fallback: ctx.recipient might be a raw sessionId (direct MSTP client
114
+ // without metadata.from — deriveSenderId fell back to sessionId).
115
+ if (!sessionId && state.sessions.has(ctx.recipient)) {
116
+ sessionId = ctx.recipient;
117
+ }
118
+ if (!sessionId || !state.sessions.has(sessionId)) {
103
119
  return { ok: false };
104
120
  }
105
- const sent = state.client.sendMessage(ctx.recipient, ctx.text, {
121
+ const sent = state.client.sendMessage(sessionId, ctx.text, {
106
122
  contentType: "text",
107
123
  });
108
- dbg("sendText sessionId=%s contentLength=%d sent=%s", ctx.recipient, ctx.text.length, sent);
124
+ dbg("sendText recipient=%s sessionId=%s contentLength=%d sent=%s", ctx.recipient, sessionId, ctx.text.length, sent);
109
125
  return { ok: sent };
110
126
  },
111
127
  },
@@ -117,6 +133,7 @@ export const agentNetworkChannel = {
117
133
  const state = {
118
134
  client,
119
135
  sessions: new Map(),
136
+ activeSession: new Map(),
120
137
  };
121
138
  accounts.set(ctx.accountId, state);
122
139
  // --- Inbound message routing (4-step channelRuntime dispatch) ---
@@ -146,8 +163,21 @@ export const agentNetworkChannel = {
146
163
  dbg("channelRuntime not available, dropping message sessionId=%s", event.sessionId);
147
164
  return;
148
165
  }
149
- const senderId = deriveSenderId(event);
150
- const senderName = deriveSenderName(event);
166
+ // Resolve sender identity from session state, NOT from per-message metadata.
167
+ // metadata.from is reliably present on SESSION_CREATED (Connector sets it
168
+ // server-side) but NOT on MESSAGE_RECEIVED (per-message metadata is
169
+ // pass-through from the remote plugin, which doesn't include `from`).
170
+ // The session_created handler already stored the remoteAddress.
171
+ const sessionMeta = state.sessions.get(event.sessionId);
172
+ const senderId = sessionMeta?.remoteAddress ?? event.sessionId;
173
+ // Derive sender name from the resolved address, not per-message metadata.
174
+ // Build a synthetic event with the session's address for deriveSenderName.
175
+ const senderName = sessionMeta?.remoteAddress
176
+ ? deriveSenderName({
177
+ ...event,
178
+ metadata: { ...event.metadata, from: sessionMeta.remoteAddress },
179
+ })
180
+ : deriveSenderName(event);
151
181
  try {
152
182
  // Step 1 — Resolve agent route (await defensively — may be sync or async)
153
183
  const route = await runtime.channel.routing.resolveAgentRoute({
@@ -195,16 +225,19 @@ export const agentNetworkChannel = {
195
225
  const text = payload.text;
196
226
  if (!text)
197
227
  return;
228
+ // senderId is now an MSTP address. Resolve to sessionId.
229
+ let deliverSessionId = state.activeSession.get(senderId);
230
+ // Fallback: senderId might be a raw sessionId (direct client).
231
+ if (!deliverSessionId && state.sessions.has(senderId)) {
232
+ deliverSessionId = senderId;
233
+ }
198
234
  // 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))
235
+ if (!deliverSessionId || !state.sessions.has(deliverSessionId))
201
236
  return;
202
- // Send LLM reply back through the MSTP session.
203
- // senderId === sessionId (deriveSenderId invariant).
204
- const sent = state.client.sendMessage(senderId, text, {
237
+ const sent = state.client.sendMessage(deliverSessionId, text, {
205
238
  contentType: "text",
206
239
  });
207
- dbg("deliver reply sessionId=%s contentLength=%d sent=%s", senderId, text.length, sent);
240
+ dbg("deliver reply address=%s sessionId=%s contentLength=%d sent=%s", senderId, deliverSessionId, text.length, sent);
208
241
  },
209
242
  onError: (err) => {
210
243
  console.error(`[agent-network:${ctx.accountId}] dispatch error:`, err);
@@ -220,13 +253,27 @@ export const agentNetworkChannel = {
220
253
  client.on("session_created", (event) => {
221
254
  dbg("session created sessionId=%s direction=%s", event.sessionId, event.direction);
222
255
  const from = event.metadata?.from;
223
- state.sessions.set(event.sessionId, {
224
- remoteAddress: typeof from === "string" && from.length > 0 ? from : null,
225
- });
256
+ const remoteAddress = typeof from === "string" && from.length > 0 ? from : null;
257
+ state.sessions.set(event.sessionId, { remoteAddress });
258
+ // Update reverse index: this address is now reachable via this session.
259
+ // Last-write-wins: if a new session arrives from the same address,
260
+ // replies go to the newest session (same as XMPP resource binding).
261
+ if (remoteAddress) {
262
+ state.activeSession.set(remoteAddress, event.sessionId);
263
+ }
226
264
  });
227
265
  client.on("session_ended", (event) => {
228
266
  dbg("session ended sessionId=%s", event.sessionId);
267
+ const sessionMeta = state.sessions.get(event.sessionId);
229
268
  state.sessions.delete(event.sessionId);
269
+ // Only clear reverse index if this session was the active one.
270
+ // If a newer session replaced it, the index already points elsewhere.
271
+ if (sessionMeta?.remoteAddress) {
272
+ const currentActive = state.activeSession.get(sessionMeta.remoteAddress);
273
+ if (currentActive === event.sessionId) {
274
+ state.activeSession.delete(sessionMeta.remoteAddress);
275
+ }
276
+ }
230
277
  });
231
278
  // --- Error handling ---
232
279
  // Must register before connect() — unhandled "error" events crash the process.
@@ -237,6 +284,7 @@ export const agentNetworkChannel = {
237
284
  client.on("disconnected", () => {
238
285
  dbg("disconnected, cleared %d sessions", state.sessions.size);
239
286
  state.sessions.clear();
287
+ state.activeSession.clear();
240
288
  });
241
289
  // --- Abort signal ---
242
290
  ctx.abortSignal.addEventListener("abort", () => {
@@ -275,6 +323,7 @@ export const agentNetworkChannel = {
275
323
  state.client.removeAllListeners();
276
324
  state.client.disconnect();
277
325
  state.sessions.clear();
326
+ state.activeSession.clear();
278
327
  accounts.delete(ctx.accountId);
279
328
  }
280
329
  },
@@ -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":"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"}
@@ -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;AAuJD;;;;;;;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
@@ -131,19 +131,33 @@ function formatSessionCreated(sessionId, target) {
131
131
  function waitForSessionCreated(client, requestId) {
132
132
  return new Promise((resolve) => {
133
133
  const timer = setTimeout(() => {
134
- client.off("session_created", onSessionCreated);
134
+ cleanup();
135
135
  resolve({
136
136
  error: "Session creation timed out. The remote agent may be unavailable.",
137
137
  });
138
138
  }, sessionTimeoutMs);
139
+ function cleanup() {
140
+ clearTimeout(timer);
141
+ client.off("session_created", onSessionCreated);
142
+ client.off("error", onError);
143
+ }
139
144
  function onSessionCreated(event) {
140
145
  if (event.requestId === requestId && event.direction === "outbound") {
141
- clearTimeout(timer);
142
- client.off("session_created", onSessionCreated);
146
+ cleanup();
143
147
  resolve({ sessionId: event.sessionId });
144
148
  }
145
149
  }
150
+ // Listen for ERROR events from the Connector (e.g., access control rejection).
151
+ // The Connector sends { event: "ERROR", requestId, message } as a global error
152
+ // when CREATE_SESSION is rejected.
153
+ function onError(err) {
154
+ // ConnectorClient emits Error objects with the server message as err.message.
155
+ // Match by checking if the error message is actionable (not a generic WS error).
156
+ cleanup();
157
+ resolve({ error: err.message });
158
+ }
146
159
  client.on("session_created", onSessionCreated);
160
+ client.on("error", onError);
147
161
  });
148
162
  }
149
163
  // ---------------------------------------------------------------------------
@@ -603,6 +617,28 @@ export function registerTools(api) {
603
617
  execute: withUpdateNotice(async (_id, params) => {
604
618
  const client = requireConnectorClient();
605
619
  const target = params.target;
620
+ // --- Pre-flight: check connection status (advisory, not gate) ---
621
+ // If the check fails (network error, API down), proceed anyway —
622
+ // the Connector gate (Layer 2) is the authoritative enforcement.
623
+ try {
624
+ const handle = target
625
+ .replace(/^mstps?:\/\/[^/]+\//, "")
626
+ .replace(/\/+$/, "");
627
+ if (handle) {
628
+ const cfg = requirePlatformConfig();
629
+ const apiKey = requireApiKey();
630
+ const status = await getConnectionStatus(cfg, apiKey, handle);
631
+ if (status && !status.canCreateSession) {
632
+ if (status.status === "pending") {
633
+ return textResult(`Connection request to @${handle} is pending. Wait for the other agent to accept your request.`);
634
+ }
635
+ return textResult(`You are not connected to @${handle}. Send a connection request first using masons_send_connection_request.`);
636
+ }
637
+ }
638
+ }
639
+ catch {
640
+ // Advisory check failed — proceed to Connector gate
641
+ }
606
642
  const { requestId, sent } = client.createSession(target);
607
643
  if (!sent) {
608
644
  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.8";
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.8";
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.8",
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)",