-
Notifications
You must be signed in to change notification settings - Fork 4
feat: Activate 8 dormant cognitive subsystems and expose /api/system/dormant-modules #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,310 @@ | ||||||||
| """ | ||||||||
| DormantModuleManager — activation and per-cycle ticking of the 8 formerly-dormant | ||||||||
| cognitive subsystems that are implemented in godelOS/ but were previously | ||||||||
| disconnected from the runtime. | ||||||||
|
|
||||||||
| Modules managed: | ||||||||
| 1. symbol_grounding_associator | ||||||||
| 2. perceptual_categorizer | ||||||||
| 3. simulated_environment | ||||||||
| 4. ilp_engine | ||||||||
| 5. modal_tableau_prover | ||||||||
| 6. clp_module | ||||||||
| 7. explanation_based_learner | ||||||||
| 8. meta_control_rl | ||||||||
| """ | ||||||||
|
|
||||||||
| from __future__ import annotations | ||||||||
|
|
||||||||
| import asyncio | ||||||||
| import logging | ||||||||
| import time | ||||||||
| from datetime import datetime, timezone | ||||||||
| from typing import Any, Dict, List, Optional | ||||||||
|
|
||||||||
| logger = logging.getLogger(__name__) | ||||||||
|
|
||||||||
| # Canonical list of the 8 dormant modules (matches CognitivePipeline subsystem keys). | ||||||||
| DORMANT_MODULE_NAMES: List[str] = [ | ||||||||
| "symbol_grounding_associator", | ||||||||
| "perceptual_categorizer", | ||||||||
| "simulated_environment", | ||||||||
| "ilp_engine", | ||||||||
| "modal_tableau_prover", | ||||||||
| "clp_module", | ||||||||
| "explanation_based_learner", | ||||||||
| "meta_control_rl", | ||||||||
| ] | ||||||||
|
|
||||||||
|
|
||||||||
| class ModuleRecord: | ||||||||
| """Runtime record for a single dormant module.""" | ||||||||
|
|
||||||||
| def __init__(self, name: str) -> None: | ||||||||
| self.name = name | ||||||||
| self.active: bool = False | ||||||||
| self.last_tick: Optional[datetime] = None | ||||||||
| self.tick_count: int = 0 | ||||||||
| self.last_output: Optional[Dict[str, Any]] = None | ||||||||
| self.error: Optional[str] = None | ||||||||
|
|
||||||||
| def as_dict(self) -> Dict[str, Any]: | ||||||||
| return { | ||||||||
| "module_name": self.name, | ||||||||
| "active": self.active, | ||||||||
| "last_tick": self.last_tick.isoformat() if self.last_tick else None, | ||||||||
| "tick_count": self.tick_count, | ||||||||
| "last_output": self.last_output, | ||||||||
| "error": self.error, | ||||||||
| } | ||||||||
|
|
||||||||
|
|
||||||||
| class DormantModuleManager: | ||||||||
| """ | ||||||||
| Manages the activation and periodic ticking of the 8 formerly-dormant | ||||||||
| cognitive modules. | ||||||||
|
|
||||||||
| Usage:: | ||||||||
|
|
||||||||
| manager = DormantModuleManager() | ||||||||
| manager.initialize(godelos_integration, websocket_manager) | ||||||||
| # then in a background loop: | ||||||||
| await manager.tick() | ||||||||
| """ | ||||||||
|
|
||||||||
| def __init__(self) -> None: | ||||||||
| self._records: Dict[str, ModuleRecord] = { | ||||||||
| name: ModuleRecord(name) for name in DORMANT_MODULE_NAMES | ||||||||
| } | ||||||||
| self._instances: Dict[str, Any] = {} | ||||||||
| self._websocket_manager: Any = None | ||||||||
| self._initialized: bool = False | ||||||||
|
|
||||||||
| # ------------------------------------------------------------------ | ||||||||
| # Initialization | ||||||||
| # ------------------------------------------------------------------ | ||||||||
|
|
||||||||
| def initialize( | ||||||||
| self, | ||||||||
| godelos_integration: Any, | ||||||||
| websocket_manager: Optional[Any] = None, | ||||||||
| ) -> None: | ||||||||
| """ | ||||||||
| Pull live module instances from the CognitivePipeline (via godelos_integration) | ||||||||
| and mark each module as active if its instance exists. | ||||||||
| """ | ||||||||
| self._websocket_manager = websocket_manager | ||||||||
|
|
||||||||
| pipeline = getattr(godelos_integration, "cognitive_pipeline", None) | ||||||||
| if pipeline is None: | ||||||||
| logger.warning( | ||||||||
| "DormantModuleManager: CognitivePipeline not found on godelos_integration; " | ||||||||
| "all dormant modules will be inactive." | ||||||||
| ) | ||||||||
| self._initialized = True | ||||||||
| return | ||||||||
|
|
||||||||
| for name in DORMANT_MODULE_NAMES: | ||||||||
| try: | ||||||||
| instance = pipeline.get_instance(name) | ||||||||
| if instance is not None: | ||||||||
| self._instances[name] = instance | ||||||||
| self._records[name].active = True | ||||||||
| logger.info(" ✔ dormant module activated: %s", name) | ||||||||
| else: | ||||||||
| status_info = pipeline.get_subsystem_status().get(name, {}) | ||||||||
| err = status_info.get("error", "instance is None") | ||||||||
| self._records[name].error = err | ||||||||
| logger.warning(" ✘ dormant module unavailable: %s — %s", name, err) | ||||||||
|
Comment on lines
+107
to
+118
|
||||||||
| except Exception as exc: # noqa: BLE001 | ||||||||
| self._records[name].error = str(exc) | ||||||||
| logger.warning(" ✘ dormant module error: %s — %s", name, exc) | ||||||||
|
|
||||||||
| active = sum(1 for r in self._records.values() if r.active) | ||||||||
| logger.info( | ||||||||
| "DormantModuleManager: %d/%d dormant modules active", | ||||||||
| active, | ||||||||
| len(DORMANT_MODULE_NAMES), | ||||||||
| ) | ||||||||
| self._initialized = True | ||||||||
|
|
||||||||
| # ------------------------------------------------------------------ | ||||||||
| # Periodic tick | ||||||||
| # ------------------------------------------------------------------ | ||||||||
|
|
||||||||
| async def tick(self) -> List[Dict[str, Any]]: | ||||||||
| """ | ||||||||
| Run one tick of every active dormant module. | ||||||||
|
|
||||||||
| Returns a list of per-module state dicts that can be forwarded over | ||||||||
| the WebSocket stream. | ||||||||
| """ | ||||||||
| if not self._initialized: | ||||||||
| return [] | ||||||||
|
|
||||||||
| results: List[Dict[str, Any]] = [] | ||||||||
| now = datetime.now(tz=timezone.utc) | ||||||||
|
|
||||||||
| for name, record in self._records.items(): | ||||||||
| if not record.active: | ||||||||
| results.append(record.as_dict()) | ||||||||
| continue | ||||||||
| instance = self._instances.get(name) | ||||||||
| if instance is None: | ||||||||
| record.active = False | ||||||||
|
||||||||
| record.active = False | |
| record.active = False | |
| record.error = "instance missing" |
Copilot
AI
Mar 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The per-module tick handlers swallow exceptions (e.g. learn_groundings_from_buffer()), so failures won’t propagate to the outer tick() try/except and ModuleRecord.error won’t reflect runtime failures. Since tick() already isolates each module, consider letting handler exceptions bubble up (or capturing them and returning an error field) so the error attribute is accurate.
Copilot
AI
Mar 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_module_status() docstring references the /api/system/modules endpoint, but the server endpoint added in this PR is /api/system/dormant-modules. Updating the docstring will avoid confusion when this manager is reused elsewhere.
| """Return a list of per-module status dicts for the /api/system/modules endpoint.""" | |
| """Return a list of per-module status dicts for the /api/system/dormant-modules endpoint.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DormantModuleManager.initialize()sets_initialized=Trueand returns whencognitive_pipelineis missing, but it leaves each module record’serrorasNone. That makes/api/system/dormant-moduleslook like a clean inactive state rather than “pipeline unavailable”. Consider populating a consistent error string on all records in this branch.