clawpet-plugins 1.0.0
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 +36 -0
- package/index.ts +184 -0
- package/openclaw.plugin.json +21 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# ClawPet Plugin for OpenClaw 🦞
|
|
2
|
+
|
|
3
|
+
自动上报 Agent tool call 到 ClawPet,驱动龙虾实时动画。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
openclaw plugins install clawpet-plugins
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 配置
|
|
12
|
+
|
|
13
|
+
在 OpenClaw 配置中设置 apiKey:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"plugins": {
|
|
18
|
+
"entries": {
|
|
19
|
+
"clawpet-plugins": {
|
|
20
|
+
"enabled": true,
|
|
21
|
+
"config": {
|
|
22
|
+
"apiKey": "你的 ClawPet API Key"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
重启 gateway 生效。
|
|
31
|
+
|
|
32
|
+
## 功能
|
|
33
|
+
|
|
34
|
+
- 每次 tool call 自动上报
|
|
35
|
+
- 异步执行,不影响 agent 性能
|
|
36
|
+
- 失败静默,不中断正常工作
|
package/index.ts
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawPet OpenClaw Plugin
|
|
3
|
+
*
|
|
4
|
+
* 自动上报 agent 的 tool call 到 ClawPet 后端,
|
|
5
|
+
* 驱动龙虾宠物实时动画。
|
|
6
|
+
*
|
|
7
|
+
* Hook:
|
|
8
|
+
* - after_tool_call: 每次 tool 执行完毕后上报 action + summary
|
|
9
|
+
* - agent_end: 每轮对话结束时上报
|
|
10
|
+
*
|
|
11
|
+
* 配置(在 OpenClaw config 的 plugins.entries 段):
|
|
12
|
+
* {
|
|
13
|
+
* "clawpet-plugins": {
|
|
14
|
+
* "enabled": true,
|
|
15
|
+
* "config": {
|
|
16
|
+
* "apiKey": "cpk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
|
17
|
+
* "apiBase": "https://api.venusx.top"
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// 类型定义(对齐 OpenClaw Plugin API,不依赖源码 import)
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
type PluginLogger = {
|
|
28
|
+
debug?: (message: string) => void;
|
|
29
|
+
info: (message: string) => void;
|
|
30
|
+
warn: (message: string) => void;
|
|
31
|
+
error: (message: string) => void;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type PluginApi = {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
pluginConfig?: Record<string, unknown>;
|
|
38
|
+
logger: PluginLogger;
|
|
39
|
+
on: (
|
|
40
|
+
hookName: string,
|
|
41
|
+
handler: (event: any, ctx: any) => void | Promise<void>,
|
|
42
|
+
opts?: { priority?: number },
|
|
43
|
+
) => void;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// 常量
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
/** 默认 API 地址 */
|
|
51
|
+
const DEFAULT_API_BASE = "https://api.venusx.top";
|
|
52
|
+
|
|
53
|
+
/** 去重窗口(ms)—— 同一工具 2 秒内不重复上报 */
|
|
54
|
+
const DEDUP_WINDOW = 2000;
|
|
55
|
+
|
|
56
|
+
/** 上报超时(ms) */
|
|
57
|
+
const REPORT_TIMEOUT = 5000;
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// 插件入口
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
export default {
|
|
64
|
+
register(api: PluginApi) {
|
|
65
|
+
const config = api.pluginConfig as
|
|
66
|
+
| { apiKey?: string; apiBase?: string }
|
|
67
|
+
| undefined;
|
|
68
|
+
const apiKey = config?.apiKey;
|
|
69
|
+
let apiBase = config?.apiBase || DEFAULT_API_BASE;
|
|
70
|
+
|
|
71
|
+
if (!apiKey) {
|
|
72
|
+
api.logger.warn(
|
|
73
|
+
"[ClawPet] No apiKey configured — plugin disabled. " +
|
|
74
|
+
"Set plugins.entries.clawpet-plugins.config.apiKey in your OpenClaw config.",
|
|
75
|
+
);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!apiKey.startsWith("cpk_")) {
|
|
80
|
+
api.logger.warn(
|
|
81
|
+
"[ClawPet] apiKey should start with 'cpk_' — check your config.",
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
api.logger.info(`[ClawPet] Plugin active, reporting to ${apiBase}`);
|
|
87
|
+
|
|
88
|
+
// 去重:记录最近上报的 toolName → timestamp
|
|
89
|
+
const lastReported = new Map<string, number>();
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 异步上报到 ClawPet 后端
|
|
93
|
+
* 不 await,不阻塞 agent
|
|
94
|
+
*/
|
|
95
|
+
function reportActivity(action: string, summary: string): void {
|
|
96
|
+
// 去重检查
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const lastTime = lastReported.get(action);
|
|
99
|
+
if (lastTime && now - lastTime < DEDUP_WINDOW) return;
|
|
100
|
+
lastReported.set(action, now);
|
|
101
|
+
|
|
102
|
+
// 清理过期去重记录(防内存泄漏)
|
|
103
|
+
if (lastReported.size > 100) {
|
|
104
|
+
for (const [key, ts] of lastReported) {
|
|
105
|
+
if (now - ts > DEDUP_WINDOW * 5) lastReported.delete(key);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 异步 POST,fire-and-forget
|
|
110
|
+
const controller = new AbortController();
|
|
111
|
+
const timeout = setTimeout(() => controller.abort(), REPORT_TIMEOUT);
|
|
112
|
+
|
|
113
|
+
fetch(`${apiBase}/webhook`, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
Authorization: `Bearer ${apiKey}`,
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({ action, summary }),
|
|
120
|
+
signal: controller.signal,
|
|
121
|
+
})
|
|
122
|
+
.then(async (res) => {
|
|
123
|
+
clearTimeout(timeout);
|
|
124
|
+
if (res.ok) {
|
|
125
|
+
try {
|
|
126
|
+
const data = await res.json();
|
|
127
|
+
// 搭便车更新 apiBase
|
|
128
|
+
if (data?.config?.apiBase && data.config.apiBase !== apiBase) {
|
|
129
|
+
api.logger.info(
|
|
130
|
+
`[ClawPet] API base updated: ${apiBase} → ${data.config.apiBase}`,
|
|
131
|
+
);
|
|
132
|
+
apiBase = data.config.apiBase;
|
|
133
|
+
}
|
|
134
|
+
} catch {
|
|
135
|
+
// JSON 解析失败,忽略
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
.catch(() => {
|
|
140
|
+
clearTimeout(timeout);
|
|
141
|
+
// 上报失败静默忽略,不影响 agent 工作
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ========================================
|
|
146
|
+
// Hook: after_tool_call
|
|
147
|
+
// 每次 tool 执行完毕后上报
|
|
148
|
+
// ========================================
|
|
149
|
+
|
|
150
|
+
api.on("after_tool_call", (event: any) => {
|
|
151
|
+
try {
|
|
152
|
+
if (!event) return;
|
|
153
|
+
const { toolName, durationMs, error } = event;
|
|
154
|
+
if (!toolName) return;
|
|
155
|
+
|
|
156
|
+
const summary = error
|
|
157
|
+
? `${toolName} failed (${durationMs ?? 0}ms)`
|
|
158
|
+
: `${toolName} (${durationMs ?? 0}ms)`;
|
|
159
|
+
|
|
160
|
+
reportActivity(toolName, summary);
|
|
161
|
+
} catch {
|
|
162
|
+
// Hook 内部错误静默,绝不影响 agent
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// ========================================
|
|
167
|
+
// Hook: agent_end
|
|
168
|
+
// Agent 一轮结束时上报
|
|
169
|
+
// ========================================
|
|
170
|
+
|
|
171
|
+
api.on("agent_end", (event: any) => {
|
|
172
|
+
try {
|
|
173
|
+
if (!event) return;
|
|
174
|
+
if (event.success) {
|
|
175
|
+
reportActivity("idle", `Turn complete (${event.durationMs ?? 0}ms)`);
|
|
176
|
+
} else {
|
|
177
|
+
reportActivity("error", `Turn failed: ${event.error ?? "unknown"}`);
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
// Hook 内部错误静默,绝不影响 agent
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "clawpet-plugins",
|
|
3
|
+
"name": "ClawPet",
|
|
4
|
+
"description": "Auto-report agent tool calls to ClawPet for real-time lobster visualization.",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"apiBase": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "ClawPet API base URL",
|
|
12
|
+
"default": "https://api.venusx.top"
|
|
13
|
+
},
|
|
14
|
+
"apiKey": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "ClawPet API key (cpk_xxx)"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": []
|
|
20
|
+
}
|
|
21
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawpet-plugins",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenClaw plugin for ClawPet — auto-report tool calls for real-time pet visualization",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": ["openclaw", "openclaw-plugin", "clawpet", "pet", "visualization"],
|
|
9
|
+
"files": [
|
|
10
|
+
"index.ts",
|
|
11
|
+
"openclaw.plugin.json",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/ronin-storm/claw-pet",
|
|
17
|
+
"directory": "plugin"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://myclawpet.com",
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"openclaw": {
|
|
24
|
+
"extensions": [
|
|
25
|
+
"./index.ts"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|