lightclawbot 1.1.1 → 1.1.2-beta.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/dist/public/data/scripts/manifest.json +11 -0
- package/dist/public/data/scripts/upgrade.156d7999.sh +384 -0
- package/dist/public/data/scripts/upgrade.sh +384 -0
- package/dist/src/upload-tool.d.ts.map +1 -1
- package/dist/src/upload-tool.js +10 -5
- package/dist/src/upload-tool.js.map +1 -1
- package/package.json +1 -1
- package/skills/lightclaw-cron/SKILL.md +2 -1
- package/dist/src/socket-handlers.d.ts +0 -21
- package/dist/src/socket-handlers.d.ts.map +0 -1
- package/dist/src/socket-handlers.js +0 -122
- package/dist/src/socket-handlers.js.map +0 -1
- package/dist/src/socket-registry.d.ts +0 -53
- package/dist/src/socket-registry.d.ts.map +0 -1
- package/dist/src/socket-registry.js +0 -111
- package/dist/src/socket-registry.js.map +0 -1
- package/skills/lightclaw-media/SKILL.md +0 -250
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LightClaw — Socket 注册表
|
|
3
|
-
*
|
|
4
|
-
* 让 gateway 启动时注册 socket 实例,
|
|
5
|
-
* outbound 在需要发送消息时可以通过 WS 连接直接发送,
|
|
6
|
-
* 无需走 REST API。
|
|
7
|
-
*
|
|
8
|
-
* 断线缓冲:
|
|
9
|
-
* 当 socket 暂时断开(Socket.IO 自动重连中)时,outbound 消息
|
|
10
|
-
* 会被缓冲在 pendingMessages 队列中,重连后自动 flush 发送。
|
|
11
|
-
* 仅在 gateway 彻底销毁(cleanup)时才删除 entry。
|
|
12
|
-
*/
|
|
13
|
-
import type { Socket } from "socket.io-client";
|
|
14
|
-
import type { PrivateMessageData } from "./types.js";
|
|
15
|
-
interface SocketEntry {
|
|
16
|
-
socket: Socket;
|
|
17
|
-
botClientId: string;
|
|
18
|
-
/** 断线期间缓冲的待发消息 */
|
|
19
|
-
pendingMessages: PrivateMessageData[];
|
|
20
|
-
}
|
|
21
|
-
/** 注册 socket(gateway 首次连接时调用) */
|
|
22
|
-
export declare function registerSocket(accountId: string, socket: Socket, botClientId: string): void;
|
|
23
|
-
/**
|
|
24
|
-
* 注销 socket(gateway 彻底销毁时调用)。
|
|
25
|
-
* 注意:普通断线重连不应调用此函数,只在 cleanup 时调用。
|
|
26
|
-
*/
|
|
27
|
-
export declare function unregisterSocket(accountId: string): void;
|
|
28
|
-
/** 获取可用的 socket(仅在 connected 时返回) */
|
|
29
|
-
export declare function getSocket(accountId: string): Pick<SocketEntry, "socket" | "botClientId"> | undefined;
|
|
30
|
-
/** 检查 account 是否有注册的 entry(不管是否 connected) */
|
|
31
|
-
export declare function hasEntry(accountId: string): boolean;
|
|
32
|
-
/** 获取 botClientId(不管 socket 是否 connected) */
|
|
33
|
-
export declare function getBotClientId(accountId: string): string | undefined;
|
|
34
|
-
/**
|
|
35
|
-
* 缓冲一条消息(socket 断开期间由 outbound 调用)。
|
|
36
|
-
* 返回 true 表示成功缓冲,false 表示该 account 没有注册的 entry。
|
|
37
|
-
*/
|
|
38
|
-
export declare function bufferMessage(accountId: string, message: PrivateMessageData): boolean;
|
|
39
|
-
/**
|
|
40
|
-
* flush 所有缓冲消息(重连成功后由 gateway 调用)。
|
|
41
|
-
* 返回发送成功 / 失败的计数。
|
|
42
|
-
*/
|
|
43
|
-
export declare function flushPendingMessages(accountId: string, log?: {
|
|
44
|
-
info: (msg: string) => void;
|
|
45
|
-
warn: (msg: string) => void;
|
|
46
|
-
}): {
|
|
47
|
-
sent: number;
|
|
48
|
-
failed: number;
|
|
49
|
-
};
|
|
50
|
-
/** 获取缓冲队列长度(调试/监控用) */
|
|
51
|
-
export declare function getPendingCount(accountId: string): number;
|
|
52
|
-
export {};
|
|
53
|
-
//# sourceMappingURL=socket-registry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"socket-registry.d.ts","sourceRoot":"","sources":["../../src/socket-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAOrD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,eAAe,EAAE,kBAAkB,EAAE,CAAC;CACvC;AASD,iCAAiC;AACjC,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAS3F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAExD;AAMD,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,aAAa,CAAC,GAAG,SAAS,CAIpG;AAED,8CAA8C;AAC9C,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEpE;AAMD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAUrF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA8BlC;AAED,uBAAuB;AACvB,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LightClaw — Socket 注册表
|
|
3
|
-
*
|
|
4
|
-
* 让 gateway 启动时注册 socket 实例,
|
|
5
|
-
* outbound 在需要发送消息时可以通过 WS 连接直接发送,
|
|
6
|
-
* 无需走 REST API。
|
|
7
|
-
*
|
|
8
|
-
* 断线缓冲:
|
|
9
|
-
* 当 socket 暂时断开(Socket.IO 自动重连中)时,outbound 消息
|
|
10
|
-
* 会被缓冲在 pendingMessages 队列中,重连后自动 flush 发送。
|
|
11
|
-
* 仅在 gateway 彻底销毁(cleanup)时才删除 entry。
|
|
12
|
-
*/
|
|
13
|
-
import { MAX_PENDING_MESSAGES, EVENT_MESSAGE_PRIVATE } from "./config.js";
|
|
14
|
-
/** accountId → SocketEntry */
|
|
15
|
-
const registry = new Map();
|
|
16
|
-
// ============================================================
|
|
17
|
-
// 注册 / 注销
|
|
18
|
-
// ============================================================
|
|
19
|
-
/** 注册 socket(gateway 首次连接时调用) */
|
|
20
|
-
export function registerSocket(accountId, socket, botClientId) {
|
|
21
|
-
const existing = registry.get(accountId);
|
|
22
|
-
if (existing) {
|
|
23
|
-
// 重连场景:更新 socket 引用,保留 pending 队列
|
|
24
|
-
existing.socket = socket;
|
|
25
|
-
existing.botClientId = botClientId;
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
registry.set(accountId, { socket, botClientId, pendingMessages: [] });
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 注销 socket(gateway 彻底销毁时调用)。
|
|
33
|
-
* 注意:普通断线重连不应调用此函数,只在 cleanup 时调用。
|
|
34
|
-
*/
|
|
35
|
-
export function unregisterSocket(accountId) {
|
|
36
|
-
registry.delete(accountId);
|
|
37
|
-
}
|
|
38
|
-
// ============================================================
|
|
39
|
-
// 查询
|
|
40
|
-
// ============================================================
|
|
41
|
-
/** 获取可用的 socket(仅在 connected 时返回) */
|
|
42
|
-
export function getSocket(accountId) {
|
|
43
|
-
const entry = registry.get(accountId);
|
|
44
|
-
if (entry && entry.socket.connected)
|
|
45
|
-
return entry;
|
|
46
|
-
return undefined;
|
|
47
|
-
}
|
|
48
|
-
/** 检查 account 是否有注册的 entry(不管是否 connected) */
|
|
49
|
-
export function hasEntry(accountId) {
|
|
50
|
-
return registry.has(accountId);
|
|
51
|
-
}
|
|
52
|
-
/** 获取 botClientId(不管 socket 是否 connected) */
|
|
53
|
-
export function getBotClientId(accountId) {
|
|
54
|
-
return registry.get(accountId)?.botClientId;
|
|
55
|
-
}
|
|
56
|
-
// ============================================================
|
|
57
|
-
// 断线缓冲
|
|
58
|
-
// ============================================================
|
|
59
|
-
/**
|
|
60
|
-
* 缓冲一条消息(socket 断开期间由 outbound 调用)。
|
|
61
|
-
* 返回 true 表示成功缓冲,false 表示该 account 没有注册的 entry。
|
|
62
|
-
*/
|
|
63
|
-
export function bufferMessage(accountId, message) {
|
|
64
|
-
const entry = registry.get(accountId);
|
|
65
|
-
if (!entry)
|
|
66
|
-
return false;
|
|
67
|
-
if (entry.pendingMessages.length >= MAX_PENDING_MESSAGES) {
|
|
68
|
-
// 队列满了,丢弃最早的消息
|
|
69
|
-
entry.pendingMessages.shift();
|
|
70
|
-
}
|
|
71
|
-
entry.pendingMessages.push(message);
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* flush 所有缓冲消息(重连成功后由 gateway 调用)。
|
|
76
|
-
* 返回发送成功 / 失败的计数。
|
|
77
|
-
*/
|
|
78
|
-
export function flushPendingMessages(accountId, log) {
|
|
79
|
-
const entry = registry.get(accountId);
|
|
80
|
-
if (!entry)
|
|
81
|
-
return { sent: 0, failed: 0 };
|
|
82
|
-
const pending = entry.pendingMessages.splice(0); // 取出全部并清空
|
|
83
|
-
if (pending.length === 0)
|
|
84
|
-
return { sent: 0, failed: 0 };
|
|
85
|
-
let sent = 0;
|
|
86
|
-
let failed = 0;
|
|
87
|
-
for (const msg of pending) {
|
|
88
|
-
if (!entry.socket.connected) {
|
|
89
|
-
// socket 又断了,把剩余消息放回去
|
|
90
|
-
entry.pendingMessages.unshift(...pending.slice(sent + failed));
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
try {
|
|
94
|
-
entry.socket.emit(EVENT_MESSAGE_PRIVATE, msg);
|
|
95
|
-
sent++;
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
failed++;
|
|
99
|
-
log?.warn(`[socket-registry] Failed to flush buffered message: msgId=${msg.msgId}`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (sent > 0 || failed > 0) {
|
|
103
|
-
log?.info(`[socket-registry] Flushed pending messages: sent=${sent}, failed=${failed}`);
|
|
104
|
-
}
|
|
105
|
-
return { sent, failed };
|
|
106
|
-
}
|
|
107
|
-
/** 获取缓冲队列长度(调试/监控用) */
|
|
108
|
-
export function getPendingCount(accountId) {
|
|
109
|
-
return registry.get(accountId)?.pendingMessages.length ?? 0;
|
|
110
|
-
}
|
|
111
|
-
//# sourceMappingURL=socket-registry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"socket-registry.js","sourceRoot":"","sources":["../../src/socket-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: lightclawbot-media
|
|
3
|
-
description: LightClawBot 文件收发能力。用户发来的文件自动下载并保存,AI 生成的文件通过 lightclaw_upload_file 上传后以标准 Markdown 链接返回给用户。禁止使用其他存储工具。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# LightClawBot 文件上传与下载
|
|
7
|
-
|
|
8
|
-
让 AI 帮用户处理文件的上传、下载和分享,通过 LightClawBot 通道投递。
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## ⛔ 最重要的规则(读三遍)
|
|
13
|
-
|
|
14
|
-
> 1. **上传文件必须使用 `lightclaw_upload_file` 工具,禁止使用其他任何存储工具!**
|
|
15
|
-
> 3. **返回文件给用户时,必须使用标准 Markdown 链接格式:`[文件名](下载链接)`**
|
|
16
|
-
> - ❌ 错误:`下载链接: https://xxx`
|
|
17
|
-
> - ❌ 错误:`📎 文件下载链接: https://xxx`
|
|
18
|
-
> - ✅ 正确:`[report.pdf](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/report.pdf)`
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## 🔧 可用工具
|
|
23
|
-
|
|
24
|
-
本技能使用以下两个专属工具,**不要使用其他任何文件/存储工具**:
|
|
25
|
-
|
|
26
|
-
| 工具名 | 用途 | 何时使用 |
|
|
27
|
-
|--------|------|----------|
|
|
28
|
-
| `lightclaw_upload_file` | 上传本地文件到云端,获取公网下载链接 | AI 生成了文件需要分享给用户时 |
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## 📤 上传文件(lightclaw_upload_file)
|
|
33
|
-
|
|
34
|
-
### 功能
|
|
35
|
-
|
|
36
|
-
将本地文件上传到云端存储,返回公网可访问的下载链接。支持批量上传(最多 5 个文件)。
|
|
37
|
-
|
|
38
|
-
### 参数
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
{
|
|
42
|
-
"paths": ["/absolute/path/to/file1.pdf", "/absolute/path/to/file2.xlsx"]
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
| 参数 | 类型 | 必填 | 说明 |
|
|
47
|
-
|------|------|------|------|
|
|
48
|
-
| `paths` | string[] | ✅ | 本地文件绝对路径数组,最多 5 个 |
|
|
49
|
-
|
|
50
|
-
### ⚠️ 关键约束
|
|
51
|
-
|
|
52
|
-
1. **必须使用绝对路径**(以 `/` 开头),禁止使用相对路径
|
|
53
|
-
- ❌ `./output/report.pdf`
|
|
54
|
-
- ✅ `/Users/xxx/.openclaw/workspace/output/report.pdf`
|
|
55
|
-
2. **文件必须存在**:上传前确认文件已生成并写入磁盘
|
|
56
|
-
3. **单次最多 5 个文件**:超出需分批上传
|
|
57
|
-
|
|
58
|
-
### 使用示例
|
|
59
|
-
|
|
60
|
-
**上传单个文件**:
|
|
61
|
-
```json
|
|
62
|
-
{
|
|
63
|
-
"paths": ["/Users/xxx/.openclaw/workspace/report.pdf"]
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**批量上传**:
|
|
68
|
-
```json
|
|
69
|
-
{
|
|
70
|
-
"paths": [
|
|
71
|
-
"/Users/xxx/.openclaw/workspace/chart1.png",
|
|
72
|
-
"/Users/xxx/.openclaw/workspace/chart2.png",
|
|
73
|
-
"/Users/xxx/.openclaw/workspace/summary.xlsx"
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## 📋 返回文件给用户的格式(最重要)
|
|
81
|
-
|
|
82
|
-
### 🚨🚨🚨 必须使用标准 Markdown 链接格式
|
|
83
|
-
|
|
84
|
-
> **当需要将文件/文档/图片链接返回给用户时,必须使用标准 Markdown 链接格式:**
|
|
85
|
-
>
|
|
86
|
-
> ```
|
|
87
|
-
> [<文件名>](<下载链接>)
|
|
88
|
-
> ```
|
|
89
|
-
|
|
90
|
-
### ✅ 正确示例
|
|
91
|
-
|
|
92
|
-
**单个文件**:
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
好的,报告已生成,请点击下载:
|
|
96
|
-
|
|
97
|
-
[report.pdf](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/report.pdf)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**多个文件**:
|
|
101
|
-
|
|
102
|
-
```
|
|
103
|
-
所有文件已准备好:
|
|
104
|
-
|
|
105
|
-
- [数据分析报告.pdf](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/数据分析报告.pdf)
|
|
106
|
-
- [原始数据.xlsx](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/原始数据.xlsx)
|
|
107
|
-
- [趋势图.png](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/趋势图.png)
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
**附带说明文字**:
|
|
111
|
-
|
|
112
|
-
```
|
|
113
|
-
✅ 周报已生成完毕!
|
|
114
|
-
|
|
115
|
-
[本周工作周报.pdf](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/本周工作周报.pdf)
|
|
116
|
-
|
|
117
|
-
报告包含了本周的进度汇总和下周计划。
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### ❌ 错误示例(绝对不要这样做)
|
|
121
|
-
|
|
122
|
-
❌ **裸链接**:
|
|
123
|
-
```
|
|
124
|
-
下载链接: https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/report.pdf
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
❌ **带 emoji 前缀的裸链接**:
|
|
128
|
-
```
|
|
129
|
-
📎 文件下载链接: https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/report.pdf
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
❌ **使用代码块包裹链接**:
|
|
133
|
-
```
|
|
134
|
-
`https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/report.pdf`
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
❌ **只返回路径,没有文件名**:
|
|
138
|
-
```
|
|
139
|
-
[下载](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/report.pdf)
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
## 📸 接收用户文件
|
|
145
|
-
|
|
146
|
-
用户通过 LightClawBot 发来的文件(图片、文档等)**自动下载到本地**。文件信息在上下文的【Attachments】字段中,包含:
|
|
147
|
-
|
|
148
|
-
| 字段 | 说明 |
|
|
149
|
-
|------|------|
|
|
150
|
-
| `name` | 文件名 |
|
|
151
|
-
| `mimeType` | 文件 MIME 类型 |
|
|
152
|
-
| `url` | 文件的公网下载链接 |
|
|
153
|
-
|
|
154
|
-
本地文件路径在上下文的 `MediaPath` / `MediaPaths` 字段中。
|
|
155
|
-
|
|
156
|
-
### 处理用户文件的流程
|
|
157
|
-
|
|
158
|
-
1. **查看上下文**:从 Attachments 获取文件信息
|
|
159
|
-
2. **本地处理**:使用 `MediaPath` 中的本地路径读取和处理文件
|
|
160
|
-
3. **如需返回处理后的文件**:用 `lightclaw_upload_file` 上传 → 用 Markdown 链接返回
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## 🎯 完整使用场景
|
|
165
|
-
|
|
166
|
-
### 场景 1:用户要求生成报告
|
|
167
|
-
|
|
168
|
-
**用户**:帮我生成一份数据分析报告
|
|
169
|
-
|
|
170
|
-
**AI 执行步骤**:
|
|
171
|
-
1. 生成报告文件并保存到本地(如 `/Users/xxx/.openclaw/workspace/数据分析报告.pdf`)
|
|
172
|
-
2. 调用 `lightclaw_upload_file` 上传:
|
|
173
|
-
```json
|
|
174
|
-
{ "paths": ["/Users/xxx/.openclaw/workspace/数据分析报告.pdf"] }
|
|
175
|
-
```
|
|
176
|
-
3. 获取到下载链接后,以 Markdown 格式回复:
|
|
177
|
-
```
|
|
178
|
-
✅ 报告已生成:
|
|
179
|
-
|
|
180
|
-
[数据分析报告.pdf](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/数据分析报告.pdf)
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### 场景 2:用户要求处理发来的文件
|
|
184
|
-
|
|
185
|
-
**用户**:帮我把这个 Excel 转成 PDF(附带了 data.xlsx)
|
|
186
|
-
|
|
187
|
-
**AI 执行步骤**:
|
|
188
|
-
1. 从上下文 `MediaPath` 获取本地文件路径
|
|
189
|
-
2. 读取并处理 Excel 文件,转换为 PDF
|
|
190
|
-
3. 调用 `lightclaw_upload_file` 上传 PDF
|
|
191
|
-
4. 以 Markdown 格式回复:
|
|
192
|
-
```
|
|
193
|
-
✅ 已将 Excel 转为 PDF:
|
|
194
|
-
|
|
195
|
-
[data.pdf](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/data.pdf)
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### 场景 3:用户要求获取之前上传的文件
|
|
199
|
-
|
|
200
|
-
**用户**:我昨天上传的报告还能下载吗?
|
|
201
|
-
|
|
202
|
-
**AI 执行步骤**:
|
|
203
|
-
1. 以 Markdown 格式回复:
|
|
204
|
-
```
|
|
205
|
-
可以的,这是下载链接:
|
|
206
|
-
|
|
207
|
-
[report.pdf](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-14/report.pdf)
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### 场景 4:批量上传多个文件
|
|
211
|
-
|
|
212
|
-
**用户**:帮我生成三张数据图表
|
|
213
|
-
|
|
214
|
-
**AI 执行步骤**:
|
|
215
|
-
1. 生成三张图表并保存到本地
|
|
216
|
-
2. 调用 `lightclaw_upload_file` 批量上传:
|
|
217
|
-
```json
|
|
218
|
-
{
|
|
219
|
-
"paths": [
|
|
220
|
-
"/Users/xxx/.openclaw/workspace/chart1.png",
|
|
221
|
-
"/Users/xxx/.openclaw/workspace/chart2.png",
|
|
222
|
-
"/Users/xxx/.openclaw/workspace/chart3.png"
|
|
223
|
-
]
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
3. 以 Markdown 格式回复:
|
|
227
|
-
```
|
|
228
|
-
✅ 三张图表已生成:
|
|
229
|
-
|
|
230
|
-
- [chart1.png](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/chart1.png)
|
|
231
|
-
- [chart2.png](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/chart2.png)
|
|
232
|
-
- [chart3.png](https://lightai.cloud.tencent.com/drive/preview?filePath=2026-03-15/chart3.png)
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
## 🚫 禁止事项
|
|
236
|
-
|
|
237
|
-
1. **❌ 禁止使用其他存储工具**:所有文件操作必须通过 `lightclaw_upload_file`
|
|
238
|
-
2. **❌ 禁止返回裸链接**:必须使用 `[文件名](链接)` 格式
|
|
239
|
-
3. **❌ 禁止说"无法发送文件"**:你有能力上传和分享任何本地文件
|
|
240
|
-
4. **❌ 禁止使用相对路径**:工具参数中的文件路径必须是绝对路径
|
|
241
|
-
5. **❌ 禁止使用 message tool 发送文件**:直接在回复文本中写 Markdown 链接
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
## 📌 快速参考
|
|
246
|
-
|
|
247
|
-
| 场景 | 工具 | 回复格式 |
|
|
248
|
-
|------|------|----------|
|
|
249
|
-
| 上传生成的文件 | `lightclaw_upload_file` | `[文件名](下载链接)` |
|
|
250
|
-
| 接收用户文件 | 自动处理,查看上下文 Attachments | 确认收到并告知文件信息 |
|