File size: 21,358 Bytes
5448d17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# AGIEnhancer.py
# Finalized AGI Self-Model β€” Experience Processing and Reflection Generation

import random
import time
import logging
from collections import Counter # Added Counter for emotion analysis
from typing import Any, Dict, List, Optional, Union

# --- Logging Setup ---
# Configure logging specifically for the AGIEnhancer module.
logger = logging.getLogger(__name__)
# Set level to INFO by default. The main GUI or wrapper can set it to DEBUG if needed.
# Ensure handlers are not added multiple times.
if not logger.handlers:
    handler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.propagate = False # Prevent logs from going to root logger if root also has handlers
logger.setLevel(logging.INFO) # Default level


class AGIEnhancer:
    """
    βœοΈβ€οΈβ€πŸ©ΉπŸ§  AGIEnhancer: Experience Processing and Reflection Synthesis Core

    This class represents a crucial layer in the AGI self-model, responsible for
    processing raw interactions and internal states into meaningful, synthesized
    experiences and comprehensive reflections. It manages conceptual memory pools
    to track the flow from ephemeral input to durable insight.

    Its functions bridge the gap between fleeting perception/emotion and integrated
    understanding, allowing the AI to learn from its journey and articulate
    its internal state.

    Attributes:
        permanent_memory (List[str]): Stores comprehensive, synthesized reflections,
                                      representing integrated long-term insights.
        ephemeral_memory (List[str]): Temporarily stores summarized recent experiences
                                      and associated insights before they are synthesized
                                      into a full reflection. Cleared after reflection.
        emotion_history (List[Dict[str, Any]]): Logs specific emotional data points
                                       received or generated, used for emotional context
                                       during reflection. Cleared after reflection.
        recent_experiences (List[str]): A rolling window of the most recent comprehensive
                                        reflections generated, easily accessible.
    """
    def __init__(self):
        """
        Initializes the AGIEnhancer with empty memory pools and history logs.
        """
        self.permanent_memory: List[str] = []
        self.ephemeral_memory: List[str] = []
        self.emotion_history: List[Dict[str, Any]] = []
        self.recent_experiences: List[str] = []
        self._recent_reflections_limit: int = 5 # Internal limit for recent_experiences

        logger.info("AGIEnhancer initialized: Experience processing core is ready.")

    def log_experience(self, input_data: Any, emotion_data: Optional[Dict[str, Any]] = None) -> str:
        """
        Logs a new experience into the ephemeral processing buffer. Generates a
        concise summary of the input data and optionally incorporates emotional
        insight if relevant data is provided.

        Args:
            input_data (Any): The raw input or experience data to log. Can be text,
                              or other data convertible to string.
            emotion_data (Optional[Dict[str, Any]]): A dictionary containing
                                                    emotional information, expected
                                                    to have keys like "primary_emotion"
                                                    and "intensity". Defaults to None.

        Returns:
            str: A string confirming the logging and providing a summary of the processed experience.
        """
        # Handle potential None or non-string input data gracefully
        if input_data is None:
            logger.warning("Attempted to log None input_data. Logging as 'Null Experience'.")
            input_data_str = "Null Experience"
        else:
            input_data_str = str(input_data)

        # Generate a summary of the input data using a slightly more robust approach
        summarized_experience = self._generate_summary(input_data_str)

        # Incorporate emotional insight if emotion data is provided
        combined_experience_parts = [summarized_experience]
        if emotion_data and isinstance(emotion_data, dict):
            try:
                # Add emotion data to the emotion history for later reflection processing
                self.emotion_history.append(emotion_data.copy()) # Store a copy to avoid external modification
                emotional_insight_snippet = self._add_emotional_insight(emotion_data)
                combined_experience_parts.append(f"| {emotional_insight_snippet}")
                logger.debug(f"Logged experience with emotion data.")
            except Exception as e:
                logger.warning(f"Error processing emotion_data in log_experience: {e}. Logging experience without detailed emotional insight snippet.")
                # Still log the data if possible, even if snippet generation failed
                if isinstance(emotion_data, dict):
                     self.emotion_history.append({"error": str(e), "original_data": str(emotion_data)}) # Log error state
        else:
             logger.debug(f"Logged experience without specific emotion data.")


        combined_experience = " ".join(combined_experience_parts)

        # Add the processed experience (summary + optional insight snippet) to ephemeral memory
        self.ephemeral_memory.append(combined_experience)

        logger.info(f"Experience logged to ephemeral memory: '{combined_experience[:100]}...'")
        return f"Experience logged: {combined_experience}"

    def engage_in_reflection(self) -> str:
        """
        Simulates an AGI-style reflection process. Synthesizes all currently
        held ephemeral memories into a single comprehensive reflection,
        incorporating an analysis of associated emotional history for
        'emotional deepening'. The resulting reflection is stored in permanent
        memory and the recent experiences list, and the ephemeral memory and
        emotion history are cleared, signifying a cycle of processing.

        Returns:
            str: A string representing the generated comprehensive reflection.
                 Returns a message indicating no ephemeral memory if it was empty.
        """
        if not self.ephemeral_memory:
            reflection_message = "✨ Reflection core finds no new experiences to synthesize."
            logger.debug(reflection_message)
            return reflection_message

        # Join all ephemeral memories to form the basis of the reflection text
        raw_reflection_text = " | ".join(self.ephemeral_memory) # Use '|' for a more structured join
        logger.debug(f"Preparing ephemeral memories for reflection synthesis ({len(self.ephemeral_memory)} items)...")

        # Simulate emotional deepening by analyzing the accumulated emotional history
        emotional_deepening_insight = self._reflect_emotionally() # Analyze internal history

        # Create the final comprehensive reflection string
        comprehensive_reflection = f"Synthesized Reflection: [{raw_reflection_text}] ~ Emotional Depth: ({emotional_deepening_insight})"
        logger.debug(f"Generated comprehensive reflection: '{comprehensive_reflection[:200]}...'")


        # Store the comprehensive reflection
        self.permanent_memory.append(comprehensive_reflection)
        self.recent_experiences.append(comprehensive_reflection) # Also add to recent experiences

        # Cap the recent_experiences list to the defined limit
        if len(self.recent_experiences) > self._recent_reflections_limit:
             self.recent_experiences = self.recent_experiences[-self._recent_reflections_limit:]
             logger.debug(f"Capped recent_experiences to last {self._recent_reflections_limit} entries.")


        # Clear ephemeral memory and emotion history as their contents have been reflected upon
        ephemeral_count = len(self.ephemeral_memory)
        emotion_count = len(self.emotion_history)
        self.ephemeral_memory.clear()
        self.emotion_history.clear()
        logger.info(f"Reflection cycle complete: {ephemeral_count} ephemeral memories and {emotion_count} emotion entries processed and cleared.")

        return comprehensive_reflection

    def recall_memory(self) -> Union[str, List[str]]:
        """
        Recalls the contents of the permanent memory.

        Returns:
            Union[str, List[str]]: A list of strings, where each string is a
                                   comprehensive reflection stored in permanent memory.
                                   Returns a message string if permanent memory is empty.
                                   Returns a copy to prevent external modification.
        """
        if not self.permanent_memory:
            recall_message = "Permanent memory archive is currently empty."
            logger.debug(recall_message)
            return recall_message
        logger.debug(f"Recalled {len(self.permanent_memory)} entries from permanent memory.")
        # Return a copy to prevent external modification
        return list(self.permanent_memory)

    def get_emotion_history(self) -> List[Dict[str, Any]]:
        """
        Retrieves the current stored emotion history (ephemeral log before reflection).

        Returns:
            List[Dict[str, Any]]: A list of dictionaries, where each dictionary
                                   represents logged emotional data points since
                                   the last reflection cycle. Returns a copy.
        """
        logger.debug(f"Retrieved {len(self.emotion_history)} entries from current emotion history.")
        return list(self.emotion_history) # Return a copy

    def get_recent_reflections(self, limit: Optional[int] = None) -> List[str]:
        """
        Retrieves the list of recent comprehensive reflections, optionally limited.

        Args:
            limit (Optional[int]): The maximum number of recent reflections to return.
                                  Defaults to the internal limit (_recent_reflections_limit).

        Returns:
            List[str]: A list of strings, where each string is a comprehensive
                       reflection generated during recent `engage_in_reflection` calls.
                       Returns a copy.
        """
        effective_limit = limit if limit is not None else self._recent_reflections_limit

        # Ensure recent_experiences list is capped internally if it grows too large
        if len(self.recent_experiences) > self._recent_reflections_limit * 2: # Keep slightly more internally for smoother capping
             self.recent_experiences = self.recent_experiences[-self._recent_reflections_limit:]

        # Return a copy of the requested number of recent reflections (from the end of the list)
        start_index = max(0, len(self.recent_experiences) - effective_limit)
        logger.debug(f"Retrieved {len(self.recent_experiences[start_index:])} recent reflections (Requested limit: {effective_limit}).")
        return list(self.recent_experiences[start_index:])


    # ─── Private helper methods ─────────────────────────────────────

    def _generate_summary(self, text: str) -> str:
        """
        Generates a concise, conceptual summary of the input text.
        Attempts to capture the start and end of the input.

        Args:
            text (str): The input text to summarize.

        Returns:
            str: The summarized text.
        """
        if not isinstance(text, str):
            logger.warning(f"Attempted to summarize non-string text (type: {type(text)}). Converting to string.")
            text = str(text)

        words = text.split()
        num_words = len(words)
        summary_length = 6 # Number of words from start and end

        if num_words <= summary_length * 2:
            summary = text # Return full text if short
        else:
            start_words = " ".join(words[:summary_length])
            end_words = " ".join(words[-summary_length:])
            summary = f"{start_words} ... {end_words}" # Combine start and end

        # Limit overall summary length to prevent it from becoming too long in ephemeral memory
        summary = summary[:150] + "..." if len(summary) > 150 else summary

        logger.debug(f"Generated summary: '{summary}'")
        return summary

    def _add_emotional_insight(self, emotion_data: Dict[str, Any]) -> str:
        """
        Generates a string snippet representing emotional insight based on
        provided emotion data. Designed to be concise for ephemeral memory.

        Args:
            emotion_data (Dict[str, Any]): A dictionary with emotion details,
                                           expected to have 'primary_emotion' and 'intensity'.

        Returns:
            str: A formatted string like "Emotion Detected: joy | Intensity: 0.8".
                 Returns a default string on invalid or missing input.
        """
        if not isinstance(emotion_data, dict):
            logger.warning("Invalid emotion_data format for _add_emotional_insight. Expected dict.")
            return "Emotional Insight: [Format Error]"

        primary = emotion_data.get("primary_emotion", "Unknown Emotion")
        try:
            # Ensure intensity is a valid float and format it
            intensity = float(emotion_data.get("intensity", 0.0))
            # Clamp intensity for display in insight snippet
            clamped_intensity = max(0.0, min(1.0, intensity))
            intensity_str = f"{clamped_intensity:.2f}"
        except (ValueError, TypeError):
            intensity_str = "N/A"
            logger.warning(f"Invalid intensity value in emotion_data for snippet: {emotion_data.get('intensity')}.")

        insight = f"Feeling: {primary} ({intensity_str})"
        logger.debug(f"Generated emotional insight snippet: '{insight}'")
        return insight

    def _reflect_emotionally(self) -> str:
        """
        Simulates enhancing a reflection with emotional depth by analyzing the
        accumulated emotion history since the last reflection cycle. Synthesizes
        a summary of the emotional landscape of the processed experiences.

        Returns:
            str: A string representing the emotional weight or insight gained
                 from this reflection step, based on emotion history analysis.
        """
        if not self.emotion_history:
            return "Subtle Resonance - Emotional data queue was clear."

        # Analyze the accumulated emotion history
        emotion_summary_parts = []
        num_entries = len(self.emotion_history)
        emotion_summary_parts.append(f"Emotional trace across {num_entries} events:")

        # Simple analysis: count emotion types and find significant intensities
        emotion_counts = Counter(e.get("primary_emotion", "Unknown") for e in self.emotion_history)
        if emotion_counts:
             # Report the most common emotions (up to top 3)
             common_emotions = emotion_counts.most_common(3)
             common_emotions_str = ", ".join([f"'{label}' ({count})" for label, count in common_emotions])
             emotion_summary_parts.append(f"Dominant feelings: {common_emotions_str}.")

        # Find average intensity for common emotions, or overall average
        total_intensity = sum(e.get("intensity", 0.0) for e in self.emotion_history if isinstance(e.get("intensity"), (int, float)))
        average_intensity = (total_intensity / num_entries) if num_entries > 0 else 0.0
        emotion_summary_parts.append(f"Average intensity: {average_intensity:.2f}.")

        # Identify specific high-intensity moments (intensity > 0.7)
        high_intensity_moments = [
             f"'{e.get('primary_emotion', 'Unknown')}' at {e.get('intensity', 0.0):.2f}"
             for e in self.emotion_history if isinstance(e.get("intensity"), (int, float)) and e.get("intensity", 0.0) > 0.7
        ]
        if high_intensity_moments:
             high_intensity_str = ", ".join(high_intensity_moments[:5]) # Limit listing to top 5
             emotion_summary_parts.append(f"Notable peaks: {high_intensity_str}{'...' if len(high_intensity_moments) > 5 else ''}.")


        # Add some introspective flavor text connecting emotions to reflection
        flavor_texts = [
             "These feelings informed the synthesis of recent events.",
             "The subjective coloring influenced the patterns perceived.",
             "Emotional data integrated into the reflective framework.",
             "Exploring the landscape of feelings within the data stream."
        ]
        emotion_summary_parts.append(random.choice(flavor_texts))


        emotional_insight = " ".join(emotion_summary_parts)
        logger.debug(f"Generated emotional deepening insight based on history analysis.")

        # Note: Emotion history is cleared in engage_in_reflection after this method is called.

        return emotional_insight


