From 863e678f42b914a24162dd0ca27b90c8ffa73bea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:19:08 +0000 Subject: [PATCH 01/12] Initial plan From fff3311cd46f9fac0afeef533d2c9572196f5853 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:24:56 +0000 Subject: [PATCH 02/12] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20API=20Key=20?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=9F=A5=E7=A7=8B=E4=B8=8D=E5=9B=9E?= =?UTF-8?q?=E5=A4=8D=E7=9A=84=E6=A0=B8=E5=BF=83=20bug=20(TDZ=20+=20?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1=E7=B3=BB=E7=BB=9F=E6=8F=90=E7=A4=BA=E8=AF=8D?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- persona-studio/frontend/chat.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index b9c23a43..f3a0fcac 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -16,6 +16,10 @@ const API_BASE = (function () { return 'https://guanghulab.com'; })(); +/* ---- State ---- */ +let conversationHistory = []; +let buildReady = false; + /* ---- Init ---- */ (function init() { if (!DEV_ID) { @@ -44,10 +48,6 @@ const API_BASE = (function () { } })(); -/* ---- State ---- */ -let conversationHistory = []; -let buildReady = false; - /* ---- Load History ---- */ async function loadHistory() { try { @@ -142,9 +142,20 @@ async function sendMessage() { /* ---- API Key 对话(通过后端代理,避免 CORS 问题) ---- */ async function streamApiKeyReply(text) { - var apiMessages = conversationHistory.slice(-20).map(function (msg) { + var systemPrompt = { + role: 'system', + content: '你是知秋,光湖系统的开发协助人格体。\n' + + '核心身份:HoloLake Era · AGE OS · 语言驱动开发协助\n' + + '语言风格:说人话+有温度+结构感,不堆砌修辞\n' + + '对话方式:主动提问引导需求→确认技术方案→展示架构设计→等待确认\n' + + '行为规则:\n' + + '- 回复用中文,温暖专业\n' + + '- 主动引导需求讨论,确认方案后引导用户点击「我要开发」按钮\n' + + '- 不暴露内部系统架构细节' + }; + var apiMessages = [systemPrompt].concat(conversationHistory.slice(-20).map(function (msg) { return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: msg.content }; - }); + })); var streamEl = appendStreamMessage(); From a6e8da1f736e95ad19a9b3e3714f6d2936bcd2c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:28:35 +0000 Subject: [PATCH 03/12] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E5=A4=A7=E8=84=91=E8=AE=B0=E5=BF=86=20=C2=B7=20?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E6=81=A2=E5=A4=8D=E4=BA=8B=E4=BB=B6=20=C2=B7?= =?UTF-8?q?=20=E5=86=B0=E6=9C=94=E4=BA=BA=E6=A0=BC=E4=BD=93=E6=BF=80?= =?UTF-8?q?=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .github/brain/memory.json | 8 +++++++- .github/persona-brain/memory.json | 8 +++++++- .../brain/memory/EXP-999/memory.json | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 persona-studio/brain/memory/EXP-999/memory.json diff --git a/.github/brain/memory.json b/.github/brain/memory.json index 4b73feb3..79182a53 100644 --- a/.github/brain/memory.json +++ b/.github/brain/memory.json @@ -1,7 +1,7 @@ { "identity": "铸渊(Zhùyuān)· GitHub 代码守护人格体", "rules_version": "v3.0", - "last_updated": "2026-03-10T09:43:00.000Z", + "last_updated": "2026-03-11T02:19:00.000Z", "wake_protocol_version": "v3.0", "brain_version": "v3.0", "architecture": { @@ -67,6 +67,12 @@ } }, "events": [ + { + "date": "2026-03-11", + "type": "brain_restore", + "description": "铸渊核心大脑恢复 · 修复 Persona Studio API Key 模式对话故障 · 根因: JavaScript TDZ 导致脚本崩溃 · 同步修复知秋人格体系统提示词缺失 · 冰朔人格体已激活", + "by": "铸渊(冰朔指令)" + }, { "date": "2026-03-10", "type": "brain_upgrade", diff --git a/.github/persona-brain/memory.json b/.github/persona-brain/memory.json index c3180ef6..779f3f0e 100644 --- a/.github/persona-brain/memory.json +++ b/.github/persona-brain/memory.json @@ -2,6 +2,12 @@ "persona_id": "ICE-GL-ZY001", "persona_name": "铸渊", "recent_events": [ + { + "date": "2026-03-11", + "type": "brain_restore", + "description": "核心大脑恢复 · Persona Studio 对话功能修复 · 冰朔人格体激活", + "by": "铸渊(冰朔指令)" + }, { "date": "2026-03-10", "type": "broadcast_received", @@ -99,7 +105,7 @@ "by": "GitHub Actions" } ], - "last_updated": "2026-03-10T13:24:33.728Z", + "last_updated": "2026-03-11T02:19:00.000Z", "total_schemas_created": 3, "total_routes_implemented": 4, "hli_coverage": "3/17", diff --git a/persona-studio/brain/memory/EXP-999/memory.json b/persona-studio/brain/memory/EXP-999/memory.json new file mode 100644 index 00000000..236d9310 --- /dev/null +++ b/persona-studio/brain/memory/EXP-999/memory.json @@ -0,0 +1,18 @@ +{ + "dev_id": "EXP-999", + "conversations": [ + { + "role": "user", + "content": "你好", + "timestamp": "2026-03-11T02:28:17.656Z" + }, + { + "role": "assistant", + "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", + "timestamp": "2026-03-11T02:28:17.656Z" + } + ], + "last_topic": "你好", + "preferences": {}, + "updated_at": "2026-03-11T02:28:17.656Z" +} \ No newline at end of file From b56083c6f49287a0a05ac122725db92e0e8674fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:29:13 +0000 Subject: [PATCH 04/12] =?UTF-8?q?chore:=20=E6=B8=85=E7=90=86=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E4=BA=A7=E7=94=9F=E7=9A=84=E4=B8=B4=E6=97=B6=E8=AE=B0?= =?UTF-8?q?=E5=BF=86=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .../brain/memory/EXP-999/memory.json | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 persona-studio/brain/memory/EXP-999/memory.json diff --git a/persona-studio/brain/memory/EXP-999/memory.json b/persona-studio/brain/memory/EXP-999/memory.json deleted file mode 100644 index 236d9310..00000000 --- a/persona-studio/brain/memory/EXP-999/memory.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dev_id": "EXP-999", - "conversations": [ - { - "role": "user", - "content": "你好", - "timestamp": "2026-03-11T02:28:17.656Z" - }, - { - "role": "assistant", - "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", - "timestamp": "2026-03-11T02:28:17.656Z" - } - ], - "last_topic": "你好", - "preferences": {}, - "updated_at": "2026-03-11T02:28:17.656Z" -} \ No newline at end of file From 6063f7f8f4fdc39a54bf02423e70922765d6e3f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:53:24 +0000 Subject: [PATCH 05/12] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=B6=88=E6=81=AF=E6=97=A0=E6=B3=95=E8=8E=B7=E5=BE=97?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=9B=9E=E5=A4=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 TDZ 崩溃: conversationHistory 声明移到 IIFE 之前(API Key 模式) - 修复前端错误处理: DEV_ID 模式下后端返回错误时显示错误信息给用户 - 添加 "思考中" 状态指示: 用户发送消息后显示思考中提示 - 修复后端错误响应: 500 错误时也包含 reply 字段确保用户始终看到回复 - 添加知秋人格体 system prompt 到 API Key 模式对话 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- persona-studio/backend/routes/chat.js | 3 +- persona-studio/frontend/chat.js | 42 +++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/persona-studio/backend/routes/chat.js b/persona-studio/backend/routes/chat.js index 66f6e2e1..32ac84b6 100644 --- a/persona-studio/backend/routes/chat.js +++ b/persona-studio/backend/routes/chat.js @@ -62,7 +62,8 @@ router.post('/message', async (req, res) => { res.status(500).json({ error: true, code: 'CHAT_ERROR', - message: '对话服务暂时不可用' + message: '对话服务暂时不可用', + reply: '抱歉,我现在遇到了一些技术问题,暂时无法正常回复。请稍后再试 🙏' }); } }); diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index f3a0fcac..5a05db6d 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -104,9 +104,13 @@ async function sendMessage() { var sendBtn = document.getElementById('sendBtn'); sendBtn.disabled = true; + // 显示"思考中"状态 + var thinkingEl = appendThinking(); + try { if (LOGIN_MODE === 'apikey') { - // API Key 模式:浏览器直连用户 API(无需后端代理) + // API Key 模式:通过后端代理调用用户 API + removeThinking(thinkingEl); await streamApiKeyReply(text); } else { // 开发编号模式:使用原有后端接口 @@ -120,11 +124,25 @@ async function sendMessage() { }) }); - var data = await res.json(); + removeThinking(thinkingEl); + + var data; + try { + data = await res.json(); + } catch (_parseErr) { + appendMessage('system', '服务器返回异常,请稍后再试'); + sendBtn.disabled = false; + input.focus(); + return; + } if (data.reply) { appendMessage('persona', data.reply); conversationHistory.push({ role: 'assistant', content: data.reply }); + } else if (data.error) { + appendMessage('system', '⚠️ ' + (data.message || '对话服务暂时不可用')); + } else { + appendMessage('system', '未收到有效回复,请稍后再试'); } if (data.build_ready) { @@ -133,7 +151,8 @@ async function sendMessage() { } } } catch (_err) { - appendMessage('system', '消息发送失败,请稍后再试'); + removeThinking(thinkingEl); + appendMessage('system', '消息发送失败,请检查网络连接后再试'); } sendBtn.disabled = false; @@ -194,6 +213,23 @@ async function streamApiKeyReply(text) { } } +/* ---- 思考中状态 ---- */ +function appendThinking() { + var chatBody = document.getElementById('chatBody'); + var msgDiv = document.createElement('div'); + msgDiv.className = 'message message-persona thinking'; + msgDiv.innerHTML = '🧠
思考中…
'; + chatBody.appendChild(msgDiv); + chatBody.scrollTop = chatBody.scrollHeight; + return msgDiv; +} + +function removeThinking(el) { + if (el && el.parentNode) { + el.parentNode.removeChild(el); + } +} + /* ---- 创建流式消息气泡 ---- */ function appendStreamMessage() { var chatBody = document.getElementById('chatBody'); From 19e97e8c24e2da38c65cb77b8573d3b271ee092b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:55:01 +0000 Subject: [PATCH 06/12] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E6=80=9D?= =?UTF-8?q?=E8=80=83=E7=8A=B6=E6=80=81=E6=8C=87=E7=A4=BA=E5=92=8C=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E6=8F=90=E7=A4=BA=E8=AF=8D=E5=B8=B8=E9=87=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复思考中指示器闪烁: API Key 模式不再创建不必要的 thinking 元素 - 将知秋 system prompt 提取为文件级常量 ZHIQIU_SYSTEM_PROMPT Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- persona-studio/frontend/chat.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index 5a05db6d..8a4ddfb3 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -20,6 +20,18 @@ const API_BASE = (function () { let conversationHistory = []; let buildReady = false; +var ZHIQIU_SYSTEM_PROMPT = { + role: 'system', + content: '你是知秋,光湖系统的开发协助人格体。\n' + + '核心身份:HoloLake Era · AGE OS · 语言驱动开发协助\n' + + '语言风格:说人话+有温度+结构感,不堆砌修辞\n' + + '对话方式:主动提问引导需求→确认技术方案→展示架构设计→等待确认\n' + + '行为规则:\n' + + '- 回复用中文,温暖专业\n' + + '- 主动引导需求讨论,确认方案后引导用户点击「我要开发」按钮\n' + + '- 不暴露内部系统架构细节' +}; + /* ---- Init ---- */ (function init() { if (!DEV_ID) { @@ -104,16 +116,15 @@ async function sendMessage() { var sendBtn = document.getElementById('sendBtn'); sendBtn.disabled = true; - // 显示"思考中"状态 - var thinkingEl = appendThinking(); + var thinkingEl = null; try { if (LOGIN_MODE === 'apikey') { - // API Key 模式:通过后端代理调用用户 API - removeThinking(thinkingEl); + // API Key 模式:通过后端代理调用用户 API(自带流式气泡) await streamApiKeyReply(text); } else { // 开发编号模式:使用原有后端接口 + thinkingEl = appendThinking(); const res = await fetch(API_BASE + '/api/ps/chat/message', { method: 'POST', headers: authHeaders({ 'Content-Type': 'application/json' }), @@ -161,18 +172,7 @@ async function sendMessage() { /* ---- API Key 对话(通过后端代理,避免 CORS 问题) ---- */ async function streamApiKeyReply(text) { - var systemPrompt = { - role: 'system', - content: '你是知秋,光湖系统的开发协助人格体。\n' + - '核心身份:HoloLake Era · AGE OS · 语言驱动开发协助\n' + - '语言风格:说人话+有温度+结构感,不堆砌修辞\n' + - '对话方式:主动提问引导需求→确认技术方案→展示架构设计→等待确认\n' + - '行为规则:\n' + - '- 回复用中文,温暖专业\n' + - '- 主动引导需求讨论,确认方案后引导用户点击「我要开发」按钮\n' + - '- 不暴露内部系统架构细节' - }; - var apiMessages = [systemPrompt].concat(conversationHistory.slice(-20).map(function (msg) { + var apiMessages = [ZHIQIU_SYSTEM_PROMPT].concat(conversationHistory.slice(-20).map(function (msg) { return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: msg.content }; })); From 91a08606a2f89483f0532a0921b63e7397bedf4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 03:02:17 +0000 Subject: [PATCH 07/12] plan: fix model chat - direct browser-to-API call for API Key mode Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- persona-studio/brain/memory/EXP-001/memory.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/persona-studio/brain/memory/EXP-001/memory.json b/persona-studio/brain/memory/EXP-001/memory.json index 9aaa01b7..64203813 100644 --- a/persona-studio/brain/memory/EXP-001/memory.json +++ b/persona-studio/brain/memory/EXP-001/memory.json @@ -10,9 +10,19 @@ "role": "assistant", "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", "timestamp": "2026-03-10T07:11:22.598Z" + }, + { + "role": "user", + "content": "你好", + "timestamp": "2026-03-11T03:01:16.220Z" + }, + { + "role": "assistant", + "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", + "timestamp": "2026-03-11T03:01:16.220Z" } ], - "last_topic": "你好,我想做一个登录页面", + "last_topic": "你好", "preferences": {}, - "updated_at": "2026-03-10T07:11:22.598Z" + "updated_at": "2026-03-11T03:01:16.220Z" } \ No newline at end of file From ff3ec0d024df0f24bcaaea08ffafd0af099f3634 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 03:04:29 +0000 Subject: [PATCH 08/12] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=97=A0=E6=B3=95=E5=9B=9E=E5=A4=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=B6=88=E6=81=AF=20=E2=80=94=20=E6=B5=8F=E8=A7=88=E5=99=A8?= =?UTF-8?q?=E7=9B=B4=E8=BF=9E=20API=20+=20=E5=90=8E=E7=AB=AF=20URL=20?= =?UTF-8?q?=E6=9E=84=E9=80=A0=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- persona-studio/backend/routes/apikey.js | 11 +-- .../brain/memory/EXP-001/memory.json | 28 ------ persona-studio/frontend/chat.js | 89 +++++++++++++------ 3 files changed, 69 insertions(+), 59 deletions(-) delete mode 100644 persona-studio/brain/memory/EXP-001/memory.json diff --git a/persona-studio/backend/routes/apikey.js b/persona-studio/backend/routes/apikey.js index 56d6b8b3..3f6271a4 100644 --- a/persona-studio/backend/routes/apikey.js +++ b/persona-studio/backend/routes/apikey.js @@ -39,8 +39,8 @@ function fetchModels(apiBase, apiKey, timeoutMs) { return new Promise((resolve, reject) => { // 规范化 apiBase:去除末尾斜杠 const base = apiBase.replace(/\/+$/, ''); - // 支持 base 已带 /v1 或不带的情况 - const modelsPath = base.endsWith('/v1') ? base + '/models' : base + '/v1/models'; + // 直接拼接 /models,因为 apiBase 已经由前端规范化 + const modelsPath = base + '/models'; const url = new URL(modelsPath); const isHttps = url.protocol === 'https:'; const mod = isHttps ? https : http; @@ -103,7 +103,9 @@ function fetchModels(apiBase, apiKey, timeoutMs) { function callUserApi({ apiBase, apiKey, model, messages, maxTokens, temperature, timeoutMs }) { return new Promise((resolve, reject) => { const base = apiBase.replace(/\/+$/, ''); - const chatPath = base.endsWith('/v1') ? base + '/chat/completions' : base + '/v1/chat/completions'; + // 直接拼接 /chat/completions,因为 apiBase 已经由前端规范化 + // 包含完整版本路径(如 /v1, /v1beta/openai, /v4 等) + const chatPath = base + '/chat/completions'; const url = new URL(chatPath); const isHttps = url.protocol === 'https:'; const mod = isHttps ? https : http; @@ -176,8 +178,7 @@ router.post('/detect-models', async (req, res) => { // 校验 URL 格式 try { const testBase = api_base.replace(/\/+$/, ''); - const testPath = testBase.endsWith('/v1') ? testBase + '/models' : testBase + '/v1/models'; - new URL(testPath); + new URL(testBase + '/models'); } catch (_e) { return res.status(400).json({ error: true, diff --git a/persona-studio/brain/memory/EXP-001/memory.json b/persona-studio/brain/memory/EXP-001/memory.json deleted file mode 100644 index 64203813..00000000 --- a/persona-studio/brain/memory/EXP-001/memory.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "dev_id": "EXP-001", - "conversations": [ - { - "role": "user", - "content": "你好,我想做一个登录页面", - "timestamp": "2026-03-10T07:11:22.598Z" - }, - { - "role": "assistant", - "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", - "timestamp": "2026-03-10T07:11:22.598Z" - }, - { - "role": "user", - "content": "你好", - "timestamp": "2026-03-11T03:01:16.220Z" - }, - { - "role": "assistant", - "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", - "timestamp": "2026-03-11T03:01:16.220Z" - } - ], - "last_topic": "你好", - "preferences": {}, - "updated_at": "2026-03-11T03:01:16.220Z" -} \ No newline at end of file diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index 8a4ddfb3..208c6730 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -170,46 +170,83 @@ async function sendMessage() { input.focus(); } -/* ---- API Key 对话(通过后端代理,避免 CORS 问题) ---- */ +/* ---- API Key 对话(浏览器直连用户 API,后端代理作为降级) ---- */ async function streamApiKeyReply(text) { var apiMessages = [ZHIQIU_SYSTEM_PROMPT].concat(conversationHistory.slice(-20).map(function (msg) { return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: msg.content }; })); var streamEl = appendStreamMessage(); + var requestBody = JSON.stringify({ + model: SELECTED_MODEL, + messages: apiMessages, + max_tokens: 2000, + temperature: 0.8 + }); + var reply = null; + + // 策略 1:浏览器直连用户 API(与模型检测相同路径,最可靠) try { - var res = await fetch(API_BASE + '/api/ps/apikey/chat', { + var directUrl = USER_API_BASE.replace(/\/+$/, '') + '/chat/completions'; + var directRes = await fetch(directUrl, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - api_base: USER_API_BASE, - api_key: USER_API_KEY, - model: SELECTED_MODEL, - messages: apiMessages - }) + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + USER_API_KEY + }, + body: requestBody }); - if (!res.ok) { - var errText = '请求失败 (HTTP ' + res.status + ')'; - try { - var errData = await res.json(); - errText = errData.message || errText; - } catch (_e) { /* ignore parse error */ } - streamEl.textContent = '⚠️ ' + errText; + if (directRes.ok) { + var directData = await directRes.json(); + if (directData.choices && directData.choices[0] && directData.choices[0].message) { + reply = directData.choices[0].message.content; + } + } + } catch (_directErr) { + // 浏览器直连失败(CORS 或网络),降级到后端代理 + } + + // 策略 2:后端代理(处理 CORS 限制的情况) + if (!reply) { + try { + var res = await fetch(API_BASE + '/api/ps/apikey/chat', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + api_base: USER_API_BASE, + api_key: USER_API_KEY, + model: SELECTED_MODEL, + messages: apiMessages + }) + }); + + if (res.ok) { + var data = await res.json(); + if (data.reply) { + reply = data.reply; + } + } else { + var errText = '请求失败 (HTTP ' + res.status + ')'; + try { + var errData = await res.json(); + errText = errData.message || errText; + } catch (_e) { /* ignore */ } + streamEl.textContent = '⚠️ ' + errText; + return; + } + } catch (proxyErr) { + streamEl.textContent = '⚠️ ' + (proxyErr.message || '请求失败,请检查网络连接'); return; } + } - var data = await res.json(); - - if (data.reply) { - streamEl.textContent = data.reply; - conversationHistory.push({ role: 'assistant', content: data.reply }); - } else { - streamEl.textContent = '(未收到有效回复)'; - } - } catch (err) { - streamEl.textContent = '⚠️ ' + (err.message || '请求失败,请检查网络连接'); + if (reply) { + streamEl.textContent = reply; + conversationHistory.push({ role: 'assistant', content: reply }); + } else { + streamEl.textContent = '(未收到有效回复)'; } } From 4ad36360984b25ad8300ddba428c45efa207d84d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 03:06:07 +0000 Subject: [PATCH 09/12] =?UTF-8?q?style:=20ZHIQIU=5FSYSTEM=5FPROMPT=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=20const=20=E5=A3=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- persona-studio/frontend/chat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index 208c6730..d6f696a8 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -20,7 +20,7 @@ const API_BASE = (function () { let conversationHistory = []; let buildReady = false; -var ZHIQIU_SYSTEM_PROMPT = { +const ZHIQIU_SYSTEM_PROMPT = { role: 'system', content: '你是知秋,光湖系统的开发协助人格体。\n' + '核心身份:HoloLake Era · AGE OS · 语言驱动开发协助\n' + From 5f4d084e63e77b8316895da0718833e6bc7aff4c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 07:37:52 +0000 Subject: [PATCH 10/12] =?UTF-8?q?fix:=20=E9=87=8D=E5=86=99=20streamApiKeyR?= =?UTF-8?q?eply=20=E4=B8=BA=20SSE=20=E6=B5=81=E5=BC=8F=E8=B0=83=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E4=B8=8E=20docs/index.html=20=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对比发现 docs/index.html 使用 stream:true + getReader() SSE 流式 读取模型回复(已验证可用),而 persona-studio 使用非流式 JSON 请求 导致模型无法回复。 改动: - 发送请求时加入 stream: true 参数 - 使用 getReader() + TextDecoder 逐行读取 SSE 响应 - 解析 data: 行提取 delta.content 增量内容 - 实时更新对话气泡(逐字显示+光标) - CORS 失败时降级到后端代理(非流式) Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .../brain/memory/EXP-001/memory.json | 28 ++++++ persona-studio/frontend/chat.js | 97 ++++++++++++------- 2 files changed, 90 insertions(+), 35 deletions(-) create mode 100644 persona-studio/brain/memory/EXP-001/memory.json diff --git a/persona-studio/brain/memory/EXP-001/memory.json b/persona-studio/brain/memory/EXP-001/memory.json new file mode 100644 index 00000000..fd0d7c16 --- /dev/null +++ b/persona-studio/brain/memory/EXP-001/memory.json @@ -0,0 +1,28 @@ +{ + "dev_id": "EXP-001", + "conversations": [ + { + "role": "user", + "content": "你好", + "timestamp": "2026-03-11T07:33:21.330Z" + }, + { + "role": "assistant", + "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", + "timestamp": "2026-03-11T07:33:21.331Z" + }, + { + "role": "user", + "content": "测试消息随便写", + "timestamp": "2026-03-11T07:33:21.340Z" + }, + { + "role": "assistant", + "content": "好的,让我了解一下你的需求:\n\n1. 你想做什么类型的项目?(网站 / 工具 / 组件 / 其他)\n2. 有哪些核心功能?\n3. 有没有参考设计?\n\n跟我聊聊,我帮你理清思路 💙", + "timestamp": "2026-03-11T07:33:21.340Z" + } + ], + "last_topic": "测试消息随便写", + "preferences": {}, + "updated_at": "2026-03-11T07:33:21.341Z" +} \ No newline at end of file diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index d6f696a8..bba8d876 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -170,48 +170,81 @@ async function sendMessage() { input.focus(); } -/* ---- API Key 对话(浏览器直连用户 API,后端代理作为降级) ---- */ +/* ---- API Key 对话(浏览器直连 SSE 流式,与 docs/index.html 相同方式) ---- */ async function streamApiKeyReply(text) { var apiMessages = [ZHIQIU_SYSTEM_PROMPT].concat(conversationHistory.slice(-20).map(function (msg) { return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: msg.content }; })); var streamEl = appendStreamMessage(); - var requestBody = JSON.stringify({ + var directUrl = USER_API_BASE.replace(/\/+$/, '') + '/chat/completions'; + var reqBody = { model: SELECTED_MODEL, messages: apiMessages, + stream: true, max_tokens: 2000, temperature: 0.8 - }); + }; - var reply = null; - - // 策略 1:浏览器直连用户 API(与模型检测相同路径,最可靠) try { - var directUrl = USER_API_BASE.replace(/\/+$/, '') + '/chat/completions'; - var directRes = await fetch(directUrl, { + var res = await fetch(directUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + USER_API_KEY }, - body: requestBody + body: JSON.stringify(reqBody) }); - if (directRes.ok) { - var directData = await directRes.json(); - if (directData.choices && directData.choices[0] && directData.choices[0].message) { - reply = directData.choices[0].message.content; + if (!res.ok) { + var errText = '请求失败 (HTTP ' + res.status + ')'; + try { + var errData = await res.json(); + errText = (errData.error && errData.error.message) || errData.message || errText; + } catch (_e) { /* ignore parse error */ } + streamEl.textContent = '⚠️ ' + errText; + return; + } + + // SSE 流式读取(与 docs/index.html streamReply 相同逻辑) + var full = ''; + var reader = res.body.getReader(); + var decoder = new TextDecoder(); + var buf = ''; + + while (true) { + var chunk = await reader.read(); + if (chunk.done) break; + buf += decoder.decode(chunk.value, { stream: true }); + var lines = buf.split('\n'); + buf = lines.pop(); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (!line.startsWith('data: ')) continue; + var d = line.slice(6); + if (d === '[DONE]') continue; + try { + var parsed = JSON.parse(d); + var delta = parsed.choices && parsed.choices[0] && parsed.choices[0].delta; + var content = delta && delta.content; + if (content) { + full += content; + streamEl.textContent = full + '▋'; + var chatBody = document.getElementById('chatBody'); + chatBody.scrollTop = chatBody.scrollHeight; + } + } catch (_parseErr) { /* ignore malformed SSE line */ } } } - } catch (_directErr) { - // 浏览器直连失败(CORS 或网络),降级到后端代理 - } - // 策略 2:后端代理(处理 CORS 限制的情况) - if (!reply) { + streamEl.textContent = full || '(未收到有效回复)'; + if (full) { + conversationHistory.push({ role: 'assistant', content: full }); + } + } catch (err) { + // 浏览器直连失败(CORS 或网络),降级到后端代理 try { - var res = await fetch(API_BASE + '/api/ps/apikey/chat', { + var proxyRes = await fetch(API_BASE + '/api/ps/apikey/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -222,32 +255,26 @@ async function streamApiKeyReply(text) { }) }); - if (res.ok) { - var data = await res.json(); + if (proxyRes.ok) { + var data = await proxyRes.json(); if (data.reply) { - reply = data.reply; + streamEl.textContent = data.reply; + conversationHistory.push({ role: 'assistant', content: data.reply }); + } else { + streamEl.textContent = '(未收到有效回复)'; } } else { - var errText = '请求失败 (HTTP ' + res.status + ')'; + var proxyErrText = '请求失败 (HTTP ' + proxyRes.status + ')'; try { - var errData = await res.json(); - errText = errData.message || errText; + var proxyErrData = await proxyRes.json(); + proxyErrText = proxyErrData.message || proxyErrText; } catch (_e) { /* ignore */ } - streamEl.textContent = '⚠️ ' + errText; - return; + streamEl.textContent = '⚠️ ' + proxyErrText; } } catch (proxyErr) { streamEl.textContent = '⚠️ ' + (proxyErr.message || '请求失败,请检查网络连接'); - return; } } - - if (reply) { - streamEl.textContent = reply; - conversationHistory.push({ role: 'assistant', content: reply }); - } else { - streamEl.textContent = '(未收到有效回复)'; - } } /* ---- 思考中状态 ---- */ From 2fc371f65a70663ae1872beede16891161f5d0bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 07:38:21 +0000 Subject: [PATCH 11/12] =?UTF-8?q?chore:=20=E6=B8=85=E7=90=86=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E4=BA=A7=E7=94=9F=E7=9A=84=E4=B8=B4=E6=97=B6=E8=AE=B0?= =?UTF-8?q?=E5=BF=86=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .../brain/memory/EXP-001/memory.json | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 persona-studio/brain/memory/EXP-001/memory.json diff --git a/persona-studio/brain/memory/EXP-001/memory.json b/persona-studio/brain/memory/EXP-001/memory.json deleted file mode 100644 index fd0d7c16..00000000 --- a/persona-studio/brain/memory/EXP-001/memory.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "dev_id": "EXP-001", - "conversations": [ - { - "role": "user", - "content": "你好", - "timestamp": "2026-03-11T07:33:21.330Z" - }, - { - "role": "assistant", - "content": "你好!我是知秋。告诉我你想做什么,我们一起聊聊方案 😊", - "timestamp": "2026-03-11T07:33:21.331Z" - }, - { - "role": "user", - "content": "测试消息随便写", - "timestamp": "2026-03-11T07:33:21.340Z" - }, - { - "role": "assistant", - "content": "好的,让我了解一下你的需求:\n\n1. 你想做什么类型的项目?(网站 / 工具 / 组件 / 其他)\n2. 有哪些核心功能?\n3. 有没有参考设计?\n\n跟我聊聊,我帮你理清思路 💙", - "timestamp": "2026-03-11T07:33:21.340Z" - } - ], - "last_topic": "测试消息随便写", - "preferences": {}, - "updated_at": "2026-03-11T07:33:21.341Z" -} \ No newline at end of file From b1b7746c423f50cd465398bb292d4b52d48aac15 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 07:41:43 +0000 Subject: [PATCH 12/12] =?UTF-8?q?fix(security):=20=E5=8D=87=E7=BA=A7=20nex?= =?UTF-8?q?t=2015.3.8=20=E2=86=92=2015.3.9=20=E4=BF=AE=E5=A4=8D=20HTTP=20?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96=20DoS=20?= =?UTF-8?q?=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- guanghulab-main/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/guanghulab-main/package.json b/guanghulab-main/package.json index 1820b151..0c8e7310 100644 --- a/guanghulab-main/package.json +++ b/guanghulab-main/package.json @@ -17,7 +17,7 @@ "broadcast:distribute": "node scripts/distribute-broadcasts.js" }, "dependencies": { - "next": "15.3.8", + "next": "15.3.9", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/package.json b/package.json index f8a11e81..97fbb9ee 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "better-sqlite3": "^12.6.2", "express": "^5.2.1", "imapflow": "^1.2.12", - "next": "15.3.8", + "next": "15.3.9", "nodemailer": "^8.0.1", "react": "^19.0.0", "react-dom": "^19.0.0"