frontend: intercept AgentIO.inputw in project_form.changed, XHR splits on 0x0a

Backend: untouched (sends 0x0a newlines)
Frontend: on project_form.changed, unbind AgentIO's native inputed, rebind with custom XHR that sends url-encoded body and parses 0x0a-separated NDJSON
This commit is contained in:
ymq 2026-08-08 22:08:55 +08:00
parent 75dff51764
commit e2291b7735
2 changed files with 5 additions and 5 deletions

View File

@ -211,7 +211,7 @@ if action == 'send_message':
ctx = await _load_ctx(sor, uid)
model = await _sel_model(sor, user_model_id)
if not model:
d = json.dumps({"error": "没有可用的LLM模型配置"}, ensure_ascii=False)+'\\n'
d = json.dumps({"error": "没有可用的LLM模型配置"}, ensure_ascii=False)+'\n'
debug(f"YIELD error: {d[:80]}")
yield d
return
@ -234,12 +234,12 @@ if action == 'send_message':
if act.get('action') == 'tool_call':
tool = act.get('tool','')
label = _tool_labels.get(tool,tool)
d = json.dumps({"content": f"🔄 {label}..."}, ensure_ascii=False)+'\\n'
d = json.dumps({"content": f"🔄 {label}..."}, ensure_ascii=False)+'\n'
debug(f"YIELD progress: {d[:60]}")
yield d
result = await _exec_tool(sor, tool, act.get('params',{}), ctx, uid, org_id)
ok = result.startswith("OK:")
d = json.dumps({"content": f"{'✅' if ok else '❌'} {label}: {result}"}, ensure_ascii=False)+'\\n'
d = json.dumps({"content": f"{'✅' if ok else '❌'} {label}: {result}"}, ensure_ascii=False)+'\n'
debug(f"YIELD result: {d[:60]}")
yield d
msgs.append({"role":"assistant","content":raw})
@ -248,7 +248,7 @@ if action == 'send_message':
agent_reply = raw; break
if not agent_reply: agent_reply = "处理超时"
d = json.dumps({"content": agent_reply}, ensure_ascii=False)+'\\n'
d = json.dumps({"content": agent_reply}, ensure_ascii=False)+'\n'
debug(f"YIELD final: {d[:60]}")
yield d
await sor.C('pipeline_conversations',{'id':getID(),'role':'agent','content':agent_reply,'msg_type':'text','org_id':org_id,'created_by':'system'})

View File

@ -192,7 +192,7 @@
"event": "inputed",
"actiontype": "script",
"target": "self",
"script": "console.log('BIND inputed fired, params:',params);var p=params.prompt;var mid=params.model_id||'';if(typeof mid==='object'&&mid!==null)mid=mid.model_id||'';var ctx=bricks.getWidgetById('context_data',bricks.app);var cd=ctx?ctx.getValue():{};var iid=cd.iteration_id||'';var pid=cd.project_id||'';var fnames=params.file_names||[];var chat=bricks.getWidgetById('chat_scroll',bricks.app);var at=null;var _makeWidget=function(desc){if(!desc||!desc.widgettype)return null;var Klass=bricks.Factory.get(desc.widgettype);if(!Klass)return null;var opts=JSON.parse(JSON.stringify(desc.options||{}));if(desc.subwidgets&&desc.subwidgets.length>0){opts.subwidgets=desc.subwidgets.map(function(s){return _makeWidget(s)}).filter(function(s){return s!==null})}return new Klass(opts)};if(chat){var ub=new bricks.HBox({width:'100%'});var um=new bricks.VBox({width:'85%',alignSelf:'flex-end',bgcolor:'#dbeafe',borderRadius:'12px',padding:'12px 16px',marginBottom:'10px',gap:'4px'});um.add_widget(new bricks.Text({text:'你',cfontsize:0.75,color:'#2563eb',fontWeight:'bold'}));um.add_widget(new bricks.Text({text:p,cfontsize:0.95,color:'#1e293b',whiteSpace:'pre-wrap'}));for(var i=0;i<fnames.length;i++){var fn=fnames[i];var fl=new bricks.Text({text:'📎 '+fn,cfontsize:0.75,color:'#3b82f6',css:'file-tag',style:{background:'#eff6ff',padding:'2px 8px',borderRadius:'4px',display:'inline-block',marginTop:'4px'}});um.add_widget(fl)}ub.add_widget(new bricks.VBox({css:'filler'}));ub.add_widget(um);ub.add_widget(new bricks.Svg({rate:2,url:bricks_resource('imgs/chat-user.svg')}));chat.add_widget(ub);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);}"
"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.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<lines.length;j++){var line=lines[j].trim();if(!line)continue;try{var obj=JSON.parse(line);if(obj.content&&at){var pw=at.parent();if(pw){pw.remove_widget(at);at=null}var tw=new bricks.Text({text:obj.content,cfontsize:0.85,color:'#334155',whiteSpace:'pre-wrap',width:'100%'});pw.add_widget(tw);chat.scrollToBottom()}}catch(e){console.log(e)}}};xhr.onload=function(){var s=bricks.getWidgetById('stats_row',bricks.app);if(s)s.render({})};xhr.onerror=function(){if(at)at.set_text('网络错误')};xhr.send('message_text='+encodeURIComponent(p)+'&model_id='+encodeURIComponent(mid))})}"
}
]
}