@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/README.md
CHANGED
|
@@ -15,14 +15,15 @@
|
|
|
15
15
|
```ts
|
|
16
16
|
// host:装配后直接调服务
|
|
17
17
|
await ctx.sessionEditor.retry({ action: "retry", sessionId, turn: 2, cascade: "truncate" });
|
|
18
|
-
const
|
|
18
|
+
const result = await ctx.sessionEditor.retry({ sessionId, turn, cascade: "truncate" });
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
HTTP
|
|
21
|
+
HTTP 面:`POST /session-editor`(注册面与页面侧路径口径见
|
|
22
|
+
[设计 20260917-编排层操作语义](./.agents/designs/20260917-编排层操作语义.md))。
|
|
22
23
|
|
|
23
24
|
## 结论
|
|
24
25
|
|
|
25
|
-
edit / retry / reroll 就地重写**同一会话**(session id
|
|
26
|
+
edit / retry / reroll 就地重写**同一会话**(session id 不变),只有 `fork` 派生新 id;`recall` 只截断并把文本
|
|
26
27
|
交回 composer,由用户改后自己发
|
|
27
28
|
([ADR 就地编辑重写同一会话而非新建会话](./.agents/adrs/20260917-就地编辑重写同一会话而非新建会话.md))。
|
|
28
29
|
|
package/dist/client.cjs
CHANGED
|
@@ -4,176 +4,43 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
-
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
8
7
|
require("@morlay/dsh-client-ui-conversation/client");
|
|
9
8
|
let _morlay_dsh_client_ui_primitives_client = require("@morlay/dsh-client-ui-primitives/client");
|
|
10
9
|
let react = require("react");
|
|
11
10
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
12
11
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
13
12
|
let react_dom = require("react-dom");
|
|
14
|
-
//#region src/shared.ts
|
|
15
|
-
const SESSION_EDITOR_PATH = "/session-editor";
|
|
16
13
|
//#endregion
|
|
17
14
|
//#region src/client/controller.ts
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
function messageOf(error) {
|
|
22
|
-
return error instanceof Error ? error.message : String(error);
|
|
23
|
-
}
|
|
24
|
-
function conversationRevision(snapshot) {
|
|
25
|
-
return [
|
|
26
|
-
snapshot.openState,
|
|
27
|
-
snapshot.removed,
|
|
28
|
-
snapshot.hasMore
|
|
29
|
-
].join("|");
|
|
30
|
-
}
|
|
15
|
+
/** 编辑器的 HTTP 路径:宿主(web 与桌面)在同一张路由表上服务它,页面不再按 ownsHost 加前缀。 */
|
|
16
|
+
const EDITOR_API_PATH = "/session-editor";
|
|
31
17
|
var SessionEditorController = class {
|
|
32
18
|
sessionId;
|
|
33
|
-
store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
|
|
34
|
-
status: "idle",
|
|
35
|
-
error: null,
|
|
36
|
-
pending: null,
|
|
37
|
-
timeline: null
|
|
38
|
-
});
|
|
39
19
|
face;
|
|
40
|
-
ctx;
|
|
41
20
|
sessions;
|
|
42
|
-
|
|
43
|
-
sessionSource;
|
|
44
|
-
sessionSourceDispose;
|
|
45
|
-
sessionRevision;
|
|
46
|
-
disposed = false;
|
|
47
|
-
users = 0;
|
|
21
|
+
pending = null;
|
|
48
22
|
constructor(ctx, sessionId) {
|
|
49
23
|
this.sessionId = sessionId;
|
|
50
|
-
this.ctx = ctx;
|
|
51
24
|
this.sessions = ctx.get("sessions");
|
|
52
|
-
this.uiWorkspace = ctx.get("uiWorkspace");
|
|
53
25
|
this.face = {
|
|
54
|
-
hooks: { sessionEditor: this.store },
|
|
55
|
-
acquire: () => {
|
|
56
|
-
this.users += 1;
|
|
57
|
-
if (this.users === 1 && this.disposed) this.revive();
|
|
58
|
-
return () => this.release();
|
|
59
|
-
},
|
|
60
|
-
load: () => {
|
|
61
|
-
this.load();
|
|
62
|
-
},
|
|
63
|
-
edit: (message, text, cascade) => this.mutate({
|
|
64
|
-
action: "edit",
|
|
65
|
-
sessionId: this.sessionId,
|
|
66
|
-
eventSeq: message.eventSeq,
|
|
67
|
-
blockIndex: message.blockIndex,
|
|
68
|
-
text,
|
|
69
|
-
cascade
|
|
70
|
-
}),
|
|
71
26
|
retry: (turn, cascade) => this.mutate({
|
|
72
27
|
action: "retry",
|
|
73
28
|
sessionId: this.sessionId,
|
|
74
29
|
turn,
|
|
75
30
|
cascade
|
|
76
31
|
}),
|
|
77
|
-
|
|
78
|
-
action: "reroll",
|
|
79
|
-
sessionId: this.sessionId
|
|
80
|
-
}),
|
|
81
|
-
rewind: (toBoundary) => this.mutate({
|
|
82
|
-
action: "rewind",
|
|
83
|
-
sessionId: this.sessionId,
|
|
84
|
-
toBoundary
|
|
85
|
-
}),
|
|
86
|
-
recall: (message) => this.mutate({
|
|
32
|
+
recall: (message, texts) => this.mutate({
|
|
87
33
|
action: "recall",
|
|
88
34
|
sessionId: this.sessionId,
|
|
89
35
|
eventSeq: message.eventSeq
|
|
90
|
-
}, () => this.setComposerDraft(
|
|
91
|
-
openVersion: (sessionId) => {
|
|
92
|
-
this.uiWorkspace.openSession(sessionId);
|
|
93
|
-
return Promise.resolve();
|
|
94
|
-
}
|
|
36
|
+
}, () => this.setComposerDraft(texts.join("\n\n")))
|
|
95
37
|
};
|
|
96
|
-
this.observe();
|
|
97
|
-
}
|
|
98
|
-
observe() {
|
|
99
|
-
this.sessionSource = void 0;
|
|
100
|
-
this.sessionSourceDispose?.();
|
|
101
|
-
this.bindSessionSource();
|
|
102
|
-
this.sessions.list.subscribe(() => this.invalidate());
|
|
103
|
-
}
|
|
104
|
-
bindSessionSource() {
|
|
105
|
-
const source = this.sessions.binding(this.sessionId)?.session;
|
|
106
|
-
if (source === this.sessionSource) return;
|
|
107
|
-
this.sessionSourceDispose?.();
|
|
108
|
-
this.sessionSource = source;
|
|
109
|
-
this.sessionRevision = source === void 0 ? void 0 : conversationRevision(source.getSnapshot());
|
|
110
|
-
this.sessionSourceDispose = source?.subscribe(() => {
|
|
111
|
-
this.invalidate();
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
invalidate() {
|
|
115
|
-
if (this.disposed || this.store.getSnapshot().status === "idle") return;
|
|
116
|
-
this.load();
|
|
117
|
-
}
|
|
118
|
-
release() {
|
|
119
|
-
this.users -= 1;
|
|
120
|
-
if (this.users <= 0) this.dispose();
|
|
121
|
-
}
|
|
122
|
-
dispose() {
|
|
123
|
-
if (this.disposed) return;
|
|
124
|
-
this.disposed = true;
|
|
125
|
-
this.sessionSourceDispose?.();
|
|
126
|
-
this.sessionSourceDispose = void 0;
|
|
127
|
-
this.sessionSource = void 0;
|
|
128
|
-
this.sessionRevision = void 0;
|
|
129
|
-
}
|
|
130
|
-
revive() {
|
|
131
|
-
this.disposed = false;
|
|
132
|
-
this.observe();
|
|
133
|
-
this.load();
|
|
134
|
-
}
|
|
135
|
-
async load() {
|
|
136
|
-
if (this.disposed) return;
|
|
137
|
-
this.store.update((state) => {
|
|
138
|
-
state.status = "loading";
|
|
139
|
-
state.error = null;
|
|
140
|
-
});
|
|
141
|
-
try {
|
|
142
|
-
const response = await fetch(`${editorApiPath()}?sessionId=${encodeURIComponent(this.sessionId)}`, {
|
|
143
|
-
method: "GET",
|
|
144
|
-
headers: { accept: "application/json" },
|
|
145
|
-
cache: "no-store"
|
|
146
|
-
});
|
|
147
|
-
const value = await response.json();
|
|
148
|
-
if (this.disposed) return;
|
|
149
|
-
if (response.ok) this.store.update((state) => {
|
|
150
|
-
state.status = "ready";
|
|
151
|
-
state.error = null;
|
|
152
|
-
state.timeline = value;
|
|
153
|
-
});
|
|
154
|
-
else {
|
|
155
|
-
const error = value["error"];
|
|
156
|
-
this.store.update((state) => {
|
|
157
|
-
state.status = "error";
|
|
158
|
-
state.error = typeof error === "string" ? error : `请求失败:HTTP ${String(response.status)}`;
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
} catch (error) {
|
|
162
|
-
if (this.disposed) return;
|
|
163
|
-
this.store.update((state) => {
|
|
164
|
-
state.status = "error";
|
|
165
|
-
state.error = messageOf(error);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
38
|
}
|
|
169
39
|
async mutate(operation, onApplied) {
|
|
170
|
-
if (this.
|
|
171
|
-
this.
|
|
172
|
-
state.pending = operation.action;
|
|
173
|
-
state.error = null;
|
|
174
|
-
});
|
|
40
|
+
if (this.pending !== null) return false;
|
|
41
|
+
this.pending = operation.action;
|
|
175
42
|
try {
|
|
176
|
-
const response = await fetch(
|
|
43
|
+
const response = await fetch(EDITOR_API_PATH, {
|
|
177
44
|
method: "POST",
|
|
178
45
|
headers: {
|
|
179
46
|
accept: "application/json",
|
|
@@ -182,54 +49,48 @@ window.__ModuleLoader__.load({
|
|
|
182
49
|
body: JSON.stringify(operation)
|
|
183
50
|
});
|
|
184
51
|
const value = await response.json();
|
|
185
|
-
if (this.disposed) return true;
|
|
186
52
|
if (!response.ok) {
|
|
187
53
|
const error = value["error"];
|
|
188
54
|
throw new Error(typeof error === "string" ? error : `请求失败:HTTP ${String(response.status)}`);
|
|
189
55
|
}
|
|
190
|
-
this.store.update((state) => {
|
|
191
|
-
state.pending = null;
|
|
192
|
-
});
|
|
193
56
|
onApplied?.();
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
57
|
+
try {
|
|
58
|
+
await this.rebuildWindow();
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.warn("[session-editor] 操作已生效,但会话窗口重建失败:", error);
|
|
198
61
|
}
|
|
199
|
-
const face = this.sessions.binding(this.sessionId)?.session;
|
|
200
|
-
const resync = face.resync;
|
|
201
|
-
if (resync !== void 0) try {
|
|
202
|
-
await resync.call(face);
|
|
203
|
-
const projections = face.projections;
|
|
204
|
-
if (typeof projections?.truncate !== "function") {
|
|
205
|
-
location.reload();
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
projections.truncate(-1);
|
|
209
|
-
this.load();
|
|
210
|
-
return true;
|
|
211
|
-
} catch {}
|
|
212
|
-
location.reload();
|
|
213
62
|
return true;
|
|
214
|
-
} catch
|
|
215
|
-
if (this.disposed) return false;
|
|
216
|
-
this.store.update((state) => {
|
|
217
|
-
state.pending = null;
|
|
218
|
-
state.error = messageOf(error);
|
|
219
|
-
});
|
|
63
|
+
} catch {
|
|
220
64
|
return false;
|
|
65
|
+
} finally {
|
|
66
|
+
this.pending = null;
|
|
221
67
|
}
|
|
222
68
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
69
|
+
/**
|
|
70
|
+
* 让上游重开该会话的历史窗口(rewind 之后客户端窗口的 seq 基线已经失效)。
|
|
71
|
+
*
|
|
72
|
+
* 探测顺序:`binding(id).session.resync()`(上游 ClientSession 的重建入口,类型面没暴露)
|
|
73
|
+
* → `sessions.refresh()`(只刷列表元数据,聊胜于无)→ 都没有就记一条 warn。
|
|
74
|
+
*/
|
|
75
|
+
async rebuildWindow() {
|
|
76
|
+
const sessions = this.sessions;
|
|
77
|
+
const face = sessions.binding?.(this.sessionId)?.session;
|
|
78
|
+
const resync = face?.resync;
|
|
79
|
+
if (typeof resync === "function") {
|
|
80
|
+
await resync.call(face);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (typeof sessions.refresh === "function") {
|
|
84
|
+
await sessions.refresh();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.warn("[session-editor] 未找到会话窗口重建入口(binding.resync / refresh 都不可用),窗口可能停留在 rewind 之前的状态");
|
|
227
88
|
}
|
|
228
|
-
setComposerDraft(
|
|
89
|
+
setComposerDraft(text) {
|
|
229
90
|
if (this.sessions.binding(this.sessionId) === void 0) return;
|
|
230
91
|
const scoped = this.sessions.scope(this.sessionId);
|
|
231
92
|
if (scoped === void 0) return;
|
|
232
|
-
scoped.get("conversation")?.input?.for(scoped).restoreDraft(
|
|
93
|
+
scoped.get("conversation")?.input?.for(scoped).restoreDraft(text);
|
|
233
94
|
}
|
|
234
95
|
};
|
|
235
96
|
//#endregion
|
|
@@ -710,6 +571,7 @@ window.__ModuleLoader__.load({
|
|
|
710
571
|
}
|
|
711
572
|
return {
|
|
712
573
|
text: texts.join("\n\n"),
|
|
574
|
+
texts,
|
|
713
575
|
images,
|
|
714
576
|
rest
|
|
715
577
|
};
|
|
@@ -744,6 +606,7 @@ window.__ModuleLoader__.load({
|
|
|
744
606
|
}
|
|
745
607
|
const UserMessageNodeView = (0, react.memo)(function UserMessageNodeView({ node, renderMessageImages, t, openFile, openSkill, recall, retry }) {
|
|
746
608
|
const data = node.data;
|
|
609
|
+
const recallTexts = contentParts(data.content).texts;
|
|
747
610
|
const [confirmingRecall, setConfirmingRecall] = (0, react.useState)(null);
|
|
748
611
|
const [confirmingRetry, setConfirmingRetry] = (0, react.useState)(false);
|
|
749
612
|
const turnLocation = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn : void 0;
|
|
@@ -783,7 +646,7 @@ window.__ModuleLoader__.load({
|
|
|
783
646
|
onClick: () => {
|
|
784
647
|
const target = confirmingRecall;
|
|
785
648
|
setConfirmingRecall(null);
|
|
786
|
-
recall(target);
|
|
649
|
+
recall(target, recallTexts);
|
|
787
650
|
},
|
|
788
651
|
children: "撤回并编辑"
|
|
789
652
|
})]
|
|
@@ -1366,9 +1229,6 @@ window.__ModuleLoader__.load({
|
|
|
1366
1229
|
}
|
|
1367
1230
|
return controller;
|
|
1368
1231
|
};
|
|
1369
|
-
ctx.on("connection/reset", () => {
|
|
1370
|
-
for (const controller of controllers.values()) controller.load();
|
|
1371
|
-
});
|
|
1372
1232
|
registerChatNodeRenderers(ctx, controllerFor);
|
|
1373
1233
|
ctx.slots.inject("conversation.composer.dock", () => registerComposerStats(ctx.slots));
|
|
1374
1234
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as SessionEditorResult, S as SessionEditorOperation, _ as RecallOperation, b as RetryableTurn, c as editableMessages, g as EditableMessageBlock, h as EditOperation, i as closedTurns, m as retryableTurns, v as RerollOperation, x as RewindOperation, y as RetryOperation } from "./plan-
|
|
1
|
+
import { C as SessionEditorResult, S as SessionEditorOperation, _ as RecallOperation, b as RetryableTurn, c as editableMessages, g as EditableMessageBlock, h as EditOperation, i as closedTurns, m as retryableTurns, v as RerollOperation, x as RewindOperation, y as RetryOperation } from "./plan-BUTplrpz.cjs";
|
|
2
2
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
3
3
|
import { UserMessage } from "@deepseek-ai/dsh-llm";
|
|
4
4
|
import { AgentCancelCause, Session, SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
5
|
-
import { BranchBoundary,
|
|
5
|
+
import { BranchBoundary, CascadePolicy, EditableBlockKind } from "@morlay/session-branch";
|
|
6
6
|
//#region src/index.d.ts
|
|
7
7
|
declare module "@deepseek-ai/cordis" {
|
|
8
8
|
interface Context {
|
|
@@ -56,13 +56,10 @@ declare class SessionEditor extends Service {
|
|
|
56
56
|
agentPreset?: string;
|
|
57
57
|
}, signal?: AbortSignal): Promise<SessionId>;
|
|
58
58
|
rewind(id: SessionId, toBoundary: number, signal?: AbortSignal): Promise<import("@deepseek-ai/dsh-session-persistence").SessionPersistenceSnapshot>;
|
|
59
|
-
timeline(sessionId: SessionId, signal?: AbortSignal): Promise<BranchTimeline$1>;
|
|
60
59
|
edit(operation: EditOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
61
60
|
reroll(operation: RerollOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
62
61
|
retry(operation: RetryOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
63
62
|
recall(operation: RecallOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
64
|
-
editableMessages(sessionId: SessionId, signal?: AbortSignal): Promise<EditableMessageBlock[]>;
|
|
65
|
-
retryableTurns(sessionId: SessionId, signal?: AbortSignal): Promise<RetryableTurn[]>;
|
|
66
63
|
private branchOperation;
|
|
67
64
|
private recallOperation;
|
|
68
65
|
private seedStart;
|
|
@@ -72,4 +69,4 @@ declare class SessionEditor extends Service {
|
|
|
72
69
|
private prepareReplay;
|
|
73
70
|
}
|
|
74
71
|
//#endregion
|
|
75
|
-
export { type
|
|
72
|
+
export { type CascadePolicy, type EditOperation, type EditableBlockKind, type EditableMessageBlock, EditorAgent, EditorAgentHandle, EditorAgentRegistry, type RecallOperation, type RerollOperation, type RetryOperation, type RetryableTurn, type RewindOperation, SessionEditor, SessionEditor as default, type SessionEditorOperation, type SessionEditorResult, closedTurns, editableMessages, retryableTurns };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { C as SessionEditorResult, S as SessionEditorOperation, _ as RecallOperation, b as RetryableTurn, c as editableMessages, g as EditableMessageBlock, h as EditOperation, i as closedTurns, m as retryableTurns, v as RerollOperation, x as RewindOperation, y as RetryOperation } from "./plan-
|
|
1
|
+
import { C as SessionEditorResult, S as SessionEditorOperation, _ as RecallOperation, b as RetryableTurn, c as editableMessages, g as EditableMessageBlock, h as EditOperation, i as closedTurns, m as retryableTurns, v as RerollOperation, x as RewindOperation, y as RetryOperation } from "./plan-BKgGPZdD.mjs";
|
|
2
2
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
3
3
|
import { AgentCancelCause, Session, SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
4
|
-
import { BranchBoundary,
|
|
4
|
+
import { BranchBoundary, CascadePolicy, EditableBlockKind } from "@morlay/session-branch";
|
|
5
5
|
import { UserMessage } from "@deepseek-ai/dsh-llm";
|
|
6
6
|
//#region src/index.d.ts
|
|
7
7
|
declare module "@deepseek-ai/cordis" {
|
|
@@ -56,13 +56,10 @@ declare class SessionEditor extends Service {
|
|
|
56
56
|
agentPreset?: string;
|
|
57
57
|
}, signal?: AbortSignal): Promise<SessionId>;
|
|
58
58
|
rewind(id: SessionId, toBoundary: number, signal?: AbortSignal): Promise<import("@deepseek-ai/dsh-session-persistence").SessionPersistenceSnapshot>;
|
|
59
|
-
timeline(sessionId: SessionId, signal?: AbortSignal): Promise<BranchTimeline$1>;
|
|
60
59
|
edit(operation: EditOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
61
60
|
reroll(operation: RerollOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
62
61
|
retry(operation: RetryOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
63
62
|
recall(operation: RecallOperation, signal?: AbortSignal): Promise<SessionEditorResult>;
|
|
64
|
-
editableMessages(sessionId: SessionId, signal?: AbortSignal): Promise<EditableMessageBlock[]>;
|
|
65
|
-
retryableTurns(sessionId: SessionId, signal?: AbortSignal): Promise<RetryableTurn[]>;
|
|
66
63
|
private branchOperation;
|
|
67
64
|
private recallOperation;
|
|
68
65
|
private seedStart;
|
|
@@ -72,4 +69,4 @@ declare class SessionEditor extends Service {
|
|
|
72
69
|
private prepareReplay;
|
|
73
70
|
}
|
|
74
71
|
//#endregion
|
|
75
|
-
export { type
|
|
72
|
+
export { type CascadePolicy, type EditOperation, type EditableBlockKind, type EditableMessageBlock, EditorAgent, EditorAgentHandle, EditorAgentRegistry, type RecallOperation, type RerollOperation, type RetryOperation, type RetryableTurn, type RewindOperation, SessionEditor, SessionEditor as default, type SessionEditorOperation, type SessionEditorResult, closedTurns, editableMessages, retryableTurns };
|
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as SESSION_EDITOR_PATH } from "./shared-BBbOTwy4.mjs";
|
|
2
2
|
import { closedTurns, droppedCompactions, editPlan, editableMessages, precedingContentIndex, recallBoundary, rerollPlan, restoreCompactions, retryPlan, retryableTurns } from "./plan.mjs";
|
|
3
3
|
import { Service } from "@deepseek-ai/cordis";
|
|
4
4
|
import { SessionSeq } from "@deepseek-ai/dsh-session";
|
|
5
|
-
import {
|
|
5
|
+
import { SessionBranchError, balanceRewindPrefix } from "@morlay/session-branch";
|
|
6
6
|
//#region src/index.ts
|
|
7
|
-
function appendLogSeedEvent(events, type, data
|
|
7
|
+
function appendLogSeedEvent(events, type, data) {
|
|
8
8
|
events.push({
|
|
9
9
|
type,
|
|
10
10
|
seq: events.length,
|
|
11
11
|
time: Date.now(),
|
|
12
|
-
data
|
|
13
|
-
...ignorable ? { ignorable: true } : {}
|
|
12
|
+
data
|
|
14
13
|
});
|
|
15
14
|
}
|
|
16
15
|
function appendSurfaceSeedEvent(events, type, data, intent) {
|
|
@@ -50,22 +49,8 @@ function keepFromOf(events, boundary) {
|
|
|
50
49
|
if (boundary < 0) return 0;
|
|
51
50
|
return events[boundary]?.type === "turn/end" ? boundary + 1 : boundary;
|
|
52
51
|
}
|
|
53
|
-
async function appendSeedSuffixLive(session, seedSuffix
|
|
52
|
+
async function appendSeedSuffixLive(session, seedSuffix) {
|
|
54
53
|
for (const event of seedSuffix) {
|
|
55
|
-
if (event.ignorable === true) {
|
|
56
|
-
const s = session;
|
|
57
|
-
const seq = s.log.length;
|
|
58
|
-
await appendDirect([{
|
|
59
|
-
...event,
|
|
60
|
-
seq
|
|
61
|
-
}]);
|
|
62
|
-
s.log.push({
|
|
63
|
-
...event,
|
|
64
|
-
seq
|
|
65
|
-
});
|
|
66
|
-
s.eventsSnapshot = void 0;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
54
|
const s = session;
|
|
70
55
|
const raw = event;
|
|
71
56
|
if (raw.surfaceOp !== void 0) s.append(event.type, event.data, {
|
|
@@ -99,9 +84,6 @@ var SessionEditor = class extends Service {
|
|
|
99
84
|
await this.stopLoop(id, signal);
|
|
100
85
|
return this.ctx.sessionBranch.rewind(id, toBoundary, signal);
|
|
101
86
|
}
|
|
102
|
-
timeline(sessionId, signal) {
|
|
103
|
-
return this.ctx.sessionBranch.timeline(sessionId, signal);
|
|
104
|
-
}
|
|
105
87
|
edit(operation, signal) {
|
|
106
88
|
return this.branchOperation(operation, signal);
|
|
107
89
|
}
|
|
@@ -114,14 +96,6 @@ var SessionEditor = class extends Service {
|
|
|
114
96
|
recall(operation, signal) {
|
|
115
97
|
return this.recallOperation(operation, signal);
|
|
116
98
|
}
|
|
117
|
-
async editableMessages(sessionId, signal) {
|
|
118
|
-
const events = await this.readEvents(sessionId, signal);
|
|
119
|
-
return editableMessages(closedTurns(events));
|
|
120
|
-
}
|
|
121
|
-
async retryableTurns(sessionId, signal) {
|
|
122
|
-
const events = await this.readEvents(sessionId, signal);
|
|
123
|
-
return retryableTurns(closedTurns(events));
|
|
124
|
-
}
|
|
125
99
|
async branchOperation(operation, signal) {
|
|
126
100
|
signal?.throwIfAborted();
|
|
127
101
|
const events = await this.readEvents(operation.sessionId, signal);
|
|
@@ -134,8 +108,6 @@ var SessionEditor = class extends Service {
|
|
|
134
108
|
const keepFrom = keepFromOf(events, boundary);
|
|
135
109
|
const compactions = droppedCompactions(events, keepFrom, plan.targetSeq);
|
|
136
110
|
const replayTurn = preceding < 0 ? 1 : turns[preceding].turn + 1;
|
|
137
|
-
const versionSeed = [];
|
|
138
|
-
appendLogSeedEvent(versionSeed, "session-branch/version", plan.version, true);
|
|
139
111
|
const manualSeed = [];
|
|
140
112
|
if (plan.manualTurn !== void 0) appendManualTurn(manualSeed, {
|
|
141
113
|
...plan.manualTurn,
|
|
@@ -146,11 +118,7 @@ var SessionEditor = class extends Service {
|
|
|
146
118
|
const live = this.ctx.sessions.get(operation.sessionId);
|
|
147
119
|
await this.ctx.sessionBranch.rewind(operation.sessionId, boundary, signal);
|
|
148
120
|
const seedStart = this.seedStart(live, events, keepFrom);
|
|
149
|
-
const seedSuffix = [
|
|
150
|
-
...versionSeed,
|
|
151
|
-
...restoreCompactions(compactions, keepFrom, seedStart + versionSeed.length),
|
|
152
|
-
...manualSeed
|
|
153
|
-
];
|
|
121
|
+
const seedSuffix = [...restoreCompactions(compactions, keepFrom, seedStart), ...manualSeed];
|
|
154
122
|
await this.appendSeedSuffix(operation.sessionId, live, seedSuffix, events, keepFrom);
|
|
155
123
|
let queuedTurns = 0;
|
|
156
124
|
if (replay.agent !== void 0 && plan.queuedUsers.length > 0) {
|
|
@@ -191,10 +159,8 @@ var SessionEditor = class extends Service {
|
|
|
191
159
|
async appendSeedSuffix(sessionId, live, seedSuffix, events, keepFrom) {
|
|
192
160
|
if (seedSuffix.length === 0) return;
|
|
193
161
|
if (live !== void 0) {
|
|
194
|
-
const handle = this.ctx.sessionPersistence.tracker.writerOf(sessionId);
|
|
195
|
-
if (handle === void 0) throw new Error(`session "${sessionId}" has no live write handle for the version effect`);
|
|
196
162
|
await this.ctx.sessions.flush(live);
|
|
197
|
-
await appendSeedSuffixLive(live, seedSuffix
|
|
163
|
+
await appendSeedSuffixLive(live, seedSuffix);
|
|
198
164
|
await this.ctx.sessions.flush(live);
|
|
199
165
|
return;
|
|
200
166
|
}
|
|
@@ -342,12 +308,6 @@ function respondJson(response, status, value) {
|
|
|
342
308
|
});
|
|
343
309
|
response.end(JSON.stringify(value));
|
|
344
310
|
}
|
|
345
|
-
async function readTimeline(editor, sessionId) {
|
|
346
|
-
const timeline = await editor.timeline(sessionId);
|
|
347
|
-
const messages = await editor.editableMessages(sessionId);
|
|
348
|
-
const retryable = await editor.retryableTurns(sessionId);
|
|
349
|
-
return toTimelinePayload(sessionId, timeline, messages, retryable);
|
|
350
|
-
}
|
|
351
311
|
async function runOperation(editor, operation) {
|
|
352
312
|
switch (operation.action) {
|
|
353
313
|
case "edit": {
|
|
@@ -396,10 +356,6 @@ async function runOperation(editor, operation) {
|
|
|
396
356
|
}
|
|
397
357
|
async function handleRoute(editor, request, response) {
|
|
398
358
|
try {
|
|
399
|
-
if (request.method === "GET") {
|
|
400
|
-
respondJson(response, 200, await readTimeline(editor, sessionIdOf(new URL(request.url ?? "/session-editor", "http://session-editor.local").searchParams.get("sessionId"))));
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
359
|
if (request.method === "POST") {
|
|
404
360
|
respondJson(response, 200, await runOperation(editor, decodeOperation(await requestJson(request))));
|
|
405
361
|
return;
|
|
@@ -422,40 +378,6 @@ function registerHttpRoutes(ctx) {
|
|
|
422
378
|
handler: (request, response) => handleRoute(editor, request, response)
|
|
423
379
|
});
|
|
424
380
|
}, "session-editor: HTTP route");
|
|
425
|
-
const registerConnectionRoute = () => {
|
|
426
|
-
const connection = ctx.get("connection", false);
|
|
427
|
-
if (connection === void 0) return;
|
|
428
|
-
const editor = ctx.sessionEditor;
|
|
429
|
-
ctx.effect(() => connection.fetch.register({
|
|
430
|
-
path: `/api${SESSION_EDITOR_PATH}`,
|
|
431
|
-
methods: ["GET", "POST"],
|
|
432
|
-
requestBody: "buffered",
|
|
433
|
-
fetch: (request) => handleFetchRoute(editor, request)
|
|
434
|
-
}), "session-editor: connection fetch route");
|
|
435
|
-
};
|
|
436
|
-
ctx.on("internal/service", (name) => {
|
|
437
|
-
if (name === "connection") registerConnectionRoute();
|
|
438
|
-
});
|
|
439
|
-
registerConnectionRoute();
|
|
440
|
-
}
|
|
441
|
-
async function handleFetchRoute(editor, request) {
|
|
442
|
-
try {
|
|
443
|
-
if (request.method === "GET") return jsonResponse(200, await readTimeline(editor, sessionIdOf(new URL(request.url).searchParams.get("sessionId"))));
|
|
444
|
-
if (request.method === "POST") return jsonResponse(200, await runOperation(editor, decodeOperation(await request.json())));
|
|
445
|
-
return new Response(null, { status: 405 });
|
|
446
|
-
} catch (error) {
|
|
447
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
448
|
-
return jsonResponse(error instanceof TypeError ? 400 : 409, { error: message });
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
function jsonResponse(status, value) {
|
|
452
|
-
return new Response(JSON.stringify(value), {
|
|
453
|
-
status,
|
|
454
|
-
headers: {
|
|
455
|
-
"content-type": "application/json; charset=utf-8",
|
|
456
|
-
"cache-control": "no-store"
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
381
|
}
|
|
460
382
|
//#endregion
|
|
461
|
-
export {
|
|
383
|
+
export { SessionEditor, SessionEditor as default, closedTurns, editableMessages, retryableTurns };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AssistantMessage, UserMessage } from "@deepseek-ai/dsh-llm";
|
|
2
1
|
import { SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
3
|
-
import {
|
|
2
|
+
import { CascadePolicy } from "@morlay/session-branch";
|
|
3
|
+
import { AssistantMessage, UserMessage } from "@deepseek-ai/dsh-llm";
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
interface EditOperation {
|
|
6
6
|
action: "edit";
|
|
@@ -71,7 +71,6 @@ interface ClosedTurn {
|
|
|
71
71
|
interface OperationPlan {
|
|
72
72
|
anchorSeq: number;
|
|
73
73
|
rewindBoundary?: number;
|
|
74
|
-
version: SessionBranchVersionEvent;
|
|
75
74
|
manualTurn?: {
|
|
76
75
|
turn: number;
|
|
77
76
|
user: UserMessage;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
2
|
-
import { BranchTimeline, CascadePolicy, SessionBranchVersionEvent } from "@morlay/session-branch";
|
|
3
1
|
import { AssistantMessage, UserMessage } from "@deepseek-ai/dsh-llm";
|
|
2
|
+
import { SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
3
|
+
import { CascadePolicy } from "@morlay/session-branch";
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
interface EditOperation {
|
|
6
6
|
action: "edit";
|
|
@@ -71,7 +71,6 @@ interface ClosedTurn {
|
|
|
71
71
|
interface OperationPlan {
|
|
72
72
|
anchorSeq: number;
|
|
73
73
|
rewindBoundary?: number;
|
|
74
|
-
version: SessionBranchVersionEvent;
|
|
75
74
|
manualTurn?: {
|
|
76
75
|
turn: number;
|
|
77
76
|
user: UserMessage;
|
package/dist/plan.d.cts
CHANGED
|
@@ -1,2 +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-
|
|
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-BUTplrpz.cjs";
|
|
2
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 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-
|
|
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-BKgGPZdD.mjs";
|
|
2
2
|
export { ClosedTurn, CompactionBracket, OperationPlan, closedTurns, downstreamUsers, droppedCompactions, editPlan, editableMessages, precedingContentIndex, recallBoundary, rerollPlan, restoreCompactions, retryPlan, retryableTurns };
|