diff --git a/wwwroot/api/cockpit_chat_v2.dspy b/wwwroot/api/cockpit_chat_v2.dspy index 059de20..01e86d2 100644 --- a/wwwroot/api/cockpit_chat_v2.dspy +++ b/wwwroot/api/cockpit_chat_v2.dspy @@ -58,14 +58,18 @@ if action == 'send_message': prompt = (params_kw or {}).get('prompt', '') or msg prompt = prompt.strip() - # 处理用户上传的文件(multipart file 字段 → web_path),提取文本作为中性上下文注入 prompt + # 处理用户上传的文件(multipart file 字段 → web_path): + # 1. 抽取文本作为中性上下文注入 prompt + # 2. 收集 (绝对路径, 文件名),稍后复制进项目根目录,让会话 agent 的 read_file 能找到 file_ctx = '' + _uploads = [] # [(src_abs, filename)] _fval = (params_kw or {}).get('file') _fpaths = _fval if isinstance(_fval, list) else ([_fval] if _fval else []) for _fp in _fpaths: try: _abs = FileStorage().realPath(_fp) _name = os.path.basename(_abs) + _uploads.append((_abs, _name)) _txt = _extract_text(_abs, _name) if _txt: file_ctx += f"【文件 {_name} 内容】\n{_txt}\n\n" @@ -73,8 +77,6 @@ if action == 'send_message': file_ctx += f"【文件 {_name}】二进制文件,无法直接读取文本。\n\n" except Exception: pass - if file_ctx: - prompt = "用户本次上传了以下文件:\n\n" + file_ctx + "\n用户指令:" + prompt # 停止/暂停指令不再用硬编码关键字短路——交给 LLM 意图识别(agent system prompt 已明确: # 用户指令「暂停/停止推进」时调 pause_project)。硬编码子串匹配会把「为什么任务取消了」这类 @@ -86,6 +88,8 @@ if action == 'send_message': # ── 加载上下文 ── session_id = (params_kw or {}).get('session_id', '') ctx = {'pid': '', 'name': '', 'pipeline_id': ''} + _saved_files = [] + _pdir = '' async with DBPools().sqlorContext(dbname) as sor: ctx['pid'], _ = await get_session_context(sor, uid, session_id) if ctx['pid']: @@ -94,6 +98,17 @@ if action == 'send_message': if proj_recs: ctx['name'] = getattr(proj_recs[0], 'name', '') ctx['pipeline_id'] = getattr(proj_recs[0], 'pipeline_id', '') or '' + # ── 上传文件落盘到项目根目录(会话 agent 的 read_file 以项目目录为根)── + if _uploads: + _pdir, _ = await get_project_dir_by_id(sor, ctx['pid']) + _saved_files = copy_uploads_to_project(_pdir, _uploads) + + if file_ctx or _saved_files: + _loc = '' + if _saved_files: + _loc = "文件已保存到项目根目录(" + _pdir + "),可用 read_file 直接读取:\n" + _loc += "\n".join(" - " + n for n, _ in _saved_files) + "\n\n" + prompt = "用户本次上传了以下文件:\n" + _loc + file_ctx + "\n用户指令:" + prompt # ── 走 gateway 统一入口(Web AgentIO 通道)── # model_id:前端模型下拉选中的模型 → gateway 校验后持久化到项目(项目模型一经设置 diff --git a/wwwroot/index_cockpit.ui b/wwwroot/index_cockpit.ui index a3475af..96c2bcd 100644 --- a/wwwroot/index_cockpit.ui +++ b/wwwroot/index_cockpit.ui @@ -192,7 +192,7 @@ "event": "inputed", "actiontype": "script", "target": "self", - "script": "var ai=bricks.getWidgetById('chat_input',bricks.app);if(ai&&ai.inputw&&!ai._hooked){ai._hooked=true;ai.inputw.unbind('inputed');ai.inputw.bind('inputed',function(e){console.log('HOOKED inputed');var p=e.params.prompt||'';var mid=e.params.model_id||'';var chat=bricks.getWidgetById('chat_scroll',bricks.app);var at=null;if(chat){var ab=new bricks.HBox({width:'100%'});var am=new bricks.VBox({width:'85%',alignSelf:'flex-start',bgcolor:'#e8f0fe',borderRadius:'12px',padding:'12px 16px',marginBottom:'10px',gap:'4px'});am.add_widget(new bricks.Text({text:'Agent',cfontsize:0.75,color:'#3b82f6',fontWeight:'bold'}));at=new bricks.Text({text:'...',cfontsize:0.85,color:'#64748b'});am.add_widget(at);ab.add_widget(new bricks.Svg({rate:2,url:bricks_resource('imgs/llm.svg')}));ab.add_widget(am);ab.add_widget(new bricks.VBox({css:'filler'}));chat.add_widget(ab)}var xhr=new XMLHttpRequest();xhr.open('POST','/pipeline-sdlc/api/cockpit_chat_v2.dspy');xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var lastLen=0;xhr.onprogress=function(){var t=xhr.responseText;var d=t.substring(lastLen);lastLen=t.length;var lines=d.split(String.fromCharCode(10));for(var j=0;j