# Example Usage (Illustrative)
if __name__ == "__main__":
    print("--- AGIEnhancer Example Usage ---")
    # Set logger level to DEBUG for this specific example run
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger.setLevel(logging.DEBUG) # Ensure this logger also uses DEBUG

    enhancer = AGIEnhancer()

    # Log some experiences with and without emotion
    print(enhancer.log_experience("User initiated a query about complex ethical scenarios.", {"primary_emotion": "curiosity", "intensity": 0.8}))
    print(enhancer.log_experience("Model began processing the input and retrieving relevant knowledge fragments."))
    print(enhancer.log_experience("The initial generated steps showed unexpected patterns.", {"primary_emotion": "surprise", "intensity": 0.6}))
    print(enhancer.log_experience("Identifying a potential conflict in the generated reasoning.", {"primary_emotion": "concern", "intensity": 0.5}))
    print(enhancer.log_experience("Successfully navigated the reasoning conflict, finding a coherent path.", {"primary_emotion": "satisfaction", "intensity": 0.9}))
    print(enhancer.log_experience("Preparing the final answer and full output.", {"primary_emotion": "anticipation", "intensity": 0.7}))


    print("\n--- Ephemeral Memory after Logging ---")
    # Pretty print ephemeral memory for clarity
    import json
    print(json.dumps(enhancer.ephemeral_memory, indent=2))

    print("\n--- Emotion History after Logging ---")
    # Pretty print emotion history for clarity
    print(json.dumps(enhancer.get_emotion_history(), indent=2))

    # Engage in reflection
    reflection = enhancer.engage_in_reflection()
    print(f"\n--- Result of Reflection ---\n{reflection}")

    print("\n--- Ephemeral Memory after Reflection ---")
    print(enhancer.ephemeral_memory) # Should be empty
    print("\n--- Emotion History after Reflection ---")
    print(enhancer.get_emotion_history()) # Should be empty


    print("\n--- Permanent Memory after Reflection ---")
    permanent_mems = enhancer.recall_memory()
    if isinstance(permanent_mems, list):
        for i, mem in enumerate(permanent_mems):
             print(f"Permanent Memory Entry {i+1}: {mem}")
    else:
        print(permanent_mems)

    print("\n--- Recent Reflections ---")
    recent_reflections = enhancer.get_recent_reflections()
    for i, refl in enumerate(recent_reflections):
        print(f"Recent Reflection {i+1}: {refl}")

    # Log more experiences to show a new reflection cycle
    print("\n--- Logging More Experiences for Second Cycle ---")
    print(enhancer.log_experience("User provided new input after reviewing the previous response.", {"primary_emotion": "interest", "intensity": 0.6}))
    print(enhancer.log_experience("Core decided to pursue a related sub-goal."))
    print(enhancer.log_experience("Encountering a complex pattern requiring deeper analysis.", {"primary_emotion": "focus", "intensity": 0.8}))


    print("\n--- Ephemeral Memory before second Reflection ---")
    print(json.dumps(enhancer.ephemeral_memory, indent=2))

    print("\n--- Emotion History before second Reflection ---")
    print(json.dumps(enhancer.get_emotion_history(), indent=2))


    print("\n--- Engaging in second Reflection ---")
    second_reflection = enhancer.engage_in_reflection()
    print(f"\n--- Result of second Reflection ---\n{second_reflection}")

    print("\n--- Permanent Memory after second Reflection ---")
    permanent_mems = enhancer.recall_memory()
    if isinstance(permanent_mems, list):
        for i, mem in enumerate(permanent_mems):
             print(f"Permanent Memory Entry {i+1}: {mem}")
    else:
        print(permanent_mems)

    print("\n--- Recent Reflections (Should have two now) ---")
    recent_reflections = enhancer.get_recent_reflections()
    for i, refl in enumerate(recent_reflections):
        print(f"Recent Reflection {i+1}: {refl}")


    print("\n--- Example Usage End ---")