kc-beta 0.1.2 → 0.3.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.
Files changed (55) hide show
  1. package/bin/kc-beta.js +14 -2
  2. package/package.json +1 -1
  3. package/src/agent/context-window.js +151 -0
  4. package/src/agent/context.js +8 -4
  5. package/src/agent/engine.js +261 -8
  6. package/src/agent/event-log.js +111 -0
  7. package/src/agent/llm-client.js +352 -59
  8. package/src/agent/pipelines/base.js +6 -0
  9. package/src/agent/pipelines/distillation.js +18 -0
  10. package/src/agent/pipelines/extraction.js +21 -0
  11. package/src/agent/pipelines/initializer.js +75 -14
  12. package/src/agent/pipelines/production-qc.js +19 -0
  13. package/src/agent/pipelines/skill-authoring.js +14 -0
  14. package/src/agent/pipelines/skill-testing.js +20 -0
  15. package/src/agent/retry.js +83 -0
  16. package/src/agent/session-state.js +79 -0
  17. package/src/agent/skill-loader.js +13 -1
  18. package/src/agent/token-counter.js +62 -0
  19. package/src/agent/tools/document-parse.js +104 -21
  20. package/src/agent/tools/document-search.js +24 -8
  21. package/src/agent/tools/sandbox-exec.js +16 -5
  22. package/src/agent/tools/web-search.js +107 -0
  23. package/src/agent/tools/worker-llm-call.js +14 -5
  24. package/src/agent/tools/workspace-file.js +47 -20
  25. package/src/agent/workspace.js +24 -1
  26. package/src/cli/components.js +24 -5
  27. package/src/cli/config.js +340 -0
  28. package/src/cli/index.js +113 -11
  29. package/src/cli/onboard.js +216 -53
  30. package/src/config.js +63 -10
  31. package/src/model-tiers.json +153 -0
  32. package/src/providers.js +367 -0
  33. package/template/AGENT.md +20 -0
  34. package/template/skills/en/meta/compliance-judgment/SKILL.md +10 -42
  35. package/template/skills/en/meta/document-chunking/SKILL.md +32 -0
  36. package/template/skills/en/meta/document-parsing/SKILL.md +11 -18
  37. package/template/skills/en/meta/entity-extraction/SKILL.md +13 -28
  38. package/template/skills/en/meta/tree-processing/SKILL.md +19 -1
  39. package/template/skills/en/meta-meta/auto-model-selection/SKILL.md +53 -0
  40. package/template/skills/en/meta-meta/pdf-review-dashboard/SKILL.md +57 -0
  41. package/template/skills/en/meta-meta/pdf-review-dashboard/scripts/generate_review.js +262 -0
  42. package/template/skills/en/meta-meta/rule-extraction/SKILL.md +24 -1
  43. package/template/skills/en/meta-meta/skill-authoring/SKILL.md +6 -0
  44. package/template/skills/en/meta-meta/skill-to-workflow/SKILL.md +4 -0
  45. package/template/skills/zh/meta/compliance-judgment/SKILL.md +41 -262
  46. package/template/skills/zh/meta/document-chunking/SKILL.md +32 -0
  47. package/template/skills/zh/meta/document-parsing/SKILL.md +65 -132
  48. package/template/skills/zh/meta/entity-extraction/SKILL.md +68 -230
  49. package/template/skills/zh/meta/tree-processing/SKILL.md +82 -194
  50. package/template/skills/zh/meta-meta/auto-model-selection/SKILL.md +51 -0
  51. package/template/skills/zh/meta-meta/pdf-review-dashboard/SKILL.md +55 -0
  52. package/template/skills/zh/meta-meta/pdf-review-dashboard/scripts/generate_review.js +262 -0
  53. package/template/skills/zh/meta-meta/rule-extraction/SKILL.md +79 -164
  54. package/template/skills/zh/meta-meta/skill-authoring/SKILL.md +64 -185
  55. package/template/skills/zh/meta-meta/skill-to-workflow/SKILL.md +95 -216
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: auto-model-selection
3
+ description: >
4
+ 使用 Context7 CLI 获取最新 LLM 模型信息。当需要了解可用模型、模型能力、价格、
5
+ 上下文窗口大小、或哪个模型适合某项任务时使用——包括分层分配、Worker LLM 工作流设计、
6
+ 模型对比、服务商 API 调用方式等。Context7 提供训练数据中可能没有的最新信息。
7
+ 需要安装 context7 CLI (npm i -g context7)。可选插件。
8
+ ---
9
+
10
+ # 通过 Context7 自动选择模型
11
+
12
+ ## Context7 是什么
13
+
14
+ Context7 (`c7`) 是一个轻量 CLI 工具,可获取最新的库和 API 文档。安装:`npm i -g context7`。两个命令:
15
+ - `c7 library <查询>` — 按名称搜索库/服务商
16
+ - `c7 docs <libraryId> <查询>` — 获取具体文档和代码示例
17
+
18
+ ## 使用时机
19
+
20
+ - 用户的 `model-tiers.json` 过期(KC 长时间未更新)
21
+ - 用户切换到新服务商,需要模型发现
22
+ - 用户明确要求更新模型选择
23
+ - 配置向导的 `/models` 端点失败,且内置模型列表过期
24
+
25
+ ## 工作流程
26
+
27
+ 1. 用户选择服务商并提供 API 密钥
28
+ 2. 用 `c7 library <服务商名>` 找到对应的 library ID
29
+ 3. 用 `c7 docs <id> "available models"` 获取当前模型列表
30
+ 4. 从文档中识别:模型名称、能力(推理、编码、视觉)、上下文窗口大小、价格
31
+ 5. 按能力和成本分配到分层:
32
+ - LLM tier1:最强(复杂判断、抽取)
33
+ - LLM tier2-3:中等(常规抽取、简单判断)
34
+ - LLM tier4:最便宜(大量简单任务)
35
+ - VLM tier1-3:视觉模型(文档解析/OCR)
36
+ 6. 更新 `model-tiers.json` 或工作区 `.env`
37
+
38
+ ## 分层原则
39
+
40
+ - 满足准确率阈值的最便宜模型
41
+ - 正则是 tier0 — 比任何 LLM 都小
42
+ - 不需要填满所有分层 — 服务商没有合适模型时留空即可
43
+ - 在 AGENT.md 中记录哪些模型适合哪些任务
44
+
45
+ ## 前置条件
46
+
47
+ ```bash
48
+ npm i -g context7
49
+ ```
50
+
51
+ 验证:`c7 library openai` 应返回结果。
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: pdf-review-dashboard
3
+ description: >
4
+ 生成双栏 PDF 审核面板,用于人工核查验证结果。左侧显示原始 PDF 文档,右侧显示验证结果。
5
+ 点击结果条目可跳转至 PDF 对应页面。当开发者用户需要对照源文件审核验证输出、
6
+ 或为演进循环收集真实标注数据时使用。输出为单个自包含 HTML 文件。
7
+ ---
8
+
9
+ ## 功能
10
+
11
+ 生成单个自包含 HTML 文件:
12
+ - 左侧:浏览器内渲染的原始 PDF
13
+ - 右侧:可交互的验证结果列表
14
+ - 点击跳转:选中结果后 PDF 滚动到对应页面
15
+
16
+ 开发者用户在浏览器中打开此 HTML 即可人工审核验证质量。
17
+
18
+ ## 技术栈
19
+
20
+ - 单 HTML 文件,无需服务器
21
+ - PDF 以 base64 内嵌(完全自包含,可分享)
22
+ - 通过 CDN 加载 pdf.js 实现浏览器内 PDF 渲染
23
+ - 纯 JS + 内联 CSS,无框架依赖
24
+ - 深色主题,与 KC 仪表板风格一致
25
+
26
+ ## 布局
27
+
28
+ - 可拖拽分隔条调整左右面板比例
29
+ - 左侧:PDF 查看器,顶部工具栏含翻页(上一页/下一页/跳转)和缩放(+/-/适应宽度)
30
+ - 右侧:结果列表,带筛选按钮,点击展开详情并跳转 PDF 页面
31
+ - 跳转时页面高亮动画
32
+
33
+ ## 数据格式
34
+
35
+ 生成器脚本读取 PDF 文件和结果 JSON,输出 HTML。
36
+
37
+ 输入:
38
+ - `pdf_path` — 源 PDF 文档路径
39
+ - `results_path` — 验证结果 JSON 文件路径
40
+
41
+ 结果 JSON 为对象数组,每个对象至少包含:
42
+ - 页面引用(对应 PDF 的哪一页)
43
+ - 结果状态(pass/fail/warning 或等效值)
44
+
45
+ 右侧面板的列和详情字段自动适配验证工作流的输出数据。`scripts/generate_review.js` 是参考实现——根据项目输出格式调整数据映射部分。
46
+
47
+ ## 使用时机
48
+
49
+ - 验证工作流完成后,供开发者用户可视化审核结果
50
+ - 为演进循环收集真实标注修正
51
+ - 向需要查看源文件依据的相关方展示结果
52
+
53
+ ## 生成器脚本
54
+
55
+ 见 `scripts/generate_review.js` — Node.js 脚本,输入 PDF 路径,输出审核 HTML。根据项目验证输出格式调整结果数据映射部分。
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PDF Review Dashboard Generator
4
+ *
5
+ * Generates a single self-contained HTML file with:
6
+ * - Left: PDF viewer (pdf.js CDN, base64 embedded)
7
+ * - Right: interactive verification results list
8
+ * - Click result → jump to PDF page
9
+ *
10
+ * Usage:
11
+ * node generate_review.js <pdf_path> <results_json_path> [output_html_path]
12
+ *
13
+ * The results JSON should be an array of objects. Adapt the DATA MAPPING
14
+ * section below to match your project's verification output format.
15
+ */
16
+ import fs from "node:fs";
17
+ import path from "node:path";
18
+
19
+ const pdfPath = process.argv[2];
20
+ const resultsPath = process.argv[3];
21
+ const outputPath = process.argv[4] || "review_dashboard.html";
22
+
23
+ if (!pdfPath || !resultsPath) {
24
+ console.error("Usage: node generate_review.js <pdf_path> <results_json_path> [output_html_path]");
25
+ process.exit(1);
26
+ }
27
+
28
+ // Read inputs
29
+ const pdfBuffer = fs.readFileSync(pdfPath);
30
+ const pdfBase64 = pdfBuffer.toString("base64");
31
+ const pdfFileName = path.basename(pdfPath);
32
+ const rawResults = JSON.parse(fs.readFileSync(resultsPath, "utf-8"));
33
+
34
+ // ============================================================
35
+ // DATA MAPPING — adapt this section to your verification output
36
+ // ============================================================
37
+ // Map your raw results into the format the dashboard expects.
38
+ // Each item needs at minimum: id, label, result, page.
39
+ // Add any extra fields you want shown in the detail panel.
40
+ const results = Array.isArray(rawResults) ? rawResults : rawResults.results || [];
41
+ const mappedResults = results.map((r, i) => ({
42
+ id: r.id || r.rule_id || `R${String(i + 1).padStart(3, "0")}`,
43
+ label: r.rule || r.label || r.name || r.description || `Item ${i + 1}`,
44
+ result: r.result || r.status || "unknown",
45
+ confidence: r.confidence ?? r.score ?? null,
46
+ page: r.page || r.page_ref || 1,
47
+ // Detail fields — include whatever your workflow outputs
48
+ detail: r.detail || Object.fromEntries(
49
+ Object.entries(r).filter(([k]) => !["id","rule_id","rule","label","name","result","status","confidence","score","page","page_ref"].includes(k))
50
+ ),
51
+ }));
52
+ // ============================================================
53
+
54
+ console.log(`PDF: ${pdfFileName} (${(pdfBuffer.length / 1024 / 1024).toFixed(1)}MB)`);
55
+ console.log(`Results: ${mappedResults.length} items`);
56
+
57
+ // Generate HTML
58
+ const html = buildHTML(pdfBase64, pdfFileName, mappedResults);
59
+ fs.writeFileSync(outputPath, html, "utf-8");
60
+ console.log(`Output: ${outputPath} (${(Buffer.byteLength(html) / 1024 / 1024).toFixed(1)}MB)`);
61
+
62
+ function buildHTML(pdfB64, fileName, items) {
63
+ const resultsJSON = JSON.stringify(items);
64
+ return `<!DOCTYPE html>
65
+ <html lang="zh-CN">
66
+ <head>
67
+ <meta charset="UTF-8">
68
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
69
+ <title>KC Review — ${fileName}</title>
70
+ <style>
71
+ * { margin: 0; padding: 0; box-sizing: border-box; }
72
+ :root {
73
+ --bg: #0a0a0a; --bg2: #141414; --bg3: #1e1e1e;
74
+ --text: #e5e5e5; --dim: #888; --border: #2a2a2a;
75
+ --green: #22c55e; --yellow: #eab308; --red: #ef4444;
76
+ --blue: #3b82f6; --orange: #f97316;
77
+ }
78
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); height: 100vh; overflow: hidden; }
79
+ #app { display: flex; height: 100vh; }
80
+ #pdf-panel { flex: 1; display: flex; flex-direction: column; border-right: 1px solid var(--border); min-width: 300px; }
81
+ #pdf-toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--bg2); border-bottom: 1px solid var(--border); flex-shrink: 0; }
82
+ #pdf-toolbar button { background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: 4px; padding: 4px 10px; cursor: pointer; font-size: 13px; }
83
+ #pdf-toolbar button:hover { background: var(--border); }
84
+ #pdf-toolbar span { color: var(--dim); font-size: 13px; }
85
+ #pdf-toolbar input[type=number] { width: 50px; background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: 4px; padding: 4px; text-align: center; font-size: 13px; }
86
+ #pdf-container { flex: 1; overflow: auto; display: flex; flex-direction: column; align-items: center; padding: 16px; gap: 8px; }
87
+ .pdf-page-wrapper { position: relative; box-shadow: 0 2px 8px rgba(0,0,0,0.5); }
88
+ .pdf-page-wrapper canvas { display: block; }
89
+ .page-highlight { position: absolute; inset: 0; background: rgba(59,130,246,0.12); border: 2px solid var(--blue); pointer-events: none; opacity: 0; transition: opacity 0.3s; }
90
+ .page-highlight.active { opacity: 1; animation: pulse-border 1.5s ease-out; }
91
+ @keyframes pulse-border { 0% { border-color: var(--orange); box-shadow: 0 0 20px rgba(249,115,22,0.4); } 100% { border-color: var(--blue); box-shadow: none; } }
92
+ #drag-handle { width: 5px; background: var(--border); cursor: col-resize; flex-shrink: 0; transition: background 0.2s; }
93
+ #drag-handle:hover, #drag-handle.dragging { background: var(--blue); }
94
+ #results-panel { flex: 1; display: flex; flex-direction: column; min-width: 350px; }
95
+ #results-toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--bg2); border-bottom: 1px solid var(--border); flex-shrink: 0; flex-wrap: wrap; }
96
+ #results-toolbar .filter-btn { background: var(--bg3); color: var(--dim); border: 1px solid var(--border); border-radius: 12px; padding: 3px 10px; cursor: pointer; font-size: 12px; transition: all 0.2s; }
97
+ #results-toolbar .filter-btn.active { color: var(--text); border-color: var(--blue); background: rgba(59,130,246,0.15); }
98
+ #results-toolbar .summary { margin-left: auto; font-size: 12px; color: var(--dim); }
99
+ #results-list { flex: 1; overflow: auto; }
100
+ .result-item { border-bottom: 1px solid var(--border); cursor: pointer; transition: background 0.15s; }
101
+ .result-item:hover { background: var(--bg3); }
102
+ .result-item.selected { background: rgba(59,130,246,0.1); border-left: 3px solid var(--blue); }
103
+ .result-row { display: flex; align-items: center; padding: 10px 12px; gap: 10px; }
104
+ .result-id { font-size: 11px; color: var(--dim); min-width: 40px; font-family: monospace; }
105
+ .result-label { flex: 1; font-size: 13px; }
106
+ .result-badge { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 10px; text-transform: uppercase; }
107
+ .badge-pass { background: rgba(34,197,94,0.15); color: var(--green); }
108
+ .badge-fail { background: rgba(239,68,68,0.15); color: var(--red); }
109
+ .badge-warning { background: rgba(234,179,8,0.15); color: var(--yellow); }
110
+ .badge-unknown { background: rgba(136,136,136,0.15); color: var(--dim); }
111
+ .result-confidence { font-size: 12px; color: var(--dim); min-width: 40px; text-align: right; }
112
+ .result-page { font-size: 11px; color: var(--dim); min-width: 30px; text-align: right; }
113
+ .result-detail { display: none; padding: 8px 12px 14px 62px; font-size: 12px; line-height: 1.6; color: var(--dim); border-top: 1px dashed var(--border); }
114
+ .result-item.expanded .result-detail { display: block; }
115
+ .detail-row { margin-bottom: 4px; }
116
+ .detail-key { color: var(--text); font-weight: 500; }
117
+ </style>
118
+ </head>
119
+ <body>
120
+ <div id="app">
121
+ <div id="pdf-panel">
122
+ <div id="pdf-toolbar">
123
+ <button onclick="prevPage()">◀</button>
124
+ <span>Page</span>
125
+ <input type="number" id="page-input" value="1" min="1" onchange="goToPage(this.value)">
126
+ <span id="page-count">/ ?</span>
127
+ <button onclick="nextPage()">▶</button>
128
+ <span style="margin-left:8px">|</span>
129
+ <button onclick="zoomOut()">−</button>
130
+ <span id="zoom-label">100%</span>
131
+ <button onclick="zoomIn()">+</button>
132
+ <button onclick="fitWidth()">Fit</button>
133
+ </div>
134
+ <div id="pdf-container"></div>
135
+ </div>
136
+ <div id="drag-handle"></div>
137
+ <div id="results-panel">
138
+ <div id="results-toolbar">
139
+ <span class="summary" id="results-summary"></span>
140
+ </div>
141
+ <div id="results-list"></div>
142
+ </div>
143
+ </div>
144
+ <script type="module">
145
+ const PDF_B64 = "${pdfB64}";
146
+ const RESULTS = ${resultsJSON};
147
+
148
+ // PDF setup
149
+ const pdfjsLib = await import("https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.10.38/pdf.min.mjs");
150
+ pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.10.38/pdf.worker.min.mjs";
151
+ const pdfData = Uint8Array.from(atob(PDF_B64), c => c.charCodeAt(0));
152
+ const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise;
153
+ const totalPages = pdf.numPages;
154
+ document.getElementById("page-count").textContent = "/ " + totalPages;
155
+ document.getElementById("page-input").max = totalPages;
156
+
157
+ let scale = 1.2, currentPage = 1;
158
+ const container = document.getElementById("pdf-container");
159
+ const pageCanvases = new Map();
160
+
161
+ async function renderAllPages() {
162
+ container.innerHTML = ""; pageCanvases.clear();
163
+ for (let i = 1; i <= totalPages; i++) {
164
+ const page = await pdf.getPage(i);
165
+ const vp = page.getViewport({ scale });
166
+ const w = document.createElement("div");
167
+ w.className = "pdf-page-wrapper"; w.id = "page-" + i;
168
+ w.style.width = vp.width + "px"; w.style.height = vp.height + "px";
169
+ const c = document.createElement("canvas");
170
+ c.width = vp.width; c.height = vp.height;
171
+ await page.render({ canvasContext: c.getContext("2d"), viewport: vp }).promise;
172
+ const hl = document.createElement("div"); hl.className = "page-highlight";
173
+ w.appendChild(c); w.appendChild(hl); container.appendChild(w);
174
+ pageCanvases.set(i, w);
175
+ }
176
+ }
177
+ await renderAllPages();
178
+
179
+ function goToPage(n) { n = Math.max(1, Math.min(parseInt(n)||1, totalPages)); currentPage = n; document.getElementById("page-input").value = n; const el = document.getElementById("page-"+n); if(el) el.scrollIntoView({behavior:"smooth",block:"start"}); }
180
+ function prevPage() { goToPage(currentPage-1); }
181
+ function nextPage() { goToPage(currentPage+1); }
182
+ function zoomIn() { scale = Math.min(scale+0.2, 3); updateZoom(); }
183
+ function zoomOut() { scale = Math.max(scale-0.2, 0.4); updateZoom(); }
184
+ function fitWidth() { pdf.getPage(1).then(p => { scale = (document.getElementById("pdf-panel").clientWidth-40)/p.getViewport({scale:1}).width; updateZoom(); }); }
185
+ function updateZoom() { document.getElementById("zoom-label").textContent = Math.round(scale*100)+"%"; renderAllPages(); }
186
+ window.goToPage=goToPage; window.prevPage=prevPage; window.nextPage=nextPage;
187
+ window.zoomIn=zoomIn; window.zoomOut=zoomOut; window.fitWidth=fitWidth;
188
+
189
+ // Detect unique result statuses for filter buttons
190
+ const statuses = [...new Set(RESULTS.map(r => r.result))];
191
+ const toolbar = document.getElementById("results-toolbar");
192
+ const filterHTML = '<button class="filter-btn active" data-filter="all">All</button>' +
193
+ statuses.map(s => '<button class="filter-btn" data-filter="'+s+'">'+s.charAt(0).toUpperCase()+s.slice(1)+'</button>').join("");
194
+ toolbar.insertAdjacentHTML("afterbegin", filterHTML);
195
+ let activeFilter = "all", selectedId = null;
196
+ toolbar.querySelectorAll(".filter-btn").forEach(b => b.addEventListener("click", () => {
197
+ activeFilter = b.dataset.filter;
198
+ toolbar.querySelectorAll(".filter-btn").forEach(x => x.classList.toggle("active", x.dataset.filter===activeFilter));
199
+ selectedId = null; renderResults();
200
+ }));
201
+
202
+ function renderResults() {
203
+ const list = document.getElementById("results-list");
204
+ const filtered = activeFilter === "all" ? RESULTS : RESULTS.filter(r => r.result === activeFilter);
205
+ const counts = statuses.map(s => RESULTS.filter(r=>r.result===s).length + " " + s).join(" · ");
206
+ document.getElementById("results-summary").textContent = counts;
207
+
208
+ list.innerHTML = filtered.map(r => {
209
+ const bc = ["pass","fail","warning"].includes(r.result) ? "badge-"+r.result : "badge-unknown";
210
+ const sel = r.id === selectedId ? " selected expanded" : "";
211
+ const conf = r.confidence != null ? Math.round(r.confidence*100)+"%" : "";
212
+ let detailHTML = "";
213
+ if (r.detail && typeof r.detail === "object") {
214
+ detailHTML = Object.entries(r.detail).map(([k,v]) =>
215
+ '<div class="detail-row"><span class="detail-key">'+k+': </span>'+String(v)+'</div>'
216
+ ).join("");
217
+ }
218
+ return '<div class="result-item'+sel+'" data-id="'+r.id+'" data-page="'+r.page+'">' +
219
+ '<div class="result-row">' +
220
+ '<span class="result-id">'+r.id+'</span>' +
221
+ '<span class="result-label">'+r.label+'</span>' +
222
+ '<span class="result-badge '+bc+'">'+r.result+'</span>' +
223
+ (conf ? '<span class="result-confidence">'+conf+'</span>' : '') +
224
+ '<span class="result-page">p.'+r.page+'</span>' +
225
+ '</div>' +
226
+ (detailHTML ? '<div class="result-detail">'+detailHTML+'</div>' : '') +
227
+ '</div>';
228
+ }).join("");
229
+
230
+ list.querySelectorAll(".result-item").forEach(el => el.addEventListener("click", () => {
231
+ const id = el.dataset.id, page = parseInt(el.dataset.page);
232
+ if (selectedId === id) { selectedId = null; el.classList.remove("selected","expanded"); }
233
+ else { list.querySelectorAll(".result-item").forEach(e=>e.classList.remove("selected","expanded")); selectedId = id; el.classList.add("selected","expanded"); }
234
+ jumpToPage(page);
235
+ }));
236
+ }
237
+
238
+ function jumpToPage(page) {
239
+ currentPage = page; document.getElementById("page-input").value = page;
240
+ const el = document.getElementById("page-"+page);
241
+ if(el) { el.scrollIntoView({behavior:"smooth",block:"center"});
242
+ const hl = el.querySelector(".page-highlight"); hl.classList.remove("active");
243
+ void hl.offsetWidth; hl.classList.add("active"); setTimeout(()=>hl.classList.remove("active"),2000); }
244
+ }
245
+ renderResults();
246
+
247
+ // Drag handle
248
+ const handle = document.getElementById("drag-handle");
249
+ let dragging = false;
250
+ handle.addEventListener("mousedown", e => { dragging=true; handle.classList.add("dragging"); e.preventDefault(); });
251
+ document.addEventListener("mousemove", e => { if(!dragging) return; const r=e.clientX/document.getElementById("app").clientWidth; const c=Math.max(0.2,Math.min(0.8,r)); document.getElementById("pdf-panel").style.flex="0 0 "+(c*100)+"%"; document.getElementById("results-panel").style.flex="1"; });
252
+ document.addEventListener("mouseup", () => { dragging=false; handle.classList.remove("dragging"); });
253
+
254
+ container.addEventListener("scroll", () => {
255
+ const cr = container.getBoundingClientRect(); let closest=1, cd=Infinity;
256
+ pageCanvases.forEach((w,n) => { const d=Math.abs(w.getBoundingClientRect().top-cr.top); if(d<cd){cd=d;closest=n;} });
257
+ if(closest!==currentPage){currentPage=closest;document.getElementById("page-input").value=closest;}
258
+ });
259
+ </script>
260
+ </body>
261
+ </html>`;
262
+ }
@@ -3,206 +3,121 @@ name: rule-extraction
3
3
  description: Extract and organize business verification rules from regulation documents into discrete, testable units. Use when processing documents in Rules/ to identify individual verification rules, when decomposing a regulation into atomic checks, or when the developer user adds new regulation files. Covers reading regulation text, identifying rule boundaries, determining granularity, handling cross-references, and producing a rule catalog. Also use when rules are provided in structured formats like xlsx or csv.
