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,
  }),
});