DSH / Atlas
2026-09-18implementedarchitecture

Declarative Agent presets and retained revisions

声明式 Agent preset 与保留代际

Preset directories duplicate Cordis configuration ownership. Separate discovery, metadata, copying and editing APIs cannot express the same composition through an ordinary profile patch. Disposing a definition during a save must also preserve plugins still used by running Agents.

English

Problem

Preset directories duplicate Cordis configuration ownership. Separate discovery, metadata, copying and editing APIs cannot express the same composition through an ordinary profile patch. Disposing a definition during a save must also preserve plugins still used by running Agents.

Decision

dsh-agent-preset-registry owns selection and runtime revisions; dsh-agent-preset declares an identity, display metadata and child plugin list in ordinary Cordis YAML. Definitions activate eagerly. Activation failures remain in the roster and reject new bindings without preventing the application from starting.

The registry owns each revision's scope and Loader tree. Agents link their own scopes to the selected revision, and children inherit their parent's exact revision. Updates retire the former revision; Agents and temporary cold readers retain references until disposal. The final release disposes a retired tree. Host registries and the Agent loop remain shared; preset service providers and consumers require an isolated realm.

The Web editor and agent_preset tool accept only child plugin YAML. Saving writes the active profile's user patch, preserving display metadata and unrelated configuration. Revision checks and profile locking prevent overwriting concurrent saves; validation rejects a higher-priority override that would defeat the edit. Persistence and activation outcomes are reported separately. Tool writes require approval or full access because configuration executes in the Host.

Session data continues to record the preset identity. Restart resolves that identity against current configuration and rejects a missing definition; reusing a blank Session for a new conversation does not resolve it (decision). Old executable revisions are process-local, not serialized. New sessions without an explicit preset resolve selectedDefault; Client choice filtering and default correction follow the preset UI policy.

Alternatives considered

Keep directory presets alongside declarations. Two writable sources would compete for an identity and require precedence, migration and editing rules. Ordinary profile configuration supplies the required persistence and layering, so presets have no separate paths.

Let each declaring plugin own its live child tree. Loader disposal during an edit would revoke tools from running Agents. Registry ownership gives retained revisions an explicit lifetime independent of the declaration.

Load only on first selection. Lazy activation delays diagnostics and adds pending-first-use state. Eager activation is acceptable for these compositions and exposes failures before selection.

Reject application startup for a broken preset. A failed optional capability set should remain repairable in Web. Healthy definitions and Host services remain available.

Consequences

One process can run Agents with different capabilities while sharing each selected revision. Retired revisions remain in memory while referenced. Presets do not provide a security sandbox, and a user override replaces the entire child list rather than merging future builtin changes.

The former directory and per-session-mount decision is preserved as historical context. Host service ownership remains documented in the Host-plane note.

Testing

Registry tests cover retained parent and child scopes, cold-reader leases, selection logging and failed activation. Editor tests cross real profile patches, check conflict rejection and preserve nested expressions. The shipped Web composition test checks activation, scoped tools, Creator skills and profile edits against built packages.

中文

Problem

Preset 目录重复承担 Cordis 配置的所有权。独立的发现、元数据、复制和编辑 API 无法通过普通 profile 补丁表达相同组装。保存时释放定义,也必须保留运行中 Agent 仍在使用的插件。

Decision

dsh-agent-preset-registry 负责选择与运行时代际;dsh-agent-preset 在普通 Cordis YAML 中声明标识、显示元数据和子插件列表。定义提前激活。激活失败保留在列表中,并拒绝新绑定,但不阻止应用启动。

注册表拥有各代际的 scope 与 Loader 树。Agent 将自身 scope 链接到选定代际,子 Agent 继承父方的确切代际。更新使旧代际退役;Agent 和临时历史读取者保留引用,直至释放。最后一个引用释放后,退役树被销毁。Host 注册表和 Agent loop 保持共享;preset 的服务提供方与消费者需要处于隔离 realm 中。

Web 编辑器与 agent_preset 工具只接受子插件 YAML。保存写入当前 profile 的用户补丁,保留显示元数据和无关配置。版本检查和 profile 锁防止覆盖并发保存;验证拒绝会使编辑失效的更高优先级覆盖。持久化与激活结果分别报告。配置在 Host 中执行,因此工具写入需要批准或完全访问权限。

会话数据继续记录 preset 标识。重启时根据当前配置解析该标识,定义缺失则拒绝恢复;为新对话复用空白会话时不解析该标识(决策)。旧的可执行代际仅保留在进程内,不会序列化。未显式指定 preset 的新会话解析 selectedDefault;客户端选项过滤和默认值修正遵循预设 UI 策略。

Alternatives considered

同时保留目录 preset 与声明。 两个可写来源会争用标识,需要额外的优先级、迁移和编辑规则。普通 profile 配置已提供所需持久化和分层,因此 preset 不再有独立路径。

让声明插件拥有运行中的子树。 编辑时 Loader 释放插件会撤销运行中 Agent 的工具。注册表所有权使保留代际具有独立于声明的明确生命周期。

首次选择时才加载。 延迟激活推迟诊断,并增加首次使用的等待状态。提前激活适用于这些组装,且可在选择前暴露失败。

Preset 损坏就拒绝应用启动。 可选能力集失败后应仍能在 Web 中修复。健康定义和 Host 服务保持可用。

Consequences

同一进程可以运行能力不同的 Agent,同时共享各选定代际。退役代际在仍有引用时占用内存。Preset 不提供安全沙箱,用户覆盖会替换整个子插件列表,不会合并后续内置变更。

原有目录与逐会话挂载决策保留为历史背景。Host 服务所有权继续由 Host 平面说明记录。

Testing

注册表测试覆盖父子 scope 保留、历史读取租约、选择日志及激活失败。编辑器测试使用真实 profile 补丁,检查冲突拒绝并保留嵌套表达式。随附 Web 组装测试通过构建产物验证激活、作用域工具、Creator 技能和 profile 编辑。