- agents table with name, avatar, description, model, persona, instructions, soft-delete - AgentEndpoint (GET/POST/PUT/DELETE /api/agents) - sessions + chains now reference agent_id - ChatEndpoint resolves agent from session (no agent = no chat) - system prompt built from agent persona + instructions - frontend: agent editor with avatar upload, agent cards on dashboard - session: agent dropdown replaces model picker, choice persisted
76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
// ── Dashboard Page ──
|
|
|
|
registerPage('dashboard', {
|
|
async init() {
|
|
// Sessions laden
|
|
const sessions = await apiGetSessions();
|
|
const grid = document.getElementById('sessionCards');
|
|
grid.innerHTML = '';
|
|
|
|
for (const s of sessions) {
|
|
const card = document.createElement('div');
|
|
card.className = 'card clickable';
|
|
card.innerHTML = `
|
|
<div class="card-title">${escHtml(s.name || 'Unbenannt')}</div>
|
|
<div class="card-sub">${formatDate(s.updatedAt)}</div>
|
|
`;
|
|
card.addEventListener('click', () => {
|
|
navigateTo('session', { id: s.sessionId });
|
|
});
|
|
grid.appendChild(card);
|
|
}
|
|
|
|
const newSessionBtn = document.getElementById('newSessionBtn');
|
|
if (newSessionBtn) {
|
|
newSessionBtn.addEventListener('click', async () => {
|
|
const session = await apiCreateSession();
|
|
navigateTo('session', { id: session.sessionId });
|
|
});
|
|
}
|
|
|
|
// Agents laden
|
|
const agents = await apiGetAgents();
|
|
const agentGrid = document.getElementById('agentCards');
|
|
agentGrid.innerHTML = '';
|
|
|
|
for (const a of agents) {
|
|
const card = document.createElement('div');
|
|
card.className = 'card clickable';
|
|
card.innerHTML = `
|
|
<div class="agent-card-avatar">${a.avatar ? `<img src="${a.avatar}" alt="">` : '?'}</div>
|
|
<div class="card-title">${escHtml(a.name)}</div>
|
|
<div class="card-sub">${escHtml(a.model || 'sonnet')}</div>
|
|
`;
|
|
card.addEventListener('click', () => {
|
|
navigateTo('agent', { id: a.agentId });
|
|
});
|
|
agentGrid.appendChild(card);
|
|
}
|
|
|
|
// Neuer Agent Placeholder
|
|
const placeholder = document.createElement('div');
|
|
placeholder.className = 'card placeholder clickable';
|
|
placeholder.innerHTML = `
|
|
<div class="card-icon">+</div>
|
|
<div class="card-title">Neuer Agent</div>
|
|
`;
|
|
placeholder.addEventListener('click', () => navigateTo('agent'));
|
|
agentGrid.appendChild(placeholder);
|
|
},
|
|
destroy() {}
|
|
});
|
|
|
|
function escHtml(s) {
|
|
const d = document.createElement('div');
|
|
d.textContent = s;
|
|
return d.innerHTML;
|
|
}
|
|
|
|
function formatDate(iso) {
|
|
if (!iso) return '';
|
|
return new Date(iso).toLocaleString('de-AT', {
|
|
day: '2-digit', month: '2-digit', year: '2-digit',
|
|
hour: '2-digit', minute: '2-digit'
|
|
});
|
|
}
|