/api/v1/fs/cp 接口用于复制文件或目录,同时复制源对象已有的向量索引记录并将记录 URI 映射到目标路径。源对象保留。复制已有索引不需要重新解析源文件或重新生成源文件 Embedding。
复制文件时,目标是完整文件 URI;复制目录时,目标 URI 就是复制后的目录根,不会在目标下再自动嵌套源目录名。同名文件会被覆盖,已存在目录会合并,目标独有文件保留。
说明
本接口没有 overwrite=false 或自动备份选项;需要避免覆盖时,应使用新的目标路径。
完成 API Key 获取,确认数据库访问地址;源对象必须存在,目标的父目录必须已存在。调用身份需要读取源对象,并对目标及实际受影响的条目有相应写入权限。
项目 | 内容 | 说明 |
|---|---|---|
URI | /api/v1/fs/cp | 相对于数据库访问地址的路径 |
请求方法 | POST | 参数为 JSON 请求体 |
请求头 | Content-Type: application/json | JSON 消息类型 |
Authorization: Bearer {API_KEY} | Bearer Token 鉴权 |
参数 | 类型 | 必选 | 默认值 | 备注 |
|---|---|---|---|---|
from_uri | string | 是 | — | 源文件或源目录 URI,例如 viking://resources/source/api.md。 |
to_uri | string | 是 | — | 目标的精确 URI。复制文件必须包含目标文件名且不能以 / 结尾;复制目录时为目标目录根。目标父目录必须存在。 |
recursive | bool | 否 | false | 复制目录必须为 true;复制文件可省略。响应中的 recursive 表示实际复制对象是否为目录。 |
复制规则:
场景 | 行为 |
|---|---|
文件 → 不存在的文件 | 创建精确目标文件,复制源已有索引。 |
文件 → 已存在的文件 | 覆盖目标文件,不自动保存旧版本。 |
目录 → 不存在的目录 | recursive=true 时创建目标根并复制子树。 |
目录 → 已存在的目录 | 合并:同路径文件覆盖,目标独有条目保留,不做整个目标目录替换。 |
文件与目录类型冲突 | 拒绝复制,例如源为文件但目标为目录。 |
源与目标相同、互为祖先/后代 | 拒绝复制,不允许将目录复制到自身子目录,也不允许反向重叠。 |
向量索引 | 复用源中已经存在的索引记录及其标签等索引元数据,不保证为未索引的源内容新建索引;源无对应记录时也不能据此认为旧目标索引一定被清除。 |
成功响应表示文件复制与已有索引复制阶段已完成,仍需等待目标父目录摘要刷新(增加新的子内容摘要)。
字段 | 类型 | 参数说明 |
|---|---|---|
status | string | ok 或 error。 |
result | object | 复制结果对象。 |
result.operation_id | string | 本次复制操作标识,可用于日志排查;不是异步任务查询 ID。 |
result.operation | string | copy。 |
result.from / to | string | 规范化后的源 URI 和目标 URI。请求字段名为 from_uri、to_uri,响应字段名为 from、to。 |
result.recursive | bool | 实际对象为目录时为 true,文件为 false。 |
result.phase | string | 成功的复制阶段为 completed。 |
result.files_created | int | 复制写入的文件数,包含覆盖写入;不是仅新建文件数,也不含目录数。 |
result.vectors | object | 可选的索引转移统计,不能当成目标全量索引数或复制文件数。 |
result.vectors.scanned / written | int | 扫描的源索引记录数、写入的目标索引记录数。 |
result.vectors.deleted / restored / batches | int | 索引转移流程删除、恢复的记录数及处理批次数;不表示文件旧版本已备份。 |
result.semantic_root_uri | string | 可选,需要后续语义刷新的目标父目录 URI。 |
result.semantic_status | string | 可选,queued、skipped 或 failed;描述父目录刷新,不是文件复制阶段。 |
result.semantic_error | string | 可选,父目录刷新入队失败的说明。 |
error.code / message / details | string / string / object | 失败时的错误码、描述及可选详情。 |
HTTP 状态码 | error.code | 说明与处理 |
|---|---|---|
401 | UNAUTHENTICATED | 缺少或无效 API Key。 |
403 | PERMISSION_DENIED | 源不可读、目标不可写或复制涉及不可见数据;检查权限范围。 |
400 | INVALID_ARGUMENT / INVALID_URI | URI 无效、路径重叠、类型冲突或文件目标缺少文件名;更换合法路径。 |
404 | NOT_FOUND | 源对象或目标父目录不存在;先确认源或创建父目录。 |
412 | FAILED_PRECONDITION | 复制目录未传 recursive=true。 |
409 | CONFLICT / ABORTED | 锁竞争、索引记录冲突等;核对当前状态后重试,不盲目覆盖。 |
500 / 503 | INTERNAL / PROCESSING_ERROR / UNAVAILABLE | 存储或索引处理失败,具体码以响应为准;检查目标是否部分写入或被清理,必要时恢复备份。 |
curl -X POST "https://xxx/api/v1/fs/cp" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-key" \ -d '{ "from_uri": "viking://resources/source/api.md", "to_uri": "viking://resources/release/api-copy.md" }'
前提:viking://resources/release 已存在。成功响应示意:
{ "status": "ok", "result": { "operation_id": "e0b6a9cfc4b84595b04b52448c2c03ce", "operation": "copy", "from": "viking://resources/source/api.md", "to": "viking://resources/release/api-copy.md", "recursive": false, "phase": "completed", "files_created": 1, "vectors": {"scanned": 3, "written": 3, "deleted": 0, "restored": 0, "batches": 1}, "semantic_root_uri": "viking://resources/release", "semantic_status": "queued" } }
curl -X POST "https://xxx/api/v1/fs/cp" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-key" \ -d '{ "from_uri": "viking://resources/source", "to_uri": "viking://resources/release/source-copy", "recursive": true }'