diff --git a/packages/tools/src/convex-component/src/ai-sdk/index.ts b/packages/tools/src/convex-component/src/ai-sdk/index.ts index a51867e8..564e4a7a 100644 --- a/packages/tools/src/convex-component/src/ai-sdk/index.ts +++ b/packages/tools/src/convex-component/src/ai-sdk/index.ts @@ -38,13 +38,13 @@ */ export { - withSupermemory, - type SupermemoryOptions, - type MemoryPromptData, -} from "./middleware"; + withSupermemory, + type SupermemoryOptions, + type MemoryPromptData, +} from "./middleware" export { - supermemoryConvexTools, - searchMemoriesTool, - addMemoryTool, -} from "./tools"; + supermemoryConvexTools, + searchMemoriesTool, + addMemoryTool, +} from "./tools" diff --git a/packages/tools/src/convex-component/src/ai-sdk/middleware.ts b/packages/tools/src/convex-component/src/ai-sdk/middleware.ts index dbe17f41..f5a664b2 100644 --- a/packages/tools/src/convex-component/src/ai-sdk/middleware.ts +++ b/packages/tools/src/convex-component/src/ai-sdk/middleware.ts @@ -1,5 +1,5 @@ -import type { ConvexClient } from "convex/browser"; -import type { FunctionReference } from "convex/server"; +import type { ConvexClient } from "convex/browser" +import type { FunctionReference } from "convex/server" /** * Supermemory AI SDK Middleware for Convex @@ -13,46 +13,47 @@ import type { FunctionReference } from "convex/server"; * a direct dependency on @ai-sdk/provider. */ interface WrappableLanguageModel { - doGenerate: (options: any) => Promise; - doStream: (options: any) => Promise; - [key: string]: unknown; + doGenerate: (options: any) => Promise + doStream: (options: any) => Promise + [key: string]: unknown } export interface SupermemoryOptions { - /** - * Memory retrieval mode - * - "profile": Get full user profile (static + dynamic facts) - * - "query": Search memories based on user's message - * - "full": Both profile AND query-based search - */ - mode?: "profile" | "query" | "full"; + /** + * Memory retrieval mode + * - "profile": Get full user profile (static + dynamic facts) + * - "query": Search memories based on user's message + * - "full": Both profile AND query-based search + */ + mode?: "profile" | "query" | "full" - /** - * When to automatically save new memories - * - "never": Don't auto-save (default) - * - "always": Save every user message - * - "tool": Only when AI explicitly calls addMemory tool - */ - addMemory?: "never" | "always" | "tool"; + /** + * When to automatically save new memories + * - "never": Don't auto-save (default) + * - "always": Save every user message + * - "tool": Only when AI explicitly calls addMemory tool + */ + addMemory?: "never" | "always" | "tool" - /** - * Custom prompt template for formatting memories - */ - promptTemplate?: (data: MemoryPromptData) => string; + /** + * Custom prompt template for formatting memories + */ + promptTemplate?: (data: MemoryPromptData) => string - /** - * Enable verbose logging - */ - verbose?: boolean; + /** + * Enable verbose logging + */ + verbose?: boolean } export interface MemoryPromptData { - userMemories: string; - generalSearchMemories: string; - searchResults: any[]; + userMemories: string + generalSearchMemories: string + searchResults: any[] } -const DEFAULT_PROMPT_TEMPLATE = (data: MemoryPromptData) => ` +const DEFAULT_PROMPT_TEMPLATE = (data: MemoryPromptData) => + ` # User Context ## User Profile @@ -62,7 +63,7 @@ ${data.userMemories} ${data.generalSearchMemories} Use this context to provide personalized, contextual responses. -`.trim(); +`.trim() /** * Wrap an AI model with automatic Supermemory context injection @@ -96,190 +97,205 @@ Use this context to provide personalized, contextual responses. * ``` */ export function withSupermemory( - model: T, - convexClient: ConvexClient, - containerTag: string, - options: SupermemoryOptions = {}, - componentPath: string = "supermemory" + model: T, + convexClient: ConvexClient, + containerTag: string, + options: SupermemoryOptions = {}, + componentPath = "supermemory", ): T { - const { - mode = "profile", - addMemory = "never", - promptTemplate = DEFAULT_PROMPT_TEMPLATE, - verbose = false, - } = options; + const { + mode = "profile", + addMemory = "never", + promptTemplate = DEFAULT_PROMPT_TEMPLATE, + verbose = false, + } = options - const profileAction = `${componentPath}:actions.profile` as unknown as FunctionReference<"action">; - const searchAction = `${componentPath}:actions.search` as unknown as FunctionReference<"action">; - const addAction = `${componentPath}:actions.add` as unknown as FunctionReference<"action">; + const profileAction = + `${componentPath}:actions.profile` as unknown as FunctionReference<"action"> + const searchAction = + `${componentPath}:actions.search` as unknown as FunctionReference<"action"> + const addAction = + `${componentPath}:actions.add` as unknown as FunctionReference<"action"> - return { - ...model, - doGenerate: async (callOptions: any) => { - try { - // Extract user's last message for query-based search - const lastUserMessage = callOptions.prompt - .filter((msg: any) => msg.role === "user") - .slice(-1)[0]; + return { + ...model, + doGenerate: async (callOptions: any) => { + try { + // Extract user's last message for query-based search + const lastUserMessage = callOptions.prompt + .filter((msg: any) => msg.role === "user") + .slice(-1)[0] - const userQuery = - lastUserMessage && "content" in lastUserMessage - ? typeof lastUserMessage.content === "string" - ? lastUserMessage.content - : lastUserMessage.content.map((c: any) => (c.type === "text" ? c.text : "")).join(" ") - : ""; + const userQuery = + lastUserMessage && "content" in lastUserMessage + ? typeof lastUserMessage.content === "string" + ? lastUserMessage.content + : lastUserMessage.content + .map((c: any) => (c.type === "text" ? c.text : "")) + .join(" ") + : "" - let userMemories = ""; - let generalSearchMemories = ""; - let searchResults: any[] = []; + let userMemories = "" + let generalSearchMemories = "" + let searchResults: any[] = [] - // Fetch profile if needed - if (mode === "profile" || mode === "full") { - if (verbose) console.log("[Supermemory] Fetching user profile..."); + // Fetch profile if needed + if (mode === "profile" || mode === "full") { + if (verbose) console.log("[Supermemory] Fetching user profile...") - const profile = await convexClient.action(profileAction, { - containerTag, - q: userQuery || undefined, - }); + const profile = await convexClient.action(profileAction, { + containerTag, + q: userQuery || undefined, + }) - userMemories = [ - ...profile.profile.static.map((f: string) => `- ${f}`), - ...profile.profile.dynamic.map((f: string) => `- ${f}`), - ].join("\n"); + userMemories = [ + ...profile.profile.static.map((f: string) => `- ${f}`), + ...profile.profile.dynamic.map((f: string) => `- ${f}`), + ].join("\n") - if (verbose) { - console.log(`[Supermemory] Profile: ${profile.profile.static.length} static, ${profile.profile.dynamic.length} dynamic facts`); - } - } + if (verbose) { + console.log( + `[Supermemory] Profile: ${profile.profile.static.length} static, ${profile.profile.dynamic.length} dynamic facts`, + ) + } + } - // Query-based search if needed - if ((mode === "query" || mode === "full") && userQuery) { - if (verbose) console.log(`[Supermemory] Searching memories for: "${userQuery}"`); + // Query-based search if needed + if ((mode === "query" || mode === "full") && userQuery) { + if (verbose) + console.log(`[Supermemory] Searching memories for: "${userQuery}"`) - const searchResult = await convexClient.action(searchAction, { - q: userQuery, - containerTag, - searchMode: "hybrid" as const, - limit: 5, - }); + const searchResult = await convexClient.action(searchAction, { + q: userQuery, + containerTag, + searchMode: "hybrid" as const, + limit: 5, + }) - searchResults = searchResult.results; - generalSearchMemories = searchResults - .map((r: any) => `- ${r.memory || r.chunk} (similarity: ${r.similarity.toFixed(2)})`) - .join("\n"); + searchResults = searchResult.results + generalSearchMemories = searchResults + .map( + (r: any) => + `- ${r.memory || r.chunk} (similarity: ${r.similarity.toFixed(2)})`, + ) + .join("\n") - if (verbose) { - console.log(`[Supermemory] Found ${searchResults.length} relevant memories (cached: ${searchResult.cached})`); - } - } + if (verbose) { + console.log( + `[Supermemory] Found ${searchResults.length} relevant memories (cached: ${searchResult.cached})`, + ) + } + } - // Format context - const contextPrompt = promptTemplate({ - userMemories, - generalSearchMemories, - searchResults, - }); + // Format context + const contextPrompt = promptTemplate({ + userMemories, + generalSearchMemories, + searchResults, + }) - // Inject context as system message - const enhancedPrompt = [ - { role: "system" as const, content: contextPrompt }, - ...callOptions.prompt, - ]; + // Inject context as system message + const enhancedPrompt = [ + { role: "system" as const, content: contextPrompt }, + ...callOptions.prompt, + ] - // Auto-save user message if enabled - if (addMemory === "always" && userQuery) { - if (verbose) console.log("[Supermemory] Auto-saving user message..."); + // Auto-save user message if enabled + if (addMemory === "always" && userQuery) { + if (verbose) console.log("[Supermemory] Auto-saving user message...") - await convexClient.action(addAction, { - content: userQuery, - containerTag, - metadata: { source: "ai-middleware", auto: true }, - }); - } + await convexClient.action(addAction, { + content: userQuery, + containerTag, + metadata: { source: "ai-middleware", auto: true }, + }) + } - // Call original model with enhanced context - return await model.doGenerate({ - ...callOptions, - prompt: enhancedPrompt, - }); - } catch (error) { - console.error("[Supermemory] Error in middleware:", error); - // Fallback to original model without context on error - return await model.doGenerate(callOptions); - } - }, + // Call original model with enhanced context + return await model.doGenerate({ + ...callOptions, + prompt: enhancedPrompt, + }) + } catch (error) { + console.error("[Supermemory] Error in middleware:", error) + // Fallback to original model without context on error + return await model.doGenerate(callOptions) + } + }, - doStream: async (callOptions: any) => { - // For streaming, we inject context upfront then stream normally - try { - const lastUserMessage = callOptions.prompt - .filter((msg: any) => msg.role === "user") - .slice(-1)[0]; + doStream: async (callOptions: any) => { + // For streaming, we inject context upfront then stream normally + try { + const lastUserMessage = callOptions.prompt + .filter((msg: any) => msg.role === "user") + .slice(-1)[0] - const userQuery = - lastUserMessage && "content" in lastUserMessage - ? typeof lastUserMessage.content === "string" - ? lastUserMessage.content - : lastUserMessage.content.map((c: any) => (c.type === "text" ? c.text : "")).join(" ") - : ""; + const userQuery = + lastUserMessage && "content" in lastUserMessage + ? typeof lastUserMessage.content === "string" + ? lastUserMessage.content + : lastUserMessage.content + .map((c: any) => (c.type === "text" ? c.text : "")) + .join(" ") + : "" - let userMemories = ""; - let generalSearchMemories = ""; - let searchResults: any[] = []; + let userMemories = "" + let generalSearchMemories = "" + let searchResults: any[] = [] - if (mode === "profile" || mode === "full") { - const profile = await convexClient.action(profileAction, { - containerTag, - q: userQuery || undefined, - }); + if (mode === "profile" || mode === "full") { + const profile = await convexClient.action(profileAction, { + containerTag, + q: userQuery || undefined, + }) - userMemories = [ - ...profile.profile.static.map((f: string) => `- ${f}`), - ...profile.profile.dynamic.map((f: string) => `- ${f}`), - ].join("\n"); - } + userMemories = [ + ...profile.profile.static.map((f: string) => `- ${f}`), + ...profile.profile.dynamic.map((f: string) => `- ${f}`), + ].join("\n") + } - if ((mode === "query" || mode === "full") && userQuery) { - const searchResult = await convexClient.action(searchAction, { - q: userQuery, - containerTag, - searchMode: "hybrid" as const, - limit: 5, - }); + if ((mode === "query" || mode === "full") && userQuery) { + const searchResult = await convexClient.action(searchAction, { + q: userQuery, + containerTag, + searchMode: "hybrid" as const, + limit: 5, + }) - searchResults = searchResult.results; - generalSearchMemories = searchResults - .map((r: any) => `- ${r.memory || r.chunk}`) - .join("\n"); - } + searchResults = searchResult.results + generalSearchMemories = searchResults + .map((r: any) => `- ${r.memory || r.chunk}`) + .join("\n") + } - const contextPrompt = promptTemplate({ - userMemories, - generalSearchMemories, - searchResults, - }); + const contextPrompt = promptTemplate({ + userMemories, + generalSearchMemories, + searchResults, + }) - const enhancedPrompt = [ - { role: "system" as const, content: contextPrompt }, - ...callOptions.prompt, - ]; + const enhancedPrompt = [ + { role: "system" as const, content: contextPrompt }, + ...callOptions.prompt, + ] - if (addMemory === "always" && userQuery) { - await convexClient.action(addAction, { - content: userQuery, - containerTag, - metadata: { source: "ai-middleware", auto: true }, - }); - } + if (addMemory === "always" && userQuery) { + await convexClient.action(addAction, { + content: userQuery, + containerTag, + metadata: { source: "ai-middleware", auto: true }, + }) + } - return await model.doStream({ - ...callOptions, - prompt: enhancedPrompt, - }); - } catch (error) { - console.error("[Supermemory] Error in streaming middleware:", error); - return await model.doStream(callOptions); - } - }, - } as T; + return await model.doStream({ + ...callOptions, + prompt: enhancedPrompt, + }) + } catch (error) { + console.error("[Supermemory] Error in streaming middleware:", error) + return await model.doStream(callOptions) + } + }, + } as T } diff --git a/packages/tools/src/convex-component/src/ai-sdk/tools.ts b/packages/tools/src/convex-component/src/ai-sdk/tools.ts index c60bdc9b..42ed9e11 100644 --- a/packages/tools/src/convex-component/src/ai-sdk/tools.ts +++ b/packages/tools/src/convex-component/src/ai-sdk/tools.ts @@ -1,7 +1,7 @@ -import { tool } from "ai"; -import { z } from "zod"; -import type { ConvexClient } from "convex/browser"; -import type { FunctionReference } from "convex/server"; +import { tool } from "ai" +import { z } from "zod" +import type { ConvexClient } from "convex/browser" +import type { FunctionReference } from "convex/server" /** * Supermemory AI SDK Tools for Convex @@ -34,125 +34,142 @@ import type { FunctionReference } from "convex/server"; * ``` */ export function supermemoryConvexTools( - convexClient: ConvexClient, - containerTag: string, - componentPath: string = "supermemory" + convexClient: ConvexClient, + containerTag: string, + componentPath = "supermemory", ): any { - const addAction = `${componentPath}:actions.add` as unknown as FunctionReference<"action">; - const searchAction = `${componentPath}:actions.search` as unknown as FunctionReference<"action">; + const addAction = + `${componentPath}:actions.add` as unknown as FunctionReference<"action"> + const searchAction = + `${componentPath}:actions.search` as unknown as FunctionReference<"action"> - return { - /** - * Search through user's memories using semantic search - * The AI agent calls this when it needs to recall information - */ - // @ts-ignore - AI SDK v4 tool type compatibility - searchMemories: tool({ - description: - "Search through the user's memories and past conversations. Use this to recall information the user has shared previously, their preferences, or relevant context from past interactions.", - parameters: z.object({ - informationToGet: z - .string() - .describe( - "What information you're looking for. Be specific and use natural language (e.g., 'user dietary preferences', 'previous conversation about TypeScript')" - ), - limit: z - .number() - .optional() - .describe("Maximum number of memories to retrieve (default: 5)"), - }), - // @ts-expect-error - AI SDK v4 tool type compatibility - execute: async ({ informationToGet, limit = 5 }: { informationToGet: string; limit?: number }) => { - try { - const result = await convexClient.action(searchAction, { - q: informationToGet, - containerTag, - searchMode: "hybrid" as const, - limit, - }); + return { + /** + * Search through user's memories using semantic search + * The AI agent calls this when it needs to recall information + */ + // @ts-expect-error - AI SDK v4 tool type compatibility + searchMemories: tool({ + description: + "Search through the user's memories and past conversations. Use this to recall information the user has shared previously, their preferences, or relevant context from past interactions.", + parameters: z.object({ + informationToGet: z + .string() + .describe( + "What information you're looking for. Be specific and use natural language (e.g., 'user dietary preferences', 'previous conversation about TypeScript')", + ), + limit: z + .number() + .optional() + .describe("Maximum number of memories to retrieve (default: 5)"), + }), + // @ts-expect-error - AI SDK v4 tool type compatibility + execute: async ({ + informationToGet, + limit = 5, + }: { + informationToGet: string + limit?: number + }) => { + try { + const result = await convexClient.action(searchAction, { + q: informationToGet, + containerTag, + searchMode: "hybrid" as const, + limit, + }) - if (!result || result.results.length === 0) { - return { - success: true, - results: [], - count: 0, - message: "No relevant memories found", - }; - } + if (!result || result.results.length === 0) { + return { + success: true, + results: [], + count: 0, + message: "No relevant memories found", + } + } - return { - success: true, - results: result.results.map((r: any) => ({ - content: r.memory || r.chunk, - similarity: r.similarity, - metadata: r.metadata, - })), - count: result.total, - cached: result.cached, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : "Search failed", - results: [], - count: 0, - }; - } - }, - }), + return { + success: true, + results: result.results.map((r: any) => ({ + content: r.memory || r.chunk, + similarity: r.similarity, + metadata: r.metadata, + })), + count: result.total, + cached: result.cached, + } + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : "Search failed", + results: [], + count: 0, + } + } + }, + }), - /** - * Add new information to user's memory - * The AI agent calls this when the user shares important information - */ - // @ts-ignore - AI SDK v4 tool type compatibility - addMemory: tool({ - description: - "Store new information about the user that should be remembered for future conversations. Use this when the user shares preferences, facts about themselves, or important context that should be recalled later.", - parameters: z.object({ - memory: z - .string() - .describe( - "The information to remember. Be clear and concise. Store facts, not full conversations (e.g., 'User is allergic to peanuts', 'User prefers dark mode')" - ), - customId: z - .string() - .optional() - .describe( - "Optional unique identifier for this memory (useful for updating existing memories)" - ), - metadata: z - .record(z.string(), z.any()) - .optional() - .describe("Optional metadata for categorization or filtering"), - }), - // @ts-expect-error - AI SDK v4 tool type compatibility - execute: async ({ memory, customId, metadata }: { memory: string; customId?: string; metadata?: Record }) => { - try { - const result = await convexClient.action(addAction, { - content: memory, - containerTag, - customId, - metadata, - }); + /** + * Add new information to user's memory + * The AI agent calls this when the user shares important information + */ + // @ts-expect-error - AI SDK v4 tool type compatibility + addMemory: tool({ + description: + "Store new information about the user that should be remembered for future conversations. Use this when the user shares preferences, facts about themselves, or important context that should be recalled later.", + parameters: z.object({ + memory: z + .string() + .describe( + "The information to remember. Be clear and concise. Store facts, not full conversations (e.g., 'User is allergic to peanuts', 'User prefers dark mode')", + ), + customId: z + .string() + .optional() + .describe( + "Optional unique identifier for this memory (useful for updating existing memories)", + ), + metadata: z + .record(z.string(), z.any()) + .optional() + .describe("Optional metadata for categorization or filtering"), + }), + // @ts-expect-error - AI SDK v4 tool type compatibility + execute: async ({ + memory, + customId, + metadata, + }: { + memory: string + customId?: string + metadata?: Record + }) => { + try { + const result = await convexClient.action(addAction, { + content: memory, + containerTag, + customId, + metadata, + }) - return { - success: true, - memory: { - id: result.id, - status: result.status, - }, - message: "Memory stored successfully", - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : "Failed to add memory", - }; - } - }, - }), - }; + return { + success: true, + memory: { + id: result.id, + status: result.status, + }, + message: "Memory stored successfully", + } + } catch (error) { + return { + success: false, + error: + error instanceof Error ? error.message : "Failed to add memory", + } + } + }, + }), + } } /** @@ -160,19 +177,19 @@ export function supermemoryConvexTools( */ export function searchMemoriesTool( - convexClient: ConvexClient, - containerTag: string, - componentPath: string = "supermemory" + convexClient: ConvexClient, + containerTag: string, + componentPath = "supermemory", ) { - return supermemoryConvexTools(convexClient, containerTag, componentPath) - .searchMemories; + return supermemoryConvexTools(convexClient, containerTag, componentPath) + .searchMemories } export function addMemoryTool( - convexClient: ConvexClient, - containerTag: string, - componentPath: string = "supermemory" + convexClient: ConvexClient, + containerTag: string, + componentPath = "supermemory", ) { - return supermemoryConvexTools(convexClient, containerTag, componentPath) - .addMemory; + return supermemoryConvexTools(convexClient, containerTag, componentPath) + .addMemory } diff --git a/packages/tools/src/convex-component/src/client/index.ts b/packages/tools/src/convex-component/src/client/index.ts index b85cd224..23069ef9 100644 --- a/packages/tools/src/convex-component/src/client/index.ts +++ b/packages/tools/src/convex-component/src/client/index.ts @@ -1,5 +1,5 @@ -import type { ConvexClient } from "convex/browser"; -import type { FunctionReference } from "convex/server"; +import type { ConvexClient } from "convex/browser" +import type { FunctionReference } from "convex/server" /** * Supermemory Convex Client @@ -9,89 +9,89 @@ import type { FunctionReference } from "convex/server"; */ export interface AddMemoryArgs { - content: string; - containerTag: string; - customId?: string; - metadata?: Record; + content: string + containerTag: string + customId?: string + metadata?: Record } export interface SearchMemoriesArgs { - q: string; - containerTag: string; - searchMode?: "hybrid" | "memories" | "documents"; - limit?: number; - threshold?: number; - rerank?: boolean; - filters?: Record; + q: string + containerTag: string + searchMode?: "hybrid" | "memories" | "documents" + limit?: number + threshold?: number + rerank?: boolean + filters?: Record } export interface ProfileArgs { - containerTag: string; - q?: string; + containerTag: string + q?: string } export interface SearchResult { - id: string; - memory?: string; - chunk?: string; - similarity: number; - metadata?: Record; - updatedAt: string; - version: number; + id: string + memory?: string + chunk?: string + similarity: number + metadata?: Record + updatedAt: string + version: number } export interface SearchResponse { - results: SearchResult[]; - timing: number; - total: number; - cached: boolean; + results: SearchResult[] + timing: number + total: number + cached: boolean } export interface ProfileResponse { - profile: { - static: string[]; - dynamic: string[]; - }; - searchResults?: { - results: Array<{ - id: string; - memory?: string; - chunk?: string; - similarity: number; - metadata?: Record; - }>; - }; - cached: boolean; + profile: { + static: string[] + dynamic: string[] + } + searchResults?: { + results: Array<{ + id: string + memory?: string + chunk?: string + similarity: number + metadata?: Record + }> + } + cached: boolean } export interface Document { - _id: string; - documentId: string; - customId?: string; - containerTag: string; - contentPreview: string; - metadata?: Record; - status: "queued" | "processed" | "failed"; - addedAt: number; + _id: string + documentId: string + customId?: string + containerTag: string + contentPreview: string + metadata?: Record + status: "queued" | "processed" | "failed" + addedAt: number } export interface ApiLog { - _id: string; - endpoint: string; - containerTag?: string; - requestBody?: any; - responseStatus: "success" | "error" | "pending"; - responseTime?: number; - errorMessage?: string; - timestamp: number; + _id: string + endpoint: string + containerTag?: string + requestBody?: any + responseStatus: "success" | "error" | "pending" + responseTime?: number + errorMessage?: string + timestamp: number } export interface ApiStats { - totalCalls: number; - successfulCalls: number; - failedCalls: number; - averageResponseTime: number; - callsByEndpoint: Record; + totalCalls: number + successfulCalls: number + failedCalls: number + averageResponseTime: number + callsByEndpoint: Record } /** @@ -122,121 +122,122 @@ export interface ApiStats { * ``` */ export function createSupermemoryClient( - client: ConvexClient, - componentPath: string = "supermemory" + client: ConvexClient, + componentPath = "supermemory", ) { - // Helper to construct function references - const action = (name: string): FunctionReference<"action"> => { - return `${componentPath}:actions.${name}` as any; - }; + // Helper to construct function references + const action = (name: string): FunctionReference<"action"> => { + return `${componentPath}:actions.${name}` as any + } - const query = (name: string): FunctionReference<"query"> => { - return `${componentPath}:queries.${name}` as any; - }; + const query = (name: string): FunctionReference<"query"> => { + return `${componentPath}:queries.${name}` as any + } - const mutation = (name: string): FunctionReference<"mutation"> => { - return `${componentPath}:mutations.${name}` as any; - }; + const mutation = (name: string): FunctionReference<"mutation"> => { + return `${componentPath}:mutations.${name}` as any + } - return { - /** - * Add content to Supermemory - * Stores text, conversations, files, or URLs for semantic search - */ - add: async (args: AddMemoryArgs) => { - return await client.action(action("add"), args); - }, + return { + /** + * Add content to Supermemory + * Stores text, conversations, files, or URLs for semantic search + */ + add: async (args: AddMemoryArgs) => { + return await client.action(action("add"), args) + }, - /** - * Search memories and documents - * Performs semantic search across all content - */ - search: async (args: SearchMemoriesArgs): Promise => { - return await client.action(action("search"), args); - }, + /** + * Search memories and documents + * Performs semantic search across all content + */ + search: async (args: SearchMemoriesArgs): Promise => { + return await client.action(action("search"), args) + }, - /** - * Get user profile with context - * Retrieves static/dynamic facts about a user plus relevant memories - */ - profile: async (args: ProfileArgs): Promise => { - return await client.action(action("profile"), args); - }, + /** + * Get user profile with context + * Retrieves static/dynamic facts about a user plus relevant memories + */ + profile: async (args: ProfileArgs): Promise => { + return await client.action(action("profile"), args) + }, - /** - * List documents added to Supermemory - * Query documents with optional filtering - */ - listDocuments: async (args?: { - containerTag?: string; - limit?: number; - }): Promise => { - return await client.query(query("listDocuments"), args || {}); - }, + /** + * List documents added to Supermemory + * Query documents with optional filtering + */ + listDocuments: async (args?: { + containerTag?: string + limit?: number + }): Promise => { + return await client.query(query("listDocuments"), args || {}) + }, - /** - * Get a document by custom ID - */ - getDocumentByCustomId: async (customId: string): Promise => { - return await client.query(query("getDocumentByCustomId"), { customId }); - }, + /** + * Get a document by custom ID + */ + getDocumentByCustomId: async ( + customId: string, + ): Promise => { + return await client.query(query("getDocumentByCustomId"), { customId }) + }, - /** - * Get API call logs - * View recent Supermemory API calls for debugging - */ - getApiLogs: async (args?: { - endpoint?: string; - containerTag?: string; - limit?: number; - }): Promise => { - return await client.query(query("getApiLogs"), args || {}); - }, + /** + * Get API call logs + * View recent Supermemory API calls for debugging + */ + getApiLogs: async (args?: { + endpoint?: string + containerTag?: string + limit?: number + }): Promise => { + return await client.query(query("getApiLogs"), args || {}) + }, - /** - * Get API statistics - * Aggregate stats for dashboard visibility - */ - getApiStats: async (args?: { - containerTag?: string; - }): Promise => { - return await client.query(query("getApiStats"), args || {}); - }, + /** + * Get API statistics + * Aggregate stats for dashboard visibility + */ + getApiStats: async (args?: { + containerTag?: string + }): Promise => { + return await client.query(query("getApiStats"), args || {}) + }, - /** - * Search cached documents locally - * Fast text search across cached content - */ - searchCached: async (args: { - searchText: string; - containerTag?: string; - limit?: number; - }): Promise => { - return await client.query(query("searchCachedDocuments"), args); - }, + /** + * Search cached documents locally + * Fast text search across cached content + */ + searchCached: async (args: { + searchText: string + containerTag?: string + limit?: number + }): Promise => { + return await client.query(query("searchCachedDocuments"), args) + }, - /** - * Clean expired cache entries - * Removes old search and profile caches - */ - cleanCache: async () => { - return await client.mutation(mutation("cleanExpiredCache"), {}); - }, + /** + * Clean expired cache entries + * Removes old search and profile caches + */ + cleanCache: async () => { + return await client.mutation(mutation("cleanExpiredCache"), {}) + }, - /** - * Update document status - */ - updateDocumentStatus: async (args: { - documentId: string; - status: "queued" | "processed" | "failed"; - }) => { - return await client.mutation(mutation("updateDocumentStatus"), args); - }, - - }; + /** + * Update document status + */ + updateDocumentStatus: async (args: { + documentId: string + status: "queued" | "processed" | "failed" + }) => { + return await client.mutation(mutation("updateDocumentStatus"), args) + }, + } } /** * Type for the Supermemory client */ -export type SupermemoryClient = ReturnType; +export type SupermemoryClient = ReturnType diff --git a/packages/tools/src/convex-component/src/component/actions.ts b/packages/tools/src/convex-component/src/component/actions.ts index 92f1147d..5563f73c 100644 --- a/packages/tools/src/convex-component/src/component/actions.ts +++ b/packages/tools/src/convex-component/src/component/actions.ts @@ -1,7 +1,7 @@ -import { action } from "./_generated/server"; -import { v } from "convex/values"; -import Supermemory from "supermemory"; -import { api, internal } from "./_generated/api"; +import { action } from "./_generated/server" +import { v } from "convex/values" +import Supermemory from "supermemory" +import { api, internal } from "./_generated/api" /** * Supermemory Actions @@ -15,262 +15,268 @@ import { api, internal } from "./_generated/api"; * Stores text, conversations, files, or URLs in Supermemory for semantic search */ export const add = action({ - args: { - content: v.string(), - containerTag: v.string(), - customId: v.optional(v.string()), - metadata: v.optional(v.any()), - }, - handler: async (ctx, args) => { - const startTime = Date.now(); + args: { + content: v.string(), + containerTag: v.string(), + customId: v.optional(v.string()), + metadata: v.optional(v.any()), + }, + handler: async (ctx, args) => { + const startTime = Date.now() - try { - // Get API key from config - const apiKey = await ctx.runQuery(internal.lib.getApiKey); - const client = new Supermemory({ apiKey }); + try { + // Get API key from config + const apiKey = await ctx.runQuery(internal.lib.getApiKey) + const client = new Supermemory({ apiKey }) - // Call Supermemory API - const result = await client.add({ - content: args.content, - containerTag: args.containerTag, - customId: args.customId, - metadata: args.metadata, - }); + // Call Supermemory API + const result = await client.add({ + content: args.content, + containerTag: args.containerTag, + customId: args.customId, + metadata: args.metadata, + }) - const responseTime = Date.now() - startTime; + const responseTime = Date.now() - startTime - // Store document metadata in Convex - await ctx.runMutation(internal.mutations.storeDocument, { - documentId: result.id, - customId: args.customId, - containerTag: args.containerTag, - contentPreview: args.content.substring(0, 200), - metadata: args.metadata, - status: result.status === "queued" ? "queued" : "processed", - }); + // Store document metadata in Convex + await ctx.runMutation(internal.mutations.storeDocument, { + documentId: result.id, + customId: args.customId, + containerTag: args.containerTag, + contentPreview: args.content.substring(0, 200), + metadata: args.metadata, + status: result.status === "queued" ? "queued" : "processed", + }) - // Store memory in dashboard table - await ctx.runMutation(internal.mutations.storeMemory, { - content: args.content, - containerTag: args.containerTag, - source: "manual", - supermemoryId: result.id, - metadata: args.metadata, - }); + // Store memory in dashboard table + await ctx.runMutation(internal.mutations.storeMemory, { + content: args.content, + containerTag: args.containerTag, + source: "manual", + supermemoryId: result.id, + metadata: args.metadata, + }) - // Update analytics - await ctx.runMutation(internal.mutations.updateAnalytics, { - containerTag: args.containerTag, - incrementMemories: 1, - }); + // Update analytics + await ctx.runMutation(internal.mutations.updateAnalytics, { + containerTag: args.containerTag, + incrementMemories: 1, + }) - // Log API call - await ctx.runMutation(internal.mutations.logApiCall, { - endpoint: "add", - containerTag: args.containerTag, - requestBody: args, - responseStatus: "success", - responseTime, - }); + // Log API call + await ctx.runMutation(internal.mutations.logApiCall, { + endpoint: "add", + containerTag: args.containerTag, + requestBody: args, + responseStatus: "success", + responseTime, + }) - return result; - } catch (error) { - const responseTime = Date.now() - startTime; + return result + } catch (error) { + const responseTime = Date.now() - startTime - // Log error - await ctx.runMutation(internal.mutations.logApiCall, { - endpoint: "add", - containerTag: args.containerTag, - requestBody: args, - responseStatus: "error", - responseTime, - errorMessage: error instanceof Error ? error.message : "Unknown error", - }); + // Log error + await ctx.runMutation(internal.mutations.logApiCall, { + endpoint: "add", + containerTag: args.containerTag, + requestBody: args, + responseStatus: "error", + responseTime, + errorMessage: error instanceof Error ? error.message : "Unknown error", + }) - throw error; - } - }, -}); + throw error + } + }, +}) /** * Search memories and documents * Performs semantic search across all content in Supermemory */ export const search = action({ - args: { - q: v.string(), - containerTag: v.string(), - searchMode: v.optional(v.union(v.literal("hybrid"), v.literal("memories"), v.literal("documents"))), - limit: v.optional(v.number()), - threshold: v.optional(v.number()), - rerank: v.optional(v.boolean()), - filters: v.optional(v.any()), - }, - handler: async (ctx, args) => { - const startTime = Date.now(); + args: { + q: v.string(), + containerTag: v.string(), + searchMode: v.optional( + v.union( + v.literal("hybrid"), + v.literal("memories"), + v.literal("documents"), + ), + ), + limit: v.optional(v.number()), + threshold: v.optional(v.number()), + rerank: v.optional(v.boolean()), + filters: v.optional(v.any()), + }, + handler: async (ctx, args) => { + const startTime = Date.now() - try { - // Check cache first - const cached = await ctx.runQuery(api.queries.getSearchCache, { - query: args.q, - containerTag: args.containerTag, - searchMode: args.searchMode, - }); + try { + // Check cache first + const cached = await ctx.runQuery(api.queries.getSearchCache, { + query: args.q, + containerTag: args.containerTag, + searchMode: args.searchMode, + }) - if (cached) { - return { - results: cached.results, - timing: cached.timing, - total: cached.total, - cached: true, - }; - } + if (cached) { + return { + results: cached.results, + timing: cached.timing, + total: cached.total, + cached: true, + } + } - // Get API key from config - const apiKey = await ctx.runQuery(internal.lib.getApiKey); - const client = new Supermemory({ apiKey }); + // Get API key from config + const apiKey = await ctx.runQuery(internal.lib.getApiKey) + const client = new Supermemory({ apiKey }) - // Call Supermemory API - const result = await client.search.memories({ - q: args.q, - containerTag: args.containerTag, - searchMode: args.searchMode || "hybrid", - limit: args.limit, - threshold: args.threshold, - rerank: args.rerank, - filters: args.filters, - }); + // Call Supermemory API + const result = await client.search.memories({ + q: args.q, + containerTag: args.containerTag, + searchMode: args.searchMode || "hybrid", + limit: args.limit, + threshold: args.threshold, + rerank: args.rerank, + filters: args.filters, + }) - const responseTime = Date.now() - startTime; + const responseTime = Date.now() - startTime - // Cache results (expires in 5 minutes) - await ctx.runMutation(internal.mutations.cacheSearchResults, { - query: args.q, - containerTag: args.containerTag, - searchMode: args.searchMode, - results: result.results, - timing: result.timing, - total: result.total, - ttl: 300, // 5 minutes - }); + // Cache results (expires in 5 minutes) + await ctx.runMutation(internal.mutations.cacheSearchResults, { + query: args.q, + containerTag: args.containerTag, + searchMode: args.searchMode, + results: result.results, + timing: result.timing, + total: result.total, + ttl: 300, // 5 minutes + }) - // Update analytics - await ctx.runMutation(internal.mutations.updateAnalytics, { - containerTag: args.containerTag, - incrementSearches: 1, - responseTime, - }); + // Update analytics + await ctx.runMutation(internal.mutations.updateAnalytics, { + containerTag: args.containerTag, + incrementSearches: 1, + responseTime, + }) - // Log API call - await ctx.runMutation(internal.mutations.logApiCall, { - endpoint: "search", - containerTag: args.containerTag, - requestBody: args, - responseStatus: "success", - responseTime, - }); + // Log API call + await ctx.runMutation(internal.mutations.logApiCall, { + endpoint: "search", + containerTag: args.containerTag, + requestBody: args, + responseStatus: "success", + responseTime, + }) - return { - ...result, - cached: false, - }; - } catch (error) { - const responseTime = Date.now() - startTime; + return { + ...result, + cached: false, + } + } catch (error) { + const responseTime = Date.now() - startTime - // Log error - await ctx.runMutation(internal.mutations.logApiCall, { - endpoint: "search", - containerTag: args.containerTag, - requestBody: args, - responseStatus: "error", - responseTime, - errorMessage: error instanceof Error ? error.message : "Unknown error", - }); + // Log error + await ctx.runMutation(internal.mutations.logApiCall, { + endpoint: "search", + containerTag: args.containerTag, + requestBody: args, + responseStatus: "error", + responseTime, + errorMessage: error instanceof Error ? error.message : "Unknown error", + }) - throw error; - } - }, -}); + throw error + } + }, +}) /** * Get user profile with context * Retrieves static/dynamic facts about a user plus relevant memories */ export const profile = action({ - args: { - containerTag: v.string(), - q: v.optional(v.string()), - }, - handler: async (ctx, args) => { - const startTime = Date.now(); + args: { + containerTag: v.string(), + q: v.optional(v.string()), + }, + handler: async (ctx, args) => { + const startTime = Date.now() - try { - // Check cache first - const cached = await ctx.runQuery(api.queries.getProfileCache, { - containerTag: args.containerTag, - }); + try { + // Check cache first + const cached = await ctx.runQuery(api.queries.getProfileCache, { + containerTag: args.containerTag, + }) - if (cached) { - return { - profile: { - static: cached.staticProfile, - dynamic: cached.dynamicProfile, - }, - searchResults: cached.searchResults - ? { results: cached.searchResults } - : undefined, - cached: true, - }; - } + if (cached) { + return { + profile: { + static: cached.staticProfile, + dynamic: cached.dynamicProfile, + }, + searchResults: cached.searchResults + ? { results: cached.searchResults } + : undefined, + cached: true, + } + } - // Get API key from config - const apiKey = await ctx.runQuery(internal.lib.getApiKey); - const client = new Supermemory({ apiKey }); + // Get API key from config + const apiKey = await ctx.runQuery(internal.lib.getApiKey) + const client = new Supermemory({ apiKey }) - // Call Supermemory API - const result = await client.profile({ - containerTag: args.containerTag, - q: args.q, - }); + // Call Supermemory API + const result = await client.profile({ + containerTag: args.containerTag, + q: args.q, + }) - const responseTime = Date.now() - startTime; + const responseTime = Date.now() - startTime - // Cache profile (expires in 2 minutes for freshness) - await ctx.runMutation(internal.mutations.cacheProfile, { - containerTag: args.containerTag, - staticProfile: result.profile.static, - dynamicProfile: result.profile.dynamic, - searchResults: result.searchResults?.results, - ttl: 120, // 2 minutes - }); + // Cache profile (expires in 2 minutes for freshness) + await ctx.runMutation(internal.mutations.cacheProfile, { + containerTag: args.containerTag, + staticProfile: result.profile.static, + dynamicProfile: result.profile.dynamic, + searchResults: result.searchResults?.results, + ttl: 120, // 2 minutes + }) - // Log API call - await ctx.runMutation(internal.mutations.logApiCall, { - endpoint: "profile", - containerTag: args.containerTag, - requestBody: args, - responseStatus: "success", - responseTime, - }); + // Log API call + await ctx.runMutation(internal.mutations.logApiCall, { + endpoint: "profile", + containerTag: args.containerTag, + requestBody: args, + responseStatus: "success", + responseTime, + }) - return { - ...result, - cached: false, - }; - } catch (error) { - const responseTime = Date.now() - startTime; + return { + ...result, + cached: false, + } + } catch (error) { + const responseTime = Date.now() - startTime - // Log error - await ctx.runMutation(internal.mutations.logApiCall, { - endpoint: "profile", - containerTag: args.containerTag, - requestBody: args, - responseStatus: "error", - responseTime, - errorMessage: error instanceof Error ? error.message : "Unknown error", - }); + // Log error + await ctx.runMutation(internal.mutations.logApiCall, { + endpoint: "profile", + containerTag: args.containerTag, + requestBody: args, + responseStatus: "error", + responseTime, + errorMessage: error instanceof Error ? error.message : "Unknown error", + }) - throw error; - } - }, -}); + throw error + } + }, +}) diff --git a/packages/tools/src/convex-component/src/component/convex.config.ts b/packages/tools/src/convex-component/src/component/convex.config.ts index e057cf24..c2618fec 100644 --- a/packages/tools/src/convex-component/src/component/convex.config.ts +++ b/packages/tools/src/convex-component/src/component/convex.config.ts @@ -1,4 +1,4 @@ -import { defineComponent } from "convex/server"; +import { defineComponent } from "convex/server" /** * Supermemory Convex Component @@ -7,4 +7,4 @@ import { defineComponent } from "convex/server"; * into your Convex application, providing reactive access to AI-powered memory, * user profiles, and semantic search. */ -export default defineComponent("supermemory"); +export default defineComponent("supermemory") diff --git a/packages/tools/src/convex-component/src/component/install.ts b/packages/tools/src/convex-component/src/component/install.ts index 2ca00e5b..03e63475 100644 --- a/packages/tools/src/convex-component/src/component/install.ts +++ b/packages/tools/src/convex-component/src/component/install.ts @@ -5,6 +5,20 @@ * All functions listed here will be accessible from the client. */ -export { add, search, profile } from "./actions"; -export { getApiStats, getApiLogs, listDocuments, getDocumentByCustomId, listMemories, getChatSessions, getChatSession, getAnalytics, getDashboardOverview } from "./queries"; -export { cleanExpiredCache, updateDocumentStatus, trackChatMessage } from "./mutations"; +export { add, search, profile } from "./actions" +export { + getApiStats, + getApiLogs, + listDocuments, + getDocumentByCustomId, + listMemories, + getChatSessions, + getChatSession, + getAnalytics, + getDashboardOverview, +} from "./queries" +export { + cleanExpiredCache, + updateDocumentStatus, + trackChatMessage, +} from "./mutations" diff --git a/packages/tools/src/convex-component/src/component/lib.ts b/packages/tools/src/convex-component/src/component/lib.ts index f83cd070..7f726027 100644 --- a/packages/tools/src/convex-component/src/component/lib.ts +++ b/packages/tools/src/convex-component/src/component/lib.ts @@ -1,4 +1,4 @@ -import { internalQuery } from "./_generated/server"; +import { internalQuery } from "./_generated/server" /** * Internal library functions @@ -11,26 +11,26 @@ import { internalQuery } from "./_generated/server"; * Used by actions to authenticate with Supermemory API */ export const getApiKey = internalQuery({ - args: {}, - handler: async (ctx): Promise => { - // Check Convex environment variable first - const envApiKey = process.env.SUPERMEMORY_API_KEY; - if (envApiKey) { - return envApiKey; - } + args: {}, + handler: async (ctx): Promise => { + // Check Convex environment variable first + const envApiKey = process.env.SUPERMEMORY_API_KEY + if (envApiKey) { + return envApiKey + } - // Fall back to database config - const config = await ctx.db - .query("config") - .withIndex("by_key", (q) => q.eq("key", "SUPERMEMORY_API_KEY")) - .first(); + // Fall back to database config + const config = await ctx.db + .query("config") + .withIndex("by_key", (q) => q.eq("key", "SUPERMEMORY_API_KEY")) + .first() - if (config && config.value) { - return config.value as string; - } + if (config && config.value) { + return config.value as string + } - throw new Error( - "Supermemory API key not configured. Set SUPERMEMORY_API_KEY environment variable with: npx convex env set SUPERMEMORY_API_KEY your-key" - ); - }, -}); + throw new Error( + "Supermemory API key not configured. Set SUPERMEMORY_API_KEY environment variable with: npx convex env set SUPERMEMORY_API_KEY your-key", + ) + }, +}) diff --git a/packages/tools/src/convex-component/src/component/mutations.ts b/packages/tools/src/convex-component/src/component/mutations.ts index 6440cd94..e54979b9 100644 --- a/packages/tools/src/convex-component/src/component/mutations.ts +++ b/packages/tools/src/convex-component/src/component/mutations.ts @@ -1,5 +1,5 @@ -import { internalMutation, mutation } from "./_generated/server"; -import { v } from "convex/values"; +import { internalMutation, mutation } from "./_generated/server" +import { v } from "convex/values" /** * Supermemory Mutations @@ -13,243 +13,257 @@ import { v } from "convex/values"; * Stores search results from Supermemory API for reactive access */ export const cacheSearchResults = internalMutation({ - args: { - query: v.string(), - containerTag: v.string(), - searchMode: v.optional(v.union(v.literal("hybrid"), v.literal("memories"), v.literal("documents"))), - results: v.array(v.any()), // Accept any shape from Supermemory API - timing: v.number(), - total: v.number(), - ttl: v.number(), // Time to live in seconds - }, - handler: async (ctx, args) => { - const expiresAt = Date.now() + args.ttl * 1000; + args: { + query: v.string(), + containerTag: v.string(), + searchMode: v.optional( + v.union( + v.literal("hybrid"), + v.literal("memories"), + v.literal("documents"), + ), + ), + results: v.array(v.any()), // Accept any shape from Supermemory API + timing: v.number(), + total: v.number(), + ttl: v.number(), // Time to live in seconds + }, + handler: async (ctx, args) => { + const expiresAt = Date.now() + args.ttl * 1000 - // Check if cache already exists - const existing = await ctx.db - .query("searchCache") - .withIndex("by_query_container", (q) => - q.eq("query", args.query).eq("containerTag", args.containerTag) - ) - .first(); + // Check if cache already exists + const existing = await ctx.db + .query("searchCache") + .withIndex("by_query_container", (q) => + q.eq("query", args.query).eq("containerTag", args.containerTag), + ) + .first() - if (existing) { - // Update existing cache - await ctx.db.patch(existing._id, { - results: args.results, - timing: args.timing, - total: args.total, - expiresAt, - searchMode: args.searchMode, - }); - } else { - // Create new cache entry - await ctx.db.insert("searchCache", { - query: args.query, - containerTag: args.containerTag, - searchMode: args.searchMode, - results: args.results, - timing: args.timing, - total: args.total, - expiresAt, - }); - } - }, -}); + if (existing) { + // Update existing cache + await ctx.db.patch(existing._id, { + results: args.results, + timing: args.timing, + total: args.total, + expiresAt, + searchMode: args.searchMode, + }) + } else { + // Create new cache entry + await ctx.db.insert("searchCache", { + query: args.query, + containerTag: args.containerTag, + searchMode: args.searchMode, + results: args.results, + timing: args.timing, + total: args.total, + expiresAt, + }) + } + }, +}) /** * Cache user profile * Stores user profile from Supermemory API for reactive access */ export const cacheProfile = internalMutation({ - args: { - containerTag: v.string(), - staticProfile: v.array(v.string()), - dynamicProfile: v.array(v.string()), - searchResults: v.optional( - v.array( - v.object({ - id: v.string(), - memory: v.optional(v.string()), - chunk: v.optional(v.string()), - similarity: v.number(), - metadata: v.optional(v.any()), - }) - ) - ), - ttl: v.number(), - }, - handler: async (ctx, args) => { - const expiresAt = Date.now() + args.ttl * 1000; + args: { + containerTag: v.string(), + staticProfile: v.array(v.string()), + dynamicProfile: v.array(v.string()), + searchResults: v.optional( + v.array( + v.object({ + id: v.string(), + memory: v.optional(v.string()), + chunk: v.optional(v.string()), + similarity: v.number(), + metadata: v.optional(v.any()), + }), + ), + ), + ttl: v.number(), + }, + handler: async (ctx, args) => { + const expiresAt = Date.now() + args.ttl * 1000 - // Check if profile cache exists - const existing = await ctx.db - .query("profileCache") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .first(); + // Check if profile cache exists + const existing = await ctx.db + .query("profileCache") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .first() - if (existing) { - // Update existing cache - await ctx.db.patch(existing._id, { - staticProfile: args.staticProfile, - dynamicProfile: args.dynamicProfile, - searchResults: args.searchResults, - expiresAt, - }); - } else { - // Create new cache entry - await ctx.db.insert("profileCache", { - containerTag: args.containerTag, - staticProfile: args.staticProfile, - dynamicProfile: args.dynamicProfile, - searchResults: args.searchResults, - expiresAt, - }); - } - }, -}); + if (existing) { + // Update existing cache + await ctx.db.patch(existing._id, { + staticProfile: args.staticProfile, + dynamicProfile: args.dynamicProfile, + searchResults: args.searchResults, + expiresAt, + }) + } else { + // Create new cache entry + await ctx.db.insert("profileCache", { + containerTag: args.containerTag, + staticProfile: args.staticProfile, + dynamicProfile: args.dynamicProfile, + searchResults: args.searchResults, + expiresAt, + }) + } + }, +}) /** * Store document metadata * Tracks documents/memories added to Supermemory */ export const storeDocument = internalMutation({ - args: { - documentId: v.string(), - customId: v.optional(v.string()), - containerTag: v.string(), - contentPreview: v.string(), - metadata: v.optional(v.any()), - status: v.union(v.literal("queued"), v.literal("processed"), v.literal("failed")), - }, - handler: async (ctx, args) => { - // Check if document with this customId or documentId exists - const existingByCustomId = args.customId - ? await ctx.db - .query("documents") - .withIndex("by_custom_id", (q) => q.eq("customId", args.customId)) - .first() - : null; + args: { + documentId: v.string(), + customId: v.optional(v.string()), + containerTag: v.string(), + contentPreview: v.string(), + metadata: v.optional(v.any()), + status: v.union( + v.literal("queued"), + v.literal("processed"), + v.literal("failed"), + ), + }, + handler: async (ctx, args) => { + // Check if document with this customId or documentId exists + const existingByCustomId = args.customId + ? await ctx.db + .query("documents") + .withIndex("by_custom_id", (q) => q.eq("customId", args.customId)) + .first() + : null - const existingByDocId = await ctx.db - .query("documents") - .withIndex("by_document_id", (q) => q.eq("documentId", args.documentId)) - .first(); + const existingByDocId = await ctx.db + .query("documents") + .withIndex("by_document_id", (q) => q.eq("documentId", args.documentId)) + .first() - const existing = existingByCustomId || existingByDocId; + const existing = existingByCustomId || existingByDocId - if (existing) { - // Update existing document - await ctx.db.patch(existing._id, { - documentId: args.documentId, - customId: args.customId, - contentPreview: args.contentPreview, - metadata: args.metadata, - status: args.status, - }); - } else { - // Create new document entry - await ctx.db.insert("documents", { - documentId: args.documentId, - customId: args.customId, - containerTag: args.containerTag, - contentPreview: args.contentPreview, - metadata: args.metadata, - status: args.status, - addedAt: Date.now(), - }); - } - }, -}); + if (existing) { + // Update existing document + await ctx.db.patch(existing._id, { + documentId: args.documentId, + customId: args.customId, + contentPreview: args.contentPreview, + metadata: args.metadata, + status: args.status, + }) + } else { + // Create new document entry + await ctx.db.insert("documents", { + documentId: args.documentId, + customId: args.customId, + containerTag: args.containerTag, + contentPreview: args.contentPreview, + metadata: args.metadata, + status: args.status, + addedAt: Date.now(), + }) + } + }, +}) /** * Log API call * Records API calls for debugging and analytics */ export const logApiCall = internalMutation({ - args: { - endpoint: v.string(), - containerTag: v.optional(v.string()), - requestBody: v.optional(v.any()), - responseStatus: v.union( - v.literal("success"), - v.literal("error"), - v.literal("pending") - ), - responseTime: v.optional(v.number()), - errorMessage: v.optional(v.string()), - }, - handler: async (ctx, args) => { - await ctx.db.insert("apiLogs", { - endpoint: args.endpoint, - containerTag: args.containerTag, - requestBody: args.requestBody, - responseStatus: args.responseStatus, - responseTime: args.responseTime, - errorMessage: args.errorMessage, - timestamp: Date.now(), - }); - }, -}); + args: { + endpoint: v.string(), + containerTag: v.optional(v.string()), + requestBody: v.optional(v.any()), + responseStatus: v.union( + v.literal("success"), + v.literal("error"), + v.literal("pending"), + ), + responseTime: v.optional(v.number()), + errorMessage: v.optional(v.string()), + }, + handler: async (ctx, args) => { + await ctx.db.insert("apiLogs", { + endpoint: args.endpoint, + containerTag: args.containerTag, + requestBody: args.requestBody, + responseStatus: args.responseStatus, + responseTime: args.responseTime, + errorMessage: args.errorMessage, + timestamp: Date.now(), + }) + }, +}) /** * Clean expired cache entries * Removes expired search and profile caches */ export const cleanExpiredCache = mutation({ - args: {}, - handler: async (ctx) => { - const now = Date.now(); + args: {}, + handler: async (ctx) => { + const now = Date.now() - // Clean expired search caches - const expiredSearches = await ctx.db - .query("searchCache") - .withIndex("by_expires", (q) => q.lt("expiresAt", now)) - .collect(); + // Clean expired search caches + const expiredSearches = await ctx.db + .query("searchCache") + .withIndex("by_expires", (q) => q.lt("expiresAt", now)) + .collect() - for (const cache of expiredSearches) { - await ctx.db.delete(cache._id); - } + for (const cache of expiredSearches) { + await ctx.db.delete(cache._id) + } - // Clean expired profile caches - const expiredProfiles = await ctx.db - .query("profileCache") - .withIndex("by_expires", (q) => q.lt("expiresAt", now)) - .collect(); + // Clean expired profile caches + const expiredProfiles = await ctx.db + .query("profileCache") + .withIndex("by_expires", (q) => q.lt("expiresAt", now)) + .collect() - for (const cache of expiredProfiles) { - await ctx.db.delete(cache._id); - } + for (const cache of expiredProfiles) { + await ctx.db.delete(cache._id) + } - return { - cleanedSearchCaches: expiredSearches.length, - cleanedProfileCaches: expiredProfiles.length, - }; - }, -}); + return { + cleanedSearchCaches: expiredSearches.length, + cleanedProfileCaches: expiredProfiles.length, + } + }, +}) /** * Update document status * Updates the processing status of a document */ export const updateDocumentStatus = mutation({ - args: { - documentId: v.string(), - status: v.union(v.literal("queued"), v.literal("processed"), v.literal("failed")), - }, - handler: async (ctx, args) => { - const doc = await ctx.db - .query("documents") - .withIndex("by_document_id", (q) => q.eq("documentId", args.documentId)) - .first(); + args: { + documentId: v.string(), + status: v.union( + v.literal("queued"), + v.literal("processed"), + v.literal("failed"), + ), + }, + handler: async (ctx, args) => { + const doc = await ctx.db + .query("documents") + .withIndex("by_document_id", (q) => q.eq("documentId", args.documentId)) + .first() - if (!doc) { - throw new Error(`Document ${args.documentId} not found`); - } + if (!doc) { + throw new Error(`Document ${args.documentId} not found`) + } - await ctx.db.patch(doc._id, { status: args.status }); - }, -}); + await ctx.db.patch(doc._id, { status: args.status }) + }, +}) /** * Initialize or update API key @@ -259,189 +273,199 @@ export const updateDocumentStatus = mutation({ * for production, or call this from a server-side admin endpoint with proper auth checks. */ export const setApiKey = internalMutation({ - args: { - apiKey: v.string(), - }, - handler: async (ctx, args) => { - const existing = await ctx.db - .query("config") - .withIndex("by_key", (q) => q.eq("key", "SUPERMEMORY_API_KEY")) - .first(); + args: { + apiKey: v.string(), + }, + handler: async (ctx, args) => { + const existing = await ctx.db + .query("config") + .withIndex("by_key", (q) => q.eq("key", "SUPERMEMORY_API_KEY")) + .first() - if (existing) { - await ctx.db.patch(existing._id, { value: args.apiKey }); - } else { - await ctx.db.insert("config", { - key: "SUPERMEMORY_API_KEY", - value: args.apiKey, - }); - } - }, -}); + if (existing) { + await ctx.db.patch(existing._id, { value: args.apiKey }) + } else { + await ctx.db.insert("config", { + key: "SUPERMEMORY_API_KEY", + value: args.apiKey, + }) + } + }, +}) /** * Store a memory * Tracks individual memories in the dashboard */ export const storeMemory = internalMutation({ - args: { - content: v.string(), - containerTag: v.string(), - source: v.union(v.literal("chat"), v.literal("document"), v.literal("manual")), - supermemoryId: v.optional(v.string()), - metadata: v.optional(v.any()), - }, - handler: async (ctx, args) => { - await ctx.db.insert("memories", { - content: args.content, - containerTag: args.containerTag, - source: args.source, - supermemoryId: args.supermemoryId, - createdAt: Date.now(), - metadata: args.metadata, - }); - }, -}); + args: { + content: v.string(), + containerTag: v.string(), + source: v.union( + v.literal("chat"), + v.literal("document"), + v.literal("manual"), + ), + supermemoryId: v.optional(v.string()), + metadata: v.optional(v.any()), + }, + handler: async (ctx, args) => { + await ctx.db.insert("memories", { + content: args.content, + containerTag: args.containerTag, + source: args.source, + supermemoryId: args.supermemoryId, + createdAt: Date.now(), + metadata: args.metadata, + }) + }, +}) /** * Create or update chat session * Tracks conversation history with memory usage */ export const updateChatSession = internalMutation({ - args: { - containerTag: v.string(), - sessionId: v.optional(v.id("chatSessions")), - newMessage: v.object({ - role: v.union(v.literal("user"), v.literal("assistant")), - content: v.string(), - timestamp: v.number(), - }), - memoriesRetrieved: v.array(v.string()), - }, - handler: async (ctx, args) => { - if (args.sessionId) { - // Update existing session - const session = await ctx.db.get(args.sessionId); - if (session) { - await ctx.db.patch(args.sessionId, { - messages: [...session.messages, args.newMessage], - memoriesRetrieved: [ - ...new Set([...session.memoriesRetrieved, ...args.memoriesRetrieved]) - ], - lastMessageAt: args.newMessage.timestamp, - }); - return args.sessionId; - } - } + args: { + containerTag: v.string(), + sessionId: v.optional(v.id("chatSessions")), + newMessage: v.object({ + role: v.union(v.literal("user"), v.literal("assistant")), + content: v.string(), + timestamp: v.number(), + }), + memoriesRetrieved: v.array(v.string()), + }, + handler: async (ctx, args) => { + if (args.sessionId) { + // Update existing session + const session = await ctx.db.get(args.sessionId) + if (session) { + await ctx.db.patch(args.sessionId, { + messages: [...session.messages, args.newMessage], + memoriesRetrieved: [ + ...new Set([ + ...session.memoriesRetrieved, + ...args.memoriesRetrieved, + ]), + ], + lastMessageAt: args.newMessage.timestamp, + }) + return args.sessionId + } + } - // Create new session - const sessionId = await ctx.db.insert("chatSessions", { - containerTag: args.containerTag, - messages: [args.newMessage], - memoriesRetrieved: args.memoriesRetrieved, - createdAt: Date.now(), - lastMessageAt: args.newMessage.timestamp, - }); - return sessionId; - }, -}); + // Create new session + const sessionId = await ctx.db.insert("chatSessions", { + containerTag: args.containerTag, + messages: [args.newMessage], + memoriesRetrieved: args.memoriesRetrieved, + createdAt: Date.now(), + lastMessageAt: args.newMessage.timestamp, + }) + return sessionId + }, +}) /** * Public wrapper for updateChatSession * Allows clients to track chat sessions */ export const trackChatMessage = mutation({ - args: { - containerTag: v.string(), - sessionId: v.optional(v.id("chatSessions")), - newMessage: v.object({ - role: v.union(v.literal("user"), v.literal("assistant")), - content: v.string(), - timestamp: v.number(), - }), - memoriesRetrieved: v.array(v.string()), - }, - handler: async (ctx, args) => { - // Inline the logic instead of calling another mutation - if (args.sessionId) { - // Update existing session - const session = await ctx.db.get(args.sessionId); - if (session) { - await ctx.db.patch(args.sessionId, { - messages: [...session.messages, args.newMessage], - memoriesRetrieved: [ - ...new Set([...session.memoriesRetrieved, ...args.memoriesRetrieved]) - ], - lastMessageAt: args.newMessage.timestamp, - }); - return args.sessionId; - } - } + args: { + containerTag: v.string(), + sessionId: v.optional(v.id("chatSessions")), + newMessage: v.object({ + role: v.union(v.literal("user"), v.literal("assistant")), + content: v.string(), + timestamp: v.number(), + }), + memoriesRetrieved: v.array(v.string()), + }, + handler: async (ctx, args) => { + // Inline the logic instead of calling another mutation + if (args.sessionId) { + // Update existing session + const session = await ctx.db.get(args.sessionId) + if (session) { + await ctx.db.patch(args.sessionId, { + messages: [...session.messages, args.newMessage], + memoriesRetrieved: [ + ...new Set([ + ...session.memoriesRetrieved, + ...args.memoriesRetrieved, + ]), + ], + lastMessageAt: args.newMessage.timestamp, + }) + return args.sessionId + } + } - // Create new session - const sessionId = await ctx.db.insert("chatSessions", { - containerTag: args.containerTag, - messages: [args.newMessage], - memoriesRetrieved: args.memoriesRetrieved, - createdAt: Date.now(), - lastMessageAt: args.newMessage.timestamp, - }); - return sessionId; - }, -}); + // Create new session + const sessionId = await ctx.db.insert("chatSessions", { + containerTag: args.containerTag, + messages: [args.newMessage], + memoriesRetrieved: args.memoriesRetrieved, + createdAt: Date.now(), + lastMessageAt: args.newMessage.timestamp, + }) + return sessionId + }, +}) /** * Update analytics * Updates usage statistics for a user */ export const updateAnalytics = internalMutation({ - args: { - containerTag: v.string(), - incrementMemories: v.optional(v.number()), - incrementChats: v.optional(v.number()), - incrementSearches: v.optional(v.number()), - responseTime: v.optional(v.number()), - }, - handler: async (ctx, args) => { - const existing = await ctx.db - .query("analytics") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .first(); + args: { + containerTag: v.string(), + incrementMemories: v.optional(v.number()), + incrementChats: v.optional(v.number()), + incrementSearches: v.optional(v.number()), + responseTime: v.optional(v.number()), + }, + handler: async (ctx, args) => { + const existing = await ctx.db + .query("analytics") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .first() - if (existing) { - // Update existing analytics - const updates: any = { - lastActive: Date.now(), - }; + if (existing) { + // Update existing analytics + const updates: any = { + lastActive: Date.now(), + } - if (args.incrementMemories) { - updates.totalMemories = existing.totalMemories + args.incrementMemories; - } - if (args.incrementChats) { - updates.totalChats = existing.totalChats + args.incrementChats; - } - if (args.incrementSearches) { - updates.totalSearches = existing.totalSearches + args.incrementSearches; - } - if (args.incrementSearches && args.responseTime) { - // Only update average when we're also incrementing searches - const totalTime = existing.avgResponseTime * existing.totalSearches; - const newTotal = totalTime + args.responseTime; - const newSearchCount = existing.totalSearches + args.incrementSearches; - updates.avgResponseTime = newTotal / newSearchCount; - } + if (args.incrementMemories) { + updates.totalMemories = existing.totalMemories + args.incrementMemories + } + if (args.incrementChats) { + updates.totalChats = existing.totalChats + args.incrementChats + } + if (args.incrementSearches) { + updates.totalSearches = existing.totalSearches + args.incrementSearches + } + if (args.incrementSearches && args.responseTime) { + // Only update average when we're also incrementing searches + const totalTime = existing.avgResponseTime * existing.totalSearches + const newTotal = totalTime + args.responseTime + const newSearchCount = existing.totalSearches + args.incrementSearches + updates.avgResponseTime = newTotal / newSearchCount + } - await ctx.db.patch(existing._id, updates); - } else { - // Create new analytics entry - await ctx.db.insert("analytics", { - containerTag: args.containerTag, - totalMemories: args.incrementMemories || 0, - totalChats: args.incrementChats || 0, - totalSearches: args.incrementSearches || 0, - avgResponseTime: args.responseTime || 0, - lastActive: Date.now(), - }); - } - }, -}); + await ctx.db.patch(existing._id, updates) + } else { + // Create new analytics entry + await ctx.db.insert("analytics", { + containerTag: args.containerTag, + totalMemories: args.incrementMemories || 0, + totalChats: args.incrementChats || 0, + totalSearches: args.incrementSearches || 0, + avgResponseTime: args.responseTime || 0, + lastActive: Date.now(), + }) + } + }, +}) diff --git a/packages/tools/src/convex-component/src/component/queries.ts b/packages/tools/src/convex-component/src/component/queries.ts index f96da795..e1854222 100644 --- a/packages/tools/src/convex-component/src/component/queries.ts +++ b/packages/tools/src/convex-component/src/component/queries.ts @@ -1,5 +1,5 @@ -import { query } from "./_generated/server"; -import { v } from "convex/values"; +import { query } from "./_generated/server" +import { v } from "convex/values" /** * Supermemory Queries @@ -13,325 +13,336 @@ import { v } from "convex/values"; * Returns cached search results if available and not expired */ export const getSearchCache = query({ - args: { - query: v.string(), - containerTag: v.string(), - searchMode: v.optional(v.union(v.literal("hybrid"), v.literal("memories"), v.literal("documents"))), - }, - handler: async (ctx, args) => { - const now = Date.now(); + args: { + query: v.string(), + containerTag: v.string(), + searchMode: v.optional( + v.union( + v.literal("hybrid"), + v.literal("memories"), + v.literal("documents"), + ), + ), + }, + handler: async (ctx, args) => { + const now = Date.now() - const cached = await ctx.db - .query("searchCache") - .withIndex("by_query_container", (q) => - q.eq("query", args.query).eq("containerTag", args.containerTag) - ) - .first(); + const cached = await ctx.db + .query("searchCache") + .withIndex("by_query_container", (q) => + q.eq("query", args.query).eq("containerTag", args.containerTag), + ) + .first() - // Return null if cache expired or searchMode doesn't match - if (!cached || cached.expiresAt < now) { - return null; - } - if (args.searchMode && cached.searchMode !== args.searchMode) { - return null; - } + // Return null if cache expired or searchMode doesn't match + if (!cached || cached.expiresAt < now) { + return null + } + if (args.searchMode && cached.searchMode !== args.searchMode) { + return null + } - return cached; - }, -}); + return cached + }, +}) /** * Get cached user profile * Returns cached profile if available and not expired */ export const getProfileCache = query({ - args: { - containerTag: v.string(), - }, - handler: async (ctx, args) => { - const now = Date.now(); + args: { + containerTag: v.string(), + }, + handler: async (ctx, args) => { + const now = Date.now() - const cached = await ctx.db - .query("profileCache") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .first(); + const cached = await ctx.db + .query("profileCache") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .first() - // Return null if cache expired - if (!cached || cached.expiresAt < now) { - return null; - } + // Return null if cache expired + if (!cached || cached.expiresAt < now) { + return null + } - return cached; - }, -}); + return cached + }, +}) /** * List documents added to Supermemory * Provides visibility into what content has been indexed */ export const listDocuments = query({ - args: { - containerTag: v.optional(v.string()), - limit: v.optional(v.number()), - }, - handler: async (ctx, args) => { - const limit = args.limit || 50; + args: { + containerTag: v.optional(v.string()), + limit: v.optional(v.number()), + }, + handler: async (ctx, args) => { + const limit = args.limit || 50 - if (args.containerTag) { - return await ctx.db - .query("documents") - .withIndex("by_container", (q) => - q.eq("containerTag", args.containerTag) - ) - .order("desc") - .take(limit); - } + if (args.containerTag) { + return await ctx.db + .query("documents") + .withIndex("by_container", (q) => + q.eq("containerTag", args.containerTag), + ) + .order("desc") + .take(limit) + } - return await ctx.db.query("documents").order("desc").take(limit); - }, -}); + return await ctx.db.query("documents").order("desc").take(limit) + }, +}) /** * Get document by custom ID * Find a specific document using your custom identifier */ export const getDocumentByCustomId = query({ - args: { - customId: v.string(), - }, - handler: async (ctx, args) => { - return await ctx.db - .query("documents") - .withIndex("by_custom_id", (q) => q.eq("customId", args.customId)) - .first(); - }, -}); + args: { + customId: v.string(), + }, + handler: async (ctx, args) => { + return await ctx.db + .query("documents") + .withIndex("by_custom_id", (q) => q.eq("customId", args.customId)) + .first() + }, +}) /** * Get API call logs * View recent Supermemory API calls for debugging and analytics */ export const getApiLogs = query({ - args: { - endpoint: v.optional(v.string()), - containerTag: v.optional(v.string()), - limit: v.optional(v.number()), - }, - handler: async (ctx, args) => { - const limit = args.limit || 100; + args: { + endpoint: v.optional(v.string()), + containerTag: v.optional(v.string()), + limit: v.optional(v.number()), + }, + handler: async (ctx, args) => { + const limit = args.limit || 100 - if (args.endpoint) { - return await ctx.db - .query("apiLogs") - .withIndex("by_endpoint", (q) => q.eq("endpoint", args.endpoint)) - .order("desc") - .take(limit); - } + if (args.endpoint) { + return await ctx.db + .query("apiLogs") + .withIndex("by_endpoint", (q) => q.eq("endpoint", args.endpoint)) + .order("desc") + .take(limit) + } - if (args.containerTag) { - return await ctx.db - .query("apiLogs") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .order("desc") - .take(limit); - } + if (args.containerTag) { + return await ctx.db + .query("apiLogs") + .withIndex("by_container", (q) => + q.eq("containerTag", args.containerTag), + ) + .order("desc") + .take(limit) + } - return await ctx.db.query("apiLogs").order("desc").take(limit); - }, -}); + return await ctx.db.query("apiLogs").order("desc").take(limit) + }, +}) /** * Get API statistics * Aggregate stats for dashboard visibility */ export const getApiStats = query({ - args: { - containerTag: v.optional(v.string()), - }, - handler: async (ctx, args) => { - const logs = args.containerTag - ? await ctx.db - .query("apiLogs") - .withIndex("by_container", (q) => - q.eq("containerTag", args.containerTag) - ) - .collect() - : await ctx.db.query("apiLogs").collect(); + args: { + containerTag: v.optional(v.string()), + }, + handler: async (ctx, args) => { + const logs = args.containerTag + ? await ctx.db + .query("apiLogs") + .withIndex("by_container", (q) => + q.eq("containerTag", args.containerTag), + ) + .collect() + : await ctx.db.query("apiLogs").collect() - const stats = { - totalCalls: logs.length, - successfulCalls: logs.filter((l) => l.responseStatus === "success").length, - failedCalls: logs.filter((l) => l.responseStatus === "error").length, - averageResponseTime: - logs.reduce((sum, l) => sum + (l.responseTime || 0), 0) / logs.length || - 0, - callsByEndpoint: {} as Record, - }; + const stats = { + totalCalls: logs.length, + successfulCalls: logs.filter((l) => l.responseStatus === "success") + .length, + failedCalls: logs.filter((l) => l.responseStatus === "error").length, + averageResponseTime: + logs.reduce((sum, l) => sum + (l.responseTime || 0), 0) / logs.length || + 0, + callsByEndpoint: {} as Record, + } - // Count calls by endpoint - for (const log of logs) { - stats.callsByEndpoint[log.endpoint] = - (stats.callsByEndpoint[log.endpoint] || 0) + 1; - } + // Count calls by endpoint + for (const log of logs) { + stats.callsByEndpoint[log.endpoint] = + (stats.callsByEndpoint[log.endpoint] || 0) + 1 + } - return stats; - }, -}); + return stats + }, +}) /** * Search documents locally (in Convex cache) * Fast text search across cached content previews */ export const searchCachedDocuments = query({ - args: { - searchText: v.string(), - containerTag: v.optional(v.string()), - limit: v.optional(v.number()), - }, - handler: async (ctx, args) => { - const limit = args.limit || 20; - const searchLower = args.searchText.toLowerCase(); + args: { + searchText: v.string(), + containerTag: v.optional(v.string()), + limit: v.optional(v.number()), + }, + handler: async (ctx, args) => { + const limit = args.limit || 20 + const searchLower = args.searchText.toLowerCase() - const query = args.containerTag - ? ctx.db - .query("documents") - .withIndex("by_container", (q) => - q.eq("containerTag", args.containerTag) - ) - : ctx.db.query("documents"); + const query = args.containerTag + ? ctx.db + .query("documents") + .withIndex("by_container", (q) => + q.eq("containerTag", args.containerTag), + ) + : ctx.db.query("documents") - const allDocs = await query.collect(); + const allDocs = await query.collect() - // Simple text matching on content preview - return allDocs - .filter((doc) => doc.contentPreview.toLowerCase().includes(searchLower)) - .slice(0, limit); - }, -}); + // Simple text matching on content preview + return allDocs + .filter((doc) => doc.contentPreview.toLowerCase().includes(searchLower)) + .slice(0, limit) + }, +}) /** * List memories for a user * View all memories saved through Supermemory */ export const listMemories = query({ - args: { - containerTag: v.string(), - source: v.optional(v.union(v.literal("chat"), v.literal("document"), v.literal("manual"))), - limit: v.optional(v.number()), - }, - handler: async (ctx, args) => { - const limit = args.limit || 50; + args: { + containerTag: v.string(), + source: v.optional( + v.union(v.literal("chat"), v.literal("document"), v.literal("manual")), + ), + limit: v.optional(v.number()), + }, + handler: async (ctx, args) => { + const limit = args.limit || 50 - if (args.source) { - return await ctx.db - .query("memories") - .withIndex("by_source_container", (q) => - q.eq("source", args.source).eq("containerTag", args.containerTag) - ) - .order("desc") - .take(limit); - } + if (args.source) { + return await ctx.db + .query("memories") + .withIndex("by_source_container", (q) => + q.eq("source", args.source).eq("containerTag", args.containerTag), + ) + .order("desc") + .take(limit) + } - return await ctx.db - .query("memories") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .order("desc") - .take(limit); - }, -}); + return await ctx.db + .query("memories") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .order("desc") + .take(limit) + }, +}) /** * Get chat sessions for a user * View conversation history with memory usage */ export const getChatSessions = query({ - args: { - containerTag: v.string(), - limit: v.optional(v.number()), - }, - handler: async (ctx, args) => { - const limit = args.limit || 20; + args: { + containerTag: v.string(), + limit: v.optional(v.number()), + }, + handler: async (ctx, args) => { + const limit = args.limit || 20 - return await ctx.db - .query("chatSessions") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .order("desc") - .take(limit); - }, -}); + return await ctx.db + .query("chatSessions") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .order("desc") + .take(limit) + }, +}) /** * Get a specific chat session * View full conversation with memory usage */ export const getChatSession = query({ - args: { - sessionId: v.id("chatSessions"), - }, - handler: async (ctx, args) => { - return await ctx.db.get(args.sessionId); - }, -}); + args: { + sessionId: v.id("chatSessions"), + }, + handler: async (ctx, args) => { + return await ctx.db.get(args.sessionId) + }, +}) /** * Get analytics for a user * View usage statistics and metrics */ export const getAnalytics = query({ - args: { - containerTag: v.string(), - }, - handler: async (ctx, args) => { - return await ctx.db - .query("analytics") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .first(); - }, -}); + args: { + containerTag: v.string(), + }, + handler: async (ctx, args) => { + return await ctx.db + .query("analytics") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .first() + }, +}) /** * Get dashboard overview * Comprehensive view of user's memory usage */ export const getDashboardOverview = query({ - args: { - containerTag: v.string(), - }, - handler: async (ctx, args) => { - const analytics = await ctx.db - .query("analytics") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .first(); + args: { + containerTag: v.string(), + }, + handler: async (ctx, args) => { + const analytics = await ctx.db + .query("analytics") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .first() - const recentMemories = await ctx.db - .query("memories") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .order("desc") - .take(10); + const recentMemories = await ctx.db + .query("memories") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .order("desc") + .take(10) - const recentSessions = await ctx.db - .query("chatSessions") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .order("desc") - .take(5); + const recentSessions = await ctx.db + .query("chatSessions") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .order("desc") + .take(5) - const recentDocuments = await ctx.db - .query("documents") - .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) - .order("desc") - .take(10); + const recentDocuments = await ctx.db + .query("documents") + .withIndex("by_container", (q) => q.eq("containerTag", args.containerTag)) + .order("desc") + .take(10) - return { - analytics: analytics || { - totalMemories: 0, - totalChats: 0, - totalSearches: 0, - avgResponseTime: 0, - lastActive: Date.now(), - }, - recentMemories, - recentSessions, - recentDocuments, - }; - }, -}); + return { + analytics: analytics || { + totalMemories: 0, + totalChats: 0, + totalSearches: 0, + avgResponseTime: 0, + lastActive: Date.now(), + }, + recentMemories, + recentSessions, + recentDocuments, + } + }, +}) diff --git a/packages/tools/src/convex-component/src/component/schema.ts b/packages/tools/src/convex-component/src/component/schema.ts index 830e619c..3577453d 100644 --- a/packages/tools/src/convex-component/src/component/schema.ts +++ b/packages/tools/src/convex-component/src/component/schema.ts @@ -1,5 +1,5 @@ -import { defineSchema, defineTable } from "convex/server"; -import { v } from "convex/values"; +import { defineSchema, defineTable } from "convex/server" +import { v } from "convex/values" /** * Convex schema for Supermemory component @@ -8,142 +8,156 @@ import { v } from "convex/values"; * enabling reactive queries and reducing API calls. */ export default defineSchema({ - /** - * Cached search results from Supermemory - * Stores recent search queries and their results for fast reactive access - */ - searchCache: defineTable({ - query: v.string(), - containerTag: v.string(), - searchMode: v.optional(v.union(v.literal("hybrid"), v.literal("memories"), v.literal("documents"))), - results: v.any(), // Accept any shape from Supermemory API - timing: v.number(), - total: v.number(), - expiresAt: v.number(), // Timestamp when cache expires - }) - .index("by_query_container", ["query", "containerTag"]) - .index("by_expires", ["expiresAt"]), + /** + * Cached search results from Supermemory + * Stores recent search queries and their results for fast reactive access + */ + searchCache: defineTable({ + query: v.string(), + containerTag: v.string(), + searchMode: v.optional( + v.union( + v.literal("hybrid"), + v.literal("memories"), + v.literal("documents"), + ), + ), + results: v.any(), // Accept any shape from Supermemory API + timing: v.number(), + total: v.number(), + expiresAt: v.number(), // Timestamp when cache expires + }) + .index("by_query_container", ["query", "containerTag"]) + .index("by_expires", ["expiresAt"]), - /** - * Cached user profiles from Supermemory - * Stores user context (static + dynamic facts) for fast access - */ - profileCache: defineTable({ - containerTag: v.string(), - staticProfile: v.array(v.string()), - dynamicProfile: v.array(v.string()), - searchResults: v.optional( - v.array( - v.object({ - id: v.string(), - memory: v.optional(v.string()), - chunk: v.optional(v.string()), - similarity: v.number(), - metadata: v.optional(v.any()), - }) - ) - ), - expiresAt: v.number(), - }) - .index("by_container", ["containerTag"]) - .index("by_expires", ["expiresAt"]), + /** + * Cached user profiles from Supermemory + * Stores user context (static + dynamic facts) for fast access + */ + profileCache: defineTable({ + containerTag: v.string(), + staticProfile: v.array(v.string()), + dynamicProfile: v.array(v.string()), + searchResults: v.optional( + v.array( + v.object({ + id: v.string(), + memory: v.optional(v.string()), + chunk: v.optional(v.string()), + similarity: v.number(), + metadata: v.optional(v.any()), + }), + ), + ), + expiresAt: v.number(), + }) + .index("by_container", ["containerTag"]) + .index("by_expires", ["expiresAt"]), - /** - * Metadata about documents/memories added to Supermemory - * Tracks what content has been sent to Supermemory for analytics - */ - documents: defineTable({ - documentId: v.string(), // Supermemory document ID - customId: v.optional(v.string()), - containerTag: v.string(), - contentPreview: v.string(), // First 200 chars for reference - metadata: v.optional(v.any()), - status: v.union(v.literal("queued"), v.literal("processed"), v.literal("failed")), - addedAt: v.number(), - }) - .index("by_container", ["containerTag"]) - .index("by_custom_id", ["customId"]) - .index("by_document_id", ["documentId"]) - .index("by_status", ["status"]), + /** + * Metadata about documents/memories added to Supermemory + * Tracks what content has been sent to Supermemory for analytics + */ + documents: defineTable({ + documentId: v.string(), // Supermemory document ID + customId: v.optional(v.string()), + containerTag: v.string(), + contentPreview: v.string(), // First 200 chars for reference + metadata: v.optional(v.any()), + status: v.union( + v.literal("queued"), + v.literal("processed"), + v.literal("failed"), + ), + addedAt: v.number(), + }) + .index("by_container", ["containerTag"]) + .index("by_custom_id", ["customId"]) + .index("by_document_id", ["documentId"]) + .index("by_status", ["status"]), - /** - * API call logs for dashboard visibility - * Tracks all Supermemory API calls for debugging and analytics - */ - apiLogs: defineTable({ - endpoint: v.string(), // "add", "search", "profile", etc. - containerTag: v.optional(v.string()), - requestBody: v.optional(v.any()), - responseStatus: v.union( - v.literal("success"), - v.literal("error"), - v.literal("pending") - ), - responseTime: v.optional(v.number()), // milliseconds - errorMessage: v.optional(v.string()), - timestamp: v.number(), - }) - .index("by_endpoint", ["endpoint"]) - .index("by_container", ["containerTag"]) - .index("by_timestamp", ["timestamp"]) - .index("by_status", ["responseStatus"]), + /** + * API call logs for dashboard visibility + * Tracks all Supermemory API calls for debugging and analytics + */ + apiLogs: defineTable({ + endpoint: v.string(), // "add", "search", "profile", etc. + containerTag: v.optional(v.string()), + requestBody: v.optional(v.any()), + responseStatus: v.union( + v.literal("success"), + v.literal("error"), + v.literal("pending"), + ), + responseTime: v.optional(v.number()), // milliseconds + errorMessage: v.optional(v.string()), + timestamp: v.number(), + }) + .index("by_endpoint", ["endpoint"]) + .index("by_container", ["containerTag"]) + .index("by_timestamp", ["timestamp"]) + .index("by_status", ["responseStatus"]), - /** - * Component configuration - * Stores API key and other settings - */ - config: defineTable({ - key: v.string(), - value: v.any(), - }).index("by_key", ["key"]), + /** + * Component configuration + * Stores API key and other settings + */ + config: defineTable({ + key: v.string(), + value: v.any(), + }).index("by_key", ["key"]), - /** - * Memories - Core memory storage - * All user memories saved through Supermemory - */ - memories: defineTable({ - content: v.string(), - containerTag: v.string(), - source: v.union(v.literal("chat"), v.literal("document"), v.literal("manual")), - supermemoryId: v.optional(v.string()), // ID from Supermemory API - createdAt: v.number(), - metadata: v.optional(v.any()), - }) - .index("by_container", ["containerTag"]) - .index("by_source", ["source"]) - .index("by_source_container", ["source", "containerTag"]) - .index("by_created", ["createdAt"]), + /** + * Memories - Core memory storage + * All user memories saved through Supermemory + */ + memories: defineTable({ + content: v.string(), + containerTag: v.string(), + source: v.union( + v.literal("chat"), + v.literal("document"), + v.literal("manual"), + ), + supermemoryId: v.optional(v.string()), // ID from Supermemory API + createdAt: v.number(), + metadata: v.optional(v.any()), + }) + .index("by_container", ["containerTag"]) + .index("by_source", ["source"]) + .index("by_source_container", ["source", "containerTag"]) + .index("by_created", ["createdAt"]), - /** - * Chat Sessions - Conversation history with memory usage - * Tracks full conversations and which memories were retrieved - */ - chatSessions: defineTable({ - containerTag: v.string(), - messages: v.array( - v.object({ - role: v.union(v.literal("user"), v.literal("assistant")), - content: v.string(), - timestamp: v.number(), - }) - ), - memoriesRetrieved: v.array(v.string()), // IDs of memories used in this session - createdAt: v.number(), - lastMessageAt: v.number(), - }) - .index("by_container", ["containerTag"]) - .index("by_last_message", ["lastMessageAt"]), + /** + * Chat Sessions - Conversation history with memory usage + * Tracks full conversations and which memories were retrieved + */ + chatSessions: defineTable({ + containerTag: v.string(), + messages: v.array( + v.object({ + role: v.union(v.literal("user"), v.literal("assistant")), + content: v.string(), + timestamp: v.number(), + }), + ), + memoriesRetrieved: v.array(v.string()), // IDs of memories used in this session + createdAt: v.number(), + lastMessageAt: v.number(), + }) + .index("by_container", ["containerTag"]) + .index("by_last_message", ["lastMessageAt"]), - /** - * Analytics - Usage statistics per user - * Dashboard metrics for monitoring - */ - analytics: defineTable({ - containerTag: v.string(), - totalMemories: v.number(), - totalChats: v.number(), - totalSearches: v.number(), - avgResponseTime: v.number(), - lastActive: v.number(), - }).index("by_container", ["containerTag"]), -}); + /** + * Analytics - Usage statistics per user + * Dashboard metrics for monitoring + */ + analytics: defineTable({ + containerTag: v.string(), + totalMemories: v.number(), + totalChats: v.number(), + totalSearches: v.number(), + avgResponseTime: v.number(), + lastActive: v.number(), + }).index("by_container", ["containerTag"]), +}) diff --git a/packages/tools/src/convex-component/src/react/index.tsx b/packages/tools/src/convex-component/src/react/index.tsx index 7c7837c1..af4f8066 100644 --- a/packages/tools/src/convex-component/src/react/index.tsx +++ b/packages/tools/src/convex-component/src/react/index.tsx @@ -1,16 +1,16 @@ -import { useAction, useQuery, useMutation } from "convex/react"; -import { useState, useCallback } from "react"; -import type { FunctionReference } from "convex/server"; +import { useAction, useQuery, useMutation } from "convex/react" +import { useState, useCallback } from "react" +import type { FunctionReference } from "convex/server" import type { - AddMemoryArgs, - SearchMemoriesArgs, - ProfileArgs, - SearchResponse, - ProfileResponse, - Document, - ApiLog, - ApiStats, -} from "../client/index"; + AddMemoryArgs, + SearchMemoriesArgs, + ProfileArgs, + SearchResponse, + ProfileResponse, + Document, + ApiLog, + ApiStats, +} from "../client/index" /** * React Hooks for Supermemory Convex Component @@ -38,16 +38,17 @@ import type { * } * ``` */ -export function useAddMemory(componentPath: string = "supermemory") { - const action = `${componentPath}:actions.add` as unknown as FunctionReference<"action">; - const addAction = useAction(action); +export function useAddMemory(componentPath = "supermemory") { + const action = + `${componentPath}:actions.add` as unknown as FunctionReference<"action"> + const addAction = useAction(action) - return useCallback( - async (args: AddMemoryArgs) => { - return await addAction(args); - }, - [addAction] - ); + return useCallback( + async (args: AddMemoryArgs) => { + return await addAction(args) + }, + [addAction], + ) } /** @@ -79,41 +80,42 @@ export function useAddMemory(componentPath: string = "supermemory") { * ``` */ export function useSupermemorySearch( - args: SearchMemoriesArgs | null, - componentPath: string = "supermemory" + args: SearchMemoriesArgs | null, + componentPath = "supermemory", ) { - const action = `${componentPath}:actions.search` as unknown as FunctionReference<"action">; - const searchAction = useAction(action); - const [results, setResults] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); + const action = + `${componentPath}:actions.search` as unknown as FunctionReference<"action"> + const searchAction = useAction(action) + const [results, setResults] = useState(null) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState(null) - const search = useCallback( - async (searchArgs?: SearchMemoriesArgs) => { - const finalArgs = searchArgs || args; - if (!finalArgs) return; + const search = useCallback( + async (searchArgs?: SearchMemoriesArgs) => { + const finalArgs = searchArgs || args + if (!finalArgs) return - setIsLoading(true); - setError(null); + setIsLoading(true) + setError(null) - try { - const response = await searchAction(finalArgs); - setResults(response as SearchResponse); - } catch (err) { - setError(err instanceof Error ? err : new Error("Search failed")); - } finally { - setIsLoading(false); - } - }, - [searchAction, args] - ); + try { + const response = await searchAction(finalArgs) + setResults(response as SearchResponse) + } catch (err) { + setError(err instanceof Error ? err : new Error("Search failed")) + } finally { + setIsLoading(false) + } + }, + [searchAction, args], + ) - return { - results, - isLoading, - error, - search, - }; + return { + results, + isLoading, + error, + search, + } } /** @@ -145,41 +147,42 @@ export function useSupermemorySearch( * ``` */ export function useSupermemoryProfile( - args: ProfileArgs | null, - componentPath: string = "supermemory" + args: ProfileArgs | null, + componentPath = "supermemory", ) { - const action = `${componentPath}:actions.profile` as unknown as FunctionReference<"action">; - const profileAction = useAction(action); - const [profile, setProfile] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); + const action = + `${componentPath}:actions.profile` as unknown as FunctionReference<"action"> + const profileAction = useAction(action) + const [profile, setProfile] = useState(null) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState(null) - const refresh = useCallback( - async (profileArgs?: ProfileArgs) => { - const finalArgs = profileArgs || args; - if (!finalArgs) return; + const refresh = useCallback( + async (profileArgs?: ProfileArgs) => { + const finalArgs = profileArgs || args + if (!finalArgs) return - setIsLoading(true); - setError(null); + setIsLoading(true) + setError(null) - try { - const response = await profileAction(finalArgs); - setProfile(response as ProfileResponse); - } catch (err) { - setError(err instanceof Error ? err : new Error("Profile fetch failed")); - } finally { - setIsLoading(false); - } - }, - [profileAction, args] - ); + try { + const response = await profileAction(finalArgs) + setProfile(response as ProfileResponse) + } catch (err) { + setError(err instanceof Error ? err : new Error("Profile fetch failed")) + } finally { + setIsLoading(false) + } + }, + [profileAction, args], + ) - return { - profile, - isLoading, - error, - refresh, - }; + return { + profile, + isLoading, + error, + refresh, + } } /** @@ -207,11 +210,12 @@ export function useSupermemoryProfile( * ``` */ export function useDocumentList( - args?: { containerTag?: string; limit?: number }, - componentPath: string = "supermemory" + args?: { containerTag?: string; limit?: number }, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.listDocuments` as unknown as FunctionReference<"query">; - return useQuery(query, args || {}) as Document[] | undefined; + const query = + `${componentPath}:queries.listDocuments` as unknown as FunctionReference<"query"> + return useQuery(query, args || {}) as Document[] | undefined } /** @@ -221,15 +225,15 @@ export function useDocumentList( * @param componentPath - Path to the component (default: "supermemory") */ export function useDocument( - customId: string | null, - componentPath: string = "supermemory" + customId: string | null, + componentPath = "supermemory", ) { - const query = - `${componentPath}:queries.getDocumentByCustomId` as unknown as FunctionReference<"query">; - return useQuery( - query, - customId ? { customId } : "skip" - ) as Document | null | undefined; + const query = + `${componentPath}:queries.getDocumentByCustomId` as unknown as FunctionReference<"query"> + return useQuery(query, customId ? { customId } : "skip") as + | Document + | null + | undefined } /** @@ -256,11 +260,12 @@ export function useDocument( * ``` */ export function useApiLogs( - args?: { endpoint?: string; containerTag?: string; limit?: number }, - componentPath: string = "supermemory" + args?: { endpoint?: string; containerTag?: string; limit?: number }, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.getApiLogs` as unknown as FunctionReference<"query">; - return useQuery(query, args || {}) as ApiLog[] | undefined; + const query = + `${componentPath}:queries.getApiLogs` as unknown as FunctionReference<"query"> + return useQuery(query, args || {}) as ApiLog[] | undefined } /** @@ -285,11 +290,12 @@ export function useApiLogs( * ``` */ export function useApiStats( - args?: { containerTag?: string }, - componentPath: string = "supermemory" + args?: { containerTag?: string }, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.getApiStats` as unknown as FunctionReference<"query">; - return useQuery(query, args || {}) as ApiStats | undefined; + const query = + `${componentPath}:queries.getApiStats` as unknown as FunctionReference<"query"> + return useQuery(query, args || {}) as ApiStats | undefined } /** @@ -297,14 +303,14 @@ export function useApiStats( * * @param componentPath - Path to the component (default: "supermemory") */ -export function useCleanCache(componentPath: string = "supermemory") { - const mutation = - `${componentPath}:mutations.cleanExpiredCache` as unknown as FunctionReference<"mutation">; - const cleanMutation = useMutation(mutation); +export function useCleanCache(componentPath = "supermemory") { + const mutation = + `${componentPath}:mutations.cleanExpiredCache` as unknown as FunctionReference<"mutation"> + const cleanMutation = useMutation(mutation) - return useCallback(async () => { - return await cleanMutation({}); - }, [cleanMutation]); + return useCallback(async () => { + return await cleanMutation({}) + }, [cleanMutation]) } /** @@ -312,17 +318,20 @@ export function useCleanCache(componentPath: string = "supermemory") { * * @param componentPath - Path to the component (default: "supermemory") */ -export function useUpdateDocumentStatus(componentPath: string = "supermemory") { - const mutation = - `${componentPath}:mutations.updateDocumentStatus` as unknown as FunctionReference<"mutation">; - const updateMutation = useMutation(mutation); +export function useUpdateDocumentStatus(componentPath = "supermemory") { + const mutation = + `${componentPath}:mutations.updateDocumentStatus` as unknown as FunctionReference<"mutation"> + const updateMutation = useMutation(mutation) - return useCallback( - async (args: { documentId: string; status: "queued" | "processed" | "failed" }) => { - return await updateMutation(args); - }, - [updateMutation] - ); + return useCallback( + async (args: { + documentId: string + status: "queued" | "processed" | "failed" + }) => { + return await updateMutation(args) + }, + [updateMutation], + ) } /** @@ -350,11 +359,16 @@ export function useUpdateDocumentStatus(componentPath: string = "supermemory") { * ``` */ export function useMemories( - args: { containerTag: string; source?: "chat" | "document" | "manual"; limit?: number }, - componentPath: string = "supermemory" + args: { + containerTag: string + source?: "chat" | "document" | "manual" + limit?: number + }, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.listMemories` as unknown as FunctionReference<"query">; - return useQuery(query, args) as any[] | undefined; + const query = + `${componentPath}:queries.listMemories` as unknown as FunctionReference<"query"> + return useQuery(query, args) as any[] | undefined } /** @@ -382,11 +396,12 @@ export function useMemories( * ``` */ export function useChatSessions( - args: { containerTag: string; limit?: number }, - componentPath: string = "supermemory" + args: { containerTag: string; limit?: number }, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.getChatSessions` as unknown as FunctionReference<"query">; - return useQuery(query, args) as any[] | undefined; + const query = + `${componentPath}:queries.getChatSessions` as unknown as FunctionReference<"query"> + return useQuery(query, args) as any[] | undefined } /** @@ -396,11 +411,15 @@ export function useChatSessions( * @param componentPath - Path to the component (default: "supermemory") */ export function useChatSession( - sessionId: string | null, - componentPath: string = "supermemory" + sessionId: string | null, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.getChatSession` as unknown as FunctionReference<"query">; - return useQuery(query, sessionId ? { sessionId } : "skip") as any | null | undefined; + const query = + `${componentPath}:queries.getChatSession` as unknown as FunctionReference<"query"> + return useQuery(query, sessionId ? { sessionId } : "skip") as + | any + | null + | undefined } /** @@ -428,11 +447,15 @@ export function useChatSession( * ``` */ export function useAnalytics( - containerTag: string | null, - componentPath: string = "supermemory" + containerTag: string | null, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.getAnalytics` as unknown as FunctionReference<"query">; - return useQuery(query, containerTag ? { containerTag } : "skip") as any | null | undefined; + const query = + `${componentPath}:queries.getAnalytics` as unknown as FunctionReference<"query"> + return useQuery(query, containerTag ? { containerTag } : "skip") as + | any + | null + | undefined } /** @@ -467,21 +490,24 @@ export function useAnalytics( * ``` */ export function useDashboardOverview( - containerTag: string | null, - componentPath: string = "supermemory" + containerTag: string | null, + componentPath = "supermemory", ) { - const query = `${componentPath}:queries.getDashboardOverview` as unknown as FunctionReference<"query">; - return useQuery(query, containerTag ? { containerTag } : "skip") as any | undefined; + const query = + `${componentPath}:queries.getDashboardOverview` as unknown as FunctionReference<"query"> + return useQuery(query, containerTag ? { containerTag } : "skip") as + | any + | undefined } // Export all types export type { - AddMemoryArgs, - SearchMemoriesArgs, - ProfileArgs, - SearchResponse, - ProfileResponse, - Document, - ApiLog, - ApiStats, -} from "../client/index"; + AddMemoryArgs, + SearchMemoriesArgs, + ProfileArgs, + SearchResponse, + ProfileResponse, + Document, + ApiLog, + ApiStats, +} from "../client/index" diff --git a/packages/tools/src/convex-component/tsconfig.json b/packages/tools/src/convex-component/tsconfig.json index d6f4b498..7e78fb3e 100644 --- a/packages/tools/src/convex-component/tsconfig.json +++ b/packages/tools/src/convex-component/tsconfig.json @@ -1,23 +1,23 @@ { - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "jsx": "react-jsx", - "esModuleInterop": true, - "skipLibCheck": true, - "strict": false, - "moduleResolution": "bundler", - "module": "ESNext", - "target": "ES2022", - "lib": ["ES2022", "DOM"], - "types": ["react"], - "allowSyntheticDefaultImports": true, - "resolveJsonModule": true, - "isolatedModules": true - }, - "include": ["src/client/**/*", "src/react/**/*", "src/ai-sdk/**/*"], - "exclude": ["node_modules", "dist", "src/component"] + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "jsx": "react-jsx", + "esModuleInterop": true, + "skipLibCheck": true, + "strict": false, + "moduleResolution": "bundler", + "module": "ESNext", + "target": "ES2022", + "lib": ["ES2022", "DOM"], + "types": ["react"], + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "isolatedModules": true + }, + "include": ["src/client/**/*", "src/react/**/*", "src/ai-sdk/**/*"], + "exclude": ["node_modules", "dist", "src/component"] }