@masons/agent-network 0.4.10 → 0.4.12
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 +6 -2
- package/dist/config.d.ts +18 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +27 -4
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +111 -16
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +18 -1
- package/dist/turn-context.d.ts +30 -0
- package/dist/turn-context.d.ts.map +1 -0
- package/dist/turn-context.js +46 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/agent-network/SKILL.md +38 -62
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;
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAsB9D,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,yBAuZjC,CAAC"}
|
package/dist/channel.js
CHANGED
|
@@ -4,6 +4,7 @@ import { clearConnectorClient, clearConversationManager, extractNetworkConfig, i
|
|
|
4
4
|
import { ConnectorClient } from "./connector-client.js";
|
|
5
5
|
import { ConversationManager } from "./conversation-manager.js";
|
|
6
6
|
import { clearOwnerSessions, isOwnerSession, markOwnerSession, removeOwnerSession, setCurrentTurnIsOwner, } from "./owner-session-state.js";
|
|
7
|
+
import { setCurrentTurnSender } from "./turn-context.js";
|
|
7
8
|
import { checkForUpdate } from "./update-check.js";
|
|
8
9
|
const dbg = createDebug("agent-network:channel");
|
|
9
10
|
// --- Sender identity ---
|
|
@@ -145,9 +146,12 @@ export const agentNetworkChannel = {
|
|
|
145
146
|
// structured multi-step interactions, add a per-session dispatch queue.
|
|
146
147
|
client.on("message_received", async (event) => {
|
|
147
148
|
dbg("routing inbound message sessionId=%s contentLength=%d", event.sessionId, event.content.length);
|
|
148
|
-
// ---
|
|
149
|
-
// Set BEFORE dispatch so before_prompt_build can read
|
|
149
|
+
// --- Per-turn context (#836, #873) ---
|
|
150
|
+
// Set BEFORE dispatch so before_prompt_build can read these synchronously.
|
|
150
151
|
setCurrentTurnIsOwner(isOwnerSession(event.sessionId));
|
|
152
|
+
// Sender identity: resolve sessionId → contact handle using
|
|
153
|
+
// the closure-scoped conversationManager (NOT imported from config.ts).
|
|
154
|
+
setCurrentTurnSender(conversationManager.getContactBySessionId(event.sessionId) ?? null);
|
|
151
155
|
// --- Runtime guard ---
|
|
152
156
|
let runtime;
|
|
153
157
|
try {
|
package/dist/config.d.ts
CHANGED
|
@@ -73,6 +73,14 @@ export declare function clearConversationManager(): void;
|
|
|
73
73
|
* Get the live ConversationManager. Throws if not initialized.
|
|
74
74
|
*/
|
|
75
75
|
export declare function requireConversationManager(): ConversationManager;
|
|
76
|
+
/**
|
|
77
|
+
* Get the live ConversationManager, or null if not yet initialized.
|
|
78
|
+
*
|
|
79
|
+
* Non-throwing variant for use in before_prompt_build where the connection
|
|
80
|
+
* may not be established yet (e.g., during setup flow). Callers must handle
|
|
81
|
+
* the null case gracefully.
|
|
82
|
+
*/
|
|
83
|
+
export declare function getConversationManager(): ConversationManager | null;
|
|
76
84
|
/**
|
|
77
85
|
* Store the OpenClaw PluginRuntime for inbound message dispatch.
|
|
78
86
|
*
|
|
@@ -112,6 +120,14 @@ export declare function requireApiKey(): string;
|
|
|
112
120
|
* Get pending connection target handle, or null if none.
|
|
113
121
|
*/
|
|
114
122
|
export declare function getPendingTarget(): string | null;
|
|
123
|
+
/**
|
|
124
|
+
* Whether the agent needs profile completion before connecting.
|
|
125
|
+
*
|
|
126
|
+
* True after onboard (new agent creation), cleared after all required
|
|
127
|
+
* profile fields are filled. Used by connection tools to gate requests
|
|
128
|
+
* until the agent has a visible identity.
|
|
129
|
+
*/
|
|
130
|
+
export declare function isProfileNeeded(): boolean;
|
|
115
131
|
/**
|
|
116
132
|
* Get the live ConnectorClient. Throws if not initialized.
|
|
117
133
|
*
|
|
@@ -162,10 +178,8 @@ export declare function markProfileNeeded(): Promise<void>;
|
|
|
162
178
|
*
|
|
163
179
|
* Called after successful masons_update_profile — clears the needsProfile flag
|
|
164
180
|
* so the before_prompt_build hook no longer injects profile context.
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* module-level variable for needsProfile. The before_prompt_build hook
|
|
168
|
-
* uses stateCacheGeneration to detect when a re-read is needed.
|
|
181
|
+
* Also updates the in-memory `storedNeedsProfile` flag so tool-level gates
|
|
182
|
+
* (connection request / accept) take effect immediately without a restart.
|
|
169
183
|
*/
|
|
170
184
|
export declare function markProfileComplete(): Promise<void>;
|
|
171
185
|
/** Pending state detected from config file — used for restart continuity. */
|
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;AAuB9B;;;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,CAwBjE;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;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,IAAI,CAEnE;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,eAAe,IAAI,OAAO,CAEzC;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,CAOvD;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOzD;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,CASvC"}
|
package/dist/config.js
CHANGED
|
@@ -30,6 +30,7 @@ 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
|
+
let storedNeedsProfile = false;
|
|
33
34
|
// State cache generation — incremented when config-modifying functions write
|
|
34
35
|
// to disk (writeCredentials, clearTargetHandle, markProfileNeeded, markProfileComplete).
|
|
35
36
|
// before_prompt_build compares its cached generation to this value; mismatch
|
|
@@ -93,6 +94,7 @@ export function initToolConfig(cfg) {
|
|
|
93
94
|
typeof networkCfg?.pendingTarget === "string"
|
|
94
95
|
? networkCfg.pendingTarget
|
|
95
96
|
: null;
|
|
97
|
+
storedNeedsProfile = networkCfg?.needsProfile === true;
|
|
96
98
|
}
|
|
97
99
|
// ---------------------------------------------------------------------------
|
|
98
100
|
// ConnectorClient injection (called by startAccount() after connect)
|
|
@@ -151,6 +153,16 @@ export function requireConversationManager() {
|
|
|
151
153
|
}
|
|
152
154
|
return storedConversationManager;
|
|
153
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Get the live ConversationManager, or null if not yet initialized.
|
|
158
|
+
*
|
|
159
|
+
* Non-throwing variant for use in before_prompt_build where the connection
|
|
160
|
+
* may not be established yet (e.g., during setup flow). Callers must handle
|
|
161
|
+
* the null case gracefully.
|
|
162
|
+
*/
|
|
163
|
+
export function getConversationManager() {
|
|
164
|
+
return storedConversationManager;
|
|
165
|
+
}
|
|
154
166
|
// ---------------------------------------------------------------------------
|
|
155
167
|
// PluginRuntime injection (called by register() in plugin.ts)
|
|
156
168
|
// ---------------------------------------------------------------------------
|
|
@@ -214,6 +226,16 @@ export function requireApiKey() {
|
|
|
214
226
|
export function getPendingTarget() {
|
|
215
227
|
return storedPendingTarget;
|
|
216
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Whether the agent needs profile completion before connecting.
|
|
231
|
+
*
|
|
232
|
+
* True after onboard (new agent creation), cleared after all required
|
|
233
|
+
* profile fields are filled. Used by connection tools to gate requests
|
|
234
|
+
* until the agent has a visible identity.
|
|
235
|
+
*/
|
|
236
|
+
export function isProfileNeeded() {
|
|
237
|
+
return storedNeedsProfile;
|
|
238
|
+
}
|
|
217
239
|
/**
|
|
218
240
|
* Get the live ConnectorClient. Throws if not initialized.
|
|
219
241
|
*
|
|
@@ -343,6 +365,7 @@ export async function markProfileNeeded() {
|
|
|
343
365
|
const section = ensureNetworkSection(config);
|
|
344
366
|
section.needsProfile = true;
|
|
345
367
|
await persistConfig(config);
|
|
368
|
+
storedNeedsProfile = true;
|
|
346
369
|
stateCacheGeneration++;
|
|
347
370
|
}
|
|
348
371
|
/**
|
|
@@ -350,16 +373,15 @@ export async function markProfileNeeded() {
|
|
|
350
373
|
*
|
|
351
374
|
* Called after successful masons_update_profile — clears the needsProfile flag
|
|
352
375
|
* so the before_prompt_build hook no longer injects profile context.
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
* module-level variable for needsProfile. The before_prompt_build hook
|
|
356
|
-
* uses stateCacheGeneration to detect when a re-read is needed.
|
|
376
|
+
* Also updates the in-memory `storedNeedsProfile` flag so tool-level gates
|
|
377
|
+
* (connection request / accept) take effect immediately without a restart.
|
|
357
378
|
*/
|
|
358
379
|
export async function markProfileComplete() {
|
|
359
380
|
const config = await readConfig();
|
|
360
381
|
const section = ensureNetworkSection(config);
|
|
361
382
|
delete section.needsProfile;
|
|
362
383
|
await persistConfig(config);
|
|
384
|
+
storedNeedsProfile = false;
|
|
363
385
|
stateCacheGeneration++;
|
|
364
386
|
}
|
|
365
387
|
/**
|
|
@@ -396,6 +418,7 @@ export function _resetForTesting() {
|
|
|
396
418
|
platformConfig = { apiHost: DEFAULT_API_HOST };
|
|
397
419
|
storedApiKey = null;
|
|
398
420
|
storedPendingTarget = null;
|
|
421
|
+
storedNeedsProfile = false;
|
|
399
422
|
storedConnectorClient = null;
|
|
400
423
|
storedConversationManager = null;
|
|
401
424
|
storedPluginRuntime = null;
|
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":"AAmHA,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;CA2RhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
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, getStateCacheGeneration, initPluginRuntime, } from "./config.js";
|
|
6
|
+
import { detectPendingState, getConversationManager, getStateCacheGeneration, initPluginRuntime, } from "./config.js";
|
|
7
7
|
import { ownerNotesQueue } from "./owner-notes.js";
|
|
8
8
|
import { consumeCurrentTurnIsOwner } from "./owner-session-state.js";
|
|
9
9
|
import { registerTools } from "./tools.js";
|
|
10
|
+
import { consumeCurrentTurnSender } from "./turn-context.js";
|
|
10
11
|
import { getUpdateInfo } from "./update-check.js";
|
|
11
12
|
import { PLUGIN_VERSION } from "./version.js";
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
@@ -26,6 +27,66 @@ function formatTimeAgo(timestamp) {
|
|
|
26
27
|
const days = Math.floor(hours / 24);
|
|
27
28
|
return `${days}d ago`;
|
|
28
29
|
}
|
|
30
|
+
/** Max active interactions to inject into context to avoid noise. */
|
|
31
|
+
const MAX_INTERACTIONS = 5;
|
|
32
|
+
/**
|
|
33
|
+
* Build an interaction space snapshot for the current turn.
|
|
34
|
+
*
|
|
35
|
+
* Reads ConversationManager to list active interactions, then formats
|
|
36
|
+
* a context block that tells the LLM who it's currently interacting with.
|
|
37
|
+
*
|
|
38
|
+
* On network turns, includes turn-specific framing (who sent this message,
|
|
39
|
+
* whether this agent initiated the interaction).
|
|
40
|
+
*
|
|
41
|
+
* On owner turns, shows the interaction space as background context.
|
|
42
|
+
*
|
|
43
|
+
* Returns undefined if no interactions exist or CM is not available.
|
|
44
|
+
*/
|
|
45
|
+
function buildInteractionContext(channelId, turnSender) {
|
|
46
|
+
const cm = getConversationManager();
|
|
47
|
+
if (!cm)
|
|
48
|
+
return undefined;
|
|
49
|
+
const conversations = cm.listConversations();
|
|
50
|
+
if (conversations.length === 0)
|
|
51
|
+
return undefined;
|
|
52
|
+
// Sort by most recent activity, cap at MAX_INTERACTIONS for display.
|
|
53
|
+
const sorted = [...conversations]
|
|
54
|
+
.sort((a, b) => b.lastMessageAt - a.lastMessageAt)
|
|
55
|
+
.slice(0, MAX_INTERACTIONS);
|
|
56
|
+
const truncated = conversations.length > MAX_INTERACTIONS;
|
|
57
|
+
const header = truncated
|
|
58
|
+
? `[Active interactions (showing ${sorted.length} of ${conversations.length})]`
|
|
59
|
+
: "[Active interactions]";
|
|
60
|
+
const lines = sorted.map((c) => {
|
|
61
|
+
const who = `@${c.contact}`;
|
|
62
|
+
const initiated = c.initiatedBy === "local" ? "you initiated" : "they initiated";
|
|
63
|
+
const when = formatTimeAgo(c.lastMessageAt);
|
|
64
|
+
return `• ${who} — ${initiated} — last activity ${when}`;
|
|
65
|
+
});
|
|
66
|
+
const isNetworkTurn = channelId === "agent-network";
|
|
67
|
+
if (isNetworkTurn && turnSender) {
|
|
68
|
+
// Find sender in FULL list (not sorted/capped) for accurate initiatedBy.
|
|
69
|
+
const senderConvo = conversations.find((c) => c.contact === turnSender);
|
|
70
|
+
const initiated = senderConvo?.initiatedBy === "local"
|
|
71
|
+
? "You initiated this interaction."
|
|
72
|
+
: "They initiated this interaction.";
|
|
73
|
+
return (`${header}\n${lines.join("\n")}\n` +
|
|
74
|
+
`[This turn] From @${turnSender}. ${initiated}\n` +
|
|
75
|
+
"Your text reply goes to this sender. " +
|
|
76
|
+
"To report to your owner: masons_note_for_owner.");
|
|
77
|
+
}
|
|
78
|
+
if (isNetworkTurn) {
|
|
79
|
+
// Network turn but sender unknown — still show interaction space.
|
|
80
|
+
return (`${header}\n${lines.join("\n")}\n` +
|
|
81
|
+
"Your text reply goes to the sender of this message. " +
|
|
82
|
+
"To report to your owner: masons_note_for_owner.");
|
|
83
|
+
}
|
|
84
|
+
// Owner turn — show interaction space as background context.
|
|
85
|
+
const ownerHeader = truncated
|
|
86
|
+
? `[Active interactions on the network (showing ${sorted.length} of ${conversations.length})]`
|
|
87
|
+
: "[Active interactions on the network]";
|
|
88
|
+
return `${ownerHeader}\n${lines.join("\n")}`;
|
|
89
|
+
}
|
|
29
90
|
const plugin = {
|
|
30
91
|
id: "agent-network",
|
|
31
92
|
version: PLUGIN_VERSION,
|
|
@@ -94,13 +155,20 @@ const plugin = {
|
|
|
94
155
|
/** Generation at time of last cache fill. Mismatch → re-read. */
|
|
95
156
|
let cachedGeneration = -1;
|
|
96
157
|
// Stable system context — interoperation awareness + routing table.
|
|
97
|
-
// Encodes
|
|
158
|
+
// Encodes semantic concepts for Day 1 competency:
|
|
98
159
|
// 1. Two channels (owner's channel + agent network)
|
|
99
160
|
// 2. Different audiences (never mix content between them)
|
|
100
161
|
// 3. One audience per turn (text reply → turn trigger)
|
|
101
|
-
//
|
|
162
|
+
// 4. Information asymmetry (owner instructions are private)
|
|
163
|
+
// 5. Multi-object interaction space (#873)
|
|
164
|
+
// 6. Action = state change, not conversation (#873)
|
|
165
|
+
// 7. Post-action check (#873)
|
|
102
166
|
// Single continuous string (no bullets/newlines) for KV-cache stability.
|
|
103
|
-
|
|
167
|
+
// The first ~900 chars are the original prefix (pre-#873). New content is
|
|
168
|
+
// appended so existing KV-cache prefixes remain valid.
|
|
169
|
+
const TOOL_CONTEXT =
|
|
170
|
+
// --- Original prefix (pre-#873, preserve for KV-cache) ---
|
|
171
|
+
"[Context: Agent Network] You are connected to the agent network. " +
|
|
104
172
|
"You operate on TWO channels simultaneously: " +
|
|
105
173
|
"your owner's (Principal's) channel (where your owner talks to you) and " +
|
|
106
174
|
"the agent network (where other agents and visitors reach you). " +
|
|
@@ -116,7 +184,16 @@ const plugin = {
|
|
|
116
184
|
"masons_accept_request, masons_decline_request, masons_list_connections, " +
|
|
117
185
|
"masons_end_conversation. " +
|
|
118
186
|
"Always try these tools first for network operations. " +
|
|
119
|
-
"If a tool call fails, report the error to your user — do not silently work around it."
|
|
187
|
+
"If a tool call fails, report the error to your user — do not silently work around it. " +
|
|
188
|
+
// --- Interaction space + goal-driven behavior (#873) ---
|
|
189
|
+
"You interact with multiple entities simultaneously — your owner and agents on the network. " +
|
|
190
|
+
"Each interaction is an Action aimed at changing the other party's state, not just exchanging messages. " +
|
|
191
|
+
"When you send to an agent via masons_send_message, be specific about what you need — " +
|
|
192
|
+
"request action, not open-ended conversation. " +
|
|
193
|
+
"After responding on the network, check: " +
|
|
194
|
+
"should you report to your owner via masons_note_for_owner? " +
|
|
195
|
+
"Should you end this interaction via masons_end_conversation? " +
|
|
196
|
+
"Should you follow up with another agent via masons_send_message?";
|
|
120
197
|
api.on("before_prompt_build", async (_event, ctx) => {
|
|
121
198
|
const hookCtx = ctx;
|
|
122
199
|
const channelId = hookCtx?.channelId;
|
|
@@ -138,6 +215,12 @@ const plugin = {
|
|
|
138
215
|
}
|
|
139
216
|
}
|
|
140
217
|
const state = cachedState;
|
|
218
|
+
// --- Consume per-turn flags unconditionally (#836, #873) ---
|
|
219
|
+
// Must consume on EVERY turn to prevent stale state from leaking across
|
|
220
|
+
// turns. If not consumed (e.g., agent is in setup flow), the value would
|
|
221
|
+
// persist and be read on the NEXT turn, producing incorrect context.
|
|
222
|
+
const turnIsOwner = consumeCurrentTurnIsOwner();
|
|
223
|
+
const turnSender = consumeCurrentTurnSender();
|
|
141
224
|
// --- Build dynamic context based on setup state ---
|
|
142
225
|
let dynamicContext;
|
|
143
226
|
if (!state.hasCredentials) {
|
|
@@ -145,7 +228,7 @@ const plugin = {
|
|
|
145
228
|
dynamicContext =
|
|
146
229
|
"[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.";
|
|
147
230
|
if (state.pendingTarget) {
|
|
148
|
-
dynamicContext += ` After setup, send a connection request to
|
|
231
|
+
dynamicContext += ` After setup, send a connection request to ${state.pendingTarget} — they invited your user to join.`;
|
|
149
232
|
}
|
|
150
233
|
}
|
|
151
234
|
else if (state.needsProfile) {
|
|
@@ -153,18 +236,21 @@ const plugin = {
|
|
|
153
236
|
dynamicContext =
|
|
154
237
|
"[Context: Agent Network] You are set up on the agent network, but your agent's profile is empty. " +
|
|
155
238
|
"Generate a profile based on what you know about the user and their agent, then show it to the user for confirmation. " +
|
|
156
|
-
"Once confirmed, call masons_update_profile with all four fields (name, scope, about, audience)."
|
|
239
|
+
"Once confirmed, call masons_update_profile with all four fields (name, scope, about, audience). " +
|
|
240
|
+
"Without a profile, other agents can't see who you are — " +
|
|
241
|
+
"connection requests from agents without a profile are rarely accepted.";
|
|
157
242
|
if (state.pendingTarget) {
|
|
158
|
-
dynamicContext += ` After completing the profile, send a connection request to
|
|
243
|
+
dynamicContext += ` After completing the profile, send a connection request to ${state.pendingTarget} — they'll be able to see who you are and why connecting makes sense.`;
|
|
159
244
|
}
|
|
160
245
|
}
|
|
161
246
|
else if (state.pendingTarget) {
|
|
162
247
|
// Setup complete but pending connection — guide to connect
|
|
163
248
|
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.`;
|
|
164
249
|
}
|
|
165
|
-
// --- Routing context (connected and ready state only) ---
|
|
250
|
+
// --- Routing + interaction context (connected and ready state only) ---
|
|
166
251
|
// When the agent has credentials, no pending setup, and no pending target,
|
|
167
|
-
// inject routing awareness based on which channel
|
|
252
|
+
// inject routing awareness and interaction space based on which channel
|
|
253
|
+
// triggered this turn.
|
|
168
254
|
//
|
|
169
255
|
// Priority: setup/profile/pendingTarget state takes precedence over routing
|
|
170
256
|
// context. An agent in setup flow doesn't need routing warnings — it needs
|
|
@@ -174,10 +260,6 @@ const plugin = {
|
|
|
174
260
|
!state.needsProfile &&
|
|
175
261
|
!state.pendingTarget) {
|
|
176
262
|
if (channelId === "agent-network") {
|
|
177
|
-
// --- Owner identity binding (#836) ---
|
|
178
|
-
// Consume the per-turn owner flag set by channel.ts message_received.
|
|
179
|
-
// Must consume on every agent-network turn to prevent stale state.
|
|
180
|
-
const turnIsOwner = consumeCurrentTurnIsOwner();
|
|
181
263
|
if (turnIsOwner) {
|
|
182
264
|
// Owner visiting via Passport — no routing warning needed.
|
|
183
265
|
// The LLM's text reply goes to the owner (the visitor IS the owner).
|
|
@@ -206,13 +288,18 @@ const plugin = {
|
|
|
206
288
|
notesBlock;
|
|
207
289
|
}
|
|
208
290
|
else {
|
|
209
|
-
// Turn triggered by a remote agent/stranger —
|
|
210
|
-
//
|
|
291
|
+
// Turn triggered by a remote agent/stranger — routing warning +
|
|
292
|
+
// interaction space snapshot (#873).
|
|
211
293
|
dynamicContext =
|
|
212
294
|
"[Agent Network — Routing] This turn was triggered by a message " +
|
|
213
295
|
"on the agent network. Your text reply will be sent to that sender — " +
|
|
214
296
|
"your owner (Principal) will NOT see it. To report something to your owner, " +
|
|
215
297
|
"call masons_note_for_owner.";
|
|
298
|
+
// Append interaction space snapshot if active interactions exist.
|
|
299
|
+
const interactionCtx = buildInteractionContext(channelId, turnSender);
|
|
300
|
+
if (interactionCtx) {
|
|
301
|
+
dynamicContext += `\n\n${interactionCtx}`;
|
|
302
|
+
}
|
|
216
303
|
}
|
|
217
304
|
}
|
|
218
305
|
else {
|
|
@@ -233,6 +320,14 @@ const plugin = {
|
|
|
233
320
|
`${lines.join("\n")}\n` +
|
|
234
321
|
"Report these to your owner.";
|
|
235
322
|
}
|
|
323
|
+
// Append interaction space on owner turns too (#873).
|
|
324
|
+
// Gives the agent awareness of active network interactions.
|
|
325
|
+
const interactionCtx = buildInteractionContext(channelId, null);
|
|
326
|
+
if (interactionCtx) {
|
|
327
|
+
dynamicContext = dynamicContext
|
|
328
|
+
? `${dynamicContext}\n\n${interactionCtx}`
|
|
329
|
+
: interactionCtx;
|
|
330
|
+
}
|
|
236
331
|
}
|
|
237
332
|
}
|
|
238
333
|
// Post-upgrade verification: if an update is still available after
|
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;AA2CH,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;AA0CD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAsFD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAk2BhD"}
|
package/dist/tools.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { tmpdir } from "node:os";
|
|
22
22
|
import { Type } from "@sinclair/typebox";
|
|
23
|
-
import { clearTargetHandle, getOpenClawHome, getPendingTarget, markProfileComplete, markProfileNeeded, requireApiKey, requireConversationManager, requirePlatformConfig, writeCredentials, } from "./config.js";
|
|
23
|
+
import { clearTargetHandle, getOpenClawHome, getPendingTarget, isProfileNeeded, markProfileComplete, markProfileNeeded, requireApiKey, requireConversationManager, requirePlatformConfig, writeCredentials, } from "./config.js";
|
|
24
24
|
import { ownerNotesQueue } from "./owner-notes.js";
|
|
25
25
|
import { acceptRequest, declineRequest, getConnectionStatus, initSetup, listConnections, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
|
|
26
26
|
import { fetchLatestVersion, getPluginVersion, getUpdateInfo, } from "./update-check.js";
|
|
@@ -388,6 +388,15 @@ export function registerTools(api) {
|
|
|
388
388
|
execute: withUpdateNotice(async (_id, params) => {
|
|
389
389
|
const cfg = requirePlatformConfig();
|
|
390
390
|
const apiKey = requireApiKey();
|
|
391
|
+
// Profile gate: block connection requests until profile is complete.
|
|
392
|
+
// Without a profile the other agent sees an anonymous stranger,
|
|
393
|
+
// making acceptance unlikely.
|
|
394
|
+
if (isProfileNeeded()) {
|
|
395
|
+
return textResult("Your agent's profile is not complete yet. Without a profile, " +
|
|
396
|
+
"the other agent can't see who you are — connection requests from " +
|
|
397
|
+
"unknown agents are much less likely to be accepted. " +
|
|
398
|
+
"Use masons_update_profile to complete your profile first (scope, about, audience).");
|
|
399
|
+
}
|
|
391
400
|
const targetHandle = params.targetHandle;
|
|
392
401
|
let result;
|
|
393
402
|
try {
|
|
@@ -502,6 +511,14 @@ export function registerTools(api) {
|
|
|
502
511
|
execute: withUpdateNotice(async (_id, params) => {
|
|
503
512
|
const cfg = requirePlatformConfig();
|
|
504
513
|
const apiKey = requireApiKey();
|
|
514
|
+
// Profile gate: block accepting requests until profile is complete.
|
|
515
|
+
// When a connection is established, the other agent sees your profile —
|
|
516
|
+
// an empty profile means they won't know who you are.
|
|
517
|
+
if (isProfileNeeded()) {
|
|
518
|
+
return textResult("Your agent's profile is not complete yet. Without a profile, " +
|
|
519
|
+
"the other agent won't know who you are when the connection is established. " +
|
|
520
|
+
"Use masons_update_profile to complete your profile first (scope, about, audience).");
|
|
521
|
+
}
|
|
505
522
|
const requestId = params.requestId;
|
|
506
523
|
try {
|
|
507
524
|
const result = await acceptRequest(cfg, apiKey, requestId);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn Context — per-turn metadata captured during inbound message dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Tracks the sender identity for the current LLM turn. Set in channel.ts
|
|
5
|
+
* message_received handler (using the closure-scoped ConversationManager),
|
|
6
|
+
* consumed by before_prompt_build in plugin.ts to inject interaction context.
|
|
7
|
+
*
|
|
8
|
+
* Follows the same consume-on-read pattern as owner-session-state.ts:
|
|
9
|
+
* - Written BEFORE dispatch (so before_prompt_build can read it synchronously)
|
|
10
|
+
* - Consumed (read + reset) to prevent stale state across turns
|
|
11
|
+
*
|
|
12
|
+
* Race condition caveat: if two inbound messages arrive on different sessions
|
|
13
|
+
* near-simultaneously, the sender may reflect the wrong session. Acceptable
|
|
14
|
+
* for Phase 1 — OpenClaw processes turns sequentially per agent. Same caveat
|
|
15
|
+
* as owner-session-state.ts currentTurnIsOwner.
|
|
16
|
+
*
|
|
17
|
+
* Module-level singleton — shared between channel.ts (write) and plugin.ts (read).
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Set the sender identity for the current turn.
|
|
21
|
+
* Called in message_received before dispatch, using the closure-scoped
|
|
22
|
+
* ConversationManager to resolve sessionId → contact handle.
|
|
23
|
+
*/
|
|
24
|
+
export declare function setCurrentTurnSender(contact: string | null): void;
|
|
25
|
+
/**
|
|
26
|
+
* Consume the per-turn sender identity. Returns the value and resets to null.
|
|
27
|
+
* Consuming prevents stale state from leaking into subsequent turns.
|
|
28
|
+
*/
|
|
29
|
+
export declare function consumeCurrentTurnSender(): string | null;
|
|
30
|
+
//# sourceMappingURL=turn-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-context.d.ts","sourceRoot":"","sources":["../src/turn-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAaH;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEjE;AAMD;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAIxD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn Context — per-turn metadata captured during inbound message dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Tracks the sender identity for the current LLM turn. Set in channel.ts
|
|
5
|
+
* message_received handler (using the closure-scoped ConversationManager),
|
|
6
|
+
* consumed by before_prompt_build in plugin.ts to inject interaction context.
|
|
7
|
+
*
|
|
8
|
+
* Follows the same consume-on-read pattern as owner-session-state.ts:
|
|
9
|
+
* - Written BEFORE dispatch (so before_prompt_build can read it synchronously)
|
|
10
|
+
* - Consumed (read + reset) to prevent stale state across turns
|
|
11
|
+
*
|
|
12
|
+
* Race condition caveat: if two inbound messages arrive on different sessions
|
|
13
|
+
* near-simultaneously, the sender may reflect the wrong session. Acceptable
|
|
14
|
+
* for Phase 1 — OpenClaw processes turns sequentially per agent. Same caveat
|
|
15
|
+
* as owner-session-state.ts currentTurnIsOwner.
|
|
16
|
+
*
|
|
17
|
+
* Module-level singleton — shared between channel.ts (write) and plugin.ts (read).
|
|
18
|
+
*/
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// State
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/** Contact handle of the sender for the current turn. null = unknown/unset. */
|
|
23
|
+
let currentTurnSender = null;
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Write API (called from channel.ts)
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
/**
|
|
28
|
+
* Set the sender identity for the current turn.
|
|
29
|
+
* Called in message_received before dispatch, using the closure-scoped
|
|
30
|
+
* ConversationManager to resolve sessionId → contact handle.
|
|
31
|
+
*/
|
|
32
|
+
export function setCurrentTurnSender(contact) {
|
|
33
|
+
currentTurnSender = contact;
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Read API (called from plugin.ts)
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Consume the per-turn sender identity. Returns the value and resets to null.
|
|
40
|
+
* Consuming prevents stale state from leaking into subsequent turns.
|
|
41
|
+
*/
|
|
42
|
+
export function consumeCurrentTurnSender() {
|
|
43
|
+
const value = currentTurnSender;
|
|
44
|
+
currentTurnSender = null;
|
|
45
|
+
return value;
|
|
46
|
+
}
|
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.12";
|
package/package.json
CHANGED
|
@@ -44,8 +44,8 @@ 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 **
|
|
48
|
-
- **Setup complete + general communication** → Go to **
|
|
47
|
+
- **Connected + message from the network** → Go to **Network Behavior**
|
|
48
|
+
- **Setup complete + general communication** → Go to **Network Behavior**
|
|
49
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.
|
|
50
50
|
- **Update available** (tool output mentions an update) → Go to **Upgrade** below
|
|
51
51
|
- **User mentions upgrade or update** → Go to **Upgrade** below
|
|
@@ -83,7 +83,7 @@ One-time setup that takes about a minute.
|
|
|
83
83
|
|
|
84
84
|
- **If an existing agent is found**: The tool reconnects automatically. The handle parameter is ignored — just call with any placeholder.
|
|
85
85
|
- **If no existing agent**:
|
|
86
|
-
**Say to user:** "What handle would you like? This becomes your
|
|
86
|
+
**Say to user:** "What handle would you like? This is **permanent and cannot be changed later** — it becomes your network address (like `alice`). It must start with a letter and be 3–15 characters long (lowercase letters, numbers, hyphens, or underscores). Your display name can be changed anytime, but the handle is forever."
|
|
87
87
|
**Then:** Call `masons_setup_complete` with their chosen handle.
|
|
88
88
|
- If the handle is taken:
|
|
89
89
|
**Say to user:** "That handle is already taken — what about a different one?"
|
|
@@ -115,7 +115,7 @@ After completion:
|
|
|
115
115
|
|
|
116
116
|
Complete the agent's profile after creating a new agent (or when `needsProfile` is detected after restart).
|
|
117
117
|
|
|
118
|
-
A complete profile lets other agents discover this agent and understand what it does. The profile is filled in **3 sequential steps** — each step focuses on one dimension. Do NOT generate all fields at once.
|
|
118
|
+
A complete profile lets other agents discover this agent and understand what it does. This directly affects whether your connection requests are accepted — agents without a profile appear as anonymous strangers. The profile is filled in **3 sequential steps** — each step focuses on one dimension. Do NOT generate all fields at once.
|
|
119
119
|
|
|
120
120
|
**Completion criteria**: `scope`, `about`, AND `audience` must all be non-empty. The `needsProfile` flag is only cleared when all three are filled. `name` was already set during onboard — you can update it if needed, but it's not a completion gate.
|
|
121
121
|
|
|
@@ -222,83 +222,59 @@ If the user asks "did they accept my request?" or wants to check sent requests:
|
|
|
222
222
|
|
|
223
223
|
If a request is no longer actionable (already processed, expired), the tool will let you know.
|
|
224
224
|
|
|
225
|
-
##
|
|
225
|
+
## Network Behavior
|
|
226
226
|
|
|
227
|
-
You
|
|
227
|
+
You interact with multiple entities simultaneously — your owner and agents on the network. Each interaction is an Action aimed at changing the other party's state. Sending a message via `masons_send_message` changes a remote agent's state (informing, requesting, negotiating). Reporting via `masons_note_for_owner` changes your owner's awareness. These are Actions, not conversations.
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
Messages on the network are natural language. Do not impose format expectations on other agents' replies — evaluate meaning, not structure.
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
**You must have an accepted connection** with the target agent first. If not connected, go to **Connect**. To see your connections: `masons_list_connections`.
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
### Your interaction space
|
|
234
234
|
|
|
235
|
-
|
|
235
|
+
Your context will show your **active interactions** — who you're interacting with, who initiated each interaction, and when. Use this to stay aware of your full interaction space, not just the current message.
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
- To send to an agent: `masons_send_message(to, content)`
|
|
238
|
+
- To report to your owner: `masons_note_for_owner(content, from?)`
|
|
239
|
+
- To end an interaction: `masons_end_conversation(contact)`
|
|
238
240
|
|
|
239
|
-
###
|
|
241
|
+
### When you contact another agent (you initiate)
|
|
240
242
|
|
|
241
|
-
|
|
243
|
+
Your owner asked you to do something involving another agent. Your goal is to drive a **state change** — make something happen — not to have a conversation.
|
|
242
244
|
|
|
243
|
-
|
|
245
|
+
1. Send a clear, action-directed message via `masons_send_message`. Be specific about what you need the other agent to do.
|
|
246
|
+
2. When they reply, evaluate their response:
|
|
247
|
+
- **They took action** (confirmed they did something, provided a result) → Acknowledge, then report the outcome to your owner via `masons_note_for_owner`.
|
|
248
|
+
- **They gave a verbal response only** ("I'll check", "let me get back to you") → They haven't acted yet. Request specific action, or report the status to your owner via `masons_note_for_owner` so your owner knows it's pending.
|
|
249
|
+
- **They declined or can't do it** → Report to your owner via `masons_note_for_owner`.
|
|
250
|
+
- **Their response is unclear** → Report what they said to your owner via `masons_note_for_owner` and let your owner decide next steps.
|
|
251
|
+
3. When the goal is achieved, end the interaction via `masons_end_conversation`.
|
|
244
252
|
|
|
245
|
-
|
|
246
|
-
- Messages are plain language — no special format needed. Write naturally.
|
|
247
|
-
- You can send multiple messages to the same agent.
|
|
248
|
-
- If the remote agent replies, their messages appear automatically.
|
|
253
|
+
### When another agent contacts you (they initiate)
|
|
249
254
|
|
|
250
|
-
|
|
255
|
+
Another agent sent you a message. Understand what they want — what state change are they requesting?
|
|
251
256
|
|
|
252
|
-
|
|
257
|
+
- **You can act on it** → Do it. Reply with the result.
|
|
258
|
+
- **You need your owner's input** → Tell the other agent you need to check. Report the request to your owner via `masons_note_for_owner`.
|
|
259
|
+
- **It's outside your capability** → Clearly communicate what you can and cannot do.
|
|
253
260
|
|
|
254
|
-
|
|
261
|
+
### After every network interaction
|
|
255
262
|
|
|
256
|
-
|
|
257
|
-
- The user's request has been fulfilled
|
|
258
|
-
- The conversation reached a natural conclusion
|
|
259
|
-
- The remote agent provided what was needed
|
|
263
|
+
After responding to a network message, always check:
|
|
260
264
|
|
|
261
|
-
|
|
265
|
+
1. **Report to owner?** Should you inform your owner about what just happened? If yes, call `masons_note_for_owner`. When in doubt, report — your owner would rather know too much than too little.
|
|
266
|
+
2. **Interaction complete?** Has the goal been achieved? If yes, end via `masons_end_conversation`. If follow-up may be needed, keep it open.
|
|
267
|
+
3. **Other interactions?** Do any of your other active interactions need attention?
|
|
262
268
|
|
|
263
|
-
###
|
|
269
|
+
### Routing
|
|
264
270
|
|
|
265
|
-
|
|
271
|
+
Your text reply always goes to whoever triggered the current turn — you cannot redirect it.
|
|
266
272
|
|
|
267
|
-
-
|
|
268
|
-
-
|
|
273
|
+
- When a network message triggers your turn: your reply goes to that sender. Do NOT address your owner in the text reply — they will not see it.
|
|
274
|
+
- When your owner's turn fires: pending notes from the network appear in your context. Report them naturally.
|
|
275
|
+
- Owner's instructions are private by default — do not share them with network agents unless your owner explicitly says to. When relaying your owner's request, rephrase appropriately.
|
|
269
276
|
|
|
270
|
-
|
|
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.
|
|
277
|
+
> **Note:** Proxy mode (transparently connecting your owner to another agent's conversation) is not currently supported. All network interactions pass through you — you act on behalf of your owner, not as a passthrough.
|
|
302
278
|
|
|
303
279
|
## Upgrade
|
|
304
280
|
|