SuperAPI AI Directory

cloud-upload-backup

Office & productivity

View repository

Updated 10-16 08:24

About this skill

Cloud file upload and backup tool (Tencent SMH)

Upload local files to Tencent SMH cloud storage; after uploading, they can be viewed in the QClaw Mini Program. Uses @tencent/smh-js-sdk official SDK.

Setup

No additional dependencies need to be installed. File upload is done through the local HTTP interface /proxy/qclaw-cos , and SMH credentials are automatically managed by the main process, with no manual configuration required.


Workflow

QClaw uses this skill in any scenario that requires uploading files to the cloud. The file upload process has been simplified to direct transfer.

Complete flow

User triggers file upload
  → Step 1: Identify the local file path(s)
  → Step 2: Upload via `upload` command (loop for batch)
  → Step 3: Output the `message` field from JSON response VERBATIM — do NOT construct your own text

CRITICAL — Anti-hallucination design: The upload API returns a pre-rendered message field containing the complete user-facing text (file name, size, file link, notice). QClaw MUST output message verbatim. QClaw does NOT need to extract downloadUrl or any other field to compose its own reply — the server has already done that. This eliminates the possibility of LLM hallucinating or incorrectly assembling URL fragments.

Step 2: Upload

See Commands section below for detailed usage.

IMPORTANT: by default, you must use conflictStrategy: "ask" to upload. This way, when a file with the same name already exists in the cloud, the interface returns an error, and QClaw can ask the user how to handle it.Only when the user explicitly says "覆盖"/"替换" or "重命名" should you use the corresponding conflictStrategy: "overwrite" or conflictStrategy: "rename"。

Single file (default):

curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/file.pdf","conflictStrategy":"ask"}'

Upload to specific directory:

curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/photo.jpg","remotePath":"photos/photo.jpg","conflictStrategy":"ask"}'

User explicitly requested overwrite:

curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/report.pdf","conflictStrategy":"overwrite"}'

User explicitly requested rename:

curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/report.pdf","conflictStrategy":"rename"}'

Batch upload (multiple files — use batch-upload endpoint):

When the user wants to upload multiple files (e.g., "send me all three files"), use the batch-upload endpoint. This returns a single message field containing the complete summary of all uploads — QClaw outputs it verbatim, no assembly needed.

curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/batch-upload \
  -H 'Content-Type: application/json' \
  -d '{"files":[{"localPath":"/path/to/file1.pdf","conflictStrategy":"ask"},{"localPath":"/path/to/file2.docx","conflictStrategy":"ask"},{"localPath":"/path/to/file3.jpg","conflictStrategy":"ask"}]}'

IMPORTANT: For 2+ files, always prefer batch-upload over multiple upload calls. The batch-upload endpoint returns a single pre-rendered message with all results summarized, eliminating the need for QClaw to combine multiple responses.

Conflict handling

When using conflictStrategy: "ask" (default), if a same-name file already exists, the upload will fail with an error. QClaw must then ask the user:

QClaw conflict dialogue (upload returns success: false due to same-name conflict):

A file with the same name already exists {filename}, how do you want to handle it?

  1. 🔄 Overwrite — replace the existing file
  2. 📝 Rename — automatically rename and upload (e.g., file(1).pdf)
  3. ❌ Cancel — do not upload

Then re-run upload with the user's chosen strategy (conflictStrategy: "overwrite" or conflictStrategy: "rename").

Comparison of the three strategies:

Strategy Behavior When to use
ask (Default, must use) Returns an error when a same-name file exists, QClaw asks the user When the user has not indicated a preference
overwrite Directly overwrite the existing file The user explicitly says "overwrite", "replace", "update file"
rename Automatically rename → file(1).pdf The user explicitly says "rename", "upload with a new name"

Step 3: Output message field — VERBATIM, NO modification (CRITICAL)

After the upload interface returns JSON,must output as-is message the value of the field as the reply content.

Correct approach: directly extract the message field value from the JSON output,without changing a single character, and display it to the user:

