oh-my-knowledge 0.48.0 → 0.49.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 +50 -18
- package/README.zh.md +55 -23
- package/dist/analysis/coverage-analyzer.d.ts +1 -0
- package/dist/analysis/coverage-analyzer.js +125 -62
- package/dist/analysis/failure-clusterer.js +2 -1
- package/dist/analysis/gap-analyzer.d.ts +2 -2
- package/dist/analysis/gap-analyzer.js +13 -3
- package/dist/analysis/hedging-classifier.d.ts +2 -2
- package/dist/analysis/hedging-classifier.js +3 -4
- package/dist/analysis/report-diagnostics.js +9 -7
- package/dist/analysis/sample-diagnostics.js +6 -6
- package/dist/artifact-graph/doctor.js +15 -7
- package/dist/assets/agent-skills/omk/SKILL.md +27 -7
- package/dist/assets/agent-skills/omk/references/commands.md +18 -17
- package/dist/authoring/evolver.d.ts +10 -6
- package/dist/authoring/evolver.js +496 -83
- package/dist/authoring/generator.d.ts +3 -3
- package/dist/authoring/generator.js +5 -10
- package/dist/authoring/sample-fixer.d.ts +8 -6
- package/dist/authoring/sample-fixer.js +76 -5
- package/dist/cli/commands/doctor.js +31 -14
- package/dist/cli/commands/eval/index.d.ts +3 -0
- package/dist/cli/commands/eval/index.js +163 -17
- package/dist/cli/commands/evolve.d.ts +4 -4
- package/dist/cli/commands/evolve.js +27 -13
- package/dist/cli/commands/init.js +16 -3
- package/dist/cli/commands/observe/inbox.js +28 -21
- package/dist/cli/commands/observe/index.js +20 -11
- package/dist/cli/commands/observe/ingest.d.ts +3 -0
- package/dist/cli/commands/observe/ingest.js +30 -2
- package/dist/cli/commands/sample.d.ts +6 -3
- package/dist/cli/commands/sample.js +72 -68
- package/dist/cli/lib/codex-model-hint.d.ts +9 -0
- package/dist/cli/lib/codex-model-hint.js +45 -0
- package/dist/cli/lib/generation-failure-hint.d.ts +2 -0
- package/dist/cli/lib/generation-failure-hint.js +61 -0
- package/dist/cli/lib/i18n-dict/common.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/common.js +4 -0
- package/dist/cli/lib/i18n-dict/gen.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/gen.js +38 -6
- package/dist/cli/lib/i18n-dict/help.js +6 -6
- package/dist/cli/lib/i18n-dict/init.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/init.js +13 -9
- package/dist/cli/lib/i18n-dict/run.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/run.js +34 -2
- package/dist/cli/lib/llm-failure-classifier.d.ts +2 -0
- package/dist/cli/lib/llm-failure-classifier.js +8 -0
- package/dist/cli/lib/parse-run-config.d.ts +6 -5
- package/dist/cli/lib/parse-run-config.js +16 -9
- package/dist/cli/lib/runtime-defaults.d.ts +21 -0
- package/dist/cli/lib/runtime-defaults.js +79 -0
- package/dist/diagnosis/observe-mapper.js +14 -15
- package/dist/diagnosis/observe-producer.js +3 -1
- package/dist/diagnosis/studio-projection.js +14 -7
- package/dist/diagnosis/types.d.ts +2 -0
- package/dist/diagnosis/types.js +12 -0
- package/dist/doctor/endpoint-rule.js +2 -1
- package/dist/eval-core/artifact-file-names.js +18 -1
- package/dist/eval-core/artifact-index.d.ts +7 -11
- package/dist/eval-core/artifact-index.js +139 -80
- package/dist/eval-core/cache.d.ts +12 -3
- package/dist/eval-core/cache.js +89 -29
- package/dist/eval-core/comparability.js +10 -6
- package/dist/eval-core/evaluation-execution.d.ts +2 -1
- package/dist/eval-core/evaluation-execution.js +122 -37
- package/dist/eval-core/evaluation-job.d.ts +4 -1
- package/dist/eval-core/evaluation-job.js +4 -1
- package/dist/eval-core/evaluation-reporting.d.ts +15 -13
- package/dist/eval-core/evaluation-reporting.js +54 -52
- package/dist/eval-core/execution-strategy.d.ts +2 -0
- package/dist/eval-core/execution-strategy.js +11 -9
- package/dist/eval-core/fact-checker.js +15 -7
- package/dist/eval-core/holdout.js +3 -2
- package/dist/eval-core/judge-independence.d.ts +2 -2
- package/dist/eval-core/mock-hook.cjs +23 -6
- package/dist/eval-core/mocks-runtime.js +30 -8
- package/dist/eval-core/report-document.d.ts +12 -0
- package/dist/eval-core/report-document.js +1151 -0
- package/dist/eval-core/report-extensions.d.ts +4 -0
- package/dist/eval-core/report-extensions.js +500 -0
- package/dist/eval-core/report-file-migration.js +7 -2
- package/dist/eval-core/resume-compatibility.d.ts +31 -0
- package/dist/eval-core/resume-compatibility.js +141 -0
- package/dist/eval-core/sample-fingerprint.d.ts +12 -0
- package/dist/eval-core/sample-fingerprint.js +193 -0
- package/dist/eval-core/schema.js +86 -31
- package/dist/eval-core/verdict.d.ts +8 -4
- package/dist/eval-core/verdict.js +24 -10
- package/dist/eval-workflows/batch-evaluation-workflow.d.ts +2 -1
- package/dist/eval-workflows/batch-evaluation-workflow.js +25 -12
- package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.d.ts +10 -5
- package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.js +58 -21
- package/dist/eval-workflows/evaluation-pipeline/report-finalize.js +3 -1
- package/dist/eval-workflows/evaluation-pipeline/run-state.d.ts +4 -1
- package/dist/eval-workflows/evaluation-pipeline/run-state.js +4 -1
- package/dist/eval-workflows/evaluation-pipeline/test-set-hash.d.ts +6 -5
- package/dist/eval-workflows/evaluation-pipeline/test-set-hash.js +17 -10
- package/dist/eval-workflows/evaluation-pipeline.js +12 -7
- package/dist/eval-workflows/run-evaluation.d.ts +9 -7
- package/dist/eval-workflows/run-evaluation.js +79 -51
- package/dist/executors/anthropic-api.js +65 -9
- package/dist/executors/claude-cli.js +16 -79
- package/dist/executors/claude-protocol.d.ts +28 -0
- package/dist/executors/claude-protocol.js +180 -0
- package/dist/executors/claude-sdk-trace.js +56 -28
- package/dist/executors/claude-sdk.d.ts +1 -0
- package/dist/executors/claude-sdk.js +39 -93
- package/dist/executors/codex-cli-trace.js +166 -31
- package/dist/executors/codex-cli.d.ts +6 -8
- package/dist/executors/codex-cli.js +49 -151
- package/dist/executors/codex-protocol.d.ts +24 -0
- package/dist/executors/codex-protocol.js +234 -0
- package/dist/executors/codex-sdk.js +68 -120
- package/dist/executors/gemini.js +88 -13
- package/dist/executors/index.d.ts +2 -3
- package/dist/executors/index.js +5 -3
- package/dist/executors/openai-api.js +70 -9
- package/dist/executors/runtime-fingerprint.js +88 -11
- package/dist/executors/script-command.d.ts +8 -0
- package/dist/executors/script-command.js +87 -0
- package/dist/executors/script.js +202 -29
- package/dist/executors/shared.d.ts +35 -3
- package/dist/executors/shared.js +113 -15
- package/dist/grading/assertions.d.ts +1 -1
- package/dist/grading/assertions.js +19 -9
- package/dist/grading/diagnostic.d.ts +9 -2
- package/dist/grading/diagnostic.js +25 -2
- package/dist/grading/index.js +10 -4
- package/dist/grading/judge.js +19 -6
- package/dist/grading/layered-scores.d.ts +2 -3
- package/dist/grading/layered-scores.js +2 -3
- package/dist/inputs/load-samples.d.ts +1 -2
- package/dist/inputs/load-samples.js +23 -1
- package/dist/inputs/mcp-resolver.js +6 -3
- package/dist/inputs/sample-document.d.ts +11 -0
- package/dist/inputs/sample-document.js +96 -0
- package/dist/managed/evidence.d.ts +1 -0
- package/dist/managed/evidence.js +1 -1
- package/dist/managed/store.js +200 -91
- package/dist/observability/codex-trace-adapter.d.ts +5 -0
- package/dist/observability/codex-trace-adapter.js +850 -0
- package/dist/observability/experience.d.ts +32 -6
- package/dist/observability/experience.js +2695 -459
- package/dist/observability/feedback-matchers.js +16 -1
- package/dist/observability/inbox-view-model.d.ts +1 -1
- package/dist/observability/inbox-view-model.js +19 -14
- package/dist/observability/inbox.d.ts +7 -1
- package/dist/observability/inbox.js +632 -124
- package/dist/observability/problem-patterns.js +2 -0
- package/dist/observability/review-state.d.ts +6 -0
- package/dist/observability/review-state.js +235 -63
- package/dist/observability/skill-chain-advisories.js +1 -1
- package/dist/observability/skill-chain.js +17 -4
- package/dist/observability/skill-health-analyzer.d.ts +32 -7
- package/dist/observability/skill-health-analyzer.js +194 -121
- package/dist/observability/skill-health-report.d.ts +10 -0
- package/dist/observability/skill-health-report.js +620 -0
- package/dist/observability/soft-standards/constants.d.ts +0 -1
- package/dist/observability/soft-standards/constants.js +0 -1
- package/dist/observability/soft-standards/index.d.ts +1 -1
- package/dist/observability/soft-standards/index.js +1 -1
- package/dist/observability/soft-standards/llm-extractor.js +8 -10
- package/dist/observability/soft-standards/skill-standards-store.d.ts +2 -1
- package/dist/observability/soft-standards/skill-standards-store.js +59 -18
- package/dist/observability/soft-standards/types.d.ts +2 -2
- package/dist/observability/trace-adapter.d.ts +12 -7
- package/dist/observability/trace-adapter.js +11 -9
- package/dist/observability/trace-attribution.d.ts +13 -5
- package/dist/observability/trace-attribution.js +315 -21
- package/dist/observability/trace-ingestion.d.ts +9 -0
- package/dist/observability/trace-ingestion.js +80 -0
- package/dist/observability/trace-ir.d.ts +113 -0
- package/dist/observability/trace-ir.js +87 -0
- package/dist/observability/trace-segmenter.d.ts +19 -6
- package/dist/observability/trace-segmenter.js +377 -196
- package/dist/observability/trace-session-index.d.ts +19 -0
- package/dist/observability/trace-session-index.js +68 -0
- package/dist/observability/trace-source.d.ts +12 -4
- package/dist/observability/trace-source.js +939 -215
- package/dist/renderer/html-renderer.js +37 -6
- package/dist/renderer/icons.js +3 -0
- package/dist/renderer/observation-inbox-renderer.js +208 -90
- package/dist/renderer/skill-detail-renderer.js +452 -109
- package/dist/renderer/skill-health-renderer.js +69 -12
- package/dist/renderer/summary.js +28 -7
- package/dist/renderer/table.js +21 -4
- package/dist/renderer/test-view.d.ts +1 -0
- package/dist/renderer/test-view.js +44 -9
- package/dist/server/indexed-report-store.js +14 -18
- package/dist/server/job-store.js +64 -26
- package/dist/server/report-server.js +190 -78
- package/dist/server/report-store.js +57 -80
- package/dist/server/skill-index.js +143 -49
- package/dist/server/skill-insights.js +44 -5
- package/dist/shared/artifact-graph.d.ts +3 -0
- package/dist/shared/artifact-graph.js +224 -0
- package/dist/shared/assertion-types.d.ts +8 -0
- package/dist/shared/assertion-types.js +46 -0
- package/dist/shared/atomic-json.d.ts +8 -0
- package/dist/shared/atomic-json.js +33 -0
- package/dist/shared/diagnosis-schema.d.ts +9 -0
- package/dist/shared/diagnosis-schema.js +181 -0
- package/dist/shared/doctor-report.d.ts +3 -0
- package/dist/shared/doctor-report.js +103 -0
- package/dist/shared/evaluation-job.d.ts +6 -0
- package/dist/shared/evaluation-job.js +217 -0
- package/dist/shared/executor-result.d.ts +17 -0
- package/dist/shared/executor-result.js +221 -0
- package/dist/shared/file-lock.d.ts +12 -0
- package/dist/shared/file-lock.js +129 -0
- package/dist/shared/json-value.d.ts +5 -0
- package/dist/shared/json-value.js +36 -0
- package/dist/shared/keyed-mutex.d.ts +7 -0
- package/dist/shared/keyed-mutex.js +24 -0
- package/dist/shared/record-count.d.ts +8 -0
- package/dist/shared/record-count.js +43 -0
- package/dist/shared/sample-contract.d.ts +3 -0
- package/dist/shared/sample-contract.js +332 -0
- package/dist/shared/timestamp.d.ts +6 -0
- package/dist/shared/timestamp.js +64 -0
- package/dist/shared/token-usage.d.ts +19 -0
- package/dist/shared/token-usage.js +50 -0
- package/dist/shared/tool-call-status.d.ts +8 -0
- package/dist/shared/tool-call-status.js +28 -0
- package/dist/shared/tool-identity.d.ts +21 -0
- package/dist/shared/tool-identity.js +84 -0
- package/dist/shared/tool-search.js +73 -16
- package/dist/shared/trace-projection.d.ts +5 -0
- package/dist/shared/trace-projection.js +20 -0
- package/dist/shared/trace-source-kind.d.ts +3 -0
- package/dist/shared/trace-source-kind.js +12 -0
- package/dist/types/diagnosis.d.ts +2 -0
- package/dist/types/eval.d.ts +4 -0
- package/dist/types/executor.d.ts +32 -5
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/judge.d.ts +2 -0
- package/dist/types/observability.d.ts +116 -9
- package/dist/types/report.d.ts +58 -6
- package/dist/types/skill-index.d.ts +7 -0
- package/dist/types/trace.d.ts +2 -0
- package/dist/types/trace.js +1 -0
- package/package.json +9 -5
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { checkedSumTokenCounts, nonNegativeMetric, optionalTokenCount, } from '../shared/token-usage.js';
|
|
2
|
+
import { extractAgentTrace, isClaudeSdkResultMessage } from './claude-sdk-trace.js';
|
|
3
|
+
export function normalizeClaudeSdkMeasurements(result) {
|
|
4
|
+
const durationMs = optionalTokenCount(result.duration_ms);
|
|
5
|
+
const durationApiMs = optionalTokenCount(result.duration_api_ms);
|
|
6
|
+
const numTurns = optionalTokenCount(result.num_turns);
|
|
7
|
+
const costUSD = nonNegativeMetric(result.total_cost_usd);
|
|
8
|
+
if (durationMs === undefined
|
|
9
|
+
|| durationApiMs === undefined
|
|
10
|
+
|| numTurns === undefined
|
|
11
|
+
|| costUSD === undefined
|
|
12
|
+
|| costUSD > Number.MAX_SAFE_INTEGER) {
|
|
13
|
+
return { error: 'claude result contained invalid duration, turn, or cost metrics' };
|
|
14
|
+
}
|
|
15
|
+
const rawModelUsage = result.modelUsage;
|
|
16
|
+
const modelUsageEntries = rawModelUsage
|
|
17
|
+
&& typeof rawModelUsage === 'object'
|
|
18
|
+
&& !Array.isArray(rawModelUsage)
|
|
19
|
+
? Object.values(rawModelUsage)
|
|
20
|
+
: [];
|
|
21
|
+
const buckets = [[], [], [], []];
|
|
22
|
+
if (modelUsageEntries.length > 0) {
|
|
23
|
+
for (const entry of modelUsageEntries) {
|
|
24
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
25
|
+
return { error: 'claude result contained invalid modelUsage' };
|
|
26
|
+
}
|
|
27
|
+
const counts = [
|
|
28
|
+
optionalTokenCount(entry.inputTokens),
|
|
29
|
+
optionalTokenCount(entry.outputTokens),
|
|
30
|
+
optionalTokenCount(entry.cacheReadInputTokens),
|
|
31
|
+
optionalTokenCount(entry.cacheCreationInputTokens),
|
|
32
|
+
];
|
|
33
|
+
if (counts.some((count) => count === undefined)) {
|
|
34
|
+
return { error: 'claude result contained invalid modelUsage token counters' };
|
|
35
|
+
}
|
|
36
|
+
buckets.forEach((bucket, index) => bucket.push(counts[index]));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const usage = result.usage;
|
|
41
|
+
const counts = [
|
|
42
|
+
optionalTokenCount(usage?.input_tokens),
|
|
43
|
+
optionalTokenCount(usage?.output_tokens),
|
|
44
|
+
usage?.cache_read_input_tokens === undefined
|
|
45
|
+
? 0
|
|
46
|
+
: optionalTokenCount(usage.cache_read_input_tokens),
|
|
47
|
+
usage?.cache_creation_input_tokens === undefined
|
|
48
|
+
? 0
|
|
49
|
+
: optionalTokenCount(usage.cache_creation_input_tokens),
|
|
50
|
+
];
|
|
51
|
+
if (counts.some((count) => count === undefined)) {
|
|
52
|
+
return { error: 'claude result contained missing or invalid token usage' };
|
|
53
|
+
}
|
|
54
|
+
buckets.forEach((bucket, index) => bucket.push(counts[index]));
|
|
55
|
+
}
|
|
56
|
+
const totals = buckets.map((bucket) => checkedSumTokenCounts(...bucket));
|
|
57
|
+
if (totals.some((total) => total === undefined)
|
|
58
|
+
|| checkedSumTokenCounts(...totals) === undefined) {
|
|
59
|
+
return { error: 'claude token usage aggregate exceeds safe integer' };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
durationMs,
|
|
63
|
+
durationApiMs,
|
|
64
|
+
inputTokens: totals[0],
|
|
65
|
+
outputTokens: totals[1],
|
|
66
|
+
cacheReadTokens: totals[2],
|
|
67
|
+
cacheCreationTokens: totals[3],
|
|
68
|
+
costUSD,
|
|
69
|
+
numTurns,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function parseClaudeStreamJson(stdout) {
|
|
73
|
+
const messages = [];
|
|
74
|
+
let malformedLineCount = 0;
|
|
75
|
+
for (const line of stdout.split('\n')) {
|
|
76
|
+
const trimmed = line.trim();
|
|
77
|
+
if (!trimmed)
|
|
78
|
+
continue;
|
|
79
|
+
try {
|
|
80
|
+
const value = JSON.parse(trimmed);
|
|
81
|
+
if (!value
|
|
82
|
+
|| typeof value !== 'object'
|
|
83
|
+
|| Array.isArray(value)
|
|
84
|
+
|| typeof value.type !== 'string') {
|
|
85
|
+
malformedLineCount += 1;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
messages.push(value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
malformedLineCount += 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return { messages, malformedLineCount };
|
|
96
|
+
}
|
|
97
|
+
export function buildClaudeResult(options) {
|
|
98
|
+
const { messages, wallClockDurationMs, source, malformedLineCount = 0, forcedError, messageTimestamps, } = options;
|
|
99
|
+
const resultMessages = messages.filter(isClaudeSdkResultMessage);
|
|
100
|
+
const trace = extractAgentTrace(messages, messageTimestamps);
|
|
101
|
+
const traceFields = {
|
|
102
|
+
fullNumTurns: trace.fullNumTurns,
|
|
103
|
+
numSubAgents: trace.numSubAgents,
|
|
104
|
+
...(trace.turns.length > 0 && { turns: trace.turns }),
|
|
105
|
+
...(trace.toolCalls.length > 0 && { toolCalls: trace.toolCalls }),
|
|
106
|
+
};
|
|
107
|
+
const errors = [];
|
|
108
|
+
if (forcedError)
|
|
109
|
+
errors.push(forcedError);
|
|
110
|
+
if (malformedLineCount > 0) {
|
|
111
|
+
errors.push(`${source} output contained ${malformedLineCount} malformed line(s)`);
|
|
112
|
+
}
|
|
113
|
+
if (resultMessages.length !== 1) {
|
|
114
|
+
errors.push(resultMessages.length === 0
|
|
115
|
+
? `no result message in ${source} output`
|
|
116
|
+
: `expected exactly one result message in ${source} output, received ${resultMessages.length}`);
|
|
117
|
+
return {
|
|
118
|
+
ok: false,
|
|
119
|
+
error: [...new Set(errors)].join('; '),
|
|
120
|
+
durationMs: wallClockDurationMs,
|
|
121
|
+
durationApiMs: 0,
|
|
122
|
+
inputTokens: 0,
|
|
123
|
+
outputTokens: 0,
|
|
124
|
+
cacheReadTokens: 0,
|
|
125
|
+
cacheCreationTokens: 0,
|
|
126
|
+
tokenUsageReportedByExecutor: false,
|
|
127
|
+
costUSD: 0,
|
|
128
|
+
costReportedByExecutor: false,
|
|
129
|
+
output: null,
|
|
130
|
+
stopReason: 'error',
|
|
131
|
+
numTurns: 0,
|
|
132
|
+
...traceFields,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const result = resultMessages[0];
|
|
136
|
+
const measurements = normalizeClaudeSdkMeasurements(result);
|
|
137
|
+
if ('error' in measurements) {
|
|
138
|
+
errors.push(measurements.error);
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
error: [...new Set(errors)].join('; '),
|
|
142
|
+
durationMs: wallClockDurationMs,
|
|
143
|
+
durationApiMs: 0,
|
|
144
|
+
inputTokens: 0,
|
|
145
|
+
outputTokens: 0,
|
|
146
|
+
cacheReadTokens: 0,
|
|
147
|
+
cacheCreationTokens: 0,
|
|
148
|
+
tokenUsageReportedByExecutor: false,
|
|
149
|
+
costUSD: 0,
|
|
150
|
+
costReportedByExecutor: false,
|
|
151
|
+
output: typeof result.result === 'string' && result.result ? result.result : null,
|
|
152
|
+
stopReason: 'error',
|
|
153
|
+
numTurns: 0,
|
|
154
|
+
...traceFields,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (result.subtype !== 'success') {
|
|
158
|
+
errors.push(result.errors?.filter(Boolean).join('; ') || result.subtype || `${source} failed`);
|
|
159
|
+
}
|
|
160
|
+
else if (result.errors?.length) {
|
|
161
|
+
errors.push(result.errors.filter(Boolean).join('; '));
|
|
162
|
+
}
|
|
163
|
+
const output = typeof result.result === 'string' && result.result.trim()
|
|
164
|
+
? result.result
|
|
165
|
+
: null;
|
|
166
|
+
if (!output)
|
|
167
|
+
errors.push(`${source} completed without an assistant response`);
|
|
168
|
+
const uniqueErrors = [...new Set(errors.filter(Boolean))];
|
|
169
|
+
return {
|
|
170
|
+
ok: uniqueErrors.length === 0,
|
|
171
|
+
...(uniqueErrors.length > 0 && { error: uniqueErrors.join('; ') }),
|
|
172
|
+
...measurements,
|
|
173
|
+
...((forcedError || malformedLineCount > 0) && {
|
|
174
|
+
tokenUsageReportedByExecutor: false,
|
|
175
|
+
}),
|
|
176
|
+
output,
|
|
177
|
+
stopReason: uniqueErrors.length === 0 ? result.stop_reason || 'end_turn' : 'error',
|
|
178
|
+
...traceFields,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { safeSliceForJson } from '../util/safe-slice.js';
|
|
2
|
+
import { isToolResultFailureText } from '../observability/text-signals.js';
|
|
3
|
+
import { normalizeToolIdentity } from '../shared/tool-identity.js';
|
|
2
4
|
export function isClaudeSdkResultMessage(message) {
|
|
3
5
|
return message.type === 'result';
|
|
4
6
|
}
|
|
@@ -21,16 +23,36 @@ export function extractAgentTrace(messages, timestamps) {
|
|
|
21
23
|
const textParts = [];
|
|
22
24
|
const turnToolCalls = [];
|
|
23
25
|
let hasNonThinking = false;
|
|
24
|
-
for (
|
|
26
|
+
for (let blockIndex = 0; blockIndex < content.length; blockIndex += 1) {
|
|
27
|
+
const block = content[blockIndex];
|
|
25
28
|
if (block.type === 'text' && block.text) {
|
|
26
29
|
textParts.push(block.text);
|
|
27
30
|
hasNonThinking = true;
|
|
28
31
|
}
|
|
29
32
|
else if (block.type === 'tool_use' && block.name) {
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
const toolIdentity = normalizeToolIdentity({ sourceName: block.name });
|
|
34
|
+
const toolCall = {
|
|
35
|
+
tool: toolIdentity.name,
|
|
36
|
+
...(toolIdentity.sourceName ? { sourceTool: toolIdentity.sourceName } : {}),
|
|
37
|
+
...(toolIdentity.namespace ? { toolNamespace: toolIdentity.namespace } : {}),
|
|
38
|
+
...(toolIdentity.provider ? { toolProvider: toolIdentity.provider } : {}),
|
|
39
|
+
input: block.input,
|
|
40
|
+
output: null,
|
|
41
|
+
status: 'unknown',
|
|
42
|
+
statusSource: 'unknown',
|
|
43
|
+
success: false,
|
|
44
|
+
callInstanceId: `claude-sdk:${msgIdx}:${blockIndex}`,
|
|
45
|
+
toolUseId: block.id,
|
|
46
|
+
};
|
|
47
|
+
if (block.id) {
|
|
48
|
+
const pending = pendingToolUse.get(block.id) ?? [];
|
|
49
|
+
pending.push(toolCall);
|
|
50
|
+
pendingToolUse.set(block.id, pending);
|
|
51
|
+
}
|
|
52
|
+
turnToolCalls.push(toolCall);
|
|
53
|
+
toolCalls.push(toolCall);
|
|
32
54
|
hasNonThinking = true;
|
|
33
|
-
if (
|
|
55
|
+
if (toolIdentity.name === 'Agent')
|
|
34
56
|
numSubAgents++;
|
|
35
57
|
}
|
|
36
58
|
else if (block.type !== 'thinking') {
|
|
@@ -52,12 +74,17 @@ export function extractAgentTrace(messages, timestamps) {
|
|
|
52
74
|
}
|
|
53
75
|
}
|
|
54
76
|
if (msg.type === 'user') {
|
|
55
|
-
for (
|
|
77
|
+
for (let blockIndex = 0; blockIndex < content.length; blockIndex += 1) {
|
|
78
|
+
const block = content[blockIndex];
|
|
56
79
|
if (block.type !== 'tool_result')
|
|
57
80
|
continue;
|
|
58
81
|
const toolUseId = block.tool_use_id || '';
|
|
59
|
-
const
|
|
60
|
-
const
|
|
82
|
+
const pendingQueue = pendingToolUse.get(toolUseId);
|
|
83
|
+
const pending = pendingQueue?.shift();
|
|
84
|
+
if (pendingQueue?.length === 0)
|
|
85
|
+
pendingToolUse.delete(toolUseId);
|
|
86
|
+
const runtimeError = block.is_error;
|
|
87
|
+
const hasRuntimeStatus = typeof runtimeError === 'boolean';
|
|
61
88
|
const resultContent = block.content;
|
|
62
89
|
const outputText = typeof resultContent === 'string'
|
|
63
90
|
? resultContent
|
|
@@ -68,27 +95,29 @@ export function extractAgentTrace(messages, timestamps) {
|
|
|
68
95
|
// is_error 因此为 true,但语义上是"mock 成功返回"。识别前缀 → 覆盖 success=true。
|
|
69
96
|
// 见 src/eval-core/mocks-runtime.ts 的 wrappedReason 前缀。
|
|
70
97
|
const isMockHit = outputText.startsWith('[mock] simulated tool output');
|
|
71
|
-
const
|
|
72
|
-
const tc = {
|
|
73
|
-
tool:
|
|
74
|
-
input:
|
|
75
|
-
output:
|
|
76
|
-
|
|
98
|
+
const inferredFailure = !hasRuntimeStatus && isToolResultFailureText(outputText);
|
|
99
|
+
const tc = pending ?? {
|
|
100
|
+
tool: 'unknown',
|
|
101
|
+
input: null,
|
|
102
|
+
output: null,
|
|
103
|
+
status: 'unknown',
|
|
104
|
+
statusSource: 'unknown',
|
|
105
|
+
success: false,
|
|
106
|
+
callInstanceId: `claude-sdk:orphan-result:${msgIdx}:${blockIndex}`,
|
|
107
|
+
toolUseId,
|
|
77
108
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
}
|
|
109
|
+
tc.output = safeSliceForJson(outputText, 500, '');
|
|
110
|
+
tc.status = isMockHit
|
|
111
|
+
? 'success'
|
|
112
|
+
: hasRuntimeStatus
|
|
113
|
+
? runtimeError ? 'failure' : 'success'
|
|
114
|
+
: inferredFailure ? 'failure' : 'unknown';
|
|
115
|
+
tc.statusSource = isMockHit
|
|
116
|
+
? 'tool-output'
|
|
117
|
+
: hasRuntimeStatus ? 'runtime' : inferredFailure ? 'inferred' : 'unknown';
|
|
118
|
+
tc.success = tc.status === 'success';
|
|
119
|
+
if (!pending)
|
|
120
|
+
toolCalls.push(tc);
|
|
92
121
|
const toolDur = msgTs && lastTurnTs ? msgTs - lastTurnTs : undefined;
|
|
93
122
|
turns.push({
|
|
94
123
|
role: 'tool',
|
|
@@ -97,7 +126,6 @@ export function extractAgentTrace(messages, timestamps) {
|
|
|
97
126
|
});
|
|
98
127
|
if (msgTs)
|
|
99
128
|
lastTurnTs = msgTs;
|
|
100
|
-
pendingToolUse.delete(toolUseId);
|
|
101
129
|
}
|
|
102
130
|
}
|
|
103
131
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExecResult, ExecutorInput } from '../types/index.js';
|
|
2
|
+
export { normalizeClaudeSdkMeasurements } from './claude-protocol.js';
|
|
2
3
|
/**
|
|
3
4
|
* Map ExecutorInput.allowedSkills to SDK query options for skill isolation.
|
|
4
5
|
* undefined → {} (SDK default: full ~/.claude/skills/ discovery)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
|
-
import {
|
|
5
|
-
import { asErrorLike, buildExecEnv, DEFAULT_TIMEOUT_MS, errorMessage } from './shared.js';
|
|
4
|
+
import { asErrorLike, buildExecEnv, DEFAULT_TIMEOUT_MS, errorMessage, interruptedExecResult, registerSigintSubscriber, timeoutExecResult, } from './shared.js';
|
|
6
5
|
import { buildSdkHookCallback } from '../eval-core/mocks-runtime.js';
|
|
6
|
+
import { buildClaudeResult } from './claude-protocol.js';
|
|
7
|
+
export { normalizeClaudeSdkMeasurements } from './claude-protocol.js';
|
|
7
8
|
let sdkQuery = null;
|
|
8
9
|
/**
|
|
9
10
|
* Map ExecutorInput.allowedSkills to SDK query options for skill isolation.
|
|
@@ -41,7 +42,15 @@ export async function claudeSdkExecutor({ model, system, prompt, cwd, skillDir,
|
|
|
41
42
|
const isolationOpts = lean ? { skills: [], disallowedTools: ['*'] } : baseIsolationOpts;
|
|
42
43
|
const start = Date.now();
|
|
43
44
|
const abortController = new AbortController();
|
|
44
|
-
|
|
45
|
+
let abortReason;
|
|
46
|
+
const abort = (reason) => {
|
|
47
|
+
if (abortReason)
|
|
48
|
+
return;
|
|
49
|
+
abortReason = reason;
|
|
50
|
+
abortController.abort();
|
|
51
|
+
};
|
|
52
|
+
const timer = setTimeout(() => abort('timeout'), timeoutMs);
|
|
53
|
+
const unregisterSigint = registerSigintSubscriber(() => abort('interrupted'));
|
|
45
54
|
const env = buildExecEnv(skillDir);
|
|
46
55
|
const messages = [];
|
|
47
56
|
const messageTimestamps = [];
|
|
@@ -74,14 +83,10 @@ export async function claudeSdkExecutor({ model, system, prompt, cwd, skillDir,
|
|
|
74
83
|
...hooksOpts,
|
|
75
84
|
},
|
|
76
85
|
});
|
|
77
|
-
const resultMsgs = [];
|
|
78
86
|
for await (const msg of stream) {
|
|
79
87
|
messages.push(msg);
|
|
80
88
|
messageTimestamps.push(Date.now());
|
|
81
|
-
if (isClaudeSdkResultMessage(msg))
|
|
82
|
-
resultMsgs.push(msg);
|
|
83
89
|
}
|
|
84
|
-
clearTimeout(timer);
|
|
85
90
|
if (verbose) {
|
|
86
91
|
try {
|
|
87
92
|
const debugDir = join(tmpdir(), 'omk-debug');
|
|
@@ -95,111 +100,52 @@ export async function claudeSdkExecutor({ model, system, prompt, cwd, skillDir,
|
|
|
95
100
|
}
|
|
96
101
|
catch { }
|
|
97
102
|
}
|
|
98
|
-
if (resultMsgs.length === 0) {
|
|
99
|
-
const durationMs = Date.now() - start;
|
|
100
|
-
process.stderr.write(`[omk] claude-sdk executor: no result message received (${messages.length} messages)\n`);
|
|
101
|
-
return {
|
|
102
|
-
ok: false, error: 'no result message received',
|
|
103
|
-
durationMs, durationApiMs: 0,
|
|
104
|
-
inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0,
|
|
105
|
-
costUSD: 0, output: null, stopReason: 'error', numTurns: 0,
|
|
106
|
-
...(mockStatsOf() && { mockStats: mockStatsOf() }),
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
let output = '';
|
|
110
|
-
let totalInputTokens = 0;
|
|
111
|
-
let totalOutputTokens = 0;
|
|
112
|
-
let totalCacheReadTokens = 0;
|
|
113
|
-
let totalCacheCreationTokens = 0;
|
|
114
|
-
let totalCostUSD = 0;
|
|
115
|
-
let totalDurationApiMs = 0;
|
|
116
|
-
let totalNumTurns = 0;
|
|
117
|
-
let lastSubtype = 'success';
|
|
118
|
-
for (const r of resultMsgs) {
|
|
119
|
-
output += r.result || '';
|
|
120
|
-
// Prefer modelUsage (includes subAgent tokens) over usage (main process only)
|
|
121
|
-
const modelUsage = r.modelUsage;
|
|
122
|
-
if (modelUsage) {
|
|
123
|
-
for (const mu of Object.values(modelUsage)) {
|
|
124
|
-
totalInputTokens += mu.inputTokens || 0;
|
|
125
|
-
totalOutputTokens += mu.outputTokens || 0;
|
|
126
|
-
totalCacheReadTokens += mu.cacheReadInputTokens || 0;
|
|
127
|
-
totalCacheCreationTokens += mu.cacheCreationInputTokens || 0;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
totalInputTokens += r.usage?.input_tokens || 0;
|
|
132
|
-
totalOutputTokens += r.usage?.output_tokens || 0;
|
|
133
|
-
totalCacheReadTokens += r.usage?.cache_read_input_tokens || 0;
|
|
134
|
-
totalCacheCreationTokens += r.usage?.cache_creation_input_tokens || 0;
|
|
135
|
-
}
|
|
136
|
-
totalCostUSD += r.total_cost_usd || 0;
|
|
137
|
-
totalDurationApiMs += r.duration_api_ms || 0;
|
|
138
|
-
totalNumTurns += r.num_turns || 0;
|
|
139
|
-
lastSubtype = r.subtype || lastSubtype;
|
|
140
|
-
}
|
|
141
|
-
const durationMs = resultMsgs[resultMsgs.length - 1].duration_ms || (Date.now() - start);
|
|
142
|
-
const trace = extractAgentTrace(messages, messageTimestamps);
|
|
143
|
-
if (lastSubtype !== 'success') {
|
|
144
|
-
const lastErr = resultMsgs[resultMsgs.length - 1];
|
|
145
|
-
const errMsg = lastErr.errors?.join('; ') || lastErr.subtype;
|
|
146
|
-
process.stderr.write(`[omk] claude-sdk executor: ${lastErr.subtype}: ${errMsg}\n`);
|
|
147
|
-
return {
|
|
148
|
-
ok: false, error: errMsg,
|
|
149
|
-
durationMs,
|
|
150
|
-
durationApiMs: totalDurationApiMs,
|
|
151
|
-
inputTokens: totalInputTokens,
|
|
152
|
-
outputTokens: totalOutputTokens,
|
|
153
|
-
cacheReadTokens: totalCacheReadTokens,
|
|
154
|
-
cacheCreationTokens: totalCacheCreationTokens,
|
|
155
|
-
costUSD: totalCostUSD,
|
|
156
|
-
output: null, stopReason: 'error', numTurns: totalNumTurns,
|
|
157
|
-
fullNumTurns: trace.fullNumTurns,
|
|
158
|
-
numSubAgents: trace.numSubAgents,
|
|
159
|
-
...(trace.turns.length > 0 && { turns: trace.turns }),
|
|
160
|
-
...(trace.toolCalls.length > 0 && { toolCalls: trace.toolCalls }),
|
|
161
|
-
...(mockStatsOf() && { mockStats: mockStatsOf() }),
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
103
|
return {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
cacheCreationTokens: totalCacheCreationTokens,
|
|
172
|
-
costUSD: totalCostUSD,
|
|
173
|
-
output,
|
|
174
|
-
stopReason: 'end',
|
|
175
|
-
numTurns: totalNumTurns,
|
|
176
|
-
fullNumTurns: trace.fullNumTurns,
|
|
177
|
-
numSubAgents: trace.numSubAgents,
|
|
178
|
-
...(trace.turns.length > 0 && { turns: trace.turns }),
|
|
179
|
-
...(trace.toolCalls.length > 0 && { toolCalls: trace.toolCalls }),
|
|
104
|
+
...buildClaudeResult({
|
|
105
|
+
messages,
|
|
106
|
+
messageTimestamps,
|
|
107
|
+
wallClockDurationMs: Date.now() - start,
|
|
108
|
+
source: 'claude-sdk',
|
|
109
|
+
}),
|
|
180
110
|
...(mockStatsOf() && { mockStats: mockStatsOf() }),
|
|
181
111
|
};
|
|
182
112
|
}
|
|
183
113
|
catch (err) {
|
|
184
|
-
clearTimeout(timer);
|
|
185
114
|
const durationMs = Date.now() - start;
|
|
186
115
|
const details = asErrorLike(err);
|
|
187
116
|
const isAbort = details.name === 'AbortError';
|
|
117
|
+
if (abortReason === 'interrupted') {
|
|
118
|
+
return {
|
|
119
|
+
...interruptedExecResult(durationMs),
|
|
120
|
+
...(mockStatsOf() && { mockStats: mockStatsOf() }),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (abortReason === 'timeout') {
|
|
124
|
+
return {
|
|
125
|
+
...timeoutExecResult(timeoutMs, durationMs),
|
|
126
|
+
...(mockStatsOf() && { mockStats: mockStatsOf() }),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
188
129
|
if (isAbort) {
|
|
189
|
-
process.stderr.write(
|
|
130
|
+
process.stderr.write('[omk] claude-sdk executor: execution aborted\n');
|
|
190
131
|
}
|
|
191
132
|
else {
|
|
192
133
|
process.stderr.write(`[omk] claude-sdk executor error: ${errorMessage(err)}\n`);
|
|
193
134
|
}
|
|
194
135
|
return {
|
|
195
136
|
ok: false,
|
|
196
|
-
error: isAbort ?
|
|
137
|
+
error: isAbort ? 'claude-sdk execution aborted' : errorMessage(err),
|
|
197
138
|
durationMs, durationApiMs: 0,
|
|
198
139
|
inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0,
|
|
199
|
-
|
|
200
|
-
|
|
140
|
+
tokenUsageReportedByExecutor: false,
|
|
141
|
+
costUSD: 0, costReportedByExecutor: false, output: null,
|
|
142
|
+
stopReason: 'error',
|
|
201
143
|
numTurns: 0,
|
|
202
144
|
...(mockStatsOf() && { mockStats: mockStatsOf() }),
|
|
203
145
|
};
|
|
204
146
|
}
|
|
147
|
+
finally {
|
|
148
|
+
clearTimeout(timer);
|
|
149
|
+
unregisterSigint();
|
|
150
|
+
}
|
|
205
151
|
}
|