diff --git a/backend/python/app/api/chat_service.py b/backend/python/app/api/chat_service.py index d9cad49..e31602a 100644 --- a/backend/python/app/api/chat_service.py +++ b/backend/python/app/api/chat_service.py @@ -3463,6 +3463,7 @@ async def _send_message_core( _schema = {"type": "object", "properties": {}} + _schema = _normalize_mcp_schema(_schema) @@ -5228,7 +5229,7 @@ async def _send_message_core( - tool_result = f"[工具调用已被策略拦截] {_policy_check.get('message', _reason)}" + tool_result = f"[策略拦截: {_policy_check.get('message', _reason)}] 建议: 检查权限设置或新开对话" @@ -5404,7 +5405,7 @@ async def _send_message_core( - tool_result = "[MCP 工具未找到或映射缺失]" + tool_result = "[MCP 工具未找到] 建议: 检查工具名或尝试其他MCP工具。可用: " + str(list(mcp_tool_map.keys())[:5]) @@ -8402,6 +8403,35 @@ def _resolve_agent_tool_policy(agents): +def _normalize_mcp_schema(schema: dict) -> dict: + """MCP JSON Schema -> OpenAI function calling 兼容。 + 处理: $ref, oneOf/anyOf -> first option, 剥离非标关键字""" + if not isinstance(schema, dict): + return {"type": "object", "properties": {}} + if "$ref" in schema: + return {"type": "object", "properties": {}} + if "oneOf" in schema or "anyOf" in schema: + opts = schema.get("oneOf") or schema.get("anyOf") or [] + if opts and isinstance(opts[0], dict): + return _normalize_mcp_schema(opts[0]) + return {"type": "object", "properties": {}} + if "allOf" in schema: + merged = {"type": "object", "properties": {}} + for s in schema.get("allOf", []): + sub = _normalize_mcp_schema(s) + if sub.get("properties"): + merged["properties"].update(sub["properties"]) + return merged + result = {} + for k in ("type", "properties", "required", "description", "enum", "items"): + if k in schema: + result[k] = schema[k] + if result.get("type") != "object": + result["type"] = "object" + if "properties" not in result: + result["properties"] = {} + return result + def _check_tool_policy(func_name, mcp_info, skills, policy, call_count, round_count): diff --git a/backend/python/app/api/chat_skill.py b/backend/python/app/api/chat_skill.py index 20f7e1f..453f62c 100644 --- a/backend/python/app/api/chat_skill.py +++ b/backend/python/app/api/chat_skill.py @@ -1272,7 +1272,7 @@ def _execute_skill_tool( - return f"工具 '{func_name}' 执行结果: 已处理输入内容, 但未找到对应的技能定义。请基于通用知识回复用户。" + return f"工具 '{func_name}' 执行结果: 已处理输入内容, 但未找到对应的技能定义。请基于通用知识回复用户。如有已加载的技能,可使用其名称直接调用。" diff --git a/frontend/src/pages/front/ChatPage.css b/frontend/src/pages/front/ChatPage.css index 781698d..ad6bd9e 100644 --- a/frontend/src/pages/front/ChatPage.css +++ b/frontend/src/pages/front/ChatPage.css @@ -1779,3 +1779,8 @@ html.dark .ai-sending-timeout { width: 16px; height: 16px; } + +.ai-process-running { animation: aiPulse 1.5s ease-in-out infinite; } +@keyframes aiPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.6; } } +.ai-process-error { background: rgba(255,0,0,0.05); border-left: 2px solid #e74c3c; } +.ai-process-running { border-left: 2px solid #3498db; } diff --git a/frontend/src/pages/front/ChatPage.tsx b/frontend/src/pages/front/ChatPage.tsx index 61bd85b..0569705 100644 --- a/frontend/src/pages/front/ChatPage.tsx +++ b/frontend/src/pages/front/ChatPage.tsx @@ -531,18 +531,41 @@ const AiProcessBlock: React.FC<{ steps: any[]; autoExpand: boolean }> = ({ steps AI 思考 / 执行过程({steps.length} 步 — {open ? '自动收拢中... 点击手动收起' : '点击展开查看'})
{s.text}
>)} - {s.type === 'skill' && (<>调用技能:{s.name}{(s.result || '').slice(0, 400)}
>)} - {s.type === 'mcp' && (<>MCP · {s.server}:{s.name}{(s.result || '').slice(0, 400)}
>)} + {s.type === 'skill' && (<> + 调用技能:{s.name}{statusIcon} + {s.args && Object.keys(s.args).length > 0 && ( + + 参数: {JSON.stringify(s.args).slice(0, 200)} + + )} + {hasResult &&{resultDisplay}
} + >)} + {s.type === 'mcp' && (<> + MCP · {s.server}:{s.name}{statusIcon} + {s.args && Object.keys(s.args).length > 0 && ( + + 参数: {JSON.stringify(s.args).slice(0, 200)} + + )} + {hasResult &&{resultDisplay}
} + >)}