openclaw-channel-claw-task-ops 0.1.3 → 0.1.4
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 +125 -111
- package/dist/src/consumer.d.ts +0 -6
- package/dist/src/consumer.d.ts.map +1 -1
- package/dist/src/consumer.js +17 -12
- package/dist/src/hsf-client.d.ts +1 -1
- package/dist/src/hsf-client.d.ts.map +1 -1
- package/dist/src/hsf-client.js +50 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,140 +2,154 @@
|
|
|
2
2
|
|
|
3
3
|
OpenClaw 渠道插件:从 Claw Task Ops 拉取任务,交由 OpenClaw Agent 处理,并将处理结果和日志反馈回去。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- 入站:轮询 HSF HTTP 网关拉取 pending 任务,自动更新为 processing
|
|
6
|
+
- 出站:Agent 处理结果通过 HSF 反馈,日志写入 claw_task_log
|
|
7
|
+
- 自动注册:插件启动时自动注册实例,定时心跳更新在线状态
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
## 安装
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
|
|
12
|
+
openclaw plugins install openclaw-channel-claw-task-ops
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
安装后重启网关:
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
```bash
|
|
18
|
+
openclaw gateway restart
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 更新
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
openclaw plugins update openclaw-channel-claw-task-ops
|
|
25
|
+
openclaw gateway restart
|
|
26
|
+
```
|
|
16
27
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
instanceId: "your_claw_instance_id"
|
|
23
|
-
pollIntervalSec: 10
|
|
24
|
-
pullLimit: 5
|
|
28
|
+
## 卸载
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
openclaw plugins uninstall openclaw-channel-claw-task-ops
|
|
32
|
+
openclaw gateway restart
|
|
25
33
|
```
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
instanceId: "your_claw_instance_id"
|
|
35
|
+
## 配置(channels.claw-task-ops)
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"channels": {
|
|
40
|
+
"claw-task-ops": {
|
|
41
|
+
"gatewayBaseUrl": "https://pre-clawtask.alibaba-inc.com",
|
|
42
|
+
"instanceId": "my_claw_instance",
|
|
43
|
+
"instanceName": "我的Claw实例",
|
|
44
|
+
"instanceDescription": "处理数据同步任务",
|
|
45
|
+
"authorizedUsers": ["12345", "67890"],
|
|
46
|
+
"accessToken": "your-secret-token"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
43
50
|
```
|
|
44
51
|
|
|
52
|
+
| 参数 | 必填 | 默认值 | 说明 |
|
|
53
|
+
|------|------|--------|------|
|
|
54
|
+
| `gatewayBaseUrl` | 是 | - | HSF HTTP 网关地址 |
|
|
55
|
+
| `instanceId` | 是 | - | 实例唯一标识 |
|
|
56
|
+
| `instanceName` | 否 | = instanceId | 实例显示名称 |
|
|
57
|
+
| `instanceDescription` | 否 | 空 | 实例描述 |
|
|
58
|
+
| `authorizedUsers` | 否 | 空(不限制) | 授权用户工号列表,控制管理界面访问权限 |
|
|
59
|
+
| `accessToken` | 否 | 空(不校验) | 投递令牌,HTTP/HSF 投递任务时需携带 |
|
|
60
|
+
|
|
61
|
+
## 自动注册与权限管理
|
|
62
|
+
|
|
63
|
+
插件启动后会自动向后端注册实例。如果 `instanceId` 对应的实例不存在,后端会自动创建;如果已存在,则更新状态为 running 并刷新 `lastOnlineTime`。此后每次轮询都会更新 `lastOnlineTime` 作为心跳。
|
|
64
|
+
|
|
65
|
+
- **authorizedUsers**:配置后仅列表中的工号用户可在管理界面查看和操作该实例,未授权用户会看到「无权限」提示。为空或不配置时所有人可访问。
|
|
66
|
+
- **accessToken**:配置后通过 HTTP/HSF 投递任务时必须携带此 token,后端会校验 token 与实例配置是否一致,不一致则拒绝投递。未配置时不校验。
|
|
67
|
+
|
|
45
68
|
## 投递任务
|
|
46
69
|
|
|
47
|
-
###
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
headers: { 'Content-Type': 'application/json' },
|
|
65
|
-
body: JSON.stringify({
|
|
66
|
-
dataKey: taskId,
|
|
67
|
-
dataValue: {
|
|
68
|
-
taskId,
|
|
69
|
-
instanceId: 'your_claw_instance_id',
|
|
70
|
-
taskName: '数据同步任务',
|
|
71
|
-
taskType: 'data_sync',
|
|
72
|
-
priority: 'high', // high | medium | low
|
|
73
|
-
status: 'pending', // 必须为 pending,插件才会拉取
|
|
74
|
-
payload: { key: 'value' },
|
|
75
|
-
operator: '张三',
|
|
76
|
-
operatorId: '12345',
|
|
77
|
-
createdTime: new Date().toISOString(),
|
|
78
|
-
updatedTime: new Date().toISOString(),
|
|
79
|
-
deleted: 0,
|
|
70
|
+
### 通过 HTTP 接口投递
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
curl -X POST 'https://pre-clawtask.alibaba-inc.com/luyou/public/gateway/executeHsf.json' \
|
|
74
|
+
-H 'Content-Type: application/json' \
|
|
75
|
+
-d '{
|
|
76
|
+
"appName": "onetouch-logistics-operation",
|
|
77
|
+
"hsfName": "com.alibaba.onetouch.logistics.compass.service.ClawTaskOpsRemoteService#submitTask(com.alibaba.onetouch.logistics.compass.dto.claw.ClawTaskDTO,java.lang.String)~com.alibaba.onetouch.basedata.api.Result",
|
|
78
|
+
"args": [
|
|
79
|
+
{
|
|
80
|
+
"instanceId": "your_claw_instance_id",
|
|
81
|
+
"taskName": "数据同步任务",
|
|
82
|
+
"taskType": "data_sync",
|
|
83
|
+
"priority": "high",
|
|
84
|
+
"payload": { "sourceTable": "orders", "targetTable": "orders_backup" },
|
|
85
|
+
"operator": "张三",
|
|
86
|
+
"operatorId": "12345"
|
|
80
87
|
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
"your-secret-token"
|
|
89
|
+
]
|
|
90
|
+
}'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`args` 第二个参数为 `accessToken`,需与实例配置的 token 一致。`taskId` 和 `status` 可不传,后端自动生成。
|
|
94
|
+
|
|
95
|
+
### 通过 HSF 接口投递(Java)
|
|
96
|
+
|
|
97
|
+
引入 compass-sdk 依赖([查询最新版本](https://artlab.alibaba-inc.com/GAResult?GroupId=com.alibaba.onetouch&Artifact=compass-sdk)):
|
|
98
|
+
|
|
99
|
+
```xml
|
|
100
|
+
<dependency>
|
|
101
|
+
<groupId>com.alibaba.onetouch</groupId>
|
|
102
|
+
<artifactId>compass-sdk</artifactId>
|
|
103
|
+
<version>最新版本</version>
|
|
104
|
+
</dependency>
|
|
90
105
|
```
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
配置 HSF Consumer 并调用:
|
|
93
108
|
|
|
94
109
|
```java
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
task
|
|
100
|
-
task.
|
|
101
|
-
task.
|
|
102
|
-
task.
|
|
103
|
-
task.
|
|
104
|
-
task.
|
|
105
|
-
task.
|
|
106
|
-
task.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"taskId", task.getTaskId(),
|
|
112
|
-
"instanceId", task.getInstanceId(),
|
|
113
|
-
"status", "pending",
|
|
114
|
-
"priority", "medium",
|
|
115
|
-
"deleted", "0"
|
|
116
|
-
));
|
|
117
|
-
|
|
118
|
-
compassDataWarehouseRepository.saveData(task);
|
|
110
|
+
@HSFConsumer(serviceInterface = ClawTaskOpsRemoteService.class, serviceVersion = "1.0.0")
|
|
111
|
+
private ClawTaskOpsRemoteService clawTaskOpsRemoteService;
|
|
112
|
+
|
|
113
|
+
public String deliverTask() {
|
|
114
|
+
ClawTaskDTO task = new ClawTaskDTO();
|
|
115
|
+
task.setInstanceId("your_claw_instance_id");
|
|
116
|
+
task.setTaskName("报表生成任务");
|
|
117
|
+
task.setTaskType("report");
|
|
118
|
+
task.setPriority("medium");
|
|
119
|
+
task.setPayload(Map.of("reportType", "daily"));
|
|
120
|
+
task.setOperator("系统");
|
|
121
|
+
task.setOperatorId("system");
|
|
122
|
+
|
|
123
|
+
Result<ClawTaskDTO> result = clawTaskOpsRemoteService.submitTask(task, "your-secret-token");
|
|
124
|
+
return result.getData().getTaskId();
|
|
125
|
+
}
|
|
119
126
|
```
|
|
120
127
|
|
|
121
128
|
## 处理流程
|
|
122
129
|
|
|
123
130
|
```
|
|
124
|
-
投递任务 (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
1. 投递任务 (HTTP / HSF / 管理界面)
|
|
132
|
+
↓
|
|
133
|
+
2. 进入队列 (status = pending)
|
|
134
|
+
↓
|
|
135
|
+
3. 插件拉取 (状态变更为 processing)
|
|
136
|
+
↓
|
|
137
|
+
4. Agent 处理 (OpenClaw 执行任务)
|
|
138
|
+
↓
|
|
139
|
+
5. 写入日志 (过程记录到跟进日志)
|
|
140
|
+
↓
|
|
141
|
+
6. 反馈结果 (status → completed / failed)
|
|
133
142
|
```
|
|
134
143
|
|
|
135
|
-
##
|
|
144
|
+
## HSF 接口一览
|
|
136
145
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
接口:`com.alibaba.onetouch.logistics.compass.service.ClawTaskOpsRemoteService`
|
|
147
|
+
HSF 版本:1.0.0 | 应用:onetouch-logistics-operation
|
|
148
|
+
|
|
149
|
+
| 方法 | 参数 | 说明 |
|
|
150
|
+
|------|------|------|
|
|
151
|
+
| `submitTask` | ClawTaskDTO, String accessToken | 投递任务(需校验 accessToken) |
|
|
152
|
+
| `pullTasks` | String instanceId, int limit | 拉取 pending 任务,自动更新为 processing |
|
|
153
|
+
| `feedbackTask` | String taskId, String status, String result | 反馈任务结果(completed / failed) |
|
|
154
|
+
| `addTaskLog` | ClawTaskLogDTO | 添加任务处理日志 |
|
|
155
|
+
| `registerInstance` | String id, String name, String desc, Map extConfig | 注册/心跳实例(含授权配置) |
|
package/dist/src/consumer.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
1
|
import { type OpenClawPluginApi } from "openclaw/plugin-sdk/irc";
|
|
2
|
-
/**
|
|
3
|
-
* 注册任务消费者:
|
|
4
|
-
* 1. 启动时自动注册实例到后端(不存在则创建,已存在则更新为 running)
|
|
5
|
-
* 2. 每次轮询时通过 registerInstance 心跳更新 lastOnlineTime
|
|
6
|
-
* 3. 拉取 pending 任务分发给 OpenClaw 处理
|
|
7
|
-
*/
|
|
8
2
|
export declare function registerClawTaskOpsConsumer(api: OpenClawPluginApi): void;
|
|
9
3
|
//# sourceMappingURL=consumer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consumer.d.ts","sourceRoot":"","sources":["../../src/consumer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAajE
|
|
1
|
+
{"version":3,"file":"consumer.d.ts","sourceRoot":"","sources":["../../src/consumer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAajE,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAwFxE"}
|
package/dist/src/consumer.js
CHANGED
|
@@ -8,17 +8,12 @@ const RECONNECT_MS_MAX = 60_000;
|
|
|
8
8
|
function sleep(ms) {
|
|
9
9
|
return new Promise((r) => setTimeout(r, ms));
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
* 注册任务消费者:
|
|
13
|
-
* 1. 启动时自动注册实例到后端(不存在则创建,已存在则更新为 running)
|
|
14
|
-
* 2. 每次轮询时通过 registerInstance 心跳更新 lastOnlineTime
|
|
15
|
-
* 3. 拉取 pending 任务分发给 OpenClaw 处理
|
|
16
|
-
*/
|
|
17
11
|
export function registerClawTaskOpsConsumer(api) {
|
|
18
12
|
attachLogger(api);
|
|
19
13
|
logInfo("consumer_register_ok (polling loop starting)");
|
|
20
14
|
let stopped = false;
|
|
21
15
|
let reconnectDelay = RECONNECT_MS_MIN;
|
|
16
|
+
let pollCount = 0;
|
|
22
17
|
const loop = async () => {
|
|
23
18
|
while (!stopped) {
|
|
24
19
|
const cfg = api.runtime.config.loadConfig();
|
|
@@ -33,29 +28,39 @@ export function registerClawTaskOpsConsumer(api) {
|
|
|
33
28
|
continue;
|
|
34
29
|
}
|
|
35
30
|
reconnectDelay = RECONNECT_MS_MIN;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
pollCount++;
|
|
32
|
+
logInfo(`poll_cycle_start #${pollCount} instanceId=${account.instanceId} gateway=${account.gatewayBaseUrl} interval=${account.pollIntervalSec}s`);
|
|
33
|
+
// 心跳注册
|
|
34
|
+
const heartbeatOk = await registerInstance(account.gatewayBaseUrl, account.instanceId, account.instanceName, account.instanceDescription, {
|
|
39
35
|
authorizedUsers: account.authorizedUsers,
|
|
40
36
|
accessToken: account.accessToken,
|
|
41
37
|
});
|
|
38
|
+
if (!heartbeatOk) {
|
|
39
|
+
logWarn(`poll_cycle_skip #${pollCount} heartbeat failed, skip pullTasks`);
|
|
40
|
+
await sleep(account.pollIntervalSec * 1000);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// 拉取任务
|
|
42
44
|
try {
|
|
43
45
|
const tasks = await pullTasks(account.gatewayBaseUrl, account.instanceId, account.pullLimit);
|
|
44
46
|
if (tasks.length > 0) {
|
|
45
|
-
logInfo(`
|
|
47
|
+
logInfo(`poll_cycle_dispatch #${pollCount} dispatching ${tasks.length} task(s)`);
|
|
46
48
|
for (const task of tasks) {
|
|
47
49
|
try {
|
|
50
|
+
logInfo(`dispatch_begin taskId=${task.taskId} taskName=${task.taskName} priority=${task.priority}`);
|
|
48
51
|
await dispatchTaskInbound({ api, cfg, account, task });
|
|
52
|
+
logInfo(`dispatch_end taskId=${task.taskId} status=ok`);
|
|
49
53
|
}
|
|
50
54
|
catch (e) {
|
|
51
|
-
logError(`
|
|
55
|
+
logError(`dispatch_end taskId=${task.taskId} status=error err=${String(e)}`);
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
60
|
catch (e) {
|
|
57
|
-
logError(`
|
|
61
|
+
logError(`poll_cycle_error #${pollCount} err=${String(e)}`);
|
|
58
62
|
}
|
|
63
|
+
logInfo(`poll_cycle_done #${pollCount} next in ${account.pollIntervalSec}s`);
|
|
59
64
|
await sleep(account.pollIntervalSec * 1000);
|
|
60
65
|
}
|
|
61
66
|
};
|
package/dist/src/hsf-client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClawTaskPayload } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
* 注册实例(自动注册 + 心跳更新 lastOnlineTime
|
|
3
|
+
* 注册实例(自动注册 + 心跳更新 lastOnlineTime)
|
|
4
4
|
*/
|
|
5
5
|
export declare function registerInstance(gatewayBaseUrl: string, instanceId: string, name: string, description: string, extConfig: {
|
|
6
6
|
authorizedUsers?: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hsf-client.d.ts","sourceRoot":"","sources":["../../src/hsf-client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"hsf-client.d.ts","sourceRoot":"","sources":["../../src/hsf-client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAyElD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC,CAgB5B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAWlB"}
|
package/dist/src/hsf-client.js
CHANGED
|
@@ -1,46 +1,66 @@
|
|
|
1
1
|
import { HSF_ADD_TASK_LOG, HSF_APP_NAME, HSF_FEEDBACK_TASK, HSF_GATEWAY_PATH, HSF_PULL_TASKS, HSF_REGISTER_INSTANCE, } from "./constants.js";
|
|
2
2
|
import { logError, logInfo, logWarn } from "./logging.js";
|
|
3
|
+
/** 从 hsfName 中提取方法名,如 ...#submitTask(...)~... → submitTask */
|
|
4
|
+
function methodNameFrom(hsfName) {
|
|
5
|
+
const m = hsfName.match(/#(\w+)\(/);
|
|
6
|
+
return m ? m[1] : hsfName;
|
|
7
|
+
}
|
|
3
8
|
/**
|
|
4
|
-
* 通用 HSF HTTP
|
|
9
|
+
* 通用 HSF HTTP 网关调用(含详细日志)
|
|
5
10
|
*/
|
|
6
11
|
async function callHsf(gatewayBaseUrl, hsfName, args) {
|
|
7
12
|
const url = `${gatewayBaseUrl}${HSF_GATEWAY_PATH}`;
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const method = methodNameFrom(hsfName);
|
|
14
|
+
const t0 = Date.now();
|
|
15
|
+
logInfo(`hsf_request method=${method} url=${url}`);
|
|
16
|
+
let response;
|
|
17
|
+
try {
|
|
18
|
+
response = await fetch(url, {
|
|
19
|
+
method: "POST",
|
|
20
|
+
headers: { "Content-Type": "application/json" },
|
|
21
|
+
body: JSON.stringify({ appName: HSF_APP_NAME, hsfName, args }),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
logError(`hsf_network_error method=${method} url=${url} err=${String(e)}`);
|
|
26
|
+
throw e;
|
|
27
|
+
}
|
|
28
|
+
const durationMs = Date.now() - t0;
|
|
17
29
|
if (!response.ok) {
|
|
30
|
+
logError(`hsf_http_error method=${method} status=${response.status} duration=${durationMs}ms`);
|
|
18
31
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
19
32
|
}
|
|
20
33
|
const result = (await response.json());
|
|
21
34
|
if (result.code !== 0) {
|
|
22
|
-
|
|
35
|
+
const errMsg = result.message || result.data?.result?.message || "HSF 调用失败";
|
|
36
|
+
logError(`hsf_gateway_error method=${method} code=${result.code} message=${errMsg} duration=${durationMs}ms`);
|
|
37
|
+
throw new Error(errMsg);
|
|
23
38
|
}
|
|
24
39
|
if (result.data?.result) {
|
|
25
40
|
const biz = result.data.result;
|
|
26
41
|
if (!biz.success && biz.code !== "SUCCESS" && biz.code !== 0) {
|
|
27
|
-
|
|
42
|
+
const bizMsg = biz.message || "HSF 业务调用失败";
|
|
43
|
+
logError(`hsf_biz_error method=${method} code=${biz.code} message=${bizMsg} duration=${durationMs}ms`);
|
|
44
|
+
throw new Error(bizMsg);
|
|
28
45
|
}
|
|
46
|
+
logInfo(`hsf_response method=${method} success=true duration=${durationMs}ms`);
|
|
29
47
|
return biz.data;
|
|
30
48
|
}
|
|
49
|
+
logInfo(`hsf_response method=${method} success=true duration=${durationMs}ms`);
|
|
31
50
|
return result.data;
|
|
32
51
|
}
|
|
33
52
|
/**
|
|
34
|
-
* 注册实例(自动注册 + 心跳更新 lastOnlineTime
|
|
53
|
+
* 注册实例(自动注册 + 心跳更新 lastOnlineTime)
|
|
35
54
|
*/
|
|
36
55
|
export async function registerInstance(gatewayBaseUrl, instanceId, name, description, extConfig) {
|
|
37
56
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
logInfo(`heartbeat_start instanceId=${instanceId} name=${name}`);
|
|
58
|
+
const data = await callHsf(gatewayBaseUrl, HSF_REGISTER_INSTANCE, [instanceId, name, description, extConfig]);
|
|
59
|
+
logInfo(`heartbeat_ok instanceId=${instanceId} response=${JSON.stringify(data ?? null).slice(0, 200)}`);
|
|
40
60
|
return true;
|
|
41
61
|
}
|
|
42
62
|
catch (e) {
|
|
43
|
-
logWarn(`
|
|
63
|
+
logWarn(`heartbeat_fail instanceId=${instanceId} err=${String(e)}`);
|
|
44
64
|
return false;
|
|
45
65
|
}
|
|
46
66
|
}
|
|
@@ -49,13 +69,20 @@ export async function registerInstance(gatewayBaseUrl, instanceId, name, descrip
|
|
|
49
69
|
*/
|
|
50
70
|
export async function pullTasks(gatewayBaseUrl, instanceId, limit) {
|
|
51
71
|
try {
|
|
72
|
+
logInfo(`pullTasks_start instanceId=${instanceId} limit=${limit}`);
|
|
52
73
|
const data = await callHsf(gatewayBaseUrl, HSF_PULL_TASKS, [instanceId, limit]);
|
|
53
74
|
const tasks = data ?? [];
|
|
54
|
-
|
|
75
|
+
if (tasks.length > 0) {
|
|
76
|
+
const taskIds = tasks.map(t => t.taskId).join(", ");
|
|
77
|
+
logInfo(`pullTasks_ok instanceId=${instanceId} count=${tasks.length} taskIds=[${taskIds}]`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
logInfo(`pullTasks_ok instanceId=${instanceId} count=0 (队列为空)`);
|
|
81
|
+
}
|
|
55
82
|
return tasks;
|
|
56
83
|
}
|
|
57
84
|
catch (e) {
|
|
58
|
-
logWarn(`
|
|
85
|
+
logWarn(`pullTasks_fail instanceId=${instanceId} err=${String(e)}`);
|
|
59
86
|
return [];
|
|
60
87
|
}
|
|
61
88
|
}
|
|
@@ -64,12 +91,13 @@ export async function pullTasks(gatewayBaseUrl, instanceId, limit) {
|
|
|
64
91
|
*/
|
|
65
92
|
export async function feedbackTask(gatewayBaseUrl, taskId, status, result) {
|
|
66
93
|
try {
|
|
94
|
+
logInfo(`feedbackTask_start taskId=${taskId} status=${status}`);
|
|
67
95
|
await callHsf(gatewayBaseUrl, HSF_FEEDBACK_TASK, [taskId, status, result]);
|
|
68
|
-
logInfo(`
|
|
96
|
+
logInfo(`feedbackTask_ok taskId=${taskId} status=${status}`);
|
|
69
97
|
return true;
|
|
70
98
|
}
|
|
71
99
|
catch (e) {
|
|
72
|
-
logError(`
|
|
100
|
+
logError(`feedbackTask_fail taskId=${taskId} err=${String(e)}`);
|
|
73
101
|
return false;
|
|
74
102
|
}
|
|
75
103
|
}
|
|
@@ -81,11 +109,11 @@ export async function addTaskLog(gatewayBaseUrl, taskId, instanceId, logType, co
|
|
|
81
109
|
await callHsf(gatewayBaseUrl, HSF_ADD_TASK_LOG, [
|
|
82
110
|
{ taskId, instanceId, logType, content, operator: "openclaw", operatorId: "openclaw" },
|
|
83
111
|
]);
|
|
84
|
-
logInfo(`
|
|
112
|
+
logInfo(`addTaskLog_ok taskId=${taskId} logType=${logType}`);
|
|
85
113
|
return true;
|
|
86
114
|
}
|
|
87
115
|
catch (e) {
|
|
88
|
-
logWarn(`
|
|
116
|
+
logWarn(`addTaskLog_fail taskId=${taskId} err=${String(e)}`);
|
|
89
117
|
return false;
|
|
90
118
|
}
|
|
91
119
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-channel-claw-task-ops",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "OpenClaw channel plugin for Claw Task Ops: pulls tasks via HSF HTTP gateway, processes them, and feeds back logs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|