Skip to content

feat: 飞书导入换轨 lark-cli + PPT 收归 slides-writer 子代理 - #272

Open
lzp-plus wants to merge 11 commits into
devfrom
feat/room-board-navigation
Open

lzp-plus wants to merge 11 commits into
devfrom
feat/room-board-navigation

Conversation

@lzp-plus

@lzp-plus lzp-plus commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • 飞书:授权与导入链路整体换轨 lark-cli——授权/断开直连本机凭据,列举/正文/评论/媒体直读;数据源卡补文档统计、抽屉内嵌授权导入面板、批量导入面板重挂载找回进行中批次
  • PPT:slides 四件套从主 Agent 工具面剔除,收归 slides-writer 子代理(六套风格 skills + 结构化输出契约);主 Agent 只留 slides_draft(create/edit) 调度;桌面「AI 修改」弹层与产物库新建 PPT 指令同步改道
  • genoffice 子模块指针 bump 到 4f66a9c:接入 page-spec 硬校验(拒绝 emoji 与文本墨迹叠压,页面不合格让模型重试),上游已合入 genoffice main(genoffice#1)
  • 修复:SaaS 登录会话自愈(OIDC 超时响应照常采纳 + refresh 被拒清本地会话);转录同步撞跨账号 409 记录进 blockedSources,防对账无限重排队
  • 测试:会话恢复适配启动恢复重试;office/pdf 文件导入→解析→记忆理解引擎全链路 e2e

Test plan

  • 网关 slides-writer-tools / subagent-tools 测试(11 通过)
  • 桌面 office-agent-ask / private-transcription-sync 测试(10 通过)
  • genoffice apps/slides page-spec 测试(14 通过)
  • 真机冒烟:飞书导入、PPT 生成与 AI 修改链路

- OIDC 登录用 epoch 判定接管:服务端已按一设备一会话吊销旧会话,超时后
  到达的响应照常采纳,避免客户端抱着被吊销的旧 token 死循环 401
- refresh 遇 401/403 清空本地会话,心跳/租约续期不再空转刷屏,待重新登录
- 主进程:start 省略 phase 时按授权环境自动选阶段;新增 disconnect
  (lark-cli auth logout 清本机凭据);verificationUrl 首次出现自动拉起浏览器
- 渲染层:数据源页飞书改走本地授权(连接宫格固定入口 + 已连接卡 + 抽屉
  换绑/断开),存量 oo 飞书连接在数据源页隐藏;授权过程改弹居中对话框
- 浏览器 mock:agentAuth 状态机(__feishu.completeAuth/reset)+
  AgentPanel.css 引入,mock 页可复现授权卡
- 网关新增 GET /v1/document-import/batches/active:按 provider+连接名
  查最近一条 running 批次,无则 null;终态后不再返回
- 桌面主进程/preload/桥接透传 activeImportBatch
- 导入面板打开或切换连接时找回后台仍在跑的批次:恢复进度条、续接轮询
  到终态,完成/取消 toast 与列表刷新同样生效;runActiveRef 防与本地
  新批次双写
docx/pdf/xlsx 真实接线(FilesService→parseVersion→统一理解引擎→
MemoryCore 子进程→mock LLM),断言解析文本真实到达记忆引擎出原子;
xlsx 默认策略不进记忆。test 脚本单独隔离跑(与 memory-doc-pipeline 同法)
…tion

# Conflicts:
#	apps/desktop/src/main/cloud/saas-client.ts
#	apps/desktop/src/renderer/src/components/pages/sources/SourceCard.tsx
合并 dev 后 initialize 记忆会在无账号时清空,status() 重跑会话恢复并拿
存量 token refresh;原 mock 对 /app/auth/refresh 回订阅形状导致恢复失败
进入 2 秒重试睡眠,假时钟下无人推进而挂起。refresh 改回登录形状(与登录
同会话族),4 用例恢复通过。
- 新增 lark-action-runner:把适配器发出的 OpenConnector action 翻译成
  lark-cli 命令,CLI 信封归一化成 oo 形状(providers.ts 解析零改动),
  错误统一分类成 ImportConnectorError
- service:飞书不经 OpenConnector 连接解析;授权门禁(auth status 缓存
  30s,缺失映射 422 引导授权);图片/媒体经 lark-cli 下载到本地文件;
  create-server 注入 larkCli 配置
- FeishuAuthCard 显示可见文档数/已导入数(列举缓存,未列举显示 —/0)
- 导入面板新增 standalone 模式:不拉 OpenConnector 连接、不显示连接
  缺失引导;飞书抽屉直接内嵌,授权态由数据源页维护
- SourcesPage:飞书已授权即拉导入统计;连接提示文案去掉「连接器」页
  指引(飞书已不走该入口)
- 网关:slides 四工具从用户档工具面剔除(SLIDES_TOOL_NAMES 单一事实源),
  新增 slides_draft(create/edit) 派发子代理并归一结构化结果;
  注册 slides-writer 工具面(slides 四件套 + 素材自取只读面)
- 子代理:新增 agents/slides-writer(六套风格 skills + 结构化输出契约),
  read 工具改为相对 revision 根解析路径
- 桌面:PPT「AI 修改」弹层与产物库新建 PPT 的指令改走 slides_draft

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

总评

本 PR 体量较大(飞书导入换轨 lark-cli、PPT 四件套收归 slides-writer 子代理、SaaS 登录会话自愈、转录 409 防重排队),整体实现质量较高。已核实的安全面:lark-cli 执行层 spawn(shell:false) 无 shell 注入面;媒体下载 token 经 [A-Za-z0-9]+ 白名单提取后再拼路径,无路径穿越;openExternalUrl 仅放行 http/https,授权链接自动开浏览器不会执行任意协议;skill read 工具改为 root 相对解析后仍受 startsWith(root+sep) 约束;slides-writer 工具面 allowlist 与 SLIDES_TOOL_NAMES 有测试同步断言,主 Agent 用户档剔除逻辑覆盖 main/main-direct/main-lite。测试覆盖(lark-runner、batch active、slides-writer-tools、subagent-tools、session-recovery)扎实。

未发现安全/隐私阻塞项;以下按严重度列出建议关注的问题。

发现(按严重度)

  1. 【中·发布风险】引擎硬校验未随本 PR 落地,子模块指针悬空
    agents/slides-writer/SYSTEM.md:26 向子 Agent 承诺「引擎硬校验(emoji/文本重叠违规整页拒绝,报错回传后修正重试)」,该校验位于 genoffice 子模块的未推送分支(PR 备注自述当前账号推不上去),本 PR 中 apps/desktop/vendor/genoffice 指针无任何变化。指针 bump 跟进之前,防 emoji/防重叠只余模型自查,实际兜底弱于 SYSTEM.md 与主 Agent 工具描述的承诺。建议把指针跟进 PR 显式挂到本 PR 或 issue 上跟踪,避免两步之间的质量空窗被遗忘。

  2. 【中·运行风险】飞书换轨后的真实 CLI 输出契约未经真机验证
    test plan 中「真机冒烟:飞书导入」未勾选。apps/gateway/src/modules/documents/import/lark-action-runner.ts:102-114 对 drive files list 条目(type/token/name/url/modified_time/owner_display_name 等)原样透传给 providers.ts 的键名解析,:45-56 的 result_meta 拍平同样依赖 CLI 实际输出形状——单测 fixture 是测试作者自证的,无法证明真实 lark-cli 契约一致。若字段名有出入,列举/搜索可能仍通但 owner/updatedAt 静默缺失。建议合并前完成一次真机冒烟(导出侧已在用的 docs +search/+fetch 契约可信度高,风险集中在 drive files list/wiki 系列与评论条目)。

  3. 【低】refresh 401/403 即清本地会话,瞬时故障会强制登出
    apps/desktop/src/main/cloud/saas-client.ts:1622-1624:refresh 被拒(401/403)立即 clearSession() 删除本地 refresh token。线上事故背景可以理解,但若 401/403 来自网关瞬时故障/鉴权服务异常(token 实际仍有效),用户被强制登出且无法自愈。可考虑仅在响应体可判定「会话已被吊销/轮换」时才清,至少补一个可观测信号区分两种成因。

  4. 【低】blockedSources 以服务端错误文案正则为转移,且无清理路径
    apps/desktop/src/main/transcription/private-transcription-sync.ts:418:/owned by another account/i 匹配错误 message 决定永久拉黑,服务端文案一变即回到无限重排队(正是本 PR 要修的问题);且 blockedSources 无过期/清理机制(记录被原账号删除后也永不再试)。建议改用结构化判据(如 SaasRequestError 的 status===409 + 稳定错误码)。

  5. 【低·效率】授权状态轮询每 8s 双份 spawn 子进程且无缓存
    apps/desktop/src/main/agent-auth/controller.ts:136-140 的 status() 每次真实 spawn lark-cli --version + auth status(后者每次读系统钥匙串),叠加 apps/desktop/src/renderer/src/components/agent/AgentAuthChallengeCard.tsx:20-38 的 8s 轮询;SourcesPage 与 Agent 面板的 hook 同时挂载时为双份。建议 controller 侧对环境探测加短 TTL 缓存(网关侧 ensureFeishuLarkAuth 已有 30s 缓存可对齐)。

  6. 【低】找回批次轮询连续失败后本地标记语义不准
    apps/desktop/src/renderer/src/components/pages/ConnectorDocumentImportPanel.tsx:288-290:找回(resume)路径连续 10 次状态查询失败后把批次在 UI 本地置为 cancelled,而网关侧批次可能仍在跑(或已被 recoverInterrupted 置 failed)——与用户主动取消不可区分;对比 startBatch 路径(:369)是抛错中断。建议统一为「状态未知/失败」语义。

  7. 【提示】pageSize 非数字时会把 "NaN" 传给 CLI
    apps/gateway/src/modules/documents/import/lark-action-runner.ts:120:String(Math.min(Number(textValue(input.pageSize) ?? 20), 20))——pageSize 为非数字字符串时 Number→NaN,--page-size NaN 直传 CLI。当前适配器恒传数字,仅防御性问题。

  8. 【提示·可读性】 apps/gateway/src/modules/documents/import/service.ts 的 materializeRemoteAssets 中 try 块内 replaceAsync 调用未随 try 缩进(约 1259 行起),阅读时容易漏看 try/finally(临时媒体目录清理)边界。

结论

无阻塞发现:未发现可实证的安全/隐私问题、数据丢失、运行时回归或构建/发布失败,故仅以评论提出以上建议,重点跟进第 1、2 条。

此 PR 修改了高风险文件,需要人工批准,不会自动合并。

  • apps/gateway/package.json

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant