oh-my-knowledge 0.52.3 → 0.54.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 (106) hide show
  1. package/README.md +21 -1
  2. package/README.zh.md +21 -1
  3. package/dist/assets/agent-skills/omk/SKILL.md +6 -0
  4. package/dist/assets/agent-skills/omk/references/commands.md +1 -1
  5. package/dist/authoring/evolver.js +1 -1
  6. package/dist/authoring/generator.js +1 -1
  7. package/dist/cli/commands/eval/index.js +7 -6
  8. package/dist/cli/commands/install.js +5 -1
  9. package/dist/cli/lib/generation-failure-hint.js +6 -8
  10. package/dist/cli/lib/runtime-defaults.d.ts +2 -0
  11. package/dist/cli/lib/runtime-defaults.js +7 -4
  12. package/dist/dsh-plugin/cordis.patch.yml +3 -0
  13. package/dist/dsh-plugin/host-executor.d.ts +93 -0
  14. package/dist/dsh-plugin/host-executor.js +232 -0
  15. package/dist/dsh-plugin/index.d.ts +30 -0
  16. package/dist/dsh-plugin/index.js +275 -0
  17. package/dist/dsh-plugin/observe.d.ts +47 -0
  18. package/dist/dsh-plugin/observe.js +359 -0
  19. package/dist/dsh-plugin/protocol.d.ts +21 -0
  20. package/dist/dsh-plugin/protocol.js +229 -0
  21. package/dist/dsh-plugin/trace-adapter.d.ts +48 -0
  22. package/dist/dsh-plugin/trace-adapter.js +590 -0
  23. package/dist/eval-core/comparability.js +3 -0
  24. package/dist/eval-core/evaluation-execution.js +5 -13
  25. package/dist/eval-core/evaluation-reporting.d.ts +7 -4
  26. package/dist/eval-core/evaluation-reporting.js +39 -18
  27. package/dist/eval-core/judge-independence.d.ts +1 -1
  28. package/dist/eval-core/judge-independence.js +1 -1
  29. package/dist/eval-core/report-document.js +6 -0
  30. package/dist/eval-core/resume-compatibility.d.ts +1 -0
  31. package/dist/eval-core/resume-compatibility.js +5 -4
  32. package/dist/eval-workflows/batch-evaluation-workflow.js +1 -1
  33. package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.js +4 -2
  34. package/dist/eval-workflows/evaluation-pipeline.d.ts +3 -1
  35. package/dist/eval-workflows/evaluation-pipeline.js +7 -3
  36. package/dist/eval-workflows/run-evaluation.d.ts +4 -2
  37. package/dist/eval-workflows/run-evaluation.js +7 -3
  38. package/dist/executors/{anthropic-api.d.ts → anthropic/api.d.ts} +1 -1
  39. package/dist/executors/{anthropic-api.js → anthropic/api.js} +4 -2
  40. package/dist/executors/{claude-cli.d.ts → anthropic/claude/cli.d.ts} +1 -1
  41. package/dist/executors/{claude-cli.js → anthropic/claude/cli.js} +5 -3
  42. package/dist/executors/anthropic/claude/protocol.d.ts +87 -0
  43. package/dist/executors/{claude-protocol.js → anthropic/claude/protocol.js} +6 -6
  44. package/dist/executors/{claude-sdk.d.ts → anthropic/claude/sdk.d.ts} +2 -2
  45. package/dist/executors/{claude-sdk.js → anthropic/claude/sdk.js} +8 -5
  46. package/dist/executors/anthropic/claude/trace.d.ts +9 -0
  47. package/dist/executors/{claude-sdk-trace.js → anthropic/claude/trace.js} +5 -5
  48. package/dist/executors/{capabilities.d.ts → core/capabilities.d.ts} +3 -5
  49. package/dist/executors/{capabilities.js → core/capabilities.js} +4 -11
  50. package/dist/executors/core/http.d.ts +6 -0
  51. package/dist/executors/core/http.js +19 -0
  52. package/dist/executors/core/limits.d.ts +2 -0
  53. package/dist/executors/core/limits.js +2 -0
  54. package/dist/executors/core/optional-dependencies.d.ts +7 -0
  55. package/dist/executors/core/optional-dependencies.js +35 -0
  56. package/dist/executors/core/registry.d.ts +145 -0
  57. package/dist/executors/core/registry.js +127 -0
  58. package/dist/executors/core/runtime-fingerprint.d.ts +13 -0
  59. package/dist/executors/{runtime-fingerprint.js → core/runtime-fingerprint.js} +119 -59
  60. package/dist/executors/core/runtime.d.ts +12 -0
  61. package/dist/executors/core/runtime.js +61 -0
  62. package/dist/executors/core/subprocess.d.ts +44 -0
  63. package/dist/executors/{shared.js → core/subprocess.js} +20 -156
  64. package/dist/executors/index.d.ts +4 -4
  65. package/dist/executors/index.js +26 -15
  66. package/dist/executors/{openai-api.d.ts → openai/api.d.ts} +1 -1
  67. package/dist/executors/{openai-api.js → openai/api.js} +4 -2
  68. package/dist/executors/{codex-cli.d.ts → openai/codex/cli.d.ts} +3 -3
  69. package/dist/executors/{codex-cli.js → openai/codex/cli.js} +5 -3
  70. package/dist/executors/openai/codex/protocol.d.ts +72 -0
  71. package/dist/executors/{codex-protocol.js → openai/codex/protocol.js} +33 -2
  72. package/dist/executors/{codex-sdk.d.ts → openai/codex/sdk.d.ts} +18 -4
  73. package/dist/executors/{codex-sdk.js → openai/codex/sdk.js} +7 -4
  74. package/dist/executors/{codex-cli-trace.d.ts → openai/codex/trace.d.ts} +2 -2
  75. package/dist/executors/{codex-cli-trace.js → openai/codex/trace.js} +4 -4
  76. package/dist/executors/{script.d.ts → script/index.d.ts} +1 -1
  77. package/dist/executors/{script.js → script/index.js} +6 -4
  78. package/dist/grading/judge.d.ts +1 -1
  79. package/dist/grading/judge.js +1 -1
  80. package/dist/observability/conversation-catalog.js +1 -1
  81. package/dist/observability/experience.js +4 -0
  82. package/dist/observability/inbox.d.ts +4 -1
  83. package/dist/observability/inbox.js +7 -2
  84. package/dist/observability/trace-ir.d.ts +6 -3
  85. package/dist/observability/turn-index.js +4 -0
  86. package/dist/renderer/conversation-renderer.js +20 -6
  87. package/dist/renderer/html-renderer.js +30 -11
  88. package/dist/renderer/knowledge-debugger-renderer.js +6 -1
  89. package/dist/renderer/observation-inbox-renderer.js +2 -2
  90. package/dist/renderer/trajectory-live.d.ts +1 -0
  91. package/dist/renderer/trajectory-live.js +5 -2
  92. package/dist/shared/trace-source-kind.js +1 -0
  93. package/dist/types/executor.d.ts +13 -2
  94. package/dist/types/judge.d.ts +2 -2
  95. package/dist/types/observability.d.ts +1 -1
  96. package/dist/types/trace.d.ts +1 -1
  97. package/package.json +25 -5
  98. package/dist/executors/claude-protocol.d.ts +0 -28
  99. package/dist/executors/claude-sdk-trace.d.ts +0 -9
  100. package/dist/executors/codex-protocol.d.ts +0 -24
  101. package/dist/executors/gemini.d.ts +0 -2
  102. package/dist/executors/gemini.js +0 -156
  103. package/dist/executors/runtime-fingerprint.d.ts +0 -6
  104. package/dist/executors/shared.d.ts +0 -226
  105. /package/dist/executors/{script-command.d.ts → script/command.d.ts} +0 -0
  106. /package/dist/executors/{script-command.js → script/command.js} +0 -0
