@relaymessenger/openclaw-plugin 0.3.0 → 0.3.3
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/dist/src/channel.js +8 -6
- package/dist/src/client.js +14 -4
- package/dist/src/responding.js +13 -0
- package/package.json +1 -1
- package/src/channel.ts +8 -6
- package/src/client.ts +21 -4
- package/src/responding.ts +21 -0
package/dist/src/channel.js
CHANGED
|
@@ -27,6 +27,7 @@ import { buildRelayInboundFacts } from "./inbound.js";
|
|
|
27
27
|
import { createRelayAccountLifecycleRegistry } from "./lifecycle.js";
|
|
28
28
|
import { deriveRelayIdempotencyKey, RELAY_TEXT_CHUNK_LIMIT, reconcileRelayUnknownSend, sendRelayText, } from "./outbound.js";
|
|
29
29
|
import { runRelayPollLoop } from "./poll-loop.js";
|
|
30
|
+
import { markRespondingBeforeAttempt } from "./responding.js";
|
|
30
31
|
import { getRelayRuntime } from "./runtime.js";
|
|
31
32
|
import { relaySenderIsAllowed, resolveRelayAllowedSenderIds } from "./security.js";
|
|
32
33
|
export const RELAY_CHANNEL_ID = "relay";
|
|
@@ -244,7 +245,13 @@ async function dispatchRelayInbound(params) {
|
|
|
244
245
|
// Admission, runtime resolution, route/session lookup, envelope building,
|
|
245
246
|
// and context finalization above are replay-safe. The durable attempt starts
|
|
246
247
|
// immediately before OpenClaw can invoke the agent or its tools.
|
|
247
|
-
await
|
|
248
|
+
await markRespondingBeforeAttempt({
|
|
249
|
+
client: params.client,
|
|
250
|
+
conversationId: facts.conversationId,
|
|
251
|
+
messageId: facts.messageId,
|
|
252
|
+
label: "OpenClaw",
|
|
253
|
+
markAttempt: params.markAttempt,
|
|
254
|
+
});
|
|
248
255
|
await runtime.channel.inbound.dispatchReply({
|
|
249
256
|
cfg: params.cfg,
|
|
250
257
|
channel: RELAY_CHANNEL_ID,
|
|
@@ -434,11 +441,6 @@ async function startRelayAccount(ctx) {
|
|
|
434
441
|
allowedSenderIds,
|
|
435
442
|
markAttempt,
|
|
436
443
|
});
|
|
437
|
-
// Read watermark after the turn is handled: read implies delivered;
|
|
438
|
-
// best effort — a failed receipt must not replay the event.
|
|
439
|
-
await client
|
|
440
|
-
.markRead({ conversationId: facts.conversationId, messageId: facts.messageId })
|
|
441
|
-
.catch((error) => log(`[relay] markRead failed: ${String(error)}`));
|
|
442
444
|
},
|
|
443
445
|
});
|
|
444
446
|
}
|
package/dist/src/client.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// Thin Relay REST client for the OpenClaw channel plugin.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// without an OpenClaw runtime.
|
|
1
|
+
// Thin Relay REST client boundary for the standalone OpenClaw channel plugin.
|
|
2
|
+
// Owns the abort-aware long poll, idempotent sends, typing, responding, and
|
|
3
|
+
// read watermarks without loading an OpenClaw runtime in unit tests.
|
|
5
4
|
import { isIP } from "node:net";
|
|
6
5
|
export const DEFAULT_RELAY_BASE_URL = "https://api.relayapp.im";
|
|
7
6
|
function isLoopbackHostname(hostname) {
|
|
@@ -207,6 +206,17 @@ export function createRelayClient(options) {
|
|
|
207
206
|
signal: params.signal,
|
|
208
207
|
});
|
|
209
208
|
},
|
|
209
|
+
setResponding: async (params) => {
|
|
210
|
+
await request({
|
|
211
|
+
method: "POST",
|
|
212
|
+
path: `/v1/conversations/${encodeURIComponent(params.conversationId)}/responding`,
|
|
213
|
+
body: {
|
|
214
|
+
message_id: params.messageId,
|
|
215
|
+
...(params.label ? { label: params.label } : {}),
|
|
216
|
+
},
|
|
217
|
+
signal: params.signal,
|
|
218
|
+
});
|
|
219
|
+
},
|
|
210
220
|
markRead: async (params) => {
|
|
211
221
|
await request({
|
|
212
222
|
method: "POST",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The receipt must commit before OpenClaw can run an agent or tool. A rejected
|
|
3
|
+
* receipt leaves the durable attempt marker untouched, so the poll loop can
|
|
4
|
+
* replay the event safely instead of hiding the failure after execution.
|
|
5
|
+
*/
|
|
6
|
+
export async function markRespondingBeforeAttempt(params) {
|
|
7
|
+
await params.client.setResponding({
|
|
8
|
+
conversationId: params.conversationId,
|
|
9
|
+
messageId: params.messageId,
|
|
10
|
+
label: params.label,
|
|
11
|
+
});
|
|
12
|
+
await params.markAttempt();
|
|
13
|
+
}
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
sendRelayText,
|
|
51
51
|
} from "./outbound.js";
|
|
52
52
|
import { runRelayPollLoop } from "./poll-loop.js";
|
|
53
|
+
import { markRespondingBeforeAttempt } from "./responding.js";
|
|
53
54
|
import { getRelayRuntime } from "./runtime.js";
|
|
54
55
|
import { relaySenderIsAllowed, resolveRelayAllowedSenderIds } from "./security.js";
|
|
55
56
|
import type { RelayCoreConfig, ResolvedRelayAccount } from "./types.js";
|
|
@@ -286,7 +287,13 @@ async function dispatchRelayInbound(params: {
|
|
|
286
287
|
// Admission, runtime resolution, route/session lookup, envelope building,
|
|
287
288
|
// and context finalization above are replay-safe. The durable attempt starts
|
|
288
289
|
// immediately before OpenClaw can invoke the agent or its tools.
|
|
289
|
-
await
|
|
290
|
+
await markRespondingBeforeAttempt({
|
|
291
|
+
client: params.client,
|
|
292
|
+
conversationId: facts.conversationId,
|
|
293
|
+
messageId: facts.messageId,
|
|
294
|
+
label: "OpenClaw",
|
|
295
|
+
markAttempt: params.markAttempt,
|
|
296
|
+
});
|
|
290
297
|
await runtime.channel.inbound.dispatchReply({
|
|
291
298
|
cfg: params.cfg,
|
|
292
299
|
channel: RELAY_CHANNEL_ID,
|
|
@@ -492,11 +499,6 @@ async function startRelayAccount(ctx: ChannelGatewayContext<ResolvedRelayAccount
|
|
|
492
499
|
allowedSenderIds,
|
|
493
500
|
markAttempt,
|
|
494
501
|
});
|
|
495
|
-
// Read watermark after the turn is handled: read implies delivered;
|
|
496
|
-
// best effort — a failed receipt must not replay the event.
|
|
497
|
-
await client
|
|
498
|
-
.markRead({ conversationId: facts.conversationId, messageId: facts.messageId })
|
|
499
|
-
.catch((error) => log(`[relay] markRead failed: ${String(error)}`));
|
|
500
502
|
},
|
|
501
503
|
});
|
|
502
504
|
} catch (error) {
|
package/src/client.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// Thin Relay REST client for the OpenClaw channel plugin.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// without an OpenClaw runtime.
|
|
1
|
+
// Thin Relay REST client boundary for the standalone OpenClaw channel plugin.
|
|
2
|
+
// Owns the abort-aware long poll, idempotent sends, typing, responding, and
|
|
3
|
+
// read watermarks without loading an OpenClaw runtime in unit tests.
|
|
5
4
|
import { isIP } from "node:net";
|
|
6
5
|
import type {
|
|
7
6
|
RelayAgentProfile,
|
|
@@ -146,6 +145,12 @@ export type RelayClient = {
|
|
|
146
145
|
label?: string;
|
|
147
146
|
signal?: AbortSignal;
|
|
148
147
|
}) => Promise<void>;
|
|
148
|
+
setResponding: (params: {
|
|
149
|
+
conversationId: string;
|
|
150
|
+
messageId: string;
|
|
151
|
+
label?: string;
|
|
152
|
+
signal?: AbortSignal;
|
|
153
|
+
}) => Promise<void>;
|
|
149
154
|
markRead: (params: {
|
|
150
155
|
conversationId: string;
|
|
151
156
|
messageId: string;
|
|
@@ -301,6 +306,18 @@ export function createRelayClient(options: RelayClientOptions): RelayClient {
|
|
|
301
306
|
});
|
|
302
307
|
},
|
|
303
308
|
|
|
309
|
+
setResponding: async (params) => {
|
|
310
|
+
await request({
|
|
311
|
+
method: "POST",
|
|
312
|
+
path: `/v1/conversations/${encodeURIComponent(params.conversationId)}/responding`,
|
|
313
|
+
body: {
|
|
314
|
+
message_id: params.messageId,
|
|
315
|
+
...(params.label ? { label: params.label } : {}),
|
|
316
|
+
},
|
|
317
|
+
signal: params.signal,
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
|
|
304
321
|
markRead: async (params) => {
|
|
305
322
|
await request({
|
|
306
323
|
method: "POST",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RelayClient } from "./client.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The receipt must commit before OpenClaw can run an agent or tool. A rejected
|
|
5
|
+
* receipt leaves the durable attempt marker untouched, so the poll loop can
|
|
6
|
+
* replay the event safely instead of hiding the failure after execution.
|
|
7
|
+
*/
|
|
8
|
+
export async function markRespondingBeforeAttempt(params: {
|
|
9
|
+
client: RelayClient;
|
|
10
|
+
conversationId: string;
|
|
11
|
+
messageId: string;
|
|
12
|
+
label: string;
|
|
13
|
+
markAttempt: () => Promise<void>;
|
|
14
|
+
}): Promise<void> {
|
|
15
|
+
await params.client.setResponding({
|
|
16
|
+
conversationId: params.conversationId,
|
|
17
|
+
messageId: params.messageId,
|
|
18
|
+
label: params.label,
|
|
19
|
+
});
|
|
20
|
+
await params.markAttempt();
|
|
21
|
+
}
|