@relaymessenger/openclaw-plugin 0.4.7-staging.21 → 0.4.7-staging.23
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.
- package/README.md +6 -4
- package/contracts/relay-v1.lock.json +6 -6
- package/dist/src/dispatch.js +2 -2
- package/dist/src/outbound.js +17 -3
- package/package.json +2 -2
- package/src/dispatch.ts +2 -2
- package/src/outbound.ts +16 -3
package/README.md
CHANGED
|
@@ -26,11 +26,13 @@ checks any number of options and submits them once; checking sends nothing, and
|
|
|
26
26
|
a person answers a given selection once. iOS may draw a checkmark in place of
|
|
27
27
|
each bullet and repeat the prompt's title, as presentation only.
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Payment
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
The agent ends the final answer with a `payment` JSON fence holding the
|
|
32
|
+
payment request's fields (`description`, `category`, and `amount` with
|
|
33
|
+
`currency`, or `mode: "subscription"` with `price_id`). The plugin creates the
|
|
34
|
+
request with its own Relay token, on the card's own idempotency key; the words
|
|
35
|
+
go first and the payment card follows as its own Message.
|
|
34
36
|
|
|
35
37
|
## Install
|
|
36
38
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"relayServer": {
|
|
3
3
|
"repository": "RelayMessenger/Relay-Server",
|
|
4
|
-
"commit": "
|
|
4
|
+
"commit": "51bc3ecd9b203a3fc75fe0ab7a105b6751080678",
|
|
5
5
|
"openapiPath": "contracts/developer/openapi.yaml",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "7b41c21bebd99d28d103da1c3fe380642542e5b6243bb4319e501d7609d8ab0f"
|
|
7
7
|
},
|
|
8
8
|
"relaySdk": {
|
|
9
9
|
"package": "@relaymessenger/sdk",
|
|
10
|
-
"version": "0.3.6-staging.
|
|
11
|
-
"integrity": "sha512-
|
|
12
|
-
"operationsSha256": "
|
|
13
|
-
"workspaceOpenapiSha256": "
|
|
10
|
+
"version": "0.3.6-staging.25",
|
|
11
|
+
"integrity": "sha512-OHmpqxGHc5DRjIaNc+5v5m7zuf7+y+5032Ca6lCvNajUUtkLeYp4TGMxzGTzCUg3Kmv62Kj7HE2wpQn1hfZxuQ==",
|
|
12
|
+
"operationsSha256": "2480be91815b2e9e35305026b0a6ef61ddf2bb6db1b349d2a6da3eb875f4707f",
|
|
13
|
+
"workspaceOpenapiSha256": "7b41c21bebd99d28d103da1c3fe380642542e5b6243bb4319e501d7609d8ab0f",
|
|
14
14
|
"usedOperations": [
|
|
15
15
|
{
|
|
16
16
|
"method": "GET",
|
package/dist/src/dispatch.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BUTTONS_GUIDANCE, BUTTONS_BLOCK_INSTRUCTION,
|
|
1
|
+
import { BUTTONS_GUIDANCE, BUTTONS_BLOCK_INSTRUCTION, PAYMENT_BLOCK_INSTRUCTION, PAYMENT_GUIDANCE, LINK_LINE_INSTRUCTION, SELECTION_GUIDANCE, SELECTION_BLOCK_INSTRUCTION, selectionReplyContext } from "@relaymessenger/sdk";
|
|
2
2
|
import { buildChannelInboundEventContext, resolveChannelInboundRouteEnvelope, } from "openclaw/plugin-sdk/channel-inbound";
|
|
3
3
|
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
4
4
|
import { bindIngressLifecycleToReplyOptions } from "openclaw/plugin-sdk/channel-outbound";
|
|
@@ -179,7 +179,7 @@ export async function dispatchRelayEvent(params) {
|
|
|
179
179
|
inboundEventKind: "user_request",
|
|
180
180
|
body,
|
|
181
181
|
bodyForAgent: [facts.text, selectionReplyContext(facts.selection, facts.richMessage),
|
|
182
|
-
`${BUTTONS_BLOCK_INSTRUCTION} ${LINK_LINE_INSTRUCTION} ${BUTTONS_GUIDANCE} ${SELECTION_BLOCK_INSTRUCTION} ${SELECTION_GUIDANCE} ${
|
|
182
|
+
`${BUTTONS_BLOCK_INSTRUCTION} ${LINK_LINE_INSTRUCTION} ${BUTTONS_GUIDANCE} ${SELECTION_BLOCK_INSTRUCTION} ${SELECTION_GUIDANCE} ${PAYMENT_BLOCK_INSTRUCTION} ${PAYMENT_GUIDANCE}`,
|
|
183
183
|
].filter(Boolean).join("\n\n"),
|
|
184
184
|
rawBody: facts.text,
|
|
185
185
|
commandBody: facts.text,
|
package/dist/src/outbound.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { answerMessages, indexedIdempotencyKey, Relay, RelayAPIError, } from "@relaymessenger/sdk";
|
|
2
|
+
import { answerMessages, createPaymentPart, 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) {
|
|
@@ -27,11 +27,25 @@ export function deriveRelayIdempotencyKey(params) {
|
|
|
27
27
|
*/
|
|
28
28
|
export async function sendRelayText(params) {
|
|
29
29
|
await params.onPlatformSendDispatch?.();
|
|
30
|
-
const { messages, error } = answerMessages(params.text);
|
|
30
|
+
const { messages, payment, error } = answerMessages(params.text);
|
|
31
31
|
if (error)
|
|
32
32
|
params.onButtonsError?.(error);
|
|
33
|
-
if (messages.length === 0)
|
|
33
|
+
if (messages.length === 0 && !payment)
|
|
34
34
|
messages.push([{ type: "text", value: params.text }]);
|
|
35
|
+
if (payment) {
|
|
36
|
+
// Created with the card's own key, so a retry of this delivery returns
|
|
37
|
+
// the same request. A refusal after words went out is reported and the
|
|
38
|
+
// words stand; with nothing sent yet, it is the delivery's own error.
|
|
39
|
+
const key = indexedIdempotencyKey(params.idempotencyKey, messages.length);
|
|
40
|
+
try {
|
|
41
|
+
messages.push([await createPaymentPart(params.relay, payment, key, params.signal ? { signal: params.signal } : undefined)]);
|
|
42
|
+
}
|
|
43
|
+
catch (refusal) {
|
|
44
|
+
if (!(refusal instanceof RelayAPIError) || refusal.retryable || messages.length === 0)
|
|
45
|
+
throw refusal;
|
|
46
|
+
params.onButtonsError?.(`the payment was not sent: ${refusal.message}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
35
49
|
let first;
|
|
36
50
|
for (const [index, parts] of messages.entries()) {
|
|
37
51
|
const response = await params.relay.chats.messages.send(params.chatId, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@relaymessenger/openclaw-plugin",
|
|
3
|
-
"version": "0.4.7-staging.
|
|
3
|
+
"version": "0.4.7-staging.23",
|
|
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.
|
|
40
|
+
"@relaymessenger/sdk": "0.3.6-staging.25"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^26.6.2",
|
package/src/dispatch.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BUTTONS_GUIDANCE, BUTTONS_BLOCK_INSTRUCTION,
|
|
1
|
+
import { BUTTONS_GUIDANCE, BUTTONS_BLOCK_INSTRUCTION, PAYMENT_BLOCK_INSTRUCTION, PAYMENT_GUIDANCE, LINK_LINE_INSTRUCTION, SELECTION_GUIDANCE, SELECTION_BLOCK_INSTRUCTION, selectionReplyContext } from "@relaymessenger/sdk";
|
|
2
2
|
import type {
|
|
3
3
|
Message,
|
|
4
4
|
Relay,
|
|
@@ -245,7 +245,7 @@ export async function dispatchRelayEvent(params: {
|
|
|
245
245
|
inboundEventKind: "user_request",
|
|
246
246
|
body,
|
|
247
247
|
bodyForAgent: [facts.text, selectionReplyContext(facts.selection, facts.richMessage),
|
|
248
|
-
`${BUTTONS_BLOCK_INSTRUCTION} ${LINK_LINE_INSTRUCTION} ${BUTTONS_GUIDANCE} ${SELECTION_BLOCK_INSTRUCTION} ${SELECTION_GUIDANCE} ${
|
|
248
|
+
`${BUTTONS_BLOCK_INSTRUCTION} ${LINK_LINE_INSTRUCTION} ${BUTTONS_GUIDANCE} ${SELECTION_BLOCK_INSTRUCTION} ${SELECTION_GUIDANCE} ${PAYMENT_BLOCK_INSTRUCTION} ${PAYMENT_GUIDANCE}`,
|
|
249
249
|
].filter(Boolean).join("\n\n"),
|
|
250
250
|
rawBody: facts.text,
|
|
251
251
|
commandBody: facts.text,
|
package/src/outbound.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import {
|
|
3
3
|
answerMessages,
|
|
4
|
+
createPaymentPart,
|
|
4
5
|
indexedIdempotencyKey,
|
|
5
6
|
Relay,
|
|
6
7
|
RelayAPIError,
|
|
@@ -43,7 +44,7 @@ export function deriveRelayIdempotencyKey(params: {
|
|
|
43
44
|
* Message; the response is the first Message's, the one the reply anchors to.
|
|
44
45
|
*/
|
|
45
46
|
export async function sendRelayText(params: {
|
|
46
|
-
relay: Pick<Relay, "chats">;
|
|
47
|
+
relay: Pick<Relay, "chats" | "paymentRequests">;
|
|
47
48
|
chatId: string;
|
|
48
49
|
text: string;
|
|
49
50
|
replyToId?: string | null | undefined;
|
|
@@ -53,9 +54,21 @@ export async function sendRelayText(params: {
|
|
|
53
54
|
onButtonsError?: (error: string) => void;
|
|
54
55
|
}): Promise<MessageSendResponse> {
|
|
55
56
|
await params.onPlatformSendDispatch?.();
|
|
56
|
-
const { messages, error } = answerMessages(params.text);
|
|
57
|
+
const { messages, payment, error } = answerMessages(params.text);
|
|
57
58
|
if (error) params.onButtonsError?.(error);
|
|
58
|
-
if (messages.length === 0) messages.push([{ type: "text", value: params.text }]);
|
|
59
|
+
if (messages.length === 0 && !payment) messages.push([{ type: "text", value: params.text }]);
|
|
60
|
+
if (payment) {
|
|
61
|
+
// Created with the card's own key, so a retry of this delivery returns
|
|
62
|
+
// the same request. A refusal after words went out is reported and the
|
|
63
|
+
// words stand; with nothing sent yet, it is the delivery's own error.
|
|
64
|
+
const key = indexedIdempotencyKey(params.idempotencyKey, messages.length);
|
|
65
|
+
try {
|
|
66
|
+
messages.push([await createPaymentPart(params.relay, payment, key, params.signal ? { signal: params.signal } : undefined)]);
|
|
67
|
+
} catch (refusal) {
|
|
68
|
+
if (!(refusal instanceof RelayAPIError) || refusal.retryable || messages.length === 0) throw refusal;
|
|
69
|
+
params.onButtonsError?.(`the payment was not sent: ${refusal.message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
59
72
|
let first: MessageSendResponse | undefined;
|
|
60
73
|
for (const [index, parts] of messages.entries()) {
|
|
61
74
|
const response = await params.relay.chats.messages.send(
|