removed cache

This commit is contained in:
Sreeram Sreedhar 2026-04-20 16:58:18 -07:00
parent 76a32dfd00
commit c1aa4b19cd
9 changed files with 12 additions and 395 deletions

View file

@ -4,7 +4,7 @@ import type { FunctionReference } from "convex/server"
/**
* Supermemory AI SDK Middleware for Convex
*
* Wraps AI models to automatically inject user context from Convex-cached memories.
* Wraps AI models to automatically inject user context from Supermemory.
*/
/**
@ -182,7 +182,7 @@ export function withSupermemory<T extends WrappableLanguageModel>(
if (verbose) {
console.log(
`[Supermemory] Found ${searchResults.length} relevant memories (cached: ${searchResult.cached})`,
`[Supermemory] Found ${searchResults.length} relevant memories`,
)
}
}
@ -200,15 +200,15 @@ export function withSupermemory<T extends WrappableLanguageModel>(
...callOptions.prompt,
]
// Auto-save user message if enabled
// Auto-save user message if enabled (fire-and-forget to avoid blocking)
if (addMemory === "always" && userQuery) {
if (verbose) console.log("[Supermemory] Auto-saving user message...")
await convexClient.action(addAction, {
convexClient.action(addAction, {
content: userQuery,
containerTag,
metadata: { source: "ai-middleware", auto: true },
})
}).catch((e) => console.error("[Supermemory] Failed to auto-save:", e))
}
// Call original model with enhanced context
@ -281,11 +281,11 @@ export function withSupermemory<T extends WrappableLanguageModel>(
]
if (addMemory === "always" && userQuery) {
await convexClient.action(addAction, {
convexClient.action(addAction, {
content: userQuery,
containerTag,
metadata: { source: "ai-middleware", auto: true },
})
}).catch((e) => console.error("[Supermemory] Failed to auto-save:", e))
}
return await model.doStream({

View file

@ -7,7 +7,7 @@ import type { FunctionReference } from "convex/server"
* Supermemory AI SDK Tools for Convex
*
* Provides AI agent tools that use Convex actions for memory operations.
* All operations are cached and tracked in the Convex dashboard.
* All operations are tracked in the Convex dashboard.
*/
/**
@ -95,7 +95,6 @@ export function supermemoryConvexTools(
metadata: r.metadata,
})),
count: result.total,
cached: result.cached,
}
} catch (error) {
return {

View file

@ -44,7 +44,6 @@ export interface SearchResponse {
results: SearchResult[]
timing: number
total: number
cached: boolean
}
export interface ProfileResponse {
@ -61,7 +60,6 @@ export interface ProfileResponse {
metadata?: Record<string, any>
}>
}
cached: boolean
}
export interface Document {
@ -206,26 +204,6 @@ export function createSupermemoryClient(
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<Document[]> => {
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"), {})
},
/**
* Update document status
*/

View file

@ -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 { internal } from "./_generated/api"
/**
* Supermemory Actions
@ -123,22 +123,6 @@ export const search = action({
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,
})
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 })
@ -156,17 +140,6 @@ export const search = action({
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
})
// Update analytics
await ctx.runMutation(internal.mutations.updateAnalytics, {
containerTag: args.containerTag,
@ -184,10 +157,7 @@ export const search = action({
responseTime,
})
return {
...result,
cached: false,
}
return result
} catch (error) {
const responseTime = Date.now() - startTime
@ -224,24 +194,6 @@ export const profile = action({
const startTime = Date.now()
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,
}
}
// Get API key from config
const apiKey = await ctx.runQuery(internal.lib.getApiKey)
const client = new Supermemory({ apiKey })
@ -254,15 +206,6 @@ export const profile = action({
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
})
// Log API call
await ctx.runMutation(internal.mutations.logApiCall, {
endpoint: "profile",
@ -272,10 +215,7 @@ export const profile = action({
responseTime,
})
return {
...result,
cached: false,
}
return result
} catch (error) {
const responseTime = Date.now() - startTime

View file

@ -18,7 +18,6 @@ export {
getDashboardOverview,
} from "./queries"
export {
cleanExpiredCache,
updateDocumentStatus,
trackChatMessage,
} from "./mutations"

View file

@ -8,113 +8,6 @@ import { v } from "convex/values"
* These functions update the Convex cache with Supermemory data.
*/
/**
* Cache search results
* 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
// 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,
})
}
},
})
/**
* 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
// 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,
})
}
},
})
/**
* Store document metadata
* Tracks documents/memories added to Supermemory
@ -202,42 +95,6 @@ export const logApiCall = internalMutation({
},
})
/**
* Clean expired cache entries
* Removes expired search and profile caches
*/
export const cleanExpiredCache = mutation({
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()
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()
for (const cache of expiredProfiles) {
await ctx.db.delete(cache._id)
}
return {
cleanedSearchCaches: expiredSearches.length,
cleanedProfileCaches: expiredProfiles.length,
}
},
})
/**
* Update document status
* Updates the processing status of a document

View file

@ -4,74 +4,10 @@ import { v } from "convex/values"
/**
* Supermemory Queries
*
* Queries provide reactive, read-only access to cached Supermemory data.
* Queries provide reactive, read-only access to Supermemory data.
* Components using these queries will automatically re-render when data changes.
*/
/**
* Get cached search results
* 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()
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
}
const effectiveMode = args.searchMode || "hybrid"
if (cached.searchMode !== effectiveMode) {
return null
}
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()
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 cached
},
})
/**
* List documents added to Supermemory
* Provides visibility into what content has been indexed
@ -191,37 +127,6 @@ export const getApiStats = query({
},
})
/**
* 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()
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()
// 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

View file

@ -8,52 +8,6 @@ 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 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

View file

@ -298,21 +298,6 @@ export function useApiStats(
return useQuery(query, args || {}) as ApiStats | undefined
}
/**
* Hook to clean expired cache
*
* @param componentPath - Path to the component (default: "supermemory")
*/
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])
}
/**
* Hook to update document status
*