feat: implement model persistence with per-session overrides
- Add session_config SQLite table for per-session settings - Update routing to support session override → agent config → global default resolution chain - Upgrade WebChat SessionBridge from NativeAgent to AgentOrchestrator - Add /model, /local, /cloud commands to Telegram adapter - Add /model command to WebChat gateway handlers - Clear session overrides on /reset command - Pass memoryStore and config through to SessionBridge - Add comprehensive tests for all new functionality Fixes model persistence bug where TUI model changes didn't affect WebChat/Telegram sessions. Now: - TUI /model sets global default (persists across restarts, affects all new sessions) - WebChat/Telegram /model sets session override (only that conversation, cleared on /reset) - WebChat sessions gain AgentOrchestrator features (delegation, compaction, memory)
This commit is contained in:
@@ -8,6 +8,9 @@ export interface Session {
|
||||
getHistory(): Message[];
|
||||
clear(): void;
|
||||
replaceHistory(messages: Message[]): void;
|
||||
getConfig(key: string): string | undefined;
|
||||
setConfig(key: string, value: string): void;
|
||||
deleteConfig(key: string): void;
|
||||
}
|
||||
|
||||
export class ManagedSession implements Session {
|
||||
@@ -64,6 +67,18 @@ export class ManagedSession implements Session {
|
||||
setHistory(messages: Message[]): void {
|
||||
this.history = [...messages];
|
||||
}
|
||||
|
||||
getConfig(key: string): string | undefined {
|
||||
return this.store.getSessionConfig(this.id, key);
|
||||
}
|
||||
|
||||
setConfig(key: string, value: string): void {
|
||||
this.store.setSessionConfig(this.id, key, value);
|
||||
}
|
||||
|
||||
deleteConfig(key: string): void {
|
||||
this.store.deleteSessionConfig(this.id, key);
|
||||
}
|
||||
}
|
||||
|
||||
export class SessionManager {
|
||||
@@ -129,4 +144,22 @@ export class SessionManager {
|
||||
this.sessions.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get a session config value. */
|
||||
getSessionConfig(frontend: string, userId: string, key: string): string | undefined {
|
||||
const session = this.getSession(frontend, userId);
|
||||
return session.getConfig(key);
|
||||
}
|
||||
|
||||
/** Set a session config value. */
|
||||
setSessionConfig(frontend: string, userId: string, key: string, value: string): void {
|
||||
const session = this.getSession(frontend, userId);
|
||||
session.setConfig(key, value);
|
||||
}
|
||||
|
||||
/** Delete a session config value. */
|
||||
deleteSessionConfig(frontend: string, userId: string, key: string): void {
|
||||
const session = this.getSession(frontend, userId);
|
||||
session.deleteConfig(key);
|
||||
}
|
||||
}
|
||||
|
||||
+59
-4
@@ -36,6 +36,13 @@ export class SessionStore {
|
||||
code_used TEXT NOT NULL,
|
||||
PRIMARY KEY (channel, sender_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS session_config (
|
||||
session_id TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
PRIMARY KEY (session_id, key)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_session_config_session ON session_config(session_id);
|
||||
`);
|
||||
}
|
||||
|
||||
@@ -78,8 +85,11 @@ export class SessionStore {
|
||||
}
|
||||
|
||||
clearSession(sessionId: string): void {
|
||||
const stmt = this.db.prepare('DELETE FROM messages WHERE session_id = ?');
|
||||
stmt.run(sessionId);
|
||||
const transaction = this.db.transaction(() => {
|
||||
this.db.prepare('DELETE FROM messages WHERE session_id = ?').run(sessionId);
|
||||
this.db.prepare('DELETE FROM session_config WHERE session_id = ?').run(sessionId);
|
||||
});
|
||||
transaction();
|
||||
}
|
||||
|
||||
listSessions(): string[] {
|
||||
@@ -98,10 +108,12 @@ export class SessionStore {
|
||||
|
||||
if (stale.length === 0) {return [];}
|
||||
|
||||
const deleteStmt = this.db.prepare('DELETE FROM messages WHERE session_id = ?');
|
||||
const deleteMessages = this.db.prepare('DELETE FROM messages WHERE session_id = ?');
|
||||
const deleteConfig = this.db.prepare('DELETE FROM session_config WHERE session_id = ?');
|
||||
const transaction = this.db.transaction(() => {
|
||||
for (const { session_id } of stale) {
|
||||
deleteStmt.run(session_id);
|
||||
deleteMessages.run(session_id);
|
||||
deleteConfig.run(session_id);
|
||||
}
|
||||
});
|
||||
transaction();
|
||||
@@ -136,6 +148,49 @@ export class SessionStore {
|
||||
};
|
||||
}
|
||||
|
||||
/** Get a single config value for a session. */
|
||||
getSessionConfig(sessionId: string, key: string): string | undefined {
|
||||
const stmt = this.db.prepare(
|
||||
'SELECT value FROM session_config WHERE session_id = ? AND key = ?',
|
||||
);
|
||||
const row = stmt.get(sessionId, key) as { value: string } | undefined;
|
||||
return row?.value;
|
||||
}
|
||||
|
||||
/** Get all config values for a session. */
|
||||
getAllSessionConfig(sessionId: string): Record<string, string> {
|
||||
const stmt = this.db.prepare(
|
||||
'SELECT key, value FROM session_config WHERE session_id = ?',
|
||||
);
|
||||
const rows = stmt.all(sessionId) as Array<{ key: string; value: string }>;
|
||||
const result: Record<string, string> = {};
|
||||
for (const row of rows) {
|
||||
result[row.key] = row.value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Set a config value for a session. Upserts (INSERT OR REPLACE). */
|
||||
setSessionConfig(sessionId: string, key: string, value: string): void {
|
||||
this.db.prepare(
|
||||
'INSERT OR REPLACE INTO session_config (session_id, key, value) VALUES (?, ?, ?)',
|
||||
).run(sessionId, key, value);
|
||||
}
|
||||
|
||||
/** Delete a config value for a session. */
|
||||
deleteSessionConfig(sessionId: string, key: string): void {
|
||||
this.db.prepare(
|
||||
'DELETE FROM session_config WHERE session_id = ? AND key = ?',
|
||||
).run(sessionId, key);
|
||||
}
|
||||
|
||||
/** Delete all config for a session (used when session is cleared/pruned). */
|
||||
clearSessionConfig(sessionId: string): void {
|
||||
this.db.prepare(
|
||||
'DELETE FROM session_config WHERE session_id = ?',
|
||||
).run(sessionId);
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.db.close();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user