Skip to content

feat: 【代码回合】subagent流式输出+路径拦截+Office文档+reasoning_content适配 - #464

Open
openjiuwen-sync-bot[bot] wants to merge 1 commit into
openJiuwen-ai:dev-stablefrom
openjiuwenai:sync/pr-2285
Open

feat: 【代码回合】subagent流式输出+路径拦截+Office文档+reasoning_content适配#464
openjiuwen-sync-bot[bot] wants to merge 1 commit into
openJiuwen-ai:dev-stablefrom
openjiuwenai:sync/pr-2285

Conversation

@openjiuwen-sync-bot

@openjiuwen-sync-bot openjiuwen-sync-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Paired: GitHub #464GitCode !2285

agent-core PR 描述

What type of PR is this?
/kind feature

Self-checklist:

    • 设计:PR对应的方案是否已经经过Maintainer评审,方案检视意见是否均已答复并完成方案修改
    • 测试:PR中的代码是否已有UT/ST测试用例进行充分的覆盖,新增测试用例是否随本PR一并上库或已经上库
    • 验证:PR描述信息中是否已包含对该PR对应的Feature、Refactor、Bugfix的预期目标达成情况的详细验证结果描述
    • 接口:是否涉及对外接口变更,相应变更已得到接口评审组织的通过,API对应的注释信息已经刷新正确
    • 文档:是否涉及官网文档修改,如果涉及请及时提交资料到Doc仓

背景

本批次回合 agent-core 侧 4 个 PR,覆盖子 agent 流式输出、reasoning_content 字段适配、create_deep_agent 路径拦截参数、ReadFileTool Office 文档读取。均为小修小改,不重构现有架构,基于 subagent_box_file_core 分支。

涉及 PR

PR 标题 策略
!1604 / !1981 / !2051 / !1956 子 agent 流式输出 按《Subagent流式输出方案_agent-core.md》合并回合,TaskTool 转发子 agent 流式 chunk 到父 session
!1179 适配大模型 API 关于 reasoning_content 字段要求 直接回合,消息归一化补全 reasoning_content
!1882 create_deep_agent 增加 allowed_paths 参数 直接回合,参数名 allowed_paths 语义明确无歧义
!1899 ReadFileTool 支持 Office 文档(.docx/.xlsx/.pptx) 直接回合,复用 python-docx/openpyxl/python-pptx

方案

PR 1604 / 1981 / 2051 / 1956 — 子 agent 流式输出

背景:TaskTool 委派子 agent 时仅返回最终结果,父 agent 无法实时看到子 agent 的思考与产出,并行子 agent 的流式输出也无法区分来源。

方案

  • TaskTool.invoke 创建子 session 时注入 source_metadatasource_agent_idsubagent_typeparent_session_id),调用 subagent.stream() 并将每个 chunk 转发到父 session.write_stream(),使前端实时看到子 agent 进度。
  • 子 session 携带 source_metadata 后 chunk 自动带 source_agent_id(经 Session._tag_stream_payload 注入 chunk.payload),并行子 agent 流可被前端区分(配合 jiuwenswarm 侧 E2A 透传)。
  • 子 session 使用独立 stream_writer_manager,避免共享父 SWM 导致流关闭冲突。
  • 转发失败只 warning 不中断主流程(容错)。

链路

flowchart TD
    A["TaskTool 创建 child_session<br/>注入 source_metadata(source_agent_id 等)"]
    B["ReActAgent._inner_stream<br/>调用 child_session.write_stream 写入 chunk"]
    C["Session._tag_stream_payload<br/>用 source_metadata 注入 chunk.payload"]
    D["TaskTool 转发 chunk<br/>到 parent_session.write_stream"]
    E["jiuwenswarm E2A<br/>_parse_stream_chunk 提取 source_agent_id"]
    A --> B --> C --> D --> E
Loading

文件openjiuwen/harness/tools/subagent/task_tool.py

PR 1179 — reasoning_content 字段适配

背景:部分大模型 API 要求 assistant 消息携带 reasoning_content 字段,缺失会导致请求被拒或思考链丢失。

