oh-my-knowledge 0.46.0 → 0.47.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 +17 -3
- package/README.zh.md +17 -3
- package/dist/cli/commands/doctor.js +2 -1
- package/dist/cli/commands/eval/index.js +8 -0
- package/dist/cli/lib/i18n-dict/run.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/run.js +4 -0
- package/dist/doctor/renderer.d.ts +1 -0
- package/dist/doctor/renderer.js +63 -0
- package/dist/eval-core/verdict.d.ts +2 -2
- package/dist/eval-core/verdict.js +36 -2
- package/dist/eval-workflows/messages.js +2 -2
- package/dist/eval-workflows/run-evaluation.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
**English** | [简体中文](./README.zh.md)
|
|
10
10
|
|
|
11
|
-
**
|
|
12
|
-
|
|
11
|
+
**Is this knowledge input (prompt / skill / RAG / agent) any good, and can you ship it with evidence?**
|
|
12
|
+
`doctor` checks whether this knowledge input is coherent enough to measure; `eval` fixes the model and samples, changes only the knowledge input, and tells you whether the new version is genuinely better. Bootstrap CI and length-debias are on by default; Krippendorff α appears the moment you add a gold set.
|
|
13
13
|
|
|
14
14
|
📖 **Full documentation: [oh-my-knowledge.pages.dev](https://oh-my-knowledge.pages.dev)** (searchable, English / 简体中文)
|
|
15
15
|
|
|
@@ -35,6 +35,20 @@ Walkthrough: [5-minute quickstart guide](docs/quickstart-skill-eval.md) (recomme
|
|
|
35
35
|
|
|
36
36
|
Deeper: [who omk is for](docs/explanation/who-omk-is-for.md) · [CLI reference](docs/reference/cli.md) · [how it works](docs/explanation/architecture.md) · [eval sample format](docs/reference/eval-sample-format.md) · [executors](docs/reference/executors.md) · [artifact layout](docs/reference/artifact-layout.md)
|
|
37
37
|
|
|
38
|
+
## The first workflow
|
|
39
|
+
|
|
40
|
+
omk is primarily for authors and maintainers of LLM knowledge artifacts who need a release decision, not for passive end-users of a skill. The first workflow is deliberately small:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
change a skill / prompt / agent artifact
|
|
44
|
+
→ run omk doctor to catch structure, dependency, and measurability problems
|
|
45
|
+
→ run omk eval to compare against a baseline on the same samples
|
|
46
|
+
→ read the report / Studio view for the next concrete fix
|
|
47
|
+
→ decide ship / don't ship
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`observe` is the later production-feedback loop: useful once real usage traces exist, but not required for omk's first value. The trunk is the pre-ship doctor → eval decision.
|
|
51
|
+
|
|
38
52
|
## Use inside AI Coding Agents
|
|
39
53
|
|
|
40
54
|
Install the official omk Agent Skill to let your coding agent run omk workflows from natural language:
|
|
@@ -73,7 +87,7 @@ You can also describe the goal in natural language, such as "compare v1 vs v2" o
|
|
|
73
87
|
|
|
74
88
|
## Why this tool
|
|
75
89
|
|
|
76
|
-
Teams doing knowledge engineering produce lots of knowledge artifacts (skills today, but also prompts, agents, workflows…). When someone asks "
|
|
90
|
+
Teams doing knowledge engineering produce lots of knowledge artifacts (skills today, but also prompts, agents, workflows…). When someone asks "can we ship v2, and why?", you need objective data instead of gut feeling. `oh-my-knowledge` solves this with controlled experiments: **same model, same test samples, only the knowledge artifact changes.**
|
|
77
91
|
|
|
78
92
|
## Why omk over alternatives
|
|
79
93
|
|
package/README.zh.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
[English](./README.md) | **简体中文**
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
**一段知识输入(prompt / skill / RAG / agent)好不好,能不能有证据地发布?**
|
|
12
|
+
`doctor` 先检查这类知识输入是否清楚到值得测;`eval` 固定模型和用例,只改变知识输入,判断新版本是否真的更好。Bootstrap 置信区间、长度去偏默认开,配一份人工 gold 就自动算 Krippendorff α。
|
|
13
13
|
|
|
14
14
|
📖 **完整文档:[oh-my-knowledge.pages.dev/zh](https://oh-my-knowledge.pages.dev/zh/)**(可搜索,可切换英文)
|
|
15
15
|
|
|
@@ -35,6 +35,20 @@ omk eval --control code-review-v1 --treatment code-review-v2
|
|
|
35
35
|
|
|
36
36
|
深入:[为谁、解决什么](docs/zh/explanation/who-omk-is-for.md) · [CLI 参考](docs/zh/reference/cli.md) · [工作原理](docs/zh/explanation/architecture.md) · [评测用例格式](docs/zh/reference/eval-sample-format.md) · [执行器](docs/zh/reference/executors.md) · [artifact 布局](docs/zh/reference/artifact-layout.md)
|
|
37
37
|
|
|
38
|
+
## 第一条工作流
|
|
39
|
+
|
|
40
|
+
omk 主要给 LLM 知识载体的作者 / 维护者用,帮他们做发布判断;它不是给被动安装 skill 的普通使用者用的。第一条工作流应该很短:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
改了一个 skill / prompt / agent artifact
|
|
44
|
+
→ 跑 omk doctor,先抓结构、依赖和可测性问题
|
|
45
|
+
→ 跑 omk eval,在同一批用例上和 baseline 对比
|
|
46
|
+
→ 看报告 / Studio,知道下一步具体该改哪里
|
|
47
|
+
→ 决定发布 / 不发布
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`observe` 是后续的生产反馈闭环:等真实使用 trace 存在后很有价值,但不是 omk 第一价值的前提。主干先是发布前的 doctor → eval 判断。
|
|
51
|
+
|
|
38
52
|
## 在 AI Coding Agent 中使用
|
|
39
53
|
|
|
40
54
|
安装 omk 官方 Agent Skill 后,可以直接用自然语言让 coding agent 跑 omk 工作流:
|
|
@@ -73,7 +87,7 @@ omk sample skills/my-skill.md
|
|
|
73
87
|
|
|
74
88
|
## 为什么需要这个工具
|
|
75
89
|
|
|
76
|
-
做知识工程的团队会产出大量知识载体(当前常见是 skill,也包括 prompt、agent、workflow 等)。当被问到「v2
|
|
90
|
+
做知识工程的团队会产出大量知识载体(当前常见是 skill,也包括 prompt、agent、workflow 等)。当被问到「v2 能不能发、为什么」时,需要客观数据而非主观判断。`oh-my-knowledge` 通过控制变量实验解决这个问题:**相同模型、相同评测用例,只改变知识载体。**
|
|
77
91
|
|
|
78
92
|
## 为什么选 omk
|
|
79
93
|
|
|
@@ -178,7 +178,7 @@ export default class Doctor extends BaseCommand {
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
const { runDoctor } = await import('../../doctor/index.js');
|
|
181
|
-
const { renderDoctorReportText, renderDoctorReportJson } = await import('../../doctor/renderer.js');
|
|
181
|
+
const { renderDoctorReportText, renderDoctorReportJson, renderDoctorActionPlanText } = await import('../../doctor/renderer.js');
|
|
182
182
|
const { getRegisteredRules } = await import('../../doctor/rules.js');
|
|
183
183
|
const { isComposerRule } = await import('../../types/doctor.js');
|
|
184
184
|
// 默认:静态规则 + 在线检查(LLM health composer + endpoint 自定义维度 external=true)。
|
|
@@ -236,6 +236,7 @@ export default class Doctor extends BaseCommand {
|
|
|
236
236
|
? `doctor failed: ${report.totals.fail} 个 skill 未通过 (${report.totals.warn} warn / ${report.totals.pass} pass)`
|
|
237
237
|
: `doctor failed: ${report.totals.fail} skills did not pass (${report.totals.warn} warn / ${report.totals.pass} pass)`;
|
|
238
238
|
console.error(summary);
|
|
239
|
+
process.stderr.write(renderDoctorActionPlanText(report, lang));
|
|
239
240
|
}
|
|
240
241
|
}
|
|
241
242
|
else {
|
|
@@ -152,6 +152,14 @@ async function emitBatchVerdict(report, reportsDir, values, lang) {
|
|
|
152
152
|
for (const result of results) {
|
|
153
153
|
emitVerdictText(` ${result.verdict.level}: ${result.treatment} — ${result.verdict.headline}`);
|
|
154
154
|
}
|
|
155
|
+
const next = lang === 'zh'
|
|
156
|
+
? (failed === 0
|
|
157
|
+
? '全部通过,可以进入发布流程:请留存这些报告作为发布证据;如果是受管 skill,再运行 `omk promote`。'
|
|
158
|
+
: '先处理未通过的 skill;逐个打开对应报告,看最差层和失败用例后再重跑。')
|
|
159
|
+
: (failed === 0
|
|
160
|
+
? 'all skills passed and are ready for release: keep these reports as release evidence; for managed skills, run `omk promote`.'
|
|
161
|
+
: 'fix the failing skills first; open each report, inspect the weakest layer and failing samples, then re-run.');
|
|
162
|
+
emitVerdictText(tCli('cli.run.batch_verdict_next_step', lang, { next }));
|
|
155
163
|
return failed === 0 ? 0 : 1;
|
|
156
164
|
}
|
|
157
165
|
async function announceSavedReport({ report, filePath, reportsDir, values, lang, }) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { CliMessage } from './types.js';
|
|
2
|
-
export type RunMessageKey = 'cli.progress.preflight_starting' | 'cli.progress.sample_retry' | 'cli.progress.sample_error' | 'cli.progress.sample_executing' | 'cli.progress.sample_exec_done' | 'cli.progress.output_preview' | 'cli.progress.judging' | 'cli.progress.judged' | 'cli.progress.skipped' | 'cli.progress.sample_done' | 'cli.progress.sample_failed_done' | 'cli.run.invalid_repeat' | 'cli.run.invalid_holdout_ratio' | 'cli.run.invalid_judge_repeat' | 'cli.run.no_debias_length_active' | 'cli.run.invalid_bootstrap_samples' | 'cli.run.bootstrap_samples_too_large' | 'cli.run.dry_run_no_scores' | 'cli.run.skill_section' | 'cli.run.run_section' | 'cli.run.batch_complete' | 'cli.run.batch_verdict_header' | 'cli.run.batch_child_report_missing' | 'cli.run.eval_complete' | 'cli.run.tally' | 'cli.run.report_saved' | 'cli.run.evidence_recorded' | 'cli.run.evidence_recorded_unbound' | 'cli.run.report_only_gate_skipped' | 'cli.run.report_server_running' | 'cli.run.report_server_view' | 'cli.run.report_server_stop' | 'cli.run.no_serve_in_non_tty' | 'cli.run.no_serve_view_hint' | 'cli.run.gold_load_failed' | 'cli.run.gold_load_issue' | 'cli.run.contamination_warning' | 'cli.run.skip_connectivity_warning';
|
|
2
|
+
export type RunMessageKey = 'cli.progress.preflight_starting' | 'cli.progress.sample_retry' | 'cli.progress.sample_error' | 'cli.progress.sample_executing' | 'cli.progress.sample_exec_done' | 'cli.progress.output_preview' | 'cli.progress.judging' | 'cli.progress.judged' | 'cli.progress.skipped' | 'cli.progress.sample_done' | 'cli.progress.sample_failed_done' | 'cli.run.invalid_repeat' | 'cli.run.invalid_holdout_ratio' | 'cli.run.invalid_judge_repeat' | 'cli.run.no_debias_length_active' | 'cli.run.invalid_bootstrap_samples' | 'cli.run.bootstrap_samples_too_large' | 'cli.run.dry_run_no_scores' | 'cli.run.skill_section' | 'cli.run.run_section' | 'cli.run.batch_complete' | 'cli.run.batch_verdict_header' | 'cli.run.batch_verdict_next_step' | 'cli.run.batch_child_report_missing' | 'cli.run.eval_complete' | 'cli.run.tally' | 'cli.run.report_saved' | 'cli.run.evidence_recorded' | 'cli.run.evidence_recorded_unbound' | 'cli.run.report_only_gate_skipped' | 'cli.run.report_server_running' | 'cli.run.report_server_view' | 'cli.run.report_server_stop' | 'cli.run.no_serve_in_non_tty' | 'cli.run.no_serve_view_hint' | 'cli.run.gold_load_failed' | 'cli.run.gold_load_issue' | 'cli.run.contamination_warning' | 'cli.run.skip_connectivity_warning';
|
|
3
3
|
export declare const runDict: Record<RunMessageKey, CliMessage>;
|
|
@@ -87,6 +87,10 @@ export const runDict = {
|
|
|
87
87
|
zh: '批量评测结论:{status}({passed}/{total} 通过)',
|
|
88
88
|
en: 'Batch verdict: {status} ({passed}/{total} passed)',
|
|
89
89
|
},
|
|
90
|
+
'cli.run.batch_verdict_next_step': {
|
|
91
|
+
zh: ' 下一步:{next}',
|
|
92
|
+
en: ' Next: {next}',
|
|
93
|
+
},
|
|
90
94
|
'cli.run.batch_child_report_missing': {
|
|
91
95
|
zh: '⚠ 子报告缺失:{id},将按不可 ship 处理。\n',
|
|
92
96
|
en: '⚠ Child report missing: {id}; treating it as not shippable.\n',
|
|
@@ -12,5 +12,6 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { Lang } from '../types/shared.js';
|
|
14
14
|
import type { DoctorReport } from '../types/index.js';
|
|
15
|
+
export declare function renderDoctorActionPlanText(report: DoctorReport, lang: Lang): string;
|
|
15
16
|
export declare function renderDoctorReportText(report: DoctorReport, lang: Lang, write?: (s: string) => void): void;
|
|
16
17
|
export declare function renderDoctorReportJson(report: DoctorReport): string;
|
package/dist/doctor/renderer.js
CHANGED
|
@@ -43,6 +43,68 @@ function renderRuleLine(result, ruleLabel, lang, indent = ' ') {
|
|
|
43
43
|
}
|
|
44
44
|
return line;
|
|
45
45
|
}
|
|
46
|
+
function compactActionText(text) {
|
|
47
|
+
return (text ?? '').replace(/\s+/g, ' ').trim();
|
|
48
|
+
}
|
|
49
|
+
function collectDoctorRepairItems(report, lang) {
|
|
50
|
+
const allItems = [];
|
|
51
|
+
for (const skill of report.skills) {
|
|
52
|
+
for (const result of skill.results) {
|
|
53
|
+
if (result.status !== 'fail' && result.status !== 'warn')
|
|
54
|
+
continue;
|
|
55
|
+
const action = compactActionText(result.hint || result.message);
|
|
56
|
+
allItems.push({
|
|
57
|
+
skillName: skill.skillName,
|
|
58
|
+
status: result.status,
|
|
59
|
+
label: renderRuleLabel(result, lang),
|
|
60
|
+
action,
|
|
61
|
+
isSummary: result.ruleId.endsWith(':_summary'),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const focusedItems = allItems.filter((item) => !item.isSummary);
|
|
66
|
+
const source = focusedItems.length > 0 ? focusedItems : allItems;
|
|
67
|
+
const sorted = [...source].sort((a, b) => STATUS_RANK[a.status] - STATUS_RANK[b.status]);
|
|
68
|
+
return { items: sorted.slice(0, 6), total: source.length };
|
|
69
|
+
}
|
|
70
|
+
export function renderDoctorActionPlanText(report, lang) {
|
|
71
|
+
const { items, total } = collectDoctorRepairItems(report, lang);
|
|
72
|
+
if (items.length === 0) {
|
|
73
|
+
return lang === 'zh'
|
|
74
|
+
? '\n下一步:doctor 已通过,可以继续运行 `omk eval`。\n'
|
|
75
|
+
: '\nNext: doctor passed; continue with `omk eval`.\n';
|
|
76
|
+
}
|
|
77
|
+
const hasFail = items.some((item) => item.status === 'fail');
|
|
78
|
+
const lines = [
|
|
79
|
+
'',
|
|
80
|
+
lang === 'zh'
|
|
81
|
+
? (hasFail ? '修复清单(先处理阻塞项):' : '修复清单(建议处理,不阻断 eval):')
|
|
82
|
+
: (hasFail ? 'Repair checklist (fix blocking items first):' : 'Repair checklist (recommended; does not block eval):'),
|
|
83
|
+
];
|
|
84
|
+
items.forEach((item, index) => {
|
|
85
|
+
const status = statusLabel(item.status, lang);
|
|
86
|
+
if (lang === 'zh') {
|
|
87
|
+
lines.push(` ${index + 1}. [${item.skillName}] ${status}:${item.label}。${item.action}`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
lines.push(` ${index + 1}. [${item.skillName}] ${status}: ${item.label}. ${item.action}`);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
const remaining = total - items.length;
|
|
94
|
+
if (remaining > 0) {
|
|
95
|
+
lines.push(lang === 'zh'
|
|
96
|
+
? ` ……还有 ${remaining} 项,运行 \`omk doctor\` 查看完整明细。`
|
|
97
|
+
: ` ...and ${remaining} more; run \`omk doctor\` for full detail.`);
|
|
98
|
+
}
|
|
99
|
+
lines.push(hasFail
|
|
100
|
+
? (lang === 'zh'
|
|
101
|
+
? '下一步:先修阻塞项,重跑 `omk doctor --gate`;通过后再跑 `omk eval`。'
|
|
102
|
+
: 'Next: fix the blocking items, re-run `omk doctor --gate`, then run `omk eval`.')
|
|
103
|
+
: (lang === 'zh'
|
|
104
|
+
? '下一步:可以先跑 `omk eval`,但发布前建议把这些 warning 处理掉。'
|
|
105
|
+
: 'Next: you can run `omk eval`, but clear these warnings before shipping.'));
|
|
106
|
+
return `${lines.join('\n')}\n`;
|
|
107
|
+
}
|
|
46
108
|
function segmentResults(results) {
|
|
47
109
|
const segs = [];
|
|
48
110
|
const groupSegMap = new Map();
|
|
@@ -115,6 +177,7 @@ export function renderDoctorReportText(report, lang, write = (s) => process.stde
|
|
|
115
177
|
? `\n总览: ${report.totals.pass} 通过 / ${report.totals.warn} 警告 / ${report.totals.fail} 失败\n`
|
|
116
178
|
: `\nSummary: ${report.totals.pass} pass / ${report.totals.warn} warn / ${report.totals.fail} fail\n`;
|
|
117
179
|
write(summary);
|
|
180
|
+
write(renderDoctorActionPlanText(report, lang));
|
|
118
181
|
}
|
|
119
182
|
export function renderDoctorReportJson(report) {
|
|
120
183
|
return JSON.stringify(report, null, 2);
|
|
@@ -166,8 +166,8 @@ export declare function medianStabilityCV(report: Report): {
|
|
|
166
166
|
cv: number;
|
|
167
167
|
} | null;
|
|
168
168
|
/**
|
|
169
|
-
* Plain-text formatter for the `omk eval` verdict. Stays
|
|
170
|
-
* spec — one verdict
|
|
169
|
+
* Plain-text formatter for the `omk eval` verdict. Stays terse for the
|
|
170
|
+
* spec — one verdict, rationale bullets, one ship recommendation, and one next step.
|
|
171
171
|
*/
|
|
172
172
|
export declare function formatVerdictText(result: VerdictResult, options?: {
|
|
173
173
|
verbose?: boolean;
|
|
@@ -108,6 +108,7 @@ export function computeVerdict(report, options = {}) {
|
|
|
108
108
|
...(judgeInd.rationale ? { judgeAgreement: judgeInd.rationale } : {}),
|
|
109
109
|
...(overfit.rationale ? { overfitting: overfit.rationale } : {}),
|
|
110
110
|
...(gap.rationale ? { gapSignal: gap.rationale } : {}),
|
|
111
|
+
shipRecommendation: recommendation('SOLO', []),
|
|
111
112
|
},
|
|
112
113
|
...((overfit.data || gap.data) ? {
|
|
113
114
|
caveats: {
|
|
@@ -583,9 +584,41 @@ function recommendation(level, _perPair, lang = 'en') {
|
|
|
583
584
|
return 'ADD A CONTROL — single-variant report. Re-run with --control baseline --treatment <name>.';
|
|
584
585
|
}
|
|
585
586
|
}
|
|
587
|
+
function releaseNextStep(level, lang) {
|
|
588
|
+
if (lang === 'zh') {
|
|
589
|
+
switch (level) {
|
|
590
|
+
case 'PROGRESS':
|
|
591
|
+
return '可以进入发布流程:请留存本次报告作为发布证据;如果这是受管 skill,再运行 `omk promote`。';
|
|
592
|
+
case 'CAUTIOUS':
|
|
593
|
+
return '先看触发的告警(分层门控、评委分歧、稳定性或 holdout),修完再重跑。';
|
|
594
|
+
case 'REGRESS':
|
|
595
|
+
return '不要发布;定位最差层和失败用例,修复后重跑。';
|
|
596
|
+
case 'NOISE':
|
|
597
|
+
return '先别发布;增加样本数或提高用例区分度,再重跑。';
|
|
598
|
+
case 'UNDERPOWERED':
|
|
599
|
+
return '把样本数加到至少 20,或先按当前规模 2× 扩充后重跑。';
|
|
600
|
+
case 'SOLO':
|
|
601
|
+
return '补一个 baseline 对照,再跑 `omk eval --control baseline --treatment <名字>`。';
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
switch (level) {
|
|
605
|
+
case 'PROGRESS':
|
|
606
|
+
return 'ready for release: keep this report as release evidence; for a managed skill, run `omk promote`.';
|
|
607
|
+
case 'CAUTIOUS':
|
|
608
|
+
return 'inspect the warnings (layer gates, judge dissent, stability, or holdout), fix them, then re-run.';
|
|
609
|
+
case 'REGRESS':
|
|
610
|
+
return 'do not ship; inspect the weakest layer and failing samples, fix them, then re-run.';
|
|
611
|
+
case 'NOISE':
|
|
612
|
+
return 'do not ship yet; add samples or sharpen the test set, then re-run.';
|
|
613
|
+
case 'UNDERPOWERED':
|
|
614
|
+
return 'increase the sample set to at least 20, or roughly 2x the current size, then re-run.';
|
|
615
|
+
case 'SOLO':
|
|
616
|
+
return 'add a baseline control and re-run `omk eval --control baseline --treatment <name>`.';
|
|
617
|
+
}
|
|
618
|
+
}
|
|
586
619
|
/**
|
|
587
|
-
* Plain-text formatter for the `omk eval` verdict. Stays
|
|
588
|
-
* spec — one verdict
|
|
620
|
+
* Plain-text formatter for the `omk eval` verdict. Stays terse for the
|
|
621
|
+
* spec — one verdict, rationale bullets, one ship recommendation, and one next step.
|
|
589
622
|
*/
|
|
590
623
|
export function formatVerdictText(result, options = {}) {
|
|
591
624
|
// lang 默认 'en':保留既有英文输出逐字节不变(verdict.test 与历史 CLI 行为)。zh 只本地化
|
|
@@ -609,6 +642,7 @@ export function formatVerdictText(result, options = {}) {
|
|
|
609
642
|
lines.push(zh ? ` 知识缺口:${result.rationale.gapSignal}` : ` Gap signal: ${result.rationale.gapSignal}`);
|
|
610
643
|
if (result.rationale.shipRecommendation) {
|
|
611
644
|
lines.push(` ${zh ? recommendation(result.level, [], 'zh') : result.rationale.shipRecommendation}`);
|
|
645
|
+
lines.push(zh ? ` 下一步:${releaseNextStep(result.level, 'zh')}` : ` Next: ${releaseNextStep(result.level, 'en')}`);
|
|
612
646
|
}
|
|
613
647
|
if (options.verbose && result.perPair && result.perPair.length > 1) {
|
|
614
648
|
lines.push('');
|
|
@@ -12,8 +12,8 @@ const MESSAGES = {
|
|
|
12
12
|
en: '⚠ --repeat=1: single-run cannot measure stability (CV will be marked "not measured"). Use --repeat 3+ to detect within-variant variance.',
|
|
13
13
|
},
|
|
14
14
|
doctor_gate_blocked: {
|
|
15
|
-
zh: '
|
|
16
|
-
en: '
|
|
15
|
+
zh: '发布前 doctor 门禁未通过,评测已中止。\n下一步:先修复上面的阻塞项,再重跑 `omk eval`。\n原因:这段输入还不值得测,继续比较分数会是 garbage-in。\n如果依赖确实由 mock / stub 提供、doctor 误报,可用 `--skip-doctor` 绕过,但这次结果由你承担不可比风险。',
|
|
16
|
+
en: 'pre-ship doctor gate failed; evaluation aborted.\nNext: fix the blocking findings above, then re-run `omk eval`.\nWhy: this input is not measurable enough yet, and comparing scores now would be garbage-in.\nIf deps are truly supplied by mocks/stubs and doctor is a false positive, use `--skip-doctor`, but you own the comparability risk.',
|
|
17
17
|
},
|
|
18
18
|
};
|
|
19
19
|
const DEFAULT_LANG = 'zh';
|
|
@@ -62,7 +62,7 @@ export async function runEvaluation({ samplesPath, skillDir, variantSpecs = [],
|
|
|
62
62
|
});
|
|
63
63
|
if (doctorReport.outcome === 'failed') {
|
|
64
64
|
renderDoctorReportText(doctorReport, lang);
|
|
65
|
-
throw new Error(`doctor failed
|
|
65
|
+
throw new Error(`doctor failed:\n${tEvalWorkflowMessage('doctor_gate_blocked', lang)}`);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-knowledge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"packageManager": "yarn@4.16.0",
|
|
5
5
|
"description": "Evaluation framework for LLM knowledge inputs — prompts, RAG corpora, skills, agent workflows. Fix the model, vary the artifact. Built-in statistical rigor: bootstrap CI, Krippendorff α, length-debias, saturation curves.",
|
|
6
6
|
"type": "module",
|
|
@@ -93,11 +93,11 @@
|
|
|
93
93
|
"license": "MIT",
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@anthropic-ai/claude-agent-sdk": "^0.3.143",
|
|
96
|
-
"@anthropic-ai/sdk": "^0.
|
|
96
|
+
"@anthropic-ai/sdk": "^0.107.0",
|
|
97
97
|
"@inquirer/prompts": "^8.4.3",
|
|
98
98
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
99
99
|
"@oclif/core": "^4",
|
|
100
|
-
"@openai/codex-sdk": "0.
|
|
100
|
+
"@openai/codex-sdk": "0.142.4",
|
|
101
101
|
"ajv": "^8.18.0",
|
|
102
102
|
"chart.js": "^4.5.1",
|
|
103
103
|
"js-yaml": "^4.1.1",
|
|
@@ -112,11 +112,11 @@
|
|
|
112
112
|
"@types/node": "^25.5.0",
|
|
113
113
|
"eslint": "^10.1.0",
|
|
114
114
|
"husky": "^9.1.7",
|
|
115
|
-
"lint-staged": "17.0.
|
|
115
|
+
"lint-staged": "17.0.8",
|
|
116
116
|
"npm-run-all2": "^9.0.1",
|
|
117
117
|
"typescript": "^6.0.2",
|
|
118
118
|
"typescript-eslint": "^8.58.0",
|
|
119
119
|
"vitepress": "^1.6.4",
|
|
120
|
-
"vitest": "4.1.
|
|
120
|
+
"vitest": "4.1.9"
|
|
121
121
|
}
|
|
122
122
|
}
|