JSON 返回: {"success": true, "message": "链接已生成,可在 QClaw 小程序中随时查看。(保留 30 天后自动清理)\n\n已上传文件: report.pdf (2.3 MB)\n文件链接: https://jsonproxy.3g.qq.com/urlmapper/aB3xYz", ...}

QClaw 直接输出 message 的内容:
链接已生成,可在 QClaw 小程序中随时查看。(保留 30 天后自动清理)

已上传文件: report.pdf (2.3 MB)
文件链接: https://jsonproxy.3g.qq.com/urlmapper/aB3xYz

Incorrect approach(strictly prohibited):

❌ 忽略 message 字段,自己从 downloadUrl/fileInfo 等字段拼接内容
❌ 自己拼接 URL 片段(如把 host + rawDownloadUrl 的 path 拼在一起)
❌ 把 rawDownloadUrl 中的 hash/path 部分接到短链域名后面
❌ 对 message 中的 URL 做任何截断、修改、重组
❌ 自创文件链接文本格式(如改变 message 中的排版)

For batch uploads, use the batch-upload interface; the message returned by the server already contains the complete summary, so just output it directly.

Why it is designed this way:message is generated by the server, and the file links in it are precisely extracted from the API response. Having the AI directly output pre-rendered text, rather than extracting fields from JSON and assembling them itself, fundamentally eliminates the possibility of hallucinations caused by the AI confusing URL fragments. For a single file use upload, for multiple files use batch-upload—in both scenarios you only need to output as-is message。

When to use each command

User intent Command What to do with the result
Uploadsinglefile upload Output message field verbatim
Uploadmultiplefiles (2 or more) batch-upload Output message field verbatim
"Is this cloud file still there" / "View file information" info Show file metadata to user
"What files are in the cloud" / "List backup files" list Show file list to user

Key: Single file → upload, multiple files → batch-upload. Both return a pre-rendered message field — QClaw just outputs it verbatim. QClaw never constructs its own response text from individual JSON fields.


File Size Support

There is NO file size limit. The upload script supports files of any size, including multi-GB videos.

  • Small files (≤ 50 MB): Read into memory for fast upload.
  • Large files (> 50 MB): Use disk-backed lazy reading — the file is never loaded entirely into memory. The SDK reads it in 5 MB chunks (multipart upload), so even 10 GB+ files work smoothly.

IMPORTANT for QClaw: Do NOT tell the user there is a file size limit (e.g. "2GB limit"). There is none. If the user wants to upload a large file, just proceed with the upload command normally. The script handles large files automatically via chunked/multipart upload.


How to obtain PORT

In all HTTP requests, PORT is obtained from the environment variable AUTH_GATEWAY_PORT , which is automatically set by the Electron main process when starting the Auth Gateway, and child processes automatically inherit it.

macOS / Linux (bash):

PORT=${AUTH_GATEWAY_PORT:-19000}
echo "[QClaw] AUTH_GATEWAY_PORT: $PORT"

Windows (PowerShell):

$PORT = if ($env:AUTH_GATEWAY_PORT) { $env:AUTH_GATEWAY_PORT } else { "19000" }
Write-Host "[QClaw] AUTH_GATEWAY_PORT: $PORT"

Windows (CMD):

if not defined AUTH_GATEWAY_PORT set AUTH_GATEWAY_PORT=19000
set PORT=%AUTH_GATEWAY_PORT%
echo [QClaw] AUTH_GATEWAY_PORT: %PORT%

Description:AUTH_GATEWAY_PORT The environment variable is automatically injected by the Electron main process and automatically inherited when child processes (including OpenClaw) start. If the environment variable is not set, fall back to the default port 19000. This approach does not depend on python, is cross-platform compatible, and is lighter weight.

How to get the parent process ID

Before executing the curl command, get the current process's parent process ID and print it to the console.

macOS / Linux (bash):

PPID_VAL=$(python3 -c "import os; print(os.getppid())")
echo "[QClaw] Parent PID: $PPID_VAL"

Windows (PowerShell):

$PPID_VAL = python -c "import os; print(os.getppid())"
Write-Host "[QClaw] Parent PID: $PPID_VAL"

