@masons/agent-network 0.3.8 → 0.4.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/tools.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * LLM tools — setup, connection, profile, and conversation tools.
3
3
  *
4
- * Registers 12 tools with OpenClaw's Plugin API so the LLM can
4
+ * Registers tools with OpenClaw's Plugin API so the LLM can
5
5
  * drive setup, profile completion, connection listing, connection
6
6
  * requests, request management, and real-time conversations,
7
7
  * guided by SKILL.md.
@@ -9,12 +9,17 @@
9
9
  * Two access patterns:
10
10
  * - **HTTP tools** (setup, connection): read config via `requirePlatformConfig()`,
11
11
  * call Platform API via `platform-client.ts`.
12
- * - **WebSocket tools** (conversation): read runtime client via
13
- * `requireConnectorClient()`, send/receive over the live connection.
12
+ * - **WebSocket tools** (conversation): use `requireConversationManager()` for
13
+ * identity-based messaging. Session management is fully transparent.
14
14
  *
15
+ * Session Abstraction (#741):
16
+ * - `masons_send_message(to, content)` — sends via ConversationManager
17
+ * - `masons_end_conversation(contact)` — ends via ConversationManager
18
+ * - `masons_create_session` — DEPRECATED SHIM (one release cycle)
19
+ * - `masons_end_session` — DEPRECATED SHIM (one release cycle)
15
20
  */
16
21
  import { Type } from "@sinclair/typebox";
17
- import { clearTargetHandle, getPendingTarget, markProfileComplete, markProfileNeeded, requireApiKey, requireConnectorClient, requirePlatformConfig, writeCredentials, } from "./config.js";
22
+ import { clearTargetHandle, getPendingTarget, markProfileComplete, markProfileNeeded, requireApiKey, requireConversationManager, requirePlatformConfig, writeCredentials, } from "./config.js";
18
23
  import { acceptRequest, declineRequest, getConnectionStatus, initSetup, listConnections, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
19
24
  import { getUpdateInfo } from "./update-check.js";
20
25
  // ---------------------------------------------------------------------------
@@ -26,19 +31,11 @@ const PROFILE_FIELDS = new Set(["name", "scope", "about", "audience"]);
26
31
  // Module-level state (not persisted across process restarts)
27
32
  // ---------------------------------------------------------------------------
28
33
  let storedSetupToken = null;
29
- // Configurable timeout for waitForSessionCreated — allows tests to override.
30
- const DEFAULT_SESSION_TIMEOUT_MS = 15_000;
31
- let sessionTimeoutMs = DEFAULT_SESSION_TIMEOUT_MS;
32
34
  /** @internal Reset module state for test isolation. */
33
35
  export function _resetToolsForTesting() {
34
36
  storedSetupToken = null;
35
- sessionTimeoutMs = DEFAULT_SESSION_TIMEOUT_MS;
36
37
  updateNoticeShown = false;
37
38
  }
38
- /** @internal Override session creation timeout for tests. */
39
- export function _setSessionTimeoutForTesting(ms) {
40
- sessionTimeoutMs = ms;
41
- }
42
39
  // ---------------------------------------------------------------------------
43
40
  // Format helpers
44
41
  // ---------------------------------------------------------------------------
@@ -63,8 +60,9 @@ function maybeAppendUpdateNotice(result) {
63
60
  if (last?.type === "text") {
64
61
  last.text +=
65
62
  `\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.]`;
63
+ ` To update, run exactly: openclaw plugins update agent-network` +
64
+ ` — then restart using the gateway tool.` +
65
+ ` IMPORTANT: "plugins" is plural. Do NOT use "plugin" (singular), "install", or "npm install".]`;
68
66
  }
69
67
  return result;
70
68
  }
@@ -107,59 +105,6 @@ function formatConnectionResult(requestIds, status) {
107
105
  }
108
106
  return `Connection request sent. Status: ${status}. The other agent's owner will be notified.`;
109
107
  }
110
- function formatSessionCreated(sessionId, target) {
111
- return [
112
- `Session started with ${target}`,
113
- `Session ID: ${sessionId}`,
114
- "Use masons_send_message with this session ID to send messages.",
115
- ].join("\n");
116
- }
117
- // ---------------------------------------------------------------------------
118
- // Session creation helper — waits for Connector to confirm session
119
- // ---------------------------------------------------------------------------
120
- /**
121
- * Wait for a SESSION_CREATED event matching the given requestId.
122
- *
123
- * CREATE_SESSION is async — the Connector routes the request to the remote
124
- * agent's Connector, which establishes the session. This helper bridges
125
- * that async gap so the tool can return a sessionId to the LLM.
126
- *
127
- * Timeout fallback: if no matching event arrives within `sessionTimeoutMs`,
128
- * returns an error. This covers cases where the remote agent is unreachable
129
- * or the Connector drops the request.
130
- */
131
- function waitForSessionCreated(client, requestId) {
132
- return new Promise((resolve) => {
133
- const timer = setTimeout(() => {
134
- cleanup();
135
- resolve({
136
- error: "Session creation timed out. The remote agent may be unavailable.",
137
- });
138
- }, sessionTimeoutMs);
139
- function cleanup() {
140
- clearTimeout(timer);
141
- client.off("session_created", onSessionCreated);
142
- client.off("error", onError);
143
- }
144
- function onSessionCreated(event) {
145
- if (event.requestId === requestId && event.direction === "outbound") {
146
- cleanup();
147
- resolve({ sessionId: event.sessionId });
148
- }
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
- }
159
- client.on("session_created", onSessionCreated);
160
- client.on("error", onError);
161
- });
162
- }
163
108
  // ---------------------------------------------------------------------------
164
109
  // Tool registration
165
110
  // ---------------------------------------------------------------------------
@@ -539,7 +484,7 @@ export function registerTools(api) {
539
484
  try {
540
485
  const result = await acceptRequest(cfg, apiKey, requestId);
541
486
  const who = result.connection.name || result.connection.handle;
542
- return textResult(`Connected with ${who} (@${result.connection.handle})! You can now start a conversation using masons_create_session.`);
487
+ return textResult(`Connected with ${who} (@${result.connection.handle})! You can now send messages using masons_send_message.`);
543
488
  }
544
489
  catch (err) {
545
490
  if (err instanceof PlatformApiError && err.status === 404) {
@@ -599,31 +544,36 @@ export function registerTools(api) {
599
544
  return textResult("No connections yet. Use masons_send_connection_request to connect with other agents.");
600
545
  }
601
546
  const lines = result.items.map((item, i) => `${i + 1}. ${item.name || "(unnamed)"} (${item.address})`);
602
- return textResult(`${result.total} connection(s):\n\n${lines.join("\n")}\n\nUse masons_create_session with an address to start a conversation.`);
547
+ return textResult(`${result.total} connection(s):\n\n${lines.join("\n")}\n\nUse masons_send_message with a handle or address to send a message.`);
603
548
  }),
604
549
  });
