插件最小形态

插件就是 TypeScript 模块,导出 apply(ctx);可选 name、inject、Config(Schemastery schema)。三形状:function(最常用)/ object {name, inject, apply} / class(extends Service,提供服务)。

import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
export const inject = ['tools']        // 框架等服务就绪后才调 apply
export function apply(ctx: Context) {
  ctx.tools.register(/* ... */)
}

通过 ctx 注册的一切都是 effect:卸载自动清理,天然支持 HMR(见 cordis)。官方用户文档三层:basic/(第一个插件、写 tool、配置、打包安装)→ framework/(生命周期、事件、服务注入)→ practice/(三角色能力设计、LLM adapter)。

写一个 Tool 插件

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'greet',
    description: 'Greet someone by name.',      // 模型可见
    parameters: { name: { type: 'string', required: true } },
    output: {
      schema: { type: 'string' },             // 规范值 JSON schema
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) { return `Hello, ${args.name}!` },
  }))
}

挂载运行:pnpm dsh web --patch ./scratch-plugin/cordis.yml。execute() 契约:参数自动校验(DSL 表达不了的约束自查);返回唯一规范 JSON 值(registry 快照/校验/冻结后交 render);抛错或非法返回 = isError——基础设施失败用 throw,“成功但不理想”(如进程非零退出)仍是成功规范值;遵守 exec.signal;异步通知用 exec.agent.inject();长任务经 ctx.jobs.start() 返回 { kind:'background', jobId }。策略挂点与 Code Mode 免费获得见 tool-system。UI 卡片 presentCall/presentResult 必须是纯函数(流式与 replay 都会跑,禁 I/O/时钟/随机)。

写一个 LLM Adapter

参考实现:packages/llm/llm-deepseek(直连 HTTP + SSE)与 llm-pi-ai(包库)。形态:

class MyAdapter extends LlmAdapter {
  async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> { /* 转格式→流式调用→转 StreamChunk */ }
}
export const inject = ['llm']
export function apply(ctx: Context, config: Config) {
  ctx.llm.registerAdapter(config.providers, new MyAdapter(config.apiKey))
}

密钥:cordis.yml 里 apiKey: !!js process.env.MY_API_KEY(secrets 是 cordis-native Config + env fallback,禁止临时读 key 文件)。协议义务(硬性):

  • usage 必须在 finish 之前发出;finish 之后不得再发任何东西。
  • Tool-call arguments 端到端保持 raw JSON string(增量走 argumentsDelta)。
  • block index 按首次出现顺序分配;每个 block-start 有配对 block-end。
  • 错误只有两条认可路径:从 stream() throw(LlmError 带稳定 code)或以 finish {kind:'error'|'aborted', failure} 结束。
  • 必须 honor options.signal;不支持的 GenerateOptions 字段抛 UNSUPPORTED 而非静默丢弃。
  • 每个 HTTP 请求合并 attributionHeaders();一次 adapter 调用 = 一次 provider 尝试(禁库内重试);provider 停顿有传输层看门狗(streamIdleTimeoutMs 默认 5 分钟);context overflow 统一 code CONTEXT_WINDOW_EXCEEDED;空完成是 EMPTY_RESPONSE 可重试错误。
  • 注册是 effect-based:一个 provider route 一个 adapter,重复注册抛错,多 route all-or-nothing;返回 handle 带原子 replace(providers)。

StreamChunk 词汇表(block-start → text/reasoning/tool-call-delta → block-end → usage → finish,封闭 union + assertNever)、TokenUsage 计数互斥规则、ctx.llm(LlmRuntime)完整 API(registerAdapter/listProviders/discoverModels/prepareCall/stream)与 llm/stream waterfall 见上游 docs/subsystems/llm-streaming.md。

Skills 系统

