206 lines
7.3 KiB
C#
206 lines
7.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using Gott.Services;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Routing;
|
|
|
|
namespace Gott.Endpoints;
|
|
|
|
public static class SessionEndpoint
|
|
{
|
|
public static void MapSessionEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
app.MapGet("/api/sessions", HandleList);
|
|
app.MapGet("/api/sessions/{sessionId}", HandleGet);
|
|
app.MapPost("/api/sessions", HandleCreate);
|
|
app.MapPut("/api/sessions/{sessionId}", HandleUpdate);
|
|
app.MapDelete("/api/sessions/{sessionId}", HandleDelete);
|
|
app.MapGet("/api/sessions/{sessionId}/system-prompt", HandleSystemPrompt);
|
|
app.MapGet("/api/sessions/{sessionId}/streaming", HandleStreaming);
|
|
app.MapPost("/api/sessions/{sessionId}/exec", HandleExec);
|
|
}
|
|
|
|
private static async Task HandleList(HttpContext ctx, DatabaseService db)
|
|
{
|
|
var sessions = await db.GetSessionsWithStats();
|
|
await ctx.Response.WriteAsJsonAsync(sessions);
|
|
}
|
|
|
|
private static async Task HandleGet(HttpContext ctx, DatabaseService db)
|
|
{
|
|
var sessionId = ctx.Request.RouteValues["sessionId"]?.ToString();
|
|
if (string.IsNullOrEmpty(sessionId))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
return;
|
|
}
|
|
var session = await db.GetSession(sessionId);
|
|
if (session == null)
|
|
{
|
|
ctx.Response.StatusCode = 404;
|
|
return;
|
|
}
|
|
await ctx.Response.WriteAsJsonAsync(session);
|
|
}
|
|
|
|
private static async Task HandleCreate(HttpContext ctx, DatabaseService db, ImageService imageService)
|
|
{
|
|
var body = await JsonSerializer.DeserializeAsync<JsonElement>(ctx.Request.Body);
|
|
|
|
var name = body.TryGetProperty("name", out var n) ? n.GetString() : "Neue Session";
|
|
var description = body.TryGetProperty("description", out var d) ? d.GetString() : null;
|
|
var imageRaw = body.TryGetProperty("image", out var img) ? img.GetString() : null;
|
|
var image = imageService.ResizeDataUrl(imageRaw);
|
|
var agentId = body.TryGetProperty("agentId", out var a) ? a.GetString() : null;
|
|
var workspace = body.TryGetProperty("workspace", out var w) ? w.GetString() : null;
|
|
var context = body.TryGetProperty("context", out var ctxEl) ? ctxEl.GetString() : null;
|
|
var customCommands = body.TryGetProperty("customCommands", out var cc) && cc.ValueKind != JsonValueKind.Null ? cc.GetRawText() : null;
|
|
|
|
var session = await db.CreateSession(name, description, image, agentId, workspace, context, customCommands);
|
|
await ctx.Response.WriteAsJsonAsync(session);
|
|
}
|
|
|
|
private static async Task HandleUpdate(HttpContext ctx, DatabaseService db, ImageService imageService)
|
|
{
|
|
var sessionId = ctx.Request.RouteValues["sessionId"]?.ToString();
|
|
if (string.IsNullOrEmpty(sessionId))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
return;
|
|
}
|
|
|
|
var body = await JsonSerializer.DeserializeAsync<JsonElement>(ctx.Request.Body);
|
|
await db.UpdateSession(sessionId, body, imageService);
|
|
|
|
var session = await db.GetSession(sessionId);
|
|
await ctx.Response.WriteAsJsonAsync(session);
|
|
}
|
|
|
|
private static async Task HandleDelete(HttpContext ctx, DatabaseService db)
|
|
{
|
|
var sessionId = ctx.Request.RouteValues["sessionId"]?.ToString();
|
|
if (string.IsNullOrEmpty(sessionId)) { ctx.Response.StatusCode = 400; return; }
|
|
|
|
await db.DeleteSession(sessionId);
|
|
ctx.Response.StatusCode = 204;
|
|
}
|
|
|
|
private static async Task HandleSystemPrompt(HttpContext ctx, DatabaseService db)
|
|
{
|
|
var sessionId = ctx.Request.RouteValues["sessionId"]?.ToString();
|
|
if (string.IsNullOrEmpty(sessionId))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
return;
|
|
}
|
|
|
|
var session = await db.GetSession(sessionId);
|
|
if (session == null)
|
|
{
|
|
ctx.Response.StatusCode = 404;
|
|
return;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(session.AgentId))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = "Kein Agent ausgewählt" });
|
|
return;
|
|
}
|
|
|
|
var agent = await db.GetAgent(session.AgentId);
|
|
if (agent == null)
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = "Agent nicht gefunden" });
|
|
return;
|
|
}
|
|
|
|
var systemPrompt = SystemPromptBuilder.Build(agent, session);
|
|
|
|
ctx.Response.ContentType = "text/plain; charset=utf-8";
|
|
await ctx.Response.WriteAsync(systemPrompt);
|
|
}
|
|
|
|
private static async Task HandleStreaming(HttpContext ctx, StreamingTracker streamingTracker)
|
|
{
|
|
var sessionId = ctx.Request.RouteValues["sessionId"]?.ToString();
|
|
if (string.IsNullOrEmpty(sessionId))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
return;
|
|
}
|
|
|
|
var isStreaming = streamingTracker.IsStreaming(sessionId);
|
|
var chainId = streamingTracker.GetChainId(sessionId);
|
|
await ctx.Response.WriteAsJsonAsync(new { streaming = isStreaming, chainId });
|
|
}
|
|
|
|
private static async Task HandleExec(HttpContext ctx, DatabaseService db)
|
|
{
|
|
var sessionId = ctx.Request.RouteValues["sessionId"]?.ToString();
|
|
if (string.IsNullOrEmpty(sessionId))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
return;
|
|
}
|
|
|
|
var session = await db.GetSession(sessionId);
|
|
if (session == null)
|
|
{
|
|
ctx.Response.StatusCode = 404;
|
|
return;
|
|
}
|
|
|
|
var body = await JsonSerializer.DeserializeAsync<JsonElement>(ctx.Request.Body);
|
|
var command = body.TryGetProperty("command", out var c) ? c.GetString() : null;
|
|
|
|
if (string.IsNullOrWhiteSpace(command))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = "Kein Befehl angegeben" });
|
|
return;
|
|
}
|
|
|
|
var workingDir = !string.IsNullOrWhiteSpace(session.Workspace) ? session.Workspace : "/tmp";
|
|
|
|
try
|
|
{
|
|
var scriptPath = $"/tmp/gott-exec-{Guid.NewGuid():N}.sh";
|
|
await System.IO.File.WriteAllTextAsync(scriptPath, $"#!/bin/bash\ncd {workingDir}\n{command}\nrm -f {scriptPath}\n");
|
|
|
|
var psi = new ProcessStartInfo
|
|
{
|
|
FileName = "systemd-run",
|
|
Arguments = $"--scope --quiet bash {scriptPath}",
|
|
WorkingDirectory = workingDir,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
CreateNoWindow = true
|
|
};
|
|
|
|
var process = Process.Start(psi);
|
|
if (process != null)
|
|
{
|
|
process.WaitForExit(500);
|
|
}
|
|
|
|
ctx.Response.StatusCode = 202;
|
|
await ctx.Response.WriteAsJsonAsync(new { status = "started", command = command });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ctx.Response.StatusCode = 500;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
|
|
}
|