Files
stack/apps/gateway/src/memory/memory.controller.ts
Jarvis 774b76447d
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/push/ci Pipeline failed
fix: rename all packages from @mosaic/* to @mosaicstack/*
- Updated all package.json name fields and dependency references
- Updated all TypeScript/JavaScript imports
- Updated .woodpecker/publish.yml filters and registry paths
- Updated tools/install.sh scope default
- Updated .npmrc registry paths (worktree + host)
- Enhanced update-checker.ts with checkForAllUpdates() multi-package support
- Updated CLI update command to show table of all packages
- Added KNOWN_PACKAGES, formatAllPackagesTable, getInstallAllCommand
- Marked checkForUpdate() with @deprecated JSDoc

Closes #391
2026-04-04 21:43:23 -05:00

128 lines
4.3 KiB
TypeScript

import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
Inject,
NotFoundException,
Param,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import type { Memory } from '@mosaicstack/memory';
import { MEMORY } from './memory.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js';
import { EmbeddingService } from './embedding.service.js';
import type { UpsertPreferenceDto, CreateInsightDto, SearchMemoryDto } from './memory.dto.js';
@Controller('api/memory')
@UseGuards(AuthGuard)
export class MemoryController {
constructor(
@Inject(MEMORY) private readonly memory: Memory,
@Inject(EmbeddingService) private readonly embeddings: EmbeddingService,
) {}
// ─── Preferences ────────────────────────────────────────────────────
@Get('preferences')
async listPreferences(@CurrentUser() user: { id: string }, @Query('category') category?: string) {
if (category) {
return this.memory.preferences.findByUserAndCategory(
user.id,
category as Parameters<typeof this.memory.preferences.findByUserAndCategory>[1],
);
}
return this.memory.preferences.findByUser(user.id);
}
@Get('preferences/:key')
async getPreference(@CurrentUser() user: { id: string }, @Param('key') key: string) {
const pref = await this.memory.preferences.findByUserAndKey(user.id, key);
if (!pref) throw new NotFoundException('Preference not found');
return pref;
}
@Post('preferences')
async upsertPreference(@CurrentUser() user: { id: string }, @Body() dto: UpsertPreferenceDto) {
return this.memory.preferences.upsert({
userId: user.id,
key: dto.key,
value: dto.value,
category: dto.category,
source: dto.source,
});
}
@Delete('preferences/:key')
@HttpCode(HttpStatus.NO_CONTENT)
async removePreference(@CurrentUser() user: { id: string }, @Param('key') key: string) {
const deleted = await this.memory.preferences.remove(user.id, key);
if (!deleted) throw new NotFoundException('Preference not found');
}
// ─── Insights ───────────────────────────────────────────────────────
@Get('insights')
async listInsights(@CurrentUser() user: { id: string }, @Query('limit') limit?: string) {
return this.memory.insights.findByUser(user.id, limit ? Number(limit) : undefined);
}
@Get('insights/:id')
async getInsight(@CurrentUser() user: { id: string }, @Param('id') id: string) {
const insight = await this.memory.insights.findById(id, user.id);
if (!insight) throw new NotFoundException('Insight not found');
return insight;
}
@Post('insights')
async createInsight(@CurrentUser() user: { id: string }, @Body() dto: CreateInsightDto) {
const embedding = this.embeddings.available
? await this.embeddings.embed(dto.content)
: undefined;
return this.memory.insights.create({
userId: user.id,
content: dto.content,
source: dto.source,
category: dto.category,
metadata: dto.metadata,
embedding: embedding ?? null,
});
}
@Delete('insights/:id')
@HttpCode(HttpStatus.NO_CONTENT)
async removeInsight(@CurrentUser() user: { id: string }, @Param('id') id: string) {
const deleted = await this.memory.insights.remove(id, user.id);
if (!deleted) throw new NotFoundException('Insight not found');
}
// ─── Search ─────────────────────────────────────────────────────────
@Post('search')
async searchMemory(@CurrentUser() user: { id: string }, @Body() dto: SearchMemoryDto) {
if (!this.embeddings.available) {
return {
query: dto.query,
results: [],
message: 'Semantic search requires OPENAI_API_KEY for embeddings',
};
}
const queryEmbedding = await this.embeddings.embed(dto.query);
const results = await this.memory.insights.searchByEmbedding(
user.id,
queryEmbedding,
dto.limit ?? 10,
dto.maxDistance ?? 0.8,
);
return { query: dto.query, results };
}
}