@workclaw/openclaw-workclaw 1.0.23 → 1.0.26

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.
Files changed (210) hide show
  1. package/dist/api.d.ts +4 -3
  2. package/dist/api.d.ts.map +1 -0
  3. package/dist/api.js +379 -3
  4. package/dist/channel-DSvR6Irx.js +50017 -0
  5. package/dist/cron-tasks-handler-C-mP3VmV.js +152 -0
  6. package/dist/index.d.ts +5 -4
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +2056 -232
  9. package/dist/jiti-4i2h0FGP.js +4814 -0
  10. package/dist/setup-entry.d.ts +2 -1
  11. package/dist/setup-entry.d.ts.map +1 -0
  12. package/dist/setup-entry.js +181 -11
  13. package/dist/src/accounts.d.ts +3 -2
  14. package/dist/src/accounts.d.ts.map +1 -0
  15. package/dist/src/api/accounts-api.d.ts +2 -1
  16. package/dist/src/api/accounts-api.d.ts.map +1 -0
  17. package/dist/src/api/prompts-api.d.ts +2 -1
  18. package/dist/src/api/prompts-api.d.ts.map +1 -0
  19. package/dist/src/api/session-api.d.ts +2 -1
  20. package/dist/src/api/session-api.d.ts.map +1 -0
  21. package/dist/src/api/skills-api.d.ts +2 -1
  22. package/dist/src/api/skills-api.d.ts.map +1 -0
  23. package/dist/src/api/workspace.d.ts +2 -1
  24. package/dist/src/api/workspace.d.ts.map +1 -0
  25. package/dist/src/channel.d.ts +3 -2
  26. package/dist/src/channel.d.ts.map +1 -0
  27. package/dist/src/config-schema.d.ts +1 -6
  28. package/dist/src/config-schema.d.ts.map +1 -0
  29. package/dist/src/connection/workclaw-client.d.ts +6 -4
  30. package/dist/src/connection/workclaw-client.d.ts.map +1 -0
  31. package/dist/src/gateway/agent-handlers.d.ts +3 -2
  32. package/dist/src/gateway/agent-handlers.d.ts.map +1 -0
  33. package/dist/src/gateway/config-writer.d.ts +3 -2
  34. package/dist/src/gateway/config-writer.d.ts.map +1 -0
  35. package/dist/src/gateway/cron-tasks-handler.d.ts +1 -0
  36. package/dist/src/gateway/cron-tasks-handler.d.ts.map +1 -0
  37. package/dist/src/gateway/message-context.d.ts +2 -1
  38. package/dist/src/gateway/message-context.d.ts.map +1 -0
  39. package/dist/src/gateway/message-dispatcher.d.ts +3 -4
  40. package/dist/src/gateway/message-dispatcher.d.ts.map +1 -0
  41. package/dist/src/gateway/reconnect.d.ts +3 -5
  42. package/dist/src/gateway/reconnect.d.ts.map +1 -0
  43. package/dist/src/gateway/skills-handler.d.ts +1 -0
  44. package/dist/src/gateway/skills-handler.d.ts.map +1 -0
  45. package/dist/src/gateway/skills-list-handler.d.ts +1 -0
  46. package/dist/src/gateway/skills-list-handler.d.ts.map +1 -0
  47. package/dist/src/gateway/tools-list-handler.d.ts +1 -0
  48. package/dist/src/gateway/tools-list-handler.d.ts.map +1 -0
  49. package/dist/src/gateway/workclaw-gateway.d.ts +4 -7
  50. package/dist/src/gateway/workclaw-gateway.d.ts.map +1 -0
  51. package/dist/src/media/upload.d.ts +1 -0
  52. package/dist/src/media/upload.d.ts.map +1 -0
  53. package/dist/src/outbound/index.d.ts +9 -6
  54. package/dist/src/outbound/index.d.ts.map +1 -0
  55. package/dist/src/outbound/workclaw-sender.d.ts +6 -4
  56. package/dist/src/outbound/workclaw-sender.d.ts.map +1 -0
  57. package/dist/src/runtime.d.ts +11 -9
  58. package/dist/src/runtime.d.ts.map +1 -0
  59. package/dist/src/secret-contract-api.d.ts +1 -0
  60. package/dist/src/secret-contract-api.d.ts.map +1 -0
  61. package/dist/src/send.d.ts +2 -1
  62. package/dist/src/send.d.ts.map +1 -0
  63. package/dist/src/setup-api.d.ts +4 -3
  64. package/dist/src/setup-api.d.ts.map +1 -0
  65. package/dist/src/setup-core.d.ts +2 -1
  66. package/dist/src/setup-core.d.ts.map +1 -0
  67. package/dist/src/setup-surface.d.ts +3 -2
  68. package/dist/src/setup-surface.d.ts.map +1 -0
  69. package/dist/src/tools/openclaw-workclaw-cron/api/index.d.ts +2 -4
  70. package/dist/src/tools/openclaw-workclaw-cron/api/index.d.ts.map +1 -0
  71. package/dist/src/tools/openclaw-workclaw-cron/index.d.ts +1 -0
  72. package/dist/src/tools/openclaw-workclaw-cron/index.d.ts.map +1 -0
  73. package/dist/src/tools/openclaw-workclaw-cron/src/add/params.d.ts +2 -4
  74. package/dist/src/tools/openclaw-workclaw-cron/src/add/params.d.ts.map +1 -0
  75. package/dist/src/tools/openclaw-workclaw-cron/src/add/sync.d.ts +2 -4
  76. package/dist/src/tools/openclaw-workclaw-cron/src/add/sync.d.ts.map +1 -0
  77. package/dist/src/tools/openclaw-workclaw-cron/src/disable/params.d.ts +2 -4
  78. package/dist/src/tools/openclaw-workclaw-cron/src/disable/params.d.ts.map +1 -0
  79. package/dist/src/tools/openclaw-workclaw-cron/src/disable/sync.d.ts +2 -4
  80. package/dist/src/tools/openclaw-workclaw-cron/src/disable/sync.d.ts.map +1 -0
  81. package/dist/src/tools/openclaw-workclaw-cron/src/enable/params.d.ts +2 -4
  82. package/dist/src/tools/openclaw-workclaw-cron/src/enable/params.d.ts.map +1 -0
  83. package/dist/src/tools/openclaw-workclaw-cron/src/enable/sync.d.ts +2 -4
  84. package/dist/src/tools/openclaw-workclaw-cron/src/enable/sync.d.ts.map +1 -0
  85. package/dist/src/tools/openclaw-workclaw-cron/src/notify/sync.d.ts +2 -6
  86. package/dist/src/tools/openclaw-workclaw-cron/src/notify/sync.d.ts.map +1 -0
  87. package/dist/src/tools/openclaw-workclaw-cron/src/remove/params.d.ts +2 -4
  88. package/dist/src/tools/openclaw-workclaw-cron/src/remove/params.d.ts.map +1 -0
  89. package/dist/src/tools/openclaw-workclaw-cron/src/remove/sync.d.ts +2 -4
  90. package/dist/src/tools/openclaw-workclaw-cron/src/remove/sync.d.ts.map +1 -0
  91. package/dist/src/tools/openclaw-workclaw-cron/src/update/params.d.ts +2 -4
  92. package/dist/src/tools/openclaw-workclaw-cron/src/update/params.d.ts.map +1 -0
  93. package/dist/src/tools/openclaw-workclaw-cron/src/update/sync.d.ts +2 -4
  94. package/dist/src/tools/openclaw-workclaw-cron/src/update/sync.d.ts.map +1 -0
  95. package/dist/src/tools/openclaw-workclaw-cron/types/index.d.ts +1 -0
  96. package/dist/src/tools/openclaw-workclaw-cron/types/index.d.ts.map +1 -0
  97. package/dist/src/tools/openclaw-workclaw-cron/utils/index.d.ts +1 -0
  98. package/dist/src/tools/openclaw-workclaw-cron/utils/index.d.ts.map +1 -0
  99. package/dist/src/tools/openclaw-workclaw-system/index.d.ts +1 -0
  100. package/dist/src/tools/openclaw-workclaw-system/index.d.ts.map +1 -0
  101. package/dist/src/tools/openclaw-workclaw-system/src/get/index.d.ts +2 -4
  102. package/dist/src/tools/openclaw-workclaw-system/src/get/index.d.ts.map +1 -0
  103. package/dist/src/tools/openclaw-workclaw-system/src/token/index.d.ts +2 -4
  104. package/dist/src/tools/openclaw-workclaw-system/src/token/index.d.ts.map +1 -0
  105. package/dist/src/types.d.ts +7 -7
  106. package/dist/src/types.d.ts.map +1 -0
  107. package/dist/src/utils/content.d.ts +1 -0
  108. package/dist/src/utils/content.d.ts.map +1 -0
  109. package/openclaw.plugin.json +6 -0
  110. package/package.json +69 -45
  111. package/api.ts +0 -3
  112. package/dist/src/accounts.js +0 -279
  113. package/dist/src/api/accounts-api.js +0 -130
  114. package/dist/src/api/prompts-api.js +0 -103
  115. package/dist/src/api/session-api.js +0 -207
  116. package/dist/src/api/skills-api.js +0 -64
  117. package/dist/src/api/workspace.js +0 -30
  118. package/dist/src/channel.js +0 -199
  119. package/dist/src/config-schema.js +0 -56
  120. package/dist/src/connection/workclaw-client.js +0 -351
  121. package/dist/src/gateway/agent-handlers.js +0 -433
  122. package/dist/src/gateway/config-writer.js +0 -302
  123. package/dist/src/gateway/cron-tasks-handler.js +0 -188
  124. package/dist/src/gateway/message-context.js +0 -509
  125. package/dist/src/gateway/message-dispatcher.js +0 -572
  126. package/dist/src/gateway/reconnect.js +0 -210
  127. package/dist/src/gateway/skills-handler.js +0 -615
  128. package/dist/src/gateway/skills-list-handler.js +0 -233
  129. package/dist/src/gateway/tools-list-handler.js +0 -101
  130. package/dist/src/gateway/workclaw-gateway.js +0 -237
  131. package/dist/src/media/upload.js +0 -125
  132. package/dist/src/outbound/index.js +0 -123
  133. package/dist/src/outbound/workclaw-sender.js +0 -95
  134. package/dist/src/runtime.js +0 -374
  135. package/dist/src/secret-contract-api.js +0 -4
  136. package/dist/src/send.js +0 -1
  137. package/dist/src/setup-api.js +0 -3
  138. package/dist/src/setup-core.js +0 -13
  139. package/dist/src/setup-surface.js +0 -363
  140. package/dist/src/tools/openclaw-workclaw-cron/api/index.js +0 -209
  141. package/dist/src/tools/openclaw-workclaw-cron/index.js +0 -33
  142. package/dist/src/tools/openclaw-workclaw-cron/src/add/params.js +0 -152
  143. package/dist/src/tools/openclaw-workclaw-cron/src/add/sync.js +0 -162
  144. package/dist/src/tools/openclaw-workclaw-cron/src/disable/params.js +0 -80
  145. package/dist/src/tools/openclaw-workclaw-cron/src/disable/sync.js +0 -107
  146. package/dist/src/tools/openclaw-workclaw-cron/src/enable/params.js +0 -80
  147. package/dist/src/tools/openclaw-workclaw-cron/src/enable/sync.js +0 -107
  148. package/dist/src/tools/openclaw-workclaw-cron/src/notify/sync.js +0 -127
  149. package/dist/src/tools/openclaw-workclaw-cron/src/remove/params.js +0 -87
  150. package/dist/src/tools/openclaw-workclaw-cron/src/remove/sync.js +0 -107
  151. package/dist/src/tools/openclaw-workclaw-cron/src/update/params.js +0 -164
  152. package/dist/src/tools/openclaw-workclaw-cron/src/update/sync.js +0 -135
  153. package/dist/src/tools/openclaw-workclaw-cron/types/index.js +0 -4
  154. package/dist/src/tools/openclaw-workclaw-cron/utils/index.js +0 -122
  155. package/dist/src/tools/openclaw-workclaw-system/index.js +0 -15
  156. package/dist/src/tools/openclaw-workclaw-system/src/get/index.js +0 -64
  157. package/dist/src/tools/openclaw-workclaw-system/src/token/index.js +0 -78
  158. package/dist/src/types.js +0 -1
  159. package/dist/src/utils/content.js +0 -38
  160. package/index.ts +0 -325
  161. package/setup-entry.ts +0 -13
  162. package/src/accounts.ts +0 -360
  163. package/src/api/accounts-api.ts +0 -156
  164. package/src/api/prompts-api.ts +0 -122
  165. package/src/api/session-api.ts +0 -246
  166. package/src/api/skills-api.ts +0 -74
  167. package/src/api/workspace.ts +0 -45
  168. package/src/channel.ts +0 -226
  169. package/src/config-schema.ts +0 -60
  170. package/src/connection/workclaw-client.ts +0 -618
  171. package/src/gateway/agent-handlers.ts +0 -551
  172. package/src/gateway/config-writer.ts +0 -378
  173. package/src/gateway/cron-tasks-handler.ts +0 -230
  174. package/src/gateway/message-context.ts +0 -645
  175. package/src/gateway/message-dispatcher.ts +0 -688
  176. package/src/gateway/reconnect.ts +0 -260
  177. package/src/gateway/skills-handler.ts +0 -805
  178. package/src/gateway/skills-list-handler.ts +0 -332
  179. package/src/gateway/tools-list-handler.ts +0 -161
  180. package/src/gateway/workclaw-gateway.ts +0 -298
  181. package/src/media/upload.ts +0 -168
  182. package/src/outbound/index.ts +0 -191
  183. package/src/outbound/workclaw-sender.ts +0 -161
  184. package/src/runtime.ts +0 -520
  185. package/src/secret-contract-api.ts +0 -4
  186. package/src/send.ts +0 -1
  187. package/src/setup-api.ts +0 -3
  188. package/src/setup-core.ts +0 -25
  189. package/src/setup-surface.ts +0 -498
  190. package/src/tools/openclaw-workclaw-cron/api/index.ts +0 -326
  191. package/src/tools/openclaw-workclaw-cron/index.ts +0 -39
  192. package/src/tools/openclaw-workclaw-cron/src/add/params.ts +0 -177
  193. package/src/tools/openclaw-workclaw-cron/src/add/sync.ts +0 -188
  194. package/src/tools/openclaw-workclaw-cron/src/disable/params.ts +0 -100
  195. package/src/tools/openclaw-workclaw-cron/src/disable/sync.ts +0 -127
  196. package/src/tools/openclaw-workclaw-cron/src/enable/params.ts +0 -100
  197. package/src/tools/openclaw-workclaw-cron/src/enable/sync.ts +0 -127
  198. package/src/tools/openclaw-workclaw-cron/src/notify/sync.ts +0 -148
  199. package/src/tools/openclaw-workclaw-cron/src/remove/params.ts +0 -109
  200. package/src/tools/openclaw-workclaw-cron/src/remove/sync.ts +0 -127
  201. package/src/tools/openclaw-workclaw-cron/src/update/params.ts +0 -195
  202. package/src/tools/openclaw-workclaw-cron/src/update/sync.ts +0 -161
  203. package/src/tools/openclaw-workclaw-cron/types/index.ts +0 -55
  204. package/src/tools/openclaw-workclaw-cron/utils/index.ts +0 -141
  205. package/src/tools/openclaw-workclaw-system/index.ts +0 -17
  206. package/src/tools/openclaw-workclaw-system/src/get/index.ts +0 -77
  207. package/src/tools/openclaw-workclaw-system/src/token/index.ts +0 -93
  208. package/src/types.ts +0 -50
  209. package/src/utils/content.ts +0 -40
  210. package/tsconfig.json +0 -34
@@ -1,233 +0,0 @@
1
- /**
2
- * Skills list handler - 处理 SKILLS_LIST 事件
3
- * 从 OpenClaw 获取 skills 列表并通过回调返回
4
- */
5
- import { readFileSync } from 'node:fs';
6
- import { execSync } from "child_process";
7
- import { homedir } from "node:os";
8
- import { join } from "node:path";
9
- import { existsSync, readdirSync, statSync } from "node:fs";
10
- /**
11
- * 处理 SKILLS_LIST 事件
12
- * @param event - 事件数据
13
- * @param baseUrl - 回调基础 URL
14
- * @param token - 鉴权 token
15
- * @param log 日志对象(可选)
16
- * @param {Function} [log.info] - 信息日志函数
17
- * @param {Function} [log.error] - 错误日志函数
18
- */
19
- export async function handleSkillsListEvent(event, baseUrl, token, log) {
20
- const agentId = Number(event.agentId);
21
- const userId = Number(event.userId);
22
- log?.info?.(`SkillsList: Handling SKILLS_LIST event for agentId: ${agentId}, userId: ${userId}`);
23
- try {
24
- // 从 OpenClaw 获取 skills 列表
25
- const skills = await fetchSkillsFromOpenClaw(agentId, userId, log);
26
- // 构建回调 payload
27
- const callbackPayload = {
28
- userId,
29
- agentId,
30
- dataList: skills,
31
- };
32
- // 发送回调
33
- const callbackUrl = `${baseUrl.replace(/\/$/, '')}/open-apis/v1/claw/push/skills`;
34
- await sendSkillsListCallback(callbackUrl, callbackPayload, token, log);
35
- log?.info?.(`SkillsList: Successfully processed SKILLS_LIST event, sent ${skills.length} skills`);
36
- }
37
- catch (error) {
38
- log?.error?.(`SkillsList: Failed to handle SKILLS_LIST event: ${String(error)}`);
39
- throw error;
40
- }
41
- }
42
- /**
43
- * 从 OpenClaw 获取 skills 列表
44
- * 包括全局技能和智能体工作区的专有技能
45
- */
46
- async function fetchSkillsFromOpenClaw(agentId, _userId, log) {
47
- log?.info?.(`SkillsList: Fetching skills from OpenClaw for agentId: ${agentId}`);
48
- try {
49
- // 使用 OpenClaw CLI 获取 skills 列表(全局技能)
50
- const result = execSync("openclaw skills list", {
51
- encoding: "utf-8",
52
- timeout: 30000, // 30秒超时
53
- });
54
- // 解析输出
55
- const globalSkills = parseSkillsListOutput(result);
56
- // 检查智能体工作区中的专有技能
57
- const agentWorkspaceSkills = await fetchAgentWorkspaceSkills(agentId, log);
58
- // 合并技能列表,去重
59
- const allSkills = mergeSkills(globalSkills, agentWorkspaceSkills);
60
- log?.info?.(`SkillsList: Found ${allSkills.length} skills (${globalSkills.length} global, ${agentWorkspaceSkills.length} agent-specific)`);
61
- return allSkills;
62
- }
63
- catch (error) {
64
- log?.error?.(`SkillsList: Error fetching skills: ${String(error)}`);
65
- // 如果获取失败,返回空列表
66
- return [];
67
- }
68
- }
69
- /**
70
- * 获取智能体工作区中的专有技能
71
- */
72
- async function fetchAgentWorkspaceSkills(agentId, log) {
73
- const skills = [];
74
- try {
75
- // 智能体工作区路径
76
- const agentWorkspace = join(homedir(), ".openclaw", "agents", `openclaw-workclaw-${agentId}`);
77
- const skillsDir = join(agentWorkspace, "skills");
78
- // 检查技能目录是否存在
79
- if (!existsSync(skillsDir)) {
80
- log?.info?.(`SkillsList: No skills directory found in agent workspace: ${skillsDir}`);
81
- return skills;
82
- }
83
- // 读取技能目录中的子目录(每个子目录是一个技能)
84
- const items = readdirSync(skillsDir);
85
- for (const item of items) {
86
- const itemPath = join(skillsDir, item);
87
- const stat = statSync(itemPath);
88
- // 如果是目录,检查里面的技能文件
89
- if (stat.isDirectory()) {
90
- const skillFiles = readdirSync(itemPath);
91
- for (const skillFile of skillFiles) {
92
- if (skillFile.endsWith('.md') || skillFile.endsWith('.prose')) {
93
- const skillFilePath = join(itemPath, skillFile);
94
- const skill = parseSkillFile(skillFilePath, item, log);
95
- if (skill) {
96
- skills.push(skill);
97
- }
98
- }
99
- }
100
- }
101
- }
102
- log?.info?.(`SkillsList: Found ${skills.length} agent-specific skills in ${skillsDir}`);
103
- }
104
- catch (error) {
105
- log?.error?.(`SkillsList: Error reading agent workspace skills: ${String(error)}`);
106
- }
107
- return skills;
108
- }
109
- /**
110
- * 解析技能文件
111
- */
112
- function parseSkillFile(filePath, skillName, log) {
113
- try {
114
- const content = readFileSync(filePath, 'utf-8');
115
- // 提取描述(从文件内容中)
116
- let description = 'Agent-specific skill';
117
- const lines = content.split('\n');
118
- for (const line of lines) {
119
- if (line.startsWith('# ')) {
120
- description = line.substring(2).trim();
121
- break;
122
- }
123
- else if (line.startsWith('summary:') || line.startsWith('Summary:')) {
124
- description = line.substring(line.indexOf(':') + 1).trim();
125
- break;
126
- }
127
- }
128
- return {
129
- typeStr: 'skill',
130
- name: skillName,
131
- description,
132
- };
133
- }
134
- catch (error) {
135
- log?.error?.(`SkillsList: Error parsing skill file ${filePath}: ${String(error)}`);
136
- return null;
137
- }
138
- }
139
- /**
140
- * 合并技能列表,去重
141
- */
142
- function mergeSkills(globalSkills, agentSkills) {
143
- const skillMap = new Map();
144
- // 先添加全局技能
145
- for (const skill of globalSkills) {
146
- skillMap.set(skill.name, skill);
147
- }
148
- // 再添加智能体专有技能(会覆盖同名的全局技能)
149
- for (const skill of agentSkills) {
150
- skillMap.set(skill.name, skill);
151
- }
152
- return Array.from(skillMap.values());
153
- }
154
- /**
155
- * 解析 openclaw skills list 的输出
156
- */
157
- function parseSkillsListOutput(output) {
158
- const skills = [];
159
- const lines = output.split('\n');
160
- // 查找表格内容(从表头后开始)
161
- let inTable = false;
162
- let headerLine = -1;
163
- for (let i = 0; i < lines.length; i++) {
164
- const line = lines[i];
165
- // 找到表头行(包含 Status | Skill | Description | Source)
166
- if (line.includes('Status') && line.includes('Skill') && line.includes('Description')) {
167
- headerLine = i;
168
- inTable = true;
169
- continue;
170
- }
171
- // 跳过分隔线
172
- if (inTable && (line.startsWith('├') || line.startsWith('┌') || line.startsWith('└'))) {
173
- continue;
174
- }
175
- // 解析表格行
176
- if (inTable && line.startsWith('│') && i > headerLine + 1) {
177
- const parsed = parseSkillsTableRow(line);
178
- if (parsed) {
179
- skills.push(parsed);
180
- }
181
- }
182
- // 表格结束
183
- if (inTable && line.startsWith('└')) {
184
- break;
185
- }
186
- }
187
- return skills;
188
- }
189
- /**
190
- * 解析单行表格数据
191
- */
192
- function parseSkillsTableRow(line) {
193
- // 移除开头的 │ 和结尾的 │
194
- const content = line.replace(/^│\s*/, '').replace(/\s*│$/, '');
195
- // 按 │ 分割列
196
- const columns = content.split('│').map(col => col.trim());
197
- if (columns.length < 4) {
198
- return null;
199
- }
200
- const status = columns[0];
201
- const skillName = columns[1];
202
- const description = columns[2];
203
- // 只返回 ready 状态的 skills
204
- if (!status.includes('✓') && !status.includes('ready')) {
205
- return null;
206
- }
207
- // 提取 skill 名称(移除 emoji)
208
- const cleanName = skillName.replace(/[\u{1F300}-\u{1F9FF}]/gu, '').trim();
209
- return {
210
- typeStr: 'skill',
211
- name: cleanName,
212
- description,
213
- };
214
- }
215
- /**
216
- * 发送 skills 列表回调
217
- */
218
- async function sendSkillsListCallback(callbackUrl, payload, token, log) {
219
- log?.info?.(`SkillsList: Sending callback to ${callbackUrl}`);
220
- const response = await fetch(callbackUrl, {
221
- method: 'POST',
222
- headers: {
223
- 'Content-Type': 'application/json',
224
- 'Authorization': `Bearer ${token}`,
225
- },
226
- body: JSON.stringify(payload),
227
- });
228
- if (!response.ok) {
229
- const errorText = await response.text().catch(() => 'Unknown error');
230
- throw new Error(`Callback failed: ${response.status} ${errorText}`);
231
- }
232
- log?.info?.(`SkillsList: Callback sent successfully`);
233
- }
@@ -1,101 +0,0 @@
1
- /**
2
- * Tools List 事件处理器
3
- * 处理云端下发的 TOOLS_LIST EVENT 消息
4
- * 从 OpenClaw 获取 tools 列表并通过 HTTP 回调返回
5
- */
6
- import { fetch } from "undici";
7
- import { readFile } from "node:fs/promises";
8
- import { homedir } from "node:os";
9
- import path from "node:path";
10
- /**
11
- * 处理 TOOLS_LIST 事件
12
- * @param event 事件数据
13
- * @param baseUrl 回调基础 URL
14
- * @param token 鉴权 token
15
- * @param log 日志函数
16
- */
17
- export async function handleToolsListEvent(event, baseUrl, token, log) {
18
- const agentId = Number(event.agentId);
19
- const userId = Number(event.userId);
20
- log?.info?.(`ToolsList: Handling TOOLS_LIST event for agentId: ${agentId}, userId: ${userId}`);
21
- try {
22
- // 从 OpenClaw 获取 tools 列表
23
- const tools = await fetchToolsFromOpenClaw(agentId, userId, log);
24
- // 构建回调 payload
25
- const callbackPayload = {
26
- userId,
27
- agentId,
28
- dataList: tools,
29
- };
30
- // 发送回调
31
- const callbackUrl = `${baseUrl.replace(/\/$/, "")}/open-apis/v1/claw/push/tools`;
32
- await sendToolsListCallback(callbackUrl, callbackPayload, token, log);
33
- log?.info?.(`ToolsList: Successfully processed TOOLS_LIST event, sent ${tools.length} tools`);
34
- }
35
- catch (error) {
36
- log?.error?.(`ToolsList: Failed to handle TOOLS_LIST event: ${String(error)}`);
37
- throw error;
38
- }
39
- }
40
- /**
41
- * 从 OpenClaw 获取 tools 列表
42
- * 根据 agent 的 tools.allow 配置决定返回哪些工具
43
- */
44
- async function fetchToolsFromOpenClaw(agentId, userId, log) {
45
- log?.info?.(`ToolsList: Fetching tools from OpenClaw for agentId: ${agentId}`);
46
- // OpenClaw 所有内置工具列表
47
- const allTools = [
48
- { typeStr: "function", name: "web_search", description: "Search the web for information using Brave Search API." },
49
- { typeStr: "function", name: "web_fetch", description: "Fetch and read content from a URL." },
50
- { typeStr: "function", name: "sessions_list", description: "List all active agent sessions." },
51
- { typeStr: "function", name: "sessions_history", description: "Get the history of a specific session." },
52
- { typeStr: "function", name: "memory_search", description: "Search memory for past conversations and information." },
53
- { typeStr: "function", name: "memory_get", description: "Get specific memory by ID." },
54
- { typeStr: "function", name: "gateway", description: "Gateway control operations." },
55
- { typeStr: "function", name: "exec", description: "Execute shell commands." },
56
- ];
57
- try {
58
- // 读取 OpenClaw 配置文件
59
- const configPath = path.join(homedir(), ".openclaw", "openclaw.json");
60
- const configContent = await readFile(configPath, "utf-8");
61
- const config = JSON.parse(configContent);
62
- // 查找对应的 agent 配置
63
- const agentConfig = config.agents?.list?.find((agent) => String(agent.id) === String(agentId) ||
64
- agent.id === `openclaw-workclaw-${agentId}`);
65
- // 获取 tools.allow 配置
66
- const allowTools = agentConfig?.tools?.allow;
67
- // 如果没有 allow 配置,或者 allow 是 ["*"],返回所有工具
68
- if (!allowTools || allowTools.length === 0 || allowTools.includes("*")) {
69
- log?.info?.(`ToolsList: Agent has no allow restriction or allow=[*], returning all ${allTools.length} tools`);
70
- return allTools;
71
- }
72
- // 如果有具体的 allow 列表,只返回列表中的工具
73
- const filteredTools = allTools.filter(tool => allowTools.includes(tool.name));
74
- log?.info?.(`ToolsList: Agent allow=${JSON.stringify(allowTools)}, returning ${filteredTools.length} tools`);
75
- return filteredTools;
76
- }
77
- catch (error) {
78
- log?.error?.(`ToolsList: Error reading agent config: ${String(error)}, returning all tools`);
79
- // 如果读取配置失败,返回所有工具
80
- return allTools;
81
- }
82
- }
83
- /**
84
- * 发送 tools 列表回调
85
- */
86
- async function sendToolsListCallback(callbackUrl, payload, token, log) {
87
- log?.info?.(`ToolsList: Sending callback to ${callbackUrl}`);
88
- const response = await fetch(callbackUrl, {
89
- method: "POST",
90
- headers: {
91
- "Content-Type": "application/json",
92
- "Authorization": `Bearer ${token}`,
93
- },
94
- body: JSON.stringify(payload),
95
- });
96
- if (!response.ok) {
97
- const errorText = await response.text();
98
- throw new Error(`Callback failed: ${response.status} ${response.statusText} - ${errorText}`);
99
- }
100
- log?.info?.(`ToolsList: Callback sent successfully: ${response.status}`);
101
- }
@@ -1,237 +0,0 @@
1
- import { buildAccountMap, resolveAccountByUserIdAndAgentId } from '../accounts.js';
2
- import { clearReconnectScheduler, clearWorkclawConnectionConfig, clearWorkclawWsConnection, createLogger, finishConnecting, getAllDispatchersByAppKey, getAppKeyByAccountId, getDispatcherByAppKeyAndAccountId, getReconnectScheduler, getWorkclawWsConnection, registerAccountContext, setReconnectScheduler, setWorkclawConnectionConfig, setWorkclawLoggerFromContext, tryStartConnecting, unregisterAccountContext, } from '../runtime.js';
3
- import { parseWorkClawMessage } from './message-context.js';
4
- import { dispatchWorkclawMessage } from './message-dispatcher.js';
5
- import { createReconnectScheduler } from './reconnect.js';
6
- export async function startWorkclawGateway(options) {
7
- const { accountId, account, cfg, log } = options;
8
- const logger = createLogger('', log);
9
- setWorkclawLoggerFromContext(logger);
10
- const rawConfig = account.config;
11
- const connectionMode = rawConfig.connectionMode || 'websocket';
12
- if (connectionMode !== 'websocket') {
13
- throw new Error(`Unsupported connectionMode: ${connectionMode}`);
14
- }
15
- await startSharedWebSocket(options);
16
- }
17
- /**
18
- * 多个账号共享一个 WebSocket 连接
19
- */
20
- async function startSharedWebSocket(options) {
21
- const { accountId, account, cfg, log } = options;
22
- const logger = createLogger('', log);
23
- const rawConfig = account.config;
24
- const baseConfig = {
25
- baseUrl: rawConfig.baseUrl,
26
- websocketUrl: rawConfig.websocketUrl,
27
- appKey: rawConfig.appKey,
28
- appSecret: rawConfig.appSecret,
29
- localIp: rawConfig.localIp,
30
- allowInsecureTls: rawConfig.allowInsecureTls,
31
- requestTimeout: rawConfig.requestTimeout,
32
- };
33
- const accountConfig = {
34
- agentId: rawConfig.agentId,
35
- userId: rawConfig.userId,
36
- openConversationId: rawConfig.openConversationId,
37
- };
38
- const appKey = baseConfig.appKey || accountId;
39
- const appKeyRaw = baseConfig.appKey ?? '';
40
- buildAccountMap(cfg);
41
- logger.info(`Gateway start accountId=${accountId} appKey=${appKeyRaw ? `${appKeyRaw.slice(0, 8)}...` : 'missing'} baseUrl=${baseConfig.baseUrl ?? ''} websocketUrl=${baseConfig.websocketUrl ?? ''}`);
42
- // 注册账号上下文
43
- const ctx = {
44
- accountId,
45
- account,
46
- cfg,
47
- baseConfig,
48
- accountConfig,
49
- log: logger,
50
- scheduleReconnect: () => {
51
- const scheduler = getReconnectScheduler(appKey);
52
- scheduler?.scheduleReconnect();
53
- },
54
- };
55
- registerAccountContext(appKey, accountId, ctx);
56
- // 检查是否已存在该 appKey 的 WebSocket
57
- const existingWs = getWorkclawWsConnection(appKey);
58
- if (existingWs) {
59
- logger.info(`Gateway using existing WebSocket for appKey=${appKey}`);
60
- return;
61
- }
62
- // 尝试获取连接锁,防止竞态条件
63
- const startResult = tryStartConnecting(appKey);
64
- if (!startResult.isConnector) {
65
- // 另一个账号正在连接(成功或失败中),等待共享的 connectingPromise
66
- logger.info(`Gateway another account is connecting, waiting... appKey=${appKey}`);
67
- const resultWs = await startResult.connectingPromise;
68
- if (resultWs) {
69
- logger.info(`Gateway connection established by another account, using it appKey=${appKey}`);
70
- return;
71
- }
72
- // 连接失败(resultWs === null),当前账号作为新 connector 重试
73
- logger.warn(`Gateway connection attempt failed, will create own connection appKey=${appKey}`);
74
- }
75
- else {
76
- // 是 connector,创建连接
77
- logger.info(`Gateway acquired connector lock, creating connection appKey=${appKey}`);
78
- }
79
- // 需要创建新的 WebSocket(只有获取到锁的账号才执行到这里)
80
- const scheduler = createReconnectScheduler({
81
- key: appKey,
82
- config: baseConfig,
83
- log: logger,
84
- onMessage: (data) => {
85
- handleSharedMessage(appKey, data, cfg, logger);
86
- },
87
- onClose: () => {
88
- scheduler.scheduleReconnect();
89
- },
90
- // 旧代码在 setWorkclawWsConnection 后、ws.onopen 前就调用 finishConnecting,
91
- // 这个回调模拟同样的时机:ws 已存入 runtime,通知所有等待者
92
- onConnectingStarted: (ws) => {
93
- finishConnecting(appKey, ws);
94
- },
95
- });
96
- setReconnectScheduler(appKey, scheduler);
97
- try {
98
- await scheduler.connect();
99
- }
100
- catch (err) {
101
- // 连接失败,通知所有等待者重试(不传 ws 表示失败)
102
- finishConnecting(appKey);
103
- throw err;
104
- }
105
- // Cache the connection config to prevent cfg mutation issues during message sends
106
- // 每个账户都有自己的配置缓存
107
- setWorkclawConnectionConfig(accountId, {
108
- appKey: baseConfig.appKey ?? '',
109
- appSecret: baseConfig.appSecret ?? '',
110
- baseUrl: baseConfig.baseUrl,
111
- websocketUrl: baseConfig.websocketUrl,
112
- localIp: baseConfig.localIp,
113
- allowInsecureTls: baseConfig.allowInsecureTls,
114
- requestTimeout: baseConfig.requestTimeout,
115
- });
116
- }
117
- /**
118
- * 处理共享 WebSocket 消息
119
- */
120
- function handleSharedMessage(appKey, data, cfg, logger) {
121
- const parsed = parseWorkClawMessage(data, logger);
122
- if (!parsed) {
123
- logger.warn?.(`Gateway failed to parse message`);
124
- return;
125
- }
126
- // ping/pong/disconnect 无需路由
127
- if (parsed.type === 'ping') {
128
- const ws = getWorkclawWsConnection(appKey);
129
- if (ws && ws.readyState === 1) { // OPEN
130
- const pongResponse = {
131
- code: 200,
132
- message: 'pong',
133
- metadata: { contentType: 'application/json' },
134
- data: JSON.stringify(parsed.pongData),
135
- };
136
- ws.send(JSON.stringify(pongResponse));
137
- }
138
- return;
139
- }
140
- if (parsed.type === 'disconnect') {
141
- const ws = getWorkclawWsConnection(appKey);
142
- ws?.close();
143
- return;
144
- }
145
- // logger.info?.(`Gateway received message: ${data}`);
146
- // 根据消息类型确定 userId 和 agentId
147
- let userId = '';
148
- let agentId = '';
149
- if (parsed.type === 'agent_message' && parsed.message) {
150
- userId = String(parsed.message.userId || '');
151
- agentId = String(parsed.message.agentId || '');
152
- }
153
- else if (parsed.type === 'agent_created') {
154
- // agent_created 触发新账号创建
155
- const allDispatchers = getAllDispatchersByAppKey(appKey);
156
- if (allDispatchers && allDispatchers.size > 0) {
157
- const firstDispatcher = allDispatchers.values().next().value;
158
- dispatchWorkclawMessage(data, firstDispatcher.ctx).catch((err) => {
159
- logger.error?.(`Dispatch error: ${String(err)}`);
160
- });
161
- }
162
- return;
163
- }
164
- else if (parsed.type === 'agent_updated' || parsed.type === 'agent_deleted') {
165
- userId = String(parsed.eventData?.futureId || parsed.eventData?.userId || '');
166
- agentId = String(parsed.eventData?.id || parsed.eventData?.agentId || '');
167
- }
168
- else if (parsed.type === 'tools_list' || parsed.type === 'skills_list' || parsed.type === 'skills_event') {
169
- userId = String(parsed.eventData?.userId || '');
170
- agentId = String(parsed.eventData?.agentId || '');
171
- }
172
- else if (parsed.type === 'init_agent') {
173
- userId = String(parsed.eventData?.futureId || parsed.eventData?.userId || '');
174
- agentId = String(parsed.eventData?.id || parsed.eventData?.agentId || '');
175
- /**
176
- * 在 init_agent 中,配置文件的agentId 为空,所有无法通过 resolveAccountByUserIdAndAgentId 查找账户
177
- */
178
- const accountId = 'default';
179
- const dispatcher = getDispatcherByAppKeyAndAccountId(appKey, accountId);
180
- if (dispatcher) {
181
- dispatchWorkclawMessage(data, dispatcher.ctx).catch((err) => {
182
- logger.error?.(`Dispatch error: ${String(err)}`);
183
- });
184
- }
185
- else {
186
- logger.warn?.(`Gateway no dispatcher for accountId=${accountId}`);
187
- }
188
- return;
189
- }
190
- else if (parsed.type === 'cron_task_event') {
191
- // 任务事件处理,使用默认账户
192
- const accountId = 'default';
193
- const dispatcher = getDispatcherByAppKeyAndAccountId(appKey, accountId);
194
- if (dispatcher) {
195
- dispatchWorkclawMessage(data, dispatcher.ctx).catch((err) => {
196
- logger.error?.(`Dispatch error: ${String(err)}`);
197
- });
198
- }
199
- else {
200
- logger.warn?.(`Gateway (per-appKey) no dispatcher for accountId=${accountId}`);
201
- }
202
- return;
203
- }
204
- else {
205
- // 未知消息类型,忽略
206
- return;
207
- }
208
- const accountId = resolveAccountByUserIdAndAgentId(cfg, userId, agentId);
209
- if (!accountId) {
210
- logger.warn?.(`Gateway no account found for userId=${userId} agentId=${agentId}`);
211
- return;
212
- }
213
- const dispatcher = getDispatcherByAppKeyAndAccountId(appKey, accountId);
214
- if (dispatcher) {
215
- dispatchWorkclawMessage(data, dispatcher.ctx).catch((err) => {
216
- logger.error?.(`Dispatch error: ${String(err)}`);
217
- });
218
- }
219
- else {
220
- logger.warn?.(`Gateway no dispatcher for accountId=${accountId}`);
221
- }
222
- }
223
- export function stopWorkclawGateway(accountId) {
224
- const appKey = getAppKeyByAccountId(accountId);
225
- if (!appKey)
226
- return;
227
- unregisterAccountContext(appKey, accountId);
228
- if (getAllDispatchersByAppKey(appKey)?.size === 0) {
229
- const ws = getWorkclawWsConnection(appKey);
230
- ws?.close();
231
- clearWorkclawWsConnection(appKey);
232
- const scheduler = getReconnectScheduler(appKey);
233
- scheduler?.stopReconnect();
234
- clearReconnectScheduler(appKey);
235
- }
236
- clearWorkclawConnectionConfig(accountId);
237
- }
@@ -1,125 +0,0 @@
1
- import { readFile, stat } from "node:fs/promises";
2
- import path from "node:path";
3
- import os from "node:os";
4
- import { fileURLToPath } from "node:url";
5
- import { Agent, fetch as undiciFetch } from "undici";
6
- export function isLocalMediaSource(value) {
7
- const trimmed = value.trim();
8
- return (trimmed.startsWith("/") ||
9
- trimmed.startsWith("./") ||
10
- trimmed.startsWith("../") ||
11
- trimmed.startsWith("~") ||
12
- trimmed.startsWith("file://"));
13
- }
14
- export function resolveLocalPath(input) {
15
- if (input.startsWith("file://")) {
16
- return fileURLToPath(input);
17
- }
18
- if (input.startsWith("~")) {
19
- return path.join(os.homedir(), input.slice(1));
20
- }
21
- return path.resolve(input);
22
- }
23
- function readResponseUrlPath(data, pathValue) {
24
- if (!pathValue)
25
- return undefined;
26
- const parts = pathValue.split(".").filter(Boolean);
27
- let current = data;
28
- for (const part of parts) {
29
- if (!current || typeof current !== "object")
30
- return undefined;
31
- current = current[part];
32
- }
33
- return typeof current === "string" ? current : undefined;
34
- }
35
- function extractUploadedUrl(responseText, responseData, pathValue) {
36
- const fromPath = readResponseUrlPath(responseData, pathValue);
37
- if (fromPath)
38
- return fromPath;
39
- const direct = responseData.url ??
40
- responseData.mediaUrl;
41
- if (typeof direct === "string" && direct.trim())
42
- return direct;
43
- const dataObj = responseData.data;
44
- if (dataObj && typeof dataObj === "object") {
45
- const dataUrl = dataObj.url;
46
- const dataMedia = dataObj.mediaUrl;
47
- if (typeof dataUrl === "string" && dataUrl.trim())
48
- return dataUrl;
49
- if (typeof dataMedia === "string" && dataMedia.trim())
50
- return dataMedia;
51
- }
52
- const resultObj = responseData.result;
53
- if (resultObj && typeof resultObj === "object") {
54
- const resultUrl = resultObj.url;
55
- const resultMedia = resultObj.mediaUrl;
56
- if (typeof resultUrl === "string" && resultUrl.trim())
57
- return resultUrl;
58
- if (typeof resultMedia === "string" && resultMedia.trim())
59
- return resultMedia;
60
- }
61
- if (responseText.trim() && /^https?:\/\//i.test(responseText.trim())) {
62
- return responseText.trim();
63
- }
64
- return undefined;
65
- }
66
- export async function uploadLocalMedia(params) {
67
- const stats = await stat(params.filePath);
68
- if (!stats.isFile()) {
69
- throw new Error(`mediaUrl is not a file: ${params.filePath}`);
70
- }
71
- const content = await readFile(params.filePath);
72
- const form = new FormData();
73
- const fieldName = params.uploadFieldName?.trim() || "file";
74
- const fileName = path.basename(params.filePath);
75
- form.set(fieldName, new Blob([content], { type: "application/octet-stream" }), fileName);
76
- if (params.uploadFormFields) {
77
- for (const [key, value] of Object.entries(params.uploadFormFields)) {
78
- form.set(key, String(value));
79
- }
80
- }
81
- const controller = new AbortController();
82
- const timeoutId = setTimeout(() => controller.abort(), params.requestTimeout);
83
- let dispatcher = undefined;
84
- let doFetch = globalThis.fetch.bind(globalThis);
85
- if (params.allowInsecureTls) {
86
- try {
87
- dispatcher = new Agent({ connect: { rejectUnauthorized: false } });
88
- doFetch = undiciFetch;
89
- }
90
- catch (error) {
91
- const message = error instanceof Error ? error.message : String(error);
92
- throw new Error(`allowInsecureTls requires undici. ${message}`);
93
- }
94
- }
95
- try {
96
- const response = await doFetch(params.uploadUrl, {
97
- method: "POST",
98
- headers: params.uploadHeaders ?? {},
99
- body: form,
100
- signal: controller.signal,
101
- ...(dispatcher ? { dispatcher } : {}),
102
- });
103
- const responseText = await response.text().catch(() => "");
104
- if (!response.ok) {
105
- throw new Error(`Upload failed: ${response.status} ${responseText}`);
106
- }
107
- let data = {};
108
- if (responseText) {
109
- try {
110
- data = JSON.parse(responseText);
111
- }
112
- catch {
113
- data = {};
114
- }
115
- }
116
- const uploadedUrl = extractUploadedUrl(responseText, data, params.uploadResponseUrlPath);
117
- if (!uploadedUrl) {
118
- throw new Error("Upload response missing file URL");
119
- }
120
- return uploadedUrl;
121
- }
122
- finally {
123
- clearTimeout(timeoutId);
124
- }
125
- }