mingdao-harness 0.4.6 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/docs/CHANGELOG-PACK.md +21 -0
- package/docs/DEVELOPER.md +46 -0
- package/docs/MIGRATION-DEYI-v0.5.md +175 -0
- package/docs/PACK-API.md +23 -6
- package/docs/PLAN-v0.5.0.md +169 -0
- package/package.json +2 -1
- package/packs/example-hello/pack.json +18 -0
- package/packs/example-hello/pack.mjs +47 -0
- package/packs/example-hello/prompts/domain.md +1 -0
- package/src/agent.js +229 -11
- package/src/cachestats.js +36 -0
- package/src/cli.js +11 -0
- package/src/commands/pack.js +196 -0
- package/src/commands/update.js +18 -0
- package/src/constraints.js +255 -0
- package/src/index.js +17 -0
- package/src/packs.js +451 -0
- package/src/prompts.js +26 -0
- package/src/tasks/worker.js +6 -0
- package/src/web/server.js +8 -0
package/README.md
CHANGED
|
@@ -203,6 +203,29 @@ mingdao sync conflicts # 跨设备冲突三选
|
|
|
203
203
|
|
|
204
204
|
多设备自动同步(会话结束静默推送);冲突绝不丢数据(自动 `.server-*` / `.remote-*` 备份 + 图形化选择);WebUI 设置面板含完整同步/分享/冲突区块。
|
|
205
205
|
|
|
206
|
+
### 垂域 Pack(v0.5.0 · Pack API v1)
|
|
207
|
+
|
|
208
|
+
把**某个行业的智能体**打包成一个可安装、可校验、可版本化的单元——不改内核源码:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
mingdao pack new tcm # 生成脚手架(manifest + 入口 + 领域提示词)
|
|
212
|
+
mingdao pack verify ./packs/tcm # 静态校验 + 运行时契约校验(CI 门禁,非 0 退出即失败)
|
|
213
|
+
mingdao pack list / info tcm # 查看已加载 Pack 与贡献面
|
|
214
|
+
mingdao cost --by pack # 垂域费用分账
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
一个 Pack 可以贡献四类东西:
|
|
218
|
+
|
|
219
|
+
| 贡献 | 作用 |
|
|
220
|
+
| --- | --- |
|
|
221
|
+
| **工具** | 领域工具,注册为 `pack__<pack>__<tool>`,与内置工具同走权限 / 审计 / schema 瘦身链路 |
|
|
222
|
+
| **约束(领域红线)** | `tool-deny` / `tool-arg-require` / `arg-forbid` / `output-forbid` / `completeness` / `confirm`,在内核三个时机**强制**(不是提示词里的一句话),命中写审计 |
|
|
223
|
+
| **领域提示词段** | 注入系统提示(确定性排序、字节稳定,不破坏前缀缓存) |
|
|
224
|
+
| **费用归因** | Pack 内模型调用走 `ctx.llm()`,自动入账 + 四维归因(`pack`/`tool`/`purpose`/`model`) |
|
|
225
|
+
|
|
226
|
+
三级遮蔽:`<项目>/.mingdao/packs/` > `~/.mingdao/packs/` > 内置 `packs/`;坏 Pack 只告警、不阻塞启动。
|
|
227
|
+
契约与示例见 [docs/PACK-API.md](docs/PACK-API.md)、内置中立示例 `packs/example-hello/`。
|
|
228
|
+
|
|
206
229
|
### 模型与 Key
|
|
207
230
|
|
|
208
231
|
- 内置:DeepSeek(v4-pro / v4-flash / v4-flash-vision-exp)、OpenAI(GPT-5 系列)、Qwen(qwen3.7-max)、GLM(GLM-5)、Kimi(kimi-latest)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Pack API 变更日志(Changelog-PACK)
|
|
2
|
+
|
|
3
|
+
只记录 **Pack API**(`pack.json` / `pack.mjs` / 约束引擎 / `ctx.llm()` / CLI)的契约变更。
|
|
4
|
+
产品功能变更见根目录 `CHANGELOG.md`。
|
|
5
|
+
|
|
6
|
+
兼容策略:同一 major 内向后兼容(minor 只增不改);支持窗口 = 最近 2 个 minor。
|
|
7
|
+
任何改动必须同步更新 `PACK-API.md` 与兼容性矩阵。
|
|
8
|
+
|
|
9
|
+
## v1(2026-09-11,随内核 v0.5.0 冻结)
|
|
10
|
+
|
|
11
|
+
**首次冻结。** 范围:
|
|
12
|
+
|
|
13
|
+
- `pack.json` manifest:`apiVersion` / `name` / `version` / `engines.mingdao` / `permissions` / `contributes`
|
|
14
|
+
- `pack.mjs` contributions:`tools` / `promptSections` / `constraints` / `memorySchema`
|
|
15
|
+
- 约束引擎 kind:`tool-deny` / `tool-arg-require` / `arg-forbid` / `output-forbid` / `completeness` / `confirm`
|
|
16
|
+
- 约束执行时机:PreToolUse / PostToolUse / 输出前
|
|
17
|
+
- `ctx.llm()` 统一模型出口(自动入账 + 四维归因)
|
|
18
|
+
- CLI:`mingdao pack list|verify|new|info|test`
|
|
19
|
+
- 兼容窗口:内核 0.5.x / 0.6.x 支持 `apiVersion: 1`
|
|
20
|
+
|
|
21
|
+
**已拍板的三条约束**(见 `PACK-API.md` §9):Pack 不得覆盖内置 Provider;`block-and-rewrite` 计费归 Pack;Pack 内 `fetch` 允许但需白名单 + 入账 + 静态告警。
|
package/docs/DEVELOPER.md
CHANGED
|
@@ -83,6 +83,52 @@ registerTool({
|
|
|
83
83
|
不做字符串拼接(防注入),由命令自行解析;执行受权限引擎门控(与 bash 同权重)。
|
|
84
84
|
改 config.tools 需重启生效(与 MCP 预设一致)。
|
|
85
85
|
|
|
86
|
+
## 二之补、垂域 Pack(v0.5.0,Pack API v1)
|
|
87
|
+
|
|
88
|
+
Preset 定制的是「提示词 + 工具白名单 + 权限」;**Pack 定制的是「一个行业的智能体」**——
|
|
89
|
+
领域工具、领域红线、领域提示词、领域费用归因,全部作为可安装单元打包,且**不改内核源码**。
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
mingdao pack new tcm # 脚手架:pack.json + pack.mjs + prompts/domain.md
|
|
93
|
+
mingdao pack verify ./packs/tcm # 契约校验(下游 CI 门禁:非 0 退出即失败)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
最小 `pack.mjs`:
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
export const apiVersion = 1;
|
|
100
|
+
export function createPack(ctx) {
|
|
101
|
+
return {
|
|
102
|
+
tools: [{
|
|
103
|
+
name: 'intake_collect',
|
|
104
|
+
description: '采集并落盘;缺项必须继续追问',
|
|
105
|
+
parameters: { type: 'object', properties: { patientId: { type: 'string' } }, required: ['patientId'] },
|
|
106
|
+
readOnly: false,
|
|
107
|
+
async run(args, toolCtx) {
|
|
108
|
+
// 统一模型出口:usage 自动入账 + 受日费用护栏约束 + Pack 归因
|
|
109
|
+
const r = await toolCtx.llm({ model: 'deepseek-v4-flash', system: '…', user: '…', purpose: 'patient-extract' });
|
|
110
|
+
return { ok: true, output: r.text, data: { /* 供 completeness 约束校验的字段 */ } };
|
|
111
|
+
},
|
|
112
|
+
}],
|
|
113
|
+
constraints: [
|
|
114
|
+
{ id: 'no-cross-patient', kind: 'tool-arg-require', tool: 'intake_collect', requireArg: 'patientId' },
|
|
115
|
+
{ id: 'ten-questions', kind: 'completeness', tool: 'intake_collect', fields: ['zhushu', 'zhendan'] },
|
|
116
|
+
{ id: 'no-conclusion', kind: 'output-forbid', pattern: '好转|治愈|确诊为', action: 'block-and-rewrite' },
|
|
117
|
+
],
|
|
118
|
+
promptSections: [{ id: 'domain', order: 100, content: '…' }],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
三条要点:
|
|
124
|
+
|
|
125
|
+
1. **领域红线由内核强制**,不是提示词建议。三个时机:调用工具前(工具/参数)、工具返回后(缺项则拒绝该结果)、正文输出前(回填会话历史**之前**改写/拦截)。命中写审计事件。
|
|
126
|
+
2. **Pack 内模型调用必须走 `ctx.llm()`**。自己 `fetch` 模型接口会让费用隐身、日费用护栏失效、`--by pack` 看不到——`pack verify` 会对此给出静态告警。
|
|
127
|
+
3. **只收紧、不放松**:约束不授予任何权限,也不改变 `permissions.js` 的判定。
|
|
128
|
+
|
|
129
|
+
完整契约(manifest 字段、约束 kind、`ctx.llm` 语义、版本兼容窗口)见 [PACK-API.md](PACK-API.md);
|
|
130
|
+
Pack API 变更史见 [CHANGELOG-PACK.md](CHANGELOG-PACK.md)。
|
|
131
|
+
|
|
86
132
|
## 三、库嵌入:最小示例
|
|
87
133
|
|
|
88
134
|
```js
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Deyi-TCM-Harness 回迁指南(v0.5.0 → Pack API v1)
|
|
2
|
+
|
|
3
|
+
> 面向:下游 Line B(中医垂域层,Linux 原机开发)
|
|
4
|
+
> 上游契约:`PACK-API.md`(v1 已冻结)· 变更史 `CHANGELOG-PACK.md`
|
|
5
|
+
> 触发:**v0.5.0 发布即回迁**(决策已确认)。目标:把 3 个域工具从 `providers/dify.mjs` 的 `chat()` 里搬出来。
|
|
6
|
+
> 纪律:下游**只通过扩展点接入,绝不修改上游源码**;内核 bug 在上游修。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 一、为什么必须迁(迁移前的真实损失)
|
|
11
|
+
|
|
12
|
+
当前 `Deyi-TCM-Harness/layer/providers/dify.mjs` 把整个中医域逻辑写进了 Provider 的 `chat()`。这是上游缺抽象导致的,不是下游的问题。具体损失:
|
|
13
|
+
|
|
14
|
+
| 应有能力 | 迁移前现状 |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| 权限引擎门控 | 域内「工具」是 `chat()` 里的正则匹配(`/^(回访\|随访)\s*(.*)$/`),绕过 `permissions.js` |
|
|
17
|
+
| 审计追溯 | 不写 `audit.jsonl`——无法回答「谁在何时读了哪位患者的病历」 |
|
|
18
|
+
| **费用与护栏** | 域内每次 DeepSeek 调用硬编码 `usage: { prompt_tokens: 0, completion_tokens: 0 }` → **完全不计费、不触发日费用护栏** |
|
|
19
|
+
| UI 工具卡片 / 流式 | 只能手工 `opts.onDelta` |
|
|
20
|
+
| 独立版本与兼容 | 整文件覆盖,无 `apiVersion`,无法 CI 校验 |
|
|
21
|
+
| 记忆 / 技能 / 预设复用 | 全部用不上 |
|
|
22
|
+
|
|
23
|
+
迁移后这六项全部进入内核的既有链路。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 二、目标结构
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Deyi-TCM-Harness/
|
|
31
|
+
layer/
|
|
32
|
+
packs/
|
|
33
|
+
tcm/
|
|
34
|
+
pack.json # manifest(apiVersion / engines / permissions / contributes / budget)
|
|
35
|
+
pack.mjs # createPack(ctx) → tools / constraints / promptSections
|
|
36
|
+
prompts/domain.md # 中医领域提示词(从 README 的职责描述落成正式文本)
|
|
37
|
+
constraints.json # 三条领域红线(也可内联在 pack.mjs)
|
|
38
|
+
examples/config.example.json
|
|
39
|
+
install.sh # 改为安装 packs/ 而不是 providers/
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`providers/dify.mjs` 里的**Dify 调用本身**保留为 Provider(协议适配是 Provider 的职责);
|
|
43
|
+
**三个域工具、四条流程、患者注册表、四态对比、回访看板**迁到 `pack-tcm`。
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 三、逐项迁移
|
|
48
|
+
|
|
49
|
+
### 3.1 三个「命令式工具」→ 真工具
|
|
50
|
+
|
|
51
|
+
迁移前(`chat()` 内字符串匹配,无权限、无审计、无卡片):
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const fu = /^(回访|随访)\s*(.*)$/.exec(query);
|
|
55
|
+
if (fu) { /* …直接产出文本,手工 opts.onDelta… */ }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
迁移后:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
// packs/tcm/pack.mjs
|
|
62
|
+
export function createPack(ctx) {
|
|
63
|
+
return {
|
|
64
|
+
tools: [
|
|
65
|
+
{ name: 'intake_collect', description: '首诊十问采集与病历落盘(缺项必须继续追问)', parameters: {…}, readOnly: false, run: intakeCollect },
|
|
66
|
+
{ name: 'visit_compare', description: '复诊四态对比(消失/减轻/无变化/加重,只陈述事实)', parameters: {…}, readOnly: false, run: visitCompare },
|
|
67
|
+
{ name: 'followup_board', description: '回访看板与单患者随访(趋势 + 预警 + 话术草稿)', parameters: {…}, readOnly: true, run: followupBoard },
|
|
68
|
+
],
|
|
69
|
+
// …
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
注册后内核自动加前缀:`pack__tcm__intake_collect` 等,与内置工具走**同一条**权限 / 审计 / schema 瘦身 / 费用链路。
|
|
75
|
+
|
|
76
|
+
### 3.2 三条红线 → 约束引擎(从提示词升级为内核强制)
|
|
77
|
+
|
|
78
|
+
| 现有红线(写在 prompt 里) | 迁移后的约束声明 |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| 缺项绝不编造 | `{ id:'ten-questions', kind:'completeness', tool:'intake_collect', fields:['zhushu','zhenduan','hanre','han','toushen','erbian','yinshi','xiongfu','kouke','jiubing'], onMissing:'reject' }` |
|
|
81
|
+
| 不输出诊疗结论 | `{ id:'no-diagnosis', kind:'output-forbid', pattern:'有效\|好转\|治愈\|确诊为', action:'block-and-rewrite' }` |
|
|
82
|
+
| 不得跨患者串病历 | `{ id:'no-cross-patient', kind:'tool-arg-require', tool:'intake_collect', requireArg:'patientId' }` |
|
|
83
|
+
|
|
84
|
+
执行时机:调用工具前(工具/参数)、工具返回后(缺项则**拒绝该结果**并回填「请继续采集」)、正文输出前(**回填会话历史之前**改写/拦截)。命中写审计事件。
|
|
85
|
+
|
|
86
|
+
> 注意:`output-forbid` 的 `block` / `block-and-rewrite` **不回显**命中的措辞——回显会把违规表述重新写进正文与历史。
|
|
87
|
+
|
|
88
|
+
### 3.3 域内模型调用 → `ctx.llm()`
|
|
89
|
+
|
|
90
|
+
迁移前(费用隐身):
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
const res = await fetch(`${deepseekBaseUrl}/chat/completions`, { … });
|
|
94
|
+
return { text, usage: { prompt_tokens: 0, completion_tokens: 0 } }; // ← 这笔钱谁也看不到
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
迁移后:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
async function deepseekJson(system, user, maxTokens = 2000) {
|
|
101
|
+
const r = await ctx.llm({ model: 'deepseek-v4-flash', system, user, maxTokens, json: true, purpose: 'patient-extract' });
|
|
102
|
+
return r.data; // json:true 时内核已解析
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
收益:usage 并入当前回合 → 今日费用 / 缓存命中率 / 峰谷 / 日费用护栏**同时生效**;并写一条 Pack 归因记录(`cost=null` 标记,与回合级总账不重复计费),`mingdao cost --by pack` 可见。
|
|
107
|
+
|
|
108
|
+
`purpose` 建议取值:`patient-extract`(患者识别)、`intake-extract`(结构化落盘)、`visit-compare`(四态对比)、`followup-script`(随访话术)。
|
|
109
|
+
|
|
110
|
+
### 3.4 患者注册表与快照落盘 → 受权限约束的 IO
|
|
111
|
+
|
|
112
|
+
`patients.json` / `intake/**` 的读写改用 `permissions.fs` 声明的路径(内核据此校验越界):
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
"permissions": { "fs": ["<MINGDAO_HOME>/patients.json", "<MINGDAO_HOME>/intake/**"] }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
同时建议把 `saveRegistry` 的 `writeFileSync` 换成上游的原子写语义(避免崩溃时半写)——这是**下游自己的代码**,上游只提供契约。
|
|
119
|
+
|
|
120
|
+
### 3.5 领域提示词 → `promptSections`
|
|
121
|
+
|
|
122
|
+
把现在散在 `chat()` 里的角色/边界说明提炼成 `prompts/domain.md`,以 `promptSections` 注入:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
"promptSections": ["prompts/domain.md"]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
内核按 `order` + `pack/id` **确定性排序**,字节稳定 → 不破坏 DeepSeek 前缀缓存。
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 四、迁移步骤(建议顺序)
|
|
133
|
+
|
|
134
|
+
1. `mingdao pack new tcm`(在 Deyi 仓库里生成 `packs/tcm/` 脚手架);
|
|
135
|
+
2. 把 `dify.mjs` 的 `intakeCollect` / `visitCompare` / `followupDashboard` / `patientFollowup` 搬到 `pack.mjs`,
|
|
136
|
+
函数体基本不动,只把「读凭据 + 直接 fetch」换成 `ctx.llm` + `ctx` 提供的只读信息;
|
|
137
|
+
3. 把患者的 JSON 读写挂到 `permissions.fs` 声明的路径;
|
|
138
|
+
4. 把三条红线写成 `constraints`;
|
|
139
|
+
5. 把领域提示词抽成 `prompts/domain.md`;
|
|
140
|
+
6. `layer/providers/dify.mjs` 只保留 **Dify 协议适配**(`createProvider` → `chat`),
|
|
141
|
+
域逻辑全部移出;`install.sh` 改为安装 `layer/packs/` 到 `$MINGDAO_HOME/packs/`;
|
|
142
|
+
7. `mingdao pack verify ./layer/packs/tcm` 必须退出 0;
|
|
143
|
+
8. 在 Deyi CI 里加:`mingdao pack verify ./layer/packs/tcm`。
|
|
144
|
+
|
|
145
|
+
**验收(DoD)**:
|
|
146
|
+
- 域内每次 DeepSeek 调用都出现在 `mingdao cost --by pack` 里;
|
|
147
|
+
- 三条红线可被测试**阻断**(缺项 / 结论性措辞 / 缺 patientId 各一条断言);
|
|
148
|
+
- 三个工具在 WebUI 显示为正常工具卡片;
|
|
149
|
+
- 同名多命中仍返回候选列表(不静默合并)——行为不回归。
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 五、兼容性与版本
|
|
154
|
+
|
|
155
|
+
| 项 | 约定 |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| 声明 | `pack.json` 写 `apiVersion: 1` + `engines.mingdao: ">=0.5 <0.7"` |
|
|
158
|
+
| 支持窗口 | 上游承诺支持最近 2 个 minor(0.5 / 0.6 支持 v1) |
|
|
159
|
+
| 上游变更 | 任何 Pack API 变更同步更新 `PACK-API.md` + `CHANGELOG-PACK.md` + 兼容性矩阵 |
|
|
160
|
+
| 下游义务 | 每个上游 minor 发布后跑一次 `pack verify`,并入 CI |
|
|
161
|
+
| 破坏性变更 | 走 major + 迁移指南(如可行再配 codemod) |
|
|
162
|
+
|
|
163
|
+
**内核 bug 一律在上游修**:下游遇到的问题如果是「扩展点不够用/行为不对」,直接反馈上游,
|
|
164
|
+
不要在下游 fork 内核——这条边界是上下游能长期并行的前提。
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 六、上游仍需补齐(下游可先按本节设计,勿依赖)
|
|
169
|
+
|
|
170
|
+
- `ctx.storage`:Pack 私有持久化命名空间(当前用 `permissions.fs` 显式路径替代);
|
|
171
|
+
- `ctx.provider`:由 Pack 贡献非 OpenAI 兼容 Provider(当前 Dify 适配仍放 `<home>/providers/`);
|
|
172
|
+
- Pack 私有存储加密(医疗 PII)→ v0.6.0「合规与确定性」;
|
|
173
|
+
- 执行账本导出 / 可回放(确定性③)→ v0.6.0。
|
|
174
|
+
|
|
175
|
+
以上四项在 v0.5.0 **不可用**,请勿在回迁中依赖。
|
package/docs/PACK-API.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# 垂域 Pack API v1(草案)
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 状态:**v1 已冻结(2026-09-11,决策已确认)**,随 v0.5.0 发布生效。本文是上游与下游之间的接口契约。
|
|
4
|
+
> 变更纪律:v1 冻结后,minor 版本只增不改;任何改动必须同步更新本文 + `CHANGELOG-PACK.md` + 兼容性矩阵。
|
|
4
5
|
> 定位:让垂域团队(中医、法律、教育、制造、政务…)**不修改内核源码**就能做出可私有化、可审计、受约束的智能体。
|
|
5
6
|
> 关联:`STRATEGY-0.5.md`(战略)、`DEVELOPER.md`(现有扩展点)、`CONFIG.md`(配置)。
|
|
6
7
|
|
|
@@ -71,6 +72,11 @@
|
|
|
71
72
|
"env": ["DIFY_API_KEY"]
|
|
72
73
|
},
|
|
73
74
|
|
|
75
|
+
"budget": { // 可选:Pack 级预算(v0.5.0 A4.5)
|
|
76
|
+
"dailyYuan": 20, // 该 Pack 当日模型调用费用上限(元);经 ctx.llm 归因统计
|
|
77
|
+
"action": "block" // 超限处理:block(阻止调用,默认)/ warn(放行并提示)
|
|
78
|
+
},
|
|
79
|
+
|
|
74
80
|
"contributes": {
|
|
75
81
|
"tools": true, // 由 pack.mjs 提供
|
|
76
82
|
"provider": "dify", // 复用/覆盖 Provider 名
|
|
@@ -201,6 +207,13 @@ const out = await ctx.llm({
|
|
|
201
207
|
|
|
202
208
|
> 这一条直接修复「域内调用 `usage: 0`」问题——**Pack 内不可能再有隐身花费**。
|
|
203
209
|
|
|
210
|
+
### Pack 级预算
|
|
211
|
+
|
|
212
|
+
manifest 可声明 `budget.dailyYuan` + `budget.action`。超限时 `ctx.llm()` 在**发起调用前**拦截
|
|
213
|
+
(`action: block`)或放行并告警(`action: warn`),粒度到 Pack 而非整个进程——
|
|
214
|
+
垂域团队能为自己包住的模型调用单独设上限,不必与宿主的日费用护栏争额度。
|
|
215
|
+
查看某 Pack 今日花费:`mingdao cost --by pack`。
|
|
216
|
+
|
|
204
217
|
---
|
|
205
218
|
|
|
206
219
|
## 6. 兼容性与版本策略
|
|
@@ -242,9 +255,13 @@ mingdao constraint test <name> # 单独跑约束反例
|
|
|
242
255
|
|
|
243
256
|
---
|
|
244
257
|
|
|
245
|
-
## 9.
|
|
258
|
+
## 9. 关键决策(✅ 已拍板 2026-09-11,v1 冻结)
|
|
259
|
+
|
|
260
|
+
1. **Pack 不得覆盖内置同名 Provider**——只允许新增。理由:内置 Provider 名称是内核契约的一部分,允许覆盖会让「内核行为」变成 Pack 可劫持的对象,安全与可预测性都受损。同名冲突在 `pack verify` 与加载时都会被拒绝并给出明确原因。
|
|
261
|
+
2. **`block-and-rewrite` 的修正请求计费归 Pack**。理由:修正是 Pack 的约束触发的额外开销,归到 Pack 才能让垂域团队看到「自己的红线花了多少钱」,也让 Pack 级预算真实反映其成本。
|
|
262
|
+
3. **Pack 内 `fetch` 允许,但必须**:① 目标在 `permissions.net` 白名单内;② 调用强制入账(`purpose` 标记)并可审计;③ `mingdao pack verify` 对「直连模型端点」的 `fetch` 给出静态告警(引导改用 `ctx.llm()`)。理由:部分垂域必须直连业务系统(HIS/ERP),一刀切禁止会把 Pack 逼回 Provider 里写 `chat()` 的老路——那正是本设计要消灭的形态。
|
|
263
|
+
|
|
264
|
+
### 仍未定(不阻塞 v1,随 v0.5.x 落地)
|
|
246
265
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
3. **Pack 内 `fetch` 一律禁止,还是允许但需在 `permissions.net` 白名单内并强制入账?**(倾向:允许 + 白名单 + 入账,因为部分域需要直连业务系统)
|
|
250
|
-
4. **Pack 私有存储是否加密**(医疗/法律 PII)?v1 先不做,v0.6 「合规与确定性」阶段再定。
|
|
266
|
+
- Pack 私有存储是否加密(医疗/法律 PII)→ **v0.6.0「合规与确定性」阶段决定**。
|
|
267
|
+
- `npm:` 来源的离线缓存策略(内网无 npm 时的分发)→ v0.6.0 与离线安装包一并设计。
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# PLAN-v0.5.0「垂域 Pack 契约」— 落地计划
|
|
2
|
+
|
|
3
|
+
> 依据:`STRATEGY-0.5.md` §七(阶段 A)+ §十(✅ 已确认 2026-09-11)。
|
|
4
|
+
> 决策:v0.5 只做 **确定性① 约束确定性 + ② 成本确定性**;③ 行为确定性(执行账本/可回放/合规导出)**放 v0.6.0**。
|
|
5
|
+
> 契约:接口定义见 `PACK-API.md`(v1 冻结目标)。
|
|
6
|
+
> 纪律:每步可独立验证;全绿门禁(6 套测试 + strict 0/0 + tsc 0)+ 新增回归断言;**v0.5.0 发布即触发 Deyi 回迁**。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 〇、进度(滚动更新)
|
|
11
|
+
|
|
12
|
+
| 阶段 | 状态 | 产出 |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| A0 契约冻结 | ✅ 完成 | `PACK-API.md` v1 冻结 + 三条决策拍板;`docs/CHANGELOG-PACK.md`(v1 条目) |
|
|
15
|
+
| A1 Pack 加载器 | ✅ 完成 | `src/packs.js`:三级遮蔽发现 / manifest 严格校验 / 极简 semver(npm 语义)/ 工具注册 / 坏 Pack 只告警 / 幂等挂载 |
|
|
16
|
+
| A2 CLI | ✅ 完成 | `src/commands/pack.js`:`list / verify / new / info`;`verify` 即下游 CI 门禁 |
|
|
17
|
+
| A3 约束引擎 | ✅ 完成(含接线) | `src/constraints.js` 三时机 + 6 kind + fail-closed;**已接入 agent**:PreToolUse(工具/参数)、PostToolUse(缺项拒绝结果)、输出前(回填历史之前改写/拦截);约束事件写审计;CLI/WebUI/worker 启动各挂载一次 |
|
|
18
|
+
| A4 成本确定性 | ✅ 完成 | `ctx.llm()` 统一模型出口(usage 并入当前回合 → 今日费用/缓存/峰谷/护栏全部生效);**Pack 归因记录**(cost=null 标记,不与回合级重复计费);`mingdao cost --by pack`;`pack verify` 对「自建模型调用」的静态告警(A4.6);**Pack 级预算**(A4.5:`budget.dailyYuan` + action,调用前拦截) |
|
|
19
|
+
| A5 提示词段 | ✅ 完成 | `buildSystemPrompt` 注入 `<pack_rules>`(按 order + pack/id 确定性排序,字节稳定不破坏前缀缓存) |
|
|
20
|
+
| A6 文档 | ✅ 完成 | `packs/example-hello/` 示例 + `PACK-API.md` + `CHANGELOG-PACK.md`;README「垂域 Pack」小节 + `DEVELOPER.md` Pack 章节(含最小 pack.mjs 与三条要点) |
|
|
21
|
+
| A7 发布 | ✅ 完成 | 版本 0.5.0;CHANGELOG + `RELEASE-NOTES-0.5.0.md`;tag `v0.5.0` |
|
|
22
|
+
| A7 下游回迁 | ⏳ 待下游执行 | 上游已交付 `docs/MIGRATION-DEYI-v0.5.md`;回迁在 Linux 原机进行 |
|
|
23
|
+
|
|
24
|
+
**已验证的端到端行为**(均有回归断言):
|
|
25
|
+
|
|
26
|
+
- `pack verify/list/info/new` 四条命令可用;`example-hello` 工具进 schema 且可执行;坏 Pack 只告警不崩启动;重复挂载幂等;
|
|
27
|
+
- 约束三时机在真实 agent 循环里生效:`tool-deny` 拦住已获权限的工具、`completeness` 缺项时**原始结果不进入模型上下文**、输出命中红线时在**回填会话历史之前**改写/拦截(否则违规措辞会被当既成事实喂回);
|
|
28
|
+
- 零约束时三处检查点全部惰性,正文原样返回(对既有行为零影响);
|
|
29
|
+
- `ctx.llm` 的子调用 usage **并入父回合**(实测 1000+500+1000=2500 prompt),并在账本留下 Pack 归因记录而不重复计费;`mingdao cost --by pack` 可见。
|
|
30
|
+
|
|
31
|
+
断言规模:smoke 83 → **86 组**;6/6 套测试全绿;tsc 0 错误;strict 0/0。
|
|
32
|
+
|
|
33
|
+
**下一步**:
|
|
34
|
+
1. **下游执行回迁**(Linux 原机):按 `MIGRATION-DEYI-v0.5.md` 把 3 个域工具搬进 `pack-tcm`,
|
|
35
|
+
`pack verify` 进下游 CI;回迁中遇到的每个「别扭点」都反馈上游当契约缺陷修(dogfooding)。
|
|
36
|
+
2. **v0.5.x**:Pack API 按回迁反馈做兼容性加固(minor 只增不改)。
|
|
37
|
+
3. **v0.6.0「合规与确定性」**:确定性③——执行账本(脱敏可导出)+ 可回放 + 离线/内网安装包 + 出网白名单自证。
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 一、目标(一句话)
|
|
42
|
+
|
|
43
|
+
让一个垂域团队(以中医为第一个参考实现)**不改内核源码**,就能把领域工具、领域红线、领域提示词、领域费用接进内核,并让它们全部进入权限 / 审计 / 费用 / UI 链路。
|
|
44
|
+
|
|
45
|
+
**验收的硬标准**:Deyi 的 3 个域工具从 `providers/dify.mjs` 的 `chat()` 里搬进 `pack-tcm`,且:
|
|
46
|
+
- 每次域内模型调用都出现在 `mingdao cost report` 里(当前硬编码 `usage: 0`,完全隐身);
|
|
47
|
+
- 中医三条红线由内核强制并可被测试阻断(当前只是提示词里的一句话);
|
|
48
|
+
- 域工具在 WebUI 里显示为正常工具卡片(当前只能在 `chat()` 里手工 `onDelta`)。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 二、交付物与顺序
|
|
53
|
+
|
|
54
|
+
### A0. 契约冻结(0.5 天)
|
|
55
|
+
|
|
56
|
+
| 项 | 内容 | 验收 |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| A0.1 | 定稿 `PACK-API.md` 三个待定问题(§9):内置 Provider 不可覆盖 / `block-and-rewrite` 计费归 Pack / Pack 内 `fetch` 允许但需白名单+入账 | 文档更新并标注「v1 冻结」 |
|
|
59
|
+
| A0.2 | 新增 `docs/CHANGELOG-PACK.md`(Pack API 变更日志,从 v1 起) | 文件存在且有 v1 条目 |
|
|
60
|
+
|
|
61
|
+
### A1. Pack 加载器 + manifest(2 天)
|
|
62
|
+
|
|
63
|
+
| 项 | 内容 | 验收 |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| A1.1 | 新增 `src/packs.js`:`listPacks()` / `loadPack(dir)` / `validateManifest()` / `mountPacks(cfg)` | 单元断言:合法 manifest 通过、非法字段/版本不匹配/保留名被拒 |
|
|
66
|
+
| A1.2 | 三级遮蔽:`<项目>/.mingdao/packs/` > `<MINGDAO_HOME>/packs/` > 内置 `packs/` | 同名时高优先级胜出(断言) |
|
|
67
|
+
| A1.3 | `config.packs` 声明式加载(本地目录 / `npm:` / `https:` 归档 + sha256) | 三种来源各一条断言;坏 Pack 不阻塞启动(回归断言) |
|
|
68
|
+
| A1.4 | 工具注册进既有注册表:命名 `pack__<pack>__<tool>`,走 `registerTool` | `buildToolSchemas` 能看到;权限/审计链路复用(断言) |
|
|
69
|
+
| A1.5 | `permissions` 最小权限校验(fs 白名单越界即拒、net 白名单) | 越界 manifest 被拒(断言) |
|
|
70
|
+
|
|
71
|
+
### A2. CLI(1 天)
|
|
72
|
+
|
|
73
|
+
| 命令 | 行为 | 验收 |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
| `mingdao pack list` | 已加载 Pack / 来源 / 版本 / 兼容状态 | 输出含名称与 apiVersion |
|
|
76
|
+
| `mingdao pack verify <dir>` | 静态校验:manifest + 文件齐全 + 约束合法 + 权限不越界 | 合法 Pack 退出 0;坏 Pack 退出非 0 **并给出可操作原因**(下游 CI 门禁) |
|
|
77
|
+
| `mingdao pack new <name>` | 脚手架(pack.json + pack.mjs + 示例工具 + 一条约束) | 生成的目录 `pack verify` 通过 |
|
|
78
|
+
| `mingdao pack info <name>` | 贡献面 + 费用统计(A4 完成后) | — |
|
|
79
|
+
| `mingdao pack test <name>` | 跑内置反例样本(约束 + 工具契约) | — |
|
|
80
|
+
|
|
81
|
+
### A3. 约束引擎 v1(3 天,**本阶段核心**)
|
|
82
|
+
|
|
83
|
+
| 项 | 内容 | 验收 |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| A3.1 | 约束声明解析 + 校验(`kind` ∈ tool-deny / tool-arg-require / arg-forbid / output-forbid / completeness / confirm) | 非法 kind 被 `pack verify` 拒绝 |
|
|
86
|
+
| A3.2 | **PreToolUse 时机**:`tool-deny` / `tool-arg-require` / `arg-forbid` → 阻止执行并回填错误给模型 | 每条 kind 一条阻断断言 |
|
|
87
|
+
| A3.3 | **PostToolUse 时机**:`completeness`(缺项则拒绝该工具结果并要求补采)/ `result-forbid` | 缺项场景断言:工具结果被拒、模型被要求补采 |
|
|
88
|
+
| A3.4 | **输出前时机**:`output-forbid` + `action` ∈ block / block-and-rewrite / warn | 命中「好转/治愈」时按 action 处理(断言) |
|
|
89
|
+
| A3.5 | 约束事件进审计(`pack`/`constraint`/`kind`/`stage`/`action`/`matched`) | 审计文件含该结构(断言) |
|
|
90
|
+
| A3.6 | 约束**只能收紧不能放松**权限(约束不授予任何权限) | 声明了约束也不改变权限判定(断言) |
|
|
91
|
+
| A3.7 | 失败 fail-closed | 约束求值异常时按阻断处理(断言) |
|
|
92
|
+
|
|
93
|
+
### A4. 成本确定性(2.5 天)
|
|
94
|
+
|
|
95
|
+
| 项 | 内容 | 验收 |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| A4.1 | `ctx.llm(opts)`:统一模型出口(复用 Provider 重试/超时/能力表;支持 `json:true`、`purpose` 标签) | Pack 内调用一次,`usage` 非 0(断言) |
|
|
98
|
+
| A4.2 | usage 自动并入当前回合 → 今日费用 / 缓存命中 / 峰谷 / 日护栏全部生效 | 记录前后 `todayCost()` 增加(断言) |
|
|
99
|
+
| A4.3 | 四维归因账本:`(pack, tool, purpose, model, session)` | `cost report --by pack` 可见 |
|
|
100
|
+
| A4.4 | `mingdao cost report --by pack` / WebUI 仪表盘加 Pack 维度 | 报告含 Pack 分账表 |
|
|
101
|
+
| A4.5 | Pack 级预算(日/任务)与护栏 action 联动 | 超预算按 action 处理(断言) |
|
|
102
|
+
| A4.6 | 禁止 Pack 内直连模型接口绕过(评审用:`pack verify` 静态告警 `fetch` 到模型端点) | 告警可复现 |
|
|
103
|
+
|
|
104
|
+
### A5. 提示词段与分离(1 天)
|
|
105
|
+
|
|
106
|
+
| 项 | 内容 | 验收 |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| A5.1 | `promptSections`(id + order + content)注入系统提示,位置在预设/记忆/技能之后 | 系统提示含该段(断言) |
|
|
109
|
+
| A5.2 | 快照语义:Pack 提示词段在会话内不变(不破坏前缀缓存) | 同回合两次构建字节一致(断言) |
|
|
110
|
+
|
|
111
|
+
### A6. 文档与示例(1 天)
|
|
112
|
+
|
|
113
|
+
| 项 | 内容 |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| A6.1 | `docs/PACK-API.md` 定稿 + 「5 分钟做出第一个 Pack」教程 |
|
|
116
|
+
| A6.2 | `packs/example-hello/` 内置最小示例(1 工具 + 1 条 output-forbid 约束) |
|
|
117
|
+
| A6.3 | `docs/DEVELOPER.md` 增加 Pack 章节,指向 PACK-API |
|
|
118
|
+
| A6.4 | README 增加「垂域 Pack」卖点段(对齐新定位,不夸大) |
|
|
119
|
+
|
|
120
|
+
### A7. 发布与回迁(1 天)
|
|
121
|
+
|
|
122
|
+
| 项 | 内容 | 验收 |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| A7.1 | 版本 0.4.6 → **0.5.0**(minor:新增 Pack API);`CHANGELOG-PACK.md` 记录 v1 冻结 | 版本一致 + 全绿 |
|
|
125
|
+
| A7.2 | 发布(自检 → commit → tag → 推 origin → 官网/镜像按既有流程) | CI + Desktop 绿 |
|
|
126
|
+
| A7.3 | **Deyi 回迁**:`pack-tcm` 从 `providers/dify.mjs` 拆出 3 工具 + 3 条约束 + 提示词段;`mingdao pack verify` 进下游 CI | 域内费用可见、红线可阻断、工具卡片正常 |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 三、排期(建议,合计 ≈ 11.5 个工作日)
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
A0 契约冻结 ──▶ A1 Pack 加载器 ──▶ A2 CLI ──┬─▶ A3 约束引擎 ──┐
|
|
134
|
+
└─▶ A4 成本确定性 ─┴─▶ A5 提示词段 ──▶ A6 文档 ──▶ A7 发布+回迁
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
A3 与 A4 可并行(不同模块),A5 依赖 A1。
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 四、风险与对策
|
|
142
|
+
|
|
143
|
+
| 风险 | 影响 | 对策 |
|
|
144
|
+
| --- | --- | --- |
|
|
145
|
+
| Pack API 设计不足,Deyi 迁不动 | v1 冻结即返工 | **A1/A3 完成后先用 `example-hello` 走通**;Deyi 回迁中发现的每个别扭点都当契约缺陷修 |
|
|
146
|
+
| 约束引擎改变 agent 主循环,伤到现有行为 | 回归风险 | 约束默认空集合 → 零 Pack 时行为与今天**完全一致**(用现有 6 套测试守住);有 Pack 才生效 |
|
|
147
|
+
| `ctx.llm()` 破坏已有的费用链路 | P0 级回归 | 复用 `recordUsage` 同一条路径,不新开记账;断言「Pack 调用与普通回合进同一账本」 |
|
|
148
|
+
| Pack 加载拖慢启动 | 体验 | 懒加载贡献面;manifest 静态校验与文件读取分离;启动只读 manifest |
|
|
149
|
+
| 零依赖被破坏 | 根基 | Pack 加载器只用 `node:fs`/`node:url`;`npm:` 来源走 `require.resolve` 语义但不引入依赖树;CI 加「运行时 0 依赖」断言 |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 五、明确不做(本阶段)
|
|
154
|
+
|
|
155
|
+
- ❌ 不做 Pack 商店 / 在线市场(v0.7+ 议题)
|
|
156
|
+
- ❌ 不做行为确定性(执行账本 / 可回放 / 合规导出)→ **v0.6.0**
|
|
157
|
+
- ❌ 不引入 Cordis 或任何重依赖
|
|
158
|
+
- ❌ 不把中医逻辑写进内核(只在 `example-hello` 里放中立示例)
|
|
159
|
+
- ❌ 不动已有省钱链路的行为(只在其上增加 Pack 维度)
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 六、完成定义(DoD)
|
|
164
|
+
|
|
165
|
+
1. `mingdao pack verify` 能对任意 Pack 目录给出**可操作**的通过/失败结论;
|
|
166
|
+
2. 一个不含领域逻辑的中立示例 Pack(`example-hello`)端到端跑通(工具可用、约束可阻断、提示词段到达、费用入账);
|
|
167
|
+
3. **Deyi 的 3 个域工具成功从 Provider 迁出**,域内费用出现在 `cost report` 里,中医红线可被测试阻断;
|
|
168
|
+
4. 全绿门禁 + strict 0/0 + tsc 0 + 运行时 0 依赖;
|
|
169
|
+
5. `PACK-API.md` 标注 v1 冻结,`CHANGELOG-PACK.md` 有 v1 条目,兼容性矩阵写下「0.5.x / 0.6.x 支持 v1」。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mingdao-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MingDao Harness —— 开源智能体框架(Agent Harness)。零依赖、开箱即用,针对 DeepSeek-V4 系列优化,开放主流模型接入。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"skills/",
|
|
17
17
|
"skills-lib/",
|
|
18
18
|
"presets/",
|
|
19
|
+
"packs/",
|
|
19
20
|
"assets/",
|
|
20
21
|
"docs/",
|
|
21
22
|
"install.sh",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiVersion": 1,
|
|
3
|
+
"name": "example-hello",
|
|
4
|
+
"displayName": "示例垂域包(最小可用)",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"engines": {
|
|
7
|
+
"mingdao": ">=0.4.6 <0.7"
|
|
8
|
+
},
|
|
9
|
+
"description": "最小示例:1 个领域工具 + 1 条输出红线约束 + 1 段领域提示词。不含任何业务逻辑,供垂域团队照抄。",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"contributes": {
|
|
12
|
+
"tools": true,
|
|
13
|
+
"promptSections": [
|
|
14
|
+
"prompts/domain.md"
|
|
15
|
+
],
|
|
16
|
+
"constraints": true
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// 示例 Pack:最小可用形态(1 工具 + 1 约束 + 1 提示词段)。
|
|
2
|
+
// 垂域团队照抄本文件即可起步;真实领域逻辑放在自己的仓库/目录里。
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
export const apiVersion = 1;
|
|
7
|
+
|
|
8
|
+
export function createPack(ctx) {
|
|
9
|
+
return {
|
|
10
|
+
tools: [
|
|
11
|
+
{
|
|
12
|
+
name: 'count_lines',
|
|
13
|
+
description: '统计某个文本文件的行数与字符数(示例工具,只读)。',
|
|
14
|
+
parameters: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: { path: { type: 'string', description: '文件路径' } },
|
|
17
|
+
required: ['path'],
|
|
18
|
+
},
|
|
19
|
+
readOnly: true,
|
|
20
|
+
async run(args) {
|
|
21
|
+
const p = String(args?.path || '');
|
|
22
|
+
if (!p) return { ok: false, error: '缺少 path 参数' };
|
|
23
|
+
try {
|
|
24
|
+
const text = fs.readFileSync(path.resolve(p), 'utf8');
|
|
25
|
+
return { ok: true, output: `行数 ${text.split('\n').length},字符数 ${text.length}` };
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return { ok: false, error: `读取失败:${e?.message || e}` };
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
|
|
33
|
+
// 领域红线:输出里出现结论性措辞即拦截(真实垂域按需替换 pattern)
|
|
34
|
+
constraints: [
|
|
35
|
+
{
|
|
36
|
+
id: 'no-conclusion',
|
|
37
|
+
kind: 'output-forbid',
|
|
38
|
+
pattern: '确诊为|治愈|保证有效',
|
|
39
|
+
action: 'block-and-rewrite',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
|
|
43
|
+
promptSections: [
|
|
44
|
+
{ id: 'domain', order: 100, content: fs.readFileSync(path.join(ctx.packDir, 'prompts', 'domain.md'), 'utf8') },
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
你是某个垂域的知识工作助手。只做事实陈述与资料整理,不输出结论性判断。
|