using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; using Gott.Models; using Gott.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace Gott.Endpoints; public static class ChatEndpoint { public static void MapChatEndpoint(this IEndpointRouteBuilder app) { app.MapPost("/api/chat", HandleChat); } private static async Task HandleChat(HttpRequest req, HttpResponse res, IHttpClientFactory httpFactory, IConfiguration config, ToolService toolService, DatabaseService db) { var body = await JsonSerializer.DeserializeAsync(req.Body); if (body == null || body.Messages == null || body.Messages.Count == 0) { res.StatusCode = 400; await res.WriteAsJsonAsync(new { error = "messages required" }); return; } var token = config["AnthropicToken"]; if (string.IsNullOrEmpty(token)) { res.StatusCode = 500; await res.WriteAsJsonAsync(new { error = "AnthropicToken not configured" }); return; } var sessionId = body.SessionId; if (string.IsNullOrEmpty(sessionId)) { res.StatusCode = 400; await res.WriteAsJsonAsync(new { error = "sessionId required" }); return; } // Agent aus Session auflösen var session = await db.GetSession(sessionId); if (session == null || string.IsNullOrEmpty(session.AgentId)) { res.StatusCode = 400; await res.WriteAsJsonAsync(new { error = "Kein Agent ausgewählt" }); return; } var agent = await db.GetAgent(session.AgentId); if (agent == null) { res.StatusCode = 400; await res.WriteAsJsonAsync(new { error = "Agent nicht gefunden" }); return; } var modelId = agent.Model switch { "opus" => "claude-opus-4-6", "sonnet" => "claude-sonnet-4-6", _ => "claude-sonnet-4-6" }; res.Headers["Content-Type"] = "text/event-stream"; res.Headers["Cache-Control"] = "no-cache"; res.Headers["Connection"] = "keep-alive"; var promptParts = new List(); promptParts.Add($"Du bist {agent.Name}."); if (!string.IsNullOrWhiteSpace(agent.Persona)) promptParts.Add($"## Persona\n{agent.Persona}"); if (!string.IsNullOrWhiteSpace(agent.Instructions)) promptParts.Add($"## Instructions\n{agent.Instructions}"); if (!string.IsNullOrWhiteSpace(session.Context)) promptParts.Add($"## Kontext\n{session.Context}"); var systemPromptText = string.Join("\n\n", promptParts); var chainId = Guid.NewGuid().ToString("N"); await db.CreateChain(new ChainRecord { ChainId = chainId, SessionId = sessionId, AgentId = agent.AgentId, Model = modelId, SystemPrompt = systemPromptText }); // Session-Timestamp aktualisieren await db.UpdateSessionTimestamp(sessionId); var messages = new List(); foreach (var msg in body.Messages) messages.Add(new { role = msg.Role, content = msg.Content }); // Nur die letzte User-Message speichern (= die neue) var lastUserMsg = body.Messages.LastOrDefault(m => m.Role == "user"); if (lastUserMsg != null) { await db.SaveMessage(new MessageRecord { ChainId = chainId, Iteration = 0, Role = "user", Type = "text", Content = lastUserMsg.Content }); } var systemPrompt = new List { new { type = "text", text = systemPromptText } }; var workspace = session.Workspace; if (!string.IsNullOrEmpty(workspace)) Directory.CreateDirectory(workspace); var anthropic = new AnthropicService(httpFactory, token, toolService, db); await anthropic.StreamChat(res, modelId, systemPrompt, messages, chainId, workspace); } }