Skip to content

fix(core): 正式支持 direct tool observation#815

Merged
dingyi222666 merged 3 commits intoChatLunaLab:v1-devfrom
CookSleep:fix/direct-tool-observation
Apr 6, 2026
Merged

fix(core): 正式支持 direct tool observation#815
dingyi222666 merged 3 commits intoChatLunaLab:v1-devfrom
CookSleep:fix/direct-tool-observation

Conversation

@CookSleep
Copy link
Copy Markdown
Member

Summary

  • 正式将 direct tool output 纳入 AgentObservation,避免最终回复对象在 agent 流程中被提前当成非法 observation 转成字符串。
  • 在 OpenAI agent、sub-agent 和消息历史落库链路中显式处理 direct tool output,统一将这类控制结果写成空的 tool message 内容。
  • 这样 character_reply 一类最终回复工具可以通过 LangChain 原生的 lc_direct_tool_output 正常结束,而不是依赖额外兜底。

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bc67ab9a-7b87-47d2-ba37-2bf58be9902f

📥 Commits

Reviewing files that changed from the base of the PR and between 5a9de81 and f50f622.

📒 Files selected for processing (1)
  • packages/extension-agent/src/sub-agent/session.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/extension-agent/src/sub-agent/session.ts

Walkthrough

本次变更在 Agent 观察类型中加入对直接工具输出(DirectToolOutput)的支持,新增并导出 observationToMessageContent,并在生成 ToolMessage.content 的多个位置改为通过该函数映射,且在遇到直接工具输出时短路返回原值或空内容。

Changes

Cohort / File(s) Summary
类型定义
packages/core/src/llm-core/agent/types.ts
新增导入 DirectToolOutput 并新增类型 AgentDirectToolObservation = DirectToolOutput & { replyEmitted?: boolean },将 AgentObservation 扩展以包含该类型。
核心观察处理与导出
packages/core/src/llm-core/agent/legacy-executor.ts, packages/core/src/llm-core/agent/executor.ts
legacy-executor 中新增并导出 observationToMessageContentisAgentObservationcoerceToAgentObservation 增加对直接工具输出的识别与短路返回(绕过原有 coercion/JSON/string 回退与警告)。在 executor.ts 中重新导出该 helper。
工具消息构造(Agent -> 消息/存储)
packages/core/src/llm-core/agent/openai/index.ts, packages/core/src/llm-core/agent/sub-agent.ts, packages/core/src/llm-core/memory/message/database_history.ts, packages/extension-agent/src/sub-agent/session.ts
将所有生成 ToolMessage.content 的位置改为使用 observationToMessageContent(step.observation)(或等价调用);在内容无效时保留失败提示逻辑,且不改变 tool_call_id/name 等元数据。

Sequence Diagram(s)

sequenceDiagram
  participant Tool
  participant AgentExecutor
  participant MessageBuilder
  participant Storage

  Tool->>AgentExecutor: return DirectToolOutput / string / complex content
  AgentExecutor->>AgentExecutor: isAgentObservation() 判断(包括 DirectToolOutput)
  AgentExecutor->>MessageBuilder: observationToMessageContent(observation)
  MessageBuilder->>Storage: create ToolMessage(name, tool_call_id, content)
  Storage-->>AgentExecutor: 存储/确认
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 我在草丛里跳跃看,
工具直出入我眼,轻声不必转,
内容一处映射稳,消息步步来相连,
小兔鼓掌又点头,代码整齐唱轻欢。

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题清晰具体,准确概括了主要变更:正式支持 direct tool observation,与变更集的核心目标相符。
Description check ✅ Passed 描述充分关联变更集,详细说明了引入 direct tool observation 支持的原因、处理方式和预期效果。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for DirectToolOutput within the agent's observation handling. It updates the AgentObservation type definition and modifies the logic in the legacy executor, OpenAI agent, sub-agent, and database history to correctly identify and process direct tool outputs, typically by setting the ToolMessage content to an empty string when such outputs are detected. I have no feedback to provide.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/src/llm-core/agent/legacy-executor.ts (1)

312-320: 直接工具输出的 replyEmitted 属性访问存在类型安全隐患。

在第 314 行和第 319 行,代码通过索引访问 last.observation['replyEmitted']。虽然 AgentDirectToolObservation 类型定义了这个可选属性,但 AgentObservation 是联合类型,当 observationstringAgentObservationComplexContent[] 时,这种访问方式会返回 undefined 而不会报错,所以运行时是安全的。

不过,建议在 TODO 注释中标记的代码移除后,考虑使用类型守卫来提高代码可读性。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/llm-core/agent/legacy-executor.ts` around lines 312 - 320,
The code in legacy-executor.ts indexes last.observation['replyEmitted'] (used
when building the output object and replyEmitted field) but observation is a
union (AgentDirectToolObservation | string | AgentObservationComplexContent[]);
add a type guard that narrows last.observation to AgentDirectToolObservation
before accessing replyEmitted (e.g., create/inline an
isAgentDirectToolObservation predicate that checks typeof last.observation ===
'object' && last.observation !== null && 'replyEmitted' in last.observation),
then use that guard when computing output (toOutput(last.observation) branch)
and replyEmitted to avoid unsafe indexing and improve readability.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/llm-core/agent/legacy-executor.ts`:
- Around line 312-320: The code in legacy-executor.ts indexes
last.observation['replyEmitted'] (used when building the output object and
replyEmitted field) but observation is a union (AgentDirectToolObservation |
string | AgentObservationComplexContent[]); add a type guard that narrows
last.observation to AgentDirectToolObservation before accessing replyEmitted
(e.g., create/inline an isAgentDirectToolObservation predicate that checks
typeof last.observation === 'object' && last.observation !== null &&
'replyEmitted' in last.observation), then use that guard when computing output
(toOutput(last.observation) branch) and replyEmitted to avoid unsafe indexing
and improve readability.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 12943ea6-4c26-486c-8e58-f2e2246d9de5

📥 Commits

Reviewing files that changed from the base of the PR and between 3692155 and c1396fd.

📒 Files selected for processing (5)
  • packages/core/src/llm-core/agent/legacy-executor.ts
  • packages/core/src/llm-core/agent/openai/index.ts
  • packages/core/src/llm-core/agent/sub-agent.ts
  • packages/core/src/llm-core/agent/types.ts
  • packages/core/src/llm-core/memory/message/database_history.ts

Reuse a shared observationToMessageContent helper so direct tool observations are converted consistently and ToolMessage content stays type-safe across agent flows.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/extension-agent/src/sub-agent/session.ts`:
- Around line 9-12: 当前从 'koishi-plugin-chatluna/llm-core/agent'
的命名导入顺序未按字母表排序,触发 lint 的 sort-imports 警告;请将导入项按字母序重新排列,例如确保
observationToMessageContent 在 AgentStep 之前或之后按字母顺序排序,从而消除警告,并保持原有导出名称不变(参照导入符号
observationToMessageContent 和 AgentStep 来定位修改处)。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7b435b46-e94d-400b-a5d3-bdf713ee5424

📥 Commits

Reviewing files that changed from the base of the PR and between c1396fd and 5a9de81.

📒 Files selected for processing (6)
  • packages/core/src/llm-core/agent/executor.ts
  • packages/core/src/llm-core/agent/legacy-executor.ts
  • packages/core/src/llm-core/agent/openai/index.ts
  • packages/core/src/llm-core/agent/sub-agent.ts
  • packages/core/src/llm-core/memory/message/database_history.ts
  • packages/extension-agent/src/sub-agent/session.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/core/src/llm-core/agent/sub-agent.ts
  • packages/core/src/llm-core/agent/executor.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/llm-core/memory/message/database_history.ts
  • packages/core/src/llm-core/agent/openai/index.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@dingyi222666 dingyi222666 merged commit b6082d4 into ChatLunaLab:v1-dev Apr 6, 2026
5 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