From 6b81f8dc509467afa011c18c888af5f829e9b4b5 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sun, 16 Aug 2026 18:02:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BA=AF=E9=80=9A=E7=94=A8=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E5=85=A5=E5=8F=A3(agent=5Fchat=5Fgeneric+agent=5Fgene?= =?UTF-8?q?ric=E7=95=8C=E9=9D=A2,=E6=97=A0=E4=BA=A7=E7=BA=BF=E6=8F=92?= =?UTF-8?q?=E4=BB=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wwwroot/agent_generic/index.ui | 26 ++++++++++++++++ wwwroot/api/agent_chat_generic.dspy | 48 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 wwwroot/agent_generic/index.ui create mode 100644 wwwroot/api/agent_chat_generic.dspy diff --git a/wwwroot/agent_generic/index.ui b/wwwroot/agent_generic/index.ui new file mode 100644 index 0000000..da880c6 --- /dev/null +++ b/wwwroot/agent_generic/index.ui @@ -0,0 +1,26 @@ +{ + "widgettype": "VBox", + "options": {"width": "100%", "height": "100%", "padding": "0"}, + "subwidgets": [ + { + "widgettype": "HBox", + "options": {"width": "100%", "alignItems": "center", "padding": "16px 24px 8px 24px", "cheight": 6, "gap": "12px"}, + "subwidgets": [ + {"widgettype": "Title2", "options": {"text": "通用会话(无产线插件)"}}, + {"widgettype": "Text", "options": {"text": "纯通用 agent,不挂任何产线工具/技能/角色/记忆", "cfontsize": 0.9, "color": "#94a3b8"}}, + {"widgettype": "Filler"} + ] + }, + { + "widgettype": "AgentIO", + "id": "chat_io", + "options": { + "css": "filler", + "url": "/pipeline_core/api/agent_chat_generic.dspy", + "model_dataurl": "/pipeline_core/api/agent_model_options.dspy", + "model_cwidth": 14, + "placeholder": "输入你的需求...(纯通用模式)" + } + } + ] +} diff --git a/wwwroot/api/agent_chat_generic.dspy b/wwwroot/api/agent_chat_generic.dspy new file mode 100644 index 0000000..3cfa1d8 --- /dev/null +++ b/wwwroot/api/agent_chat_generic.dspy @@ -0,0 +1,48 @@ +# agent_chat_generic.dspy - 纯通用会话(不挂任何产线插件) +# 用于对照测试:确定通用 agent 本身的能力,隔离产线工具/技能/角色/记忆的干扰 +# generic=True 时 gateway 跳过 resolve_project,不 load_agent_config 产线能力,只用 GENERAL_TOOLS + 通用心智 + +import json + +uid = await get_user() +if not uid: + uid = 'user-01' + +action = (params_kw or {}).get('action', 'send_message') + +if action == 'send_message': + prompt = (params_kw or {}).get('prompt', '') or '' + prompt = prompt.strip() + if not prompt: + return json.dumps({"error": "prompt 必填"}, ensure_ascii=False) + + # 停止类指令 + stop_kw = ['停止', '取消', '停下', '终止', '停', 'stop', 'cancel', 'abort'] + if prompt.strip().lower() in stop_kw: + async def _stop(): + yield json.dumps({"content": "已停止。"}, ensure_ascii=False) + '\n' + return await stream_response(request, _stop, 'text/plain; charset=utf-8') + + from pipeline_service.gateway import get_gateway + gateway = get_gateway() + + async def agent_stream(): + async for chunk in gateway.run_message("web", uid, prompt, generic=True): + data = json.loads(chunk) + t = data.get('type', '') + if t == 'tool_call': + yield json.dumps({"content": "**🔧 调用: " + data.get('tool', '') + "**\n```\n" + json.dumps(data.get('params', {}), ensure_ascii=False) + "\n```\n\n"}, ensure_ascii=False) + '\n' + elif t == 'tool_result': + yield json.dumps({"content": data.get('result', '') + "\n\n"}, ensure_ascii=False) + '\n' + elif t == 'reply': + yield json.dumps({"content": data.get('message', '')}, ensure_ascii=False) + '\n' + elif t == 'ask_user': + yield json.dumps({"content": "❓ " + data.get('message', '')}, ensure_ascii=False) + '\n' + elif t == 'error': + yield json.dumps({"error": data.get('message', '')}, ensure_ascii=False) + '\n' + else: + yield json.dumps({"content": chunk}, ensure_ascii=False) + '\n' + + return await stream_response(request, agent_stream, 'text/plain; charset=utf-8') + +return json.dumps({"error": "Unknown action: " + str(action)}, ensure_ascii=False)