让智能体在测试中可逆地改写自身脚手架并筛选更优方案
36.4/100
综合分
2
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add tang19-chao/dsh-plugin-evo-harness该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:需留意
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
README
由 DeepSeek 最新模型翻译生成dsh-plugin-evo-harness
DeepSeek Harness(Cordis)插件,用于智能体脚手架在测试时的自我进化。
模型权重保持冻结,改变的是模型外围的脚手架——八个可编辑面(系统提示词、护栏、记忆、工具指引、技能、脚本、子代理、插件)以可逆的 Cordis 能力接缝挂载(ctx.fork() + 幂等 disposer)。候选方案沿两条不对称轨道提出(记忆引导的领域轨道与无记忆的不变轨道),在隔离分支中执行,由于不存在 ground-truth 验证器,只能匿名地按行为对比,再组合成胜出的脚手架 H,并蒸馏为受治理的 CanonicalLesson 记录。Dream-RSI 提供在线元控制器(plan_grid 加上三路 exploit / explore-domain / explore-invariant / recover 组合)以及零执行的离线 dreamer,后者重放历史发现树来改进搜索策略,无需运行模型或沙箱。Universal MCP 记忆桥可对接任意 MCP 记忆后端(图、向量、时序、markdown 笔记,或灵枢 md_cg 白盒),并附加客户端侧治理 polyfill:CCG 六要素校验、虚拟命名空间隔离与负证据防火墙。完整设计(含逐模块职责与端到端时序)见 ARCHITECTURE.md。
展开完整文档(README 剩余 1 节)
dsh-plugin-evo-harness
DeepSeek Harness(Cordis)插件,用于智能体脚手架在测试时的自我进化。
模型权重保持冻结,改变的是模型外围的脚手架——八个可编辑面(系统提示词、护栏、记忆、工具指引、技能、脚本、子代理、插件)以可逆的 Cordis 能力接缝挂载(ctx.fork() + 幂等 disposer)。候选方案沿两条不对称轨道提出(记忆引导的领域轨道与无记忆的不变轨道),在隔离分支中执行,由于不存在 ground-truth 验证器,只能匿名地按行为对比,再组合成胜出的脚手架 H,并蒸馏为受治理的 CanonicalLesson 记录。Dream-RSI 提供在线元控制器(plan_grid 加上三路 exploit / explore-domain / explore-invariant / recover 组合)以及零执行的离线 dreamer,后者重放历史发现树来改进搜索策略,无需运行模型或沙箱。Universal MCP 记忆桥可对接任意 MCP 记忆后端(图、向量、时序、markdown 笔记,或灵枢 md_cg 白盒),并附加客户端侧治理 polyfill:CCG 六要素校验、虚拟命名空间隔离与负证据防火墙。完整设计(含逐模块职责与端到端时序)见 ARCHITECTURE.md。
目录
- 环境要求
- 安装与验证
- 快速开始配置
- 配置参考
- 工作原理
- 项目结构
- 测试
- 限制与状态
- 设计文档
环境要求
| 要求 | 值 | 来源 |
| Node.js | >=20.19.0 | package.json 中的 engines.node |
| pnpm | 11.7.0 | package.json 中的 packageManager(pnpm@11.7.0) |
| 运行时依赖 | @deepseek-ai/schemastery(配置 schema) | 在 package.json 的 dependencies 中声明,并在 src/index.ts 模块加载时静态导入;devDependencies:TypeScript、Vitest、@types/node、esbuild |
| Cordis 宿主 | 由宿主提供 | 本包从不导入 cordis;所有接缝都是结构性的(src/index.ts) |
| MCP 记忆服务器 | 由宿主提供 | 桥接层消费可注入的 MCP 客户端,从不依赖具体服务器(src/memory-bridge/spi.ts) |
其余一切都在挂载时注入:LLM 边界(IModelAdapter)、已挂载的 MCP 客户端、探针分支内使用的宿主任务运行器(BranchExecutor),以及 Cordis 能力适配器本身。当某次运行确实需要这些、却没有提供时,插件会直接报错,而不是假装能用——no model adapter was injected 以及 no branch executor was injected; the host must supply options.runBranch 会作为确定性失败返回。
安装与验证
安装到 DeepSeek Harness 配置档(常规路径)
包内附带 dsh.bundle.patch 层(cordis.patch.yml)和 Node 可加载的 ESM 入口(lib/index.js),因此 dsh plugin add 一步就能完成安装和挂载。Desktop 的配置档留给 Electron 应用使用,但它有自己的命令行来管理:
from a checkout of this repository (absolute path required)
dsh plugin --profile desktop add "link:<absolute-path-to-this-repo>"
dsh plugin 会把命令转发给配置档内的 pnpm,然后把每个声明了 dsh.bundle 的新依赖整理进 dsh.profile.bundles。下次启动后插件即生效。卸载用 dsh plugin --profile desktop remove dsh-plugin-evo-harness。
确认组装后的树已纳入该入口:
dsh --profile <name> --dump-config # look for id: evo-harness
从源码构建并验证
克隆仓库,安装锁定版本的工具链:
git clone <repository-url> dsh-plugin-evo-harness
cd dsh-plugin-evo-harness
corepack enable # optional: activates the pinned pnpm 11.7.0
pnpm install --frozen-lockfile
pnpm run build # bundles src/index.ts to lib/index.js (esbuild)
lib/ 是构建产物,已被 git 忽略:在任何地方安装这个包之前,先跑 pnpm run build,因为加载器会把 main/exports 解析到 lib/index.js。
下面的脚本逐字引自 package.json 的 scripts;构建项目不需要别的东西,因为 TypeScript 只做类型检查(noEmit),Vitest 在运行时转译。
| 命令 | 底层脚本 | 作用 |
| pnpm run typecheck | tsc --noEmit | 对 src/ 和 tests/ 做完整静态类型检查 |
| pnpm run test | vitest run | 运行全部单元测试和端到端测试套件 |
| pnpm run test:unit | vitest run tests/unit | 只跑单元测试套件 |
| pnpm run test:e2e | vitest run tests/e2e | 只跑端到端测试套件 |
| pnpm run check:docs | node scripts/verify-readme-counts.mjs | 机械校验 README 里的测试计数与测试结果、仓库卫生是否一致;遇到失败或挂起的测试就拒绝报告,并对照真实默认值校验配置参考(每个叶子一行,见配置参考) |
| pnpm run check:encoding | node scripts/eval/check-encoding-policy.mjs | 每个被跟踪的 blob 必须是 LF 文本,或声明为 -text 例外 |
| pnpm run check:build-smoke | node scripts/eval/smoke-build.mjs | 构建 bundle 并以 ESM 导入,断言公开接口 |
| pnpm run check:negative-result | node scripts/eval/negative-result-diag.mjs --assert | 记录的历史负结果(−0.250)一旦漂移就失败 |
| pnpm run guarded-regression | node scripts/eval/guarded-regression.mjs --json | ADR 0002 门禁 #7:在合成 fixture 上跑 release-surface、隔离和可信来源探针 |
| pnpm run check:mutation | node scripts/eval/mutation-gate.mjs --run | ADR 0005 D5:在一次性副本里重新引入四个固定缺陷,要求固定测试的名称变红——存活的变异体即判定门禁失败 |
| pnpm run check:metering | node scripts/eval/metering-coverage.mjs | 每个生产环境的 .complete(...) / .planNext(...) 调用都必须走 MeteredModelAdapter,或属于允许列表中的委托;允许列表按文件固定了精确数量,所以允许列表文件里出现第二个调用同样失败 |
| pnpm run check:orphans | node scripts/eval/check-orphan-exports.mjs | src/ 里每个导出的符号(函数、类、const、interface、类型别名、enum)都要在 src/ 或 tests/ 里有读取方;允许列表双向比对,修好的孤儿会留下过期行并导致失败。故意不检查模块私有的未调用函数——那需要调用图,不是导出扫描 |
| pnpm run check:import-coverage | node scripts/eval/check-test-import-coverage.mjs | src/ 里每个模块都必须被测试导入,直接导入或经 barrel* 再导出都算。src→src 的内部导入不算,所以只能通过插件入口到达的模块仍然失败 |
| pnpm run verify | pnpm run typecheck && pnpm run test | 完整门禁:先 typecheck,再跑全部测试套件 |
当前干净的检出上,pnpm run test 报告 200 个测试文件、3290 个通过测试(分类明细见 Testing)。本包为 private,不发布到任何 registry,因此没有发布步骤。
快速开始配置
宿主把 cordis.yml 的插件段传给插件,由 parseEvoHarnessConfig() 校验(src/config.ts)。下面的示例在插件旁边挂载一个 MCP 记忆服务器;示例里的每个值都是内置默认值,每个键都是解析器接受的键。
plugins:
1. Mount any standard MCP memory client (Mem0, official Knowledge Graph,
Zep/Graphiti, Basic-Memory, dsh-memory/灵枢, ...). The bridge auto-discovers the driver from tools/list. "@deepseek-harness/plugin-mcp": servers: mem0: command: "npx"
args: ["-y", "@mem0/mcp-server"]
env:
MEM0_API_KEY: "${MEM0_API_KEY}"
2. Mount this plugin. Everything below is a default value.
"dsh-plugin-evo-harness":
schemaVersion: 1 # default
triggerMode: "auto_fallback" # default: 'auto_fallback' | 'always' | 'slash_command'
default: all eight surfaces, in mounting order
enabledSurfaces:
- system_prompt
- guardrails
- memory
- tool_guidance
- skills
- scripts
- subagents
- plugins
memoryBridge:
mcpServerTarget: "auto" # default: sniff every mounted MCP server ('auto' or a server id)
enableGovernancePolyfill: true # default: CCG gate + namespace isolation + negative firewall
customMapping: # default: enabled=false, names only matter when you enable it
enabled: false
recallToolName: "my_custom_search"
commitToolName: "my_custom_upsert"
dreamRsi:
maxOnlineRolloutBudget: 8 # default: hard upper bound on candidate rollouts
enableAsymmetricGuidance: true # default: invariant branches stay guidance-free
offlineDreamTriggerEveryNTasks: 10 # default: completed tasks between offline dream replays
candidatePoliciesCount: 6 # default: candidate meta-policies per dream
Second-level settings page. Every leaf is .volatile(), so the DSH settings
UI can write it and the loader commits it without a restart.
modelRoute:
provider: "qodercn" # default: the verified DSH default route
model: "dfmodel"
reasoningEffort: "max" # high | max | low
可挂载的协作者在代码里注入,不在 cordis.yml 里。插件导出标准 Cordis 形状(默认的 { name, apply } 加具名 apply),宿主会替你调用;下面这段代码展示四个可选注入,加上它们,空跑就变成真实运行(src/index.ts,EvoHarnessPluginOptions):
import { apply } from 'dsh-plugin-evo-harness'; // default export is { name, inject, Config, apply }
const plugin = apply(ctx, {
config: myConfigSection, // the "dsh-plugin-evo-harness" section above (or ctx.config)
model, // IModelAdapter used by propose / compose / reflect
clients, // mounted MCP clients; omit and pass listClients for late mounts
runBranch // BranchExecutor: the host task runner executed inside a branch
});
const result = await plugin.run({
sessionId,
task: plugin.makeTask({ prompt: 'migrate the schema and report JSON' }),
trigger: 'always'
});
console.log(result.outcome, result.probesRun, result.lessonsCommitted);
await plugin.dispose();
插件通过 ctx.commands.register 注册 /evo 斜杠命令,订阅下面这些已验证的 DSH 事件,并把挂载后的句柄暴露为 evoHarness 服务。如果宿主上下文没有提供命令注册器或事件订阅器,可以用等价的入口 plugin.runFromCommand(args, context) 和 plugin.handleFallbackEvent(payload) 作为受支持的兜底方案,原因会记录在 plugin.diagnostics 里。
触发契约(已对照随包运行时验证)
下面的事件名和载荷形状是从 resources/app.asar 里读出来的,不是猜的。
| TurnEndReason.kind | 对本插件的含义 |
| completed | 正常结束;仅在 triggerMode: always 下触发 |
| error | 失败(reason.error 携带 {message, code}) |
| aborted / blocked / max-tokens / interrupted / forked | 观察到但忽略 |
| DSH 事件 | 载荷 | 用途 |
| session/event | (session, event) | event.type: 'tool/result' 配合 event.data.message.isError;event.type: 'turn/end' 配合 event.data.reason.kind |
| agent/error | {agent, turn, step, error} | 一律视为失败 |
| agent/status | {status: 'idle' \| 'running'} | idle → 通过 agent.runMaintenance 触发可选的离线 dream |
agent/status 只携带 {status}(循环发出的是 { status });智能体来自融合后的 dispatch 载荷,或来自 ctx.agents.list()。agent.runMaintenance(job) 在智能体非空闲时会抛错,所以每次调用都包在 try/catch 里,竞争失败会被记录下来,而不是抛到外面。
三种模式确实各不相同:
| triggerMode | 监听的事件 |
| slash_command | 无 —— /evo 是唯一入口 |
| auto_fallback | 仅失败事件(tool/result 错误、turn/end 错误、agent/error) |
| always | 失败事件 加上 turn/end 的 completed |
迁移说明。 早期版本文档把 task:failed 和 tool:error 写成 auto_fallback 的事件。这两个名字在 DSH 里根本不存在,所以钩子永远不会触发。它们不再是默认值;非 DSH 的传输层如果会发出这两个事件,可以通过 autoFallbackEvents 显式启用,此时插件会警告说这些名字未经核实。
DSH 派发 session/event 时用的是受控的 fire-and-forget emit,所以监听器无法返回某次运行的结果。plugin.settle() 是确定性的汇合点:它会等待每个由触发发起的运行,并返回结果。拆卸时也会等待它,因此由最后一个事件启动的运行不会中途被中止。
配置参考
默认值是 src/config.ts 中 DEFAULT_EVO_HARNESS_CONFIG 的冻结值(外加 MODEL_ROUTE_DEFAULTS 里的 modelRoute 字段,这些字段不在该对象内);下面这一节与 ARCHITECTURE.md 第 6.2 节一致。下表每个默认叶子一行:门禁 pnpm run check:docs 会在运行时遍历真实默认值(75 个 DEFAULT_EVO_HARNESS_CONFIG 叶子 + 3 个 modelRoute 字段 = 78;数组算一个叶子,后缀 [],与实现路径完全一致),一旦缺行、行过期或 Default 列漂移就失败,所以这张表不会悄悄腐烂。
校验很严格:未知键、类型错误、数值越界、重复 surface、未归一化的代理权重,都会被拒绝,并抛出 ConfigValidationError,其中带上所有问题(unknown_key、invalid_type、out_of_range、invalid_enum、duplicate_value、weights_not_normalized 等),所以 cordis.yml 里一个拼写错误会快速失败,而不是悄悄关掉某项安全功能。
| 选项 | 默认值 | 含义 |
| enabled | true | 是否挂载插件 |
| enabledSurfaces[] | ["system_prompt","guardrails","memory","tool_guidance","skills","scripts","subagents","plugins"] | 可打补丁的挂载面,按挂载顺序排列 |
| execution.applyWinningPatch | false | 探测后永久挂载胜出补丁;只能与 execution.mode: guarded-active 一起使用(其他模式下 fail-closed 拒绝) |
| execution.mode | "shadow" | 声明的执行模式:shadow(记录建议,零副作用)、baseline、guarded-active(启用补丁层受证据门控的通道)或 off |
| logging.includeTrajectorySummaries | false | 为 true 时,运行结果日志行还会带上本次运行的轨迹摘要(lifecycle / stopReason / referenceStatus);false 只保留探测/教训计数 |
| logging.level | "info" | 插件日志阈值:debug / info / warn / error / silent(silent 丢弃所有行,error 只保留错误) |
| memoryBridge.customMapping.commitToolName | "my_custom_upsert" | customMapping.enabled 为 true 时使用的提交工具名 |
| memoryBridge.customMapping.enabled | false | 为未知后端使用显式工具名映射 |
| memoryBridge.customMapping.recallToolName | "my_custom_search" | customMapping.enabled 为 true 时使用的召回工具名 |
| memoryBridge.driverHint | "auto" | 强制指定驱动:graph_entity、vector_fact、temporal_graph、markdown_note、lingshu_mdcg、custom_mapped |
| memoryBridge.enableGovernancePolyfill | true | 客户端 CCG 校验、虚拟命名空间隔离、负向防火墙 |
| memoryBridge.enableNegativeFirewall | true | 把负向教训挡在推荐通道之外 |
| memoryBridge.mcpServerTarget | "auto" | auto 会嗅探每个已挂载的 MCP 服务器,也可填具体服务器 id,如 mem0 |
| memoryBridge.namespacePrefix | "harness2" | 确定性作用域命名空间的前缀 |
| memoryBridge.promoteOnComposeSuccess | false | 组合成功后把胜出教训提升出分支作用域;自 P6.2 C1 起需显式开启,因为提升路径会写入真实的全局命名空间 |
| memoryBridge.recallLimit | 6 | 每个任务最多召回的教训数 |
| memoryBridge.requestTimeoutMs | 10000 | MCP 请求超时,单位 ms |
| memoryBridge.requireEvidence | true | 拒绝没有探测对比证据的教训 |
| modelRoute.model | "dfmodel" | 二级设置页的模型 id(仅宿主分组;见下文) |
| modelRoute.provider | "qodercn" | 二级设置页的服务商路由(仅宿主分组;见下文) |
| modelRoute.reasoningEffort | "max" | 二级设置页上的 high \| max \| low(仅宿主分组;见下文) |
| probe.maxConcurrentProbes | 4 | 并发隔离探测数(1-16) |
| probe.probeTimeoutMs | 120000 | 单个探测的超时,单位 ms(1000-600000) |
| schemaVersion | 1 | 配置 schema 版本;破坏性变更需要新一轮契约 |
| triggerMode | "auto_fallback" | auto_fallback(仅失败事件)、always(失败事件 + turn/end completed)或 slash_command(仅 /evo) |
| dreamRsi.candidatePoliciesCount | 6 | 每次 dream 生成的候选元策略数量 |
| dreamRsi.earlyStopThreshold | 0.8 | 当前生效策略使用的提前停止阈值 |
| dreamRsi.enableAsymmetricGuidance | true | 领域槽位可读记忆;不变槽位不接收引导 |
| dreamRsi.holdoutTreeCount | 0 | PR-4B 显式留出开关:从池中划出用于验证的树;0 = 不留出(validatedOnHoldout 保持 undefined);必须小于 maxTreePoolSize |
| dreamRsi.maxDepth | 3 | plan_grid 的树深度硬上限 |
| dreamRsi.maxOnlineRolloutBudget | 8 | 每个任务的候选 rollout 硬上限;plan_grid 只能调低 |
| dreamRsi.maxRecoverySlots | 1 | 每批允许的恢复槽位(最多一个) |
| dreamRsi.maxTreePoolSize | 200 | 保留用于回放的历史发现树数量 |
| dreamRsi.maxWidth | 4 | plan_grid 的树宽度硬上限 |
| dreamRsi.minMemoryConfidenceForSkip | 0.75 | 记忆置信度达到该值时,可跳过探测 |
| dreamRsi.offlineDreamTriggerEveryNTasks | 10 | 两次离线 dream 回放之间完成的任务数 |
| dreamRsi.rhoPreferences[] | [0,0.25,0.5,0.75,1] | 用于 Pareto 回放的预算偏好,严格递增 |
| dreamRsi.surrogateWeights.adoption | 0.3 | 代理奖励权重(采纳率);四个权重之和必须为 1 |
| dreamRsi.surrogateWeights.efficiency | 0.2 | 代理奖励权重(步数效率);四个权重之和必须为 1 |
| dreamRsi.surrogateWeights.selection | 0.4 | 代理奖励权重(选择);四个权重之和必须为 1 |
| dreamRsi.surrogateWeights.toolErrorPenalty | 0.1 | 代理奖励权重(工具错误惩罚);四个权重之和必须为 1 |
| jitrl.augmentFromMemory | true | 用仅来自记忆的动作扩充候选集 |
| jitrl.beta | 1 | KL 温度,乘以归一化优势 |
| jitrl.candidateCount | 3 | 向提议方请求的 K 个候选(提议层) |
| jitrl.dream.candidateJitBetas[] | [0.5,1,2] | 生成策略时抽取的候选 beta 网格;不能为空,每项必须有限且 >= 0 |
| jitrl.dream.candidateJitLambdas[] | [0.02,0.05,0.1] | 仅作兼容:接受、校验并上报,但自 P6 PR5 起不再扫描(见 src/dream-rsi/offline-dreamer.ts 中的 JIT_IGNORED_DIMENSIONS);候选只从 beta/k/threshold 网格生成 |
| jitrl.dream.driftRho | 0.7 | 热切换后旧策略经验的降权系数,取值 [0, 1] |
| jitrl.dream.hyperparamPerturbation | true | 生成候选策略时扰动 JitRL 超参数 |
| jitrl.enabled | true | JitRL 双循环总开关 |
| jitrl.exploration.alpha | 5 | 探索时在状态价值之上叠加的乐观奖励 |
| jitrl.exploration.lambda | 0.05 | 对没有支持的动作做乐观探索的概率 |
| jitrl.gamma | 0.5 | 沿步进/树路径的回报折扣 |
| jitrl.hostAdvisor.adviseThreshold | -0.5 | 邻居平均回报低于该值时,顾问建议换一个方案 |
| jitrl.hostAdvisor.enabled | false | L3 宿主工具调用顾问开关(实验性) |
| jitrl.hostAdvisor.gateThreshold | -0.8 | 邻居平均回报低于该值时,gate 模式请求用户确认(绝不自动拒绝) |
| jitrl.hostAdvisor.minSupport | 5 | 顾问介入前所需的最小邻居支持数 |
| jitrl.hostAdvisor.mode | "advisory" | advisory 给决策加注释;gate 请求用户确认,绝不自动拒绝 |
| jitrl.k | 10 | 最近邻数量(论文给出的稳健区间为 8-14) |
| jitrl.levels[] | ["meta","proposal"] | 启用的 JitRL 层;host_tool 为实验性 |
| jitrl.logitSource | "auto" | 候选 logit 来源:auto \| verbalized \| token |
| jitrl.minSupportForStrongPrior | 3 | 先验占据主导前所需的最小邻居支持数 |
| jitrl.privacy.redactSecrets | true | 从持久化状态和摘要中隐去密钥 |
| jitrl.privacy.storeRawText | false | 在抽象状态之外一并存储原始任务/观察文本 |
| jitrl.reward.clip[] | [-3,3] | 对融合奖励施加的 [min, max] 裁剪;clip[0] 必须严格小于 clip[1] |
| jitrl.reward.llmEvaluator | true | 启用 LLM 步进评判器(用途 evaluate_steps) |
| jitrl.reward.weights.llm | 0.4 | 步进奖励权重(LLM 评判);五项权重之和必须为 1 |
| jitrl.reward.weights.surrogate | 0.3 | 步进奖励权重(代理分数);五项权重之和必须为 1 |
| jitrl.reward.weights.tool | 0.2 | 步进奖励权重(工具信号);五项权重之和必须为 1 |
| jitrl.reward.weights.turn | 0.1 | 步进奖励权重(轮次信号);五项权重之和必须为 1 |
| jitrl.reward.weights.user | 0 | 步进奖励权重(用户信号);五项权重之和必须为 1 |
| jitrl.selection | "argmax" | 候选选择规则:argmax \| sample |
| jitrl.similarityThreshold | 0.3 | 判定为邻居所需的最小 Jaccard 相似度 |
| jitrl.store.driver | "jsonl" | 存储驱动;Phase 1 只提供仅追加的 JSONL 存储 |
| jitrl.store.halfLifeDays | 30 | 压缩时使用的半衰期天数;0 关闭半衰期衰减 |
| jitrl.store.maxPerBucket | 200 | 压缩时对每个桶强制执行的记录上限 |
| jitrl.store.mirrorToMemoryBridge | false | 同时把追加的经验记录镜像到宿主记忆桥 |
| jitrl.surfaceActions | false | L1 动作空间开关:每个 slotKind × focusSurface 生成一个候选(最多 4 × 8 = 32 个),而不是每个 slotKind 只生成一个 |
| jitrl.unseenFallback | "baseline" | 未见动作的取值:baseline(Q = V)或 zero(论文) |
modelRoute 的适用范围:provider / model / reasoningEffort 属于二级设置页 / cordis.patch.yml 的 modelRoute 分组——这是宿主特有的分组,splitModelRoute 会在冻结的 EvoHarnessConfig 校验运行之前,把它从原始插件配置段中提取出来(src/host-triggers.ts、 src/dsh-bridge/model-config.ts)。它们不是 EvoHarnessConfig 的根键:在本插件配置段的顶层直接写 modelRoute:,会被宿主胶水层消费;而写进程序化的 EvoHarnessConfig 段里,则会以 unknown_key 被拒绝。每个字段都是 .volatile(),所以设置界面可以改写它,无需重启。
没有默认值的可选键可以整个省略:memoryBridge.customMapping.pruneToolName、 jitrl.budget,以及 JitRL dream 扫描的两个轴 jitrl.dream.candidateJitKs(正整数)和
jitrl.dream.candidateJitSimilarityThresholds(取值在 [0, 1] 内)——这些只在宿主真正写入时才校验;
缺省表示「未配置」,绝不是「无效」。这两个扫描轴故意不出现在冻结默认值里,好让上面的叶子表保持冻结时的大小;省略时,离线 dreamer 会套用它内置的网格 [5,10,20] 和 [0.2,0.3,0.5] (src/dream-rsi/offline-dreamer.ts 中的 DEFAULT_JIT_KS / DEFAULT_JIT_SIMILARITY_THRESHOLDS),也就是说,解析出的候选网格与 INT-3 之前的行为逐字节一致。(内部 API 接受的自由格式 metadata 包同样没有默认值,但它们不是配置叶子。)
工作原理
一次演化运行会走完 src/orchestrator.ts 中实现的生命周期:
1. initialize - 通过 MCP 自动发现绑定记忆后端。
2. recall - 对到来的任务做受管控的召回;正面经验是建议,负面经验是反模式警告,而匹配任务上下文的条款会被防火墙扣下。
3. plan_grid - 当前策略 pi_t 根据任务复杂度和记忆置信度推导出宽度、深度、预算和停止条件(高置信度可以收缩到零次探测)。
4. reference_probe - 一次不做脚手架改动的基线运行,用作对照锚点。
5. select_batch - 三路组合:利用(加深最佳节点)、探索领域(记忆引导)和探索不变量(无引导、不用外部记忆),外加至多一个由失败分类驱动的恢复槽位。
6. propose - Harness2 双轨提案器为该槽位渲染提示词,并把模型的 JSON 校验成 EightSurfacePatch。
7. probe - 补丁挂载到隔离的 Cordis 分支,由宿主 runner 执行;轨迹收集器记录事件溯源步骤、工具错误和失败信号。
8. classify - 四路失败分类法(hard_unrecoverable、repairable_implementation、 weak_underexplored、repeatedly_unpromising)决定下一步动作。
9. score - 无验证器的代理分数 s_v in [0, 1],由选择、采纳率、步骤效率和工具错误率得出。
10. compose - 匿名组合器只对比候选的行为,挑出有证据支持的胜者并合并 H。
11. reflect - 反思器为成功和失败的候选输出完整的 CanonicalLesson 对象(全部六个 CCG 元素,包括克制条款)。
12. commit - 课程先通过客户端治理门,再到达 MCP 后端。
13. apply_patch - 胜出的脚手架通过幂等 disposer 永久挂载。
14. offline_dream - 每完成 N 个任务,历史树以零模型调用和零沙箱调用重放,元策略只在严格改进时热替换。
15. finalize - 向宿主返回 EvoHarnessRunResult 摘要。
代码分为四棵模块树,外加集成器持有的入口:
| 模块 | 职责 |
| src/cordis-seams/ | 分支派生、八个可逆表面挂载器、disposable 注册表和事件溯源轨迹收集器 |
| src/harness2/ | 双轨提议器(领域 vs 不变量)、匿名行为组合器、证据链反思器 |
| src/dream-rsi/ | 带因果前缀视图的发现树、失败分类法、主动策略(plan_grid + 批处理)、代理评分器、离线梦想器 |
| src/memory-bridge/ | 统一内存 SPI、MCP 自动发现、六个驱动、治理 polyfill、虚拟命名空间、课程编解码器 |
跨模块契约冻结在 src/types/contracts.ts;任何模块都不导入宿主、网络或沙箱包,因此每个测试套件都能在没有实时 LLM 的情况下运行。
项目布局
dsh-plugin-evo-harness/
├── ARCHITECTURE.md # the design document (sections 1-7)
├── CHANGELOG.md # version history and hardening notes
├── LICENSE # Apache-2.0 license (pending author confirmation)
├── package.json # engines, packageManager, scripts, devDependencies
├── tsconfig.json # strict ES2022 / Bundler typecheck, noEmit
├── scripts/
│ ├── build.mjs # esbuild bundle to lib/index.js
│ ├── build-manifest.mjs # build-freshness stamp (source + dependency digests)
│ ├── verify-readme-counts.mjs # mechanical verification of README metrics in CI
│ ├── eval-jitrl.mjs # deterministic offline JitRL evaluation CLI (pnpm run eval:jitrl)
│ ├── bench-jitrl-query.mjs # JitRL retrieval benchmark (pnpm run bench:jitrl)
│ ├── eval/ # 发布门禁:证明、编码、干净工作树、变异、一致性、PR-4A、rev6 │ ├── host-smoke/ # 真实主机冒烟测试装置(运行、宿主内、杀进程树、预算绑定) │ └── fixtures/ # 离线账本夹具(费率卡、场景、载荷) ├── src/ │ ├── index.ts # Cordis 入口点:apply(ctx)、/evo 命令、auto_fallback 钩子、evoHarness 服务
│ ├── config.ts # schema, frozen defaults, deterministic validation
│ ├── orchestrator.ts # the 15-stage lifecycle
│ ├── host-triggers.ts # verified DSH event classification and payload normalization
│ ├── types/contracts.ts # frozen contracts shared by all modules
│ ├── cordis-seams/ # eight-surface mounters, context forker, seam manager, trajectory collector
│ ├── harness2/ # proposer, composer, reflector, shared helpers
│ ├── dream-rsi/ # discovery tree, failure taxonomy, active policy, surrogate scorer, offline dreamer
│ ├── jitrl/ # JIT-RL: decision kernel, rewards, logit sources, writeback gate, stores/
│ ├── ledger/ # two-phase settlement, WAL, pricing, limits, reconciliation, usage report
│ ├── verification/ # artifact digests, host runner, quality provenance, synthesized tests
│ ├── dsh-bridge/ # DSH model/tool boundary, agent-loop executor, metered adapter, real-benefit
│ ├── persistence/ # profile data dir, policy store, durable tree pool, atomic writes
│ ├── runtime/ # execution profiles (baseline / shadow / guarded-active)
│ └── memory-bridge/ # SPI, auto-discovery, governance polyfill, namespace isolation, drivers/
└── tests/
├── unit/
│ ├── cordis-seams/ # mounts, rollback, branch isolation, trajectory metrics
│ ├── harness2/ # asymmetric prompts, anonymous composition, lesson extraction
│ ├── dream-rsi/ # tree/prefix views, taxonomy, batching, scoring, replay
│ └── memory-bridge/ # auto-discovery, governance gate, isolation, firewall, drivers
└── e2e/ # plugin entrypoint, full lifecycle, memory backends, offline dream, governance
Testing
Every adapter is injectable, so the suites run offline: no network, no LLM, no sandbox. The
unit suites cover the module contracts (eight-surface mounting and rollback, branch isolation
and trajectory metrics, asymmetric proposal prompts, anonymous composition and adoption ratios,
canonical lesson extraction, discovery-tree causal prefixes, failure taxonomy, policy planning
and batching, surrogate scoring, governance gate, negative firewall and the six memory drivers).
The end-to-end suites drive the mounted plugin through apply(ctx, config): the plugin entrypoint
(/evo command, auto_fallback events, evoHarness service, host-adapter disposal), the full
lifecycle, backend-specific memory behaviour, the governance gate, post-compose evidence and
cross-session promotion, and the offline dream trigger and model wiring.
| Command | Scope | Suites at the time of writing |
| pnpm run test:unit | tests/unit | 175 files, 2963 tests |
| pnpm run test:e2e | tests/e2e | 25 files, 327 tests |
| pnpm run test | everything | 200 files, 3290 tests |
| pnpm run verify | typecheck + everything | the gate to run before a change lands |
Individual files can be run the usual Vitest way, for example
pnpm exec vitest run tests/unit/harness2.
The P1 evidence-and-atomic-config batch (ADR 0005) added these suites, all inside the counts above:
tests/unit/config/plugin-options-shape.test.ts (the plugin-options shape counterexamples C-1…C-12
against the real apply()), tests/unit/config/model-route-effort.test.ts,
tests/unit/config/readme-default-leaves.test.ts (the Configuration reference against the real
defaults), tests/unit/seams/status-observability.test.ts and
tests/unit/seams/status-observability-contract.test.ts (the collect-or-omit counter rule) and
tests/unit/eval/mutation-gate.test.ts (the anchors/CI contract of the mutation gate). The gate
scripts themselves are scripts/verify-readme-counts.mjs (extended: it also refuses reports with
failed or pending tests and checks the Configuration reference), scripts/eval/check-attestation-target.mjs
and scripts/eval/mutation-gate.mjs.
Because check:docs compares the counts above against the live suite, it must be re-run as the
release gate whenever tests are added, removed or renamed. It also refuses to mint any count from a
report that carries failed or pending tests, and it verifies the Configuration reference against the
real defaults at run time, so a config key added to src/config.ts without a documentation row fails
the same gate.
Evidence and attestation
A digest is only evidence if someone else can recompute it. Everything below therefore reads the
git object database and never the working tree: with core.autocrlf=true this checkout holds
CRLF bytes while the object database holds LF, so hashing files on disk would make the same commit
digest differently on Windows and on the Linux CI runner.
pnpm run attest # write docs/reports/final-attestation.json for HEAD
pnpm run attest:verify # recompute it from the object database and fail on any difference
| Field | Meaning |
| commit.commitId / commit.treeId | the exact commit and its root tree (^{commit} / ^{tree}) |
| compositeSha256 | SHA-256 over sorted path:blobSha256 lines, src/ + tests/ + scripts/ |
| bindingSha256 | SHA-256 over commit, tree and composite — content identity plus commit identity |
| environment | node/platform/arch/timestamp and worktree state; recorded, never hashed |
Two commits that carry identical content share a compositeSha256 and differ in bindingSha256;
that separation is asserted by tests/unit/p62/commit-attestation.test.ts.
Which revision does the record cover? A record can only describe the commit it was generated
from, so the question is decided per commit, not assumed (ADR 0005 D1). CI runs this as its own
job, attestation-target:
node scripts/eval/check-attestation-target.mjs --json
For an ordinary commit the canonical record must be self-consistent with the commit it names
and* that commit must be an ancestor of HEAD; the gate does not claim HEAD is attested and does
not invent a parent binding. A commit that declares the git trailer Attestation-Target: first-parent
is an evidence commit: it must contain only the updated record (record-only), must not be a merge
and must not be stacked on another evidence commit, and its recorded commit.commitId must equal
HEAD^1. The target is derived mechanically from the topology the commit declares. An
unconditional --strict would be red on every commit and an unconditional HEAD^1 would be a lax
guess; both alternatives were prototype-refuted before this gate was written.
Line endings and evidence portability. The record always stores the raw worktree bytes it
saw, and nothing ever rewrites those historical digests. The PR-4A artifact verifier therefore
classifies each executed source under the versioned rule eol-equiv-v1: a digest that matches only
after the one sanctioned CRLF↔LF transform of the same text is reported as the named
eol-equivalent pass classification (carrying the rule version, separate from raw matches),
while a genuine content, BOM, binary or invalid-UTF-8 difference stays a failure. The retained
provenance-executed-sources-eol-divergent warning now fires only in the mixed state — some entries line-ending-equivalent while other executed sources genuinely drift — so neither a false red nor a silent swallow is possible. .gitattributes still governs what is committed (below).
.gitattributes declares the content policy: everything is committed as LF text unless a path is an
explicit -text exception (tests/fixtures/encoding/* holds the CRLF, BOM and binary fixtures).
pnpm run check:encoding fails the build on an undeclared non-LF blob, and also refuses a
blanket text=auto rule, because a repo-wide renormalisation would rewrite every historical blob
and invalidate every digest ever recorded. There is deliberately no silent normalisation.
The gate inspects the committed tree, not the working tree. That is intentional: if the check
read whatever is on disk it would reintroduce the very coupling to the checkout that PR-1 removes. A
new non-LF file that is still untracked therefore passes locally and fails in CI after it is
committed — which is the earliest point at which it becomes evidence.
CI additionally recomputes the same commit on Linux, macOS and Windows and fails unless all three
produce one identical compositeSha256 and one identical bindingSha256 — the cross-platform claim is measured, not assumed.
Limitations and status
Stated plainly, because they matter when you evaluate this plugin:
- Host adapter capabilities and real Hook constraints. apply(ctx, ...) discovers Cordis capabilities structurally
(ctx.prompt, ctx.permissions, ctx.tools, ctx.skills, ctx.sandbox, ctx.subagents, ctx.middleware, ctx.evoMemory,
ctx.fork) and real DSH hook events; plugin.hostAdapterSource reports 'injected', 'dsh-hooks', 'context' or
'in-memory', and the fallback is recorded in plugin.diagnostics.
When real DSH hook events are available (hostAdapterSource='dsh-hooks'), the adapter mounts listeners on
system-prompt/assemble, tools/pre-execute, tools/post-execute, and agent/pre-step with branch/session scope isolation.
However, this real Hook adapter enforces only a deterministic subset:
- It does not execute or evaluate generated middleware code (middleware execution belongs to a host-managed sandbox).
- On tools/pre-execute, it deterministically enforces explicit deny rules (toolPreconditions starting with deny, forbiddenActions matching tool:<name> or deny:<name>, and host-supplied options.denyTools).
- All non-deny natural-language rules and permissive constraints are treated as advisory observations rather than hard security boundaries.
- Identity is proven, not assumed (D1 strict default). A dispatch whose
identity cannot be proven — an anonymous {name:'bash'} with no branchId/sessionId/namespace, or an identity the ScopeRegistry resolves to unknown — receives no advisor advice, triggers no extra Jit ask, and writes no learnable experience record. Ordinary tool execution still passes through untouched: the adapter returns the host's own decision and never auto-denies or auto-asks for an unknown identity. Unknown events are only counted (scope_unknown_skipped, payload free — no tool arguments or bodies are stored). A session only re-enters the advice/learning tracks after the host completes a trusted scope registration with the ScopeRegistry; there is no allowAnonymous switch (docs/adr/0001). When no seam or hook is discoverable the plugin mounts an in-process in-memory host adapter so the lifecycle still runs deterministically; that in-memory host is not a sandbox, and the repository's own tests never talk to a real Cordis host or a real MCP server.
- Branch isolation is delegated to the host. runInIsolatedBranch disposes everything it
mounted on success, failure, timeout and abort, and the memory side gets a deterministic
branch namespace, but real filesystem/process isolation only exists if the injected host
honours the branchId/namespace it is handed (options.host / ctx.fork).
- Real runs need injections. Without an IModelAdapter, propose/compose/reflect fail loudly;
without a BranchExecutor, every probe returns a deterministic failure instead of touching a
sandbox. Neither is bundled.
- Memory capability is bounded by the backend. The governance polyfill compensates for
backends without CCG validation, metadata filtering or branch isolation (falling back to
prefix-scoped namespaces, ARCHITECTURE.md section 4.3), but it cannot add capabilities a
server does not expose.
- Planning is a heuristic, not a guarantee. plan_grid, the three-way batch portfolio and the
surrogate score are documented heuristics; the offline dreamer is the only component with a
monotonic non-regression guarantee (a candidate policy must strictly beat pi^0).
- Packaging status. The package is private, version 0.1.0, and is not published to a
registry. On push and pull requests to main (.github/workflows/ci.yml) CI runs tsc --noEmit,
the full Vitest suite, mechanical docs hygiene verification, the guarded-regression probes
(ADR 0002 gate #7) together with the node --test parity/attestation suites, the attestation-target
binding gate (ADR 0005 D1, its own job), the four-mutant mutation gate (ADR 0005 D5, its own job)
and a three-OS
(Linux/macOS/Windows) fingerprint matrix whose parity job requires
--expect-commit "${{ github.sha }}", so "the three platforms agree" is checked against the
revision the run was triggered for rather than only against each other; no status badge is shown. A
separate node24-compat job installs Node 24 explicitly and prints node -v before running the
unit suites — Node 24 support is measured only there, on a push, never asserted locally (the development machine ships Node 22, and every count on this page is a Node 22 measurement). The package is licensed under the Apache-2.0 License (with copyright attribution pending author confirmation). See CHANGELOG.md for version history.
Design document
ARCHITECTURE.md is the normative design: section 3 maps the eight surfaces
onto Cordis seams, section 4 defines the Canonical Lesson Envelope and the governance
polyfill, section 5 covers the online/offline Dream-RSI loop, section 6 the directory layout,
the interfaces and the example cordis.yml, and section 7 the end-to-end sequence.
src/types/contracts.ts is the frozen contract surface shared by the implementation modules.预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
tang19-chao/dsh-plugin-evo-harness
让智能体在测试中可逆地改写自身脚手架并筛选更优方案
相关插件 · 搜索 / 抓取
LLM 知识平台Tencent/WeKnora
概览 ·快速开始 ·新特性 ·功能 ·客户端 ·文档 ·开发
★ 36,379已汉化DSH
72
智能体记忆系统MemTensor/MemOS
MemOS 2.0 Stardust星尘
★ 12,247已汉化DSH
71.3
跨代理记忆库zilliztech/memsearch
跨平台语义记忆,给 AI 编程智能体用。
★ 2,823已汉化DSH
70.9
技能语料库EverMind-AI/SkillCorpus
SkillCorpus 能给你什么
★ 696已汉化DSH
69.8
动画花园资源检索yjl9903/AnimeGarden
動漫花園 镜像站 | 动画 BT 资源聚合站 | 动画 BT 资源开放接口
★ 1,393已汉化DSH
69.2
代码图谱记忆syncable-dev/memtrace-public
你的智能体值得拥有结构化记忆。
★ 511已汉化MCP
67.9
这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。