@actalk/inkos-core 1.1.1 → 1.2.0
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/LICENSE +661 -21
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/interaction/edit-controller.d.ts +55 -0
- package/dist/interaction/edit-controller.d.ts.map +1 -0
- package/dist/interaction/edit-controller.js +187 -0
- package/dist/interaction/edit-controller.js.map +1 -0
- package/dist/interaction/events.d.ts +45 -0
- package/dist/interaction/events.d.ts.map +1 -0
- package/dist/interaction/events.js +32 -0
- package/dist/interaction/events.js.map +1 -0
- package/dist/interaction/intents.d.ts +96 -0
- package/dist/interaction/intents.d.ts.map +1 -0
- package/dist/interaction/intents.js +58 -0
- package/dist/interaction/intents.js.map +1 -0
- package/dist/interaction/modes.d.ts +5 -0
- package/dist/interaction/modes.d.ts.map +1 -0
- package/dist/interaction/modes.js +7 -0
- package/dist/interaction/modes.js.map +1 -0
- package/dist/interaction/nl-router.d.ts +7 -0
- package/dist/interaction/nl-router.d.ts.map +1 -0
- package/dist/interaction/nl-router.js +218 -0
- package/dist/interaction/nl-router.js.map +1 -0
- package/dist/interaction/project-control.d.ts +85 -0
- package/dist/interaction/project-control.d.ts.map +1 -0
- package/dist/interaction/project-control.js +123 -0
- package/dist/interaction/project-control.js.map +1 -0
- package/dist/interaction/project-session-store.d.ts +7 -0
- package/dist/interaction/project-session-store.d.ts.map +1 -0
- package/dist/interaction/project-session-store.js +46 -0
- package/dist/interaction/project-session-store.js.map +1 -0
- package/dist/interaction/project-tools.d.ts +20 -0
- package/dist/interaction/project-tools.d.ts.map +1 -0
- package/dist/interaction/project-tools.js +516 -0
- package/dist/interaction/project-tools.js.map +1 -0
- package/dist/interaction/request-router.d.ts +3 -0
- package/dist/interaction/request-router.d.ts.map +1 -0
- package/dist/interaction/request-router.js +5 -0
- package/dist/interaction/request-router.js.map +1 -0
- package/dist/interaction/runtime.d.ts +54 -0
- package/dist/interaction/runtime.d.ts.map +1 -0
- package/dist/interaction/runtime.js +943 -0
- package/dist/interaction/runtime.js.map +1 -0
- package/dist/interaction/session.d.ts +352 -0
- package/dist/interaction/session.d.ts.map +1 -0
- package/dist/interaction/session.js +98 -0
- package/dist/interaction/session.js.map +1 -0
- package/dist/interaction/truth-authority.d.ts +4 -0
- package/dist/interaction/truth-authority.d.ts.map +1 -0
- package/dist/interaction/truth-authority.js +37 -0
- package/dist/interaction/truth-authority.js.map +1 -0
- package/dist/llm/provider.d.ts +2 -0
- package/dist/llm/provider.d.ts.map +1 -1
- package/dist/llm/provider.js +49 -14
- package/dist/llm/provider.js.map +1 -1
- package/dist/pipeline/runner.d.ts +8 -1
- package/dist/pipeline/runner.d.ts.map +1 -1
- package/dist/pipeline/runner.js +139 -4
- package/dist/pipeline/runner.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,943 @@
|
|
|
1
|
+
import { routeInteractionRequest } from "./request-router.js";
|
|
2
|
+
import { appendInteractionEvent, bindActiveBook, clearCreationDraft, clearPendingDecision, updateCreationDraft, updateAutomationMode, } from "./session.js";
|
|
3
|
+
function extractToolMetadata(value) {
|
|
4
|
+
const chapterNumber = typeof value === "object" && value !== null && "chapterNumber" in value
|
|
5
|
+
&& typeof value.chapterNumber === "number"
|
|
6
|
+
? value.chapterNumber
|
|
7
|
+
: undefined;
|
|
8
|
+
if (!value || typeof value !== "object" || !("__interaction" in value)) {
|
|
9
|
+
return {
|
|
10
|
+
...(chapterNumber !== undefined ? { activeChapterNumber: chapterNumber } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const interaction = value.__interaction;
|
|
14
|
+
return {
|
|
15
|
+
...interaction,
|
|
16
|
+
...(interaction?.activeChapterNumber === undefined && chapterNumber !== undefined
|
|
17
|
+
? { activeChapterNumber: chapterNumber }
|
|
18
|
+
: {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function resolveRuntimeLanguage(request) {
|
|
22
|
+
return request.language === "en" ? "en" : "zh";
|
|
23
|
+
}
|
|
24
|
+
function localize(language, messages) {
|
|
25
|
+
return language === "en" ? messages.en : messages.zh;
|
|
26
|
+
}
|
|
27
|
+
function localizeMode(mode, language) {
|
|
28
|
+
if (language === "en") {
|
|
29
|
+
return mode;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
auto: "自动",
|
|
33
|
+
semi: "半自动",
|
|
34
|
+
manual: "手动",
|
|
35
|
+
}[mode] ?? mode;
|
|
36
|
+
}
|
|
37
|
+
function renderCreationDraft(draft, language) {
|
|
38
|
+
const lines = language === "en"
|
|
39
|
+
? [
|
|
40
|
+
"# Current Book Draft",
|
|
41
|
+
draft.title ? `- Title: ${draft.title}` : undefined,
|
|
42
|
+
draft.genre ? `- Genre: ${draft.genre}` : undefined,
|
|
43
|
+
draft.platform ? `- Platform: ${draft.platform}` : undefined,
|
|
44
|
+
draft.worldPremise ? `- World: ${draft.worldPremise}` : undefined,
|
|
45
|
+
draft.protagonist ? `- Protagonist: ${draft.protagonist}` : undefined,
|
|
46
|
+
draft.conflictCore ? `- Core Conflict: ${draft.conflictCore}` : undefined,
|
|
47
|
+
draft.volumeOutline ? `- Volume Direction: ${draft.volumeOutline}` : undefined,
|
|
48
|
+
draft.blurb ? `- Blurb: ${draft.blurb}` : undefined,
|
|
49
|
+
draft.nextQuestion ? `- Next: ${draft.nextQuestion}` : undefined,
|
|
50
|
+
]
|
|
51
|
+
: [
|
|
52
|
+
"# 当前创作草案",
|
|
53
|
+
draft.title ? `- 书名:${draft.title}` : undefined,
|
|
54
|
+
draft.genre ? `- 题材:${draft.genre}` : undefined,
|
|
55
|
+
draft.platform ? `- 平台:${draft.platform}` : undefined,
|
|
56
|
+
draft.worldPremise ? `- 世界观:${draft.worldPremise}` : undefined,
|
|
57
|
+
draft.protagonist ? `- 主角:${draft.protagonist}` : undefined,
|
|
58
|
+
draft.conflictCore ? `- 核心冲突:${draft.conflictCore}` : undefined,
|
|
59
|
+
draft.volumeOutline ? `- 卷纲方向:${draft.volumeOutline}` : undefined,
|
|
60
|
+
draft.blurb ? `- 简介:${draft.blurb}` : undefined,
|
|
61
|
+
draft.nextQuestion ? `- 下一步:${draft.nextQuestion}` : undefined,
|
|
62
|
+
];
|
|
63
|
+
return lines.filter(Boolean).join("\n");
|
|
64
|
+
}
|
|
65
|
+
function buildTaskStartedState(session, request, language) {
|
|
66
|
+
switch (request.intent) {
|
|
67
|
+
case "write_next":
|
|
68
|
+
case "continue_book":
|
|
69
|
+
return {
|
|
70
|
+
status: "planning",
|
|
71
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
72
|
+
chapterNumber: session.activeChapterNumber,
|
|
73
|
+
stageLabel: localize(language, {
|
|
74
|
+
zh: "准备章节输入",
|
|
75
|
+
en: "preparing chapter inputs",
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
case "develop_book":
|
|
79
|
+
return {
|
|
80
|
+
status: "planning",
|
|
81
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
82
|
+
stageLabel: localize(language, {
|
|
83
|
+
zh: "收敛创作草案",
|
|
84
|
+
en: "developing book draft",
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
case "create_book":
|
|
88
|
+
return {
|
|
89
|
+
status: "planning",
|
|
90
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
91
|
+
stageLabel: localize(language, {
|
|
92
|
+
zh: "创建作品基础",
|
|
93
|
+
en: "creating book foundation",
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
case "export_book":
|
|
97
|
+
return {
|
|
98
|
+
status: "persisting",
|
|
99
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
100
|
+
chapterNumber: session.activeChapterNumber,
|
|
101
|
+
stageLabel: localize(language, {
|
|
102
|
+
zh: "导出作品文件",
|
|
103
|
+
en: "exporting book artifacts",
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
case "revise_chapter":
|
|
107
|
+
case "rewrite_chapter":
|
|
108
|
+
return {
|
|
109
|
+
status: "repairing",
|
|
110
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
111
|
+
chapterNumber: request.chapterNumber ?? session.activeChapterNumber,
|
|
112
|
+
stageLabel: request.intent === "rewrite_chapter"
|
|
113
|
+
? localize(language, { zh: "重写章节", en: "rewriting chapter" })
|
|
114
|
+
: localize(language, { zh: "修订章节", en: "revising chapter" }),
|
|
115
|
+
};
|
|
116
|
+
case "update_focus":
|
|
117
|
+
case "update_author_intent":
|
|
118
|
+
case "edit_truth":
|
|
119
|
+
return {
|
|
120
|
+
status: "persisting",
|
|
121
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
122
|
+
chapterNumber: session.activeChapterNumber,
|
|
123
|
+
stageLabel: localize(language, {
|
|
124
|
+
zh: "应用项目修改",
|
|
125
|
+
en: "applying project edit",
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
case "pause_book":
|
|
129
|
+
case "discard_book_draft":
|
|
130
|
+
return {
|
|
131
|
+
status: "blocked",
|
|
132
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
133
|
+
chapterNumber: session.activeChapterNumber,
|
|
134
|
+
stageLabel: localize(language, {
|
|
135
|
+
zh: "已由用户暂停",
|
|
136
|
+
en: "paused by user",
|
|
137
|
+
}),
|
|
138
|
+
};
|
|
139
|
+
default:
|
|
140
|
+
return {
|
|
141
|
+
status: "planning",
|
|
142
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
143
|
+
chapterNumber: session.activeChapterNumber,
|
|
144
|
+
stageLabel: localize(language, {
|
|
145
|
+
zh: `处理中:${request.intent}`,
|
|
146
|
+
en: `handling ${request.intent}`,
|
|
147
|
+
}),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function shouldWaitForHuman(automationMode, request) {
|
|
152
|
+
const contentIntent = request.intent === "write_next"
|
|
153
|
+
|| request.intent === "continue_book"
|
|
154
|
+
|| request.intent === "revise_chapter"
|
|
155
|
+
|| request.intent === "rewrite_chapter"
|
|
156
|
+
|| request.intent === "patch_chapter_text";
|
|
157
|
+
const editIntent = request.intent === "update_focus"
|
|
158
|
+
|| request.intent === "update_author_intent"
|
|
159
|
+
|| request.intent === "edit_truth"
|
|
160
|
+
|| request.intent === "rename_entity";
|
|
161
|
+
if (automationMode === "auto") {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (automationMode === "semi") {
|
|
165
|
+
return contentIntent;
|
|
166
|
+
}
|
|
167
|
+
return contentIntent || editIntent;
|
|
168
|
+
}
|
|
169
|
+
function buildPendingDecision(session, request, language, chapterNumber) {
|
|
170
|
+
if (!shouldWaitForHuman(session.automationMode, request)) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
174
|
+
if (!bookId) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
kind: "review-next-step",
|
|
179
|
+
bookId,
|
|
180
|
+
...(chapterNumber !== undefined ? { chapterNumber } : {}),
|
|
181
|
+
summary: session.automationMode === "manual"
|
|
182
|
+
? localize(language, {
|
|
183
|
+
zh: "执行已完成。请明确选择下一步操作。",
|
|
184
|
+
en: "Execution finished. Choose the next action explicitly.",
|
|
185
|
+
})
|
|
186
|
+
: localize(language, {
|
|
187
|
+
zh: "执行已完成,等待你的下一步决定。",
|
|
188
|
+
en: "Execution finished. Waiting for your next decision.",
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function buildWaitingExecution(session, request, language, chapterNumber) {
|
|
193
|
+
return {
|
|
194
|
+
status: "waiting_human",
|
|
195
|
+
bookId: request.bookId ?? session.activeBookId,
|
|
196
|
+
...(chapterNumber !== undefined ? { chapterNumber } : {}),
|
|
197
|
+
stageLabel: localize(language, {
|
|
198
|
+
zh: "等待你的下一步决定",
|
|
199
|
+
en: "waiting for your next decision",
|
|
200
|
+
}),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function appendToolEvents(session, events) {
|
|
204
|
+
if (!events || events.length === 0) {
|
|
205
|
+
return session;
|
|
206
|
+
}
|
|
207
|
+
const baseTimestamp = Date.now();
|
|
208
|
+
return events.reduce((nextSession, event, index) => appendInteractionEvent(nextSession, {
|
|
209
|
+
...event,
|
|
210
|
+
timestamp: baseTimestamp - events.length + index,
|
|
211
|
+
}), session);
|
|
212
|
+
}
|
|
213
|
+
async function handleDraftLifecycleRequest(params) {
|
|
214
|
+
const { session, request, tools, helpers } = params;
|
|
215
|
+
const { language, addEvent, markCompleted } = helpers;
|
|
216
|
+
switch (request.intent) {
|
|
217
|
+
case "develop_book": {
|
|
218
|
+
if (!tools.developBookDraft) {
|
|
219
|
+
throw new Error(localize(language, {
|
|
220
|
+
zh: "创作草案会话暂未实现。",
|
|
221
|
+
en: "Book-draft ideation is not implemented yet.",
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
if (!request.instruction) {
|
|
225
|
+
throw new Error(localize(language, {
|
|
226
|
+
zh: "创作草案需要一条用户输入。",
|
|
227
|
+
en: "Book-draft ideation requires user input.",
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
const toolResult = await tools.developBookDraft(request.instruction, session.creationDraft);
|
|
231
|
+
const metadata = extractToolMetadata(toolResult);
|
|
232
|
+
const draft = metadata.details?.creationDraft;
|
|
233
|
+
if (!draft) {
|
|
234
|
+
throw new Error(localize(language, {
|
|
235
|
+
zh: "创作草案工具没有返回草案数据。",
|
|
236
|
+
en: "Book-draft tool did not return draft data.",
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
const nextSession = appendToolEvents(updateCreationDraft(session, draft), metadata.events);
|
|
240
|
+
const completed = {
|
|
241
|
+
...markCompleted(nextSession),
|
|
242
|
+
currentExecution: metadata.currentExecution ?? markCompleted(nextSession).currentExecution,
|
|
243
|
+
};
|
|
244
|
+
return {
|
|
245
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
246
|
+
zh: "已更新创作草案。",
|
|
247
|
+
en: "Updated the book draft.",
|
|
248
|
+
})),
|
|
249
|
+
responseText: metadata.responseText ?? localize(language, {
|
|
250
|
+
zh: "已更新创作草案。",
|
|
251
|
+
en: "Updated the book draft.",
|
|
252
|
+
}),
|
|
253
|
+
details: metadata.details,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
case "show_book_draft": {
|
|
257
|
+
if (!session.creationDraft) {
|
|
258
|
+
return {
|
|
259
|
+
session: markCompleted(session),
|
|
260
|
+
responseText: localize(language, {
|
|
261
|
+
zh: "当前还没有创作草案。先告诉我你想写什么,再逐步把书收出来。",
|
|
262
|
+
en: "There is no active book draft yet. Start by telling me what you want to write.",
|
|
263
|
+
}),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
session: markCompleted(session),
|
|
268
|
+
responseText: renderCreationDraft(session.creationDraft, language),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
case "create_book": {
|
|
272
|
+
if (!tools.createBook) {
|
|
273
|
+
throw new Error(localize(language, {
|
|
274
|
+
zh: "交互运行时暂未实现创建作品。",
|
|
275
|
+
en: "Book creation is not implemented in the interaction runtime yet.",
|
|
276
|
+
}));
|
|
277
|
+
}
|
|
278
|
+
const effectiveDraft = session.creationDraft;
|
|
279
|
+
const title = request.title ?? effectiveDraft?.title;
|
|
280
|
+
if (!title) {
|
|
281
|
+
throw new Error(localize(language, {
|
|
282
|
+
zh: "创建作品需要标题。",
|
|
283
|
+
en: "Book creation requires a title.",
|
|
284
|
+
}));
|
|
285
|
+
}
|
|
286
|
+
const toolResult = await tools.createBook({
|
|
287
|
+
title,
|
|
288
|
+
genre: request.genre ?? effectiveDraft?.genre,
|
|
289
|
+
platform: request.platform ?? effectiveDraft?.platform,
|
|
290
|
+
language: request.language ?? effectiveDraft?.language,
|
|
291
|
+
chapterWordCount: request.chapterWordCount ?? effectiveDraft?.chapterWordCount,
|
|
292
|
+
targetChapters: request.targetChapters ?? effectiveDraft?.targetChapters,
|
|
293
|
+
blurb: request.blurb ?? effectiveDraft?.blurb,
|
|
294
|
+
worldPremise: request.worldPremise ?? effectiveDraft?.worldPremise,
|
|
295
|
+
settingNotes: request.settingNotes ?? effectiveDraft?.settingNotes,
|
|
296
|
+
protagonist: request.protagonist ?? effectiveDraft?.protagonist,
|
|
297
|
+
supportingCast: request.supportingCast ?? effectiveDraft?.supportingCast,
|
|
298
|
+
conflictCore: request.conflictCore ?? effectiveDraft?.conflictCore,
|
|
299
|
+
volumeOutline: request.volumeOutline ?? effectiveDraft?.volumeOutline,
|
|
300
|
+
constraints: request.constraints ?? effectiveDraft?.constraints,
|
|
301
|
+
authorIntent: request.authorIntent ?? effectiveDraft?.authorIntent,
|
|
302
|
+
currentFocus: request.currentFocus ?? effectiveDraft?.currentFocus,
|
|
303
|
+
});
|
|
304
|
+
const metadata = extractToolMetadata(toolResult);
|
|
305
|
+
const createdBookId = typeof toolResult === "object" && toolResult !== null && "bookId" in toolResult
|
|
306
|
+
&& typeof toolResult.bookId === "string"
|
|
307
|
+
? toolResult.bookId
|
|
308
|
+
: undefined;
|
|
309
|
+
if (!createdBookId) {
|
|
310
|
+
throw new Error(localize(language, {
|
|
311
|
+
zh: "创建作品工具没有返回作品 ID。",
|
|
312
|
+
en: "Create-book tool did not return a book id.",
|
|
313
|
+
}));
|
|
314
|
+
}
|
|
315
|
+
const nextSession = appendToolEvents(clearCreationDraft(bindActiveBook(session, createdBookId)), metadata.events);
|
|
316
|
+
const completed = {
|
|
317
|
+
...markCompleted(nextSession),
|
|
318
|
+
currentExecution: metadata.currentExecution ?? markCompleted(nextSession).currentExecution,
|
|
319
|
+
};
|
|
320
|
+
return {
|
|
321
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
322
|
+
zh: `已创建作品 ${createdBookId}。`,
|
|
323
|
+
en: `Created ${createdBookId}.`,
|
|
324
|
+
})),
|
|
325
|
+
responseText: metadata.responseText ?? localize(language, {
|
|
326
|
+
zh: `已创建作品 ${createdBookId}。`,
|
|
327
|
+
en: `Created ${createdBookId}.`,
|
|
328
|
+
}),
|
|
329
|
+
details: metadata.details,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
case "discard_book_draft": {
|
|
333
|
+
const completed = markCompleted(clearCreationDraft(session));
|
|
334
|
+
return {
|
|
335
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
336
|
+
zh: "已丢弃当前创作草案。",
|
|
337
|
+
en: "Discarded the current book draft.",
|
|
338
|
+
})),
|
|
339
|
+
responseText: localize(language, {
|
|
340
|
+
zh: "已丢弃当前创作草案。",
|
|
341
|
+
en: "Discarded the current book draft.",
|
|
342
|
+
}),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
default:
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async function handleBookSelectionRequest(params) {
|
|
350
|
+
const { session, request, tools, helpers } = params;
|
|
351
|
+
const { language, addEvent, markCompleted } = helpers;
|
|
352
|
+
switch (request.intent) {
|
|
353
|
+
case "list_books": {
|
|
354
|
+
const books = await tools.listBooks();
|
|
355
|
+
const completed = markCompleted(session);
|
|
356
|
+
return {
|
|
357
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
358
|
+
zh: `已列出 ${books.length} 本作品。`,
|
|
359
|
+
en: `Listed ${books.length} book(s).`,
|
|
360
|
+
})),
|
|
361
|
+
responseText: books.length > 0
|
|
362
|
+
? localize(language, {
|
|
363
|
+
zh: `作品列表:${books.join("、")}`,
|
|
364
|
+
en: `Books: ${books.join(", ")}`,
|
|
365
|
+
})
|
|
366
|
+
: localize(language, {
|
|
367
|
+
zh: "当前项目下没有作品。",
|
|
368
|
+
en: "No books found in this project.",
|
|
369
|
+
}),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
case "select_book": {
|
|
373
|
+
if (!request.bookId) {
|
|
374
|
+
throw new Error(localize(language, {
|
|
375
|
+
zh: "切换作品需要提供作品 ID。",
|
|
376
|
+
en: "Book selection requires a book id.",
|
|
377
|
+
}));
|
|
378
|
+
}
|
|
379
|
+
const books = await tools.listBooks();
|
|
380
|
+
if (!books.includes(request.bookId)) {
|
|
381
|
+
throw new Error(localize(language, {
|
|
382
|
+
zh: `当前项目中找不到作品「${request.bookId}」。`,
|
|
383
|
+
en: `Book "${request.bookId}" not found in this project.`,
|
|
384
|
+
}));
|
|
385
|
+
}
|
|
386
|
+
const completed = markCompleted(bindActiveBook(session, request.bookId));
|
|
387
|
+
return {
|
|
388
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
389
|
+
zh: `已切换当前作品到 ${request.bookId}。`,
|
|
390
|
+
en: `Bound active book to ${request.bookId}.`,
|
|
391
|
+
})),
|
|
392
|
+
responseText: localize(language, {
|
|
393
|
+
zh: `当前作品:${request.bookId}`,
|
|
394
|
+
en: `Active book: ${request.bookId}`,
|
|
395
|
+
}),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
default:
|
|
399
|
+
return undefined;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
export async function runInteractionRequest(params) {
|
|
403
|
+
const request = routeInteractionRequest(params.request);
|
|
404
|
+
const language = resolveRuntimeLanguage(request);
|
|
405
|
+
let session = params.session;
|
|
406
|
+
const addEvent = (nextSession, kind, status, detail) => appendInteractionEvent(nextSession, {
|
|
407
|
+
kind,
|
|
408
|
+
timestamp: Date.now(),
|
|
409
|
+
status,
|
|
410
|
+
bookId: nextSession.activeBookId,
|
|
411
|
+
chapterNumber: nextSession.activeChapterNumber,
|
|
412
|
+
detail,
|
|
413
|
+
});
|
|
414
|
+
if (request.mode) {
|
|
415
|
+
session = updateAutomationMode(session, request.mode);
|
|
416
|
+
}
|
|
417
|
+
session = clearPendingDecision({
|
|
418
|
+
...session,
|
|
419
|
+
currentExecution: buildTaskStartedState(session, request, language),
|
|
420
|
+
});
|
|
421
|
+
session = addEvent(session, "task.started", session.currentExecution.status, localize(language, {
|
|
422
|
+
zh: `开始执行 ${request.intent}。`,
|
|
423
|
+
en: `Started ${request.intent}.`,
|
|
424
|
+
}));
|
|
425
|
+
const markCompleted = (nextSession) => ({
|
|
426
|
+
...nextSession,
|
|
427
|
+
currentExecution: {
|
|
428
|
+
status: "completed",
|
|
429
|
+
bookId: nextSession.activeBookId,
|
|
430
|
+
chapterNumber: nextSession.activeChapterNumber,
|
|
431
|
+
stageLabel: localize(language, {
|
|
432
|
+
zh: "已完成",
|
|
433
|
+
en: "completed",
|
|
434
|
+
}),
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
const helperContext = {
|
|
438
|
+
language,
|
|
439
|
+
addEvent,
|
|
440
|
+
markCompleted,
|
|
441
|
+
};
|
|
442
|
+
const draftLifecycleResult = await handleDraftLifecycleRequest({
|
|
443
|
+
session,
|
|
444
|
+
request,
|
|
445
|
+
tools: params.tools,
|
|
446
|
+
helpers: helperContext,
|
|
447
|
+
});
|
|
448
|
+
if (draftLifecycleResult) {
|
|
449
|
+
return draftLifecycleResult;
|
|
450
|
+
}
|
|
451
|
+
const bookSelectionResult = await handleBookSelectionRequest({
|
|
452
|
+
session,
|
|
453
|
+
request,
|
|
454
|
+
tools: params.tools,
|
|
455
|
+
helpers: helperContext,
|
|
456
|
+
});
|
|
457
|
+
if (bookSelectionResult) {
|
|
458
|
+
return bookSelectionResult;
|
|
459
|
+
}
|
|
460
|
+
switch (request.intent) {
|
|
461
|
+
case "write_next":
|
|
462
|
+
case "continue_book": {
|
|
463
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
464
|
+
if (!bookId) {
|
|
465
|
+
throw new Error(localize(language, {
|
|
466
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
467
|
+
en: "No active book is bound to the interaction session.",
|
|
468
|
+
}));
|
|
469
|
+
}
|
|
470
|
+
const toolResult = await params.tools.writeNextChapter(bookId);
|
|
471
|
+
const metadata = extractToolMetadata(toolResult);
|
|
472
|
+
session = bindActiveBook(session, bookId, metadata.activeChapterNumber);
|
|
473
|
+
session = appendToolEvents(session, metadata.events);
|
|
474
|
+
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language, metadata.activeChapterNumber);
|
|
475
|
+
const completed = pendingDecision
|
|
476
|
+
? {
|
|
477
|
+
...session,
|
|
478
|
+
pendingDecision,
|
|
479
|
+
currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, metadata.activeChapterNumber),
|
|
480
|
+
}
|
|
481
|
+
: {
|
|
482
|
+
...markCompleted(session),
|
|
483
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
484
|
+
};
|
|
485
|
+
return {
|
|
486
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
487
|
+
zh: `已为 ${bookId} 完成下一章写作。`,
|
|
488
|
+
en: `Completed write_next for ${bookId}.`,
|
|
489
|
+
})),
|
|
490
|
+
responseText: metadata.responseText ?? (pendingDecision
|
|
491
|
+
? localize(language, {
|
|
492
|
+
zh: `已为 ${bookId} 完成下一章写作,等待你的下一步决定。`,
|
|
493
|
+
en: `Completed write_next for ${bookId}; waiting for your next decision.`,
|
|
494
|
+
})
|
|
495
|
+
: localize(language, {
|
|
496
|
+
zh: `已为 ${bookId} 完成下一章写作。`,
|
|
497
|
+
en: `Completed write_next for ${bookId}.`,
|
|
498
|
+
})),
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
case "revise_chapter":
|
|
502
|
+
case "rewrite_chapter": {
|
|
503
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
504
|
+
if (!bookId) {
|
|
505
|
+
throw new Error(localize(language, {
|
|
506
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
507
|
+
en: "No active book is bound to the interaction session.",
|
|
508
|
+
}));
|
|
509
|
+
}
|
|
510
|
+
if (!request.chapterNumber) {
|
|
511
|
+
throw new Error(localize(language, {
|
|
512
|
+
zh: "修订章节需要章节号。",
|
|
513
|
+
en: "Chapter number is required for chapter revision.",
|
|
514
|
+
}));
|
|
515
|
+
}
|
|
516
|
+
const mode = request.intent === "rewrite_chapter" ? "rewrite" : "local-fix";
|
|
517
|
+
const toolResult = await params.tools.reviseDraft(bookId, request.chapterNumber, mode);
|
|
518
|
+
const metadata = extractToolMetadata(toolResult);
|
|
519
|
+
const chapterNumber = metadata.activeChapterNumber ?? request.chapterNumber;
|
|
520
|
+
session = bindActiveBook(session, bookId, chapterNumber);
|
|
521
|
+
session = appendToolEvents(session, metadata.events);
|
|
522
|
+
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language, chapterNumber);
|
|
523
|
+
const completed = pendingDecision
|
|
524
|
+
? {
|
|
525
|
+
...session,
|
|
526
|
+
pendingDecision,
|
|
527
|
+
currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, chapterNumber),
|
|
528
|
+
}
|
|
529
|
+
: {
|
|
530
|
+
...markCompleted(session),
|
|
531
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
532
|
+
};
|
|
533
|
+
return {
|
|
534
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
535
|
+
zh: request.intent === "rewrite_chapter"
|
|
536
|
+
? `已为 ${bookId} 完成章节重写。`
|
|
537
|
+
: `已为 ${bookId} 完成章节修订。`,
|
|
538
|
+
en: `Completed ${request.intent} for ${bookId}.`,
|
|
539
|
+
})),
|
|
540
|
+
responseText: metadata.responseText ?? (pendingDecision
|
|
541
|
+
? localize(language, {
|
|
542
|
+
zh: request.intent === "rewrite_chapter"
|
|
543
|
+
? `已为 ${bookId} 完成章节重写,等待你的下一步决定。`
|
|
544
|
+
: `已为 ${bookId} 完成章节修订,等待你的下一步决定。`,
|
|
545
|
+
en: `Completed ${request.intent} for ${bookId}; waiting for your next decision.`,
|
|
546
|
+
})
|
|
547
|
+
: localize(language, {
|
|
548
|
+
zh: request.intent === "rewrite_chapter"
|
|
549
|
+
? `已为 ${bookId} 完成章节重写。`
|
|
550
|
+
: `已为 ${bookId} 完成章节修订。`,
|
|
551
|
+
en: `Completed ${request.intent} for ${bookId}.`,
|
|
552
|
+
})),
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
case "patch_chapter_text": {
|
|
556
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
557
|
+
if (!bookId) {
|
|
558
|
+
throw new Error(localize(language, {
|
|
559
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
560
|
+
en: "No active book is bound to the interaction session.",
|
|
561
|
+
}));
|
|
562
|
+
}
|
|
563
|
+
if (!request.chapterNumber || !request.targetText || !request.replacementText) {
|
|
564
|
+
throw new Error(localize(language, {
|
|
565
|
+
zh: "正文修补需要章节号、目标文本和替换文本。",
|
|
566
|
+
en: "Chapter patch requires chapter number, target text, and replacement text.",
|
|
567
|
+
}));
|
|
568
|
+
}
|
|
569
|
+
const toolResult = await params.tools.patchChapterText(bookId, request.chapterNumber, request.targetText, request.replacementText);
|
|
570
|
+
const metadata = extractToolMetadata(toolResult);
|
|
571
|
+
const chapterNumber = metadata.activeChapterNumber ?? request.chapterNumber;
|
|
572
|
+
session = bindActiveBook(session, bookId, chapterNumber);
|
|
573
|
+
session = appendToolEvents(session, metadata.events);
|
|
574
|
+
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language, chapterNumber);
|
|
575
|
+
const completed = pendingDecision
|
|
576
|
+
? {
|
|
577
|
+
...session,
|
|
578
|
+
pendingDecision,
|
|
579
|
+
currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, chapterNumber),
|
|
580
|
+
}
|
|
581
|
+
: {
|
|
582
|
+
...markCompleted(session),
|
|
583
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
584
|
+
};
|
|
585
|
+
return {
|
|
586
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
587
|
+
zh: `已修补 ${bookId} 的第 ${chapterNumber} 章。`,
|
|
588
|
+
en: `Patched chapter ${chapterNumber} for ${bookId}.`,
|
|
589
|
+
})),
|
|
590
|
+
responseText: metadata.responseText ?? (pendingDecision
|
|
591
|
+
? localize(language, {
|
|
592
|
+
zh: `已修补 ${bookId} 的第 ${chapterNumber} 章,等待你的下一步决定。`,
|
|
593
|
+
en: `Patched chapter ${chapterNumber} for ${bookId}; waiting for your next decision.`,
|
|
594
|
+
})
|
|
595
|
+
: localize(language, {
|
|
596
|
+
zh: `已修补 ${bookId} 的第 ${chapterNumber} 章。`,
|
|
597
|
+
en: `Patched chapter ${chapterNumber} for ${bookId}.`,
|
|
598
|
+
})),
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
case "rename_entity": {
|
|
602
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
603
|
+
if (!bookId) {
|
|
604
|
+
throw new Error(localize(language, {
|
|
605
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
606
|
+
en: "No active book is bound to the interaction session.",
|
|
607
|
+
}));
|
|
608
|
+
}
|
|
609
|
+
if (!request.oldValue || !request.newValue) {
|
|
610
|
+
throw new Error(localize(language, {
|
|
611
|
+
zh: "实体改名需要旧值和新值。",
|
|
612
|
+
en: "Entity rename requires old and new values.",
|
|
613
|
+
}));
|
|
614
|
+
}
|
|
615
|
+
const toolResult = await params.tools.renameEntity(bookId, request.oldValue, request.newValue);
|
|
616
|
+
const metadata = extractToolMetadata(toolResult);
|
|
617
|
+
session = bindActiveBook(session, bookId, metadata.activeChapterNumber);
|
|
618
|
+
session = appendToolEvents(session, metadata.events);
|
|
619
|
+
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language, metadata.activeChapterNumber);
|
|
620
|
+
const completed = pendingDecision
|
|
621
|
+
? {
|
|
622
|
+
...session,
|
|
623
|
+
pendingDecision,
|
|
624
|
+
currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, metadata.activeChapterNumber),
|
|
625
|
+
}
|
|
626
|
+
: {
|
|
627
|
+
...markCompleted(session),
|
|
628
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
629
|
+
};
|
|
630
|
+
return {
|
|
631
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
632
|
+
zh: `已在 ${bookId} 中把 ${request.oldValue} 改成 ${request.newValue}。`,
|
|
633
|
+
en: `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}.`,
|
|
634
|
+
})),
|
|
635
|
+
responseText: metadata.responseText ?? (pendingDecision
|
|
636
|
+
? localize(language, {
|
|
637
|
+
zh: `已在 ${bookId} 中把 ${request.oldValue} 改成 ${request.newValue},等待你的下一步决定。`,
|
|
638
|
+
en: `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}; waiting for your next decision.`,
|
|
639
|
+
})
|
|
640
|
+
: localize(language, {
|
|
641
|
+
zh: `已在 ${bookId} 中把 ${request.oldValue} 改成 ${request.newValue}。`,
|
|
642
|
+
en: `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}.`,
|
|
643
|
+
})),
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
case "update_focus": {
|
|
647
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
648
|
+
if (!bookId) {
|
|
649
|
+
throw new Error(localize(language, {
|
|
650
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
651
|
+
en: "No active book is bound to the interaction session.",
|
|
652
|
+
}));
|
|
653
|
+
}
|
|
654
|
+
if (!request.instruction) {
|
|
655
|
+
throw new Error(localize(language, {
|
|
656
|
+
zh: "更新焦点需要提供内容。",
|
|
657
|
+
en: "Focus update requires instruction content.",
|
|
658
|
+
}));
|
|
659
|
+
}
|
|
660
|
+
const toolResult = await params.tools.updateCurrentFocus(bookId, request.instruction);
|
|
661
|
+
const metadata = extractToolMetadata(toolResult);
|
|
662
|
+
session = bindActiveBook(session, bookId);
|
|
663
|
+
session = appendToolEvents(session, metadata.events);
|
|
664
|
+
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language);
|
|
665
|
+
const completed = pendingDecision
|
|
666
|
+
? {
|
|
667
|
+
...session,
|
|
668
|
+
pendingDecision,
|
|
669
|
+
currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language),
|
|
670
|
+
}
|
|
671
|
+
: {
|
|
672
|
+
...markCompleted(session),
|
|
673
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
674
|
+
};
|
|
675
|
+
return {
|
|
676
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
677
|
+
zh: `已更新 ${bookId} 的当前焦点。`,
|
|
678
|
+
en: `Updated current focus for ${bookId}.`,
|
|
679
|
+
})),
|
|
680
|
+
responseText: metadata.responseText ?? (pendingDecision
|
|
681
|
+
? localize(language, {
|
|
682
|
+
zh: `已更新 ${bookId} 的当前焦点,等待你的下一步决定。`,
|
|
683
|
+
en: `Updated current focus for ${bookId}; waiting for your next decision.`,
|
|
684
|
+
})
|
|
685
|
+
: localize(language, {
|
|
686
|
+
zh: `已更新 ${bookId} 的当前焦点。`,
|
|
687
|
+
en: `Updated current focus for ${bookId}.`,
|
|
688
|
+
})),
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
case "update_author_intent": {
|
|
692
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
693
|
+
if (!bookId) {
|
|
694
|
+
throw new Error(localize(language, {
|
|
695
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
696
|
+
en: "No active book is bound to the interaction session.",
|
|
697
|
+
}));
|
|
698
|
+
}
|
|
699
|
+
if (!request.instruction) {
|
|
700
|
+
throw new Error(localize(language, {
|
|
701
|
+
zh: "更新作者意图需要提供内容。",
|
|
702
|
+
en: "Author intent update requires instruction content.",
|
|
703
|
+
}));
|
|
704
|
+
}
|
|
705
|
+
const toolResult = await params.tools.updateAuthorIntent(bookId, request.instruction);
|
|
706
|
+
const metadata = extractToolMetadata(toolResult);
|
|
707
|
+
session = bindActiveBook(session, bookId);
|
|
708
|
+
session = appendToolEvents(session, metadata.events);
|
|
709
|
+
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language);
|
|
710
|
+
const completed = pendingDecision
|
|
711
|
+
? {
|
|
712
|
+
...session,
|
|
713
|
+
pendingDecision,
|
|
714
|
+
currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language),
|
|
715
|
+
}
|
|
716
|
+
: {
|
|
717
|
+
...markCompleted(session),
|
|
718
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
719
|
+
};
|
|
720
|
+
return {
|
|
721
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
722
|
+
zh: `已更新 ${bookId} 的作者意图。`,
|
|
723
|
+
en: `Updated author intent for ${bookId}.`,
|
|
724
|
+
})),
|
|
725
|
+
responseText: metadata.responseText ?? (pendingDecision
|
|
726
|
+
? localize(language, {
|
|
727
|
+
zh: `已更新 ${bookId} 的作者意图,等待你的下一步决定。`,
|
|
728
|
+
en: `Updated author intent for ${bookId}; waiting for your next decision.`,
|
|
729
|
+
})
|
|
730
|
+
: localize(language, {
|
|
731
|
+
zh: `已更新 ${bookId} 的作者意图。`,
|
|
732
|
+
en: `Updated author intent for ${bookId}.`,
|
|
733
|
+
})),
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
case "edit_truth": {
|
|
737
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
738
|
+
if (!bookId) {
|
|
739
|
+
throw new Error(localize(language, {
|
|
740
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
741
|
+
en: "No active book is bound to the interaction session.",
|
|
742
|
+
}));
|
|
743
|
+
}
|
|
744
|
+
if (!request.fileName || !request.instruction) {
|
|
745
|
+
throw new Error(localize(language, {
|
|
746
|
+
zh: "编辑真相文件需要文件名和内容。",
|
|
747
|
+
en: "Truth-file edit requires a file name and content.",
|
|
748
|
+
}));
|
|
749
|
+
}
|
|
750
|
+
const toolResult = await params.tools.writeTruthFile(bookId, request.fileName, request.instruction);
|
|
751
|
+
const metadata = extractToolMetadata(toolResult);
|
|
752
|
+
session = bindActiveBook(session, bookId);
|
|
753
|
+
session = appendToolEvents(session, metadata.events);
|
|
754
|
+
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language);
|
|
755
|
+
const completed = pendingDecision
|
|
756
|
+
? {
|
|
757
|
+
...session,
|
|
758
|
+
pendingDecision,
|
|
759
|
+
currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language),
|
|
760
|
+
}
|
|
761
|
+
: {
|
|
762
|
+
...markCompleted(session),
|
|
763
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
764
|
+
};
|
|
765
|
+
return {
|
|
766
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
767
|
+
zh: `已更新 ${bookId} 的 ${request.fileName}。`,
|
|
768
|
+
en: `Updated ${request.fileName} for ${bookId}.`,
|
|
769
|
+
})),
|
|
770
|
+
responseText: metadata.responseText ?? (pendingDecision
|
|
771
|
+
? localize(language, {
|
|
772
|
+
zh: `已更新 ${bookId} 的 ${request.fileName},等待你的下一步决定。`,
|
|
773
|
+
en: `Updated ${request.fileName} for ${bookId}; waiting for your next decision.`,
|
|
774
|
+
})
|
|
775
|
+
: localize(language, {
|
|
776
|
+
zh: `已更新 ${bookId} 的 ${request.fileName}。`,
|
|
777
|
+
en: `Updated ${request.fileName} for ${bookId}.`,
|
|
778
|
+
})),
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
case "export_book": {
|
|
782
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
783
|
+
if (!params.tools.exportBook) {
|
|
784
|
+
throw new Error(localize(language, {
|
|
785
|
+
zh: "交互运行时暂未实现导出作品。",
|
|
786
|
+
en: "Book export is not implemented in the interaction runtime yet.",
|
|
787
|
+
}));
|
|
788
|
+
}
|
|
789
|
+
if (!bookId) {
|
|
790
|
+
throw new Error(localize(language, {
|
|
791
|
+
zh: "当前交互会话还没有绑定作品。",
|
|
792
|
+
en: "No active book is bound to the interaction session.",
|
|
793
|
+
}));
|
|
794
|
+
}
|
|
795
|
+
const toolResult = await params.tools.exportBook(bookId, {
|
|
796
|
+
format: request.format,
|
|
797
|
+
approvedOnly: request.approvedOnly,
|
|
798
|
+
outputPath: request.outputPath,
|
|
799
|
+
});
|
|
800
|
+
const metadata = extractToolMetadata(toolResult);
|
|
801
|
+
session = bindActiveBook(session, bookId, metadata.activeChapterNumber);
|
|
802
|
+
session = appendToolEvents(session, metadata.events);
|
|
803
|
+
const completed = {
|
|
804
|
+
...markCompleted(session),
|
|
805
|
+
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
806
|
+
};
|
|
807
|
+
return {
|
|
808
|
+
session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
809
|
+
zh: `已导出 ${bookId}。`,
|
|
810
|
+
en: `Exported ${bookId}.`,
|
|
811
|
+
})),
|
|
812
|
+
responseText: metadata.responseText ?? localize(language, {
|
|
813
|
+
zh: `已导出 ${bookId}。`,
|
|
814
|
+
en: `Exported ${bookId}.`,
|
|
815
|
+
}),
|
|
816
|
+
details: metadata.details,
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
case "switch_mode":
|
|
820
|
+
session = markCompleted(session);
|
|
821
|
+
return {
|
|
822
|
+
session: addEvent(session, "task.completed", "completed", localize(language, {
|
|
823
|
+
zh: `已切换到${localizeMode(session.automationMode, language)}模式。`,
|
|
824
|
+
en: `Switched mode to ${session.automationMode}.`,
|
|
825
|
+
})),
|
|
826
|
+
responseText: localize(language, {
|
|
827
|
+
zh: `已切换到${localizeMode(session.automationMode, language)}模式。`,
|
|
828
|
+
en: `Switched mode to ${session.automationMode}.`,
|
|
829
|
+
}),
|
|
830
|
+
};
|
|
831
|
+
case "pause_book": {
|
|
832
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
833
|
+
const paused = {
|
|
834
|
+
...session,
|
|
835
|
+
currentExecution: {
|
|
836
|
+
status: "blocked",
|
|
837
|
+
bookId,
|
|
838
|
+
chapterNumber: session.activeChapterNumber,
|
|
839
|
+
stageLabel: localize(language, {
|
|
840
|
+
zh: "已由用户暂停",
|
|
841
|
+
en: "paused by user",
|
|
842
|
+
}),
|
|
843
|
+
},
|
|
844
|
+
};
|
|
845
|
+
return {
|
|
846
|
+
session: addEvent(paused, "task.completed", "blocked", localize(language, {
|
|
847
|
+
zh: `已暂停${bookId ?? "当前作品"}。`,
|
|
848
|
+
en: `Paused ${bookId ?? "current book"}.`,
|
|
849
|
+
})),
|
|
850
|
+
responseText: localize(language, {
|
|
851
|
+
zh: `已暂停${bookId ?? "当前作品"}。`,
|
|
852
|
+
en: `Paused ${bookId ?? "current book"}.`,
|
|
853
|
+
}),
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
case "resume_book": {
|
|
857
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
858
|
+
const resumed = {
|
|
859
|
+
...session,
|
|
860
|
+
currentExecution: {
|
|
861
|
+
status: "completed",
|
|
862
|
+
bookId,
|
|
863
|
+
chapterNumber: session.activeChapterNumber,
|
|
864
|
+
stageLabel: localize(language, {
|
|
865
|
+
zh: "可继续执行",
|
|
866
|
+
en: "ready to continue",
|
|
867
|
+
}),
|
|
868
|
+
},
|
|
869
|
+
};
|
|
870
|
+
return {
|
|
871
|
+
session: addEvent(resumed, "task.completed", "completed", localize(language, {
|
|
872
|
+
zh: `已恢复${bookId ?? "当前作品"}。`,
|
|
873
|
+
en: `Resumed ${bookId ?? "current book"}.`,
|
|
874
|
+
})),
|
|
875
|
+
responseText: localize(language, {
|
|
876
|
+
zh: `已恢复${bookId ?? "当前作品"}。`,
|
|
877
|
+
en: `Resumed ${bookId ?? "current book"}.`,
|
|
878
|
+
}),
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
case "chat": {
|
|
882
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
883
|
+
const prompt = request.instruction?.trim().toLowerCase() ?? "";
|
|
884
|
+
const toolResult = params.tools.chat
|
|
885
|
+
? await params.tools.chat(request.instruction ?? "", {
|
|
886
|
+
bookId,
|
|
887
|
+
automationMode: session.automationMode,
|
|
888
|
+
})
|
|
889
|
+
: undefined;
|
|
890
|
+
const metadata = extractToolMetadata(toolResult);
|
|
891
|
+
const responseText = metadata.responseText ?? (/^(hi|hello|hey|你好|嗨|哈喽)$/i.test(prompt)
|
|
892
|
+
? (bookId
|
|
893
|
+
? localize(language, {
|
|
894
|
+
zh: `你好。当前作品是 ${bookId}。你可以让我继续写、修订章节,或者解释当前卡住的原因。`,
|
|
895
|
+
en: `Hi. Active book is ${bookId}. Ask me to continue, revise a chapter, or explain what is blocked.`,
|
|
896
|
+
})
|
|
897
|
+
: localize(language, {
|
|
898
|
+
zh: "你好。当前还没有激活作品。你可以先打开作品、列出作品,或者直接告诉我你要写什么。",
|
|
899
|
+
en: "Hi. No active book yet. Open a book, list books, or tell me what you want to write.",
|
|
900
|
+
}))
|
|
901
|
+
: (bookId
|
|
902
|
+
? localize(language, {
|
|
903
|
+
zh: `我在。当前作品是 ${bookId}。你可以让我继续写、修订章节、重写、调整焦点,或者查看流水线为何停止。`,
|
|
904
|
+
en: `I’m here. Active book is ${bookId}. You can ask me to continue, revise a chapter, rewrite, change focus, or inspect why the pipeline stopped.`,
|
|
905
|
+
})
|
|
906
|
+
: localize(language, {
|
|
907
|
+
zh: "我在。当前还没有绑定作品。先打开作品、列出作品,或者直接描述你要写什么。",
|
|
908
|
+
en: "I’m here. No active book is bound yet. Open a book, list books, or describe what you want to write.",
|
|
909
|
+
})));
|
|
910
|
+
const completed = markCompleted(session);
|
|
911
|
+
return {
|
|
912
|
+
session: addEvent(completed, "task.completed", "completed", responseText),
|
|
913
|
+
responseText,
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
case "explain_status":
|
|
917
|
+
case "explain_failure": {
|
|
918
|
+
const bookId = request.bookId ?? session.activeBookId;
|
|
919
|
+
const baselineExecution = params.session.currentExecution;
|
|
920
|
+
const stage = baselineExecution?.stageLabel ?? baselineExecution?.status ?? "idle";
|
|
921
|
+
const summary = request.intent === "explain_failure"
|
|
922
|
+
? localize(language, {
|
|
923
|
+
zh: `当前失败上下文:${bookId ?? "当前无激活作品"} 处于 ${stage}。`,
|
|
924
|
+
en: `Current failure context: ${bookId ?? "no active book"} is at ${stage}.`,
|
|
925
|
+
})
|
|
926
|
+
: localize(language, {
|
|
927
|
+
zh: `当前状态:${bookId ?? "当前无激活作品"} 处于 ${stage}。`,
|
|
928
|
+
en: `Current status: ${bookId ?? "no active book"} is at ${stage}.`,
|
|
929
|
+
});
|
|
930
|
+
const completed = markCompleted(session);
|
|
931
|
+
return {
|
|
932
|
+
session: addEvent(completed, "task.completed", "completed", summary),
|
|
933
|
+
responseText: summary,
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
default:
|
|
937
|
+
throw new Error(localize(language, {
|
|
938
|
+
zh: `交互运行时暂未实现意图「${request.intent}」。`,
|
|
939
|
+
en: `Intent "${request.intent}" is not implemented in the interaction runtime yet.`,
|
|
940
|
+
}));
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
//# sourceMappingURL=runtime.js.map
|