oh-my-knowledge 0.49.0 → 0.51.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.
|
@@ -599,7 +599,7 @@ omk sample [skillPath] [flags]
|
|
|
599
599
|
- `--executor` `option`:执行器名。Codex 任务内自动用 codex;也可用 OMK_EXECUTOR 设置环境偏好。
|
|
600
600
|
- `--fix` `boolean`:fix 模式:基于最近评测报告自动修复 sample_design 类型失败。
|
|
601
601
|
- `--focus` `option`:生成焦点(自然语言提示)。控制 LLM 偏向哪类用例。
|
|
602
|
-
- `--from-traces` `boolean`:from-traces 模式:从 observe inbox
|
|
602
|
+
- `--from-traces` `boolean`:from-traces 模式:从 observe inbox 的失败信号回流生成评测用例草稿(provenance: production-trace),落草稿待人工 review。
|
|
603
603
|
- `--lang` `option` (默认 `zh`):输出语言 zh|en,优先级 CLI > OMK_LANG env > zh。
|
|
604
604
|
- `--model` `option`:生成 LLM model 名。Codex 自动读取本机配置;也可用 OMK_MODEL 设置环境偏好。
|
|
605
605
|
- `--no-mock` `boolean`:不生成 mocks,eval 时所有工具调用真实执行。
|
|
@@ -629,7 +629,7 @@ omk sample --batch --skill-dir skills
|
|
|
629
629
|
omk sample skills/my-skill/SKILL.md --fix
|
|
630
630
|
```
|
|
631
631
|
|
|
632
|
-
> 从 observe inbox
|
|
632
|
+
> 从 observe inbox 的失败信号回流生成评测用例草稿
|
|
633
633
|
|
|
634
634
|
```bash
|
|
635
635
|
omk sample --from-traces
|
|
@@ -100,7 +100,7 @@ export async function runObserveInbox(_args, flags, lang) {
|
|
|
100
100
|
}
|
|
101
101
|
if (recyclableCount > 0) {
|
|
102
102
|
console.log(lang === 'zh'
|
|
103
|
-
?
|
|
103
|
+
? `提示:确认信号后生成评测用例草稿:${sampleCommand}`
|
|
104
104
|
: `Tip: after confirming signals, draft regression samples: ${sampleCommand}`);
|
|
105
105
|
}
|
|
106
106
|
return;
|
|
@@ -142,7 +142,7 @@ export async function runObserveInbox(_args, flags, lang) {
|
|
|
142
142
|
: 'Tip: omk observe inbox --explore 10 --include-noise # explicitly include the noise bucket');
|
|
143
143
|
if (recyclableCount > 0) {
|
|
144
144
|
console.log(lang === 'zh'
|
|
145
|
-
?
|
|
145
|
+
? `提示:确认高风险或抽样信号后生成评测用例草稿:${sampleCommand}`
|
|
146
146
|
: `Tip: after confirming high-risk / sampled signals, draft regression samples: ${sampleCommand}`);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
@@ -103,7 +103,7 @@ export default class ObserveIngest extends BaseCommand {
|
|
|
103
103
|
const inboxCommand = `omk observe inbox --input-dir ${shellQuoteArg(outDir)}`;
|
|
104
104
|
const sampleCommand = `omk sample --from-traces --observations-dir ${shellQuoteArg(outDir)}`;
|
|
105
105
|
process.stderr.write(lang === 'zh'
|
|
106
|
-
? `observe inbox 已写入:${path}\n下一步:${inboxCommand}\n
|
|
106
|
+
? `observe inbox 已写入:${path}\n下一步:${inboxCommand}\n确认高风险或抽样信号后,可生成评测用例草稿:${sampleCommand}\n`
|
|
107
107
|
: `observe inbox written to: ${path}\nNext: ${inboxCommand}\nAfter confirming high-risk / sampled signals, draft regression samples: ${sampleCommand}\n`);
|
|
108
108
|
});
|
|
109
109
|
}
|
|
@@ -360,7 +360,7 @@ export async function runSampleFromTraces(flags, lang) {
|
|
|
360
360
|
}
|
|
361
361
|
const count = flags.count !== undefined ? Math.max(1, Number(flags.count) || 5) : undefined;
|
|
362
362
|
process.stderr.write(lang === 'zh'
|
|
363
|
-
? `🔭 发现 ${items.length} 个${flags.skill ? ` ${flags.skill} 的` : ''}
|
|
363
|
+
? `🔭 发现 ${items.length} 个${flags.skill ? ` ${flags.skill} 的` : ''}失败信号,正在生成评测用例草稿...\n`
|
|
364
364
|
: `🔭 Found ${items.length}${flags.skill ? ` ${flags.skill}` : ''} failure signal(s); generating regression-sample drafts...\n`);
|
|
365
365
|
try {
|
|
366
366
|
const { samples, costUSD } = await generateSamplesFromTraces({ items, count, model, executorName });
|
|
@@ -598,7 +598,7 @@ export default class Sample extends BaseCommand {
|
|
|
598
598
|
},
|
|
599
599
|
{
|
|
600
600
|
description: bilingual({
|
|
601
|
-
zh: '从 observe inbox
|
|
601
|
+
zh: '从 observe inbox 的失败信号回流生成评测用例草稿',
|
|
602
602
|
en: 'Recycle observe-inbox failure signals into draft regression samples',
|
|
603
603
|
}),
|
|
604
604
|
command: '<%= config.bin %> sample --from-traces',
|
|
@@ -689,7 +689,7 @@ export default class Sample extends BaseCommand {
|
|
|
689
689
|
}),
|
|
690
690
|
'from-traces': Flags.boolean({
|
|
691
691
|
description: bilingual({
|
|
692
|
-
zh: 'from-traces 模式:从 observe inbox
|
|
692
|
+
zh: 'from-traces 模式:从 observe inbox 的失败信号回流生成评测用例草稿(provenance: production-trace),落草稿待人工 review。',
|
|
693
693
|
en: 'from-traces mode: recycle observe-inbox failure signals into draft regression samples (provenance: production-trace) for review.',
|
|
694
694
|
}),
|
|
695
695
|
default: false,
|
|
@@ -3262,21 +3262,23 @@ function skillSegmentsWithOrchestrationRoles(skillSegments, orchestrationEdges)
|
|
|
3262
3262
|
const parentIds = new Set(orchestrationEdges.map((edge) => edge.parentSkillSegmentId).filter((value) => Boolean(value)));
|
|
3263
3263
|
const executorIds = new Set(orchestrationEdges.map((edge) => edge.executorSkillSegmentId).filter((value) => Boolean(value)));
|
|
3264
3264
|
return skillSegments.map((segment) => {
|
|
3265
|
-
if (parentIds.has(segment.id)
|
|
3265
|
+
if (parentIds.has(segment.id)) {
|
|
3266
|
+
const inferredFromTrace = !segment.declaredSkillType;
|
|
3266
3267
|
return {
|
|
3267
3268
|
...segment,
|
|
3268
|
-
skillType: 'router',
|
|
3269
|
-
skillTypeSource: 'trace',
|
|
3270
|
-
traceInferredSkillType: 'router',
|
|
3269
|
+
skillType: inferredFromTrace ? 'router' : segment.skillType,
|
|
3270
|
+
skillTypeSource: inferredFromTrace ? 'trace' : segment.skillTypeSource,
|
|
3271
|
+
traceInferredSkillType: inferredFromTrace ? 'router' : segment.traceInferredSkillType,
|
|
3271
3272
|
episodeRole: 'router',
|
|
3272
3273
|
};
|
|
3273
3274
|
}
|
|
3274
|
-
if (executorIds.has(segment.id)
|
|
3275
|
+
if (executorIds.has(segment.id)) {
|
|
3276
|
+
const inferredFromTrace = !segment.declaredSkillType;
|
|
3275
3277
|
return {
|
|
3276
3278
|
...segment,
|
|
3277
|
-
skillType:
|
|
3278
|
-
skillTypeSource:
|
|
3279
|
-
traceInferredSkillType:
|
|
3279
|
+
skillType: inferredFromTrace ? 'executor' : segment.skillType,
|
|
3280
|
+
skillTypeSource: inferredFromTrace ? 'trace' : segment.skillTypeSource,
|
|
3281
|
+
traceInferredSkillType: inferredFromTrace ? 'executor' : segment.traceInferredSkillType,
|
|
3280
3282
|
episodeRole: 'main_executor',
|
|
3281
3283
|
};
|
|
3282
3284
|
}
|
|
@@ -3496,40 +3498,109 @@ function sessionStoryOrchestrationEdges(episodeId, skillSegments, subagentDispat
|
|
|
3496
3498
|
});
|
|
3497
3499
|
}
|
|
3498
3500
|
}
|
|
3499
|
-
if (edges.length === 0) {
|
|
3500
|
-
const fallbackEdge = fallbackOrchestrationEdgeFromRuntime(episodeId, skillSegments, invocations);
|
|
3501
|
-
if (fallbackEdge)
|
|
3502
|
-
edges.push(fallbackEdge);
|
|
3503
|
-
}
|
|
3504
3501
|
for (const dispatch of subagentDispatches) {
|
|
3505
|
-
const
|
|
3506
|
-
const
|
|
3507
|
-
|
|
3508
|
-
const dispatchRunnerRef =
|
|
3509
|
-
|
|
3510
|
-
|| dispatch.attachTo.toolUseId === runnerRef.toolUseId
|
|
3511
|
-
: dispatch.attachTo.callInstanceId === runnerRef.callInstanceId)
|
|
3512
|
-
? runnerRef
|
|
3513
|
-
: undefined;
|
|
3502
|
+
const executor = skillSegmentForTrace(skillSegments, dispatch.traceId, dispatch.sourceTrace);
|
|
3503
|
+
const parentSegment = dispatchParentSkillSegment(skillSegments, executor, session, dispatch, router, delegator, runnerOwner);
|
|
3504
|
+
const distinctExecutor = executor?.id === parentSegment?.id ? undefined : executor;
|
|
3505
|
+
const dispatchRunnerRef = dispatchAttachmentEvidenceRef(session, dispatch);
|
|
3506
|
+
const terminal = dispatchTerminalLifecycle(session, dispatch);
|
|
3514
3507
|
edges.push({
|
|
3515
3508
|
id: hashParts('session-story-edge', episodeId, dispatch.id),
|
|
3516
3509
|
episodeId,
|
|
3517
3510
|
edgeKind: 'external_child_session',
|
|
3518
3511
|
parentSkillSegmentId: parentSegment?.id,
|
|
3519
|
-
executorSkillSegmentId:
|
|
3512
|
+
executorSkillSegmentId: distinctExecutor?.id,
|
|
3520
3513
|
childSessionId: dispatch.childSessionId,
|
|
3521
3514
|
runnerStartedRef: dispatchRunnerRef,
|
|
3522
|
-
|
|
3515
|
+
runnerCompletedRef: terminal?.status === 'completed' ? terminal.evidenceRef : undefined,
|
|
3516
|
+
status: terminal?.status ?? 'started',
|
|
3523
3517
|
evidenceRefs: uniqueEvidenceRefs([
|
|
3524
3518
|
...(parentSegment?.evidenceRefs.slice(0, 2) ?? []),
|
|
3525
|
-
...(
|
|
3519
|
+
...(distinctExecutor?.evidenceRefs.slice(0, 2) ?? []),
|
|
3526
3520
|
...(dispatchRunnerRef ? [dispatchRunnerRef] : []),
|
|
3521
|
+
...(terminal ? [terminal.evidenceRef] : []),
|
|
3527
3522
|
...dispatch.evidenceRefs,
|
|
3528
3523
|
]).slice(0, 6),
|
|
3529
3524
|
});
|
|
3530
3525
|
}
|
|
3526
|
+
if (edges.length === 0 && subagentDispatches.length === 0) {
|
|
3527
|
+
const fallbackEdge = fallbackOrchestrationEdgeFromRuntime(episodeId, skillSegments, invocations);
|
|
3528
|
+
if (fallbackEdge)
|
|
3529
|
+
edges.push(fallbackEdge);
|
|
3530
|
+
}
|
|
3531
3531
|
return edges;
|
|
3532
3532
|
}
|
|
3533
|
+
function skillSegmentForTrace(skillSegments, traceId, sourceTrace) {
|
|
3534
|
+
return skillSegments
|
|
3535
|
+
.filter((segment) => (segment.messageRanges ?? []).some((range) => range.traceId === traceId || range.sourceTrace === sourceTrace)
|
|
3536
|
+
|| segment.evidenceRefs.some((ref) => ref.traceId === traceId || ref.sourceTrace === sourceTrace))
|
|
3537
|
+
.sort((a, b) => a.order - b.order)[0];
|
|
3538
|
+
}
|
|
3539
|
+
function dispatchParentSkillSegment(skillSegments, executor, session, dispatch, router, delegator, runnerOwner) {
|
|
3540
|
+
const mainTraceIds = new Set((session.timelineTree?.main ?? [])
|
|
3541
|
+
.map((event) => event.traceId)
|
|
3542
|
+
.filter((value) => Boolean(value)));
|
|
3543
|
+
const mainSourceTraces = new Set((session.timelineTree?.main ?? [])
|
|
3544
|
+
.map((event) => event.sourceTrace)
|
|
3545
|
+
.filter(Boolean));
|
|
3546
|
+
const isMainline = (segment) => (segment.messageRanges ?? []).some((range) => Boolean(range.traceId && mainTraceIds.has(range.traceId))
|
|
3547
|
+
|| Boolean(range.sourceTrace && mainSourceTraces.has(range.sourceTrace)))
|
|
3548
|
+
|| segment.evidenceRefs.some((ref) => ref.traceRole === 'main'
|
|
3549
|
+
|| ref.traceRole === 'standalone'
|
|
3550
|
+
|| Boolean(ref.traceId && mainTraceIds.has(ref.traceId))
|
|
3551
|
+
|| mainSourceTraces.has(ref.sourceTrace));
|
|
3552
|
+
const preferred = [router, delegator]
|
|
3553
|
+
.filter((segment) => Boolean(segment))
|
|
3554
|
+
.find((segment) => segment.id !== executor?.id && isMainline(segment));
|
|
3555
|
+
if (preferred)
|
|
3556
|
+
return preferred;
|
|
3557
|
+
const dispatchStart = minString(dispatch.evidenceRefs.map((ref) => ref.timestamp));
|
|
3558
|
+
const mainline = skillSegments
|
|
3559
|
+
.filter((segment) => segment.id !== executor?.id && isMainline(segment))
|
|
3560
|
+
.filter((segment) => !dispatchStart || segment.startTimestamp <= dispatchStart)
|
|
3561
|
+
.sort((a, b) => b.startTimestamp.localeCompare(a.startTimestamp)
|
|
3562
|
+
|| b.order - a.order)[0];
|
|
3563
|
+
if (mainline)
|
|
3564
|
+
return mainline;
|
|
3565
|
+
if (runnerOwner?.id !== executor?.id && runnerOwner && isMainline(runnerOwner))
|
|
3566
|
+
return runnerOwner;
|
|
3567
|
+
return executor && isMainline(executor) ? executor : undefined;
|
|
3568
|
+
}
|
|
3569
|
+
function dispatchAttachmentEvidenceRef(session, dispatch) {
|
|
3570
|
+
const attachTo = dispatch.attachTo;
|
|
3571
|
+
if (!attachTo)
|
|
3572
|
+
return undefined;
|
|
3573
|
+
if (!attachTo.callInstanceId && !attachTo.toolUseId && attachTo.messageIndex === undefined) {
|
|
3574
|
+
return undefined;
|
|
3575
|
+
}
|
|
3576
|
+
const event = (session.timelineTree?.main ?? []).find((candidate) => {
|
|
3577
|
+
if (candidate.kind !== 'tool_use')
|
|
3578
|
+
return false;
|
|
3579
|
+
if (attachTo.callInstanceId) {
|
|
3580
|
+
return candidate.callInstanceId === attachTo.callInstanceId;
|
|
3581
|
+
}
|
|
3582
|
+
if (attachTo.toolUseId && candidate.toolUseId !== attachTo.toolUseId)
|
|
3583
|
+
return false;
|
|
3584
|
+
return attachTo.messageIndex === undefined
|
|
3585
|
+
|| candidate.messageIndex === attachTo.messageIndex;
|
|
3586
|
+
});
|
|
3587
|
+
return event ? evidenceRefFromTimeline(event) : undefined;
|
|
3588
|
+
}
|
|
3589
|
+
function dispatchTerminalLifecycle(session, dispatch) {
|
|
3590
|
+
const branch = session.timelineTree?.branches.find((candidate) => candidate.id === dispatch.branchId
|
|
3591
|
+
|| candidate.traceId === dispatch.traceId
|
|
3592
|
+
|| candidate.sourceTrace === dispatch.sourceTrace);
|
|
3593
|
+
const event = branch?.events.at(-1);
|
|
3594
|
+
if (event?.kind !== 'runtime_context')
|
|
3595
|
+
return undefined;
|
|
3596
|
+
if (event.label === 'turn_completed' || event.label === 'session_ended') {
|
|
3597
|
+
return { status: 'completed', evidenceRef: evidenceRefFromTimeline(event) };
|
|
3598
|
+
}
|
|
3599
|
+
if (event.label === 'turn_aborted' || event.label === 'turn_interrupted') {
|
|
3600
|
+
return { status: 'failed', evidenceRef: evidenceRefFromTimeline(event) };
|
|
3601
|
+
}
|
|
3602
|
+
return undefined;
|
|
3603
|
+
}
|
|
3533
3604
|
function bestPriorUpstreamSkillSegmentForRuntime(runnerOwner, runnerEvent, timeline, skillSegments) {
|
|
3534
3605
|
const runnerMessageIndex = runnerEvent?.messageIndex;
|
|
3535
3606
|
const contextText = timeline
|
|
@@ -3641,16 +3712,8 @@ function isOrchestrationRuntimeEvent(event) {
|
|
|
3641
3712
|
return /^(?:Task|Agent)$/i.test(event.toolName ?? '')
|
|
3642
3713
|
|| /runner\.js|send-input\.js|check-session\.js/i.test(text);
|
|
3643
3714
|
}
|
|
3644
|
-
if (event.kind === 'tool_result') {
|
|
3645
|
-
const trimmed = text.trim();
|
|
3646
|
-
if (/^---\s*\n?\s*name:/i.test(trimmed) || /^---\s+name:/i.test(trimmed))
|
|
3647
|
-
return false;
|
|
3648
|
-
return /"event"\s*:\s*"started"|Command still running \(session|Process exited with code|Process exited with signal/i.test(text)
|
|
3649
|
-
|| /["']?(?:child_?session_?id|agent_?id|thread_?id|session_?id)["']?\s*[:=]/i.test(text)
|
|
3650
|
-
|| /\b(?:session|thread|agent)(?:\s+id)?\s*[:=]\s*[a-z0-9][a-z0-9._-]*/i.test(text);
|
|
3651
|
-
}
|
|
3652
3715
|
if (event.kind === 'assistant_message') {
|
|
3653
|
-
return /ttyd|(?:已启动|启动了|spawned|started)
|
|
3716
|
+
return /ttyd|(?:已启动|启动了|spawned|started).{0,80}(?:subagent|sub-agent|child agent|子\s*(?:agent|代理|智能体|Claude|Codex))|(?:subagent|sub-agent|child agent|子\s*(?:agent|代理|智能体|Claude|Codex)).{0,48}(?:已启动|启动中|正在(?:执行|运行|分析)|spawned|started|running)/i.test(text)
|
|
3654
3717
|
|| /\b(?:session|thread|agent)(?:\s+id)?\s*[:=]\s*[a-z0-9][a-z0-9._-]*/i.test(text);
|
|
3655
3718
|
}
|
|
3656
3719
|
return false;
|
|
@@ -4209,16 +4272,10 @@ function inferSkillRole(group, allInvocations, session) {
|
|
|
4209
4272
|
return 'unknown';
|
|
4210
4273
|
}
|
|
4211
4274
|
function routingEvidenceEvents(invocation) {
|
|
4212
|
-
return invocation.timeline
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
return true;
|
|
4217
|
-
if (isDifferentSkillInvocationEvent(event, invocation.skillName))
|
|
4218
|
-
return true;
|
|
4219
|
-
const text = event.fullText ?? event.snippet ?? '';
|
|
4220
|
-
return /subagent|sub-agent|child agent|子\s*(?:agent|代理|智能体|Claude|Codex)|子任务|分发|委派|路由|delegate|dispatch|route|调用.+skill|走\s*`?[\w-]+`?\s*skill/i.test(text);
|
|
4221
|
-
}).slice(0, 3);
|
|
4275
|
+
return invocation.timeline
|
|
4276
|
+
.filter((event) => isOrchestrationRuntimeEvent(event)
|
|
4277
|
+
|| isDifferentSkillInvocationEvent(event, invocation.skillName))
|
|
4278
|
+
.slice(0, 3);
|
|
4222
4279
|
}
|
|
4223
4280
|
function isDifferentSkillInvocationEvent(event, currentSkillName) {
|
|
4224
4281
|
if (event.kind !== 'tool_use' || !/^Skill$/i.test(event.toolName ?? ''))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-knowledge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.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",
|