Skip to content

feat(subagents): 支持按项目设置子智能体作用范围 - #1438

Open
zszz3 wants to merge 5 commits into
vastsa:mainfrom
zszz3:codex/feat-subagent-project-scope
Open

zszz3 wants to merge 5 commits into
vastsa:mainfrom
zszz3:codex/feat-subagent-project-scope

Conversation

@zszz3

@zszz3 zszz3 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

关联 #1431。

目前用户创建的子智能体会出现在所有会话的 Task 工具中,项目专用的子智能体也会被其他项目看到。本 PR 增加“全局 / 指定项目”设置,让模型只看到并调用当前项目适用的子智能体。

改动

  • 在子智能体编辑页选择作用范围。“指定项目”支持搜索和多选;启用、禁用仍由列表开关控制。
  • 根据会话的项目目录筛选 Task 中的可用子智能体。例如 A 专用的子智能体只在 A 及其子目录的会话中可用,在 B 或无项目会话中不可见;即使模型指定它的名字,也会被拒绝执行。
  • 复用现有 scope 字段和子智能体加载流程,由 Host 在 agents.active(projectPath) 中筛选。范围设置单独保存在应用本地,不改动子智能体 Markdown;重命名保留设置,删除时清理。
  • 未设置范围的现有子智能体继续全局可用。本次仅支持用户创建的子智能体,不涉及插件的激活条件。

验证

  • 23 项前端测试、19 项 Host 子智能体测试通过,覆盖项目选择与保存、范围过滤、启停、重命名和重启后恢复。
  • Host RPC 与运行时加载的端到端测试通过,覆盖 A、B、无项目会话的可用范围。
  • Desktop 类型检查、样式检查、Rust 格式检查和 PR 基线检查通过。
  • 使用真实 DeepSeek Flash 验证:全局、A 专用、B 专用子智能体在对应会话中调用成功;在 B 中调用 A 专用子智能体返回 Unknown subagent,未启动子任务。真实模型验证在同步主线前完成,同步后重跑了上述自动化检查与 Host 端到端测试。

范围修改在下一次加载工具目录时生效,不中断正在运行的子智能体。旧版本不识别新增的范围设置,降级后会恢复原来的全局可用行为。

Keep dedicated user subagents out of unrelated session catalogs while
preserving global defaults and portable Markdown definitions. Persist
project visibility locally and filter before runtime catalog assembly.

Expose project selection in the editor independently of enablement,
using the project archive sources so recent folders remain selectable.
Cover persistence, catalog isolation, and the settings save flow.

Refs vastsa#1431
@zszz3
zszz3 marked this pull request as ready for review October 6, 2026 16:05
@zszz3 zszz3 changed the title feat(subagents): 按项目限定用户子智能体的可见与调用范围 feat(subagents): 支持按项目设置子智能体作用范围 Oct 6, 2026

@muzimu217 muzimu217 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked out the branch and reproduced the CI failure locally — full review below.

The JS failure is a stale source assertion, one line to fix

apps/desktop/test/agent-capability-settings.test.mjs:42 ("skills and MCP filter one list by level...") asserts the SubagentEditorSheet source still contains settings\.globalOnly. This PR intentionally replaces that "global-only" label with the real scope control, so the assertion no longer matches. Reproduced locally on head 758764a09:

✖ skills and MCP filter one list by level instead of stacking two sections
AssertionError: The input did not match the regular expression /settings\.globalOnly/

Updating that assertion to the new shape is the only thing between this PR and a green JS job — the new subagent-project-scope.test.mjs suite itself passes its non-Electron tests, and the Electron E2E check is green on CI.

Host-side implementation verified against #1431's facts

This is exactly the "wiring" the issue's verification pointed at, done right:

  • user_subagents.rs:302 active_for(project_path) now consumes the project path (was an unused _project_path stub that only filtered enabled), and set_scope (:518) persists instead of discarding — both matching the MCP-side reference implementation.
  • project_scope.rs is the right shape: app-local agent-capabilities/subagent-scopes.json (atomic tmp+rename write), missing file defaults to all-global, corrupt file fails closed (returns an error instead of degrading to "everything visible") — that fail-closed choice matches the body's promise and is the safer default for a visibility control.
  • Keeping definitions in ~/.agents/subagents and not adding a project-level directory preserves ADR 0112's frozen decision; the scope living app-local (not in the shareable Markdown) is a reasonable split since scope lists carry machine-local absolute paths.
  • The A/B/no-project isolation tests (user_subagents.rs:844-851) cover the delegation-catalog filter, and the author's cross-project Unknown subagent runtime rejection check closes the "model forces the name" hole the issue's soft-isolation workaround couldn't.

Two non-blocking notes

  1. Policy: this is a feat during the fix/perf contribution window — the body already flags this honestly, so that call belongs to the maintainer; the implementation itself is ready for that decision to go either way.
  2. The scope file is keyed by subagent id; the rename-preserves-scope behavior is tested, which is the right place to have pinned it.

Once the stale assertion is updated this should be mergeable from a correctness standpoint.

zszz3 added 3 commits October 7, 2026 00:15
The settings list now labels each subagent with its activation scope.\nReplace the obsolete global-only expectation with both supported labels.
Resolve the ADR from the shared documentation directory so the Chinese
marketplace page no longer blocks documentation and workspace builds.
@muzimu217

Copy link
Copy Markdown
Contributor

Confirmed on our side: the new test(subagents): align settings assertions with project scope commit resolves the stale settings\.globalOnly assertion we reproduced from agent-capability-settings.test.mjs:42, and all five checks are green on the current head. From a correctness standpoint nothing is blocking; the feat/policy-window call stays with the maintainer as noted in the review.

Keep the upstream canonical ADR link when combining both dead-link fixes.
Preserve the project scope implementation while incorporating current main.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants