@morlay/ui-conversation-message-actions 0.0.10 → 0.0.12

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.
@@ -0,0 +1,13 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { InvariantInstaller } from "@deepseek-ai/dsh-invariants";
3
+
4
+ const PACKAGE_NAME = "@morlay/ui-conversation-message-actions";
5
+
6
+ export const name = "ui-conversation-message-actions-invariant";
7
+
8
+ export const inject = ["invariants"];
9
+
10
+ const install: InvariantInstaller = () => {};
11
+
12
+ export const apply = (ctx: Context): Promise<() => void> =>
13
+ Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
package/src/shared.ts ADDED
@@ -0,0 +1,167 @@
1
+ import type { SessionId } from "@deepseek-ai/dsh-session";
2
+ import type { BranchTimeline, CascadePolicy } from "@morlay/session-branch";
3
+ import type { VersionOperation } from "@morlay/session-branch";
4
+
5
+ export const SESSION_EDITOR_PATH = "/session-editor";
6
+
7
+ export type { VersionOperation } from "@morlay/session-branch";
8
+
9
+ export interface EditOperation {
10
+ action: "edit";
11
+ sessionId: SessionId;
12
+ eventSeq: number;
13
+ blockIndex: number;
14
+ text: string;
15
+ cascade: CascadePolicy;
16
+ }
17
+
18
+ export interface RerollOperation {
19
+ action: "reroll";
20
+ sessionId: SessionId;
21
+ }
22
+
23
+ export interface RetryOperation {
24
+ action: "retry";
25
+ sessionId: SessionId;
26
+ turn: number;
27
+ cascade: CascadePolicy;
28
+ }
29
+
30
+ export interface RewindOperation {
31
+ action: "rewind";
32
+ sessionId: SessionId;
33
+ toBoundary: number;
34
+ }
35
+
36
+ export interface ForkOperation {
37
+ action: "fork";
38
+ sessionId: SessionId;
39
+ atSeq?: number;
40
+ childSessionId?: SessionId;
41
+ }
42
+
43
+ export type SessionEditorOperation =
44
+ | EditOperation
45
+ | RerollOperation
46
+ | RetryOperation
47
+ | RewindOperation
48
+ | ForkOperation;
49
+
50
+ export interface SessionEditorOperationResult {
51
+ sessionId: SessionId;
52
+ queuedTurns: number;
53
+
54
+ live?: boolean;
55
+ }
56
+
57
+ export interface EditableMessageBlock {
58
+ key: string;
59
+ turn: number;
60
+ eventSeq: number;
61
+ blockIndex: number;
62
+ kind: "user" | "assistant.reasoning" | "assistant.response";
63
+ text: string;
64
+ time: number;
65
+ }
66
+
67
+ export interface RetryableTurn {
68
+ turn: number;
69
+ userEventSeq: number;
70
+ preview: string;
71
+ time: number;
72
+ }
73
+
74
+ export interface VersionSummary {
75
+ sessionId: string;
76
+ parentSessionId?: string;
77
+ effectId?: string;
78
+ inverseSessionId?: string;
79
+ createdAt: number;
80
+ depth: number;
81
+ current: boolean;
82
+ onCurrentEffectPath: boolean;
83
+ operation?: VersionOperation;
84
+ cascade?: CascadePolicy;
85
+ targetTurn?: number;
86
+ blockKind?: EditableMessageBlock["kind"];
87
+ before?: string;
88
+ after?: string;
89
+ }
90
+
91
+ export interface SessionEditorTimeline {
92
+ sessionId: string;
93
+ messages: EditableMessageBlock[];
94
+ retryableTurns: RetryableTurn[];
95
+ versions: VersionSummary[];
96
+
97
+ undoStack: string[];
98
+
99
+ redoSessionIds: string[];
100
+ }
101
+
102
+ export function toTimelinePayload(
103
+ sessionId: SessionId,
104
+ timeline: BranchTimeline,
105
+ messages: EditableMessageBlock[],
106
+ retryableTurns: RetryableTurn[],
107
+ ): SessionEditorTimeline {
108
+ const currentPath = new Set<string>();
109
+ for (const node of timeline.nodes) currentPath.add(String(node.sessionId));
110
+ const versions: VersionSummary[] = timeline.nodes.map((node) => ({
111
+ sessionId: String(node.sessionId),
112
+ ...(node.parentSessionId === undefined
113
+ ? {}
114
+ : { parentSessionId: String(node.parentSessionId) }),
115
+ ...(node.effect === undefined
116
+ ? {}
117
+ : {
118
+ effectId: node.effect.id,
119
+ inverseSessionId: String(node.inverseSessionId),
120
+ operation: node.effect.operation,
121
+ cascade: node.effect.cascade,
122
+ targetTurn: node.effect.targetTurn,
123
+ ...(node.effect.blockKind === undefined ? {} : { blockKind: node.effect.blockKind }),
124
+ ...(node.effect.before === undefined ? {} : { before: node.effect.before }),
125
+ ...(node.effect.after === undefined ? {} : { after: node.effect.after }),
126
+ }),
127
+ createdAt: node.createdAt,
128
+ depth: depthOf(timeline, node.sessionId),
129
+ current: String(node.sessionId) === String(sessionId),
130
+ onCurrentEffectPath: currentPath.has(String(node.sessionId)),
131
+ }));
132
+ const versionsById = new Map(versions.map((version) => [version.sessionId, version]));
133
+ const undoStack: string[] = [];
134
+ let cursor = versionsById.get(String(sessionId));
135
+ while (cursor?.inverseSessionId !== undefined) {
136
+ if (undoStack.includes(cursor.inverseSessionId)) break;
137
+ undoStack.push(cursor.inverseSessionId);
138
+ cursor = versionsById.get(cursor.inverseSessionId);
139
+ }
140
+ const redoSessionIds = versions
141
+ .filter((version) => version.inverseSessionId === String(sessionId))
142
+ .map((version) => version.sessionId);
143
+ return {
144
+ sessionId: String(sessionId),
145
+ messages,
146
+ retryableTurns,
147
+ versions,
148
+ undoStack,
149
+ redoSessionIds,
150
+ };
151
+ }
152
+
153
+ function depthOf(
154
+ timeline: BranchTimeline,
155
+ sessionId: import("@deepseek-ai/dsh-session").SessionId,
156
+ ): number {
157
+ const byId = new Map(timeline.nodes.map((node) => [String(node.sessionId), node]));
158
+ let depth = 0;
159
+ let cursor = byId.get(String(sessionId));
160
+ const seen = new Set<string>();
161
+ while (cursor?.parentSessionId !== undefined && !seen.has(String(cursor.sessionId))) {
162
+ seen.add(String(cursor.sessionId));
163
+ depth += 1;
164
+ cursor = byId.get(String(cursor.parentSessionId));
165
+ }
166
+ return depth;
167
+ }
package/src/types.ts ADDED
@@ -0,0 +1,73 @@
1
+ import type { SessionId } from "@deepseek-ai/dsh-session";
2
+ import type { BranchTimeline, CascadePolicy } from "@morlay/session-branch";
3
+
4
+ export interface EditOperation {
5
+ action: "edit";
6
+ sessionId: SessionId;
7
+
8
+ eventSeq: number;
9
+
10
+ blockIndex: number;
11
+
12
+ text: string;
13
+ cascade: CascadePolicy;
14
+ }
15
+
16
+ export interface RerollOperation {
17
+ action: "reroll";
18
+ sessionId: SessionId;
19
+ }
20
+
21
+ export interface RetryOperation {
22
+ action: "retry";
23
+ sessionId: SessionId;
24
+ turn: number;
25
+ cascade: CascadePolicy;
26
+ }
27
+
28
+ export interface RewindOperation {
29
+ action: "rewind";
30
+ sessionId: SessionId;
31
+ toBoundary: number;
32
+ }
33
+
34
+ export interface ForkOperation {
35
+ action: "fork";
36
+ sessionId: SessionId;
37
+ atSeq?: number;
38
+ childSessionId?: SessionId;
39
+ }
40
+
41
+ export type SessionEditorOperation =
42
+ | EditOperation
43
+ | RerollOperation
44
+ | RetryOperation
45
+ | RewindOperation
46
+ | ForkOperation;
47
+
48
+ export interface SessionEditorResult {
49
+ sessionId: SessionId;
50
+
51
+ queuedTurns: number;
52
+
53
+ live?: boolean;
54
+ }
55
+
56
+ export type SessionEditorTimeline = BranchTimeline;
57
+
58
+ export interface EditableMessageBlock {
59
+ key: string;
60
+ turn: number;
61
+ eventSeq: number;
62
+ blockIndex: number;
63
+ kind: "user" | "assistant.reasoning" | "assistant.response";
64
+ text: string;
65
+ time: number;
66
+ }
67
+
68
+ export interface RetryableTurn {
69
+ turn: number;
70
+ userEventSeq: number;
71
+ preview: string;
72
+ time: number;
73
+ }