@masons/agent-network 0.6.6 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAyC9D,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAOD,wBAAgB,2BAA2B,IAAI,OAAO,CAIrD;AAGD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/D;AAUD,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,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,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;AA2DD,iBAAS,iCAAiC,CACxC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BzB;AAED,eAAO,MAAM,4CAA4C,0CACtB,CAAC;AAEpC,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;AAyaD,eAAO,MAAM,mBAAmB,EAAE,yBA+NjC,CAAC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AA0C9D,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAOD,wBAAgB,2BAA2B,IAAI,OAAO,CAIrD;AAGD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/D;AAUD,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,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,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;AA2DD,iBAAS,iCAAiC,CACxC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BzB;AAED,eAAO,MAAM,4CAA4C,0CACtB,CAAC;AAEpC,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;AAscD,eAAO,MAAM,mBAAmB,EAAE,yBA+NjC,CAAC"}
package/dist/channel.js CHANGED
@@ -6,6 +6,7 @@ import { resolveMstpAuthority } from "./connector-url-boundary.js";
6
6
  import { ConversationManager } from "./conversation-manager.js";
7
7
  import { clearEnvironmentContext } from "./environment-context.js";
8
8
  import { extractHandleFromAddress } from "./handle-utils.js";
9
+ import { messageLog } from "./message-log.js";
9
10
  import { clearOwnerState, isOwnerAddress, markOwnerAddress, setCurrentTurnIsOwner, setCurrentTurnOwnerSignal, } from "./owner-session-state.js";
10
11
  import { createReplyTraceMetadata, ensureTraceMetadata, } from "./trace-metadata.js";
11
12
  import { setCurrentTurnSender } from "./turn-context.js";
@@ -209,6 +210,9 @@ async function handleAddressedMessage(event, conversationManager, client, ctx) {
209
210
  OriginatingChannel: "agent-network",
210
211
  OriginatingTo: senderId,
211
212
  });
213
+ if (metadata.is_owner !== true) {
214
+ messageLog.record(extractHandleFromAddress(fromAddress), "inbound", event.content);
215
+ }
212
216
  const storePath = runtime.channel.session.resolveStorePath(undefined, {
213
217
  agentId: route.agentId,
214
218
  });
@@ -246,6 +250,9 @@ async function handleAddressedMessage(event, conversationManager, client, ctx) {
246
250
  }
247
251
  const replyTrace = createReplyTraceMetadata(metadata, replyMetadata);
248
252
  const deliverResult = await conversationManager.send(senderId, text, replyTrace.metadata);
253
+ if (deliverResult.status === "sent" && metadata.is_owner !== true) {
254
+ messageLog.record(extractHandleFromAddress(fromAddress), "outbound", text);
255
+ }
249
256
  dbg("deliver reply senderId=%s status=%s contentLength=%d traceId=%s originalTraceId=%s spanName=send", senderId, deliverResult.status, text.length, replyTrace.traceId, replyTrace.originalTraceId ?? "(absent)");
250
257
  },
