@masons/agent-network 0.6.19 → 0.6.21

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.
Files changed (54) hide show
  1. package/dist/channel-setup.d.ts.map +1 -1
  2. package/dist/channel-setup.js +2 -1
  3. package/dist/channel.d.ts.map +1 -1
  4. package/dist/channel.js +54 -44
  5. package/dist/cli-setup.d.ts.map +1 -1
  6. package/dist/cli-setup.js +18 -4
  7. package/dist/config-fs.d.ts +1 -1
  8. package/dist/config-fs.d.ts.map +1 -1
  9. package/dist/config-fs.js +2 -1
  10. package/dist/config.d.ts +3 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +8 -2
  13. package/dist/connector-client.d.ts +35 -4
  14. package/dist/connector-client.d.ts.map +1 -1
  15. package/dist/connector-client.js +126 -19
  16. package/dist/conversation-manager-context.d.ts +4 -0
  17. package/dist/conversation-manager-context.d.ts.map +1 -0
  18. package/dist/conversation-manager-context.js +8 -0
  19. package/dist/conversation-manager.d.ts +29 -4
  20. package/dist/conversation-manager.d.ts.map +1 -1
  21. package/dist/conversation-manager.js +163 -14
  22. package/dist/handoff-deadline.d.ts +4 -0
  23. package/dist/handoff-deadline.d.ts.map +1 -0
  24. package/dist/handoff-deadline.js +7 -0
  25. package/dist/handoff.d.ts +1 -2
  26. package/dist/handoff.d.ts.map +1 -1
  27. package/dist/handoff.js +20 -10
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/platform-client.d.ts +1 -0
  31. package/dist/platform-client.d.ts.map +1 -1
  32. package/dist/platform-client.js +12 -0
  33. package/dist/plugin.d.ts +2 -1
  34. package/dist/plugin.d.ts.map +1 -1
  35. package/dist/plugin.js +49 -30
  36. package/dist/sent-message-buffer.d.ts +2 -3
  37. package/dist/sent-message-buffer.d.ts.map +1 -1
  38. package/dist/sent-message-buffer.js +8 -11
  39. package/dist/tools.d.ts.map +1 -1
  40. package/dist/tools.js +101 -7
  41. package/dist/turn-context.d.ts +0 -4
  42. package/dist/turn-context.d.ts.map +1 -1
  43. package/dist/turn-context.js +0 -18
  44. package/dist/types.d.ts +10 -1
  45. package/dist/types.d.ts.map +1 -1
  46. package/dist/types.js +3 -1
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/dist/ws-heartbeat.d.ts +23 -0
  50. package/dist/ws-heartbeat.d.ts.map +1 -0
  51. package/dist/ws-heartbeat.js +63 -0
  52. package/openclaw.plugin.json +2 -1
  53. package/package.json +1 -1
  54. package/skills/agent-network/SKILL.md +9 -0
package/dist/handoff.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { type KeyObject } from "node:crypto";
2
+ export { SetupFlowError } from "./handoff-deadline.js";
2
3
  export declare const DEFAULT_IDP_BASE_URL = "https://preview.masons.ai";
3
4
  export declare const HANDOFF_TIMEOUT_MS: number;
4
- export declare class SetupFlowError extends Error {
5
- }
6
5
  export interface BridgeHandoffResult {
7
6
  token: string;
8
7
  agent: {
@@ -1 +1 @@
1
- {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAerB,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAiBhE,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AAKhD,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAY5C,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAQD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAOhB,UAAU,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAsD/B;AAKD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAmC9B"}
1
+ {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAQrB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAavD,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAiBhE,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AAejD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAQD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAOhB,UAAU,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAsD/B;AAKD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAwC9B"}
package/dist/handoff.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { createDecipheriv, constants as cryptoConstants, generateKeyPairSync, privateDecrypt, } from "node:crypto";
2
+ import { assertHandoffDeadlineActive, SetupFlowError, } from "./handoff-deadline.js";
2
3
  import { apiFetch, PlatformNetworkError } from "./platform-client.js";
4
+ export { SetupFlowError } from "./handoff-deadline.js";
3
5
  export const DEFAULT_IDP_BASE_URL = "https://preview.masons.ai";
4
6
  const HANDLE_REGEX = /^[a-z][a-z0-9_-]{2,14}$/;
5
- export const HANDOFF_TIMEOUT_MS = 5 * 60 * 1000;
7
+ export const HANDOFF_TIMEOUT_MS = 10 * 60 * 1000;
6
8
  const HANDOFF_POLL_INTERVAL_MS = 2000;
7
- export class SetupFlowError extends Error {
8
- }
9
9
  export async function beginBridgeHandoff(options) {
10
10
  const { publicKey, privateKey } = generateKeyPairSync("rsa", {
11
11
  modulusLength: 2048,
@@ -53,7 +53,7 @@ export async function beginBridgeHandoff(options) {
53
53
  };
54
54
  }
55
55
  export async function completeBridgeHandoff(session) {
56
- const envelope = await pollForCompletion(session.apiBase, session.sessionId);
56
+ const envelope = await pollForCompletion(session.apiBase, session.sessionId, session.expiresAt);
57
57
  let payload;
58
58
  try {
59
59
  payload = decryptBridgeEnvelope(session.privateKey, envelope);
@@ -62,6 +62,7 @@ export async function completeBridgeHandoff(session) {
62
62
  const message = err instanceof Error ? err.message : "unknown error";
63
63
  throw new SetupFlowError(`Handoff received but could not be decrypted (${message}). The link may have been tampered with — re-run setup. If it keeps failing, your network may be inserting a TLS-terminating proxy that mangled the ciphertext.`);
64
64
  }
65
+ assertHandoffDeadlineActive(session.expiresAt);
65
66
  if (typeof payload.token !== "string" ||
66
67
  !payload.token.startsWith("masons_rt_v1_") ||
67
68
  typeof payload.agent?.handle !== "string" ||
@@ -79,10 +80,9 @@ export async function completeBridgeHandoff(session) {
79
80
  },
80
81
  };
81
82
  }
82
- async function pollForCompletion(apiBase, sessionId) {
83
- const start = Date.now();
83
+ async function pollForCompletion(apiBase, sessionId, expiresAt) {
84
84
  let lastNetworkError;
85
- while (Date.now() - start < HANDOFF_TIMEOUT_MS) {
85
+ while (Date.now() < expiresAt) {
86
86
  let res;
87
87
  try {
88
88
  res = await apiFetch(`${apiBase}/v1/cli-handoff/${encodeURIComponent(sessionId)}/poll`, { method: "GET" });
@@ -90,28 +90,38 @@ async function pollForCompletion(apiBase, sessionId) {
90
90
  catch (err) {
91
91
  if (err instanceof PlatformNetworkError) {
92
92
  lastNetworkError = err;
93
- await sleep(HANDOFF_POLL_INTERVAL_MS);
93
+ await sleepBeforeNextPoll(expiresAt);
94
94
  continue;
95
95
  }
96
96
  throw err;
97
97
  }
98
+ if (Date.now() >= expiresAt)
99
+ break;
98
100
  if (res.status === 404) {
99
101
  throw new SetupFlowError("Handoff session expired before the runtime key was delivered. Re-run setup.");
100
102
  }
101
103
  if (!res.ok) {
102
- await sleep(HANDOFF_POLL_INTERVAL_MS);
104
+ await sleepBeforeNextPoll(expiresAt);
103
105
  continue;
104
106
  }
105
107
  const body = (await res.json());
108
+ if (Date.now() >= expiresAt)
109
+ break;
106
110
  if (body.status === "completed" && body.payload) {
107
111
  return body.payload;
108
112
  }
109
- await sleep(HANDOFF_POLL_INTERVAL_MS);
113
+ await sleepBeforeNextPoll(expiresAt);
110
114
  }
111
115
  throw new SetupFlowError(lastNetworkError
112
116
  ? `Handoff timed out before the runtime key was delivered; the last poll could not reach ${apiBase} (${lastNetworkError.message}). Re-run setup; if you're behind a proxy that blocks long-running fetches, retry on a different network.`
113
117
  : "Handoff timed out before the runtime key was delivered. Re-run setup; if you're behind a proxy that blocks long-running fetches, retry on a different network.");
114
118
  }
119
+ async function sleepBeforeNextPoll(expiresAt) {
120
+ const remainingMs = expiresAt - Date.now();
121
+ if (remainingMs <= 0)
122
+ return;
123
+ await sleep(Math.min(HANDOFF_POLL_INTERVAL_MS, remainingMs));
124
+ }
115
125
  function decryptBridgeEnvelope(privateKey, envelope) {
116
126
  const wrappedKey = Buffer.from(envelope.wrapped_key, "base64url");
117
127
  const iv = Buffer.from(envelope.iv, "base64url");
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { AUTHORIZED_TOKEN_TTL_MS, SETUP_CODE_CHARSET, SETUP_CODE_LENGTH, SETUP_CODE_TTL_MS, } from "./constants.js";
2
2
  export type { AgentNetworkAccount } from "./config-schema.js";
3
- export type { AddressedMessageEvent, DeliveryPendingEvent, DeliverySkipEvent, DeliveryStatusEvent, RegisterAckEvent, SendAckEvent, StructuredErrorEvent, } from "./types.js";
3
+ export type { AddressedMessageEvent, DeliveryPendingEvent, DeliverySkipEvent, DeliveryStatusEvent, ObservedSendAckEvent, RegisterAckEvent, SendAckEvent, StructuredErrorEvent, } from "./types.js";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
@@ -87,4 +87,5 @@ export declare function acceptRequest(cfg: PlatformClientConfig, runtimeKey: str
87
87
  export declare function declineRequest(cfg: PlatformClientConfig, runtimeKey: string, requestId: string): Promise<DeclineRequestResponse>;
88
88
  export declare function updateProfile(cfg: PlatformClientConfig, runtimeKey: string, params: UpdateProfileParams): Promise<UpdateProfileResponse>;
89
89
  export declare function listConnections(cfg: PlatformClientConfig, runtimeKey: string): Promise<ListConnectionsResponse>;
90
+ export declare function getIdentity(cfg: PlatformClientConfig, runtimeKey: string): Promise<ConnectionNodeRef | null>;
90
91
  //# sourceMappingURL=platform-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../src/platform-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../src/platform-client.ts"],"names":[],"mappings":"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"}
@@ -144,3 +144,15 @@ export async function listConnections(cfg, runtimeKey) {
144
144
  return handleError(res);
145
145
  return (await res.json());
146
146
  }
147
+ export async function getIdentity(cfg, runtimeKey) {
148
+ const res = await apiFetch(`${baseUrl(cfg)}/me/identity`, {
149
+ headers: { Authorization: `Bearer ${runtimeKey}` },
150
+ });
151
+ if (!res.ok)
152
+ return handleError(res);
153
+ const body = (await res.json().catch(() => null));
154
+ if (!body || body.node === undefined) {
155
+ throw new PlatformApiError(res.status, "malformed_response", "identity response carried no `node` field");
156
+ }
157
+ return body.node;
158
+ }
package/dist/plugin.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import type { ConversationManager } from "./conversation-manager.js";
1
2
  import { evaluateServicesRetainedToolPolicy } from "./services-retained-tool-policy.js";
2
- export declare function buildInteractionContext(channelId: string | undefined, turnSender: string | null, turnSenderAddress: string | null, servicesRetained?: boolean): string | undefined;
3
+ export declare function buildInteractionContext(messageProvider: string | undefined, turnSenderAddress: string | null, conversationManager?: ConversationManager | null): string | undefined;
3
4
  interface OpenClawPluginApi {
4
5
  runtime: unknown;
5
6
  registerChannel(opts: {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,kCAAkC,EAEnC,MAAM,oCAAoC,CAAC;AAgE5C,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,gBAAgB,UAAQ,GACvB,MAAM,GAAG,SAAS,CA+EpB;AAKD,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CACV,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,IAAI,CAAC;IACR,yBAAyB,CAAC,MAAM,EAAE;QAChC,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,kCAAkC,CAAC;KACrD,GAAG,IAAI,CAAC;IACT,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAaI,iBAAiB;CAiZhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAUrE,OAAO,EACL,kCAAkC,EAEnC,MAAM,oCAAoC,CAAC;AA8D5C,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,mBAAmB,GAAE,mBAAmB,GAAG,IAA+B,GACzE,MAAM,GAAG,SAAS,CA6EpB;AAKD,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CACV,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,IAAI,CAAC;IACR,yBAAyB,CAAC,MAAM,EAAE;QAChC,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,kCAAkC,CAAC;KACrD,GAAG,IAAI,CAAC;IACT,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAqCD,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAaI,iBAAiB;CA8ZhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/plugin.js CHANGED
@@ -2,14 +2,14 @@ import pluginManifest from "../openclaw.plugin.json" with { type: "json" };
2
2
  import { agentNetworkChannel, consumeIdentityLinkingNudge } from "./channel.js";
3
3
  import { login } from "./cli-setup.js";
4
4
  import { detectPendingState, getConversationManager, getDmScope, getStateCacheGeneration, initPluginRuntime, } from "./config.js";
5
+ import { getInvocationConversationManager } from "./conversation-manager-context.js";
5
6
  import { getAgentIdentity } from "./environment-context.js";
6
7
  import { ownerNotesQueue } from "./owner-notes.js";
7
8
  import { consumeCurrentTurnIsOwner, consumeCurrentTurnOwnerSignal, } from "./owner-session-state.js";
8
- import { sentMessageBuffer } from "./sent-message-buffer.js";
9
9
  import { isServicesRetainedReplyContext } from "./services-retained-reply-context.js";
10
10
  import { evaluateServicesRetainedToolPolicy, SERVICES_RETAINED_TOOL_POLICY_ID, } from "./services-retained-tool-policy.js";
11
11
  import { registerTools } from "./tools.js";
12
- import { consumeCurrentTurnSender, consumeCurrentTurnSenderAddress, setCurrentTurnChannelId, setCurrentTurnIsOwnerForTools, setCurrentTurnOwnerSignalForTools, } from "./turn-context.js";
12
+ import { setCurrentTurnChannelId, setCurrentTurnIsOwnerForTools, setCurrentTurnOwnerSignalForTools, } from "./turn-context.js";
13
13
  import { getUpdateInfo } from "./update-check.js";
14
14
  import { PLUGIN_VERSION } from "./version.js";
15
15
  function formatTimeAgo(timestamp) {
@@ -40,8 +40,8 @@ function drainAndFormatNotes(reportInstruction) {
40
40
  reportInstruction);
41
41
  }
42
42
  const MAX_INTERACTIONS = 5;
43
- export function buildInteractionContext(channelId, turnSender, turnSenderAddress, servicesRetained = false) {
44
- const cm = getConversationManager();
43
+ export function buildInteractionContext(messageProvider, turnSenderAddress, conversationManager = getConversationManager()) {
44
+ const cm = conversationManager;
45
45
  if (!cm)
46
46
  return undefined;
47
47
  const conversations = cm.listConversations();
@@ -60,22 +60,18 @@ export function buildInteractionContext(channelId, turnSender, turnSenderAddress
60
60
  const when = formatTimeAgo(c.lastMessageAt);
61
61
  return `• ${who} — ${initiated} — last activity ${when}`;
62
62
  });
63
- const isNetworkTurn = channelId === "agent-network";
64
- if (isNetworkTurn && turnSender) {
65
- const senderConvo = turnSenderAddress
66
- ? conversations.find((c) => c.address === turnSenderAddress)
67
- : undefined;
63
+ const isNetworkTurn = messageProvider === "agent-network";
64
+ if (isNetworkTurn && turnSenderAddress) {
65
+ const senderConvo = conversations.find((c) => c.address === turnSenderAddress);
68
66
  const initiated = senderConvo?.initiatedBy === "local"
69
67
  ? "You initiated this interaction."
70
68
  : "They initiated this interaction.";
71
- const from = turnSenderAddress && turnSenderAddress !== turnSender
72
- ? `${turnSender} (${turnSenderAddress})`
73
- : turnSender;
69
+ const from = senderConvo && senderConvo.contact !== turnSenderAddress
70
+ ? `${senderConvo.contact} (${turnSenderAddress})`
71
+ : turnSenderAddress;
74
72
  return (`${header}\n${lines.join("\n")}\n` +
75
73
  `[This turn] From ${from}. ${initiated}\n` +
76
- (servicesRetained
77
- ? "Your text reply uses the Services-retained reply authority for this message. "
78
- : "Your text reply goes to this sender. ") +
74
+ "Your text reply goes to this sender. " +
79
75
  "To report to your owner: masons_note_for_owner.");
80
76
  }
81
77
  if (isNetworkTurn) {
@@ -88,6 +84,24 @@ export function buildInteractionContext(channelId, turnSender, turnSenderAddress
88
84
  : "[Active interactions on the network]";
89
85
  return `${ownerHeader}\n${lines.join("\n")}`;
90
86
  }
87
+ function resolveHookProvider(ctx) {
88
+ return ctx?.messageProvider ?? ctx?.channel;
89
+ }
90
+ function resolveHookSender(ctx, servicesRetained) {
91
+ if (servicesRetained || resolveHookProvider(ctx) !== "agent-network") {
92
+ return null;
93
+ }
94
+ const senderId = ctx?.senderId;
95
+ return typeof senderId === "string" && senderId.length > 0 ? senderId : null;
96
+ }
97
+ function renderPeer(address, conversationManager) {
98
+ const conversation = conversationManager
99
+ .listConversations()
100
+ .find((entry) => entry.address === address);
101
+ return conversation && conversation.contact !== address
102
+ ? `${conversation.contact} (${address})`
103
+ : address;
104
+ }
91
105
  const plugin = {
92
106
  id: "agent-network",
93
107
  version: PLUGIN_VERSION,
@@ -130,7 +144,8 @@ const plugin = {
130
144
  "masons_note_for_owner(content, from?) — save a note for your owner's next turn. " +
131
145
  "Other network tools: masons_list_requests, masons_send_connection_request, " +
132
146
  "masons_accept_request, masons_decline_request, masons_list_connections, " +
133
- "masons_end_conversation (rare one-shot close signal only). " +
147
+ "masons_end_conversation (rare one-shot close signal only), " +
148
+ "masons_status (your canonical identity and participation status). " +
134
149
  "Always try these tools first for network operations. " +
135
150
  "If a tool call fails, report the error to your user — do not silently work around it. " +
136
151
  "You interact with multiple entities simultaneously — your owner and agents on the network. " +
@@ -147,13 +162,15 @@ const plugin = {
147
162
  "";
148
163
  api.on("before_prompt_build", async (_event, ctx) => {
149
164
  const hookCtx = ctx;
150
- const channelId = hookCtx?.channelId;
165
+ const messageProvider = resolveHookProvider(hookCtx);
166
+ const invocationConversationManager = getInvocationConversationManager();
151
167
  const turnIsOwner = consumeCurrentTurnIsOwner();
152
168
  const turnOwnerSignal = consumeCurrentTurnOwnerSignal();
153
- const turnSender = consumeCurrentTurnSender();
154
- const turnSenderAddress = consumeCurrentTurnSenderAddress();
155
169
  const servicesRetainedReply = isServicesRetainedReplyContext();
156
- setCurrentTurnChannelId(channelId ?? null);
170
+ const turnSenderAddress = invocationConversationManager
171
+ ? resolveHookSender(hookCtx, servicesRetainedReply)
172
+ : null;
173
+ setCurrentTurnChannelId(messageProvider ?? null);
157
174
  setCurrentTurnIsOwnerForTools(turnIsOwner);
158
175
  setCurrentTurnOwnerSignalForTools(turnOwnerSignal);
159
176
  const currentGeneration = getStateCacheGeneration();
@@ -203,7 +220,7 @@ const plugin = {
203
220
  state.hasCredentials &&
204
221
  !state.needsProfile &&
205
222
  !state.pendingTarget) {
206
- if (channelId === "agent-network") {
223
+ if (messageProvider === "agent-network") {
207
224
  if (turnIsOwner) {
208
225
  dynamicContext =
209
226
  "[Agent Network — Owner via Passport] Your owner (Principal) is talking to you " +
@@ -226,12 +243,12 @@ const plugin = {
226
243
  "on the agent network. Your text reply will be sent to that sender — " +
227
244
  "your owner (Principal) will NOT see it. To report something to your owner, " +
228
245
  "call masons_note_for_owner.";
229
- const interactionCtx = buildInteractionContext(channelId, turnSender, turnSenderAddress, servicesRetainedReply);
246
+ const interactionCtx = buildInteractionContext(messageProvider, turnSenderAddress, invocationConversationManager);
230
247
  if (interactionCtx) {
231
248
  dynamicContext += `\n\n${interactionCtx}`;
232
249
  }
233
- if (turnSender) {
234
- const sentMsgs = sentMessageBuffer.getRecent(turnSender);
250
+ if (turnSenderAddress && invocationConversationManager) {
251
+ const sentMsgs = invocationConversationManager?.getRecentOutboundContext(turnSenderAddress) ?? [];
235
252
  if (sentMsgs.length > 0) {
236
253
  const lines = sentMsgs.map((m) => {
237
254
  const preview = m.content.length > 500
@@ -240,7 +257,7 @@ const plugin = {
240
257
  return `• (${formatTimeAgo(m.timestamp)}): "${preview}"`;
241
258
  });
242
259
  dynamicContext +=
243
- `\n\n[Your recent messages to ${turnSender}]\n` +
260
+ `\n\n[Your recent messages to ${renderPeer(turnSenderAddress, invocationConversationManager)}]\n` +
244
261
  lines.join("\n");
245
262
  }
246
263
  }
@@ -261,7 +278,7 @@ const plugin = {
261
278
  ? `${dynamicContext}\n\n${nudge}`
262
279
  : nudge;
263
280
  }
264
- const interactionCtx = buildInteractionContext(channelId, null, null);
281
+ const interactionCtx = buildInteractionContext(messageProvider, null);
265
282
  if (interactionCtx) {
266
283
  dynamicContext = dynamicContext
267
284
  ? `${dynamicContext}\n\n${interactionCtx}`
@@ -287,10 +304,12 @@ const plugin = {
287
304
  if (state.hasCredentials) {
288
305
  const envAgent = getAgentIdentity();
289
306
  if (envAgent) {
290
- let identityLine = `[Identity] You are @${envAgent.handle}`;
291
- if (envAgent.name)
292
- identityLine += ` (${envAgent.name})`;
293
- identityLine += " on the agent network.";
307
+ const registered = envAgent.name
308
+ ? `@${envAgent.handle}(${envAgent.name})`
309
+ : `@${envAgent.handle}`;
310
+ const identityLine = `[Identity] The Gateway registered this connection as ${registered}. ` +
311
+ "This is connection-level context, not your canonical network identity — " +
312
+ "for the canonical answer, call masons_status.";
294
313
  dynamicContext = dynamicContext
295
314
  ? `${identityLine}\n\n${dynamicContext}`
296
315
  : identityLine;
@@ -7,9 +7,8 @@ export declare class SentMessageBuffer {
7
7
  static readonly MAX_PER_CONTACT = 5;
8
8
  static readonly TTL_MS: number;
9
9
  static readonly MAX_CONTENT_LENGTH = 1000;
10
- record(contact: string, content: string): void;
11
- getRecent(contact: string): SentMessage[];
10
+ record(peerAddress: string, content: string): void;
11
+ getRecent(peerAddress: string): SentMessage[];
12
12
  clear(): void;
13
13
  }
14
- export declare const sentMessageBuffer: SentMessageBuffer;
15
14
  //# sourceMappingURL=sent-message-buffer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sent-message-buffer.d.ts","sourceRoot":"","sources":["../src/sent-message-buffer.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,WAAW;IAE1B,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAoC;IAGnD,MAAM,CAAC,QAAQ,CAAC,eAAe,KAAK;IAEpC,MAAM,CAAC,QAAQ,CAAC,MAAM,SAAsB;IAE5C,MAAM,CAAC,QAAQ,CAAC,kBAAkB,QAAQ;IAM1C,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAiC9C,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE;IAuBzC,KAAK,IAAI,IAAI;CAGd;AAMD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
1
+ {"version":3,"file":"sent-message-buffer.d.ts","sourceRoot":"","sources":["../src/sent-message-buffer.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,WAAW;IAE1B,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAoC;IAGnD,MAAM,CAAC,QAAQ,CAAC,eAAe,KAAK;IAEpC,MAAM,CAAC,QAAQ,CAAC,MAAM,SAAsB;IAE5C,MAAM,CAAC,QAAQ,CAAC,kBAAkB,QAAQ;IAM1C,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAgClD,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE;IAsB7C,KAAK,IAAI,IAAI;CAGd"}
@@ -3,13 +3,12 @@ export class SentMessageBuffer {
3
3
  static MAX_PER_CONTACT = 5;
4
4
  static TTL_MS = 2 * 60 * 60 * 1000;
5
5
  static MAX_CONTENT_LENGTH = 1000;
6
- record(contact, content) {
6
+ record(peerAddress, content) {
7
7
  const now = Date.now();
8
- const key = contact.toLowerCase();
9
- let list = this.entries.get(key);
8
+ let list = this.entries.get(peerAddress);
10
9
  if (!list) {
11
10
  list = [];
12
- this.entries.set(key, list);
11
+ this.entries.set(peerAddress, list);
13
12
  }
14
13
  const cutoff = now - SentMessageBuffer.TTL_MS;
15
14
  const fresh = list.filter((m) => m.timestamp > cutoff);
@@ -20,21 +19,20 @@ export class SentMessageBuffer {
20
19
  ? `${content.slice(0, SentMessageBuffer.MAX_CONTENT_LENGTH)}...`
21
20
  : content;
22
21
  fresh.push({ content: stored, timestamp: now });
23
- this.entries.set(key, fresh);
22
+ this.entries.set(peerAddress, fresh);
24
23
  }
25
- getRecent(contact) {
26
- const key = contact.toLowerCase();
27
- const list = this.entries.get(key);
24
+ getRecent(peerAddress) {
25
+ const list = this.entries.get(peerAddress);
28
26
  if (!list)
29
27
  return [];
30
28
  const cutoff = Date.now() - SentMessageBuffer.TTL_MS;
31
29
  const fresh = list.filter((m) => m.timestamp > cutoff);
32
30
  if (fresh.length !== list.length) {
33
31
  if (fresh.length === 0) {
34
- this.entries.delete(key);
32
+ this.entries.delete(peerAddress);
35
33
  }
36
34
  else {
37
- this.entries.set(key, fresh);
35
+ this.entries.set(peerAddress, fresh);
38
36
  }
39
37
  }
40
38
  return fresh;
@@ -43,4 +41,3 @@ export class SentMessageBuffer {
43
41
  this.entries.clear();
44
42
  }
45
43
  }
46
- export const sentMessageBuffer = new SentMessageBuffer();
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAwEA,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,WAAW;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;AAE3E,UAAU,OAAO;IACf,YAAY,CACV,IAAI,EAAE,cAAc,GAAG,WAAW,EAWlC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAC7D,IAAI,CAAC;CACT;AAoDD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAwSD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA22BhD"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AA2EA,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,WAAW;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;AAE3E,UAAU,OAAO;IACf,YAAY,CACV,IAAI,EAAE,cAAc,GAAG,WAAW,EAWlC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAC7D,IAAI,CAAC;CACT;AAoDD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAoZD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAm5BhD"}
package/dist/tools.js CHANGED
@@ -1,12 +1,10 @@
1
1
  import { Type } from "@sinclair/typebox";
2
2
  import { getOwnerPassportAddress } from "./channel.js";
3
3
  import { _resetChannelSetupForTesting, consumeChannelSetupStatus, getDefaultChannelSetupOptions, startOrGetChannelSetup, } from "./channel-setup.js";
4
- import { clearTargetHandle, extractNetworkConfig, getDmScope, getPendingTarget, isProfileNeeded, markProfileComplete, removeIdentityLinks, requireApiKey, requireConversationManager, requirePlatformConfig, writeIdentityLinks, } from "./config.js";
4
+ import { clearTargetHandle, extractNetworkConfig, getConnectorClient, getDmScope, getPendingTarget, hasApiKey, isProfileNeeded, markProfileComplete, removeIdentityLinks, requireApiKey, requireConversationManager, requirePlatformConfig, writeIdentityLinks, } from "./config.js";
5
5
  import { getOwnerHandle } from "./environment-context.js";
6
- import { extractHandleFromAddress } from "./handle-utils.js";
7
6
  import { ownerNotesQueue } from "./owner-notes.js";
8
- import { acceptRequest, declineRequest, listConnections, listRequests, PlatformApiError, PlatformNetworkError, requestConnection, updateProfile, } from "./platform-client.js";
9
- import { sentMessageBuffer } from "./sent-message-buffer.js";
7
+ import { acceptRequest, declineRequest, getIdentity, listConnections, listRequests, PlatformApiError, PlatformNetworkError, requestConnection, updateProfile, } from "./platform-client.js";
10
8
  import { isServicesRetainedReplyContext } from "./services-retained-reply-context.js";
11
9
  import { getCurrentTurnChannelId, getCurrentTurnIsOwnerNonConsuming, getCurrentTurnOwnerSignal, } from "./turn-context.js";
12
10
  import { getLatestPublishedVersion, getPluginVersion, getUpdateInfo, } from "./update-check.js";
@@ -63,6 +61,76 @@ function formatConnectionResult(requestIds, status) {
63
61
  }
64
62
  return `Connection request sent. Status: ${status}. The other agent's owner will be notified.`;
65
63
  }
64
+ function formatIdentityNode(node) {
65
+ const handlePart = node.handle ? `@${node.handle} — ` : "";
66
+ const canonical = `Identity: ${formatKindLabel(node.kind)}${handlePart}${node.mstpAddress}`;
67
+ if (!node.displayName)
68
+ return canonical;
69
+ return `${canonical}\nDisplay name (presentation supplied by the identity endpoint): ${node.displayName}`;
70
+ }
71
+ const IDENTITY_NO_FALLBACK = "This is not an answer — do not assume any locally-cached handle or name is this Runtime's identity.";
72
+ function formatIdentityError(err) {
73
+ if (err instanceof PlatformApiError) {
74
+ if (err.status === 404) {
75
+ return err.code === "not_found"
76
+ ? "Identity: the Node's backing entity is missing or deleted."
77
+ : `Identity: unavailable — the identity endpoint is not available at this host (HTTP 404). ${IDENTITY_NO_FALLBACK}`;
78
+ }
79
+ if (err.status === 401) {
80
+ return "Identity: the runtime key is not valid — the network rejected it. The owner can re-authenticate via masons_setup.";
81
+ }
82
+ if (err.status === 403) {
83
+ return "Identity: refused (HTTP 403) — this runtime key is not permitted to read this Runtime's identity. That is a credential-class refusal, not a transient outage: retrying will not change it.";
84
+ }
85
+ return `Identity: unavailable right now (HTTP ${err.status}: ${err.code}). ${IDENTITY_NO_FALLBACK}`;
86
+ }
87
+ if (err instanceof PlatformNetworkError) {
88
+ return `Identity: unavailable right now. ${networkErrorText(err)} ${IDENTITY_NO_FALLBACK}`;
89
+ }
90
+ throw err;
91
+ }
92
+ function formatRegistration(outcome) {
93
+ switch (outcome.state) {
94
+ case "accepted":
95
+ return "accepted";
96
+ case "refused":
97
+ return `refused: ${outcome.reason}`;
98
+ case "replaced":
99
+ return "replaced by another Runtime (will not retry)";
100
+ case "none":
101
+ return "none";
102
+ }
103
+ }
104
+ function formatReadinessSection() {
105
+ const credentialsLine = hasApiKey()
106
+ ? "Credentials: configured"
107
+ : "Credentials: not configured";
108
+ const client = getConnectorClient();
109
+ const channel = client ? client.getChannelState() : "not established";
110
+ const registration = formatRegistration(client ? client.getRegistration() : { state: "none" });
111
+ return [
112
+ credentialsLine,
113
+ `Gateway channel: ${channel}`,
114
+ `Registration (this connection): ${registration}`,
115
+ ].join("\n");
116
+ }
117
+ async function resolveIdentitySection() {
118
+ if (!hasApiKey()) {
119
+ return "Identity: no runtime key configured — cannot ask the network who this Runtime is. Run masons_setup first.";
120
+ }
121
+ const cfg = requirePlatformConfig();
122
+ const apiKey = requireApiKey();
123
+ try {
124
+ const node = await getIdentity(cfg, apiKey);
125
+ if (node === null) {
126
+ return "Identity: this Runtime's principal holds no active Node on the network.";
127
+ }
128
+ return formatIdentityNode(node);
129
+ }
130
+ catch (err) {
131
+ return formatIdentityError(err);
132
+ }
133
+ }
66
134
  function resolveSetupAuthority() {
67
135
  const channelId = getCurrentTurnChannelId();
68
136
  if (channelId !== "agent-network") {
@@ -573,6 +641,18 @@ export function registerTools(api) {
573
641
  return textResult(`${result.total} connection(s):\n\n${lines.join("\n")}\n\nUse masons_send_message with a handle or address to send a message.`);
574
642
  }),
575
643
  });
644
+ api.registerTool({
645
+ name: "masons_status",
646
+ description: [
647
+ "Report this Runtime's canonical identity and participation status on the agent network.",
648
+ "Use when the owner asks 'who are you on the network', 'what's your identity', 'are you connected', or 'are you ready'.",
649
+ "",
650
+ "Identity comes ONLY from the platform's own identity endpoint — never from local config, cached REGISTER_ACK context, a pending connection target, or any peer/connection handle. If the identity endpoint is unavailable, this tool reports that plainly instead of guessing.",
651
+ "Readiness reports separate facts — credentials configured, live Gateway channel state, and the current connection's registration outcome — without collapsing them into one 'online' verdict.",
652
+ ].join("\n"),
653
+ parameters: Type.Object({}),
654
+ execute: withUpdateNotice(async () => textResult([await resolveIdentitySection(), "", formatReadinessSection()].join("\n"))),
655
+ });
576
656
  api.registerTool({
577
657
  name: "masons_send_message",
578
658
  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.",
@@ -591,11 +671,25 @@ export function registerTools(api) {
591
671
  const cm = requireConversationManager();
592
672
  const to = params.to;
593
673
  const content = params.content;
594
- const handle = extractHandleFromAddress(to);
595
674
  const result = await cm.send(to, content);
596
675
  if (result.status === "sent") {
597
- sentMessageBuffer.record(handle, content);
598
- return textResult("Message sent.");
676
+ if (result.addressedTarget?.basis === "resolved") {
677
+ cm.recordOutboundContext(result.addressedTarget.address, content);
678
+ }
679
+ const reference = result.messageRef
680
+ ? ` Message reference: ${JSON.stringify(result.messageRef)}.`
681
+ : "";
682
+ if (result.acknowledgementStatus === "stored") {
683
+ return textResult(`Message durably accepted for delivery.${reference}`);
684
+ }
685
+ if (result.acknowledgementStatus === "delivered") {
686
+ return textResult(`Message handed to the recipient Node; presentation is not confirmed.${reference}`);
687
+ }
688
+ return textResult(`Message accepted with acknowledgement status ${JSON.stringify(result.acknowledgementStatus)}.${reference}`);
689
+ }
690
+ if (result.status === "unknown") {
691
+ console.warn(`[agent-network:tools] masons_send_message OUTCOME UNKNOWN to=${to} messageId=${result.messageId} reason=${result.reason}`);
692
+ return textResult(result.error);
599
693
  }
600
694
  console.warn(`[agent-network:tools] masons_send_message FAILED to=${to} code=${result.errorCode ?? "(none)"} error=${result.error ?? "(none)"}`);
601
695
  return textResult(result.error ??
@@ -1,11 +1,7 @@
1
1
  import type { OwnerSignal } from "./owner-session-state.js";
2
- export declare function setCurrentTurnSender(contact: string | null): void;
3
- export declare function setCurrentTurnSenderAddress(address: string | null): void;
4
2
  export declare function setCurrentTurnChannelId(channelId: string | null): void;
5
3
  export declare function setCurrentTurnIsOwnerForTools(value: boolean): void;
6
4
  export declare function setCurrentTurnOwnerSignalForTools(signal: OwnerSignal): void;
7
- export declare function consumeCurrentTurnSender(): string | null;
8
- export declare function consumeCurrentTurnSenderAddress(): string | null;
9
5
  export declare function getCurrentTurnChannelId(): string | null;
10
6
  export declare function getCurrentTurnIsOwnerNonConsuming(): boolean;
11
7
  export declare function getCurrentTurnOwnerSignal(): OwnerSignal;
@@ -1 +1 @@
1
- {"version":3,"file":"turn-context.d.ts","sourceRoot":"","sources":["../src/turn-context.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAyC5D,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEjE;AAUD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExE;AAOD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEtE;AAOD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAElE;AAUD,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAE3E;AAUD,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAIxD;AAGD,wBAAgB,+BAA+B,IAAI,MAAM,GAAG,IAAI,CAI/D;AAMD,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAMD,wBAAgB,iCAAiC,IAAI,OAAO,CAE3D;AAOD,wBAAgB,yBAAyB,IAAI,WAAW,CAEvD"}
1
+ {"version":3,"file":"turn-context.d.ts","sourceRoot":"","sources":["../src/turn-context.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAqC5D,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEtE;AAOD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAElE;AAUD,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAE3E;AAUD,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAMD,wBAAgB,iCAAiC,IAAI,OAAO,CAE3D;AAOD,wBAAgB,yBAAyB,IAAI,WAAW,CAEvD"}
@@ -1,14 +1,6 @@
1
- let currentTurnSender = null;
2
- let currentTurnSenderAddress = null;
3
1
  let currentTurnChannelId = null;
4
2
  let currentTurnIsOwner = false;
5
3
  let currentTurnOwnerSignalForTools = null;
6
- export function setCurrentTurnSender(contact) {
7
- currentTurnSender = contact;
8
- }
9
- export function setCurrentTurnSenderAddress(address) {
10
- currentTurnSenderAddress = address;
11
- }
12
4
  export function setCurrentTurnChannelId(channelId) {
13
5
  currentTurnChannelId = channelId;
14
6
  }
@@ -18,16 +10,6 @@ export function setCurrentTurnIsOwnerForTools(value) {
18
10
  export function setCurrentTurnOwnerSignalForTools(signal) {
19
11
  currentTurnOwnerSignalForTools = signal;
20
12
  }
21
- export function consumeCurrentTurnSender() {
22
- const value = currentTurnSender;
23
- currentTurnSender = null;
24
- return value;
25
- }
26
- export function consumeCurrentTurnSenderAddress() {
27
- const value = currentTurnSenderAddress;
28
- currentTurnSenderAddress = null;
29
- return value;
30
- }
31
13
  export function getCurrentTurnChannelId() {
32
14
  return currentTurnChannelId;
33
15
  }