@@ -42,6 +42,7 @@ interface OpenCodeMemConfig {
4242 autoCaptureMaxIterations ?: number ;
4343 autoCaptureIterationTimeout ?: number ;
4444 autoCaptureMaxRetries ?: number ;
45+ autoCaptureMaxContextBytes ?: number ;
4546 autoCaptureLanguage ?: string ;
4647 memoryProvider ?: "openai-chat" | "openai-responses" | "anthropic" | "minimax" ;
4748 memoryModel ?: string ;
@@ -81,6 +82,8 @@ interface OpenCodeMemConfig {
8182 userProfileCentroidDriftThreshold ?: number ;
8283 userProfileEmbeddingMinDescriptionLength ?: number ;
8384 userProfileMinEvidenceForRetention ?: number ;
85+ userProfileAutoCleanupEnabled ?: boolean ;
86+ userProfileAutoCleanupInterval ?: number ;
8487 userProfileValidationEnabled ?: boolean ;
8588 showAutoCaptureToasts ?: boolean ;
8689 showUserProfileToasts ?: boolean ;
@@ -152,6 +155,7 @@ const DEFAULTS: Required<
152155 autoCaptureMaxIterations : 5 ,
153156 autoCaptureIterationTimeout : 30000 ,
154157 autoCaptureMaxRetries : 3 ,
158+ autoCaptureMaxContextBytes : 131072 ,
155159 aiSessionRetentionDays : 7 ,
156160 webServerEnabled : true ,
157161 webServerPort : 4747 ,
@@ -179,6 +183,8 @@ const DEFAULTS: Required<
179183 userProfileCentroidDriftThreshold : 0.65 ,
180184 userProfileEmbeddingMinDescriptionLength : 5 ,
181185 userProfileMinEvidenceForRetention : 3 ,
186+ userProfileAutoCleanupEnabled : true ,
187+ userProfileAutoCleanupInterval : 100 ,
182188 userProfileValidationEnabled : false ,
183189 showAutoCaptureToasts : true ,
184190 showUserProfileToasts : true ,
@@ -410,6 +416,11 @@ const CONFIG_TEMPLATE = `{
410416
411417 // Maximum number of times to retry capturing a prompt if it fails (due to network, API errors, etc.)
412418 "autoCaptureMaxRetries": 3,
419+
420+ // Maximum UTF-8 bytes for the auto-capture markdown context sent to the summary model.
421+ // Prevents HTTP 400 context overflows on models with ~131K token windows (e.g. Groq Llama).
422+ // Rough guide: tokens ≈ bytes / 4 for mixed code/prose.
423+ "autoCaptureMaxContextBytes": 131072,
413424
414425 // Days to keep AI session history before cleanup
415426 "aiSessionRetentionDays": 7,
@@ -488,6 +499,11 @@ const CONFIG_TEMPLATE = `{
488499 // Items confirmed fewer times are more likely to be pruned when confidence decays
489500 "userProfileMinEvidenceForRetention": 3,
490501
502+ // Periodically merge duplicate or irrelevant profile items with the configured AI provider
503+ "userProfileAutoCleanupEnabled": true,
504+ // Number of analyzed user prompts between automatic AI cleanup runs
505+ "userProfileAutoCleanupInterval": 100,
506+
491507 // Enable LLM validation of existing preferences against recent behavior.
492508 // When enabled, each analysis round checks if top-5 preferences still match recent prompts.
493509 // Experimental — disabled by default.
@@ -568,11 +584,23 @@ function getEmbeddingDimensions(model: string): number {
568584 return dimensionMap [ model ] || 768 ;
569585}
570586
587+ export function normalizeAutoCaptureMaxContextBytes ( value : number ) : number {
588+ if ( ! Number . isInteger ( value ) || value < 16384 || value > 16 * 1024 * 1024 ) {
589+ throw new Error ( `Invalid autoCaptureMaxContextBytes config: ${ value } ` ) ;
590+ }
591+ return value ;
592+ }
593+
571594function buildConfig ( fileConfig : OpenCodeMemConfig ) {
572595 const memoryApiKey = resolveSecretValue ( fileConfig . memoryApiKey ) ;
573596 const embeddingDimensions =
574597 fileConfig . embeddingDimensions ??
575598 getEmbeddingDimensions ( fileConfig . embeddingModel ?? DEFAULTS . embeddingModel ) ;
599+ const autoCaptureMaxContextBytes = normalizeAutoCaptureMaxContextBytes (
600+ fileConfig . autoCaptureMaxContextBytes ?? DEFAULTS . autoCaptureMaxContextBytes
601+ ) ;
602+ const userProfileAutoCleanupInterval =
603+ fileConfig . userProfileAutoCleanupInterval ?? DEFAULTS . userProfileAutoCleanupInterval ;
576604
577605 if (
578606 ! Number . isInteger ( embeddingDimensions ) ||
@@ -581,6 +609,11 @@ function buildConfig(fileConfig: OpenCodeMemConfig) {
581609 ) {
582610 throw new Error ( `Invalid embeddingDimensions config: ${ embeddingDimensions } ` ) ;
583611 }
612+ if ( ! Number . isInteger ( userProfileAutoCleanupInterval ) || userProfileAutoCleanupInterval <= 0 ) {
613+ throw new Error (
614+ `Invalid userProfileAutoCleanupInterval config: ${ userProfileAutoCleanupInterval } `
615+ ) ;
616+ }
584617
585618 return {
586619 storagePath : expandPath ( fileConfig . storagePath ?? DEFAULTS . storagePath ) ,
@@ -605,6 +638,7 @@ function buildConfig(fileConfig: OpenCodeMemConfig) {
605638 autoCaptureIterationTimeout :
606639 fileConfig . autoCaptureIterationTimeout ?? DEFAULTS . autoCaptureIterationTimeout ,
607640 autoCaptureMaxRetries : fileConfig . autoCaptureMaxRetries ?? DEFAULTS . autoCaptureMaxRetries ,
641+ autoCaptureMaxContextBytes,
608642 autoCaptureLanguage : fileConfig . autoCaptureLanguage ,
609643 memoryProvider : ( fileConfig . memoryProvider ?? "openai-chat" ) as
610644 "openai-chat" | "openai-responses" | "anthropic" | "minimax" ,
@@ -677,6 +711,9 @@ function buildConfig(fileConfig: OpenCodeMemConfig) {
677711 DEFAULTS . userProfileEmbeddingMinDescriptionLength ,
678712 userProfileMinEvidenceForRetention :
679713 fileConfig . userProfileMinEvidenceForRetention ?? DEFAULTS . userProfileMinEvidenceForRetention ,
714+ userProfileAutoCleanupEnabled :
715+ fileConfig . userProfileAutoCleanupEnabled ?? DEFAULTS . userProfileAutoCleanupEnabled ,
716+ userProfileAutoCleanupInterval,
680717 userProfileValidationEnabled :
681718 fileConfig . userProfileValidationEnabled ?? DEFAULTS . userProfileValidationEnabled ,
682719 userProfileStaleDays : fileConfig . userProfileStaleDays ?? DEFAULTS . userProfileStaleDays ,
0 commit comments