feat: DETA Agent Plugins 首发

一份产物、多宿主壳:同一目录既是 Codex 插件(.codex-plugin + .mcp.json + skills),
也是 dsh 组合包(dsh.bundle + cordis.patch.yml),能力本体以 MCP 服务提供、多宿主复用。

- Codex:插件市场 + deta 插件(默认市场与 API key 市场两份索引)
- dsh:组合包 manifest + 配置层(本地 stdio / 远程 streamable-http 两种形态)
- 技能:deta:aml-design(AML 唯一事实源、编译校验、围护结构统计、空间邻接)
- 文档:双壳架构对照、本地迭代(cachebuster)、已验证缺陷与上游限制
This commit is contained in:
ringo
2026-09-10 10:35:09 +08:00
commit b5877769de
10 changed files with 393 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
# DETA — Agent Plugins
DETA 领域能力在各类 Agent harness 上的分发仓:**一份产物,多个宿主壳**。
| 宿主 | 形态 | 安装 |
|------|------|------|
| Codex | 插件(`.codex-plugin/plugin.json` + `skills/` + `.mcp.json`);本仓同时是 Codex 插件市场 | `codex plugin marketplace add https://git.deta.city/deta/deta-agent-plugins.git` → `codex plugin add deta@deta` |
| dsh (deepseek-harness) | 组合包 bundle(`dsh.bundle.patch` + `cordis.patch.yml`) | `dsh plugin --profile <name> add ./plugins/deta` |
能力本体(AML 建筑模型读写、编译校验、围护结构统计、空间邻接查询)以 MCP 服务提供,
同一份后端与技能被所有宿主复用;新增宿主只需再加一层声明式壳。
> 命名约定:`ant` 为内部开发代号,不对外出现;对外产品名统一为 **DETA**。
> 插件、市场、MCP 服务、技能一律使用 deta 命名。
## 安装(Codex)
```bash
# 从 Git(分发用)
codex plugin marketplace add https://git.deta.city/deta/deta-agent-plugins.git
# 或本地路径(开发用)
codex plugin marketplace add ~/Dev/ant/deta-agent-plugins
codex plugin list
codex plugin add deta@deta
```
## 内容
| 插件 | 技能 | 能力 | 依赖 |
|------|------|------|------|
| `deta` | `deta:aml-design` | AML 建筑模型读写、编译与校验、围护结构统计、空间邻接查询 | node;领域服务已构建 |
## 前置条件
`deta` 插件的 MCP 后端是领域服务的无头 MCP 服务:
```bash
cd ~/Dev/ant/ant-copilot && npm run build
node dist/src/headless/mcp-server.js # 冒烟:应等待 stdin/stdout
```
环境变量:
| 变量 | 缺省 | 说明 |
|------|------|------|
| `DETA_SERVER_ROOT` | `~/Dev/ant/ant-copilot` | 领域服务仓库根目录(内部路径) |
| `ANT_HEADLESS_WORKSPACE` | `<cwd>/workspace` | AML 工作目录(`aml.xml` / `building.json` 落盘处,名称由底层服务决定) |
编译与校验类工具需要编译服务在线(`localhost:8000`);未在线时返回明确错误,
读写类工具可离线工作。
## 本地迭代
插件内容改动后 Codex 不会自动感知,按官方流程打 cachebuster 版本号再重装:
```bash
python3.11 ~/.codex/skills/.system/plugin-creator/scripts/update_plugin_cachebuster.py \
~/Dev/ant/deta-agent-plugins/plugins/deta
codex plugin add deta@deta
```
(版本号形如 `0.1.0+codex.20260910020424`;重装后需开新会话才能加载新技能。)
校验清单:
```bash
python3.11 ~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py \
~/Dev/ant/deta-agent-plugins/plugins/deta
codex plugin marketplace list
codex mcp list | grep deta
```
## 双壳架构(Codex + dsh 同一产物)
`plugins/deta/` 这一个目录同时是 Codex 插件根与 dsh 组合包根,共享核心、各带一层薄壳:
| 组成 | 文件 | Codex | dsh |
|------|------|-------|-----|
| 插件清单 | `.codex-plugin/plugin.json` | ✅ 使用 | — |
| MCP 声明 | `.mcp.json` | ✅ 使用(可放 Codex 私有键) | — |
| 组合包声明 | `package.json`(`dsh.bundle.patch`) | 忽略 | ✅ 使用 |
| 配置层 | `cordis.patch.yml` | 忽略 | ✅ 使用 |
| 领域技能 | `skills/aml-design/SKILL.md` | ✅ 共享 | ✅ 共享 |
| 本地启动器 | `bin/deta-mcp.sh` | ✅ | 由配置层的 `args` 直接指向服务入口 |
共享面(两端一致,零适配):
- **技能文件格式**:`<name>/SKILL.md` + frontmatter 必填 `name`/`description`,kebab-case。
Codex 与 dsh(`@deepseek-ai/dsh-skill-filesystem`)要求相同。
- **共享技能根**:两端都扫描 `~/.agents/skills/` 与 `<项目>/.agents/skills/`
(dsh 侧为 rank 500 / 200 的发现根,且显式支持 `<agentsHome>/skills`)。
把技能放这里即可双端生效,不需要安装插件。
- **MCP 工具命名**:两端同为 `mcp__<serverName>__<tool>`,我们统一 `serverName = deta`,
因此技能里写裸工具名(`read_source`、`apply_design`)在两端都能解析。
各自不同的部分(不共享):
- MCP 的声明位置不同(Codex 读 `.mcp.json`,dsh 读 `cordis.patch.yml` 的 mcp-client 行)。
- Codex 私有键(`default_tools_approval_mode`、`supports_parallel_tool_calls`)只写在
`.mcp.json`,不影响 dsh;dsh 无审批模式概念。
- 分发渠道不同:Codex 走 git 市场,dsh 走 npm / git / tarball,且 dsh 没有官方市场。
### dsh 侧安装与验证
```bash
# 安装进某个 profile(pnpm 转发)
dsh plugin --profile <name> add ~/Dev/ant/deta-agent-plugins/plugins/deta
# 公开发布形态(二选一)
npm publish # 用户:dsh plugin --profile <name> add deta-plugin
dsh plugin --profile <name> add github:<你>/<仓库> # 需作者提供 prepare + 用户 allowBuilds
# 只验证配置层是否合并正确(不启动、不需凭据)
cd ~/Dev/ant/deepseek-harness
node apps/cli/lib/bin.js --profile headless --dump-config \
--patch ~/Dev/ant/deta-agent-plugins/plugins/deta/cordis.patch.yml
# 输出中应出现 `# == .../plugins/deta/cordis.patch.yml` 与 deta-mcp 行
```
`cordis.patch.yml` 里远程端点那段已按公开形态写好(`streamable-http` + Bearer 头),
当前默认启用的是本地 stdio 行;服务端化完成后注释切换即可。
## 已知缺陷(实测,2026-09-10)
**上游:编码代理 × 模型服务 命名空间重复**
会话累积较多本插件工具调用后,代理会在请求里重复声明 MCP 命名空间,模型服务的
Responses 兼容层拒绝请求:
```
Duplicate namespace name 'deta'; Namespace names must be unique.
```
复现记录(同一插件、不同会话长度):
| 代理版本 | 会话规模 | 触发位置 |
|---------|---------|---------|
| 0.144.4 | 一步并发 2 次调用 | input[10]、input[18] |
| 0.144.4 | 串行 7–8 次调用 | input[37]、input[47] |
| 0.154.0 | 短会话 5 工具 | 未触发 |
| 0.154.0 | 长会话(≈15+ 工具) | input[260] |
已排除/无效的手段:`wire_api = "chat"`(该版本已移除,仅支持 responses)、
`features.non_prefixed_mcp_tool_names`(仅去掉命名空间前缀,重复依旧)、
`supports_parallel_tool_calls = false`(削弱并发触发面,长会话仍复现)。
**应对**:完成一个任务后另起会话;撞到该错误不要重试,重开会话即可(工作区文件保留)。
## 已修缺陷(实测)
| 现象 | 根因 | 修复 |
|------|------|------|
| 写类工具返回 `user cancelled MCP tool call` | MCP 工具默认需审批,非交互模式下无法弹窗 | `.mcp.json` 加 `default_tools_approval_mode: "approve"`(实测 `auto`/`writes` 都会被取消,只有 `approve` 放行) |
| 并发调用触发命名空间重复 | 代理并发序列化 | `.mcp.json` 加 `supports_parallel_tool_calls: false` |
## 目录结构
```
.agents/plugins/marketplace.json # Codex 默认市场(ChatGPT 登录用户)
.agents/plugins/api_marketplace.json # Codex API key 登录用户市场
plugins/deta/ # 同一目录 = Codex 插件根 = dsh 组合包根
├── .codex-plugin/plugin.json # Codex 插件清单
├── .mcp.json # Codex MCP 声明(含 Codex 私有键)
├── package.json # dsh 组合包声明(dsh.bundle.patch)
├── cordis.patch.yml # dsh 配置层(挂载 MCP 服务)
├── bin/deta-mcp.sh # 本地 MCP 启动器(开发用)
└── skills/aml-design/SKILL.md # 领域技能(两宿主共享)
```