feat(gateway): PreferencesService + /preferences REST + /system Valkey override (P8-011)
- PreferencesService: platform defaults, user overrides, IMMUTABLE_KEYS enforcement - PreferencesController: GET /api/preferences, POST /api/preferences, DELETE /api/preferences/:key - PreferencesModule: global module exporting PreferencesService and SystemOverrideService - SystemOverrideService: Valkey-backed session-scoped system prompt override with 5-min TTL + renew - CommandRegistryService: register /system command (socket execution) - CommandExecutorService: handle /system command via SystemOverrideService - AgentService: inject system override before each prompt turn, renew TTL; store userId in session - ChatGateway: pass userId when creating agent sessions - PreferencesService unit tests: 11 tests covering defaults, overrides, enforcement wins, immutable key errors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
33
apps/gateway/src/preferences/system-override.service.ts
Normal file
33
apps/gateway/src/preferences/system-override.service.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { createQueue, type QueueHandle } from '@mosaic/queue';
|
||||
|
||||
const SESSION_SYSTEM_KEY = (sessionId: string) => `mosaic:session:${sessionId}:system`;
|
||||
const TTL_SECONDS = 5 * 60; // 5 minutes, renewed on each turn
|
||||
|
||||
@Injectable()
|
||||
export class SystemOverrideService {
|
||||
private readonly logger = new Logger(SystemOverrideService.name);
|
||||
private readonly handle: QueueHandle;
|
||||
|
||||
constructor() {
|
||||
this.handle = createQueue();
|
||||
}
|
||||
|
||||
async set(sessionId: string, override: string): Promise<void> {
|
||||
await this.handle.redis.setex(SESSION_SYSTEM_KEY(sessionId), TTL_SECONDS, override);
|
||||
this.logger.debug(`Set system override for session ${sessionId} (TTL=${TTL_SECONDS}s)`);
|
||||
}
|
||||
|
||||
async get(sessionId: string): Promise<string | null> {
|
||||
return this.handle.redis.get(SESSION_SYSTEM_KEY(sessionId));
|
||||
}
|
||||
|
||||
async renew(sessionId: string): Promise<void> {
|
||||
await this.handle.redis.expire(SESSION_SYSTEM_KEY(sessionId), TTL_SECONDS);
|
||||
}
|
||||
|
||||
async clear(sessionId: string): Promise<void> {
|
||||
await this.handle.redis.del(SESSION_SYSTEM_KEY(sessionId));
|
||||
this.logger.debug(`Cleared system override for session ${sessionId}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user