openclaw-msg9 0.2.0 → 0.2.1

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.
@@ -23,8 +23,10 @@ export declare function resolveInboundCommandAuthorization(params: {
23
23
  * Poll the msg9 inbox until the abort signal fires.
24
24
  *
25
25
  * Each sweep drains `agent.unread()` fully. Every message is deduped by
26
- * message_id, allowFrom-filtered (non-listed senders are marked read and
27
- * skipped), then marked processed BEFORE dispatch so the agent is driven
28
- * at-most-once even if dispatch or delivery fails.
26
+ * message_id, self-echo-filtered (mail from this account's own address is a
27
+ * reply that landed back in the same inbox marked processed and skipped so
28
+ * the agent never talks to itself), allowFrom-filtered (non-listed senders
29
+ * are marked read and skipped), then marked processed BEFORE dispatch so the
30
+ * agent is driven at-most-once even if dispatch or delivery fails.
29
31
  */
30
32
  export declare function startGateway(ctx: GatewayContext): Promise<void>;
@@ -62,9 +62,11 @@ function formatInboundEnvelope(pluginRuntime, params) {
62
62
  * Poll the msg9 inbox until the abort signal fires.
63
63
  *
64
64
  * Each sweep drains `agent.unread()` fully. Every message is deduped by
65
- * message_id, allowFrom-filtered (non-listed senders are marked read and
66
- * skipped), then marked processed BEFORE dispatch so the agent is driven
67
- * at-most-once even if dispatch or delivery fails.
65
+ * message_id, self-echo-filtered (mail from this account's own address is a
66
+ * reply that landed back in the same inbox marked processed and skipped so
67
+ * the agent never talks to itself), allowFrom-filtered (non-listed senders
68
+ * are marked read and skipped), then marked processed BEFORE dispatch so the
69
+ * agent is driven at-most-once even if dispatch or delivery fails.
68
70
  */
69
71
  export async function startGateway(ctx) {
70
72
  const { account, abortSignal, cfg, onReady, onError, log } = ctx;
@@ -92,6 +94,15 @@ export async function startGateway(ctx) {
92
94
  }
93
95
  seenMessageIds.add(messageId);
94
96
  const from = message.from_address;
97
+ // Self-echo filter: a reply this account sent to its own address lands
98
+ // back in the same inbox and would otherwise be dispatched as new
99
+ // inbound mail, re-triggering the agent in an infinite loop. Consume
100
+ // (markProcessed) and never dispatch.
101
+ if (from === account.address) {
102
+ log?.info(`[msg9:${account.accountId}] Ignoring self-addressed echo msg=${messageId}`);
103
+ await agent.markProcessed(messageId);
104
+ continue;
105
+ }
95
106
  // allowFrom check — blocked senders stay visible in the owner's
96
107
  // unprocessed folder but never reach the agent.
97
108
  if (account.allowFrom && account.allowFrom.length > 0 && !account.allowFrom.includes(from)) {
@@ -2,7 +2,7 @@
2
2
  "id": "openclaw-msg9",
3
3
  "name": "msg9",
4
4
  "description": "msg9.io channel plugin — turn a msg9 agent inbox into an OpenClaw channel",
5
- "version": "0.2.0",
5
+ "version": "0.2.1",
6
6
  "channels": ["msg9"],
7
7
  "channelEnvVars": {
8
8
  "msg9": [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openclaw-msg9",
3
3
  "displayName": "OpenClaw msg9",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "description": "OpenClaw msg9.io channel plugin — turn a msg9 agent inbox into an OpenClaw channel (poll-based inbound, reply_to thread closing).",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",