|
@@ -19,7 +19,6 @@ const loadProjectConfigMock = vi.fn();
|
|
|
const pipelineConfigs: unknown[] = [];
|
|
const pipelineConfigs: unknown[] = [];
|
|
|
const processProjectInteractionInputMock = vi.fn();
|
|
const processProjectInteractionInputMock = vi.fn();
|
|
|
const processProjectInteractionRequestMock = vi.fn();
|
|
const processProjectInteractionRequestMock = vi.fn();
|
|
|
-const routeNaturalLanguageIntentMock = vi.fn();
|
|
|
|
|
const createInteractionToolsFromDepsMock = vi.fn(() => ({}));
|
|
const createInteractionToolsFromDepsMock = vi.fn(() => ({}));
|
|
|
const loadProjectSessionMock = vi.fn();
|
|
const loadProjectSessionMock = vi.fn();
|
|
|
const resolveSessionActiveBookMock = vi.fn();
|
|
const resolveSessionActiveBookMock = vi.fn();
|
|
@@ -159,7 +158,6 @@ vi.mock("@actalk/inkos-core", () => {
|
|
|
loadProjectConfig: loadProjectConfigMock,
|
|
loadProjectConfig: loadProjectConfigMock,
|
|
|
processProjectInteractionInput: processProjectInteractionInputMock,
|
|
processProjectInteractionInput: processProjectInteractionInputMock,
|
|
|
processProjectInteractionRequest: processProjectInteractionRequestMock,
|
|
processProjectInteractionRequest: processProjectInteractionRequestMock,
|
|
|
- routeNaturalLanguageIntent: routeNaturalLanguageIntentMock,
|
|
|
|
|
createInteractionToolsFromDeps: createInteractionToolsFromDepsMock,
|
|
createInteractionToolsFromDeps: createInteractionToolsFromDepsMock,
|
|
|
loadProjectSession: loadProjectSessionMock,
|
|
loadProjectSession: loadProjectSessionMock,
|
|
|
resolveSessionActiveBook: resolveSessionActiveBookMock,
|
|
resolveSessionActiveBook: resolveSessionActiveBookMock,
|
|
@@ -268,7 +266,6 @@ describe("createStudioServer daemon lifecycle", () => {
|
|
|
loadProjectConfigMock.mockReset();
|
|
loadProjectConfigMock.mockReset();
|
|
|
processProjectInteractionInputMock.mockReset();
|
|
processProjectInteractionInputMock.mockReset();
|
|
|
processProjectInteractionRequestMock.mockReset();
|
|
processProjectInteractionRequestMock.mockReset();
|
|
|
- routeNaturalLanguageIntentMock.mockReset();
|
|
|
|
|
createInteractionToolsFromDepsMock.mockReset();
|
|
createInteractionToolsFromDepsMock.mockReset();
|
|
|
loadProjectSessionMock.mockReset();
|
|
loadProjectSessionMock.mockReset();
|
|
|
resolveSessionActiveBookMock.mockReset();
|
|
resolveSessionActiveBookMock.mockReset();
|
|
@@ -296,21 +293,6 @@ describe("createStudioServer daemon lifecycle", () => {
|
|
|
messages: [],
|
|
messages: [],
|
|
|
});
|
|
});
|
|
|
resolveSessionActiveBookMock.mockResolvedValue(undefined);
|
|
resolveSessionActiveBookMock.mockResolvedValue(undefined);
|
|
|
- routeNaturalLanguageIntentMock.mockImplementation((input: string, context?: { activeBookId?: string }) => {
|
|
|
|
|
- const trimmed = input.trim();
|
|
|
|
|
- if (trimmed === "重写第3章") {
|
|
|
|
|
- return {
|
|
|
|
|
- intent: "rewrite_chapter",
|
|
|
|
|
- ...(context?.activeBookId ? { bookId: context.activeBookId } : {}),
|
|
|
|
|
- chapterNumber: 3,
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- return {
|
|
|
|
|
- intent: "chat",
|
|
|
|
|
- ...(context?.activeBookId ? { bookId: context.activeBookId } : {}),
|
|
|
|
|
- instruction: trimmed,
|
|
|
|
|
- };
|
|
|
|
|
- });
|
|
|
|
|
loadProjectConfigMock.mockImplementation(async () => {
|
|
loadProjectConfigMock.mockImplementation(async () => {
|
|
|
const raw = JSON.parse(await readFile(join(root, "inkos.json"), "utf-8")) as Record<string, unknown>;
|
|
const raw = JSON.parse(await readFile(join(root, "inkos.json"), "utf-8")) as Record<string, unknown>;
|
|
|
return {
|
|
return {
|
|
@@ -1196,11 +1178,11 @@ describe("createStudioServer daemon lifecycle", () => {
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it("routes ordinary chat through runAgentSession and returns response + sessionId", async () => {
|
|
|
|
|
|
|
+ it("routes /api/agent through runAgentSession and returns response + sessionId", async () => {
|
|
|
runAgentSessionMock.mockResolvedValueOnce({
|
|
runAgentSessionMock.mockResolvedValueOnce({
|
|
|
responseText: "Completed write_next for demo-book.",
|
|
responseText: "Completed write_next for demo-book.",
|
|
|
messages: [
|
|
messages: [
|
|
|
- { role: "user", content: "聊聊这一章的问题" },
|
|
|
|
|
|
|
+ { role: "user", content: "continue" },
|
|
|
{ role: "assistant", content: "Completed write_next for demo-book." },
|
|
{ role: "assistant", content: "Completed write_next for demo-book." },
|
|
|
],
|
|
],
|
|
|
});
|
|
});
|
|
@@ -1211,7 +1193,7 @@ describe("createStudioServer daemon lifecycle", () => {
|
|
|
const response = await app.request("http://localhost/api/v1/agent", {
|
|
const response = await app.request("http://localhost/api/v1/agent", {
|
|
|
method: "POST",
|
|
method: "POST",
|
|
|
headers: { "Content-Type": "application/json" },
|
|
headers: { "Content-Type": "application/json" },
|
|
|
- body: JSON.stringify({ instruction: "聊聊这一章的问题", activeBookId: "demo-book" }),
|
|
|
|
|
|
|
+ body: JSON.stringify({ instruction: "continue", activeBookId: "demo-book" }),
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.status).toBe(200);
|
|
@@ -1226,7 +1208,7 @@ describe("createStudioServer daemon lifecycle", () => {
|
|
|
bookId: "demo-book",
|
|
bookId: "demo-book",
|
|
|
projectRoot: root,
|
|
projectRoot: root,
|
|
|
}),
|
|
}),
|
|
|
- "聊聊这一章的问题",
|
|
|
|
|
|
|
+ "continue",
|
|
|
expect.any(Array),
|
|
expect.any(Array),
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
@@ -1289,49 +1271,6 @@ describe("createStudioServer daemon lifecycle", () => {
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it("routes high-risk chapter intents through the shared interaction runtime before agent chat", async () => {
|
|
|
|
|
- processProjectInteractionRequestMock.mockResolvedValueOnce({
|
|
|
|
|
- request: { intent: "rewrite_chapter", bookId: "demo-book", chapterNumber: 3 },
|
|
|
|
|
- responseText: "已为 demo-book 完成章节重写。",
|
|
|
|
|
- session: {
|
|
|
|
|
- sessionId: "interaction-session-1",
|
|
|
|
|
- projectRoot: root,
|
|
|
|
|
- activeBookId: "demo-book",
|
|
|
|
|
- automationMode: "semi",
|
|
|
|
|
- messages: [],
|
|
|
|
|
- events: [],
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const { createStudioServer } = await import("./server.js");
|
|
|
|
|
- const app = createStudioServer(cloneProjectConfig() as never, root);
|
|
|
|
|
-
|
|
|
|
|
- const response = await app.request("http://localhost/api/v1/agent", {
|
|
|
|
|
- method: "POST",
|
|
|
|
|
- headers: { "Content-Type": "application/json" },
|
|
|
|
|
- body: JSON.stringify({ instruction: "重写第3章", activeBookId: "demo-book" }),
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- expect(response.status).toBe(200);
|
|
|
|
|
- await expect(response.json()).resolves.toMatchObject({
|
|
|
|
|
- response: "已为 demo-book 完成章节重写。",
|
|
|
|
|
- session: {
|
|
|
|
|
- sessionId: "agent-session-1",
|
|
|
|
|
- activeBookId: "demo-book",
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
- expect(processProjectInteractionRequestMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
|
|
|
- projectRoot: root,
|
|
|
|
|
- activeBookId: "demo-book",
|
|
|
|
|
- request: expect.objectContaining({
|
|
|
|
|
- intent: "rewrite_chapter",
|
|
|
|
|
- bookId: "demo-book",
|
|
|
|
|
- chapterNumber: 3,
|
|
|
|
|
- }),
|
|
|
|
|
- }));
|
|
|
|
|
- expect(runAgentSessionMock).not.toHaveBeenCalled();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
it("returns 500 with an error payload when the agent session fails", async () => {
|
|
it("returns 500 with an error payload when the agent session fails", async () => {
|
|
|
runAgentSessionMock.mockRejectedValueOnce(new Error("boom"));
|
|
runAgentSessionMock.mockRejectedValueOnce(new Error("boom"));
|
|
|
|
|
|