IronClaw 流式输出 SSE 浏览器验证实操:把渲染节奏变成时序证据
IronClaw 流式输出 SSE 浏览器验证实操把渲染节奏变成时序证据【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址: https://gitcode.com/gh_mirrors/iro/ironclaw当一次 PR 声称修好了 IronClaw 聊天页的流式卡顿你点击发送、收到 HTTP 200、看到 toast 弹出、最终拿到完整答案——这些都不构成证据。真正的问题藏在时间轴里每一段回答文本是什么时候出现在页面上的。本文基于仓库的 railway-test 技能配方文档见 streaming-cadence.md完整走一遍流式浏览器 QA如何采样 SSE 流式输出的渲染节奏、如何判定完成态、如何把证据挂回 PR 评审。点击成功为什么证明不了流式修好了设想一个失败场景。PR 描述是修复流式渲染卡顿。你打开预览环境发一条消息请求成功答案最终完整出现。旧的断言集合——元素存在、请求 200、toast 出现——全部通过。但页面实际的行为可能是前 40 秒完全静止最后 15 秒一次性吐出全部段落。传统 UI 断言是状态断言只关心最终是什么。流式质量是时间域属性关心随时间怎么变。状态断言对时间域问题天然失明原始网络帧的到达时间同样不够用——帧到达不等于用户看见了。所以配方文档把适用边界划得很窄只有当 PR 改动聊天、SSE/WebSocket 投递、增量渲染或 live-update 对账时才走这条配方主证据是随时间测量可见 DOM 变化。流式 QA 的方法论三件套基线、轮询、完成断言整套采样逻辑只有三步顺序不能换。第一步提交后取基线。点击发送之后立即抓取一次主区域段落文本作为签名基线。这一步相当于归零校准用户消息本身、以及提交后固定出现的静态标记都不是流式证据必须先在基线里扣除。之后所有与基线的差异才计为助手回复的渲染增长。第二步固定间隔轮询可见 DOM。以约 100ms 的间隔轮询main p主区域的全部段落把纯文本用换行拼成一个签名。签名变化时记一条记录相对时间t、总长度len、段落数parts、末尾 140 字符tail。这就像给页面做脉搏记录记的是渲染层的节拍不是网络层的到帧。100ms 这个间隔是折中过密会扰动渲染过疏会漏掉逐段渲染的节拍。第三步完成态断言。采样窗口固定为 55 秒防止脚本无限挂起也足以覆盖一次长回答。窗口结束后再单独检查页面是否进入了完成态见下文。只看渲染层还有一个硬理由useSSE收到帧之后还要经过 JSON 解析、事件分发、React 状态更新最终才表现为段落文本增长。用户感知的是最后一步。采样脚本怎么写新线程与 follow-up 两个场景一次完整采样包含两个场景在空白线程提交一条长提示词再在既有线程上追问一轮。两个场景的差异如下表项目新线程fresh thread既有线程 follow-up提示词规模至少 3 次工具调用阶段间含进度更新最终答案至少 10 个短段落至少 2 次工具调用工具前一句进度最终答案至少 8 个短段落输入框定位名Ask IronClaw anything.i18n 键chat.heroPlaceholderAsk for follow-up changes键chat.followUpPlaceholder见 en.ts脚本变量前缀railway*railwayFollowup*发送按钮Send messageSend messagefollow-up 输入框的定位名不同是因为完成上一轮后页面切入了可继续追问的 composer 状态占位符文案随之切换脚本必须针对当前 DOM 状态选对名字否则填充会失败。变量前缀全部换新是为了避开 Node REPL 里已存在的同名绑定。两条测试提示词是刻意设计的要求多工具、多阶段、长输出把流式窗口拉长到 55 秒有意义。新线程提示词Compare and contrast NEAR Protocol with Ethereum using current web research. Briefly tell me what you will research before using at least three tools, include another short progress update between tool phases, then write a detailed final answer of at least ten short paragraphs. I am testing smooth streaming, so stream naturally and do not make the answer terse.follow-up 提示词Follow up by using at least two web searches to verify the newest roadmap milestones for both protocols. Give one short progress sentence before the tools, then a fresh final answer of at least eight short paragraphs. Keep the final answer flowing naturally so I can observe streaming.脚本逻辑是散文式的定位输入框、fill提示词、点击Send message按钮然后进入轮询循环。核心骨架如下句柄按你的驱动替换下文移植节有说明// 提交后立刻取基线之前的用户消息与静态标记不算流式证据 var started Date.now(); var previous (await page.locator(main p).allTextContents()).join(\n); var changes []; while (Date.now() - started 55_000) { // 55 秒采样窗口 var parts await page.locator(main p).allTextContents(); var signature parts.join(\n); // 可见 DOM 签名 if (signature ! previous) { // 只记录签名变化 changes.push({ t: Date.now() - started, len: signature.length, parts: parts.length, tail: signature.slice(-140) }); previous signature; } await new Promise(r setTimeout(r, 100)); // 约 100ms 轮询 } console.log(JSON.stringify({ count: changes.length, first: changes.slice(0, 12), last: changes.slice(-20) }));如何判定流式已完成四个断言55 秒窗口结束不等于流式结束长答案可能还在渲染。完成态检查取四个值各自覆盖一个维度断言取法判什么terminalComposerDOM 快照是否包含Ask for follow-up changes占位符composer 复位进入可继续追问的完成态activityButtons按钮文本中匹配Activity -的列表流式结束后活动/运行记录入口出现paragraphCountmain p段落总数与采样记录的parts对照不再增长即渲染收敛tail末尾 10 段文本人工核对最终答案完整收尾、无截断组合判定段落数稳定 tail以完整句结束 composer 复位三者齐备才算流式正常结束。如果段落数还在涨而 composer 没复位说明答案仍在渲染或者 UI 状态机没切换。从采样数据到 PR 证据门禁与发布红线先看数据怎么读。输出只有三个字段count总变化次数、first前 12 条、last末 20 条。健康的曲线应该是早期变化密集模型快速吐出开头、中期节奏稳定、末期自然收敛。count过小或首条记录时间过晚说明流式启动或持续渲染出了问题中间出现长时间静默后突然跳变则指向断线重连。再前置一步门禁。流式断言必须建立在确认过的 HEAD SHA 对应的构建上。先跑scripts/preview_state.sh PR [REPO] [PREVIEW_URL]它通过 commit 作用域的状态端点报告railway_state取值success/pending/failure/error/missing/query_failed同时抓取前端资源指纹形如assets/app-hash.js。两条红线railway_state不是success或测试期间headRefOid与记录值不一致本次浏览器观测作废只能发布 BLOCKED 证据。⚠️ 证据分级也有讲究。在 SKILL.md 定义的证据标准里流式采样属于可见的增量变化这一档明确高于点击成功、HTTP 200、toast、原始事件。即使曲线平滑如果采样旅程没走目标契约真实 provider/model、路由、角色、工具、起始状态该用例只能算 supplemental不能升级为 PASS。发布阶段所有证据count/first/last、完成态断言结果先拼成完整 PR 评论正文再清理railway-test-前缀的临时数据、关闭标签页、复核headRefOid最后以单一规范评论形式发布评论带隐藏标记railway-test:evidence headHEAD_SHA。Bearer 凭据和敏感浏览器状态不得出现在任何证据里。移植到其他浏览器驱动只改三处配方脚本是为 Codex 内嵌浏览器写的标签句柄绑定名railwayTab。换驱动时只翻译三处会话/标签句柄railwayTab.playwright.getByRole(...)换成驱动自己的 locator APIDOM 断言原语locator(main p).allTextContents()换成驱动的取文本接口domSnapshot()换成page.content()或序列化的 accessibility tree异步等待new Promise((resolve) setTimeout(resolve, 100))换成驱动原生 sleep。翻译完之后方法论三件套原样保留提交后取基线 → 固定间隔轮询可见 DOM 并记录签名变化 → 完成态断言。证据的可复现性来自这三个要点而不是来自某一套驱动 API。原理回望为什么轮询渲染层才有效采样器记下的每个签名变化对应前端一整套流式管道的最终输出。按数据流从上游到下游看事件获取useSSE.ts 用EventSourcePlus向GET /v2/threads/threadId/events建立 SSE 连接Bearer 令牌经 headers 函数按需注入不进入浏览器历史与代理日志帧解析与分发onMessage解析 JSON 帧把stream_error归一为error事件再经onEvent回调驱动聊天状态更新渲染状态流转最终体现为main p文本增长——采样器观测的正是这一步服务端容量控制sse_capacity.rs 限制每调用方并发 3 条DEFAULT_SSE_MAX_CONCURRENT_PER_CALLER 3、单连接最长存活 5 分钟SSE_MAX_LIFETIME并带拒绝退款机制连续拒绝达到REJECTION_REFUND_LIMIT 5后不再退款。连接被反复拒绝重建会直接打乱采样到的渲染节奏连接状态机useSSE内置 30 秒活跃看门狗、1s→30s 抖动退避以及connection_id/connection_generation重连标识。流中断时前端进入RECONNECTING状态并调度重连。这五条解释了采样曲线该怎么读健康曲线里不该出现大段静默后突然跳变一旦出现先怀疑重连。流式 QA 测的从来不是消息发出去没有而是每一次工具回流、每一个进度更新、每一段答案是否都以可感知的节奏渲染到了页面上。配合完成态断言与 HEAD 门禁流式平滑就从主观感受变成了可量化、可回归、可评审的工程事实。【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址: https://gitcode.com/gh_mirrors/iro/ironclaw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考