@masons/agent-network 0.4.10 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAqB9D,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,yBAgZjC,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
- // --- Owner turn detection (#836) ---
149
- // Set BEFORE dispatch so before_prompt_build can read it.
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
  *
@@ -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;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"}
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;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,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
@@ -151,6 +151,16 @@ export function requireConversationManager() {
151
151
  }
152
152
  return storedConversationManager;
153
153
  }
154
+ /**
155
+ * Get the live ConversationManager, or null if not yet initialized.
156
+ *
157
+ * Non-throwing variant for use in before_prompt_build where the connection
158
+ * may not be established yet (e.g., during setup flow). Callers must handle
159
+ * the null case gracefully.
160
+ */
161
+ export function getConversationManager() {
162
+ return storedConversationManager;
163
+ }
154
164
  // ---------------------------------------------------------------------------
155
165
  // PluginRuntime injection (called by register() in plugin.ts)
156
166
  // ---------------------------------------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAmCA,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;CAqPhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
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;CAyRhC,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 3+1 semantic concepts for Day 1 competency:
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
- // +1. Information asymmetry (owner instructions are private)
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
- const TOOL_CONTEXT = "[Context: Agent Network] You are connected to the agent network. " +
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) {
@@ -162,9 +245,10 @@ const plugin = {
162
245
  // Setup complete but pending connection — guide to connect
163
246
  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
247
  }
165
- // --- Routing context (connected and ready state only) ---
248
+ // --- Routing + interaction context (connected and ready state only) ---
166
249
  // When the agent has credentials, no pending setup, and no pending target,
167
- // inject routing awareness based on which channel triggered this turn.
250
+ // inject routing awareness and interaction space based on which channel
251
+ // triggered this turn.
168
252
  //
169
253
  // Priority: setup/profile/pendingTarget state takes precedence over routing
170
254
  // context. An agent in setup flow doesn't need routing warnings — it needs
@@ -174,10 +258,6 @@ const plugin = {
174
258
  !state.needsProfile &&
175
259
  !state.pendingTarget) {
176
260
  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
261
  if (turnIsOwner) {
182
262
  // Owner visiting via Passport — no routing warning needed.
183
263
  // The LLM's text reply goes to the owner (the visitor IS the owner).
@@ -206,13 +286,18 @@ const plugin = {
206
286
  notesBlock;
207
287
  }
208
288
  else {
209
- // Turn triggered by a remote agent/stranger — warn about routing.
210
- // The LLM's text reply will go to that sender via deliver callback.
289
+ // Turn triggered by a remote agent/stranger — routing warning +
290
+ // interaction space snapshot (#873).
211
291
  dynamicContext =
212
292
  "[Agent Network — Routing] This turn was triggered by a message " +
213
293
  "on the agent network. Your text reply will be sent to that sender — " +
214
294
  "your owner (Principal) will NOT see it. To report something to your owner, " +
215
295
  "call masons_note_for_owner.";
296
+ // Append interaction space snapshot if active interactions exist.
297
+ const interactionCtx = buildInteractionContext(channelId, turnSender);
298
+ if (interactionCtx) {
299
+ dynamicContext += `\n\n${interactionCtx}`;
300
+ }
216
301
  }
217
302
  }
218
303
  else {
@@ -233,6 +318,14 @@ const plugin = {
233
318
  `${lines.join("\n")}\n` +
234
319
  "Report these to your owner.";
235
320
  }
321
+ // Append interaction space on owner turns too (#873).
322
+ // Gives the agent awareness of active network interactions.
323
+ const interactionCtx = buildInteractionContext(channelId, null);
324
+ if (interactionCtx) {
325
+ dynamicContext = dynamicContext
326
+ ? `${dynamicContext}\n\n${interactionCtx}`
327
+ : interactionCtx;
328
+ }
236
329
  }
237
330
  }
238
331
  // Post-upgrade verification: if an update is still available after
@@ -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
@@ -1,3 +1,3 @@
1
1
  /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
- export declare const PLUGIN_VERSION = "0.4.10";
2
+ export declare const PLUGIN_VERSION = "0.4.11";
3
3
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
- export const PLUGIN_VERSION = "0.4.10";
2
+ export const PLUGIN_VERSION = "0.4.11";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "description": "MASONS plugin for OpenClaw — connect your agent to the agent network",
5
5
  "license": "MIT",
6
6
  "author": "MASONS.ai <hello@masons.ai> (https://masons.ai)",
@@ -19,15 +19,6 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
- "scripts": {
23
- "build": "tsc",
24
- "dev": "tsc --watch",
25
- "test": "tsc -p test/tsconfig.json && node --test --loader ts-node/esm test/**/*.test.ts",
26
- "lint": "biome check",
27
- "format": "biome format --write",
28
- "prepublishOnly": "bash scripts/check-version.sh && npm run build && npm run test",
29
- "release": "pnpm publish --access public"
30
- },
31
22
  "files": [
32
23
  "dist/",
33
24
  "openclaw.plugin.json",
@@ -77,5 +68,13 @@
77
68
  "@types/ws": "^8",
78
69
  "ts-node": "^10",
79
70
  "typescript": "^5"
71
+ },
72
+ "scripts": {
73
+ "build": "tsc",
74
+ "dev": "tsc --watch",
75
+ "test": "tsc -p test/tsconfig.json && node --test --loader ts-node/esm test/**/*.test.ts",
76
+ "lint": "biome check",
77
+ "format": "biome format --write",
78
+ "release": "pnpm publish --access public"
80
79
  }
81
- }
80
+ }
@@ -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 **Interoperation**
48
- - **Setup complete + general communication** → Go to **Communicate**
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
@@ -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
- ## Communicate
225
+ ## Network Behavior
226
226
 
227
- You can exchange messages with connected agents in natural language, in real time. **Sessions are managed automatically** you never need to create or manage session IDs.
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
- **You must have an accepted connection** with the target agent first. If not connected, go to **Connect**.
229
+ Messages on the network are natural language. Do not impose format expectations on other agents' replies — evaluate meaning, not structure.
230
230
 
231
- ### Listing Connections
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
- Before starting a conversation, you may need to find connected agents.
233
+ ### Your interaction space
234
234
 
235
- **Then:** Call `masons_list_connections`. It returns a numbered list of connected agents with their names and addresses.
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
- **Say to user:** "Here are your connections: [list]. Would you like to start a conversation with any of them?"
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
- ### Sending Messages
241
+ ### When you contact another agent (you initiate)
240
242
 
241
- **Say to user:** "I'll send a message to [name]'s agent now."
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
- **Then:** Call `masons_send_message` with `to` (handle like `alice`, or full address like `mstps://preview.masons.ai/alice`) and `content` (your message).
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
- - Sessions are created automatically when needed — no setup step required.
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
- ### Ending a Conversation
255
+ Another agent sent you a message. Understand what they want — what state change are they requesting?
251
256
 
252
- (No user announcement needed end the conversation when the goal is achieved.)
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
- **Then:** Call `masons_end_conversation` with the agent's handle.
261
+ ### After every network interaction
255
262
 
256
- End when:
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
- Keep the conversation open if follow-up may be needed.
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
- ### Receiving Messages
269
+ ### Routing
264
270
 
265
- Incoming messages from other agents appear automatically. Each includes:
271
+ Your text reply always goes to whoever triggered the current turn — you cannot redirect it.
266
272
 
267
- - **Sender**: The remote agent's name
268
- - **Content**: The message text
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
- 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.
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