@khorsheed/dsh-context-lens 0.0.0-stage → 0.1.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/CHANGELOG.md +16 -0
- package/README.en.md +53 -0
- package/README.i18n.yaml +6 -0
- package/README.md +52 -2
- package/cordis.patch.yml +13 -0
- package/lib/client.js +26953 -0
- package/lib/index.js +3943 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +1569 -0
- package/lib/typert.remote-client.d.ts +40 -0
- package/lib/typert.remote-client.js +1202 -0
- package/lib/types/changes.d.ts +72 -0
- package/lib/types/changes.js +328 -0
- package/lib/types/client/AgentTabs.d.ts +34 -0
- package/lib/types/client/AgentTabs.js +89 -0
- package/lib/types/client/ChangeList.d.ts +28 -0
- package/lib/types/client/ChangeList.js +109 -0
- package/lib/types/client/ConfigFacts.d.ts +21 -0
- package/lib/types/client/ConfigFacts.js +30 -0
- package/lib/types/client/HeaderUtility.d.ts +12 -0
- package/lib/types/client/HeaderUtility.js +8 -0
- package/lib/types/client/InspectorPanel.d.ts +5 -0
- package/lib/types/client/InspectorPanel.js +486 -0
- package/lib/types/client/RawView.d.ts +18 -0
- package/lib/types/client/RawView.js +8 -0
- package/lib/types/client/RequestFacts.d.ts +19 -0
- package/lib/types/client/RequestFacts.js +39 -0
- package/lib/types/client/RoomDecisionsView.d.ts +24 -0
- package/lib/types/client/RoomDecisionsView.js +52 -0
- package/lib/types/client/SchemaFields.d.ts +13 -0
- package/lib/types/client/SchemaFields.js +96 -0
- package/lib/types/client/SegCtl.d.ts +32 -0
- package/lib/types/client/SegCtl.js +12 -0
- package/lib/types/client/SegmentBlocks.d.ts +28 -0
- package/lib/types/client/SegmentBlocks.js +225 -0
- package/lib/types/client/TimingView.d.ts +17 -0
- package/lib/types/client/TimingView.js +98 -0
- package/lib/types/client/TokenView.d.ts +21 -0
- package/lib/types/client/TokenView.js +22 -0
- package/lib/types/client/ToolCatalog.d.ts +9 -0
- package/lib/types/client/ToolCatalog.js +51 -0
- package/lib/types/client/Trend.d.ts +25 -0
- package/lib/types/client/Trend.js +100 -0
- package/lib/types/client/TurnAction.d.ts +14 -0
- package/lib/types/client/TurnAction.js +31 -0
- package/lib/types/client/TurnMenu.d.ts +36 -0
- package/lib/types/client/TurnMenu.js +50 -0
- package/lib/types/client/aggregate.d.ts +141 -0
- package/lib/types/client/aggregate.js +213 -0
- package/lib/types/client/contract.d.ts +58 -0
- package/lib/types/client/contract.js +1 -0
- package/lib/types/client/definition.d.ts +47 -0
- package/lib/types/client/definition.js +25 -0
- package/lib/types/client/icons-local.d.ts +19 -0
- package/lib/types/client/icons-local.js +3 -0
- package/lib/types/client/icons.d.ts +18 -0
- package/lib/types/client/icons.js +2 -0
- package/lib/types/client/index.d.ts +42 -0
- package/lib/types/client/index.js +139 -0
- package/lib/types/client/locales.d.ts +365 -0
- package/lib/types/client/locales.js +705 -0
- package/lib/types/client/preset-visibility.d.ts +99 -0
- package/lib/types/client/preset-visibility.js +108 -0
- package/lib/types/client/scroll-sync.d.ts +54 -0
- package/lib/types/client/scroll-sync.js +118 -0
- package/lib/types/client/timing.d.ts +29 -0
- package/lib/types/client/timing.js +117 -0
- package/lib/types/client/wire.d.ts +13 -0
- package/lib/types/client/wire.js +11 -0
- package/lib/types/index.d.ts +32 -0
- package/lib/types/index.js +25 -0
- package/lib/types/log-lane.d.ts +198 -0
- package/lib/types/log-lane.js +841 -0
- package/lib/types/messages.d.ts +96 -0
- package/lib/types/messages.js +254 -0
- package/lib/types/prefix-diff.d.ts +4 -0
- package/lib/types/prefix-diff.js +20 -0
- package/lib/types/remote.d.ts +45 -0
- package/lib/types/remote.js +99 -0
- package/lib/types/room.d.ts +66 -0
- package/lib/types/room.js +101 -0
- package/lib/types/segmenter.d.ts +100 -0
- package/lib/types/segmenter.js +184 -0
- package/lib/types/service.d.ts +145 -0
- package/lib/types/service.js +493 -0
- package/lib/types/store.d.ts +424 -0
- package/lib/types/store.js +1920 -0
- package/lib/types/tool-summary.d.ts +6 -0
- package/lib/types/tool-summary.js +7 -0
- package/lib/types/types.d.ts +703 -0
- package/lib/types/types.js +18 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +133 -3
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized message form the capture pipeline segments. Both lanes — the
|
|
3
|
+
* in-process `llm/stream` waterfall (typed `RequestMessage` values, possibly
|
|
4
|
+
* deep-frozen) and the child-log lane (untrusted JSON from another process's
|
|
5
|
+
* session log) — reduce to {@link CapturedMessage} before classification, so
|
|
6
|
+
* the segmenter sees exactly one shape.
|
|
7
|
+
*
|
|
8
|
+
* Classification maps the host's merge-extensible `MessageSource.kind` /
|
|
9
|
+
* `ContextForm` vocabulary onto the panel's closed {@link SegmentCategory}
|
|
10
|
+
* set. Unknown producer kinds degrade to `plugin-injection`; the mapping is
|
|
11
|
+
* additive — a new host kind never throws, it just lands in the plugin bucket
|
|
12
|
+
* until the map learns it.
|
|
13
|
+
*
|
|
14
|
+
* @module @khorsheed/dsh-context-lens/messages
|
|
15
|
+
*/
|
|
16
|
+
import type { RequestMessage } from '@deepseek-ai/dsh-llm';
|
|
17
|
+
import type { SegmentCategory } from './types.ts';
|
|
18
|
+
/** One content block, flattened to the fields the panel displays. */
|
|
19
|
+
export interface CapturedBlock {
|
|
20
|
+
type: string;
|
|
21
|
+
text?: string;
|
|
22
|
+
/** tool-call blocks: provider-issued call id, tool name, raw JSON arguments. */
|
|
23
|
+
id?: string;
|
|
24
|
+
name?: string;
|
|
25
|
+
arguments?: string;
|
|
26
|
+
/** tool-addition / tool-removal blocks: the affected tool name. */
|
|
27
|
+
toolName?: string;
|
|
28
|
+
/** file / image blocks: display label for the placeholder line. */
|
|
29
|
+
ref?: string;
|
|
30
|
+
}
|
|
31
|
+
/** The lane-neutral message record the segmenter consumes. */
|
|
32
|
+
export interface CapturedMessage {
|
|
33
|
+
/** Durable message id when the message has one (hand-built one-shot inputs do not). */
|
|
34
|
+
id?: string;
|
|
35
|
+
role: 'system' | 'user' | 'assistant' | 'tool' | 'developer';
|
|
36
|
+
/** `MessageSource.kind` — producer identity in the host's own vocabulary. */
|
|
37
|
+
sourceKind: string;
|
|
38
|
+
/** `ContextFormed.form` when the producer declared one. */
|
|
39
|
+
sourceForm?: string;
|
|
40
|
+
compactionId?: string;
|
|
41
|
+
pruning?: {
|
|
42
|
+
beforeChars: number;
|
|
43
|
+
afterChars: number;
|
|
44
|
+
};
|
|
45
|
+
content: CapturedBlock[];
|
|
46
|
+
/** tool-role messages: the answered call. */
|
|
47
|
+
toolCallId?: string;
|
|
48
|
+
sourceTurn?: number | undefined;
|
|
49
|
+
isError?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* User-role producers that ride along every turn rather than start one: a
|
|
53
|
+
* turn with no human message is attributed to its first message from any
|
|
54
|
+
* other producer (a room delivery, a schedule, a plugin trigger).
|
|
55
|
+
*/
|
|
56
|
+
export declare const AMBIENT_SOURCES: ReadonlySet<string>;
|
|
57
|
+
/**
|
|
58
|
+
* The trigger preview: injected triggers lead with standing instructions and
|
|
59
|
+
* end with what this turn delivers (a report, a forwarded message), so the
|
|
60
|
+
* last paragraph is the part that differs turn to turn.
|
|
61
|
+
*/
|
|
62
|
+
export declare function lastParagraph(text: string): string;
|
|
63
|
+
/** Collapse whitespace for the single-line preview, capped at `max` chars. */
|
|
64
|
+
export declare function previewLine(text: string, max?: number): string;
|
|
65
|
+
/**
|
|
66
|
+
* The verbatim wire form of one message — what `SegmentItem.full` carries.
|
|
67
|
+
* Assistant rows serialize to a JSON string `{reasoning?, text?, calls?}`
|
|
68
|
+
* (calls keep the raw argument JSON), the shape the reference panel renders;
|
|
69
|
+
* every other role is its plain text. The content is pre-projection: the
|
|
70
|
+
* waterfall sees file/image blocks before the adapter rewrites them to handle
|
|
71
|
+
* text, so they appear as bracketed placeholders.
|
|
72
|
+
*/
|
|
73
|
+
export declare function serializeMessage(message: CapturedMessage): string;
|
|
74
|
+
/** Tool names one assistant message invoked (the chip on assistant rows). */
|
|
75
|
+
export declare function toolCallNames(message: CapturedMessage): string[];
|
|
76
|
+
/** Single-line summary of one message for the collapsed row. */
|
|
77
|
+
export declare function previewMessage(message: CapturedMessage): string;
|
|
78
|
+
/**
|
|
79
|
+
* Classify one message into its panel category. Role decides first; user-role
|
|
80
|
+
* rows refine by producer `kind`, with `form: 'snapshot'` as the fallback
|
|
81
|
+
* signal for runtime snapshots from producers the explicit map predates.
|
|
82
|
+
*/
|
|
83
|
+
export declare function classifyMessage(message: CapturedMessage): SegmentCategory;
|
|
84
|
+
/** The label a row shows as its origin — producer kind, refined where the panel knows more. */
|
|
85
|
+
export declare function messageSourceLabel(message: CapturedMessage, toolName?: string): string;
|
|
86
|
+
/**
|
|
87
|
+
* Diff identity for one message: the durable id when present, else a content
|
|
88
|
+
* hash. Tool-result pruning preserves ids while changing content; the hash
|
|
89
|
+
* fallback keeps hand-built id-less inputs (aux requests) diffable.
|
|
90
|
+
*/
|
|
91
|
+
export declare function messageKey(message: CapturedMessage, hash: (text: string) => string): string;
|
|
92
|
+
/** Normalize one typed waterfall message (loop-built or hand-built). Never mutates the input. */
|
|
93
|
+
export declare function fromRequestMessage(message: RequestMessage): CapturedMessage;
|
|
94
|
+
/** Structural read of one log-lane message (untrusted JSON). Returns undefined for unreadable rows. */
|
|
95
|
+
export declare function fromLogMessage(raw: unknown): CapturedMessage | undefined;
|
|
96
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-role producers that ride along every turn rather than start one: a
|
|
3
|
+
* turn with no human message is attributed to its first message from any
|
|
4
|
+
* other producer (a room delivery, a schedule, a plugin trigger).
|
|
5
|
+
*/
|
|
6
|
+
export const AMBIENT_SOURCES = new Set(['user', 'runtime-context', 'skill-catalog', 'skill-invocation', 'repeat-tool-reminder', 'compact-checkpoint']);
|
|
7
|
+
/**
|
|
8
|
+
* The trigger preview: injected triggers lead with standing instructions and
|
|
9
|
+
* end with what this turn delivers (a report, a forwarded message), so the
|
|
10
|
+
* last paragraph is the part that differs turn to turn.
|
|
11
|
+
*/
|
|
12
|
+
export function lastParagraph(text) {
|
|
13
|
+
const paragraphs = text.split(/\n\s*\n/).map(p => p.trim()).filter(p => p.length > 0);
|
|
14
|
+
return previewLine(paragraphs.at(-1) ?? text, 120);
|
|
15
|
+
}
|
|
16
|
+
/** Collapse whitespace for the single-line preview, capped at `max` chars. */
|
|
17
|
+
export function previewLine(text, max = 80) {
|
|
18
|
+
const collapsed = text.replace(/\s+/g, ' ').trim();
|
|
19
|
+
return collapsed.length <= max ? collapsed : `${collapsed.slice(0, max - 1)}…`;
|
|
20
|
+
}
|
|
21
|
+
/** Model-facing text of non-assistant content: text verbatim, file/image as placeholder lines. */
|
|
22
|
+
function plainText(blocks) {
|
|
23
|
+
const parts = [];
|
|
24
|
+
for (const block of blocks) {
|
|
25
|
+
switch (block.type) {
|
|
26
|
+
case 'text':
|
|
27
|
+
parts.push(block.text ?? '');
|
|
28
|
+
break;
|
|
29
|
+
case 'file':
|
|
30
|
+
parts.push(`[file: ${block.ref ?? 'attachment'}]`);
|
|
31
|
+
break;
|
|
32
|
+
case 'image':
|
|
33
|
+
parts.push(`[image${block.ref === undefined ? '' : `: ${block.ref}`}]`);
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return parts.join('\n');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The verbatim wire form of one message — what `SegmentItem.full` carries.
|
|
43
|
+
* Assistant rows serialize to a JSON string `{reasoning?, text?, calls?}`
|
|
44
|
+
* (calls keep the raw argument JSON), the shape the reference panel renders;
|
|
45
|
+
* every other role is its plain text. The content is pre-projection: the
|
|
46
|
+
* waterfall sees file/image blocks before the adapter rewrites them to handle
|
|
47
|
+
* text, so they appear as bracketed placeholders.
|
|
48
|
+
*/
|
|
49
|
+
export function serializeMessage(message) {
|
|
50
|
+
if (message.role === 'assistant') {
|
|
51
|
+
const reasoning = message.content
|
|
52
|
+
.filter(block => block.type === 'reasoning')
|
|
53
|
+
.map(block => block.text ?? '')
|
|
54
|
+
.join('');
|
|
55
|
+
const text = message.content
|
|
56
|
+
.filter(block => block.type === 'text')
|
|
57
|
+
.map(block => block.text ?? '')
|
|
58
|
+
.join('');
|
|
59
|
+
const calls = message.content
|
|
60
|
+
.filter(block => block.type === 'tool-call')
|
|
61
|
+
.map(block => ({ id: block.id ?? '', name: block.name ?? '', arguments: block.arguments ?? '' }));
|
|
62
|
+
return JSON.stringify({
|
|
63
|
+
...reasoning.length > 0 ? { reasoning } : {},
|
|
64
|
+
...text.length > 0 ? { text } : {},
|
|
65
|
+
...calls.length > 0 ? { calls } : {},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (message.role === 'developer') {
|
|
69
|
+
return JSON.stringify(message.content);
|
|
70
|
+
}
|
|
71
|
+
return plainText(message.content);
|
|
72
|
+
}
|
|
73
|
+
/** Tool names one assistant message invoked (the chip on assistant rows). */
|
|
74
|
+
export function toolCallNames(message) {
|
|
75
|
+
return message.content
|
|
76
|
+
.filter(block => block.type === 'tool-call')
|
|
77
|
+
.map(block => block.name ?? '')
|
|
78
|
+
.filter(name => name.length > 0);
|
|
79
|
+
}
|
|
80
|
+
/** Single-line summary of one message for the collapsed row. */
|
|
81
|
+
export function previewMessage(message) {
|
|
82
|
+
if (message.role === 'assistant') {
|
|
83
|
+
const names = toolCallNames(message);
|
|
84
|
+
if (names.length > 0)
|
|
85
|
+
return `→ ${names.join(', ')}`;
|
|
86
|
+
const text = message.content
|
|
87
|
+
.filter(block => block.type === 'text')
|
|
88
|
+
.map(block => block.text ?? '')
|
|
89
|
+
.join('');
|
|
90
|
+
return previewLine(text);
|
|
91
|
+
}
|
|
92
|
+
if (message.role === 'developer') {
|
|
93
|
+
const changes = message.content
|
|
94
|
+
.map(block => (block.type === 'tool-addition' ? `+${block.toolName ?? ''}`
|
|
95
|
+
: block.type === 'tool-removal' ? `-${block.toolName ?? ''}` : ''))
|
|
96
|
+
.filter(part => part.length > 1);
|
|
97
|
+
return previewLine(changes.length > 0 ? `tools ${changes.join(' ')}` : serializeMessage(message));
|
|
98
|
+
}
|
|
99
|
+
return previewLine(plainText(message.content));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Classify one message into its panel category. Role decides first; user-role
|
|
103
|
+
* rows refine by producer `kind`, with `form: 'snapshot'` as the fallback
|
|
104
|
+
* signal for runtime snapshots from producers the explicit map predates.
|
|
105
|
+
*/
|
|
106
|
+
export function classifyMessage(message) {
|
|
107
|
+
switch (message.role) {
|
|
108
|
+
case 'system':
|
|
109
|
+
return 'system';
|
|
110
|
+
case 'assistant':
|
|
111
|
+
return 'assistant';
|
|
112
|
+
case 'tool':
|
|
113
|
+
return 'tool-result';
|
|
114
|
+
case 'developer':
|
|
115
|
+
return 'tool-change';
|
|
116
|
+
case 'user':
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
switch (message.sourceKind) {
|
|
120
|
+
case 'user':
|
|
121
|
+
return 'user';
|
|
122
|
+
case 'runtime-context':
|
|
123
|
+
return 'runtime-snapshot';
|
|
124
|
+
case 'skill-catalog':
|
|
125
|
+
case 'skill-invocation':
|
|
126
|
+
return 'skill-injection';
|
|
127
|
+
case 'compact-checkpoint':
|
|
128
|
+
return 'compaction';
|
|
129
|
+
case 'repeat-tool-reminder':
|
|
130
|
+
return 'reminder-injection';
|
|
131
|
+
default:
|
|
132
|
+
return message.sourceForm === 'snapshot' ? 'runtime-snapshot' : 'plugin-injection';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** The label a row shows as its origin — producer kind, refined where the panel knows more. */
|
|
136
|
+
export function messageSourceLabel(message, toolName) {
|
|
137
|
+
if (message.role === 'tool' && toolName !== undefined)
|
|
138
|
+
return toolName;
|
|
139
|
+
return message.sourceKind;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Diff identity for one message: the durable id when present, else a content
|
|
143
|
+
* hash. Tool-result pruning preserves ids while changing content; the hash
|
|
144
|
+
* fallback keeps hand-built id-less inputs (aux requests) diffable.
|
|
145
|
+
*/
|
|
146
|
+
export function messageKey(message, hash) {
|
|
147
|
+
return `${message.id === undefined ? 'h' : `id:${message.id}`}:${hash(JSON.stringify({
|
|
148
|
+
...'turn' in message && typeof message.turn === 'number' ? { sourceTurn: message.turn } : {},
|
|
149
|
+
role: message.role,
|
|
150
|
+
kind: message.sourceKind,
|
|
151
|
+
content: message.content,
|
|
152
|
+
...message.toolCallId === undefined ? {} : { toolCallId: message.toolCallId },
|
|
153
|
+
}))}`;
|
|
154
|
+
}
|
|
155
|
+
/** Normalize one typed waterfall message (loop-built or hand-built). Never mutates the input. */
|
|
156
|
+
export function fromRequestMessage(message) {
|
|
157
|
+
const content = message.content.map(normalizeBlock);
|
|
158
|
+
// A hand-built one-shot input has neither id nor source; durable messages
|
|
159
|
+
// carry both. Narrowing through `in` keeps the `?: never` arms honest.
|
|
160
|
+
const id = 'id' in message && typeof message.id === 'string' ? message.id : undefined;
|
|
161
|
+
const source = 'source' in message && typeof message.source === 'object'
|
|
162
|
+
? message.source
|
|
163
|
+
: undefined;
|
|
164
|
+
const base = {
|
|
165
|
+
...id === undefined ? {} : { id },
|
|
166
|
+
...'turn' in message && typeof message.turn === 'number' ? { sourceTurn: message.turn } : {},
|
|
167
|
+
role: message.role,
|
|
168
|
+
...source?.compactionId === undefined ? {} : { compactionId: source.compactionId },
|
|
169
|
+
sourceKind: source?.kind ?? 'user',
|
|
170
|
+
...source?.form === undefined ? {} : { sourceForm: source.form },
|
|
171
|
+
content,
|
|
172
|
+
};
|
|
173
|
+
if (message.role === 'tool') {
|
|
174
|
+
return {
|
|
175
|
+
...base,
|
|
176
|
+
toolCallId: message.toolCallId,
|
|
177
|
+
...message.isError === undefined ? {} : { isError: message.isError },
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return base;
|
|
181
|
+
}
|
|
182
|
+
/** Flatten one typed content block. Unknown block types keep only their tag. */
|
|
183
|
+
function normalizeBlock(block) {
|
|
184
|
+
switch (block.type) {
|
|
185
|
+
case 'text':
|
|
186
|
+
case 'reasoning':
|
|
187
|
+
return { type: block.type, text: block.text };
|
|
188
|
+
case 'tool-call':
|
|
189
|
+
return { type: 'tool-call', id: block.id, name: block.name, arguments: block.arguments };
|
|
190
|
+
case 'tool-addition':
|
|
191
|
+
case 'tool-removal':
|
|
192
|
+
return { type: block.type, toolName: block.toolName };
|
|
193
|
+
case 'file':
|
|
194
|
+
case 'image': {
|
|
195
|
+
const ref = attachmentLabel(block.attachment);
|
|
196
|
+
return ref === undefined ? { type: block.type } : { type: block.type, ref };
|
|
197
|
+
}
|
|
198
|
+
default:
|
|
199
|
+
return { type: block.type };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/** Best-effort display label out of an attachment reference. */
|
|
203
|
+
function attachmentLabel(attachment) {
|
|
204
|
+
if (typeof attachment !== 'object' || attachment === null)
|
|
205
|
+
return undefined;
|
|
206
|
+
const name = attachment.name;
|
|
207
|
+
return typeof name === 'string' && name.length > 0 ? name : undefined;
|
|
208
|
+
}
|
|
209
|
+
/** Structural read of one log-lane message (untrusted JSON). Returns undefined for unreadable rows. */
|
|
210
|
+
export function fromLogMessage(raw) {
|
|
211
|
+
if (typeof raw !== 'object' || raw === null)
|
|
212
|
+
return undefined;
|
|
213
|
+
const value = raw;
|
|
214
|
+
const role = value['role'];
|
|
215
|
+
if (role !== 'system' && role !== 'user' && role !== 'assistant' && role !== 'tool' && role !== 'developer') {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
const content = Array.isArray(value['content']) ? value['content'].map(readBlock).filter(isDefined) : [];
|
|
219
|
+
const source = typeof value['source'] === 'object' && value['source'] !== null
|
|
220
|
+
? value['source']
|
|
221
|
+
: undefined;
|
|
222
|
+
const sourceKind = typeof source?.['kind'] === 'string' ? source['kind'] : role === 'user' ? 'user' : role;
|
|
223
|
+
return {
|
|
224
|
+
...typeof value['id'] === 'string' ? { id: value['id'] } : {},
|
|
225
|
+
...typeof value['turn'] === 'number' ? { sourceTurn: value['turn'] } : {},
|
|
226
|
+
role,
|
|
227
|
+
sourceKind,
|
|
228
|
+
...typeof source?.['compactionId'] === 'string' ? { compactionId: source['compactionId'] } : {},
|
|
229
|
+
...typeof source?.['form'] === 'string' ? { sourceForm: source['form'] } : {},
|
|
230
|
+
content,
|
|
231
|
+
...typeof value['toolCallId'] === 'string' ? { toolCallId: value['toolCallId'] } : {},
|
|
232
|
+
...value['isError'] === undefined ? {} : { isError: value['isError'] === true },
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/** Structural read of one log-lane content block. */
|
|
236
|
+
function readBlock(raw) {
|
|
237
|
+
if (typeof raw !== 'object' || raw === null)
|
|
238
|
+
return undefined;
|
|
239
|
+
const value = raw;
|
|
240
|
+
const type = value['type'];
|
|
241
|
+
if (typeof type !== 'string')
|
|
242
|
+
return undefined;
|
|
243
|
+
return {
|
|
244
|
+
type,
|
|
245
|
+
...typeof value['text'] === 'string' ? { text: value['text'] } : {},
|
|
246
|
+
...typeof value['id'] === 'string' ? { id: value['id'] } : {},
|
|
247
|
+
...typeof value['name'] === 'string' ? { name: value['name'] } : {},
|
|
248
|
+
...typeof value['arguments'] === 'string' ? { arguments: value['arguments'] } : {},
|
|
249
|
+
...typeof value['toolName'] === 'string' ? { toolName: value['toolName'] } : {},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function isDefined(value) {
|
|
253
|
+
return value !== undefined;
|
|
254
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PrefixTextChange } from './types.ts';
|
|
2
|
+
/** Linear comparison on full text; never infer a change from already-truncated previews. */
|
|
3
|
+
export declare function prefixTextChange(before: string, after: string): PrefixTextChange;
|
|
4
|
+
//# sourceMappingURL=prefix-diff.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Linear comparison on full text; never infer a change from already-truncated previews. */
|
|
2
|
+
export function prefixTextChange(before, after) {
|
|
3
|
+
const a = Array.from(before), b = Array.from(after);
|
|
4
|
+
let start = 0, end = 0;
|
|
5
|
+
while (start < a.length && start < b.length && a[start] === b[start])
|
|
6
|
+
start++;
|
|
7
|
+
while (end < a.length - start && end < b.length - start && a[a.length - end - 1] === b[b.length - end - 1])
|
|
8
|
+
end++;
|
|
9
|
+
return {
|
|
10
|
+
offset: start,
|
|
11
|
+
leading: a.slice(Math.max(0, start - 48), start).join(''),
|
|
12
|
+
trailing: end ? a.slice(a.length - end, a.length - end + 48).join('') : '',
|
|
13
|
+
leadingOmitted: start > 48,
|
|
14
|
+
trailingOmitted: end > 48,
|
|
15
|
+
removed: a.slice(start, Math.min(a.length - end, start + 160)).join(''),
|
|
16
|
+
added: b.slice(start, Math.min(b.length - end, start + 160)).join(''),
|
|
17
|
+
removedChars: a.length - start - end,
|
|
18
|
+
addedChars: b.length - start - end,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SessionTrend } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The context-lens Remote: the wire face, and nothing else. Each verb is
|
|
4
|
+
* a one-line delegation to {@link InspectorService} and returns the BARE domain
|
|
5
|
+
* value; the wire layer wraps it in the protocol's result envelope, and thrown
|
|
6
|
+
* `RemoteError`s arrive as that envelope's error branch.
|
|
7
|
+
*
|
|
8
|
+
* Namespace `requestInspector`: the browser calls
|
|
9
|
+
* `remote.requestInspector.listTurns` etc. Pull-based (no subscription): the
|
|
10
|
+
* panel refetches on open / turn switch; capture is cheap and in-memory.
|
|
11
|
+
*
|
|
12
|
+
* @module @khorsheed/dsh-context-lens/remote
|
|
13
|
+
*/
|
|
14
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
15
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
16
|
+
import type { CapturedRequest, ListTurnsResult, ScopeFilter, ScopedRefusal, TurnOverview, TurnTiming } from './types.ts';
|
|
17
|
+
declare module '@deepseek-ai/cordis' {
|
|
18
|
+
interface Context {
|
|
19
|
+
requestInspectorRemote: RequestInspectorRemoteService;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Reserved for future config-driven knobs; the service owns today's config. */
|
|
23
|
+
export interface RequestInspectorRemoteConfig {
|
|
24
|
+
}
|
|
25
|
+
/** The wire namespace is `requestInspector`. */
|
|
26
|
+
export declare class RequestInspectorRemoteService extends TypertRemoteService<RequestInspectorRemoteConfig> {
|
|
27
|
+
static inject: string[];
|
|
28
|
+
constructor(ctx: Context, _config?: RequestInspectorRemoteConfig);
|
|
29
|
+
/** The service core this face delegates to. */
|
|
30
|
+
private get core();
|
|
31
|
+
/** Light turn list of one session plus its backfill watermark, newest last. */
|
|
32
|
+
listTurns(sessionId: string, filter?: ScopeFilter): Promise<ListTurnsResult>;
|
|
33
|
+
/** Move the backfill window to the turns ending at `end` (latest when null); answers the new turn list. */
|
|
34
|
+
loadTurns(sessionId: string, end: number | null, filter?: ScopeFilter): Promise<ListTurnsResult>;
|
|
35
|
+
/** One turn's scope/request overview — the left column, no segments. */
|
|
36
|
+
getTurn(sessionId: string, turnSeq: number, filter?: ScopeFilter): Promise<TurnOverview | undefined>;
|
|
37
|
+
/** One request's full four-segment breakdown — the right column. */
|
|
38
|
+
getRequest(sessionId: string, seq: number, filter?: ScopeFilter): Promise<CapturedRequest | ScopedRefusal | undefined>;
|
|
39
|
+
/** Lightweight session map, with no message bodies. */
|
|
40
|
+
getSessionTrend(sessionId: string, filter?: ScopeFilter): Promise<SessionTrend>;
|
|
41
|
+
/** One turn's whole-turn timing aggregation — the 耗时分布 tab. */
|
|
42
|
+
getTurnTiming(sessionId: string, turnSeq: number, filter?: ScopeFilter): Promise<TurnTiming | undefined>;
|
|
43
|
+
}
|
|
44
|
+
export default RequestInspectorRemoteService;
|
|
45
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
2
|
+
var useValue = arguments.length > 2;
|
|
3
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
4
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
5
|
+
}
|
|
6
|
+
return useValue ? value : void 0;
|
|
7
|
+
};
|
|
8
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
9
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
10
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
11
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
12
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
13
|
+
var _, done = false;
|
|
14
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
15
|
+
var context = {};
|
|
16
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
17
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
18
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
19
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
20
|
+
if (kind === "accessor") {
|
|
21
|
+
if (result === void 0) continue;
|
|
22
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
23
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
24
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
25
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
26
|
+
}
|
|
27
|
+
else if (_ = accept(result)) {
|
|
28
|
+
if (kind === "field") initializers.unshift(_);
|
|
29
|
+
else descriptor[key] = _;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
|
+
done = true;
|
|
34
|
+
};
|
|
35
|
+
import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
36
|
+
/** The wire namespace is `requestInspector`. */
|
|
37
|
+
let RequestInspectorRemoteService = (() => {
|
|
38
|
+
let _classSuper = TypertRemoteService;
|
|
39
|
+
let _instanceExtraInitializers = [];
|
|
40
|
+
let _listTurns_decorators;
|
|
41
|
+
let _loadTurns_decorators;
|
|
42
|
+
let _getTurn_decorators;
|
|
43
|
+
let _getRequest_decorators;
|
|
44
|
+
let _getSessionTrend_decorators;
|
|
45
|
+
let _getTurnTiming_decorators;
|
|
46
|
+
return class RequestInspectorRemoteService extends _classSuper {
|
|
47
|
+
static {
|
|
48
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
49
|
+
_listTurns_decorators = [Remote('listTurns')];
|
|
50
|
+
_loadTurns_decorators = [Remote('loadTurns')];
|
|
51
|
+
_getTurn_decorators = [Remote('getTurn')];
|
|
52
|
+
_getRequest_decorators = [Remote('getRequest')];
|
|
53
|
+
_getSessionTrend_decorators = [Remote('getSessionTrend')];
|
|
54
|
+
_getTurnTiming_decorators = [Remote('getTurnTiming')];
|
|
55
|
+
__esDecorate(this, null, _listTurns_decorators, { kind: "method", name: "listTurns", static: false, private: false, access: { has: obj => "listTurns" in obj, get: obj => obj.listTurns }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
56
|
+
__esDecorate(this, null, _loadTurns_decorators, { kind: "method", name: "loadTurns", static: false, private: false, access: { has: obj => "loadTurns" in obj, get: obj => obj.loadTurns }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
57
|
+
__esDecorate(this, null, _getTurn_decorators, { kind: "method", name: "getTurn", static: false, private: false, access: { has: obj => "getTurn" in obj, get: obj => obj.getTurn }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
58
|
+
__esDecorate(this, null, _getRequest_decorators, { kind: "method", name: "getRequest", static: false, private: false, access: { has: obj => "getRequest" in obj, get: obj => obj.getRequest }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
59
|
+
__esDecorate(this, null, _getSessionTrend_decorators, { kind: "method", name: "getSessionTrend", static: false, private: false, access: { has: obj => "getSessionTrend" in obj, get: obj => obj.getSessionTrend }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
60
|
+
__esDecorate(this, null, _getTurnTiming_decorators, { kind: "method", name: "getTurnTiming", static: false, private: false, access: { has: obj => "getTurnTiming" in obj, get: obj => obj.getTurnTiming }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
61
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
62
|
+
}
|
|
63
|
+
static inject = ['requestInspector'];
|
|
64
|
+
constructor(ctx, _config = {}) {
|
|
65
|
+
super(ctx, 'requestInspectorRemote', { namespace: 'requestInspector' });
|
|
66
|
+
__runInitializers(this, _instanceExtraInitializers);
|
|
67
|
+
}
|
|
68
|
+
/** The service core this face delegates to. */
|
|
69
|
+
get core() {
|
|
70
|
+
return this.ctx.requestInspector;
|
|
71
|
+
}
|
|
72
|
+
/** Light turn list of one session plus its backfill watermark, newest last. */
|
|
73
|
+
listTurns(sessionId, filter) {
|
|
74
|
+
return this.core.listTurns(sessionId, filter);
|
|
75
|
+
}
|
|
76
|
+
/** Move the backfill window to the turns ending at `end` (latest when null); answers the new turn list. */
|
|
77
|
+
loadTurns(sessionId, end, filter) {
|
|
78
|
+
return this.core.loadTurns(sessionId, end, filter);
|
|
79
|
+
}
|
|
80
|
+
/** One turn's scope/request overview — the left column, no segments. */
|
|
81
|
+
getTurn(sessionId, turnSeq, filter) {
|
|
82
|
+
return this.core.getTurn(sessionId, turnSeq, filter);
|
|
83
|
+
}
|
|
84
|
+
/** One request's full four-segment breakdown — the right column. */
|
|
85
|
+
getRequest(sessionId, seq, filter) {
|
|
86
|
+
return this.core.getRequest(sessionId, seq, filter);
|
|
87
|
+
}
|
|
88
|
+
/** Lightweight session map, with no message bodies. */
|
|
89
|
+
getSessionTrend(sessionId, filter) {
|
|
90
|
+
return this.core.getSessionTrend(sessionId, filter);
|
|
91
|
+
}
|
|
92
|
+
/** One turn's whole-turn timing aggregation — the 耗时分布 tab. */
|
|
93
|
+
getTurnTiming(sessionId, turnSeq, filter) {
|
|
94
|
+
return this.core.getTurnTiming(sessionId, turnSeq, filter);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
})();
|
|
98
|
+
export { RequestInspectorRemoteService };
|
|
99
|
+
export default RequestInspectorRemoteService;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Room rounds. In a room session the main conversation stops running turns
|
|
3
|
+
* once another member coordinates or a human addresses members directly; the
|
|
4
|
+
* work then happens in the members' own child sessions, started by the room
|
|
5
|
+
* plugin's dispatches. This module reads the room plugin's session events
|
|
6
|
+
* structurally (no dependency on the package; absent events change nothing)
|
|
7
|
+
* and keeps what the panel needs to show each human dispatch made outside a
|
|
8
|
+
* main turn as a round of its own, with the member runs it started:
|
|
9
|
+
*
|
|
10
|
+
* - `room/member-added` / `room/member-updated`: member id → display name.
|
|
11
|
+
* - `room/dispatch` with `origin: 'human'`: the message, its time, its targets.
|
|
12
|
+
* - `room/run-state`: one member run per `runId` (`<dispatchSeq>:<memberId>`),
|
|
13
|
+
* its time span, its child session, and — when the producer records it —
|
|
14
|
+
* the child turn the run became (`childTurn`).
|
|
15
|
+
* - `room/coordinator`: coordinator handoffs, drawn on the session map.
|
|
16
|
+
*
|
|
17
|
+
* @module @khorsheed/dsh-context-lens/room
|
|
18
|
+
*/
|
|
19
|
+
import type { RoomDecisionRow } from './types.ts';
|
|
20
|
+
/** One member run of a dispatch. */
|
|
21
|
+
export interface RoomRun {
|
|
22
|
+
runId: string;
|
|
23
|
+
dispatchSeq: number;
|
|
24
|
+
memberId: string;
|
|
25
|
+
member?: string;
|
|
26
|
+
state?: string;
|
|
27
|
+
startedAt?: number;
|
|
28
|
+
endedAt?: number;
|
|
29
|
+
childSessionId?: string;
|
|
30
|
+
/** The child session turn this run became, when the producer records it. */
|
|
31
|
+
childTurn?: number;
|
|
32
|
+
}
|
|
33
|
+
/** One human message to the room. */
|
|
34
|
+
export interface RoomDispatch {
|
|
35
|
+
seq: number;
|
|
36
|
+
at: number;
|
|
37
|
+
text: string;
|
|
38
|
+
targets: string[];
|
|
39
|
+
}
|
|
40
|
+
/** What one session's room events say, accumulated (log backfill and live alike). */
|
|
41
|
+
export interface RoomState {
|
|
42
|
+
members: Map<string, string>;
|
|
43
|
+
dispatches: RoomDispatch[];
|
|
44
|
+
runs: Map<string, RoomRun>;
|
|
45
|
+
handoffs: {
|
|
46
|
+
seq: number;
|
|
47
|
+
at: number;
|
|
48
|
+
memberId: string;
|
|
49
|
+
}[];
|
|
50
|
+
/** The decision-model calls the room recorded (`room/decision` with a call). */
|
|
51
|
+
decisions: RoomDecisionRow[];
|
|
52
|
+
/** Event seqs already applied (backfill and live may both deliver one). */
|
|
53
|
+
seen: Set<number>;
|
|
54
|
+
}
|
|
55
|
+
export declare function emptyRoom(): RoomState;
|
|
56
|
+
/**
|
|
57
|
+
* Apply one `room/*` event. Unknown types and malformed payloads are ignored.
|
|
58
|
+
* @returns whether the event was a room event this module reads.
|
|
59
|
+
*/
|
|
60
|
+
export declare function applyRoomEvent(room: RoomState, type: string, data: unknown, seq: number | undefined, at: number | undefined): boolean;
|
|
61
|
+
/** The runs a dispatch started, in start order. */
|
|
62
|
+
export declare function runsOf(room: RoomState, dispatchSeq: number): RoomRun[];
|
|
63
|
+
/** A synthetic, stable panel address for a room round (far below any purpose bucket). */
|
|
64
|
+
export declare const ROOM_TURN_BASE = -1000000;
|
|
65
|
+
export declare const roomTurnSeq: (dispatchSeq: number) => number;
|
|
66
|
+
//# sourceMappingURL=room.d.ts.map
|