# All files / modules/book-generator graph.ts

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

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
    105
    106
    107
    108
    109
    110
    111
    112
    113

     /**
     * LangGraph 状态定义和工作流
     */

    import { Annotation, StateGraph, END } from '@langchain/langgraph';

    // ============ 状态定义（借鉴 OpenMAIC Annotation 模式）============

    /**
     * 进度 reducer：只增不减，防止中间步骤回退导致进度丢失
     */
    const maxReducer = (prev: number, update: number) => Math.max(prev, update);

    /**
     * 章节完成数 reducer：累加而非覆盖
     */
    const appendReducer = <T>(prev: T[], update: T | T[] | undefined) => {
      if (!update) return prev;
      const items = Array.isArray(update) ? update : [update];
      return [...prev, ...items];
    };

    export const GraphState = Annotation.Root({
      bookId: Annotation<string>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => '' as string,
      }),
      userId: Annotation<string | number>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => '' as string,
      }),
      topic: Annotation<string>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => '' as string,
      }),
      bookScale: Annotation<string>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => '1000' as string,
      }),
      /**
       * 大纲层级：1=仅章，2=章→节，3=章→节→小节。
       * reducer: update ?? _prev — 仅当 update 非 null/undefined 时才覆盖旧值。
       * 0/false 被视为 falsy 会保留旧值；合法的 genLevel 值是 1/2/3，不受此限制。
       */
      genLevel: Annotation<number>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => 2,
      }),
      /** 用户明确指定的大纲层级（undefined=未指定/自动，1/2/3=用户主动选择）。
       *  用于区分"用户主动选了2"和"系统默认2"，防止 AI 规划时误覆盖。 */
      userSpecifiedGenLevel: Annotation<number | undefined>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => undefined as number | undefined,
      }),
      description: Annotation<string>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => '' as string,
      }),
      /** AI 书籍规划结果（planBookNode 输出） */
      bookPlan: Annotation<string | undefined>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => undefined,
      }),
      /** 当前正在处理的章节号 */
      currentChapter: Annotation<number>({
        reducer: maxReducer,
        default: () => 0,
      }),
      /** 已成功完成的章节数（只增不减） */
      completedChapters: Annotation<number[]>({
        reducer: appendReducer,
        default: () => [] as number[],
      }),
      finished: Annotation<boolean>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => false,
      }),
      error: Annotation<string | undefined>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => undefined,
      }),
      /** 生成进度 0-100，只增不减 */
      progress: Annotation<number>({
        reducer: maxReducer,
        default: () => 0,
      }),
      /** 失败章节列表，通过 reducer 合并而非覆盖 */
      failedChapters: Annotation<number[]>({
        reducer: appendReducer,
        default: () => [] as number[],
      }),
      /** 质量校验是否通过（quality_check 节点设置） */
      qualityPassed: Annotation<boolean>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => true,
      }),
      /** 重写次数计数器（每次 rewrite 节点执行 +1，用于限制最大循环次数） */
      rewriteCount: Annotation<number>({
        reducer: (prev, update) => prev + (update || 0),
        default: () => 0,
      }),
      /** 最大重写次数 */
      maxRewriteCount: Annotation<number>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => 3,
      }),
      /** 质量校验结果（JSON字符串，quality_check → rewrite 传递） */
      qualityResult: Annotation<string | undefined>({
        reducer: (_prev, update) => update ?? _prev,
        default: () => undefined,
      }),
    });