All files / services/llm book-tools.ts

0% Statements 0/78
0% Branches 0/1
0% Functions 0/1
0% Lines 0/78

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104                                                                                                                                                                                                               
/**
 * 书籍生成工具集 - Tool Calling 模式
 *
 * 借鉴 OpenMAIC pblTools 做法:
 * - 用 Zod 定义输入 Schema,确保类型安全
 * - execute 函数执行实际逻辑
 * - LLM 可在生成过程中主动调用,获取上下文
 */
 
import { z } from 'zod';
import { ToolDefinition } from './index';
 
// ============ 工具定义 ============
 
/**
 * 创建书籍生成工具集
 * 使用工厂模式,绑定到具体书籍 ID 和 bookStore
 */
export function createBookTools(bookId: string, bookStore: any): ToolDefinition[] {
  return [
    // 工具1:获取已生成章节的摘要,避免内容重复
    {
      name: 'get_existing_chapters',
      description:
        '获取书籍中已经生成的章节内容摘要(前500字),用于了解已有内容,避免重复,保持风格一致。返回章节列表,每项包含章节号、标题、内容摘要。',
      inputSchema: z.object({
        chapter_numbers: z
          .array(z.number())
          .optional()
          .describe('要查询的章节号列表,不传则返回所有已完成章节'),
      }),
      execute: async ({ chapter_numbers }: { chapter_numbers?: number[] }) => {
        const book = await bookStore.getById(bookId);
        if (!book) return { error: '书籍不存在', chapters: [] };
 
        const chapters = (book.chapters || []).filter((c: any) => {
          const hasContent = c.content && c.content.length > 0;
          const inRange = !chapter_numbers || chapter_numbers.includes(c.number);
          return hasContent && inRange;
        });
 
        return {
          count: chapters.length,
          chapters: chapters.map((c: any) => ({
            number: c.number,
            title: c.title,
            summary: c.content ? c.content.slice(0, 500) + (c.content.length > 500 ? '...' : '') : '',
            wordCount: c.wordCount || 0,
          })),
        };
      },
    },
 
    // 工具2:获取书籍大纲,了解整体结构
    {
      name: 'get_book_outline',
      description:
        '获取书籍完整大纲,包括主题、结构逻辑和所有章节规划。用于了解当前章节在全书中的位置和与其他章节的关系。',
      inputSchema: z.object({}),
      execute: async () => {
        const book = await bookStore.getById(bookId);
        if (!book?.outline) return { error: '大纲不存在' };
 
        return {
          mainTheme: book.outline.mainTheme,
          structureLogic: book.outline.structureLogic,
          totalChapters: book.outline.chapters.length,
          chapters: book.outline.chapters.map((c: any) => ({
            number: c.number,
            title: c.title,
            summary: c.summary,
            keyPoints: c.keyPoints,
            estimatedWords: c.estimatedWords,
          })),
        };
      },
    },
 
    // 工具3:标记章节需要调整(LLM 发现问题时主动报告)
    {
      name: 'report_chapter_issue',
      description:
        '当发现当前章节内容与已有章节重复、结构不合理或内容缺失时,用此工具记录问题说明。返回确认消息后继续生成改进版本。',
      inputSchema: z.object({
        chapter_number: z.number().describe('问题章节号'),
        issue_type: z
          .enum(['content_overlap', 'structure_issue', 'missing_content', 'style_inconsistency'])
          .describe('问题类型'),
        description: z.string().describe('问题描述'),
        suggestion: z.string().describe('改进建议'),
      }),
      execute: async ({ chapter_number, issue_type, description, suggestion }: any) => {
        console.log(
          `[BookTools] 章节 ${chapter_number} 发现问题: [${issue_type}] ${description},建议: ${suggestion}`
        );
        return {
          acknowledged: true,
          message: `已记录问题,请根据建议"${suggestion}"重新生成第${chapter_number}章内容。`,
        };
      },
    },
  ];
}