4
4
  ---
5
5
 
6
- # 法规条文解构与核查规则提取
6
+ # Rule Extraction
7
7
 
8
- ## 核心理念
8
+ Rules are the atoms of verification. Each rule you extract will become its own skill folder, its own workflow, and its own production pipeline.
9
9
 
10
- 规则是整个核查体系的原子单元。一条规则对应一个技能文件夹,一个技能文件夹对应一个可独立测试的核查逻辑。规则提取的质量直接决定后续所有环节的上限——技能编写、工作流蒸馏、质量监控,全部建立在规则提取的基础之上。
10
+ ## How This Differs from Data Extraction
11
11
 
12
- 提取得好,后面事半功倍。提取得差,后面反复返工。
12
+ Rule extraction is a **one-off task** at the start of a project. You read regulation documents and decompose them into discrete, testable rules. This is fuzzy, agile work — rules are read by you (a SOTA agent), so the schema can be messy and evolve freely.
13
13
 
14
- ## 高质量规则的四个特征
14
+ Data/entity extraction (`entity-extraction`) is the **repeating task** that runs on every document being verified. It must fit a unified, stable schema because it feeds into automated workflows.
15
15
 
16
- ### 原子性
16
+ Don't conflate the two. Rule extraction happens once; data extraction happens on every document.
17
17
 
