fix(editor): AI composer 400, slash-menu arrows, drag handle, block outline, hint
- AI (space) -> 400 DeepSeek: fdAgent.generate now uses the clean no-tools /api/agent/generate endpoint instead of the tool-enabled conversation engine (which sends tools/tool_choice schemas DeepSeek rejects). Fixes the composer, Ask AI, AI meeting note and summarize flows. - Slash menu arrows: selection highlight was invisible on open (nothing marked), so up/down appeared dead. Call _rs() on open + after filtering, and give the selected item an accent background + left bar. Verified with jsdom harness: Down/Up move selection, Enter applies. - Block outline when selected: suppress focus rings (outline/box-shadow) on all editable blocks ([data-bid], .block-content, page title). - Drag handle (6-dot): add .block-wrapper:hover/:focus-within .block-handle so it shows on hover for normal blocks (only column-wrappers showed it before). - Empty-block hint: brighter (--text-secondary, opacity .75) so the "Press space for AI or / for commands" text is clearly visible on empty paras. - VERSION + app.main -> 5.1.3; CHANGELOG updated. - 271 tests pass; page renders 200; /api/agent/generate route registered; JS validated (node --check + jsdom).
This commit is contained in:
@@ -457,44 +457,24 @@
|
||||
self.setComposerText(t);
|
||||
setTimeout(function(){ self.send(); }, 60);
|
||||
};
|
||||
// Headless text generation (no tools) via /agent/generate — the clean
|
||||
// path used by "Ask AI" / "AI meeting note" / summarization. Sending a
|
||||
// plain write request through the tool-enabled conversation engine sends
|
||||
// a tools/tool_choice schema that some providers (e.g. DeepSeek) reject
|
||||
// with a 400. This endpoint returns {ok, text, offline, model}.
|
||||
window.fdAgent.generate = function(message, context){
|
||||
message = (message || '').trim();
|
||||
if(!message) return Promise.resolve('');
|
||||
var payload = {message: message};
|
||||
var payload = {prompt: message};
|
||||
if(context && context.trim()) payload.context = String(context).slice(0, 20000);
|
||||
return fetch('/api/agent/conversations', {
|
||||
return fetch('/api/agent/generate', {
|
||||
method:'POST', headers:{'Content-Type':'application/json'},
|
||||
body: JSON.stringify({title:'Agent'})
|
||||
}).then(function(r){ return r.json(); }).then(function(conv){
|
||||
var cid = conv && conv.id;
|
||||
if(!cid) throw new Error('Impossible de créer une conversation agent');
|
||||
return fetch('/api/agent/conversations/' + cid + '/run', {
|
||||
method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(payload)
|
||||
}).then(function(resp){
|
||||
if(!resp.ok){ return resp.json().then(function(j){ throw new Error(j.detail || ('HTTP ' + resp.status)); }); }
|
||||
var reader = resp.body.getReader();
|
||||
var dec = new TextDecoder();
|
||||
var buf = '', finalText = '', lastError = '';
|
||||
function pump(){
|
||||
return reader.read().then(function(res){
|
||||
if(res.done){ if(lastError) throw new Error(lastError); return finalText; }
|
||||
buf += dec.decode(res.value, {stream:true});
|
||||
var parts = buf.split('\n\n');
|
||||
buf = parts.pop();
|
||||
for(var i=0;i<parts.length;i++){
|
||||
var line = parts[i].replace(/^data:\s*/, '').trim();
|
||||
if(!line) continue;
|
||||
try{
|
||||
var ev = JSON.parse(line);
|
||||
if(ev.type === 'final') finalText = ev.content || '';
|
||||
else if(ev.type === 'error') lastError = ev.message || 'Erreur agent';
|
||||
}catch(e){}
|
||||
}
|
||||
return pump();
|
||||
});
|
||||
}
|
||||
return pump();
|
||||
});
|
||||
body: JSON.stringify(payload)
|
||||
}).then(function(resp){
|
||||
return resp.json();
|
||||
}).then(function(d){
|
||||
if(d && d.ok){ return d.text || ''; }
|
||||
throw new Error((d && d.error) ? d.error : 'Erreur IA');
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user