Skip to content

[Bug] 不同用户安装相同 Skill 时因 slug 全局唯一导致无法安装/被自动重命名 #810

Description

@xiangfei258

背景

roadmap 里有一条待办:

修复不同用户安装相同 Skill 时,因目前 Skill slug 全局唯一导致无法安装、会自动新增 versiontag 的问题,排查其对安装流程 and 版本管理的影响

我看了下相关代码,把问题和影响面理了一下,想先对齐下方案再动手。

问题长啥样

A 装了个 user 级的 my-skill,B 也想装个同名的 my-skill(也是 user 级,俩人互相看不见)。结果 B 装的时候因为 slug 全局唯一,被自动改成了 my-skill-v2,连 SKILL.md 的 frontmatter 都给改写了。

这俩本来该各自独立存在的(created_by 不同、share_config 不同、互相不可见),就因为全局唯一约束,用不了自己想要的 slug。

根因

主要三处:

位置 现状
DB models_business.py:234 Skill.slug 全局 unique=True
文件系统 service.py:204 get_skills_root_dir 目录 skills/{slug},slug 就是目录名,也全局唯一
判重 service.py:618 _generate_available_slug 冲突时生成 {slug}-v{idx},这就是"自动新增 versiontag"的来源(其实是 slug 重命名,不是真的版本管理)

Skill 本来就有 created_byshare_config(access_level 有 global/department/user 三档),访问控制 user_can_access_skill 也是按用户过滤的,偏偏 slug 唯一性是全局的——这俩对不上,就是问题根源。

影响面

安装流程,三条路径都走 _generate_available_slug

  • 会话里 install_skill 工具 -> import_skill_dir -> _import_skill_dir_implservice.py:700
  • 上传 prepare_skill_upload -> _stage_skill_draft_itemservice.py:658)-> confirm_skill_install_draft
  • 远程 prepare_remote_skill_install -> 同上的草稿流程

版本管理version/content_hash 主要是 builtin 在用;用户级 skill 那个"versiontag"其实就是 slug 加后缀重命名,改了唯一性之后跨用户不会再触发,但同一个用户重名安装还是得保留去重。

两个容易踩坑的连带点

  • skill_dependencies 存的是别的 skill 的 slug 字符串service.py:484{skill.slug: skill} 按 slug 索引)。slug 要是不再全局唯一,依赖解析就会歧义、互相覆盖。
  • list_visible_skills_for_management 按 slug 去重(service.py:407),同名 skill 会被误去重。

另外按 slug 查的那堆函数(get_by_slug/exists_slug/get_skill_or_raise/sync_thread_readable_skills/delete_skill 之类,大概 10 处)都得加上 owner 维度。

我想这么改

只动真正出问题的 user 级 skill,共享级不动:

  • user 级access_level=user):(created_by, slug) 联合唯一,文件放 skills/users/{uid}/{slug}
  • 共享级(global/department/builtin):slug 还是全局唯一,目录还是 skills/{slug}
  • 查询和依赖解析带上 user 上下文,再加 DB 迁移和文件迁移

难点是 PG 没法用一条 unique 约束同时表达"user 级按 uid 唯一 + 共享级全局唯一",得靠部分唯一索引 + 应用层兜。

想跟你确认几点

  1. "user 级按 (created_by, slug) 隔离、共享级保持全局唯一"这个方向 OK 吗?
  2. skill_dependencies 的 slug 引用,要不要改成"在当前用户可见域里解析"?
  3. 老数据迁移(已有 user 级 skill 的目录搬迁)要不要兼容旧路径?

方案定了我就提 PR。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions