Просмотр исходного кода

fix(v13-merge): post-merge test and UI integration fixups

- planner.test: drop _openai (renamed to _piModel on dev)
- architect.test: bump maxTokens 16384→20480 to match v13's architect
- studio phase5-hotfix/v13-hotfix-round4 tests: /api/books → /api/v1/books
- studio server.test: add isNewLayoutBook mock to @actalk/inkos-core
- TruthFiles.tsx: accept null from useApi in deriveFilePresentation
Ma 6 месяцев назад
Родитель
Сommit
aa67b60d4e

+ 3 - 3
packages/core/src/__tests__/architect.test.ts

@@ -582,7 +582,7 @@ describe("ArchitectAgent", () => {
 
     expect(chatSpy).toHaveBeenCalledWith(
       expect.any(Array),
-      expect.objectContaining({ temperature: 0.8, maxTokens: 16384 }),
+      expect.objectContaining({ temperature: 0.8, maxTokens: 20480 }),
     );
   });
 
@@ -645,7 +645,7 @@ describe("ArchitectAgent", () => {
 
     expect(chatSpy).toHaveBeenCalledWith(
       expect.any(Array),
-      expect.objectContaining({ temperature: 0.5, maxTokens: 16384 }),
+      expect.objectContaining({ temperature: 0.5, maxTokens: 20480 }),
     );
   });
 
@@ -708,7 +708,7 @@ describe("ArchitectAgent", () => {
 
     expect(chatSpy).toHaveBeenCalledWith(
       expect.any(Array),
-      expect.objectContaining({ temperature: 0.7, maxTokens: 16384 }),
+      expect.objectContaining({ temperature: 0.7, maxTokens: 20480 }),
     );
   });
 });

+ 0 - 1
packages/core/src/__tests__/planner.test.ts

@@ -63,7 +63,6 @@ const STUB_CLIENT: LLMClient = {
   provider: "openai",
   apiFormat: "chat",
   stream: false,
-  _openai: {} as never,
   defaults: { temperature: 0.7, maxTokens: 2048, thinkingBudget: 0, maxTokensCap: null, extra: {} },
 };
 

+ 13 - 13
packages/studio/src/api/phase5-hotfix.test.ts

@@ -138,7 +138,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
     const response = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/outline/story_frame.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/outline/story_frame.md",
     );
     expect(response.status).toBe(200);
     const body = await response.json() as { file: string; content: string; legacy?: boolean };
@@ -157,7 +157,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
     const response = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/roles/主要角色/主角甲.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/roles/主要角色/主角甲.md",
     );
     expect(response.status).toBe(200);
     const body = await response.json() as { file: string; content: string };
@@ -173,7 +173,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
     for (const file of ["story_bible.md", "book_rules.md"]) {
-      const res = await app.request(`http://localhost/api/books/hotfix-book/truth/${file}`);
+      const res = await app.request(`http://localhost/api/v1/books/hotfix-book/truth/${file}`);
       expect(res.status).toBe(200);
       const body = await res.json() as { legacy?: boolean };
       expect(body.legacy).toBe(true);
@@ -187,7 +187,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     // Encoded form — the :file{.+} pattern accepts this; resolveTruthFilePath
     // must reject the resolved path regardless.
     const response = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/outline/..%2F..%2Fetc%2Fpasswd",
+      "http://localhost/api/v1/books/hotfix-book/truth/outline/..%2F..%2Fetc%2Fpasswd",
     );
     expect(response.status).toBe(400);
     await expect(response.json()).resolves.toEqual({ error: "Invalid truth file" });
@@ -199,19 +199,19 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
 
     // Unknown flat file
     const response1 = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/random.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/random.md",
     );
     expect(response1.status).toBe(400);
 
     // Unknown subdir
     const response2 = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/outline/unknown.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/outline/unknown.md",
     );
     expect(response2.status).toBe(400);
 
     // roles/ with unknown tier
     const response3 = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/roles/其他/x.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/roles/其他/x.md",
     );
     expect(response3.status).toBe(400);
   });
