fix(copilot): serialize tool output to standard JSON format for frontend parsing

Changed tool output serialization in AgentService._convert_event_to_chunk()
from str() to json.dumps() to ensure structured data (dict/list) is properly
formatted as standard JSON instead of Python string representation.

Changes:
- Added json import to agent_service.py
- Modified on_tool_end event handling to use json.dumps(output, ensure_ascii=False, indent=2)
- Updated ai-chat-api-design.md to document tool_output format

Benefits:
- Frontend can parse tool results with standard JSON.parse()
- Chinese and non-ASCII characters are preserved (not escaped)
- Formatted output (indent=2) improves readability

Co-Authored-By: YueGuobin <yueguobin@outlook.com>
This commit is contained in:
YueGuobin 2026-03-09 15:15:50 +08:00
parent 13a032ea2c
commit 0f2d0e2859
2 changed files with 12 additions and 3 deletions

View File

@ -247,6 +247,13 @@ Chat API uses Server-Sent Events (SSE) for streaming transmission.
| tool_end | Tool execution complete | tool_name, tool_output, session_id |
| error | Error message | error, session_id |
| done | Stream end | session_id |
**Tool Output Format** (`tool_output` field):
- If the tool returns a non-string type (dict, list), it is automatically serialized to JSON format using `json.dumps(obj, ensure_ascii=False, indent=2)`
- If the tool returns a string type, it is passed through as-is
- This ensures all structured data is in standard JSON format, making it easy for the frontend to parse with `JSON.parse()`
- Chinese and other non-ASCII characters are preserved (not escaped to `\uXXXX`)
| heartbeat | Heartbeat keepalive | session_id |
### Message Examples
@ -317,7 +324,7 @@ Chat API uses Server-Sent Events (SSE) for streaming transmission.
{
"type": "tool_end",
"tool_name": "execute_multiple_device_commands",
"tool_output": "{...}",
"tool_output": "[\n {\n \"device_name\": \"R-1\",\n \"status\": \"success\",\n \"output\": \"Cisco IOS Software, \\n IOSv Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 15.2(1.90)\"\n },\n {\n \"device_name\": \"R-2\",\n \"status\": \"failed\",\n \"error\": \"Connection timeout\"\n }\n]",
"session_id": "xxx"
}

View File

@ -32,6 +32,7 @@ in the project directory.
"""
import asyncio
import json
import logging
import os
from datetime import datetime
@ -460,9 +461,10 @@ class AgentService:
elif event_type == "on_tool_end":
# Tool execution completed
output = data.get("output", "")
# Convert output to string if it's not already
# Convert output to JSON string if it's not already a string
# This ensures dict/list outputs are properly serialized for frontend parsing
if not isinstance(output, str):
output = str(output)
output = json.dumps(output, ensure_ascii=False, indent=2)
return {
"type": "tool_end",
"tool_name": event.get("name", ""),