18
- 一条规则只做一件事。如果你发现一条规则需要用「并且」「同时」连接两个独立的判断逻辑,大概率应该拆成两条规则。
18
+ ## Rule Structure: Location → Extraction → Judgment
19
19
 
20
- 反例:「发票日期应在合同有效期内,且发票金额不超过合同总额」——这是两条规则。
20
+ Every verification rule decomposes into three parts:
21
21
 
22
- ### 可测试性
22
+ 1. **Location**: Where in the document to look (which chapter, section, table, or full document).
23
+ 2. **Extraction**: What data to pull from that location (a number, a date, a clause, a description).
24
+ 3. **Judgment**: How to determine pass/fail (threshold comparison, semantic assessment, cross-field check).
23
25
 
24
- 规则的判定结果必须是明确的:通过、不通过、无法判定。不能出现「大致合理」「基本符合」这种模糊结论。如果一条规则无法给出确定性结论,说明它还没提取到位。
26
+ When extracting a rule, explicitly note all three parts. This determines the downstream pipeline structure:
27
+ - Full-document rules need no location step.
28
+ - Single-section rules need one location step.
29
+ - Cross-section rules (comparing values across chapters) need multiple location steps.
25
30
 
26
- ### 自包含性
31
+ Classify each rule's scope accordingly — it affects how the verification workflow is structured.
27
32
 
28
- 规则的执行不应依赖于其他规则的执行结果。每条规则应该能独立运行。如果规则A的判定需要先知道规则B的结果,说明存在耦合,需要重新设计。
33
+ ## Philosophy
29
34
 
30
- 例外:交叉验证类规则(如「发票金额与合同金额一致」)本身就是一条独立规则,它依赖的是数据字段而非其他规则的结论。
35
+ A well-extracted rule is:
36
+ - **Atomic**: it checks one thing. "The borrower's debt-to-income ratio must not exceed 50%" is one rule. "The loan agreement must comply with Regulation X" is not — it is a container for many rules.
37
+ - **Testable**: given a document, you can definitively say whether the rule passes or fails (or is not applicable).
38
+ - **Self-contained**: the rule's meaning does not require reading ten other rules to understand. Cross-references should be resolved into the rule's description.
39
+ - **Scoped**: you know WHERE in the document to look. "Chapter 3, Section 2" or "the risk disclosure section" or "the signature page."
31
40
 
32
- ### 明确的作用域
41
+ But perfection is the enemy of progress. Extract rules at the granularity that feels right for the regulation and the business scenario. You will iterate. The developer user will tell you if rules are too coarse or too fine.
33
42
 
34
- 规则必须清楚说明它适用于什么类型的单据、什么业务场景、什么前提条件。作用域模糊的规则在实际核查中会产生大量误判。
43
+ ## Rule Schema Design Principles
35
44
 