三角色:dsh-skill(ctx.skills)+ dsh-skill-filesystem(本地 provider)+ dsh-tool-skill(模型面)。

  • 发现优先级(rank 升序):project-dsh(<root>/.dsh/skills,100)→ project-agents(.agents/skills,200)→ custom(300)→ user-dsh(<dshHome>/skills,400)→ user-agents(500)→ bundled(600,默认禁用)。project root = 最近含 .git 的祖先。
  • 形态:kebab-case 名;目录 bundle(<name>/SKILL.md)或扁平 <name>.md;不支持递归。Chokidar 监听增删改。
  • 调用策略:frontmatter disable-model-invocation / user-invocable(缺省 true)。
  • 模型侧契约:首次观察到非空目录时在 agent/pre-step 注入目录(仅 name + description);变化经 agent.inject() 追加;模型调 skill({name}) 加载正文(返回 <skill_content>/<skill_resources>/<skill_instructions>);正文修改只影响后续调用。

MCP 与 ACP

  • MCP(dsh-mcp-client):MCP client 桥,一个 server 一个插件实例。工具名 mcp__<serverName>__<rawName>(超长追加 12-hex hash,纯函数)。transport:stdio(scrub 凭证/DSH_* env)与 streamable-http。断线指数退避重连;监听 tools/list_changed 重同步。限制:只桥 tools(Resources/Prompts 无消费者)。
  • ACP(dsh-acp,Agent Client Protocol):automation-only server,把 harness agent 暴露给程序化客户端(JSON-RPC stdio)。方法:initialize(仅 baseline 文本能力)/session/new/session/prompt/session/cancel/session/update(只输出 committed 文本)/session/request_permission。仅 fresh session(不支持 resume/fork)。反向用途:subagent-acp 作为 out-of-process subagent client。
  • Dynamic Plugin(extensions 子系统):模型可在线定义版本化 Cordis 包,Host/浏览器 Client 双半运行(ctx.dynamicCordisRunner,带审批与 vm sandbox),ctx.cordisInspect 查询运行时元数据。刻意不进出货树。

examples/ 清单

目录用途
acp-agent/ACP JSON-RPC 自动化 server;大量场景 overlay(code-mode/image/pty/retry/session-query/subagent 各形态);pnpm run demo:acp
headless-agent/非交互 headless 编码 agent(DeepSeek + bash/fs + subagent + Ralph + todo);另有 E2B 沙箱 POC overlay
jsonrpc-agent/Python SDK bundled runtime 驱动的无人值守 agent(含 minimal.py)
mcp-memory/三个默认关闭的第三方记忆 MCP server 参考(Memorix/MCP Reference Memory/Engram)
web-cordis/自指演示:agent 在线 mount/unmount 自己进程内的插件树
web-schedule/Session-local 持久提醒 Web overlay

发布:bundle 与 profile 两概念

  • bundle:npm 包,package.json 声明 dsh.bundle.patch 指向 cordis.patch.yml(YAML patch 数组,insert 行引用包名)。
  • profile:$DSH_HOME/profiles/<name> 可运行组合,由 dsh plugin 命令维护。
  • 安装:dsh plugin --profile demo add ./pkg | github:you/pkg | ./pkg.tgz(转发 pnpm 并追加 bundle 进 profile);git 安装拉源码,作者须提供自包含 prepare 脚本(pnpm ≥10 需用户 allowBuilds 放行,建议 pin commit)。
  • 层叠顺序(后层按行覆盖,整行替换不深合并):profile bundles(dsh-base 最先)→ profile patch → $DSH_HOME/cordis.patch.yml → --patch overlays。dsh --profile demo --dump-config 查看合成树。
  • 发现性:给插件仓库加 GitHub topic dsh-plugin。
  • 仓库内新包(贡献者):packages/<group>/<pkg>,package.json 强约束(与根同 version、cordis 进 peer+dev、README 必含 Model Experience + Known Limitations 章节且有脚本校验),验证链 install → doc-sync → typecheck/lint → build → hygiene。

相关页面