资讯动态

Onyx 移动端 Agentic Reasoning Timeline 移植设计:从 Web 到 React Native 的对等实现研究

发布时间:2026/9/11 20:26:23 来源:尧图企业网站定制
Onyx 移动端 Agentic Reasoning Timeline 移植设计从 Web 到 React Native 的对等实现研究【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer本篇技术指南基于 Onyxdanswer仓库中docs/mobile-chat/9b-timeline/01-research.md的设计研究文档系统讲解如何将 Web 端聊天界面中的Agent 推理时间线AgentTimeline即 reasoning / search / tool 子步骤的容器化展示1:1 移植到 Onyx React Native Expo 移动应用mobile/中。读者将掌握Web 端时间线的数据流与渲染契约、移动端现有的可复用接缝、三种实现方案的取舍以及最终选定的完整外壳优先Full-Parity方案在源码中的具体落地形态并理解react-hooks/refs等平台约束如何驱动实现层面的必要分叉。需求背景为什么要把 Web 推理时间线搬进移动端Web 端的 AI 助手回答中Agent 在给出最终答案前会经历一段推理过程——包括内部推理reasoning、搜索、工具调用等多个子步骤。Web 端已经通过AgentTimeline组件将这些子步骤以步骤容器step container 头部header 图标icon 连接线connector 折叠/展开collapse/expand的形式呈现给用户。9b 阶段的目标非常明确需求原文将这套时间线移植到 Onyx 的移动端React Native Expo即mobile/目录达到Web 对等web parity——不仅要看起来一样结构也要一样在 9a引用来源CitedSources的基础上扩展并注册进 PR-3 渲染器分发renderers/registry.ts体系中后端不做任何改动——推理数据包reasoning packets后端早已发出9b 将构建AgentTimeline组合层composition layer后续所有阶段search/fetch/tool 渲染器、9c–9e都将接入这一层。范围澄清9b 只做最细的行走骨架按 2026-07-16 所有者的范围锁定9b 采用FOUNDATION-ONLY仅基础策略只交付三件事turn/tab 分组引擎grouping engineAgentTimeline组合层真实步骤 折叠/展开唯一的 reasoning 步骤渲染器处理reasoning_start / reasoning_delta / reasoning_done三种包。其余一切均为独立后续阶段后续阶段内容内部/Web 搜索、fetch/open_url独立渲染器阶段python/code、coding-agent bash独立渲染器阶段custom-tool自定义工具独立渲染器阶段deep-research 嵌套 Agentsub_turn_index独立渲染器阶段memory记忆独立渲染器阶段图片生成独立阶段9e多模型model_index移动端单模型明确不做但分组必须容忍非零model_index并行工具标签页tab_index并行后续阶段但分组键与数据模型不得排除其可能性同时有三个硬性约束Web 对等是硬要求不发明新的移动端时间线聊天层保持原生位于mobile/src/chat/而非onyx-ai/shared这是 PR-2 的既定决策后端不变。现有代码基础9b 的接缝早已预留研究文档通过代码库扫描并逐一实际读取验证确认9b 需要依赖的所有接缝seam在移动端已经存在且被显式预留1. 扁平化包处理器 ——mobile/src/chat/messageProcessor.ts这是一个扁平、游标增量式nextPacketIndex的 packet→state 归约器ProcessedMessageState { nodeId: number; nextPacketIndex: number; // 游标只处理游标之后的包 citationMap: CitationMap; citations: StreamingCitation[]; seenCitationDocIds: Setstring; documentMap: Mapstring, SearchDoc; isComplete: boolean; stopReason: StopReason | undefined; // ... }源码头部注释明确写道9b extends it with turn/tab grouping timeline steps, so the shape here stays deliberately flat (grouping-free).—— 即 9b 将在其上扩展 turn/tab 分组与时间线步骤因此当前形态刻意保持扁平无分组。从当前仓库源码看messageProcessor.ts已实现了getGroupKey${turn_index}-${tab_index ?? 0}、injectSectionEnd合成SECTION_END让步骤读起来完整、handleTurnTransition新的turn_index关闭所有先前打开的分组等核心机制——这正是文档中分组引擎的雏形。2. 时间线组件桩 ——mobile/src/components/chat/AgentTimeline.tsx研究文档描述它当时是一个stub36px 导轨w-36、24pxAgentAvatar、reanimated 微光ThinkingLabel、TimelineStep列表原语TimelineStepData {key, label, status: running|done|error, icon?}连接线h-8 w-[1px] bg-border-01首尾opacity-0stepsprop 恒为[]无人填充它。它被渲染在MessageRow.AssistantMessage中、答案上方。而从当前仓库看AgentTimeline.tsx已经是完整的 Web 移植版本接收turnGroups: TurnGroup[]、chatState、stopReason等内部调用useTimelineHeader、useTimelineMetrics、useTimelineExpansion、useTimelineUIState并根据 7 种 UI 状态分发StreamingHeader / ParallelStreamingHeader / StoppedHeader / CompletedHeader——即文档中Approach C的设计已经在仓库中落地这也印证了研究结论的可行性。3. 渲染器注册表 ——mobile/src/components/chat/renderers/registry.ts移动端渲染器契约比 Web 更简单MessageRenderer { matches(packets), Component } MessageRendererProps { packets, processed }采用first-match-wins的RENDERERS数组 findRenderer目前只注册了MessageTextRenderer。相比 Web 的 render-prop 形式MessageRendererT,S这是文档明确点出的简化。4. 每 flush 全量重算 ——mobile/src/hooks/usePacketDisplay.tsprocessed useMemo(() processPackets(createInitialState(nodeId), packets), [nodeId, packets])每次 flush 全量重算数组身份每次变化。文档特别强调这刻意不是渲染期可变的 ref——移动端的react-hooks/refslint禁止在渲染期间访问ref.current因此 Web 端用 ref 持有的usePacketProcessor模式在移动端非法。这一点成为后续所有方案共同的硬约束。5. 消息行组装 ——mobile/src/components/chat/MessageRow.tsxAssistantMessage的组装顺序为usePacketDisplay(node)→Renderer packets processed/位于View classNamepx-12内→AgentTimeline在其上 → 9a 的CitedSources在其下。hasContent Renderer ! null packets.length 0。6. 流式模型 ——mobile/src/chat/streamingModels.tsPacketType当前包含MESSAGE_START/DELTA/END、STOP、SECTION_END、ERROR、CITATION_INFO、SEARCH_TOOL_DOCUMENTS_DELTA、OPEN_URL_DOCUMENTS。Placement已携带全部 4 个字段turn_index、tab_index、sub_turn_index、model_index。文档要求新增REASONING_START/DELTA/DONE以及用于分组容忍的TOP_LEVEL_BRANCHING——当前仓库中这些枚举值已存在streamingModels.ts第 16–17 行、第 46–48 行。7. 9a 复用资产mobile/src/chat/contracts/documents.ts提供完整的SearchDoc/StreamingCitation/CitationMap9a 产物供延后的 search/fetch 渲染器复用9a 的源 UISourceRow/SourceIcon/openSource/CitedSources同样可被延后阶段直接复用。后端现状推理包已存在无需改动后端已在backend/onyx/chat/llm_step.py中发出推理数据包源码证据包类型字段ReasoningStarttypereasoning_start无字段ReasoningDeltatypereasoning_delta{reasoning: str}增量文本ReasoningDonetypereasoning_done无字段数据包携带Placement.turn_index/tab_index。文档强调两个关键事实线上没有message_end——整个 turn 只能通过OverallStoptypestop完成SECTION_END通常是客户端合成的——Web 端在新的turn_index出现时把它注入先前的分组、在 STOP 时注入所有仍打开的分组——这正是步骤被标记为完成的方式。当前移动端messageProcessor.ts的injectSectionEnd与此完全对应它幂等地向分组追加合成包并在 STOP 时关闭所有仍打开的分组见handleStopPacket源码注释the backend never sends one。此外TopLevelBranching {num_parallel_branches}是并行前的元数据预并行信息移动端用它维护expectedBranches映射handleTopLevelBranching。Web 端真相源对等的目标架构Web 端实现全部位于web/src/app/app/message/messageComponents/下是 9b 的对等目标分四层1. 分组层timeline/hooks/packetProcessor.ts按${turn_index}-${tab_index ?? 0}分组、合成SECTION_END、归类 tool/display 分组随后timeline/transformers.ts完成GroupedPacket[]→TransformedStep[]→TurnGroup[]的变换其中isParallel 同一 turn_index 下有多个步骤。移动端的对应实现位于mobile/src/chat/timeline/transformers.tstransformPacketGroups将GroupedPacket映射为TransformedStep含key/turnIndex/tabIndex/packetsgroupStepsByTurn按turnIndex聚合、按tabIndex排序并计算isParallel。2. 组合层AgentMessage.tsx运行usePacketProcessorusePacedTurnGroups200ms 错峰揭晓上方渲染AgentTimeline下方渲染最终答案的RendererComponent。移动端对应mobile/src/hooks/timeline/usePacketProcessor.ts将processPackets以useMemo全量重算方式托管注释明确说明这是从 Web 的渲染期 ref 变更结构而来mobile/src/hooks/timeline/usePacedTurnGroups.ts实现了 200ms 错峰PACING_DELAY_MS 200并处理了历史回放旁路shouldBypassPacing、STOP 时立即冲刷全部待揭晓步骤、tool-after-message 隐藏答案等细节。3. 外壳层AgentTimeline.tsxuseTimelineUIState7 种状态EMPTY / DISPLAY_CONTENT_ONLY / STREAMING_SEQUENTIAL / STREAMING_PARALLEL / STOPPED / COMPLETED_COLLAPSED / COMPLETED_EXPANDEDuseTimelineExpansion默认折叠用户未手动切换时停止/答案开始后自动折叠useTimelineHeader微光头部文字useTimelineMetrics。移动端对应文件为mobile/src/hooks/timeline/下的useTimelineUIState.ts、useTimelineExpansion.ts、useTimelineHeader.ts、useTimelineMetrics.ts、useStreamingDuration.ts、useTimelineStepState.ts以及mobile/src/components/chat/timeline/headers/下的四个头部组件StreamingHeader、ParallelStreamingHeader、StoppedHeader、CompletedHeader。4. 单步层TimelineRendererComponent每步独立的isExpandedrenderType override ?? (isExpanded ? FULL : COMPACT)StepContainerTimelineIconColumn导轨 TimelineSurface色调 TimelineStepContent头/折叠/主体结尾追加 Done/Stopped 终止步骤。移动端对应mobile/src/components/chat/timeline/下的StepContainer.tsx、TimelineRendererComponent.tsx、TimelineStep.tsx、CollapsedStreamingContent.tsx、ExpandedTimelineContent.tsx以及primitives/中的TimelineRoot、TimelineHeaderRow、TimelineIconColumn、TimelineSurface、TimelineStepContent、TimelineRow、TimelineTopSpacer、timelineTokens。渲染器契约interfaces.tsWeb 采用render-prop形式MessageRendererT,S计算RendererResult[]并调用children(results)RendererResult { icon, status, content, expandedText?, // 展开态文本 supportsCollapsible?, // 是否支持折叠 alwaysCollapsible?, timelineLayout?, noPaddingRight?, surfaceBackground?, // 表面背景色 }外层StepContainer拥有包裹层渲染器自身从不绘制自己的外壳。Reasoning 渲染器timeline/renderers/reasoning/ReasoningRenderer.tsxSvgCircle图标、状态文案Thinking或提取的 markdown 标题、流式推理 markdown 的ExpandableTextDisplay、500ms 最小思考门控。移动端将推理文本解析逻辑独立为纯模块mobile/src/chat/timeline/reasoningState.ts保持 reanimated-free 以便单测constructCurrentReasoningState判断hasStart/hasEndSECTION_END/ERROR/REASONING_DONE任一即结束、拼接REASONING_DELTA文本extractFirstParagraph在推理以短 markdown 标题开头时提取title超过 60 字符视为散文而非标题MAX_TITLE_LENGTH 60。UI 侧对应ReasoningTextSheet.tsx/ReasoningTextWindow.tsx。移动端原语与平台约束关键注意事项研究文档从渲染基础设施扫描中总结了移动端的可用原语与坑可用原语View、Textfontcolor 枚举、Icon、Separator、Button、Card、Content/ContentAction、SpinnerRNAnimatedjest 安全、StreamingMarkdown富 markdown但颜色必须通过varsLight/varsDarktextPresets从onyx-ai/shared/native解析为具体 hex——markdown 库内部NativeWind 类不生效、reanimated 4.3.1当前微光效果ChatSurface使用LinearTransition/FadeIn/FadeOut没有Collapsible/Accordion原语——折叠/展开是全新工作需向所有者确认移植 Web UX 还是用 reanimated 组合没有 chevron-up需旋转chevron-down没有 brain/推理图标、没有纯圆圈字形Web 用SvgCircle——加图标是小规模的所有者决策NativeWind 间距是像素值类名数字 pxRN 没有 hover——删除 Web 的isHover分支桌面端 hover 展示必须变成常显或显式点击的触达且要真实的命中目标reanimated jest 注意事项把纯逻辑分组/步骤推导/状态机放在无 reanimated 的模块中叶子组件直接导入流式重渲染性能行组件 memoize、合并更新自动折叠的高度动画在流式过程中可能卡顿优先固定高度摘要 点击展开无障碍触发器accessibilityRolebuttonaccessibilityState{{expanded}}折叠后子元素必须从无障碍/焦点树中移除而非仅视觉隐藏。行业最佳实践研究文档汇总了六条业界共识外部资料仅作背景不构成仓库事实渐进式披露是主流——默认折叠流式中显示紧凑的 Thinking… (Ns) 标签带动画字形 耗时计时完成后自动折叠为一行摘要不要默认倾倒完整思维链DeepSeek 式的流水输出被点名批评为令人淹没Agent-UX 活动时间线——可折叠的冗余度、固定的当前步骤、分层透明度滚动的聊天线程不是好的工作流追踪器结构化的时间线而非内联文本才是正确容器触屏披露无障碍——触发器必须暴露展开/折叠状态折叠面板的子元素必须从 AX/焦点树移除RN 流式重渲染陷阱——React.memo行组件 useCallback的renderItem不要每个 tick 都给每行新的对象/函数身份合并/节流流式setState不要每个 token 都 setStateHover→触屏陷阱——每个桌面 hover 揭示都必须变成常显或显式点击的触达且要有真实命中目标RN 完全没有 hoverRN 时间线/步骤指示器库又薄又没人维护——预期从原语自己构建导轨/圆点/可折叠节点现有库是线性表单向导式的 stepper不是流式/嵌套时间线。三种实现方案方案 A —— 极简优先Lean Steps分组进处理器 reasoning 叶子接入现有导轨扩展恰好两个现有接缝、新增一个叶子分组逻辑内置于已经是纯函数的messageProcessor在ProcessedMessageState上新增steps: TimelineStep[]因此usePacketDisplay的每次 flush 全量重算路径完全不动、jest 安全给现有AgentTimelinestub 喂真实 reasoning 步骤新增一个ReasoningStep叶子流式StreamingMarkdown主体 点击切换折叠 叶子本地计时扁平{packets, processed}渲染器契约原样保留——reasoning 是时间线驻留的不是注册表渲染器因此findRenderer/RENDERERS和 9a 引用路径都不受影响不移植任何 Web 机制无 render-prop 契约、无 7 状态机、无错峰。改动文件streamingModels.ts4 枚举、4 接口、messageProcessor.ts分组 →steps/stepByKey、AgentTimeline.tsx渲染TimelineStep[]switch(kind)、MessageRow.tsx传 steps、细化isLoading新增ReasoningStep.tsx及分组单元测试。工作量约 360–420 LOC1 个 PR。代价最小改动面、对 9a 零风险、纯分组可完全单测但没有错峰、没有 7 状态头部、没有逐步 render-prop 契约第二个渲染器要接入需新增kindcase而非findRenderer即当真正的工具需要色调表面/逐步折叠时AgentTimeline要做一次有界的重构。后续契合度每个延后阶段 加kind reducer 分支 叶子 一个case9a 的 SourceRow 可落入 search/fetch 叶子更重的机制错峰、render-propRendererResult等真正有工具需要时再作为该接缝的有界演进引入。方案 B —— 灵活优先可扩展步骤接缝一个纯 turn/tab分组模块chat/timeline/grouping.ts与现有扁平processPackets并列运行都通过useMemo托管遵守 refs-lint 禁令产出TurnGroup[]的TransformedStep[]。每个步骤由优先级排序的步骤注册表镜像 Web 的findRenderer解析到一个步骤渲染器渲染器返回 WebRendererResult数据契约的移动端模拟普通对象返回非 JSX比 Web 的 render-prop 简单但同样可扩展。单个StepContainer导轨 色调表面 头部 折叠主体拥有全部 chrome渲染器从不绘制自己的包裹层。Reasoning 是 1 号渲染器也是链条最后的兜底。messageProcessor保持扁平分组是兄弟模块遵循其头部注释。新增精简版useTimelineExpansionuseTimelineUIState以及全新Collapsible原语 推理图标均为所有者确认项。改动文件新增chat/timeline/{grouping,stepContract,stepRegistry}.ts、chat/timeline/renderers/reasoning/ReasoningRenderer.tsx、components/chat/timeline/StepContainer.tsx、components/chat/timeline/{useTimelineExpansion,useTimelineUIState}.ts、components/ui/collapsible.tsx待确认、icons/reasoning-circle.tsx待确认修改streamingModels.ts、usePacketDisplay.tsturnGroups、AgentTimeline.tsx、MessageRow.tsx。工作量约 1,810 LOC生产 测试2 个 PR——9b-1 纯引擎分组 契约 注册表 reasoning 推导 测试无 UI、9b-2 UI 与接线Collapsible、StepContainer、expansion/uiState、视图层、AgentTimeline 重写。代价每个延后阶段 一个新文件谓词 返回RendererResult的渲染器分组/容器/折叠/MessageRow零改动改造代价摊薄到约 0但 LOC 约为 A 的 2 倍且引入了 reasoning 几乎用不到的契约字段alwaysCollapsible、timelineLayout部分要到阶段 2 才非投机外加 2 个所有者把关的产物带来决策延迟。后续契合度近乎完美——这就是接缝本身search/fetch 直接复用 9a 的 SourceRow并行标签页已在键中区分model_index被容忍只有嵌套是可能扩展groupStepsByTurn的阶段。方案 C —— 全量对等忠实外壳优先现在就把 Web 的整个时间线外壳 1:1 移植分组 transformersusePacedTurnGroups200ms 错峰 完整useTimelineUIState7 状态useTimelineExpansionuseTimelineHeaderuseStreamingDuration实时 Ns/Thought for {duration}useTimelineMetrics render-prop 渲染器契约 StepContainerTimelineRendererComponent Streaming/Stopped/Completed 头部 Done/Stopped 终止步骤——只接线 reasoning 渲染器主体。保持移动端每 flush 全量重算模型Web 的 ref 持有usePacketProcessor在移动端非法的方式是把分组做成纯函数usePacedTurnGroups必须重构掉 Web 的渲染期 ref 读取以符合 refs lint。该外壳在只有 reasoning 内容时与 Web行为上无法区分因此延后阶段只需添加渲染器主体。改动文件约 22 个新增 6 个修改分组、transformers、接口、错峰 hook、4 个状态/头部/指标 hook、时长 hook、3 个导轨/表面/内容原语、StepContainer TimelineRendererComponent、3 个头部组件、ReasoningRenderer、Collapsible/ExpandableTextDisplay待确认、圆形图标、AgentTimeline 重写修改streamingModels、usePacketDisplay、MessageRow、registry。工作量约 3,700–4,300 LOC坦诚地说 5–6 个 PR接线 → 错峰 → 状态 → 原语 → 渲染器 → 头部 组合。代价外壳第一天即与 Web 忠实一致微光头部文字、实时计时、错峰揭示、答案开始自动折叠、Done/Stopped、色调表面每个延后渲染器都是纯增量、外壳零返工、零漂移但这是 reasoning-only 阶段最大的 LOC/审查面7 状态机的大片区域在并行存在前以死路径形式上线错峰 自动折叠高度动画带来真实的流式性能/卡顿风险usePacedTurnGroups重构掉渲染期 ref是最容易出 bug、且存在行为分歧风险的文件。后续契合度同类最佳——并行标签页数据模型 sub_turn_index/model_index容忍内置且休眠但这种最大扩展性正是提前支付外壳成本的唯一理由。方案横评维度ALean StepsB可扩展接缝C忠实外壳规模≈400 LOC1 PR≈1,800 LOC2 PR≈4,000 LOC5–6 PR共享基础三者都新增同样的streamingModels包类型和同样的分组键${turn_index}-${tab_index ?? 0}model_index忽略分歧仅在现在建多少外壳/契约refs-lint 约束三者都被约束都不能移植 Web 渲染期可变 ref 的usePacketProcessor分组是纯useMemoC 在此风险最大错峰 hook 重构扩展性 vs YAGNI推迟 render-prop/错峰/状态机直到第二个渲染器证明形状风险之后AgentTimeline有界重构前置数据契约 注册表真正难改造的部分但不错峰/不全状态前置一切风险死代码 卡顿 移植移动靶即时对等只有 C 让外壳第一天 Web 忠实微光头部、实时计时、错峰揭示、答案自动折叠、Done/Stopped。A、B 正确渲染 reasoning 但外壳更简单路线图的对等要求是外观 AND 结构——仅 reasoning 时A/B 仍可匹配步骤/导轨/折叠形状同时推迟头部状态机所有者确认项A 一个都不需要无新原语/图标B、C 在 UI 落地前都需要Collapsible原语 推理图标决策最终选型方案 C —— 忠实外壳优先Full Parity方案 C 在 GATE 1所有者2026-07-16被选定。所有者指令原文意图I want something that matches web. I am going to build the renderers immediately — current PR goes in [first], then the renderers. I dont want any refactor later. Im fine with any number of lines — I want everything, whatever way we need it. Just dont drift away from web.我要和 Web 一致的东西。我会立刻构建渲染器——当前 PR 先合入然后渲染器。我之后不想做任何重构。行数多少我都无所谓——我要全部用任何我们需要的方式。只是别偏离 Web。对 9b 的具体含义1:1 移植 Web 的整个时间线外壳render-propMessageRendererT,S契约 RendererResult/RenderTypeHIGHLIGHT/FULL/COMPACT/INLINE、纯分组packetProcessor→transformers、usePacedTurnGroups200ms 错峰、完整useTimelineUIState7 状态useTimelineExpansionuseTimelineHeaderuseStreamingDurationuseTimelineMetrics、StepContainerTimelineRendererComponent 导轨/表面/内容原语、Streaming/Stopped/Completed 头部、Done/Stopped 终止步骤。原样采用 Web 的 render-prop 渲染器契约而非方案 B 的简化数据对象使未来每个 Web 渲染器都能近乎机械化地移植。9b 只接 reasoning 渲染器主体。休眠的并行标签页状态isParallel、STREAMING_PARALLEL、showParallelTabs和sub_turn_index/model_index容忍随外壳一起上线与 Web 一致使并行/嵌套/多模型成为日后仅 UI 层的后续工作、接缝零改动。9b 功能流范围已确认本规范只覆盖完整外壳 reasoning 渲染器。每个工具渲染器内部/Web 搜索、fetch/open_url、python/code、coding-agentbash、custom-tool、deep-research 嵌套 Agent、memory都是该零重构接缝上的独立后续 PR按阶段逐一规范先 grill 后设计由所有者构建时确定——不在本设计内。但设计必须完整规定 render-prop 契约 每种工具的渲染器清单/分发inventory/dispatch使这些后续工作机械化。唯一被接受的分叉平台强制、行为保持Web 的usePacketProcessor和usePacedTurnGroups在渲染期间读取stateRef.current重置检测/旁路而移动端react-hooks/refslint禁止这一点。这两者被重构为useMemo重算 仅 effect 写 ref的模型保持相同的分组输出和相同的 200ms 揭晓时序。这是实现层面的必然不是外观/结构漂移——渲染出的时间线与 Web 忠实一致。细节记录在 03-detailed-design.md。这一决策的落地可以从当前仓库源码中直接验证mobile/src/hooks/timeline/usePacedTurnGroups.ts的头部注释明确写道Web 版本在渲染期读取错峰 ref 被 lint 禁止因此渲染相关字段revealedStepKeys、toolPacingComplete改为由 effect/callback发布的useState内部记账待办队列、定时器、标志保留在仅在 effect/callback 中触碰的 ref 中且明确dropped webs prevPacedRef stabilization。对后续阶段的指导意义9b 选型的分层价值在于数据契约和分组键先行固化UI 机制按需演进。任何延后阶段9c–9e在接入时只需做三件事在streamingModels.ts注册对应的PacketType按 render-prop 契约实现一个返回RendererResult的渲染器复用 9a 的 SourceRow 等资产在步骤注册表/分发中登记匹配谓词——外壳StepContainer、头部状态机、错峰、折叠、Done/Stopped 终止步骤零改动。而移动端开发者需要始终牢记两条平台红线渲染期间不得触碰ref.current分组与推导一律纯useMemo纯逻辑与 reanimated 分离分组/步骤推导/状态机放在无 reanimated 模块中保证 jest 可测。这两条红线既是方案 C 相比 Web 的唯一实现分叉来源也是移动端时间线长期可维护、可单测的根本保证。结语从研究文档到当前仓库源码docs/mobile-chat/9b-timeline/系列文档00-index.md、01-research.md、02-high-level-design.md、03-detailed-design.md、04-implementation-plan.md与mobile/中的时间线实现mobile/src/chat/timeline/、mobile/src/components/chat/timeline/、mobile/src/hooks/timeline/构成了设计先行、源码印证的完整闭环。这套方法论的核心可复用于仓库内其他平台移植类任务先扫描并确认既有接缝再以对等但合法的方式重构 Web 机制最后让延后功能在零返工的接缝上机械接入。【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价