@workclaw/openclaw-workclaw 1.0.16 → 1.0.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.
Files changed (51) hide show
  1. package/README.md +21 -1
  2. package/index.ts +210 -210
  3. package/openclaw.plugin.json +1 -0
  4. package/package.json +12 -5
  5. package/setup-entry.ts +6 -0
  6. package/skills/openclaw-workclaw-cron/SKILL.md +45 -28
  7. package/src/accounts.ts +62 -37
  8. package/src/api/accounts-api.ts +88 -89
  9. package/src/api/prompts-api.ts +70 -77
  10. package/src/api/session-api.ts +99 -108
  11. package/src/api/skills-api.ts +35 -37
  12. package/src/api/workspace.ts +27 -29
  13. package/src/channel.ts +200 -202
  14. package/src/config-schema.ts +9 -9
  15. package/src/connection/workclaw-client.ts +554 -567
  16. package/src/gateway/agent-handlers.ts +392 -426
  17. package/src/gateway/config-writer.ts +228 -243
  18. package/src/gateway/message-context.ts +534 -362
  19. package/src/gateway/message-dispatcher.ts +529 -489
  20. package/src/gateway/reconnect.ts +217 -113
  21. package/src/gateway/skills-handler.ts +408 -472
  22. package/src/gateway/skills-list-handler.ts +9 -9
  23. package/src/gateway/tools-list-handler.ts +70 -72
  24. package/src/gateway/workclaw-gateway.ts +328 -486
  25. package/src/media/upload.ts +83 -94
  26. package/src/outbound/index.ts +57 -55
  27. package/src/outbound/workclaw-sender.ts +134 -133
  28. package/src/runtime.ts +291 -194
  29. package/src/send.ts +1 -1
  30. package/src/tools/openclaw-workclaw-cron/api/index.ts +6 -6
  31. package/src/tools/openclaw-workclaw-cron/src/add/params.ts +20 -19
  32. package/src/tools/openclaw-workclaw-cron/src/add/sync.ts +2 -2
  33. package/src/tools/openclaw-workclaw-cron/src/disable/params.ts +1 -1
  34. package/src/tools/openclaw-workclaw-cron/src/disable/sync.ts +3 -3
  35. package/src/tools/openclaw-workclaw-cron/src/enable/params.ts +1 -1
  36. package/src/tools/openclaw-workclaw-cron/src/enable/sync.ts +3 -3
  37. package/src/tools/openclaw-workclaw-cron/src/notify/sync.ts +2 -2
  38. package/src/tools/openclaw-workclaw-cron/src/remove/params.ts +1 -1
  39. package/src/tools/openclaw-workclaw-cron/src/remove/sync.ts +3 -3
  40. package/src/tools/openclaw-workclaw-cron/src/update/params.ts +195 -197
  41. package/src/tools/openclaw-workclaw-cron/src/update/sync.ts +4 -4
  42. package/src/tools/openclaw-workclaw-system/src/get/index.ts +2 -2
  43. package/src/tools/openclaw-workclaw-system/src/token/index.ts +4 -4
  44. package/src/types.ts +38 -40
  45. package/src/utils/content.ts +16 -21
  46. package/tests/accounts.test.ts +285 -0
  47. package/tests/message-context.test.ts +313 -0
  48. package/tests/reconnect.test.ts +257 -0
  49. package/tests/workclaw-client.test.ts +112 -0
  50. package/tsconfig.json +8 -5
  51. package/vitest.config.ts +8 -0
