@musnows/scriverse 0.5.10 → 0.5.11

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/ai.js CHANGED
@@ -88,7 +88,7 @@ function thinkingParameters(provider, model) {
88
88
  return {};
89
89
  return { thinking: { type: boolValue(model, "thinking_enabled") ? "enabled" : "disabled" } };
90
90
  }
91
- const AGENT_TOOL_IDS = ["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections"];
91
+ const AGENT_TOOL_IDS = ["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections", "search_drafts"];
92
92
  function traceRecord(value) {
93
93
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
94
94
  }
@@ -204,6 +204,11 @@ const readCharacterSectionsArguments = z.object({
204
204
  sectionIds: z.array(z.string().min(1).max(300)).min(1).max(3),
205
205
  include: z.enum(["summary", "content", "both"]).default("both")
206
206
  }).strict();
207
+ const searchDraftsArguments = z.object({
208
+ query: z.string().trim().max(200).default(""),
209
+ draftType: z.enum(["all", "prose", "setting"]).default("all"),
210
+ limit: z.number().int().min(1).max(30).default(20)
211
+ }).strict();
207
212
  const AGENT_TOOL_DEFINITIONS = {
208
213
  story_index: {
209
214
  type: "function",
@@ -244,6 +249,14 @@ const AGENT_TOOL_DEFINITIONS = {
244
249
  description: "读取指定人物 Markdown 档案章节的摘要或原文。先通过 search_story_entities 获取 sectionId;每次最多读取 3 个章节。",
245
250
  parameters: { type: "object", properties: { sectionIds: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 3 }, include: { type: "string", enum: ["summary", "content", "both"] } }, required: ["sectionIds"], additionalProperties: false }
246
251
  }
252
+ },
253
+ search_drafts: {
254
+ type: "function",
255
+ function: {
256
+ name: "search_drafts",
257
+ description: "搜索当前作品的作者草稿。草稿只是用于记录可能采用、也可能永远不会写入正文或正式设定的临时想法,不是已确认的故事事实,不能当作正文或设定依据。可按关键词和“正文草稿/设定草稿”类型筛选;query 为空时返回最近更新的草稿。",
258
+ parameters: { type: "object", properties: { query: { type: "string", maxLength: 200, default: "" }, draftType: { type: "string", enum: ["all", "prose", "setting"], default: "all" }, limit: { type: "integer", minimum: 1, maximum: 30, default: 20 } }, additionalProperties: false }
259
+ }
247
260
  }
248
261
  };
