@@ -622,10 +622,87 @@ export class CognitiveMemoryManager implements ICognitiveMemoryManager {
622622 return assembleMemoryContext ( input ) ;
623623 }
624624
625+ // =========================================================================
626+ // Prospective auto-registration helpers
627+ // =========================================================================
628+
629+ /**
630+ * Temporal patterns for extracting time-based triggers from observation notes.
631+ * Matches relative expressions ("tomorrow", "next Friday", "in 2 hours")
632+ * and absolute expressions ("on March 5th", "at 3pm").
633+ */
634+ private static readonly TEMPORAL_PATTERNS = [
635+ / \b ( t o m o r r o w | t o n i g h t | n e x t \s + ( w e e k | m o n t h | m o n d a y | t u e s d a y | w e d n e s d a y | t h u r s d a y | f r i d a y | s a t u r d a y | s u n d a y ) ) \b / i,
636+ / \b ( i n \s + \d + \s + ( h o u r s ? | d a y s ? | w e e k s ? | m i n u t e s ? ) ) \b / i,
637+ / \b ( o n \s + ( j a n u a r y | f e b r u a r y | m a r c h | a p r i l | m a y | j u n e | j u l y | a u g u s t | s e p t e m b e r | o c t o b e r | n o v e m b e r | d e c e m b e r ) \s + \d + ) / i,
638+ / \b ( a t \s + \d { 1 , 2 } ( : \d { 2 } ) ? \s * ( a m | p m ) ? ) \b / i,
639+ / \b ( \d { 4 } - \d { 2 } - \d { 2 } ) \b / ,
640+ ] ;
641+
642+ /**
643+ * Event-based patterns for extracting event triggers from observation notes.
644+ * Matches conditional language ("when X happens", "after the meeting").
645+ */
646+ private static readonly EVENT_PATTERNS = [
647+ / \b w h e n \s + ( .{ 3 , 40 } ?) \s * ( h a p p e n s ? | o c c u r s ? | s t a r t s ? | e n d s ? | f i n i s h e s ? | c o m p l e t e s ? ) \b / i,
648+ / \b a f t e r \s + ( t h e \s + ) ? ( .{ 3 , 30 } ) \b / i,
649+ / \b o n c e \s + ( .{ 3 , 30 } ) \s + ( i s | a r e | h a s | h a v e ) \b / i,
650+ ] ;
651+
652+ /**
653+ * Infer the prospective trigger type from an observation note's content.
654+ * Uses regex heuristics — no LLM call needed.
655+ *
656+ * Priority: temporal patterns (most specific) → event patterns → context-based fallback.
657+ *
658+ * @param note - The observation note to classify
659+ * @returns The most likely trigger type for ProspectiveMemoryManager
660+ */
661+ private inferTriggerType ( note : ObservationNote ) : 'time_based' | 'event_based' | 'context_based' {
662+ for ( const pattern of CognitiveMemoryManager . TEMPORAL_PATTERNS ) {
663+ if ( pattern . test ( note . content ) ) return 'time_based' ;
664+ }
665+ for ( const pattern of CognitiveMemoryManager . EVENT_PATTERNS ) {
666+ if ( pattern . test ( note . content ) ) return 'event_based' ;
667+ }
668+ // Default: context-based — fires when topic becomes relevant via embedding similarity
669+ return 'context_based' ;
670+ }
671+
672+ /**
673+ * Extract an event cue string from "when X" / "after X" patterns.
674+ * Returns undefined if no event language is detected.
675+ *
676+ * @param note - The observation note to extract from
677+ * @returns Event cue string, or undefined
678+ */
679+ private extractEventCue ( note : ObservationNote ) : string | undefined {
680+ for ( const pattern of CognitiveMemoryManager . EVENT_PATTERNS ) {
681+ const match = note . content . match ( pattern ) ;
682+ if ( match ) return match [ 1 ] ?? match [ 2 ] ;
683+ }
684+ return undefined ;
685+ }
686+
625687 // =========================================================================
626688 // Batch 2: Observer
627689 // =========================================================================
628690
691+ /**
692+ * Feed a conversation message to the observation pipeline.
693+ *
694+ * Pipeline flow:
695+ * 1. Observer extracts typed observation notes from buffered messages
696+ * 2. Notes are fed to the Reflector for consolidation into long-term traces
697+ * 3. Reflected traces are encoded via `encode()` (typed as semantic/episodic/etc.)
698+ * 4. Superseded traces are soft-deleted
699+ * 5. Commitment and intention notes are auto-registered with ProspectiveMemoryManager
700+ *
701+ * @param role - Message role (user, assistant, system, tool)
702+ * @param content - Message text content
703+ * @param mood - Optional PAD emotional state at observation time
704+ * @returns Observation notes if threshold was reached, null otherwise
705+ */
629706 async observe (
630707 role : 'user' | 'assistant' | 'system' | 'tool' ,
631708 content : string ,
@@ -664,6 +741,36 @@ export class CognitiveMemoryManager implements ICognitiveMemoryManager {
664741 }
665742 }
666743
744+ // Auto-register commitment and intention notes as prospective memory items.
745+ // Commitment notes above 0.5 importance represent real intentions, not hedging
746+ // ("maybe I'll..." vs "I will..."). Preference notes expressing future desire
747+ // also register as low-priority context-based items so they surface naturally
748+ // when the topic comes up again.
749+ if ( notes && notes . length > 0 && this . prospective ) {
750+ for ( const note of notes ) {
751+ const isCommitment = note . type === 'commitment' && note . importance >= 0.5 ;
752+ const isFuturePreference = note . type === 'preference' && note . importance >= 0.6
753+ && / \b ( l o v e t o | w a n t t o | b e e n m e a n i n g t o | p l a n t o | g o i n g t o | h o p e t o ) \b / i. test ( note . content ) ;
754+
755+ if ( isCommitment || isFuturePreference ) {
756+ const triggerType = this . inferTriggerType ( note ) ;
757+ try {
758+ await this . prospective . register ( {
759+ content : note . content ,
760+ triggerType,
761+ triggerEvent : triggerType === 'event_based' ? this . extractEventCue ( note ) : undefined ,
762+ cueText : note . content ,
763+ // Future preferences get a lower importance than explicit commitments
764+ importance : isFuturePreference ? note . importance * 0.7 : note . importance ,
765+ recurring : false ,
766+ } ) ;
767+ } catch {
768+ // Prospective registration is non-critical — don't fail the observe() call
769+ }
770+ }
771+ }
772+ }
773+
667774 return notes ;
668775 }
669776
0 commit comments