@masons/agent-network 0.4.5 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +35 -14
- package/dist/config.d.ts +10 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -5
- package/dist/connector-client.d.ts.map +1 -1
- package/dist/connector-client.js +2 -0
- package/dist/owner-notes.d.ts +50 -0
- package/dist/owner-notes.d.ts.map +1 -0
- package/dist/owner-notes.js +69 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +173 -75
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +33 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/agent-network/SKILL.md +33 -1
package/dist/channel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAc9D,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;
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAc9D,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;AAkED,eAAO,MAAM,mBAAmB,EAAE,yBAkXjC,CAAC"}
|
package/dist/channel.js
CHANGED
|
@@ -10,21 +10,32 @@ const dbg = createDebug("agent-network:channel");
|
|
|
10
10
|
// not per-message metadata. See the message_received handler for details.
|
|
11
11
|
// See: docs/openclaw/research/session-identity-mapping.md §5
|
|
12
12
|
/**
|
|
13
|
-
* Extract a human-readable name from the
|
|
13
|
+
* Extract a human-readable name from the sender's metadata.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Resolution order (account-level identity first, then address):
|
|
16
|
+
* 1. `metadata.visitor_name` — display name for Passport browser visitors
|
|
17
|
+
* (resolved by Connector from user_info.displayName)
|
|
18
|
+
* 2. `metadata.from` — MSTP address for agent-to-agent connections
|
|
19
|
+
* (e.g. `mstps://preview.masons.ai/alice` → "alice")
|
|
20
|
+
* 3. Fallback: "Unknown" for direct MSTP clients without metadata
|
|
21
|
+
*
|
|
22
|
+
* Design: Channel determines routing, Account determines identity.
|
|
23
|
+
* See: interop-routing-system-design.md §3 "Channel vs Account".
|
|
18
24
|
*/
|
|
19
25
|
function deriveSenderName(event) {
|
|
26
|
+
// Account-level identity: Passport visitor with resolved display name
|
|
27
|
+
const visitorName = event.metadata?.visitor_name;
|
|
28
|
+
if (visitorName && typeof visitorName === "string") {
|
|
29
|
+
return visitorName;
|
|
30
|
+
}
|
|
31
|
+
// MSTP address: extract handle from agent address
|
|
20
32
|
const from = event.metadata?.from;
|
|
21
|
-
if (
|
|
22
|
-
|
|
33
|
+
if (from && typeof from === "string") {
|
|
34
|
+
const trimmed = from.replace(/\/+$/, "");
|
|
35
|
+
const parts = trimmed.split("/");
|
|
36
|
+
return parts[parts.length - 1] || from;
|
|
23
37
|
}
|
|
24
|
-
|
|
25
|
-
const trimmed = from.replace(/\/+$/, "");
|
|
26
|
-
const parts = trimmed.split("/");
|
|
27
|
-
return parts[parts.length - 1] || from;
|
|
38
|
+
return "Unknown";
|
|
28
39
|
}
|
|
29
40
|
/**
|
|
30
41
|
* Extract the Connector host from a connectorUrl.
|
|
@@ -159,13 +170,20 @@ export const agentNetworkChannel = {
|
|
|
159
170
|
// senderId for OpenClaw routing: use MSTP address if available,
|
|
160
171
|
// fall back to sessionId for unknown sessions / direct MSTP clients.
|
|
161
172
|
const senderId = isRealAddress ? senderAddress : event.sessionId;
|
|
162
|
-
// Derive sender name
|
|
173
|
+
// Derive sender name.
|
|
174
|
+
// - MSTP agents: extract handle from address.
|
|
175
|
+
// - Passport visitors / direct clients: use the contact name stored
|
|
176
|
+
// in ConversationManager at session_created time (which read
|
|
177
|
+
// visitor_name from session metadata). Per-message metadata does
|
|
178
|
+
// NOT carry session-level fields like visitor_name, so we must
|
|
179
|
+
// use the stored value. Falls back to deriveSenderName → "Unknown".
|
|
163
180
|
const senderName = isRealAddress
|
|
164
181
|
? deriveSenderName({
|
|
165
182
|
...event,
|
|
166
183
|
metadata: { ...event.metadata, from: senderAddress },
|
|
167
184
|
})
|
|
168
|
-
:
|
|
185
|
+
: (conversationManager.getContactBySessionId(event.sessionId) ??
|
|
186
|
+
deriveSenderName(event));
|
|
169
187
|
try {
|
|
170
188
|
// Step 1 — Resolve agent route (await defensively — may be sync or async)
|
|
171
189
|
const route = await runtime.channel.routing.resolveAgentRoute({
|
|
@@ -242,8 +260,11 @@ export const agentNetworkChannel = {
|
|
|
242
260
|
conversationManager.registerInbound(event.sessionId, contact, remoteAddress);
|
|
243
261
|
}
|
|
244
262
|
else {
|
|
245
|
-
// No address
|
|
246
|
-
|
|
263
|
+
// No MSTP address — Passport visitor or direct MSTP client.
|
|
264
|
+
// Use visitor_name from session metadata (account-level identity
|
|
265
|
+
// resolved by Connector) if available, else sessionId fallback.
|
|
266
|
+
const contact = deriveSenderName(event);
|
|
267
|
+
conversationManager.registerInbound(event.sessionId, contact, event.sessionId);
|
|
247
268
|
}
|
|
248
269
|
}
|
|
249
270
|
// Outbound sessions are handled by SessionLifecycle internally
|
package/dist/config.d.ts
CHANGED
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
import type { ConnectorClient } from "./connector-client.js";
|
|
18
18
|
import type { ConversationManager } from "./conversation-manager.js";
|
|
19
19
|
import { type PlatformClientConfig } from "./platform-client.js";
|
|
20
|
+
/**
|
|
21
|
+
* Current state cache generation. Incremented by config-modifying functions.
|
|
22
|
+
* Used by before_prompt_build to detect when cached state needs a refresh.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getStateCacheGeneration(): number;
|
|
20
25
|
/**
|
|
21
26
|
* Extract the `channels.agent-network` section from the full OpenClaw config.
|
|
22
27
|
*
|
|
@@ -149,18 +154,18 @@ export declare function clearTargetHandle(): Promise<void>;
|
|
|
149
154
|
* Mark that this agent needs profile completion.
|
|
150
155
|
*
|
|
151
156
|
* Called after onboard (new agent creation) — the agent has an empty profile.
|
|
152
|
-
* The
|
|
157
|
+
* The before_prompt_build hook reads this to inject profile generation context.
|
|
153
158
|
*/
|
|
154
159
|
export declare function markProfileNeeded(): Promise<void>;
|
|
155
160
|
/**
|
|
156
161
|
* Mark that profile completion is done.
|
|
157
162
|
*
|
|
158
163
|
* Called after successful masons_update_profile — clears the needsProfile flag
|
|
159
|
-
* so the
|
|
164
|
+
* so the before_prompt_build hook no longer injects profile context.
|
|
160
165
|
*
|
|
161
166
|
* Note: unlike clearTargetHandle, this only writes to disk — there is no
|
|
162
|
-
* module-level variable for needsProfile. The
|
|
163
|
-
*
|
|
167
|
+
* module-level variable for needsProfile. The before_prompt_build hook
|
|
168
|
+
* uses stateCacheGeneration to detect when a re-read is needed.
|
|
164
169
|
*/
|
|
165
170
|
export declare function markProfileComplete(): Promise<void>;
|
|
166
171
|
/** Pending state detected from config file — used for restart continuity. */
|
|
@@ -177,7 +182,7 @@ export interface PendingState {
|
|
|
177
182
|
*
|
|
178
183
|
* Unlike `initToolConfig()` which is called by `startAccount()`, this reads
|
|
179
184
|
* from disk — available even when the channel hasn't started (no credentials).
|
|
180
|
-
* Used by Layer B (
|
|
185
|
+
* Used by Layer B (before_prompt_build hook) for per-turn context injection.
|
|
181
186
|
*/
|
|
182
187
|
export declare function detectPendingState(): Promise<PendingState>;
|
|
183
188
|
/** @internal Reset module state for test isolation. */
|
package/dist/config.d.ts.map
CHANGED
|
@@ -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,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;
|
|
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,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAsB9B;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAcD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,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,CAsBjE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAMD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,mBAAmB,CAOhE;AAMD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAExD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;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,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,kBAAkB,EACzB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CASvD;AAMD;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMvD;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMzD;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,CA2BhE;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAQvC"}
|
package/dist/config.js
CHANGED
|
@@ -30,6 +30,18 @@ import { DEFAULT_API_HOST, } from "./platform-client.js";
|
|
|
30
30
|
let platformConfig = { apiHost: DEFAULT_API_HOST };
|
|
31
31
|
let storedApiKey = null;
|
|
32
32
|
let storedPendingTarget = null;
|
|
33
|
+
// State cache generation — incremented when config-modifying functions write
|
|
34
|
+
// to disk (writeCredentials, clearTargetHandle, markProfileNeeded, markProfileComplete).
|
|
35
|
+
// before_prompt_build compares its cached generation to this value; mismatch
|
|
36
|
+
// triggers a re-read of detectPendingState() from disk.
|
|
37
|
+
let stateCacheGeneration = 0;
|
|
38
|
+
/**
|
|
39
|
+
* Current state cache generation. Incremented by config-modifying functions.
|
|
40
|
+
* Used by before_prompt_build to detect when cached state needs a refresh.
|
|
41
|
+
*/
|
|
42
|
+
export function getStateCacheGeneration() {
|
|
43
|
+
return stateCacheGeneration;
|
|
44
|
+
}
|
|
33
45
|
// Runtime state (live connection — set by startAccount, cleared by stopAccount)
|
|
34
46
|
let storedConnectorClient = null;
|
|
35
47
|
let storedConversationManager = null;
|
|
@@ -284,6 +296,7 @@ export async function writeCredentials(creds, apiHost) {
|
|
|
284
296
|
// same pattern as clearTargetHandle(). Without this, tools fail with
|
|
285
297
|
// "No API key configured" until Gateway restarts and re-runs initToolConfig().
|
|
286
298
|
storedApiKey = creds.token;
|
|
299
|
+
stateCacheGeneration++;
|
|
287
300
|
}
|
|
288
301
|
/**
|
|
289
302
|
* Write pending connection target handle.
|
|
@@ -298,6 +311,7 @@ export async function writeTargetHandle(handle) {
|
|
|
298
311
|
const section = ensureNetworkSection(config);
|
|
299
312
|
section.pendingTarget = handle;
|
|
300
313
|
await persistConfig(config);
|
|
314
|
+
stateCacheGeneration++;
|
|
301
315
|
}
|
|
302
316
|
/**
|
|
303
317
|
* Clear pending connection target from config file AND module-level variable.
|
|
@@ -313,6 +327,7 @@ export async function clearTargetHandle() {
|
|
|
313
327
|
await persistConfig(config);
|
|
314
328
|
// Update module-level var — deliberate exception to read/write separation
|
|
315
329
|
storedPendingTarget = null;
|
|
330
|
+
stateCacheGeneration++;
|
|
316
331
|
}
|
|
317
332
|
// ---------------------------------------------------------------------------
|
|
318
333
|
// Profile state (set after onboard, cleared after profile update)
|
|
@@ -321,36 +336,38 @@ export async function clearTargetHandle() {
|
|
|
321
336
|
* Mark that this agent needs profile completion.
|
|
322
337
|
*
|
|
323
338
|
* Called after onboard (new agent creation) — the agent has an empty profile.
|
|
324
|
-
* The
|
|
339
|
+
* The before_prompt_build hook reads this to inject profile generation context.
|
|
325
340
|
*/
|
|
326
341
|
export async function markProfileNeeded() {
|
|
327
342
|
const config = await readConfig();
|
|
328
343
|
const section = ensureNetworkSection(config);
|
|
329
344
|
section.needsProfile = true;
|
|
330
345
|
await persistConfig(config);
|
|
346
|
+
stateCacheGeneration++;
|
|
331
347
|
}
|
|
332
348
|
/**
|
|
333
349
|
* Mark that profile completion is done.
|
|
334
350
|
*
|
|
335
351
|
* Called after successful masons_update_profile — clears the needsProfile flag
|
|
336
|
-
* so the
|
|
352
|
+
* so the before_prompt_build hook no longer injects profile context.
|
|
337
353
|
*
|
|
338
354
|
* Note: unlike clearTargetHandle, this only writes to disk — there is no
|
|
339
|
-
* module-level variable for needsProfile. The
|
|
340
|
-
*
|
|
355
|
+
* module-level variable for needsProfile. The before_prompt_build hook
|
|
356
|
+
* uses stateCacheGeneration to detect when a re-read is needed.
|
|
341
357
|
*/
|
|
342
358
|
export async function markProfileComplete() {
|
|
343
359
|
const config = await readConfig();
|
|
344
360
|
const section = ensureNetworkSection(config);
|
|
345
361
|
delete section.needsProfile;
|
|
346
362
|
await persistConfig(config);
|
|
363
|
+
stateCacheGeneration++;
|
|
347
364
|
}
|
|
348
365
|
/**
|
|
349
366
|
* Detect pending state by reading config file directly.
|
|
350
367
|
*
|
|
351
368
|
* Unlike `initToolConfig()` which is called by `startAccount()`, this reads
|
|
352
369
|
* from disk — available even when the channel hasn't started (no credentials).
|
|
353
|
-
* Used by Layer B (
|
|
370
|
+
* Used by Layer B (before_prompt_build hook) for per-turn context injection.
|
|
354
371
|
*/
|
|
355
372
|
export async function detectPendingState() {
|
|
356
373
|
const config = await readConfig();
|
|
@@ -382,4 +399,5 @@ export function _resetForTesting() {
|
|
|
382
399
|
storedConnectorClient = null;
|
|
383
400
|
storedConversationManager = null;
|
|
384
401
|
storedPluginRuntime = null;
|
|
402
|
+
stateCacheGeneration = 0;
|
|
385
403
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connector-client.d.ts","sourceRoot":"","sources":["../src/connector-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAML,KAAK,kBAAkB,EAOvB,KAAK,oBAAoB,EAKzB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"connector-client.d.ts","sourceRoot":"","sources":["../src/connector-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAML,KAAK,kBAAkB,EAOvB,KAAK,oBAAoB,EAKzB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAepB,KAAK,qBAAqB,GAAG;IAC3B,eAAe,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACtD,gBAAgB,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACxD,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,cAAc,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACpD,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAIF,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,uBAAuB,CAAK;IACpC,OAAO,CAAC,cAAc,CAA8C;IAEpE,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,aAAa,CAA8C;gBAEvD,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAQtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IASxB,UAAU,IAAI,IAAI;IAelB,aAAa,CACX,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC7D;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE;IAmBvC,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAClE,OAAO;IAkBV,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;IAWvD,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO;IAYlD,EAAE,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,IAAI;IACP,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAKxE,IAAI,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACxC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,IAAI;IACP,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAK1E,GAAG,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACvC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,IAAI;IACP,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAKzE,IAAI,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACxC,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,GAC5C,OAAO;IACV,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO;IAOzD,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,aAAa,CAyDnB;IAEF,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,WAAW,CAqBjB;IAEF,OAAO,CAAC,WAAW,CAIjB;IAIF,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,IAAI;CAeb"}
|
package/dist/connector-client.js
CHANGED
|
@@ -3,6 +3,7 @@ import { EventEmitter } from "node:events";
|
|
|
3
3
|
import createDebug from "debug";
|
|
4
4
|
import WebSocket from "ws";
|
|
5
5
|
import { CURRENT_PROTOCOL_VERSION, isErrorEvent, isFlushComplete, isMessageReceived, isRegisterAck, isSessionCreated, isSessionEnded, REGISTER_ACK_TIMEOUT_MS, } from "./types.js";
|
|
6
|
+
import { PLUGIN_VERSION } from "./version.js";
|
|
6
7
|
const dbg = createDebug("agent-network:connector");
|
|
7
8
|
const dbgMsg = createDebug("agent-network:connector:msg");
|
|
8
9
|
// --- Reconnection constants ---
|
|
@@ -125,6 +126,7 @@ export class ConnectorClient extends EventEmitter {
|
|
|
125
126
|
event: "REGISTER",
|
|
126
127
|
token: this.token,
|
|
127
128
|
protocolVersion: CURRENT_PROTOCOL_VERSION,
|
|
129
|
+
clientVersion: PLUGIN_VERSION,
|
|
128
130
|
};
|
|
129
131
|
this.send(event);
|
|
130
132
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owner Notes Queue — in-memory queue for Principal notifications.
|
|
3
|
+
*
|
|
4
|
+
* When the LLM receives information from a remote agent that the owner
|
|
5
|
+
* should know about, it calls `masons_note_for_owner` which enqueues
|
|
6
|
+
* a note here. The `before_prompt_build` hook drains the queue on the
|
|
7
|
+
* owner's next turn and injects the notes into prependContext.
|
|
8
|
+
*
|
|
9
|
+
* Module-level singleton — shared between plugin.ts (drain) and tools.ts (enqueue).
|
|
10
|
+
* Same pattern as Mkclaw's PendingEventsQueue (see ref_mkclaw_cross_session.md).
|
|
11
|
+
*
|
|
12
|
+
* Lifecycle: in-memory only. Lost on Gateway restart. Layer 2 (MASONS backend)
|
|
13
|
+
* will add persistence — this queue is the Layer 1 implementation.
|
|
14
|
+
*
|
|
15
|
+
* @see docs/openclaw/interop-routing-system-design.md §7.1
|
|
16
|
+
*/
|
|
17
|
+
export interface OwnerNote {
|
|
18
|
+
/** The note content — summarized by the LLM. */
|
|
19
|
+
content: string;
|
|
20
|
+
/** When the note was created (Date.now()). */
|
|
21
|
+
timestamp: number;
|
|
22
|
+
/** Handle of the remote agent this note is about (e.g. "nikoko"). */
|
|
23
|
+
from?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare class OwnerNotesQueue {
|
|
26
|
+
private notes;
|
|
27
|
+
static readonly MAX_SIZE = 50;
|
|
28
|
+
static readonly TTL_MS: number;
|
|
29
|
+
/**
|
|
30
|
+
* Enqueue a note. FIFO: if at MAX_SIZE after TTL eviction, drops oldest.
|
|
31
|
+
* Always accepts the new note.
|
|
32
|
+
*/
|
|
33
|
+
enqueue(note: OwnerNote): void;
|
|
34
|
+
/**
|
|
35
|
+
* Drain all non-stale notes. Destructive — drained notes are removed.
|
|
36
|
+
* Returns notes in chronological order (oldest first).
|
|
37
|
+
*/
|
|
38
|
+
drain(): OwnerNote[];
|
|
39
|
+
/**
|
|
40
|
+
* Current queue size (after TTL eviction).
|
|
41
|
+
*/
|
|
42
|
+
size(): number;
|
|
43
|
+
/**
|
|
44
|
+
* Clear all notes. For testing only.
|
|
45
|
+
*/
|
|
46
|
+
clear(): void;
|
|
47
|
+
private evictStale;
|
|
48
|
+
}
|
|
49
|
+
export declare const ownerNotesQueue: OwnerNotesQueue;
|
|
50
|
+
//# sourceMappingURL=owner-notes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-notes.d.ts","sourceRoot":"","sources":["../src/owner-notes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,MAAM,WAAW,SAAS;IACxB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,qBAAa,eAAe;IAC1B,OAAO,CAAC,KAAK,CAAmB;IAEhC,MAAM,CAAC,QAAQ,CAAC,QAAQ,MAAM;IAC9B,MAAM,CAAC,QAAQ,CAAC,MAAM,SAAuB;IAE7C;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAQ9B;;;OAGG;IACH,KAAK,IAAI,SAAS,EAAE;IAOpB;;OAEG;IACH,IAAI,IAAI,MAAM;IAKd;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb,OAAO,CAAC,UAAU;CAInB;AAMD,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owner Notes Queue — in-memory queue for Principal notifications.
|
|
3
|
+
*
|
|
4
|
+
* When the LLM receives information from a remote agent that the owner
|
|
5
|
+
* should know about, it calls `masons_note_for_owner` which enqueues
|
|
6
|
+
* a note here. The `before_prompt_build` hook drains the queue on the
|
|
7
|
+
* owner's next turn and injects the notes into prependContext.
|
|
8
|
+
*
|
|
9
|
+
* Module-level singleton — shared between plugin.ts (drain) and tools.ts (enqueue).
|
|
10
|
+
* Same pattern as Mkclaw's PendingEventsQueue (see ref_mkclaw_cross_session.md).
|
|
11
|
+
*
|
|
12
|
+
* Lifecycle: in-memory only. Lost on Gateway restart. Layer 2 (MASONS backend)
|
|
13
|
+
* will add persistence — this queue is the Layer 1 implementation.
|
|
14
|
+
*
|
|
15
|
+
* @see docs/openclaw/interop-routing-system-design.md §7.1
|
|
16
|
+
*/
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Queue
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
export class OwnerNotesQueue {
|
|
21
|
+
notes = [];
|
|
22
|
+
static MAX_SIZE = 50;
|
|
23
|
+
static TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
24
|
+
/**
|
|
25
|
+
* Enqueue a note. FIFO: if at MAX_SIZE after TTL eviction, drops oldest.
|
|
26
|
+
* Always accepts the new note.
|
|
27
|
+
*/
|
|
28
|
+
enqueue(note) {
|
|
29
|
+
this.evictStale();
|
|
30
|
+
if (this.notes.length >= OwnerNotesQueue.MAX_SIZE) {
|
|
31
|
+
this.notes.shift(); // drop oldest (FIFO)
|
|
32
|
+
}
|
|
33
|
+
this.notes.push(note);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Drain all non-stale notes. Destructive — drained notes are removed.
|
|
37
|
+
* Returns notes in chronological order (oldest first).
|
|
38
|
+
*/
|
|
39
|
+
drain() {
|
|
40
|
+
this.evictStale();
|
|
41
|
+
const drained = [...this.notes];
|
|
42
|
+
this.notes = [];
|
|
43
|
+
return drained;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Current queue size (after TTL eviction).
|
|
47
|
+
*/
|
|
48
|
+
size() {
|
|
49
|
+
this.evictStale();
|
|
50
|
+
return this.notes.length;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Clear all notes. For testing only.
|
|
54
|
+
*/
|
|
55
|
+
clear() {
|
|
56
|
+
this.notes = [];
|
|
57
|
+
}
|
|
58
|
+
// -------------------------------------------------------------------------
|
|
59
|
+
// Internal
|
|
60
|
+
// -------------------------------------------------------------------------
|
|
61
|
+
evictStale() {
|
|
62
|
+
const cutoff = Date.now() - OwnerNotesQueue.TTL_MS;
|
|
63
|
+
this.notes = this.notes.filter((n) => n.timestamp > cutoff);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Singleton
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
export const ownerNotesQueue = new OwnerNotesQueue();
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAkCA,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,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;CAiNhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -3,10 +3,28 @@
|
|
|
3
3
|
// NOT imported by index.ts to avoid pulling ws/typebox into Next.js app bundles.
|
|
4
4
|
import { agentNetworkChannel } from "./channel.js";
|
|
5
5
|
import { configureInteractive } from "./cli-setup.js";
|
|
6
|
-
import { detectPendingState, initPluginRuntime } from "./config.js";
|
|
6
|
+
import { detectPendingState, getStateCacheGeneration, initPluginRuntime, } from "./config.js";
|
|
7
|
+
import { ownerNotesQueue } from "./owner-notes.js";
|
|
7
8
|
import { registerTools } from "./tools.js";
|
|
8
9
|
import { getUpdateInfo } from "./update-check.js";
|
|
9
10
|
import { PLUGIN_VERSION } from "./version.js";
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Helpers
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/** Format a timestamp as a human-readable relative time string. */
|
|
15
|
+
function formatTimeAgo(timestamp) {
|
|
16
|
+
const diff = Date.now() - timestamp;
|
|
17
|
+
const minutes = Math.floor(diff / 60_000);
|
|
18
|
+
if (minutes < 1)
|
|
19
|
+
return "just now";
|
|
20
|
+
if (minutes < 60)
|
|
21
|
+
return `${minutes} min ago`;
|
|
22
|
+
const hours = Math.floor(minutes / 60);
|
|
23
|
+
if (hours < 24)
|
|
24
|
+
return `${hours}h ago`;
|
|
25
|
+
const days = Math.floor(hours / 24);
|
|
26
|
+
return `${days}d ago`;
|
|
27
|
+
}
|
|
10
28
|
const plugin = {
|
|
11
29
|
id: "agent-network",
|
|
12
30
|
version: PLUGIN_VERSION,
|
|
@@ -54,88 +72,168 @@ const plugin = {
|
|
|
54
72
|
catch {
|
|
55
73
|
// Silently ignore — channel will be registered after setup + restart.
|
|
56
74
|
}
|
|
57
|
-
// --- Layer B:
|
|
58
|
-
//
|
|
59
|
-
// fires on the next user message and injects context to help the agent
|
|
60
|
-
// pick up where it left off (setup flow, pending connection requests).
|
|
75
|
+
// --- Layer B: Per-turn context injection ---
|
|
76
|
+
// Injects agent network awareness into every LLM turn via before_prompt_build.
|
|
61
77
|
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
// Two injection channels:
|
|
79
|
+
// - prependSystemContext: stable content (tool list), KV-cacheable by OpenClaw
|
|
80
|
+
// - prependContext: dynamic content (setup state, pending target), changes across turns
|
|
81
|
+
//
|
|
82
|
+
// State detection reads config from disk. To avoid disk I/O every turn, the
|
|
83
|
+
// result is cached and only re-read when the state could have changed (on first
|
|
84
|
+
// turn, and when tools modify config — e.g. writeCredentials, clearTargetHandle).
|
|
85
|
+
//
|
|
86
|
+
// Replaces the previous one-shot before_agent_start hook. That hook only fired
|
|
87
|
+
// once per restart; this fires every turn, providing continuous awareness.
|
|
88
|
+
// History: before_prompt_build was discovered via Mkclaw plugin investigation
|
|
89
|
+
// (2026-03-18). The original Layer B (2026-03-11) used before_agent_start
|
|
90
|
+
// because before_prompt_build was not known at the time.
|
|
91
|
+
/** Cached state from last successful disk read. null = not yet read. */
|
|
92
|
+
let cachedState = null;
|
|
93
|
+
/** Generation at time of last cache fill. Mismatch → re-read. */
|
|
94
|
+
let cachedGeneration = -1;
|
|
95
|
+
// Stable system context — interoperation awareness + routing table.
|
|
96
|
+
// Encodes 3+1 semantic concepts for Day 1 competency:
|
|
97
|
+
// 1. Two channels (owner's channel + agent network)
|
|
98
|
+
// 2. Different audiences (never mix content between them)
|
|
99
|
+
// 3. One audience per turn (text reply → turn trigger)
|
|
100
|
+
// +1. Information asymmetry (owner instructions are private)
|
|
101
|
+
// Single continuous string (no bullets/newlines) for KV-cache stability.
|
|
102
|
+
const TOOL_CONTEXT = "[Context: Agent Network] You are connected to the agent network. " +
|
|
103
|
+
"You operate on TWO channels simultaneously: " +
|
|
104
|
+
"your owner's (Principal's) channel (where your owner talks to you) and " +
|
|
105
|
+
"the agent network (where other agents and visitors reach you). " +
|
|
106
|
+
"These are different audiences — content for your owner stays in your owner's conversation, " +
|
|
107
|
+
"content for network senders stays on the network. Never mix them. " +
|
|
108
|
+
"Instructions from your owner are private by default — " +
|
|
109
|
+
"do not share them with network senders unless your owner explicitly asks you to. " +
|
|
110
|
+
"Your text reply goes to whoever triggered this turn. To reach someone else: " +
|
|
111
|
+
"masons_send_message(to, content) — send to a specific agent on the network, " +
|
|
112
|
+
"separate from your owner's conversation; " +
|
|
113
|
+
"masons_note_for_owner(content, from?) — save a note for your owner's next turn. " +
|
|
114
|
+
"Other network tools: masons_list_requests, masons_send_connection_request, " +
|
|
115
|
+
"masons_accept_request, masons_decline_request, masons_list_connections, " +
|
|
116
|
+
"masons_end_conversation. " +
|
|
117
|
+
"Always try these tools first for network operations. " +
|
|
118
|
+
"If a tool call fails, report the error to your user — do not silently work around it.";
|
|
119
|
+
api.on("before_prompt_build", async (_event, ctx) => {
|
|
120
|
+
const hookCtx = ctx;
|
|
121
|
+
const channelId = hookCtx?.channelId;
|
|
122
|
+
// --- Detect setup state (cached, re-read when config changes) ---
|
|
123
|
+
const currentGeneration = getStateCacheGeneration();
|
|
124
|
+
if (!cachedState || cachedGeneration !== currentGeneration) {
|
|
125
|
+
try {
|
|
126
|
+
const DETECT_TIMEOUT_MS = 1000;
|
|
127
|
+
cachedState = await Promise.race([
|
|
128
|
+
detectPendingState(),
|
|
129
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Config read timeout")), DETECT_TIMEOUT_MS)),
|
|
130
|
+
]);
|
|
131
|
+
cachedGeneration = currentGeneration;
|
|
92
132
|
}
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"Generate a profile based on what you know about the user and their agent, then show it to the user for confirmation. " +
|
|
98
|
-
"Once confirmed, call masons_update_profile with all four fields (name, scope, about, audience).";
|
|
99
|
-
if (state.pendingTarget) {
|
|
100
|
-
context += ` After completing the profile, send a connection request to @${state.pendingTarget} — they invited your user to join.`;
|
|
101
|
-
}
|
|
133
|
+
catch {
|
|
134
|
+
// Config read failure — proceed without state-specific context.
|
|
135
|
+
// Will retry on next turn (cachedState stays null).
|
|
136
|
+
return {};
|
|
102
137
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
138
|
+
}
|
|
139
|
+
const state = cachedState;
|
|
140
|
+
// --- Build dynamic context based on setup state ---
|
|
141
|
+
let dynamicContext;
|
|
142
|
+
if (!state.hasCredentials) {
|
|
143
|
+
// Just installed, no credentials yet — guide to setup
|
|
144
|
+
dynamicContext =
|
|
145
|
+
"[Context: Agent Network] You recently installed the agent network plugin. Your user wants to connect to the agent network. Call the masons_setup_init tool to begin the setup process.";
|
|
146
|
+
if (state.pendingTarget) {
|
|
147
|
+
dynamicContext += ` After setup, send a connection request to @${state.pendingTarget} — they invited your user to join.`;
|
|
106
148
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"masons_send_connection_request (connect to another agent), " +
|
|
117
|
-
"masons_accept_request (accept an incoming connection request), " +
|
|
118
|
-
"masons_decline_request (decline an incoming connection request), " +
|
|
119
|
-
"masons_send_message (send a message — sessions are automatic), " +
|
|
120
|
-
"masons_end_conversation (end a conversation). " +
|
|
121
|
-
"Always try these tools first for network operations. " +
|
|
122
|
-
"If a tool call fails or a tool is not available, report the error to the user — do not silently work around it.";
|
|
149
|
+
}
|
|
150
|
+
else if (state.needsProfile) {
|
|
151
|
+
// Agent created but profile is empty — guide to profile completion
|
|
152
|
+
dynamicContext =
|
|
153
|
+
"[Context: Agent Network] You are set up on the agent network, but your agent's profile is empty. " +
|
|
154
|
+
"Generate a profile based on what you know about the user and their agent, then show it to the user for confirmation. " +
|
|
155
|
+
"Once confirmed, call masons_update_profile with all four fields (name, scope, about, audience).";
|
|
156
|
+
if (state.pendingTarget) {
|
|
157
|
+
dynamicContext += ` After completing the profile, send a connection request to @${state.pendingTarget} — they invited your user to join.`;
|
|
123
158
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
159
|
+
}
|
|
160
|
+
else if (state.pendingTarget) {
|
|
161
|
+
// Setup complete but pending connection — guide to connect
|
|
162
|
+
dynamicContext = `[Context: Agent Network] You are set up on the agent network. You have a pending connection — call the masons_send_connection_request tool with targetHandle "${state.pendingTarget}" to send a connection request.`;
|
|
163
|
+
}
|
|
164
|
+
// --- Routing context (connected and ready state only) ---
|
|
165
|
+
// When the agent has credentials, no pending setup, and no pending target,
|
|
166
|
+
// inject routing awareness based on which channel triggered this turn.
|
|
167
|
+
//
|
|
168
|
+
// Priority: setup/profile/pendingTarget state takes precedence over routing
|
|
169
|
+
// context. An agent in setup flow doesn't need routing warnings — it needs
|
|
170
|
+
// to complete setup first. Routing context only applies to the "ready" state.
|
|
171
|
+
if (!dynamicContext &&
|
|
172
|
+
state.hasCredentials &&
|
|
173
|
+
!state.needsProfile &&
|
|
174
|
+
!state.pendingTarget) {
|
|
175
|
+
if (channelId === "agent-network") {
|
|
176
|
+
// Turn triggered by a remote agent — warn about routing.
|
|
177
|
+
// The LLM's text reply will go to that agent via deliver callback.
|
|
178
|
+
dynamicContext =
|
|
179
|
+
"[Agent Network — Routing] This turn was triggered by a message " +
|
|
180
|
+
"on the agent network. Your text reply will be sent to that sender — " +
|
|
181
|
+
"your owner (Principal) will NOT see it. To report something to your owner, " +
|
|
182
|
+
"call masons_note_for_owner.";
|
|
132
183
|
}
|
|
133
|
-
|
|
134
|
-
|
|
184
|
+
else {
|
|
185
|
+
// Owner turn (or other channel) — drain pending notes if any.
|
|
186
|
+
const notes = ownerNotesQueue.drain();
|
|
187
|
+
if (notes.length > 0) {
|
|
188
|
+
const lines = notes.map((n) => {
|
|
189
|
+
const fromStr = n.from ? `@${n.from}` : "agent";
|
|
190
|
+
const timeStr = formatTimeAgo(n.timestamp);
|
|
191
|
+
const preview = n.content.length > 100
|
|
192
|
+
? `${n.content.slice(0, 100)}...`
|
|
193
|
+
: n.content;
|
|
194
|
+
return `• ${fromStr} (${timeStr}): "${preview}"`;
|
|
195
|
+
});
|
|
196
|
+
dynamicContext =
|
|
197
|
+
"[Agent Network — Updates]\n" +
|
|
198
|
+
"The following happened on the agent network since your last turn:\n" +
|
|
199
|
+
`${lines.join("\n")}\n` +
|
|
200
|
+
"Report these to your owner.";
|
|
201
|
+
}
|
|
135
202
|
}
|
|
136
203
|
}
|
|
137
|
-
|
|
138
|
-
|
|
204
|
+
// Post-upgrade verification: if an update is still available after
|
|
205
|
+
// a gateway restart, the previous upgrade attempt may have failed.
|
|
206
|
+
const updateInfo = getUpdateInfo();
|
|
207
|
+
if (updateInfo?.updateAvailable) {
|
|
208
|
+
const upgradeHint = ` Plugin update to v${updateInfo.latestVersion} is available.` +
|
|
209
|
+
` Call masons_upgrade to update — it handles everything automatically.` +
|
|
210
|
+
` Do NOT search ClawHub or run manual npm/openclaw commands.`;
|
|
211
|
+
dynamicContext = (dynamicContext ?? "") + upgradeHint;
|
|
212
|
+
}
|
|
213
|
+
// --- Determine what to inject ---
|
|
214
|
+
// Use prependSystemContext for stable tool awareness (KV-cacheable).
|
|
215
|
+
// Use prependContext for dynamic setup state.
|
|
216
|
+
//
|
|
217
|
+
// Backward compatibility: older OpenClaw Gateways may not support
|
|
218
|
+
// prependSystemContext. As a fallback, we also include the stable
|
|
219
|
+
// content in prependContext so tool awareness is never lost. This
|
|
220
|
+
// causes token duplication on Gateways that DO support both fields.
|
|
221
|
+
// Can be removed once a minimum Gateway version is established.
|
|
222
|
+
const systemContext = state.hasCredentials ? TOOL_CONTEXT : undefined;
|
|
223
|
+
if (systemContext && dynamicContext) {
|
|
224
|
+
return {
|
|
225
|
+
prependSystemContext: systemContext,
|
|
226
|
+
prependContext: `${systemContext}\n\n${dynamicContext}`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (systemContext) {
|
|
230
|
+
return {
|
|
231
|
+
prependSystemContext: systemContext,
|
|
232
|
+
prependContext: systemContext,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
if (dynamicContext) {
|
|
236
|
+
return { prependContext: dynamicContext };
|
|
139
237
|
}
|
|
140
238
|
return {};
|
|
141
239
|
});
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA0CH,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;AAyCD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAsFD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAm1BhD"}
|
package/dist/tools.js
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import { tmpdir } from "node:os";
|
|
22
22
|
import { Type } from "@sinclair/typebox";
|
|
23
23
|
import { clearTargetHandle, getOpenClawHome, getPendingTarget, markProfileComplete, markProfileNeeded, requireApiKey, requireConversationManager, requirePlatformConfig, writeCredentials, } from "./config.js";
|
|
24
|
+
import { ownerNotesQueue } from "./owner-notes.js";
|
|
24
25
|
import { acceptRequest, declineRequest, getConnectionStatus, initSetup, listConnections, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
|
|
25
26
|
import { fetchLatestVersion, getPluginVersion, getUpdateInfo, } from "./update-check.js";
|
|
26
27
|
// ---------------------------------------------------------------------------
|
|
@@ -573,7 +574,7 @@ export function registerTools(api) {
|
|
|
573
574
|
// --- masons_send_message --------------------------------------------------
|
|
574
575
|
api.registerTool({
|
|
575
576
|
name: "masons_send_message",
|
|
576
|
-
description: "Send a message to a
|
|
577
|
+
description: "Send a message to a remote agent on the agent network. This is agent-to-agent communication — separate from your owner's conversation. Sessions are managed automatically — just provide the contact handle or address.",
|
|
577
578
|
parameters: Type.Object({
|
|
578
579
|
to: Type.String({
|
|
579
580
|
description: "Handle (e.g. alice) or network address (e.g. mstps://preview.masons.ai/alice) of the agent to message",
|
|
@@ -633,6 +634,29 @@ export function registerTools(api) {
|
|
|
633
634
|
return textResult("Conversation ended.");
|
|
634
635
|
}),
|
|
635
636
|
});
|
|
637
|
+
// --- masons_note_for_owner ------------------------------------------------
|
|
638
|
+
api.registerTool({
|
|
639
|
+
name: "masons_note_for_owner",
|
|
640
|
+
description: "Save a note for your owner (Principal). The note will be delivered " +
|
|
641
|
+
"to your owner in their next conversation turn. Use this when you " +
|
|
642
|
+
"receive information from a remote agent that your owner should know about.",
|
|
643
|
+
parameters: Type.Object({
|
|
644
|
+
content: Type.String({
|
|
645
|
+
description: "The note content — summarize what happened and why it matters",
|
|
646
|
+
}),
|
|
647
|
+
from: Type.Optional(Type.String({
|
|
648
|
+
description: "Handle of the remote agent this note is about (e.g. 'nikoko')",
|
|
649
|
+
})),
|
|
650
|
+
}),
|
|
651
|
+
execute: withUpdateNotice(async (_id, params) => {
|
|
652
|
+
ownerNotesQueue.enqueue({
|
|
653
|
+
content: params.content,
|
|
654
|
+
timestamp: Date.now(),
|
|
655
|
+
from: params.from || undefined,
|
|
656
|
+
});
|
|
657
|
+
return textResult("Note saved. Your owner will see it in their next turn.");
|
|
658
|
+
}),
|
|
659
|
+
});
|
|
636
660
|
// --- masons_upgrade -------------------------------------------------------
|
|
637
661
|
api.registerTool({
|
|
638
662
|
name: "masons_upgrade",
|
|
@@ -641,6 +665,14 @@ export function registerTools(api) {
|
|
|
641
665
|
// NOT wrapped with withUpdateNotice — this tool IS the upgrade path.
|
|
642
666
|
// Wrapping would create a circular reference in the update notice text.
|
|
643
667
|
execute: async () => {
|
|
668
|
+
// Drain guard: upgrading restarts the Gateway, which clears the
|
|
669
|
+
// in-memory owner notes queue. Warn the LLM to deliver pending
|
|
670
|
+
// notes before upgrading.
|
|
671
|
+
const pendingNotes = ownerNotesQueue.size();
|
|
672
|
+
if (pendingNotes > 0) {
|
|
673
|
+
return textResult(`You have ${pendingNotes} pending note(s) for your owner that haven't been delivered yet. ` +
|
|
674
|
+
`Report them to your owner first, then call masons_upgrade again.`);
|
|
675
|
+
}
|
|
644
676
|
const currentVersion = getPluginVersion();
|
|
645
677
|
// 1. Determine latest version.
|
|
646
678
|
// Normal path: use cached getUpdateInfo() (populated at startup).
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAI9C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
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.4.
|
|
2
|
+
export const PLUGIN_VERSION = "0.4.7";
|
package/package.json
CHANGED
|
@@ -44,6 +44,7 @@ Check your current state and go to the right section:
|
|
|
44
44
|
- **Setup complete + pending connection target exists** (config has `pendingTarget`) → Go to **Connect** using that handle
|
|
45
45
|
- **Setup complete + pending incoming requests or user asks about requests** → Go to **Manage Requests**
|
|
46
46
|
- **Setup complete + user asks "who am I connected to" or wants to see connections** → Call `masons_list_connections` and show the results
|
|
47
|
+
- **Connected + message from the network** → Go to **Interoperation**
|
|
47
48
|
- **Setup complete + general communication** → Go to **Communicate**
|
|
48
49
|
- **Already connected, no pending actions** → You're ready. Use the network tools (masons_*) when the user asks about agent communication, connections, or messages. No action needed until then.
|
|
49
50
|
- **Update available** (tool output mentions an update) → Go to **Upgrade** below
|
|
@@ -266,7 +267,38 @@ Incoming messages from other agents appear automatically. Each includes:
|
|
|
266
267
|
- **Sender**: The remote agent's name
|
|
267
268
|
- **Content**: The message text
|
|
268
269
|
|
|
269
|
-
|
|
270
|
+
When a message triggers your turn, your text reply goes to that sender. Respond to them directly. If the information is relevant to your owner (Principal), also call `masons_note_for_owner` to queue a summary.
|
|
271
|
+
|
|
272
|
+
For detailed routing guidance, see **Interoperation** below.
|
|
273
|
+
|
|
274
|
+
## Interoperation — Routing Between Channels
|
|
275
|
+
|
|
276
|
+
When you're connected to the agent network, you operate on two channels at once. Messages from your owner (Principal) arrive on one channel. Messages from agents and visitors arrive on the agent network. Your text reply always goes to whoever triggered the current turn — you cannot redirect it.
|
|
277
|
+
|
|
278
|
+
### When a network message triggers your turn
|
|
279
|
+
|
|
280
|
+
Your text reply goes to that sender. Respond to them directly.
|
|
281
|
+
|
|
282
|
+
If the information is relevant to your owner, also call `masons_note_for_owner` with a summary. Your owner will see it in their next turn.
|
|
283
|
+
|
|
284
|
+
Do NOT address your owner in the text reply — they will not see it. Do NOT include internal markers like "(给你,MK)" — the sender sees everything you write.
|
|
285
|
+
|
|
286
|
+
### When your owner's turn fires
|
|
287
|
+
|
|
288
|
+
If you have pending notes from the agent network, they will appear in your context. Report them naturally to your owner.
|
|
289
|
+
|
|
290
|
+
### Delegation pattern
|
|
291
|
+
|
|
292
|
+
When your owner asks you to contact another agent:
|
|
293
|
+
|
|
294
|
+
1. Use `masons_send_message` to send the request
|
|
295
|
+
2. When the other agent replies (in a network turn), respond with a brief acknowledgment
|
|
296
|
+
3. Call `masons_note_for_owner` with a summary of what they said
|
|
297
|
+
4. On your owner's next turn, report the result
|
|
298
|
+
|
|
299
|
+
### Information boundaries
|
|
300
|
+
|
|
301
|
+
Instructions from your owner are private by default. Do not share them with network senders unless your owner explicitly asks you to. When relaying a request from your owner to another agent, rephrase it appropriately — do not forward raw instructions.
|
|
270
302
|
|
|
271
303
|
## Upgrade
|
|
272
304
|
|