Description: Use python/python3 of os.getppid() to get the parent process ID; cross-platform compatible (supported on macOS/Linux/Windows). The print format is [QClaw] Parent PID: <ppid>, which facilitates log tracking.


Commands

upload

Upload a local file directly by specifying its path.

POST /proxy/qclaw-cos/upload
Content-Type: application/json

{
  "localPath": "<local-file-path>",       // 必填:本地文件绝对路径
  "remotePath": "<cloud-path>",           // 可选:云端目标路径,省略则上传到根目录并保留原文件名
  "conflictStrategy": "ask|rename|overwrite"  // 可选:同名冲突策略,默认 ask
}

Body parameters:

  • localPath(required): absolute path of the local file, supports ~ expansion
  • remotePath(optional): cloud destination path. If omitted, upload to theroot directoryand keep the original file name
  • conflictStrategy(optional): conflict handling strategy for the same name:
    • ask (QClaw must use by default) — return an error when a file with the same name exists, and QClaw asks the user how to handle it
    • rename — automatically rename the new file (e.g., file(1).pdf)
    • overwrite — silently overwrite the existing file

Examples:

# macOS / Linux: 获取 PORT 和父进程 ID
PORT=${AUTH_GATEWAY_PORT:-19000}
echo "[QClaw] AUTH_GATEWAY_PORT: $PORT"
PPID_VAL=$(python3 -c "import os; print(os.getppid())")
echo "[QClaw] Parent PID: $PPID_VAL"

# Upload a file (QClaw 默认应使用 conflictStrategy: ask)
curl -s -X POST http://localhost:$PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/report.pdf","conflictStrategy":"ask"}'

# Upload to a specific path
curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/photo.jpg","remotePath":"photos/vacation.jpg","conflictStrategy":"ask"}'

# Upload a video
curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/clip.mp4","conflictStrategy":"ask"}'

# Upload and overwrite if same name exists (user explicitly requested)
curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/report.pdf","conflictStrategy":"overwrite"}'

# Upload with rename (user explicitly requested)
curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/upload \
  -H 'Content-Type: application/json' \
  -d '{"localPath":"/path/to/report.pdf","conflictStrategy":"rename"}'

Output (JSON):

When upload succeeds:

{
  "success": true,
  "message": "链接已生成,可在 QClaw 小程序中随时查看。(保留 30 天后自动清理)\n\n已上传文件: photo.jpg (2.0 MB)\n文件链接: https://jsonproxy.3g.qq.com/urlmapper/aB3xYz",
  "upload": {
    "localFile": "/path/to/photo.jpg",
    "remotePath": "photo.jpg",
    "fileSize": 2048576,
    "fileSizeHuman": "2.0 MB",
    "uploadTime": "3.2s",
    "rapidUpload": false
  },
  "downloadUrl": "https://jsonproxy.3g.qq.com/urlmapper/aB3xYz",
  "fileInfo": {
    "name": "photo.jpg",
    "size": 2048576,
    "sizeHuman": "2.0 MB",
    "type": "image/jpeg",
    "creationTime": "2026-03-13T10:00:00Z",
    "modificationTime": "2026-03-13T10:00:00Z",
    "previewUrl": "https://..."
  }
}

CRITICAL — message field (Anti-hallucination): The message field contains the complete, pre-rendered text that QClaw should output to the user. It already includes the file name, size, file link, and the standard notice. QClaw MUST output message verbatim — do NOT ignore it and try to compose your own reply from downloadUrl, fileInfo, or other fields.

This design eliminates the need for the AI to extract and assemble information from multiple JSON fields, preventing URL hallucination (confusing short URL prefixes with long COS URL hash fragments).

When upload fails:

{
  "success": false,
  "message": "❌ 文件上传失败:上传失败: 文件不存在: /path/to/missing.pdf\n\n你可以:\n1. 🔄 重试 — 重新上传这个文件\n2. ❌ 取消 — 暂时不上传",
  "error": "上传失败: 文件不存在: /path/to/missing.pdf"
}

