From 6f0a9ae68a0c65bf6ba8a91a6006a2d3cccbfd91 Mon Sep 17 00:00:00 2001 From: Slipstream Date: Mon, 28 Apr 2025 19:22:19 -0600 Subject: [PATCH] aaa --- gurt/background.py | 65 +++++++++++++++++++++++++++++++++++++++++++++- gurt/cog.py | 1 + gurt/config.py | 4 +++ gurt_memory.py | 45 ++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/gurt/background.py b/gurt/background.py index d1cc309..1744415 100644 --- a/gurt/background.py +++ b/gurt/background.py @@ -16,7 +16,9 @@ from .config import ( INTEREST_FACT_BOOST, PROACTIVE_GOAL_CHECK_INTERVAL, STATS_PUSH_INTERVAL, # Added stats interval MOOD_OPTIONS, MOOD_CATEGORIES, MOOD_CHANGE_INTERVAL_MIN, MOOD_CHANGE_INTERVAL_MAX, # Mood change imports BASELINE_PERSONALITY, # For default traits - REFLECTION_INTERVAL_SECONDS # Import reflection interval + REFLECTION_INTERVAL_SECONDS, # Import reflection interval + # Internal Action Config + INTERNAL_ACTION_INTERVAL_SECONDS, INTERNAL_ACTION_PROBABILITY ) # Assuming analysis functions are moved from .analysis import ( @@ -290,6 +292,67 @@ async def background_processing_task(cog: 'GurtCog'): traceback.print_exc() cog.last_proactive_goal_check = now # Update timestamp even on error + # --- Random Internal Action (Runs periodically based on probability) --- + if now - cog.last_internal_action_check > INTERNAL_ACTION_INTERVAL_SECONDS: + if random.random() < INTERNAL_ACTION_PROBABILITY: + print("Considering random internal action...") + # --- Select Action --- + # For now, only use get_general_facts + selected_tool_name = "get_general_facts" + tool_func = TOOL_MAPPING.get(selected_tool_name) + tool_args = {"query": None, "limit": 5} # Example: Get 5 recent general facts + + if tool_func: + print(f" - Attempting internal action: {selected_tool_name} with args: {tool_args}") + tool_result = None + tool_error = None + try: + start_time = time.monotonic() + # Execute the tool function directly + tool_result = await tool_func(cog, **tool_args) + end_time = time.monotonic() + exec_time = end_time - start_time + + if isinstance(tool_result, dict) and "error" in tool_result: + tool_error = tool_result["error"] + result_summary = f"Error: {tool_error}" + print(f" - Internal action '{selected_tool_name}' reported error: {tool_error}") + else: + # Create a concise summary of the result + if isinstance(tool_result, dict) and "facts" in tool_result: + fact_count = tool_result.get("count", len(tool_result.get("facts", []))) + result_summary = f"Success: Retrieved {fact_count} general facts." + # Optionally include first fact if available + if fact_count > 0 and tool_result.get("facts"): + first_fact = str(tool_result["facts"][0])[:100] # Truncate first fact + result_summary += f" First: '{first_fact}...'" + else: + result_summary = f"Success: Result type {type(tool_result)}. {str(tool_result)[:200]}" # Generic success summary + print(f" - Internal action '{selected_tool_name}' completed successfully in {exec_time:.3f}s.") + + except Exception as exec_e: + tool_error = f"Exception during internal execution: {str(exec_e)}" + result_summary = f"Exception: {tool_error}" + print(f" - Internal action '{selected_tool_name}' raised exception: {exec_e}") + traceback.print_exc() + + # --- Log Action to Memory --- + try: + log_result = await cog.memory_manager.add_internal_action_log( + tool_name=selected_tool_name, + arguments=tool_args, + result_summary=result_summary + ) + if log_result.get("status") != "logged": + print(f" - Warning: Failed to log internal action to memory: {log_result.get('error')}") + except Exception as log_e: + print(f" - Error logging internal action to memory: {log_e}") + traceback.print_exc() + else: + print(f" - Error: Selected internal tool '{selected_tool_name}' not found in TOOL_MAPPING.") + # Update check timestamp regardless of whether an action was performed + cog.last_internal_action_check = now + except asyncio.CancelledError: print("Background processing task cancelled") except Exception as e: diff --git a/gurt/cog.py b/gurt/cog.py index 72b0130..968af2e 100644 --- a/gurt/cog.py +++ b/gurt/cog.py @@ -127,6 +127,7 @@ class GurtCog(commands.Cog, name="Gurt"): # Added explicit Cog name self.last_goal_check_time = time.time() # Timestamp for last goal decomposition check self.last_goal_execution_time = time.time() # Timestamp for last goal execution check self.last_proactive_goal_check = time.time() # Timestamp for last proactive goal check + self.last_internal_action_check = time.time() # Timestamp for last internal action check # --- Stats Tracking --- self.api_stats = defaultdict(lambda: {"success": 0, "failure": 0, "retries": 0, "total_time": 0.0, "count": 0}) # Keyed by model name diff --git a/gurt/config.py b/gurt/config.py index 52aefd2..be46399 100644 --- a/gurt/config.py +++ b/gurt/config.py @@ -125,6 +125,10 @@ GOAL_CHECK_INTERVAL = int(os.getenv("GOAL_CHECK_INTERVAL", 300)) # Check for pen GOAL_EXECUTION_INTERVAL = int(os.getenv("GOAL_EXECUTION_INTERVAL", 60)) # Check for active goals to execute every 1 min PROACTIVE_GOAL_CHECK_INTERVAL = int(os.getenv("PROACTIVE_GOAL_CHECK_INTERVAL", 900)) # Check if Gurt should create its own goals every 15 mins +# --- Internal Random Action Config --- +INTERNAL_ACTION_INTERVAL_SECONDS = int(os.getenv("INTERNAL_ACTION_INTERVAL_SECONDS", 600)) # How often to *consider* a random action (10 mins) +INTERNAL_ACTION_PROBABILITY = float(os.getenv("INTERNAL_ACTION_PROBABILITY", 0.1)) # Chance of performing an action each interval (10%) + # --- Topic Tracking Config --- TOPIC_UPDATE_INTERVAL = 300 # Update topics every 5 minutes TOPIC_RELEVANCE_DECAY = 0.2 diff --git a/gurt_memory.py b/gurt_memory.py index fc36553..e31e349 100644 --- a/gurt_memory.py +++ b/gurt_memory.py @@ -222,6 +222,21 @@ class MemoryManager: logger.info("Goals table created/verified.") # --- End Goals Table --- + # --- Add Internal Actions Log Table --- + await db.execute(""" + CREATE TABLE IF NOT EXISTS internal_actions ( + action_id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp REAL DEFAULT (unixepoch('now')), + tool_name TEXT NOT NULL, + arguments_json TEXT, -- Store arguments as JSON string + result_summary TEXT -- Store a summary of the result or error message + ); + """) + await db.execute("CREATE INDEX IF NOT EXISTS idx_internal_actions_timestamp ON internal_actions (timestamp);") + await db.execute("CREATE INDEX IF NOT EXISTS idx_internal_actions_tool_name ON internal_actions (tool_name);") + logger.info("Internal Actions Log table created/verified.") + # --- End Internal Actions Log Table --- + await db.commit() logger.info(f"SQLite database initialized/verified at {self.db_path}") @@ -1003,3 +1018,33 @@ class MemoryManager: except Exception as e: logger.error(f"Error deleting goal ID {goal_id}: {e}", exc_info=True) return {"error": f"Database error deleting goal: {str(e)}"} + + # --- Internal Action Log Methods --- + + async def add_internal_action_log(self, tool_name: str, arguments: Optional[Dict[str, Any]], result_summary: str) -> Dict[str, Any]: + """Logs the execution of an internal background action.""" + if not tool_name: + return {"error": "Tool name is required for logging internal action."} + logger.info(f"Logging internal action: Tool='{tool_name}', Args={arguments}, Result='{result_summary[:100]}...'") + args_json = json.dumps(arguments) if arguments else None + # Truncate result summary if too long for DB + max_summary_len = 1000 + truncated_summary = result_summary[:max_summary_len] + ('...' if len(result_summary) > max_summary_len else '') + + try: + async with self.db_lock: + async with aiosqlite.connect(self.db_path) as db: + cursor = await db.execute( + """ + INSERT INTO internal_actions (tool_name, arguments_json, result_summary, timestamp) + VALUES (?, ?, ?, unixepoch('now')) + """, + (tool_name, args_json, truncated_summary) + ) + await db.commit() + action_id = cursor.lastrowid + logger.info(f"Internal action logged successfully (ID: {action_id}): Tool='{tool_name}'") + return {"status": "logged", "action_id": action_id} + except Exception as e: + logger.error(f"Error logging internal action '{tool_name}': {e}", exc_info=True) + return {"error": f"Database error logging internal action: {str(e)}"}