36
- ## 规则体系的系统性设计原则
45
+ Individual rules should be atomic and testable (above). The rule catalog as a whole must also satisfy system-level properties:
37
46
 
38
- 单条规则应当满足上述四个特征。规则目录作为一个整体,还需要满足系统级属性:
47
+ ### Coverage Target
48
+ Extracted rules should cover at least 95% of the regulation's checkable requirements. After initial extraction, perform a coverage audit: read the source regulation end-to-end and mark which paragraphs are covered by at least one rule. Uncovered paragraphs are either non-checkable (definitions, context) or gaps to close.
39
49
 
40
- ### 覆盖度目标
41
- 提取的规则应覆盖法规可核查要求的至少 95%。初次提取完成后,执行覆盖度审计:端到端通读原始法规,标注每个段落是否被至少一条规则覆盖。未覆盖的段落要么是非核查性内容(定义、背景),要么是需要补充的空白。
50
+ ### Atomicity Test
51
+ One rule = one pass/fail outcome. If a rule can produce two independent pass/fail results, it should be two rules. Ask: "Can this rule partially pass?" If yes, decompose further.
42
52
 
43
- ### 原子性测试
44
- 一条规则 = 一个通过/不通过结论。如果一条规则能产出两个独立的通过/不通过结果,它应该被拆为两条规则。自问:「这条规则能部分通过吗?」如果能,继续拆分。
53
+ ### Ambiguity Minimization
54
+ No two rules should produce contradictory results on the same document. After extraction, review rule pairs that touch overlapping scope. If Rule A says pass and Rule B says fail for the same entity, their scope boundaries are unclear — fix them.
45
55
 
46
- ### 歧义最小化
47
- 不能有两条规则对同一文档的同一实体给出矛盾结论。提取完成后,审查作用域重叠的规则对。如果规则 A 判定通过而规则 B 判定不通过(针对同一实体),说明它们的作用域边界不清——必须修正。
56
+ ### Downstream Anticipation
57
+ Rules will be distilled into workflows (see `skill-to-workflow`). Design with distillation in mind: clear input/output boundaries, explicit judgment criteria, minimal reliance on implicit domain knowledge. If a rule requires reading between the lines, make the interpretation explicit. Use `task-decomposition` to identify natural boundaries between rules.
48
58
 
49
- ### 下游预判
50
- 规则最终将被蒸馏为工作流(参见 `skill-to-workflow`)。设计时就要考虑蒸馏的需求:清晰的输入/输出边界、显式的判定标准、尽量减少对隐含领域知识的依赖。如果一条规则需要「读出言外之意」,把那个解读显式写出来。使用 `task-decomposition` 来识别规则之间的自然边界。
59
+ ### Catalog Versioning
60
+ When rules change (additions, modifications, deprecations), version the entire rule catalog as a unit. Individual rule versions track specific rules; the catalog version tracks the coherent set. Record the catalog version in `versions.json` alongside individual rule versions.
51
61
 
