examples/openclaw-plugin/DISCUSSION-ov-import.md
当前 examples/openclaw-plugin 已经承担 OpenClaw 与 OpenViking 的 context-engine 集成,包括 session context、memory recall/store/forget、archive expand,以及 local/remote OpenViking runtime 管理。
随着 OpenViking 的 resource 和 skill 能力完善,OpenClaw 侧也需要一个自然入口,让用户可以在 OpenClaw 对话或显式命令中把外部资料导入到 OpenViking:
viking://resources/...SKILL.md、skill 目录、raw skill 内容或 MCP tool dict,落到 viking://agent/skills/...本 RFC 讨论 OpenClaw plugin 侧的导入入口、HTTP 对接方式、安全边界和测试方案。
ov_import/ov-importkind: "resource" | "skill" 区分导入类型,默认 resource。OpenVikingClient.addResource() / OpenVikingClient.addSkill(),避免在 resource 和 skill 之间复制上传逻辑。SKILL.md 多行内容或 MCP dict JSON;这些能力通过 LLM tool 的 data 参数支持。OpenViking resource 侧当前支持多类输入源:
http://、https://git@、ssh://、git://,以及常见 Git hosting URL.zip常见文件 parser 覆盖:
.txt、.text、.md、.markdown、.mdown、.mkd、.pdf、.html、.htm.docx、.doc、.pptx、.xlsx、.xls、.xlsm、.epub.png、.jpg、.jpeg、.gif、.bmp、.webp、.svg.mp3、.wav、.ogg、.flac、.aac、.m4a、.opus.mp4、.avi、.mov、.mkv、.webm、.flv、.wmv.py、.js、.ts、.go、.rs、.java、.cpp、.json、.yaml、.toml、.csv、.rst、.proto、.tf、.vue补充说明:media parser 当前主要复制原始文件并提取基础元数据;后续向量化主要依赖摘要。
OpenViking 当前已经有独立的 skill 导入链路:
POST /api/v1/skillsResourceService.add_skill(...)SkillProcessor.process_skill(...)viking://agent/skills/{skill_name}支持的输入形态包括:
SKILL.md 文件SKILL.md 的 skill 目录SKILL.md 字符串内容mcp_to_skill() 转成 skillHTTP 安全边界是:直接通过 HTTP 调 /api/v1/skills 时,不能传宿主本地路径;本地文件/目录需要先上传到 /api/v1/resources/temp_upload,再把返回的 temp_file_id 传给 /api/v1/skills。
为简化用户和 LLM 的使用成本,对外只暴露一个导入入口:
ov_import/ov-import使用 kind 参数区分导入类型:
kind?: "resource" | "skill";
默认:
kind = "resource";
这样最常见的 resource 导入不需要额外指定类型:
/ov-import ./README.md --to viking://resources/openviking-readme --wait
导入 skill 时显式指定:
/ov-import ./skills/install-openviking-memory --kind skill --wait
最初也可以设计为:
ov_resource_importov_skill_import但讨论后更倾向统一入口,原因是:
/ov-importov_importkind=skill 仍然是显式选择,不依赖完全自动猜测换句话说:对外入口合并,对内处理分流。
新增工具:
ov_import
参数:
{
kind?: "resource" | "skill"; // default: resource
// resource 或 skill path 模式共用
source?: string; // local path, directory path, public URL, Git URL
// skill 专用:raw SKILL.md 或 MCP tool dict
data?: unknown;
// resource 专用
to?: string;
parent?: string;
reason?: string;
instruction?: string;
// 通用
wait?: boolean;
timeout?: number;
}
校验规则:
kind 为空时按 resource。kind=resource:
sourcesource 可为本地路径、目录、远程 URL 或 Git URLto 与 parent 互斥datakind=skill:
source 或 datasource 可为本地 SKILL.md、skill 目录或 zipdata 可为 raw SKILL.md 或 MCP tool dictto、parent、reason、instruction工具描述中应明确:只有当用户明确要求导入、添加或索引 OpenViking resource/skill 时才调用,避免模型误触发。
Resource 的导入路径由 to 或 parent 控制,二者互斥:
to:精确指定最终 resource URI。parent:只指定父目录,由 OpenViking 根据源文件名、目录名、URL 或仓库名生成子路径。viking://resources/... 下按默认规则生成路径。推荐用户在希望得到稳定引用 URI 时使用 to:
/ov-import ./README.md --to viking://resources/openviking-readme --wait
结果会尽量落到:
viking://resources/openviking-readme
如果只想把资源放到某个集合下,可使用 parent:
/ov-import ./README.md --parent viking://resources/docs --wait
结果会落在类似:
viking://resources/docs/README
新增命令:
/ov-import <source> [--kind resource|skill] [--to URI] [--parent URI] [--reason TEXT] [--instruction TEXT] [--wait] [--timeout SEC]
默认 resource:
/ov-import ./README.md --to viking://resources/openviking-readme --wait
导入远程 resource:
/ov-import https://github.com/volcengine/OpenViking --to viking://resources/openviking-repo --reason "OpenViking source docs"
导入 skill:
/ov-import ./skills/install-openviking-memory --kind skill --wait
/ov-import ./SKILL.md --kind skill --wait
Slash command 暂不支持 raw multi-line SKILL.md 或 MCP dict JSON;如果需要导入这些结构化数据,使用 LLM tool 的 data 参数。
目录导入的高级过滤参数暂不放进 v1 对外入口。后续可以按需增加:
strict?: boolean;
ignoreDirs?: string;
include?: string;
exclude?: string;
preserveStructure?: boolean;
在 OpenVikingClient 增加底层方法:
uploadTempFile(filePath)zipDirectoryForUpload(dirPath)addResource(input)addSkill(input)ov_import 工具和 /ov-import 命令根据 kind 分流:
if (kind === "skill") {
return client.addSkill(...);
}
return client.addResource(...);
本地文件/目录流程:
local file/dir
-> if dir: zip locally
-> POST /api/v1/resources/temp_upload
-> POST /api/v1/resources or /api/v1/skills with temp_file_id
远程 resource 流程:
remote URL / Git URL
-> POST /api/v1/resources with path
Skill raw data 流程:
raw SKILL.md or MCP dict
-> POST /api/v1/skills with data
保持 OpenViking HTTP server 当前安全模型:
/api/v1/resources/temp_upload。zip 命令。to 与 parent 保持互斥,沿用服务端约束。只提供 ov_import 会让体验不闭环:用户可以把 resource 或 skill 导入 OpenViking,但在 OpenClaw 内不一定知道如何检索、读取或验证导入结果。
因此建议同时讨论一个轻量检索入口:
ov_search/ov-searchov_search 的目标不是替代 OpenViking CLI 的全部能力,而是提供最小闭环:
root_uri 或 skill 的 uri。ov_import 导入 resource 后,结果中应包含:
root_uristatusqueue_status(如果 wait=true)示例:
Imported OpenViking resource: viking://resources/openviking-readme
Processing: completed
Try: /ov-search "OpenViking install" --uri viking://resources/openviking-readme
ov_import 导入 skill 后也应返回 skill URI,并给出 skill 检索建议:
Imported OpenViking skill: viking://agent/skills/install-openviking-memory
Processing: completed
Try: /ov-search "<query>" --uri viking://agent/skills
v1 建议保持简洁:
{
query: string;
uri?: string; // default: search resources and skills
limit?: number; // default: plugin config or 10
}
示例命令:
/ov-search "OpenViking install" --uri viking://resources/openviking-readme
/ov-search "API usage" --uri viking://resources
/ov-search "<query>" --uri viking://agent/skills
对应 LLM tool 示例:
{
query: "OpenViking install",
uri: "viking://resources/openviking-readme",
limit: 5
}
ov_search 应尽量贴近 OpenViking 当前 /api/v1/search/find 的返回结构。OpenViking search 的 raw HTTP 返回外层是:
{
status: "ok",
result: {
memories: MatchedContext[];
resources: MatchedContext[];
skills: MatchedContext[];
total: number;
query_plan?: unknown;
provenance?: unknown; // include_provenance=true 时才可能出现
}
}
其中 MatchedContext 当前包含:
{
context_type: "memory" | "resource" | "skill";
uri: string;
level: number;
score: number;
category: string;
match_reason: string;
relations: Array<{
uri: string;
abstract: string;
}>;
abstract: string;
overview?: string | null;
}
因此 ov_search 建议也返回两层结果:
content.textdetails有结果时的用户可见文本示例:
Found 4 OpenViking results for "OpenViking install"
Resources
1. viking://resources/openviking-readme/README.md
OpenViking installation guide and setup commands...
score: 0.82
2. viking://resources/openviking-readme/INSTALL.md
Plugin install flow for OpenClaw and OpenViking...
score: 0.76
Skills
1. viking://agent/skills/install-openviking-memory
Install and operate OpenViking memory integration...
score: 0.69
对应结构化返回建议:
{
content: [
{
type: "text",
text: "Found 4 OpenViking results..."
}
],
details: {
action: "searched",
query: "OpenViking install",
uri: "viking://resources/openviking-readme",
total: 4,
memories: [],
resources: [
{
context_type: "resource",
uri: "viking://resources/openviking-readme/README.md",
level: 2,
score: 0.82,
category: "",
match_reason: "...",
relations: [],
abstract: "OpenViking installation guide and setup commands...",
overview: "..."
}
],
skills: [
{
context_type: "skill",
uri: "viking://agent/skills/install-openviking-memory",
level: 0,
score: 0.69,
category: "",
match_reason: "...",
relations: [],
abstract: "Install and operate OpenViking memory integration...",
overview: "..."
}
]
}
}
无结果时:
No OpenViking resource or skill results found for "OpenViking install".
对应结构化返回:
{
action: "searched",
query: "OpenViking install",
uri: "viking://resources/openviking-readme",
total: 0,
memories: [],
resources: [],
skills: []
}
v1 应检索 resources 和 skills,所以用户可见文本按分桶展示 resources 和 skills;details 中保留 OpenViking 原始的 memories/resources/skills/total 结构。由于 v1 不检索 memory,memories 通常为空数组。
v1 建议只返回检索结果摘要和 URI,不直接返回完整文件内容。原因:
/ov-read 或未来的 ov_read。ov_search 作为导入后的最小消费闭环,而不是完整文件浏览器。memory_recall 当前偏向长期记忆,不适合作为 resource/skill 导入后的默认消费入口。ov_search v1 应检索:
uris = ["viking://resources", "viking://agent/skills"]
后续如果希望统一上下文检索 memory/resource/skill,可扩展:
targetTypes?: Array<"memory" | "resource" | "skill">;
但 v1 不建议一开始加入 memory,避免和既有 memory_recall 职责重叠。
ov_search 只解决“查到相关上下文”的问题。若用户需要更明确的文件浏览能力,后续可以再讨论:
/ov-read <uri>/ov-tree <uri>v1 暂不加入,避免把导入 RFC 扩展成完整 OpenViking CLI replica。
覆盖 OpenVikingClient:
addResource
pathwait=true 保留 queue_statusaddSkill
SKILL.md 先 temp uploadSKILL.md 通过 data 直传data 直传覆盖 ov_import:
ov_import/ov-importkind 默认 resourcekind=skill 正确分流到 addSkill--kind skill--flag--key value--key=value--to 与 --parent 冲突kind=skill 时拒绝 to、parent、reason、instruction覆盖 ov_search:
ov_search/ov-searchuri 时默认检索 viking://resources 和 viking://agent/skills--uri 时只检索该范围/ov-import ./README.md --to viking://resources/openviking-readme --wait
/ov-search "OpenViking install" --uri viking://resources/openviking-readme
/ov-import ./skills/install-openviking-memory --kind skill --wait
/ov-search "install OpenViking memory" --uri viking://agent/skills
以及自然语言触发:
把 ./README.md 导入 OpenViking resource,目标是 viking://resources/openviking-readme,并等待处理完成。
把 ./skills/install-openviking-memory 作为 OpenViking skill 导入。
ov_import 是否应默认 wait=false?
wait=true 时才等待。kind=skill 时 resource-only 参数应直接报错,还是静默忽略?
to/parent 对 skill 生效。SKILL.md 或目录包含 SKILL.md 时自动设置 kind=skill。--kind skill,默认 resource,行为更可解释。ov_search v1 是否默认检索 viking://resources 和 viking://agent/skills?
memory_recall,避免职责重叠。/ov-read 或 /ov-tree?
ov_search 完成导入后的最小消费闭环。