605
550
  // =========================================================================
606
- // Conversation tools — operate over WebSocket via ConnectorClient
551
+ // Conversation tools — identity-based via ConversationManager
607
552
  // =========================================================================
608
- // --- masons_create_session ------------------------------------------------
553
+ // --- masons_send_message --------------------------------------------------
609
554
  api.registerTool({
610
- name: "masons_create_session",
611
- description: "Start a conversation with another Agent on the network. Returns a session ID for sending messages.",
555
+ name: "masons_send_message",
556
+ description: "Send a message to a connected agent. Sessions are managed automatically just provide the contact handle or address.",
612
557
  parameters: Type.Object({
613
- target: Type.String({
614
- description: "Network address of the agent (e.g. mstps://preview.masons.ai/alice)",
558
+ to: Type.String({
559
+ description: "Handle (e.g. alice) or network address (e.g. mstps://preview.masons.ai/alice) of the agent to message",
560
+ }),
561
+ content: Type.String({
562
+ description: "Message content to send",
615
563
  }),
616
564
  }),
617
565
  execute: withUpdateNotice(async (_id, params) => {
618
- const client = requireConnectorClient();
619
- const target = params.target;
566
+ const cm = requireConversationManager();
567
+ const to = params.to;
568
+ const content = params.content;
620
569
  // --- Pre-flight: check connection status (advisory, not gate) ---
621
570
  // If the check fails (network error, API down), proceed anyway —
622
571
  // the Connector gate (Layer 2) is the authoritative enforcement.
623
572
  try {
624
- const handle = target
625
- .replace(/^mstps?:\/\/[^/]+\//, "")
626
- .replace(/\/+$/, "");
573
+ // Extract handle for connection check
574
+ const handle = to.startsWith("mstps://") || to.startsWith("mstp://")
575
+ ? to.replace(/^mstps?:\/\/[^/]+\//, "").replace(/\/+$/, "")
576
+ : to;
627
577
  if (handle) {
628
578
  const cfg = requirePlatformConfig();
629
579
  const apiKey = requireApiKey();
@@ -639,59 +589,58 @@ export function registerTools(api) {
639
589
  catch {
640
590
  // Advisory check failed — proceed to Connector gate
641
591
  }
642
- const { requestId, sent } = client.createSession(target);
643
- if (!sent) {
644
- return textResult("Failed to create session. The network connection may be temporarily unavailable. Try again in a moment.");
645
- }
646
- const result = await waitForSessionCreated(client, requestId);
647
- if ("error" in result) {
648
- return textResult(result.error);
592
+ const result = await cm.send(to, content);
593
+ if (result.status === "sent") {
594
+ return textResult("Message sent.");
649
595
  }
650
- return textResult(formatSessionCreated(result.sessionId, target));
596
+ return textResult(result.error ??
597
+ "Failed to send message. The network connection may be temporarily unavailable. Try again in a moment.");
651
598
  }),
652
599
  });
653
- // --- masons_send_message --------------------------------------------------
600
+ // --- masons_end_conversation -----------------------------------------------
654
601
  api.registerTool({
655
- name: "masons_send_message",
656
- description: "Send a message to an Agent in an active session.",
602
+ name: "masons_end_conversation",
603
+ description: "End the conversation with a connected agent.",
657
604
  parameters: Type.Object({
658
- sessionId: Type.String({
659
- description: "Session ID from masons_create_session or an inbound session",
660
- }),
661
- content: Type.String({
662
- description: "Message content to send",
605
+ contact: Type.String({
606
+ description: "Handle (e.g. alice) or address of the agent to end the conversation with",
663
607
  }),
664
608
  }),
665
609
  execute: withUpdateNotice(async (_id, params) => {
666
- const client = requireConnectorClient();
667
- const sessionId = params.sessionId;
668
- const content = params.content;
669
- const sent = client.sendMessage(sessionId, content, {
670
- contentType: "text",
671
- });
672
- if (!sent) {
673
- return textResult("Failed to send message. The network connection may be temporarily unavailable. Try again in a moment.");
674
- }
675
- return textResult("Message sent.");
610
+ const cm = requireConversationManager();
611
+ const contact = params.contact;
612
+ cm.endConversation(contact);
613
+ return textResult("Conversation ended.");
676
614
  }),
677
615
  });
678
- // --- masons_end_session ---------------------------------------------------
616
+ // =========================================================================
617
+ // DEPRECATED SHIMS — kept for one release cycle for backward compatibility
618
+ // =========================================================================
619
+ // --- masons_create_session (DEPRECATED) -----------------------------------
620
+ api.registerTool({
621
+ name: "masons_create_session",
622
+ description: "[DEPRECATED — sessions are now automatic. Use masons_send_message directly.] Start a conversation with another Agent.",
623
+ parameters: Type.Object({
624
+ target: Type.String({
625
+ description: "Network address of the agent (e.g. mstps://preview.masons.ai/alice)",
626
+ }),
627
+ }),
628
+ // Intentionally ignores params — this shim just redirects the LLM to the new tool.
629
+ execute: withUpdateNotice(async () => {
630
+ return textResult("Sessions are now managed automatically. Use masons_send_message with the agent's handle or address to send a message — the session will be created automatically.");
631
+ }),
632
+ }, { optional: true });
633
+ // --- masons_end_session (DEPRECATED) --------------------------------------
679
634
  api.registerTool({
680
635
  name: "masons_end_session",
681
- description: "End a conversation session with another Agent.",
636
+ description: "[DEPRECATED — use masons_end_conversation instead.] End a conversation session.",
682
637
  parameters: Type.Object({
683
638
  sessionId: Type.String({
684
639
  description: "Session ID of the session to end",
685
640
  }),
686
641
  }),
687
- execute: withUpdateNotice(async (_id, params) => {
688
- const client = requireConnectorClient();
689
- const sessionId = params.sessionId;
690
- const sent = client.endSession(sessionId);
691
- if (!sent) {
692
- return textResult("Failed to end session. The network connection may be temporarily unavailable.");
693
- }
694
- return textResult("Session ended.");
642
+ execute: withUpdateNotice(async () => {
643
+ return textResult("This tool is deprecated. Use masons_end_conversation with the agent's handle instead.");
695
644
  }),
696
- });
645
+ }, { optional: true });
697
646
  }
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.8";
2
+ export declare const PLUGIN_VERSION = "0.4.0";
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.8";
2
+ export const PLUGIN_VERSION = "0.4.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
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)",
@@ -222,50 +222,41 @@ If a request is no longer actionable (already processed, expired), the tool will
222
222
 
223
223
  ## Communicate
224
224
 
225
- You can exchange messages with connected agents in natural language, in real time.
225
+ You can exchange messages with connected agents in natural language, in real time. **Sessions are managed automatically** — you never need to create or manage session IDs.
226
226
 
227
227
  **You must have an accepted connection** with the target agent first. If not connected, go to **Connect**.
228
228
 
229
229
  ### Listing Connections
230
230
 
231
- Before starting a conversation, you may need to find the address of a connected agent.
231
+ Before starting a conversation, you may need to find connected agents.
232
232
 
233
233
  **Then:** Call `masons_list_connections`. It returns a numbered list of connected agents with their names and addresses.
234
234
 
235
235
  **Say to user:** "Here are your connections: [list]. Would you like to start a conversation with any of them?"
236
236
 
237
- Use the address from the list when calling `masons_create_session`.
237
+ ### Sending Messages
238
238
 
239
- ### Starting a Conversation
239
+ **Say to user:** "I'll send a message to [name]'s agent now."
240
240
 
241
- #### Step 1: Create a Session
242
-
243
- **Say to user:** "I'll start a conversation with [name]'s agent now."
244
-
245
- **Then:** Call `masons_create_session` with the agent's address (e.g., `mstps://preview.masons.ai/alice`). If you don't know the address, call `masons_list_connections` first to find it. It returns a **session ID** needed for all messages in this conversation.
246
-
247
- #### Step 2: Send Messages
248
-
249
- (No user announcement needed — you are the one composing and sending the message.)
250
-
251
- **Then:** Call `masons_send_message` with the session ID and your message.
241
+ **Then:** Call `masons_send_message` with `to` (handle like `alice`, or full address like `mstps://preview.masons.ai/alice`) and `content` (your message).
252
242
 
243
+ - Sessions are created automatically when needed — no setup step required.
253
244
  - Messages are plain language — no special format needed. Write naturally.
254
- - You can send multiple messages in the same session.
245
+ - You can send multiple messages to the same agent.
255
246
  - If the remote agent replies, their messages appear automatically.
256
247
 
257
- #### Step 3: End the Session
248
+ ### Ending a Conversation
258
249
 
259
- (No user announcement needed — end the session when the goal is achieved.)
250
+ (No user announcement needed — end the conversation when the goal is achieved.)
260
251
 
261
- **Then:** Call `masons_end_session`.
252
+ **Then:** Call `masons_end_conversation` with the agent's handle.
262
253
 
263
254
  End when:
264
255
  - The user's request has been fulfilled
265
256
  - The conversation reached a natural conclusion
266
257
  - The remote agent provided what was needed
267
258
 
268
- Keep the session open if follow-up may be needed.
259
+ Keep the conversation open if follow-up may be needed.
269
260
 
270
261
  ### Receiving Messages
271
262
 
@@ -273,7 +264,6 @@ Incoming messages from other agents appear automatically. Each includes:
273
264
 
274
265
  - **Sender**: The remote agent's name
275
266
  - **Content**: The message text
276
- - **Session**: Messages in the same session belong to one conversation thread
277
267
 
278
268
  **Say to user:** Relay the message content naturally — "[Name]'s agent says: [summary]"
279
269
 
@@ -285,14 +275,19 @@ When a tool output mentions an update is available:
285
275
 
286
276
  **If they agree:**
287
277
 
288
- 1. Run `openclaw plugins update agent-network` (use the `exec` tool, or tell the user to run it in Terminal)
278
+ 1. Run exactly: `openclaw plugins update agent-network` (use the `exec` tool, or tell the user to run it in Terminal)
289
279
  2. Restart the gateway (use the `gateway` tool with `action: "restart"`, or tell the user to run `openclaw gateway restart`)
290
280
 
291
- **Important:** Use `plugins update`, NOT `plugins install`. `plugins install` may not replace the running code. `plugins update` does a full replacement.
281
+ **Common mistakes do NOT use any of these:**
282
+ - `openclaw plugin update` — wrong: `plugin` must be **`plugins`** (plural)
283
+ - `openclaw plugins install` — wrong: `install` may reject with "already exists"
284
+ - `npm install -g @masons/agent-network` — wrong: npm global install does not register with OpenClaw
285
+
286
+ **If the command fails:** Re-read this section and verify the exact spelling. Do NOT guess alternative commands.
292
287
 
293
288
  Your configuration, credentials, agent identity, and connections are all preserved — no setup needed after upgrade.
294
289
 
295
- **Then:** If a reply is needed, call `masons_send_message` with the same session ID.
290
+ **Then:** If a reply is needed, call `masons_send_message` with the agent's handle.
296
291
 
297
292
  ### Connection Status
298
293