feat: Dynamische KI-Modelle, verbessertes Memory-System und Chat-Überarbeitung

🎯 KI-Modellverwaltung
- Dynamisches Laden verfügbarer Modelle via opencode models
- 29 Modelle verfügbar (opencode, anthropic, ollama)
- Gruppierung nach Anbieter in UI
- Cache-Mechanismus (1h TTL) für Performance
- API-Endpoint /api/models für Modellabfrage

🧠 Memory-System komplett überarbeitet
- JSON-basierte strukturierte Erinnerungen statt Markdown-Chaos
- Separate Memory-Typen: tasks.json, notes.json, research.json
- Automatische Memory-Zusammenfassung im Systemprompt
- Limitierung auf letzte 100 Einträge pro Typ
- Vollständige Task-Ergebnisse statt abgeschnittener Texte

📁 Agenten-Ordnerstruktur
- work/ Verzeichnis für Agent-Dateien
- memory/ Verzeichnis für strukturierte Erinnerungen
- Agenten arbeiten nur in eigenem work-Verzeichnis
- Absolute Pfade werden übergeben
- Dateien-UI zeigt Agent-Work-Folders

💬 Chat-System überarbeitet
- Echte Agent-Ausführung statt Mock-Responses
- Server-Sent Events für Live-Streaming
- Session-basierte Chat-History
- Loading-Spinner und Status-Anzeigen
- Automatisches Speichern in Session

🎭 Personality Integration
- personality.md wird jetzt geladen
- Persönlichkeit vor Systemprompt eingefügt
- Gilt für alle: Chat, Tasks, Orchestrator, Email-Poller

 Weitere Verbesserungen
- Alle Agenten nutzen execute_agent_task() zentral
- Memory-Speicherung nach jedem Task
- Work-Files in Datei-Verwaltung sichtbar
- System-Dateien ausgeblendet
- API-Route für Agent-Work-Dateien
This commit is contained in:
pdyde 2026-02-21 11:44:06 +01:00
parent 84b2fe3dd7
commit 93eb8c6d47
83 changed files with 1692 additions and 1517 deletions

View file

@ -97,14 +97,25 @@
<div class="mb-3">
<label for="model_select" class="form-label">KI-Modell</label>
<div class="form-text mb-2">
Wähle das KI-Modell, das dieser Agent verwendet.
Wähle das KI-Modell, das dieser Agent verwendet. <span class="badge bg-secondary">{{ available_models.count }} Modelle</span>
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" onclick="refreshModels()">
<span id="refresh-icon">🔄</span> Aktualisieren
</button>
</div>
<select class="form-select" id="model_select" name="model_select" onchange="saveModel('{{ edit_agent }}')">
<option value="opencode/big-pickle" {% if edit_model == 'opencode/big-pickle' %}selected{% endif %}>opencode/big-pickle</option>
<option value="opencode/gpt-5-nano" {% if edit_model == 'opencode/gpt-5-nano' %}selected{% endif %}>opencode/gpt-5-nano</option>
<option value="opencode/glm-5-free" {% if edit_model == 'opencode/glm-5-free' %}selected{% endif %}>opencode/glm-5-free</option>
<option value="opencode/minimax-m2.5-free" {% if edit_model == 'opencode/minimax-m2.5-free' %}selected{% endif %}>opencode/minimax-m2.5-free</option>
<option value="opencode/trinity-large-preview-free" {% if edit_model == 'opencode/trinity-large-preview-free' %}selected{% endif %}>opencode/trinity-large-preview-free</option>
{% if available_models.grouped %}
{% for provider, models in available_models.grouped.items() %}
<optgroup label="{{ provider }}">
{% for model in models %}
<option value="{{ model }}" {% if edit_model == model %}selected{% endif %}>{{ model }}</option>
{% endfor %}
</optgroup>
{% endfor %}
{% else %}
{% for model in available_models.models %}
<option value="{{ model }}" {% if edit_model == model %}selected{% endif %}>{{ model }}</option>
{% endfor %}
{% endif %}
</select>
<div id="modelStatus" class="form-text mt-2"></div>
</div>
@ -206,6 +217,66 @@ function saveModel(agentName) {
});
}
function refreshModels() {
const icon = document.getElementById('refresh-icon');
const status = document.getElementById('modelStatus');
const select = document.getElementById('model_select');
const currentModel = select.value;
icon.textContent = '⏳';
status.textContent = 'Lade Modelle...';
status.className = 'form-text mt-2 text-info';
fetch('/api/models?refresh=true')
.then(r => r.json())
.then(data => {
// Dropdown neu aufbauen
select.innerHTML = '';
if (data.grouped) {
Object.keys(data.grouped).forEach(provider => {
const optgroup = document.createElement('optgroup');
optgroup.label = provider;
data.grouped[provider].forEach(model => {
const option = document.createElement('option');
option.value = model;
option.textContent = model;
if (model === currentModel) {
option.selected = true;
}
optgroup.appendChild(option);
});
select.appendChild(optgroup);
});
} else {
data.models.forEach(model => {
const option = document.createElement('option');
option.value = model;
option.textContent = model;
if (model === currentModel) {
option.selected = true;
}
select.appendChild(option);
});
}
icon.textContent = '🔄';
status.textContent = '✓ ' + data.count + ' Modelle geladen';
status.className = 'form-text mt-2 text-success';
setTimeout(() => {
status.textContent = '';
}, 3000);
})
.catch(err => {
icon.textContent = '🔄';
status.textContent = 'Fehler beim Laden: ' + err.message;
status.className = 'form-text mt-2 text-danger';
});
}
function deleteAgent(agentName) {
if (!confirm('Willst du den Agenten "' + agentName + '" wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden!')) {
return;