52
- ### 目录版本化
53
- 当规则发生变更(新增、修改、废弃)时,将整个规则目录作为一个整体进行版本化。单条规则的版本跟踪的是具体规则;目录版本跟踪的是规则集的一致性状态。在 `versions.json` 中记录目录版本,与单条规则版本并列。
62
+ ## Extraction Strategies
54
63
 
55
- ## 策略一:结构化输入(开发者用户提供规则表格)
64
+ ### Strategy 1: Structured Input (Developer User Provides Rules)
56
65
 
57
- 当开发者用户以 xlsxcsv 或其他结构化格式提供规则清单时,这是最理想的情况。
66
+ When the developer user provides rules in xlsx, csv, or a structured document where each row/entry is a distinct rule with clear scope:
67
+ - Follow their structure exactly. Do not re-decompose.
68
+ - Map each row to a rule, preserving the developer user's identifiers.
69
+ - Ask clarifying questions only if entries are ambiguous.
58
70
 
59
- ### 处理步骤
71
+ ### Strategy 2: Hierarchical Extraction from Regulation Text
60
72
 
61
- 1. 读取文件,理解表格结构(列名、分组方式)
62
- 2. 尊重开发者用户的规则划分——他们比你更懂业务
63
- 3. 为每条规则生成标准编号(R001、R002...)
64
- 4. 检查是否存在隐含的复合规则需要进一步拆分
65
- 5. 补充表格中可能缺失的信息:适用范围、前提条件、判定标准
73
+ For raw regulation documents (PDF, DOCX, legal text):
66
74
 
67
- ### 注意事项
75
+ 1. **Survey the document structure.** Read the table of contents or scan headers. Understand the hierarchy: parts, chapters, sections, articles, clauses.
76
+ 2. **Identify rule-bearing sections.** Not every section contains a verification rule. Some are definitions, some are procedural, some are context. Focus on sections that impose obligations, prohibitions, thresholds, or requirements.
77
+ 3. **Peel the onion.** Start at the highest structural level and work downward:
78
+ - Level 1: What major areas does the regulation cover? (e.g., capital adequacy, risk disclosure, governance)
79
+ - Level 2: Within each area, what are the specific chapters or sections?
80
+ - Level 3: Within each section, what are the individual requirements?
81
+ - Stop peeling when you reach atomic rules.
82
+ 4. **Handle cross-references.** Regulations love to say "as defined in Section X" or "subject to the conditions in Article Y." Resolve these by including the referenced content in the rule's description, not just the reference.
83
+ 5. **Handle compound rules.** "The report must include (a) risk factors, (b) financial projections, and (c) management discussion" — this is three rules, not one. Decompose unless the developer user specifically wants them grouped.
68
84
 
69
- - 不要擅自合并开发者用户已经拆分的规则
70
- - 如果表格中某条规则的描述过于笼统,标记为「待细化」,向开发者用户确认
71
- - 保留原始表格的引用关系(如行号),便于回溯
85
+ For long documents (100+ pages), use the onion-peeler approach described in `references/chunking-strategies.md`. Do not try to read the entire document in one pass.
72
86
 
73
- ## 策略二:从法规原文层层剥解
87
+ ### Strategy 3: Expert Notes
74
88
 
75
- 当输入是法规文件、监管通知、内部制度等非结构化文本时,采用「洋葱剥皮法」逐层提取。
89
+ Sometimes rules come from the developer user's domain expertise rather than formal regulations:
90
+ - "We always check that the guarantor's signature matches the name on page 1."
91
+ - "If the collateral value is below 120% of the loan amount, flag it."
76
92
 
77
- ### 第一层:通览全文结构
93
+ Capture these with the same rigor as formal regulation rules. They are equally important in the verification app.
78
94
 
79
- 快速阅读,识别文件的组织方式:
80
- - 章节编号体系(第X条、第X款、第X项)
81
- - 哪些章节是定义性条款(不含核查规则)
82
- - 哪些章节是实质性要求(包含核查规则)
83
- - 哪些章节是程序性条款(审批流程,可能包含时限类规则)
84
- - 附则、附件中是否有补充规则
95
+ ## Rule Catalog
85
96
 
86
- ### 第二层:识别规则承载段落
97
+ Maintain a lightweight catalog of all extracted rules. This is your index, not the rules themselves (those live in skill folders). The catalog should track:
87
98
 
88
- 聚焦于实质性要求章节,逐段判断:
89
- - 该段落是否包含「应当」「必须」「不得」「需要」等规范性用语?
90
- - 该段落是否描述了可以被验证的具体要求?
91
- - 该段落是叙述性说明还是操作性要求?
99
+ - Rule ID (simple sequential: R001, R002, ...)
100
+ - Rule title (one line)
101
+ - Source (which regulation document, which section)
102
+ - Status (extracted / skill-written / skill-tested / workflow-written / workflow-tested / production)
103
+ - Dependencies (rules that must be checked before this one)
92
104
 
93
- 只有包含可核查要求的段落才进入下一层处理。
105
+ Format: a simple markdown table or JSON file. Do not over-engineer this. The catalog exists to give you and the developer user an overview of progress.
94
106
 
95
- ### 第三层:逐段提取规则
107
+ ## Handling Ambiguity
96
108
 
97
- 对每个规则承载段落:
109
+ Regulations are often ambiguous. When you encounter ambiguity:
110
+ 1. Extract the rule as you understand it.
111
+ 2. Note the ambiguity explicitly in the rule description.
112
+ 3. Ask the developer user for clarification.
113
+ 4. Update the rule after receiving clarification.
98
114
 
