examples/openclaw-plugin/docs/oc-resource-skill-import-design.md
当前实现已调整:Agent 可见工具不再使用统一的
ov_import(kind=...),而是拆为add_resource和add_skill;手动 slash command 也对应拆为/add-resource和/add-skill,不再保留/ov-import。
当前 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 对接方式、安全边界和测试方案。
add_resource,slash command /add-resourceadd_skill,slash command /add-skillkind: "resource" | "skill" 在一个入口里分流。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。
Resource 和 skill 的落点、参数和服务端 API 不同,对外暴露两个入口:
add_resource,slash command /add-resourceadd_skill,slash command /add-skillResource 导入:
/add-resource ./README.md --to viking://resources/openviking-readme --wait
Skill 导入:
/add-skill ./skills/install-openviking-memory --wait
add_resource / add_skillkind、data、to、parent 这类互斥参数--kind skill 切换语义OpenVikingClient.addResource() / addSkill(),不复制上传逻辑换句话说:对外和对内都保持 resource / skill 分离。
新增工具:
add_resource
add_skill
参数:
{
// 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;
}
校验规则:
add_resource:
sourcesource 可为本地路径、目录、远程 URL 或 Git URLto 与 parent 互斥dataadd_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:
/add-resource ./README.md --to viking://resources/openviking-readme --wait
结果会尽量落到:
viking://resources/openviking-readme
如果只想把资源放到某个集合下,可使用 parent:
/add-resource ./README.md --parent viking://resources/docs --wait
结果会落在类似:
viking://resources/docs/README
新增命令:
/add-resource <source> [--to URI] [--parent URI] [--reason TEXT] [--instruction TEXT] [--wait] [--timeout SEC]
/add-skill <source> [--wait] [--timeout SEC]
导入 resource:
/add-resource ./README.md --to viking://resources/openviking-readme --wait
导入远程 resource:
/add-resource https://github.com/volcengine/OpenViking --to viking://resources/openviking-repo --reason "OpenViking source docs"
导入 skill:
/add-skill ./skills/install-openviking-memory --wait
/add-skill ./SKILL.md --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)add_resource 和 add_skill 分别调用底层 client 方法:
add_resource -> client.addResource(...)
add_skill -> client.addSkill(...)
本地文件/目录流程:
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 保持互斥,沿用服务端约束。只提供导入工具会让体验不闭环:用户可以把 resource 或 skill 导入 OpenViking,但在 OpenClaw 内不一定知道如何检索、读取或验证导入结果。
因此建议同时讨论一个轻量检索入口:
memory_search/memory-searchmemory_search 的目标不是替代 OpenViking CLI 的全部能力,而是提供最小闭环:
root_uri 或 skill 的 uri。add_resource 导入 resource 后,结果中应包含:
root_uristatusqueue_status(如果 wait=true)示例:
Imported OpenViking resource: viking://resources/openviking-readme
Processing: completed
Try: /memory-search "OpenViking install" --uri viking://resources/openviking-readme
add_skill 导入 skill 后也应返回 skill URI,并给出 skill 检索建议:
Imported OpenViking skill: viking://agent/skills/install-openviking-memory
Processing: completed
Try: /memory-search "<query>" --uri viking://agent/skills
v1 建议保持简洁:
{
query: string;
uri?: string; // default: search resources and skills
limit?: number; // default: plugin config or 10
}
示例命令:
/memory-search "OpenViking install" --uri viking://resources/openviking-readme
/memory-search "API usage" --uri viking://resources
/memory-search "<query>" --uri viking://agent/skills
对应 LLM tool 示例:
{
query: "OpenViking install",
uri: "viking://resources/openviking-readme",
limit: 5
}
memory_search 应尽量贴近 OpenViking 当前 /api/v1/search/find 的返回结构。OpenViking find 的 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;
}
因此 memory_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。memory_search 作为导入后的最小消费闭环,而不是完整文件浏览器。memory_recall 当前偏向长期记忆,不适合作为 resource/skill 导入后的默认消费入口。memory_search v1 应检索:
uris = ["viking://resources", "viking://agent/skills"]
后续如果希望统一上下文检索 memory/resource/skill,可扩展:
targetTypes?: Array<"memory" | "resource" | "skill">;
但 v1 不建议一开始加入 memory,避免和既有 memory_recall 职责重叠。
memory_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 直传覆盖 add_resource / add_skill:
add_resource / add_skill/add-resource / /add-skill--flag--key value--key=value--to 与 --parent 冲突/add-skill 拒绝 to、parent、reason、instruction覆盖 memory_search:
memory_search/memory-searchuri 时默认检索 viking://resources 和 viking://agent/skills--uri 时只检索该范围/add-resource ./README.md --to viking://resources/openviking-readme --wait
/memory-search "OpenViking install" --uri viking://resources/openviking-readme
/add-skill ./skills/install-openviking-memory --wait
/memory-search "install OpenViking memory" --uri viking://agent/skills
以及自然语言触发:
把 ./README.md 导入 OpenViking resource,目标是 viking://resources/openviking-readme,并等待处理完成。
把 ./skills/install-openviking-memory 作为 OpenViking skill 导入。
add_resource / add_skill 是否应默认 wait=false?
wait=true 时才等待。/add-skill 遇到 resource-only 参数应直接报错,还是静默忽略?
to/parent 对 skill 生效。SKILL.md 或目录包含 SKILL.md 时提示用户使用 /add-skill 或 agent tool add_skill。/add-skill,避免在 /add-resource 中自动猜测并改变用户意图。memory_search v1 是否默认检索 viking://resources 和 viking://agent/skills?
memory_recall,避免职责重叠。/ov-read 或 /ov-tree?
memory_search 完成导入后的最小消费闭环。