OpenViking Assets Resolver API 实战指南:Manifest 解析与 Git 权限预检
【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking
本指南以 OpenViking 的 OpenViking Assets 声明式资产体系为背景,围绕openviking-assets/1协议的两个核心 HTTP 端点——POST /api/v1/openviking-assets/resolve(Manifest 解析校验)与POST /api/v1/openviking-assets/preflight(Git 仓库只读访问预检)——讲解其请求/响应契约、错误语义与底层实现原理。读完本文,你将掌握如何直接调用 Resolver 端点完成 Manifest 的解析与验证、如何对私有 Git 仓库执行安全的权限预检,并理解ov add-resource --manifest命令背后的完整调用链与安全设计。
说明:正常情况下你不需要直接调用这些端点——运行
ov add-resource --manifest <file>时,CLI 会自动调用 Resolver 与权限预检端点。仅当你在实现自定义客户端时,才需要以本文契约直接调用它们。
一、OpenViking Assets 与 Resolver 的定位
OpenViking Assets 用声明式文件描述"一个知识库应该包含什么":最简形式下,一个 Manifest 文件直接定义要摄入的资产(assets);团队也可以把可摄入源集中维护在一个共享 Catalog 中,再由多个 Manifest 按名称挑选资产。应用 Manifest 时,CLI 会为每个资产调用add_resource创建或更新对应资源,并把资产与viking://资源的映射保存在本地。
在这一体系中,服务端是权威的协议解析器:
manifest.yaml (+ catalog.yaml 当使用共享 Catalog 时) | v Server 解析并校验 openviking-assets/1 | v Resolved Assets(标准化执行计划) | v CLI 解析本地凭据与 State | v 每个资产一次 add_resource 调用 -> viking:// 资源Resolver 端点只负责解析与校验——它不会 clone 仓库、不会创建资源、也不会启动同步任务;执行计划由客户端负责落地。这正是 docs/en/guides/18-openviking-assets.md 中"服务器返回执行计划,Resolver 端点本身不创建资源"的设计。
二、Resolve 端点:解析并校验 Manifest
2.1 端点与鉴权
POST /api/v1/openviking-assets/resolve该端点使用 OpenViking Server 标准鉴权机制。当启用 API Key 鉴权时,需携带请求头:
X-API-Key: <your-api-key>从源码看,端点在 openviking/server/routers/openviking_assets.py 中注册于前缀/api/v1/openviking-assets,通过Depends(get_request_context)获取请求上下文,再调用openviking.server.openviking_assets.resolve_openviking_assets完成解析,最终以标准信封格式{"status": "ok", "result": ...}返回。
2.2 请求体字段
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
manifest_yaml | string | 是 | — | 完整 Manifest YAML,长度 1–4,000,000 字符 |
catalog_yaml | string | 否 | — | 完整 Catalog YAML,长度 1–4,000,000 字符。当 Manifest 按名称选择资产时必须提供;当 Manifest 在catalog字段下直接定义资产时必须省略 |
manifest_label | string | 否 | manifest.yaml | 用于错误提示的 Manifest 来源标签,1–1,024 字符 |
catalog_label | string | 否 | catalog.yaml | 用于错误提示的 Catalog 来源标签,1–1,024 字符 |
这些约束与 Pydantic 请求模型一一对应:ResolveOpenVikingAssetsRequest使用extra="forbid"拒绝未知字段,manifest_yaml与catalog_yaml限制在 1 至 4,000,000 字符,两个 label 限制在 1 至 1,024 字符(openviking/server/routers/openviking_assets.py)。超限、字段类型错误或空值由请求校验层以 HTTP422拒绝。
2.3 自包含 Manifest 示例
Manifest 直接在其catalog字段下定义资产时,请求体只需携带manifest_yaml:
curl -X POST "${OPENVIKING_BASE_URL}/api/v1/openviking-assets/resolve" \ -H "Content-Type: application/json" \ -H "X-API-Key: ${OPENVIKING_API_KEY}" \ --data-binary @- <<'JSON' { "manifest_yaml": "protocol: openviking-assets/1\ncatalog:\n - name: openviking\n connector: git\n watch_interval: 1440\n params:\n repo_url: https://github.com/volcengine/OpenViking\n branch: main\n", "manifest_label": "manifest.yaml" } JSON2.4 Manifest 按名称选择资产
当 Manifest 只选择名称时(例如assets: [openviking, flask]),资产定义位于独立的 Catalog 文件中,需要把 Catalog YAML 放在catalog_yaml字段、其标签放在catalog_label字段一并提交。仓库中有一个可直接对照的完整示例(examples/openviking-assets/catalog.yaml 与 examples/openviking-assets/manifest.yaml):
catalog.yaml声明protocol: openviking-assets/1、defaults.git(如watch_interval: 1440)、以及openviking、requests、flask三个资产定义;manifest.yaml只有assets: [openviking, flask]两行,按名称从 Catalog 中挑选资产。
在 CLI 模式下,Catalog 文件的定位顺序为:--args catalog:<file>显式指定(相对当前工作目录解析)→ 未指定时使用 Manifest 同目录下的catalog.yaml。
2.5 成功响应
{ "status": "ok", "result": { "protocol": "openviking-assets/1", "manifest": "manifest.yaml", "catalog": "manifest.yaml", "assets": [ { "name": "openviking", "connector": "git", "repo_url": "https://github.com/volcengine/OpenViking", "branch": "main", "auth_ref": null, "watch_interval": 1440.0, "locator": "github.com/volcengine/OpenViking", "git_ref": "main", "asset_id": "a1b2c3d4e5f6" } ] } }响应字段含义:
locator:标准化后的仓库定位符。Git URL 规范化会移除协议、用户前缀、主机端口、尾部.git与尾部斜杠,并将主机名转为小写——因此同一仓库的 HTTPS、SSH、SCP 风格 URL 通常产生相同的 locator,而不同分支产生不同的资产。git_ref:解析后的 Git 引用(分支名或完整 commit SHA)。asset_id:由 connector、标准化 locator 与 Git 引用派生的稳定 12 位标识符(上面示例仅为格式示意)。其生成逻辑见 openviking/server/openviking_assets.py:对connector\nlocator\ngit_ref做 SHA-1 摘要并取前 12 位十六进制字符。watch_interval:以分钟为单位的 Watch 刷新间隔,0表示禁用自动刷新。catalog:回显catalog_label;对自包含 Manifest,它等于 Manifest 的 label。
测试 tests/server/test_openviking_assets.py 验证了这一逻辑:例如git@github.com:org/beta.git被规范化为github.com/org/beta,而asset_id正是hashlib.sha1(b"git\ngithub.com/org/alpha\nmain").hexdigest()[:12]。
2.6 错误响应
协议或内容校验失败时返回 HTTP400,错误码为INVALID_ARGUMENT。常见原因包括:
- YAML 格式错误或存在未知字段;
protocol不是openviking-assets/1,或 Manifest 定义了catalog却未声明protocol;include非空(v1 不支持 Manifest 组合);- Manifest 定义了
catalog又同时提交了catalog_yaml; - Manifest 按名称选择资产但未提供任何
catalog_yaml; - Manifest 引用了 Catalog 中不存在的资产;
- connector、仓库 URL、Git 引用或资产身份无效;
- 同一 Manifest 中出现重复的资产身份(重复选择名称会被去重并保留首次位置,但同一来源解析出相同
asset_id的两个资产会报错)。
空字段、字段类型错误或长度超限则由请求校验以 HTTP422拒绝。
从实现看(openviking/server/openviking_assets.py),解析器通过_StrictModel(extra="forbid", strict=True)对所有 YAML 结构做严格校验:未知字段是错误而非警告,未支持的 connector(目前仅git)即使未被本次选中也会导致整个解析失败;params内容与 clone URL 安全性只对选中资产校验。watch_interval必须是非负有限数值,params.branch与params.commit互斥,commit 必须是完整 40 位十六进制 SHA(解析时会统一转为小写)。
2.7 一个细节:to字段与目标 URI 规范化
虽然原 API 文档的请求体字段表中未列出,但源码中_CatalogAsset还支持可选的to字段(精确资源目标 URI)。HTTP 调用路径下,_normalize_asset_target_uri会复用与add_resource相同的请求边界 URI、命名空间形状与访问检查,特别是会把viking://~家目录别名在计划到达 CLI 之前展开。测试 tests/server/test_openviking_assets.py 展示了这一点:to: viking://~/resources/repos/private会被规范化为viking://user/alice/resources/repos/private。
三、Preflight 端点:只读校验 Git 仓库可访问性
3.1 端点与职责
POST /api/v1/openviking-assets/preflight该端点在 OpenViking Server 执行环境中运行只读的git ls-remote,以验证仓库及可选 ref 可读。它不会 clone 仓库、不会创建资源、也不会启动任务。Manifest 模式在 dry-run 与提交前校验两个阶段都会调用它(对应apply_manifest_core中"先完成所有 preflight,再提交第一个资产"的顺序,见 crates/ov_cli/src/openviking_assets.rs)。
3.2 请求体字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 资产名称 |
connector | string | 是 | 当前必须为git |
repo_url | string | 是 | Git clone URL |
branch | string | 否 | 要校验的分支或标签;省略时检查远端HEAD |
auth_config.username | string | 否 | HTTP Basic 用户名;默认oauth2 |
auth_config.token | string | 否 | 一次性 Git token;绝不持久化 |
Pydantic 模型PreflightOpenVikingAssetRequest还额外支持可选的commit字段(完整的 40 位十六进制 SHA,openviking/server/routers/openviking_assets.py)。auth_config.token使用SecretStr类型,确保 token 不会出现在模型 repr 中。
3.3 调用示例(私有仓库)
curl -X POST "${OPENVIKING_BASE_URL}/api/v1/openviking-assets/preflight" \ -H "Content-Type: application/json" \ -H "X-API-Key: ${OPENVIKING_API_KEY}" \ -d '{ "name": "private-repository", "connector": "git", "repo_url": "https://github.com/example/private-repository", "branch": "main", "auth_config": { "username": "oauth2", "token": "<github-token>" } }'当显式提供 token 时,preflight不会回退到服务器的 Git 凭据助手。token 通过子进程环境变量传递,不会出现在 Git 命令参数或响应中。
3.4 成功响应
{ "status": "ok", "result": { "name": "private-repository", "connector": "git", "locator": "github.com/example/private-repository", "git_ref": "main", "accessible": true } }3.5 错误响应
| HTTP 状态码 | 错误码 | 含义 |
|---|---|---|
403 | PERMISSION_DENIED | 仓库不存在、凭据无效或读权限不足 |
404 | NOT_FOUND | 仓库可读,但请求的分支/标签不存在 |
503 | UNAVAILABLE | DNS、连接或 Git 可执行文件不可用 |
504 | DEADLINE_EXCEEDED | 权限预检超过 15 秒 |
3.6 实现原理:安全的 git ls-remote
preflight_git_repository的实现非常值得借鉴,它是整个资产体系安全性的关键一环:
- URL 安全校验:
_validate_clone_url拒绝空 URL、含控制字符的 URL、以-开头(Git 会把它当参数标志)的 URL,以及ext::、fd::等 Git remote-helper 传输协议;reject_git_http_userinfo拒绝在 URL 内嵌 userinfo;require_remote_resource_source拒绝本地路径(如file://)。 - token 的强制约束:token 认证要求仓库 URL 必须为 HTTPS;token 存在时 username 必须非空。
- 凭据传递:设置
GIT_TERMINAL_PROMPT=0、GCM_INTERACTIVE=Never、GIT_SSH_COMMAND="ssh -o BatchMode=yes"禁用任何交互;有 token 时通过build_git_http_auth_env把 HTTP Basic 凭据写入进程级 Git 配置(GIT_CONFIG_COUNT机制),token 只出现在环境变量中而非命令行参数——测试 tests/server/test_openviking_assets.py 明确断言"secret-token"不出现在进程参数里,而 base64 编码的凭据只存在于GIT_CONFIG_VALUE_*环境变量中。 - 命令构造:
git ls-remote --exit-code <repo_url>;指定 branch 时追加refs/heads/<branch>与refs/tags/<branch>两个引用;只给 commit 时则检查HEAD——因为ls-remote无法证明任意历史 commit 可达,精确 SHA 由后续导入管道的 fetch/checkout 阶段验证。 - 超时与清理:默认 15 秒超时(
GIT_PREFLIGHT_TIMEOUT_SECONDS = 15.0),POSIX 下以独立进程组启动(start_new_session=True),超时或取消时对整个进程组发SIGKILL并限定 1 秒回收时间,避免僵尸进程。 - 错误映射:根据 stderr 中的网络失败特征串(
could not resolve host、connection refused等)映射为503 UNAVAILABLE;git ls-remote返回码 2 且指定了 branch 时映射为404 NOT_FOUND;其余失败一律映射为403 PERMISSION_DENIED。
四、CLI 侧的完整调用链:ov add-resource --manifest
理解端点后,再看 CLI 侧的编排会更清晰。ov add-resource --manifest manifest.yaml的完整流程(实现于 crates/ov_cli/src/openviking_assets.rs):
- 读取本地 Manifest(及需要的 Catalog)文件内容;
- 调用
/api/v1/openviking-assets/resolve获得标准化执行计划; - 从本地凭据文件(默认
~/.openviking/openviking_assets_credentials.yaml,可用环境变量OPENVIKING_ASSETS_CREDENTIALS_FILE覆盖)解析每个选中资产的auth_ref别名——Manifest 与 Catalog 只携带auth_ref别名,绝不能包含 token、密码或私钥; - 对所有资产逐一调用
/api/v1/openviking-assets/preflight,全部通过后才开始提交; - 按计划为每个资产调用
add_resource(创建或同步),并把结果写入<manifest>.state.json(协议openviking-assets-state/1)。
关键的行为约束(均有对应测试佐证):
- preflight 全量先行:任一资产 preflight 失败即整体中止,不提交任何资产、不创建任务、不写 State,
skip_failed也无法绕过 preflight 失败(crates/ov_cli/src/openviking_assets.rs)。 - 失败策略:默认 fail-fast——当前资产失败后,后续资产标记为 not attempted,已成功资产与失败记录写入 State,命令以非零码退出;
--args skip_failed:true可继续处理剩余资产,但整体仍以非零码退出,且不会回滚已创建的资源(crates/ov_cli/src/openviking_assets.rs)。 - dry-run:
--args dry_run:true会执行解析、凭据解析与完整 preflight,并打印每个资产的计划动作(create/sync),但绝不提交资源、创建任务或写 State(crates/ov_cli/src/openviking_assets.rs)。 - watch_interval 优先级(从高到低):CLI
--watch-interval> 单资产watch_interval>defaults.git.watch_interval>0(禁用自动刷新)。 - State 归属:State 只属于单一执行环境,不属于 Catalog 或 Manifest 协议;共享 Manifest 的仓库应把
*.state.json加入.gitignore;同一 Manifest 不应并发应用(State 文件没有跨进程锁)。
五、端到端验证与快速上手
5.1 前置条件
- 安装支持 OpenViking Assets 的
ovCLI; - 配置提供
/api/v1/openviking-assets/resolve的 OpenViking 服务; - 验证连通性:
ov health。
5.2 编写并校验 Manifest
创建manifest.yaml:
protocol: openviking-assets/1 catalog: - name: openviking connector: git params: repo_url: https://github.com/volcengine/OpenViking branch: main先校验(dry-run):
ov add-resource --manifest manifest.yaml --args dry_run:truedry_run会:读取本地 YAML(及 Catalog)→ 请求服务端解析校验协议 → 检查所有选中auth_ref别名在本地可解析 → 请求服务端对每个仓库用有效凭据执行只读git ls-remote权限预检 → 打印每个资产的 create/sync 计划;不会 clone 仓库、提交资源、创建任务或写 State。任一仓库不可读时 dry-run 立即以PERMISSION_DENIED退出,不产生可执行计划。
5.3 应用 Manifest
审查计划后去掉 dry_run:
ov add-resource --manifest manifest.yaml等待每个资源处理完成:
ov add-resource --manifest manifest.yaml --wait --timeout 6005.4 CLI 选项速查
--manifest模式相关选项:
| 选项 | 说明 |
|---|---|
-m, --manifest <file> | Manifest 文件 |
--args <key:value,...> | Manifest 运行选项,逗号分隔;支持键见下 |
--wait | 等待每个资源处理完成 |
--timeout <seconds> | HTTP 请求超时;原生私有 Git 导入即使不加--wait也遵守它,默认 300 秒 |
--watch-interval <minutes> | 覆盖所有资产的刷新间隔 |
--args支持的运行键(在 CLI 本地消费,绝不作为资源参数发给服务端;未知键报错):
| 键 | 说明 |
|---|---|
catalog:<file> | 按名称选择资产时的独立 Catalog 文件;默认取 Manifest 同目录catalog.yaml。Manifest 自带catalog时不使用 |
dry_run:true | 只解析协议并校验所有仓库读权限,不提交资源、不创建任务、不写 State |
skip_failed:true | 资产失败后继续处理剩余资产 |
--args既接受key:value,...逗号分隔形式,也接受完整 JSON 对象,例如--args '{"dry_run": true, "catalog": "shared/catalog.yaml"}'。
六、当前协议边界
openviking-assets/1目前的限制(详见 docs/en/guides/18-openviking-assets.md):
- 仅支持 Git 资产;
- Manifest 是扁平的,不能递归
include其他 Manifest; - 服务端 Resolver 只返回计划,不做批量提交;
- 服务端 preflight 只做只读
git ls-remote检查,不下载仓库内容; - CLI 串行执行资产;
- 孤儿资产(从 Manifest 移除的资产)不会被自动删除;
- 暂不包含
ov share指针码与从既有知识库导出 Manifest; - State 是本地文件,不跨机器同步;
- CLI 与服务端必须支持同一协议版本。
相关文档
- OpenViking Assets 协议与操作指南
- 资源管理 API
- 资源 Watch API
- OVPack 导入与导出
- 服务端实现:openviking/server/routers/openviking_assets.py、openviking/server/openviking_assets.py
- CLI 实现:crates/ov_cli/src/openviking_assets.rs
- 测试用例:tests/server/test_openviking_assets.py
- 完整示例:examples/openviking-assets/
【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考