@morlay/ui-conversation-message-actions 0.0.14-alpha.2 → 0.0.14-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 +12 -1
- package/dist/client.js +39 -29
- package/dist/index.d.mts +1 -9
- package/dist/index.mjs +1 -1
- package/dist/{plan-C-_enFsA.d.mts → plan-BdU_mnTv.d.mts} +8 -1
- package/dist/plan.d.mts +2 -2
- package/dist/plan.mjs +17 -2
- package/dist/{src-DqUEYw-N.mjs → src-ks167MhO.mjs} +52 -7
- package/dist/testing.mjs +187 -151
- package/package.json +19 -19
- package/src/client/controller.ts +21 -2
- package/src/index.ts +97 -22
- package/src/plan.ts +20 -3
package/README.md
CHANGED
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
- **edit / retry / reroll 是就地操作**:`rewind` 截断到目标轮之前的闭合
|
|
22
22
|
`turn/end` 边界,再 `append` 版本效果 + 手工回合 / 重放输入回**同一会话**
|
|
23
23
|
——session id 不变,版本树保持单根;
|
|
24
|
+
- **重放复用目标轮号**:轮首 user 编辑(含未闭合轮)整轮截断,重放接回原
|
|
25
|
+
轮号;编辑 assistant 写入 manualTurn 后同步 agent 的轮次游标;
|
|
26
|
+
- **空轮吸收**:目标轮之前的空轮(`turn/start` 后直接 `turn/end`,早期重放
|
|
27
|
+
缺陷的遗留形状)随截断一并删除,重放按保留前缀续号——轮次导航不再出现
|
|
28
|
+
点不开的空项与轮号空洞;manualTurn 的轮号同样按保留前缀收敛(正常会话
|
|
29
|
+
等于目标轮号)。版本效果仍记录**原**目标轮号(操作历史);
|
|
24
30
|
- **只有 `fork` 创建新 id**(`ForkOperation` / `forkFrom`,纯 append 派生);
|
|
25
31
|
- 版本效果事件(`session-branch/version`)携带 `ignorable: true`:live log 可见、
|
|
26
32
|
**不落 canonical log**(rdb 持久化时过滤并稠密化剩余事件);
|
|
@@ -32,6 +38,8 @@
|
|
|
32
38
|
缺失时退化为「已 durable 的就地版本」(可随时 resume 续跑):
|
|
33
39
|
|
|
34
40
|
- **live agent**(会话驻留 / 已恢复):直接 `followup` 排队,不重建、不换 id;
|
|
41
|
+
编辑前只等 agent 停下(`whenIdle`),残留排队输入由 rewind 在截断后强制
|
|
42
|
+
durable 取消(session-rdb 的 `LiveSessionHooks.inbox.clear`);
|
|
35
43
|
- **cold 会话**:`resume` 已持久化会话(`create` 对已持久化日志必失败),
|
|
36
44
|
resume 后 agent 驻留(不 dispose,避免 session 被移出 store 破坏客户端窗口);
|
|
37
45
|
- 模型 provider/model 在 **rewind 之前**从 `request/header` 解析(就地编辑
|
|
@@ -50,7 +58,10 @@
|
|
|
50
58
|
增长;重试先弹确认;未闭合轮次不显示重试;
|
|
51
59
|
- **操作后刷新**:就地编辑后优先调用客户端会话级 `resync()`(重置窗口并重新
|
|
52
60
|
拉取历史,不整页重载——rewind 的删除无法经 append-only 事件流表达,seq
|
|
53
|
-
|
|
61
|
+
回退只做增量会残留旧节点),随后丢弃该会话的全部投影行
|
|
62
|
+
(`projections.truncate(-1)`)——投影 store 按 higher-seq-wins 保留 rewind
|
|
63
|
+
前的高 seq 旧值,截断后的正确值 seq 更小,永远覆盖不上(轮次导航残留已
|
|
64
|
+
删除的轮次);不可用时回退 `location.reload()`;
|
|
54
65
|
- **构建约束**:client bundle 必须是**单文件**(client-modules 只服务/加载
|
|
55
66
|
`client.js`)——`noExternal` 全内联第三方 + `inlineDynamicImports` 合并
|
|
56
67
|
动态 import,`@deepseek-ai/*` 一律 external(平台 seed 词或独立插件,
|
package/dist/client.js
CHANGED
|
@@ -14,6 +14,10 @@ window.__ModuleLoader__.load({
|
|
|
14
14
|
const SESSION_EDITOR_PATH = "/session-editor";
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/client/controller.ts
|
|
17
|
+
/** desktop 壳(官方 dsh-desktop-host)注入的 transport 标记:ownsHost 时 API 走 /api 前缀。 */
|
|
18
|
+
function editorApiPath() {
|
|
19
|
+
return globalThis.__DSH_TRANSPORT__?.ownsHost === true ? `/api${SESSION_EDITOR_PATH}` : SESSION_EDITOR_PATH;
|
|
20
|
+
}
|
|
17
21
|
function messageOf(error) {
|
|
18
22
|
return error instanceof Error ? error.message : String(error);
|
|
19
23
|
}
|
|
@@ -127,7 +131,7 @@ window.__ModuleLoader__.load({
|
|
|
127
131
|
state.error = null;
|
|
128
132
|
});
|
|
129
133
|
try {
|
|
130
|
-
const response = await fetch(`${
|
|
134
|
+
const response = await fetch(`${editorApiPath()}?sessionId=${encodeURIComponent(this.sessionId)}`, {
|
|
131
135
|
method: "GET",
|
|
132
136
|
headers: { accept: "application/json" },
|
|
133
137
|
cache: "no-store"
|
|
@@ -161,7 +165,7 @@ window.__ModuleLoader__.load({
|
|
|
161
165
|
state.error = null;
|
|
162
166
|
});
|
|
163
167
|
try {
|
|
164
|
-
const response = await fetch(
|
|
168
|
+
const response = await fetch(editorApiPath(), {
|
|
165
169
|
method: "POST",
|
|
166
170
|
headers: {
|
|
167
171
|
accept: "application/json",
|
|
@@ -187,6 +191,12 @@ window.__ModuleLoader__.load({
|
|
|
187
191
|
const resync = face.resync;
|
|
188
192
|
if (resync !== void 0) try {
|
|
189
193
|
await resync.call(face);
|
|
194
|
+
const projections = face.projections;
|
|
195
|
+
if (typeof projections?.truncate !== "function") {
|
|
196
|
+
location.reload();
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
projections.truncate(-1);
|
|
190
200
|
this.load();
|
|
191
201
|
return true;
|
|
192
202
|
} catch {}
|
|
@@ -352,11 +362,11 @@ window.__ModuleLoader__.load({
|
|
|
352
362
|
}
|
|
353
363
|
var MessageIconActions_module_css_default = {
|
|
354
364
|
"runTimeDot": "lKOSUG_runTimeDot",
|
|
355
|
-
"actions": "lKOSUG_actions",
|
|
356
|
-
"visuallyHidden": "lKOSUG_visuallyHidden",
|
|
357
365
|
"timeEnd": "lKOSUG_timeEnd",
|
|
366
|
+
"action": "lKOSUG_action",
|
|
358
367
|
"timeStart": "lKOSUG_timeStart",
|
|
359
|
-
"
|
|
368
|
+
"actions": "lKOSUG_actions",
|
|
369
|
+
"visuallyHidden": "lKOSUG_visuallyHidden"
|
|
360
370
|
};
|
|
361
371
|
//#endregion
|
|
362
372
|
//#region src/client/chat-node/MessageIconActions.tsx
|
|
@@ -498,8 +508,8 @@ window.__ModuleLoader__.load({
|
|
|
498
508
|
document.head.appendChild(tag);
|
|
499
509
|
}
|
|
500
510
|
var MessageEditDialog_module_css_default = {
|
|
501
|
-
"
|
|
502
|
-
"
|
|
511
|
+
"input": "_7VqDXa_input",
|
|
512
|
+
"actions": "_7VqDXa_actions"
|
|
503
513
|
};
|
|
504
514
|
//#endregion
|
|
505
515
|
//#region src/client/chat-node/MessageEditDialog.tsx
|
|
@@ -570,34 +580,34 @@ window.__ModuleLoader__.load({
|
|
|
570
580
|
document.head.appendChild(tag);
|
|
571
581
|
}
|
|
572
582
|
var MessageItem_module_css_default = {
|
|
573
|
-
"
|
|
583
|
+
"retryRow": "okW0Ua_retryRow",
|
|
574
584
|
"turnErrorRow": "okW0Ua_turnErrorRow",
|
|
575
|
-
"
|
|
576
|
-
"
|
|
577
|
-
"
|
|
578
|
-
"
|
|
579
|
-
"
|
|
580
|
-
"
|
|
581
|
-
"compactionRow": "okW0Ua_compactionRow",
|
|
585
|
+
"bubble": "okW0Ua_bubble",
|
|
586
|
+
"confirmActions": "okW0Ua_confirmActions",
|
|
587
|
+
"userRow": "okW0Ua_userRow",
|
|
588
|
+
"compactionLeading": "okW0Ua_compactionLeading",
|
|
589
|
+
"compactionButton": "okW0Ua_compactionButton",
|
|
590
|
+
"retry-shimmer": "okW0Ua_retry-shimmer",
|
|
582
591
|
"compactionContextIcon": "okW0Ua_compactionContextIcon",
|
|
583
|
-
"
|
|
592
|
+
"turnErrorDot": "okW0Ua_turnErrorDot",
|
|
593
|
+
"compactionSummary": "okW0Ua_compactionSummary",
|
|
584
594
|
"compactionBody": "okW0Ua_compactionBody",
|
|
585
|
-
"
|
|
595
|
+
"turnErrorCopy": "okW0Ua_turnErrorCopy",
|
|
596
|
+
"userStack": "okW0Ua_userStack",
|
|
597
|
+
"turnErrorTitle": "okW0Ua_turnErrorTitle",
|
|
586
598
|
"turnErrorMessage": "okW0Ua_turnErrorMessage",
|
|
587
|
-
"retryRow": "okW0Ua_retryRow",
|
|
588
|
-
"compactionDisclosureIcon": "okW0Ua_compactionDisclosureIcon",
|
|
589
|
-
"retry-shimmer": "okW0Ua_retry-shimmer",
|
|
590
|
-
"compactionLeading": "okW0Ua_compactionLeading",
|
|
591
|
-
"contextRow": "okW0Ua_contextRow",
|
|
592
|
-
"compactionSummary": "okW0Ua_compactionSummary",
|
|
593
|
-
"bubble": "okW0Ua_bubble",
|
|
594
599
|
"retrySummary": "okW0Ua_retrySummary",
|
|
595
|
-
"
|
|
600
|
+
"retryDetailLabel": "okW0Ua_retryDetailLabel",
|
|
601
|
+
"maxTokensTitle": "okW0Ua_maxTokensTitle",
|
|
602
|
+
"compactionDisclosureIcon": "okW0Ua_compactionDisclosureIcon",
|
|
603
|
+
"retryText": "okW0Ua_retryText",
|
|
596
604
|
"refChip": "okW0Ua_refChip",
|
|
597
|
-
"
|
|
598
|
-
"
|
|
599
|
-
"
|
|
600
|
-
"
|
|
605
|
+
"turnErrorCode": "okW0Ua_turnErrorCode",
|
|
606
|
+
"compactionRow": "okW0Ua_compactionRow",
|
|
607
|
+
"retryDetails": "okW0Ua_retryDetails",
|
|
608
|
+
"contextRow": "okW0Ua_contextRow",
|
|
609
|
+
"compactionTitle": "okW0Ua_compactionTitle",
|
|
610
|
+
"compactionSep": "okW0Ua_compactionSep"
|
|
601
611
|
};
|
|
602
612
|
//#endregion
|
|
603
613
|
//#region src/client/chat-node/MessageItem.tsx
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { _ as SessionEditorOperation, d as EditOperation, f as EditableMessageBlock, g as RewindOperation, h as RetryableTurn, m as RetryOperation, o as editableMessages, p as RerollOperation, r as closedTurns, u as retryableTurns, v as SessionEditorResult } from "./plan-BdU_mnTv.mjs";
|
|
2
2
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
3
3
|
import { Session, SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
4
4
|
import { BranchBoundary, BranchTimeline, BranchTimeline as BranchTimeline$1, CascadePolicy, EditableBlockKind, SESSION_BRANCH_VERSION_SCHEMA, SessionBranchVersionEvent } from "@morlay/session-branch";
|
|
@@ -14,14 +14,6 @@ interface EditorAgent {
|
|
|
14
14
|
followup(message: UserMessage): void;
|
|
15
15
|
/** 等待 agent 到达 quiescence(当前 turn/任务结束后 resolve)。 */
|
|
16
16
|
whenIdle(): Promise<void>;
|
|
17
|
-
/**
|
|
18
|
-
* 队列中是否有待处理输入(next-turn / next-step)。rewind 截断会删除这些
|
|
19
|
-
* 输入所属轮次的事件,残留的 inbox 状态会与截断后的 log 失配,使后续
|
|
20
|
-
* splice 落库后无法从日志重放——编辑前必须清空。
|
|
21
|
-
*/
|
|
22
|
-
readonly inboxPending: boolean;
|
|
23
|
-
/** 清空待处理输入(落库 canceled splice,须在 rewind 前调用)。 */
|
|
24
|
-
clearInbox(): void;
|
|
25
17
|
}
|
|
26
18
|
interface EditorAgentHandle {
|
|
27
19
|
readonly agent: EditorAgent;
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as SessionEditor, t as SESSION_BRANCH_VERSION_SCHEMA } from "./src-
|
|
1
|
+
import { n as SessionEditor, t as SESSION_BRANCH_VERSION_SCHEMA } from "./src-ks167MhO.mjs";
|
|
2
2
|
import { closedTurns, editableMessages, retryableTurns } from "./plan.mjs";
|
|
3
3
|
export { SESSION_BRANCH_VERSION_SCHEMA, SessionEditor, SessionEditor as default, closedTurns, editableMessages, retryableTurns };
|
|
@@ -78,9 +78,16 @@ interface OperationPlan {
|
|
|
78
78
|
declare function closedTurns(events: readonly SessionEvent[]): ClosedTurn[];
|
|
79
79
|
declare function editableMessages(turns: readonly ClosedTurn[]): EditableMessageBlock[];
|
|
80
80
|
declare function retryableTurns(turns: readonly ClosedTurn[]): RetryableTurn[];
|
|
81
|
+
/**
|
|
82
|
+
* 目标轮之前最后一个「有内容」轮次的下标:跳过既无用户输入也无助手回复的
|
|
83
|
+
* 空轮。空轮是早期重放缺陷的遗留(turn/start 后直接 turn/end),在轨迹 /
|
|
84
|
+
* 轮次导航里表现为点不开的空项,并让后续轮号出现空洞。rewind 把它们随
|
|
85
|
+
* 目标轮一起截断,重放按保留前缀续号即可自愈。
|
|
86
|
+
*/
|
|
87
|
+
declare function precedingContentIndex(turns: readonly ClosedTurn[], turnIndex: number): number;
|
|
81
88
|
declare function downstreamUsers(turns: readonly ClosedTurn[], start: number): UserMessage[];
|
|
82
89
|
declare function editPlan(operation: EditOperation, turns: readonly ClosedTurn[]): OperationPlan;
|
|
83
90
|
declare function retryPlan(operation: RetryOperation, turns: readonly ClosedTurn[]): OperationPlan;
|
|
84
91
|
declare function rerollPlan(operation: RerollOperation, turns: readonly ClosedTurn[]): OperationPlan;
|
|
85
92
|
//#endregion
|
|
86
|
-
export {
|
|
93
|
+
export { SessionEditorOperation as _, editPlan as a, rerollPlan as c, EditOperation as d, EditableMessageBlock as f, RewindOperation as g, RetryableTurn as h, downstreamUsers as i, retryPlan as l, RetryOperation as m, OperationPlan as n, editableMessages as o, RerollOperation as p, closedTurns as r, precedingContentIndex as s, ClosedTurn as t, retryableTurns as u, SessionEditorResult as v };
|
package/dist/plan.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as editPlan, c as
|
|
2
|
-
export { ClosedTurn, OperationPlan, closedTurns, downstreamUsers, editPlan, editableMessages, rerollPlan, retryPlan, retryableTurns };
|
|
1
|
+
import { a as editPlan, c as rerollPlan, i as downstreamUsers, l as retryPlan, n as OperationPlan, o as editableMessages, r as closedTurns, s as precedingContentIndex, t as ClosedTurn, u as retryableTurns } from "./plan-BdU_mnTv.mjs";
|
|
2
|
+
export { ClosedTurn, OperationPlan, closedTurns, downstreamUsers, editPlan, editableMessages, precedingContentIndex, rerollPlan, retryPlan, retryableTurns };
|
package/dist/plan.mjs
CHANGED
|
@@ -100,6 +100,21 @@ function retryableTurns(turns) {
|
|
|
100
100
|
time: turn.user.time
|
|
101
101
|
}]);
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* 目标轮之前最后一个「有内容」轮次的下标:跳过既无用户输入也无助手回复的
|
|
105
|
+
* 空轮。空轮是早期重放缺陷的遗留(turn/start 后直接 turn/end),在轨迹 /
|
|
106
|
+
* 轮次导航里表现为点不开的空项,并让后续轮号出现空洞。rewind 把它们随
|
|
107
|
+
* 目标轮一起截断,重放按保留前缀续号即可自愈。
|
|
108
|
+
*/
|
|
109
|
+
function precedingContentIndex(turns, turnIndex) {
|
|
110
|
+
let index = turnIndex - 1;
|
|
111
|
+
while (index >= 0) {
|
|
112
|
+
const turn = turns[index];
|
|
113
|
+
if (turn.users.length > 0 || turn.assistants.length > 0) break;
|
|
114
|
+
index -= 1;
|
|
115
|
+
}
|
|
116
|
+
return index;
|
|
117
|
+
}
|
|
103
118
|
function downstreamUsers(turns, start) {
|
|
104
119
|
return turns.slice(start).flatMap((turn) => turn.users.map((user) => cloneUser(user.data)));
|
|
105
120
|
}
|
|
@@ -144,7 +159,7 @@ function editPlan(operation, turns) {
|
|
|
144
159
|
const later = operation.cascade === "preserve" ? downstreamUsers(turns, turnIndex + 1) : [];
|
|
145
160
|
return {
|
|
146
161
|
anchorSeq: turn.startSeq,
|
|
147
|
-
...
|
|
162
|
+
...userIndex === 0 ? {} : { rewindBoundary: event.seq },
|
|
148
163
|
version: pairVersionEffect(operation.sessionId, {
|
|
149
164
|
operation: "edit",
|
|
150
165
|
cascade: operation.cascade,
|
|
@@ -222,4 +237,4 @@ function rerollPlan(operation, turns) {
|
|
|
222
237
|
throw new SessionBranchError("当前会话没有可重生成的已落定助手回复。", "INVALID_BOUNDARY");
|
|
223
238
|
}
|
|
224
239
|
//#endregion
|
|
225
|
-
export { closedTurns, downstreamUsers, editPlan, editableMessages, rerollPlan, retryPlan, retryableTurns };
|
|
240
|
+
export { closedTurns, downstreamUsers, editPlan, editableMessages, precedingContentIndex, rerollPlan, retryPlan, retryableTurns };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { closedTurns, editPlan, editableMessages, rerollPlan, retryPlan, retryableTurns } from "./plan.mjs";
|
|
1
|
+
import { closedTurns, editPlan, editableMessages, precedingContentIndex, rerollPlan, retryPlan, retryableTurns } from "./plan.mjs";
|
|
2
2
|
import { Service } from "@deepseek-ai/cordis";
|
|
3
3
|
import { SessionSeq } from "@deepseek-ai/dsh-session";
|
|
4
4
|
import { SESSION_BRANCH_VERSION_SCHEMA as SESSION_BRANCH_VERSION_SCHEMA$1, SessionBranchError, balanceRewindPrefix } from "@morlay/session-branch";
|
|
@@ -173,18 +173,24 @@ var SessionEditor = class extends Service {
|
|
|
173
173
|
const turns = closedTurns(events);
|
|
174
174
|
const plan = operation.action === "edit" ? editPlan(operation, turns) : operation.action === "retry" ? retryPlan(operation, turns) : rerollPlan(operation, turns);
|
|
175
175
|
const headerConfig = events.findLast((event) => event.type === "request/header")?.data.header.config;
|
|
176
|
+
const turnIndex = turns.findIndex((turn) => turn.startSeq === plan.anchorSeq);
|
|
177
|
+
const preceding = precedingContentIndex(turns, turnIndex);
|
|
178
|
+
const boundary = plan.rewindBoundary !== void 0 ? plan.rewindBoundary : preceding < 0 ? -1 : turns[preceding].endSeq;
|
|
179
|
+
const replayTurn = preceding < 0 ? 1 : turns[preceding].turn + 1;
|
|
176
180
|
const seedSuffix = [];
|
|
177
181
|
appendLogSeedEvent(seedSuffix, "session-branch/version", plan.version, true);
|
|
178
|
-
if (plan.manualTurn !== void 0) appendManualTurn(seedSuffix,
|
|
182
|
+
if (plan.manualTurn !== void 0) appendManualTurn(seedSuffix, {
|
|
183
|
+
...plan.manualTurn,
|
|
184
|
+
turn: replayTurn
|
|
185
|
+
});
|
|
179
186
|
const replay = await this.prepareReplay(operation.sessionId, plan.queuedUsers, signal, headerConfig);
|
|
180
|
-
const turnIndex = turns.findIndex((turn) => turn.startSeq === plan.anchorSeq);
|
|
181
|
-
const boundary = plan.rewindBoundary !== void 0 ? plan.rewindBoundary : turnIndex <= 0 ? -1 : turns[turnIndex - 1].endSeq;
|
|
182
187
|
const live = this.ctx.sessions.get(operation.sessionId);
|
|
183
188
|
await this.ctx.sessionBranch.rewind(operation.sessionId, boundary, signal);
|
|
184
189
|
if (seedSuffix.length > 0) {
|
|
185
190
|
if (live !== void 0) {
|
|
186
191
|
const handle = this.ctx.sessionPersistence.tracker.writerOf(operation.sessionId);
|
|
187
192
|
if (handle === void 0) throw new Error(`session "${operation.sessionId}" has no live write handle for the version effect`);
|
|
193
|
+
await this.ctx.sessions.flush(live);
|
|
188
194
|
await appendSeedSuffixLive(live, seedSuffix, (events) => handle.append(events));
|
|
189
195
|
await this.ctx.sessions.flush(live);
|
|
190
196
|
} else {
|
|
@@ -204,6 +210,11 @@ var SessionEditor = class extends Service {
|
|
|
204
210
|
}
|
|
205
211
|
let queuedTurns = 0;
|
|
206
212
|
if (replay.agent !== void 0 && plan.queuedUsers.length > 0) {
|
|
213
|
+
const lastSeedTurn = seedSuffix.findLast((event) => event.type === "turn/start")?.data.turn;
|
|
214
|
+
if (lastSeedTurn !== void 0) {
|
|
215
|
+
const phase = replay.agent.phase;
|
|
216
|
+
if (phase !== void 0) phase.lastTurn = lastSeedTurn;
|
|
217
|
+
}
|
|
207
218
|
for (const message of plan.queuedUsers) replay.agent.followup(message);
|
|
208
219
|
await this.ctx.sessions.flush(replay.agent.session);
|
|
209
220
|
queuedTurns = plan.queuedUsers.length;
|
|
@@ -234,7 +245,6 @@ var SessionEditor = class extends Service {
|
|
|
234
245
|
if (existing !== void 0) {
|
|
235
246
|
await existing.whenIdle();
|
|
236
247
|
signal?.throwIfAborted();
|
|
237
|
-
if (existing.inboxPending) existing.clearInbox();
|
|
238
248
|
return { agent: existing };
|
|
239
249
|
}
|
|
240
250
|
const provider = headerConfig?.provider ?? "";
|
|
@@ -403,9 +413,9 @@ async function handleRoute(editor, request, response) {
|
|
|
403
413
|
}
|
|
404
414
|
}
|
|
405
415
|
function registerHttpRoutes(ctx) {
|
|
406
|
-
const webServer = ctx.get("webServer");
|
|
407
|
-
if (webServer === void 0) return;
|
|
408
416
|
ctx.effect(() => {
|
|
417
|
+
const webServer = ctx.get("webServer");
|
|
418
|
+
if (webServer === void 0) return () => {};
|
|
409
419
|
const editor = ctx.sessionEditor;
|
|
410
420
|
return webServer.register({
|
|
411
421
|
kind: "exact",
|
|
@@ -413,6 +423,41 @@ function registerHttpRoutes(ctx) {
|
|
|
413
423
|
handler: (request, response) => handleRoute(editor, request, response)
|
|
414
424
|
});
|
|
415
425
|
}, "session-editor: HTTP route");
|
|
426
|
+
const registerConnectionRoute = () => {
|
|
427
|
+
const connection = ctx.get("connection", false);
|
|
428
|
+
if (connection === void 0) return;
|
|
429
|
+
const editor = ctx.sessionEditor;
|
|
430
|
+
ctx.effect(() => connection.fetch.register({
|
|
431
|
+
path: `/api${SESSION_EDITOR_PATH}`,
|
|
432
|
+
methods: ["GET", "POST"],
|
|
433
|
+
requestBody: "buffered",
|
|
434
|
+
fetch: (request) => handleFetchRoute(editor, request)
|
|
435
|
+
}), "session-editor: connection fetch route");
|
|
436
|
+
};
|
|
437
|
+
ctx.on("internal/service", (name) => {
|
|
438
|
+
if (name === "connection") registerConnectionRoute();
|
|
439
|
+
});
|
|
440
|
+
registerConnectionRoute();
|
|
441
|
+
}
|
|
442
|
+
/** connection.fetch 路由的 Fetch 形态处理(与 webServer 的 node:http 形态同语义)。 */
|
|
443
|
+
async function handleFetchRoute(editor, request) {
|
|
444
|
+
try {
|
|
445
|
+
if (request.method === "GET") return jsonResponse(200, await readTimeline(editor, sessionIdOf(new URL(request.url).searchParams.get("sessionId"))));
|
|
446
|
+
if (request.method === "POST") return jsonResponse(200, await runOperation(editor, decodeOperation(await request.json())));
|
|
447
|
+
return new Response(null, { status: 405 });
|
|
448
|
+
} catch (error) {
|
|
449
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
450
|
+
return jsonResponse(error instanceof TypeError ? 400 : 409, { error: message });
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function jsonResponse(status, value) {
|
|
454
|
+
return new Response(JSON.stringify(value), {
|
|
455
|
+
status,
|
|
456
|
+
headers: {
|
|
457
|
+
"content-type": "application/json; charset=utf-8",
|
|
458
|
+
"cache-control": "no-store"
|
|
459
|
+
}
|
|
460
|
+
});
|
|
416
461
|
}
|
|
417
462
|
//#endregion
|
|
418
463
|
export { SessionEditor as n, SESSION_BRANCH_VERSION_SCHEMA$1 as t };
|