Fix skill execution: wire run_skill to actually invoke agent, show results in modal
This commit is contained in:
parent
1c5ce61e4a
commit
2bf866b0b1
|
|
@ -156,6 +156,7 @@ async function quickRunSkill(name) {
|
|||
<option value="gemini">Gemini CLI</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="skillResult" style="display:none"></div>
|
||||
`, `
|
||||
<button class="btn btn-ghost" onclick="closeModal()">Cancel</button>
|
||||
<button class="btn btn-primary" onclick="executeSkillRun('${name}')">▶ Run</button>
|
||||
|
|
@ -165,11 +166,32 @@ async function quickRunSkill(name) {
|
|||
async function executeSkillRun(name) {
|
||||
const input = document.getElementById('qrsInput').value;
|
||||
const agent = document.getElementById('qrsAgent').value;
|
||||
const runBtn = document.querySelector('#modalContainer .btn-primary');
|
||||
const resultArea = document.getElementById('skillResult');
|
||||
|
||||
if (runBtn) { runBtn.disabled = true; runBtn.textContent = '⏳ Running...'; }
|
||||
if (resultArea) {
|
||||
resultArea.style.display = 'block';
|
||||
resultArea.innerHTML = '<div class="loading" style="padding:20px"><div class="loading-spinner"></div><span style="margin-left:8px">Executing skill...</span></div>';
|
||||
}
|
||||
|
||||
try {
|
||||
const r = await api.runSkill(name, input, agent);
|
||||
closeModal();
|
||||
showToast(`"${name}" dispatched to ${r.agent} #${r.run_id}`, 'success');
|
||||
if (resultArea) {
|
||||
const outputText = r.output || '(no output)';
|
||||
resultArea.innerHTML = `
|
||||
<div class="card" style="margin-top:8px">
|
||||
<div class="card-header" style="border-color:var(--green-dim)">
|
||||
<span class="card-title" style="color:var(--green)">✓ Completed — ${r.agent} #${r.run_id}</span>
|
||||
</div>
|
||||
<pre style="max-height:400px;overflow:auto;font-size:12px;white-space:pre-wrap;margin:0;padding:12px;background:var(--bg-code, #1a1a2e);border-radius:0 0 8px 8px">${escapeHtml(outputText)}</pre>
|
||||
</div>`;
|
||||
}
|
||||
if (runBtn) { runBtn.textContent = '✓ Done'; runBtn.disabled = false; }
|
||||
} catch (err) {
|
||||
showToast(`Error: ${err.message}`, 'error');
|
||||
if (resultArea) {
|
||||
resultArea.innerHTML = `<div class="empty-state" style="padding:20px"><div class="empty-state-icon">⚠</div><div class="empty-state-title">Error</div><div class="empty-state-desc">${escapeHtml(err.message)}</div></div>`;
|
||||
}
|
||||
if (runBtn) { runBtn.textContent = '▶ Run'; runBtn.disabled = false; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
54
server.py
54
server.py
|
|
@ -205,6 +205,10 @@ def run_skill(name: str, req: Optional[SkillRunRequest] = None):
|
|||
agent_choice = req.agent if req else "auto"
|
||||
skill_input = req.input if req else ""
|
||||
|
||||
# Read skill files
|
||||
skill_md = read_file(path / "SKILL.md")
|
||||
learnings = read_file(path / "learnings.md")
|
||||
|
||||
# Determine which agent based on skill type
|
||||
if agent_choice == "auto":
|
||||
devops_keywords = ["devops", "audit", "deploy", "k8s", "gcp", "infra", "terraform"]
|
||||
|
|
@ -214,23 +218,65 @@ def run_skill(name: str, req: Optional[SkillRunRequest] = None):
|
|||
elif any(k in name for k in research_keywords):
|
||||
agent_choice = "gemini"
|
||||
else:
|
||||
agent_choice = "opencode"
|
||||
# Check SKILL.md for explicit agent assignment
|
||||
for line in skill_md.split('\n'):
|
||||
line = line.strip()
|
||||
if "Primary:" in line:
|
||||
candidate = line.split(":")[-1].strip().lower()
|
||||
if candidate in ("opencode", "hermes", "gemini"):
|
||||
agent_choice = candidate
|
||||
break
|
||||
if agent_choice == "auto":
|
||||
agent_choice = "opencode"
|
||||
|
||||
# Build prompt from skill instructions + learnings + user input
|
||||
prompt = f"Execute the '{name}' skill.\n\n"
|
||||
if skill_md:
|
||||
prompt += f"## Skill Instructions\n{skill_md}\n\n"
|
||||
if learnings and learnings.strip():
|
||||
prompt += f"## Past Learnings\n{learnings}\n\n"
|
||||
if skill_input:
|
||||
prompt += f"## User Input\n{skill_input}"
|
||||
|
||||
run_id = str(uuid.uuid4())[:8]
|
||||
|
||||
# Execute via agent
|
||||
try:
|
||||
response_text = execute_agent(agent_choice, prompt)
|
||||
except subprocess.TimeoutExpired:
|
||||
response_text = f"⏱ Skill '{name}' timed out on agent '{agent_choice}'."
|
||||
except FileNotFoundError:
|
||||
response_text = f"⚠ Agent '{agent_choice}' CLI not installed. Install it and try again."
|
||||
except Exception as e:
|
||||
response_text = f"⚠ Error executing skill: {str(e)}"
|
||||
|
||||
# Save output to learnings.md
|
||||
timestamp = get_timestamp()[:10]
|
||||
existing = read_file(path / "learnings.md")
|
||||
new_entry = (
|
||||
f"\n## {timestamp} (Run {run_id})\n"
|
||||
f"- Agent: {agent_choice}\n"
|
||||
f"- Input: {skill_input or '(none)'}\n"
|
||||
f"- Output: {response_text[:500]}\n"
|
||||
)
|
||||
write_file(path / "learnings.md", existing + new_entry)
|
||||
|
||||
# Log execution
|
||||
run_id = str(uuid.uuid4())[:8]
|
||||
append_audit({
|
||||
"action": "skill_run",
|
||||
"skill": name,
|
||||
"agent": agent_choice,
|
||||
"run_id": run_id,
|
||||
"output_preview": response_text[:100],
|
||||
})
|
||||
|
||||
return {
|
||||
"status": "started",
|
||||
"status": "completed",
|
||||
"run_id": run_id,
|
||||
"skill": name,
|
||||
"agent": agent_choice,
|
||||
"message": f"Skill '{name}' dispatched to {agent_choice}",
|
||||
"output": response_text,
|
||||
"message": f"Skill '{name}' completed via {agent_choice}",
|
||||
}
|
||||
|
||||
@app.get("/api/skills/{name}/eval")
|
||||
|
|
|
|||
Loading…
Reference in New Issue