@usewhisper/mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -0
- package/dist/server.js +1648 -0
- package/dist/server.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/server.ts","../../src/db/index.ts","../../src/db/schema.ts","../../src/engine/retriever.ts","../../src/engine/embeddings.ts","../../src/engine/compressor.ts","../../src/engine/ingest.ts","../../src/engine/chunker.ts","../../src/engine/extractor.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { db, projects, sources, memories, conversations, messages } from \"../db/index.js\";\nimport { eq, and, sql, desc } from \"drizzle-orm\";\nimport { retrieve } from \"../engine/retriever.js\";\nimport { ingestDocument } from \"../engine/ingest.js\";\nimport { embedSingle } from \"../engine/embeddings.js\";\n\nconst ORG_ID = process.env.WHISPER_ORG_ID || \"\";\n\nconst server = new McpServer({\n name: \"whisper-context\",\n version: \"0.1.0\",\n});\n\nasync function resolveProject(name: string) {\n const [proj] = await db\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.orgId, ORG_ID),\n sql`(${projects.name} = ${name} OR ${projects.slug} = ${name})`\n )\n )\n .limit(1);\n return proj;\n}\n\n// ─── query_context ──────────────────────────────────────────\n\nserver.tool(\n \"query_context\",\n \"Search your knowledge base for relevant context. Returns packed context ready for LLM consumption. Supports hybrid vector+keyword search, memory inclusion, and knowledge graph traversal.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"What are you looking for?\"),\n top_k: z.number().optional().default(10).describe(\"Number of results\"),\n chunk_types: z.array(z.string()).optional().describe(\"Filter: code, function, class, documentation, api_spec, schema, config, text\"),\n include_memories: z.boolean().optional().default(false).describe(\"Include relevant memories\"),\n include_graph: z.boolean().optional().default(false).describe(\"Include knowledge graph traversal\"),\n user_id: z.string().optional().describe(\"User ID for memory scoping\"),\n session_id: z.string().optional().describe(\"Session ID for memory scoping\"),\n max_tokens: z.number().optional().describe(\"Max tokens for packed context\"),\n },\n async ({ project, query, top_k, chunk_types, include_memories, include_graph, user_id, session_id, max_tokens }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const response = await retrieve({\n projectId: proj.id,\n query,\n topK: top_k,\n chunkTypes: chunk_types,\n includeMemories: include_memories,\n includeGraph: include_graph,\n userId: user_id,\n sessionId: session_id,\n maxTokens: max_tokens,\n });\n\n if (response.results.length === 0) {\n return { content: [{ type: \"text\" as const, text: \"No relevant context found.\" }] };\n }\n\n const header = `Found ${response.meta.totalResults} results (${response.meta.latencyMs}ms${response.meta.cacheHit ? \", cached\" : \"\"}):\\n\\n`;\n return { content: [{ type: \"text\" as const, text: header + response.context }] };\n }\n);\n\n// ─── add_memory ─────────────────────────────────────────────\n\nserver.tool(\n \"add_memory\",\n \"Store a memory (fact, preference, decision) that persists across conversations. Memories can be scoped to a user, session, or agent.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n content: z.string().describe(\"The memory content to store\"),\n memory_type: z.enum([\"factual\", \"episodic\", \"semantic\", \"procedural\"]).optional().default(\"factual\"),\n user_id: z.string().optional().describe(\"User this memory belongs to\"),\n session_id: z.string().optional().describe(\"Session scope\"),\n agent_id: z.string().optional().describe(\"Agent scope\"),\n importance: z.number().optional().default(0.5).describe(\"Importance 0-1\"),\n },\n async ({ project, content, memory_type, user_id, session_id, agent_id, importance }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const embedding = await embedSingle(content);\n const [memory] = await db\n .insert(memories)\n .values({\n projectId: proj.id,\n content,\n memoryType: memory_type,\n userId: user_id,\n sessionId: session_id,\n agentId: agent_id,\n importance,\n embedding,\n })\n .returning();\n\n return { content: [{ type: \"text\" as const, text: `Memory stored (id: ${memory.id}, type: ${memory_type}).` }] };\n }\n);\n\n// ─── search_memories ────────────────────────────────────────\n\nserver.tool(\n \"search_memories\",\n \"Search stored memories by semantic similarity. Recall facts, preferences, past decisions from previous interactions.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"What to search for\"),\n user_id: z.string().optional().describe(\"Filter by user\"),\n session_id: z.string().optional().describe(\"Filter by session\"),\n top_k: z.number().optional().default(10).describe(\"Number of results\"),\n },\n async ({ project, query, user_id, session_id, top_k }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const queryEmbedding = await embedSingle(query);\n const conditions: any[] = [\n eq(memories.projectId, proj.id),\n eq(memories.isActive, true),\n sql`(${memories.expiresAt} IS NULL OR ${memories.expiresAt} > NOW())`,\n ];\n if (user_id) conditions.push(eq(memories.userId, user_id));\n if (session_id) conditions.push(eq(memories.sessionId, session_id));\n\n const results = await db\n .select({\n id: memories.id,\n content: memories.content,\n memoryType: memories.memoryType,\n importance: memories.importance,\n similarity: sql<number>`1 - (${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(memories)\n .where(and(...conditions))\n .orderBy(sql`${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(top_k);\n\n if (results.length === 0) return { content: [{ type: \"text\" as const, text: \"No memories found.\" }] };\n\n const text = results\n .map((r, i) => `${i + 1}. [${r.memoryType}, importance: ${r.importance}, score: ${(r.similarity as number).toFixed(3)}]\\n${r.content}`)\n .join(\"\\n\\n\");\n\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── list_projects ──────────────────────────────────────────\n\nserver.tool(\n \"list_projects\",\n \"List all available context projects.\",\n {},\n async () => {\n const projs = await db.select().from(projects).where(eq(projects.orgId, ORG_ID));\n const text = projs.length === 0\n ? \"No projects found.\"\n : projs.map((p) => `- ${p.name} (${p.slug})${p.description ? `: ${p.description}` : \"\"}`).join(\"\\n\");\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── list_sources ───────────────────────────────────────────\n\nserver.tool(\n \"list_sources\",\n \"List all data sources connected to a project.\",\n { project: z.string().describe(\"Project name or slug\") },\n async ({ project }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const srcs = await db.select().from(sources).where(eq(sources.projectId, proj.id));\n const text = srcs.length === 0\n ? \"No sources connected.\"\n : srcs.map((s) => `- ${s.name} (${s.connectorType}) — ${s.status} | ${s.documentCount} docs, ${s.chunkCount} chunks`).join(\"\\n\");\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── add_context ────────────────────────────────────────────\n\nserver.tool(\n \"add_context\",\n \"Add text content to a project's knowledge base.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n title: z.string().describe(\"Title for this content\"),\n content: z.string().describe(\"The text content to index\"),\n },\n async ({ project, title, content }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n let [directSource] = await db\n .select().from(sources)\n .where(and(eq(sources.projectId, proj.id), eq(sources.connectorType, \"custom\"), eq(sources.name, \"mcp-ingest\")))\n .limit(1);\n\n if (!directSource) {\n [directSource] = await db\n .insert(sources)\n .values({ projectId: proj.id, name: \"mcp-ingest\", connectorType: \"custom\", config: {}, status: \"ready\" })\n .returning();\n }\n\n await ingestDocument({ sourceId: directSource.id, projectId: proj.id, externalId: `mcp-${title}`, title, content });\n return { content: [{ type: \"text\" as const, text: `Indexed \"${title}\" (${content.length} chars) into '${project}'.` }] };\n }\n);\n\n// ─── track_conversation ─────────────────────────────────────\n\nserver.tool(\n \"track_conversation\",\n \"Add a message to a conversation. Creates the conversation if it doesn't exist.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Unique session identifier\"),\n role: z.enum([\"user\", \"assistant\", \"system\", \"tool\"]),\n content: z.string().describe(\"Message content\"),\n user_id: z.string().optional().describe(\"User identifier\"),\n },\n async ({ project, session_id, role, content, user_id }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n let [conv] = await db\n .select().from(conversations)\n .where(and(eq(conversations.projectId, proj.id), eq(conversations.sessionId, session_id)))\n .limit(1);\n\n if (!conv) {\n [conv] = await db\n .insert(conversations)\n .values({ projectId: proj.id, sessionId: session_id, userId: user_id })\n .returning();\n }\n\n await db.insert(messages).values({ conversationId: conv.id, role, content });\n await db.update(conversations)\n .set({ messageCount: sql`${conversations.messageCount} + 1`, updatedAt: new Date() })\n .where(eq(conversations.id, conv.id));\n\n return { content: [{ type: \"text\" as const, text: `Message added (session: ${session_id}).` }] };\n }\n);\n\n// ─── get_conversation ───────────────────────────────────────\n\nserver.tool(\n \"get_conversation\",\n \"Retrieve conversation history for a session.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Session identifier\"),\n limit: z.number().optional().default(50),\n },\n async ({ project, session_id, limit }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const [conv] = await db\n .select().from(conversations)\n .where(and(eq(conversations.projectId, proj.id), eq(conversations.sessionId, session_id)))\n .limit(1);\n\n if (!conv) return { content: [{ type: \"text\" as const, text: \"No conversation found for this session.\" }] };\n\n const msgs = await db.select().from(messages)\n .where(eq(messages.conversationId, conv.id))\n .orderBy(messages.createdAt)\n .limit(limit);\n\n const text = msgs.map((m) => `[${m.role}]: ${m.content}`).join(\"\\n\\n\");\n return { content: [{ type: \"text\" as const, text: text || \"No messages yet.\" }] };\n }\n);\n\n// ─── Start ──────────────────────────────────────────────────\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"Whisper Context MCP server running on stdio\");\n}\n\nmain().catch(console.error);\n","import { drizzle } from \"drizzle-orm/postgres-js\";\nimport postgres from \"postgres\";\nimport * as schema from \"./schema.js\";\n\nconst connectionString = process.env.DATABASE_URL!;\n\nconst client = postgres(connectionString, { max: 10 });\n\nexport const db = drizzle(client, { schema });\n\nexport * from \"./schema.js\";\n","import {\n pgTable,\n uuid,\n text,\n timestamp,\n integer,\n boolean,\n jsonb,\n vector,\n index,\n uniqueIndex,\n pgEnum,\n real,\n serial,\n} from \"drizzle-orm/pg-core\";\n\n// ─── Enums ───────────────────────────────────────────────────\n\nexport const connectorTypeEnum = pgEnum(\"connector_type\", [\n \"github\",\n \"gitlab\",\n \"url\",\n \"sitemap\",\n \"text\",\n \"pdf\",\n \"api_spec\",\n \"database\",\n \"confluence\",\n \"notion\",\n \"slack\",\n \"discord\",\n \"arxiv\",\n \"huggingface\",\n \"npm_package\",\n \"pypi_package\",\n \"custom\",\n]);\n\nexport const sourceStatusEnum = pgEnum(\"source_status\", [\n \"pending\",\n \"indexing\",\n \"ready\",\n \"failed\",\n \"stale\",\n \"syncing\",\n]);\n\nexport const chunkTypeEnum = pgEnum(\"chunk_type\", [\n \"code\",\n \"function\",\n \"class\",\n \"documentation\",\n \"api_spec\",\n \"schema\",\n \"config\",\n \"text\",\n \"comment\",\n \"readme\",\n \"research\",\n \"conversation\",\n \"dataset\",\n]);\n\nexport const memoryTypeEnum = pgEnum(\"memory_type\", [\n \"factual\", // structured facts: \"user prefers TypeScript\"\n \"episodic\", // past interaction summaries\n \"semantic\", // general knowledge\n \"procedural\", // how-to knowledge\n]);\n\nexport const relationTypeEnum = pgEnum(\"relation_type\", [\n \"imports\",\n \"exports\",\n \"calls\",\n \"implements\",\n \"extends\",\n \"references\",\n \"depends_on\",\n \"related_to\",\n \"part_of\",\n \"contradicts\",\n \"supersedes\",\n]);\n\n// ─── Organizations & Auth ────────────────────────────────────\n\nexport const organizations = pgTable(\n \"organizations\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n whisperOrgId: text(\"whisper_org_id\").unique(), // link to main Whisper org\n name: text(\"name\").notNull(),\n plan: text(\"plan\").default(\"free\").notNull(), // free, pro, enterprise\n settings: jsonb(\"settings\").$type<{\n defaultEmbeddingModel?: string;\n defaultChunkSize?: number;\n maxSources?: number;\n maxDocuments?: number;\n maxQueriesPerDay?: number;\n }>().default({}),\n usageLimits: jsonb(\"usage_limits\").$type<{\n queriesPerDay: number;\n documentsTotal: number;\n sourcesTotal: number;\n storageBytes: number;\n }>().default({\n queriesPerDay: 1000,\n documentsTotal: 10000,\n sourcesTotal: 50,\n storageBytes: 1073741824, // 1GB\n }),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"orgs_whisper_org_idx\").on(t.whisperOrgId),\n ]\n);\n\nexport const apiKeys = pgTable(\n \"api_keys\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n name: text(\"name\").notNull(),\n keyHash: text(\"key_hash\").notNull(),\n keyPrefix: text(\"key_prefix\").notNull(), // \"wctx_xxxx\" for identification\n scopes: jsonb(\"scopes\").$type<string[]>().default([\"read\", \"write\"]),\n rateLimit: integer(\"rate_limit\").default(100), // requests per minute\n lastUsedAt: timestamp(\"last_used_at\"),\n expiresAt: timestamp(\"expires_at\"),\n isActive: boolean(\"is_active\").default(true).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"api_keys_hash_idx\").on(t.keyHash),\n index(\"api_keys_org_idx\").on(t.orgId),\n index(\"api_keys_prefix_idx\").on(t.keyPrefix),\n ]\n);\n\n// ─── Projects (Knowledge Bases) ──────────────────────────────\n\nexport const projects = pgTable(\n \"projects\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n name: text(\"name\").notNull(),\n slug: text(\"slug\").notNull(),\n description: text(\"description\"),\n settings: jsonb(\"settings\").$type<{\n embeddingModel?: string;\n embeddingDimensions?: number;\n chunkSize?: number;\n chunkOverlap?: number;\n rerankModel?: string;\n defaultTopK?: number;\n defaultThreshold?: number;\n }>().default({\n embeddingModel: \"text-embedding-3-small\",\n embeddingDimensions: 1536,\n chunkSize: 1000,\n chunkOverlap: 200,\n defaultTopK: 10,\n defaultThreshold: 0.3,\n }),\n isPublic: boolean(\"is_public\").default(false).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"projects_org_slug_idx\").on(t.orgId, t.slug),\n index(\"projects_org_idx\").on(t.orgId),\n index(\"projects_public_idx\").on(t.isPublic),\n ]\n);\n\n// ─── Data Sources ────────────────────────────────────────────\n\nexport const sources = pgTable(\n \"sources\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n connectorType: connectorTypeEnum(\"connector_type\").notNull(),\n name: text(\"name\").notNull(),\n config: jsonb(\"config\").$type<Record<string, any>>().default({}),\n status: sourceStatusEnum(\"status\").default(\"pending\").notNull(),\n syncSchedule: text(\"sync_schedule\"), // cron expression for auto-sync\n lastSyncAt: timestamp(\"last_sync_at\"),\n lastSyncDurationMs: integer(\"last_sync_duration_ms\"),\n syncError: text(\"sync_error\"),\n documentCount: integer(\"document_count\").default(0),\n chunkCount: integer(\"chunk_count\").default(0),\n contentHash: text(\"content_hash\"), // for change detection\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"sources_project_idx\").on(t.projectId),\n index(\"sources_status_idx\").on(t.status),\n index(\"sources_type_idx\").on(t.connectorType),\n ]\n);\n\n// ─── Documents ───────────────────────────────────────────────\n\nexport const documents = pgTable(\n \"documents\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n sourceId: uuid(\"source_id\")\n .notNull()\n .references(() => sources.id, { onDelete: \"cascade\" }),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n externalId: text(\"external_id\"),\n title: text(\"title\"),\n content: text(\"content\"),\n contentHash: text(\"content_hash\"),\n url: text(\"url\"),\n language: text(\"language\"), // programming language or natural language\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n tokenCount: integer(\"token_count\").default(0),\n isActive: boolean(\"is_active\").default(true).notNull(),\n lastIndexedAt: timestamp(\"last_indexed_at\"),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"documents_source_idx\").on(t.sourceId),\n index(\"documents_project_idx\").on(t.projectId),\n uniqueIndex(\"documents_source_external_idx\").on(t.sourceId, t.externalId),\n index(\"documents_hash_idx\").on(t.contentHash),\n index(\"documents_active_idx\").on(t.projectId, t.isActive),\n ]\n);\n\n// ─── Chunks (with vector embeddings) ─────────────────────────\n\nexport const chunks = pgTable(\n \"chunks\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n documentId: uuid(\"document_id\")\n .notNull()\n .references(() => documents.id, { onDelete: \"cascade\" }),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n content: text(\"content\").notNull(),\n chunkType: chunkTypeEnum(\"chunk_type\").default(\"text\").notNull(),\n chunkIndex: integer(\"chunk_index\").default(0),\n // Search\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n // Full-text search column (populated via trigger or app)\n searchContent: text(\"search_content\"), // stripped/normalized for BM25\n // Metadata\n metadata: jsonb(\"metadata\").$type<{\n filePath?: string;\n language?: string;\n startLine?: number;\n endLine?: number;\n functionName?: string;\n className?: string;\n url?: string;\n title?: string;\n section?: string;\n parentChunkId?: string;\n [key: string]: any;\n }>().default({}),\n tokenCount: integer(\"token_count\").default(0),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"chunks_document_idx\").on(t.documentId),\n index(\"chunks_project_idx\").on(t.projectId),\n index(\"chunks_type_idx\").on(t.chunkType),\n index(\"chunks_project_type_idx\").on(t.projectId, t.chunkType),\n ]\n);\n\n// ─── Graph: Entity Relationships ─────────────────────────────\n\nexport const entities = pgTable(\n \"entities\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n name: text(\"name\").notNull(),\n entityType: text(\"entity_type\").notNull(), // function, class, module, concept, api_endpoint, etc.\n description: text(\"description\"),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n sourceChunkId: uuid(\"source_chunk_id\").references(() => chunks.id, { onDelete: \"set null\" }),\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"entities_project_idx\").on(t.projectId),\n index(\"entities_type_idx\").on(t.projectId, t.entityType),\n uniqueIndex(\"entities_project_name_type_idx\").on(t.projectId, t.name, t.entityType),\n ]\n);\n\nexport const relations = pgTable(\n \"relations\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n fromEntityId: uuid(\"from_entity_id\")\n .notNull()\n .references(() => entities.id, { onDelete: \"cascade\" }),\n toEntityId: uuid(\"to_entity_id\")\n .notNull()\n .references(() => entities.id, { onDelete: \"cascade\" }),\n relationType: relationTypeEnum(\"relation_type\").notNull(),\n weight: real(\"weight\").default(1.0),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"relations_project_idx\").on(t.projectId),\n index(\"relations_from_idx\").on(t.fromEntityId),\n index(\"relations_to_idx\").on(t.toEntityId),\n uniqueIndex(\"relations_unique_idx\").on(t.fromEntityId, t.toEntityId, t.relationType),\n ]\n);\n\n// ─── Memories (user/session/agent scoped) ────────────────────\n\nexport const memories = pgTable(\n \"memories\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n // Scoping\n userId: text(\"user_id\"), // user-scoped memory\n sessionId: text(\"session_id\"), // session-scoped memory\n agentId: text(\"agent_id\"), // agent-scoped memory\n // Memory content\n memoryType: memoryTypeEnum(\"memory_type\").default(\"factual\").notNull(),\n content: text(\"content\").notNull(),\n summary: text(\"summary\"), // LLM-generated summary\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n // Management\n importance: real(\"importance\").default(0.5), // 0-1 how important is this\n accessCount: integer(\"access_count\").default(0),\n lastAccessedAt: timestamp(\"last_accessed_at\"),\n expiresAt: timestamp(\"expires_at\"), // optional TTL\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n isActive: boolean(\"is_active\").default(true).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"memories_project_idx\").on(t.projectId),\n index(\"memories_user_idx\").on(t.projectId, t.userId),\n index(\"memories_session_idx\").on(t.projectId, t.sessionId),\n index(\"memories_agent_idx\").on(t.projectId, t.agentId),\n index(\"memories_type_idx\").on(t.projectId, t.memoryType),\n index(\"memories_active_idx\").on(t.projectId, t.isActive),\n index(\"memories_expires_idx\").on(t.expiresAt),\n ]\n);\n\n// ─── Conversations (context sharing) ─────────────────────────\n\nexport const conversations = pgTable(\n \"conversations\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n sessionId: text(\"session_id\"),\n userId: text(\"user_id\"),\n agentId: text(\"agent_id\"),\n title: text(\"title\"),\n summary: text(\"summary\"),\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n messageCount: integer(\"message_count\").default(0),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"conversations_project_idx\").on(t.projectId),\n index(\"conversations_session_idx\").on(t.sessionId),\n index(\"conversations_user_idx\").on(t.userId),\n ]\n);\n\nexport const messages = pgTable(\n \"messages\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n conversationId: uuid(\"conversation_id\")\n .notNull()\n .references(() => conversations.id, { onDelete: \"cascade\" }),\n role: text(\"role\").notNull(), // user, assistant, system, tool\n content: text(\"content\").notNull(),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"messages_conversation_idx\").on(t.conversationId),\n index(\"messages_created_idx\").on(t.conversationId, t.createdAt),\n ]\n);\n\n// ─── Webhooks ────────────────────────────────────────────────\n\nexport const webhooks = pgTable(\n \"webhooks\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n url: text(\"url\").notNull(),\n secret: text(\"secret\").notNull(),\n events: jsonb(\"events\").$type<string[]>().default([\n \"source.synced\",\n \"document.indexed\",\n \"memory.created\",\n ]),\n isActive: boolean(\"is_active\").default(true).notNull(),\n lastDeliveredAt: timestamp(\"last_delivered_at\"),\n failureCount: integer(\"failure_count\").default(0),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"webhooks_org_idx\").on(t.orgId),\n ]\n);\n\n// ─── Usage Tracking ──────────────────────────────────────────\n\nexport const usageEvents = pgTable(\n \"usage_events\",\n {\n id: serial(\"id\").primaryKey(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n projectId: uuid(\"project_id\"),\n eventType: text(\"event_type\").notNull(), // query, ingest, sync, memory_add, memory_search\n source: text(\"source\").default(\"api\"), // api, mcp, sdk, webhook\n tokensUsed: integer(\"tokens_used\").default(0),\n embeddingTokens: integer(\"embedding_tokens\").default(0),\n latencyMs: integer(\"latency_ms\"),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"usage_org_idx\").on(t.orgId),\n index(\"usage_project_idx\").on(t.projectId),\n index(\"usage_type_idx\").on(t.eventType),\n index(\"usage_created_idx\").on(t.createdAt),\n index(\"usage_org_created_idx\").on(t.orgId, t.createdAt),\n ]\n);\n\n// ─── Query Cache ─────────────────────────────────────────────\n\nexport const queryCache = pgTable(\n \"query_cache\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n queryHash: text(\"query_hash\").notNull(),\n query: text(\"query\").notNull(),\n results: jsonb(\"results\").$type<any[]>().default([]),\n hitCount: integer(\"hit_count\").default(0),\n expiresAt: timestamp(\"expires_at\").notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"cache_project_query_idx\").on(t.projectId, t.queryHash),\n index(\"cache_expires_idx\").on(t.expiresAt),\n ]\n);\n","import { db, chunks, documents, sources, memories, entities, relations, queryCache } from \"../db/index.js\";\nimport { eq, sql, and, inArray, or, desc, asc, isNull, gt } from \"drizzle-orm\";\nimport { embedSingle } from \"./embeddings.js\";\nimport { compressContext, type CompressionOptions } from \"./compressor.js\";\nimport { createHash } from \"crypto\";\nimport OpenAI from \"openai\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport interface RetrievalResult {\n id: string;\n content: string;\n score: number;\n metadata: Record<string, any>;\n documentTitle?: string;\n sourceName?: string;\n chunkType: string;\n source: \"vector\" | \"bm25\" | \"hybrid\" | \"memory\" | \"graph\";\n}\n\nexport interface QueryOptions {\n projectId: string;\n query: string;\n topK?: number;\n threshold?: number;\n chunkTypes?: string[];\n sourceIds?: string[];\n // Hybrid search\n hybridSearch?: boolean;\n vectorWeight?: number; // 0-1, default 0.7\n bm25Weight?: number; // 0-1, default 0.3\n // Reranking\n rerank?: boolean;\n rerankTopK?: number;\n // Memory inclusion\n includeMemories?: boolean;\n userId?: string;\n sessionId?: string;\n agentId?: string;\n // Graph\n includeGraph?: boolean;\n graphDepth?: number;\n // Context packing\n maxTokens?: number;\n // Compression\n compress?: boolean;\n compressionStrategy?: \"summarize\" | \"extract\" | \"delta\" | \"adaptive\";\n previousContextHash?: string;\n // Caching\n useCache?: boolean;\n cacheTtlSeconds?: number;\n}\n\nexport interface ContextResponse {\n results: RetrievalResult[];\n context: string; // packed context string ready for LLM\n meta: {\n totalResults: number;\n latencyMs: number;\n cacheHit: boolean;\n tokensUsed: number;\n contextHash?: string;\n compression?: {\n originalTokens: number;\n compressedTokens: number;\n reductionPercent: number;\n strategy: string;\n };\n };\n}\n\n// ─── Main Query Function ─────────────────────────────────────\n\nexport async function retrieve(opts: QueryOptions): Promise<ContextResponse> {\n const {\n projectId,\n query,\n topK = 10,\n threshold = 0.3,\n chunkTypes,\n hybridSearch = true,\n vectorWeight = 0.7,\n bm25Weight = 0.3,\n rerank = true,\n rerankTopK,\n includeMemories = false,\n userId,\n sessionId,\n agentId,\n includeGraph = false,\n graphDepth = 1,\n maxTokens,\n compress = false,\n compressionStrategy = \"adaptive\",\n previousContextHash,\n useCache = true,\n cacheTtlSeconds = 300,\n } = opts;\n\n const startTime = Date.now();\n\n // ─── Check Cache ─────────────────────────────────────────\n if (useCache) {\n const cached = await checkCache(projectId, query);\n if (cached) {\n return {\n results: cached as RetrievalResult[],\n context: packContext(cached as RetrievalResult[], maxTokens),\n meta: {\n totalResults: cached.length,\n latencyMs: Date.now() - startTime,\n cacheHit: true,\n tokensUsed: 0,\n },\n };\n }\n }\n\n // ─── Embed Query ─────────────────────────────────────────\n const queryEmbedding = await embedSingle(query);\n\n let allResults: RetrievalResult[] = [];\n\n // ─── Vector Search ───────────────────────────────────────\n const vectorResults = await vectorSearch(projectId, queryEmbedding, topK * 2, chunkTypes);\n allResults.push(...vectorResults);\n\n // ─── BM25 Full-Text Search ───────────────────────────────\n if (hybridSearch) {\n const bm25Results = await fullTextSearch(projectId, query, topK * 2, chunkTypes);\n allResults.push(...bm25Results);\n }\n\n // ─── Memory Search ───────────────────────────────────────\n if (includeMemories) {\n const memoryResults = await memorySearch(projectId, queryEmbedding, {\n userId,\n sessionId,\n agentId,\n topK: Math.ceil(topK / 3),\n });\n allResults.push(...memoryResults);\n }\n\n // ─── Graph Traversal ─────────────────────────────────────\n if (includeGraph) {\n const graphResults = await graphSearch(projectId, queryEmbedding, {\n depth: graphDepth,\n topK: Math.ceil(topK / 3),\n });\n allResults.push(...graphResults);\n }\n\n // ─── Deduplicate ─────────────────────────────────────────\n allResults = deduplicateResults(allResults);\n\n // ─── Reciprocal Rank Fusion (for hybrid) ─────────────────\n if (hybridSearch) {\n allResults = reciprocalRankFusion(allResults, vectorWeight, bm25Weight);\n }\n\n // ─── Filter by threshold ─────────────────────────────────\n allResults = allResults.filter((r) => r.score >= threshold);\n\n // ─── Rerank with LLM ────────────────────────────────────\n if (rerank && allResults.length > 0) {\n const reranked = await rerankResults(query, allResults, rerankTopK || topK);\n allResults = reranked;\n }\n\n // ─── Limit to topK ──────────────────────────────────────\n allResults = allResults.slice(0, topK);\n\n // ─── Enrich with document/source metadata ────────────────\n allResults = await enrichResults(allResults);\n\n // ─── Context packing ─────────────────────────────────────\n let context = packContext(allResults, maxTokens);\n const contextHash = createHash(\"sha256\").update(context).digest(\"hex\").slice(0, 16);\n\n // ─── Compression ──────────────────────────────────────────\n let compressionMeta: ContextResponse[\"meta\"][\"compression\"];\n if (compress && context.length > 0) {\n const compressed = await compressContext(context, {\n maxTokens: maxTokens || 4000,\n strategy: compressionStrategy,\n previousContextHash,\n });\n context = compressed.context;\n compressionMeta = {\n originalTokens: compressed.originalTokens,\n compressedTokens: compressed.compressedTokens,\n reductionPercent: compressed.reductionPercent,\n strategy: compressed.strategy,\n };\n }\n\n // ─── Cache results ───────────────────────────────────────\n if (useCache && allResults.length > 0) {\n await setCache(projectId, query, allResults, cacheTtlSeconds);\n }\n\n const latencyMs = Date.now() - startTime;\n\n return {\n results: allResults,\n context,\n meta: {\n totalResults: allResults.length,\n latencyMs,\n cacheHit: false,\n tokensUsed: estimateTokens(context),\n contextHash,\n compression: compressionMeta,\n },\n };\n}\n\n// ─── Vector Search ───────────────────────────────────────────\n\nasync function vectorSearch(\n projectId: string,\n queryEmbedding: number[],\n limit: number,\n chunkTypes?: string[]\n): Promise<RetrievalResult[]> {\n const conditions = [eq(chunks.projectId, projectId)];\n if (chunkTypes && chunkTypes.length > 0) {\n conditions.push(inArray(chunks.chunkType, chunkTypes as any));\n }\n\n const results = await db\n .select({\n id: chunks.id,\n content: chunks.content,\n chunkType: chunks.chunkType,\n metadata: chunks.metadata,\n documentId: chunks.documentId,\n similarity: sql<number>`1 - (${chunks.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(chunks)\n .where(and(...conditions))\n .orderBy(sql`${chunks.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(limit);\n\n return results.map((r) => ({\n id: r.id,\n content: r.content,\n score: r.similarity,\n metadata: (r.metadata as Record<string, any>) || {},\n chunkType: r.chunkType,\n source: \"vector\" as const,\n }));\n}\n\n// ─── Full-Text Search (BM25-style via pg tsvector) ───────────\n\nasync function fullTextSearch(\n projectId: string,\n query: string,\n limit: number,\n chunkTypes?: string[]\n): Promise<RetrievalResult[]> {\n // Sanitize query for tsquery\n const tsQuery = query\n .replace(/[^\\w\\s]/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter((w) => w.length > 1)\n .join(\" & \");\n\n if (!tsQuery) return [];\n\n const conditions = [eq(chunks.projectId, projectId)];\n if (chunkTypes && chunkTypes.length > 0) {\n conditions.push(inArray(chunks.chunkType, chunkTypes as any));\n }\n\n const results = await db\n .select({\n id: chunks.id,\n content: chunks.content,\n chunkType: chunks.chunkType,\n metadata: chunks.metadata,\n documentId: chunks.documentId,\n rank: sql<number>`ts_rank(to_tsvector('english', coalesce(${chunks.searchContent}, ${chunks.content})), to_tsquery('english', ${tsQuery}))`,\n })\n .from(chunks)\n .where(\n and(\n ...conditions,\n sql`to_tsvector('english', coalesce(${chunks.searchContent}, ${chunks.content})) @@ to_tsquery('english', ${tsQuery})`\n )\n )\n .orderBy(sql`ts_rank(to_tsvector('english', coalesce(${chunks.searchContent}, ${chunks.content})), to_tsquery('english', ${tsQuery})) DESC`)\n .limit(limit);\n\n // Normalize ranks to 0-1\n const maxRank = results.length > 0 ? Math.max(...results.map((r) => r.rank)) : 1;\n\n return results.map((r) => ({\n id: r.id,\n content: r.content,\n score: maxRank > 0 ? r.rank / maxRank : 0,\n metadata: (r.metadata as Record<string, any>) || {},\n chunkType: r.chunkType,\n source: \"bm25\" as const,\n }));\n}\n\n// ─── Memory Search ───────────────────────────────────────────\n\nasync function memorySearch(\n projectId: string,\n queryEmbedding: number[],\n opts: { userId?: string; sessionId?: string; agentId?: string; topK: number }\n): Promise<RetrievalResult[]> {\n const conditions = [\n eq(memories.projectId, projectId),\n eq(memories.isActive, true),\n or(isNull(memories.expiresAt), gt(memories.expiresAt, new Date())),\n ];\n\n if (opts.userId) conditions.push(eq(memories.userId, opts.userId));\n if (opts.sessionId) conditions.push(eq(memories.sessionId, opts.sessionId));\n if (opts.agentId) conditions.push(eq(memories.agentId, opts.agentId));\n\n const results = await db\n .select({\n id: memories.id,\n content: memories.content,\n memoryType: memories.memoryType,\n metadata: memories.metadata,\n importance: memories.importance,\n similarity: sql<number>`1 - (${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(memories)\n .where(and(...conditions))\n .orderBy(sql`${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(opts.topK);\n\n // Update access counts\n if (results.length > 0) {\n const ids = results.map((r) => r.id);\n await db\n .update(memories)\n .set({\n accessCount: sql`${memories.accessCount} + 1`,\n lastAccessedAt: new Date(),\n })\n .where(inArray(memories.id, ids));\n }\n\n return results.map((r) => ({\n id: r.id,\n content: r.content,\n score: r.similarity * (r.importance || 0.5),\n metadata: { ...(r.metadata as Record<string, any>), memoryType: r.memoryType },\n chunkType: \"memory\" as any,\n source: \"memory\" as const,\n }));\n}\n\n// ─── Graph Search ────────────────────────────────────────────\n\nasync function graphSearch(\n projectId: string,\n queryEmbedding: number[],\n opts: { depth: number; topK: number }\n): Promise<RetrievalResult[]> {\n // Find most relevant entities\n const relevantEntities = await db\n .select({\n id: entities.id,\n name: entities.name,\n entityType: entities.entityType,\n description: entities.description,\n metadata: entities.metadata,\n sourceChunkId: entities.sourceChunkId,\n similarity: sql<number>`1 - (${entities.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(entities)\n .where(eq(entities.projectId, projectId))\n .orderBy(sql`${entities.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(5);\n\n if (relevantEntities.length === 0) return [];\n\n // Traverse relationships\n const entityIds = relevantEntities.map((e) => e.id);\n\n const relatedEntities = await db\n .select({\n id: entities.id,\n name: entities.name,\n entityType: entities.entityType,\n description: entities.description,\n metadata: entities.metadata,\n sourceChunkId: entities.sourceChunkId,\n relationType: relations.relationType,\n weight: relations.weight,\n })\n .from(relations)\n .innerJoin(entities, eq(relations.toEntityId, entities.id))\n .where(\n and(\n eq(relations.projectId, projectId),\n inArray(relations.fromEntityId, entityIds)\n )\n )\n .limit(opts.topK);\n\n // Get chunks for related entities\n const chunkIds = [\n ...relevantEntities.map((e) => e.sourceChunkId).filter(Boolean),\n ...relatedEntities.map((e) => e.sourceChunkId).filter(Boolean),\n ] as string[];\n\n if (chunkIds.length === 0) return [];\n\n const relatedChunks = await db\n .select()\n .from(chunks)\n .where(inArray(chunks.id, chunkIds));\n\n return relatedChunks.map((c) => {\n const entity = relevantEntities.find((e) => e.sourceChunkId === c.id);\n return {\n id: c.id,\n content: c.content,\n score: entity ? entity.similarity * 0.8 : 0.5,\n metadata: {\n ...(c.metadata as Record<string, any>),\n entityName: entity?.name,\n entityType: entity?.entityType,\n },\n chunkType: c.chunkType,\n source: \"graph\" as const,\n };\n });\n}\n\n// ─── Reciprocal Rank Fusion ──────────────────────────────────\n\nfunction reciprocalRankFusion(\n results: RetrievalResult[],\n vectorWeight: number,\n bm25Weight: number,\n k = 60\n): RetrievalResult[] {\n const scoreMap = new Map<string, { result: RetrievalResult; score: number }>();\n\n // Group by source type and rank\n const vectorResults = results.filter((r) => r.source === \"vector\");\n const bm25Results = results.filter((r) => r.source === \"bm25\");\n const otherResults = results.filter((r) => r.source !== \"vector\" && r.source !== \"bm25\");\n\n // RRF scoring for vector results\n vectorResults.forEach((r, rank) => {\n const existing = scoreMap.get(r.id);\n const rrfScore = vectorWeight / (k + rank + 1);\n if (existing) {\n existing.score += rrfScore;\n } else {\n scoreMap.set(r.id, { result: r, score: rrfScore });\n }\n });\n\n // RRF scoring for BM25 results\n bm25Results.forEach((r, rank) => {\n const existing = scoreMap.get(r.id);\n const rrfScore = bm25Weight / (k + rank + 1);\n if (existing) {\n existing.score += rrfScore;\n existing.result.source = \"hybrid\";\n } else {\n scoreMap.set(r.id, { result: { ...r, source: \"hybrid\" }, score: rrfScore });\n }\n });\n\n // Add other results with their original scores\n otherResults.forEach((r) => {\n if (!scoreMap.has(r.id)) {\n scoreMap.set(r.id, { result: r, score: r.score * 0.5 });\n }\n });\n\n return Array.from(scoreMap.values())\n .sort((a, b) => b.score - a.score)\n .map((entry) => ({ ...entry.result, score: entry.score }));\n}\n\n// ─── LLM Reranking ───────────────────────────────────────────\n\nasync function rerankResults(\n query: string,\n results: RetrievalResult[],\n topK: number\n): Promise<RetrievalResult[]> {\n if (results.length <= 3) return results; // not worth reranking\n\n // Take top candidates for reranking (limit to save tokens)\n const candidates = results.slice(0, Math.min(results.length, topK * 3));\n\n const prompt = `Given the query: \"${query}\"\n\nRank these ${candidates.length} text passages by relevance (most relevant first). Return ONLY a JSON array of indices (0-based), e.g. [2, 0, 4, 1, 3].\n\n${candidates.map((r, i) => `[${i}] ${r.content.slice(0, 300)}`).join(\"\\n\\n\")}`;\n\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [{ role: \"user\", content: prompt }],\n temperature: 0,\n max_tokens: 200,\n });\n\n const text = res.choices[0]?.message?.content?.trim() || \"\";\n const match = text.match(/\\[[\\d,\\s]+\\]/);\n if (!match) return results;\n\n const indices: number[] = JSON.parse(match[0]);\n const reranked: RetrievalResult[] = [];\n\n for (const idx of indices) {\n if (idx >= 0 && idx < candidates.length) {\n reranked.push({\n ...candidates[idx],\n score: 1 - reranked.length * (1 / indices.length), // normalize\n });\n }\n }\n\n // Add any results that weren't reranked\n for (const r of results) {\n if (!reranked.find((rr) => rr.id === r.id)) {\n reranked.push(r);\n }\n }\n\n return reranked.slice(0, topK);\n } catch {\n // Fallback to original ordering if reranking fails\n return results.slice(0, topK);\n }\n}\n\n// ─── Deduplication ───────────────────────────────────────────\n\nfunction deduplicateResults(results: RetrievalResult[]): RetrievalResult[] {\n const seen = new Map<string, RetrievalResult>();\n\n for (const r of results) {\n const existing = seen.get(r.id);\n if (!existing || r.score > existing.score) {\n seen.set(r.id, r);\n }\n }\n\n return Array.from(seen.values());\n}\n\n// ─── Context Packing ─────────────────────────────────────────\n\nfunction packContext(results: RetrievalResult[], maxTokens?: number): string {\n if (results.length === 0) return \"\";\n\n const limit = maxTokens || 8000;\n let totalTokens = 0;\n const packed: string[] = [];\n\n for (const r of results) {\n const header = buildChunkHeader(r);\n const block = `${header}\\n${r.content}\\n`;\n const tokens = estimateTokens(block);\n\n if (totalTokens + tokens > limit) break;\n\n packed.push(block);\n totalTokens += tokens;\n }\n\n return packed.join(\"\\n---\\n\\n\");\n}\n\nfunction buildChunkHeader(r: RetrievalResult): string {\n const parts: string[] = [];\n\n if (r.sourceName) parts.push(`Source: ${r.sourceName}`);\n if (r.documentTitle) parts.push(`Document: ${r.documentTitle}`);\n if (r.metadata?.filePath) parts.push(`File: ${r.metadata.filePath}`);\n if (r.metadata?.startLine) parts.push(`Lines: ${r.metadata.startLine}-${r.metadata.endLine || \"?\"}`);\n if (r.chunkType && r.chunkType !== \"text\") parts.push(`Type: ${r.chunkType}`);\n\n return parts.length > 0 ? `[${parts.join(\" | \")}]` : \"\";\n}\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n// ─── Enrich Results ──────────────────────────────────────────\n\nasync function enrichResults(results: RetrievalResult[]): Promise<RetrievalResult[]> {\n // Get unique document IDs from chunk results\n const chunkResults = results.filter((r) => r.source !== \"memory\");\n if (chunkResults.length === 0) return results;\n\n // We need document IDs — stored in metadata or we need to query\n const chunkIds = chunkResults.map((r) => r.id);\n\n const chunkDocs = await db\n .select({\n chunkId: chunks.id,\n docTitle: documents.title,\n sourceName: sources.name,\n docId: documents.id,\n sourceId: sources.id,\n })\n .from(chunks)\n .innerJoin(documents, eq(chunks.documentId, documents.id))\n .innerJoin(sources, eq(documents.sourceId, sources.id))\n .where(inArray(chunks.id, chunkIds));\n\n const enrichMap = new Map(chunkDocs.map((d) => [d.chunkId, d]));\n\n return results.map((r) => {\n const enrichment = enrichMap.get(r.id);\n if (enrichment) {\n return {\n ...r,\n documentTitle: enrichment.docTitle || undefined,\n sourceName: enrichment.sourceName || undefined,\n };\n }\n return r;\n });\n}\n\n// ─── Cache ───────────────────────────────────────────────────\n\nfunction hashQuery(query: string): string {\n return createHash(\"sha256\").update(query.toLowerCase().trim()).digest(\"hex\");\n}\n\nasync function checkCache(projectId: string, query: string) {\n const hash = hashQuery(query);\n\n const [cached] = await db\n .select()\n .from(queryCache)\n .where(\n and(\n eq(queryCache.projectId, projectId),\n eq(queryCache.queryHash, hash),\n gt(queryCache.expiresAt, new Date())\n )\n )\n .limit(1);\n\n if (cached) {\n await db\n .update(queryCache)\n .set({ hitCount: sql`${queryCache.hitCount} + 1` })\n .where(eq(queryCache.id, cached.id));\n\n return cached.results;\n }\n\n return null;\n}\n\nasync function setCache(\n projectId: string,\n query: string,\n results: RetrievalResult[],\n ttlSeconds: number\n) {\n const hash = hashQuery(query);\n const expiresAt = new Date(Date.now() + ttlSeconds * 1000);\n\n await db\n .insert(queryCache)\n .values({\n projectId,\n queryHash: hash,\n query,\n results: results as any,\n expiresAt,\n })\n .onConflictDoUpdate({\n target: [queryCache.projectId, queryCache.queryHash],\n set: { results: results as any, expiresAt, hitCount: 0 },\n });\n}\n","import OpenAI from \"openai\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\nexport async function embed(texts: string[]): Promise<number[][]> {\n const res = await openai.embeddings.create({\n model: \"text-embedding-3-small\",\n input: texts,\n dimensions: 1536,\n });\n\n return res.data.map((d) => d.embedding);\n}\n\nexport async function embedSingle(text: string): Promise<number[]> {\n const [embedding] = await embed([text]);\n return embedding;\n}\n","import OpenAI from \"openai\";\nimport { db, chunks, memories } from \"../db/index.js\";\nimport { eq, sql } from \"drizzle-orm\";\nimport { createHash } from \"crypto\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport interface CompressedContext {\n context: string;\n originalTokens: number;\n compressedTokens: number;\n reductionPercent: number;\n strategy: string;\n}\n\nexport interface CompressionOptions {\n maxTokens?: number;\n strategy?: \"summarize\" | \"extract\" | \"delta\" | \"adaptive\";\n previousContextHash?: string; // for delta mode\n previousContext?: string; // for delta mode\n targetReduction?: number; // 0-1, e.g. 0.6 = reduce by 60%\n}\n\n// ─── In-memory delta cache ──────────────────────────────────\n\nconst deltaCache = new Map<string, { context: string; hash: string; timestamp: number }>();\nconst DELTA_CACHE_TTL = 600_000; // 10 min\n\nfunction hashContext(text: string): string {\n return createHash(\"sha256\").update(text).digest(\"hex\").slice(0, 16);\n}\n\n// ─── Main Compression Function ──────────────────────────────\n\nexport async function compressContext(\n rawContext: string,\n opts: CompressionOptions = {}\n): Promise<CompressedContext> {\n const {\n maxTokens = 4000,\n strategy = \"adaptive\",\n previousContextHash,\n previousContext,\n targetReduction = 0.5,\n } = opts;\n\n const originalTokens = estimateTokens(rawContext);\n\n // If already under budget, return as-is\n if (originalTokens <= maxTokens) {\n return {\n context: rawContext,\n originalTokens,\n compressedTokens: originalTokens,\n reductionPercent: 0,\n strategy: \"none\",\n };\n }\n\n switch (strategy) {\n case \"delta\":\n return deltaCompress(rawContext, originalTokens, maxTokens, previousContextHash, previousContext);\n case \"summarize\":\n return summarizeCompress(rawContext, originalTokens, maxTokens);\n case \"extract\":\n return extractCompress(rawContext, originalTokens, maxTokens);\n case \"adaptive\":\n default:\n return adaptiveCompress(rawContext, originalTokens, maxTokens, previousContextHash, previousContext);\n }\n}\n\n// ─── Adaptive Strategy ──────────────────────────────────────\n// Picks the best strategy based on context characteristics\n\nasync function adaptiveCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number,\n previousHash?: string,\n previousCtx?: string\n): Promise<CompressedContext> {\n const ratio = originalTokens / maxTokens;\n\n // If we have previous context and it's similar, use delta\n if (previousHash || previousCtx) {\n const delta = await deltaCompress(rawContext, originalTokens, maxTokens, previousHash, previousCtx);\n if (delta.compressedTokens <= maxTokens) return delta;\n }\n\n // Light compression (under 2x budget): extract key info\n if (ratio < 2) {\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Heavy compression (over 2x budget): summarize\n return summarizeCompress(rawContext, originalTokens, maxTokens);\n}\n\n// ─── Delta Compression ──────────────────────────────────────\n// Only sends what changed since the last context\n\nasync function deltaCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number,\n previousHash?: string,\n previousCtx?: string\n): Promise<CompressedContext> {\n const currentHash = hashContext(rawContext);\n\n // Check if identical\n if (previousHash && previousHash === currentHash) {\n return {\n context: \"[No changes since last context]\",\n originalTokens,\n compressedTokens: 8,\n reductionPercent: 99,\n strategy: \"delta-identical\",\n };\n }\n\n // Get previous context from cache or parameter\n let prevCtx = previousCtx;\n if (!prevCtx && previousHash) {\n const cached = deltaCache.get(previousHash);\n if (cached && Date.now() - cached.timestamp < DELTA_CACHE_TTL) {\n prevCtx = cached.context;\n }\n }\n\n if (!prevCtx) {\n // No previous context to diff against, fall back to extract\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Split into blocks and find differences\n const prevBlocks = new Set(prevCtx.split(\"\\n---\\n\").map((b) => b.trim()));\n const currentBlocks = rawContext.split(\"\\n---\\n\").map((b) => b.trim());\n\n const newBlocks: string[] = [];\n const unchangedCount = { count: 0 };\n\n for (const block of currentBlocks) {\n if (prevBlocks.has(block)) {\n unchangedCount.count++;\n } else {\n newBlocks.push(block);\n }\n }\n\n let deltaContext: string;\n if (newBlocks.length === 0) {\n deltaContext = \"[No new information since last query]\";\n } else {\n const header = `[${unchangedCount.count} unchanged results omitted, ${newBlocks.length} new/updated]\\n\\n`;\n deltaContext = header + newBlocks.join(\"\\n---\\n\");\n }\n\n // Trim if still over budget\n const deltaTokens = estimateTokens(deltaContext);\n if (deltaTokens > maxTokens) {\n const truncated = truncateToTokens(deltaContext, maxTokens);\n deltaCache.set(currentHash, { context: rawContext, hash: currentHash, timestamp: Date.now() });\n\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"delta-truncated\",\n };\n }\n\n // Cache current context for next delta\n deltaCache.set(currentHash, { context: rawContext, hash: currentHash, timestamp: Date.now() });\n\n return {\n context: deltaContext,\n originalTokens,\n compressedTokens: estimateTokens(deltaContext),\n reductionPercent: Math.round((1 - estimateTokens(deltaContext) / originalTokens) * 100),\n strategy: \"delta\",\n };\n}\n\n// ─── Extract Compression ────────────────────────────────────\n// LLM extracts only the most relevant parts\n\nasync function extractCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number\n): Promise<CompressedContext> {\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n {\n role: \"system\",\n content: `You are a context compressor. Extract and preserve ONLY the most important information from the provided context. Remove redundancy, boilerplate, and low-value content. Keep code snippets, key facts, API signatures, and important relationships. Output should be ${maxTokens} tokens or less. Do NOT add commentary — just output the compressed context.`,\n },\n { role: \"user\", content: rawContext },\n ],\n max_tokens: maxTokens,\n temperature: 0,\n });\n\n const compressed = res.choices[0]?.message?.content?.trim() || rawContext;\n const compressedTokens = estimateTokens(compressed);\n\n return {\n context: compressed,\n originalTokens,\n compressedTokens,\n reductionPercent: Math.round((1 - compressedTokens / originalTokens) * 100),\n strategy: \"extract\",\n };\n } catch {\n // Fallback to truncation\n const truncated = truncateToTokens(rawContext, maxTokens);\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"truncate-fallback\",\n };\n }\n}\n\n// ─── Summarize Compression ──────────────────────────────────\n// For heavy compression — summarizes each block then combines\n\nasync function summarizeCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number\n): Promise<CompressedContext> {\n const blocks = rawContext.split(\"\\n---\\n\").filter((b) => b.trim());\n\n // If few blocks, summarize the whole thing\n if (blocks.length <= 3) {\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Summarize each block individually, then combine\n const budgetPerBlock = Math.floor(maxTokens / blocks.length);\n\n try {\n const summaries = await Promise.all(\n blocks.map(async (block) => {\n if (estimateTokens(block) <= budgetPerBlock) return block;\n\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n {\n role: \"system\",\n content: `Summarize this context block in ${budgetPerBlock} tokens or less. Preserve code signatures, key facts, and important details. Output only the summary.`,\n },\n { role: \"user\", content: block },\n ],\n max_tokens: budgetPerBlock,\n temperature: 0,\n });\n\n return res.choices[0]?.message?.content?.trim() || block.slice(0, budgetPerBlock * 4);\n })\n );\n\n const compressed = summaries.join(\"\\n\\n---\\n\\n\");\n let compressedTokens = estimateTokens(compressed);\n\n // Final trim if still over\n let finalContext = compressed;\n if (compressedTokens > maxTokens) {\n finalContext = truncateToTokens(compressed, maxTokens);\n compressedTokens = estimateTokens(finalContext);\n }\n\n return {\n context: finalContext,\n originalTokens,\n compressedTokens,\n reductionPercent: Math.round((1 - compressedTokens / originalTokens) * 100),\n strategy: \"summarize\",\n };\n } catch {\n const truncated = truncateToTokens(rawContext, maxTokens);\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"truncate-fallback\",\n };\n }\n}\n\n// ─── Pre-computed Chunk Summaries ────────────────────────────\n// Summarize chunks at ingest time so retrieval is cheaper\n\nexport async function summarizeChunk(content: string, chunkType: string): Promise<string> {\n // Only summarize large chunks\n if (estimateTokens(content) < 200) return content;\n\n try {\n const prompt = chunkType === \"code\"\n ? \"Summarize this code in 2-3 sentences. Include: function/class names, what it does, parameters, return type.\"\n : \"Summarize this text in 2-3 sentences. Preserve key facts, names, and important details.\";\n\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n { role: \"system\", content: prompt },\n { role: \"user\", content: content.slice(0, 3000) },\n ],\n max_tokens: 150,\n temperature: 0,\n });\n\n return res.choices[0]?.message?.content?.trim() || content;\n } catch {\n return content;\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction truncateToTokens(text: string, maxTokens: number): string {\n const maxChars = maxTokens * 4;\n if (text.length <= maxChars) return text;\n return text.slice(0, maxChars) + \"\\n\\n[...truncated]\";\n}\n\n// Cleanup stale delta cache entries periodically\nsetInterval(() => {\n const now = Date.now();\n for (const [key, val] of deltaCache) {\n if (now - val.timestamp > DELTA_CACHE_TTL) deltaCache.delete(key);\n }\n}, 60_000);\n","import { db, documents, chunks, sources } from \"../db/index.js\";\nimport { eq } from \"drizzle-orm\";\nimport { chunkText } from \"./chunker.js\";\nimport { embed } from \"./embeddings.js\";\nimport { extractEntities } from \"./extractor.js\";\nimport { createHash } from \"crypto\";\nimport PQueue from \"p-queue\";\n\nconst queue = new PQueue({ concurrency: 3 });\n\n// Entity extraction is async and non-blocking — failures don't break ingestion\nconst ENABLE_AUTO_EXTRACTION = process.env.DISABLE_AUTO_EXTRACTION !== \"true\";\n\nexport interface IngestDocumentInput {\n sourceId: string;\n projectId: string;\n externalId: string;\n title: string;\n content: string;\n metadata?: Record<string, any>;\n filePath?: string;\n skipEntityExtraction?: boolean;\n}\n\nexport async function ingestDocument(input: IngestDocumentInput) {\n const { sourceId, projectId, externalId, title, content, metadata = {}, filePath } = input;\n\n const contentHash = createHash(\"sha256\").update(content).digest(\"hex\");\n\n // Upsert document\n const [doc] = await db\n .insert(documents)\n .values({\n sourceId,\n projectId,\n externalId,\n title,\n content,\n metadata,\n contentHash,\n })\n .onConflictDoUpdate({\n target: [documents.sourceId, documents.externalId],\n set: { title, content, metadata, contentHash, updatedAt: new Date() },\n })\n .returning();\n\n // Delete old chunks for this document\n await db.delete(chunks).where(eq(chunks.documentId, doc.id));\n\n // Chunk the content\n const textChunks = chunkText(content, {\n filePath: filePath || externalId,\n metadata: { ...metadata, title },\n });\n\n if (textChunks.length === 0) return doc;\n\n // Embed in batches of 50\n const batchSize = 50;\n const insertedChunkIds: string[] = [];\n\n for (let i = 0; i < textChunks.length; i += batchSize) {\n const batch = textChunks.slice(i, i + batchSize);\n const embeddings = await embed(batch.map((c) => c.content));\n\n const inserted = await db.insert(chunks).values(\n batch.map((chunk, j) => ({\n documentId: doc.id,\n projectId,\n content: chunk.content,\n chunkType: chunk.chunkType,\n chunkIndex: chunk.chunkIndex,\n metadata: chunk.metadata,\n embedding: embeddings[j],\n tokenCount: Math.ceil(chunk.content.length / 4),\n }))\n ).returning({ id: chunks.id });\n\n insertedChunkIds.push(...inserted.map((c) => c.id));\n }\n\n // Auto entity extraction (fire-and-forget, non-blocking)\n if (ENABLE_AUTO_EXTRACTION && !input.skipEntityExtraction) {\n // Only extract from the first few significant chunks to save tokens\n const chunksToExtract = textChunks\n .filter((c) => c.content.length > 200)\n .slice(0, 5);\n\n for (let i = 0; i < chunksToExtract.length; i++) {\n const chunk = chunksToExtract[i];\n const chunkId = insertedChunkIds[textChunks.indexOf(chunk)];\n\n // Don't await — let it run in background\n extractEntities(projectId, chunk.content, chunk.chunkType, metadata, chunkId).catch(() => {\n // Silently ignore extraction failures\n });\n }\n }\n\n // Update source counts\n const docCount = await db\n .select({ count: db.$count(documents, eq(documents.sourceId, sourceId)) })\n .from(documents);\n\n const chunkCount = await db\n .select({ count: db.$count(chunks, eq(chunks.documentId, doc.id)) })\n .from(chunks);\n\n await db\n .update(sources)\n .set({\n documentCount: Number(docCount[0]?.count || 0),\n chunkCount: Number(chunkCount[0]?.count || 0),\n lastSyncAt: new Date(),\n status: \"ready\",\n updatedAt: new Date(),\n })\n .where(eq(sources.id, sourceId));\n\n return doc;\n}\n\nexport async function ingestDocuments(inputs: IngestDocumentInput[]) {\n const results = await Promise.all(\n inputs.map((input) => queue.add(() => ingestDocument(input)))\n );\n return results;\n}\n","export interface Chunk {\n content: string;\n metadata: Record<string, any>;\n chunkType: \"code\" | \"documentation\" | \"api_spec\" | \"schema\" | \"config\" | \"text\" | \"comment\";\n chunkIndex: number;\n}\n\nconst CODE_EXTENSIONS = new Set([\n \".ts\", \".tsx\", \".js\", \".jsx\", \".py\", \".java\", \".go\", \".rb\",\n \".php\", \".cs\", \".rs\", \".swift\", \".kt\", \".scala\", \".c\", \".cpp\",\n \".h\", \".hpp\", \".sol\", \".vy\",\n]);\n\nconst CONFIG_EXTENSIONS = new Set([\n \".json\", \".yaml\", \".yml\", \".toml\", \".ini\", \".env\", \".xml\",\n]);\n\nexport function detectChunkType(filePath?: string, content?: string): Chunk[\"chunkType\"] {\n if (!filePath) return \"text\";\n\n const ext = \".\" + filePath.split(\".\").pop()?.toLowerCase();\n\n if (CODE_EXTENSIONS.has(ext)) return \"code\";\n if (CONFIG_EXTENSIONS.has(ext)) return \"config\";\n if (filePath.includes(\"schema\") || filePath.includes(\"migration\")) return \"schema\";\n if (filePath.endsWith(\".md\") || filePath.endsWith(\".mdx\") || filePath.endsWith(\".rst\")) return \"documentation\";\n if (filePath.includes(\"openapi\") || filePath.includes(\"swagger\")) return \"api_spec\";\n\n return \"text\";\n}\n\nexport function chunkText(\n content: string,\n opts: {\n chunkSize?: number;\n chunkOverlap?: number;\n filePath?: string;\n metadata?: Record<string, any>;\n } = {}\n): Chunk[] {\n const { chunkSize = 1000, chunkOverlap = 200, filePath, metadata = {} } = opts;\n const chunkType = detectChunkType(filePath, content);\n\n // For code, try to split on function/class boundaries first\n if (chunkType === \"code\") {\n return chunkCode(content, { chunkSize, filePath, metadata });\n }\n\n // For everything else, split by paragraphs/sections then by size\n return chunkBySize(content, { chunkSize, chunkOverlap, chunkType, metadata });\n}\n\nfunction chunkCode(\n content: string,\n opts: { chunkSize: number; filePath?: string; metadata?: Record<string, any> }\n): Chunk[] {\n const { chunkSize, filePath, metadata = {} } = opts;\n const lines = content.split(\"\\n\");\n const chunks: Chunk[] = [];\n\n // Split on common code boundaries\n const boundaries = [\n /^(export\\s+)?(async\\s+)?function\\s+/,\n /^(export\\s+)?(default\\s+)?class\\s+/,\n /^(export\\s+)?const\\s+\\w+\\s*=\\s*(async\\s+)?\\(/,\n /^(export\\s+)?const\\s+\\w+\\s*=\\s*\\{/,\n /^(export\\s+)?interface\\s+/,\n /^(export\\s+)?type\\s+/,\n /^(export\\s+)?enum\\s+/,\n /^def\\s+/, // Python\n /^class\\s+/, // Python/Java\n /^func\\s+/, // Go\n /^pub\\s+(fn|struct|enum|impl)/, // Rust\n ];\n\n let currentChunk: string[] = [];\n let currentStart = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i].trimStart();\n const isBoundary = boundaries.some((b) => b.test(trimmed));\n\n if (isBoundary && currentChunk.length > 0) {\n const chunkContent = currentChunk.join(\"\\n\").trim();\n if (chunkContent.length > 0) {\n chunks.push({\n content: chunkContent,\n chunkType: \"code\",\n chunkIndex: chunks.length,\n metadata: {\n ...metadata,\n filePath,\n startLine: currentStart + 1,\n endLine: i,\n },\n });\n }\n currentChunk = [lines[i]];\n currentStart = i;\n } else {\n currentChunk.push(lines[i]);\n }\n\n // If chunk is too big, flush it\n if (currentChunk.join(\"\\n\").length > chunkSize * 1.5) {\n const chunkContent = currentChunk.join(\"\\n\").trim();\n if (chunkContent.length > 0) {\n chunks.push({\n content: chunkContent,\n chunkType: \"code\",\n chunkIndex: chunks.length,\n metadata: {\n ...metadata,\n filePath,\n startLine: currentStart + 1,\n endLine: i + 1,\n },\n });\n }\n currentChunk = [];\n currentStart = i + 1;\n }\n }\n\n // Flush remaining\n if (currentChunk.length > 0) {\n const chunkContent = currentChunk.join(\"\\n\").trim();\n if (chunkContent.length > 0) {\n chunks.push({\n content: chunkContent,\n chunkType: \"code\",\n chunkIndex: chunks.length,\n metadata: {\n ...metadata,\n filePath,\n startLine: currentStart + 1,\n endLine: lines.length,\n },\n });\n }\n }\n\n return chunks;\n}\n\nfunction chunkBySize(\n content: string,\n opts: {\n chunkSize: number;\n chunkOverlap: number;\n chunkType: Chunk[\"chunkType\"];\n metadata?: Record<string, any>;\n }\n): Chunk[] {\n const { chunkSize, chunkOverlap, chunkType, metadata = {} } = opts;\n const chunks: Chunk[] = [];\n\n // Split on double newlines (paragraphs) first\n const paragraphs = content.split(/\\n\\n+/);\n let current = \"\";\n\n for (const para of paragraphs) {\n if ((current + \"\\n\\n\" + para).length > chunkSize && current.length > 0) {\n chunks.push({\n content: current.trim(),\n chunkType,\n chunkIndex: chunks.length,\n metadata,\n });\n // Keep overlap\n const words = current.split(/\\s+/);\n const overlapWords = words.slice(-Math.floor(chunkOverlap / 5));\n current = overlapWords.join(\" \") + \"\\n\\n\" + para;\n } else {\n current = current ? current + \"\\n\\n\" + para : para;\n }\n }\n\n if (current.trim().length > 0) {\n chunks.push({\n content: current.trim(),\n chunkType,\n chunkIndex: chunks.length,\n metadata,\n });\n }\n\n return chunks;\n}\n","import OpenAI from \"openai\";\nimport { db, entities, relations, memories } from \"../db/index.js\";\nimport { eq, and } from \"drizzle-orm\";\nimport { embedSingle } from \"./embeddings.js\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ═══════════════════════════════════════════════════════════════\n// ENTITY EXTRACTION (runs during ingestion)\n// ═══════════════════════════════════════════════════════════════\n\ninterface ExtractedEntity {\n name: string;\n type: string; // function, class, module, concept, api_endpoint, config, service, etc.\n description: string;\n}\n\ninterface ExtractedRelation {\n from: string;\n fromType: string;\n to: string;\n toType: string;\n relation: string; // imports, calls, extends, depends_on, etc.\n}\n\nexport async function extractEntities(\n projectId: string,\n content: string,\n chunkType: string,\n metadata: Record<string, any> = {},\n chunkId?: string\n): Promise<{ entities: number; relations: number }> {\n // Skip small chunks\n if (content.length < 100) return { entities: 0, relations: 0 };\n\n const isCode = [\"code\", \"function\", \"class\"].includes(chunkType);\n\n const prompt = isCode\n ? `Analyze this code and extract entities and relationships.\n\nEntities: functions, classes, interfaces, types, modules, variables, constants, API endpoints, services.\nRelations: imports, exports, calls, implements, extends, depends_on, references, part_of.\n\nCode:\n\\`\\`\\`\n${content.slice(0, 3000)}\n\\`\\`\\`\n\nRespond with JSON only:\n{\n \"entities\": [{\"name\": \"...\", \"type\": \"function|class|interface|module|constant|api_endpoint|service\", \"description\": \"one line\"}],\n \"relations\": [{\"from\": \"name\", \"fromType\": \"type\", \"to\": \"name\", \"toType\": \"type\", \"relation\": \"imports|calls|extends|implements|depends_on|references|part_of\"}]\n}`\n : `Analyze this text and extract key entities (concepts, people, tools, services, APIs, technologies) and their relationships.\n\nText:\n${content.slice(0, 3000)}\n\nRespond with JSON only:\n{\n \"entities\": [{\"name\": \"...\", \"type\": \"concept|tool|service|api|technology|person|organization\", \"description\": \"one line\"}],\n \"relations\": [{\"from\": \"name\", \"fromType\": \"type\", \"to\": \"name\", \"toType\": \"type\", \"relation\": \"references|depends_on|related_to|part_of|supersedes\"}]\n}`;\n\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [{ role: \"user\", content: prompt }],\n temperature: 0,\n max_tokens: 1000,\n response_format: { type: \"json_object\" },\n });\n\n const text = res.choices[0]?.message?.content?.trim() || \"{}\";\n const parsed = JSON.parse(text);\n\n const extractedEntities: ExtractedEntity[] = parsed.entities || [];\n const extractedRelations: ExtractedRelation[] = parsed.relations || [];\n\n let entityCount = 0;\n let relationCount = 0;\n\n // Upsert entities\n const entityMap = new Map<string, string>(); // name:type -> id\n\n for (const ent of extractedEntities.slice(0, 20)) {\n if (!ent.name || !ent.type) continue;\n\n const embedding = await embedSingle(`${ent.type}: ${ent.name} - ${ent.description || \"\"}`);\n\n const [entity] = await db\n .insert(entities)\n .values({\n projectId,\n name: ent.name,\n entityType: ent.type,\n description: ent.description,\n metadata: { ...metadata, autoExtracted: true },\n sourceChunkId: chunkId,\n embedding,\n })\n .onConflictDoUpdate({\n target: [entities.projectId, entities.name, entities.entityType],\n set: {\n description: ent.description,\n sourceChunkId: chunkId,\n embedding,\n updatedAt: new Date(),\n },\n })\n .returning();\n\n entityMap.set(`${ent.name}:${ent.type}`, entity.id);\n entityCount++;\n }\n\n // Upsert relations\n for (const rel of extractedRelations.slice(0, 30)) {\n if (!rel.from || !rel.to || !rel.relation) continue;\n\n const fromId = entityMap.get(`${rel.from}:${rel.fromType}`);\n const toId = entityMap.get(`${rel.to}:${rel.toType}`);\n\n if (!fromId || !toId) continue;\n\n // Validate relation type\n const validRelations = [\n \"imports\", \"exports\", \"calls\", \"implements\", \"extends\",\n \"references\", \"depends_on\", \"related_to\", \"part_of\",\n \"contradicts\", \"supersedes\",\n ];\n if (!validRelations.includes(rel.relation)) continue;\n\n await db\n .insert(relations)\n .values({\n projectId,\n fromEntityId: fromId,\n toEntityId: toId,\n relationType: rel.relation as any,\n metadata: { autoExtracted: true },\n })\n .onConflictDoUpdate({\n target: [relations.fromEntityId, relations.toEntityId, relations.relationType],\n set: { metadata: { autoExtracted: true } },\n });\n\n relationCount++;\n }\n\n return { entities: entityCount, relations: relationCount };\n } catch {\n return { entities: 0, relations: 0 };\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY EXTRACTION (runs on conversation messages)\n// ═══════════════════════════════════════════════════════════════\n\ninterface ExtractedMemory {\n content: string;\n type: \"factual\" | \"episodic\" | \"semantic\" | \"procedural\";\n importance: number;\n}\n\n/**\n * Analyzes a conversation message (or batch) and extracts facts worth remembering.\n * Call this after adding messages to a conversation.\n */\nexport async function extractMemories(\n projectId: string,\n messages: { role: string; content: string }[],\n opts?: { userId?: string; sessionId?: string; agentId?: string }\n): Promise<{ memoriesCreated: number }> {\n if (messages.length === 0) return { memoriesCreated: 0 };\n\n const conversation = messages\n .map((m) => `[${m.role}]: ${m.content}`)\n .join(\"\\n\\n\");\n\n // Skip very short conversations\n if (conversation.length < 50) return { memoriesCreated: 0 };\n\n const prompt = `Analyze this conversation and extract important facts, preferences, decisions, or knowledge worth remembering for future interactions.\n\nRules:\n- Only extract truly useful information (not greetings, acknowledgments, etc.)\n- Each memory should be a standalone fact\n- Set importance 0-1 (1 = critical preference/decision, 0.3 = minor detail)\n- Type: factual (facts/preferences), episodic (what happened), semantic (general knowledge), procedural (how to do something)\n- If nothing worth remembering, return empty array\n\nConversation:\n${conversation.slice(0, 4000)}\n\nRespond with JSON only:\n{\n \"memories\": [\n {\"content\": \"standalone fact\", \"type\": \"factual|episodic|semantic|procedural\", \"importance\": 0.5}\n ]\n}`;\n\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [{ role: \"user\", content: prompt }],\n temperature: 0,\n max_tokens: 500,\n response_format: { type: \"json_object\" },\n });\n\n const text = res.choices[0]?.message?.content?.trim() || \"{}\";\n const parsed = JSON.parse(text);\n const extracted: ExtractedMemory[] = parsed.memories || [];\n\n let created = 0;\n\n for (const mem of extracted.slice(0, 10)) {\n if (!mem.content || mem.content.length < 10) continue;\n\n const embedding = await embedSingle(mem.content);\n\n const validTypes = [\"factual\", \"episodic\", \"semantic\", \"procedural\"];\n const memType = validTypes.includes(mem.type) ? mem.type : \"factual\";\n const importance = Math.max(0, Math.min(1, mem.importance || 0.5));\n\n await db.insert(memories).values({\n projectId,\n content: mem.content,\n memoryType: memType as any,\n importance,\n userId: opts?.userId,\n sessionId: opts?.sessionId,\n agentId: opts?.agentId,\n embedding,\n metadata: { autoExtracted: true },\n });\n\n created++;\n }\n\n return { memoriesCreated: created };\n } catch {\n return { memoriesCreated: 0 };\n }\n}\n"],"mappings":"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","names":["eq","and","sql","text","OpenAI","openai","text","text","createHash","OpenAI","openai","estimateTokens","text","eq","chunks","OpenAI","openai","OpenAI","text","createHash","eq","and","eq","sql","text"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@usewhisper/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Model Context Protocol server for Whisper Context API - Connect Claude Desktop to your knowledge base",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"whisper-context-mcp": "./dist/server.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/server.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"whisper",
|
|
17
|
+
"context",
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"claude",
|
|
21
|
+
"ai",
|
|
22
|
+
"llm",
|
|
23
|
+
"rag",
|
|
24
|
+
"knowledge-base"
|
|
25
|
+
],
|
|
26
|
+
"author": "Whisper",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/Alixus/whisper"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://usewhisper.dev",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/Alinxus/whisper/issues"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
38
|
+
"drizzle-orm": "^0.45.1",
|
|
39
|
+
"openai": "^4.80.0",
|
|
40
|
+
"postgres": "^3.4.0",
|
|
41
|
+
"zod": "^3.24.0",
|
|
42
|
+
"dotenv": "^16.0.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.0.0",
|
|
46
|
+
"tsup": "^8.3.0",
|
|
47
|
+
"typescript": "^5.7.0"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|