Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion scripts/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,3 @@ function main() {
}

main();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion scripts/migrate-tests.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ function migrateDirectory(dir) {
}

migrateDirectory("tests");
// AUDIT_MARKER
1 change: 0 additions & 1 deletion scripts/migrate-v1-to-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,4 +405,3 @@ migrate(storagePath)
console.error("Migration failed:", error);
process.exit(1);
});
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -751,4 +751,3 @@ export function isConfigured(): boolean {
// The system should check specific sub-configurations when features are invoked.
return true;
}
// AUDIT_MARKER
13 changes: 6 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
}
})();

if (CONFIG.webServerEnabled) {

Check failure on line 69 in src/index.ts

View workflow job for this annotation

GitHub Actions / check

TypeError: undefined is not an object (evaluating 'CONFIG.webServerEnabled')

at <anonymous> (/home/runner/work/opencode-mem0/opencode-mem0/src/index.ts:69:7) at async <anonymous> (/home/runner/work/opencode-mem0/opencode-mem0/tests/tool-scope.test.ts:165:26)

Check failure on line 69 in src/index.ts

View workflow job for this annotation

GitHub Actions / check

TypeError: undefined is not an object (evaluating 'CONFIG.webServerEnabled')

at <anonymous> (/home/runner/work/opencode-mem0/opencode-mem0/src/index.ts:69:7) at async <anonymous> (/home/runner/work/opencode-mem0/opencode-mem0/tests/tool-scope.test.ts:156:26)

Check failure on line 69 in src/index.ts

View workflow job for this annotation

GitHub Actions / check

TypeError: undefined is not an object (evaluating 'CONFIG.webServerEnabled')

at <anonymous> (/home/runner/work/opencode-mem0/opencode-mem0/src/index.ts:69:7) at async <anonymous> (/home/runner/work/opencode-mem0/opencode-mem0/tests/tool-scope.test.ts:147:26)
startWebServer({
port: CONFIG.webServerPort,
host: CONFIG.webServerHost,
Expand All @@ -88,7 +88,7 @@
duration: 3000,
},
})
.catch(() => {});
.catch((err) => log("Toast display failed", { error: String(err) }));
}
});

Expand All @@ -103,7 +103,7 @@
duration: 5000,
},
})
.catch(() => {});
.catch((err) => log("Toast display failed", { error: String(err) }));
}
} else {
if (ctx.client?.tui) {
Expand All @@ -116,7 +116,7 @@
duration: 3000,
},
})
.catch(() => {});
.catch((err) => log("Toast display failed", { error: String(err) }));
}
}
})
Expand All @@ -133,7 +133,7 @@
duration: 5000,
},
})
.catch(() => {});
.catch((err) => log("Toast display failed", { error: String(err) }));
}
});
}
Expand Down Expand Up @@ -278,7 +278,7 @@
duration: 5000,
},
})
.catch(() => {});
.catch((err) => log("Toast display failed", { error: String(err) }));
}
}
},
Expand Down Expand Up @@ -587,7 +587,7 @@
duration: 3000,
},
})
.catch(() => {});
.catch((err) => log("Toast display failed", { error: String(err) }));
}

