@musnows/scriverse 0.4.10 → 0.4.12

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/dist/app.js CHANGED
@@ -348,6 +348,42 @@ const contextSchema = z.object({
348
348
  settingIds: optionalStrings,
349
349
  includeBookSummary: z.boolean().optional()
350
350
  });
351
+ const analysisTaskTypeSchema = z.enum(["structure", "chapter-analysis", "character-extraction", "character-summary", "character-identity-audit", "timeline-analysis", "worldview-analysis", "setting-extraction", "consistency-check", "report-update", "book-analysis"]);
352
+ const relationshipAnalysisScopeSchema = z.object({
353
+ type: z.enum(["chapter", "book"]),
354
+ chapterId: identifier.optional(),
355
+ includeAllSettings: z.boolean().optional(),
356
+ additionalPrompt: z.string().trim().max(10_000).optional(),
357
+ characterIds: z.array(identifier).max(20).optional(),
358
+ replaceExistingRelationships: z.boolean().optional()
359
+ }).strict().superRefine((scope, context) => {
360
+ if (scope.type === "chapter" && !scope.chapterId) {
361
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["chapterId"], message: "指定章节分析必须提供章节标识" });
362
+ }
363
+ if (scope.includeAllSettings && scope.type !== "book") {
364
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["includeAllSettings"], message: "包含所有设定仅支持全书人物关系分析" });
365
+ }
366
+ if (scope.characterIds && new Set(scope.characterIds).size !== scope.characterIds.length) {
367
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["characterIds"], message: "被分析角色不能重复" });
368
+ }
369
+ if (scope.replaceExistingRelationships && !scope.characterIds?.length) {
370
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["replaceExistingRelationships"], message: "覆盖已有关系前必须选择被分析角色" });
371
+ }
372
+ });
373
+ const analysisTaskSchema = z.union([
374
+ z.object({ taskType: z.literal("relationship-analysis"), scope: relationshipAnalysisScopeSchema.optional() }).strict(),
375
+ z.object({ taskType: analysisTaskTypeSchema, scope: jsonObject.optional() }).strict().superRefine((input, context) => {
376
+ if (input.scope?.includeAllSettings !== undefined) {
377
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "includeAllSettings"], message: "包含所有设定仅支持人物关系分析" });
378
+ }
379
+ if (input.scope?.additionalPrompt !== undefined) {
380
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "additionalPrompt"], message: "额外分析提示仅支持人物关系分析" });
381
+ }
382
+ if (input.scope?.characterIds !== undefined || input.scope?.replaceExistingRelationships !== undefined) {
383
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "characterIds"], message: "被分析角色仅支持人物关系分析" });
384
+ }
385
+ })
386
+ ]);
351
387
  function data(response, value, status = 200) {
352
388
  response.status(status).json({ data: value });
353
389
  }
@@ -1294,7 +1330,7 @@ export function createRuntime(options) {
1294
1330
  : store.listTasks(request.params.workId));
1295
1331
  });
1296
1332
  app.post("/api/works/:workId/tasks", (request, response) => {
1297
- const input = parse(z.object({ taskType: z.enum(["structure", "chapter-analysis", "character-extraction", "character-summary", "character-identity-audit", "timeline-analysis", "relationship-analysis", "worldview-analysis", "setting-extraction", "consistency-check", "report-update", "book-analysis"]), scope: jsonObject.optional() }), request.body);
1333
+ const input = parse(analysisTaskSchema, request.body);
1298
1334
  data(response, store.createTask(request.params.workId, input), 201);
1299
1335
  });
1300
1336
  app.post("/api/works/:workId/tasks/auto-run", (request, response) => {
@@ -1358,6 +1394,7 @@ export function createRuntime(options) {
1358
1394
  metadata: z.object({
1359
1395
  modelDisplayName: z.string().max(200).optional(),
1360
1396
  outputTokens: z.number().int().min(0).max(10_000_000).optional(),
1397
+ cacheHitPercent: z.number().min(0).max(100).optional(),
1361
1398
  processDurationMs: z.number().int().min(0).max(86_400_000).optional(),
1362
1399
  toolCalls: z.array(aiToolCallResultSchema).max(12).optional(),
1363
1400
  processSteps: z.array(aiProcessStepSchema).max(50).optional()
@@ -1528,6 +1565,7 @@ export function createRuntime(options) {
1528
1565
  provider: suggestion.provider,
1529
1566
  model: suggestion.model,
1530
1567
  outputTokens: suggestion.outputTokens,
1568
+ cacheHitPercent: suggestion.cacheHitPercent,
1531
1569
  chapterVersion: suggestion.chapterVersion,
1532
1570
  toolCalls: suggestion.toolCalls,
1533
1571
  processSteps: suggestion.processSteps
@@ -1603,18 +1641,28 @@ export function createRuntime(options) {
1603
1641
  response.type("text/html").send(html);
1604
1642
  };
1605
1643
  app.get(["/", "/index.html"], sendIndexHtml);
1644
+ const setStaticCacheControl = (response) => {
1645
+ const version = response.req.query.v;
1646
+ response.setHeader("Cache-Control", typeof version === "string" && version.length > 0
1647
+ ? "public, max-age=31536000, immutable"
1648
+ : "public, max-age=3600, must-revalidate");
1649
+ };
1606
1650
  const vditorPath = join(process.cwd(), "node_modules", "vditor", "dist");
1607
1651
  if (existsSync(vditorPath)) {
1608
1652
  app.use("/vendor/vditor/dist", express.static(vditorPath, {
1653
+ cacheControl: false,
1609
1654
  index: false,
1610
- maxAge: 0,
1611
- setHeaders: (response) => response.setHeader("Cache-Control", "no-store")
1655
+ etag: true,
1656
+ lastModified: true,
1657
+ setHeaders: setStaticCacheControl
1612
1658
  }));
1613
1659
  }
1614
1660
  app.use(express.static(publicPath, {
1661
+ cacheControl: false,
1615
1662
  index: false,
1616
- maxAge: 0,
1617
- setHeaders: (response) => response.setHeader("Cache-Control", "no-store")
1663
+ etag: true,
1664
+ lastModified: true,
1665
+ setHeaders: setStaticCacheControl
1618
1666
  }));
1619
1667
  app.get("/{*path}", (request, response, next) => {
1620
1668
  if (request.path.startsWith("/api/"))