方案

  • base_model_client:消息归一化时为所有 assistant 消息补全 reasoning_content=""(dict 形式遍历补全并浅拷贝避免修改原 dict,BaseMessage 形式统一设置)。
  • react_agent(legacy):构造 AssistantMessage 时透传 reasoning_content=getattr(llm_output, "reasoning_content", None),用 getattr 安全取值兼容无此字段的模型。

文件

  • openjiuwen/core/foundation/llm/model_clients/base_model_client.py
  • openjiuwen/core/single_agent/legacy/react_agent.py

PR 1882 — create_deep_agent 增加 allowed_paths 参数

背景restrict_to_work_dir=True 时 sandbox 默认只允许子 agent 自身 workspace,子 agent 无法读取父 agent 的技能目录(SKILL.md 等)。

方案resolve_deep_agent_parts / create_deep_agent 增加 allowed_paths: Optional[List[str]] 参数,非 None 时设置 work_config.sandbox_root=allowed_paths,将指定目录纳入沙箱白名单。参数名 allowed_paths 语义明确无歧义,与现有 sandbox_root 对齐。默认 None,向后兼容。

文件openjiuwen/harness/factory.py

PR 1899 — ReadFileTool 支持 Office 文档

背景:ReadFileTool 仅支持文本/图片/PDF/Notebook,无法读取 .docx/.xlsx/.pptx 等 Office 文档(ZIP 压缩二进制格式),子 agent 处理办公文档时需手动转换。

方案

  • 新增 _OFFICE_DOC_EXTENSIONS.docx/.doc/.xlsx/.xls/.pptx/.ppt)与 _is_office_doc 判断,Office 文档纳入二进制检查豁免。
  • 新增 _read_office_doc 分发到 _read_docx/_read_xlsx/_read_pptx,复用 python-docx/openpyxl/python-pptx 解析。
  • MAX_OFFICE_DOC_SIZE_BYTES = 10MB 限制防止大文件 OOM(与旧架构 PR 1899 一致)。
  • 旧格式 .doc/.xls/.ppt 明确提示转换为现代格式。
  • ImportError 友好提示安装对应包。
  • 解析通过 asyncio.to_thread 避免阻塞事件循环。
  • 更新 READ_FILE_DESCRIPTION 说明 Office 文档支持。
  • pyproject.toml 新增 python-pptx>=0.6.23 依赖。

文件

  • openjiuwen/harness/tools/filesystem.py
  • openjiuwen/harness/prompts/tools/filesystem.py
  • pyproject.toml

文件变更

文件 增/删 说明
openjiuwen/harness/tools/subagent/task_tool.py +47 流式输出转发 + source_metadata
openjiuwen/core/foundation/llm/model_clients/base_model_client.py +20/-2 reasoning_content 归一化
openjiuwen/core/single_agent/legacy/react_agent.py +3/-1 reasoning_content 透传
openjiuwen/harness/factory.py +14 allowed_paths 参数
openjiuwen/harness/tools/filesystem.py +167 Office 文档读取
openjiuwen/harness/prompts/tools/filesystem.py +10/-1 工具描述更新
pyproject.toml +1 python-pptx 依赖

合计 7 文件,+247/-15。

验证

  • ✅ 语法检查通过(ast.parse)
  • ✅ reasoning_content 适配:assistant 消息(dict/BaseMessage 两种形式)均补全字段
  • ✅ allowed_paths:透传链 create_deep_agent → resolve_deep_agent_parts → LocalWorkConfig.sandbox_root 完整
  • ✅ 流式输出:source_agent_id 经 child_session._tag_stream_payload 注入 chunk.payload,端到端验证
  • ✅ Office 文档:docx/xlsx/pptx 解析正确,10MB 大小限制,旧格式友好提示

Linked Closing Issues:

@openjiuwen-collaboration-bot

openjiuwen-collaboration-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

head_sha: 3584fe5e75e9b56ecc8dc1c68da046ca60c0cbf7

变更摘要

