Some checks failed
CI / Check / macos-latest (push) Has been cancelled
CI / Check / ubuntu-latest (push) Has been cancelled
CI / Check / windows-latest (push) Has been cancelled
CI / Test / macos-latest (push) Has been cancelled
CI / Test / ubuntu-latest (push) Has been cancelled
CI / Test / windows-latest (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / Secrets Scan (push) Has been cancelled
CI / Install Script Smoke Test (push) Has been cancelled
148 lines
4.6 KiB
JavaScript
148 lines
4.6 KiB
JavaScript
// OpenFang Sessions Page — Session listing + Memory tab
|
|
'use strict';
|
|
|
|
function sessionsPage() {
|
|
return {
|
|
tab: 'sessions',
|
|
// -- Sessions state --
|
|
sessions: [],
|
|
searchFilter: '',
|
|
loading: true,
|
|
loadError: '',
|
|
|
|
// -- Memory state --
|
|
memAgentId: '',
|
|
kvPairs: [],
|
|
showAdd: false,
|
|
newKey: '',
|
|
newValue: '""',
|
|
editingKey: null,
|
|
editingValue: '',
|
|
memLoading: false,
|
|
memLoadError: '',
|
|
|
|
// -- Sessions methods --
|
|
async loadSessions() {
|
|
this.loading = true;
|
|
this.loadError = '';
|
|
try {
|
|
var data = await OpenFangAPI.get('/api/sessions');
|
|
var sessions = data.sessions || [];
|
|
var agents = Alpine.store('app').agents;
|
|
var agentMap = {};
|
|
agents.forEach(function(a) { agentMap[a.id] = a.name; });
|
|
sessions.forEach(function(s) {
|
|
s.agent_name = agentMap[s.agent_id] || '';
|
|
});
|
|
this.sessions = sessions;
|
|
} catch(e) {
|
|
this.sessions = [];
|
|
this.loadError = e.message || 'Could not load sessions.';
|
|
}
|
|
this.loading = false;
|
|
},
|
|
|
|
async loadData() { return this.loadSessions(); },
|
|
|
|
get filteredSessions() {
|
|
var f = this.searchFilter.toLowerCase();
|
|
if (!f) return this.sessions;
|
|
return this.sessions.filter(function(s) {
|
|
return (s.agent_name || '').toLowerCase().indexOf(f) !== -1 ||
|
|
(s.agent_id || '').toLowerCase().indexOf(f) !== -1;
|
|
});
|
|
},
|
|
|
|
openInChat(session) {
|
|
var agents = Alpine.store('app').agents;
|
|
var agent = agents.find(function(a) { return a.id === session.agent_id; });
|
|
if (agent) {
|
|
Alpine.store('app').pendingAgent = agent;
|
|
}
|
|
location.hash = 'agents';
|
|
},
|
|
|
|
deleteSession(sessionId) {
|
|
var self = this;
|
|
OpenFangToast.confirm('Delete Session', 'This will permanently remove the session and its messages.', async function() {
|
|
try {
|
|
await OpenFangAPI.del('/api/sessions/' + sessionId);
|
|
self.sessions = self.sessions.filter(function(s) { return s.session_id !== sessionId; });
|
|
OpenFangToast.success('Session deleted');
|
|
} catch(e) {
|
|
OpenFangToast.error('Failed to delete session: ' + e.message);
|
|
}
|
|
});
|
|
},
|
|
|
|
// -- Memory methods --
|
|
async loadKv() {
|
|
if (!this.memAgentId) { this.kvPairs = []; return; }
|
|
this.memLoading = true;
|
|
this.memLoadError = '';
|
|
try {
|
|
var data = await OpenFangAPI.get('/api/memory/agents/' + this.memAgentId + '/kv');
|
|
this.kvPairs = data.kv_pairs || [];
|
|
} catch(e) {
|
|
this.kvPairs = [];
|
|
this.memLoadError = e.message || 'Could not load memory data.';
|
|
}
|
|
this.memLoading = false;
|
|
},
|
|
|
|
async addKey() {
|
|
if (!this.memAgentId || !this.newKey.trim()) return;
|
|
var value;
|
|
try { value = JSON.parse(this.newValue); } catch(e) { value = this.newValue; }
|
|
try {
|
|
await OpenFangAPI.put('/api/memory/agents/' + this.memAgentId + '/kv/' + encodeURIComponent(this.newKey), { value: value });
|
|
this.showAdd = false;
|
|
OpenFangToast.success('Key "' + this.newKey + '" saved');
|
|
this.newKey = '';
|
|
this.newValue = '""';
|
|
await this.loadKv();
|
|
} catch(e) {
|
|
OpenFangToast.error('Failed to save key: ' + e.message);
|
|
}
|
|
},
|
|
|
|
deleteKey(key) {
|
|
var self = this;
|
|
OpenFangToast.confirm('Delete Key', 'Delete key "' + key + '"? This cannot be undone.', async function() {
|
|
try {
|
|
await OpenFangAPI.del('/api/memory/agents/' + self.memAgentId + '/kv/' + encodeURIComponent(key));
|
|
OpenFangToast.success('Key "' + key + '" deleted');
|
|
await self.loadKv();
|
|
} catch(e) {
|
|
OpenFangToast.error('Failed to delete key: ' + e.message);
|
|
}
|
|
});
|
|
},
|
|
|
|
startEdit(kv) {
|
|
this.editingKey = kv.key;
|
|
this.editingValue = typeof kv.value === 'object' ? JSON.stringify(kv.value, null, 2) : String(kv.value);
|
|
},
|
|
|
|
cancelEdit() {
|
|
this.editingKey = null;
|
|
this.editingValue = '';
|
|
},
|
|
|
|
async saveEdit() {
|
|
if (!this.editingKey || !this.memAgentId) return;
|
|
var value;
|
|
try { value = JSON.parse(this.editingValue); } catch(e) { value = this.editingValue; }
|
|
try {
|
|
await OpenFangAPI.put('/api/memory/agents/' + this.memAgentId + '/kv/' + encodeURIComponent(this.editingKey), { value: value });
|
|
OpenFangToast.success('Key "' + this.editingKey + '" updated');
|
|
this.editingKey = null;
|
|
this.editingValue = '';
|
|
await this.loadKv();
|
|
} catch(e) {
|
|
OpenFangToast.error('Failed to save: ' + e.message);
|
|
}
|
|
}
|
|
};
|
|
}
|