oh-my-knowledge 0.51.2 → 0.52.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 +27 -6
- package/README.zh.md +27 -6
- package/dist/assets/agent-skills/omk/SKILL.md +8 -8
- package/dist/observability/codex-conversation-index.d.ts +88 -0
- package/dist/observability/codex-conversation-index.js +566 -0
- package/dist/observability/codex-protocol.d.ts +12 -0
- package/dist/observability/codex-protocol.js +78 -0
- package/dist/observability/codex-tool-status.d.ts +16 -0
- package/dist/observability/codex-tool-status.js +114 -0
- package/dist/observability/codex-trace-adapter.js +342 -119
- package/dist/observability/conversation-catalog.d.ts +38 -0
- package/dist/observability/conversation-catalog.js +573 -0
- package/dist/observability/conversation-index-process.d.ts +1 -0
- package/dist/observability/conversation-index-process.js +31 -0
- package/dist/observability/conversation-view-model.d.ts +5 -0
- package/dist/observability/conversation-view-model.js +100 -0
- package/dist/observability/experience.d.ts +3 -1
- package/dist/observability/experience.js +248 -7
- package/dist/observability/inbox.js +40 -2
- package/dist/observability/knowledge-debugger.d.ts +4 -0
- package/dist/observability/knowledge-debugger.js +364 -0
- package/dist/observability/polling-subscription-hub.d.ts +27 -0
- package/dist/observability/polling-subscription-hub.js +149 -0
- package/dist/observability/source-record-archive.d.ts +13 -0
- package/dist/observability/source-record-archive.js +324 -0
- package/dist/observability/task-window.d.ts +8 -0
- package/dist/observability/task-window.js +36 -0
- package/dist/observability/trace-ir.d.ts +66 -1
- package/dist/observability/trace-source.d.ts +1 -0
- package/dist/observability/trace-source.js +12 -5
- package/dist/observability/turn-index.d.ts +3 -0
- package/dist/observability/turn-index.js +251 -0
- package/dist/renderer/conversation-renderer.d.ts +9 -0
- package/dist/renderer/conversation-renderer.js +410 -0
- package/dist/renderer/icons.js +1 -0
- package/dist/renderer/inline-markdown.d.ts +6 -0
- package/dist/renderer/inline-markdown.js +158 -0
- package/dist/renderer/knowledge-debugger-renderer.d.ts +9 -0
- package/dist/renderer/knowledge-debugger-renderer.js +2280 -0
- package/dist/renderer/observation-inbox-renderer.js +9 -0
- package/dist/renderer/skill-list-renderer.js +2 -1
- package/dist/renderer/trajectory-live.d.ts +42 -0
- package/dist/renderer/trajectory-live.js +258 -0
- package/dist/renderer/trajectory-routing.d.ts +60 -0
- package/dist/renderer/trajectory-routing.js +351 -0
- package/dist/server/report-server.d.ts +4 -1
- package/dist/server/report-server.js +274 -6
- package/dist/types/observability.d.ts +225 -1
- package/package.json +8 -5
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { loadLatestObservationInboxReports } from './inbox.js';
|
|
2
|
+
import { durationMsBetween } from '../shared/time.js';
|
|
3
|
+
export function buildConversationIndexViewModel(observationsDir) {
|
|
4
|
+
const groups = new Map();
|
|
5
|
+
const reports = loadLatestObservationInboxReports(observationsDir);
|
|
6
|
+
for (const report of reports) {
|
|
7
|
+
for (const session of report.experience?.sessions ?? []) {
|
|
8
|
+
const group = groups.get(session.threadId) ?? {
|
|
9
|
+
threadId: session.threadId,
|
|
10
|
+
sourceThreadId: session.sourceThreadId,
|
|
11
|
+
sourceKind: session.sourceKind,
|
|
12
|
+
sessions: [],
|
|
13
|
+
tasks: new Map(),
|
|
14
|
+
relatedSkills: new Set(),
|
|
15
|
+
};
|
|
16
|
+
group.sessions.push(session);
|
|
17
|
+
group.relatedSkills.add(session.skillName);
|
|
18
|
+
const attributedIds = new Set(session.attributedEventIds);
|
|
19
|
+
for (const turn of session.turns) {
|
|
20
|
+
const related = turn.eventIds.some((id) => attributedIds.has(id));
|
|
21
|
+
const existing = group.tasks.get(turn.turnId);
|
|
22
|
+
if (!existing || turn.eventIds.length > existing.turn.eventIds.length) {
|
|
23
|
+
group.tasks.set(turn.turnId, {
|
|
24
|
+
turn,
|
|
25
|
+
experienceSessionId: session.id,
|
|
26
|
+
relatedSkills: new Set(existing?.relatedSkills ?? []),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (related) {
|
|
30
|
+
const task = group.tasks.get(turn.turnId);
|
|
31
|
+
task?.relatedSkills.add(session.skillName);
|
|
32
|
+
if (task && task.experienceSessionId !== session.id) {
|
|
33
|
+
task.experienceSessionId = session.id;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
groups.set(session.threadId, group);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const conversations = Array.from(groups.values())
|
|
41
|
+
.map(finalizeConversation)
|
|
42
|
+
.filter((conversation) => conversation.tasks.length > 0)
|
|
43
|
+
.sort((left, right) => ((right.endTimestamp ?? '').localeCompare(left.endTimestamp ?? '')
|
|
44
|
+
|| left.threadId.localeCompare(right.threadId)));
|
|
45
|
+
return {
|
|
46
|
+
conversations,
|
|
47
|
+
totalTurnCount: conversations.reduce((sum, item) => sum + (item.turnCount ?? 0), 0),
|
|
48
|
+
totalToolCallCount: conversations.reduce((sum, item) => sum + (item.toolCallCount ?? 0), 0),
|
|
49
|
+
totalToolFailureCount: conversations.reduce((sum, item) => sum + (item.toolFailureCount ?? 0), 0),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Test/compatibility adapter for persisted observe reports. */
|
|
53
|
+
export function createObservationConversationCatalog(observationsDir) {
|
|
54
|
+
return {
|
|
55
|
+
async listConversations() {
|
|
56
|
+
return buildConversationIndexViewModel(observationsDir);
|
|
57
|
+
},
|
|
58
|
+
async getConversation(threadId) {
|
|
59
|
+
return buildConversationIndexViewModel(observationsDir).conversations.find((item) => item.threadId === threadId);
|
|
60
|
+
},
|
|
61
|
+
async loadTaskTrajectory() {
|
|
62
|
+
return undefined;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function finalizeConversation(group) {
|
|
67
|
+
const tasks = Array.from(group.tasks.values())
|
|
68
|
+
.map(({ turn, experienceSessionId, relatedSkills }) => ({
|
|
69
|
+
turnId: turn.turnId,
|
|
70
|
+
sourceTurnId: turn.sourceTurnId,
|
|
71
|
+
experienceSessionId,
|
|
72
|
+
title: turn.title,
|
|
73
|
+
startTimestamp: turn.startTimestamp,
|
|
74
|
+
endTimestamp: turn.endTimestamp,
|
|
75
|
+
durationMs: durationMsBetween(turn.startTimestamp, turn.endTimestamp),
|
|
76
|
+
status: turn.status,
|
|
77
|
+
eventCount: turn.eventIds.length,
|
|
78
|
+
toolCallCount: turn.toolCallCount,
|
|
79
|
+
toolFailureCount: turn.toolFailureCount,
|
|
80
|
+
relatedSkillNames: Array.from(relatedSkills).sort(),
|
|
81
|
+
}))
|
|
82
|
+
.sort((left, right) => ((left.startTimestamp ?? '').localeCompare(right.startTimestamp ?? '')
|
|
83
|
+
|| left.turnId.localeCompare(right.turnId)));
|
|
84
|
+
const firstTask = tasks[0];
|
|
85
|
+
const lastTask = tasks.at(-1);
|
|
86
|
+
return {
|
|
87
|
+
threadId: group.threadId,
|
|
88
|
+
sourceThreadId: group.sourceThreadId,
|
|
89
|
+
sourceKind: group.sourceKind,
|
|
90
|
+
title: firstTask?.title ?? '未命名对话',
|
|
91
|
+
startTimestamp: firstTask?.startTimestamp,
|
|
92
|
+
endTimestamp: lastTask?.endTimestamp ?? lastTask?.startTimestamp,
|
|
93
|
+
durationMs: durationMsBetween(firstTask?.startTimestamp, lastTask?.endTimestamp ?? lastTask?.startTimestamp),
|
|
94
|
+
turnCount: tasks.length,
|
|
95
|
+
toolCallCount: tasks.reduce((sum, task) => sum + task.toolCallCount, 0),
|
|
96
|
+
toolFailureCount: tasks.reduce((sum, task) => sum + task.toolFailureCount, 0),
|
|
97
|
+
relatedSkillNames: Array.from(group.relatedSkills).sort(),
|
|
98
|
+
tasks,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -15,7 +15,7 @@ export type PersistedExperienceSessionStory = Omit<ExperienceSessionStory, 'cont
|
|
|
15
15
|
export type PersistedExperienceReviewerReport = Omit<ExperienceReviewerReport, 'sessionStory' | 'sessionStoryRef'> & {
|
|
16
16
|
sessionStoryRef: 'session';
|
|
17
17
|
};
|
|
18
|
-
export type PersistedExperienceSession = Omit<ExperienceSessionSummary, 'timelineRef' | 'timelinePreviewEventIds' | 'timelinePreview' | 'fullSessionTimeline' | 'timelineTree' | 'sessionStory' | 'reviewerReport'> & {
|
|
18
|
+
export type PersistedExperienceSession = Omit<ExperienceSessionSummary, 'timelineRef' | 'timelinePreviewEventIds' | 'attributedEventIds' | 'timelinePreview' | 'fullSessionTimeline' | 'timelineTree' | 'sessionStory' | 'reviewerReport'> & {
|
|
19
19
|
timelineRef: string;
|
|
20
20
|
timelinePreviewEventIds: string[];
|
|
21
21
|
sessionStory?: PersistedExperienceSessionStory;
|
|
@@ -41,6 +41,8 @@ export declare function normalizeObservationExperienceReport(value: unknown): Ob
|
|
|
41
41
|
* invocation/session views through normalizeObservationExperienceReport().
|
|
42
42
|
*/
|
|
43
43
|
export declare function compactObservationExperienceReport(report: ObservationExperienceReport): PersistedObservationExperienceReport;
|
|
44
|
+
/** Project one source-neutral Trace IR session into Studio's semantic timeline. */
|
|
45
|
+
export declare function projectTraceSessionTimeline(session: TraceSession): ExperienceTimelineEvent[];
|
|
44
46
|
export declare function isExperienceTraceInProgress(session: ExperienceSessionSummary): boolean;
|
|
45
47
|
export declare function hasRecognizableUserGoalText(value: string | undefined): boolean;
|
|
46
48
|
export declare function foldExperienceChecklistItems(items: ExperienceChecklistItem[]): {
|
|
@@ -6,6 +6,7 @@ import { observationMetricAnnotationVerdict, observationReviewStateKey } from '.
|
|
|
6
6
|
import { correlateTraceToolEvents, normalizeTraceTimestamp, } from './trace-ir.js';
|
|
7
7
|
import { skillSegmentTimestampObserved, UNOBSERVED_TRACE_TIMESTAMP, } from './trace-segmenter.js';
|
|
8
8
|
import { createTraceSessionIndex, traceSessionRefIdentity } from './trace-session-index.js';
|
|
9
|
+
import { reconstructExperienceTurns } from './turn-index.js';
|
|
9
10
|
import { extractCommandEnvelopeText, stripCommandEnvelopeText } from './trace-attribution.js';
|
|
10
11
|
import { hasAssistantDeliverableArtifactText, hasAssistantDeliverySignalText, hasUserHardRuleText, isAssistantProgressUpdateText, isAssistantProtocolReplyText, isSyntheticUserMessageText, isToolResultFailureText, isUserInteractionMetricText } from './text-signals.js';
|
|
11
12
|
import { durationMsBetween } from '../shared/time.js';
|
|
@@ -290,6 +291,8 @@ function normalizeExperienceSessionShells(values, strict) {
|
|
|
290
291
|
return null;
|
|
291
292
|
if (records.some((value) => typeof value.id !== 'string'
|
|
292
293
|
|| typeof value.skillName !== 'string'
|
|
294
|
+
|| !isOptionalString(value.threadId)
|
|
295
|
+
|| !isOptionalString(value.sourceThreadId)
|
|
293
296
|
|| typeof value.sessionId !== 'string'
|
|
294
297
|
|| typeof value.sourceTrace !== 'string'
|
|
295
298
|
|| !isObservationSourceKind(value.sourceKind)
|
|
@@ -326,6 +329,7 @@ function normalizeExperienceSessionShells(values, strict) {
|
|
|
326
329
|
|| !isExperienceAssistiveInference(value.assistiveInference)
|
|
327
330
|
|| !isExperienceProblemPatternArray(value.problemPatterns)
|
|
328
331
|
|| !isStringArray(value.relatedObservationIds)
|
|
332
|
+
|| (value.turns !== undefined && !isExperienceTurnSummaryArray(value.turns))
|
|
329
333
|
|| !(strict
|
|
330
334
|
? isExperienceTimelineScope(value.timelineScope)
|
|
331
335
|
: isLegacyExperienceTimelineScope(value.timelineScope))
|
|
@@ -350,6 +354,14 @@ function normalizeExperienceSessionShells(values, strict) {
|
|
|
350
354
|
&& !isExperienceReviewerReport(value.reviewerReport, strict))))
|
|
351
355
|
return null;
|
|
352
356
|
return records.map((value) => {
|
|
357
|
+
const sourceThreadId = typeof value.sourceThreadId === 'string'
|
|
358
|
+
? value.sourceThreadId
|
|
359
|
+
: typeof value.threadId === 'string'
|
|
360
|
+
? value.threadId
|
|
361
|
+
: value.sessionId;
|
|
362
|
+
const threadId = typeof value.threadId === 'string'
|
|
363
|
+
? value.threadId
|
|
364
|
+
: hashParts('thread', sourceThreadId);
|
|
353
365
|
const sessionStory = isObjectRecord(value.sessionStory)
|
|
354
366
|
? {
|
|
355
367
|
...value.sessionStory,
|
|
@@ -362,7 +374,10 @@ function normalizeExperienceSessionShells(values, strict) {
|
|
|
362
374
|
: undefined;
|
|
363
375
|
return {
|
|
364
376
|
...value,
|
|
377
|
+
threadId,
|
|
378
|
+
sourceThreadId,
|
|
365
379
|
invocationIds: Array.isArray(value.invocationIds) ? value.invocationIds : [],
|
|
380
|
+
turns: isExperienceTurnSummaryArray(value.turns) ? value.turns : [],
|
|
366
381
|
timelinePreview: Array.isArray(value.timelinePreview) ? value.timelinePreview : [],
|
|
367
382
|
fullSessionTimeline: Array.isArray(value.fullSessionTimeline) ? value.fullSessionTimeline : [],
|
|
368
383
|
sessionStory,
|
|
@@ -491,10 +506,13 @@ function isExperienceEvidenceKind(value) {
|
|
|
491
506
|
'user_message',
|
|
492
507
|
'synthetic_user_event',
|
|
493
508
|
'assistant_message',
|
|
509
|
+
'model_activity',
|
|
510
|
+
'agent_activity',
|
|
494
511
|
'tool_use',
|
|
495
512
|
'tool_result',
|
|
496
513
|
'skill_context',
|
|
497
514
|
'runtime_context',
|
|
515
|
+
'lifecycle',
|
|
498
516
|
'observation',
|
|
499
517
|
]);
|
|
500
518
|
}
|
|
@@ -511,13 +529,26 @@ function isExperienceEvidenceRef(value) {
|
|
|
511
529
|
if (value.traceRole !== undefined
|
|
512
530
|
&& !isEnumValue(value.traceRole, ['standalone', 'main', 'subagent']))
|
|
513
531
|
return false;
|
|
532
|
+
if (value.modelActivityKind !== undefined && value.modelActivityKind !== 'reasoning')
|
|
533
|
+
return false;
|
|
534
|
+
if (value.contentVisibility !== undefined
|
|
535
|
+
&& !isEnumValue(value.contentVisibility, ['plaintext', 'opaque']))
|
|
536
|
+
return false;
|
|
537
|
+
if (value.contentSource !== undefined
|
|
538
|
+
&& !isEnumValue(value.contentSource, ['summary', 'content', 'text']))
|
|
539
|
+
return false;
|
|
540
|
+
if (value.runtimeKind !== undefined
|
|
541
|
+
&& !isEnumValue(value.runtimeKind, ['session_context', 'execution_context', 'settings', 'goal', 'context_compaction', 'usage']))
|
|
542
|
+
return false;
|
|
514
543
|
if (value.role !== undefined
|
|
515
544
|
&& !isEnumValue(value.role, ['user', 'assistant', 'tool', 'other']))
|
|
516
545
|
return false;
|
|
517
546
|
return [
|
|
518
547
|
value.traceLabel,
|
|
519
548
|
value.traceId,
|
|
549
|
+
value.turnId,
|
|
520
550
|
value.messageUuid,
|
|
551
|
+
value.sourceType,
|
|
521
552
|
value.callInstanceId,
|
|
522
553
|
value.toolUseId,
|
|
523
554
|
value.label,
|
|
@@ -880,10 +911,13 @@ function isTimelineEvent(value) {
|
|
|
880
911
|
'user_message',
|
|
881
912
|
'synthetic_user_event',
|
|
882
913
|
'assistant_message',
|
|
914
|
+
'model_activity',
|
|
915
|
+
'agent_activity',
|
|
883
916
|
'tool_use',
|
|
884
917
|
'tool_result',
|
|
885
918
|
'skill_context',
|
|
886
919
|
'runtime_context',
|
|
920
|
+
'lifecycle',
|
|
887
921
|
'observation',
|
|
888
922
|
].includes(String(value.kind))
|
|
889
923
|
|| typeof value.sourceTrace !== 'string'
|
|
@@ -914,10 +948,32 @@ function isTimelineEvent(value) {
|
|
|
914
948
|
&& value.toolStatus !== 'cancelled'
|
|
915
949
|
&& value.toolStatus !== 'unknown')
|
|
916
950
|
return false;
|
|
951
|
+
if (value.modelActivityKind !== undefined && value.modelActivityKind !== 'reasoning')
|
|
952
|
+
return false;
|
|
953
|
+
if (value.contentVisibility !== undefined
|
|
954
|
+
&& value.contentVisibility !== 'plaintext'
|
|
955
|
+
&& value.contentVisibility !== 'opaque')
|
|
956
|
+
return false;
|
|
957
|
+
if (value.contentSource !== undefined
|
|
958
|
+
&& value.contentSource !== 'summary'
|
|
959
|
+
&& value.contentSource !== 'content'
|
|
960
|
+
&& value.contentSource !== 'text')
|
|
961
|
+
return false;
|
|
962
|
+
if (value.runtimeKind !== undefined
|
|
963
|
+
&& value.runtimeKind !== 'session_context'
|
|
964
|
+
&& value.runtimeKind !== 'execution_context'
|
|
965
|
+
&& value.runtimeKind !== 'settings'
|
|
966
|
+
&& value.runtimeKind !== 'goal'
|
|
967
|
+
&& value.runtimeKind !== 'context_compaction'
|
|
968
|
+
&& value.runtimeKind !== 'usage')
|
|
969
|
+
return false;
|
|
917
970
|
const optionalStrings = [
|
|
918
971
|
value.traceId,
|
|
919
972
|
value.traceLabel,
|
|
973
|
+
value.turnId,
|
|
920
974
|
value.messageUuid,
|
|
975
|
+
value.sourceType,
|
|
976
|
+
value.model,
|
|
921
977
|
value.callInstanceId,
|
|
922
978
|
value.toolUseId,
|
|
923
979
|
value.label,
|
|
@@ -937,6 +993,29 @@ function isTimelineEvent(value) {
|
|
|
937
993
|
function isTimelineEventArray(value) {
|
|
938
994
|
return Array.isArray(value) && value.every(isTimelineEvent);
|
|
939
995
|
}
|
|
996
|
+
function isExperienceTurnSummaryArray(value) {
|
|
997
|
+
return Array.isArray(value) && value.every((turn) => (isObjectRecord(turn)
|
|
998
|
+
&& typeof turn.turnId === 'string'
|
|
999
|
+
&& isOptionalString(turn.sourceTurnId)
|
|
1000
|
+
&& (turn.boundaryBasis === 'turn_id'
|
|
1001
|
+
|| turn.boundaryBasis === 'turn_lifecycle'
|
|
1002
|
+
|| turn.boundaryBasis === 'user_message')
|
|
1003
|
+
&& isOptionalString(turn.traceId)
|
|
1004
|
+
&& typeof turn.sourceTrace === 'string'
|
|
1005
|
+
&& isOptionalTimestamp(turn.startTimestamp)
|
|
1006
|
+
&& isOptionalTimestamp(turn.endTimestamp)
|
|
1007
|
+
&& (turn.status === 'completed'
|
|
1008
|
+
|| turn.status === 'aborted'
|
|
1009
|
+
|| turn.status === 'interrupted'
|
|
1010
|
+
|| turn.status === 'open'
|
|
1011
|
+
|| turn.status === 'unknown')
|
|
1012
|
+
&& typeof turn.title === 'string'
|
|
1013
|
+
&& isStringArray(turn.eventIds)
|
|
1014
|
+
&& isNonNegativeInteger(turn.userMessageCount)
|
|
1015
|
+
&& isNonNegativeInteger(turn.assistantMessageCount)
|
|
1016
|
+
&& isNonNegativeInteger(turn.toolCallCount)
|
|
1017
|
+
&& isNonNegativeInteger(turn.toolFailureCount)));
|
|
1018
|
+
}
|
|
940
1019
|
function isTimelineTree(value) {
|
|
941
1020
|
if (!isObjectRecord(value)
|
|
942
1021
|
|| typeof value.sessionId !== 'string'
|
|
@@ -1455,6 +1534,7 @@ export function compactObservationExperienceReport(report) {
|
|
|
1455
1534
|
sessions: hydrated.sessions.map((session) => {
|
|
1456
1535
|
const { timelinePreview, sessionStory, reviewerReport } = session;
|
|
1457
1536
|
const persisted = omitProperties(session, [
|
|
1537
|
+
'attributedEventIds',
|
|
1458
1538
|
'timelinePreview',
|
|
1459
1539
|
'fullSessionTimeline',
|
|
1460
1540
|
'timelineTree',
|
|
@@ -1533,11 +1613,18 @@ function hydrateExperienceTimelines(report) {
|
|
|
1533
1613
|
const fullSessionTimeline = storedTimeline
|
|
1534
1614
|
? flattenedTimeline(timelineRef)
|
|
1535
1615
|
: session.fullSessionTimeline;
|
|
1616
|
+
const turns = session.turns.length > 0
|
|
1617
|
+
? session.turns
|
|
1618
|
+
: reconstructExperienceTurns(fullSessionTimeline);
|
|
1536
1619
|
const timelinePreviewEventIds = session.timelinePreviewEventIds
|
|
1537
1620
|
?? session.timelinePreview.map((event) => event.id);
|
|
1538
1621
|
const timelinePreview = timelinePreviewEventIds.length > 0
|
|
1539
1622
|
? selectEvents(timelineRef, timelinePreviewEventIds, session.timelinePreview)
|
|
1540
1623
|
: fullSessionTimeline.slice(0, TIMELINE_PREVIEW_EVENT_LIMIT);
|
|
1624
|
+
const attributedEventIds = unique(session.invocationIds.flatMap((id) => {
|
|
1625
|
+
const invocation = invocationById.get(id);
|
|
1626
|
+
return invocation?.timelineEventIds ?? invocation?.timeline.map((event) => event.id) ?? [];
|
|
1627
|
+
}));
|
|
1541
1628
|
const contextRef = session.sessionStory?.contextRef
|
|
1542
1629
|
?? storyContextRefForSessionGroup(firstInvocation?.sessionGroupKey ?? session.sessionId);
|
|
1543
1630
|
const storyContext = storyContextById.get(contextRef);
|
|
@@ -1554,9 +1641,11 @@ function hydrateExperienceTimelines(report) {
|
|
|
1554
1641
|
return {
|
|
1555
1642
|
...session,
|
|
1556
1643
|
timelineRef,
|
|
1644
|
+
attributedEventIds,
|
|
1557
1645
|
timelinePreviewEventIds: timelinePreview.map((event) => event.id),
|
|
1558
1646
|
timelinePreview,
|
|
1559
1647
|
fullSessionTimeline,
|
|
1648
|
+
turns,
|
|
1560
1649
|
timelineTree: storedTimeline?.tree ?? session.timelineTree,
|
|
1561
1650
|
sessionStory,
|
|
1562
1651
|
reviewerReport: session.reviewerReport && sessionStory
|
|
@@ -1962,7 +2051,8 @@ function timelineScopeMatches(session, invocations, timeline) {
|
|
|
1962
2051
|
? events.length - 1 - Math.max(...previewPositions)
|
|
1963
2052
|
: 0;
|
|
1964
2053
|
const scope = session.timelineScope;
|
|
1965
|
-
return
|
|
2054
|
+
return sameStringSet(session.attributedEventIds, invocationEventIds)
|
|
2055
|
+
&& scope.segmentEventCount === invocationEventIds.size
|
|
1966
2056
|
&& scope.previewEventCount === previewEventIds.length
|
|
1967
2057
|
&& scope.fullSessionEventCount === events.length
|
|
1968
2058
|
&& traceRecordRangesEqual(scope.segmentRecordRanges, traceRecordRanges(invocationEvents))
|
|
@@ -2138,6 +2228,11 @@ function countRecordsEqual(left, right) {
|
|
|
2138
2228
|
function sameStringArray(left, right) {
|
|
2139
2229
|
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
2140
2230
|
}
|
|
2231
|
+
function sameStringSet(left, right) {
|
|
2232
|
+
return left.length === right.size
|
|
2233
|
+
&& new Set(left).size === left.length
|
|
2234
|
+
&& left.every((value) => right.has(value));
|
|
2235
|
+
}
|
|
2141
2236
|
function storyContextsFromSessions(sessions, invocations) {
|
|
2142
2237
|
const invocationById = new Map(invocations.map((invocation) => [invocation.id, invocation]));
|
|
2143
2238
|
const contexts = new Map();
|
|
@@ -2386,6 +2481,10 @@ function buildTimelineWindow(session, start, end) {
|
|
|
2386
2481
|
}
|
|
2387
2482
|
return events.sort((a, b) => a.order - b.order);
|
|
2388
2483
|
}
|
|
2484
|
+
/** Project one source-neutral Trace IR session into Studio's semantic timeline. */
|
|
2485
|
+
export function projectTraceSessionTimeline(session) {
|
|
2486
|
+
return buildTimelineWindow(session, 0, session.events.length);
|
|
2487
|
+
}
|
|
2389
2488
|
function timelineEventsFromTraceEvent(session, event, eventIndex) {
|
|
2390
2489
|
const messageIndex = event.sourceIndex;
|
|
2391
2490
|
const base = {
|
|
@@ -2398,6 +2497,8 @@ function timelineEventsFromTraceEvent(session, event, eventIndex) {
|
|
|
2398
2497
|
logicalMessageIndex: messageIndex,
|
|
2399
2498
|
sourceLineIndex: messageIndex,
|
|
2400
2499
|
messageUuid: event.sourceEventId ?? event.eventId,
|
|
2500
|
+
sourceType: event.sourceType,
|
|
2501
|
+
turnId: event.turnId,
|
|
2401
2502
|
timestamp: event.timestamp,
|
|
2402
2503
|
};
|
|
2403
2504
|
const order = eventIndex * 10;
|
|
@@ -2422,11 +2523,27 @@ function timelineEventsFromTraceEvent(session, event, eventIndex) {
|
|
|
2422
2523
|
kind: protocolReply ? 'runtime_context' : 'assistant_message',
|
|
2423
2524
|
role: 'assistant',
|
|
2424
2525
|
order,
|
|
2526
|
+
model: event.model,
|
|
2425
2527
|
snippet: snippet(event.text, 700),
|
|
2426
2528
|
fullText: fullText(event.text),
|
|
2427
2529
|
label: protocolReply ? 'assistant protocol reply' : 'assistant message',
|
|
2428
2530
|
})];
|
|
2429
2531
|
}
|
|
2532
|
+
if (event.eventKind === 'model_activity') {
|
|
2533
|
+
return [timelineEvent({
|
|
2534
|
+
...base,
|
|
2535
|
+
kind: 'model_activity',
|
|
2536
|
+
role: 'assistant',
|
|
2537
|
+
order,
|
|
2538
|
+
model: event.model,
|
|
2539
|
+
modelActivityKind: event.activityKind,
|
|
2540
|
+
contentVisibility: event.contentVisibility,
|
|
2541
|
+
contentSource: event.contentSource,
|
|
2542
|
+
snippet: snippet(event.text, 700),
|
|
2543
|
+
fullText: fullText(event.text),
|
|
2544
|
+
label: 'model reasoning',
|
|
2545
|
+
})];
|
|
2546
|
+
}
|
|
2430
2547
|
if (event.eventKind === 'tool_call') {
|
|
2431
2548
|
const inputText = JSON.stringify(event.input);
|
|
2432
2549
|
return [timelineEvent({
|
|
@@ -2464,7 +2581,7 @@ function timelineEventsFromTraceEvent(session, event, eventIndex) {
|
|
|
2464
2581
|
if (event.eventKind === 'lifecycle') {
|
|
2465
2582
|
return [timelineEvent({
|
|
2466
2583
|
...base,
|
|
2467
|
-
kind: '
|
|
2584
|
+
kind: 'lifecycle',
|
|
2468
2585
|
role: 'other',
|
|
2469
2586
|
order,
|
|
2470
2587
|
snippet: snippet(`${event.phase}${event.reason ? `: ${event.reason}` : ''}`, 700),
|
|
@@ -2472,6 +2589,111 @@ function timelineEventsFromTraceEvent(session, event, eventIndex) {
|
|
|
2472
2589
|
label: event.phase,
|
|
2473
2590
|
})];
|
|
2474
2591
|
}
|
|
2592
|
+
if (event.eventKind === 'runtime_context') {
|
|
2593
|
+
const details = JSON.stringify({
|
|
2594
|
+
runtimeName: event.runtimeName,
|
|
2595
|
+
runtimeVersion: event.runtimeVersion,
|
|
2596
|
+
cwd: event.cwd,
|
|
2597
|
+
workspaceRoots: event.workspaceRoots,
|
|
2598
|
+
currentDate: event.currentDate,
|
|
2599
|
+
timezone: event.timezone,
|
|
2600
|
+
model: event.model,
|
|
2601
|
+
modelProvider: event.modelProvider,
|
|
2602
|
+
serviceTier: event.serviceTier,
|
|
2603
|
+
reasoningEffort: event.reasoningEffort,
|
|
2604
|
+
reasoningSummary: event.reasoningSummary,
|
|
2605
|
+
personality: event.personality,
|
|
2606
|
+
approvalPolicy: event.approvalPolicy,
|
|
2607
|
+
approvalReviewer: event.approvalReviewer,
|
|
2608
|
+
permissionProfile: event.permissionProfile,
|
|
2609
|
+
sandboxMode: event.sandboxMode,
|
|
2610
|
+
collaborationMode: event.collaborationMode,
|
|
2611
|
+
realtimeActive: event.realtimeActive,
|
|
2612
|
+
multiAgentMode: event.multiAgentMode,
|
|
2613
|
+
multiAgentVersion: event.multiAgentVersion,
|
|
2614
|
+
memoryMode: event.memoryMode,
|
|
2615
|
+
historyMode: event.historyMode,
|
|
2616
|
+
contextWindowId: event.contextWindowId,
|
|
2617
|
+
availableTools: event.availableTools,
|
|
2618
|
+
instructions: event.instructions,
|
|
2619
|
+
goal: event.goal,
|
|
2620
|
+
goalStatus: event.goalStatus,
|
|
2621
|
+
summary: event.summary,
|
|
2622
|
+
});
|
|
2623
|
+
const visible = event.summary
|
|
2624
|
+
?? event.goal
|
|
2625
|
+
?? event.instructions
|
|
2626
|
+
?? [event.runtimeName, event.runtimeVersion, event.cwd, event.model, event.reasoningEffort, event.collaborationMode]
|
|
2627
|
+
.filter(Boolean)
|
|
2628
|
+
.join(' · ');
|
|
2629
|
+
return [timelineEvent({
|
|
2630
|
+
...base,
|
|
2631
|
+
kind: 'runtime_context',
|
|
2632
|
+
role: 'other',
|
|
2633
|
+
order,
|
|
2634
|
+
model: event.model,
|
|
2635
|
+
runtimeKind: event.runtimeKind,
|
|
2636
|
+
snippet: snippet(visible, 700),
|
|
2637
|
+
fullText: fullText(details),
|
|
2638
|
+
label: event.runtimeKind,
|
|
2639
|
+
})];
|
|
2640
|
+
}
|
|
2641
|
+
if (event.eventKind === 'context_compaction') {
|
|
2642
|
+
return [timelineEvent({
|
|
2643
|
+
...base,
|
|
2644
|
+
kind: 'runtime_context',
|
|
2645
|
+
role: 'other',
|
|
2646
|
+
order,
|
|
2647
|
+
runtimeKind: 'context_compaction',
|
|
2648
|
+
snippet: snippet(event.summary ?? 'context compacted', 700),
|
|
2649
|
+
fullText: fullText(JSON.stringify(event)),
|
|
2650
|
+
label: 'context compacted',
|
|
2651
|
+
})];
|
|
2652
|
+
}
|
|
2653
|
+
if (event.eventKind === 'agent_activity') {
|
|
2654
|
+
const visible = event.text
|
|
2655
|
+
?? [event.activity, event.author, event.recipient, event.agentPath, event.agentId]
|
|
2656
|
+
.filter(Boolean)
|
|
2657
|
+
.join(' · ');
|
|
2658
|
+
return [timelineEvent({
|
|
2659
|
+
...base,
|
|
2660
|
+
kind: 'agent_activity',
|
|
2661
|
+
role: 'other',
|
|
2662
|
+
order,
|
|
2663
|
+
snippet: snippet(visible, 700),
|
|
2664
|
+
fullText: fullText(JSON.stringify({
|
|
2665
|
+
activityKind: event.activityKind,
|
|
2666
|
+
activity: event.activity,
|
|
2667
|
+
author: event.author,
|
|
2668
|
+
recipient: event.recipient,
|
|
2669
|
+
agentId: event.agentId,
|
|
2670
|
+
agentPath: event.agentPath,
|
|
2671
|
+
text: event.text,
|
|
2672
|
+
})),
|
|
2673
|
+
label: event.activityKind === 'communication' ? 'agent communication' : 'agent status',
|
|
2674
|
+
})];
|
|
2675
|
+
}
|
|
2676
|
+
if (event.eventKind === 'usage') {
|
|
2677
|
+
const usageText = JSON.stringify({
|
|
2678
|
+
model: event.model,
|
|
2679
|
+
inputTokens: event.inputTokens,
|
|
2680
|
+
outputTokens: event.outputTokens,
|
|
2681
|
+
cacheReadTokens: event.cacheReadTokens,
|
|
2682
|
+
cacheCreationTokens: event.cacheCreationTokens,
|
|
2683
|
+
reasoningTokens: event.reasoningTokens,
|
|
2684
|
+
});
|
|
2685
|
+
return [timelineEvent({
|
|
2686
|
+
...base,
|
|
2687
|
+
kind: 'runtime_context',
|
|
2688
|
+
role: 'other',
|
|
2689
|
+
order,
|
|
2690
|
+
model: event.model,
|
|
2691
|
+
runtimeKind: 'usage',
|
|
2692
|
+
snippet: snippet(usageText, 700),
|
|
2693
|
+
fullText: fullText(usageText),
|
|
2694
|
+
label: 'token usage',
|
|
2695
|
+
})];
|
|
2696
|
+
}
|
|
2475
2697
|
if (event.eventKind === 'unknown') {
|
|
2476
2698
|
const rawText = safeRecordText(event.raw);
|
|
2477
2699
|
if (!hasAssistantTurnFailedText(rawText))
|
|
@@ -2503,7 +2725,12 @@ function userTimelineEvents(event, base, order) {
|
|
|
2503
2725
|
}));
|
|
2504
2726
|
}
|
|
2505
2727
|
const text = commandEnvelope ? stripCommandEnvelopeText(event.text) : event.text;
|
|
2506
|
-
|
|
2728
|
+
const displayedSourceText = event.displayText?.trim() || event.text;
|
|
2729
|
+
const displayText = commandEnvelope
|
|
2730
|
+
? stripCommandEnvelopeText(displayedSourceText)
|
|
2731
|
+
: displayedSourceText;
|
|
2732
|
+
const semanticText = event.origin === 'human' ? displayText : text;
|
|
2733
|
+
if (!semanticText.trim())
|
|
2507
2734
|
return events;
|
|
2508
2735
|
const kind = event.origin === 'human'
|
|
2509
2736
|
? 'user_message'
|
|
@@ -2517,8 +2744,8 @@ function userTimelineEvents(event, base, order) {
|
|
|
2517
2744
|
kind,
|
|
2518
2745
|
role: kind === 'user_message' ? 'user' : kind === 'synthetic_user_event' ? 'other' : 'tool',
|
|
2519
2746
|
order: order + (commandEnvelope ? 1 : 0),
|
|
2520
|
-
snippet: snippet(
|
|
2521
|
-
fullText: fullText(
|
|
2747
|
+
snippet: snippet(semanticText, 700),
|
|
2748
|
+
fullText: fullText(semanticText),
|
|
2522
2749
|
label: userTextEventLabel(kind),
|
|
2523
2750
|
}));
|
|
2524
2751
|
return events;
|
|
@@ -2585,6 +2812,11 @@ function evidenceRefFromTimeline(event) {
|
|
|
2585
2812
|
toolUseId: event.toolUseId,
|
|
2586
2813
|
timestamp: event.timestamp,
|
|
2587
2814
|
role: event.role,
|
|
2815
|
+
modelActivityKind: event.modelActivityKind,
|
|
2816
|
+
contentVisibility: event.contentVisibility,
|
|
2817
|
+
contentSource: event.contentSource,
|
|
2818
|
+
sourceType: event.sourceType,
|
|
2819
|
+
runtimeKind: event.runtimeKind,
|
|
2588
2820
|
label: event.label,
|
|
2589
2821
|
snippet: event.snippet,
|
|
2590
2822
|
};
|
|
@@ -2841,12 +3073,19 @@ function summarizeExperienceSessions(invocations, sessionGroupsByKey, generatedA
|
|
|
2841
3073
|
const ruleFindings = ruleFindingsForEvidence(indicators, timeline, observationRefs, evidenceChain, metricScopeId);
|
|
2842
3074
|
const assistiveInference = assistiveInferenceForEvidence(indicators, evidenceChain, ruleFindings);
|
|
2843
3075
|
const problemPatterns = mergeExperienceProblemPatterns(group.flatMap((invocation) => invocation.problemPatterns));
|
|
3076
|
+
const sourceThreadId = sessionGroup.find((session) => session.role === 'main')?.rootRunId
|
|
3077
|
+
?? sessionGroup[0]?.rootRunId
|
|
3078
|
+
?? first.sessionId;
|
|
3079
|
+
const threadId = hashParts('thread', first.sessionGroupKey);
|
|
3080
|
+
const turns = reconstructExperienceTurns(fullSessionTimeline);
|
|
2844
3081
|
const storyInvocations = invocations
|
|
2845
3082
|
.filter((invocation) => invocation.sessionGroupKey === first.sessionGroupKey)
|
|
2846
3083
|
.sort(compareStoryInvocations);
|
|
2847
3084
|
const baseSession = {
|
|
2848
3085
|
id: metricScopeId,
|
|
2849
3086
|
skillName: first.skillName,
|
|
3087
|
+
threadId,
|
|
3088
|
+
sourceThreadId,
|
|
2850
3089
|
sessionId: first.sessionId,
|
|
2851
3090
|
sourceTrace: first.sourceTrace,
|
|
2852
3091
|
sourceKind: first.sourceKind,
|
|
@@ -2873,6 +3112,8 @@ function summarizeExperienceSessions(invocations, sessionGroupsByKey, generatedA
|
|
|
2873
3112
|
relatedObservationIds,
|
|
2874
3113
|
timelineRef: timelineRefForSessionGroup(first.sessionGroupKey),
|
|
2875
3114
|
timelinePreviewEventIds: previewEvents.map((event) => event.id),
|
|
3115
|
+
attributedEventIds: timeline.map((event) => event.id),
|
|
3116
|
+
turns,
|
|
2876
3117
|
timelinePreview: previewEvents,
|
|
2877
3118
|
fullSessionTimeline,
|
|
2878
3119
|
timelineTree,
|
|
@@ -3591,7 +3832,7 @@ function dispatchTerminalLifecycle(session, dispatch) {
|
|
|
3591
3832
|
|| candidate.traceId === dispatch.traceId
|
|
3592
3833
|
|| candidate.sourceTrace === dispatch.sourceTrace);
|
|
3593
3834
|
const event = branch?.events.at(-1);
|
|
3594
|
-
if (event?.kind !== 'runtime_context')
|
|
3835
|
+
if (event?.kind !== 'lifecycle' && event?.kind !== 'runtime_context')
|
|
3595
3836
|
return undefined;
|
|
3596
3837
|
if (event.label === 'turn_completed' || event.label === 'session_ended') {
|
|
3597
3838
|
return { status: 'completed', evidenceRef: evidenceRefFromTimeline(event) };
|
|
@@ -5104,7 +5345,7 @@ function userFeedbackStepText(session, reviewState) {
|
|
|
5104
5345
|
feedbackCounts.positiveFeedbackCount > 0 ? `正向反馈 ${feedbackCounts.positiveFeedbackCount} 次` : '',
|
|
5105
5346
|
session.indicators.userGoalShiftCount > 0 ? `目标切换 ${session.indicators.userGoalShiftCount} 次` : '',
|
|
5106
5347
|
].filter(Boolean);
|
|
5107
|
-
return parts.length > 0 ? `用户反馈信号:${parts.join(',')}。` : '
|
|
5348
|
+
return parts.length > 0 ? `用户反馈信号:${parts.join(',')}。` : '原始日志里没有看到人工追问、纠正、负向反馈或目标切换。';
|
|
5108
5349
|
}
|
|
5109
5350
|
function userFeedbackStepStatus(session, reviewState) {
|
|
5110
5351
|
const feedbackCounts = canonicalFeedbackCountsForSession(session, reviewState);
|
|
@@ -18,6 +18,7 @@ import { parseTraceIngestionSummary } from './trace-ingestion.js';
|
|
|
18
18
|
import { createTraceSessionIndex, traceSessionRefIdentity } from './trace-session-index.js';
|
|
19
19
|
import { isInstalledSkillAssetPath } from './trace-attribution.js';
|
|
20
20
|
import { writeJsonFileAtomic } from '../shared/atomic-json.js';
|
|
21
|
+
import { writeObservationSourceRecordArchives } from './source-record-archive.js';
|
|
21
22
|
// observe inbox(观测收件箱)产物根目录。导出名沿用 *_OBSERVATIONS_DIR 以少动 importer,
|
|
22
23
|
// 但落盘目录已统一到 observe-inbox 词根(命令 omk observe inbox / kind observe-inbox)。
|
|
23
24
|
// 项目级 .omk/observe-inbox 优先、全局兜底 —— 这套 project/global 归属是既有正常行为,本次只改名不改归属。
|
|
@@ -700,7 +701,14 @@ export function saveObservationInboxReport(report, outDir = DEFAULT_OBSERVATIONS
|
|
|
700
701
|
// 例: '2026-05-07T12:00:00.999Z' → '2026-05-07T12-00-00-999'
|
|
701
702
|
const stamp = report.meta.generatedAt.replace(/[:.]/g, '-').replace(/Z$/, '');
|
|
702
703
|
const path = reportFilePath(outDir, `${stamp}-${randomRunToken()}`);
|
|
703
|
-
|
|
704
|
+
const sourceRecordArchives = writeObservationSourceRecordArchives(report, outDir, path);
|
|
705
|
+
const persisted = sourceRecordArchives.length > 0
|
|
706
|
+
? { ...compact, meta: { ...compact.meta, sourceRecordArchives } }
|
|
707
|
+
: compact;
|
|
708
|
+
if (!normalizeObservationInboxReport(persisted)) {
|
|
709
|
+
throw new Error('拒绝写入原始日志引用无效的 observe inbox 报告。');
|
|
710
|
+
}
|
|
711
|
+
writeJsonFileAtomic(path, persisted);
|
|
704
712
|
return path;
|
|
705
713
|
}
|
|
706
714
|
export function compactObservationInboxReport(report) {
|
|
@@ -790,6 +798,11 @@ function normalizeObservationInboxReport(value) {
|
|
|
790
798
|
};
|
|
791
799
|
}
|
|
792
800
|
function observationInboxReferencesAreConsistent(meta, items, experience) {
|
|
801
|
+
const archiveRefs = meta.sourceRecordArchives ?? [];
|
|
802
|
+
const experienceSessionIds = new Set(experience?.sessions.map((session) => session.id) ?? []);
|
|
803
|
+
if (new Set(archiveRefs.map((ref) => ref.experienceSessionId)).size !== archiveRefs.length
|
|
804
|
+
|| archiveRefs.some((ref) => !experienceSessionIds.has(ref.experienceSessionId)))
|
|
805
|
+
return false;
|
|
793
806
|
const itemIds = new Set(items.map((item) => item.id));
|
|
794
807
|
if (itemIds.size !== items.length)
|
|
795
808
|
return false;
|
|
@@ -888,7 +901,10 @@ function isObservationInboxMeta(value) {
|
|
|
888
901
|
&& !isInboxTimestampRecord(value.skillInvocationLastSeen))
|
|
889
902
|
|| (value.skillToolCallCounts !== undefined
|
|
890
903
|
&& (!isInboxRecord(value.skillToolCallCounts)
|
|
891
|
-
|| !Object.values(value.skillToolCallCounts).every(isInboxCountRecord)))
|
|
904
|
+
|| !Object.values(value.skillToolCallCounts).every(isInboxCountRecord)))
|
|
905
|
+
|| (value.sourceRecordArchives !== undefined
|
|
906
|
+
&& (!Array.isArray(value.sourceRecordArchives)
|
|
907
|
+
|| !value.sourceRecordArchives.every(isObservationSourceRecordArchiveRef))))
|
|
892
908
|
return false;
|
|
893
909
|
if (value.sessionTimeRange !== undefined
|
|
894
910
|
&& (!isInboxRecord(value.sessionTimeRange)
|
|
@@ -914,6 +930,28 @@ function isObservationInboxMeta(value) {
|
|
|
914
930
|
|| (Array.isArray(value.sessionTimeRanges)
|
|
915
931
|
&& value.sessionTimeRanges.every(isObservationSessionTimeRange));
|
|
916
932
|
}
|
|
933
|
+
function isObservationSourceRecordArchiveRef(value) {
|
|
934
|
+
if (!isInboxRecord(value)
|
|
935
|
+
|| typeof value.experienceSessionId !== 'string'
|
|
936
|
+
|| !['available', 'partial', 'unavailable'].includes(String(value.status))
|
|
937
|
+
|| (value.relativePath !== undefined && typeof value.relativePath !== 'string')
|
|
938
|
+
|| !isInboxCount(value.recordCount)
|
|
939
|
+
|| !isInboxCount(value.omittedRecordCount)
|
|
940
|
+
|| !isInboxCount(value.byteCount)
|
|
941
|
+
|| typeof value.truncated !== 'boolean')
|
|
942
|
+
return false;
|
|
943
|
+
if (value.status === 'unavailable' && value.relativePath !== undefined)
|
|
944
|
+
return false;
|
|
945
|
+
if (value.status !== 'unavailable' && typeof value.relativePath !== 'string')
|
|
946
|
+
return false;
|
|
947
|
+
return value.reason === undefined || [
|
|
948
|
+
'no_record_ranges',
|
|
949
|
+
'source_missing',
|
|
950
|
+
'unsupported_source',
|
|
951
|
+
'read_failed',
|
|
952
|
+
'archive_limit',
|
|
953
|
+
].includes(String(value.reason));
|
|
954
|
+
}
|
|
917
955
|
function isObservationSessionTimeRange(value) {
|
|
918
956
|
return isInboxRecord(value)
|
|
919
957
|
&& typeof value.sessionId === 'string'
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DebugKnowledgeEvidence, ExperienceTimelineEvent, KnowledgeDebuggerViewModel, ObservationSourceRecordArchiveView, TaskTrajectorySession, TaskReplayStep, TraceIngestionSummary } from '../types/index.js';
|
|
2
|
+
export declare function buildKnowledgeDebuggerViewModel(session: TaskTrajectorySession, targetTurnId: string, ingestion?: TraceIngestionSummary, sourceRecords?: ObservationSourceRecordArchiveView): KnowledgeDebuggerViewModel;
|
|
3
|
+
export declare function buildTaskReplaySteps(session: TaskTrajectorySession, timeline: ExperienceTimelineEvent[], knowledgeEvidence: DebugKnowledgeEvidence[]): TaskReplayStep[];
|
|
4
|
+
export declare function projectKnowledgeEvidence(timeline: ExperienceTimelineEvent[]): DebugKnowledgeEvidence[];
|