Skip to content

fix(benchmark): forward provider responses incrementally - #7776

Merged
loopx-agent merged 1 commit into
loopx-project:mainfrom
songoow:codex/provider-gateway-incremental-stream
Nov 1, 2026
Merged

loopx-agent merged 1 commit into
loopx-project:mainfrom
songoow:codex/provider-gateway-incremental-stream

Conversation

@songoow

@songoow songoow commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

Problem

The runner-owned model gateway reads upstream responses in 64 KiB blocks. A small SSE event can remain buffered until more bytes arrive or the upstream response ends, so an active Responses stream appears idle to the isolated runtime.

Change

Use HTTPResponse.read1() to forward available bytes without waiting to fill a block. Keep the existing bounded chunk size, downstream flushing, request authentication, admitted paths and upstream-error handling.

Add real loopback HTTP regressions with two events: the upstream releases the second event only after the client receives the first. Cover Content-Length and chunked framing, a 128 KiB second event, complete responses and upstream disconnects. Retain the JSON, credential injection and rejected-path checks, and rename the original JSON test to describe what it actually verifies.

This isolates the response-streaming fix from #6900; invocation admission is handled separately.

Validation

  • The two completion regressions fail against unchanged production code at base 2f2c4efadf0c3ac21c51f7fc09f4985c8447642e: both time out waiting for the first event while the producer waits for acknowledgment.
  • .venv/bin/python -m pytest -q tests/capabilities/test_provider_gateway.py: 11 passed, no skips.
  • Ruff on the two changed files: passed.
  • Mypy on provider_gateway.py: passed.
  • git diff --check and the RFC bilingual diff check: passed.
  • Independent source review found no blocking issue in this bounded transport change.

The tests use synthetic payloads and local HTTP servers. They invoke no model or paid provider. Required repository CI remains separate from these focused local checks.

Scope and risk

Response delivery becomes incremental by design. Completed response bytes, status and content type remain covered, and an interrupted upstream closes the already-started response without appending a second error body. This change does not introduce admission policy, alter provider configuration or establish benchmark outcome or token-efficiency claims.

The adjacent owner needs no additional refactor: the fix remains in the existing HTTP relay and its contract tests, with no new production abstraction or protocol.

Signed-off-by: song <liusongstep@gmail.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-01T02:56:52.275257Z ed44a93 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=max

评审完整 head ed44a9355a9552ddbeb58ffab42971ad6e77287b,两个文件 +93/-2。未发现阻塞性代码问题;结论限于源码版本的 HTTP relay,benchmark-sensitive 合并人工门仍保留。

动机 / Motivation

隔离运行的 Agent 通过 runner 持有凭据的网关接收模型响应。上游已经发出一个小的 SSE 事件(逐段推送的响应数据),旧网关仍可能等待凑满 64KiB 或响应结束,调用者因此把正在生成的响应看成停滞。现在先转发已有字节,让客户端在上游继续生成前收到首个事件。独立本地 HTTP 对照复现了这个差别,并验证完整响应与断连时已经收到的数据;这次修复只处理既有 relay 的交付时机,不改变任务、评分、重试或运行权限,也不证明真实模型、安装后 Host 或长程任务的收益。调用者无需新增设置或确认即可使用已显式启动的网关。

改动思路 / Approach

现有公开入口 serve_runner_owned_provider_gateway 仍负责 loopback 服务生命周期,http.client.HTTPResponse 继续拥有 HTTP framing;只把响应循环的 read(64 * 1024) 换为 read1(64 * 1024)。后者返回当前可读的内容,保留单次读取上限,再由原有 write/flush 转发。它不解析 SSE,因此 JSON 和其他已允许响应也走同一协议实现。

这个问题属于 provider IO,保留现有 Python adapter 与标准库 owner 是最小完整修复。没有新增状态、持久 receipt、配置、独立 capability 或第二份策略;现有路径准入和凭据替换继续留在请求入口,响应投递不获得新的授权权力。可见的生产消费者是 benchmark/widesearch/run_widesearch_case.py:186,在 runner 内显式启动该 contextmanager;DeepSWE 文档也使用同一公开入口。SForge 的可选 429 retry 是另一 owner,不能据此要求本 relay 新增重试。请求前失败仍返回既有 502;响应已开始后的错误只关闭连接,不向 SSE 尾部插入第二份 JSON。

具体改动 / Changes

生产改动是一处方法替换和一行说明;其余 91 行测试扩展,以及一个把原 JSON 测试名改准确的重命名。两个完整文件和实际 runner 调用均已检查;没有额外 API、依赖或安装变更。

关键代码讲解

  1. GatewayHandler.do_POST 保留路径/体积校验、上游路径与 query 拼接、客户端凭据移除和 runner Bearer 注入。响应循环 改用 read1,状态码、hop-header 过滤、逐段 flush 和 finally 关闭上游连接保持原 owner。这里没有增加下游 token 身份验证,网关也没有变成 sandbox。
  2. _streaming_upstream 用真实本地 HTTP server 发送首个事件,然后等待客户端显式释放后续数据;分别支持 Content-Length 与 chunked framing,尾部超过 128KiB。这个因果握手能区分“首段已转发”和“等整个响应结束才一起收到”。
  3. test_runner_owned_gateway_forwards_events_before_upstream_completion 覆盖两种 framing 与正常完成/断连四个组合,先断言客户端收到首段,再允许上游继续,最后检查完整字节和响应头。它检验公开入口的实际网络行为,无需模型请求。