@@ -1,133 +1,134 @@
1
- import type { OpenclawWorkclawConnectionConfig } from '../connection/workclaw-client.js'
2
- import type { OpenclawWorkclawFullAccountConfig } from '../types.js'
1
+ import type { WorkclawFullAccountConfig } from "../types.js";
3
2
  import {
4
- resolveOpenclawWorkclawMessage,
5
- sendOpenclawWorkclawMessage,
6
- sendOpenclawWorkclawReplyMessage as sendWorkclawReplyToMessage,
7
-
8
- } from '../connection/workclaw-client.js'
9
- import { getOpenclawWorkclawLogger } from '../runtime.js'
3
+ sendWorkclawMessage,
4
+ sendWorkclawReplyMessage as sendWorkclawReplyToMessage,
5
+ resolveWorkclawMessage,
6
+ type WorkclawConnectionConfig,
7
+ } from "../connection/workclaw-client.js";
8
+ import { getWorkclawLogger } from "../runtime.js";
10
9
 
11
10
  export interface WorkClawSenderParams {
12
- cacheKey: string
13
- to: string
14
- text: string
15
- mediaUrl?: string
16
- replyToMessageId?: string
17
- openConversationId?: string
18
- agentId?: string | number
19
- config: OpenclawWorkclawFullAccountConfig
20
- /**
21
- * 消息类型:
22
- * - "reply": 回复消息(用户触发)
23
- * - "push": 主动推送(定时任务触发)
24
- */
25
- messageType?: 'reply' | 'push'
26
- msgType?: string
27
- last?: boolean
11
+ cacheKey: string;
12
+ to: string;
13
+ text: string;
14
+ mediaUrl?: string;
15
+ replyToMessageId?: string;
16
+ openConversationId?: string;
17
+ agentId?: string | number;
18
+ config: WorkclawFullAccountConfig;
19
+ /**
20
+ * 消息类型:
21
+ * - "reply": 回复消息(用户触发)
22
+ * - "push": 主动推送(定时任务触发)
23
+ */
24
+ messageType?: "reply" | "push";
25
+ msgType?: string;
26
+ last?: boolean;
28
27
  }
29
28
 
