插件最小形态
插件就是 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 统一 codeCONTEXT_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→--patchoverlays。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。
相关页面
- cordis — 框架机制;tool-system — 执行管线
- engineering — 仓库内开发的 gate 与纪律