Agents: CRUD, DB table, session binding, replace model picker

- agents table with name, avatar, description, model, persona, instructions, soft-delete
- AgentEndpoint (GET/POST/PUT/DELETE /api/agents)
- sessions + chains now reference agent_id
- ChatEndpoint resolves agent from session (no agent = no chat)
- system prompt built from agent persona + instructions
- frontend: agent editor with avatar upload, agent cards on dashboard
- session: agent dropdown replaces model picker, choice persisted
This commit is contained in:
Meleki committed 2026-02-26 20:59:19 +01:00
1 parent 0cd2d51d32
commit 449c872296
16 files changed
+552 -46

No files matched your search

+83 -2
View File
@@ -78,10 +78,83 @@ public class DatabaseService
FOREIGN KEY (chain_id) REFERENCES chains(chain_id)
);
CREATE TABLE IF NOT EXISTS agents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
agent_id TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
avatar TEXT,
description TEXT,
model TEXT NOT NULL DEFAULT 'sonnet',
persona TEXT,
instructions TEXT,
is_deleted INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_chains_session ON chains(session_id);
CREATE INDEX IF NOT EXISTS idx_chains_archive ON chains(archive_id);
CREATE INDEX IF NOT EXISTS idx_messages_chain ON messages(chain_id);
");
// Migrations
TryAddColumn(conn, "sessions", "agent_id", "TEXT");
TryAddColumn(conn, "chains", "agent_id", "TEXT");
}
private void TryAddColumn(SqliteConnection conn, string table, string column, string type)
{
try { conn.Execute($"ALTER TABLE {table} ADD COLUMN {column} {type}"); }
catch { /* column already exists */ }
}
// ── Agents ──
public async Task<AgentRecord> CreateAgent(AgentRecord agent)
{
using var conn = CreateConnection();
var now = DateTime.UtcNow.ToString("o");
agent.AgentId = Guid.NewGuid().ToString("N");
agent.CreatedAt = now;
agent.UpdatedAt = now;
await conn.ExecuteAsync(@"
INSERT INTO agents (agent_id, name, avatar, description, model, persona, instructions, is_deleted, created_at, updated_at)
VALUES (@AgentId, @Name, @Avatar, @Description, @Model, @Persona, @Instructions, 0, @CreatedAt, @UpdatedAt)
", agent);
return agent;
}
public async Task<IEnumerable<AgentRecord>> GetAgents()
{
using var conn = CreateConnection();
return await conn.QueryAsync<AgentRecord>(
"SELECT * FROM agents WHERE is_deleted = 0 ORDER BY name");
}
public async Task<AgentRecord> GetAgent(string agentId)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<AgentRecord>(
"SELECT * FROM agents WHERE agent_id = @agentId AND is_deleted = 0", new { agentId });
}
public async Task UpdateAgent(AgentRecord agent)
{
using var conn = CreateConnection();
agent.UpdatedAt = DateTime.UtcNow.ToString("o");
await conn.ExecuteAsync(@"
UPDATE agents SET name = @Name, avatar = @Avatar, description = @Description,
model = @Model, persona = @Persona, instructions = @Instructions, updated_at = @UpdatedAt
WHERE agent_id = @AgentId
", agent);
}
public async Task DeleteAgent(string agentId)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE agents SET is_deleted = 1, updated_at = @now WHERE agent_id = @agentId",
new { agentId, now = DateTime.UtcNow.ToString("o") });
}
// ── Sessions ──
@@ -134,6 +207,14 @@ public class DatabaseService
new { sessionId, name, now = DateTime.UtcNow.ToString("o") });
}
public async Task UpdateSessionAgent(string sessionId, string agentId)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE sessions SET agent_id = @agentId, updated_at = @now WHERE session_id = @sessionId",
new { sessionId, agentId, now = DateTime.UtcNow.ToString("o") });
}
// ── Archives ──
public async Task<ArchiveRecord> CreateArchive(string sessionId, string name = null)
@@ -195,8 +276,8 @@ public class DatabaseService
using var conn = CreateConnection();
chain.CreatedAt = DateTime.UtcNow.ToString("o");
await conn.ExecuteAsync(@"
INSERT INTO chains (chain_id, session_id, archive_id, model, system_prompt, input_tokens, output_tokens, iterations, stop_reason, duration_ms, created_at)
VALUES (@ChainId, @SessionId, @ArchiveId, @Model, @SystemPrompt, @InputTokens, @OutputTokens, @Iterations, @StopReason, @DurationMs, @CreatedAt)
INSERT INTO chains (chain_id, session_id, archive_id, agent_id, model, system_prompt, input_tokens, output_tokens, iterations, stop_reason, duration_ms, created_at)
VALUES (@ChainId, @SessionId, @ArchiveId, @AgentId, @Model, @SystemPrompt, @InputTokens, @OutputTokens, @Iterations, @StopReason, @DurationMs, @CreatedAt)
", chain);
}