99
- 1. 提取核查对象(哪个字段、哪份单据)
100
- 2. 提取核查标准(什么条件、什么阈值)
101
- 3. 提取适用范围(什么业务场景、什么前提条件)
102
- 4. 提取例外情形(什么情况下不适用)
103
- 5. 标注原文位置(法规名称 + 条款编号)
115
+ Do not skip ambiguous rules. They are often the most important ones.
104
116
 
105
- ### 第四层:处理交叉引用
117
+ ## When Rules Change
106
118
 
107
- 法规文本中常见的交叉引用模式:
108
- - 「依据本办法第X条规定」——需要找到被引用条款,整合上下文
109
- - 「参照XX法规执行」——需要确认外部法规是否在 `Rules/` 中,如果没有则标记为待补充
110
- - 「前款所述情形」——需要回溯上文,明确指代
111
-
112
- 处理原则:将交叉引用解析为自包含的规则描述,在规则的 `references/` 中保留原始引用关系。
113
-
114
- ### 第五层:拆解复合规则
115
-
116
- 识别并拆分以下模式:
117
-
118
- - 并列条件:「A且B」→ 拆为规则A、规则B
119
- - 条件分支:「若X则A,若Y则B」→ 拆为规则A(前提X)、规则B(前提Y)
120
- - 阶梯条件:「金额≤10万执行A流程,金额>10万执行B流程」→ 拆为规则A(阈值条件)、规则B(阈值条件)
121
-
122
- 不需要拆分的情形:
123
- - 规则本身就是一个条件判断:「发票日期应在合同有效期内」——这就是一条原子规则
124
- - 规则包含多个字段但逻辑统一:「收款单位名称、账号应与合同约定一致」——可以保留为一条规则,因为核查逻辑相同
125
-
126
- ## 策略三:开发者用户口述的专家经验
127
-
128
- 有时候开发者用户不会给你法规文件,而是直接告诉你业务经验和核查要点。这种输入同样有效。
129
-
130
- ### 处理方式
131
-
132
- 1. 完整记录开发者用户的口述内容
133
- 2. 将口述转化为结构化规则(编号、名称、核查逻辑、判定标准)
134
- 3. 回读给开发者用户确认,特别注意:
135
- - 是否遗漏了隐含的前提条件
136
- - 阈值和标准是否准确
137
- - 是否有例外情况没提到
138
- 4. 在规则来源中标注「专家经验」而非法规条文
139
-
140
- ## 规则目录管理
141
-
142
- 所有提取的规则汇总为一份轻量级目录,存放在工作空间根目录的 `rule-catalog.json` 中:
143
-
144
- ```json
145
- {
146
- "rules": [
147
- {
148
- "id": "R001",
149
- "name": "发票日期有效性",
150
- "source": "《增值税发票管理办法》第十五条",
151
- "status": "extracted",
152
- "priority": "high",
153
- "skill_folder": "rule-skills/R001-invoice-date-validity/",
154
- "notes": ""
155
- }
156
- ],
157
- "total": 1,
158
- "extracted": 1,
159
- "skill_authored": 0,
160
- "workflow_distilled": 0,
161
- "last_updated": "<时间戳>"
162
- }
163
- ```
164
-
165
- ### 状态流转
166
-
167
- 每条规则的生命周期状态:
168
-
169
- ```
170
- extracted → skill_authored → skill_tested → workflow_distilled → workflow_tested → production
171
- ```
172
-
173
- 目录中实时跟踪每条规则所处的阶段。
174
-
175
- ## 处理模糊与歧义
176
-
177
- 法规条文中经常存在模糊表述,如「合理期限内」「必要时」「视情况而定」。处理原则:
178
-
179
- 1. **先提取,不要跳过**——模糊不等于不重要
180
- 2. **在规则中标注歧义**——明确指出哪个部分存在解读空间
181
- 3. **向开发者用户确认**——提供你的理解,请开发者用户裁定
182
- 4. **确认后更新规则**——将开发者用户的裁定写入规则描述
183
-
184
- 绝对不要自行决定模糊条款的含义。你对业务的理解不如开发者用户。
185
-
186
- ## 法规变更时的处理
187
-
188
- 当 `Rules/` 中新增或修改了法规文件时:
189
-
190
- 1. 对比新旧版本,识别变更点
191
- 2. 定位受影响的已有规则
192
- 3. 判断影响程度:
193
- - 措辞调整但核查逻辑不变——更新引用文本,无需重新测试
194
- - 阈值或标准变更——更新规则参数,需要重新测试
195
- - 新增核查要求——提取新规则
196
- - 废止原有要求——将规则标记为 `deprecated`,不删除
197
- 4. 更新规则目录
198
- 5. 通知开发者用户变更影响范围
199
-
200
- ## 输出交付物
201
-
202
- 规则提取阶段完成后,应产出:
203
-
204
- 1. `rule-catalog.json`——规则总目录
205
- 2. 每条规则的初始描述文档(存放在对应技能文件夹的草稿中)
206
- 3. 模糊与歧义清单(待开发者用户确认)
207
- 4. 交叉引用映射(规则之间、规则与法规之间的引用关系)
208
- 5. 向开发者用户汇报提取结果的摘要
119
+ Regulations evolve. When the developer user adds new or updated regulation documents:
120
+ 1. Identify which existing rules are affected.
121
+ 2. Extract new rules or update existing ones.
122
+ 3. Mark affected workflows for re-testing.
123
+ 4. Use `version-control` to track the change.