feat: agent platform initial commit

- FastAPI + HTMX UI: dashboard, agents CRUD, chat, audit, tools
- SQLite schema: agents, conversations, messages, audit, sessions
- Code-agent sync (agents/*.py -> DB on startup)
- MCP client with health check
- Token auth (Bearer + session)
- LiteLLM integration via llm.py
- Docker Compose: agent-platform + mcp-tools services
- Smoke tests pass: /health 200, /api/agents 200, / 401
This commit is contained in:
Leopold
2026-07-05 22:18:00 +02:00
commit 64b840c94c
30 changed files with 2690 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
{% extends "base.html" %}
{% block title %}{% if agent %}Agent bearbeiten{% else %}Neuer Agent{% endif %} Agent Platform{% endblock %}
{% block content %}
<div class="page-header">
<h1>{% if agent %}{{ agent.name }}{% else %}Neuer Agent{% endif %}</h1>
<a href="/agents" class="btn">Zurück</a>
</div>
<form {% if agent %}hx-put="/api/agents/{{ agent.id }}"{% else %}hx-post="/api/agents"{% endif %} hx-target="#result" hx-swap="innerHTML" class="card form">
<div class="form-group">
<label>ID (nur Kleinbuchstaben, Zahlen, _ und -)</label>
{% if agent %}
<input type="text" value="{{ agent.id }}" readonly>
{% else %}
<input type="text" name="id" required pattern="^[a-z0-9_-]+$" placeholder="mein_agent">
{% endif %}
</div>
<div class="form-group">
<label>Name (Anzeigename)</label>
<input type="text" name="name" required value="{{ agent.name if agent else '' }}">
</div>
<div class="form-group">
<label>Beschreibung</label>
<input type="text" name="description" value="{{ agent.description if agent else '' }}">
</div>
<div class="form-group">
<label>System-Prompt</label>
<textarea name="system_prompt" rows="6" required>{{ agent.system_prompt if agent else '' }}</textarea>
</div>
<div class="form-group">
<label>Erlaubte Tools (Mehrfachauswahl)</label>
<div class="checkbox-group">
{% set selected = agent.allowed_tools if agent else [] %}
{% if available_tools %}
{% for tool in available_tools %}
<label class="checkbox-label">
<input type="checkbox" name="allowed_tools" value="{{ tool.name }}" {% if tool.name in selected %}checked{% endif %}>
<code>{{ tool.name }}</code>
</label>
{% endfor %}
{% else %}
<input type="text" name="allowed_tools_csv" placeholder="tool1,tool2 (MCP nicht erreichbar)" value="{{ selected|join(',') }}">
{% endif %}
</div>
<small>Verfügbare Tools vom MCP-Server. Falls nicht erreichbar, manuell als CSV.</small>
</div>
<div class="form-row">
<div class="form-group" style="flex:1">
<label>LLM-Modell (leer = Default aus Config)</label>
<input type="text" name="model" placeholder="z.B. anthropic/claude-sonnet-4.5" value="{{ agent.model if agent and agent.model else '' }}">
</div>
<div class="form-group" style="width:120px">
<label>Temperature</label>
<input type="number" name="temperature" step="0.1" min="0" max="2" value="{{ agent.temperature if agent else 0.7 }}">
</div>
<div class="form-group" style="width:140px">
<label>Max Tokens</label>
<input type="number" name="max_tokens" min="100" max="32000" value="{{ agent.max_tokens if agent else 2000 }}">
</div>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" name="enabled" value="true" {% if not agent or agent.enabled %}checked{% endif %}>
Aktiv (Agent darf verwendet werden)
</label>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">{% if agent %}Speichern{% else %}Anlegen{% endif %}</button>
<a href="/agents" class="btn">Abbrechen</a>
</div>
<div id="result"></div>
</form>
{% if agent %}
<section class="card">
<h2>Chat testen</h2>
<form hx-post="/api/chat/{{ agent.id }}" hx-target="#chat-result" hx-swap="innerHTML" class="form">
<textarea name="message" rows="3" required placeholder="Hallo, was kannst du?"></textarea>
<button type="submit" class="btn">Senden</button>
</form>
<div id="chat-result"></div>
</section>
{% endif %}
{% endblock %}