feat: v6.6.0 — Agent phase 5 : API publique agent (/api/v2/agents, run synchrone JSON) + marketplace skills (export/import portable + galerie de 6 presets, palette / du panneau) + webhooks agent.run.started/failed · 764 tests verts
This commit is contained in:
@@ -500,7 +500,7 @@
|
||||
allProviders: [], providers: [], providerModels: [], llmProvider: 'offline',
|
||||
llmModel: '', llmKeys: [], defaultProvider: 'offline',
|
||||
activeContext: null, ctxPinnedKey: null,
|
||||
contextChips: [], skills: [],
|
||||
contextChips: [], skills: [], gallery: [],
|
||||
mentionOpen: false, mentionItems: [], mentionQuery: '', mentionLoad: false,
|
||||
mentionFocus: -1, _mentionFrom: null, _mentionTimer: null, _atNode: null,
|
||||
cmdFocus: -1, slashDismiss: false,
|
||||
@@ -811,6 +811,42 @@
|
||||
fetch('/api/agent/skills').then(function(r){return r.json()}).then(function(d){
|
||||
self.skills = d.skills || [];
|
||||
}).catch(function(){ self.skills = []; });
|
||||
// Galerie de skills (marketplace, v6.6.0) — presets installables en 1 clic.
|
||||
fetch('/api/agent/skills/gallery').then(function(r){return r.json()}).then(function(d){
|
||||
var installed = {};
|
||||
(self.skills || []).forEach(function(s){ installed[String(s.name).toLowerCase()] = true; });
|
||||
self.gallery = (d.gallery || []).filter(function(g){
|
||||
return !installed[String(g.name).toLowerCase()];
|
||||
});
|
||||
}).catch(function(){ self.gallery = []; });
|
||||
},
|
||||
// Installe un preset de galerie puis l'épingle au contexte (phase 5).
|
||||
installGallerySkill(slug, icon, name){
|
||||
var self = this;
|
||||
fetch('/api/agent/skills/gallery/' + encodeURIComponent(slug) + '/install', {
|
||||
method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{}'
|
||||
}).then(function(r){
|
||||
return r.json().then(function(d){ return {ok: r.ok, d: d}; });
|
||||
}).then(function(res){
|
||||
if(!res.ok){
|
||||
self.toast((res.d && res.d.detail) || 'Installation impossible.', true);
|
||||
return;
|
||||
}
|
||||
self.toast('Skill « ' + (res.d.name || name || slug) + ' » installée.');
|
||||
self.fetchSkills();
|
||||
self._pinDbSkill(res.d.id, res.d.name || name || slug, res.d.icon || icon || '📦');
|
||||
}).catch(function(){ self.toast('Installation impossible (réseau).', true); });
|
||||
},
|
||||
// Épingle un skill enregistré (id DB) dans les chips de contexte.
|
||||
_pinDbSkill(id, name, icon){
|
||||
var exists = this.contextChips.some(function(ch){ return ch.kind === 'skill' && ch.skillId === id; });
|
||||
if(exists){ this.toast('Ce skill est déjà épinglé au contexte.'); return; }
|
||||
var pin = {key:'skill-'+id, kind:'skill', icon: icon || '✨',
|
||||
label: String(name || '').replace(/^\//, ''), token:'skill:'+id, skillId:id};
|
||||
this.contextChips.push(pin);
|
||||
this.clearComposer();
|
||||
this._insertToken({token:pin.token, label:pin.label, icon:pin.icon, kind:'skill'});
|
||||
this.toast('Skill épinglé — décrivez votre demande, il sera appliqué à l\u2019envoi.');
|
||||
},
|
||||
loadConversations(){
|
||||
var self = this;
|
||||
@@ -1254,7 +1290,11 @@
|
||||
items.forEach(function(o){ o._i = seq++; out.push(o); });
|
||||
}
|
||||
var skillsPresent = false, admPresent = false;
|
||||
var built = [], dbs = [], adm = [];
|
||||
var built = [], dbs = [], adm = [], gal = [];
|
||||
var installedNames = {};
|
||||
for(var j=0;j<(this.skills||[]).length;j++){
|
||||
installedNames[String(this.skills[j].name).toLowerCase()] = true;
|
||||
}
|
||||
for(var i=0;i<FD_SKILLS.length;i++){
|
||||
if(qmatch(FD_SKILLS[i].cmd)){
|
||||
var s = FD_SKILLS[i];
|
||||
@@ -1267,6 +1307,15 @@
|
||||
dbs.push({key:'db-'+sk.id, cmd:'/'+sk.name, desc:(sk.description || 'Skill enregistré'), icon:'✨', _type:'db', skillId:sk.id});
|
||||
}
|
||||
}
|
||||
// Galerie (marketplace) — presets pas encore installés.
|
||||
for(i=0;i<(this.gallery||[]).length;i++){
|
||||
var g = this.gallery[i];
|
||||
if(installedNames[String(g.name).toLowerCase()]) continue;
|
||||
if(qmatch(g.slug)){
|
||||
gal.push({key:'gal-'+g.slug, cmd:'/'+g.slug, desc:(g.description || 'Skill galerie'),
|
||||
icon:(g.icon || '📦'), _type:'gallery', slug:g.slug, skillName:g.name});
|
||||
}
|
||||
}
|
||||
for(i=0;i<FD_ADMIN_CMDS.length;i++){
|
||||
if(qmatch(FD_ADMIN_CMDS[i].cmd)) adm.push({key:'adm-'+FD_ADMIN_CMDS[i].cmd, cmd:FD_ADMIN_CMDS[i].cmd, desc:FD_ADMIN_CMDS[i].desc});
|
||||
}
|
||||
@@ -1276,7 +1325,11 @@
|
||||
out.push({_sep:'Skills', key:'sep-skills'});
|
||||
pushItems(built.concat(dbs));
|
||||
}
|
||||
if(skillsPresent && admPresent) out.push({_sep:'Commandes', key:'sep-adm'});
|
||||
if(gal.length){
|
||||
out.push({_sep:'Galerie', key:'sep-gal'});
|
||||
pushItems(gal);
|
||||
}
|
||||
if((skillsPresent || gal.length) && admPresent) out.push({_sep:'Commandes', key:'sep-adm'});
|
||||
if(admPresent) pushItems(adm);
|
||||
this._slashSeq = seq;
|
||||
return out;
|
||||
@@ -1302,17 +1355,14 @@
|
||||
this._focusComposer();
|
||||
return;
|
||||
}
|
||||
if(c._type === 'gallery'){
|
||||
this.installGallerySkill(c.slug, c.icon, c.skillName);
|
||||
this.cmdFocus = -1; this.slashDismiss = false;
|
||||
this._focusComposer();
|
||||
return;
|
||||
}
|
||||
if(c._type === 'db'){
|
||||
var exists = this.contextChips.some(function(ch){ return ch.kind === 'skill' && ch.skillId === c.skillId; });
|
||||
if(exists){ this.toast('Ce skill est déjà épinglé au contexte.'); }
|
||||
else {
|
||||
var pin = {key:'skill-'+c.skillId, kind:'skill', icon:c.icon||'✨',
|
||||
label:String(c.cmd).replace(/^\//, ''), token:'skill:'+c.skillId, skillId:c.skillId};
|
||||
this.contextChips.push(pin);
|
||||
this.clearComposer();
|
||||
this._insertToken({token:pin.token, label:pin.label, icon:pin.icon, kind:'skill'});
|
||||
this.toast('Skill épinglé — décrivez votre demande, il sera appliqué à l\u2019envoi.');
|
||||
}
|
||||
this._pinDbSkill(c.skillId, c.cmd, c.icon);
|
||||
} else {
|
||||
var slug = String(c.cmd).replace(/^\/+/, '').toLowerCase().replace(/\s+/g, '-');
|
||||
var builtinExists = this.contextChips.some(function(ch){ return ch.kind === 'skill' && ch.token === 'builtin:' + slug; });
|
||||
|
||||
Reference in New Issue
Block a user