oh-my-knowledge 0.53.0 → 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.
- package/README.md +9 -1
- package/README.zh.md +9 -1
- package/dist/assets/agent-skills/omk/SKILL.md +2 -0
- package/dist/dsh-plugin/index.d.ts +4 -2
- package/dist/dsh-plugin/index.js +134 -15
- package/dist/dsh-plugin/observe.d.ts +47 -0
- package/dist/dsh-plugin/observe.js +359 -0
- package/dist/dsh-plugin/trace-adapter.d.ts +48 -0
- package/dist/dsh-plugin/trace-adapter.js +590 -0
- package/dist/observability/conversation-catalog.js +1 -1
- package/dist/observability/experience.js +4 -0
- package/dist/observability/inbox.d.ts +4 -1
- package/dist/observability/inbox.js +7 -2
- package/dist/observability/trace-ir.d.ts +6 -3
- package/dist/observability/turn-index.js +4 -0
- package/dist/renderer/conversation-renderer.js +20 -6
- package/dist/renderer/knowledge-debugger-renderer.js +6 -1
- package/dist/renderer/observation-inbox-renderer.js +2 -2
- package/dist/renderer/trajectory-live.d.ts +1 -0
- package/dist/renderer/trajectory-live.js +5 -2
- package/dist/shared/trace-source-kind.js +1 -0
- package/dist/types/observability.d.ts +1 -1
- package/dist/types/trace.d.ts +1 -1
- package/package.json +5 -1
|
@@ -5,7 +5,7 @@ import { OMK_HOME } from '../eval-core/default-dirs.js';
|
|
|
5
5
|
import { isReportFileName, randomRunToken, reportFilePath } from '../eval-core/artifact-file-names.js';
|
|
6
6
|
import { migrateLegacyReportFiles } from '../eval-core/report-file-migration.js';
|
|
7
7
|
import { extractGapSignalsFromTrace } from '../analysis/gap-analyzer.js';
|
|
8
|
-
import { loadTraceSessions, tracesToResultEntries, skillSegmentTimestampObserved, } from './trace-adapter.js';
|
|
8
|
+
import { loadTraceSessions, segmentTraceBySkill, tracesToResultEntries, skillSegmentTimestampObserved, } from './trace-adapter.js';
|
|
9
9
|
import { normalizeTraceTimestamp } from './trace-ir.js';
|
|
10
10
|
import { isSearchToolCall, toolCallQuery } from '../shared/tool-search.js';
|
|
11
11
|
import { isToolCallFailure, isToolCallSuccess } from '../shared/tool-call-status.js';
|
|
@@ -410,7 +410,12 @@ function skillSessionCountKey(segment) {
|
|
|
410
410
|
* `buildObserveDiagnosticsFromReport(report)` 写入 `report.diagnostics`。
|
|
411
411
|
*/
|
|
412
412
|
export function buildObservationInboxReport(tracePath, options = {}) {
|
|
413
|
-
const { sessions,
|
|
413
|
+
const { sessions, ingestion } = tracesToResultEntries(tracePath);
|
|
414
|
+
return buildObservationInboxReportFromTraceSessions(tracePath, sessions, ingestion, options);
|
|
415
|
+
}
|
|
416
|
+
/** Build the existing inbox artifact from an in-memory source-neutral corpus. */
|
|
417
|
+
export function buildObservationInboxReportFromTraceSessions(tracePath, sessions, ingestion, options = {}) {
|
|
418
|
+
const segments = sessions.flatMap(segmentTraceBySkill);
|
|
414
419
|
const skillSegments = segments.filter((segment) => segment.skillName !== 'general');
|
|
415
420
|
const generatedAt = new Date().toISOString();
|
|
416
421
|
const sessionTimeRanges = buildSessionTimeRanges(sessions);
|
|
@@ -60,8 +60,8 @@ export interface TraceUsageEvent extends TraceEventBase {
|
|
|
60
60
|
model?: string;
|
|
61
61
|
inputTokens: number;
|
|
62
62
|
outputTokens: number;
|
|
63
|
-
cacheReadTokens
|
|
64
|
-
cacheCreationTokens
|
|
63
|
+
cacheReadTokens?: number;
|
|
64
|
+
cacheCreationTokens?: number;
|
|
65
65
|
reasoningTokens?: number;
|
|
66
66
|
}
|
|
67
67
|
export interface TraceModelActivityEvent extends TraceEventBase {
|
|
@@ -74,7 +74,7 @@ export interface TraceModelActivityEvent extends TraceEventBase {
|
|
|
74
74
|
}
|
|
75
75
|
export interface TraceLifecycleEvent extends TraceEventBase {
|
|
76
76
|
eventKind: 'lifecycle';
|
|
77
|
-
phase: 'session_started' | 'session_ended' | 'turn_started' | 'turn_completed' | 'turn_aborted' | 'turn_interrupted';
|
|
77
|
+
phase: 'session_started' | 'session_ended' | 'turn_started' | 'turn_completed' | 'turn_failed' | 'turn_aborted' | 'turn_interrupted' | 'turn_ended_unknown' | 'step_started' | 'step_completed';
|
|
78
78
|
reason?: string;
|
|
79
79
|
durationMs?: number;
|
|
80
80
|
}
|
|
@@ -105,6 +105,9 @@ export interface TraceRuntimeContextEvent extends TraceEventBase {
|
|
|
105
105
|
memoryMode?: string;
|
|
106
106
|
historyMode?: string;
|
|
107
107
|
contextWindowId?: string;
|
|
108
|
+
parentRunId?: string;
|
|
109
|
+
delegationDepth?: number;
|
|
110
|
+
sourceOrigin?: string;
|
|
108
111
|
availableTools?: string[];
|
|
109
112
|
instructions?: string;
|
|
110
113
|
goal?: string;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
const TERMINAL_LIFECYCLE_LABELS = new Set([
|
|
3
3
|
'turn_completed',
|
|
4
|
+
'turn_failed',
|
|
4
5
|
'turn_aborted',
|
|
5
6
|
'turn_interrupted',
|
|
7
|
+
'turn_ended_unknown',
|
|
6
8
|
]);
|
|
7
9
|
/** Reconstruct every observable task without consulting Skill attribution. */
|
|
8
10
|
export function reconstructExperienceTurns(timeline) {
|
|
@@ -124,6 +126,8 @@ function turnStatus(events) {
|
|
|
124
126
|
const labels = new Set(events.map((event) => event.label));
|
|
125
127
|
if (labels.has('turn_completed'))
|
|
126
128
|
return 'completed';
|
|
129
|
+
if (labels.has('turn_failed'))
|
|
130
|
+
return 'failed';
|
|
127
131
|
if (labels.has('turn_aborted'))
|
|
128
132
|
return 'aborted';
|
|
129
133
|
if (labels.has('turn_interrupted'))
|
|
@@ -54,8 +54,8 @@ export function renderConversationIndexPage(model, lang = DEFAULT_LANG) {
|
|
|
54
54
|
const rows = conversations.map((conversation) => renderConversationRow(conversation, lang)).join('');
|
|
55
55
|
const content = model.conversations.length > 0
|
|
56
56
|
? `<div class="conversation-list" role="list">${rows}</div>`
|
|
57
|
-
: `<div class="empty-state"><strong>${zh ? '
|
|
58
|
-
return layout(zh ? '
|
|
57
|
+
: `<div class="empty-state"><strong>${zh ? '还没有可浏览的对话' : 'No conversations yet'}</strong><span>${zh ? '从受支持的 runtime 摄取任务轨迹后,会话会显示在这里。' : 'Sessions appear here after a supported runtime supplies task trajectories.'}</span></div>`;
|
|
58
|
+
return layout(zh ? '对话' : 'Conversations', `
|
|
59
59
|
<main class="conversation-page conversation-index-app" data-activity-revision="${e(activity.revision)}">
|
|
60
60
|
<header class="conversation-app-head">
|
|
61
61
|
<a class="conversation-app-brand" href="/${langQuery}">
|
|
@@ -67,7 +67,7 @@ export function renderConversationIndexPage(model, lang = DEFAULT_LANG) {
|
|
|
67
67
|
</nav>
|
|
68
68
|
</header>
|
|
69
69
|
<div class="conversation-app-body">
|
|
70
|
-
<section class="conversation-browser" aria-label="${zh ? '
|
|
70
|
+
<section class="conversation-browser" aria-label="${zh ? '对话' : 'Conversations'}">
|
|
71
71
|
<header class="conversation-toolbar">
|
|
72
72
|
<div class="conversation-browser-title">
|
|
73
73
|
<h1>${zh ? '对话' : 'Conversations'}</h1>
|
|
@@ -117,7 +117,7 @@ export function renderConversationDetailPage(conversation, lang = DEFAULT_LANG)
|
|
|
117
117
|
<header class="conversation-page-head conversation-detail-head">
|
|
118
118
|
<div>
|
|
119
119
|
<a class="back-link" href="/conversations${langSuffix}">${zh ? '返回对话总览' : 'Back to conversations'}</a>
|
|
120
|
-
<p class="conversation-eyebrow"
|
|
120
|
+
<p class="conversation-eyebrow">${e(sourceLabel(conversation))} · ${e(shortThreadId(conversation.sourceThreadId))}</p>
|
|
121
121
|
<h1>${renderSafeInlineMarkdown(conversation.title)}</h1>
|
|
122
122
|
<div class="detail-meta">
|
|
123
123
|
${conversation.model ? `<span>${e(conversation.model)}</span>` : ''}
|
|
@@ -157,8 +157,8 @@ function renderConversationRow(conversation, lang) {
|
|
|
157
157
|
? '<span class="index-pending">—</span>'
|
|
158
158
|
: `<span><b>${conversation.turnCount}</b>${zh ? '任务' : 'tasks'}</span>`;
|
|
159
159
|
const activity = openTask
|
|
160
|
-
? `<strong class="running-label"><i aria-hidden="true"></i>${zh ? '进行中' : 'Running'}</strong><span>${e(updated)} · ${e(conversation.model ??
|
|
161
|
-
: `<strong>${e(updated)}</strong><span>${e(conversation.model ??
|
|
160
|
+
? `<strong class="running-label"><i aria-hidden="true"></i>${zh ? '进行中' : 'Running'}</strong><span>${e(updated)} · ${e(conversation.model ?? sourceLabel(conversation))}</span>`
|
|
161
|
+
: `<strong>${e(updated)}</strong><span>${e(conversation.model ?? sourceLabel(conversation))}</span>`;
|
|
162
162
|
const liveTaskLink = openTaskHref
|
|
163
163
|
? `<a class="live-task-link" href="${e(openTaskHref)}" aria-label="${zh ? '查看进行中任务的实时轨迹' : 'View the live trajectory for the running task'}"><i aria-hidden="true"></i>${zh ? '查看实时轨迹' : 'View live'}</a>`
|
|
164
164
|
: '';
|
|
@@ -345,10 +345,24 @@ function compactPath(value) {
|
|
|
345
345
|
function shortThreadId(value) {
|
|
346
346
|
return value.length > 18 ? `${value.slice(0, 8)}…${value.slice(-6)}` : value;
|
|
347
347
|
}
|
|
348
|
+
function sourceLabel(conversation) {
|
|
349
|
+
if (conversation.sourceKind === 'dsh')
|
|
350
|
+
return 'DeepSeek Harness';
|
|
351
|
+
if (conversation.sourceKind === 'codex')
|
|
352
|
+
return 'Codex';
|
|
353
|
+
if (conversation.sourceKind === 'claude')
|
|
354
|
+
return 'Claude';
|
|
355
|
+
if (conversation.sourceKind === 'openclaw')
|
|
356
|
+
return 'OpenClaw';
|
|
357
|
+
if (conversation.sourceKind === 'markdown_log')
|
|
358
|
+
return 'Markdown';
|
|
359
|
+
return 'Runtime';
|
|
360
|
+
}
|
|
348
361
|
function statusLabel(status, lang) {
|
|
349
362
|
const zh = lang === 'zh';
|
|
350
363
|
const labels = {
|
|
351
364
|
completed: ['已完成', 'Completed'],
|
|
365
|
+
failed: ['已失败', 'Failed'],
|
|
352
366
|
aborted: ['已中止', 'Aborted'],
|
|
353
367
|
interrupted: ['已打断', 'Interrupted'],
|
|
354
368
|
open: ['进行中', 'Open'],
|
|
@@ -1101,6 +1101,7 @@ export function renderKnowledgeDebuggerPage(model, lang = DEFAULT_LANG, options
|
|
|
1101
1101
|
syncing: zh ? '同步中' : 'Syncing',
|
|
1102
1102
|
reconnecting: zh ? '重连中' : 'Reconnecting',
|
|
1103
1103
|
failed: zh ? '实时更新失败' : 'Live update failed',
|
|
1104
|
+
taskFailed: zh ? '任务已失败' : 'Task failed',
|
|
1104
1105
|
following: zh ? '跟随中' : 'Following',
|
|
1105
1106
|
resume: zh ? '跟随最新' : 'Follow latest',
|
|
1106
1107
|
pending: zh ? '查看更新' : 'View update',
|
|
@@ -1456,8 +1457,12 @@ function lifecycleEventLabel(label, lang) {
|
|
|
1456
1457
|
session_ended: { zh: '会话结束', en: 'Session ended' },
|
|
1457
1458
|
turn_started: { zh: '本轮开始', en: 'Turn started' },
|
|
1458
1459
|
turn_completed: { zh: '本轮完成', en: 'Turn completed' },
|
|
1460
|
+
turn_failed: { zh: '本轮失败', en: 'Turn failed' },
|
|
1459
1461
|
turn_aborted: { zh: '本轮中止', en: 'Turn aborted' },
|
|
1460
1462
|
turn_interrupted: { zh: '本轮被打断', en: 'Turn interrupted' },
|
|
1463
|
+
turn_ended_unknown: { zh: '本轮结束状态未知', en: 'Turn ended with unknown status' },
|
|
1464
|
+
step_started: { zh: '步骤开始', en: 'Step started' },
|
|
1465
|
+
step_completed: { zh: '步骤完成', en: 'Step completed' },
|
|
1461
1466
|
};
|
|
1462
1467
|
return labels[label ?? '']?.[lang] ?? (label || (lang === 'zh' ? '运行状态变化' : 'Lifecycle event'));
|
|
1463
1468
|
}
|
|
@@ -1466,7 +1471,7 @@ function lifecycleMilestoneTone(label) {
|
|
|
1466
1471
|
return 'start';
|
|
1467
1472
|
if (label === 'session_ended' || label === 'turn_completed')
|
|
1468
1473
|
return 'end';
|
|
1469
|
-
if (label === 'turn_aborted' || label === 'turn_interrupted')
|
|
1474
|
+
if (label === 'turn_failed' || label === 'turn_aborted' || label === 'turn_interrupted')
|
|
1470
1475
|
return 'warning';
|
|
1471
1476
|
return 'neutral';
|
|
1472
1477
|
}
|
|
@@ -188,8 +188,8 @@ export function renderObservationInboxPage(model, lang = DEFAULT_LANG) {
|
|
|
188
188
|
</div>`;
|
|
189
189
|
};
|
|
190
190
|
const renderSourceBadge = (item) => {
|
|
191
|
-
const label = item.sourceKind === 'openclaw' ? 'OpenClaw' : item.sourceKind === 'codex' ? 'Codex' : item.sourceKind === 'markdown_log' ? 'Markdown log' : item.sourceKind === 'claude' ? 'Claude' : 'Unknown';
|
|
192
|
-
const color = item.sourceKind === 'openclaw' ? '#7c3aed' : item.sourceKind === 'codex' ? '#1677ff' : item.sourceKind === 'markdown_log' ? 'var(--green)' : item.sourceKind === 'claude' ? 'var(--accent)' : 'var(--text-muted)';
|
|
191
|
+
const label = item.sourceKind === 'dsh' ? 'DeepSeek Harness' : item.sourceKind === 'openclaw' ? 'OpenClaw' : item.sourceKind === 'codex' ? 'Codex' : item.sourceKind === 'markdown_log' ? 'Markdown log' : item.sourceKind === 'claude' ? 'Claude' : 'Unknown';
|
|
192
|
+
const color = item.sourceKind === 'dsh' ? '#0f766e' : item.sourceKind === 'openclaw' ? '#7c3aed' : item.sourceKind === 'codex' ? '#1677ff' : item.sourceKind === 'markdown_log' ? 'var(--green)' : item.sourceKind === 'claude' ? 'var(--accent)' : 'var(--text-muted)';
|
|
193
193
|
return `<span title="调用日志来源:${e(label)}" style="display:inline-flex;margin-top:4px;padding:2px 6px;border-radius:999px;background:var(--bg-muted);color:${color};font-size:11px;font-weight:650">${e(label)}</span>`;
|
|
194
194
|
};
|
|
195
195
|
const confidenceHeaderHelp = '判断把握:OMK 对“这条 过程发现 是否需要处理/是否高风险/需关注”的规则判断有多确定。归属把握:OMK 把这条 过程发现 归到当前 skill 名下有多确定,例如明确调用 skill 通常更高。';
|
|
@@ -48,7 +48,9 @@ export function createTrajectoryLiveController(options) {
|
|
|
48
48
|
const state = terminalState ?? (!followLatest && pendingRevision
|
|
49
49
|
? 'pending'
|
|
50
50
|
: (followLatest ? 'following' : 'paused'));
|
|
51
|
-
const terminalLabel = terminalState
|
|
51
|
+
const terminalLabel = terminalState
|
|
52
|
+
? terminalState === 'failed' ? labels.taskFailed : labels[terminalState]
|
|
53
|
+
: undefined;
|
|
52
54
|
followButton.dataset.state = state;
|
|
53
55
|
followButton.dataset.following = String(followLatest);
|
|
54
56
|
followButton.setAttribute('aria-pressed', String(followLatest));
|
|
@@ -212,6 +214,7 @@ export function createTrajectoryLiveController(options) {
|
|
|
212
214
|
try {
|
|
213
215
|
const update = JSON.parse(event.data);
|
|
214
216
|
const explicitTerminal = update.status === 'completed'
|
|
217
|
+
|| update.status === 'failed'
|
|
215
218
|
|| update.status === 'aborted'
|
|
216
219
|
|| update.status === 'interrupted';
|
|
217
220
|
const streamTerminal = update.liveObservable === false || explicitTerminal;
|
|
@@ -226,7 +229,7 @@ export function createTrajectoryLiveController(options) {
|
|
|
226
229
|
if (!update.revision || update.revision === shell.dataset.liveRevision) {
|
|
227
230
|
const quiet = update.status === 'unknown';
|
|
228
231
|
const connectionLabel = terminalState
|
|
229
|
-
? labels[terminalState]
|
|
232
|
+
? terminalState === 'failed' ? labels.taskFailed : labels[terminalState]
|
|
230
233
|
: quiet ? labels.reconnecting : labels.live;
|
|
231
234
|
setConnectionState(terminalState ?? (quiet ? 'reconnecting' : 'live'), connectionLabel);
|
|
232
235
|
updateFollowControl();
|
|
@@ -381,7 +381,7 @@ export type DebugKnowledgeAccessKind = 'injected' | 'read' | 'returned';
|
|
|
381
381
|
export type TaskReplayStepKind = 'user_request' | 'user_message' | 'user_correction' | 'runtime_context' | 'skill_context' | 'tool_exchange' | 'unmatched_tool_result' | 'assistant_message' | 'model_activity' | 'lifecycle' | 'observation' | 'system_event';
|
|
382
382
|
export type TaskReplayIntegrityCode = 'task_boundary_unavailable' | 'timeline_truncated' | 'malformed_records' | 'ignored_values' | 'unknown_events' | 'unmatched_tool_calls' | 'unmatched_tool_results' | 'missing_timestamps';
|
|
383
383
|
export type TaskWindowBasis = 'turn_id' | 'turn_lifecycle' | 'user_message' | 'unresolved';
|
|
384
|
-
export type ExperienceTurnStatus = 'completed' | 'aborted' | 'interrupted' | 'open' | 'unknown';
|
|
384
|
+
export type ExperienceTurnStatus = 'completed' | 'failed' | 'aborted' | 'interrupted' | 'open' | 'unknown';
|
|
385
385
|
/**
|
|
386
386
|
* One user-visible task inside a source thread. `turnId` is the stable,
|
|
387
387
|
* source-neutral identity used by Studio routes. `sourceTurnId` preserves the
|
package/dist/types/trace.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Stable source identity shared by execution evidence and Trace IR. */
|
|
2
|
-
export type TraceSourceKind = 'claude' | 'codex' | 'openclaw' | 'markdown_log' | 'unknown';
|
|
2
|
+
export type TraceSourceKind = 'claude' | 'codex' | 'dsh' | 'openclaw' | 'markdown_log' | 'unknown';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-knowledge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"packageManager": "yarn@4.16.0",
|
|
5
5
|
"description": "OMK — Observe. Measure. Know. Evidence-backed knowledge changes for AI applications.",
|
|
6
6
|
"type": "module",
|
|
@@ -85,6 +85,10 @@
|
|
|
85
85
|
"release-evidence",
|
|
86
86
|
"llm-observability",
|
|
87
87
|
"prompt-engineering",
|
|
88
|
+
"deepseek-harness",
|
|
89
|
+
"dsh-plugin",
|
|
90
|
+
"dsh",
|
|
91
|
+
"cordis",
|
|
88
92
|
"codex",
|
|
89
93
|
"codex-cli",
|
|
90
94
|
"openai",
|