|
@@ -11,6 +11,7 @@ import {
|
|
|
} from "./session.js";
|
|
} from "./session.js";
|
|
|
|
|
|
|
|
type ReviseMode = "local-fix" | "rewrite";
|
|
type ReviseMode = "local-fix" | "rewrite";
|
|
|
|
|
+type RuntimeLanguage = "zh" | "en";
|
|
|
|
|
|
|
|
export interface InteractionRuntimeTools {
|
|
export interface InteractionRuntimeTools {
|
|
|
readonly listBooks: () => Promise<ReadonlyArray<string>>;
|
|
readonly listBooks: () => Promise<ReadonlyArray<string>>;
|
|
@@ -91,9 +92,30 @@ function extractToolMetadata(value: unknown): InteractionToolMetadata {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function resolveRuntimeLanguage(request: InteractionRequest): RuntimeLanguage {
|
|
|
|
|
+ return request.language === "en" ? "en" : "zh";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function localize<T>(language: RuntimeLanguage, messages: { zh: T; en: T }): T {
|
|
|
|
|
+ return language === "en" ? messages.en : messages.zh;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function localizeMode(mode: AutomationMode, language: RuntimeLanguage): string {
|
|
|
|
|
+ if (language === "en") {
|
|
|
|
|
+ return mode;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ auto: "自动",
|
|
|
|
|
+ semi: "半自动",
|
|
|
|
|
+ manual: "手动",
|
|
|
|
|
+ }[mode] ?? mode;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function buildTaskStartedState(
|
|
function buildTaskStartedState(
|
|
|
session: InteractionSession,
|
|
session: InteractionSession,
|
|
|
request: InteractionRequest,
|
|
request: InteractionRequest,
|
|
|
|
|
+ language: RuntimeLanguage,
|
|
|
): ExecutionState {
|
|
): ExecutionState {
|
|
|
switch (request.intent) {
|
|
switch (request.intent) {
|
|
|
case "write_next":
|
|
case "write_next":
|
|
@@ -102,20 +124,29 @@ function buildTaskStartedState(
|
|
|
status: "planning",
|
|
status: "planning",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
chapterNumber: session.activeChapterNumber,
|
|
chapterNumber: session.activeChapterNumber,
|
|
|
- stageLabel: "preparing chapter inputs",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "准备章节输入",
|
|
|
|
|
+ en: "preparing chapter inputs",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
case "create_book":
|
|
case "create_book":
|
|
|
return {
|
|
return {
|
|
|
status: "planning",
|
|
status: "planning",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
- stageLabel: "creating book foundation",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "创建作品基础",
|
|
|
|
|
+ en: "creating book foundation",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
case "export_book":
|
|
case "export_book":
|
|
|
return {
|
|
return {
|
|
|
status: "persisting",
|
|
status: "persisting",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
chapterNumber: session.activeChapterNumber,
|
|
chapterNumber: session.activeChapterNumber,
|
|
|
- stageLabel: "exporting book artifacts",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "导出作品文件",
|
|
|
|
|
+ en: "exporting book artifacts",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
case "revise_chapter":
|
|
case "revise_chapter":
|
|
|
case "rewrite_chapter":
|
|
case "rewrite_chapter":
|
|
@@ -123,7 +154,9 @@ function buildTaskStartedState(
|
|
|
status: "repairing",
|
|
status: "repairing",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
chapterNumber: request.chapterNumber ?? session.activeChapterNumber,
|
|
chapterNumber: request.chapterNumber ?? session.activeChapterNumber,
|
|
|
- stageLabel: request.intent === "rewrite_chapter" ? "rewriting chapter" : "revising chapter",
|
|
|
|
|
|
|
+ stageLabel: request.intent === "rewrite_chapter"
|
|
|
|
|
+ ? localize(language, { zh: "重写章节", en: "rewriting chapter" })
|
|
|
|
|
+ : localize(language, { zh: "修订章节", en: "revising chapter" }),
|
|
|
};
|
|
};
|
|
|
case "update_focus":
|
|
case "update_focus":
|
|
|
case "update_author_intent":
|
|
case "update_author_intent":
|
|
@@ -132,21 +165,30 @@ function buildTaskStartedState(
|
|
|
status: "persisting",
|
|
status: "persisting",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
chapterNumber: session.activeChapterNumber,
|
|
chapterNumber: session.activeChapterNumber,
|
|
|
- stageLabel: "applying project edit",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "应用项目修改",
|
|
|
|
|
+ en: "applying project edit",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
case "pause_book":
|
|
case "pause_book":
|
|
|
return {
|
|
return {
|
|
|
status: "blocked",
|
|
status: "blocked",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
chapterNumber: session.activeChapterNumber,
|
|
chapterNumber: session.activeChapterNumber,
|
|
|
- stageLabel: "paused by user",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "已由用户暂停",
|
|
|
|
|
+ en: "paused by user",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
default:
|
|
default:
|
|
|
return {
|
|
return {
|
|
|
status: "planning",
|
|
status: "planning",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
chapterNumber: session.activeChapterNumber,
|
|
chapterNumber: session.activeChapterNumber,
|
|
|
- stageLabel: `handling ${request.intent}`,
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: `处理中:${request.intent}`,
|
|
|
|
|
+ en: `handling ${request.intent}`,
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -177,6 +219,7 @@ function shouldWaitForHuman(
|
|
|
function buildPendingDecision(
|
|
function buildPendingDecision(
|
|
|
session: InteractionSession,
|
|
session: InteractionSession,
|
|
|
request: InteractionRequest,
|
|
request: InteractionRequest,
|
|
|
|
|
+ language: RuntimeLanguage,
|
|
|
chapterNumber?: number,
|
|
chapterNumber?: number,
|
|
|
): PendingDecision | undefined {
|
|
): PendingDecision | undefined {
|
|
|
if (!shouldWaitForHuman(session.automationMode, request)) {
|
|
if (!shouldWaitForHuman(session.automationMode, request)) {
|
|
@@ -193,21 +236,31 @@ function buildPendingDecision(
|
|
|
bookId,
|
|
bookId,
|
|
|
...(chapterNumber !== undefined ? { chapterNumber } : {}),
|
|
...(chapterNumber !== undefined ? { chapterNumber } : {}),
|
|
|
summary: session.automationMode === "manual"
|
|
summary: session.automationMode === "manual"
|
|
|
- ? "Execution finished. Choose the next action explicitly."
|
|
|
|
|
- : "Execution finished. Waiting for your next decision.",
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: "执行已完成。请明确选择下一步操作。",
|
|
|
|
|
+ en: "Execution finished. Choose the next action explicitly.",
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: "执行已完成,等待你的下一步决定。",
|
|
|
|
|
+ en: "Execution finished. Waiting for your next decision.",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function buildWaitingExecution(
|
|
function buildWaitingExecution(
|
|
|
session: InteractionSession,
|
|
session: InteractionSession,
|
|
|
request: InteractionRequest,
|
|
request: InteractionRequest,
|
|
|
|
|
+ language: RuntimeLanguage,
|
|
|
chapterNumber?: number,
|
|
chapterNumber?: number,
|
|
|
): ExecutionState {
|
|
): ExecutionState {
|
|
|
return {
|
|
return {
|
|
|
status: "waiting_human",
|
|
status: "waiting_human",
|
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
bookId: request.bookId ?? session.activeBookId,
|
|
|
...(chapterNumber !== undefined ? { chapterNumber } : {}),
|
|
...(chapterNumber !== undefined ? { chapterNumber } : {}),
|
|
|
- stageLabel: "waiting for your next decision",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "等待你的下一步决定",
|
|
|
|
|
+ en: "waiting for your next decision",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -232,6 +285,7 @@ export async function runInteractionRequest(params: {
|
|
|
readonly tools: InteractionRuntimeTools;
|
|
readonly tools: InteractionRuntimeTools;
|
|
|
}): Promise<InteractionRuntimeResult> {
|
|
}): Promise<InteractionRuntimeResult> {
|
|
|
const request = routeInteractionRequest(params.request);
|
|
const request = routeInteractionRequest(params.request);
|
|
|
|
|
+ const language = resolveRuntimeLanguage(request);
|
|
|
let session = params.session;
|
|
let session = params.session;
|
|
|
const addEvent = (
|
|
const addEvent = (
|
|
|
nextSession: InteractionSession,
|
|
nextSession: InteractionSession,
|
|
@@ -253,9 +307,12 @@ export async function runInteractionRequest(params: {
|
|
|
|
|
|
|
|
session = clearPendingDecision({
|
|
session = clearPendingDecision({
|
|
|
...session,
|
|
...session,
|
|
|
- currentExecution: buildTaskStartedState(session, request),
|
|
|
|
|
|
|
+ currentExecution: buildTaskStartedState(session, request, language),
|
|
|
});
|
|
});
|
|
|
- session = addEvent(session, "task.started", session.currentExecution!.status, `Started ${request.intent}.`);
|
|
|
|
|
|
|
+ session = addEvent(session, "task.started", session.currentExecution!.status, localize(language, {
|
|
|
|
|
+ zh: `开始执行 ${request.intent}。`,
|
|
|
|
|
+ en: `Started ${request.intent}.`,
|
|
|
|
|
+ }));
|
|
|
|
|
|
|
|
const markCompleted = (nextSession: InteractionSession): InteractionSession => ({
|
|
const markCompleted = (nextSession: InteractionSession): InteractionSession => ({
|
|
|
...nextSession,
|
|
...nextSession,
|
|
@@ -263,17 +320,26 @@ export async function runInteractionRequest(params: {
|
|
|
status: "completed",
|
|
status: "completed",
|
|
|
bookId: nextSession.activeBookId,
|
|
bookId: nextSession.activeBookId,
|
|
|
chapterNumber: nextSession.activeChapterNumber,
|
|
chapterNumber: nextSession.activeChapterNumber,
|
|
|
- stageLabel: "completed",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "已完成",
|
|
|
|
|
+ en: "completed",
|
|
|
|
|
+ }),
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
switch (request.intent) {
|
|
switch (request.intent) {
|
|
|
case "create_book": {
|
|
case "create_book": {
|
|
|
if (!params.tools.createBook) {
|
|
if (!params.tools.createBook) {
|
|
|
- throw new Error("Book creation is not implemented in the interaction runtime yet.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "交互运行时暂未实现创建作品。",
|
|
|
|
|
+ en: "Book creation is not implemented in the interaction runtime yet.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!request.title) {
|
|
if (!request.title) {
|
|
|
- throw new Error("Book creation requires a title.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "创建作品需要标题。",
|
|
|
|
|
+ en: "Book creation requires a title.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.createBook({
|
|
const toolResult = await params.tools.createBook({
|
|
|
title: request.title,
|
|
title: request.title,
|
|
@@ -289,7 +355,10 @@ export async function runInteractionRequest(params: {
|
|
|
? (toolResult as { bookId: string }).bookId
|
|
? (toolResult as { bookId: string }).bookId
|
|
|
: undefined;
|
|
: undefined;
|
|
|
if (!createdBookId) {
|
|
if (!createdBookId) {
|
|
|
- throw new Error("Create-book tool did not return a book id.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "创建作品工具没有返回作品 ID。",
|
|
|
|
|
+ en: "Create-book tool did not return a book id.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
session = bindActiveBook(session, createdBookId);
|
|
session = bindActiveBook(session, createdBookId);
|
|
|
session = appendToolEvents(session, metadata.events);
|
|
session = appendToolEvents(session, metadata.events);
|
|
@@ -298,8 +367,14 @@ export async function runInteractionRequest(params: {
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Created ${createdBookId}.`),
|
|
|
|
|
- responseText: metadata.responseText ?? `Created ${createdBookId}.`,
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已创建作品 ${createdBookId}。`,
|
|
|
|
|
+ en: `Created ${createdBookId}.`,
|
|
|
|
|
+ })),
|
|
|
|
|
+ responseText: metadata.responseText ?? localize(language, {
|
|
|
|
|
+ zh: `已创建作品 ${createdBookId}。`,
|
|
|
|
|
+ en: `Created ${createdBookId}.`,
|
|
|
|
|
+ }),
|
|
|
details: metadata.details,
|
|
details: metadata.details,
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
@@ -307,7 +382,10 @@ export async function runInteractionRequest(params: {
|
|
|
case "continue_book": {
|
|
case "continue_book": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.writeNextChapter(bookId);
|
|
const toolResult = await params.tools.writeNextChapter(bookId);
|
|
|
const metadata = extractToolMetadata(toolResult);
|
|
const metadata = extractToolMetadata(toolResult);
|
|
@@ -316,24 +394,34 @@ export async function runInteractionRequest(params: {
|
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
|
session,
|
|
session,
|
|
|
request,
|
|
request,
|
|
|
|
|
+ language,
|
|
|
metadata.activeChapterNumber,
|
|
metadata.activeChapterNumber,
|
|
|
);
|
|
);
|
|
|
const completed = pendingDecision
|
|
const completed = pendingDecision
|
|
|
? {
|
|
? {
|
|
|
...session,
|
|
...session,
|
|
|
pendingDecision,
|
|
pendingDecision,
|
|
|
- currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, metadata.activeChapterNumber),
|
|
|
|
|
|
|
+ currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, metadata.activeChapterNumber),
|
|
|
}
|
|
}
|
|
|
: {
|
|
: {
|
|
|
...markCompleted(session),
|
|
...markCompleted(session),
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Completed write_next for ${bookId}.`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已为 ${bookId} 完成下一章写作。`,
|
|
|
|
|
+ en: `Completed write_next for ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
responseText: metadata.responseText ?? (
|
|
responseText: metadata.responseText ?? (
|
|
|
pendingDecision
|
|
pendingDecision
|
|
|
- ? `Completed write_next for ${bookId}; waiting for your next decision.`
|
|
|
|
|
- : `Completed write_next for ${bookId}.`
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `已为 ${bookId} 完成下一章写作,等待你的下一步决定。`,
|
|
|
|
|
+ en: `Completed write_next for ${bookId}; waiting for your next decision.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: `已为 ${bookId} 完成下一章写作。`,
|
|
|
|
|
+ en: `Completed write_next for ${bookId}.`,
|
|
|
|
|
+ })
|
|
|
),
|
|
),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
@@ -341,34 +429,61 @@ export async function runInteractionRequest(params: {
|
|
|
const books = await params.tools.listBooks();
|
|
const books = await params.tools.listBooks();
|
|
|
const completed = markCompleted(session);
|
|
const completed = markCompleted(session);
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Listed ${books.length} book(s).`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已列出 ${books.length} 本作品。`,
|
|
|
|
|
+ en: `Listed ${books.length} book(s).`,
|
|
|
|
|
+ })),
|
|
|
responseText: books.length > 0
|
|
responseText: books.length > 0
|
|
|
- ? `Books: ${books.join(", ")}`
|
|
|
|
|
- : "No books found in this project.",
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `作品列表:${books.join("、")}`,
|
|
|
|
|
+ en: `Books: ${books.join(", ")}`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: "当前项目下没有作品。",
|
|
|
|
|
+ en: "No books found in this project.",
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "select_book": {
|
|
case "select_book": {
|
|
|
if (!request.bookId) {
|
|
if (!request.bookId) {
|
|
|
- throw new Error("Book selection requires a book id.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "切换作品需要提供作品 ID。",
|
|
|
|
|
+ en: "Book selection requires a book id.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const books = await params.tools.listBooks();
|
|
const books = await params.tools.listBooks();
|
|
|
if (!books.includes(request.bookId)) {
|
|
if (!books.includes(request.bookId)) {
|
|
|
- throw new Error(`Book "${request.bookId}" not found in this project.`);
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: `当前项目中找不到作品「${request.bookId}」。`,
|
|
|
|
|
+ en: `Book "${request.bookId}" not found in this project.`,
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const completed = markCompleted(bindActiveBook(session, request.bookId));
|
|
const completed = markCompleted(bindActiveBook(session, request.bookId));
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Bound active book to ${request.bookId}.`),
|
|
|
|
|
- responseText: `Opened ${request.bookId}.`,
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已切换当前作品到 ${request.bookId}。`,
|
|
|
|
|
+ en: `Bound active book to ${request.bookId}.`,
|
|
|
|
|
+ })),
|
|
|
|
|
+ responseText: localize(language, {
|
|
|
|
|
+ zh: `当前作品:${request.bookId}`,
|
|
|
|
|
+ en: `Active book: ${request.bookId}`,
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "revise_chapter":
|
|
case "revise_chapter":
|
|
|
case "rewrite_chapter": {
|
|
case "rewrite_chapter": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!request.chapterNumber) {
|
|
if (!request.chapterNumber) {
|
|
|
- throw new Error("Chapter number is required for chapter revision.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "修订章节需要章节号。",
|
|
|
|
|
+ en: "Chapter number is required for chapter revision.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const mode: ReviseMode = request.intent === "rewrite_chapter" ? "rewrite" : "local-fix";
|
|
const mode: ReviseMode = request.intent === "rewrite_chapter" ? "rewrite" : "local-fix";
|
|
|
const toolResult = await params.tools.reviseDraft(bookId, request.chapterNumber, mode);
|
|
const toolResult = await params.tools.reviseDraft(bookId, request.chapterNumber, mode);
|
|
@@ -379,34 +494,56 @@ export async function runInteractionRequest(params: {
|
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
|
session,
|
|
session,
|
|
|
request,
|
|
request,
|
|
|
|
|
+ language,
|
|
|
chapterNumber,
|
|
chapterNumber,
|
|
|
);
|
|
);
|
|
|
const completed = pendingDecision
|
|
const completed = pendingDecision
|
|
|
? {
|
|
? {
|
|
|
...session,
|
|
...session,
|
|
|
pendingDecision,
|
|
pendingDecision,
|
|
|
- currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, chapterNumber),
|
|
|
|
|
|
|
+ currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, chapterNumber),
|
|
|
}
|
|
}
|
|
|
: {
|
|
: {
|
|
|
...markCompleted(session),
|
|
...markCompleted(session),
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Completed ${request.intent} for ${bookId}.`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: request.intent === "rewrite_chapter"
|
|
|
|
|
+ ? `已为 ${bookId} 完成章节重写。`
|
|
|
|
|
+ : `已为 ${bookId} 完成章节修订。`,
|
|
|
|
|
+ en: `Completed ${request.intent} for ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
responseText: metadata.responseText ?? (
|
|
responseText: metadata.responseText ?? (
|
|
|
pendingDecision
|
|
pendingDecision
|
|
|
- ? `Completed ${request.intent} for ${bookId}; waiting for your next decision.`
|
|
|
|
|
- : `Completed ${request.intent} for ${bookId}.`
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: request.intent === "rewrite_chapter"
|
|
|
|
|
+ ? `已为 ${bookId} 完成章节重写,等待你的下一步决定。`
|
|
|
|
|
+ : `已为 ${bookId} 完成章节修订,等待你的下一步决定。`,
|
|
|
|
|
+ en: `Completed ${request.intent} for ${bookId}; waiting for your next decision.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: request.intent === "rewrite_chapter"
|
|
|
|
|
+ ? `已为 ${bookId} 完成章节重写。`
|
|
|
|
|
+ : `已为 ${bookId} 完成章节修订。`,
|
|
|
|
|
+ en: `Completed ${request.intent} for ${bookId}.`,
|
|
|
|
|
+ })
|
|
|
),
|
|
),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "patch_chapter_text": {
|
|
case "patch_chapter_text": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!request.chapterNumber || !request.targetText || !request.replacementText) {
|
|
if (!request.chapterNumber || !request.targetText || !request.replacementText) {
|
|
|
- throw new Error("Chapter patch requires chapter number, target text, and replacement text.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "正文修补需要章节号、目标文本和替换文本。",
|
|
|
|
|
+ en: "Chapter patch requires chapter number, target text, and replacement text.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.patchChapterText(
|
|
const toolResult = await params.tools.patchChapterText(
|
|
|
bookId,
|
|
bookId,
|
|
@@ -421,34 +558,50 @@ export async function runInteractionRequest(params: {
|
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
|
session,
|
|
session,
|
|
|
request,
|
|
request,
|
|
|
|
|
+ language,
|
|
|
chapterNumber,
|
|
chapterNumber,
|
|
|
);
|
|
);
|
|
|
const completed = pendingDecision
|
|
const completed = pendingDecision
|
|
|
? {
|
|
? {
|
|
|
...session,
|
|
...session,
|
|
|
pendingDecision,
|
|
pendingDecision,
|
|
|
- currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, chapterNumber),
|
|
|
|
|
|
|
+ currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, chapterNumber),
|
|
|
}
|
|
}
|
|
|
: {
|
|
: {
|
|
|
...markCompleted(session),
|
|
...markCompleted(session),
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Patched chapter ${chapterNumber} for ${bookId}.`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已修补 ${bookId} 的第 ${chapterNumber} 章。`,
|
|
|
|
|
+ en: `Patched chapter ${chapterNumber} for ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
responseText: metadata.responseText ?? (
|
|
responseText: metadata.responseText ?? (
|
|
|
pendingDecision
|
|
pendingDecision
|
|
|
- ? `Patched chapter ${chapterNumber} for ${bookId}; waiting for your next decision.`
|
|
|
|
|
- : `Patched chapter ${chapterNumber} for ${bookId}.`
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `已修补 ${bookId} 的第 ${chapterNumber} 章,等待你的下一步决定。`,
|
|
|
|
|
+ en: `Patched chapter ${chapterNumber} for ${bookId}; waiting for your next decision.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: `已修补 ${bookId} 的第 ${chapterNumber} 章。`,
|
|
|
|
|
+ en: `Patched chapter ${chapterNumber} for ${bookId}.`,
|
|
|
|
|
+ })
|
|
|
),
|
|
),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "rename_entity": {
|
|
case "rename_entity": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!request.oldValue || !request.newValue) {
|
|
if (!request.oldValue || !request.newValue) {
|
|
|
- throw new Error("Entity rename requires old and new values.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "实体改名需要旧值和新值。",
|
|
|
|
|
+ en: "Entity rename requires old and new values.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.renameEntity(bookId, request.oldValue, request.newValue);
|
|
const toolResult = await params.tools.renameEntity(bookId, request.oldValue, request.newValue);
|
|
|
const metadata = extractToolMetadata(toolResult);
|
|
const metadata = extractToolMetadata(toolResult);
|
|
@@ -457,130 +610,191 @@ export async function runInteractionRequest(params: {
|
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(
|
|
|
session,
|
|
session,
|
|
|
request,
|
|
request,
|
|
|
|
|
+ language,
|
|
|
metadata.activeChapterNumber,
|
|
metadata.activeChapterNumber,
|
|
|
);
|
|
);
|
|
|
const completed = pendingDecision
|
|
const completed = pendingDecision
|
|
|
? {
|
|
? {
|
|
|
...session,
|
|
...session,
|
|
|
pendingDecision,
|
|
pendingDecision,
|
|
|
- currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, metadata.activeChapterNumber),
|
|
|
|
|
|
|
+ currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language, metadata.activeChapterNumber),
|
|
|
}
|
|
}
|
|
|
: {
|
|
: {
|
|
|
...markCompleted(session),
|
|
...markCompleted(session),
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}.`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已在 ${bookId} 中把 ${request.oldValue} 改成 ${request.newValue}。`,
|
|
|
|
|
+ en: `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
responseText: metadata.responseText ?? (
|
|
responseText: metadata.responseText ?? (
|
|
|
pendingDecision
|
|
pendingDecision
|
|
|
- ? `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}; waiting for your next decision.`
|
|
|
|
|
- : `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}.`
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `已在 ${bookId} 中把 ${request.oldValue} 改成 ${request.newValue},等待你的下一步决定。`,
|
|
|
|
|
+ en: `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}; waiting for your next decision.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: `已在 ${bookId} 中把 ${request.oldValue} 改成 ${request.newValue}。`,
|
|
|
|
|
+ en: `Renamed ${request.oldValue} to ${request.newValue} in ${bookId}.`,
|
|
|
|
|
+ })
|
|
|
),
|
|
),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "update_focus": {
|
|
case "update_focus": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!request.instruction) {
|
|
if (!request.instruction) {
|
|
|
- throw new Error("Focus update requires instruction content.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "更新焦点需要提供内容。",
|
|
|
|
|
+ en: "Focus update requires instruction content.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.updateCurrentFocus(bookId, request.instruction);
|
|
const toolResult = await params.tools.updateCurrentFocus(bookId, request.instruction);
|
|
|
const metadata = extractToolMetadata(toolResult);
|
|
const metadata = extractToolMetadata(toolResult);
|
|
|
session = bindActiveBook(session, bookId);
|
|
session = bindActiveBook(session, bookId);
|
|
|
session = appendToolEvents(session, metadata.events);
|
|
session = appendToolEvents(session, metadata.events);
|
|
|
- const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request);
|
|
|
|
|
|
|
+ const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language);
|
|
|
const completed = pendingDecision
|
|
const completed = pendingDecision
|
|
|
? {
|
|
? {
|
|
|
...session,
|
|
...session,
|
|
|
pendingDecision,
|
|
pendingDecision,
|
|
|
- currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request),
|
|
|
|
|
|
|
+ currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language),
|
|
|
}
|
|
}
|
|
|
: {
|
|
: {
|
|
|
...markCompleted(session),
|
|
...markCompleted(session),
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Updated current focus for ${bookId}.`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的当前焦点。`,
|
|
|
|
|
+ en: `Updated current focus for ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
responseText: metadata.responseText ?? (
|
|
responseText: metadata.responseText ?? (
|
|
|
pendingDecision
|
|
pendingDecision
|
|
|
- ? `Updated current focus for ${bookId}; waiting for your next decision.`
|
|
|
|
|
- : `Updated current focus for ${bookId}.`
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的当前焦点,等待你的下一步决定。`,
|
|
|
|
|
+ en: `Updated current focus for ${bookId}; waiting for your next decision.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的当前焦点。`,
|
|
|
|
|
+ en: `Updated current focus for ${bookId}.`,
|
|
|
|
|
+ })
|
|
|
),
|
|
),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "update_author_intent": {
|
|
case "update_author_intent": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!request.instruction) {
|
|
if (!request.instruction) {
|
|
|
- throw new Error("Author intent update requires instruction content.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "更新作者意图需要提供内容。",
|
|
|
|
|
+ en: "Author intent update requires instruction content.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.updateAuthorIntent(bookId, request.instruction);
|
|
const toolResult = await params.tools.updateAuthorIntent(bookId, request.instruction);
|
|
|
const metadata = extractToolMetadata(toolResult);
|
|
const metadata = extractToolMetadata(toolResult);
|
|
|
session = bindActiveBook(session, bookId);
|
|
session = bindActiveBook(session, bookId);
|
|
|
session = appendToolEvents(session, metadata.events);
|
|
session = appendToolEvents(session, metadata.events);
|
|
|
- const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request);
|
|
|
|
|
|
|
+ const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language);
|
|
|
const completed = pendingDecision
|
|
const completed = pendingDecision
|
|
|
? {
|
|
? {
|
|
|
...session,
|
|
...session,
|
|
|
pendingDecision,
|
|
pendingDecision,
|
|
|
- currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request),
|
|
|
|
|
|
|
+ currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language),
|
|
|
}
|
|
}
|
|
|
: {
|
|
: {
|
|
|
...markCompleted(session),
|
|
...markCompleted(session),
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Updated author intent for ${bookId}.`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的作者意图。`,
|
|
|
|
|
+ en: `Updated author intent for ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
responseText: metadata.responseText ?? (
|
|
responseText: metadata.responseText ?? (
|
|
|
pendingDecision
|
|
pendingDecision
|
|
|
- ? `Updated author intent for ${bookId}; waiting for your next decision.`
|
|
|
|
|
- : `Updated author intent for ${bookId}.`
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的作者意图,等待你的下一步决定。`,
|
|
|
|
|
+ en: `Updated author intent for ${bookId}; waiting for your next decision.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的作者意图。`,
|
|
|
|
|
+ en: `Updated author intent for ${bookId}.`,
|
|
|
|
|
+ })
|
|
|
),
|
|
),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "edit_truth": {
|
|
case "edit_truth": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!request.fileName || !request.instruction) {
|
|
if (!request.fileName || !request.instruction) {
|
|
|
- throw new Error("Truth-file edit requires a file name and content.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "编辑真相文件需要文件名和内容。",
|
|
|
|
|
+ en: "Truth-file edit requires a file name and content.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.writeTruthFile(bookId, request.fileName, request.instruction);
|
|
const toolResult = await params.tools.writeTruthFile(bookId, request.fileName, request.instruction);
|
|
|
const metadata = extractToolMetadata(toolResult);
|
|
const metadata = extractToolMetadata(toolResult);
|
|
|
session = bindActiveBook(session, bookId);
|
|
session = bindActiveBook(session, bookId);
|
|
|
session = appendToolEvents(session, metadata.events);
|
|
session = appendToolEvents(session, metadata.events);
|
|
|
- const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request);
|
|
|
|
|
|
|
+ const pendingDecision = metadata.pendingDecision ?? buildPendingDecision(session, request, language);
|
|
|
const completed = pendingDecision
|
|
const completed = pendingDecision
|
|
|
? {
|
|
? {
|
|
|
...session,
|
|
...session,
|
|
|
pendingDecision,
|
|
pendingDecision,
|
|
|
- currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request),
|
|
|
|
|
|
|
+ currentExecution: metadata.currentExecution ?? buildWaitingExecution(session, request, language),
|
|
|
}
|
|
}
|
|
|
: {
|
|
: {
|
|
|
...markCompleted(session),
|
|
...markCompleted(session),
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Updated ${request.fileName} for ${bookId}.`),
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的 ${request.fileName}。`,
|
|
|
|
|
+ en: `Updated ${request.fileName} for ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
responseText: metadata.responseText ?? (
|
|
responseText: metadata.responseText ?? (
|
|
|
pendingDecision
|
|
pendingDecision
|
|
|
- ? `Updated ${request.fileName} for ${bookId}; waiting for your next decision.`
|
|
|
|
|
- : `Updated ${request.fileName} for ${bookId}.`
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的 ${request.fileName},等待你的下一步决定。`,
|
|
|
|
|
+ en: `Updated ${request.fileName} for ${bookId}; waiting for your next decision.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: `已更新 ${bookId} 的 ${request.fileName}。`,
|
|
|
|
|
+ en: `Updated ${request.fileName} for ${bookId}.`,
|
|
|
|
|
+ })
|
|
|
),
|
|
),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "export_book": {
|
|
case "export_book": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
|
if (!params.tools.exportBook) {
|
|
if (!params.tools.exportBook) {
|
|
|
- throw new Error("Book export is not implemented in the interaction runtime yet.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "交互运行时暂未实现导出作品。",
|
|
|
|
|
+ en: "Book export is not implemented in the interaction runtime yet.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
if (!bookId) {
|
|
if (!bookId) {
|
|
|
- throw new Error("No active book is bound to the interaction session.");
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: "当前交互会话还没有绑定作品。",
|
|
|
|
|
+ en: "No active book is bound to the interaction session.",
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
const toolResult = await params.tools.exportBook(bookId, {
|
|
const toolResult = await params.tools.exportBook(bookId, {
|
|
|
format: request.format,
|
|
format: request.format,
|
|
@@ -595,16 +809,28 @@ export async function runInteractionRequest(params: {
|
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
currentExecution: metadata.currentExecution ?? markCompleted(session).currentExecution,
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(completed, "task.completed", "completed", `Exported ${bookId}.`),
|
|
|
|
|
- responseText: metadata.responseText ?? `Exported ${bookId}.`,
|
|
|
|
|
|
|
+ session: addEvent(completed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已导出 ${bookId}。`,
|
|
|
|
|
+ en: `Exported ${bookId}.`,
|
|
|
|
|
+ })),
|
|
|
|
|
+ responseText: metadata.responseText ?? localize(language, {
|
|
|
|
|
+ zh: `已导出 ${bookId}。`,
|
|
|
|
|
+ en: `Exported ${bookId}.`,
|
|
|
|
|
+ }),
|
|
|
details: metadata.details,
|
|
details: metadata.details,
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "switch_mode":
|
|
case "switch_mode":
|
|
|
session = markCompleted(session);
|
|
session = markCompleted(session);
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(session, "task.completed", "completed", `Switched mode to ${session.automationMode}.`),
|
|
|
|
|
- responseText: `Switched mode to ${session.automationMode}.`,
|
|
|
|
|
|
|
+ session: addEvent(session, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已切换到${localizeMode(session.automationMode, language)}模式。`,
|
|
|
|
|
+ en: `Switched mode to ${session.automationMode}.`,
|
|
|
|
|
+ })),
|
|
|
|
|
+ responseText: localize(language, {
|
|
|
|
|
+ zh: `已切换到${localizeMode(session.automationMode, language)}模式。`,
|
|
|
|
|
+ en: `Switched mode to ${session.automationMode}.`,
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
case "pause_book": {
|
|
case "pause_book": {
|
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
const bookId = request.bookId ?? session.activeBookId;
|
|
@@ -614,12 +840,21 @@ export async function runInteractionRequest(params: {
|
|
|
status: "blocked" as const,
|
|
status: "blocked" as const,
|
|
|
bookId,
|
|
bookId,
|
|
|
chapterNumber: session.activeChapterNumber,
|
|
chapterNumber: session.activeChapterNumber,
|
|
|
- stageLabel: "paused by user",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "已由用户暂停",
|
|
|
|
|
+ en: "paused by user",
|
|
|
|
|
+ }),
|
|
|
},
|
|
},
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(paused, "task.completed", "blocked", `Paused ${bookId ?? "current book"}.`),
|
|
|
|
|
- responseText: `Paused ${bookId ?? "current book"}.`,
|
|
|
|
|
|
|
+ session: addEvent(paused, "task.completed", "blocked", localize(language, {
|
|
|
|
|
+ zh: `已暂停${bookId ?? "当前作品"}。`,
|
|
|
|
|
+ en: `Paused ${bookId ?? "current book"}.`,
|
|
|
|
|
+ })),
|
|
|
|
|
+ responseText: localize(language, {
|
|
|
|
|
+ zh: `已暂停${bookId ?? "当前作品"}。`,
|
|
|
|
|
+ en: `Paused ${bookId ?? "current book"}.`,
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "resume_book": {
|
|
case "resume_book": {
|
|
@@ -630,12 +865,21 @@ export async function runInteractionRequest(params: {
|
|
|
status: "completed" as const,
|
|
status: "completed" as const,
|
|
|
bookId,
|
|
bookId,
|
|
|
chapterNumber: session.activeChapterNumber,
|
|
chapterNumber: session.activeChapterNumber,
|
|
|
- stageLabel: "ready to continue",
|
|
|
|
|
|
|
+ stageLabel: localize(language, {
|
|
|
|
|
+ zh: "可继续执行",
|
|
|
|
|
+ en: "ready to continue",
|
|
|
|
|
+ }),
|
|
|
},
|
|
},
|
|
|
};
|
|
};
|
|
|
return {
|
|
return {
|
|
|
- session: addEvent(resumed, "task.completed", "completed", `Resumed ${bookId ?? "current book"}.`),
|
|
|
|
|
- responseText: `Resumed ${bookId ?? "current book"}.`,
|
|
|
|
|
|
|
+ session: addEvent(resumed, "task.completed", "completed", localize(language, {
|
|
|
|
|
+ zh: `已恢复${bookId ?? "当前作品"}。`,
|
|
|
|
|
+ en: `Resumed ${bookId ?? "current book"}.`,
|
|
|
|
|
+ })),
|
|
|
|
|
+ responseText: localize(language, {
|
|
|
|
|
+ zh: `已恢复${bookId ?? "当前作品"}。`,
|
|
|
|
|
+ en: `Resumed ${bookId ?? "current book"}.`,
|
|
|
|
|
+ }),
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
case "chat": {
|
|
case "chat": {
|
|
@@ -651,11 +895,23 @@ export async function runInteractionRequest(params: {
|
|
|
const responseText = metadata.responseText ?? (
|
|
const responseText = metadata.responseText ?? (
|
|
|
/^(hi|hello|hey|你好|嗨|哈喽)$/i.test(prompt)
|
|
/^(hi|hello|hey|你好|嗨|哈喽)$/i.test(prompt)
|
|
|
? (bookId
|
|
? (bookId
|
|
|
- ? `Hi. Active book is ${bookId}. Ask me to continue, revise a chapter, or explain what is blocked.`
|
|
|
|
|
- : "Hi. No active book yet. Open a book, list books, or tell me what you want to write.")
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `你好。当前作品是 ${bookId}。你可以让我继续写、修订章节,或者解释当前卡住的原因。`,
|
|
|
|
|
+ en: `Hi. Active book is ${bookId}. Ask me to continue, revise a chapter, or explain what is blocked.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: "你好。当前还没有激活作品。你可以先打开作品、列出作品,或者直接告诉我你要写什么。",
|
|
|
|
|
+ en: "Hi. No active book yet. Open a book, list books, or tell me what you want to write.",
|
|
|
|
|
+ }))
|
|
|
: (bookId
|
|
: (bookId
|
|
|
- ? `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.`
|
|
|
|
|
- : "I’m here. No active book is bound yet. Open a book, list books, or describe what you want to write.")
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `我在。当前作品是 ${bookId}。你可以让我继续写、修订章节、重写、调整焦点,或者查看流水线为何停止。`,
|
|
|
|
|
+ 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.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: "我在。当前还没有绑定作品。先打开作品、列出作品,或者直接描述你要写什么。",
|
|
|
|
|
+ en: "I’m here. No active book is bound yet. Open a book, list books, or describe what you want to write.",
|
|
|
|
|
+ }))
|
|
|
);
|
|
);
|
|
|
const completed = markCompleted(session);
|
|
const completed = markCompleted(session);
|
|
|
return {
|
|
return {
|
|
@@ -669,8 +925,14 @@ export async function runInteractionRequest(params: {
|
|
|
const baselineExecution = params.session.currentExecution;
|
|
const baselineExecution = params.session.currentExecution;
|
|
|
const stage = baselineExecution?.stageLabel ?? baselineExecution?.status ?? "idle";
|
|
const stage = baselineExecution?.stageLabel ?? baselineExecution?.status ?? "idle";
|
|
|
const summary = request.intent === "explain_failure"
|
|
const summary = request.intent === "explain_failure"
|
|
|
- ? `Current failure context: ${bookId ?? "no active book"} is at ${stage}.`
|
|
|
|
|
- : `Current status: ${bookId ?? "no active book"} is at ${stage}.`;
|
|
|
|
|
|
|
+ ? localize(language, {
|
|
|
|
|
+ zh: `当前失败上下文:${bookId ?? "当前无激活作品"} 处于 ${stage}。`,
|
|
|
|
|
+ en: `Current failure context: ${bookId ?? "no active book"} is at ${stage}.`,
|
|
|
|
|
+ })
|
|
|
|
|
+ : localize(language, {
|
|
|
|
|
+ zh: `当前状态:${bookId ?? "当前无激活作品"} 处于 ${stage}。`,
|
|
|
|
|
+ en: `Current status: ${bookId ?? "no active book"} is at ${stage}.`,
|
|
|
|
|
+ });
|
|
|
const completed = markCompleted(session);
|
|
const completed = markCompleted(session);
|
|
|
return {
|
|
return {
|
|
|
session: addEvent(completed, "task.completed", "completed", summary),
|
|
session: addEvent(completed, "task.completed", "completed", summary),
|
|
@@ -678,6 +940,9 @@ export async function runInteractionRequest(params: {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
default:
|
|
default:
|
|
|
- throw new Error(`Intent "${request.intent}" is not implemented in the interaction runtime yet.`);
|
|
|
|
|
|
|
+ throw new Error(localize(language, {
|
|
|
|
|
+ zh: `交互运行时暂未实现意图「${request.intent}」。`,
|
|
|
|
|
+ en: `Intent "${request.intent}" is not implemented in the interaction runtime yet.`,
|
|
|
|
|
+ }));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|