@morlay/ui-conversation-message-actions 0.0.19-alpha.3 → 0.0.19-alpha.4
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 +4 -3
- package/dist/client.cjs +39 -179
- package/dist/index.d.cts +3 -6
- package/dist/index.d.mts +3 -6
- package/dist/index.mjs +8 -86
- package/dist/{plan-CT_6Y1fD.d.cts → plan-BKgGPZdD.d.mts} +2 -3
- package/dist/{plan-Cm9hCord.d.mts → plan-BUTplrpz.d.cts} +2 -3
- package/dist/plan.d.cts +1 -1
- package/dist/plan.d.mts +1 -1
- package/dist/plan.mjs +2 -49
- package/dist/shared-BBbOTwy4.mjs +4 -0
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.mts +2 -2
- package/dist/testing.mjs +582 -199
- package/package.json +6 -6
- package/src/client/chat-node/MessageItem.tsx +6 -3
- package/src/client/controller.ts +58 -221
- package/src/client/index.ts +0 -4
- package/src/index.ts +5 -143
- package/src/plan.ts +2 -54
- package/src/shared.ts +1 -96
- package/src/testing.ts +0 -2
- package/src/types.ts +1 -3
- package/dist/shared-LK3nImWW.mjs +0 -55
package/src/plan.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import type { AssistantMessage, ContentBlock, UserMessage } from "@deepseek-ai/dsh-llm";
|
|
3
3
|
import { SessionSeq } from "@deepseek-ai/dsh-session";
|
|
4
|
-
import type { SessionEvent
|
|
5
|
-
import {
|
|
6
|
-
SESSION_BRANCH_VERSION_SCHEMA,
|
|
7
|
-
SessionBranchError,
|
|
8
|
-
type EditableBlockKind,
|
|
9
|
-
type SessionBranchEffect,
|
|
10
|
-
type SessionBranchVersionEvent,
|
|
11
|
-
} from "@morlay/session-branch";
|
|
4
|
+
import type { SessionEvent } from "@deepseek-ai/dsh-session";
|
|
5
|
+
import { SessionBranchError } from "@morlay/session-branch";
|
|
12
6
|
import type {
|
|
13
7
|
EditOperation,
|
|
14
8
|
EditableMessageBlock,
|
|
@@ -34,7 +28,6 @@ export interface OperationPlan {
|
|
|
34
28
|
anchorSeq: number;
|
|
35
29
|
|
|
36
30
|
rewindBoundary?: number;
|
|
37
|
-
version: SessionBranchVersionEvent;
|
|
38
31
|
|
|
39
32
|
manualTurn?: { turn: number; user: UserMessage; assistant: AssistantMessage };
|
|
40
33
|
|
|
@@ -220,17 +213,6 @@ function assistantReplacement(
|
|
|
220
213
|
}) as AssistantMessage;
|
|
221
214
|
}
|
|
222
215
|
|
|
223
|
-
function pairVersionEffect(
|
|
224
|
-
sourceSessionId: SessionId,
|
|
225
|
-
effect: Omit<SessionBranchEffect, "id">,
|
|
226
|
-
): SessionBranchVersionEvent {
|
|
227
|
-
return {
|
|
228
|
-
schemaVersion: SESSION_BRANCH_VERSION_SCHEMA,
|
|
229
|
-
effect: { ...effect, id: randomUUID() },
|
|
230
|
-
inverse: { kind: "restore-version", sessionId: sourceSessionId },
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
216
|
export function editPlan(operation: EditOperation, turns: readonly ClosedTurn[]): OperationPlan {
|
|
235
217
|
const turnIndex = turns.findIndex(
|
|
236
218
|
(turn) =>
|
|
@@ -262,16 +244,6 @@ export function editPlan(operation: EditOperation, turns: readonly ClosedTurn[])
|
|
|
262
244
|
anchorSeq: turn.startSeq,
|
|
263
245
|
|
|
264
246
|
...(userIndex === 0 ? {} : { rewindBoundary: event.seq }),
|
|
265
|
-
version: pairVersionEffect(operation.sessionId, {
|
|
266
|
-
operation: "edit",
|
|
267
|
-
cascade: operation.cascade,
|
|
268
|
-
targetTurn: turn.turn,
|
|
269
|
-
targetEventSeq: event.seq,
|
|
270
|
-
targetBlockIndex: operation.blockIndex,
|
|
271
|
-
blockKind: "user",
|
|
272
|
-
before: before.text,
|
|
273
|
-
after: operation.text,
|
|
274
|
-
}),
|
|
275
247
|
queuedUsers: [edited, ...sameTurnFollowups, ...later],
|
|
276
248
|
targetSeq: event.seq,
|
|
277
249
|
};
|
|
@@ -282,22 +254,10 @@ export function editPlan(operation: EditOperation, turns: readonly ClosedTurn[])
|
|
|
282
254
|
const before = event.data.message.content[operation.blockIndex];
|
|
283
255
|
if (!isTextualBlock(before))
|
|
284
256
|
throw new SessionBranchError("所选助手消息块不是文本或思考。", "INVALID_BOUNDARY");
|
|
285
|
-
const blockKind: EditableBlockKind =
|
|
286
|
-
before.type === "reasoning" ? "assistant.reasoning" : "assistant.response";
|
|
287
257
|
if (turn.user === undefined)
|
|
288
258
|
throw new SessionBranchError("所选助手消息没有可重建的用户输入。", "INVALID_BOUNDARY");
|
|
289
259
|
return {
|
|
290
260
|
anchorSeq: turn.startSeq,
|
|
291
|
-
version: pairVersionEffect(operation.sessionId, {
|
|
292
|
-
operation: "edit",
|
|
293
|
-
cascade: operation.cascade,
|
|
294
|
-
targetTurn: turn.turn,
|
|
295
|
-
targetEventSeq: event.seq,
|
|
296
|
-
targetBlockIndex: operation.blockIndex,
|
|
297
|
-
blockKind,
|
|
298
|
-
before: before.text,
|
|
299
|
-
after: operation.text,
|
|
300
|
-
}),
|
|
301
261
|
manualTurn: {
|
|
302
262
|
turn: turn.turn,
|
|
303
263
|
user: cloneUser(turn.user.data),
|
|
@@ -315,12 +275,6 @@ export function retryPlan(operation: RetryOperation, turns: readonly ClosedTurn[
|
|
|
315
275
|
throw new SessionBranchError("所选回合没有可重放的用户输入。", "INVALID_BOUNDARY");
|
|
316
276
|
return {
|
|
317
277
|
anchorSeq: turn.startSeq,
|
|
318
|
-
version: pairVersionEffect(operation.sessionId, {
|
|
319
|
-
operation: "retry",
|
|
320
|
-
cascade: operation.cascade,
|
|
321
|
-
targetTurn: turn.turn,
|
|
322
|
-
targetEventSeq: turn.user.seq,
|
|
323
|
-
}),
|
|
324
278
|
queuedUsers:
|
|
325
279
|
operation.cascade === "preserve"
|
|
326
280
|
? downstreamUsers(turns, turnIndex)
|
|
@@ -343,12 +297,6 @@ export function rerollPlan(
|
|
|
343
297
|
if (target === undefined) continue;
|
|
344
298
|
return {
|
|
345
299
|
anchorSeq: turn.startSeq,
|
|
346
|
-
version: pairVersionEffect(operation.sessionId, {
|
|
347
|
-
operation: "reroll",
|
|
348
|
-
cascade: "truncate",
|
|
349
|
-
targetTurn: turn.turn,
|
|
350
|
-
targetEventSeq: target.seq,
|
|
351
|
-
}),
|
|
352
300
|
queuedUsers: turn.users.map((user) => cloneUser(user.data)),
|
|
353
301
|
targetSeq: target.seq,
|
|
354
302
|
};
|
package/src/shared.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { SessionId } from "@deepseek-ai/dsh-session";
|
|
2
|
-
import type {
|
|
3
|
-
import type { VersionOperation } from "@morlay/session-branch";
|
|
2
|
+
import type { CascadePolicy } from "@morlay/session-branch";
|
|
4
3
|
|
|
5
4
|
export const SESSION_EDITOR_PATH = "/session-editor";
|
|
6
5
|
|
|
@@ -79,97 +78,3 @@ export interface RetryableTurn {
|
|
|
79
78
|
time: number;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
export interface VersionSummary {
|
|
83
|
-
sessionId: string;
|
|
84
|
-
parentSessionId?: string;
|
|
85
|
-
effectId?: string;
|
|
86
|
-
inverseSessionId?: string;
|
|
87
|
-
createdAt: number;
|
|
88
|
-
depth: number;
|
|
89
|
-
current: boolean;
|
|
90
|
-
onCurrentEffectPath: boolean;
|
|
91
|
-
operation?: VersionOperation;
|
|
92
|
-
cascade?: CascadePolicy;
|
|
93
|
-
targetTurn?: number;
|
|
94
|
-
blockKind?: EditableMessageBlock["kind"];
|
|
95
|
-
before?: string;
|
|
96
|
-
after?: string;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface SessionEditorTimeline {
|
|
100
|
-
sessionId: string;
|
|
101
|
-
messages: EditableMessageBlock[];
|
|
102
|
-
retryableTurns: RetryableTurn[];
|
|
103
|
-
versions: VersionSummary[];
|
|
104
|
-
|
|
105
|
-
undoStack: string[];
|
|
106
|
-
|
|
107
|
-
redoSessionIds: string[];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function toTimelinePayload(
|
|
111
|
-
sessionId: SessionId,
|
|
112
|
-
timeline: BranchTimeline,
|
|
113
|
-
messages: EditableMessageBlock[],
|
|
114
|
-
retryableTurns: RetryableTurn[],
|
|
115
|
-
): SessionEditorTimeline {
|
|
116
|
-
const currentPath = new Set<string>();
|
|
117
|
-
for (const node of timeline.nodes) currentPath.add(String(node.sessionId));
|
|
118
|
-
const versions: VersionSummary[] = timeline.nodes.map((node) => ({
|
|
119
|
-
sessionId: String(node.sessionId),
|
|
120
|
-
...(node.parentSessionId === undefined
|
|
121
|
-
? {}
|
|
122
|
-
: { parentSessionId: String(node.parentSessionId) }),
|
|
123
|
-
...(node.effect === undefined
|
|
124
|
-
? {}
|
|
125
|
-
: {
|
|
126
|
-
effectId: node.effect.id,
|
|
127
|
-
inverseSessionId: String(node.inverseSessionId),
|
|
128
|
-
operation: node.effect.operation,
|
|
129
|
-
cascade: node.effect.cascade,
|
|
130
|
-
targetTurn: node.effect.targetTurn,
|
|
131
|
-
...(node.effect.blockKind === undefined ? {} : { blockKind: node.effect.blockKind }),
|
|
132
|
-
...(node.effect.before === undefined ? {} : { before: node.effect.before }),
|
|
133
|
-
...(node.effect.after === undefined ? {} : { after: node.effect.after }),
|
|
134
|
-
}),
|
|
135
|
-
createdAt: node.createdAt,
|
|
136
|
-
depth: depthOf(timeline, node.sessionId),
|
|
137
|
-
current: String(node.sessionId) === String(sessionId),
|
|
138
|
-
onCurrentEffectPath: currentPath.has(String(node.sessionId)),
|
|
139
|
-
}));
|
|
140
|
-
const versionsById = new Map(versions.map((version) => [version.sessionId, version]));
|
|
141
|
-
const undoStack: string[] = [];
|
|
142
|
-
let cursor = versionsById.get(String(sessionId));
|
|
143
|
-
while (cursor?.inverseSessionId !== undefined) {
|
|
144
|
-
if (undoStack.includes(cursor.inverseSessionId)) break;
|
|
145
|
-
undoStack.push(cursor.inverseSessionId);
|
|
146
|
-
cursor = versionsById.get(cursor.inverseSessionId);
|
|
147
|
-
}
|
|
148
|
-
const redoSessionIds = versions
|
|
149
|
-
.filter((version) => version.inverseSessionId === String(sessionId))
|
|
150
|
-
.map((version) => version.sessionId);
|
|
151
|
-
return {
|
|
152
|
-
sessionId: String(sessionId),
|
|
153
|
-
messages,
|
|
154
|
-
retryableTurns,
|
|
155
|
-
versions,
|
|
156
|
-
undoStack,
|
|
157
|
-
redoSessionIds,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function depthOf(
|
|
162
|
-
timeline: BranchTimeline,
|
|
163
|
-
sessionId: import("@deepseek-ai/dsh-session").SessionId,
|
|
164
|
-
): number {
|
|
165
|
-
const byId = new Map(timeline.nodes.map((node) => [String(node.sessionId), node]));
|
|
166
|
-
let depth = 0;
|
|
167
|
-
let cursor = byId.get(String(sessionId));
|
|
168
|
-
const seen = new Set<string>();
|
|
169
|
-
while (cursor?.parentSessionId !== undefined && !seen.has(String(cursor.sessionId))) {
|
|
170
|
-
seen.add(String(cursor.sessionId));
|
|
171
|
-
depth += 1;
|
|
172
|
-
cursor = byId.get(String(cursor.parentSessionId));
|
|
173
|
-
}
|
|
174
|
-
return depth;
|
|
175
|
-
}
|
package/src/testing.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
type SessionHeader,
|
|
10
10
|
} from "@deepseek-ai/dsh-session";
|
|
11
11
|
import SessionProjectionRegistry from "@deepseek-ai/dsh-session-projection";
|
|
12
|
-
import { type BranchTimeline } from "@morlay/session-branch";
|
|
13
12
|
import SessionPersistenceSqlite from "@morlay/session-rdb";
|
|
14
13
|
import { parseJsonlArtifact } from "@morlay/session-rdb/artifact";
|
|
15
14
|
import { EmptySettings, meta, oneTurnLog } from "@morlay/session-rdb/testing";
|
|
@@ -17,7 +16,6 @@ import { SESSION_EDITOR_PATH } from "./shared.ts";
|
|
|
17
16
|
import { SessionEditor } from "@morlay/ui-conversation-message-actions";
|
|
18
17
|
|
|
19
18
|
export {
|
|
20
|
-
BranchTimeline,
|
|
21
19
|
SESSION_EDITOR_PATH,
|
|
22
20
|
Session,
|
|
23
21
|
SessionIdBrand,
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SessionId } from "@deepseek-ai/dsh-session";
|
|
2
|
-
import type {
|
|
2
|
+
import type { CascadePolicy } from "@morlay/session-branch";
|
|
3
3
|
|
|
4
4
|
export interface EditOperation {
|
|
5
5
|
action: "edit";
|
|
@@ -61,8 +61,6 @@ export interface SessionEditorResult {
|
|
|
61
61
|
live?: boolean;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export type SessionEditorTimeline = BranchTimeline;
|
|
65
|
-
|
|
66
64
|
export interface EditableMessageBlock {
|
|
67
65
|
key: string;
|
|
68
66
|
|
package/dist/shared-LK3nImWW.mjs
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
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 };
|