From 5c553aae1965c082c8cc5f000637ae08b5ac6cfc Mon Sep 17 00:00:00 2001 From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com> Date: Mon, 18 May 2026 09:58:34 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-writing-backend-orchestrator-blueprint.md | 645 ++++++++++++++ .../docs/ai-writing-final-execution-plan.md | 806 ++++++++++++++++++ .../ai-writing-frontend-refactor-checklist.md | 472 ++++++++++ .../ai-writing-weak-model-multi-agent-prd.md | 718 ++++++++++++++++ 4 files changed, 2641 insertions(+) create mode 100644 frontend-web/docs/ai-writing-backend-orchestrator-blueprint.md create mode 100644 frontend-web/docs/ai-writing-final-execution-plan.md create mode 100644 frontend-web/docs/ai-writing-frontend-refactor-checklist.md create mode 100644 frontend-web/docs/ai-writing-weak-model-multi-agent-prd.md diff --git a/frontend-web/docs/ai-writing-backend-orchestrator-blueprint.md b/frontend-web/docs/ai-writing-backend-orchestrator-blueprint.md new file mode 100644 index 00000000..d44e3f78 --- /dev/null +++ b/frontend-web/docs/ai-writing-backend-orchestrator-blueprint.md @@ -0,0 +1,645 @@ +# AI 写作后端新路线设计草案 + +## 1. 目标 + +为“弱模型多 Agent 写作工作流”建设一条独立后端路线,满足以下要求: + +- 不影响现有同事正在开发的功能 +- 不强耦合现有 DeerFlow 通用对话主链路 +- 可独立部署、独立调试、独立回滚 +- 支持多阶段写作编排、人工介入、失败重试、流式事件输出 + +--- + +## 2. 推荐建设方式 + +优先建议: + +- 在 `offline-backend-20260512` 下新建独立应用或独立模块 + +建议目录: + +```text +offline-backend-20260512/ + apps/ + ai_writing_orchestrator/ + api/ + application/ + domain/ + infrastructure/ + prompts/ + tests/ +``` + +如果当前后端没有 `apps/` 结构,也可以采用: + +```text +offline-backend-20260512/ + ai-writing-orchestrator/ + api/ + application/ + domain/ + infrastructure/ + prompts/ + tests/ +``` + +重点不是目录名字,而是一定要把“多 Agent 写作编排”与现有通用聊天能力隔离开。 + +--- + +## 3. 技术路线建议 + +推荐组合: + +- 编排框架:`LangGraph` +- 模型调用:接你们内网模型网关 +- 检索层:接内网知识库 / 文档库 / 搜索服务 +- 状态存储:先用数据库或 Redis + DB,后续再演进 +- 事件输出:SSE 或流式 HTTP + +推荐原因: + +- `LangGraph` 适合状态机和多节点回退 +- 对弱模型最关键的是“强流程控制”,不是“自由 Agent 对话” +- 后续加人工确认节点和 checkpoint 会更自然 + +--- + +## 4. 分层设计 + +建议按四层拆分。 + +## 4.1 API 层 + +职责: + +- 接收前端请求 +- 鉴权 +- 参数校验 +- 返回 workflow 信息 +- 提供事件流出口 + +建议文件: + +```text +api/ + routes/ + workflows.py + workflow_events.py + schemas/ + workflow_request.py + workflow_response.py +``` + +## 4.2 Application 层 + +职责: + +- 组织用例 +- 调度 workflow service +- 管理人工确认动作 +- 处理重试和终止逻辑 + +建议文件: + +```text +application/ + services/ + workflow_service.py + workflow_event_service.py + human_action_service.py + use_cases/ + create_workflow.py + start_workflow.py + confirm_outline.py + rewrite_section.py + approve_final.py +``` + +## 4.3 Domain 层 + +职责: + +- 定义工作流状态机 +- 定义 Agent 输入输出协议 +- 定义 artifact 与评分模型 + +建议文件: + +```text +domain/ + models/ + workflow.py + workflow_stage.py + workflow_event.py + artifact.py + review_result.py + agents/ + researcher.py + outliner.py + writer.py + editor.py + supervisor.py + graphs/ + writing_graph.py + policies/ + retry_policy.py + quality_policy.py +``` + +## 4.4 Infrastructure 层 + +职责: + +- 访问模型网关 +- 访问检索服务 +- 访问数据库 +- 发送事件 +- 缓存与日志 + +建议文件: + +```text +infrastructure/ + llm/ + model_client.py + retrieval/ + intranet_search_client.py + knowledge_base_client.py + persistence/ + workflow_repository.py + artifact_repository.py + streaming/ + sse_publisher.py + logging/ + workflow_logger.py +``` + +--- + +## 5. 工作流最小闭环 + +第一版建议只做如下状态机: + +1. `collect_materials` +2. `generate_outline` +3. `await_outline_confirmation` +4. `write_draft` +5. `review_draft` +6. `rewrite_if_needed` +7. `complete` + +终止规则: + +- 编辑评分达标则完成 +- 否则进入重写 +- 最多重写 2 次 +- 超过次数则标记 `human_intervention_required` + +--- + +## 6. Agent 模块设计 + +## 6.1 Researcher + +输入: + +- 主题 +- 用户要求 +- 检索范围 +- 可用资料源 + +输出: + +- `material_cards` +- `facts` +- `quotes` +- `examples` +- `risks` +- `source_refs` + +程序职责: + +- 先做检索 +- 再把检索结果裁剪后送给模型 +- 输出必须结构化 + +## 6.2 Outliner + +输入: + +- 用户要求 +- 研究结果 + +输出: + +- `title_candidates` +- `outline_sections` +- `key_points_per_section` + +约束: + +- 提纲优先,不写正文 + +## 6.3 Writer + +输入: + +- 已确认提纲 +- 素材卡片 +- 风格要求 + +输出: + +- `draft_sections` +- `section_source_refs` +- `full_draft_markdown` + +建议: + +- 按章节分段生成,不要一次长文直出 + +## 6.4 Editor + +输入: + +- 初稿 +- 提纲 +- 素材 +- 用户要求 + +输出: + +- `issues` +- `severity` +- `score` +- `rewrite_instructions` +- `decision` + +规则: + +- 先查事实,再查结构,再查文风 + +## 6.5 Supervisor + +输入: + +- 各阶段结果 +- 重试计数 +- 评分结果 + +输出: + +- 下一跳节点 +- 是否需要人工确认 +- 是否结束 + +--- + +## 7. Prompt 组织建议 + +建议为每个 Agent 分开管理 prompt,不要写成一个超级 prompt。 + +建议目录: + +```text +prompts/ + researcher/ + system.txt + output_schema.json + outliner/ + system.txt + output_schema.json + writer/ + system.txt + output_schema.json + editor/ + system.txt + output_schema.json + supervisor/ + system.txt +``` + +原则: + +- 每个 Agent 一套职责 +- 每个 Agent 一套输出 schema +- Prompt 版本可管理 +- 后续支持 A/B 调参 + +--- + +## 8. 弱模型适配策略 + +## 8.1 先检索后生成 + +不要让模型自己“想资料”,程序先检索、裁剪、去重后再喂给模型。 + +## 8.2 短上下文任务化 + +每个节点只给弱模型一小段明确任务: + +- 研究归纳 +- 提纲整理 +- 单章节写作 +- 单章节审稿 + +## 8.3 结构化输出 + +优先 JSON 或 Pydantic schema,不要放任自然语言自由返回。 + +## 8.4 章节级重写 + +不要整篇回炉。编辑指出第 2 节有问题,就只重写第 2 节。 + +## 8.5 程序接管质量门槛 + +例如: + +- 资料引用数不足,不进入下一步 +- 提纲章节数过少,直接重生 +- 编辑评分低于阈值,自动重写 + +--- + +## 9. 数据模型建议 + +## 9.1 Workflow + +建议字段: + +- `id` +- `status` +- `current_stage` +- `user_id` +- `thread_id` +- `input_payload` +- `current_artifact_id` +- `retry_count` +- `created_at` +- `updated_at` + +## 9.2 Workflow Artifact + +建议字段: + +- `id` +- `workflow_id` +- `artifact_type` +- `stage` +- `version` +- `title` +- `content` +- `metadata` + +## 9.3 Workflow Event + +建议字段: + +- `id` +- `workflow_id` +- `event_type` +- `stage` +- `agent_name` +- `payload` +- `created_at` + +## 9.4 Human Action + +建议字段: + +- `workflow_id` +- `action_type` +- `payload` +- `operator` +- `created_at` + +--- + +## 10. API 草案 + +## 10.1 创建任务 + +`POST /api/ai-writing/workflows` + +请求: + +```json +{ + "topic": "主题", + "articleType": "行业分析", + "audience": "管理层", + "tone": "专业克制", + "targetLength": 3000, + "constraints": ["避免口语化"], + "referenceScope": ["内网知识库", "项目复盘文档"] +} +``` + +返回: + +```json +{ + "workflowId": "wf_xxx", + "status": "idle" +} +``` + +## 10.2 启动任务 + +`POST /api/ai-writing/workflows/{id}/start` + +## 10.3 查询任务 + +`GET /api/ai-writing/workflows/{id}` + +## 10.4 订阅事件 + +`GET /api/ai-writing/workflows/{id}/events` + +返回事件流示例: + +```json +{ + "type": "stage_changed", + "stage": "generating_outline", + "message": "正在生成提纲" +} +``` + +## 10.5 确认提纲 + +`POST /api/ai-writing/workflows/{id}/confirm-outline` + +## 10.6 指定章节重写 + +`POST /api/ai-writing/workflows/{id}/rewrite-section` + +## 10.7 确认终稿 + +`POST /api/ai-writing/workflows/{id}/approve-final` + +--- + +## 11. LangGraph 实现建议 + +## 11.1 推荐 graph 节点 + +- `load_input` +- `retrieve_materials` +- `normalize_materials` +- `generate_outline` +- `wait_for_outline_confirmation` +- `write_sections` +- `merge_sections` +- `review_draft` +- `rewrite_sections` +- `publish_final_artifact` + +## 11.2 推荐 state + +建议 state 字段: + +- `workflow_id` +- `input_payload` +- `materials` +- `outline` +- `outline_confirmed` +- `draft_sections` +- `merged_draft` +- `review_result` +- `rewrite_targets` +- `final_article` +- `retry_count` +- `events` + +## 11.3 条件边 + +建议条件边逻辑: + +- 提纲未确认 -> 等待用户 +- 编辑通过 -> 完成 +- 编辑不通过且可重试 -> 重写 +- 编辑不通过且超限 -> 人工介入 + +--- + +## 12. 可观测性要求 + +第一版就建议带上以下能力: + +- 每个 workflow 的事件日志 +- 每个 Agent 的输入输出摘要 +- 每次重试原因 +- 每个阶段耗时 +- 每次模型调用 token 与错误日志 + +后续排问题会非常依赖这些数据。 + +--- + +## 13. 测试建议 + +## 13.1 单元测试 + +覆盖: + +- stage 流转 +- retry policy +- quality policy +- 事件构造 + +## 13.2 集成测试 + +覆盖: + +- 创建任务到完成的主链路 +- 提纲确认链路 +- 审稿失败后重写链路 +- 人工介入链路 + +## 13.3 Prompt 回归集 + +建议建立 10-20 个固定写作样例,做回归: + +- 短文 +- 长文 +- 事实密集型文章 +- 宣传型文章 +- 分析型文章 + +--- + +## 14. 开发顺序建议 + +## Step 1:先做 domain 与 API 契约 + +先定: + +- stage 枚举 +- event 枚举 +- artifact 结构 +- human action payload + +## Step 2:先做 fake orchestrator + +先不接真实模型,只模拟事件流,把前后端联调跑通。 + +## Step 3:接 Researcher + Outliner + +优先把“研究 + 提纲”做出来,因为这是弱模型提升最大的环节。 + +## Step 4:接 Writer + Editor + +再接初稿和审稿重写。 + +## Step 5:接可观测性和缓存 + +最后再补生产化能力。 + +--- + +## 15. 风险控制建议 + +### 风险 1:直接复用现有线程流,导致协议污染 + +建议: + +- workflow 用独立 route 和独立 event schema + +### 风险 2:写作结果与右侧 artifact 模型不兼容 + +建议: + +- 后端统一输出标准 markdown artifact + +### 风险 3:弱模型频繁输出不合法 JSON + +建议: + +- 每个节点加 schema repair +- 加轻量重试 +- 尽量减少复杂嵌套输出 + +### 风险 4:研究资料太多导致上下文爆炸 + +建议: + +- 检索后先裁剪、摘要、分桶 + +--- + +## 16. 最终建议 + +后端第一版最重要的是把“状态机、事件流、人工确认、章节重写”这四件事做对,而不是一开始就追求很多花哨 Agent。 + +建议 MVP 只保留: + +1. Researcher +2. Outliner +3. Writer +4. Editor +5. Supervisor + +当这条链路稳定后,再继续扩展 fact-checker、style editor、compliance reviewer。 diff --git a/frontend-web/docs/ai-writing-final-execution-plan.md b/frontend-web/docs/ai-writing-final-execution-plan.md new file mode 100644 index 00000000..cd8805cd --- /dev/null +++ b/frontend-web/docs/ai-writing-final-execution-plan.md @@ -0,0 +1,806 @@ +# AI 写作执行方案 + +## 1. 总体原则 + +本项目的最终落地原则: + +1. 前端继续基于当前 `open-canvas` 页面开发,不复制第二套页面 +2. 后端单独开 `ai-writing-orchestrator` 新路线,不侵入现有主链路 +3. 编排框架采用 `LangGraph` +4. 写作工作流采用 `Researcher -> Outliner -> Writer -> Editor -> Supervisor` +5. Agent 间输出统一采用 `JSON Schema / Pydantic` +6. 前后端通过 `SSE` 传递工作流事件 +7. 第一版只做最小闭环,不做过多花哨扩展 + +一句话说明: + +用独立的新后端路线承载多 Agent 写作工作流,前端继续复用 `open-canvas`,实现上采用 `LangGraph + A/B/C Agent + SSE` 的最小闭环。 + +--- + +## 2. 项目边界 + +## 2.1 前端边界 + +继续使用当前页面: + +- [CanvasResizableLayout.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/layout/CanvasResizableLayout.tsx) +- [CanvasChatPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/chat/CanvasChatPanel.tsx) +- [CanvasArtifactPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/artifact/CanvasArtifactPanel.tsx) + +前端做的事情: + +- 左侧增加“写作工作流模式” +- 展示多 Agent 执行进度与中间产物 +- 提供提纲确认和指定章节重写 +- 将初稿、终稿同步到右侧 artifact + +前端不做的事情: + +- 不重写右侧编辑器 +- 不重写现有普通 chat 流程 +- 不把 workflow 状态散落在多个旧 context 里 + +## 2.2 后端边界 + +后端采用独立新路线: + +推荐目录: + +```text +offline-backend-20260512/ + apps/ + ai_writing_orchestrator/ + api/ + application/ + domain/ + infrastructure/ + prompts/ + tests/ +``` + +后端做的事情: + +- 实现写作 workflow 状态机 +- 实现 A/B/C Agent 与 Supervisor +- 接内网模型与内网检索 +- 输出标准事件流和文章 artifact + +后端不做的事情: + +- 不直接改现有 DeerFlow 主流程 +- 不把工作流逻辑塞到现有通用 thread 协议里 + +## 2.3 资料搜集边界 + +第一版处于互联网开发阶段,因此研究员的资料搜集先走互联网检索,不接内网检索服务。 + +第一版要求: + +- 研究员可以调用互联网搜索能力收集公开资料 +- 研究结果必须保留来源 URL、标题、摘要、抓取时间 +- 检索层必须抽象成统一接口,不能把互联网搜索逻辑写死在 Agent prompt 或 graph 节点里 + +第二版预留: + +- 后续替换或并行接入内网搜索接口 +- 后续接入内部知识库、文档库、FAQ、项目复盘库 +- 前端和工作流层不因检索源变化而改协议 + +统一设计要求: + +- `Researcher` 只依赖“检索接口”,不依赖具体是互联网还是内网 +- `writing_graph` 只读取标准化后的素材结果 +- API、事件流、artifact 结构不区分互联网资料和内网资料 + +推荐检索抽象: + +```text +infrastructure/ + retrieval/ + base.py + internet_search_client.py + intranet_search_client.py + retriever_router.py +``` + +建议接口: + +```python +class RetrievalProvider(Protocol): + def search(self, query: str, top_k: int) -> list[RetrievedDocument]: ... + +class RetrievedDocument(BaseModel): + title: str + url: str | None + source_type: str + snippet: str + published_at: str | None = None + fetched_at: str + reliability: str | None = None +``` + +第一版路由策略: + +- 默认 `internet` +- 配置项预留 `intranet`、`hybrid` + +例如: + +```yaml +retrieval: + provider: internet + top_k: 8 + timeout_seconds: 15 +``` + +这样第一版先跑公网资料,后续切换内网时,只替换 `retriever_router` 和对应 provider,不改 workflow 主逻辑。 + +--- + +## 3. 第一版产品目标 + +用户在 `open-canvas` 中选择“写作工作流模式”后,可以完成以下流程: + +1. 输入主题、体裁、读者、风格、篇幅 +2. 研究员搜集资料并输出素材卡片 +3. 提纲 Agent 生成提纲 +4. 用户确认提纲 +5. Writer 生成初稿 +6. Editor 给出问题清单与评分 +7. 不达标则重写一次或两次 +8. 终稿写入右侧 artifact + +第一版成功标准: + +- 不是“生成得像最强模型一样好” +- 而是“明显优于单轮直出,并且流程可控、可回退、可人工介入” + +## 3.1 第一版研究员目标 + +第一版 `Researcher` 的核心职责,不是“写文章”,而是“给 Writer 准备可信、可引用、可筛选的素材”。 + +第一版输入: + +- 用户主题 +- 用户写作要求 +- 检索源配置,第一版默认 `internet` + +第一版输出至少包含: + +- `material_cards` +- `facts` +- `quotes` +- `examples` +- `risks` +- `source_refs` + +每条素材最少要带: + +- 来源标题 +- 来源 URL +- 摘要 +- 可信度标签 +- 被引用的原始片段或整理后的事实点 + +第一版 Researcher 的程序流程建议: + +1. 根据主题自动生成 3-5 个检索 query +2. 调用互联网检索接口拿回候选文档 +3. 做去重、裁剪、初筛 +4. 让模型将结果整理成结构化素材卡片 +5. 将结构化结果返回给 Outliner 和 Writer + +第一版先不做: + +- 深度网页 crawling +- 多轮自动追问式深研究 +- 内网知识库接入 +- 复杂引用格式生成 + +--- + +## 4. 最终工作流 + +## 4.1 Agent 角色 + +### `Researcher` + +职责: + +- 从配置的检索源检索信息 +- 产出结构化素材卡片 +- 标注来源、可信度、风险点 + +第一版说明: + +- 默认走互联网公开资料检索 +- 必须预留后续切换到内网检索源的接口 +- 检索实现放在 `infrastructure/retrieval/`,不要写死在 prompt 中 + +第一版检索源字段建议: + +- `source_type = "internet"` +- 后续预留 `source_type = "intranet" | "hybrid"` + +输出: + +- `material_cards` +- `facts` +- `quotes` +- `examples` +- `risks` +- `source_refs` + +### `Outliner` + +职责: + +- 根据用户要求和研究结果生成提纲 + +输出: + +- `title_candidates` +- `outline_sections` +- `key_points_per_section` + +### `Writer` + +职责: + +- 基于提纲和素材写初稿 +- 按章节写,不一次生成整篇长文 + +输出: + +- `draft_sections` +- `section_source_refs` +- `full_draft_markdown` + +### `Editor` + +职责: + +- 检查事实、结构、文风 +- 给出评分与重写建议 + +输出: + +- `issues` +- `severity` +- `score` +- `rewrite_instructions` +- `decision` + +### `Supervisor` + +职责: + +- 负责流程调度 +- 负责通过 / 重写 / 人工介入判断 + +## 4.2 状态机 + +第一版统一采用: + +- `idle` +- `collecting_materials` +- `generating_outline` +- `await_outline_confirmation` +- `writing_draft` +- `reviewing_draft` +- `rewriting_draft` +- `completed` +- `failed` +- `human_intervention_required` + +## 4.3 流程闭环 + +最小闭环固定为: + +1. `Research` +2. `Outline` +3. `HumanConfirmOutline` +4. `Draft` +5. `Review` +6. `RewriteIfNeeded` +7. `Complete` + +重试规则: + +- 最多重写 2 次 +- 达标则完成 +- 超限则进入人工介入 + +## 4.4 LangGraph 推荐节点 + +第一版推荐节点: + +- `load_input` +- `build_search_queries` +- `retrieve_materials` +- `normalize_materials` +- `generate_outline` +- `wait_for_outline_confirmation` +- `write_sections` +- `merge_sections` +- `review_draft` +- `rewrite_sections` +- `publish_final_artifact` + +其中和资料搜集直接相关的节点说明: + +### `build_search_queries` + +职责: + +- 根据用户主题和目标文章类型,生成 3-5 个检索 query + +### `retrieve_materials` + +职责: + +- 调用检索 provider 获取候选文档 +- 第一版默认走 `internet_search_client` +- 后续可切到 `intranet_search_client` + +### `normalize_materials` + +职责: + +- 做去重 +- 做摘要裁剪 +- 做来源字段统一 +- 输出标准 `RetrievedDocument[]` + +--- + +## 5. 前端最终做法 + +## 5.1 目录建议 + +在现有 `open-canvas` 下新增: + +```text +frontend-web/src/open-canvas/ + workflow/ + api/ + writing-workflow.ts + components/ + WritingWorkflowEntryForm.tsx + WritingWorkflowTimeline.tsx + WritingWorkflowEventList.tsx + WritingWorkflowArtifactDrawer.tsx + WritingWorkflowConfirmCard.tsx + WritingWorkflowHeader.tsx + CanvasWorkflowPanel.tsx + contexts/ + WritingWorkflowContext.tsx + hooks/ + useWritingWorkflow.ts + useWritingWorkflowEvents.ts + types/ + workflow.ts +``` + +## 5.2 左侧改造策略 + +`CanvasChatPanel` 只承担模式切换与容器职责: + +- `chat` 模式:沿用现有普通聊天 +- `writing_pipeline` 模式:渲染 `CanvasWorkflowPanel` + +新面板负责: + +- 写作任务表单 +- 进度时间线 +- 事件列表 +- 中间产物抽屉 +- 提纲确认卡片 + +## 5.3 右侧衔接策略 + +继续复用现有 `CanvasArtifactPanel`。 + +同步规则: + +- 提纲:可选同步到右侧预览 +- 初稿:同步到右侧 +- 重写稿:覆盖当前草稿 +- 终稿:作为最终 artifact + +## 5.4 前端状态设计 + +新增: + +- `workflowMode` +- `workflowRunId` +- `workflowStage` +- `workflowStatus` +- `workflowEvents` +- `workflowArtifacts` +- `workflowPendingAction` + +注意: + +- workflow 状态放进新的 `WritingWorkflowContext` +- 不塞进现有 `CanvasGraphContext` + +## 5.5 前端显示的资料信息 + +第一版左侧至少要能展示研究员产出的资料摘要: + +- 来源标题 +- 来源域名或 URL +- 资料摘要 +- 可信度标签 +- 是否被提纲或正文引用 + +建议在 `WritingWorkflowArtifactDrawer.tsx` 中增加“素材卡片”视图。 + +注意: + +- 第一版显示公开互联网来源即可 +- 后续接内网时,这个展示层不变,只是来源字段从 URL 变成内网文档标识或内部链接 + +--- + +## 6. 后端最终做法 + +## 6.1 分层 + +推荐分层: + +```text +api/ +application/ +domain/ +infrastructure/ +prompts/ +tests/ +``` + +## 6.2 核心模块 + +建议核心文件: + +```text +domain/ + models/ + workflow.py + workflow_stage.py + workflow_event.py + artifact.py + review_result.py + agents/ + researcher.py + outliner.py + writer.py + editor.py + supervisor.py + graphs/ + writing_graph.py + policies/ + retry_policy.py + quality_policy.py +``` + +## 6.3 检索层实现要求 + +第一版检索层必须独立成基础设施模块,不允许: + +- 在 Agent prompt 中直接拼接“去网上找资料” +- 在 graph 节点中散落请求第三方搜索的代码 +- 把互联网检索和内网检索混在一个无抽象的函数里 + +建议结构: + +```text +infrastructure/ + retrieval/ + base.py + internet_search_client.py + intranet_search_client.py + retriever_router.py + material_normalizer.py +``` + +建议职责: + +- `internet_search_client.py` + - 第一版实际使用 + - 对接互联网搜索 API 或爬取网关 + +- `intranet_search_client.py` + - 第一版只保留接口和空实现或 mock + - 后续接企业内部接口 + +- `retriever_router.py` + - 根据配置选择 provider + +- `material_normalizer.py` + - 统一清洗和标准化结果 + +## 6.4 Prompt 管理 + +统一独立存放: + +```text +prompts/ + researcher/ + system.txt + output_schema.json + outliner/ + system.txt + output_schema.json + writer/ + system.txt + output_schema.json + editor/ + system.txt + output_schema.json + supervisor/ + system.txt +``` + +## 6.5 输出约束 + +每个 Agent 都必须: + +- 优先输出 JSON / Pydantic schema +- 失败时允许轻量 repair 和一次重试 +- 避免自由散文式输出 + +## 6.6 Researcher 的实现细则 + +Researcher 推荐由两部分组成: + +1. 程序化检索 +2. 模型化整理 + +推荐伪流程: + +```python +def run_research(topic: str, article_type: str, provider: RetrievalProvider): + queries = build_queries(topic, article_type) + raw_docs = [] + for query in queries: + raw_docs.extend(provider.search(query=query, top_k=5)) + docs = normalize_materials(raw_docs) + docs = dedupe_materials(docs) + docs = rank_materials(docs) + return llm_extract_material_cards(docs) +``` + +第一版建议: + +- 先把 query 生成逻辑做简单 +- `top_k` 先控制在 5-10 +- 先做轻量去重和摘要裁剪 +- 不做很重的网页全文抓取 + +--- + +## 7. 前后端协议 + +## 7.1 API + +第一版统一提供: + +- `POST /api/ai-writing/workflows` +- `POST /api/ai-writing/workflows/{id}/start` +- `GET /api/ai-writing/workflows/{id}` +- `GET /api/ai-writing/workflows/{id}/events` +- `POST /api/ai-writing/workflows/{id}/confirm-outline` +- `POST /api/ai-writing/workflows/{id}/rewrite-section` +- `POST /api/ai-writing/workflows/{id}/approve-final` + +## 7.2 SSE 事件 + +统一事件类型: + +- `workflow_started` +- `stage_changed` +- `agent_started` +- `agent_output_chunk` +- `artifact_generated` +- `human_confirmation_required` +- `retry_scheduled` +- `workflow_completed` +- `workflow_failed` + +第一版前端不需要消费复杂嵌套事件,只要先把这 9 类打通。 + +## 7.3 配置项补充 + +建议增加以下配置项: + +```yaml +retrieval: + provider: internet + top_k: 8 + timeout_seconds: 15 + enable_content_fetch: false + +workflow: + max_revisions: 2 + +models: + researcher: your-default-model + outliner: your-default-model + writer: your-default-model + editor: your-default-model +``` + +说明: + +- 第一版 `provider=internet` +- 第二版可切成 `intranet` 或 `hybrid` + +--- + +## 8. 必须做 / 延后做 / 不建议现在做 + +## 8.1 必须做 + +### 架构 + +- 独立后端路线 `ai-writing-orchestrator` +- 前端独立 `workflow/` 目录 +- LangGraph 状态机 +- `Researcher / Outliner / Writer / Editor / Supervisor` +- 独立检索抽象层,第一版先落互联网 provider + +### 协议 + +- 标准 workflow 状态枚举 +- 标准 SSE 事件枚举 +- 标准 artifact 结构 +- JSON / Pydantic 输出约束 + +### 功能 + +- 启动写作任务 +- 研究阶段 +- 提纲阶段 +- 提纲确认 +- 初稿生成 +- 审稿与最多 2 次重写 +- 终稿同步到右侧 +- 素材卡片展示 +- 来源 URL、标题、摘要、可信度落库或挂在 artifact metadata + +### UI + +- 模式切换 +- 时间线 +- 事件列表 +- 提纲确认卡片 +- 右侧终稿显示 +- 左侧素材卡片视图 + +## 8.2 延后做 + +- 章节级精准重写 +- 初稿多版本树 +- FactChecker +- StyleEditor +- ComplianceReviewer +- 自动评分看板 +- 素材引用可视化高亮 +- 更复杂的人机协作节点 +- 内网知识库正式接入 +- 混合检索 `hybrid` +- 网页全文抓取与深摘要 + +## 8.3 不建议现在做 + +- 直接接入现有 DeerFlow 主 agent 包 +- 同时试 MetaGPT、CrewAI、AutoGen 多套底座 +- 一开始就做 5 个以上 Agent +- 一开始就做很复杂的文章版本管理 +- 一开始就把评分阈值和 prompt 写死得非常细 + +## 9. 最终开发顺序 + +## Step 1:先定契约 + +先一起拍板: + +- stage 枚举 +- event 枚举 +- artifact 结构 +- confirm / rewrite 的 payload +- retrieval provider 接口 +- RetrievedDocument 结构 + +## Step 2:先做 fake workflow + +后端先不接真实模型,只吐 mock SSE 事件,前端把左侧工作台跑通。 + +## Step 3:先接互联网版 Researcher + Outliner + +优先打磨“研究 + 提纲”,这是弱模型提升最大的部分。 + +这一阶段要求: + +- `Researcher` 先走互联网检索 +- `retriever_router` 可配置 +- `intranet_search_client` 先留接口空壳 + +## Step 4:接 Writer + Editor + +再补初稿与审稿重写闭环。 + +## Step 5:接右侧 artifact + +把初稿和终稿稳定写入右侧。 + +## Step 6:补生产化 + +- 缓存 +- 日志 +- 错误回放 +- 配置化 prompt + +## 10. 推荐任务拆分 + +## 前端 + +- `CanvasChatPanel` 模式切换 +- `workflow/` 目录与类型 +- 时间线 / 事件列表 / 确认卡片 +- SSE 订阅 hook +- 右侧 artifact 映射 +- 素材卡片列表展示 +- 来源字段展示规范 + +## 后端 + +- workflow API +- LangGraph graph +- 5 个 Agent 模块 +- Prompt 目录 +- SSE 输出 +- 仓储与日志 +- `RetrievalProvider` 抽象 +- `internet_search_client` +- `intranet_search_client` 预留接口 +- `material_normalizer` + +## Prompt / 算法 + +- Researcher prompt +- Outliner prompt +- Writer prompt +- Editor prompt +- JSON schema +- 失败样本回归 + +## 联调 + +- mock SSE +- 真模型接入 +- artifact 同步校验 +- 提纲确认链路验证 +- 互联网资料来源字段联调 +- 素材卡片到提纲引用链路联调 + +--- + +## 11. 开发过程中的约束 + +开发过程中统一采用下面这套口径: + +- 产品形态:当前 `open-canvas` 页面上的“写作工作流模式” +- 技术底座:`LangGraph` +- 核心模式:`Researcher -> Outliner -> Writer -> Editor -> Supervisor` +- 后端方式:独立 `ai-writing-orchestrator` +- 检索方式:第一版 `internet`,接口预留 `intranet` +- 通信方式:`SSE` +- 输出方式:`JSON Schema / Pydantic` +- 第一版目标:先做最小闭环,不追求角色数量和复杂度 + +给开发团队的统一口径: + +“我们在 `open-canvas` 上开发写作工作流模式,后端单开 `ai-writing-orchestrator`,第一版先用互联网资料检索,保留内网检索接入口,用 LangGraph 编排 Researcher、Outliner、Writer、Editor、Supervisor,把研究、提纲、初稿、审稿重写这条最小闭环做稳。” diff --git a/frontend-web/docs/ai-writing-frontend-refactor-checklist.md b/frontend-web/docs/ai-writing-frontend-refactor-checklist.md new file mode 100644 index 00000000..b7119431 --- /dev/null +++ b/frontend-web/docs/ai-writing-frontend-refactor-checklist.md @@ -0,0 +1,472 @@ +# AI 写作前端改造清单 + +## 1. 目标 + +在不新增第二套页面的前提下,基于现有 `open-canvas` 页面,把左侧从“单轮聊天输入框”升级为“多 Agent 写作工作台”,右侧继续沿用当前 `artifact` 编辑与流式预览能力。 + +当前核心文件: + +- [CanvasResizableLayout.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/layout/CanvasResizableLayout.tsx) +- [CanvasChatPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/chat/CanvasChatPanel.tsx) +- [CanvasArtifactPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/artifact/CanvasArtifactPanel.tsx) +- [CanvasGraphContext.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/contexts/CanvasGraphContext.tsx) +- [CanvasStreamContext.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/contexts/CanvasStreamContext.tsx) +- [useCanvasThreadStream.ts](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/hooks/useCanvasThreadStream.ts) +- [runs.ts](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/api/runs.ts) + +--- + +## 2. 改造原则 + +- 不改右侧主编辑器交互心智 +- 不复制新页面 +- 不破坏现有普通 chat 模式 +- 新增“写作工作流模式”时尽量以增量状态字段和新组件完成 +- 所有 workflow 能力都应允许逐步灰度 + +--- + +## 3. 推荐前端结构 + +建议在 `frontend-web/src/open-canvas` 下新增以下目录: + +```text +frontend-web/src/open-canvas/ + workflow/ + api/ + writing-workflow.ts + components/ + WritingWorkflowEntryForm.tsx + WritingWorkflowTimeline.tsx + WritingWorkflowEventList.tsx + WritingWorkflowArtifactDrawer.tsx + WritingWorkflowConfirmCard.tsx + WritingWorkflowHeader.tsx + contexts/ + WritingWorkflowContext.tsx + hooks/ + useWritingWorkflow.ts + useWritingWorkflowEvents.ts + types/ + workflow.ts + utils/ + workflow-event.ts +``` + +说明: + +- `open-canvas` 原有聊天、artifact、editor 目录不重构 +- 以 `workflow/` 作为新能力边界,减少对既有文件的侵入 + +--- + +## 4. 状态设计 + +## 4.1 新增的核心状态 + +建议新增: + +- `workflowMode: "chat" | "writing_pipeline"` +- `workflowRunId: string | null` +- `workflowStage` +- `workflowStatus: "idle" | "running" | "waiting_user" | "completed" | "failed"` +- `workflowEvents: WritingWorkflowEvent[]` +- `workflowArtifacts: WritingWorkflowArtifact[]` +- `workflowPendingAction: WritingPendingAction | null` + +## 4.2 推荐类型定义 + +建议在 `workflow/types/workflow.ts` 中先定义: + +```ts +export type WritingWorkflowStage = + | "idle" + | "collecting_materials" + | "generating_outline" + | "await_outline_confirmation" + | "writing_draft" + | "reviewing_draft" + | "rewriting_draft" + | "completed" + | "failed"; + +export type WritingWorkflowEventType = + | "workflow_started" + | "stage_changed" + | "agent_started" + | "agent_output_chunk" + | "artifact_generated" + | "human_confirmation_required" + | "retry_scheduled" + | "workflow_completed" + | "workflow_failed"; +``` + +第一版把类型先收紧,后续再扩展。 + +--- + +## 5. 组件拆分建议 + +## 5.1 左侧主面板改造 + +当前 `CanvasChatPanel` 建议只承担“模式路由”和布局容器职责,不继续无限堆逻辑。 + +建议改造为: + +- `chat` 模式继续渲染现有消息列表 + 输入框 +- `writing_pipeline` 模式渲染新的工作流视图 + +建议拆分出: + +- `CanvasChatConversation.tsx` +- `CanvasChatInputBox.tsx` +- `CanvasWorkflowPanel.tsx` + +这样后续不会把 `CanvasChatPanel.tsx` 变成一个过大的组件。 + +## 5.2 新增组件职责 + +### `WritingWorkflowEntryForm.tsx` + +负责采集: + +- 主题 +- 文章类型 +- 目标读者 +- 语气风格 +- 目标篇幅 +- 是否需要引用资料 +- 禁写项 +- 补充说明 + +### `WritingWorkflowTimeline.tsx` + +负责显示阶段: + +- 研究中 +- 提纲生成中 +- 等待确认提纲 +- 正在写初稿 +- 正在审稿 +- 正在重写 +- 已完成 + +### `WritingWorkflowEventList.tsx` + +负责显示细粒度事件: + +- 哪个 Agent 开始执行 +- 当前在处理哪一步 +- 当前产生了什么中间结果 +- 是否重试 + +### `WritingWorkflowArtifactDrawer.tsx` + +负责展示中间产物: + +- 素材卡片 +- 提纲 +- 初稿 +- 编辑意见 +- 重写稿 + +### `WritingWorkflowConfirmCard.tsx` + +负责展示用户确认点: + +- 确认提纲 +- 驳回提纲并附带修改意见 +- 继续写稿 +- 指定重写章节 + +--- + +## 6. Context 与 Hook 改造建议 + +## 6.1 `CanvasGraphContext` + +当前它只维护: + +- `messages` +- `artifact` +- `streamingArtifact` +- `isStreaming` + +建议不要把 workflow 状态直接塞进现有 `CanvasGraphContext`,否则会让语义过重。 + +推荐做法: + +- 保留 `CanvasGraphContext` 继续服务右侧 artifact 和通用流式状态 +- 新增 `WritingWorkflowContext` + +## 6.2 `WritingWorkflowContext` + +建议承载: + +- 当前 workflow 运行状态 +- 中间产物列表 +- 待确认操作 +- workflow 事件缓存 +- 启动 / 取消 / 确认 / 重写等 action + +## 6.3 `useCanvasThreadStream` + +当前这个 hook 已经负责: + +- 创建 thread +- 提交消息 +- 接收 thread stream +- 将 `update_artifact` 同步到右侧 + +建议不要把“多 Agent workflow 状态机”也硬塞进去。 + +推荐方案: + +- 保留 `useCanvasThreadStream` 给普通 chat 或兼容旧能力使用 +- 新增 `useWritingWorkflow` +- 新增 `useWritingWorkflowEvents` + +分工如下: + +- `useCanvasThreadStream`:普通对话流 +- `useWritingWorkflow`:创建 workflow、提交表单、触发确认动作 +- `useWritingWorkflowEvents`:订阅 workflow 事件流 + +--- + +## 7. API 接入建议 + +## 7.1 前端 API 文件 + +新增: + +- `workflow/api/writing-workflow.ts` + +建议暴露方法: + +- `createWorkflow(payload)` +- `startWorkflow(id)` +- `getWorkflow(id)` +- `subscribeWorkflowEvents(id, handlers)` +- `confirmOutline(id, payload)` +- `rewriteSection(id, payload)` +- `approveFinal(id)` + +## 7.2 事件流形式 + +优先级建议: + +1. `SSE` +2. 流式 HTTP chunk +3. 轮询兜底 + +理由: + +- 事件驱动比整段消息流更适合 workflow UI +- 可以更方便映射到时间线和事件列表 + +--- + +## 8. 与右侧 Artifact 的衔接 + +## 8.1 现有优势 + +当前 `CanvasArtifactPanel` 已具备: + +- 流式展示内容 +- 最终 artifact 渲染 +- 右侧编辑体验成熟 + +这意味着多 Agent 工作流不需要再做第二套文章渲染,只要把最终阶段结果推成 artifact 即可。 + +## 8.2 建议接法 + +工作流各阶段结果按两类处理: + +- 中间产物:进入左侧 `workflowArtifacts` +- 可阅读正文:同步一份到右侧 `artifact` + +推荐映射: + +- 提纲:可选同步到右侧,供用户预览 +- 初稿:同步到右侧 +- 重写稿:覆盖或新增版本到右侧 +- 终稿:作为最终右侧主版本 + +## 8.3 版本策略 + +建议右侧版本保留: + +- `outline` +- `draft_v1` +- `draft_v2` +- `final` + +如果现有 artifact 数据结构不方便承载完整版本树,第一版可先保留在 workflowArtifacts 中,右侧只展示当前激活版本。 + +--- + +## 9. 页面交互流程 + +## 9.1 用户首次进入 + +- 默认仍是现有 chat 模式 +- 在左侧增加一个显眼切换入口:`普通对话` / `写作工作流` + +## 9.2 启动写作工作流 + +- 用户填写写作任务表单 +- 点击“开始生成” +- 左侧切换到时间线 + 事件流视图 +- 右侧进入 loading 或素材 / 提纲预览态 + +## 9.3 等待提纲确认 + +- 时间线停在 `await_outline_confirmation` +- 左侧出现确认卡片 +- 用户可执行: + - 通过提纲 + - 要求调整提纲 + - 追加要求 + +## 9.4 生成初稿与审稿 + +- 左侧显示 Agent 事件 +- 右侧展示初稿内容 +- 审稿意见在左侧展示,同时高亮需要重写的章节 + +## 9.5 完成 + +- 左侧显示“终稿已完成” +- 右侧进入可继续局部 AI 编辑状态 + +--- + +## 10. 分步开发清单 + +## Step 1:类型与假数据 + +目标: + +- 先把 workflow 的类型、mock 数据、组件骨架搭好 + +任务: + +- 新建 `workflow/types/workflow.ts` +- 新建 `workflow/components/*` +- 用本地 mock 事件驱动时间线和事件流 + +验收: + +- 不接后端也能在页面中演示完整流程 + +## Step 2:模式切换 + +目标: + +- 在 `CanvasChatPanel` 中接入 `chat / writing_pipeline` 双模式 + +任务: + +- 拆出 `CanvasWorkflowPanel` +- 增加模式切换 UI +- 保证旧 chat 不回归 + +验收: + +- 现有功能不受影响 +- 新模式可进入表单页 + +## Step 3:接入 workflow API + +目标: + +- 从 mock 切到真实 API + +任务: + +- 接 `create/start/get/events` +- 实现基础错误态和重试态 + +验收: + +- 前后端可联调跑一条主链路 + +## Step 4:接入确认节点 + +目标: + +- 支持提纲确认和指定章节重写 + +任务: + +- 做确认卡片 +- 做动作回传 + +验收: + +- 用户能在流程中介入 + +## Step 5:打通右侧版本 + +目标: + +- 让 workflow 产物稳定进入右侧编辑器 + +任务: + +- 约定 artifact 映射 +- 接入版本切换或当前版本覆盖 + +验收: + +- 终稿稳定显示在右侧 + +--- + +## 11. 建议修改点位 + +优先涉及文件: + +- [CanvasChatPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/chat/CanvasChatPanel.tsx) +- [CanvasGraphContext.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/contexts/CanvasGraphContext.tsx) +- [useCanvasThreadStream.ts](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/hooks/useCanvasThreadStream.ts) +- [CanvasArtifactPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/artifact/CanvasArtifactPanel.tsx) + +建议新增,不建议重写原有: + +- `open-canvas/workflow/api/writing-workflow.ts` +- `open-canvas/workflow/contexts/WritingWorkflowContext.tsx` +- `open-canvas/workflow/hooks/useWritingWorkflow.ts` +- `open-canvas/workflow/hooks/useWritingWorkflowEvents.ts` +- `open-canvas/workflow/components/*` + +--- + +## 12. 联调约定 + +前后端需要尽早统一: + +- workflow id 命名 +- stage 枚举 +- event type 枚举 +- artifact type 枚举 +- user action payload +- 错误码与可恢复动作 + +建议先由前端与后端共同确认一份 `workflow.ts` 契约文档,再开工。 + +--- + +## 13. 最终建议 + +前端最重要的不是“把 Agent 结果展示出来”,而是把“工作流过程可视化并允许人工介入”做清楚。 + +第一版建议先保证三件事: + +1. 左侧能看见阶段进展 +2. 用户能确认提纲 +3. 右侧能稳定收到初稿和终稿 + +只要这三件事稳定,后续再继续加章节重写、评分展示、素材卡片增强,风险会小很多。 diff --git a/frontend-web/docs/ai-writing-weak-model-multi-agent-prd.md b/frontend-web/docs/ai-writing-weak-model-multi-agent-prd.md new file mode 100644 index 00000000..e2293119 --- /dev/null +++ b/frontend-web/docs/ai-writing-weak-model-multi-agent-prd.md @@ -0,0 +1,718 @@ +# AI 写作弱模型多 Agent 编排需求文档 + +## 1. 背景与目标 + +当前 `open-canvas` 页面右侧的成品展示与编辑体验已经比较成熟,但左侧模型直接生成文章的质量还不稳定。对于内网部署的弱性能大模型,单轮直出通常会出现以下问题: + +- 结构松散,长文容易跑题 +- 素材不足,内容空泛 +- 事实依据弱,容易幻觉 +- 润色能力有限,语言风格不统一 +- 一次生成失败后缺少可控的纠偏机制 + +因此本次需求的核心目标不是继续优化“单个模型一次写完”,而是在内网用代码编排一个“小型杂志社工作流”,让弱模型通过多角色分工协作,产出明显优于单模型直出的文章质量。 + +建议的角色分工: + +- `Agent A 研究员`:负责搜集内网素材、归纳事实、提取观点 +- `Agent B 作家`:基于选题、素材和结构写初稿 +- `Agent C 严苛编辑`:负责挑错、质检、润色、打回重写 +- `Supervisor / Orchestrator`:负责流程调度、状态记录、重试与终止判断 + +--- + +## 2. 本次建设边界 + +### 2.1 前端边界 + +前端继续使用现有 `open-canvas` 页面,不新开第二套编辑器页面。 + +当前相关入口: + +- [CanvasResizableLayout.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/layout/CanvasResizableLayout.tsx) +- [CanvasChatPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/chat/CanvasChatPanel.tsx) +- [CanvasArtifactPanel.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/components/artifact/CanvasArtifactPanel.tsx) +- [CanvasStreamContext.tsx](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/contexts/CanvasStreamContext.tsx) +- [runs.ts](/F:/react/deeflow-code/deerflow-server-master/frontend-web/src/open-canvas/api/runs.ts) + +前端本期只做以下增强: + +- 在左侧聊天区增加“写作工作流模式” +- 让用户能看到多 Agent 阶段进度,而不是只看到最终回答 +- 支持结构化输入:主题、体裁、目标读者、篇幅、语气、参考资料、禁写项 +- 支持查看中间产物:提纲、素材卡片、初稿、编辑意见、终稿 +- 支持人工介入:确认提纲、确认初稿、接受编辑建议、手动重跑某一步 + +### 2.2 后端边界 + +后端必须单开新路线,不影响其他同事当前功能开发。 + +建议原则: + +- 不直接改现有 DeerFlow 主流程 +- 不把多 Agent 逻辑硬塞进当前通用对话链路 +- 以独立服务或独立模块形式建设 +- 通过清晰 API 与当前前端页面对接 + +推荐落地位置: + +- 基于仓库中的 `offline-backend-20260512` 单独开一条 `ai-writing-orchestrator` 路线 +- 或在后端新建独立目录,例如 `offline-backend-20260512/apps/ai_writing_orchestrator` + +--- + +## 3. 为什么多 Agent 对弱模型更合适 + +弱模型最怕“一个 prompt 做完所有事”,因为这要求模型同时完成: + +- 选题理解 +- 信息检索 +- 信息筛选 +- 结构规划 +- 长文写作 +- 自我校验 +- 风格润色 + +把这些任务拆开后,每个 Agent 只处理一个更短、更清晰、更容易被弱模型完成的子任务,通常会带来以下收益: + +- 降低单次上下文复杂度 +- 降低一次性长输出失败率 +- 把“写得不好”变成“某一步做得不好”,便于重试 +- 可以在关键节点插入规则校验与人工确认 +- 可以用程序补足模型短板,而不是完全依赖模型智力 + +这套方案的本质不是“让模型变聪明”,而是“让系统更会组织模型工作”。 + +--- + +## 4. 可借鉴的开源项目 + +以下项目适合借鉴,但不建议整套照搬。建议以“借鉴状态机、角色协作、阶段拆分、重试与审稿机制”为主。 + +### 4.1 第一优先级:LangGraph + +推荐原因: + +- 天然适合把写作流程建模成状态图 +- 支持多步骤、条件分支、重试、人工介入 +- 便于把“研究 -> 提纲 -> 初稿 -> 评审 -> 重写”固化成可控流程 +- 对“弱模型 + 强流程控制”很友好 + +可借鉴点: + +- `StateGraph` 的状态驱动编排 +- 每一步单独定义输入、输出、失败处理 +- 可视化地表达“通过 / 打回 / 重试 / 终止” + +参考: + +- [langchain-ai/langgraph](https://github.com/langchain-ai/langgraph) +- [langgraph supervisor pattern](https://github.com/langchain-ai/langgraph-supervisor-py) + +### 4.2 第二优先级:STORM + +推荐原因: + +- 它本身就是“研究 + 提纲 + 成文 + 打磨”的长文系统 +- 对“先研究后写作”的思路非常契合 +- 很适合借鉴其“问题驱动研究”和“分阶段生成”的思想 + +根据其 GitHub README,STORM 将长文生成拆成两个大阶段:先研究并产出提纲,再基于提纲与资料写长文;其引擎进一步拆成知识整理、提纲生成、正文生成、文章润色四个模块。 + +这和我们的目标高度一致,尤其适合借鉴: + +- 提纲先行 +- 素材引用先行 +- 分模块写作 +- 后置润色 + +参考: + +- [stanford-oval/storm](https://github.com/stanford-oval/storm) + +### 4.3 第三优先级:Deep Research Agent + +推荐原因: + +- 明确支持本地模型与云模型混用 +- 已经包含研究、写作、质量校验、缓存、重试等能力 +- 很适合借鉴“研究阶段如何约束弱模型” + +根据其 README,这个项目采用四个专职 Agent,并且带有可信度评分、质量验证、重试逻辑、缓存和 checkpoint。 + +特别适合借鉴: + +- 素材缓存 +- 分阶段质量评分 +- 节点失败重试 +- 研究结果结构化存储 + +参考: + +- [tarun7r/deep-research-agent](https://github.com/tarun7r/deep-research-agent) + +### 4.4 可选借鉴:CrewAI + +推荐原因: + +- 角色扮演表达自然 +- 写“研究员 / 作家 / 编辑”这种协作关系很直观 +- Flow + Crew 的组织方式适合做 demo 和快速验证 + +不建议作为首选底座的原因: + +- 更偏“Agent 角色编排体验” +- 若要做企业内网稳定落地,状态管理和流程可控性通常不如 LangGraph 路线清晰 + +适合借鉴: + +- 角色定义写法 +- Task 模板 +- 多角色协作 prompt 结构 + +参考: + +- [crewAIInc/crewAI](https://github.com/crewAIInc/crewAI) + +### 4.5 不建议新项目优先采用:AutoGen + +原因: + +- 截至最近公开信息,`microsoft/autogen` 已进入 maintenance mode +- 官方建议新项目优先采用 `Microsoft Agent Framework` + +如果要借鉴,只建议借鉴早期多 Agent 对话模式,不建议作为本项目主框架。 + +参考: + +- [microsoft/autogen](https://github.com/microsoft/autogen) +- [microsoft/agent-framework](https://github.com/microsoft/agent-framework) + +### 4.6 结论 + +综合本项目需求,建议技术选型优先级如下: + +1. `LangGraph` 作为主编排框架 +2. `STORM` 借鉴研究-提纲-成文-润色的模块划分 +3. `Deep Research Agent` 借鉴缓存、评分、重试、可观测性 +4. `CrewAI` 借鉴角色 prompt 设计与任务模板 + +--- + +## 5. 目标产品形态 + +用户在当前 `open-canvas` 页面中,不再只是“向模型提问写文章”,而是启动一个可视化的写作流水线。 + +理想交互流程: + +1. 用户输入主题、用途、风格、读者、篇幅要求 +2. 系统先进入“研究阶段” +3. 系统给出资料卡片与候选提纲 +4. 用户确认提纲或调整 +5. 系统生成初稿 +6. 严苛编辑给出问题清单 +7. 系统自动重写问题段落 +8. 系统输出终稿到右侧编辑区 +9. 用户可继续局部改写、扩写、精简 + +核心体验目标: + +- 左侧像“编辑部工作台” +- 右侧像“成文编辑器” +- 用户知道系统现在进行到哪一步 +- 用户可以在关键节点接管,而不是只能等待最终结果 + +--- + +## 6. 多 Agent 流程设计 + +## 6.1 建议的最小可用流程 MVP + +第一版不要一上来做很复杂,建议先做 4 步闭环: + +1. `Research` + - 输入:主题、用户要求、内网资料源 + - 输出:素材卡片列表、可引用事实列表、风险点列表 + +2. `Outline` + - 输入:用户要求 + 素材卡片 + - 输出:结构化提纲 + +3. `Draft` + - 输入:提纲 + 素材卡片 + - 输出:初稿 + +4. `ReviewAndRewrite` + - 输入:初稿 + 用户要求 + 素材卡片 + - 输出:问题清单、改写稿、终稿 + +MVP 终止条件: + +- 编辑评分达标则结束 +- 不达标最多重写 2 次 +- 超过次数则返回“需要人工介入” + +## 6.2 第二阶段增强流程 + +在 MVP 跑通后,再增加: + +- `Planner`:根据文章类型动态规划流程 +- `SectionWriter`:按章节分别写作,避免长文崩坏 +- `FactChecker`:逐段核对素材来源 +- `StyleEditor`:统一语气、标题风格、句式节奏 +- `ComplianceReviewer`:内网场景下做敏感词、保密、术语规范检查 + +## 6.3 建议的状态机 + +建议将流程状态固定为: + +- `idle` +- `collecting_materials` +- `generating_outline` +- `await_outline_confirmation` +- `writing_draft` +- `reviewing_draft` +- `rewriting_draft` +- `completed` +- `failed` +- `human_intervention_required` + +这样前端和后端都可以围绕统一状态通信。 + +--- + +## 7. Agent 角色定义建议 + +## 7.1 Agent A 研究员 + +职责: + +- 搜集内网知识库、文档库、FAQ、历史稿件中的相关信息 +- 输出结构化素材,而不是长篇自然语言 +- 对每条素材标注来源、可信度、适用角度 + +输出格式建议: + +- `facts[]` +- `quotes[]` +- `examples[]` +- `risks[]` +- `source_refs[]` + +约束建议: + +- 禁止直接生成整篇文章 +- 不做风格化表达 +- 每条结论必须可回溯到来源 + +## 7.2 Agent B 作家 + +职责: + +- 严格基于提纲和素材写稿 +- 按章节写,而不是一次写完整篇 +- 对每段附带素材引用 ID,便于后续审核 + +约束建议: + +- 无素材不发挥 +- 每段只服务一个小节目标 +- 段落长度控制 +- 输出结构化草稿数据,而不仅是纯文本 + +## 7.3 Agent C 严苛编辑 + +职责: + +- 检查逻辑跳跃、素材不足、事实不稳、表述空泛、风格不统一 +- 输出明确的“问题清单”和“改写指令” +- 必要时打回指定章节,而不是整篇推翻 + +输出格式建议: + +- `issues[]` +- `severity` +- `rewrite_instructions[]` +- `accept/reject` + +编辑原则建议: + +- 优先挑事实问题,再挑结构问题,最后才是文风问题 +- 问题描述必须可执行,不能只说“写得不够好” + +## 7.4 Supervisor + +职责: + +- 负责流程启动、状态流转、失败重试、记录日志 +- 判断是否需要回到上一步 +- 控制最大重试次数 +- 对外提供统一 API 与流式事件 + +--- + +## 8. 前端需求 + +## 8.1 保持当前页面结构不变 + +继续沿用当前左右布局: + +- 左侧:聊天 + 流程进度 + 中间产物 +- 右侧:最终文章编辑与局部 AI 改写 + +不建议再复制一套新页面,以免造成维护分叉。 + +## 8.2 左侧新增 UI 模块 + +建议在 `CanvasChatPanel` 基础上新增: + +- 写作任务表单 +- 工作流阶段时间线 +- Agent 执行日志面板 +- 中间产物抽屉 +- 人工确认卡片 + +建议新增的前端概念: + +- `workflowMode`: `chat | writing_pipeline` +- `workflowStage` +- `workflowRunId` +- `workflowEvents[]` +- `workflowArtifacts[]` + +## 8.3 需要展示的中间产物 + +至少支持展示: + +- 素材卡片 +- 提纲 +- 初稿 +- 编辑问题单 +- 重写结果 +- 最终定稿 + +这些内容建议不仅显示在消息区,也保存到右侧可选版本中,便于回看。 + +## 8.4 人工介入节点 + +至少提供两个确认点: + +- 提纲确认 +- 初稿确认或编辑后重跑 + +后续可扩展: + +- 指定重写某个章节 +- 锁定某段不允许再改 +- 替换某条素材后重新生成 + +--- + +## 9. 后端需求 + +## 9.1 架构原则 + +后端新路线必须满足: + +- 与现有通用对话链路解耦 +- 与现有 Agent 运行时解耦 +- 独立维护 Prompt、状态机、数据结构 +- 可以单独部署、单独回滚、单独压测 + +## 9.2 推荐模块划分 + +建议后端拆分为以下模块: + +- `workflow_orchestrator` +- `agent_registry` +- `material_retriever` +- `outline_generator` +- `draft_writer` +- `editor_reviewer` +- `rewrite_engine` +- `workflow_store` +- `stream_event_adapter` + +## 9.3 API 建议 + +建议最小 API: + +- `POST /api/ai-writing/workflows` + - 创建写作任务 + +- `POST /api/ai-writing/workflows/{id}/start` + - 启动流程 + +- `GET /api/ai-writing/workflows/{id}` + - 查询当前状态 + +- `GET /api/ai-writing/workflows/{id}/events` + - 获取事件流或轮询事件 + +- `POST /api/ai-writing/workflows/{id}/confirm-outline` + - 用户确认提纲 + +- `POST /api/ai-writing/workflows/{id}/rewrite-section` + - 指定章节重写 + +- `POST /api/ai-writing/workflows/{id}/approve-final` + - 确认终稿 + +## 9.4 流式事件建议 + +为了与当前 `CanvasStreamContext` 风格兼容,建议后端输出结构化事件流,例如: + +- `workflow_started` +- `stage_changed` +- `agent_started` +- `agent_output_chunk` +- `artifact_generated` +- `human_confirmation_required` +- `retry_scheduled` +- `workflow_completed` +- `workflow_failed` + +前端只要订阅事件,就能把左侧工作台做出来。 + +--- + +## 10. 弱模型优化策略 + +这是本项目成功的关键,不能只靠“多 Agent”这四个字。 + +## 10.1 强约束输出格式 + +每个 Agent 尽量输出 JSON 或结构化对象,不要自由发挥。 + +原因: + +- 便于程序消费 +- 便于后续 Agent 接续 +- 便于失败重试 +- 便于质量评估 + +## 10.2 长文拆成章节生成 + +不要让弱模型一次生成整篇长文,建议: + +- 先出提纲 +- 再按章节逐段写 +- 最后统一润色 + +## 10.3 把检索和写作分离 + +研究员只负责找资料,作家只负责组织表达。不要让写作 Agent 同时去“边搜边编”。 + +## 10.4 程序兜底而不是模型兜底 + +程序需要承担: + +- 去重 +- 引用格式化 +- 章节拼接 +- 长度控制 +- 评分阈值判断 +- 重试路由 + +## 10.5 小步快跑、失败可回退 + +每步都要能独立失败、独立重试、独立回放。 + +## 10.6 引入可量化评分 + +编辑 Agent 输出不能只是一段文字,建议给出评分维度: + +- 相关性 +- 事实性 +- 结构完整度 +- 语言流畅度 +- 风格一致性 + +系统据此决定是否进入下一步。 + +--- + +## 11. 分阶段实施计划 + +## Phase 1:需求冻结与技术验证 + +目标: + +- 确认文章类型范围 +- 确认内网资料来源 +- 选定主框架 +- 跑通最小多 Agent demo + +交付物: + +- 技术选型说明 +- 角色与状态机设计 +- 1 个主题的端到端 demo + +验收标准: + +- 弱模型可完成“研究 -> 提纲 -> 初稿 -> 编辑 -> 重写”闭环 + +## Phase 2:后端新路线搭建 + +目标: + +- 建立独立 orchestrator +- 建立 workflow state store +- 建立事件流输出 +- 建立可配置 prompt 模板 + +交付物: + +- 独立服务目录 +- 基础 API +- 状态机运行骨架 + +验收标准: + +- 不依赖现有主流程改造即可独立跑通 + +## Phase 3:前端接入当前页面 + +目标: + +- 在 `CanvasChatPanel` 接入工作流模式 +- 增加阶段展示与人工确认 +- 中间产物可视化 + +交付物: + +- 左侧工作流时间线 +- 中间产物展示面板 +- 流程控制按钮 + +验收标准: + +- 用户可以在当前页面完成一次全流程写作 + +## Phase 4:质量优化 + +目标: + +- 强化素材检索质量 +- 提高提纲质量 +- 引入章节级重写 +- 引入评分与回退机制 + +交付物: + +- 质量评估规则 +- 重试策略 +- Prompt 调优包 + +验收标准: + +- 弱模型效果明显优于单轮直出 + +## Phase 5:生产化 + +目标: + +- 加缓存 +- 加日志 +- 加监控 +- 加失败告警 +- 加审计记录 + +交付物: + +- 可观测性方案 +- 运行日志与回放 +- 配置中心或 prompt 管理机制 + +验收标准: + +- 可长期维护并可定位问题 + +--- + +## 12. 团队协作与隔离方案 + +为了不影响其他同事,建议采用以下协作原则: + +- 新后端目录独立开发 +- 新接口使用独立路由前缀 +- 前端只在 `open-canvas` 内增量开发 +- 不修改现有公共线程协议,必要时增加新事件类型 +- Prompt、Agent 配置、评分规则独立存放 + +推荐分工: + +- 前端 1 人:负责左侧工作流 UI 与右侧版本接入 +- 后端 1-2 人:负责 orchestrator、Agent 执行、事件流 +- 算法/Prompt 1 人:负责角色 prompt、评分规则、失败样本调优 + +--- + +## 13. 风险与规避 + +### 风险 1:Agent 太多,成本和耗时暴涨 + +规避: + +- MVP 只保留 3 个业务 Agent + 1 个 Supervisor +- 长文按章节写,失败只重写局部 + +### 风险 2:弱模型在自由对话场景中失控 + +规避: + +- 全流程结构化 +- 每步只做一件事 +- 强约束输入输出格式 + +### 风险 3:内网检索质量不足,导致垃圾进垃圾出 + +规避: + +- 先把资料源治理好 +- 对素材做来源、可信度、去重处理 + +### 风险 4:前后端协议频繁变化影响联调 + +规避: + +- 先定义事件模型和 artifact 模型 +- 先 mock 数据,再并行开发 + +### 风险 5:影响现有功能稳定性 + +规避: + +- 新路线、新接口、新状态机 +- 不侵入现有主链路 + +--- + +## 14. 推荐结论 + +本项目推荐的总体策略: + +1. 前端继续基于当前 `open-canvas` 页面开发,不复制新页面 +2. 后端单独开 `ai-writing-orchestrator` 新路线,避免影响现有同事 +3. 主框架优先采用 `LangGraph` +4. 流程设计借鉴 `STORM` +5. 质量控制借鉴 `Deep Research Agent` +6. 角色设计与任务模板可参考 `CrewAI` +7. 第一版只做 4 步 MVP:研究、提纲、初稿、编辑重写 + +一句话总结: + +不是继续“调一个更强的 prompt”,而是把弱模型放进一个可控的编辑部流水线,让系统帮它把复杂写作拆开完成。 + +--- + +## 15. 参考链接 + +- [LangGraph](https://github.com/langchain-ai/langgraph) +- [LangGraph Supervisor](https://github.com/langchain-ai/langgraph-supervisor-py) +- [STORM](https://github.com/stanford-oval/storm) +- [Deep Research Agent](https://github.com/tarun7r/deep-research-agent) +- [CrewAI](https://github.com/crewAIInc/crewAI) +- [Microsoft Agent Framework](https://github.com/microsoft/agent-framework) +- [AutoGen](https://github.com/microsoft/autogen) From fd759d6845c7da1c9d460bad835e78308b5627da Mon Sep 17 00:00:00 2001 From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com> Date: Mon, 18 May 2026 17:44:08 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BE=9D=E8=B5=96=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend-web/docs/测试.md | 2 + frontend-web/package-lock.json | 690 ++++++++++++++++++++++++++++++++- 2 files changed, 691 insertions(+), 1 deletion(-) diff --git a/frontend-web/docs/测试.md b/frontend-web/docs/测试.md index ba65cbb4..1f05bed6 100644 --- a/frontend-web/docs/测试.md +++ b/frontend-web/docs/测试.md @@ -105,3 +105,5 @@ PYTHONPATH=. uv run pytest tests/test_ai_writing_graph.py -v # 19 tests ``` 两个测试文件均应全部通过(0 failed)。 + +npm install @tiptap/core @tiptap/starter-kit @tiptap/extension-underline @tiptap/extension-placeholder \ No newline at end of file diff --git a/frontend-web/package-lock.json b/frontend-web/package-lock.json index 2edad9b5..0437d4af 100644 --- a/frontend-web/package-lock.json +++ b/frontend-web/package-lock.json @@ -35,6 +35,13 @@ "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-use-controllable-state": "^1.2.2", "@tanstack/react-query": "^5.90.17", + "@tiptap/core": "^3.23.4", + "@tiptap/extension-bubble-menu": "^3.23.4", + "@tiptap/extension-placeholder": "^3.23.4", + "@tiptap/extension-underline": "^3.23.4", + "@tiptap/pm": "^3.23.4", + "@tiptap/react": "^3.23.4", + "@tiptap/starter-kit": "^3.23.4", "@types/hast": "^3.0.4", "@uiw/codemirror-theme-basic": "^4.25.4", "@uiw/codemirror-theme-monokai": "^4.25.4", @@ -74,6 +81,7 @@ "streamdown": "1.4.0", "tailwind-merge": "^3.4.0", "tdesign-react": "^1.12.3", + "tiptap-markdown": "^0.9.0", "tokenlens": "^1.3.1", "unist-util-visit": "^5.0.0", "use-stick-to-bottom": "^1.1.1", @@ -4262,6 +4270,417 @@ "react": "^18 || ^19" } }, + "node_modules/@tiptap/core": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.23.4.tgz", + "integrity": "sha512-ni2LWE52bVeSt3L2HVBSmbBw+elc32ATej9C68EyKzN/8vR5ILxFn6RCdDTKm4asmwZyq2jys12dKmBdWMr9QA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.23.4.tgz", + "integrity": "sha512-7YjSibNlPcy9eGK+tHt5G/Njr7nPxl+rZ3rCC6TwtLIRLSHPnoGDsfFOgTPkXxaQcE1a/VQwemnYfWc3kdIjDQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.23.4.tgz", + "integrity": "sha512-3L9tnZ12i+98u5df2nV2zGu/sc3rhI87E3ocn1YYAO8PJUAgZnMwdet8JawCrS1uut5sRKlxo3SXEmdNfRVm/w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.23.4.tgz", + "integrity": "sha512-EPTpL/IFp/aTGZErBq/Mc3dKznj6G/qNEkVYWjueOn1oKApyT0P6WVHGvu/vpMdErhzmoGDuFPPGVS6T8Upx2Q==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.23.4.tgz", + "integrity": "sha512-mXB2KZOz1R+E6VNTZ3vzdAk7ZDGKjPmsJEZIQg1B5qRycTKg49/rCCkLA2QnqAwX6BzS3mLLH1RWE2W0oXD7vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.4" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.23.4.tgz", + "integrity": "sha512-C0TeRipMycUEBnV+Mzx6eLp/yZb6Vi/waP3Tkb0lO5/ikg7LWLB7AlmMunjIXEUcR/pJHID/aEh5PfJFpysUDg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.23.4.tgz", + "integrity": "sha512-UEU1w/85CSNKktbhESnIRmtjKcH7DeschReZA8err1wAnYLTKzid5ucnJSJ25iRg2V5Fnuws5gnPT5CVgdfXCQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.23.4.tgz", + "integrity": "sha512-YC4G6VkxT629rlqUTwD6XvOpxjvghn7fxrK4RbyKVJY2C6E1vgmX0won1Ast6v+qTE6iONOMS6f6VyPxSGjg4w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.23.4.tgz", + "integrity": "sha512-ujJQUIENk0RwVFCh5g/TOSEv1a7Pnam/cjHmSUqHWUNZkYS9aOqjm+JfURJPCinRS2oHvo3AARul5mkKgDJYcA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.23.4" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.23.4.tgz", + "integrity": "sha512-eAc72bKM26yIPx0jsU8qdjE71vFNVu5R9jGbdItBMFc0SPLS4qY8g+8RJ+iWoLwbcSEpgooLS9D9sLfdAU+Tvw==", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.23.4.tgz", + "integrity": "sha512-RuyvOlIGP6UpVOc0Lw0L63jKLtYM49CNhPV2OMSfwwwbBZ3pJGos2/SqpYg71d3sn+qpsAopS4Pfr8iPZog73A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.23.4" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.23.4.tgz", + "integrity": "sha512-ODlpZCi7n136BH9luM09EFL8Pg+bbRCd0tzCQM5BKMXRkLitYZA8Gl/f5DLmGJ50wzFsDPXK2Br2g9UvZK7COg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.23.4.tgz", + "integrity": "sha512-8W9Hqi0J69Xbqg08nPf4xRMJXMccaKFAgUE1tvy5PAWJSQxOMwkKQXgZXxwe+80sOMUnV8qveBqUy/ODMPgAxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.23.4.tgz", + "integrity": "sha512-EA4kK8ywZ4dQNOdxeZbplmDDs5T5LjMgHpqxRwukj9wwKiILOK5E3fcKm1fCKh9Q02w96jax6YVccHwmgJP3sQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.23.4.tgz", + "integrity": "sha512-jUAHi+HZlg47BzgVIy6y/UH5vev7vPQ95jddhB5K3hC122kvWFMXlken7UOnqzbxNcHs2+4Oi/ZJirYMpT4P5w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.23.4.tgz", + "integrity": "sha512-XjxltY7MomwfTs6jmN6Bw5bb/upb34lpyqv2RiXppFTK25Br7ipksRjUpWpB4/csZeg30qwrLGVKxCol38ffrw==", + "dependencies": { + "linkifyjs": "^4.3.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.23.4.tgz", + "integrity": "sha512-yuauDm6qW/7q+ZO0YJBKQEGdnUm6DDTJM8AMp9bMZrT4jRf/zyUtNcZ91QEfFvBcyVuI+10PIOXtNPevhQ741Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.23.4.tgz", + "integrity": "sha512-Q/JXosShD5oyDwukE6igdrZD2lb0ZgyoQTHYchk0pzU4frClFbn3RI1wKP+XeqKLhdO6KH2WZ9rERGH7PtDi7Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.4" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.23.4.tgz", + "integrity": "sha512-9FezifCfuoc0o+5K6l4QNOOfelqxnDGg/f9oL1D/LFZPC54bPxpWWft9QCWOqyqZgyLCLjbCjciAlbgkrFUmmw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.4" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.23.4.tgz", + "integrity": "sha512-+3ofyssYnOTa1+nFWEmCAY1ngn8nAV1xo25JnNNC87NMU9WkSgr93jB7/uUJP0uui1C2dBLlaup3XXm108yarw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.4" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.23.4.tgz", + "integrity": "sha512-KbhXjCFzWphvFn5VU7E4dtmYDm+bssI1i0+CnXPWCXkjdaaX88ck68Xp1fKz8/bbI/CqlgiNDO/3TvqgtZ6woQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-placeholder": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.23.4.tgz", + "integrity": "sha512-yHtAZkFR9M2AQmCi555w4ns1BBCqwRyYDYMtd10DBvqPX7T3TmGerPdUfI6sLr74GxnZ5zHOnOYdwAbeG5JzNw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.23.4" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.23.4.tgz", + "integrity": "sha512-Vnq5vW801zPbu1LtKeA5k4R241jY+hRjXeijYwIPxy15KzIiipY12518HiCf6/8kkRbMxgOfdYg9X4BRV3HV3g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.23.4.tgz", + "integrity": "sha512-q9kxver/MR18p66aWZHSPycnr9hcBFyVGeGj8gf+BQCzn5hpvtSYTfLvk1nq8GFhygdQ9/e3f7B5ovrm/jnpvw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.23.4.tgz", + "integrity": "sha512-F1ocPT10LV+seky25R1TMCRdc/Iof99jLcDSYDGr6mNEDY4ct2RvOeSM8aDdYq6CkH+vXt3i3JDeRwV23KzswQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.23.4.tgz", + "integrity": "sha512-SlGPXauW8iKWG7wwuwC/0y/smLImp0h6GBIGgNnTBgIP/ThXQnjLMSZH0mW/REO87dQxkku01V3ARRywi+juhg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.23.4.tgz", + "integrity": "sha512-+C5ngcoza47n3MjtjVBqBEBICPC0McdbwzJ+X6SSCviCLoqnSYanv5mIX9HWG0Q4fJ4BkdNM3VibZUxQaTbKyQ==", + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-keymap": "^1.2.2", + "prosemirror-model": "^1.24.1", + "prosemirror-schema-list": "^1.5.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.38.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.23.4.tgz", + "integrity": "sha512-mb5aIY9PuLreOVLExqs+8BAI20I/8+jCUBfEIqheuFY2GRRuBiwczejSlYuADfVDBbPVN5uPw4UMADCaH5wueQ==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.23.4", + "@tiptap/extension-floating-menu": "^3.23.4" + }, + "peerDependencies": { + "@tiptap/core": "3.23.4", + "@tiptap/pm": "3.23.4", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.23.4.tgz", + "integrity": "sha512-3VhU+NO6/ec9DMj/5Ej0nzARSq42cXnqW+QHCmTL3FNXkXQz+tw1KlfruT5GGJ3M0RssjWjRC0a39N/4S3qxeA==", + "dependencies": { + "@tiptap/core": "^3.23.4", + "@tiptap/extension-blockquote": "^3.23.4", + "@tiptap/extension-bold": "^3.23.4", + "@tiptap/extension-bullet-list": "^3.23.4", + "@tiptap/extension-code": "^3.23.4", + "@tiptap/extension-code-block": "^3.23.4", + "@tiptap/extension-document": "^3.23.4", + "@tiptap/extension-dropcursor": "^3.23.4", + "@tiptap/extension-gapcursor": "^3.23.4", + "@tiptap/extension-hard-break": "^3.23.4", + "@tiptap/extension-heading": "^3.23.4", + "@tiptap/extension-horizontal-rule": "^3.23.4", + "@tiptap/extension-italic": "^3.23.4", + "@tiptap/extension-link": "^3.23.4", + "@tiptap/extension-list": "^3.23.4", + "@tiptap/extension-list-item": "^3.23.4", + "@tiptap/extension-list-keymap": "^3.23.4", + "@tiptap/extension-ordered-list": "^3.23.4", + "@tiptap/extension-paragraph": "^3.23.4", + "@tiptap/extension-strike": "^3.23.4", + "@tiptap/extension-text": "^3.23.4", + "@tiptap/extension-underline": "^3.23.4", + "@tiptap/extensions": "^3.23.4", + "@tiptap/pm": "^3.23.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, "node_modules/@tokenlens/core": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@tokenlens/core/-/core-1.3.0.tgz", @@ -4606,6 +5025,20 @@ "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==" }, + "node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==" + }, + "node_modules/@types/markdown-it": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.9.tgz", + "integrity": "sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==", + "dependencies": { + "@types/linkify-it": "^3", + "@types/mdurl": "^1" + } + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -4614,6 +5047,11 @@ "@types/unist": "*" } }, + "node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==" + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -4641,7 +5079,6 @@ }, "node_modules/@types/react-dom": { "version": "19.2.3", - "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -4668,6 +5105,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==" + }, "node_modules/@types/validator": { "version": "13.15.10", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", @@ -4910,6 +5352,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "node_modules/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", @@ -5986,6 +6433,14 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fault": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", @@ -6867,6 +7322,19 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/linkifyjs": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.3.tgz", + "integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==" + }, "node_modules/lodash-es": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", @@ -6931,6 +7399,38 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-task-lists": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz", + "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==" + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", @@ -7224,6 +7724,11 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, "node_modules/mermaid": { "version": "11.14.0", "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz", @@ -7945,6 +8450,11 @@ "regex-recursion": "^6.0.2" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==" + }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -8176,6 +8686,160 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/prosemirror-changeset": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-markdown": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz", + "integrity": "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==", + "dependencies": { + "@types/markdown-it": "^14.0.0", + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-markdown/node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==" + }, + "node_modules/prosemirror-markdown/node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/prosemirror-markdown/node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==" + }, + "node_modules/prosemirror-model": { + "version": "1.25.6", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.6.tgz", + "integrity": "sha512-RIm+e9BiqAaJ1mRECv3vR3C+VG8ELoTTI+47tVudGi82yLnFOx3G/p/iSPK1HmHQdKhkkrJ68NJqxh7S+FBVmQ==", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.41.8", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz", + "integrity": "sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==", + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "engines": { + "node": ">=6" + } + }, "node_modules/raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -8608,6 +9272,11 @@ "fsevents": "~2.3.2" } }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==" + }, "node_modules/roughjs": { "version": "4.6.6", "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", @@ -8907,6 +9576,20 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tiptap-markdown": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/tiptap-markdown/-/tiptap-markdown-0.9.0.tgz", + "integrity": "sha512-dKLQ9iiuGNgrlGVjrNauF/UBzWu4LYOx5pkD0jNkmQt/GOwfCJsBuzZTsf1jZ204ANHOm572mZ9PYvGh1S7tpQ==", + "dependencies": { + "@types/markdown-it": "^13.0.7", + "markdown-it": "^14.1.0", + "markdown-it-task-lists": "^2.1.1", + "prosemirror-markdown": "^1.11.1" + }, + "peerDependencies": { + "@tiptap/core": "^3.0.1" + } + }, "node_modules/tokenlens": { "version": "1.3.1", "license": "MIT", @@ -8968,6 +9651,11 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + }, "node_modules/ufo": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz",