diff --git a/backend/package.json b/backend/package.json index d26e545..ad60e40 100644 --- a/backend/package.json +++ b/backend/package.json @@ -29,6 +29,7 @@ "@bytelyst/fastify-core": "^0.1.0", "@bytelyst/field-encrypt": "^0.1.0", "@bytelyst/llm": "file:../../learning_ai_common_plat/packages/llm", + "@bytelyst/palace": "file:../../learning_ai_common_plat/packages/palace", "@bytelyst/logger": "^0.1.0", "fastify": "5.7.4", "jose": "^6.0.8", diff --git a/backend/src/lib/config.ts b/backend/src/lib/config.ts index ad3479a..eb30e1a 100644 --- a/backend/src/lib/config.ts +++ b/backend/src/lib/config.ts @@ -25,6 +25,12 @@ const envSchema = baseBackendConfigSchema.extend({ FIELD_ENCRYPT_KEY: z.string().default(''), FIELD_ENCRYPT_MEK_NAME: z.string().default('notelett-mek'), AZURE_KEYVAULT_URL: z.string().default(''), + // ── Palace (MemPalace) ── + PALACE_ENABLED: z.coerce.boolean().default(true), + PALACE_EXTRACTION_ENABLED: z.coerce.boolean().default(true), + PALACE_WAKE_UP_BUDGET: z.coerce.number().int().min(100).default(600), + PALACE_RELEVANCE_HALF_LIFE_DAYS: z.coerce.number().int().min(1).default(90), + PALACE_DEDUP_THRESHOLD: z.coerce.number().min(0).max(1).default(0.90), }); export const config = envSchema.parse(process.env); diff --git a/backend/src/lib/cosmos-init.ts b/backend/src/lib/cosmos-init.ts index ad4569b..0021e41 100644 --- a/backend/src/lib/cosmos-init.ts +++ b/backend/src/lib/cosmos-init.ts @@ -18,6 +18,13 @@ const CONTAINER_DEFS: Record = { note_intake_rules: { partitionKeyPath: '/userId' }, note_intake_jobs: { partitionKeyPath: '/userId' }, note_collaborators: { partitionKeyPath: '/sharedWithUserId' }, + // ── Palace (MemPalace) ── + palace_wings: { partitionKeyPath: '/userId' }, + palace_rooms: { partitionKeyPath: '/userId' }, + palace_memories: { partitionKeyPath: '/userId' }, + palace_tunnels: { partitionKeyPath: '/userId' }, + palace_kg: { partitionKeyPath: '/userId' }, + palace_diaries: { partitionKeyPath: '/userId' }, }; export async function initCosmosIfNeeded(): Promise { diff --git a/backend/src/modules/palace/types.ts b/backend/src/modules/palace/types.ts new file mode 100644 index 0000000..6b7fd98 --- /dev/null +++ b/backend/src/modules/palace/types.ts @@ -0,0 +1,74 @@ +import { z } from 'zod'; +import type { BasePalaceWingDoc, BasePalaceRoomDoc, BasePalaceMemoryDoc, BasePalaceTunnelDoc, BasePalaceKGTripleDoc, BasePalaceDiaryDoc } from '@bytelyst/palace'; + +// ── Hall Types (NoteLett preset) ──────────────────────────────────── + +export const HALL_TYPES = ['decisions', 'events', 'discoveries', 'preferences', 'advice', 'insights'] as const; +export type HallType = (typeof HALL_TYPES)[number]; + +// ── NoteLett-specific palace document types ───────────────────────── + +export interface PalaceWingDoc extends BasePalaceWingDoc { + sourceWorkspaceId: string; + techStack?: string; +} + +export interface PalaceRoomDoc extends BasePalaceRoomDoc {} + +export interface PalaceMemoryDoc extends BasePalaceMemoryDoc { + hall: HallType; + sourceNoteId?: string; + sourceTaskId?: string; +} + +export interface PalaceTunnelDoc extends BasePalaceTunnelDoc { + roomA: string; + roomB: string; + reason: string; +} + +export interface PalaceKGTripleDoc extends BasePalaceKGTripleDoc { + sourceTaskId?: string; +} + +export interface PalaceDiaryDoc extends BasePalaceDiaryDoc {} + +// ── Zod Schemas ───────────────────────────────────────────────────── + +export const PalaceSearchQuerySchema = z.object({ + q: z.string().min(1).max(500), + wingId: z.string().max(128).optional(), + roomId: z.string().max(128).optional(), + hall: z.enum(HALL_TYPES).optional(), + limit: z.coerce.number().int().min(1).max(50).default(10), +}); + +export const StoreMemorySchema = z.object({ + wingId: z.string().min(1).max(128), + roomId: z.string().min(1).max(128), + hall: z.enum(HALL_TYPES), + content: z.string().min(1).max(5000), + sourceNoteId: z.string().max(128).optional(), +}); + +export const PruneRequestSchema = z.object({ + wingId: z.string().min(1).max(128).optional(), + olderThanDays: z.coerce.number().int().min(1).default(180), + minRelevance: z.coerce.number().min(0).max(1).default(0.1), +}); + +export const KGEntityQuerySchema = z.object({ + entity: z.string().min(1).max(256), + wingId: z.string().max(128).optional(), + asOf: z.string().max(30).optional(), +}); + +export const WakeUpQuerySchema = z.object({ + task: z.string().max(500).optional(), +}); + +export type PalaceSearchQuery = z.infer; +export type StoreMemoryInput = z.infer; +export type PruneRequest = z.infer; +export type KGEntityQuery = z.infer; +export type WakeUpQuery = z.infer; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f5d61e..a6421d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: '@bytelyst/logger': specifier: ^0.1.0 version: 0.1.0 + '@bytelyst/palace': + specifier: file:../../learning_ai_common_plat/packages/palace + version: file:../learning_ai_common_plat/packages/palace(zod@3.25.76) fastify: specifier: 5.7.4 version: 5.7.4 @@ -1039,6 +1042,11 @@ packages: '@bytelyst/offline-queue@0.1.0': resolution: {integrity: sha512-JOW9B1mQ6hp29qAsRcCzSa9KWyzds01K2KnP7J3QtgFErdrkPGUJa2WajVeyrG31dSHC3awQPKglddxUJ6IFGw==, tarball: http://localhost:3300/api/packages/bytelyst/npm/%40bytelyst%2Foffline-queue/-/0.1.0/offline-queue-0.1.0.tgz} + '@bytelyst/palace@file:../learning_ai_common_plat/packages/palace': + resolution: {directory: ../learning_ai_common_plat/packages/palace, type: directory} + peerDependencies: + zod: ^3.0.0 + '@bytelyst/platform-client@0.1.0': resolution: {integrity: sha512-KmlxcYp4mFuhdTCj8QT+1QGXtk1ViM1hGqGrO7qMhy+IEnjFHsqMxboArUpR/ZTqWNXa1SrH4w7ws29xtjUO1w==, tarball: http://localhost:3300/api/packages/bytelyst/npm/%40bytelyst%2Fplatform-client/-/0.1.0/platform-client-0.1.0.tgz} @@ -7229,6 +7237,10 @@ snapshots: '@bytelyst/offline-queue@0.1.0': {} + '@bytelyst/palace@file:../learning_ai_common_plat/packages/palace(zod@3.25.76)': + dependencies: + zod: 3.25.76 + '@bytelyst/platform-client@0.1.0': {} '@bytelyst/queue@0.1.0': {} @@ -8513,9 +8525,7 @@ snapshots: metro-runtime: 0.83.5 transitivePeerDependencies: - '@babel/core' - - bufferutil - supports-color - - utf-8-validate '@react-native/normalize-colors@0.83.2': {} @@ -10136,7 +10146,7 @@ snapshots: eslint: 9.39.4(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.4(jiti@2.6.1)) @@ -10169,7 +10179,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -10247,7 +10257,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): + eslint-plugin-import@2.32.0(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9