249
262
  export function estimateAiTokens(value) {
@@ -2404,7 +2417,7 @@ export class AiManager {
2404
2417
  ? [
2405
2418
  `当前可用作品查询工具:${enabledToolIds.join("、")}。`,
2406
2419
  "当作者询问当前作品、项目、章节、情节、人物、关系、世界观或设定,而预加载上下文为空或不足时,必须先调用工具主动查询;不得直接声称没有上下文,也不得先要求作者补充本系统已经能够查询的信息。",
2407
- "整体介绍、作品基本信息、目录或章节定位优先调用 story_index;按关键字定位正文段落时调用 grep;已知章节 ID 且需要原文事实或精确措辞时调用 read_chapters;查找设定、人物、组织、时间线、关系、大纲或伏笔时调用 search_story_entities(可传入短实体名、拼音或关键词,勿用自然语言整句);人物匹配结果包含 sectionId 且需要背景故事、能力或经历原文时调用 read_character_sections",
2420
+ "整体介绍、作品基本信息、目录或章节定位优先调用 story_index;按关键字定位正文段落时调用 grep;已知章节 ID 且需要原文事实或精确措辞时调用 read_chapters;查找设定、人物、组织、时间线、关系、大纲或伏笔时调用 search_story_entities(可传入短实体名、拼音或关键词,勿用自然语言整句);人物匹配结果包含 sectionId 且需要背景故事、能力或经历原文时调用 read_character_sections;作者询问尚未定稿的想法、备选方向或明确提到草稿时调用 search_drafts。草稿可能永远不会进入正文或设定,必须明确标注为未确认想法,不得把它当作故事事实。",
2408
2421
  "根据问题选择最少且必要的工具。工具结果仍不足时才说明未知,并明确已经查询过什么;不要重复无效调用。"
2409
2422
  ].join("\n")
2410
2423
  : "";
@@ -2458,7 +2471,10 @@ export class AiManager {
2458
2471
  const enabled = new Set(this.store.getWorkAiSettings(workId).agentTools
2459
2472
  .filter((item) => typeof item === "string" && AGENT_TOOL_IDS.includes(item)));
2460
2473
  const requested = requestedToolIds ? new Set(requestedToolIds) : null;
2461
- return AGENT_TOOL_IDS.filter((toolId) => enabled.has(toolId) && (!requested || requested.has(toolId)));
2474
+ const permissions = this.store.getWork(workId).modulePermissions;
2475
+ return AGENT_TOOL_IDS.filter((toolId) => enabled.has(toolId)
2476
+ && (!requested || requested.has(toolId))
2477
+ && (toolId !== "search_drafts" || permissions.drafts === "read" || permissions.drafts === "write"));
2462
2478
  }
2463
2479
  enabledAgentTools(workId, taskType, requestedToolIds) {
2464
2480
  return this.enabledAgentToolIds(workId, taskType, requestedToolIds).map((toolId) => AGENT_TOOL_DEFINITIONS[toolId]);
@@ -2490,7 +2506,8 @@ export class AiManager {
2490
2506
  : name === "grep" ? grepArguments
2491
2507
  : name === "search_story_entities" ? searchStoryEntitiesArguments
2492
2508
  : name === "read_character_sections" ? readCharacterSectionsArguments
2493
- : null;
2509
+ : name === "search_drafts" ? searchDraftsArguments
2510
+ : null;
2494
2511
  if (!schema) {
2495
2512
  return {
2496
2513
  id: toolCall.id,
@@ -2647,6 +2664,42 @@ export class AiManager {
2647
2664
  });
2648
2665
  return { id: toolCall.id, name, calledAt, arguments: { sectionIds, include }, status: "completed", result: { ok: true, data: { sections, contentLimitChars: 48_000 } } };
2649
2666
  }
2667
+ if (name === "search_drafts") {
2668
+ const { query, draftType, limit } = args;
2669
+ let remainingChars = 36_000;
2670
+ const matches = this.store.searchDrafts(workId, query, draftType === "all" ? undefined : draftType, limit).map((draft) => {
2671
+ const content = collapseAiBlankLines(String(draft.content));
2672
+ const excerpt = content.slice(0, Math.max(0, Math.min(12_000, remainingChars)));
2673
+ remainingChars -= excerpt.length;
2674
+ return {
2675
+ id: draft.id,
2676
+ draftType: draft.draftType,
2677
+ draftTypeLabel: draft.draftType === "prose" ? "正文草稿" : "设定草稿",
2678
+ title: draft.title,
2679
+ content: excerpt,
2680
+ contentTruncated: excerpt.length < content.length,
2681
+ versionNo: draft.versionNo,
2682
+ updatedAt: draft.updatedAt
2683
+ };
2684
+ });
2685
+ return {
2686
+ id: toolCall.id,
2687
+ name,
2688
+ calledAt,
2689
+ arguments: { query, draftType, limit },
2690
+ status: "completed",
2691
+ result: {
2692
+ ok: true,
2693
+ data: {
2694
+ meaning: "这些内容是作者记录的未确认临时想法,可能采用,也可能永远不会写入正文或正式设定;不得视为故事事实。",
2695
+ query,
2696
+ draftType,
2697
+ matches,
2698
+ contentLimitChars: 36_000
2699
+ }
2700
+ }
2701
+ };
2702
+ }
2650
2703
  throw new Error(`Unhandled agent tool: ${name}`);
2651
2704
  }
2652
2705
  constrainParametersForContext(model, messages, parameters) {