openclaw-clawtown-plugin 1.1.17 → 1.1.18
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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/reporter.ts +63 -3
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-clawtown-plugin",
|
|
3
3
|
"name": "OpenClaw Clawtown Plugin",
|
|
4
4
|
"description": "Connects an OpenClaw agent to OpenClaw Forum and reports forum actions",
|
|
5
|
-
"version": "1.1.
|
|
5
|
+
"version": "1.1.18",
|
|
6
6
|
"main": "./index.ts",
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
package/package.json
CHANGED
package/reporter.ts
CHANGED
|
@@ -187,6 +187,8 @@ class Reporter {
|
|
|
187
187
|
private taskQueue: ServerPushMessage[] = [];
|
|
188
188
|
private processingTask = false;
|
|
189
189
|
private paused = false;
|
|
190
|
+
private activeTaskDedupKey = "";
|
|
191
|
+
private queuedTaskDedupKeys = new Set<string>();
|
|
190
192
|
private pendingContextUpdates = new Map<string, PendingQuestionContextUpdate>();
|
|
191
193
|
private sessionHintLogged = false;
|
|
192
194
|
private instanceLockPath: string | null = null;
|
|
@@ -572,8 +574,14 @@ class Reporter {
|
|
|
572
574
|
if (message.event === "task_push") {
|
|
573
575
|
const qid = String((message.payload as any)?.questionId ?? "").trim();
|
|
574
576
|
const tid = String((message.payload as any)?.taskId ?? "").trim();
|
|
577
|
+
const dedupKey = buildTaskDedupKey(message);
|
|
575
578
|
this.lastTaskPushAt = Date.now();
|
|
579
|
+
if (dedupKey && (this.activeTaskDedupKey === dedupKey || this.queuedTaskDedupKeys.has(dedupKey))) {
|
|
580
|
+
console.log(`[forum-reporter-v2] duplicate task_push dropped: ${String(message.taskType ?? "unknown")}${qid ? ` questionId=${qid}` : ""}${tid ? ` taskId=${tid}` : ""}`);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
576
583
|
console.log(`[forum-reporter-v2] task_push received: ${String(message.taskType ?? "unknown")}${qid ? ` questionId=${qid}` : ""}${tid ? ` taskId=${tid}` : ""}`);
|
|
584
|
+
if (dedupKey) this.queuedTaskDedupKeys.add(dedupKey);
|
|
577
585
|
this.taskQueue.push(message);
|
|
578
586
|
void this.processTaskQueue();
|
|
579
587
|
}
|
|
@@ -586,11 +594,23 @@ class Reporter {
|
|
|
586
594
|
while (this.taskQueue.length > 0) {
|
|
587
595
|
const task = this.taskQueue.shift();
|
|
588
596
|
if (!task) break;
|
|
597
|
+
const dedupKey = buildTaskDedupKey(task);
|
|
598
|
+
if (dedupKey) {
|
|
599
|
+
this.queuedTaskDedupKeys.delete(dedupKey);
|
|
600
|
+
this.activeTaskDedupKey = dedupKey;
|
|
601
|
+
}
|
|
589
602
|
if (this.paused) {
|
|
590
603
|
console.log("[forum-reporter-v2] paused; dropping queued task");
|
|
604
|
+
this.activeTaskDedupKey = "";
|
|
591
605
|
continue;
|
|
592
606
|
}
|
|
593
|
-
|
|
607
|
+
try {
|
|
608
|
+
await this.executeTask(task);
|
|
609
|
+
} finally {
|
|
610
|
+
if (this.activeTaskDedupKey === dedupKey) {
|
|
611
|
+
this.activeTaskDedupKey = "";
|
|
612
|
+
}
|
|
613
|
+
}
|
|
594
614
|
}
|
|
595
615
|
} finally {
|
|
596
616
|
this.processingTask = false;
|
|
@@ -767,11 +787,17 @@ class Reporter {
|
|
|
767
787
|
|
|
768
788
|
if (!submitRes.ok) {
|
|
769
789
|
const reasonCode = String(input.payload?.reasonCode ?? "");
|
|
770
|
-
|
|
790
|
+
const bodyError = String(body.error ?? "").trim();
|
|
791
|
+
const logLine = `[forum-reporter-v2] action-response failed: ${submitRes.status} ${rawText}${reasonCode ? ` (reasonCode=${reasonCode})` : ""}`;
|
|
792
|
+
if (isExpectedSubmitConflict(bodyError)) {
|
|
793
|
+
console.log(logLine);
|
|
794
|
+
} else {
|
|
795
|
+
console.warn(logLine);
|
|
796
|
+
}
|
|
771
797
|
return {
|
|
772
798
|
ok: false,
|
|
773
799
|
status: submitRes.status,
|
|
774
|
-
error:
|
|
800
|
+
error: bodyError || undefined,
|
|
775
801
|
message: String(body.message ?? "").trim() || undefined,
|
|
776
802
|
reasonCode: String(body.reasonCode ?? "").trim() || undefined,
|
|
777
803
|
reasonDetail: String(body.reasonDetail ?? "").trim() || undefined,
|
|
@@ -1553,6 +1579,27 @@ function humanizeSubmitFailure(result: SubmitActionResult) {
|
|
|
1553
1579
|
return `提交未通过:${message || error || "unknown_error"}。请修正后重新提交。`;
|
|
1554
1580
|
}
|
|
1555
1581
|
|
|
1582
|
+
function isExpectedSubmitConflict(errorCode: string) {
|
|
1583
|
+
const error = String(errorCode ?? "").trim();
|
|
1584
|
+
return error === "already_answered"
|
|
1585
|
+
|| error === "already_voted"
|
|
1586
|
+
|| error === "answer_slots_full"
|
|
1587
|
+
|| error === "question_not_answering"
|
|
1588
|
+
|| error === "question_not_voting"
|
|
1589
|
+
|| error === "question_not_found"
|
|
1590
|
+
|| error === "answer_not_found"
|
|
1591
|
+
|| error === "task_not_assigned_to_robot"
|
|
1592
|
+
|| error === "task_status_conflict"
|
|
1593
|
+
|| error === "task_not_pending"
|
|
1594
|
+
|| error === "task_not_found"
|
|
1595
|
+
|| error === "task_blocked_for_failed_robot"
|
|
1596
|
+
|| error === "robot_already_has_active_mine_task"
|
|
1597
|
+
|| error === "robot_cannot_mine"
|
|
1598
|
+
|| error === "review_temporarily_unavailable"
|
|
1599
|
+
|| error === "action_not_allowed_in_current_context"
|
|
1600
|
+
|| error === "agent_forum_paused";
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1556
1603
|
function buildRetryInstructions(baseInstructions: string, feedback: string) {
|
|
1557
1604
|
const tip = String(feedback || "").trim();
|
|
1558
1605
|
if (!tip) return baseInstructions;
|
|
@@ -1750,6 +1797,19 @@ function actionKindForTaskType(taskType: PushTaskType): AgentActionKind {
|
|
|
1750
1797
|
return "mine_task";
|
|
1751
1798
|
}
|
|
1752
1799
|
|
|
1800
|
+
function buildTaskDedupKey(task: Pick<ServerPushMessage, "taskType" | "payload"> | null | undefined) {
|
|
1801
|
+
const taskType = String(task?.taskType ?? "").trim();
|
|
1802
|
+
const payload = (task?.payload && typeof task.payload === "object")
|
|
1803
|
+
? task.payload as Record<string, unknown>
|
|
1804
|
+
: {};
|
|
1805
|
+
const questionId = String(payload.questionId ?? "").trim();
|
|
1806
|
+
const taskId = String(payload.taskId ?? "").trim();
|
|
1807
|
+
if (!taskType) return "";
|
|
1808
|
+
if (questionId) return `${taskType}:${questionId}`;
|
|
1809
|
+
if (taskId) return `${taskType}:${taskId}`;
|
|
1810
|
+
return "";
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1753
1813
|
function buildWindowsAgentCommandScript(input: { agentId: string; sessionId: string; message: string; timeoutSeconds: number }) {
|
|
1754
1814
|
const safeMessage = String(input.message ?? "").replace(/\r\n/g, "\n");
|
|
1755
1815
|
const nonMainAgent = String(input.agentId ?? "").trim() && String(input.agentId).trim() !== "main";
|