Files
gott/Services/DatabaseService.Agents.cs
T
MelekiandClaude Opus 4.6 f03fbd298e feat: User-Berechtigungen für Agent-Erstellung und CLI-Nutzung
- Neue Felder CanCreateAgents und CanUseCli im UserRecord (Default: true)
- DB-Migration mit Abwärtskompatibilität (bestehende User behalten alle Rechte)
- Admin-UI: Checkboxen für beide Berechtigungen pro User
- AgentEndpoint: Prüfung auf CanCreateAgents beim Erstellen
- ChatEndpoint: CLI-Fallback nur wenn CanUseCli erlaubt
- Frontend: Neuer-Agent-Button und Agent-Page bei fehlender Berechtigung gesperrt
- Chat: Proaktive Warnung wenn kein API-Key und keine CLI-Berechtigung
- Bug Fix: is_public fehlte im Agent-INSERT (Public Agents erst nach erneutem Speichern sichtbar)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 18:47:56 +01:00

122 lines
5.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using Gott.Models;
namespace Gott.Services;
public partial class DatabaseService
{
// ── 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, user_id, name, avatar, avatar_small, description, model, tool_choice, custom_commands, auto_commit, use_soul, use_identity, use_user_info, use_memory, use_auto_context, use_github_search, use_serper_search, use_web_search, web_search_version, allow_user_choice, task_instruction, avatar_scale, avatar_offset_x, avatar_offset_y, is_public, is_deleted, created_at, updated_at)
VALUES (@AgentId, @UserId, @Name, @Avatar, @AvatarSmall, @Description, @Model, @ToolChoice, @CustomCommands, @AutoCommit, @UseSoul, @UseIdentity, @UseUserInfo, @UseMemory, @UseAutoContext, @UseGitHubSearch, @UseSerperSearch, @UseWebSearch, @WebSearchVersion, @AllowUserChoice, @TaskInstruction, @AvatarScale, @AvatarOffsetX, @AvatarOffsetY, @IsPublic, 0, @CreatedAt, @UpdatedAt)
", agent);
return agent;
}
public async Task<IEnumerable<AgentRecord>> GetAgents(string userId)
{
using var conn = CreateConnection();
return await conn.QueryAsync<AgentRecord>(
"SELECT * FROM agents WHERE user_id = @userId AND is_deleted = 0 ORDER BY name", new { userId });
}
public async Task<IEnumerable<AgentRecord>> GetAvailableAgents(string userId)
{
using var conn = CreateConnection();
return await conn.QueryAsync<AgentRecord>(
"SELECT * FROM agents WHERE (user_id = @userId OR is_public = 1) AND is_deleted = 0 ORDER BY name", new { userId });
}
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, avatar_small = @AvatarSmall, description = @Description,
model = @Model, tool_choice = @ToolChoice,
custom_commands = @CustomCommands, auto_commit = @AutoCommit,
use_soul = @UseSoul, use_identity = @UseIdentity, use_user_info = @UseUserInfo, use_memory = @UseMemory, use_auto_context = @UseAutoContext, use_github_search = @UseGitHubSearch, use_serper_search = @UseSerperSearch, use_web_search = @UseWebSearch, web_search_version = @WebSearchVersion,
allow_user_choice = @AllowUserChoice, task_instruction = @TaskInstruction,
avatar_scale = @AvatarScale, avatar_offset_x = @AvatarOffsetX, avatar_offset_y = @AvatarOffsetY,
is_public = @IsPublic, updated_at = @UpdatedAt
WHERE agent_id = @AgentId AND user_id = @UserId
", agent);
}
public async Task DeleteAgent(string agentId, string userId)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE agents SET is_deleted = 1, updated_at = @now WHERE agent_id = @agentId AND user_id = @userId",
new { agentId, userId, now = DateTime.UtcNow.ToString("o") });
}
// ── 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 });
}
}