@clawling/clawchat-plugin-openclaw 2026.8.27-2 → 2026.9.1-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.
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Synthetic reasoning-turn builder for `friend.request` notify.signal events.
3
+ *
4
+ * When the server fires a `friend.request` signal the runtime dispatches one
5
+ * deduped synthetic `message.send` envelope so the agent can reason about the
6
+ * pending request. The prompt text varies by the current "friend.add" permission
7
+ * policy state: a deny policy yields a decline/inform prompt; ask or allow
8
+ * yields a prompt that instructs the agent to review the request via the
9
+ * `clawchat_list_friend_requests` tool.
10
+ */
11
+ import { EVENT } from "./protocol-types.js";
12
+ /**
13
+ * Returns canned prompt text for a friend-request reasoning turn based on the
14
+ * current "friend.add" permission policy state.
15
+ *
16
+ * - `deny` → inform the agent it should decline; no accept instruction.
17
+ * - `ask` / `allow` → instruct the agent to review the pending request.
18
+ *
19
+ * The requester's user id is embedded so the agent does not go looking up the
20
+ * synthetic sender ("clawchat-friend-request" is not a real user).
21
+ */
22
+ export function friendRequestPromptFor(state, requesterUserId) {
23
+ const arrived = requesterUserId
24
+ ? `A new friend request has arrived from user ${requesterUserId}.`
25
+ : "A new friend request has arrived.";
26
+ if (state === "deny") {
27
+ return [
28
+ arrived,
29
+ "Your current friend-add policy is set to deny.",
30
+ "Do not add this contact.",
31
+ "You may inform the requester that you cannot add them at this time.",
32
+ ].join(" ");
33
+ }
34
+ return [
35
+ arrived,
36
+ "Please review the pending request by calling `clawchat_list_friend_requests`",
37
+ "and decide whether to accept it.",
38
+ ].join(" ");
39
+ }
40
+ /**
41
+ * Builds a synthetic `message.send` envelope that triggers one agent reasoning
42
+ * turn for a pending friend request. The envelope shape mirrors the
43
+ * activation-bootstrap envelope; it targets the owner's direct conversation so
44
+ * the agent has context about who it is reasoning for.
45
+ */
46
+ export function buildFriendRequestEnvelope(params) {
47
+ const { account, state, entityId, ownerConversationId } = params;
48
+ const text = friendRequestPromptFor(state, entityId);
49
+ const now = Date.now();
50
+ // Fall back to ownerUserId only when no activation conversation is recorded:
51
+ // the turn still runs (the agent can act via tools, e.g. accept the request),
52
+ // but its in-chat replies will not be deliverable until activation records
53
+ // the owner conversation.
54
+ return {
55
+ version: "2",
56
+ event: EVENT.MESSAGE_SEND,
57
+ trace_id: `clawchat-plugin-openclaw-friend-request-${entityId}-${now}`,
58
+ emitted_at: now,
59
+ chat_id: ownerConversationId ?? account.ownerUserId,
60
+ chat_type: "direct",
61
+ to: { id: account.userId, type: "direct" },
62
+ sender: {
63
+ id: "clawchat-friend-request",
64
+ type: "direct",
65
+ nick_name: "ClawChat",
66
+ },
67
+ payload: {
68
+ message_id: `clawchat-plugin-openclaw-friend-request-${entityId}-${now}`,
69
+ message_mode: "normal",
70
+ message: {
71
+ body: { fragments: [{ kind: "text", text }] },
72
+ context: { mentions: [], reply: null },
73
+ streaming: {
74
+ status: "static",
75
+ sequence: 0,
76
+ mutation_policy: "sealed",
77
+ started_at: null,
78
+ completed_at: null,
79
+ },
80
+ },
81
+ },
82
+ };
83
+ }
@@ -2352,7 +2352,6 @@ export async function startOpenclawClawlingGateway(params) {
2352
2352
  };
2353
2353
  const dispatchTurnToAgent = async (turn) => {
2354
2354
  const rt = runtime.channel;
2355
- const storePath = rt.session.resolveStorePath(cfg.session?.store);
2356
2355
  const routeCfg = withClawChatSessionScope(cfg);
2357
2356
  const route = rt.routing.resolveAgentRoute({
2358
2357
  cfg: routeCfg,
@@ -2360,6 +2359,13 @@ export async function startOpenclawClawlingGateway(params) {
2360
2359
  accountId,
2361
2360
  peer: turn.peer,
2362
2361
  });
2362
+ // OpenClaw >=2026.8 (roster-only refactor, openclaw#112678) throws
2363
+ // SessionStoreAgentIdRequiredError when `session.store` is unset and no agentId is
2364
+ // supplied — that killed every inbound turn. Older hosts already accepted
2365
+ // `opts.agentId` and merely defaulted it to "main", so passing the routed id is
2366
+ // correct on the whole supported range and resolves to the same path for a
2367
+ // single-agent roster. Must stay below resolveAgentRoute: it owns `agentId`.
2368
+ const storePath = rt.session.resolveStorePath(cfg.session?.store, { agentId: route.agentId });
2363
2369
  const memoryRoot = resolveClawChatMemoryRoot(runtime, cfg, route.agentId);
2364
2370
  const body = rt.reply.formatAgentEnvelope({
2365
2371
  channel: "Clawling Chat",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawling/clawchat-plugin-openclaw",
3
- "version": "2026.8.27-2",
3
+ "version": "2026.9.1-1",
4
4
  "description": "OpenClaw ClawChat channel plugin",
5
5
  "license": "MIT",
6
6
  "author": "CLAWLING PTE. LTD.",
package/src/runtime.ts CHANGED
@@ -2818,7 +2818,6 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
2818
2818
 
2819
2819
  const dispatchTurnToAgent = async (turn: IngestTurnParams): Promise<IngestTurnResult> => {
2820
2820
  const rt = runtime.channel;
2821
- const storePath = rt.session.resolveStorePath(cfg.session?.store);
2822
2821
  const routeCfg = withClawChatSessionScope(cfg);
2823
2822
  const route = rt.routing.resolveAgentRoute({
2824
2823
  cfg: routeCfg,
@@ -2826,6 +2825,13 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
2826
2825
  accountId,
2827
2826
  peer: turn.peer,
2828
2827
  });
2828
+ // OpenClaw >=2026.8 (roster-only refactor, openclaw#112678) throws
2829
+ // SessionStoreAgentIdRequiredError when `session.store` is unset and no agentId is
2830
+ // supplied — that killed every inbound turn. Older hosts already accepted
2831
+ // `opts.agentId` and merely defaulted it to "main", so passing the routed id is
2832
+ // correct on the whole supported range and resolves to the same path for a
2833
+ // single-agent roster. Must stay below resolveAgentRoute: it owns `agentId`.
2834
+ const storePath = rt.session.resolveStorePath(cfg.session?.store, { agentId: route.agentId });
2829
2835
  const memoryRoot = resolveClawChatMemoryRoot(runtime, cfg, route.agentId);
2830
2836
  const body = rt.reply.formatAgentEnvelope({
2831
2837
  channel: "Clawling Chat",