@@ -0,0 +1,590 @@
1
+ import { normalizeToolIdentity } from '../shared/tool-identity.js';
2
+ import { correlateTraceToolEvents, createTraceId, traceTimestampBounds, } from '../observability/trace-ir.js';
3
+ export class DshTraceUnsupportedEventError extends Error {
4
+ eventType;
5
+ seq;
6
+ constructor(eventType, seq) {
7
+ super(`DSH session 包含 OMK 尚不认识的 required event:${eventType}(seq=${seq})。`);
8
+ this.eventType = eventType;
9
+ this.seq = seq;
10
+ this.name = 'DshTraceUnsupportedEventError';
11
+ }
12
+ }
13
+ const AUXILIARY_EVENT_TYPES = new Set([
14
+ 'agent-preset/selected',
15
+ 'agent/inbox/spliced',
16
+ 'approval/asked',
17
+ 'approval/decided',
18
+ 'approval/policy',
19
+ 'command/done',
20
+ 'command/run',
21
+ 'feedback/record',
22
+ 'goal/change',
23
+ 'hook/invoked',
24
+ 'hook/result',
25
+ 'llm/retry',
26
+ 'llm/retry-started',
27
+ 'permission/preset',
28
+ 'plan/mode',
29
+ 'sandbox/mode',
30
+ 'schedule/change',
31
+ 'session/title',
32
+ 'session/title-llm-request',
33
+ 'subagent/descriptor',
34
+ 'team/member',
35
+ 'team/message/delivered',
36
+ 'team/message/queued',
37
+ 'team/task',
38
+ 'tool-workflow/agent-end',
39
+ 'tool-workflow/agent-start',
40
+ 'tool-workflow/run-end',
41
+ 'tool-workflow/run-start',
42
+ 'tool/code-dispatch',
43
+ 'tool/code-dispatch-start',
44
+ 'web/deepseek-search-llm-request',
45
+ ]);
46
+ const PROJECTED_EVENT_TYPES = new Set([
47
+ 'assistant/chunk',
48
+ 'assistant/message',
49
+ 'request/context',
50
+ 'request/header',
51
+ 'session/end-seed',
52
+ 'step/end',
53
+ 'step/start',
54
+ 'todo/write',
55
+ 'tool/call',
56
+ 'tool/result',
57
+ 'turn/end',
58
+ 'turn/start',
59
+ 'user/message',
60
+ ]);
61
+ function supportsEventType(eventType) {
62
+ return PROJECTED_EVENT_TYPES.has(eventType)
63
+ || AUXILIARY_EVENT_TYPES.has(eventType)
64
+ || eventType.startsWith('compaction/');
65
+ }
66
+ function isRecord(value) {
67
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
68
+ }
69
+ function stringValue(value) {
70
+ return typeof value === 'string' && value.trim() ? value : undefined;
71
+ }
72
+ function nonNegativeInteger(value) {
73
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0
74
+ ? value
75
+ : undefined;
76
+ }
77
+ function timestamp(value) {
78
+ const milliseconds = nonNegativeInteger(value);
79
+ if (milliseconds === undefined)
80
+ return undefined;
81
+ return new Date(milliseconds).toISOString();
82
+ }
83
+ function textFromContent(value) {
84
+ if (typeof value === 'string')
85
+ return value;
86
+ if (!Array.isArray(value))
87
+ return '';
88
+ return value.flatMap((block) => (isRecord(block) && block.type === 'text' && typeof block.text === 'string'
89
+ ? [block.text]
90
+ : [])).join('');
91
+ }
92
+ function reasoningFromContent(value) {
93
+ if (!Array.isArray(value))
94
+ return [];
95
+ return value.flatMap((block) => (isRecord(block) && block.type === 'reasoning' && typeof block.text === 'string'
96
+ ? [block.text]
97
+ : []));
98
+ }
99
+ function jsonText(value) {
100
+ try {
101
+ return JSON.stringify(value);
102
+ }
103
+ catch {
104
+ return String(value ?? '');
105
+ }
106
+ }
107
+ function objectInput(value) {
108
+ if (isRecord(value))
109
+ return value;
110
+ if (typeof value === 'string') {
111
+ try {
112
+ const parsed = JSON.parse(value);
113
+ if (isRecord(parsed))
114
+ return parsed;
115
+ }
116
+ catch {
117
+ // Preserve the exact provider output below.
118
+ }
119
+ return { rawArguments: value };
120
+ }
121
+ return { rawArguments: value ?? null };
122
+ }
123
+ function turnId(runId, data) {
124
+ const turn = nonNegativeInteger(data.turn);
125
+ return turn === undefined ? undefined : `dsh:${runId}:turn:${turn}`;
126
+ }
127
+ function eventBase(runId, event, sourceIndex, suffix) {
128
+ const data = isRecord(event.data) ? event.data : {};
129
+ return {
130
+ eventId: `${runId}:${event.seq}:${suffix}`,
131
+ sourceIndex,
132
+ sourceType: event.type,
133
+ timestamp: timestamp(event.time),
134
+ turnId: turnId(runId, data),
135
+ };
136
+ }
137
+ function messageOrigin(source) {
138
+ if (!isRecord(source))
139
+ return 'synthetic';
140
+ const sourceKind = stringValue(source.kind);
141
+ if (sourceKind === 'user')
142
+ return 'human';
143
+ if (sourceKind === 'skill-invocation' || sourceKind === 'skill-catalog')
144
+ return 'skill-context';
145
+ if (sourceKind?.includes('skill'))
146
+ return 'skill-context';
147
+ if (sourceKind === 'plugin' || sourceKind === 'agent-instructions')
148
+ return 'runtime';
149
+ return 'synthetic';
150
+ }
151
+ function turnEndProjection(reason) {
152
+ const record = isRecord(reason) ? reason : {};
153
+ const reasonKind = stringValue(record.kind) ?? 'unknown';
154
+ if (reasonKind === 'completed')
155
+ return { phase: 'turn_completed', status: 'completed', reason: reasonKind };
156
+ if (reasonKind === 'aborted')
157
+ return { phase: 'turn_aborted', status: 'aborted', reason: jsonText(record) };
158
+ if (reasonKind === 'interrupted')
159
+ return { phase: 'turn_interrupted', status: 'interrupted', reason: reasonKind };
160
+ if (reasonKind === 'error' || reasonKind === 'blocked' || reasonKind === 'max-tokens') {
161
+ return { phase: 'turn_failed', status: 'failed', reason: jsonText(record) };
162
+ }
163
+ return {
164
+ phase: 'turn_ended_unknown',
165
+ status: 'unknown',
166
+ reason: `unknown terminal reason: ${jsonText(record)}`,
167
+ };
168
+ }
169
+ function requestFacts(data) {
170
+ if (isRecord(data.header)) {
171
+ const config = isRecord(data.header.config) ? data.header.config : {};
172
+ return {
173
+ model: stringValue(config.model),
174
+ provider: stringValue(config.provider),
175
+ reasoningEffort: stringValue(config.reasoningEffort),
176
+ };
177
+ }
178
+ return {
179
+ model: stringValue(data.model),
180
+ provider: stringValue(data.provider),
181
+ contextWindowId: nonNegativeInteger(data.contextWindow)?.toString(),
182
+ };
183
+ }
184
+ function compactionEvents(runId, event, sourceIndex) {
185
+ const data = isRecord(event.data) ? event.data : {};
186
+ if (event.type === 'compaction/summary') {
187
+ return [{
188
+ ...eventBase(runId, event, sourceIndex, 'compaction-summary'),
189
+ eventKind: 'context_compaction',
190
+ summary: textFromContent(data.summary),
191
+ replacementItemCount: Array.isArray(data.shadowedSeqs) ? data.shadowedSeqs.length : undefined,
192
+ }];
193
+ }
194
+ return [{
195
+ ...eventBase(runId, event, sourceIndex, 'compaction'),
196
+ eventKind: 'runtime_context',
197
+ runtimeKind: 'execution_context',
198
+ summary: `${event.type}: ${jsonText(data)}`,
199
+ }];
200
+ }
201
+ function auxiliaryEvent(runId, event, sourceIndex) {
202
+ const data = isRecord(event.data) ? event.data : {};
203
+ const agentActivity = event.type.startsWith('subagent/')
204
+ || event.type.startsWith('team/')
205
+ || event.type.startsWith('tool-workflow/');
206
+ if (agentActivity) {
207
+ return {
208
+ ...eventBase(runId, event, sourceIndex, 'agent-activity'),
209
+ eventKind: 'agent_activity',
210
+ activityKind: event.type.includes('message') ? 'communication' : 'status',
211
+ activity: event.type,
212
+ agentId: stringValue(data.agentId) ?? stringValue(data.memberId),
213
+ author: stringValue(data.author),
214
+ recipient: stringValue(data.recipient),
215
+ text: jsonText(data),
216
+ };
217
+ }
218
+ return {
219
+ ...eventBase(runId, event, sourceIndex, 'runtime-context'),
220
+ eventKind: 'runtime_context',
221
+ runtimeKind: event.type.startsWith('goal/') || event.type === 'todo/write' ? 'goal' : 'execution_context',
222
+ goal: event.type.startsWith('goal/') || event.type === 'todo/write' ? jsonText(data) : undefined,
223
+ summary: `${event.type}: ${jsonText(data)}`,
224
+ };
225
+ }
226
+ function toolResultData(data) {
227
+ const message = isRecord(data.message) ? data.message : {};
228
+ const blocks = Array.isArray(message.content) ? message.content.filter(isRecord) : [];
229
+ const result = blocks.find((block) => block.type === 'tool-result');
230
+ const content = isRecord(result) ? result.content : undefined;
231
+ const output = textFromContent(content) || jsonText(content ?? result ?? data);
232
+ return {
233
+ callId: isRecord(result) ? stringValue(result.toolCallId) : undefined,
234
+ output,
235
+ failed: data.error !== undefined || (isRecord(result) && result.isError === true),
236
+ };
237
+ }
238
+ function validateEnvelope(event, expectedSeq) {
239
+ if (!Number.isSafeInteger(event.seq) || event.seq !== expectedSeq) {
240
+ throw new Error(`DSH session event seq 不连续:期望 ${expectedSeq},实际 ${String(event.seq)}。`);
241
+ }
242
+ if (!Number.isSafeInteger(event.time) || event.time < 0) {
243
+ throw new Error(`DSH session event time 非法:seq=${event.seq}。`);
244
+ }
245
+ if (!event.type.trim())
246
+ throw new Error(`DSH session event type 为空:seq=${event.seq}。`);
247
+ }
248
+ /** Project one validated, backend-neutral DSH logical log into OMK Trace IR. */
249
+ export function adaptDshSession(header, inputEvents, options = {}) {
250
+ const runId = String(header.id);
251
+ if (!runId.trim())
252
+ throw new Error('DSH session header 缺少 id。');
253
+ const seedLength = header.seedLength === undefined ? 0 : nonNegativeInteger(header.seedLength);
254
+ if (seedLength === undefined || seedLength > inputEvents.length) {
255
+ throw new Error(`DSH session header seedLength 非法:${String(header.seedLength)}。`);
256
+ }
257
+ inputEvents.forEach(validateEnvelope);
258
+ const activeEvents = inputEvents.slice(seedLength);
259
+ const isSubagent = header.origin === 'subagent';
260
+ const sourcePath = `dsh:${runId}`;
261
+ const traceId = createTraceId({ sourceKind: 'dsh', runId, sourcePath });
262
+ const rootRunId = options.rootRunId ?? (isSubagent ? header.parentSession : undefined) ?? runId;
263
+ const role = options.role ?? (isSubagent ? 'subagent' : 'main');
264
+ const events = [{
265
+ eventKind: 'lifecycle',
266
+ eventId: `${runId}:header:session-started`,
267
+ sourceIndex: 0,
268
+ sourceType: 'session/header',
269
+ timestamp: timestamp(header.createdAt),
270
+ phase: 'session_started',
271
+ }, {
272
+ eventKind: 'runtime_context',
273
+ eventId: `${runId}:header:context`,
274
+ sourceIndex: 0,
275
+ sourceType: 'session/header',
276
+ timestamp: timestamp(header.createdAt),
277
+ runtimeKind: 'session_context',
278
+ runtimeName: 'DeepSeek Harness',
279
+ cwd: header.cwd,
280
+ parentRunId: isSubagent ? header.parentSession : undefined,
281
+ delegationDepth: header.delegationDepth,
282
+ sourceOrigin: header.origin,
283
+ historyMode: header.seedLength === undefined ? undefined : `seed:${header.seedLength}`,
284
+ summary: jsonText({
285
+ agentPreset: header.agentPreset,
286
+ parentSession: header.parentSession,
287
+ origin: header.origin,
288
+ delegationDepth: header.delegationDepth,
289
+ seedLength: header.seedLength,
290
+ }),
291
+ }];
292
+ const pendingTools = new Set();
293
+ const openTurns = new Set();
294
+ const openSteps = new Set();
295
+ const assembledSteps = new Set();
296
+ let unknownEventCount = 0;
297
+ let ignoredChunkCount = 0;
298
+ let unmatchedToolResultCount = 0;
299
+ const terminal = { status: 'unknown' };
300
+ let observedModel;
301
+ let observedProvider;
302
+ for (const event of activeEvents) {
303
+ if (event.type !== 'assistant/message')
304
+ continue;
305
+ const data = isRecord(event.data) ? event.data : {};
306
+ const turn = nonNegativeInteger(data.turn);
307
+ const step = nonNegativeInteger(data.step);
308
+ if (turn !== undefined && step !== undefined)
309
+ assembledSteps.add(`${turn}:${step}`);
310
+ }
311
+ inputEvents.slice(0, seedLength).forEach((event) => {
312
+ if (event.ignorable !== true && !supportsEventType(event.type)) {
313
+ throw new DshTraceUnsupportedEventError(event.type, event.seq);
314
+ }
315
+ });
316
+ activeEvents.forEach((event, activeIndex) => {
317
+ const index = seedLength + activeIndex;
318
+ const sourceIndex = index + 1;
319
+ const data = isRecord(event.data) ? event.data : {};
320
+ const base = (suffix) => eventBase(runId, event, sourceIndex, suffix);
321
+ const sourceEventId = (value) => {
322
+ const id = stringValue(value);
323
+ return id ? { sourceEventId: id } : {};
324
+ };
325
+ if (event.type === 'turn/start') {
326
+ const turn = nonNegativeInteger(data.turn);
327
+ if (turn === undefined)
328
+ throw new Error(`DSH turn/start 缺少 turn:seq=${event.seq}。`);
329
+ openTurns.add(turn);
330
+ terminal.status = 'open';
331
+ events.push({ ...base('turn-start'), eventKind: 'lifecycle', phase: 'turn_started' });
332
+ return;
333
+ }
334
+ if (event.type === 'turn/end') {
335
+ const turn = nonNegativeInteger(data.turn);
336
+ if (turn === undefined)
337
+ throw new Error(`DSH turn/end 缺少 turn:seq=${event.seq}。`);
338
+ openTurns.delete(turn);
339
+ const projection = turnEndProjection(data.reason);
340
+ terminal.status = projection.status;
341
+ events.push({
342
+ ...base('turn-end'),
343
+ eventKind: 'lifecycle',
344
+ phase: projection.phase,
345
+ reason: projection.reason,
346
+ });
347
+ return;
348
+ }
349
+ if (event.type === 'step/start' || event.type === 'step/end') {
350
+ const turn = nonNegativeInteger(data.turn);
351
+ const step = nonNegativeInteger(data.step);
352
+ if (turn === undefined || step === undefined) {
353
+ throw new Error(`DSH ${event.type} 缺少 turn/step:seq=${event.seq}。`);
354
+ }
355
+ const key = `${turn}:${step}`;
356
+ if (event.type === 'step/start')
357
+ openSteps.add(key);
358
+ else
359
+ openSteps.delete(key);
360
+ events.push({
361
+ ...base(event.type === 'step/start' ? 'step-start' : 'step-end'),
362
+ eventKind: 'lifecycle',
363
+ phase: event.type === 'step/start' ? 'step_started' : 'step_completed',
364
+ reason: `step=${step}`,
365
+ });
366
+ return;
367
+ }
368
+ if (event.type === 'user/message') {
369
+ const text = textFromContent(data.content);
370
+ const source = isRecord(data.source) ? data.source : undefined;
371
+ events.push({
372
+ ...base('user-message'),
373
+ ...sourceEventId(data.id),
374
+ eventKind: 'message',
375
+ role: 'user',
376
+ origin: messageOrigin(source),
377
+ text,
378
+ attributionSkill: source?.kind === 'skill-invocation' ? stringValue(source.name) : undefined,
379
+ });
380
+ return;
381
+ }
382
+ if (event.type === 'assistant/message') {
383
+ const message = isRecord(data.message) ? data.message : {};
384
+ const source = isRecord(message.source) ? message.source : {};
385
+ const model = stringValue(source.model);
386
+ const provider = stringValue(source.provider);
387
+ observedModel = model ?? observedModel;
388
+ observedProvider = provider ?? observedProvider;
389
+ const text = textFromContent(message.content);
390
+ if (text) {
391
+ events.push({
392
+ ...base('assistant-message'),
393
+ ...sourceEventId(message.id),
394
+ eventKind: 'message',
395
+ role: 'assistant',
396
+ origin: 'synthetic',
397
+ text,
398
+ model,
399
+ });
400
+ }
401
+ reasoningFromContent(message.content).forEach((reasoning, reasoningIndex) => {
402
+ events.push({
403
+ ...base(`reasoning-${reasoningIndex}`),
404
+ ...sourceEventId(message.id),
405
+ eventKind: 'model_activity',
406
+ activityKind: 'reasoning',
407
+ contentVisibility: 'plaintext',
408
+ contentSource: 'content',
409
+ text: reasoning,
410
+ model,
411
+ });
412
+ });
413
+ if (isRecord(data.usage)) {
414
+ const inputTokens = nonNegativeInteger(data.usage.inputTokens);
415
+ const outputTokens = nonNegativeInteger(data.usage.outputTokens);
416
+ if (inputTokens === undefined || outputTokens === undefined) {
417
+ throw new Error(`DSH assistant/message usage 非法:seq=${event.seq}。`);
418
+ }
419
+ events.push({
420
+ ...base('usage'),
421
+ eventKind: 'usage',
422
+ model,
423
+ inputTokens,
424
+ outputTokens,
425
+ cacheReadTokens: nonNegativeInteger(data.usage.cacheReadTokens),
426
+ cacheCreationTokens: nonNegativeInteger(data.usage.cacheWriteTokens),
427
+ reasoningTokens: nonNegativeInteger(data.usage.reasoningTokens),
428
+ });
429
+ }
430
+ return;
431
+ }
432
+ if (event.type === 'assistant/chunk') {
433
+ const turn = nonNegativeInteger(data.turn);
434
+ const step = nonNegativeInteger(data.step);
435
+ const chunk = isRecord(data.chunk) ? data.chunk : {};
436
+ if (turn !== undefined && step !== undefined && assembledSteps.has(`${turn}:${step}`)) {
437
+ ignoredChunkCount += 1;
438
+ return;
439
+ }
440
+ if (chunk.type === 'reasoning-delta' && typeof chunk.text === 'string' && chunk.text) {
441
+ events.push({
442
+ ...base('reasoning-delta'),
443
+ eventKind: 'model_activity',
444
+ activityKind: 'reasoning',
445
+ contentVisibility: 'plaintext',
446
+ contentSource: 'text',
447
+ text: chunk.text,
448
+ model: observedModel,
449
+ });
450
+ }
451
+ else if (chunk.type === 'text-delta' && typeof chunk.text === 'string' && chunk.text) {
452
+ events.push({
453
+ ...base('text-delta'),
454
+ eventKind: 'message',
455
+ role: 'assistant',
456
+ origin: 'synthetic',
457
+ text: chunk.text,
458
+ model: observedModel,
459
+ });
460
+ }
461
+ else {
462
+ ignoredChunkCount += 1;
463
+ }
464
+ return;
465
+ }
466
+ if (event.type === 'tool/call') {
467
+ const callId = stringValue(data.callId);
468
+ const name = stringValue(data.name);
469
+ if (!callId || !name)
470
+ throw new Error(`DSH tool/call 缺少 callId/name:seq=${event.seq}。`);
471
+ pendingTools.add(callId);
472
+ events.push({
473
+ ...base('tool-call'),
474
+ ...sourceEventId(callId),
475
+ eventKind: 'tool_call',
476
+ callId,
477
+ callInstanceId: `${runId}:${callId}`,
478
+ tool: normalizeToolIdentity({ sourceName: name }),
479
+ input: objectInput(data.arguments),
480
+ model: observedModel,
481
+ });
482
+ return;
483
+ }
484
+ if (event.type === 'tool/result') {
485
+ const result = toolResultData(data);
486
+ if (!result.callId)
487
+ throw new Error(`DSH tool/result 缺少 toolCallId:seq=${event.seq}。`);
488
+ if (!pendingTools.delete(result.callId))
489
+ unmatchedToolResultCount += 1;
490
+ events.push({
491
+ ...base('tool-result'),
492
+ ...sourceEventId(result.callId),
493
+ eventKind: 'tool_result',
494
+ callId: result.callId,
495
+ callInstanceId: `${runId}:${result.callId}`,
496
+ output: result.output,
497
+ status: result.failed ? 'failure' : 'success',
498
+ statusSource: 'runtime',
499
+ });
500
+ return;
501
+ }
502
+ if (event.type === 'request/header' || event.type === 'request/context') {
503
+ const facts = requestFacts(data);
504
+ observedModel = facts.model ?? observedModel;
505
+ observedProvider = facts.provider ?? observedProvider;
506
+ events.push({
507
+ ...base('request-context'),
508
+ eventKind: 'runtime_context',
509
+ runtimeKind: 'execution_context',
510
+ runtimeName: 'DeepSeek Harness',
511
+ model: facts.model,
512
+ modelProvider: facts.provider,
513
+ reasoningEffort: facts.reasoningEffort,
514
+ contextWindowId: facts.contextWindowId,
515
+ summary: `${event.type}: ${jsonText(data)}`,
516
+ });
517
+ return;
518
+ }
519
+ if (event.type === 'session/end-seed') {
520
+ events.push({
521
+ ...base('seed-boundary'),
522
+ eventKind: 'runtime_context',
523
+ runtimeKind: 'session_context',
524
+ historyMode: `seed-boundary:${event.seq}`,
525
+ summary: 'DSH session seed boundary',
526
+ });
527
+ return;
528
+ }
529
+ if (event.type.startsWith('compaction/')) {
530
+ events.push(...compactionEvents(runId, event, sourceIndex));
531
+ return;
532
+ }
533
+ if (event.type === 'todo/write' || AUXILIARY_EVENT_TYPES.has(event.type)) {
534
+ events.push(auxiliaryEvent(runId, event, sourceIndex));
535
+ return;
536
+ }
537
+ if (event.ignorable === true) {
538
+ unknownEventCount += 1;
539
+ events.push({
540
+ ...base('unknown'),
541
+ eventKind: 'unknown',
542
+ raw: event,
543
+ });
544
+ return;
545
+ }
546
+ throw new DshTraceUnsupportedEventError(event.type, event.seq);
547
+ });
548
+ const correlated = correlateTraceToolEvents(events);
549
+ const bounds = traceTimestampBounds(correlated.map((event) => event.timestamp));
550
+ const unmatchedToolCallCount = pendingTools.size;
551
+ const openTurnCount = openTurns.size;
552
+ const openStepCount = openSteps.size;
553
+ const complete = unmatchedToolCallCount === 0
554
+ && unmatchedToolResultCount === 0
555
+ && openTurnCount === 0
556
+ && openStepCount === 0
557
+ && terminal.status !== 'open'
558
+ && terminal.status !== 'unknown';
559
+ return {
560
+ session: {
561
+ runId,
562
+ rootRunId,
563
+ ...(isSubagent && header.parentSession ? { parentRunId: header.parentSession } : {}),
564
+ traceId,
565
+ groupPath: options.groupPath ?? `dsh:${rootRunId}`,
566
+ role,
567
+ label: role === 'subagent' ? `DSH subagent ${runId}` : `DSH session ${runId}`,
568
+ sourcePath,
569
+ sourceKind: 'dsh',
570
+ events: correlated,
571
+ cwd: header.cwd,
572
+ entrypoint: 'dsh',
573
+ sourceMetadata: {
574
+ provider: observedProvider,
575
+ model: observedModel,
576
+ },
577
+ ...bounds,
578
+ },
579
+ integrity: {
580
+ complete,
581
+ status: terminal.status,
582
+ unknownEventCount,
583
+ ignoredChunkCount,
584
+ unmatchedToolCallCount,
585
+ unmatchedToolResultCount,
586
+ openTurnCount,
587
+ openStepCount,
588
+ },
589
+ };
590
+ }
@@ -44,6 +44,9 @@ function packageReasons(pkg, label) {
44
44
  }
