Skip to content

[Bug]: harnesses/codex:后端不流式下发 agentMessage/delta 时(如火山方舟 agentplan 网关 + codex 0.144.x),第三方智能体每轮回复"空响应",usage 全 0 #7431

Description

@Jasonsun77

环境

  • QwenPaw:2.2.0b3(pip 安装,Linux x86_64)
  • codex-cli:0.144.4(codex_cli_bin,app-server 模式)
  • 接入方式:第三方智能体,agent.jsonbackend: "codex"
  • 模型提供商:某厂商 Responses 协议网关(下称"该网关";应公开提交要求对提供商做匿名化,细节可私信提供),公开模型 glm-5-3-flash

现象

console 频道与该 codex 智能体对话,每轮都得到"助手返回了空响应。",无任何错误日志。日志签名:

Usage for session ...: {'provider_id': '', 'model_name': '', 'prompt_tokens': 2, 'completion_tokens': 0, 'total_tokens': 2, 'estimated': True, ...}
console stream done: event_count=3 has_response=True

而以下两条路径均正常,说明问题在 QwenPaw 适配层而非上游:

  1. 直接 codex exec(同目录、同 provider)回复正常;
  2. 用与 QwenPaw 相同的 JSON-RPC 序列直接驱动 app-server(initialize → thread/start → turn/start),turn 正常完成并返回完整 agentMessage

根因分析

三重证据指向同一结论:当后端不流式下发 item/agentMessage/delta 时,harnesses/codex/adapter.py_convert_notification 会把最终文本整体丢弃。

  1. 实拍事件流(0.144.4 + 该网关):全程没有任何 item/agentMessage/delta 事件;完整文本直接出现在 item/started / item/completeditem.text 中。turn/completed 为瘦负载:{"items": [], "itemsView": "notLoaded"}。codex 自身日志同时刷出 OutputTextDelta without active item / ReasoningSummaryDelta without active item(该网关的流式分片顺序触发了 codex 0.144 的流式状态机问题,文本最终以非流式 item 兜底送达)。
  2. 适配层代码_convert_notificationitem/completed 分支只处理 _TOOL_ITEM_TYPES(commandExecution 等);agentMessage 类型的 item/completed 掉出分支返回 None。文本进入事件流的唯一通道是 item/agentMessage/deltaTEXT_DELTA。零 delta ⇒ 零文本 ⇒ "空响应"。usage 全 0/estimated 同因(thread/tokenUsage/updated 未被消费)。
  3. 同类问题已有官方确认:姊妹项目 sipeed/picoclaw 试了下微信功能-不完善 #2674("Codex OAuth: empty assistant response when ChatGPT backend streams items via response.output_item.done",签名同样是 token 有计数、content_chars=0),修复方案 PR add google tag to track copaw website traffic #2581 即"把流式 item 事件累积的文本嫁接回终结事件"。

复现步骤

  1. 将某 Responses 协议网关配置为 codex 的 provider(触发该问题的网关行为特征:不下发 item/agentMessage/delta、终结事件为瘦负载);
  2. 创建 backend: "codex" 的第三方智能体,模型选 glm-5-3-flash;
  3. console 发送任意消息 → 每轮"助手返回了空响应。",usage 全 0。
    (本地验过的旁证:deepseek 等正常流式 Responses 后端因 delta 正常下发,不触发此问题——这也解释了"换 provider 后突然全空"的现象。)

修复建议(已在本地验证)

_convert_notification 中按 picoclaw #2581 的模式补上"整段文本嫁接 + 按已流式量去重",不影响正常流式后端:

  • __init__ 增加实例状态 self._delta_chars: dict[str, int](itemId → 已流式字符数);
  • item/agentMessage/delta 分支累加 self._delta_chars[itemId]
  • item/completeditem_type == "agentMessage" 时,设 delivered = self._delta_chars.pop(itemId, 0),若 len(item.text) > delivered 则补发 TEXT_DELTA(text=item.text[delivered:]),否则返回 None(正常流式后端 delta 已发全量,天然去重不重复);
  • turn/completed 分支 self._delta_chars.clear()
  • 由于需要访问实例状态,_convert_notification@staticmethod 改为实例方法(现有调用点均为 self._convert_notification(...),无破坏)。

本地单元测试 5/5 通过:纯 completed 嫁接(该网关场景)、delta 全量去重、部分 delta 差额嫁接、turn 结束状态清理、工具事件路径不受影响。

期望行为

后端以非流式 item 形式(或瘦负载 turn/completed)返回内容时,codex 第三方智能体仍能正常产出回复,并正确记录 usage。

备注

  • 若维护者已在新版修复,请告知对应版本号,以便受影响用户升级;
  • 本地补丁可提供完整 diff 备选 PR,欢迎评论索引。

Activity

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

  • Status
    Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions