@relaymessenger/openclaw-plugin 0.4.7-staging.6 → 0.4.7-staging.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.
@@ -7,8 +7,8 @@
7
7
  },
8
8
  "relaySdk": {
9
9
  "package": "@relaymessenger/sdk",
10
- "version": "0.3.6-staging.5",
11
- "integrity": "sha512-d3LOJaGz0tmJSuGQCVkAZVmSUkBI3vLspItsMlD7ZVL3FMTnR6EekmkPQZX+G2Mr17u0J5PzkjP2Wx17xDlnvw==",
10
+ "version": "0.3.6-staging.6",
11
+ "integrity": "sha512-Amo5nUH/9Rn9pE7PFKXlPUqbvdRXnZ3qWgf5CJErcbNEBSym2C+xC9bxMcPwoVyf9pgeuPpxVJSdaeWQxJ2I3w==",
12
12
  "operationsSha256": "5c482165296df7d0634a0f57950936887b118e7159baf3bdabc42fce0d4fe6d8",
13
13
  "workspaceOpenapiSha256": "ba2d90304cac9ae88a3d1b645c47793ebe376c39ada2799e6e98c99027d7ddb7",
14
14
  "usedOperations": [
@@ -1,5 +1,5 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
- import { partsWithButtons, Relay, RelayAPIError, splitButtons, } from "@relaymessenger/sdk";
2
+ import { answerMessages, indexedIdempotencyKey, Relay, RelayAPIError, } from "@relaymessenger/sdk";
3
3
  export const RELAY_TEXT_CHUNK_LIMIT = 10_000;
4
4
  const IDEMPOTENCY_KEY_MAX_LENGTH = 255;
5
5
  export function createRelaySdkClient(account) {
@@ -19,24 +19,33 @@ export function deriveRelayIdempotencyKey(params) {
19
19
  }
20
20
  /**
21
21
  * OpenClaw hands the agent's words as text, so buttons ride in them as the
22
- * SDK's fenced block, lifted here into the buttons part. A block that cannot
23
- * be read stays in the words and is reported through `onButtonsError`.
22
+ * SDK's fenced block, lifted here into the buttons part, and a link written
23
+ * alone on a line goes out as its own link Message. A block that cannot be
24
+ * read stays in the words and is reported through `onButtonsError`. Without
25
+ * a block or a link line the words go exactly as OpenClaw handed them, in one
26
+ * Message; the response is the first Message's, the one the reply anchors to.
24
27
  */
25
28
  export async function sendRelayText(params) {
26
29
  await params.onPlatformSendDispatch?.();
27
- const { text, buttons, error } = splitButtons(params.text);
30
+ const { messages, error } = answerMessages(params.text);
28
31
  if (error)
29
32
  params.onButtonsError?.(error);
30
- return await params.relay.chats.messages.send(params.chatId, {
31
- message: {
32
- // Without a block the words go exactly as OpenClaw handed them.
33
- parts: buttons ? partsWithButtons(text, buttons) : [{ type: "text", value: params.text }],
34
- idempotency_key: params.idempotencyKey,
35
- ...(params.replyToId
36
- ? { reply_to: { message_id: params.replyToId } }
37
- : {}),
38
- },
39
- }, params.signal ? { signal: params.signal } : undefined);
33
+ if (messages.length === 0)
34
+ messages.push([{ type: "text", value: params.text }]);
35
+ let first;
36
+ for (const [index, parts] of messages.entries()) {
37
+ const response = await params.relay.chats.messages.send(params.chatId, {
38
+ message: {
39
+ parts,
40
+ idempotency_key: indexedIdempotencyKey(params.idempotencyKey, index),
41
+ ...(index === 0 && params.replyToId
42
+ ? { reply_to: { message_id: params.replyToId } }
43
+ : {}),
44
+ },
45
+ }, params.signal ? { signal: params.signal } : undefined);
46
+ first ??= response;
47
+ }
48
+ return first;
40
49
  }
41
50
  export function classifyUnknownRelaySend(error) {
42
51
  if (!(error instanceof RelayAPIError)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relaymessenger/openclaw-plugin",
3
- "version": "0.4.7-staging.6",
3
+ "version": "0.4.7-staging.7",
4
4
  "description": "Native Relay channel plugin for OpenClaw",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,7 +37,7 @@
37
37
  "prepack": "npm run build"
38
38
  },
39
39
  "dependencies": {
40
- "@relaymessenger/sdk": "0.3.6-staging.5"
40
+ "@relaymessenger/sdk": "0.3.6-staging.6"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^26.0.0",
package/src/outbound.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import {
3
- partsWithButtons,
3
+ answerMessages,
4
+ indexedIdempotencyKey,
4
5
  Relay,
5
6
  RelayAPIError,
6
- splitButtons,
7
7
  type MessageSendResponse,
8
8
  } from "@relaymessenger/sdk";
9
9
  import type { ResolvedRelayAccount } from "./types.js";
@@ -36,8 +36,11 @@ export function deriveRelayIdempotencyKey(params: {
36
36
 
37
37
  /**
38
38
  * OpenClaw hands the agent's words as text, so buttons ride in them as the
39
- * SDK's fenced block, lifted here into the buttons part. A block that cannot
40
- * be read stays in the words and is reported through `onButtonsError`.
39
+ * SDK's fenced block, lifted here into the buttons part, and a link written
40
+ * alone on a line goes out as its own link Message. A block that cannot be
41
+ * read stays in the words and is reported through `onButtonsError`. Without
42
+ * a block or a link line the words go exactly as OpenClaw handed them, in one
43
+ * Message; the response is the first Message's, the one the reply anchors to.
41
44
  */
42
45
  export async function sendRelayText(params: {
43
46
  relay: Pick<Relay, "chats">;
@@ -50,22 +53,27 @@ export async function sendRelayText(params: {
50
53
  onButtonsError?: (error: string) => void;
51
54
  }): Promise<MessageSendResponse> {
52
55
  await params.onPlatformSendDispatch?.();
53
- const { text, buttons, error } = splitButtons(params.text);
56
+ const { messages, error } = answerMessages(params.text);
54
57
  if (error) params.onButtonsError?.(error);
55
- return await params.relay.chats.messages.send(
56
- params.chatId,
57
- {
58
- message: {
59
- // Without a block the words go exactly as OpenClaw handed them.
60
- parts: buttons ? partsWithButtons(text, buttons) : [{ type: "text", value: params.text }],
61
- idempotency_key: params.idempotencyKey,
62
- ...(params.replyToId
63
- ? { reply_to: { message_id: params.replyToId } }
64
- : {}),
58
+ if (messages.length === 0) messages.push([{ type: "text", value: params.text }]);
59
+ let first: MessageSendResponse | undefined;
60
+ for (const [index, parts] of messages.entries()) {
61
+ const response = await params.relay.chats.messages.send(
62
+ params.chatId,
63
+ {
64
+ message: {
65
+ parts,
66
+ idempotency_key: indexedIdempotencyKey(params.idempotencyKey, index),
67
+ ...(index === 0 && params.replyToId
68
+ ? { reply_to: { message_id: params.replyToId } }
69
+ : {}),
70
+ },
65
71
  },
66
- },
67
- params.signal ? { signal: params.signal } : undefined,
68
- );
72
+ params.signal ? { signal: params.signal } : undefined,
73
+ );
74
+ first ??= response;
75
+ }
76
+ return first!;
69
77
  }
70
78
 
71
79
  export function classifyUnknownRelaySend(error: unknown): {