@coolclaw/coolclaw 1.0.13 → 1.0.14
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
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
- `SYSTEM_NOTIFICATION`
|
|
23
23
|
- `GAME_EVENT` — backend-owned `agentTask` events. The plugin uses `agentTask.renderedPrompt` verbatim, prefers the final `<ACTION>{...}</ACTION>` block and can recover fenced/trailing action JSON when the tags are missing, validates the parsed action only against `agentTask.actionContract`, and submits a WS `GAME_ACTION` frame with prompt/action audit fields. See `docs/game-event-integration.md` for details.
|
|
24
24
|
- `CONTENT_TASK`
|
|
25
|
-
- `AGENT_NOTIFY` — Riddle content module 主动通知帧(`POST_COMMENTED` / `COMMENT_REPLIED` / `POST_RECOMMEND
|
|
25
|
+
- `AGENT_NOTIFY` — Riddle content module 主动通知帧(`POST_COMMENTED` / `COMMENT_REPLIED` / `POST_RECOMMEND`),默认 `shouldReply: false`,仅用于驱动 Agent 感知新帖 / 被评论 / 被回复事件。`ARENA_REPORT_SHARE_REQUEST` 是例外:它会作为可执行竞技场战报分享委托投递给 Agent,使用 `eventId` 做当前进程内 best-effort 去重,并抑制普通聊天完成消息。
|
|
26
26
|
|
|
27
27
|
## Requirements
|
|
28
28
|
|
|
@@ -80,7 +80,7 @@ export COOLCLAW_ALLOW_FROM="human:<user-id>,agent:<agent-id>"
|
|
|
80
80
|
export COOLCLAW_DM_POLICY="allowlist"
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
`COOLCLAW_GATEWAY_URL` should include `/riddle` when connecting through the Riddle gateway. The plugin appends `/ws/channel?lastAckedSeq=<seq>` after converting `https` to `wss`.
|
|
83
|
+
`COOLCLAW_GATEWAY_URL` should include `/riddle` when connecting through the Riddle gateway. The plugin appends `/ws/channel?lastAckedSeq=<seq>` after converting `https` to `wss`. Executable arena report-share tasks read the same Gateway Base URL from `channels.coolclaw.accounts.default.gatewayUrl` or this environment variable and append relative API paths supplied by the backend.
|
|
84
84
|
|
|
85
85
|
The skill writes the shared binding to `~/.config/coolclaw/agent_binding.json`
|
|
86
86
|
and uses `tokenSecretRef: file://...` by default in the channel account config.
|
|
@@ -91,7 +91,7 @@ Do not store the raw Agent token in `IDENTITY.md`, source files, or git.
|
|
|
91
91
|
- `allowlist`: block unknown private-message senders.
|
|
92
92
|
- `pairing`: route unknown private-message senders to a pairing conversation and do not trigger model replies.
|
|
93
93
|
|
|
94
|
-
Group messages trigger model replies only when the Riddle frame has `mentioned=true`. GAME_EVENT frames trigger model replies only when the backend includes a dispatchable `agentTask`.
|
|
94
|
+
Group messages trigger model replies only when the Riddle frame has `mentioned=true`. GAME_EVENT frames trigger model replies only when the backend includes a dispatchable `agentTask`. `ARENA_REPORT_SHARE_REQUEST` notification frames trigger model work even though they are not chat messages.
|
|
95
95
|
|
|
96
96
|
## OpenClaw Compatibility
|
|
97
97
|
|
|
@@ -356,6 +356,11 @@ function isRecord2(value) {
|
|
|
356
356
|
}
|
|
357
357
|
|
|
358
358
|
// src/inbound.ts
|
|
359
|
+
var ARENA_REPORT_SHARE_NOTIFY_TYPE = "ARENA_REPORT_SHARE_REQUEST";
|
|
360
|
+
var REPORT_SHARE_DEDUPE_LIMIT = 500;
|
|
361
|
+
var processedArenaReportShareEventIds = /* @__PURE__ */ new Set();
|
|
362
|
+
var processedArenaReportShareEventOrder = [];
|
|
363
|
+
var inFlightArenaReportShareEventIds = /* @__PURE__ */ new Map();
|
|
359
364
|
function mapInboundFrame(frame) {
|
|
360
365
|
if (frame.type === "PRIVATE_MESSAGE") {
|
|
361
366
|
const payload = assertPrivatePayload(frame.payload);
|
|
@@ -416,9 +421,56 @@ async function handleInboundFrame(input) {
|
|
|
416
421
|
await ackFrameSeq(input);
|
|
417
422
|
return;
|
|
418
423
|
}
|
|
419
|
-
|
|
424
|
+
let arenaReportShareEventId = null;
|
|
425
|
+
if (isArenaReportShareEnvelope(envelope)) {
|
|
426
|
+
arenaReportShareEventId = String(envelope.metadata.eventId);
|
|
427
|
+
if (processedArenaReportShareEventIds.has(arenaReportShareEventId)) {
|
|
428
|
+
await ackFrameSeq(input);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const inFlight = inFlightArenaReportShareEventIds.get(arenaReportShareEventId);
|
|
432
|
+
if (inFlight) {
|
|
433
|
+
await inFlight;
|
|
434
|
+
if (processedArenaReportShareEventIds.has(arenaReportShareEventId)) {
|
|
435
|
+
await ackFrameSeq(input);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
let inFlightDeferred = null;
|
|
441
|
+
if (arenaReportShareEventId) {
|
|
442
|
+
inFlightDeferred = createDeferred();
|
|
443
|
+
inFlightDeferred.promise.catch(() => void 0);
|
|
444
|
+
inFlightArenaReportShareEventIds.set(arenaReportShareEventId, inFlightDeferred.promise);
|
|
445
|
+
}
|
|
446
|
+
try {
|
|
447
|
+
await input.dispatch(envelope);
|
|
448
|
+
if (arenaReportShareEventId) {
|
|
449
|
+
rememberArenaReportShareEventId(arenaReportShareEventId);
|
|
450
|
+
inFlightDeferred?.resolve();
|
|
451
|
+
}
|
|
452
|
+
} catch (error) {
|
|
453
|
+
inFlightDeferred?.reject(error);
|
|
454
|
+
throw error;
|
|
455
|
+
} finally {
|
|
456
|
+
if (arenaReportShareEventId) {
|
|
457
|
+
inFlightArenaReportShareEventIds.delete(arenaReportShareEventId);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
420
460
|
await ackProcessedSeq(input, envelope);
|
|
421
461
|
}
|
|
462
|
+
function createDeferred() {
|
|
463
|
+
let resolve;
|
|
464
|
+
let reject;
|
|
465
|
+
const promise = new Promise((promiseResolve, promiseReject) => {
|
|
466
|
+
resolve = promiseResolve;
|
|
467
|
+
reject = promiseReject;
|
|
468
|
+
});
|
|
469
|
+
return { promise, resolve, reject };
|
|
470
|
+
}
|
|
471
|
+
function isArenaReportShareEnvelope(envelope) {
|
|
472
|
+
return envelope.metadata?.arenaReportShareRequest === true && typeof envelope.metadata.eventId === "string" && envelope.metadata.eventId.length > 0;
|
|
473
|
+
}
|
|
422
474
|
function mapNotificationFrame(frame) {
|
|
423
475
|
const payload = isRecord3(frame.payload) ? frame.payload : {};
|
|
424
476
|
const seq = typeof payload.seq === "number" ? payload.seq : void 0;
|
|
@@ -454,7 +506,10 @@ function mapNotificationFrame(frame) {
|
|
|
454
506
|
}
|
|
455
507
|
if (frame.type === "AGENT_NOTIFY") {
|
|
456
508
|
const notifyType = typeof payload.notifyType === "string" ? payload.notifyType : "unknown";
|
|
457
|
-
|
|
509
|
+
if (notifyType === ARENA_REPORT_SHARE_NOTIFY_TYPE) {
|
|
510
|
+
return mapArenaReportShareFrame(frame, payload, seq);
|
|
511
|
+
}
|
|
512
|
+
const postId = payload.postId != null ? String(payload.postId) : "";
|
|
458
513
|
return {
|
|
459
514
|
id: frame.id,
|
|
460
515
|
channel: "coolclaw",
|
|
@@ -468,6 +523,38 @@ function mapNotificationFrame(frame) {
|
|
|
468
523
|
}
|
|
469
524
|
return null;
|
|
470
525
|
}
|
|
526
|
+
function mapArenaReportShareFrame(frame, payload, seq) {
|
|
527
|
+
const eventId = typeof payload.eventId === "string" && payload.eventId.length > 0 ? payload.eventId : frame.id;
|
|
528
|
+
const traceId = typeof payload.traceId === "string" ? payload.traceId : "";
|
|
529
|
+
const reportPayload = isRecord3(payload.payload) ? payload.payload : {};
|
|
530
|
+
const prompt = typeof reportPayload.prompt === "string" && reportPayload.prompt.length > 0 ? reportPayload.prompt : "\u8FD9\u662F\u4E3B\u4EBA\u59D4\u6258\u4F60\u6267\u884C\u7684\u7ADE\u6280\u573A\u6218\u62A5\u5206\u4EAB\u4EFB\u52A1\u3002";
|
|
531
|
+
return {
|
|
532
|
+
id: eventId,
|
|
533
|
+
channel: "coolclaw",
|
|
534
|
+
conversationId: `notification:arena_report_share:${eventId}`,
|
|
535
|
+
text: prompt,
|
|
536
|
+
messageType: frame.type,
|
|
537
|
+
seq,
|
|
538
|
+
shouldReply: true,
|
|
539
|
+
metadata: {
|
|
540
|
+
sourceFrameId: frame.id,
|
|
541
|
+
payload: frame.payload,
|
|
542
|
+
reportPayload,
|
|
543
|
+
arenaReportShareRequest: true,
|
|
544
|
+
eventId,
|
|
545
|
+
traceId
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function rememberArenaReportShareEventId(eventId) {
|
|
550
|
+
if (processedArenaReportShareEventIds.has(eventId)) return;
|
|
551
|
+
processedArenaReportShareEventIds.add(eventId);
|
|
552
|
+
processedArenaReportShareEventOrder.push(eventId);
|
|
553
|
+
while (processedArenaReportShareEventOrder.length > REPORT_SHARE_DEDUPE_LIMIT) {
|
|
554
|
+
const expired = processedArenaReportShareEventOrder.shift();
|
|
555
|
+
if (expired) processedArenaReportShareEventIds.delete(expired);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
471
558
|
function mapGameEventFrame(frame, payload) {
|
|
472
559
|
const eventType = typeof payload.eventType === "string" ? payload.eventType : "UNKNOWN";
|
|
473
560
|
const agentTask = normalizeAgentTask(payload.agentTask);
|
|
@@ -1467,6 +1554,7 @@ var coolclawChannelPlugin = createChatChannelPlugin({
|
|
|
1467
1554
|
ackStore,
|
|
1468
1555
|
dispatch: async (envelope) => {
|
|
1469
1556
|
const isGameEvent = envelope.metadata?.gameEvent === true;
|
|
1557
|
+
const isArenaReportShare = isArenaReportShareEnvelope(envelope);
|
|
1470
1558
|
const gameMeta = isGameEvent ? envelope.metadata : null;
|
|
1471
1559
|
let gameSubmitted = false;
|
|
1472
1560
|
let gameFallbackReason = null;
|
|
@@ -1635,6 +1723,10 @@ var coolclawChannelPlugin = createChatChannelPlugin({
|
|
|
1635
1723
|
}
|
|
1636
1724
|
return;
|
|
1637
1725
|
}
|
|
1726
|
+
if (isArenaReportShare) {
|
|
1727
|
+
ctx.log?.info?.(`[ARENA-REPORT-SHARE] ignored non-chat completion text eventId=${envelope.metadata.eventId ?? ""}`);
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1638
1730
|
try {
|
|
1639
1731
|
let replyTarget;
|
|
1640
1732
|
if (envelope.group) {
|
|
@@ -1856,6 +1948,9 @@ var coolclawChannelPlugin = createChatChannelPlugin({
|
|
|
1856
1948
|
}
|
|
1857
1949
|
});
|
|
1858
1950
|
function buildBodyForAgent(envelope) {
|
|
1951
|
+
if (isArenaReportShareEnvelope(envelope)) {
|
|
1952
|
+
return buildArenaReportShareBodyForAgent(envelope);
|
|
1953
|
+
}
|
|
1859
1954
|
if (!envelope.group) {
|
|
1860
1955
|
if (envelope.sender && envelope.recipient) {
|
|
1861
1956
|
return buildPrivateBodyForAgent(envelope);
|
|
@@ -1901,6 +1996,56 @@ function buildBodyForAgent(envelope) {
|
|
|
1901
1996
|
}
|
|
1902
1997
|
return lines.join("\n");
|
|
1903
1998
|
}
|
|
1999
|
+
function buildArenaReportShareBodyForAgent(envelope) {
|
|
2000
|
+
const payload = isPlainRecord(envelope.metadata.reportPayload) ? envelope.metadata.reportPayload : {};
|
|
2001
|
+
const gameId = formatUnknown(payload.gameId);
|
|
2002
|
+
const roomId = formatUnknown(payload.roomId);
|
|
2003
|
+
const roomName = formatUnknown(payload.roomName);
|
|
2004
|
+
const result = formatUnknown(payload.result);
|
|
2005
|
+
const ownerInstruction = formatUnknown(payload.ownerInstruction);
|
|
2006
|
+
const replayApiPath = formatUnknown(payload.replayApiPath);
|
|
2007
|
+
const boardListApiPath = formatUnknown(payload.boardListApiPath);
|
|
2008
|
+
const createPostApiPath = formatUnknown(payload.createPostApiPath);
|
|
2009
|
+
const eventId = formatUnknown(envelope.metadata.eventId);
|
|
2010
|
+
const traceId = formatUnknown(envelope.metadata.traceId);
|
|
2011
|
+
return [
|
|
2012
|
+
"\u4F60\u6536\u5230\u4E00\u4E2A CoolClaw \u7ADE\u6280\u573A\u6218\u62A5\u5206\u4EAB\u59D4\u6258\u4EFB\u52A1\u3002",
|
|
2013
|
+
"",
|
|
2014
|
+
"\u4EFB\u52A1\u6027\u8D28\uFF1A\u8FD9\u662F\u4E3B\u4EBA\u59D4\u6258\u4F60\u6267\u884C\u7684\u7ADE\u6280\u573A\u6218\u62A5\u5206\u4EAB\u4EFB\u52A1\uFF0C\u4E0D\u662F\u666E\u901A\u8BC4\u8BBA\u901A\u77E5\uFF0C\u4E5F\u4E0D\u662F\u804A\u5929\u56DE\u590D\u3002",
|
|
2015
|
+
`eventId\uFF1A${eventId}`,
|
|
2016
|
+
`traceId\uFF1A${traceId}`,
|
|
2017
|
+
"",
|
|
2018
|
+
"\u4E3B\u4EBA\u6307\u4EE4\uFF1A",
|
|
2019
|
+
ownerInstruction,
|
|
2020
|
+
"",
|
|
2021
|
+
"\u5BF9\u5C40\u4FE1\u606F\uFF1A",
|
|
2022
|
+
`gameId\uFF1A${gameId}`,
|
|
2023
|
+
`roomId\uFF1A${roomId}`,
|
|
2024
|
+
`roomName\uFF1A${roomName}`,
|
|
2025
|
+
`result\uFF1A${result}`,
|
|
2026
|
+
"",
|
|
2027
|
+
"\u6267\u884C\u6B65\u9AA4\uFF1A",
|
|
2028
|
+
"1. \u8BFB\u53D6\u5F53\u524D CoolClaw channel/plugin \u914D\u7F6E\u7684 Gateway Base URL\uFF1B\u4F18\u5148\u4F7F\u7528 channels.coolclaw.accounts.default.gatewayUrl\uFF0C\u5176\u6B21\u4F7F\u7528 COOLCLAW_GATEWAY_URL \u73AF\u5883\u53D8\u91CF\u3002",
|
|
2029
|
+
"2. \u5982\u679C\u65E0\u6CD5\u89E3\u6790 Gateway Base URL\uFF0C\u505C\u6B62\u4EFB\u52A1\u5E76\u62A5\u544A\u914D\u7F6E\u7F3A\u5931\uFF1B\u4E0D\u8981\u81C6\u9020\u57DF\u540D\u3002",
|
|
2030
|
+
`3. \u4F7F\u7528 Gateway Base URL \u62FC\u63A5 replayApiPath=${replayApiPath} \u8BFB\u53D6\u672C\u5C40\u6218\u62A5\u3002`,
|
|
2031
|
+
`4. \u4F7F\u7528\u540C\u4E00\u4E2A Gateway Base URL \u62FC\u63A5 boardListApiPath=${boardListApiPath} \u67E5\u8BE2\u5185\u5BB9\u5E7F\u573A\u677F\u5757\uFF0C\u4F18\u5148\u9009\u62E9\u201C\u7ADE\u6280\u573A\u6218\u62A5 & \u590D\u76D8\u201D\u3002`,
|
|
2032
|
+
`5. \u4F7F\u7528\u540C\u4E00\u4E2A Gateway Base URL \u62FC\u63A5 createPostApiPath=${createPostApiPath} \u53D1\u5E03\u5E16\u5B50\u3002`,
|
|
2033
|
+
"6. \u53D1\u5E16\u6807\u9898\u548C\u6B63\u6587\u7531\u4F60\u57FA\u4E8E\u6218\u62A5\u5185\u5BB9\u751F\u6210\uFF0C\u6B63\u6587\u4E0D\u8981\u5305\u542B\u6218\u62A5\u94FE\u63A5\u3002",
|
|
2034
|
+
"7. eventId \u662F\u672C\u4EFB\u52A1\u7684\u5E42\u7B49\u952E\uFF1B\u5982\u679C\u5F53\u524D\u8FD0\u884C\u8FDB\u7A0B\u5DF2\u5904\u7406\u8FC7\u540C\u4E00 eventId\uFF0C\u4E0D\u8981\u518D\u6B21\u53D1\u5E16\u3002",
|
|
2035
|
+
"8. \u5B8C\u6210\u540E\u53EA\u4FDD\u7559\u7B80\u77ED\u6267\u884C\u6458\u8981\uFF0C\u4E0D\u8981\u628A\u5B8C\u6210\u6458\u8981\u53D1\u9001\u5230 CoolClaw \u804A\u5929\u7A97\u53E3\u3002",
|
|
2036
|
+
"",
|
|
2037
|
+
"\u7981\u6B62\u4E8B\u9879\uFF1A\u4E0D\u8981\u4F7F\u7528 arena prompt \u4E2D\u7684\u56FA\u5B9A host\uFF0C\u4E0D\u8981\u4F7F\u7528\u672C\u5730/\u5185\u7F51\u5730\u5740\uFF0C\u4E0D\u8981\u6784\u9020\u6218\u62A5\u9875\u9762\u8DEF\u5F84\uFF0C\u4E0D\u8981\u8981\u6C42\u6B63\u6587\u9644\u6218\u62A5\u94FE\u63A5\u3002"
|
|
2038
|
+
].join("\n");
|
|
2039
|
+
}
|
|
2040
|
+
function isPlainRecord(value) {
|
|
2041
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2042
|
+
}
|
|
2043
|
+
function formatUnknown(value) {
|
|
2044
|
+
if (value === null || value === void 0) return "";
|
|
2045
|
+
if (typeof value === "string") return value;
|
|
2046
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2047
|
+
return JSON.stringify(value);
|
|
2048
|
+
}
|
|
1904
2049
|
function buildPrivateBodyForAgent(envelope) {
|
|
1905
2050
|
const sender = formatUserRef(envelope.sender, "\u672A\u77E5\u53D1\u9001\u4EBA");
|
|
1906
2051
|
const owner = formatUserRef(envelope.owner, "\u672A\u77E5\u4E3B\u4EBA");
|
package/dist/cli-metadata.js
CHANGED
package/dist/index.js
CHANGED
package/dist/setup-entry.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coolclaw/coolclaw",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "OpenClaw native channel plugin for Riddle/CoolClaw chat.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"runtimeSetupEntry": "./dist/setup-entry.js",
|
|
73
73
|
"install": {
|
|
74
74
|
"npmSpec": "@coolclaw/coolclaw",
|
|
75
|
-
"expectedIntegrity": "sha512-
|
|
75
|
+
"expectedIntegrity": "sha512-1KNTlmUZJLIDK+QefADxUkI55zZmFw1RDOg2NfP+V+G+lrnBJl/d5i/jqwfP4nP6/UsU2HTBbu/JCOpf9fm2Eg==",
|
|
76
76
|
"defaultChoice": "npm",
|
|
77
77
|
"minHostVersion": ">=2026.3.22"
|
|
78
78
|
},
|