Description (描述)
__build_response_event (src/google/adk/flows/llm_flows/functions.py) 中的 skip_summarization 文本附加操作并未将其作用域限定为 AgentTool,因此它会对每个设置了 skip_summarization 的工具触发。对于函数响应属于内部确认(internal acknowledgement)的非 AgentTool 工具,这会将原始响应负载作为可见文本直接暴露给用户。
Background (背景)
PR google#5974(关闭了 google#3881)添加了此代码块,以确保 AgentTool 的输出不会在不渲染函数响应的 UI 中丢失:
# src/google/adk/flows/llm_flows/functions.py (current main)
has_displayable_result = display_result is not None and display_result != {
'result': None
}
if (
tool_context.actions.skip_summarization
and 'error' not in function_result
and has_displayable_result
):
if isinstance(display_result, str):
result_text = display_result
else:
result_text = json.dumps(display_result, ensure_ascii=False, default=str)
content.parts.append(types.Part.from_text(text=result_text))
Issue google#3881 是专门针对 AgentTool 的(其标题为:"The agent doesn't work as expected when skip_summarization is set to True in AgentTool"),并且该 PR 的标题是 "ensure AgentTool text output when skip_summarization is True"。但是,该条件仅检查了 tool_context.actions.skip_summarization —— 并没有 isinstance(tool, AgentTool) 的条件防护,因此该行为被应用到了所有工具上。
Why this is a problem (为什么这是一个问题)
工具设置 skip_summarization 也有可能是出于完全相反的原因:它们的函数响应是一个不应被总结或显示的内部确认消息。UI / 小组件渲染工具就是常见的例子 —— 它们返回类似 {"status": "ok"} 的内容,并设置 skip_summarization=True,因为面向用户的最终结果是一个渲染出来的小组件,而不是文本。
在缺乏条件防护的附加操作下,该确认消息(ack)被强制转换成了文本 Part。随后,文本 Part 绕过了通常用于剥离 functionResponse / functionCall / thought 部分的 UI/SSE 过滤器,导致原始负载({"status": "ok", ...})作为可见文本呈现给用户。在升级到包含 google#5974 的构建版本后,我们观察到一个持续存在的、用户可见的回归问题:渲染样式的工具开始将它们的确认 JSON 泄露到聊天记录中。
Steps to reproduce (复现步骤)
定义一个非 AgentTool(例如 FunctionTool),设置 tool_context.actions.skip_summarization = True 并返回一个字典,例如 {"status": "ok"}。
通过正常的函数调用流程来调用它。
除了 functionResponse 部分之外,产生的函数响应事件还包含一个额外的带有序列化字典的 Part.from_text(...)。
预期行为:仅存在 functionResponse 部分(确认消息不作为文本显示)。
实际行为:附加了一个携带序列化响应的文本 Part。
Proposed fix (建议修复方案)
使用 isinstance(tool, AgentTool) 为该附加操作添加条件防护,使其符合最初的意图 —— AgentTool 保留其文本输出;其他选择退出总结的工具则不会将其函数响应作为文本重复输出。
已附带实现此修复(并包含回归测试)的 PR。
Environment (环境)
ADK: 当前 main 分支
Affected since (受影响版本始于): PR feat(skills): Allow opt-in session state injection in skill instructions google#5974 / 提交 "fix: ensure AgentTool text output when skip_summarization is True"
Description (描述)
__build_response_event (src/google/adk/flows/llm_flows/functions.py) 中的 skip_summarization 文本附加操作并未将其作用域限定为 AgentTool,因此它会对每个设置了 skip_summarization 的工具触发。对于函数响应属于内部确认(internal acknowledgement)的非 AgentTool 工具,这会将原始响应负载作为可见文本直接暴露给用户。
Background (背景)
PR google#5974(关闭了 google#3881)添加了此代码块,以确保 AgentTool 的输出不会在不渲染函数响应的 UI 中丢失:
Issue google#3881 是专门针对 AgentTool 的(其标题为:"The agent doesn't work as expected when skip_summarization is set to True in AgentTool"),并且该 PR 的标题是 "ensure AgentTool text output when skip_summarization is True"。但是,该条件仅检查了 tool_context.actions.skip_summarization —— 并没有 isinstance(tool, AgentTool) 的条件防护,因此该行为被应用到了所有工具上。
Why this is a problem (为什么这是一个问题)
工具设置 skip_summarization 也有可能是出于完全相反的原因:它们的函数响应是一个不应被总结或显示的内部确认消息。UI / 小组件渲染工具就是常见的例子 —— 它们返回类似 {"status": "ok"} 的内容,并设置 skip_summarization=True,因为面向用户的最终结果是一个渲染出来的小组件,而不是文本。
在缺乏条件防护的附加操作下,该确认消息(ack)被强制转换成了文本 Part。随后,文本 Part 绕过了通常用于剥离 functionResponse / functionCall / thought 部分的 UI/SSE 过滤器,导致原始负载({"status": "ok", ...})作为可见文本呈现给用户。在升级到包含 google#5974 的构建版本后,我们观察到一个持续存在的、用户可见的回归问题:渲染样式的工具开始将它们的确认 JSON 泄露到聊天记录中。
Steps to reproduce (复现步骤)
定义一个非 AgentTool(例如 FunctionTool),设置 tool_context.actions.skip_summarization = True 并返回一个字典,例如 {"status": "ok"}。
通过正常的函数调用流程来调用它。
除了 functionResponse 部分之外,产生的函数响应事件还包含一个额外的带有序列化字典的 Part.from_text(...)。
预期行为:仅存在 functionResponse 部分(确认消息不作为文本显示)。
实际行为:附加了一个携带序列化响应的文本 Part。
Proposed fix (建议修复方案)
使用 isinstance(tool, AgentTool) 为该附加操作添加条件防护,使其符合最初的意图 —— AgentTool 保留其文本输出;其他选择退出总结的工具则不会将其函数响应作为文本重复输出。
已附带实现此修复(并包含回归测试)的 PR。
Environment (环境)
ADK: 当前 main 分支
Affected since (受影响版本始于): PR feat(skills): Allow opt-in session state injection in skill instructions google#5974 / 提交 "fix: ensure AgentTool text output when skip_summarization is True"