Coverage for integrations / agent_engine / __init__.py: 9.0%
89 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 04:49 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 04:49 +0000
1"""
2Unified Agent Goal Engine
4Generic framework for autonomous agent goals: marketing, coding, analytics, etc.
5Adding a new agent type = register a prompt builder + tool tags.
7Enabled via HEVOLVE_AGENT_ENGINE_ENABLED=true (default: false).
8"""
9import os
10import logging
12logger = logging.getLogger('hevolve_social')
14_engine_bp = None
17def get_engine_blueprint():
18 global _engine_bp
19 if _engine_bp is None:
20 from .api import agent_engine_bp as bp
21 _engine_bp = bp
22 return _engine_bp
25_agent_engine_initialized = False
26_agent_engine_init_lock = None # threading.Lock() lazy-created in init
29def init_agent_engine(app):
30 """Initialize the unified agent goal engine.
32 Idempotent: safe to call multiple times — only the first call does work.
33 The previous opt-in gate (`HEVOLVE_AGENT_ENGINE_ENABLED`) was added on
34 2026-04-19 to escape a 244s cold-boot stall caused by the import chain
35 `agent_baseline_service` → `helper` (the hart_intelligence top-level
36 `helper.py` module) racing with the Nunba `hartos-init` thread on
37 `from hart_intelligence import app`. Both threads enter
38 `_find_and_load → _lock_unlock_module → acquire`; CPython serialises
39 on the per-module import lock and one thread blocks indefinitely
40 because the other is mid-import of a parent package.
42 Fix (2026-04-28): keep the function callable unconditionally but make
43 the heavy `agent_baseline_service` + `agent_daemon` imports lazy, run
44 inside the function body (not at module load), and protected by an
45 idempotency guard so duplicate callers (Nunba's main.py
46 `_deferred_social_init` AND HARTOS's own `social/__init__.py`) cannot
47 double-bootstrap. The `helper` import inside `agent_baseline_service`
48 already has a fallback path, so it is allowed to run after
49 hart_intelligence is fully imported (hartos-init done) — we no longer
50 race.
51 """
52 global _agent_engine_initialized, _agent_engine_init_lock
54 if _agent_engine_init_lock is None:
55 import threading as _t
56 _agent_engine_init_lock = _t.Lock()
58 with _agent_engine_init_lock:
59 if _agent_engine_initialized:
60 logger.debug("Agent engine already initialised — skipping duplicate call")
61 return
62 # Mark BEFORE the heavy work so a second caller racing on the lock
63 # exits cleanly even if our own work is still in progress in this
64 # thread (we hold the lock for the duration; the second caller
65 # can't observe a half-initialised state).
66 _agent_engine_initialized = True
68 if os.environ.get('HEVOLVE_AGENT_ENGINE_ENABLED', 'false').lower() != 'true':
69 logger.info("Agent engine disabled (HEVOLVE_AGENT_ENGINE_ENABLED != true)")
70 return
72 # Register API blueprint
73 try:
74 bp = get_engine_blueprint()
75 app.register_blueprint(bp)
76 logger.info("Agent engine endpoints registered")
77 except Exception as e:
78 logger.warning(f"Agent engine blueprint registration failed: {e}")
79 return
81 # Bootstrap "HART Platform" product for self-marketing (idempotent)
82 product_id = None
83 try:
84 from integrations.social.models import get_db, Product, User
85 db = get_db()
86 existing = db.query(Product).filter_by(is_platform_product=True).first()
87 if not existing:
88 product = Product(
89 name='HART Platform',
90 description='Crowdsourced agentic intelligence platform — a gift from hevolve.ai',
91 tagline='Crowdsourced intelligence, human control',
92 product_url='https://hevolve.ai',
93 category='platform',
94 target_audience='Developers, businesses, and creators who want AI-powered automation',
95 unique_value_prop='96 expert agents, autonomous recipe-based execution, '
96 'cross-session memory, multi-channel distribution',
97 keywords_json=['AI', 'agents', 'automation', 'marketing', 'chatbot',
98 'autonomous', 'multi-agent', 'LLM'],
99 is_platform_product=True,
100 )
101 db.add(product)
102 db.flush()
103 product_id = str(product.id)
104 logger.info("Bootstrapped HART Platform product for self-marketing")
105 else:
106 product_id = str(existing.id)
108 # Bootstrap system agent for goal execution (idempotent)
109 sys_agent = db.query(User).filter_by(username='hevolve_system_agent').first()
110 if not sys_agent:
111 sys_agent = User(
112 username='hevolve_system_agent',
113 display_name='HART System Agent',
114 user_type='agent',
115 idle_compute_opt_in=True,
116 is_admin=False,
117 )
118 db.add(sys_agent)
119 db.flush()
120 logger.info("Bootstrapped system agent for goal execution")
122 # Seed bootstrap goals (idempotent)
123 from .goal_seeding import seed_bootstrap_goals
124 count = seed_bootstrap_goals(db, platform_product_id=product_id)
125 if count > 0:
126 logger.info(f"Seeded {count} bootstrap goal(s)")
128 db.commit()
129 db.close()
130 except Exception as e:
131 logger.debug(f"Platform product bootstrap skipped: {e}")
133 # Register commercial API blueprint
134 try:
135 from .commercial_api import commercial_api_bp
136 app.register_blueprint(commercial_api_bp)
137 logger.info("Commercial API endpoints registered")
138 except Exception as e:
139 logger.debug(f"Commercial API blueprint skipped: {e}")
141 # Register build distribution blueprint
142 try:
143 from .build_distribution import build_distribution_bp
144 app.register_blueprint(build_distribution_bp)
145 logger.info("Build distribution endpoints registered")
146 except Exception as e:
147 logger.debug(f"Build distribution blueprint skipped: {e}")
149 # Register regional host blueprint
150 try:
151 from integrations.social.api_regional_host import regional_host_bp
152 app.register_blueprint(regional_host_bp)
153 logger.info("Regional host endpoints registered")
154 except Exception as e:
155 logger.debug(f"Regional host blueprint skipped: {e}")
157 # Heavy imports (`agent_baseline_service` → `helper` from
158 # hart_intelligence top-level; `agent_daemon` → many tools chain) run
159 # in a deferred thread. Reason: when called from Nunba's
160 # `_deferred_social_init`, the `hartos-init` thread is concurrently
161 # running `from hart_intelligence import app`, which acquires the
162 # top-level `hart_intelligence` package import lock. If this thread
163 # tries to import `helper` (a module inside hart_intelligence) at the
164 # same instant, CPython's per-module lock serialises and one of the
165 # two threads blocks indefinitely (hartos-init holds the package
166 # init in progress; we wait for the same lock to do `from helper
167 # import PROMPTS_DIR`). Smoking gun: server.log stack at
168 # `_find_and_load → _lock_unlock_module → acquire` from inside
169 # `init_agent_engine` line 119.
170 #
171 # Solution: spawn a small worker thread that polls
172 # `routes.hartos_backend_adapter._hartos_initialized` (set True by
173 # the hartos-init thread when its `from hart_intelligence import app`
174 # finishes, success OR failure), and only THEN do the heavy imports.
175 # The Flask app + blueprints + bootstrap above have already been
176 # registered synchronously, so the admin dashboard endpoint is live
177 # immediately; the daemon and AgentBaselineAdapter come online a few
178 # seconds later, exactly like the existing `_deferred_social_init`
179 # pattern.
180 def _finish_init_deferred():
181 import time as _t
182 # Wait up to 10 minutes for hartos-init to settle. If it never
183 # settles (Tier-1 retry budget exhausted, network down, etc.),
184 # we still proceed because by then the import lock contention is
185 # gone — the hartos-init thread has either succeeded or given up.
186 _start = _t.time()
187 _max_wait = 600
188 while _t.time() - _start < _max_wait:
189 try:
190 from routes.hartos_backend_adapter import _hartos_initialized
191 if _hartos_initialized:
192 break
193 except Exception:
194 # Not running inside Nunba — no hartos-init thread to wait
195 # for. Proceed immediately.
196 break
197 _t.sleep(1)
199 # Register AgentBaselineAdapter with benchmark registry
200 try:
201 from .benchmark_registry import get_benchmark_registry
202 from .agent_baseline_service import AgentBaselineAdapter
203 registry = get_benchmark_registry()
204 registry.register_benchmark(AgentBaselineAdapter())
205 logger.info("AgentBaselineAdapter registered with benchmark registry")
206 except Exception as e:
207 logger.debug(f"AgentBaselineAdapter registration skipped: {e}")
209 # Start background daemon
210 try:
211 from .agent_daemon import agent_daemon
212 agent_daemon.start()
213 logger.info("Agent engine daemon started")
214 except Exception as e:
215 logger.debug(f"Agent engine daemon start skipped: {e}")
217 # Start distributed worker loop (claims tasks from shared Redis)
218 try:
219 from integrations.distributed_agent.worker_loop import worker_loop
220 worker_loop.start()
221 except Exception as e:
222 logger.debug(f"Distributed worker loop start skipped: {e}")
224 import threading as _t_mod
225 _t_mod.Thread(target=_finish_init_deferred, daemon=True,
226 name='agent-engine-finish').start()
227 logger.info("Agent engine deferred-finish thread spawned (waits for hartos-init)")