本次变更从 agent-core 侧回合 4 个 PR,主要涉及子 agent 流式输出、reasoning_content 字段适配、路径拦截参数以及 Office 文档读取能力四个方向。核心改动包括:TaskTool 从同步 invoke 改为流式 stream 调用,将子 agent 的流式 chunk 实时转发至父 session,并注入 source_metadata 以区分并行子 agent 的输出;BaseModelClient 消息归一化补全 reasoning_content 字段以满足部分兼容 API 的要求;create_deep_agent / resolve_deep_agent_parts 新增 allowed_paths 参数用于路径拦截;ReadFileTool 扩展支持 .docx / .xlsx / .pptx 文档的读取解析。

主要改动

  • TaskTool 子 agent 流式输出: TaskTool.invoke 改为使用 create_agent_session 创建携带 source_metadata 的子 session,通过 subagent.stream() 遍历 chunk 并调用 parent_session.write_stream(chunk) 转发至父流,使前端可实时看到子 agent 进度,且并行子 agent 可通过 source_agent_id 区分来源。

  • reasoning_content 字段归一化: BaseModelClient._normalize_messages 对字典类消息和 BaseMessage 类消息均补全 reasoning_content 字段(缺失时设为空字符串),同时 LegacyReActAgent 在构造 AssistantMessage 时从 LLM 输出中透传 reasoning_content,确保与要求该字段的 OpenAI 兼容 API 对接。

  • create_deep_agent 新增 allowed_paths 参数: resolve_deep_agent_partscreate_deep_agent 均新增 allowed_paths: Optional[List[str]] 参数,当传入时将其作为 sandbox_root 传递给 LocalWorkConfig,实现子 agent 工作目录的路径白名单拦截。

  • ReadFileTool Office 文档读取支持: 新增 _OFFICE_DOC_EXTENSIONS 扩展名集(.docx/.doc/.xlsx/.xls/.pptx/.ppt)及对应的 _read_docx_read_xlsx_read_pptx 解析方法,分别依赖 python-docxopenpyxlpython-pptx 将文档内容提取为 Markdown 格式,并在 pyproject.toml 中补充 python-pptx 依赖。旧版格式(.doc/.xls/.ppt)会抛出明确错误提示用户转换格式。

@openjiuwen-collaboration-bot

openjiuwen-collaboration-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

head_sha: 3584fe5e75e9b56ecc8dc1c68da046ca60c0cbf7

代码审查

✅ 未发现问题

@openjiuwen-collaboration-bot

Copy link
Copy Markdown

head_sha: 3584fe5e75e9b56ecc8dc1c68da046ca60c0cbf7

任务名称 结果 日志操作
静态检查 ✅SUCCESS 点此跳转
防投毒检查 ✅SUCCESS 点此跳转
开源合规检查 ✅SUCCESS 点此跳转
UT测试 ❌FAILED 点此跳转
ST测试 N/A N/A
build 编译包 N/A N/A
ruff codecheck ❌FAILED 点此跳转

@openjiuwen-collaboration-bot

Copy link
Copy Markdown

head_sha: 31996876d6e403b23ba2e645b182e8a80e0f54fb

任务名称 结果 日志操作
静态检查 ✅SUCCESS 点此跳转
防投毒检查 ✅SUCCESS 点此跳转
开源合规检查 ✅SUCCESS 点此跳转
UT测试 ✅SUCCESS 点此跳转
ST测试 N/A N/A
build 编译包 N/A N/A
ruff codecheck ❌FAILED 点此跳转

)
assert agent.ability_manager.get("task_tool") is not None

agent.react_agent.set_llm(fake_model)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

head_sha: 31996876d6e403b23ba2e645b182e8a80e0f54fb

[建议][Should Fix][Clean] ruff codecheck FAILED(PR 描述中已标注)。test_expert_harness_hot_load.py 中存在多处连续空行(E303 too many blank lines),可能为 ruff 失败原因之一。建议运行 ruff check --fix 和 ruff format 修复所有格式问题后重新推送。

问题: ruff codecheck FAILED(PR 描述中已标注)。test_expert_harness_hot_load.py 中存在多处连续空行(E303 too many blank lines),可能为 ruff 失败原因之一。建议运行 ruff check --fix 和 ruff format 修复所有格式问题后重新推送。

触发场景: ruff codecheck FAILED(PR 描述中已标注)。test_expert_harness_hot_load.py 中存在多处连续空行(E303 too many blank lines),可能为 ruff 失败原因之一。建议运行 ruff check --fix 和 ruff format 修复所有格式问题后重新推送。

