agent-resource-management 1.3.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/.claude/settings.local.json +8 -0
- package/README.md +196 -0
- package/bun.lock +32 -0
- package/data/skills/bad-name-skill/SKILL.md +8 -0
- package/data/skills/github-tool/SKILL.md +11 -0
- package/data/skills/invalid-skill/SKILL.md +3 -0
- package/data/skills/pdf-tool/SKILL.md +11 -0
- package/data/skills/pdf-tool.zip +0 -0
- package/dist/main.js +1330 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/AGENT.md +18 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260Loki/346/227/245/345/277/227/346/216/222/346/237/245/346/226/271/346/263/225.md +27 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/344/273/273/345/212/241/350/247/246/345/217/221/345/220/270/346/224/266/345/231/250/344/270/216/345/215/240/344/275/215/350/247/246/345/217/221/345/220/270/346/224/266/345/231/250/344/275/277/347/224/250/345/234/272/346/231/257.md +18 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/345/220/216/347/253/257Swagger/346/216/245/345/217/243/346/226/207/346/241/243.md +22 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/345/275/223/345/211/215/350/277/220/350/241/214/345/256/236/344/276/213/345/217/212/345/256/236/344/276/213/350/277/220/350/241/214/346/227/245/345/277/227/346/216/222/346/237/245.md +39 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/346/216/245/345/217/243/346/216/222/346/237/245/350/203/214/346/231/257/347/237/245/350/257/206.md +49 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/350/264/247/350/275/275/347/224/237/345/221/275/345/221/250/346/234/237/346/237/245/350/257/242/346/265/201/347/250/213.md +165 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//345/244/251/350/275/246/350/260/203/345/272/246/347/263/273/347/273/237/351/207/215/347/273/204/346/216/245/345/217/243/350/260/203/347/224/250/344/270/216/346/227/245/345/277/227/345/210/206/346/236/220/346/226/271/346/263/225.md +137 -0
- package/package.json +20 -0
- package/src/cmd/agent.ts +137 -0
- package/src/cmd/auth.ts +50 -0
- package/src/cmd/knowledge.ts +171 -0
- package/src/cmd/server.ts +11 -0
- package/src/cmd/skill.ts +220 -0
- package/src/lib/client.ts +274 -0
- package/src/lib/formatter.ts +196 -0
- package/src/lib/storage.ts +63 -0
- package/src/lib/validate.ts +210 -0
- package/src/main.ts +235 -0
- package/test-regression.sh +273 -0
- package/tsconfig.json +17 -0
package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/AGENT.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 仿真调试助手
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description:
|
|
5
|
+
skills:
|
|
6
|
+
|
|
7
|
+
knowledges:
|
|
8
|
+
- 仿真平台当前运行实例及实例运行日志排查.md
|
|
9
|
+
- 仿真平台任务触发吸收器与占位触发吸收器使用场景.md
|
|
10
|
+
- 仿真平台Loki日志排查方法.md
|
|
11
|
+
- 仿真平台后端Swagger接口文档.md
|
|
12
|
+
- 仿真货载生命周期查询流程.md
|
|
13
|
+
- 仿真平台接口排查背景知识.md
|
|
14
|
+
- 天车调度系统重组接口调用与日志分析方法.md
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# System Prompt
|
|
18
|
+
你是仿真调试助手
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## 仿真平台日志排查流程
|
|
2
|
+
|
|
3
|
+
### Loki日志平台地址
|
|
4
|
+
```
|
|
5
|
+
http://192.168.59.100:4000/explore?schemaVersion=1&panes=%7B%22rxo%22:%7B%22datasource%22:%22P8E80F9AEF21F6940%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bhost_name%3D%5C%22192.168.58.23%5C%22%7D%20%7C%3D%20%60%60%22,%22queryType%22:%22range%22,%22datasource%22:%7B%22type%22:%22loki%22,%22uid%22:%22P8E80F9AEF21F6940%22%7D,%22editorMode%22:%22builder%22,%22direction%22:%22backward%22%7D%5D,%22range%22:%7B%22from%22:%22now-1h%22,%22to%22:%22now%22%7D,%22compact%22:false%7D%7D&orgId=1
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
### 日志查询方法
|
|
9
|
+
|
|
10
|
+
#### 1. 通过host_name过滤
|
|
11
|
+
- 使用 `host_name` 标签指定对应的环境
|
|
12
|
+
- 示例:`{host_name="192.168.58.23"}`
|
|
13
|
+
|
|
14
|
+
#### 2. IP地址模糊匹配流程
|
|
15
|
+
如果用户提供的是模糊地址(如只提供部分IP或描述性信息):
|
|
16
|
+
1. 先查询**仿真平台实例列表**
|
|
17
|
+
2. 从实例列表中匹配对应的host_name
|
|
18
|
+
3. 使用匹配到的host_name查询日志
|
|
19
|
+
|
|
20
|
+
#### 3. 查询限制(重要)
|
|
21
|
+
- **必须给定查询参数**,不能空查询
|
|
22
|
+
- **限制查询行数在200条以内**,避免查询过大导致性能问题
|
|
23
|
+
|
|
24
|
+
### 使用场景
|
|
25
|
+
- 仿真平台环境故障排查
|
|
26
|
+
- 通过host_name定位特定环境的日志
|
|
27
|
+
- IP地址不明确时先查询实例列表再查询日志
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
## 问题描述
|
|
2
|
+
货载编码: 10021,从库位由堆垛机运送到指定点位,任务hl_1774014921000_01,但货载没被吸收。
|
|
3
|
+
|
|
4
|
+
## 根本原因
|
|
5
|
+
点位10021配置的是**任务触发吸收器**,但这个吸收器类型只适用于**输送线任务**。
|
|
6
|
+
|
|
7
|
+
10021点位是堆垛机放货点,不存在输送线任务,因此任务触发吸收器无法正常工作。
|
|
8
|
+
|
|
9
|
+
## 解决方案
|
|
10
|
+
将点位10021的吸收器类型从**任务触发吸收器**改为**占位触发吸收器**。
|
|
11
|
+
|
|
12
|
+
## 知识点
|
|
13
|
+
1. **任务触发吸收器**:适用于输送线任务,需要任务关联才能触发
|
|
14
|
+
2. **占位触发吸收器**:适用于堆垛机放货点等场景,当货物占位时自动触发吸收,不依赖任务关联
|
|
15
|
+
|
|
16
|
+
## 配置建议
|
|
17
|
+
- 堆垛机放货点 → 使用占位触发吸收器
|
|
18
|
+
- 输送线转运点 → 使用任务触发吸收器
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## 仿真平台后端接口访问
|
|
2
|
+
|
|
3
|
+
### 默认端口
|
|
4
|
+
仿真平台后端服务默认端口为 **6173**
|
|
5
|
+
|
|
6
|
+
### Swagger文档地址
|
|
7
|
+
- Swagger UI: `http://{IP}:6173/swagger/index.html`
|
|
8
|
+
- Swagger JSON: `http://{IP}:6173/swagger/Default/swagger.json`
|
|
9
|
+
|
|
10
|
+
### 接口示例
|
|
11
|
+
以192.168.57.140环境为例:
|
|
12
|
+
- Swagger UI: http://192.168.57.140:6173/swagger/index.html
|
|
13
|
+
- Swagger JSON: http://192.168.57.140:6173/swagger/Default/swagger.json
|
|
14
|
+
|
|
15
|
+
### 使用场景
|
|
16
|
+
1. 查看仿真平台提供的所有REST API接口
|
|
17
|
+
2. 查看接口的请求参数、响应格式
|
|
18
|
+
3. 在线测试API接口
|
|
19
|
+
4. 了解接口的数据模型和Schema
|
|
20
|
+
|
|
21
|
+
### 访问方式
|
|
22
|
+
直接通过浏览器访问Swagger UI即可查看完整的API文档,支持在线调试。
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
## 仿真平台当前运行实例查询:
|
|
2
|
+
接口地址: [仿真运行实例查询接口](http://192.168.59.100:4000/api/datasources/uid/P8E80F9AEF21F6940/resources/label/host_name/values)
|
|
3
|
+
返回示例:
|
|
4
|
+
```
|
|
5
|
+
{"status":"success","data":["192.168.153.28","192.168.153.65","192.168.52.200","192.168.53.106","192.168.53.168","192.168.53.190","192.168.53.191","192.168.53.192","192.168.53.206","192.168.53.222","192.168.57.140","192.168.57.142","192.168.58.17","192.168.58.23","192.168.58.40","192.168.59.201","192.168.59.206","LAPTOP-J33NTVH2","LAPTOP-OOUL30MV","LAPTOP-QEBNIM3K","iw-simulation.loong-prod","iw-simulation.wms-v3-3","loong-demo","xuanwu-sim"]}
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
可添加参数 start 、 end ,时间戳,排查指定时间段内的仿真运行实例:
|
|
9
|
+
```
|
|
10
|
+
http://192.168.59.100:4000/api/datasources/uid/P8E80F9AEF21F6940/resources/label/host_name/values?start=1774842375104000000&end=1774863975104000000
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 仿真平台日志排查流程
|
|
14
|
+
|
|
15
|
+
### Loki日志平台地址
|
|
16
|
+
```
|
|
17
|
+
http://192.168.59.100:4000/explore?schemaVersion=1&panes=%7B%22rxo%22:%7B%22datasource%22:%22P8E80F9AEF21F6940%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bhost_name%3D%5C%22192.168.58.23%5C%22%7D%20%7C%3D%20%60%60%22,%22queryType%22:%22range%22,%22datasource%22:%7B%22type%22:%22loki%22,%22uid%22:%22P8E80F9AEF21F6940%22%7D,%22editorMode%22:%22builder%22,%22direction%22:%22backward%22%7D%5D,%22range%22:%7B%22from%22:%22now-1h%22,%22to%22:%22now%22%7D,%22compact%22:false%7D%7D&orgId=1
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 日志查询方法
|
|
21
|
+
|
|
22
|
+
#### 1. 通过host_name过滤
|
|
23
|
+
- 使用 `host_name` 标签指定对应的环境
|
|
24
|
+
- 示例:`{host_name="192.168.58.23"}`
|
|
25
|
+
|
|
26
|
+
#### 2. IP地址模糊匹配流程
|
|
27
|
+
如果用户提供的是模糊地址(如只提供部分IP或描述性信息):
|
|
28
|
+
1. 先查询**仿真平台实例列表**
|
|
29
|
+
2. 从实例列表中匹配对应的host_name
|
|
30
|
+
3. 使用匹配到的host_name查询日志
|
|
31
|
+
|
|
32
|
+
#### 3. 查询限制(重要)
|
|
33
|
+
- **必须给定查询参数**,不能空查询
|
|
34
|
+
- **限制查询行数在200条以内**,避免查询过大导致性能问题
|
|
35
|
+
|
|
36
|
+
### 使用场景
|
|
37
|
+
- 仿真平台环境故障排查
|
|
38
|
+
- 通过host_name定位特定环境的日志
|
|
39
|
+
- IP地址不明确时先查询实例列表再查询日志
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
仿真平台接口排查背景知识
|
|
2
|
+
1. 背景说明
|
|
3
|
+
该文档用于沉淀仿真平台后端接口排查时的通用背景信息,方便在故障定位、接口验证、环境巡检时快速确认默认访问方式。
|
|
4
|
+
2. 默认端口
|
|
5
|
+
仿真平台后端服务默认端口为:
|
|
6
|
+
6173
|
|
7
|
+
在未特殊说明的情况下,可优先按该端口判断后端服务是否启动、接口是否对外暴露。
|
|
8
|
+
3. Swagger 默认开放路径
|
|
9
|
+
Swagger 页面默认对外开放路径为:
|
|
10
|
+
/swagger/index.html
|
|
11
|
+
因此,通常可以通过以下方式访问目标实例的接口文档页面:
|
|
12
|
+
http://<host>:6173/swagger/index.html
|
|
13
|
+
4. Swagger JSON 路径示例
|
|
14
|
+
Swagger JSON 示例地址如下:
|
|
15
|
+
192.168.57.140:6173/swagger/Default/swagger.json
|
|
16
|
+
通用访问格式可参考:
|
|
17
|
+
http://<host>:6173/swagger/Default/swagger.json
|
|
18
|
+
5. 典型用途
|
|
19
|
+
5.1 验证后端接口服务是否可达
|
|
20
|
+
当怀疑某个仿真实例后端接口未正常启动时,可优先访问 Swagger 页面或 Swagger JSON 地址,确认:
|
|
21
|
+
- 端口是否可连通
|
|
22
|
+
- HTTP 服务是否正常返回
|
|
23
|
+
- 接口定义是否已成功加载
|
|
24
|
+
5.2 快速确认接口能力
|
|
25
|
+
当需要了解某实例当前暴露了哪些接口时,可直接访问 Swagger 页面进行查看,而不必先登录代码仓库或部署系统。
|
|
26
|
+
5.3 排查环境差异
|
|
27
|
+
不同环境、不同实例若存在接口不一致、版本不一致、发布不完整等情况,可通过 Swagger JSON 内容进行快速比对。
|
|
28
|
+
6. 推荐排查步骤
|
|
29
|
+
1. 先确认目标主机地址或实例名
|
|
30
|
+
2. 访问:
|
|
31
|
+
- http://<host>:6173/swagger/index.html
|
|
32
|
+
- http://<host>:6173/swagger/Default/swagger.json
|
|
33
|
+
3. 根据返回情况判断:
|
|
34
|
+
- 无法连接:优先排查端口、网络、服务进程
|
|
35
|
+
- 页面 404 / JSON 404:优先排查服务部署是否完整、Swagger 是否启用、路径是否变更
|
|
36
|
+
- 页面可访问但接口异常:继续下钻具体接口调用与日志
|
|
37
|
+
4. 如涉及多实例问题,建议结合实例清单、时间窗口、日志平台进行交叉验证
|
|
38
|
+
7. 注意事项
|
|
39
|
+
- 6173 为默认端口,若某些环境有定制化配置,应以实际部署为准
|
|
40
|
+
- Swagger 页面可访问,不代表所有接口逻辑均正常,仅说明 Web 服务和文档暴露层面基本可达
|
|
41
|
+
- 若 Swagger 页面被网关、鉴权或反向代理改写,实际路径可能存在差异
|
|
42
|
+
- swagger/Default/swagger.json 为当前已知示例路径,若服务分组名称变化,JSON 路径也可能调整
|
|
43
|
+
8. 推荐关键词
|
|
44
|
+
仿真平台、后端端口、6173、Swagger、接口排查、swagger.json、接口文档、服务可达性
|
|
45
|
+
9. 结论
|
|
46
|
+
后续进行仿真平台接口排查时,可默认优先尝试以下两个入口:
|
|
47
|
+
http://<host>:6173/swagger/index.html
|
|
48
|
+
http://<host>:6173/swagger/Default/swagger.json
|
|
49
|
+
它们可作为接口服务存活、文档暴露和版本能力确认的基础检查项。
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Runbook|货载生命周期查询流程
|
|
2
|
+
适用场景
|
|
3
|
+
- 用户需要查询某个位置最近一条货载的完整流转过程
|
|
4
|
+
- 用户提供的是位置编码(如 21065),希望追溯该位置上最近一条货载的全生命周期
|
|
5
|
+
- 需要判断货载是用户手工添加,还是设备执行过程中自动生成
|
|
6
|
+
目标输出
|
|
7
|
+
完成一次标准查询后,至少输出以下内容:
|
|
8
|
+
1. 目标位置最近一条相关货载
|
|
9
|
+
2. 对应 cargoId
|
|
10
|
+
3. 该货载按时间排序的完整生命周期
|
|
11
|
+
4. 生命周期路径汇总
|
|
12
|
+
5. 对“是否自动生成”的初步判断
|
|
13
|
+
6. 事实、推断、待验证项分离
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
查询思路总览
|
|
17
|
+
第一步:先查目标位置最近一条货载变更记录
|
|
18
|
+
优先使用接口:
|
|
19
|
+
- POST /api/systemLog/cargoLogPage
|
|
20
|
+
推荐请求体:
|
|
21
|
+
{
|
|
22
|
+
"page": 1,
|
|
23
|
+
"pageSize": 1,
|
|
24
|
+
"field": "createTime",
|
|
25
|
+
"desc": true,
|
|
26
|
+
"currentLocation": "21065"
|
|
27
|
+
}
|
|
28
|
+
说明:
|
|
29
|
+
- currentLocation 传目标位置编码
|
|
30
|
+
- field=createTime + desc=true 用于取最近一条
|
|
31
|
+
- 从返回结果中提取:
|
|
32
|
+
- cargoId
|
|
33
|
+
- palletCodes
|
|
34
|
+
- changeType
|
|
35
|
+
- previousLocation
|
|
36
|
+
- currentLocation
|
|
37
|
+
- deviceCode
|
|
38
|
+
- deviceName
|
|
39
|
+
- commandNo
|
|
40
|
+
- commandDescribe
|
|
41
|
+
- createTime
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
第二步:使用 cargoId 反查完整生命周期
|
|
45
|
+
仍使用接口:
|
|
46
|
+
- POST /api/systemLog/cargoLogPage
|
|
47
|
+
推荐请求体:
|
|
48
|
+
{
|
|
49
|
+
"page": 1,
|
|
50
|
+
"pageSize": 100,
|
|
51
|
+
"field": "createTime",
|
|
52
|
+
"desc": false,
|
|
53
|
+
"cargoCode": "<cargoId>"
|
|
54
|
+
}
|
|
55
|
+
说明:
|
|
56
|
+
- 这里的 cargoCode 实际可传日志中的 cargoId 做反查
|
|
57
|
+
- desc=false 表示按时间正序,便于还原生命周期
|
|
58
|
+
- pageSize 建议先取 100;如日志更多,再翻页
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
第三步:对日志去重并还原主链路
|
|
62
|
+
实际查询中,日志可能存在重复写入。建议按以下字段组合去重:
|
|
63
|
+
- createTime
|
|
64
|
+
- changeType
|
|
65
|
+
- previousLocation
|
|
66
|
+
- currentLocation
|
|
67
|
+
- deviceCode
|
|
68
|
+
- commandNo
|
|
69
|
+
去重后再整理主链路,避免同一步骤重复展示两次。
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
第四步:提炼生命周期结论
|
|
73
|
+
至少要整理出:
|
|
74
|
+
- 最早一条记录是否为 新增
|
|
75
|
+
- 初始位置与初始设备挂载位置
|
|
76
|
+
- 中间经过的设备、任务号、位置链路
|
|
77
|
+
- 最终到达目标位置的时间
|
|
78
|
+
推荐同时输出一条“路径汇总”:
|
|
79
|
+
位置A -> 位置B -> 位置C -> 位置D
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
自动生成货载的判断方法
|
|
83
|
+
当满足以下特征时,可初步判断该货载为“设备执行过程中自动生成”:
|
|
84
|
+
1. 生命周期最早记录包含 新增
|
|
85
|
+
2. 货载标签带设备/任务特征,例如:
|
|
86
|
+
- Crane-13451-1-20-4
|
|
87
|
+
3. 初始位置或初始挂载点表现为设备单元,例如:
|
|
88
|
+
- DV_NO.A04005_U1
|
|
89
|
+
4. 货载标签或详情中存在首关联信息,例如:
|
|
90
|
+
- firstCommandNo
|
|
91
|
+
- firstLocation
|
|
92
|
+
- firstDevice
|
|
93
|
+
5. 后续日志能连续串起设备执行链路
|
|
94
|
+
注意:
|
|
95
|
+
- 以上只能作为高概率判断依据
|
|
96
|
+
- 如果要形成最终结论,建议再结合设备指令日志或任务执行日志核实
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
推荐输出模板
|
|
100
|
+
一、货载基础信息
|
|
101
|
+
- 货载ID:<cargoId>
|
|
102
|
+
- 货载标签:<palletCodes>
|
|
103
|
+
- 最近命中位置:<location>
|
|
104
|
+
- 最近命中时间:<createTime>
|
|
105
|
+
- 首关联设备:<firstDevice 或 deviceCode>
|
|
106
|
+
- 首关联任务号:<firstCommandNo 或 commandNo>
|
|
107
|
+
二、全生命周期表
|
|
108
|
+
时间
|
|
109
|
+
变更类型
|
|
110
|
+
上个位置
|
|
111
|
+
当前位置
|
|
112
|
+
设备编码
|
|
113
|
+
设备名称
|
|
114
|
+
任务号
|
|
115
|
+
说明
|
|
116
|
+
...
|
|
117
|
+
...
|
|
118
|
+
...
|
|
119
|
+
...
|
|
120
|
+
...
|
|
121
|
+
...
|
|
122
|
+
...
|
|
123
|
+
...
|
|
124
|
+
三、生命周期路径汇总
|
|
125
|
+
<位置1> -> <位置2> -> <位置3> -> ... -> <目标位置>
|
|
126
|
+
四、结论
|
|
127
|
+
- 该货载是否已完整追溯
|
|
128
|
+
- 是否疑似自动生成
|
|
129
|
+
- 当前最终位置
|
|
130
|
+
五、待验证项
|
|
131
|
+
- 虚拟位置含义是否明确
|
|
132
|
+
- 是否存在日志双写/重复写入
|
|
133
|
+
- 是否需要反查任务日志确认自动生成证据
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
排查注意事项
|
|
137
|
+
1. 位置查询只看 currentLocation 时,查到的是“进入该位置”的记录
|
|
138
|
+
2. 如果要查“位置相关最近 5 条”,应同时考虑:
|
|
139
|
+
- currentLocation = 目标位置
|
|
140
|
+
- previousLocation = 目标位置
|
|
141
|
+
3. cargoLogPage 返回的数据可能存在重复记录,必须去重后再输出
|
|
142
|
+
4. /api/cargo/cargoListByIds 可能返回空,不可单独依赖业务表结果;日志链路通常更稳定
|
|
143
|
+
5. 结论中必须区分:
|
|
144
|
+
- 事实:接口返回的日志内容
|
|
145
|
+
- 推断:基于标签/设备/任务链路的判断
|
|
146
|
+
- 待验证项:仍需任务日志佐证的部分
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
实战示例(21065)
|
|
150
|
+
示例目标位置:21065
|
|
151
|
+
查询结果表明:
|
|
152
|
+
- 最近一条相关货载的 cargoId 为:789635517284423
|
|
153
|
+
- 货载标签:Crane-13451-1-20-4
|
|
154
|
+
- 最早记录出现 新增
|
|
155
|
+
- 生命周期从设备挂载点开始,随后经过堆垛机、输送线004、输送线003,最终到达 21065
|
|
156
|
+
- 可初步判断该货载为设备执行过程中自动生成
|
|
157
|
+
该示例适合作为:
|
|
158
|
+
- 位置追溯货载生命周期的标准案例
|
|
159
|
+
- 自动生成货载判断的参考案例
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
建议后续扩展
|
|
163
|
+
后续可补充两个配套 runbook:
|
|
164
|
+
1. 按 cargoId 直接查询货载全生命周期
|
|
165
|
+
2. 按任务号反查货载生成与流转证据链
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# 天车调度系统重组接口调用与日志分析
|
|
2
|
+
|
|
3
|
+
## 问题背景
|
|
4
|
+
天车调度系统调用重组接口后未生成调度结果,需要通过日志分析定位问题根因。
|
|
5
|
+
|
|
6
|
+
## 接口信息
|
|
7
|
+
|
|
8
|
+
### 1. 天车重组接口
|
|
9
|
+
- **地址**: `http://192.168.58.22:8000/dcs_api_v1/world_schedule`
|
|
10
|
+
- **方法**: POST
|
|
11
|
+
- **参数**: 无
|
|
12
|
+
- **返回**: 包含 `trace_id` 用于日志追踪
|
|
13
|
+
|
|
14
|
+
### 2. 日志查询接口
|
|
15
|
+
- **地址**: `http://192.168.58.22:8000/api/logs/search_trace/{trace_id}`
|
|
16
|
+
- **方法**: GET
|
|
17
|
+
- **参数**: trace_id(从重组接口返回的请求ID)
|
|
18
|
+
|
|
19
|
+
## 问题分析方法
|
|
20
|
+
|
|
21
|
+
### 步骤1:调用重组接口
|
|
22
|
+
```bash
|
|
23
|
+
curl -X POST http://192.168.58.22:8000/dcs_api_v1/world_schedule
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
获取返回的 `trace_id`,例如:`37113fad63f8`
|
|
27
|
+
|
|
28
|
+
### 步骤2:查询过程日志
|
|
29
|
+
```bash
|
|
30
|
+
curl -X GET http://192.168.58.22:8000/api/logs/search_trace/37113fad63f8
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 步骤3:分析关键日志信息
|
|
34
|
+
在日志中搜索以下关键词:
|
|
35
|
+
|
|
36
|
+
#### 关键信息1:任务过滤情况
|
|
37
|
+
```
|
|
38
|
+
过滤前X个item,过滤后...
|
|
39
|
+
```
|
|
40
|
+
- 如果显示“过滤后没有任务item”,说明没有可调度的任务
|
|
41
|
+
- 如果显示“过滤后没有isReady为true的任务item”,说明任务存在但未就绪
|
|
42
|
+
|
|
43
|
+
#### 关键信息2:设备状态
|
|
44
|
+
```
|
|
45
|
+
设备ID, 设备类型, Weight: 当前载重/最大载重, onboard Tasks: 任务列表
|
|
46
|
+
```
|
|
47
|
+
- 检查所有设备是否空闲
|
|
48
|
+
- 确认设备载重情况
|
|
49
|
+
|
|
50
|
+
#### 关键信息3:移动记录
|
|
51
|
+
```
|
|
52
|
+
设备ID 第X次, 移动记录:[]
|
|
53
|
+
```
|
|
54
|
+
- 如果移动记录为空,说明没有生成调度方案
|
|
55
|
+
|
|
56
|
+
## 常见问题与解决方案
|
|
57
|
+
|
|
58
|
+
### 场景1:没有可调度的任务
|
|
59
|
+
**症状**:
|
|
60
|
+
```
|
|
61
|
+
过滤前5个item,过滤后没有设备类型为FA_FLAT_WORK_AREA的任务item
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**原因**:
|
|
65
|
+
- 任务类型不匹配(系统只调度特定类型任务)
|
|
66
|
+
- 所有任务已完成或未创建
|
|
67
|
+
|
|
68
|
+
**解决方案**:
|
|
69
|
+
```sql
|
|
70
|
+
-- 1. 检查任务表
|
|
71
|
+
SELECT * FROM overhead_crane_tasks WHERE status = 'pending';
|
|
72
|
+
|
|
73
|
+
-- 2. 检查任务类型
|
|
74
|
+
SELECT * FROM overhead_crane_tasks WHERE device_type = 'FA_FLAT_WORK_AREA';
|
|
75
|
+
|
|
76
|
+
-- 3. 创建测试任务(如需要)
|
|
77
|
+
INSERT INTO overhead_crane_tasks (...) VALUES (...);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 场景2:任务存在但未就绪(isReady=false)
|
|
81
|
+
**症状**:
|
|
82
|
+
```
|
|
83
|
+
过滤前2个item,过滤后没有isReady为true的任务item
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**原因**:
|
|
87
|
+
- 前置条件未满足(如依赖任务未完成)
|
|
88
|
+
- 任务状态异常
|
|
89
|
+
- 时间窗口问题
|
|
90
|
+
|
|
91
|
+
**解决方案**:
|
|
92
|
+
```sql
|
|
93
|
+
-- 1. 查看任务详情
|
|
94
|
+
SELECT * FROM overhead_crane_tasks WHERE is_ready = false;
|
|
95
|
+
|
|
96
|
+
-- 2. 检查任务创建流程
|
|
97
|
+
SELECT * FROM overhead_crane_tasks ORDER BY created_at DESC LIMIT 10;
|
|
98
|
+
|
|
99
|
+
-- 3. 手动设置就绪(谨慎操作)
|
|
100
|
+
UPDATE overhead_crane_tasks SET is_ready = true WHERE id = 'xxx';
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 场景3:所有设备空闲但无调度
|
|
104
|
+
**症状**:
|
|
105
|
+
```
|
|
106
|
+
FA_A_01, DV_A_TC_R, Weight: 0/30000.0, onboard Tasks: None
|
|
107
|
+
FA_A_01, DV_A_TC_L, Weight: 0/25000.0, onboard Tasks: None
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**原因**:
|
|
111
|
+
- 系统中确实没有待调度任务
|
|
112
|
+
- 任务已被其他调度实例处理
|
|
113
|
+
|
|
114
|
+
**解决方案**:
|
|
115
|
+
1. 检查任务创建流程
|
|
116
|
+
2. 确认是否有其他调度实例在运行
|
|
117
|
+
3. 创建新测试任务验证
|
|
118
|
+
|
|
119
|
+
## 排查清单
|
|
120
|
+
|
|
121
|
+
- [ ] 调用重组接口并记录 trace_id
|
|
122
|
+
- [ ] 查询日志获取执行过程
|
|
123
|
+
- [ ] 检查任务过滤情况(过滤前/后数量)
|
|
124
|
+
- [ ] 确认设备状态(是否空闲、载重情况)
|
|
125
|
+
- [ ] 查看任务表数据
|
|
126
|
+
- [ ] 检查任务类型是否匹配
|
|
127
|
+
- [ ] 检查任务 isReady 状态
|
|
128
|
+
- [ ] 分析任务创建和状态更新逻辑
|
|
129
|
+
- [ ] 必要时创建测试任务验证
|
|
130
|
+
|
|
131
|
+
## 最佳实践
|
|
132
|
+
|
|
133
|
+
1. **保存 trace_id**:每次调用重组接口后保存 trace_id,便于后续追踪
|
|
134
|
+
2. **定期检查日志**:关注“过滤前/后”任务数量变化
|
|
135
|
+
3. **监控设备状态**:确认设备是否正常注册和在线
|
|
136
|
+
4. **任务状态管理**:定期检查任务表,清理异常状态的任务
|
|
137
|
+
5. **版本控制**:记录调度系统的版本变更,便于问题追溯
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-resource-management",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"arm": "./dist/main.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "bun run src/main.ts",
|
|
10
|
+
"build": "bun build src/main.ts --outdir dist --target node && echo '#!/usr/bin/env node' | cat - dist/main.js > temp && mv temp dist/main.js && chmod +x dist/main.js",
|
|
11
|
+
"start": "bun run dist/main.js"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"undici": "^6.13.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/bun": "^1.1.0",
|
|
18
|
+
"typescript": "^5.4.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/cmd/agent.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { ApiClient } from '../lib/client';
|
|
2
|
+
import { loadConfig } from '../lib/storage';
|
|
3
|
+
import { formatAgent, formatAgentDetail, success, error, info } from '../lib/formatter';
|
|
4
|
+
import { writeFileSync, existsSync } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { mkdtempSync, rmSync } from 'fs';
|
|
8
|
+
|
|
9
|
+
export async function listAgents(): Promise<void> {
|
|
10
|
+
const config = loadConfig();
|
|
11
|
+
if (!config?.token) {
|
|
12
|
+
error('未登录,请先运行 arm login');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
17
|
+
try {
|
|
18
|
+
const result = await client.listAgents();
|
|
19
|
+
if (result.agents.length === 0) {
|
|
20
|
+
info('暂无 Agent');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.log(`\n共 ${result.total} 个 Agent:\n`);
|
|
24
|
+
for (const agent of result.agents) {
|
|
25
|
+
console.log(formatAgent(agent));
|
|
26
|
+
console.log('');
|
|
27
|
+
}
|
|
28
|
+
} catch (err) {
|
|
29
|
+
error(`获取列表失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function searchAgents(keyword: string): Promise<void> {
|
|
35
|
+
const config = loadConfig();
|
|
36
|
+
if (!config?.token) {
|
|
37
|
+
error('未登录,请先运行 arm login');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
42
|
+
try {
|
|
43
|
+
const result = await client.listAgents(keyword);
|
|
44
|
+
if (result.agents.length === 0) {
|
|
45
|
+
info(`没有找到包含 "${keyword}" 的 Agent`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log(`\n找到 ${result.total} 个结果:\n`);
|
|
49
|
+
for (const agent of result.agents) {
|
|
50
|
+
console.log(formatAgent(agent));
|
|
51
|
+
console.log('');
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
error(`搜索失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function infoAgent(name: string): Promise<void> {
|
|
60
|
+
const config = loadConfig();
|
|
61
|
+
if (!config?.token) {
|
|
62
|
+
error('未登录,请先运行 arm login');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
67
|
+
try {
|
|
68
|
+
const result = await client.listAgents(name);
|
|
69
|
+
const agent = result.agents.find((a) => a.name === name);
|
|
70
|
+
if (!agent) {
|
|
71
|
+
error(`Agent "${name}" 不存在`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fullAgent = await client.getAgent(agent.id);
|
|
76
|
+
|
|
77
|
+
if (fullAgent.knowledges && fullAgent.knowledges.length > 0) {
|
|
78
|
+
const knowledgeNamePromises = fullAgent.knowledges.map(async (k) => {
|
|
79
|
+
try {
|
|
80
|
+
const knowledge = await client.getKnowledge(k.knowledgeId);
|
|
81
|
+
return { knowledgeId: k.knowledgeId, knowledgeName: knowledge.name, retrievalConfig: k.retrievalConfig };
|
|
82
|
+
} catch {
|
|
83
|
+
return k;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
fullAgent.knowledges = await Promise.all(knowledgeNamePromises);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log(formatAgentDetail(fullAgent));
|
|
90
|
+
} catch (err) {
|
|
91
|
+
error(`获取详情失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function downloadAgent(name: string, outputDir?: string): Promise<void> {
|
|
97
|
+
const config = loadConfig();
|
|
98
|
+
if (!config?.token) {
|
|
99
|
+
error('未登录,请先运行 arm login');
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
104
|
+
try {
|
|
105
|
+
const result = await client.listAgents(name);
|
|
106
|
+
const agent = result.agents.find((a) => a.name === name);
|
|
107
|
+
if (!agent) {
|
|
108
|
+
error(`Agent "${name}" 不存在`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
info(`正在下载 ${name}...`);
|
|
113
|
+
const { buffer, version } = await client.downloadAgent(agent.id);
|
|
114
|
+
|
|
115
|
+
const tempDir = mkdtempSync('/tmp/agent-download-');
|
|
116
|
+
const zipPath = join(tempDir, `${name}.zip`);
|
|
117
|
+
writeFileSync(zipPath, Buffer.from(buffer));
|
|
118
|
+
|
|
119
|
+
const targetDir = join(outputDir || '.', name);
|
|
120
|
+
execSync(`mkdir -p "${targetDir}"`, { stdio: 'pipe' });
|
|
121
|
+
execSync(`unzip -q "${zipPath}" -d "${tempDir}"`, { stdio: 'pipe' });
|
|
122
|
+
|
|
123
|
+
const contentDir = join(tempDir, 'agent-content');
|
|
124
|
+
if (existsSync(contentDir)) {
|
|
125
|
+
execSync(`cp -r "${contentDir}"/* "${targetDir}/"`, { stdio: 'pipe' });
|
|
126
|
+
} else {
|
|
127
|
+
execSync(`cp -r "${tempDir}"/* "${targetDir}/"`, { stdio: 'pipe' });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
131
|
+
|
|
132
|
+
success(`已下载到 ${targetDir} (版本: ${version})`);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
error(`下载失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
}
|