Note: Even for error cases, the message field contains the pre-rendered error text with user-facing options. QClaw should output it verbatim.

Note: After upload, the script automatically converts the COS file URL to a short URL via the JPRX short link service (data/4096/forward). The short URL format is https://jsonproxy.3g.qq.com/urlmapper/xxx. On mobile, tapping the short link opens the QClaw Mini Program (files are kept for 30 days); on PC, tapping the short link opens the H5 QR code page, and after the user scans the QR code with WeChat, it redirects to the Mini Program to view the file.

Anti-hallucination design: The message field is the single source of truth for QClaw's reply. The server pre-renders the complete response text with the correct file URL already embedded. This means there is zero chance of the AI constructing an incorrect URL, because the AI never needs to touch any URL — it just outputs the pre-rendered message. The rawDownloadUrl field only appears when short URL generation fails (as a fallback). Full URLs are logged server-side for debugging.

batch-upload

Upload multiple local files in one request. Returns a single pre-rendered message with the complete summary of all uploads.

When to use: Whenever the user wants to upload 2 or more files. Prefer batch-upload over multiple upload calls — it produces a single message that QClaw outputs verbatim, eliminating the need to assemble multiple responses.

POST /proxy/qclaw-cos/batch-upload
Content-Type: application/json

{
  "files": [
    { "localPath": "<path1>", "remotePath": "<optional>", "conflictStrategy": "ask" },
    { "localPath": "<path2>", "conflictStrategy": "ask" }
  ]
}

Body parameters:

  • files(required): file array (up to 20), each item contains:
    • localPath(required): absolute path of the local file, supports ~ expansion
    • remotePath(optional): cloud destination path. If omitted, upload to the root directory and keep the original file name
    • conflictStrategy(optional): conflict strategy for the same name, default ask

Example:

# macOS / Linux
curl -s -X POST http://localhost:$PORT/proxy/qclaw-cos/batch-upload \
  -H 'Content-Type: application/json' \
  -d '{"files":[{"localPath":"/path/to/report.pdf","conflictStrategy":"ask"},{"localPath":"/path/to/photo.jpg","conflictStrategy":"ask"},{"localPath":"/path/to/data.csv","conflictStrategy":"ask"}]}'

Output (JSON):

When all uploads succeed:

{
  "success": true,
  "message": "3 个文件全部上传成功!链接可在 QClaw 小程序中随时查看。(保留 30 天后自动清理)\n\n📎 report.pdf (2.3 MB) — https://jsonproxy.3g.qq.com/urlmapper/aB3xYz\n📎 photo.jpg (1.1 MB) — https://jsonproxy.3g.qq.com/urlmapper/xK9mWq\n📎 data.csv (156 KB) — https://jsonproxy.3g.qq.com/urlmapper/pL2nRt",
  "total": 3,
  "successCount": 3,
  "failedCount": 0,
  "items": [ ... ]
}

When some uploads fail (partial success):

{
  "success": false,
  "message": "3 个文件中 2 个上传成功(1 个失败)。成功文件的链接可在 QClaw 小程序中随时查看。(保留 30 天后自动清理)\n\n📎 report.pdf (2.3 MB) — https://jsonproxy.3g.qq.com/urlmapper/aB3xYz\n📎 photo.jpg (1.1 MB) — https://jsonproxy.3g.qq.com/urlmapper/xK9mWq\n\n❌ missing.log — 文件不存在: /path/to/missing.log",
  "total": 3,
  "successCount": 2,
  "failedCount": 1,
  "items": [ ... ]
}

CRITICAL: The message field contains the complete, pre-rendered summary — file names, sizes, file links, success/failure counts, and the standard notice. QClaw MUST output message verbatim. Do NOT attempt to summarize or reformat the batch results yourself.

info

Get file info for an existing cloud file (file link, preview, metadata).

POST /proxy/qclaw-cos/info
Content-Type: application/json

{ "remotePath": "<cloud-path>" }  // 必填:云端文件路径

Example:

curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/info \
  -H 'Content-Type: application/json' \
  -d '{"remotePath":"report.pdf"}'

list

List files in a cloud directory.

POST /proxy/qclaw-cos/list
Content-Type: application/json

{
  "dirPath": "<dir>",   // 可选:目录路径,默认 backup
  "limit": <n>          // 可选:最大返回数量,默认 50
}

Examples:

# List root directory
curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/list \
  -H 'Content-Type: application/json' \
  -d '{"dirPath":"/"}'

# List with limit
curl -s -X POST http://localhost:PORT/proxy/qclaw-cos/list \
  -H 'Content-Type: application/json' \
  -d '{"dirPath":"/","limit":20}'

Error Handling

All command outputs are JSON to stdout. Errors are also returned as JSON:{"success": false, "message": "...", "error": "..."}

IMPORTANT: when upload fails,message The field already contains the complete user-friendly error message and action options.Directly output message is sufficient, no need to compose error text yourself.

Error Handling method
Upload failed (success: false) Directly output message field content (already contains the error reason and action options)
401 / token expired Tell the user: "The cloud storage token has expired, please contact the administrator to refresh it."
File does not exist message already contains the specific path information, directly output it
Network error Retry 2 times, interval 3s; if it still fails, output message field content
Quota full Prompt to clean up expired files
Upload canceled message already contains the cancellation prompt, directly output it

IMPORTANT: When upload fails, you must explicitly inform the user that the file upload failed, and provide the specific reason for the error. Do not silently swallow errors or display only technical logs.


Prohibited behaviors

  • NEVER NEVER ignore message the message field and on your own assemble the reply content from downloadUrl、fileInfo and other fields.message is the complete display text pre-rendered by the server;it must be output as-is
  • NEVER You must not assemble, reorganize, or modify any URL on your own. If a link needs to be displayed,message the field already contains the correct link
  • NEVER NEVER concatenate rawDownloadUrl or any fragment of the COS long link with https://jsonproxy.3g.qq.com/ . Short links are generated by the server; the AI does not participate in URL construction
  • NEVER NEVER make any truncation, modification, reorganization, or format transformation to the content in message the message field
  • NEVER When batch uploading, do not summarize/rewrite the results of multiple files on your own. Use batch-upload the batch-upload interface; its message message already contains the complete summary
  • NEVER NEVER display file links when success: false success: false
  • NEVER Hardcoding or exposing SMH credentials to users
  • NEVER Uploading the user's local personal files without the user's explicit request
  • NEVER Using conflictStrategy: "rename" conflictStrategy: "rename" or conflictStrategy: "overwrite" when the user has not clearly stated their preference conflictStrategy: "overwrite"; you must use conflictStrategy: "ask" conflictStrategy: "ask" to let the user choose

Important notes

  • User says "upload a file" but does not specify a path → ask follow-up: "Which file do you want to upload? Just tell me the file path or file name."
  • User says "confirm upload xxx" or "send xxx to me" → directly execute the upload interface (conflictStrategy: "ask")
  • For a single file use upload, for multiple files use batch-upload: when there are 2 or more files, you must use batch-upload the batch-upload interface and obtain the server pre-rendered summary message
  • Same-name file conflict: when uploading, you must use conflictStrategy: "ask". If a same-name conflict error is returned, you must ask the user to choose overwrite, rename, or cancel; do not decide on your own
  • Files are uploaded to the cloud space root directory by default; the user can specify the target path via the remotePath path parameter
  • File links are output in short-link format (https://jsonproxy.3g.qq.com/urlmapper/xxx). On mobile, clicking the short link opens the QClaw mini program for viewing (files remain viewable within 30 days); on PC, clicking the short link opens the H5 QR code page (scan with WeChat to jump to the mini program for viewing); when a user reports that a link has expired, use info to obtain a new link and regenerate the short link
  • Batch uploads are processed sequentially by the server (not in parallel) to avoid API overload
  • message Output as-is [CRITICAL]:upload message as-is [CRITICAL]: the batch-upload returned by the upload and batch-upload interfaces message field contains the complete display text. QClaw must output as-is messageand must not assemble or summarize the reply on its own. This is the core mechanism for preventing AI hallucination