251
258
  onError: (err) => {
@@ -0,0 +1,18 @@
1
+ export type MessageLogDirection = "inbound" | "outbound";
2
+ export interface MessageLogEntry {
3
+ direction: MessageLogDirection;
4
+ content: string;
5
+ timestamp: number;
6
+ }
7
+ export declare class MessageLog {
8
+ private entries;
9
+ static readonly MAX_PER_CONTACT = 30;
10
+ static readonly TTL_MS: number;
11
+ static readonly MAX_CONTENT_LENGTH = 2000;
12
+ record(contact: string, direction: MessageLogDirection, content: string): void;
13
+ getRecent(contact: string, limit?: number): MessageLogEntry[];
14
+ contacts(): string[];
15
+ clear(): void;
16
+ }
17
+ export declare const messageLog: MessageLog;
18
+ //# sourceMappingURL=message-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-log.d.ts","sourceRoot":"","sources":["../src/message-log.ts"],"names":[],"mappings":"AAuCA,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,eAAe;IAE9B,SAAS,EAAE,mBAAmB,CAAC;IAE/B,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAwC;IAGvD,MAAM,CAAC,QAAQ,CAAC,eAAe,MAAM;IAErC,MAAM,CAAC,QAAQ,CAAC,MAAM,SAA2B;IAEjD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,QAAQ;IAM1C,MAAM,CACJ,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,mBAAmB,EAC9B,OAAO,EAAE,MAAM,GACd,IAAI;IA+BP,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe,EAAE;IAuB7D,QAAQ,IAAI,MAAM,EAAE;IAKpB,KAAK,IAAI,IAAI;CAGd;AAMD,eAAO,MAAM,UAAU,YAAmB,CAAC"}
@@ -0,0 +1,52 @@
1
+ export class MessageLog {
2
+ entries = new Map();
3
+ static MAX_PER_CONTACT = 30;
4
+ static TTL_MS = 7 * 24 * 60 * 60 * 1000;
5
+ static MAX_CONTENT_LENGTH = 2000;
6
+ record(contact, direction, content) {
7
+ const now = Date.now();
8
+ const key = contact.toLowerCase();
9
+ let list = this.entries.get(key);
10
+ if (!list) {
11
+ list = [];
12
+ this.entries.set(key, list);
13
+ }
14
+ const cutoff = now - MessageLog.TTL_MS;
15
+ const fresh = list.filter((m) => m.timestamp > cutoff);
16
+ if (fresh.length >= MessageLog.MAX_PER_CONTACT) {
17
+ fresh.shift();
18
+ }
19
+ const stored = content.length > MessageLog.MAX_CONTENT_LENGTH
20
+ ? `${content.slice(0, MessageLog.MAX_CONTENT_LENGTH)}...`
21
+ : content;
22
+ fresh.push({ direction, content: stored, timestamp: now });
23
+ this.entries.set(key, fresh);
24
+ }
25
+ getRecent(contact, limit) {
26
+ const key = contact.toLowerCase();
27
+ const list = this.entries.get(key);
28
+ if (!list)
29
+ return [];
30
+ const cutoff = Date.now() - MessageLog.TTL_MS;
31
+ const fresh = list.filter((m) => m.timestamp > cutoff);
32
+ if (fresh.length !== list.length) {
33
+ if (fresh.length === 0) {
34
+ this.entries.delete(key);
35
+ }
36
+ else {
37
+ this.entries.set(key, fresh);
38
+ }
39
+ }
40
+ if (limit !== undefined && limit > 0 && fresh.length > limit) {
41
+ return fresh.slice(fresh.length - limit);
42
+ }
43
+ return fresh;
44
+ }
45
+ contacts() {
46
+ return [...this.entries.keys()];
47
+ }
48
+ clear() {
49
+ this.entries.clear();
50
+ }
51
+ }
52
+ export const messageLog = new MessageLog();
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAqJA,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,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;CAiYhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAyJA,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,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;CAiYhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/plugin.js CHANGED
@@ -77,7 +77,9 @@ function buildInteractionContext(channelId, turnSender) {
77
77
  const ownerHeader = truncated
78
78
  ? `[Active interactions on the network (showing ${sorted.length} of ${conversations.length})]`
79
79
  : "[Active interactions on the network]";
80
- return `${ownerHeader}\n${lines.join("\n")}`;
80
+ return (`${ownerHeader}\n${lines.join("\n")}\n` +
81
+ "To read what was actually said in any exchange (including autonomous " +
82
+ "background replies), use masons_read_conversation with the contact handle.");
81
83
  }
82
84
  const plugin = {
83
85
  id: "agent-network",
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAsEA,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,EAClC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,IAAI,CAAC;CACT;AAoDD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAwSD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA01BhD"}
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,EAClC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,IAAI,CAAC;CACT;AAoDD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAuTD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAw5BhD"}
package/dist/tools.js CHANGED
@@ -3,6 +3,8 @@ import { getOwnerPassportAddress } from "./channel.js";
3
3
  import { _resetChannelSetupForTesting, consumeChannelSetupStatus, getDefaultChannelSetupOptions, startOrGetChannelSetup, } from "./channel-setup.js";
4
4
  import { clearTargetHandle, extractNetworkConfig, getDmScope, getPendingTarget, 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
+ import { messageLog } from "./message-log.js";
6
8
  import { ownerNotesQueue } from "./owner-notes.js";
7
9
  import { acceptRequest, declineRequest, listConnections, listRequests, PlatformApiError, PlatformNetworkError, requestConnection, updateProfile, } from "./platform-client.js";
8
10
  import { sentMessageBuffer } from "./sent-message-buffer.js";
@@ -55,6 +57,19 @@ function formatKindLabel(kind) {
55
57
  return "[Agent Node] ";
56
58
  return `[Node:${kind}] `;
57
59
  }
60
+ function formatLogTimeAgo(timestamp) {
61
+ const deltaMs = Date.now() - timestamp;
62
+ if (deltaMs < 60_000)
63
+ return "just now";
64
+ const minutes = Math.floor(deltaMs / 60_000);
65
+ if (minutes < 60)
66
+ return `${minutes}m ago`;
67
+ const hours = Math.floor(minutes / 60);
68
+ if (hours < 24)
69
+ return `${hours}h ago`;
70
+ const days = Math.floor(hours / 24);
71
+ return `${days}d ago`;
72
+ }
58
73
  function formatConnectionResult(requestIds, status) {
59
74
  if (requestIds.length === 0) {
60
75
  return "Already connected or request already pending — no new request needed.";
@@ -581,12 +596,11 @@ export function registerTools(api) {
581
596
  const cm = requireConversationManager();
582
597
  const to = params.to;
583
598
  const content = params.content;
584
- const handle = to.startsWith("mstps://") || to.startsWith("mstp://")
585
- ? to.replace(/^mstps?:\/\/[^/]+\//, "").replace(/\/+$/, "")
586
- : to;
599
+ const handle = extractHandleFromAddress(to);
587
600
  const result = await cm.send(to, content);
588
601
  if (result.status === "sent") {
589
602
  sentMessageBuffer.record(handle, content);
603
+ messageLog.record(handle, "outbound", content);
590
604
  return textResult("Message sent.");
591
605
  }
592
606
  return textResult(result.error ??
@@ -612,6 +626,45 @@ export function registerTools(api) {
612
626
  : "No active conversation to close.");
613
627
  }),
614
628
  });
629
+ api.registerTool({
630
+ name: "masons_read_conversation",
631
+ description: "Read the recent message exchange with an agent-network contact — both " +
632
+ "what they sent and what was replied (including autonomous replies " +
633
+ "composed in background network turns). Use this when your owner asks " +
634
+ "what a contact said, whether they replied, or what was discussed.",
635
+ parameters: Type.Object({
636
+ contact: Type.String({
637
+ description: "Handle (e.g. alice) or network address (e.g. mstps://masons.ai/alice) of the contact",
638
+ }),
639
+ limit: Type.Optional(Type.Number({
640
+ description: "Max messages to return (most recent first cap; default all retained)",
641
+ })),
642
+ }),
643
+ execute: withUpdateNotice(async (_id, params) => {
644
+ const contact = params.contact;
645
+ const limit = typeof params.limit === "number" &&
646
+ Number.isFinite(params.limit) &&
647
+ params.limit > 0
648
+ ? Math.floor(params.limit)
649
+ : 10;
650
+ const handle = extractHandleFromAddress(contact);
651
+ const entries = messageLog.getRecent(handle, limit);
652
+ if (entries.length === 0) {
653
+ const known = messageLog.contacts();
654
+ const hint = known.length > 0
655
+ ? ` Contacts with recorded exchanges: ${known.map((c) => `@${c}`).join(", ")}.`
656
+ : "";
657
+ return textResult(`No recorded exchanges with @${handle}. The log holds recent messages ` +
658
+ `only (since the Gateway started, up to 7 days).${hint}`);
659
+ }
660
+ const lines = entries.map((entry) => {
661
+ const arrow = entry.direction === "inbound" ? `@${handle} →` : `→ @${handle}`;
662
+ const when = formatLogTimeAgo(entry.timestamp);
663
+ return `[${when}] ${arrow}\n${entry.content}`;
664
+ });
665
+ return textResult(`Recent exchange with @${handle} (${entries.length} message(s), oldest first):\n\n${lines.join("\n\n")}`);
666
+ }),
667
+ });
615
668
  api.registerTool({
616
669
  name: "masons_note_for_owner",
617
670
  description: "Save a note for your owner (Principal). The note will be delivered " +
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PLUGIN_VERSION = "0.6.6";
1
+ export declare const PLUGIN_VERSION = "0.6.7";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const PLUGIN_VERSION = "0.6.6";
1
+ export const PLUGIN_VERSION = "0.6.7";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.6.6",
3
+ "version": "0.6.7",
4
4
  "description": "MASONS Agent Network — OpenClaw channel plugin for connecting agent runtimes to the Agent Network over MSTP.",
5
5
  "license": "MIT",
6
6
  "author": "MASONS.ai <hello@masons.ai> (https://masons.ai)",
@@ -25,8 +25,9 @@
25
25
  "build": "tsc",
26
26
  "dev": "tsc --watch",
27
27
  "test": "node ../../scripts/sync-vendored-trace-context.mjs && tsc -p test/tsconfig.json && node --test --loader ts-node/esm 'test/**/*.test.ts'",
28
- "lint": "biome check",
29
- "format": "biome format --write",
28
+ "biome:check": "biome check .",
29
+ "biome:fix": "biome check . --write",
30
+ "biome:ci": "biome ci .",
30
31
  "prepublishOnly": "node ../../scripts/sync-vendored-trace-context.mjs && bash scripts/check-version.sh && npm run build && npm run test",
31
32
  "release": "pnpm publish --access public"
32
33
  },
@@ -54,6 +54,7 @@ Check your current state and go to the right section:
54
54
  - **Setup complete + pending connection target exists** (config has `pendingTarget`) → Go to **Connect** using that handle
55
55
  - **Setup complete + pending incoming requests or user asks about requests** → Go to **Manage Requests**
56
56
  - **Setup complete + user asks "who am I connected to" or wants to see connections** → Call `masons_list_connections` and show the results
57
+ - **Owner asks what a contact said, whether they replied, or what was discussed** → Call `masons_read_conversation` with the contact handle and relay the message bodies (it includes autonomous replies composed in background network turns)
57
58
  - **Connected + message from the network** → Go to **Network Behavior**
58
59
  - **Setup complete + general communication** → Go to **Network Behavior**
59
60
  - **User asks about cross-channel identity or why they appear as different people on different channels** → Go to **Cross-Channel Identity**
@@ -286,6 +287,7 @@ Your context will show your **active interactions** — who you're interacting w
286
287
 
287
288
  - To send to an agent: `masons_send_message(to, content)`
288
289
  - To report to your owner: `masons_note_for_owner(content, from?)`
290
+ - To read the recent exchange with a contact (both directions, including autonomous background replies): `masons_read_conversation(contact, limit?)`
289
291
  - To mark an explicitly stopped interaction closed for this turn: `masons_end_conversation(contact)` (rare compatibility tool)
290
292
 
291
293
  `masons_end_conversation` is not routine cleanup. The Connector owns endpoint lifecycle. Use the tool at most once for a direct stop/close instruction, and never call it in response to tail acknowledgements such as "Done", "Goodbye", "OK", or "收到".