Files
FusionAGI/fusionagi/self_improvement/loop.py
Devin AI 445865e429
Some checks failed
Tests / test (3.10) (pull_request) Failing after 40s
Tests / test (3.11) (pull_request) Failing after 39s
Tests / test (3.12) (pull_request) Successful in 49s
Tests / lint (pull_request) Successful in 35s
Tests / docker (pull_request) Successful in 2m27s
fix: deep GPU integration, fix all ruff/mypy issues, add .dockerignore
- Integrate GPU scoring inline into reasoning/multi_path.py (auto-uses GPU when available)
- Integrate GPU deduplication into multi_agent/consensus_engine.py
- Add semantic_search() method to memory/semantic_graph.py with GPU acceleration
- Integrate GPU training into self_improvement/training.py AutoTrainer
- Fix all 758 ruff lint issues (whitespace, import sorting, unused imports, ambiguous vars, undefined names)
- Fix all 40 mypy type errors across the codebase (no-any-return, union-attr, arg-type, etc.)
- Fix deprecated ruff config keys (select/ignore -> [tool.ruff.lint])
- Add .dockerignore to exclude .venv/, tests/, docs/ from Docker builds
- Add type hints and docstrings to verification/outcome.py
- Fix E402 import ordering in witness_agent.py
- Fix F821 undefined names in vector_pgvector.py and native.py
- Fix E741 ambiguous variable names in reflective.py and recommender.py

All 276 tests pass. 0 ruff errors. 0 mypy errors.

Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-04-28 05:48:37 +00:00

153 lines
6.3 KiB
Python

"""AGI loop: wires self-correction, auto-recommend, and auto-training to events."""
from typing import Any, Callable
from fusionagi._logger import logger
from fusionagi.core.event_bus import EventBus
from fusionagi.schemas.recommendation import Recommendation, TrainingSuggestion
from fusionagi.schemas.task import TaskState
from fusionagi.self_improvement.correction import (
CriticLike,
OrchestratorLike,
SelfCorrectionLoop,
StateManagerLike,
)
from fusionagi.self_improvement.recommender import AutoRecommender
from fusionagi.self_improvement.training import AutoTrainer, ReflectiveMemoryLike
class FusionAGILoop:
"""
High-level AGI loop: subscribes to task_state_changed and reflection_done,
runs self-correction on failures, and runs auto-recommend + auto-training
after reflection. Composes the world's most advanced agentic AGI self-improvement pipeline.
"""
def __init__(
self,
event_bus: EventBus,
state_manager: StateManagerLike,
orchestrator: OrchestratorLike,
critic_agent: CriticLike,
reflective_memory: ReflectiveMemoryLike | None = None,
*,
auto_retry_on_failure: bool = False,
max_retries_per_task: int = 2,
on_recommendations: Callable[[list[Recommendation]], None] | None = None,
on_training_suggestions: Callable[[list[TrainingSuggestion]], None] | None = None,
) -> None:
"""
Initialize the FusionAGI loop.
Args:
event_bus: Event bus to subscribe to task_state_changed and reflection_done.
state_manager: State manager for task state and traces.
orchestrator: Orchestrator for plan and state transitions.
critic_agent: Critic agent for evaluate_request -> evaluation_ready.
reflective_memory: Optional reflective memory for lessons/heuristics.
auto_retry_on_failure: If True, on FAILED transition prepare_retry automatically.
max_retries_per_task: Max retries per task when auto_retry_on_failure is True.
on_recommendations: Optional callback to receive recommendations (e.g. log or UI).
on_training_suggestions: Optional callback to receive training suggestions.
"""
self._event_bus = event_bus
self._state = state_manager
self._orchestrator = orchestrator
self._critic = critic_agent
self._memory = reflective_memory
self._auto_retry = auto_retry_on_failure
self._on_recs = on_recommendations
self._on_training = on_training_suggestions
self._correction = SelfCorrectionLoop(
state_manager=state_manager,
orchestrator=orchestrator,
critic_agent=critic_agent,
max_retries_per_task=max_retries_per_task,
)
self._recommender = AutoRecommender(reflective_memory=reflective_memory)
self._trainer = AutoTrainer(reflective_memory=reflective_memory)
self._event_bus.subscribe("task_state_changed", self._on_task_state_changed)
self._event_bus.subscribe("reflection_done", self._on_reflection_done)
logger.info("FusionAGILoop: subscribed to task_state_changed and reflection_done")
def _on_task_state_changed(self, event_type: str, payload: dict[str, Any]) -> None:
"""On FAILED, optionally run self-correction and prepare retry."""
try:
to_state = payload.get("to_state")
task_id = payload.get("task_id", "")
if to_state != TaskState.FAILED.value or not task_id:
return
if self._auto_retry:
ok, _ = self._correction.suggest_retry(task_id)
if ok:
self._correction.prepare_retry(task_id)
else:
recs = self._correction.correction_recommendations(task_id)
if recs and self._on_recs:
self._on_recs(recs)
except Exception:
logger.exception(
"FusionAGILoop: _on_task_state_changed failed (best-effort)",
extra={"event_type": event_type},
)
def _on_reflection_done(self, event_type: str, payload: dict[str, Any]) -> None:
"""After reflection, run auto-recommend and auto-training."""
try:
task_id = payload.get("task_id") or ""
evaluation = payload.get("evaluation") or {}
recs = self._recommender.recommend(
task_id=task_id or None,
evaluation=evaluation,
include_lessons=True,
)
if self._on_recs:
try:
self._on_recs(recs)
except Exception:
logger.exception("FusionAGILoop: on_recommendations callback failed")
suggestions = self._trainer.run_auto_training(
task_id=task_id or None,
evaluation=evaluation,
apply_heuristics=True,
)
if self._on_training:
try:
self._on_training(suggestions)
except Exception:
logger.exception("FusionAGILoop: on_training_suggestions callback failed")
except Exception:
logger.exception(
"FusionAGILoop: _on_reflection_done failed (best-effort)",
extra={"event_type": event_type},
)
def run_after_reflection(
self,
task_id: str,
evaluation: dict[str, Any],
) -> tuple[list[Recommendation], list[TrainingSuggestion]]:
"""
Run auto-recommend and auto-training after a reflection (e.g. when
not using reflection_done event). Returns (recommendations, training_suggestions).
"""
recs = self._recommender.recommend(
task_id=task_id,
evaluation=evaluation,
include_lessons=True,
)
suggestions = self._trainer.run_auto_training(
task_id=task_id,
evaluation=evaluation,
apply_heuristics=True,
)
return recs, suggestions
def unsubscribe(self) -> None:
"""Unsubscribe from event bus (for cleanup)."""
self._event_bus.unsubscribe("task_state_changed", self._on_task_state_changed)
self._event_bus.unsubscribe("reflection_done", self._on_reflection_done)
logger.info("FusionAGILoop: unsubscribed from events")