log("Compaction memory injected", {
Expand Down Expand Up @@ -634,4 +634,3 @@

return output;
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ export const id =
typeof pkg.name === "string" && pkg.name.trim() ? pkg.name.trim() : "opencode-mem0";
export { OpenCodeMemPlugin };
export default { id, server: OpenCodeMemPlugin } satisfies PluginModule;
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/ai-provider-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,3 @@ export class AIProviderFactory {
return getAISessionManager().cleanupExpiredSessions();
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/opencode-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,3 @@ export async function generateStructuredOutput<T>(options: {
});
return result.output as T;
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/provider-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ export function buildMemoryProviderConfig(
iterationTimeout: overrides.iterationTimeout ?? config.autoCaptureIterationTimeout,
};
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/providers/anthropic-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,3 @@ export class AnthropicMessagesProvider extends BaseAIProvider {
return null;
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/providers/base-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ export abstract class BaseAIProvider {

abstract supportsSession(): boolean;
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/providers/google-gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,3 @@ export class GoogleGeminiProvider extends BaseAIProvider {
return { success: false, error: `Max iterations (${maxIterations}) reached`, iterations };
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/providers/openai-chat-completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,4 +434,3 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
};
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/providers/openai-responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,3 @@ export class OpenAIResponsesProvider extends BaseAIProvider {
return data;
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/session/ai-session-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,3 @@ export const aiSessionManager = {
return getAISessionManager().getLastSequence.bind(getAISessionManager());
},
} as unknown as AISessionManager;
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/session/session-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,3 @@ export interface SessionUpdateParams {
conversationId?: string;
metadata?: Record<string, any>;
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/tools/tool-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,3 @@ export class ToolSchemaConverter {
};
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/ai/validators/user-profile-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,3 @@ export class UserProfileValidator {
return errors;
}
}
// AUDIT_MARKER
79 changes: 43 additions & 36 deletions src/services/api-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,15 @@ export async function handleListMemories(
includePrompts: boolean = true
): Promise<ApiResponse<PaginatedResponse<Memory | any>>> {
try {
const safePage = Number.isFinite(page) && page > 0 ? Math.min(Math.floor(page), 10000) : 1;
const safePageSize =
Number.isFinite(pageSize) && pageSize > 0 && pageSize <= 100 ? Math.floor(pageSize) : 20;
await embeddingService.warmup();
let allMemories: any[] = [];
if (tag) {
const { scope: tagScope, hash } = extractScopeFromTag(tag);
const shards = shardManager.getAllShards(tagScope, hash);
const limit = page * pageSize; // Fetch enough to cover the requested page across shards
const limit = safePage * safePageSize; // Fetch enough to cover the requested page across shards
for (const shard of shards) {
const db = connectionManager.getConnection(shard.dbPath);
const memories = vectorSearch.listMemories(db, tag, limit);
Expand Down Expand Up @@ -233,9 +236,9 @@ export async function handleListMemories(
timeline = sortedTimeline;

const total = timeline.length;
const totalPages = Math.ceil(total / pageSize);
const offset = (page - 1) * pageSize;
const paginatedResults = timeline.slice(offset, offset + pageSize);
const totalPages = Math.ceil(total / safePageSize);
const offset = (safePage - 1) * safePageSize;
const paginatedResults = timeline.slice(offset, offset + safePageSize);

const items = paginatedResults.map((item: any) => {
if (item.type === "memory") {
Expand Down Expand Up @@ -270,7 +273,10 @@ export async function handleListMemories(
}
});

return { success: true, data: { items, total, page, pageSize, totalPages } };
return {
success: true,
data: { items, total, page: safePage, pageSize: safePageSize, totalPages },
};
} catch (error) {
log("handleListMemories: error", { error: String(error) });
return { success: false, error: "Internal error" };
Expand Down Expand Up @@ -491,6 +497,9 @@ export async function handleSearch(
): Promise<ApiResponse<PaginatedResponse<SearchResultItem>>> {
try {
if (!query) return { success: false, error: "query is required" };
const safePage = Number.isFinite(page) && page > 0 ? Math.min(Math.floor(page), 10000) : 1;
const safePageSize =
Number.isFinite(pageSize) && pageSize > 0 && pageSize <= 100 ? Math.floor(pageSize) : 20;
await embeddingService.warmup();
const queryVector = await embeddingService.embedWithTimeout(query);
let memoryResults: any[] = [];
Expand All @@ -500,42 +509,35 @@ export async function handleSearch(
const shards = shardManager.getAllShards(scope, hash);
for (const shard of shards) {
try {
const results = await vectorSearch.searchInShard(shard, queryVector, tag, pageSize * 2);
const results = await vectorSearch.searchInShard(
shard,
queryVector,
tag,
safePageSize * 2
);
memoryResults.push(...results);
} catch (error) {
log("Shard search error", { shardId: shard.id, error: String(error) });
}
}
const projectPath = getProjectPathFromTag(tag);
promptResults = userPromptManager.searchPrompts(query, projectPath, pageSize * 2);
promptResults = userPromptManager.searchPrompts(query, projectPath, safePageSize * 2);
} else {
const userShards = shardManager.getAllShards("user", "");
const projectShards = shardManager.getAllShards("project", "");
const uniqueTags = new Set<string>();
for (const shard of projectShards) {
const db = connectionManager.getConnection(shard.dbPath);
const tags = vectorSearch.getDistinctTags(db);
for (const t of tags) {
if (t.container_tag) uniqueTags.add(t.container_tag);
}
}
for (const containerTag of uniqueTags) {
const { scope, hash } = extractScopeFromTag(containerTag);
const shards = shardManager.getAllShards(scope, hash);
for (const shard of shards) {
try {
const results = await vectorSearch.searchInShard(
shard,
queryVector,
containerTag,
pageSize
);
memoryResults.push(...results);
} catch (error) {
log("Shard search error", { shardId: shard.id, error: String(error) });
}
const searchedPaths = new Set<string>();
for (const shard of [...userShards, ...projectShards]) {
Comment on lines +526 to +529

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep untagged web searches scoped to project shards

When the web UI searches with no selected tag, it calls /api/search without tag from the project memory view, and handleListMemories/LocalMemoryClient both treat the untagged/all-projects case as project-only. Adding userShards here means any migrated mem_user_* memories are now searched with an empty containerTag and returned in that project UI, exposing personal/user-scope memories and making them selectable for project memory actions. Please keep this branch to project shards unless the API/UI explicitly requests a user scope.

Useful? React with 👍 / 👎.

if (searchedPaths.has(shard.dbPath)) continue;
searchedPaths.add(shard.dbPath);
try {
const perShardLimit = Math.min(safePage * safePageSize, 500);
const results = await vectorSearch.searchInShard(shard, queryVector, "", perShardLimit);
memoryResults.push(...results);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} catch (error) {
log("Shard search error", { shardId: shard.id, error: String(error) });
}
}
promptResults = userPromptManager.searchPrompts(query, undefined, pageSize * 2);
promptResults = userPromptManager.searchPrompts(query, undefined, safePageSize * 2);
}

const formattedPrompts: FormattedPrompt[] = promptResults.map((p) => ({
Expand Down Expand Up @@ -575,9 +577,12 @@ export async function handleSearch(
);

const total = combinedResults.length;
const totalPages = Math.ceil(total / pageSize);
const offset = (page - 1) * pageSize;
const paginatedResults: SearchResultItem[] = combinedResults.slice(offset, offset + pageSize);
const totalPages = Math.ceil(total / safePageSize);
const offset = (safePage - 1) * safePageSize;
const paginatedResults: SearchResultItem[] = combinedResults.slice(
offset,
offset + safePageSize
);

const missingPromptIds = new Set<string>();
const missingMemoryIds = new Set<string>();
Expand Down Expand Up @@ -640,7 +645,10 @@ export async function handleSearch(
}
}

return { success: true, data: { items: paginatedResults, total, page, pageSize, totalPages } };
return {
success: true,
data: { items: paginatedResults, total, page: safePage, pageSize: safePageSize, totalPages },
};
} catch (error) {
log("handleSearch: error", { error: String(error) });
return { success: false, error: "Internal error" };
Expand Down Expand Up @@ -1179,4 +1187,3 @@ export async function handleConflictStats(): Promise<
return { success: false, error: "Internal error" };
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/auto-capture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,4 +393,3 @@ Analyze this conversation. If it contains technical work (code, bugs, features,
tags: (result.data.tags || []).map((t: string) => t.toLowerCase().trim()),
};
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/cleanup-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,3 @@ export class CleanupService {
}

export const cleanupService = new CleanupService();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,4 +444,3 @@ export class LocalMemoryClient {
}

export const memoryClient = new LocalMemoryClient();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,3 @@ export function formatContextForPrompt(

return parts.join("\n");
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/deduplication-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,3 @@ export class DeduplicationService {
}

export const deduplicationService = new DeduplicationService();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/embedding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,3 @@ export class EmbeddingService {
}

export const embeddingService = EmbeddingService.getInstance();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/jsonc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,3 @@ export function stripJsoncComments(content: string): string {
// Remove trailing commas before } or ]
return result.replace(/,\s*([}\]])/g, "$1");
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/language-detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,3 @@ export function getLanguageName(code: string): string {
}
return lang?.name || "English";
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/memory-conflicts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -654,4 +654,3 @@ export function getAllUnresolvedConflicts(

return allConflicts.sort((a, b) => b.detectedAt - a.detectedAt).slice(0, limit);
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/memory-lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,4 +415,3 @@ export async function runLifecycleMaintenance(): Promise<void> {
log("Lifecycle maintenance error", { error: String(error) });
}
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/memory-scoring-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,3 @@ export async function runOneTimeScoringRecalculation(): Promise<{
}> {
return recalculateAllScores(true);
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/memory-scoring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,4 +619,3 @@ export function recordAccess(currentAccessCount: number): {
lastAccessed: Date.now(),
};
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/migration-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,4 +350,3 @@ export class MigrationService {
}

export const migrationService = new MigrationService();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/platform-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,3 @@ export function serve(options: ServeOptions): Promise<PlatformServer> {

return createNodeServer(options);
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/privacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ export function isFullyPrivate(content: string): boolean {
const stripped = stripPrivateContent(content).trim();
return stripped === "[REDACTED]" || stripped === "";
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/retrieval-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,3 @@ export function calculateDiversityPenalty(

return 0;
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/secret-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,3 @@ export function resolveSecretValue(value: string | undefined): string | undefine

return value;
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/sqlite/connection-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,3 @@ export class ConnectionManager {
}

export const connectionManager = new ConnectionManager();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/sqlite/shard-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,4 +405,3 @@ export class ShardManager {
}

export const shardManager = new ShardManager();
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/sqlite/sqlite-bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,3 @@ export function getDatabase(): new (path: string) => Database {
}
return DatabaseImpl;
}
// AUDIT_MARKER
1 change: 0 additions & 1 deletion src/services/sqlite/transcript-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,3 @@ export class TranscriptManager {
}

export const transcriptManager = new TranscriptManager();
// AUDIT_MARKER
Loading
Loading