Implement Skills feature: filesystem-based skills with agent assignment
- Add SkillService: scans data/skills/ directory, parses _meta.json and SKILL.md frontmatter - Add SkillEndpoint: REST API for listing skills and managing agent-skill assignments - Add agent_skills DB table for agent-to-skill mapping (only relation in DB, skills live on filesystem) - Extend SystemPromptBuilder: inject assigned skills' SKILL.md content into system prompt - Extend ChatEndpoint + SessionEndpoint: load agent skills and pass to prompt builder - Frontend: skill checkboxes in agent form, API functions for skill management - Add form.css styling for skill list items
This commit is contained in:
1 parent
b18dc78651
commit
cf6caea2dc
11 files changed
+454
-6
No files matched your search
@@ -134,6 +134,17 @@ public class DatabaseService
|
||||
TryAddColumn(conn, "agents", "use_identity", "INTEGER NOT NULL DEFAULT 1");
|
||||
TryAddColumn(conn, "agents", "use_user_info", "INTEGER NOT NULL DEFAULT 1");
|
||||
TryAddColumn(conn, "agents", "use_memory", "INTEGER NOT NULL DEFAULT 1");
|
||||
|
||||
conn.Execute(@"
|
||||
CREATE TABLE IF NOT EXISTS agent_skills (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
agent_id TEXT NOT NULL,
|
||||
skill_slug TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
UNIQUE(agent_id, skill_slug)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_agent_skills_agent ON agent_skills(agent_id);
|
||||
");
|
||||
}
|
||||
|
||||
private void TryAddColumn(SqliteConnection conn, string table, string column, string type)
|
||||
@@ -570,4 +581,51 @@ public class DatabaseService
|
||||
ORDER BY m.id",
|
||||
new { sessionId });
|
||||
}
|
||||
|
||||
// ── Agent Skills ──
|
||||
|
||||
public async Task<IEnumerable<string>> GetAgentSkills(string agentId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
return await conn.QueryAsync<string>(
|
||||
"SELECT skill_slug FROM agent_skills WHERE agent_id = @agentId ORDER BY skill_slug",
|
||||
new { agentId });
|
||||
}
|
||||
|
||||
public async Task SetAgentSkills(string agentId, IEnumerable<string> skillSlugs)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
using var tx = conn.BeginTransaction();
|
||||
|
||||
await conn.ExecuteAsync("DELETE FROM agent_skills WHERE agent_id = @agentId", new { agentId }, tx);
|
||||
|
||||
var now = DateTime.UtcNow.ToString("o");
|
||||
foreach (var slug in skillSlugs)
|
||||
{
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT INTO agent_skills (agent_id, skill_slug, created_at)
|
||||
VALUES (@agentId, @slug, @now)",
|
||||
new { agentId, slug, now }, tx);
|
||||
}
|
||||
|
||||
tx.Commit();
|
||||
}
|
||||
|
||||
public async Task AddAgentSkill(string agentId, string skillSlug)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var now = DateTime.UtcNow.ToString("o");
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT OR IGNORE INTO agent_skills (agent_id, skill_slug, created_at)
|
||||
VALUES (@agentId, @skillSlug, @now)",
|
||||
new { agentId, skillSlug, now });
|
||||
}
|
||||
|
||||
public async Task RemoveAgentSkill(string agentId, string skillSlug)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
await conn.ExecuteAsync(
|
||||
"DELETE FROM agent_skills WHERE agent_id = @agentId AND skill_slug = @skillSlug",
|
||||
new { agentId, skillSlug });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user