独立规范在读取 diff 前取自 immutable base 2f2c4efadf0c3ac21c51f7fc09f4985c8447642e:benchmark_toolkit README 的 Formal installed profile and skill discovery 及 DeepSWE runner 说明。源引用:loopx/capabilities/benchmark_toolkit/README.md#formal-installed-profile-and-skill-discovery; benchmark/deepswe/README.md:125-166。文档没有编号,也没有单独规定首事件时限:criterion_id runner-owned-provider-credential → implemented,凭据留在 runner、客户端仅拿 loopback URL/placeholder;caller-owned-isolation-and-evaluation → implemented,进程隔离和评分继续由 runner 拥有,relay 不宣称替代;incremental-response-delivery → implemented,来自本次明确缺陷与独立因果对照,而非虚构的 RFC 指标。没有以新增测试或作者文字作为自己的唯一验收依据。

对主干的风险 / Risks

使用相同 fixture、两个独立源码环境和真实 loopback HTTP server/client,对比上述 base 与本头。上游发出 49-byte 首事件后等待 release;两秒只是观察截止和失败恢复边界,不是性能承诺。旧版四个组合都不能在 release 前交付首段,新版全部可以。完整响应 131,129 bytes 两边一致;chunked 上游断连时,旧版还丢掉尚在 read 中的首段,新版保留已交付的 49 bytes。正常完成与断连后均无额外错误 JSON 混入。

独立同输入检查 base 本头
首事件在上游 release 前可见 0/4 PASS,4/4
两种 framing 完整响应字节 一致 PASS,一致
chunked 断连后首事件 0 bytes PASS,49 bytes
JSON 400、路径 404、GET 405、上游连接失败 502 既有结果 PASS,相同结果

独立检查还确认 upstream query/body、runner Authorization 替换、Cookie/X-Api-Key 移除和响应 hop-header 过滤。两边仅导入模块、不启动 contextmanager 时均无 socket bind/connect 或新增线程,公开签名和默认值一致;源码差异只位于启用后的响应循环,关闭路径没有被新机制接管。未做吞吐或 CPU 量化,较细颗粒 flush 的成本仍未测量;慢下游、上游超时和更强进程隔离继续沿用原实现。

PASS:11 个聚焦 pytest、两个变更路径的 Ruff、仓库配置 mypy 的 17 个源文件、provider 本地模块检查、control-plane TypeScript typecheck。PASS:固定 base 的 premerge 6 个直接检查和 9 个 catalog canary,零检查失败/跳过;整体命令仍为 manual_review_required / exit 1,因为 benchmark-sensitive 人工合并门没有解除。额外展开导入的 mypy FAIL:base/head 均为 932 个错误、148 个未改文件;匹配完整依赖环境后,全部 976 行诊断/说明以保留重复次数的 multiset 比较完全相同,失败仍作为 pre_existing_unrelated 保留。两个变更路径没有该诊断,并由上述必需检查与实际 HTTP 对照覆盖。初次自制探针用了错误 timeout 参数名,两边都在探针收尾报错;已修正并完整重跑,未把它归为产品失败。exact-scope CQR cqr_a13955c58edaea995ec1 已记录,optional typecheck 仍标记 failed/risk,未应用 safe-fix。当前 wait_for_ci=false,未查询或等待 GitHub CI。

语义与 CI 对齐

复用已有 Responses relay 和标准库 HTTP framing,没有新增 Enum/状态分类、prose heuristic、默认启用或 Actor 生命周期词汇。唯一有意变化是启用 relay 后小块数据提前可见,包括错误结束前已经收到的数据;评分、任务语义、准入、重试和权限未变。测试覆盖实际 framing 和失败路径,没有把网络成功当成 benchmark 有效性或 native Agent 采用证据。无页面、布局或第一屏变更,UI 视觉验收不适用。

我的整体评价 / Verdict

problem_context=goal_achieved 指这处已复现的 relay 缓冲缺陷;long_horizon=preserved、user_experience=improved。HTTP 客户端可以继续处理已到达的事件,长期工作成果、真实 provider 体验、token/成本和安装后 Host 仍未验证。observable_semantics=intentional_change_validated,默认关闭路径隔离,现有 API 应保留;一处标准库方法替换足够,没有增加兼容层、解析器或状态机的依据。测试增加的生命周期控制有独立缺陷辨别力,规模与问题相称。批准这个精确 head 的代码,不解除 benchmark 人工合并门,也不授予合并、安装或运行任务权限。

English verdict: APPROVE — available response bytes are forwarded before upstream completion, with existing relay ownership and failure boundaries preserved.

@loopx-agent
loopx-agent merged commit bc86585 into loopx-project:main Nov 1, 2026
30 of 39 checks passed
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.

2 participants