30
- export async function sendOpenclawWorkclawOutboundMessage(
31
- params: WorkClawSenderParams,
29
+
30
+ export async function sendWorkclawOutboundMessage(
31
+ params: WorkClawSenderParams,
32
32
  ): Promise<{ messageId: string }> {
33
- const {
34
- cacheKey,
35
- to,
36
- mediaUrl,
37
- replyToMessageId,
38
- openConversationId,
39
- agentId,
40
- config,
41
- messageType = 'reply',
42
- last,
43
- } = params
44
-
45
- let msgType = params.msgType
46
- let content = params.text
47
-
48
- // 优先级: 传入参数 > 配置
49
- const resolvedAgentId = agentId ?? config.agentId
50
-
51
- if (resolvedAgentId === undefined || resolvedAgentId === null || String(resolvedAgentId).trim() === '') {
52
- throw new Error(
53
- 'agentId is required for sending messages. '
54
- + 'Please create an account via cloud platform command or configure accounts in openclaw.json',
55
- )
56
- }
57
-
58
- if (!msgType) {
59
- ({ msgType, content } = resolveOpenclawWorkclawMessage(content, mediaUrl))
60
- }
61
-
62
- // msgType 转换为 "1"(文本)或其他类型码
63
- const messageTypeCode = msgType === 'text' ? '1' : msgType
64
-
65
- // 构建 OpenclawWorkclawConnectionConfig(短名格式,用于 connection 模块)
66
- const workclawConfig: OpenclawWorkclawConnectionConfig = {
67
- baseUrl: config.baseUrl ?? '',
68
- appKey: config.appKey ?? '',
69
- appSecret: config.appSecret ?? '',
70
- localIp: config.localIp,
71
- allowInsecureTls: config.allowInsecureTls,
72
- requestTimeout: config.requestTimeout,
73
- }
74
-
75
- // 解析 userId 作为 receiveId(优先使用配置中保存的原始 userId)
76
- // 配置中的 userId 是原始值(可能为负数),to 是绝对值(OpenClaw 要求)
77
- const receiveId = config.userId ?? to
78
-
79
- // 从配置中读取 endpoint,支持自定义
80
- const replyEndpoint = config.replyEndpoint || '/open-apis/im/v1/messages/{messageId}/reply'
81
- const pushEndpoint = config.pushEndpoint || '/open-apis/im/v1/messages'
82
-
83
- if (messageType === 'reply') {
84
- // 回复消息需要 replyToMessageId
85
- if (!replyToMessageId) {
86
- throw new Error('replyToMessageId is required for reply message')
33
+ const {
34
+ cacheKey,
35
+ to,
36
+ mediaUrl,
37
+ replyToMessageId,
38
+ openConversationId,
39
+ agentId,
40
+ config,
41
+ messageType = "reply",
42
+ last,
43
+ } = params;
44
+
45
+ let msgType = params.msgType;
46
+ let content = params.text;
47
+
48
+ // 优先级: 传入参数 > 配置
49
+ const resolvedAgentId = agentId ?? config.agentId;
50
+
51
+ if (resolvedAgentId === undefined || resolvedAgentId === null || String(resolvedAgentId).trim() === "") {
52
+ throw new Error(
53
+ "agentId is required for sending messages. " +
54
+ "Please create an account via cloud platform command or configure accounts in openclaw.json"
55
+ );
87
56
  }
88
57
 
89
- // 优先使用传入的 openConversationId,其次使用配置中持久化的
90
- const resolvedOpenConversationId = openConversationId ?? config.openConversationId
91
- getOpenclawWorkclawLogger().info(`Sending reply message to messageId: ${replyToMessageId}, openConversationId: ${resolvedOpenConversationId}`)
92
-
93
- const msgId = await sendWorkclawReplyToMessage({
94
- cacheKey,
95
- config: workclawConfig,
96
- agentId: resolvedAgentId,
97
- receiveId,
98
- msgType: messageTypeCode,
99
- content,
100
- messageId: replyToMessageId,
101
- openConversationId: resolvedOpenConversationId,
102
- endpoint: replyEndpoint.replace('{messageId}', String(replyToMessageId)),
103
- last,
104
- })
105
-
106
- return { messageId: msgId }
107
- }
108
- else {
109
- // 主动推送消息
110
- getOpenclawWorkclawLogger().info(` Sending proactive message`)
111
-
112
- // 优先使用传入的 openConversationId,其次使用配置中持久化的
113
- const resolvedOpenConversationId = openConversationId ?? config.openConversationId
114
- getOpenclawWorkclawLogger().info(` Resolved openConversationId: ${resolvedOpenConversationId}`)
115
- getOpenclawWorkclawLogger().info(` Config openConversationId: ${config.openConversationId}`)
116
-
117
- const msgId = await sendOpenclawWorkclawMessage({
118
- cacheKey,
119
- config: workclawConfig,
120
- agentId: resolvedAgentId,
121
- receiveId,
122
- msgType: messageTypeCode,
123
- content,
124
- openConversationId: resolvedOpenConversationId,
125
- endpoint: pushEndpoint,
126
- last,
127
- })
128
-
129
- return { messageId: msgId }
130
- }
58
+
59
+ if (!msgType) {
60
+ ({ msgType, content } = resolveWorkclawMessage(content, mediaUrl));
61
+ }
62
+
63
+
64
+ // msgType 转换为 "1"(文本)或其他类型码
65
+ const messageTypeCode = msgType === "text" ? "1" : msgType;
66
+
67
+ // 构建 WorkclawConnectionConfig(短名格式,用于 connection 模块)
68
+ const workclawConfig: WorkclawConnectionConfig = {
69
+ baseUrl: config.baseUrl ?? "",
70
+ appKey: config.appKey ?? "",
71
+ appSecret: config.appSecret ?? "",
72
+ localIp: config.localIp,
73
+ allowInsecureTls: config.allowInsecureTls,
74
+ requestTimeout: config.requestTimeout,
75
+ };
76
+
77
+ // 解析 userId 作为 receiveId(优先使用配置中保存的原始 userId)
78
+ // 配置中的 userId 是原始值(可能为负数),to 是绝对值(OpenClaw 要求)
79
+ const receiveId = config.userId ?? to;
80
+
81
+ // 从配置中读取 endpoint,支持自定义
82
+ const replyEndpoint = config.replyEndpoint || "/open-apis/im/v1/messages/{messageId}/reply";
83
+ const pushEndpoint = config.pushEndpoint || "/open-apis/im/v1/messages";
84
+
85
+ if (messageType === "reply") {
86
+ // 回复消息需要 replyToMessageId
87
+ if (!replyToMessageId) {
88
+ throw new Error("replyToMessageId is required for reply message");
89
+ }
90
+
91
+ // 优先使用传入的 openConversationId,其次使用配置中持久化的
92
+ const resolvedOpenConversationId = openConversationId ?? config.openConversationId;
93
+ getWorkclawLogger().info(`Sending reply message to messageId: ${replyToMessageId}, openConversationId: ${resolvedOpenConversationId}`);
94
+
95
+ const msgId = await sendWorkclawReplyToMessage({
96
+ cacheKey,
97
+ config: workclawConfig,
98
+ agentId: resolvedAgentId,
99
+ receiveId,
100
+ msgType: messageTypeCode,
101
+ content,
102
+ messageId: replyToMessageId,
103
+ openConversationId: resolvedOpenConversationId,
104
+ endpoint: replyEndpoint.replace("{messageId}", String(replyToMessageId)),
105
+ last,
106
+ });
107
+
108
+ return { messageId: msgId };
109
+ } else {
110
+ // 主动推送消息
111
+ getWorkclawLogger().info(` Sending proactive message`);
112
+
113
+ // 优先使用传入的 openConversationId,其次使用配置中持久化的
114
+ const resolvedOpenConversationId = openConversationId ?? config.openConversationId;
115
+ getWorkclawLogger().info(` Resolved openConversationId: ${resolvedOpenConversationId}`);
116
+ getWorkclawLogger().info(` Config openConversationId: ${config.openConversationId}`);
117
+
118
+ const msgId = await sendWorkclawMessage({
119
+ cacheKey,
120
+ config: workclawConfig,
121
+ agentId: resolvedAgentId,
122
+ receiveId,
123
+ msgType: messageTypeCode,
124
+ content,
125
+ openConversationId: resolvedOpenConversationId,
126
+ endpoint: pushEndpoint,
127
+ last,
128
+ });
129
+
130
+ return { messageId: msgId };
131
+ }
131
132
  }
132
133
 
133
134
  /**
@@ -135,23 +136,23 @@ export async function sendOpenclawWorkclawOutboundMessage(
135
136
  * POST /im/v1/messages
136
137
  */
137
138
  export async function sendWorkClawPushMessage(
138
- params: Omit<WorkClawSenderParams, 'messageType'>,
139
+ params: Omit<WorkClawSenderParams, "messageType">,
139
140
  ): Promise<{ messageId: string }> {
140
- return sendOpenclawWorkclawOutboundMessage({
141
- ...params,
142
- messageType: 'push',
143
- })
141
+ return sendWorkclawOutboundMessage({
142
+ ...params,
143
+ messageType: "push",
144
+ });
144
145
  }
145
146
 
146
147
  /**
147
148
  * 发送回复消息(用户触发)
148
149
  * POST /im/v1/messages/{messageId}/reply
149
150
  */
150
- export async function sendOpenclawWorkclawReplyMessage(
151
- params: Omit<WorkClawSenderParams, 'messageType'>,
151
+ export async function sendWorkclawReplyMessage(
152
+ params: Omit<WorkClawSenderParams, "messageType">,
152
153
  ): Promise<{ messageId: string }> {
153
- return sendOpenclawWorkclawOutboundMessage({
154
- ...params,
155
- messageType: 'reply',
156
- })
154
+ return sendWorkclawOutboundMessage({
155
+ ...params,
156
+ messageType: "reply",
157
+ });
157
158
  }