@morlay/ui-conversation-message-actions 0.0.18 → 0.0.19-alpha.1
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 +29 -98
- package/dist/client.cjs +1380 -0
- package/dist/client.d.cts +6 -0
- package/dist/client.d.mts +6 -0
- package/dist/index.d.cts +75 -0
- package/dist/index.d.mts +3 -33
- package/dist/index.mjs +460 -2
- package/dist/invariant.d.cts +7 -0
- package/dist/{plan-BSa7k9HO.d.mts → plan-CT_6Y1fD.d.cts} +11 -9
- package/dist/plan-Cm9hCord.d.mts +101 -0
- package/dist/plan.d.cts +2 -0
- package/dist/plan.d.mts +2 -2
- package/dist/plan.mjs +145 -11
- package/dist/shared-LK3nImWW.mjs +55 -0
- package/dist/testing.d.cts +3242 -0
- package/dist/testing.d.mts +11 -5
- package/dist/testing.mjs +1976 -3775
- package/package.json +34 -31
- package/src/client/chat-node/MessageIconActions.styles.ts +76 -0
- package/src/client/chat-node/MessageIconActions.tsx +30 -11
- package/src/client/chat-node/MessageItem.styles.ts +247 -0
- package/src/client/chat-node/MessageItem.tsx +32 -39
- package/src/client/chat-node/message-chrome.ts +0 -2
- package/src/client/chat-node/register.ts +3 -4
- package/src/client/chat-node/use-calendar-day.ts +0 -4
- package/src/client/composer-stats/StatsPills.styles.ts +57 -0
- package/src/client/composer-stats/StatsPills.tsx +384 -0
- package/src/client/composer-stats/register.ts +17 -0
- package/src/client/composer-stats/stat-dialog.styles.ts +70 -0
- package/src/client/composer-stats/stat-dialog.ts +52 -0
- package/src/client/composer-stats/token-format.ts +85 -0
- package/src/client/composer-stats/turn-reading.ts +35 -0
- package/src/client/controller.ts +32 -114
- package/src/client/index.ts +8 -24
- package/src/index.ts +105 -118
- package/src/plan.ts +189 -24
- package/src/shared.ts +1 -1
- package/src/testing.ts +1 -5
- package/src/types.ts +1 -1
- package/dist/client.js +0 -806
- package/dist/src-B4HwXsob.mjs +0 -499
- package/src/client/chat-node/MessageIconActions.module.css +0 -86
- package/src/client/chat-node/MessageItem.module.css +0 -290
- package/src/client/css-modules.d.ts +0 -4
- package/src/client/import-action.tsx +0 -74
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
2
|
+
import { BranchTimeline, CascadePolicy, SessionBranchVersionEvent } from "@morlay/session-branch";
|
|
3
|
+
import { AssistantMessage, UserMessage } from "@deepseek-ai/dsh-llm";
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
interface EditOperation {
|
|
6
|
+
action: "edit";
|
|
7
|
+
sessionId: SessionId;
|
|
8
|
+
eventSeq: number;
|
|
9
|
+
blockIndex: number;
|
|
10
|
+
text: string;
|
|
11
|
+
cascade: CascadePolicy;
|
|
12
|
+
}
|
|
13
|
+
interface RerollOperation {
|
|
14
|
+
action: "reroll";
|
|
15
|
+
sessionId: SessionId;
|
|
16
|
+
}
|
|
17
|
+
interface RetryOperation {
|
|
18
|
+
action: "retry";
|
|
19
|
+
sessionId: SessionId;
|
|
20
|
+
turn: number;
|
|
21
|
+
cascade: CascadePolicy;
|
|
22
|
+
}
|
|
23
|
+
interface RewindOperation {
|
|
24
|
+
action: "rewind";
|
|
25
|
+
sessionId: SessionId;
|
|
26
|
+
toBoundary: number;
|
|
27
|
+
}
|
|
28
|
+
interface RecallOperation {
|
|
29
|
+
action: "recall";
|
|
30
|
+
sessionId: SessionId;
|
|
31
|
+
eventSeq: number;
|
|
32
|
+
}
|
|
33
|
+
interface ForkOperation {
|
|
34
|
+
action: "fork";
|
|
35
|
+
sessionId: SessionId;
|
|
36
|
+
atSeq?: number;
|
|
37
|
+
childSessionId?: SessionId;
|
|
38
|
+
}
|
|
39
|
+
type SessionEditorOperation = EditOperation | RerollOperation | RetryOperation | RewindOperation | RecallOperation | ForkOperation;
|
|
40
|
+
interface SessionEditorResult {
|
|
41
|
+
sessionId: SessionId;
|
|
42
|
+
queuedTurns: number;
|
|
43
|
+
live?: boolean;
|
|
44
|
+
}
|
|
45
|
+
interface EditableMessageBlock {
|
|
46
|
+
key: string;
|
|
47
|
+
turn?: number;
|
|
48
|
+
eventSeq: number;
|
|
49
|
+
blockIndex: number;
|
|
50
|
+
kind: "user" | "assistant.reasoning" | "assistant.response";
|
|
51
|
+
text: string;
|
|
52
|
+
time: number;
|
|
53
|
+
}
|
|
54
|
+
interface RetryableTurn {
|
|
55
|
+
turn: number;
|
|
56
|
+
userEventSeq: number;
|
|
57
|
+
preview: string;
|
|
58
|
+
time: number;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/plan.d.ts
|
|
62
|
+
interface ClosedTurn {
|
|
63
|
+
turn: number;
|
|
64
|
+
startSeq: number;
|
|
65
|
+
endSeq?: number;
|
|
66
|
+
closed: boolean;
|
|
67
|
+
user?: SessionEvent<"user/message">;
|
|
68
|
+
users: SessionEvent<"user/message">[];
|
|
69
|
+
assistants: SessionEvent<"assistant/message">[];
|
|
70
|
+
}
|
|
71
|
+
interface OperationPlan {
|
|
72
|
+
anchorSeq: number;
|
|
73
|
+
rewindBoundary?: number;
|
|
74
|
+
version: SessionBranchVersionEvent;
|
|
75
|
+
manualTurn?: {
|
|
76
|
+
turn: number;
|
|
77
|
+
user: UserMessage;
|
|
78
|
+
assistant: AssistantMessage;
|
|
79
|
+
};
|
|
80
|
+
queuedUsers: UserMessage[];
|
|
81
|
+
targetSeq: number;
|
|
82
|
+
}
|
|
83
|
+
declare function closedTurns(events: readonly SessionEvent[]): ClosedTurn[];
|
|
84
|
+
declare function editableMessages(turns: readonly ClosedTurn[]): EditableMessageBlock[];
|
|
85
|
+
declare function retryableTurns(turns: readonly ClosedTurn[]): RetryableTurn[];
|
|
86
|
+
declare function precedingContentIndex(turns: readonly ClosedTurn[], turnIndex: number): number;
|
|
87
|
+
declare function downstreamUsers(turns: readonly ClosedTurn[], start: number): UserMessage[];
|
|
88
|
+
declare function recallBoundary(events: readonly SessionEvent[], turns: readonly ClosedTurn[], eventSeq: number): number;
|
|
89
|
+
declare function editPlan(operation: EditOperation, turns: readonly ClosedTurn[]): OperationPlan;
|
|
90
|
+
declare function retryPlan(operation: RetryOperation, turns: readonly ClosedTurn[]): OperationPlan;
|
|
91
|
+
declare function rerollPlan(operation: RerollOperation, turns: readonly ClosedTurn[]): OperationPlan;
|
|
92
|
+
interface CompactionBracket {
|
|
93
|
+
start: SessionEvent;
|
|
94
|
+
summary?: SessionEvent;
|
|
95
|
+
checkpoint: SessionEvent;
|
|
96
|
+
end: SessionEvent;
|
|
97
|
+
}
|
|
98
|
+
declare function droppedCompactions(events: readonly SessionEvent[], keepFrom: number, targetSeq: number): CompactionBracket[];
|
|
99
|
+
declare function restoreCompactions(brackets: readonly CompactionBracket[], keepFrom: number, base: number): SessionEvent[];
|
|
100
|
+
//#endregion
|
|
101
|
+
export { SessionEditorResult as C, SessionEditorOperation as S, RecallOperation as _, downstreamUsers as a, RetryableTurn as b, editableMessages as c, rerollPlan as d, restoreCompactions as f, EditableMessageBlock as g, EditOperation as h, closedTurns as i, precedingContentIndex as l, retryableTurns as m, CompactionBracket as n, droppedCompactions as o, retryPlan as p, OperationPlan as r, editPlan as s, ClosedTurn as t, recallBoundary as u, RerollOperation as v, RewindOperation as x, RetryOperation as y };
|
package/dist/plan.d.cts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as downstreamUsers, c as editableMessages, d as rerollPlan, f as restoreCompactions, i as closedTurns, l as precedingContentIndex, m as retryableTurns, n as CompactionBracket, o as droppedCompactions, p as retryPlan, r as OperationPlan, s as editPlan, t as ClosedTurn, u as recallBoundary } from "./plan-CT_6Y1fD.cjs";
|
|
2
|
+
export { ClosedTurn, CompactionBracket, OperationPlan, closedTurns, downstreamUsers, droppedCompactions, editPlan, editableMessages, precedingContentIndex, recallBoundary, rerollPlan, restoreCompactions, retryPlan, retryableTurns };
|
package/dist/plan.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { ClosedTurn, OperationPlan, closedTurns, downstreamUsers, editPlan, editableMessages, precedingContentIndex, recallBoundary, rerollPlan, retryPlan, retryableTurns };
|
|
1
|
+
import { a as downstreamUsers, c as editableMessages, d as rerollPlan, f as restoreCompactions, i as closedTurns, l as precedingContentIndex, m as retryableTurns, n as CompactionBracket, o as droppedCompactions, p as retryPlan, r as OperationPlan, s as editPlan, t as ClosedTurn, u as recallBoundary } from "./plan-Cm9hCord.mjs";
|
|
2
|
+
export { ClosedTurn, CompactionBracket, OperationPlan, closedTurns, downstreamUsers, droppedCompactions, editPlan, editableMessages, precedingContentIndex, recallBoundary, rerollPlan, restoreCompactions, retryPlan, retryableTurns };
|
package/dist/plan.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SessionSeq } from "@deepseek-ai/dsh-session";
|
|
1
2
|
import { SESSION_BRANCH_VERSION_SCHEMA, SessionBranchError } from "@morlay/session-branch";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
//#region src/plan.ts
|
|
@@ -100,12 +101,6 @@ function retryableTurns(turns) {
|
|
|
100
101
|
time: turn.user.time
|
|
101
102
|
}]);
|
|
102
103
|
}
|
|
103
|
-
/**
|
|
104
|
-
* 目标轮之前最后一个「有内容」轮次的下标:跳过既无用户输入也无助手回复的
|
|
105
|
-
* 空轮。空轮是早期重放缺陷的遗留(turn/start 后直接 turn/end),在轨迹 /
|
|
106
|
-
* 轮次导航里表现为点不开的空项,并让后续轮号出现空洞。rewind 把它们随
|
|
107
|
-
* 目标轮一起截断,重放按保留前缀续号即可自愈。
|
|
108
|
-
*/
|
|
109
104
|
function precedingContentIndex(turns, turnIndex) {
|
|
110
105
|
let index = turnIndex - 1;
|
|
111
106
|
while (index >= 0) {
|
|
@@ -187,7 +182,8 @@ function editPlan(operation, turns) {
|
|
|
187
182
|
edited,
|
|
188
183
|
...sameTurnFollowups,
|
|
189
184
|
...later
|
|
190
|
-
]
|
|
185
|
+
],
|
|
186
|
+
targetSeq: event.seq
|
|
191
187
|
};
|
|
192
188
|
}
|
|
193
189
|
if (!turn.closed) throw new SessionBranchError("未闭合轮次的助手消息不可编辑。", "INVALID_BOUNDARY");
|
|
@@ -212,7 +208,8 @@ function editPlan(operation, turns) {
|
|
|
212
208
|
user: cloneUser(turn.user.data),
|
|
213
209
|
assistant: assistantReplacement(event, operation.blockIndex, operation.text)
|
|
214
210
|
},
|
|
215
|
-
queuedUsers: operation.cascade === "preserve" ? downstreamUsers(turns, turnIndex + 1) : []
|
|
211
|
+
queuedUsers: operation.cascade === "preserve" ? downstreamUsers(turns, turnIndex + 1) : [],
|
|
212
|
+
targetSeq: event.seq
|
|
216
213
|
};
|
|
217
214
|
}
|
|
218
215
|
function retryPlan(operation, turns) {
|
|
@@ -227,7 +224,8 @@ function retryPlan(operation, turns) {
|
|
|
227
224
|
targetTurn: turn.turn,
|
|
228
225
|
targetEventSeq: turn.user.seq
|
|
229
226
|
}),
|
|
230
|
-
queuedUsers: operation.cascade === "preserve" ? downstreamUsers(turns, turnIndex) : turn.users.map((user) => cloneUser(user.data))
|
|
227
|
+
queuedUsers: operation.cascade === "preserve" ? downstreamUsers(turns, turnIndex) : turn.users.map((user) => cloneUser(user.data)),
|
|
228
|
+
targetSeq: turn.user.seq
|
|
231
229
|
};
|
|
232
230
|
}
|
|
233
231
|
function rerollPlan(operation, turns) {
|
|
@@ -244,10 +242,146 @@ function rerollPlan(operation, turns) {
|
|
|
244
242
|
targetTurn: turn.turn,
|
|
245
243
|
targetEventSeq: target.seq
|
|
246
244
|
}),
|
|
247
|
-
queuedUsers: turn.users.map((user) => cloneUser(user.data))
|
|
245
|
+
queuedUsers: turn.users.map((user) => cloneUser(user.data)),
|
|
246
|
+
targetSeq: target.seq
|
|
248
247
|
};
|
|
249
248
|
}
|
|
250
249
|
throw new SessionBranchError("当前会话没有可重生成的已落定助手回复。", "INVALID_BOUNDARY");
|
|
251
250
|
}
|
|
251
|
+
const COMPACTION_TYPES = /* @__PURE__ */ new Set([
|
|
252
|
+
"compaction/start",
|
|
253
|
+
"compaction/summary",
|
|
254
|
+
"compaction/end"
|
|
255
|
+
]);
|
|
256
|
+
function compactionTypeOf(event) {
|
|
257
|
+
return COMPACTION_TYPES.has(event.type) ? event.type : void 0;
|
|
258
|
+
}
|
|
259
|
+
function isCompactionCheckpoint(event) {
|
|
260
|
+
if (event.type !== "user/message") return false;
|
|
261
|
+
const op = event.surfaceOp;
|
|
262
|
+
if (typeof op !== "object" || op === null) return false;
|
|
263
|
+
const source = event.data.source;
|
|
264
|
+
return source.kind === "plugin" && source.plugin === "compact";
|
|
265
|
+
}
|
|
266
|
+
function compactionBrackets(events) {
|
|
267
|
+
const brackets = [];
|
|
268
|
+
let open;
|
|
269
|
+
for (const event of events) {
|
|
270
|
+
const type = compactionTypeOf(event);
|
|
271
|
+
if (type === "compaction/start") {
|
|
272
|
+
open = { start: event };
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (open === void 0) continue;
|
|
276
|
+
if (type === "compaction/summary") {
|
|
277
|
+
open.summary = event;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (type === "compaction/end") {
|
|
281
|
+
if (open.checkpoint !== void 0) brackets.push({
|
|
282
|
+
start: open.start,
|
|
283
|
+
...open.summary === void 0 ? {} : { summary: open.summary },
|
|
284
|
+
checkpoint: open.checkpoint,
|
|
285
|
+
end: event
|
|
286
|
+
});
|
|
287
|
+
open = void 0;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (isCompactionCheckpoint(event)) open.checkpoint = event;
|
|
291
|
+
}
|
|
292
|
+
return brackets;
|
|
293
|
+
}
|
|
294
|
+
function droppedCompactions(events, keepFrom, targetSeq) {
|
|
295
|
+
return compactionBrackets(events).filter((bracket) => bracket.start.seq >= keepFrom && bracket.end.seq < targetSeq);
|
|
296
|
+
}
|
|
297
|
+
function replacementRange(event) {
|
|
298
|
+
const op = event.surfaceOp;
|
|
299
|
+
if (op?.op !== "replace") return void 0;
|
|
300
|
+
if (typeof op.startSeq !== "number" || typeof op.endSeq !== "number") return void 0;
|
|
301
|
+
return {
|
|
302
|
+
start: op.startSeq,
|
|
303
|
+
end: op.endSeq
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function numberList(value) {
|
|
307
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "number") : [];
|
|
308
|
+
}
|
|
309
|
+
function restoreCompactions(brackets, keepFrom, base) {
|
|
310
|
+
const moved = /* @__PURE__ */ new Map();
|
|
311
|
+
const resolve = (seq) => seq < keepFrom ? seq : moved.get(seq);
|
|
312
|
+
const resolveAll = (seqs) => {
|
|
313
|
+
const resolved = [];
|
|
314
|
+
for (const seq of seqs) {
|
|
315
|
+
const next = resolve(seq);
|
|
316
|
+
if (next === void 0) return void 0;
|
|
317
|
+
resolved.push(next);
|
|
318
|
+
}
|
|
319
|
+
return resolved;
|
|
320
|
+
};
|
|
321
|
+
const restored = [];
|
|
322
|
+
for (const bracket of brackets) {
|
|
323
|
+
const range = replacementRange(bracket.checkpoint);
|
|
324
|
+
const shadowedSeqs = resolveAll(numberList((bracket.summary?.data)?.shadowedSeqs));
|
|
325
|
+
const start = range === void 0 ? void 0 : resolve(range.start);
|
|
326
|
+
const end = range === void 0 ? void 0 : resolve(range.end);
|
|
327
|
+
if (start === void 0 || end === void 0 || shadowedSeqs === void 0) continue;
|
|
328
|
+
const at = base + restored.length;
|
|
329
|
+
const summary = bracket.summary;
|
|
330
|
+
const checkpointSeq = at + (summary === void 0 ? 1 : 2);
|
|
331
|
+
moved.set(bracket.start.seq, at);
|
|
332
|
+
if (summary !== void 0) moved.set(summary.seq, at + 1);
|
|
333
|
+
moved.set(bracket.checkpoint.seq, checkpointSeq);
|
|
334
|
+
moved.set(bracket.end.seq, checkpointSeq + 1);
|
|
335
|
+
const sources = [
|
|
336
|
+
at,
|
|
337
|
+
...summary === void 0 ? [] : [at + 1],
|
|
338
|
+
...shadowedSeqs
|
|
339
|
+
];
|
|
340
|
+
restored.push(standaloneCompaction(bracket.start, at), ...summary === void 0 ? [] : [meteringShadowPrice(summary, at + 1, {
|
|
341
|
+
start,
|
|
342
|
+
end
|
|
343
|
+
}, shadowedSeqs)], replacementCheckpoint(bracket.checkpoint, checkpointSeq, {
|
|
344
|
+
start,
|
|
345
|
+
end
|
|
346
|
+
}, sources), standaloneCompaction(bracket.end, checkpointSeq + 1));
|
|
347
|
+
}
|
|
348
|
+
return restored;
|
|
349
|
+
}
|
|
350
|
+
function standaloneCompaction(event, seq) {
|
|
351
|
+
return {
|
|
352
|
+
...event,
|
|
353
|
+
seq: SessionSeq(seq),
|
|
354
|
+
data: {
|
|
355
|
+
...event.data,
|
|
356
|
+
turn: null
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function meteringShadowPrice(event, seq, range, shadowedSeqs) {
|
|
361
|
+
return {
|
|
362
|
+
...event,
|
|
363
|
+
seq: SessionSeq(seq),
|
|
364
|
+
data: {
|
|
365
|
+
...event.data,
|
|
366
|
+
shadowedRange: {
|
|
367
|
+
start: range.start,
|
|
368
|
+
end: range.end
|
|
369
|
+
},
|
|
370
|
+
shadowedSeqs: [...shadowedSeqs]
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function replacementCheckpoint(event, seq, range, sources) {
|
|
375
|
+
return {
|
|
376
|
+
...event,
|
|
377
|
+
seq: SessionSeq(seq),
|
|
378
|
+
surfaceOp: {
|
|
379
|
+
op: "replace",
|
|
380
|
+
startSeq: range.start,
|
|
381
|
+
endSeq: range.end
|
|
382
|
+
},
|
|
383
|
+
sourceEventSeqs: [...sources]
|
|
384
|
+
};
|
|
385
|
+
}
|
|
252
386
|
//#endregion
|
|
253
|
-
export { closedTurns, downstreamUsers, editPlan, editableMessages, precedingContentIndex, recallBoundary, rerollPlan, retryPlan, retryableTurns };
|
|
387
|
+
export { closedTurns, downstreamUsers, droppedCompactions, editPlan, editableMessages, precedingContentIndex, recallBoundary, rerollPlan, restoreCompactions, retryPlan, retryableTurns };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/shared.ts
|
|
2
|
+
const SESSION_EDITOR_PATH = "/session-editor";
|
|
3
|
+
function toTimelinePayload(sessionId, timeline, messages, retryableTurns) {
|
|
4
|
+
const currentPath = /* @__PURE__ */ new Set();
|
|
5
|
+
for (const node of timeline.nodes) currentPath.add(String(node.sessionId));
|
|
6
|
+
const versions = timeline.nodes.map((node) => ({
|
|
7
|
+
sessionId: String(node.sessionId),
|
|
8
|
+
...node.parentSessionId === void 0 ? {} : { parentSessionId: String(node.parentSessionId) },
|
|
9
|
+
...node.effect === void 0 ? {} : {
|
|
10
|
+
effectId: node.effect.id,
|
|
11
|
+
inverseSessionId: String(node.inverseSessionId),
|
|
12
|
+
operation: node.effect.operation,
|
|
13
|
+
cascade: node.effect.cascade,
|
|
14
|
+
targetTurn: node.effect.targetTurn,
|
|
15
|
+
...node.effect.blockKind === void 0 ? {} : { blockKind: node.effect.blockKind },
|
|
16
|
+
...node.effect.before === void 0 ? {} : { before: node.effect.before },
|
|
17
|
+
...node.effect.after === void 0 ? {} : { after: node.effect.after }
|
|
18
|
+
},
|
|
19
|
+
createdAt: node.createdAt,
|
|
20
|
+
depth: depthOf(timeline, node.sessionId),
|
|
21
|
+
current: String(node.sessionId) === String(sessionId),
|
|
22
|
+
onCurrentEffectPath: currentPath.has(String(node.sessionId))
|
|
23
|
+
}));
|
|
24
|
+
const versionsById = new Map(versions.map((version) => [version.sessionId, version]));
|
|
25
|
+
const undoStack = [];
|
|
26
|
+
let cursor = versionsById.get(String(sessionId));
|
|
27
|
+
while (cursor?.inverseSessionId !== void 0) {
|
|
28
|
+
if (undoStack.includes(cursor.inverseSessionId)) break;
|
|
29
|
+
undoStack.push(cursor.inverseSessionId);
|
|
30
|
+
cursor = versionsById.get(cursor.inverseSessionId);
|
|
31
|
+
}
|
|
32
|
+
const redoSessionIds = versions.filter((version) => version.inverseSessionId === String(sessionId)).map((version) => version.sessionId);
|
|
33
|
+
return {
|
|
34
|
+
sessionId: String(sessionId),
|
|
35
|
+
messages,
|
|
36
|
+
retryableTurns,
|
|
37
|
+
versions,
|
|
38
|
+
undoStack,
|
|
39
|
+
redoSessionIds
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function depthOf(timeline, sessionId) {
|
|
43
|
+
const byId = new Map(timeline.nodes.map((node) => [String(node.sessionId), node]));
|
|
44
|
+
let depth = 0;
|
|
45
|
+
let cursor = byId.get(String(sessionId));
|
|
46
|
+
const seen = /* @__PURE__ */ new Set();
|
|
47
|
+
while (cursor?.parentSessionId !== void 0 && !seen.has(String(cursor.sessionId))) {
|
|
48
|
+
seen.add(String(cursor.sessionId));
|
|
49
|
+
depth += 1;
|
|
50
|
+
cursor = byId.get(String(cursor.parentSessionId));
|
|
51
|
+
}
|
|
52
|
+
return depth;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { toTimelinePayload as n, SESSION_EDITOR_PATH as t };
|