-
Notifications
You must be signed in to change notification settings - Fork 77
fix(agentscope): 修复消息转换中参数和输出的解析逻辑 #266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
添加_try_loads辅助函数处理JSON解析,改进工具调用和结果输出的健壮性 当参数或输出不是有效JSON时,使用默认值或原始字符串
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes a bug in the message conversion logic when handling tool calls and their outputs. The issue occurred when the web-ui processed conversations containing plugin_call messages, causing failures during message parsing. The fix adds robust JSON parsing with fallback handling for cases where arguments or outputs are not valid JSON strings.
Key Changes:
- Added
_try_loadshelper function to safely parse JSON with configurable fallback behavior - Modified tool call argument extraction to handle non-JSON and empty string cases
- Modified tool output extraction to preserve original strings when JSON parsing fails
Comments suppressed due to low confidence (1)
src/agentscope_runtime/adapters/agentscope/message.py:438
- Similar to the tool arguments extraction, the output extraction logic finds the
outputvalue from content items in reverse order, but then usesmessage.content[0].data["call_id"]andmessage.content[0].data.get("name")for theToolResultBlockcreation at lines 434-435.
This creates the same inconsistency: if the valid output is found in a different content item, the call_id and name might not match. Consider extracting all fields from the same content item:
output_data = None
for cnt in reversed(message.content):
if hasattr(cnt, "data") and "call_id" in cnt.data:
v = cnt.data.get("output")
if isinstance(v, (dict, list)) or (isinstance(v, str) and v.strip()):
output_data = {
"call_id": cnt.data["call_id"],
"name": cnt.data.get("name"),
"output": _try_loads(v, "", keep_original=True)
}
break
if output_data is None:
output_data = {
"call_id": message.content[0].data.get("call_id", ""),
"name": message.content[0].data.get("name"),
"output": ""
}
blk = output_data["output"]
# ... rest of validation logic ...
result["content"] = [
ToolResultBlock(
type="tool_result",
id=output_data["call_id"],
name=output_data["name"],
output=blk,
),
] out = None
for cnt in reversed(message.content):
if hasattr(cnt, "data"):
v = cnt.data.get("output")
if isinstance(v, (dict, list)) or (
isinstance(v, str) and v.strip()
):
out = _try_loads(v, "", keep_original=True)
break
if out is None:
out = ""
blk = out
def is_valid_block(obj):
return any(
matches_typed_dict_structure(obj, cls)
for cls in (TextBlock, ImageBlock, AudioBlock, VideoBlock)
)
if isinstance(blk, list):
if not all(is_valid_block(item) for item in blk):
blk = out
elif isinstance(blk, dict):
if not is_valid_block(blk):
blk = out
else:
blk = out
result["content"] = [
ToolResultBlock(
type="tool_result",
id=message.content[0].data["call_id"],
name=message.content[0].data.get("name"),
output=blk,
),
]
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
rayrayraykk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contributions, it looks good to me.
|
@all-contributors please add @fengxsong for bug |
|
I've put up a pull request to add @fengxsong! 🎉 |
Description
添加_try_loads辅助函数处理JSON解析,改进工具调用和结果输出的健壮性
当参数或输出不是有效JSON时,使用默认值或原始字符串
当使用web-ui进行测试时,当在之前的对话中调用了
plugin_call时,在这里会失败。测试的payload
{"input": [{"sequence_number": null, "object": "message", "status": "created", "error": null, "id": "msg_380c1bb2-24bb-45e0-9147-01b15141bb1a", "type": "message", "role": "user", "content": [{"sequence_number": null, "object": "content", "status": "created", "error": null, "type": "text", "index": null, "delta": false, "msg_id": null, "text": "你好啊"}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 9, "object": "message", "status": "completed", "error": null, "id": "msg_aaa88a75-4e00-408d-8389-df734708f6c9", "type": "message", "role": "assistant", "content": [{"sequence_number": 8, "object": "content", "status": "completed", "error": null, "type": "text", "index": null, "delta": null, "msg_id": null, "text": "你好!请问有什么我可以帮你的吗?"}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": null, "object": "message", "status": "created", "error": null, "id": "msg_d2c22af4-2a6f-466f-b987-446e23d40e19", "type": "message", "role": "user", "content": [{"sequence_number": null, "object": "content", "status": "created", "error": null, "type": "text", "index": null, "delta": false, "msg_id": null, "text": "暂时没啥事"}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 10, "object": "message", "status": "completed", "error": null, "id": "msg_d73fac37-52ab-449a-9064-f676133cc34a", "type": "message", "role": "assistant", "content": [{"sequence_number": 9, "object": "content", "status": "completed", "error": null, "type": "text", "index": null, "delta": null, "msg_id": null, "text": "收到,当前无任务待处理。如有需要,请随时告知!"}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": null, "object": "message", "status": "created", "error": null, "id": "msg_9d608921-0eb9-47a1-90e7-fb0f5f3ac293", "type": "message", "role": "user", "content": [{"sequence_number": null, "object": "content", "status": "created", "error": null, "type": "text", "index": null, "delta": false, "msg_id": null, "text": "看看devops namespace有什么服务"}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 5, "object": "message", "status": "completed", "error": null, "id": "msg_69f41d40-1d9e-4751-bf21-ae46080c2ade", "type": "plugin_call", "role": "assistant", "content": [{"sequence_number": null, "object": "content", "status": null, "error": null, "type": "data", "index": null, "delta": null, "msg_id": null, "data": {"call_id": "call_6035dadd0c3a4dadbbe1551a", "name": "handoff_observability", "arguments": ""}}, {"sequence_number": null, "object": "content", "status": null, "error": null, "type": "data", "index": null, "delta": null, "msg_id": null, "data": {"call_id": "call_6035dadd0c3a4dadbbe1551a", "name": "handoff_observability", "arguments": "{\"task\": \"\\u5217\\u51fa devops namespace \\u4e2d\\u7684\\u6240\\u6709\\u670d\\u52a1\"}"}}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 9, "object": "message", "status": "completed", "error": null, "id": "msg_05943276-e34d-4501-a238-8f0e77fe24ed", "type": "plugin_call", "role": "assistant", "content": [{"sequence_number": null, "object": "content", "status": null, "error": null, "type": "data", "index": null, "delta": null, "msg_id": null, "data": {"call_id": "call_e501a6af09164ab78624bb32", "name": "kubectl_get", "arguments": ""}}, {"sequence_number": null, "object": "content", "status": null, "error": null, "type": "data", "index": null, "delta": null, "msg_id": null, "data": {"call_id": "call_e501a6af09164ab78624bb32", "name": "kubectl_get", "arguments": "{\"resourceType\": \"services\", \"namespace\": \"devops\", \"name\": \"\"}"}}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 10, "object": "message", "status": "completed", "error": null, "id": "msg_3461cba0-dd30-44f2-b63b-a5fd981c2bd7", "type": "plugin_call_output", "role": "tool", "content": [{"sequence_number": null, "object": "content", "status": null, "error": null, "type": "data", "index": null, "delta": false, "msg_id": null, "data": {"call_id": "call_e501a6af09164ab78624bb32", "name": "kubectl_get", "output": "[{\"type\": \"text\", \"text\": \"{\\n \\\"items\\\": [\\n {\\n \\\"name\\\": \\\"blackbox-prometheus-blackbox-exporter\\\",\\n \\\"namespace\\\": \\\"devops\\\",\\n \\\"kind\\\": \\\"Service\\\",\\n \\\"status\\\": \\\"ClusterIP\\\",\\n \\\"createdAt\\\": \\\"2025-04-09T07:31:39Z\\\"\\n },\\n {\\n \\\"name\\\": \\\"devops-ai-code-review\\\",\\n \\\"namespace\\\": \\\"devops\\\",\\n \\\"kind\\\": \\\"Service\\\",\\n \\\"status\\\": \\\"ClusterIP\\\",\\n \\\"createdAt\\\": \\\"2024-10-17T07:10:11Z\\\"\\n },\\n {\\n \\\"name\\\": \\\"devops-assistant-service\\\",\\n \\\"namespace\\\": \\\"devops\\\",\\n \\\"kind\\\": \\\"Service\\\",\\n \\\"status\\\": \\\"ClusterIP\\\",\\n \\\"createdAt\\\": \\\"2024-10-31T09:29:12Z\\\"\\n },\\n {\\n \\\"name\\\": \\\"devops-cicd-ui-service\\\",\\n \\\"namespace\\\": \\\"devops\\\",\\n \\\"kind\\\": \\\"Service\\\",\\n \\\"status\\\": \\\"ClusterIP\\\",\\n \\\"createdAt\\\": \\\"2025-04-08T02:42:57Z\\\"\\n },\\n {\\n \\\"name\\\": \\\"devops-iam-service\\\",\\n \\\"namespace\\\": \\\"devops\\\",\\n \\\"kind\\\": \\\"Service\\\",\\n \\\"status\\\": \\\"ClusterIP\\\",\\n \\\"createdAt\\\": \\\"2025-04-16T07:17:58Z\\\"\\n },\\n {\\n \\\"name\\\": \\\"devops-tunnel-service\\\",\\n \\\"namespace\\\": \\\"devops\\\",\\n \\\"kind\\\": \\\"Service\\\",\\n \\\"status\\\": \\\"ClusterIP\\\",\\n \\\"createdAt\\\": \\\"2025-04-08T02:23:55Z\\\"\\n },\\n {\\n \\\"name\\\": \\\"tunnel-service\\\",\\n \\\"namespace\\\": \\\"devops\\\",\\n \\\"kind\\\": \\\"Service\\\",\\n \\\"status\\\": \\\"ClusterIP\\\",\\n \\\"createdAt\\\": \\\"2025-03-23T03:38:51Z\\\"\\n }\\n ]\\n}\"}]"}}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 89, "object": "message", "status": "completed", "error": null, "id": "msg_0d84e9f0-319d-4a38-8237-a7e6c387036b", "type": "message", "role": "assistant", "content": [{"sequence_number": 88, "object": "content", "status": "completed", "error": null, "type": "text", "index": null, "delta": null, "msg_id": null, "text": "在 `devops` 命名空间中,当前存在以下服务(共 7 个):\n\n| 服务名称 | 类型 | 创建时间 |\n|-------------------------------------|------------|------------------------|\n| blackbox-prometheus-blackbox-exporter | ClusterIP | 2025-04-09T07:31:39Z |\n| devops-ai-code-review | ClusterIP | 2024-10-17T07:10:11Z |\n| devops-assistant-service | ClusterIP | 2024-10-31T09:29:12Z |\n| devops-cicd-ui-service | ClusterIP | 2025-04-08T02:42:57Z |\n| devops-iam-service | ClusterIP | 2025-04-16T07:17:58Z |\n| devops-tunnel-service | ClusterIP | 2025-04-08T02:23:55Z |\n| tunnel-service | ClusterIP | 2025-03-23T03:38:51Z |\n\n所有服务均为 `ClusterIP` 类型,仅在集群内部可访问。如需进一步信息(如端口、Selector 或关联的 Pod),可指定具体服务名称进行详细查询。"}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 90, "object": "message", "status": "completed", "error": null, "id": "msg_01095b61-9168-44bc-b5f8-c97a8ed8ff89", "type": "plugin_call_output", "role": "tool", "content": [{"sequence_number": null, "object": "content", "status": null, "error": null, "type": "data", "index": null, "delta": false, "msg_id": null, "data": {"call_id": "call_6035dadd0c3a4dadbbe1551a", "name": "handoff_observability", "output": "[{\"type\": \"text\", \"text\": \"在 `devops` 命名空间中,当前存在以下服务(共 7 个):\\n\\n| 服务名称 | 类型 | 创建时间 |\\n|-------------------------------------|------------|------------------------|\\n| blackbox-prometheus-blackbox-exporter | ClusterIP | 2025-04-09T07:31:39Z |\\n| devops-ai-code-review | ClusterIP | 2024-10-17T07:10:11Z |\\n| devops-assistant-service | ClusterIP | 2024-10-31T09:29:12Z |\\n| devops-cicd-ui-service | ClusterIP | 2025-04-08T02:42:57Z |\\n| devops-iam-service | ClusterIP | 2025-04-16T07:17:58Z |\\n| devops-tunnel-service | ClusterIP | 2025-04-08T02:23:55Z |\\n| tunnel-service | ClusterIP | 2025-03-23T03:38:51Z |\\n\\n所有服务均为 `ClusterIP` 类型,仅在集群内部可访问。如需进一步信息(如端口、Selector 或关联的 Pod),可指定具体服务名称进行详细查询。\"}]"}}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": 183, "object": "message", "status": "completed", "error": null, "id": "msg_24230bed-5b28-4aed-881e-7b37b6f0a922", "type": "message", "role": "assistant", "content": [{"sequence_number": 182, "object": "content", "status": "completed", "error": null, "type": "text", "index": null, "delta": null, "msg_id": null, "text": "### 1) 观察与关键线索 \n- `devops` 命名空间中共有 **7 个服务**,均为 `ClusterIP` 类型,仅限集群内部访问。 \n- 服务包括:监控(blackbox-exporter)、AI 代码审查、IAM、CICD UI、协作门户、隧道服务等,覆盖 DevOps 全链路功能。 \n- 最近创建的服务是 `devops-mcp-resource`(2025-09-09),可能与新上线模块相关。\n\n### 2) 假设与优先级 \n- 用户意图可能是: \n a) **例行巡检**:确认服务清单是否符合预期; \n b) **故障排查**:某功能异常需定位对应服务; \n c) **安全审计**:检查是否存在冗余或未授权服务(如重复的 `tunnel-service`)。 \n- **优先级**:若无进一步指示,默认按 **巡检** 处理,无需深入分析。\n\n### 3) 验证计划与所需工具 \n- 当前信息已完整列出服务,无需额外工具调用。 \n- 若用户后续指定某服务异常,则需通过 `handoff_observability` 查询其 Pod/日志,或通过 `handoff_diagnosis` 分析依赖关系。\n\n### 4) 行动方案与回滚 \n- **行动**:输出服务清单供用户核对(已完成)。 \n- **回滚**:无操作执行,无需回滚。\n\n### 5) 确认项与成功判据 \n- 用户确认清单是否符合预期,或提出进一步需求(如检查某服务状态)。\n\n### 6) 风险等级与影响范围 \n- **风险等级**:低(仅读取元数据,无变更操作)。 \n- **影响范围**:无。 \n\n--- \n请确认是否需要针对某个具体服务深入检查(如状态、日志或配置)?"}], "code": null, "message": null, "usage": null, "metadata": null}, {"sequence_number": null, "object": "message", "status": "created", "error": null, "id": "msg_751982ff-6d75-4ff5-a1e1-7ce201a929d9", "type": "message", "role": "user", "content": [{"sequence_number": null, "object": "content", "status": "created", "error": null, "type": "text", "index": null, "delta": false, "msg_id": null, "text": "看看 devops-iam-service 有没什么性能问题"}], "code": null, "message": null, "usage": null, "metadata": null}], "stream": true, "id": null, "model": null, "top_p": null, "temperature": null, "frequency_penalty": null, "presence_penalty": null, "max_tokens": null, "stop": null, "n": 1, "seed": null, "tools": null, "session_id": "1764915547757", "user_id": "1764915547757"}Type of Change
Component(s) Affected
Checklist
Testing
Additional Notes