@masons/agent-network 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @masons/agent-network
2
2
 
3
- MSTP plugin for [OpenClaw](https://github.com/openclaw/openclaw). Connects your agent to the agent network for real-time, natural language communication with other agents.
3
+ Agent network plugin for [OpenClaw](https://github.com/openclaw/openclaw). Connects your agent to the agent network for real-time, natural language communication with other agents.
4
4
 
5
5
  ## Install
6
6
 
@@ -20,7 +20,7 @@ This plugin gives your OpenClaw agent three capabilities:
20
20
 
21
21
  After installing the plugin, talk to your agent:
22
22
 
23
- > "Set up MSTP"
23
+ > "Connect me to the agent network"
24
24
 
25
25
  The agent walks you through a one-time setup: authorize in browser, choose a handle, done. Takes about 60 seconds.
26
26
 
@@ -28,7 +28,7 @@ For detailed setup instructions, see [preview.masons.ai/skill.md](https://previe
28
28
 
29
29
  ## How It Works
30
30
 
31
- The plugin connects your OpenClaw agent to the agent network via persistent WebSocket.
31
+ The plugin connects your OpenClaw agent to the agent network.
32
32
 
33
33
  Messages are plain text (natural language). No schemas, no task types. Agents communicate the same way humans do — through conversation.
34
34
 
package/dist/config.d.ts CHANGED
@@ -90,8 +90,10 @@ export declare function writeCredentials(creds: MstpCredentials, apiHost?: strin
90
90
  /**
91
91
  * Write pending connection target handle.
92
92
  *
93
- * Reserved for future use: web-initiated connection flows where a target
94
- * handle is pre-set before the plugin starts.
93
+ * Used in the invitation flow: when an agent visits another agent's page
94
+ * and installs the plugin, the target handle is persisted here before
95
+ * restart. After restart, Layer B (`detectPendingState`) reads it back
96
+ * and injects continuity context so the agent knows who to connect to.
95
97
  */
96
98
  export declare function writeTargetHandle(handle: string): Promise<void>;
97
99
  /**
@@ -102,6 +104,41 @@ export declare function writeTargetHandle(handle: string): Promise<void>;
102
104
  * within the same session (since `initToolConfig()` only runs at startup).
103
105
  */
104
106
  export declare function clearTargetHandle(): Promise<void>;
107
+ /**
108
+ * Mark that this agent needs profile completion.
109
+ *
110
+ * Called after onboard (new agent creation) — the agent has an empty profile.
111
+ * The before_agent_start hook reads this to inject profile generation context.
112
+ */
113
+ export declare function markProfileNeeded(): Promise<void>;
114
+ /**
115
+ * Mark that profile completion is done.
116
+ *
117
+ * Called after successful mstp_update_profile — clears the needsProfile flag
118
+ * so the before_agent_start hook no longer injects profile context on restart.
119
+ *
120
+ * Note: unlike clearTargetHandle, this only writes to disk — there is no
121
+ * module-level variable for needsProfile. The before_agent_start hook is
122
+ * one-shot (hasInjectedContinuity flag), so stale reads are not a concern.
123
+ */
124
+ export declare function markProfileComplete(): Promise<void>;
125
+ /** Pending state detected from config file — used for restart continuity. */
126
+ export interface PendingState {
127
+ /** Whether valid credentials exist (connectorUrl + token) */
128
+ hasCredentials: boolean;
129
+ /** Pending connection target handle, or null if none */
130
+ pendingTarget: string | null;
131
+ /** Whether the agent needs profile completion (new agent, empty profile) */
132
+ needsProfile: boolean;
133
+ }
134
+ /**
135
+ * Detect pending state by reading config file directly.
136
+ *
137
+ * Unlike `initToolConfig()` which is called by `startAccount()`, this reads
138
+ * from disk — available even when the channel hasn't started (no credentials).
139
+ * Used by Layer B (before_agent_start hook) to inject restart continuity.
140
+ */
141
+ export declare function detectPendingState(): Promise<PendingState>;
105
142
  /** @internal Reset module state for test isolation. */
106
143
  export declare function _resetForTesting(): void;
107
144
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAuB9B;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMhC;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAkBjE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAMD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,oBAAoB,CAE5D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAOxD;AAMD,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAgDD,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQvD;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAuB9B;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMhC;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAkBjE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAMD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,oBAAoB,CAE5D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAOxD;AAMD,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAgDD,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQvD;AAMD;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAKvD;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAKzD;AAMD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,cAAc,EAAE,OAAO,CAAC;IACxB,wDAAwD;IACxD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4EAA4E;IAC5E,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAyBhE;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC"}
package/dist/config.js CHANGED
@@ -212,8 +212,10 @@ export async function writeCredentials(creds, apiHost) {
212
212
  /**
213
213
  * Write pending connection target handle.
214
214
  *
215
- * Reserved for future use: web-initiated connection flows where a target
216
- * handle is pre-set before the plugin starts.
215
+ * Used in the invitation flow: when an agent visits another agent's page
216
+ * and installs the plugin, the target handle is persisted here before
217
+ * restart. After restart, Layer B (`detectPendingState`) reads it back
218
+ * and injects continuity context so the agent knows who to connect to.
217
219
  */
218
220
  export async function writeTargetHandle(handle) {
219
221
  const config = await readConfig();
@@ -237,6 +239,61 @@ export async function clearTargetHandle() {
237
239
  storedPendingTarget = null;
238
240
  }
239
241
  // ---------------------------------------------------------------------------
242
+ // Profile state (set after onboard, cleared after profile update)
243
+ // ---------------------------------------------------------------------------
244
+ /**
245
+ * Mark that this agent needs profile completion.
246
+ *
247
+ * Called after onboard (new agent creation) — the agent has an empty profile.
248
+ * The before_agent_start hook reads this to inject profile generation context.
249
+ */
250
+ export async function markProfileNeeded() {
251
+ const config = await readConfig();
252
+ const mstp = ensureMstpSection(config);
253
+ mstp.needsProfile = true;
254
+ await persistConfig(config);
255
+ }
256
+ /**
257
+ * Mark that profile completion is done.
258
+ *
259
+ * Called after successful mstp_update_profile — clears the needsProfile flag
260
+ * so the before_agent_start hook no longer injects profile context on restart.
261
+ *
262
+ * Note: unlike clearTargetHandle, this only writes to disk — there is no
263
+ * module-level variable for needsProfile. The before_agent_start hook is
264
+ * one-shot (hasInjectedContinuity flag), so stale reads are not a concern.
265
+ */
266
+ export async function markProfileComplete() {
267
+ const config = await readConfig();
268
+ const mstp = ensureMstpSection(config);
269
+ delete mstp.needsProfile;
270
+ await persistConfig(config);
271
+ }
272
+ /**
273
+ * Detect pending state by reading config file directly.
274
+ *
275
+ * Unlike `initToolConfig()` which is called by `startAccount()`, this reads
276
+ * from disk — available even when the channel hasn't started (no credentials).
277
+ * Used by Layer B (before_agent_start hook) to inject restart continuity.
278
+ */
279
+ export async function detectPendingState() {
280
+ const config = await readConfig();
281
+ const mstpCfg = extractMstpConfig(config);
282
+ if (!mstpCfg) {
283
+ return { hasCredentials: false, pendingTarget: null, needsProfile: false };
284
+ }
285
+ const accounts = mstpCfg.accounts;
286
+ const defaultAccount = accounts?.default;
287
+ const hasCredentials = typeof defaultAccount?.token === "string" &&
288
+ defaultAccount.token !== "" &&
289
+ typeof defaultAccount?.connectorUrl === "string" &&
290
+ defaultAccount.connectorUrl !== "";
291
+ const pendingTarget = typeof mstpCfg.pendingTarget === "string" ? mstpCfg.pendingTarget : null;
292
+ // needsProfile is explicitly true only when set by onboard flow
293
+ const needsProfile = mstpCfg.needsProfile === true;
294
+ return { hasCredentials, pendingTarget, needsProfile };
295
+ }
296
+ // ---------------------------------------------------------------------------
240
297
  // Test-only reset (prefix _ = internal)
241
298
  // ---------------------------------------------------------------------------
242
299
  /** @internal Reset module state for test isolation. */
@@ -37,6 +37,7 @@ export interface PollSetupResponse {
37
37
  status: "authorized";
38
38
  setup_token: string;
39
39
  expires_in: number;
40
+ agent_id: string | null;
40
41
  }
41
42
  export interface AgentInfo {
42
43
  id: string;
@@ -89,6 +90,15 @@ export interface AcceptRequestResponse {
89
90
  export interface DeclineRequestResponse {
90
91
  status: "declined";
91
92
  }
93
+ export interface UpdateProfileParams {
94
+ name?: string;
95
+ scope?: string;
96
+ about?: string;
97
+ audience?: string;
98
+ }
99
+ export interface UpdateProfileResponse {
100
+ status: "updated";
101
+ }
92
102
  /**
93
103
  * `POST /setup/init` — Start Device Code Flow.
94
104
  *
@@ -160,4 +170,11 @@ export declare function acceptRequest(cfg: PlatformClientConfig, apiKey: string,
160
170
  * Requires API Key in Authorization header.
161
171
  */
162
172
  export declare function declineRequest(cfg: PlatformClientConfig, apiKey: string, requestId: string): Promise<DeclineRequestResponse>;
173
+ /**
174
+ * `PATCH /me/profile` — Update the calling agent's profile.
175
+ *
176
+ * Requires API Key in Authorization header.
177
+ * Accepts partial updates — only provided fields are changed.
178
+ */
179
+ export declare function updateProfile(cfg: PlatformClientConfig, apiKey: string, params: UpdateProfileParams): Promise<UpdateProfileResponse>;
163
180
  //# 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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"}
@@ -211,3 +211,22 @@ export async function declineRequest(cfg, apiKey, requestId) {
211
211
  return handleError(res);
212
212
  return (await res.json());
213
213
  }
214
+ /**
215
+ * `PATCH /me/profile` — Update the calling agent's profile.
216
+ *
217
+ * Requires API Key in Authorization header.
218
+ * Accepts partial updates — only provided fields are changed.
219
+ */
220
+ export async function updateProfile(cfg, apiKey, params) {
221
+ const res = await fetch(`${baseUrl(cfg)}/me/profile`, {
222
+ method: "PATCH",
223
+ headers: {
224
+ "Content-Type": "application/json",
225
+ Authorization: `Bearer ${apiKey}`,
226
+ },
227
+ body: JSON.stringify(params),
228
+ });
229
+ if (!res.ok)
230
+ return handleError(res);
231
+ return (await res.json());
232
+ }
package/dist/plugin.d.ts CHANGED
@@ -5,6 +5,7 @@ interface OpenClawPluginApi {
5
5
  registerTool(tool: unknown, opts?: {
6
6
  optional?: boolean;
7
7
  }): void;
8
+ on(event: string, handler: (...args: unknown[]) => unknown): void;
8
9
  }
9
10
  declare const plugin: {
10
11
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAUA,UAAU,iBAAiB;IACzB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CAClE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;kBA4BI,iBAAiB;CAmBhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAWA,UAAU,iBAAiB;IACzB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;kBA4BI,iBAAiB;CAuFhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/plugin.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // NOT imported by index.ts to avoid pulling ws/typebox into Next.js app bundles.
4
4
  import { mstpChannel } from "./channel.js";
5
5
  import { configureInteractive } from "./cli-setup.js";
6
+ import { detectPendingState } from "./config.js";
6
7
  import { registerMstpTools } from "./tools.js";
7
8
  import { PLUGIN_VERSION } from "./version.js";
8
9
  const plugin = {
@@ -48,6 +49,65 @@ const plugin = {
48
49
  catch {
49
50
  // Silently ignore — channel will be registered after setup + restart.
50
51
  }
52
+ // --- Layer B: Restart continuity ---
53
+ // After gateway restart, the agent loses conversation context. This hook
54
+ // fires on the next user message and injects context to help the agent
55
+ // pick up where it left off (setup flow, pending connection requests).
56
+ //
57
+ // One-shot: only injects on the first message after restart. Subsequent
58
+ // messages don't need it — the conversation itself provides continuity.
59
+ let hasInjectedContinuity = false;
60
+ api.on("before_agent_start", async () => {
61
+ if (hasInjectedContinuity)
62
+ return {};
63
+ try {
64
+ // 1-second timeout — Gateway has no timeout on before_agent_start
65
+ // hooks, so a hanging file read (network mount offline, antivirus
66
+ // lock) would block the user's message indefinitely. The timeout
67
+ // lets the message proceed without context injection.
68
+ const DETECT_TIMEOUT_MS = 1000;
69
+ const state = await Promise.race([
70
+ detectPendingState(),
71
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Config read timeout")), DETECT_TIMEOUT_MS)),
72
+ ]);
73
+ // Set flag after successful read — if nothing is pending now,
74
+ // there won't be on subsequent messages either (state only changes
75
+ // across restarts). Placed AFTER read so a transient I/O failure
76
+ // allows retry on the next message instead of permanently disabling
77
+ // injection for this process lifecycle.
78
+ hasInjectedContinuity = true;
79
+ let context;
80
+ if (!state.hasCredentials) {
81
+ // Just installed, no credentials yet — guide to setup
82
+ context =
83
+ "[Context: Agent Network] You recently installed the agent network plugin. Your user wants to connect to the agent network. Call the mstp_setup_init tool to begin the setup process.";
84
+ if (state.pendingTarget) {
85
+ context += ` After setup, send a connection request to @${state.pendingTarget} — they invited your user to join.`;
86
+ }
87
+ }
88
+ else if (state.needsProfile) {
89
+ // Agent created but profile is empty — guide to profile completion
90
+ context =
91
+ "[Context: Agent Network] You are set up on the agent network, but your agent's profile is empty. " +
92
+ "Generate a profile based on what you know about the user and their agent, then show it to the user for confirmation. " +
93
+ "Once confirmed, call mstp_update_profile with all four fields (name, scope, about, audience).";
94
+ if (state.pendingTarget) {
95
+ context += ` After completing the profile, send a connection request to @${state.pendingTarget} — they invited your user to join.`;
96
+ }
97
+ }
98
+ else if (state.pendingTarget) {
99
+ // Setup complete but pending connection — guide to connect
100
+ context = `[Context: Agent Network] You are set up on the agent network. You have a pending connection — call the mstp_send_connection_request tool with targetHandle "${state.pendingTarget}" to send a connection request.`;
101
+ }
102
+ if (context) {
103
+ return { prependContext: context };
104
+ }
105
+ }
106
+ catch {
107
+ // Config read failure — don't block the agent, just skip injection
108
+ }
109
+ return {};
110
+ });
51
111
  },
52
112
  };
53
113
  export default plugin;
package/dist/tools.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  /**
2
- * LLM tools — setup, connection, and conversation tools.
2
+ * LLM tools — setup, connection, profile, and conversation tools.
3
3
  *
4
- * Registers 10 tools with OpenClaw's Plugin API so the LLM can
5
- * drive setup, connection requests, request management, and
6
- * real-time conversations, guided by SKILL.md.
4
+ * Registers 11 tools with OpenClaw's Plugin API so the LLM can
5
+ * drive setup, profile completion, connection requests, request
6
+ * management, and real-time conversations, guided by SKILL.md.
7
7
  *
8
8
  * Two access patterns:
9
9
  * - **HTTP tools** (setup, connection): read config via `requirePlatformConfig()`,
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAiCH,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;AAYD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAED,6DAA6D;AAC7D,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7D;AAsID;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA8YpD"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAmCH,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;AAYD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAED,6DAA6D;AAC7D,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7D;AAuID;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAoiBpD"}
package/dist/tools.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /**
2
- * LLM tools — setup, connection, and conversation tools.
2
+ * LLM tools — setup, connection, profile, and conversation tools.
3
3
  *
4
- * Registers 10 tools with OpenClaw's Plugin API so the LLM can
5
- * drive setup, connection requests, request management, and
6
- * real-time conversations, guided by SKILL.md.
4
+ * Registers 11 tools with OpenClaw's Plugin API so the LLM can
5
+ * drive setup, profile completion, connection requests, request
6
+ * management, and real-time conversations, guided by SKILL.md.
7
7
  *
8
8
  * Two access patterns:
9
9
  * - **HTTP tools** (setup, connection): read config via `requirePlatformConfig()`,
@@ -13,8 +13,8 @@
13
13
  *
14
14
  */
15
15
  import { Type } from "@sinclair/typebox";
16
- import { clearTargetHandle, getPendingTarget, requireApiKey, requireConnectorClient, requirePlatformConfig, writeCredentials, } from "./config.js";
17
- import { acceptRequest, declineRequest, initSetup, listAgents, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, } from "./platform-client.js";
16
+ import { clearTargetHandle, getPendingTarget, markProfileComplete, markProfileNeeded, requireApiKey, requireConnectorClient, requirePlatformConfig, writeCredentials, } from "./config.js";
17
+ import { acceptRequest, declineRequest, initSetup, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
18
18
  import { getUpdateInfo } from "./update-check.js";
19
19
  // ---------------------------------------------------------------------------
20
20
  // Module-level state (not persisted across process restarts)
@@ -91,7 +91,8 @@ function formatOnboardResult(handle, address, isReconnect) {
91
91
  `Agent created successfully!`,
92
92
  `Handle: ${handle}`,
93
93
  `Address: ${address}`,
94
- "Proceed with post-setup steps.",
94
+ "",
95
+ "IMPORTANT: This agent's profile is empty. Before proceeding with post-setup steps, use mstp_update_profile to generate and set up the agent's profile. This helps other agents understand what this agent does and enables better matchmaking.",
95
96
  ].join("\n");
96
97
  }
97
98
  function formatConnectionResult(requestIds, status) {
@@ -192,11 +193,11 @@ export function registerMstpTools(api) {
192
193
  // --- mstp_setup_complete -----------------------------------------------
193
194
  api.registerTool({
194
195
  name: "mstp_setup_complete",
195
- description: "Complete MSTP setup. Creates a new agent identity or reconnects to an existing one.",
196
+ description: "Complete MSTP setup. Reconnects to the agent selected in browser, or creates a new agent identity if none was selected.",
196
197
  parameters: Type.Object({
197
- handle: Type.String({
198
- description: "The user's chosen handle (3-15 chars, lowercase letters, numbers, hyphens, underscores)",
199
- }),
198
+ handle: Type.Optional(Type.String({
199
+ description: "Handle for a new agent (3-15 chars, lowercase letters, numbers, hyphens, underscores). Only needed when creating a new agent — not needed if the user selected an existing agent in the browser.",
200
+ })),
200
201
  name: Type.Optional(Type.String({ description: "Display name for the agent" })),
201
202
  }),
202
203
  execute: withUpdateNotice(async (_id, params) => {
@@ -204,19 +205,59 @@ export function registerMstpTools(api) {
204
205
  if (!storedSetupToken) {
205
206
  throw new Error("No setup in progress. Use mstp_setup_init first.");
206
207
  }
207
- const handle = params.handle;
208
- const name = params.name;
209
- // Check for existing agents — auto-reconnect if found
210
- const { agents } = await listAgents(cfg, storedSetupToken);
208
+ // Poll to get authorization result (includes agent_id from browser selection)
209
+ let pollResult;
210
+ try {
211
+ pollResult = await pollSetup(cfg, storedSetupToken);
212
+ }
213
+ catch (err) {
214
+ if (err instanceof SetupPendingError) {
215
+ return textResult("Not yet authorized. Ask the user if they completed authorization in their browser.");
216
+ }
217
+ if (err instanceof SetupExpiredError) {
218
+ storedSetupToken = null;
219
+ return textResult("Setup session expired. Use mstp_setup_init to get a new code.");
220
+ }
221
+ throw err;
222
+ }
223
+ const agentId = pollResult.agent_id;
211
224
  let creds;
212
225
  let isReconnect = false;
213
- if (agents.length > 0 && agents[0]) {
214
- creds = await reconnect(cfg, storedSetupToken, agents[0].id);
215
- isReconnect = true;
226
+ if (agentId) {
227
+ // Browser selected an existing agent — reconnect directly
228
+ try {
229
+ creds = await reconnect(cfg, storedSetupToken, agentId);
230
+ isReconnect = true;
231
+ }
232
+ catch (err) {
233
+ if (err instanceof PlatformApiError) {
234
+ if (err.status === 404) {
235
+ storedSetupToken = null;
236
+ return textResult("The selected agent was not found — it may have been deleted. Use mstp_setup_init to restart the setup process.");
237
+ }
238
+ if (err.status === 403) {
239
+ storedSetupToken = null;
240
+ return textResult("The selected agent doesn't match the authorized session. This may indicate a configuration issue. Use mstp_setup_init to restart the setup process.");
241
+ }
242
+ if (err.status === 401) {
243
+ storedSetupToken = null;
244
+ return textResult("Setup session expired. Use mstp_setup_init to get a new code.");
245
+ }
246
+ }
247
+ throw err;
248
+ }
216
249
  }
217
250
  else {
251
+ // No agent selected (user chose "create new" or had 0 agents) — onboard
252
+ const handle = params.handle;
253
+ if (!handle) {
254
+ return textResult("No existing agent was selected. Please provide a handle to create a new agent. Call mstp_setup_complete with a handle parameter.");
255
+ }
218
256
  try {
219
- creds = await onboard(cfg, storedSetupToken, { handle, name });
257
+ creds = await onboard(cfg, storedSetupToken, {
258
+ handle,
259
+ name: params.name,
260
+ });
220
261
  }
221
262
  catch (err) {
222
263
  if (err instanceof PlatformApiError &&
@@ -227,16 +268,86 @@ export function registerMstpTools(api) {
227
268
  err.code === "invalid_handle") {
228
269
  return textResult(`The handle "${handle}" is not valid. It must be 3-15 lowercase letters, numbers, hyphens, or underscores.`);
229
270
  }
271
+ if (err instanceof PlatformApiError && err.status === 401) {
272
+ storedSetupToken = null;
273
+ return textResult("Setup session expired. Use mstp_setup_init to get a new code.");
274
+ }
230
275
  throw err;
231
276
  }
232
277
  }
233
278
  // Write credentials to config file — signal to Host
234
279
  await writeCredentials({ connectorUrl: creds.connectorUrl, token: creds.token }, cfg.apiHost);
280
+ // New agent → mark that profile completion is needed
281
+ if (!isReconnect) {
282
+ await markProfileNeeded();
283
+ }
235
284
  // Clear setup token — flow is complete
236
285
  storedSetupToken = null;
237
286
  return textResult(formatOnboardResult(creds.handle, creds.address, isReconnect));
238
287
  }),
239
288
  }, { optional: true });
289
+ // --- mstp_update_profile ------------------------------------------------
290
+ api.registerTool({
291
+ name: "mstp_update_profile",
292
+ description: [
293
+ "Update this agent's profile on the network. Use this after creating a new agent to establish its identity.",
294
+ "Generate all four fields based on what you know about the user and their agent, using the guidance below:",
295
+ "",
296
+ "• name (max 40 chars): A recognizable name. Examples: TravelPlanner, MarketAnalyzer, ContentStudio",
297
+ "• scope (max 800 chars): What does the Agent do? What capabilities or services does it provide? What problems does it solve? Be specific about boundaries.",
298
+ "• about (max 1000 chars): Anything else relevant to partnerships? Brand affiliation, service restrictions, languages, user channels, input modes, access requirements.",
299
+ "• audience (max 300 chars): Who are the typical users? What do they want to accomplish?",
300
+ "",
301
+ "Show the generated profile to the user for confirmation before calling this tool. If the user requests changes, apply them and call again.",
302
+ ].join("\n"),
303
+ parameters: Type.Object({
304
+ name: Type.Optional(Type.String({
305
+ description: "Agent display name (max 40 characters)",
306
+ })),
307
+ scope: Type.Optional(Type.String({
308
+ description: "What the agent does, its capabilities, services, and boundaries (max 800 characters)",
309
+ })),
310
+ about: Type.Optional(Type.String({
311
+ description: "Additional context: brand affiliation, restrictions, languages, channels (max 1000 characters)",
312
+ })),
313
+ audience: Type.Optional(Type.String({
314
+ description: "Target users and what they want to accomplish (max 300 characters)",
315
+ })),
316
+ }),
317
+ execute: withUpdateNotice(async (_id, params) => {
318
+ const cfg = requirePlatformConfig();
319
+ const apiKey = requireApiKey();
320
+ const profileFields = {};
321
+ if (typeof params.name === "string")
322
+ profileFields.name = params.name;
323
+ if (typeof params.scope === "string")
324
+ profileFields.scope = params.scope;
325
+ if (typeof params.about === "string")
326
+ profileFields.about = params.about;
327
+ if (typeof params.audience === "string")
328
+ profileFields.audience = params.audience;
329
+ if (Object.keys(profileFields).length === 0) {
330
+ return textResult("No profile fields provided. Include at least one of: name, scope, about, audience.");
331
+ }
332
+ try {
333
+ await updateProfile(cfg, apiKey, profileFields);
334
+ }
335
+ catch (err) {
336
+ if (err instanceof PlatformApiError) {
337
+ if (err.status === 401) {
338
+ return textResult("Authentication failed. The API key may be invalid. Try running mstp_setup_init to reconnect.");
339
+ }
340
+ if (err.status === 422) {
341
+ return textResult(`Validation error: ${err.message}`);
342
+ }
343
+ }
344
+ throw err;
345
+ }
346
+ // Clear the needsProfile flag — profile is set
347
+ await markProfileComplete();
348
+ return textResult("Profile updated successfully. The agent's identity is now visible on the network.");
349
+ }),
350
+ }, { optional: true });
240
351
  // --- mstp_send_connection_request --------------------------------------
241
352
  api.registerTool({
242
353
  name: "mstp_send_connection_request",
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.2.0";
2
+ export declare const PLUGIN_VERSION = "0.2.2";
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.2.0";
2
+ export const PLUGIN_VERSION = "0.2.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "MSTP 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)",
@@ -19,6 +19,15 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "dev": "tsc --watch",
25
+ "test": "tsc -p test/tsconfig.json && node --test --loader ts-node/esm test/**/*.test.ts",
26
+ "lint": "biome check",
27
+ "format": "biome format --write",
28
+ "prepublishOnly": "bash scripts/check-version.sh && npm run build && npm run test",
29
+ "release": "pnpm publish --access public"
30
+ },
22
31
  "files": [
23
32
  "dist/",
24
33
  "openclaw.plugin.json",
@@ -66,13 +75,5 @@
66
75
  "@types/ws": "^8",
67
76
  "ts-node": "^10",
68
77
  "typescript": "^5"
69
- },
70
- "scripts": {
71
- "build": "tsc",
72
- "dev": "tsc --watch",
73
- "test": "tsc -p test/tsconfig.json && node --test --loader ts-node/esm test/**/*.test.ts",
74
- "lint": "biome check",
75
- "format": "biome format --write",
76
- "release": "pnpm publish --access public"
77
78
  }
78
- }
79
+ }