45
45
  function runtimeUnverifiableReasons(runtime) {
46
46
  const reasons = [];
47
+ if (runtime.auditability?.status === 'partial') {
48
+ reasons.push(...(runtime.auditability.reasons ?? ['runtime auditability partial']));
49
+ }
47
50
  if (runtime.runtimeKind === 'api')
48
51
  return reasons;
49
52
  if (runtime.runtimeKind === 'agent-sdk') {
@@ -5,22 +5,14 @@ import { grade } from '../grading/index.js';
5
5
  import { checkFacts } from './fact-checker.js';
6
6
  import { resolveExecutionStrategy } from './execution-strategy.js';
7
7
  import { DEFAULT_CACHE_DIR, DEFAULT_ISOLATED_CWD_DIR } from './default-dirs.js';
8
- import { getExecutorRuntimeFingerprint } from '../executors/runtime-fingerprint.js';
8
+ import { resolveExecutorRuntimeFingerprint } from '../executors/core/runtime-fingerprint.js';
9
+ import { isRegisteredExecutorName } from '../executors/core/registry.js';
9
10
  import { ownRecordValue, setOwnRecordValue, } from '../shared/record-count.js';
10
11
  import { executorResultValidationError, normalizeExecResultToolIdentities, } from '../shared/executor-result.js';
11
12
  import { hashSampleExecutionDependencies } from './sample-fingerprint.js';
12
13
  import { resolveDiagnosticTarget } from '../grading/diagnostic.js';
13
14
  import { dirname, join, resolve } from 'node:path';
14
15
  import { mkdir, mkdtemp, rm } from 'node:fs/promises';
15
- const PREFLIGHT_RUNTIME_LABEL_EXECUTORS = new Set([
16
- 'claude',
17
- 'claude-sdk',
18
- 'codex',
19
- 'codex-sdk',
20
- 'gemini',
21
- 'anthropic-api',
22
- 'openai-api',
23
- ]);
24
16
  async function runWithConcurrency(tasks, concurrency, fn) {
25
17
  let index = 0;
26
18
  async function worker() {
@@ -119,9 +111,9 @@ export async function executeTasks({ tasks, executor, executorName, model, noJud
119
111
  const total = tasks.length;
120
112
  onProgress?.({ phase: 'start', completed: idx, total, sample_id: task.sample_id, variant: task.variant });
121
113
  const executionPlan = resolveExecutionStrategy(task, model, timeoutMs, verbose, effort, samplesBaseDir);
122
- const executorRuntime = getExecutorRuntimeFingerprint(effectiveExecutorName, model, {
114
+ const executorRuntime = resolveExecutorRuntimeFingerprint(effectiveExecutorName, model, {
123
115
  skillDir: executionPlan.input.skillDir,
124
- });
116
+ }, executor);
125
117
  let execResult;
126
118
  // include allowedSkills in cache key so isolation-on / isolation-off runs
127
119
  // don't share cache entries, and include runtime fingerprint so a binary/SDK bump
@@ -390,7 +382,7 @@ export async function executeTasks({ tasks, executor, executorName, model, noJud
390
382
  return { results, totalCostUSD, skipped, budgetExhausted };
391
383
  }
392
384
  export function preflightRuntimeLabel(executorName, model) {
393
- return PREFLIGHT_RUNTIME_LABEL_EXECUTORS.has(executorName) ? `${executorName}:${model}` : `custom:${model}`;
385
+ return isRegisteredExecutorName(executorName) ? `${executorName}:${model}` : `custom:${model}`;
394
386
  }
395
387
  export async function preflight(executor, model, timeoutMs = 180000, label) {
396
388
  const result = await executor({
@@ -1,18 +1,19 @@
1
- import { getExecutorRuntimeFingerprint } from '../executors/runtime-fingerprint.js';
1
+ import { getExecutorRuntimeFingerprint } from '../executors/core/runtime-fingerprint.js';
2
2
  import type { Artifact, Report, Sample, Task, VariantResult, GitInfo, EvaluationJob, EvaluationRequest, EvaluationRun, ReportDocument } from '../types/index.js';
3
3
  export declare const DEFAULT_OUTPUT_DIR: string;
4
4
  export declare const EVALUATION_REPORT_SCHEMA_VERSION = 5;
5
5
  export declare function hashString(str: string): string;
6
6
  export { hashSample } from './sample-fingerprint.js';
7
7
  export declare function getCliVersion(): string;
8
- export declare function getGitInfo(): GitInfo | null;
9
- export declare function buildExecutorRuntimesByVariant({ variants, model, executorName, tasks, artifacts, request, }: {
8
+ export declare function getGitInfo(cwd?: string): GitInfo | null;
9
+ export declare function buildExecutorRuntimesByVariant({ variants, model, executorName, tasks, artifacts, request, executor, }: {
10
10
  variants: string[];
11
11
  model: string;
12
12
  executorName: string;
13
13
  tasks: Task[];
14
14
  artifacts: Artifact[];
15
15
  request?: Pick<EvaluationRequest, 'skillDir' | 'timeoutMs'>;
16
+ executor?: import('../types/index.js').ExecutorFn;
16
17
  }): Record<string, ReturnType<typeof getExecutorRuntimeFingerprint>>;
17
18
  interface AggregateReportOptions {
18
19
  runId: string;
@@ -31,8 +32,10 @@ interface AggregateReportOptions {
31
32
  run?: EvaluationRun;
32
33
  job?: EvaluationJob;
33
34
  layeredStats?: boolean;
35
+ executor?: import('../types/index.js').ExecutorFn;
36
+ judgeExecutors?: Readonly<Record<string, import('../types/index.js').ExecutorFn>>;
34
37
  }
35
- export declare function aggregateReport({ runId, variants, model, judgeModel, noJudge, executorName, samples, samplesBaseDir, tasks, results, totalCostUSD, artifacts, request, run, job, layeredStats, }: AggregateReportOptions): Report;
38
+ export declare function aggregateReport({ runId, variants, model, judgeModel, noJudge, executorName, samples, samplesBaseDir, tasks, results, totalCostUSD, artifacts, request, run, job, layeredStats, executor, judgeExecutors, }: AggregateReportOptions): Report;
36
39
  export type PersistableReport = ReportDocument;
37
40
  export declare function persistReport(report: PersistableReport, outputDir: string | null): string | null;
38
41
  /**