@@ -223,7 +223,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
     const response = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/book_rules.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/book_rules.md",
       {
         method: "PUT",
         headers: { "Content-Type": "application/json" },
@@ -240,7 +240,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
     const response = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/outline/story_frame.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/outline/story_frame.md",
       {
         method: "PUT",
         headers: { "Content-Type": "application/json" },
@@ -266,7 +266,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
     const response = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/roles/major/Mara.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/roles/major/Mara.md",
     );
     expect(response.status).toBe(200);
     const body = await response.json() as { content: string };
@@ -279,7 +279,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
     const response = await app.request(
-      "http://localhost/api/books/hotfix-book/truth/roles/minor/Kit.md",
+      "http://localhost/api/v1/books/hotfix-book/truth/roles/minor/Kit.md",
       {
         method: "PUT",
         headers: { "Content-Type": "application/json" },
@@ -301,7 +301,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const response = await app.request("http://localhost/api/books/hotfix-book/truth");
+    const response = await app.request("http://localhost/api/v1/books/hotfix-book/truth");
     const body = await response.json() as { files: ReadonlyArray<{ name: string }> };
     const names = body.files.map((f) => f.name);
     expect(names).toContain("roles/major/Mara.md");
@@ -318,7 +318,7 @@ describe("Phase 5 hotfix 1 — Studio truth file endpoints", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const response = await app.request("http://localhost/api/books/hotfix-book/truth");
+    const response = await app.request("http://localhost/api/v1/books/hotfix-book/truth");
     expect(response.status).toBe(200);
     const body = await response.json() as { files: ReadonlyArray<{ name: string; legacy?: true }> };
     const names = body.files.map((f) => f.name).sort();

+ 1 - 0
packages/studio/src/api/server.test.ts

@@ -176,6 +176,7 @@ vi.mock("@actalk/inkos-core", () => {
     getServiceApiKey: getServiceApiKeyMock,
     listModelsForService: listModelsForServiceMock,
     GLOBAL_ENV_PATH: join(tmpdir(), "inkos-global.env"),
+    isNewLayoutBook: vi.fn(async () => false),
   };
 });
 

+ 6 - 6
packages/studio/src/api/v13-hotfix-round4.test.ts

@@ -127,7 +127,7 @@ describe("Issue 1 — Studio: old book (no outline/story_frame.md)", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const res = await app.request("http://localhost/api/books/old-book/truth/story_bible.md");
+    const res = await app.request("http://localhost/api/v1/books/old-book/truth/story_bible.md");
     expect(res.status).toBe(200);
     const body = await res.json() as { file: string; content: string; legacy?: boolean };
     expect(body.content).toContain("Authoritative content");
@@ -138,7 +138,7 @@ describe("Issue 1 — Studio: old book (no outline/story_frame.md)", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const res = await app.request("http://localhost/api/books/old-book/truth/story_bible.md", {
+    const res = await app.request("http://localhost/api/v1/books/old-book/truth/story_bible.md", {
       method: "PUT",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify({ content: "# Updated Bible" }),
@@ -152,7 +152,7 @@ describe("Issue 1 — Studio: old book (no outline/story_frame.md)", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const res = await app.request("http://localhost/api/books/old-book/truth");
+    const res = await app.request("http://localhost/api/v1/books/old-book/truth");
     expect(res.status).toBe(200);
     const body = await res.json() as { files: ReadonlyArray<{ name: string; legacy?: true }> };
     const bibleEntry = body.files.find((f) => f.name === "story_bible.md");
@@ -189,7 +189,7 @@ describe("Issue 1 — Studio: new book (has outline/story_frame.md)", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const res = await app.request("http://localhost/api/books/new-book/truth/story_bible.md");
+    const res = await app.request("http://localhost/api/v1/books/new-book/truth/story_bible.md");
     expect(res.status).toBe(200);
     const body = await res.json() as { legacy?: boolean };
     expect(body.legacy).toBe(true);
@@ -199,7 +199,7 @@ describe("Issue 1 — Studio: new book (has outline/story_frame.md)", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const res = await app.request("http://localhost/api/books/new-book/truth/story_bible.md", {
+    const res = await app.request("http://localhost/api/v1/books/new-book/truth/story_bible.md", {
       method: "PUT",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify({ content: "# Attempt" }),
@@ -213,7 +213,7 @@ describe("Issue 1 — Studio: new book (has outline/story_frame.md)", () => {
     const { createStudioServer } = await import("./server.js");
     const app = createStudioServer(cloneProjectConfig() as never, root);
 
-    const res = await app.request("http://localhost/api/books/new-book/truth");
+    const res = await app.request("http://localhost/api/v1/books/new-book/truth");
     expect(res.status).toBe(200);
     const body = await res.json() as { files: ReadonlyArray<{ name: string; legacy?: true }> };
     const bibleEntry = body.files.find((f) => f.name === "story_bible.md");

+ 1 - 1
packages/studio/src/pages/TruthFiles.tsx

@@ -34,7 +34,7 @@ export interface FilePresentation {
 
 export function deriveFilePresentation(
   fileName: string | null,
-  fileData: { content: string | null; legacy?: boolean } | undefined,
+  fileData: { content: string | null; legacy?: boolean } | null | undefined,
 ): FilePresentation {
   const legacy = fileData?.legacy === true;
   const authoritativePath = fileName ? SHIM_AUTHORITATIVE_PATH[fileName] ?? null : null;