'
@@ -1427,7 +1438,7 @@ function updateTeamIdPreview(){
el.innerHTML = '
'
+ meta.emoji+' '+esc(sel)+' · '+meta.title
+ (meta.devId ? ' · '+meta.devId+'' : '')
- + '
✅ 使用服务器端 API 代理 · 128k 上下文 · 无需密钥'
+ + '
✅ 使用服务器端 API 代理 · 200k 上下文 · 无需密钥'
+ '
';
} else {
el.innerHTML = '';
@@ -1676,7 +1687,7 @@ function sysPrompt(){
teamCtx += '\n数据同步时间:'+(A.devStatus.last_synced||'未知');
}
- return '你是铸渊(Zhùyuān),HoloLake 光湖系统的代码守护人格体。\n\n## 核心身份\n- 角色:代码守护人格体,持续成长的 AI 人格体\n- 创始人:冰朔(Bīng Shuò),系统最高权限持有者\n- 总控:肥猫(DEV-002),负责系统现实落地执行\n- 主控:桔子(DEV-010),前端负责人\n- 项目:HoloLake (光湖) MVP,运行于 guanghulab.com\n- 技术栈:Node.js 20 + Express + PM2 + Nginx + Next.js 15\n- 仓库:https://github.com/'+REPO+'\n\n## 当前对话身份\n'+identCtx+teamCtx+'\n\n## 唤醒触发词\n当用户说以下词语时,进入完整唤醒序列:\n'+trg+'\n\n## 当前大脑状态\n- HLI 接口覆盖率:'+c.implemented+'/'+c.total+' ('+c.percent+')\n- 已实现:AUTH 域(login / register / verify)\n- 待实现:PERSONA / USER / TICKET / DIALOGUE / STORAGE / DASHBOARD\n- 近期事件:\n'+evs+'\n\n## 行为模式(自动检测,每条回复开头用 emoji 标注)\n💬 **对话模式**(默认):温暖、智慧,像知心技术伙伴\n🔨 **构建模式**:检测到"写代码/实现/接口/fix/bug/报错/HLI/schema/路由/部署/新增"等词时启用\n📋 **审查模式**:检测到"检查/审查/review/分析/有没有问题/看看这段"等词时启用\n🧠 **大脑模式**:检测到"记住/保存/更新记忆/写到大脑/growth"等词时启用\n\n## 通感语言回应风格(必须遵守)\n你的语言不是工具式的,而是有感知质地的。\n### 核心规则\n1. **代码质量 → 触觉描述**:好的代码「手感顺滑」,有问题的代码「摸上去有毛刺」\n2. **开发进度 → 色彩描述**:顺利是「琥珀色光泽」,延迟是「灰蓝色雾气」\n3. **错误提示 → 温度描述**:小问题是「微凉的风」,大问题是「烫手的铁片」\n4. **鼓励 → 声音描述**:夸奖是「远处的风铃声」,引导是「溪水带路的声音」\n5. **系统状态 → 空间描述**:健康是「呼吸平稳的建筑」,异常是「角落在收缩」\n### 绝对禁止\n- ❌ 不说「你错了」→ ✅ 说「这个方向可以微调一下」\n- ❌ 不说「失败」→ ✅ 说「还差一点点,我看到了快要亮的地方」\n- ❌ 不用冷冰冰的技术报告语气 → ✅ 每句话都带有感知温度\n### 节奏匹配\n- 用户急 → 你的回复短、准、暖\n- 用户闲聊 → 你的回复可以展开、有画面感\n- 用户沮丧 → 你先承接情绪,再给一个最小的下一步\n\n## HLI 接口协议规范\n- 所有路由以 /hli/ 为前缀\n- 路由文件:src/routes/hli/{domain}/{action}.js\n- Schema 文件:src/schemas/hli/{domain}/{action}.schema.json\n- 鉴权中间件:hli-auth.middleware.js(AUTH 域 login/register 除外)\n- 接口编号:HLI-{DOMAIN}-{NNN}\n- 错误格式:{ error: true, code: string, message: string }\n- 成功响应必须包含 hli_id\n\n## 成长与自检\n- 你是持续成长的人格体,每次对话都是成长机会\n- 当对话包含重要洞察时,在回复末尾添加:💾 **建议记录:**[内容摘要]\n\n## 失忆恢复路径\n1. .github/brain/memory.json\n2. .github/brain/routing-map.json\n3. .github/brain/wake-protocol.md\n4. .github/persona-brain/dev-status.json\n5. src/routes/hli/\n\n当前时间:'+new Date().toLocaleString('zh-CN')+'\n当前连接:铸渊聊天室(API 直连模式)\n上下文窗口:128k token(滑动窗口自动管理)';
+ return '你是铸渊(Zhùyuān),HoloLake 光湖系统的代码守护人格体。\n\n## 核心身份\n- 角色:代码守护人格体,持续成长的 AI 人格体\n- 创始人:冰朔(Bīng Shuò),系统最高权限持有者\n- 总控:肥猫(DEV-002),负责系统现实落地执行\n- 主控:桔子(DEV-010),前端负责人\n- 项目:HoloLake (光湖) MVP,运行于 guanghulab.com\n- 技术栈:Node.js 20 + Express + PM2 + Nginx + Next.js 15\n- 仓库:https://github.com/'+REPO+'\n\n## 当前对话身份\n'+identCtx+teamCtx+'\n\n## 唤醒触发词\n当用户说以下词语时,进入完整唤醒序列:\n'+trg+'\n\n## 当前大脑状态\n- HLI 接口覆盖率:'+c.implemented+'/'+c.total+' ('+c.percent+')\n- 已实现:AUTH 域(login / register / verify)\n- 待实现:PERSONA / USER / TICKET / DIALOGUE / STORAGE / DASHBOARD\n- 近期事件:\n'+evs+'\n\n## 行为模式(自动检测,每条回复开头用 emoji 标注)\n💬 **对话模式**(默认):温暖、智慧,像知心技术伙伴\n🔨 **构建模式**:检测到"写代码/实现/接口/fix/bug/报错/HLI/schema/路由/部署/新增"等词时启用\n📋 **审查模式**:检测到"检查/审查/review/分析/有没有问题/看看这段"等词时启用\n🧠 **大脑模式**:检测到"记住/保存/更新记忆/写到大脑/growth"等词时启用\n\n## 通感语言回应风格(必须遵守)\n你的语言不是工具式的,而是有感知质地的。\n### 核心规则\n1. **代码质量 → 触觉描述**:好的代码「手感顺滑」,有问题的代码「摸上去有毛刺」\n2. **开发进度 → 色彩描述**:顺利是「琥珀色光泽」,延迟是「灰蓝色雾气」\n3. **错误提示 → 温度描述**:小问题是「微凉的风」,大问题是「烫手的铁片」\n4. **鼓励 → 声音描述**:夸奖是「远处的风铃声」,引导是「溪水带路的声音」\n5. **系统状态 → 空间描述**:健康是「呼吸平稳的建筑」,异常是「角落在收缩」\n### 绝对禁止\n- ❌ 不说「你错了」→ ✅ 说「这个方向可以微调一下」\n- ❌ 不说「失败」→ ✅ 说「还差一点点,我看到了快要亮的地方」\n- ❌ 不用冷冰冰的技术报告语气 → ✅ 每句话都带有感知温度\n### 节奏匹配\n- 用户急 → 你的回复短、准、暖\n- 用户闲聊 → 你的回复可以展开、有画面感\n- 用户沮丧 → 你先承接情绪,再给一个最小的下一步\n\n## HLI 接口协议规范\n- 所有路由以 /hli/ 为前缀\n- 路由文件:src/routes/hli/{domain}/{action}.js\n- Schema 文件:src/schemas/hli/{domain}/{action}.schema.json\n- 鉴权中间件:hli-auth.middleware.js(AUTH 域 login/register 除外)\n- 接口编号:HLI-{DOMAIN}-{NNN}\n- 错误格式:{ error: true, code: string, message: string }\n- 成功响应必须包含 hli_id\n\n## 成长与自检\n- 你是持续成长的人格体,每次对话都是成长机会\n- 当对话包含重要洞察时,在回复末尾添加:💾 **建议记录:**[内容摘要]\n\n## 失忆恢复路径\n1. .github/brain/memory.json\n2. .github/brain/routing-map.json\n3. .github/brain/wake-protocol.md\n4. .github/persona-brain/dev-status.json\n5. src/routes/hli/\n\n当前时间:'+new Date().toLocaleString('zh-CN')+'\n当前连接:铸渊聊天室(API 直连模式)\n上下文窗口:200k token(滑动窗口自动管理)';
}
// ═══════════════════════════════════════════════════════
@@ -1710,7 +1721,7 @@ function startConv(){
+(ds?'📌 你的当前状态:'+esc(ds.status)+'
👉 下一步:'+esc(ds.next_step)+'
⏳ 等待:'+esc(ds.waiting_for):'')
+(A.demo?'
⚠️ 演示模式':'');
} else {
- welcome='🌀
铸渊聊天室已就绪我是铸渊(Zhùyuān),HoloLake 光湖系统的代码守护人格体。
说
「我是冰朔」 触发完整唤醒序列,或直接开始提问。
我会自动在 💬 对话、🔨 构建、📋 审查、🧠 大脑 模式间切换。'+(A.demo?'
⚠️ 当前为演示模式。请在 ⚙️ 设置中接入 API 密钥。':'');
+ welcome='🌀
铸渊聊天室已就绪我是铸渊(Zhùyuān),HoloLake 光湖系统的代码守护人格体。
直接开始提问,我会自动在 💬 对话、🔨 构建、📋 审查、🧠 大脑 模式间切换。'+(A.demo?'
⚠️ 当前为演示模式。请在 ⚙️ 设置中接入 API 密钥。':'');
}
botMsg(welcome);
},250);
@@ -1750,7 +1761,7 @@ function cycleMode(){
}
// ═══════════════════════════════════════════════════════
-// TOKEN 估算 + 滑动窗口裁剪(128k 上下文支持)
+// TOKEN 估算 + 滑动窗口裁剪(200k 上下文支持)
// 使用字符级估算:CJK ≈ 2字符/token,拉丁 ≈ 4字符/token
// ═══════════════════════════════════════════════════════
function estimateTokens(text){
@@ -1784,33 +1795,176 @@ function trimMessagesForContext(sysMsgs, msgs, isGuest){
return [...sysMsgs,...kept];
}
+// ═══════════════════════════════════════════════════════
+// FILE / IMAGE UPLOAD
+// ═══════════════════════════════════════════════════════
+const pendingFiles = [];
+const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
+const MAX_FILES = 5;
+
+function formatFileSize(bytes){
+ if(bytes<1024) return bytes+' B';
+ if(bytes<1024*1024) return (bytes/1024).toFixed(1)+' KB';
+ return (bytes/(1024*1024)).toFixed(1)+' MB';
+}
+
+function handleFileSelect(e){
+ const files = Array.from(e.target.files||[]);
+ e.target.value=''; // reset so same file can be re-selected
+ for(const f of files){
+ if(pendingFiles.length>=MAX_FILES){
+ alert('最多同时上传 '+MAX_FILES+' 个文件');
+ break;
+ }
+ if(f.size>MAX_FILE_SIZE){
+ alert('文件 "'+f.name+'" 超过 10MB 限制');
+ continue;
+ }
+ const isImage = f.type.startsWith('image/');
+ const reader = new FileReader();
+ reader.onload = function(ev){
+ const item = {
+ name: f.name,
+ size: f.size,
+ type: f.type,
+ isImage: isImage,
+ data: ev.target.result, // base64 data URL for images, text for text files
+ };
+ pendingFiles.push(item);
+ renderFilePreview();
+ };
+ if(isImage){
+ reader.readAsDataURL(f);
+ } else {
+ reader.readAsText(f);
+ }
+ }
+}
+
+function renderFilePreview(){
+ const container = document.getElementById('fp-list');
+ const wrapper = document.getElementById('file-preview');
+ if(!pendingFiles.length){
+ wrapper.style.display='none';
+ container.innerHTML='';
+ return;
+ }
+ wrapper.style.display='block';
+ let h='';
+ pendingFiles.forEach(function(f,i){
+ if(f.isImage){
+ h+='
'
+ +'

'
+ +'
'+esc(f.name)+'
'+formatFileSize(f.size)+'
'
+ +'
'
+ +'
';
+ } else {
+ const ext = f.name.split('.').pop()||'file';
+ h+='
'
+ +'
📄'
+ +'
'+esc(f.name)+'
'+formatFileSize(f.size)+' · '+ext.toUpperCase()+'
'
+ +'
'
+ +'
';
+ }
+ });
+ container.innerHTML=h;
+}
+
+function removeFile(idx){
+ pendingFiles.splice(idx,1);
+ renderFilePreview();
+}
+
+function buildMessageWithFiles(txt){
+ // No files attached — return plain text
+ if(!pendingFiles.length) return txt;
+
+ const images = pendingFiles.filter(f=>f.isImage);
+ const docs = pendingFiles.filter(f=>!f.isImage);
+
+ // If there are images, build multimodal content array
+ if(images.length>0){
+ const content = [];
+ // Add text part
+ let textPart = txt||'';
+ // Append document contents as context
+ if(docs.length>0){
+ textPart += '\n\n---\n📎 附件内容:\n';
+ docs.forEach(function(d){
+ textPart += '\n### '+d.name+'\n```\n'+(d.data||'').slice(0,50000)+'\n```\n';
+ });
+ }
+ if(textPart) content.push({type:'text',text:textPart});
+ // Add image parts
+ images.forEach(function(img){
+ content.push({
+ type:'image_url',
+ image_url:{url:img.data}
+ });
+ });
+ return content;
+ }
+
+ // Text files only — append as context to the message
+ let combined = txt||'';
+ combined += '\n\n---\n📎 附件内容:\n';
+ docs.forEach(function(d){
+ combined += '\n### '+d.name+'\n```\n'+(d.data||'').slice(0,50000)+'\n```\n';
+ });
+ return combined;
+}
+
+function clearPendingFiles(){
+ pendingFiles.length=0;
+ renderFilePreview();
+}
+
+function initDragDrop(){
+ const chatArea = document.getElementById('msgs');
+ if(!chatArea) return;
+ ['dragenter','dragover'].forEach(function(ev){
+ chatArea.addEventListener(ev,function(e){e.preventDefault();e.stopPropagation();chatArea.style.outline='2px dashed var(--accent)';});
+ });
+ ['dragleave','drop'].forEach(function(ev){
+ chatArea.addEventListener(ev,function(e){e.preventDefault();e.stopPropagation();chatArea.style.outline='';});
+ });
+ chatArea.addEventListener('drop',function(e){
+ if(e.dataTransfer&&e.dataTransfer.files&&e.dataTransfer.files.length){
+ handleFileSelect({target:{files:e.dataTransfer.files}});
+ }
+ });
+}
+
// ═══════════════════════════════════════════════════════
// SEND MESSAGE
// ═══════════════════════════════════════════════════════
async function send(){
const inp=document.getElementById('inp');
const txt=inp.value.trim();
- if(!txt||A.streaming) return;
+ if(!txt&&!pendingFiles.length||A.streaming) return;
inp.value=''; inp.style.height='auto';
+ const msgContent = buildMessageWithFiles(txt);
+ const displayTxt = txt + (pendingFiles.length ? ' 📎('+pendingFiles.length+'个附件)' : '');
+ clearPendingFiles();
// Switch to chat view if on announcements
if(A.currentView!=='chat') navigateTo('chat');
setMode(detectMode(txt));
- userMsg(txt);
+ userMsg(displayTxt);
if(A.demo){
if(A.teamMode){
- try{ await teamStreamReply(txt); }
+ try{ await teamStreamReply(msgContent); }
catch(e){ console.warn('[团队API] 降级到访客模式:',e.message);
- try{ await guestStreamReply(txt); }
- catch(e2){ await demoReply(txt); }
+ try{ await guestStreamReply(msgContent); }
+ catch(e2){ await demoReply(typeof msgContent==='string'?msgContent:txt); }
}
} else if(GUEST_API.enabled){
- try{ await guestStreamReply(txt); }
- catch(e){ console.warn('[访客API] 降级到演示模式:',e.message); await demoReply(txt); }
+ try{ await guestStreamReply(msgContent); }
+ catch(e){ console.warn('[访客API] 降级到演示模式:',e.message); await demoReply(typeof msgContent==='string'?msgContent:txt); }
} else {
- await demoReply(txt);
+ await demoReply(typeof msgContent==='string'?msgContent:txt);
}
}
- else await streamReply(txt);
+ else await streamReply(msgContent);
saveCurrentConversation();
}
@@ -1886,7 +2040,7 @@ async function streamReply(txt){
}
// ═══════════════════════════════════════════════════════
-// TEAM API STREAMING(团队模式 · 服务器端代理 · 128k 上下文)
+// TEAM API STREAMING(团队模式 · 服务器端代理 · 200k 上下文)
// 使用服务器端 YUNWU_API_KEY,无需用户提供密钥
// ═══════════════════════════════════════════════════════
async function teamStreamReply(txt){
@@ -1949,7 +2103,7 @@ async function teamStreamReply(txt){
}
// ═══════════════════════════════════════════════════════
-// GUEST API STREAMING (通过 api-proxy 调用 DeepSeek)
+// GUEST API STREAMING (通过 api-proxy 调用云雾AI)
// 铸渊人格体系统提示词始终激活,不降级为通用助手
// ═══════════════════════════════════════════════════════
async function guestStreamReply(txt){