影响: CI ruff 检查不通过,可能阻塞合入。

建议修复: 运行 ruff check --fix tests/unit_tests/harness/test_expert_harness_hot_load.pyruff format tests/unit_tests/harness/test_expert_harness_hot_load.py,修复所有 ruff 告警后重新推送。

验证建议: 补充或执行覆盖该场景的单元测试/回归验证,确认修复后不会再次触发该问题。

本批次回合 agent-core 侧 4 类改动,覆盖流式输出、路径拦截、Office 文档读取
与 reasoning_content 字段适配,均为小修小改,不重构现有架构。

背景:TaskTool 委派子 agent 时仅返回最终结果,父 agent 无法实时看到子 agent
的思考与产出,并行子 agent 的流式输出也无法区分来源。

方案:
- TaskTool.invoke 创建子 session 时注入 source_metadata(source_agent_id、
  subagent_type、parent_session_id),调用 subagent.stream() 并将每个 chunk
  转发到父 session.write_stream(),使前端实时看到子 agent 进度。
- 子 session 携带 source_metadata 后 chunk 自动带 source_agent_id,并行子
  agent 流可被前端区分(配合 jiuwenswarm 侧 E2A 透传)。
- 子 session 使用独立 stream_writer_manager,避免共享父 SWM 导致流关闭冲突。

文件:openjiuwen/harness/tools/subagent/task_tool.py

背景:部分大模型 API 要求 assistant 消息携带 reasoning_content 字段,缺失
会导致请求被拒或思考链丢失。

方案:
- base_model_client:消息归一化时为所有 assistant 消息补全
  reasoning_content=""(dict 形式遍历补全,BaseMessage 形式统一设置)。
- react_agent(legacy):构造 AssistantMessage 时透传
  reasoning_content=getattr(llm_output, "reasoning_content", None),
  用 getattr 安全取值兼容无此字段的模型。

文件:
- openjiuwen/core/foundation/llm/model_clients/base_model_client.py
- openjiuwen/core/single_agent/legacy/react_agent.py

背景:restrict_to_work_dir=True 时 sandbox 默认只允许子 agent 自身 workspace,
子 agent 无法读取父 agent 的技能目录(SKILL.md 等)。

方案:resolve_deep_agent_parts / create_deep_agent 增加 allowed_paths 参数,
非 None 时设置 work_config.sandbox_root=allowed_paths,将指定目录纳入沙箱白名单。
参数名 allowed_paths 语义明确无歧义,与现有 sandbox_root 对齐。

文件:openjiuwen/harness/factory.py

背景:ReadFileTool 仅支持文本/图片/PDF/Notebook,无法读取 .docx/.xlsx/.pptx
等 Office 文档,子 agent 处理办公文档时需手动转换。

方案:
- 新增 _OFFICE_DOC_EXTENSIONS(.docx/.doc/.xlsx/.xls/.pptx/.ppt)与
  _is_office_doc 判断,Office 文档纳入二进制检查豁免。
- 新增 _read_office_doc 分发到 _read_docx/_read_xlsx/_read_pptx,
  复用 python-docx/openpyxl/python-pptx 解析,MAX_OFFICE_DOC_SIZE_BYTES
  限制 10MB 防止大文件 OOM。
- 更新 READ_FILE_DESCRIPTION 说明 Office 文档支持。
- pyproject.toml 新增 python-pptx>=0.6.23 依赖。

文件:
- openjiuwen/harness/tools/filesystem.py
- openjiuwen/harness/prompts/tools/filesystem.py
- pyproject.toml
@openjiuwen-collaboration-bot

Copy link
Copy Markdown

head_sha: 31145baca7431569007cc8188a6cfd388bc43a33

任务名称 结果 日志操作
静态检查 ✅SUCCESS 点此跳转
防投毒检查 ✅SUCCESS 点此跳转
开源合规检查 ✅SUCCESS 点此跳转
UT测试 ✅SUCCESS 点此跳转
ST测试 N/A N/A
build 编译包 N/A N/A
ruff codecheck ❌FAILED 点此跳转

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant