algo-cli-runtime 0.14.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. algo_cli/__init__.py +3 -0
  2. algo_cli/__main__.py +7 -0
  3. algo_cli/_internal/__init__.py +12 -0
  4. algo_cli/_internal/policy_chain.py +259 -0
  5. algo_cli/action_registry.py +1047 -0
  6. algo_cli/agent_blocks.py +550 -0
  7. algo_cli/agent_pipeline.py +1457 -0
  8. algo_cli/agent_threads.py +308 -0
  9. algo_cli/animations.py +316 -0
  10. algo_cli/cache_admission.py +209 -0
  11. algo_cli/capability_mask.py +66 -0
  12. algo_cli/chat_protocol.py +116 -0
  13. algo_cli/chatgpt_auth.py +510 -0
  14. algo_cli/chatgpt_client.py +657 -0
  15. algo_cli/code_rag.py +479 -0
  16. algo_cli/config.py +651 -0
  17. algo_cli/context_budget.py +679 -0
  18. algo_cli/credential_helpers.py +315 -0
  19. algo_cli/deliberation.py +29 -0
  20. algo_cli/display.py +1470 -0
  21. algo_cli/evals/__init__.py +21 -0
  22. algo_cli/evals/algorithm_effectiveness.py +560 -0
  23. algo_cli/evals/competitive_harness_rating.py +702 -0
  24. algo_cli/evals/cot_quality.py +220 -0
  25. algo_cli/evals/harness_retrieval_benchmark.py +401 -0
  26. algo_cli/evals/performance_regression.py +136 -0
  27. algo_cli/evals/scorecard_grading.py +308 -0
  28. algo_cli/evals/session_distribution.py +84 -0
  29. algo_cli/execution_guardrails.py +806 -0
  30. algo_cli/extensions_manifest.py +84 -0
  31. algo_cli/git_evidence.py +227 -0
  32. algo_cli/google_workspace.py +407 -0
  33. algo_cli/google_workspace_auth.py +523 -0
  34. algo_cli/harness.py +2587 -0
  35. algo_cli/identity.py +557 -0
  36. algo_cli/index_compute_lab.py +228 -0
  37. algo_cli/inference_harness.py +70 -0
  38. algo_cli/intelligence/__init__.py +1103 -0
  39. algo_cli/intelligence/acrobat_config.py +307 -0
  40. algo_cli/intelligence/acrobat_manifests.py +338 -0
  41. algo_cli/intelligence/acrobat_models.py +195 -0
  42. algo_cli/intelligence/acrobat_pipeline.py +295 -0
  43. algo_cli/intelligence/acrobat_runtime.py +302 -0
  44. algo_cli/intelligence/acrobat_security.py +261 -0
  45. algo_cli/intelligence/acrobat_workflows.py +226 -0
  46. algo_cli/intelligence/actionability.py +165 -0
  47. algo_cli/intelligence/adversarial_audit.py +136 -0
  48. algo_cli/intelligence/agent_arena.py +92 -0
  49. algo_cli/intelligence/agent_benchmark.py +236 -0
  50. algo_cli/intelligence/agent_runtime.py +171 -0
  51. algo_cli/intelligence/agents_as_tools.py +70 -0
  52. algo_cli/intelligence/artifact_binding.py +80 -0
  53. algo_cli/intelligence/autonomous_engineer.py +1976 -0
  54. algo_cli/intelligence/backpressure.py +99 -0
  55. algo_cli/intelligence/bloom_filter.py +186 -0
  56. algo_cli/intelligence/bonferroni.py +66 -0
  57. algo_cli/intelligence/boundary_compaction.py +98 -0
  58. algo_cli/intelligence/catalog_verifier.py +172 -0
  59. algo_cli/intelligence/cavecrew.py +118 -0
  60. algo_cli/intelligence/changelog.py +176 -0
  61. algo_cli/intelligence/checkpoint_resume.py +92 -0
  62. algo_cli/intelligence/circuit_breaker.py +88 -0
  63. algo_cli/intelligence/clarification_gate.py +101 -0
  64. algo_cli/intelligence/code_graph.py +180 -0
  65. algo_cli/intelligence/coderank.py +97 -0
  66. algo_cli/intelligence/consistent_hash.py +150 -0
  67. algo_cli/intelligence/consortium_synthesis.py +139 -0
  68. algo_cli/intelligence/construction/__init__.py +241 -0
  69. algo_cli/intelligence/construction/common.py +273 -0
  70. algo_cli/intelligence/construction/documents.py +496 -0
  71. algo_cli/intelligence/construction/labor_units.py +1395 -0
  72. algo_cli/intelligence/construction/payments.py +470 -0
  73. algo_cli/intelligence/construction/risk.py +784 -0
  74. algo_cli/intelligence/content_extractor.py +132 -0
  75. algo_cli/intelligence/context_adaptive.py +102 -0
  76. algo_cli/intelligence/context_ops.py +95 -0
  77. algo_cli/intelligence/count_min.py +145 -0
  78. algo_cli/intelligence/cow_state.py +103 -0
  79. algo_cli/intelligence/critic_loop.py +119 -0
  80. algo_cli/intelligence/cross_source.py +113 -0
  81. algo_cli/intelligence/daemon_mode.py +99 -0
  82. algo_cli/intelligence/dag_orchestration.py +151 -0
  83. algo_cli/intelligence/deep_research.py +155 -0
  84. algo_cli/intelligence/degenerate_detector.py +78 -0
  85. algo_cli/intelligence/delta_report.py +92 -0
  86. algo_cli/intelligence/discovery_event_log.py +92 -0
  87. algo_cli/intelligence/document_ingest.py +298 -0
  88. algo_cli/intelligence/dual_layer_validate.py +151 -0
  89. algo_cli/intelligence/echo_fidelity.py +73 -0
  90. algo_cli/intelligence/ema_tuning.py +104 -0
  91. algo_cli/intelligence/event_log.py +92 -0
  92. algo_cli/intelligence/evidence_graph.py +114 -0
  93. algo_cli/intelligence/extension_host.py +162 -0
  94. algo_cli/intelligence/extension_manifest.py +115 -0
  95. algo_cli/intelligence/falsification_suite.py +178 -0
  96. algo_cli/intelligence/finance/__init__.py +169 -0
  97. algo_cli/intelligence/finance/anomalies.py +135 -0
  98. algo_cli/intelligence/finance/ap_ar.py +351 -0
  99. algo_cli/intelligence/finance/cash.py +162 -0
  100. algo_cli/intelligence/finance/close.py +332 -0
  101. algo_cli/intelligence/finance/common.py +244 -0
  102. algo_cli/intelligence/finance/construction.py +135 -0
  103. algo_cli/intelligence/finance/controls.py +172 -0
  104. algo_cli/intelligence/finance/evidence.py +119 -0
  105. algo_cli/intelligence/finance/exceptions.py +157 -0
  106. algo_cli/intelligence/finance/reconciliations.py +254 -0
  107. algo_cli/intelligence/finance/revenue.py +109 -0
  108. algo_cli/intelligence/finance/tax.py +74 -0
  109. algo_cli/intelligence/finance/workpapers.py +111 -0
  110. algo_cli/intelligence/finding_record.py +120 -0
  111. algo_cli/intelligence/flow_dag.py +267 -0
  112. algo_cli/intelligence/gatherer.py +223 -0
  113. algo_cli/intelligence/golden_master.py +98 -0
  114. algo_cli/intelligence/graph_rag.py +195 -0
  115. algo_cli/intelligence/group_chat.py +143 -0
  116. algo_cli/intelligence/hash_dedup.py +145 -0
  117. algo_cli/intelligence/hyperloglog.py +128 -0
  118. algo_cli/intelligence/incremental_index.py +316 -0
  119. algo_cli/intelligence/index_store.py +16 -0
  120. algo_cli/intelligence/iteration_plan.py +133 -0
  121. algo_cli/intelligence/kernel_plugins.py +167 -0
  122. algo_cli/intelligence/lesson_catalog.py +135 -0
  123. algo_cli/intelligence/llm_fallback.py +169 -0
  124. algo_cli/intelligence/log2_histogram.py +267 -0
  125. algo_cli/intelligence/lsp_integration.py +147 -0
  126. algo_cli/intelligence/memory_evolution.py +117 -0
  127. algo_cli/intelligence/minhash_lsh.py +182 -0
  128. algo_cli/intelligence/multi_model_score.py +174 -0
  129. algo_cli/intelligence/multi_tier_grade.py +211 -0
  130. algo_cli/intelligence/negative_controls.py +113 -0
  131. algo_cli/intelligence/numeric_clamp.py +63 -0
  132. algo_cli/intelligence/occ_editor.py +66 -0
  133. algo_cli/intelligence/output_normalize.py +112 -0
  134. algo_cli/intelligence/parallel_delegation.py +98 -0
  135. algo_cli/intelligence/parallel_fanout.py +104 -0
  136. algo_cli/intelligence/permission_modes.py +105 -0
  137. algo_cli/intelligence/pre_push_gate.py +68 -0
  138. algo_cli/intelligence/prefetch.py +171 -0
  139. algo_cli/intelligence/process_framework.py +217 -0
  140. algo_cli/intelligence/project_graph.py +387 -0
  141. algo_cli/intelligence/query_expansion.py +146 -0
  142. algo_cli/intelligence/ralph_loop.py +117 -0
  143. algo_cli/intelligence/rate_limiter.py +153 -0
  144. algo_cli/intelligence/refactor_transaction.py +94 -0
  145. algo_cli/intelligence/research_workspace.py +108 -0
  146. algo_cli/intelligence/retraction_ledger.py +72 -0
  147. algo_cli/intelligence/saga_pattern.py +88 -0
  148. algo_cli/intelligence/session_fork.py +100 -0
  149. algo_cli/intelligence/shadow_editor.py +67 -0
  150. algo_cli/intelligence/shell_session.py +213 -0
  151. algo_cli/intelligence/source_registry.py +143 -0
  152. algo_cli/intelligence/spawn_scales.py +99 -0
  153. algo_cli/intelligence/stat_stability.py +104 -0
  154. algo_cli/intelligence/structural_validator.py +148 -0
  155. algo_cli/intelligence/subagent_spawner.py +111 -0
  156. algo_cli/intelligence/symmetric_verify.py +70 -0
  157. algo_cli/intelligence/task_classifier.py +129 -0
  158. algo_cli/intelligence/team_execution.py +122 -0
  159. algo_cli/intelligence/tiered_access.py +121 -0
  160. algo_cli/intelligence/utility_registry.py +159 -0
  161. algo_cli/intuition_engine.py +560 -0
  162. algo_cli/intuition_injector.py +82 -0
  163. algo_cli/kernels/__init__.py +5 -0
  164. algo_cli/kernels/manifest.py +763 -0
  165. algo_cli/main.py +3903 -0
  166. algo_cli/memory_candidates.py +541 -0
  167. algo_cli/memory_echo_veil.py +394 -0
  168. algo_cli/memory_runtime.py +112 -0
  169. algo_cli/model_info.py +548 -0
  170. algo_cli/model_profile.py +160 -0
  171. algo_cli/model_routing.py +74 -0
  172. algo_cli/oneshot.py +331 -0
  173. algo_cli/perf_telemetry.py +389 -0
  174. algo_cli/plugins.py +245 -0
  175. algo_cli/private_event_store.py +654 -0
  176. algo_cli/quantization/__init__.py +24 -0
  177. algo_cli/quantization/lloyd_max.py +98 -0
  178. algo_cli/quantization/turbo_quant.py +308 -0
  179. algo_cli/reasoning/__init__.py +46 -0
  180. algo_cli/reasoning/combinatorial.py +356 -0
  181. algo_cli/reasoning/graph_of_thought.py +297 -0
  182. algo_cli/reasoning/mcts.py +220 -0
  183. algo_cli/reasoning/neuro_symbolic.py +250 -0
  184. algo_cli/reasoning/react.py +246 -0
  185. algo_cli/reasoning/reflexion.py +225 -0
  186. algo_cli/reasoning/tree_of_thought.py +241 -0
  187. algo_cli/reasoning_bridge.py +150 -0
  188. algo_cli/reconciliation.py +284 -0
  189. algo_cli/reflex.py +385 -0
  190. algo_cli/resources/docs/ALGO.md +13958 -0
  191. algo_cli/resources/docs/algo-cli-algorithm-evidence-contract.md +60 -0
  192. algo_cli/resources/docs/algo-cli-execution-verification-contract.md +59 -0
  193. algo_cli/resources/docs/algo-cli-memory-lifecycle-contract.md +72 -0
  194. algo_cli/resources/docs/harness-extension-cleanup-recommendation.md +41 -0
  195. algo_cli/resources/docs/index-compute-lab-integration.md +32 -0
  196. algo_cli/resources/docs/inference-harness-loop-blueprint-2026-06.md +55 -0
  197. algo_cli/resources/docs/main-split-map.md +35 -0
  198. algo_cli/resources/docs/privacy-and-context.md +48 -0
  199. algo_cli/resources/docs/reflex-loop-v0.2.md +354 -0
  200. algo_cli/resources/skills/README.md +26 -0
  201. algo_cli/resources/skills/algo-cli.md +59 -0
  202. algo_cli/resources/skills/edit-file-precision.md +49 -0
  203. algo_cli/resources/skills/harness-search-first.md +47 -0
  204. algo_cli/resources/skills/memory-recall-ritual.md +51 -0
  205. algo_cli/resources/skills/qol-algorithms.md +224 -0
  206. algo_cli/resources/skills/smart-error-recovery.md +56 -0
  207. algo_cli/resources/skills/tool-selection-cheatsheet.md +65 -0
  208. algo_cli/retrieval_algorithms.py +127 -0
  209. algo_cli/runtime_qos.py +236 -0
  210. algo_cli/runtime_services.py +320 -0
  211. algo_cli/session_commands.py +95 -0
  212. algo_cli/session_mode.py +113 -0
  213. algo_cli/skills.py +430 -0
  214. algo_cli/slash_dispatch.py +1265 -0
  215. algo_cli/small_context.py +206 -0
  216. algo_cli/spawn_budget.py +89 -0
  217. algo_cli/task_ledger.py +84 -0
  218. algo_cli/task_router.py +197 -0
  219. algo_cli/tool_context.py +94 -0
  220. algo_cli/tool_contract.py +99 -0
  221. algo_cli/tool_policy.py +357 -0
  222. algo_cli/tool_runtime.py +647 -0
  223. algo_cli/tools.py +3056 -0
  224. algo_cli/url_scheme.py +174 -0
  225. algo_cli/verify.py +154 -0
  226. algo_cli/version_manifest.py +178 -0
  227. algo_cli/vision_screenshot_verify.py +76 -0
  228. algo_cli/workspace_resolver.py +68 -0
  229. algo_cli/x_account.py +209 -0
  230. algo_cli/xai_auth.py +374 -0
  231. algo_cli/xai_client.py +600 -0
  232. algo_cli_runtime-0.14.0.dist-info/METADATA +369 -0
  233. algo_cli_runtime-0.14.0.dist-info/RECORD +237 -0
  234. algo_cli_runtime-0.14.0.dist-info/WHEEL +4 -0
  235. algo_cli_runtime-0.14.0.dist-info/entry_points.txt +3 -0
  236. algo_cli_runtime-0.14.0.dist-info/licenses/LICENSE +21 -0
  237. ollama_cli/__init__.py +67 -0
@@ -0,0 +1,1976 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Autonomous Engineer v1.0 — Foundation (Phase 1, hardened)
4
+
5
+ Single-file autonomous engineering runtime.
6
+
7
+ Core: Scheduler + Workers + Memory (SQLite) + Execution Sandbox + LLM Router
8
+
9
+ Hardening notes (see CHANGELOG block at bottom of file for the full list):
10
+ - Fixed the shebang.
11
+ - ExecutionSandbox now enforces a real timeout via subprocess isolation,
12
+ with optional POSIX memory limits. This is *isolation*, not a security
13
+ boundary — read the class docstring before running untrusted code.
14
+ - MemoryEngine now applies WAL, enforces foreign keys, is thread-safe
15
+ (lock-guarded writes, check_same_thread=False), and exposes close().
16
+ - Scheduler now creates real session/task rows so the FK chain is valid.
17
+ - Pruned unused imports.
18
+ """
19
+
20
+ import ast
21
+ import json
22
+ import logging
23
+ import os
24
+ import re
25
+ import signal
26
+ import sqlite3
27
+ import tempfile
28
+ import statistics
29
+ import subprocess
30
+ import sys
31
+ import threading
32
+ import time
33
+ import uuid
34
+ from dataclasses import dataclass, asdict
35
+ from pathlib import Path
36
+ from typing import Any, Dict, Iterator, List, Optional
37
+
38
+ # Optional deps
39
+ try:
40
+ import ollama
41
+ HAS_OLLAMA = True
42
+ except ImportError:
43
+ HAS_OLLAMA = False
44
+
45
+ # POSIX-only resource limits (available on Linux/WSL2, not on native Windows).
46
+ try:
47
+ import resource # type: ignore
48
+ HAS_RESOURCE = True
49
+ except ImportError:
50
+ resource = None # type: ignore
51
+ HAS_RESOURCE = False
52
+
53
+
54
+ # =============================================================================
55
+ # LOGGING
56
+ # =============================================================================
57
+ # Library pattern: attach a NullHandler so importing this module never emits
58
+ # output on its own. Call setup_logging() (or configure the root logger) to see
59
+ # messages. Diagnostics go through this logger; the CLI keeps actual *results*
60
+ # on stdout via print(), so they stay pipeable while chatter goes to stderr.
61
+ logger = logging.getLogger("autonomous_engineer")
62
+ logger.addHandler(logging.NullHandler())
63
+
64
+
65
+ def setup_logging(level: str = "INFO",
66
+ log_file: Optional[str] = None) -> logging.Logger:
67
+ """Configure the package logger. Idempotent — safe to call repeatedly."""
68
+ lg = logging.getLogger("autonomous_engineer")
69
+ lg.setLevel(getattr(logging, str(level).upper(), logging.INFO))
70
+ # Drop any non-Null handlers from a previous call to avoid duplicates.
71
+ for h in list(lg.handlers):
72
+ if not isinstance(h, logging.NullHandler):
73
+ lg.removeHandler(h)
74
+ fmt = logging.Formatter(
75
+ "%(asctime)s %(levelname)-7s %(name)s: %(message)s",
76
+ datefmt="%H:%M:%S",
77
+ )
78
+ stream = logging.StreamHandler() # stderr
79
+ stream.setFormatter(fmt)
80
+ lg.addHandler(stream)
81
+ if log_file:
82
+ fileh = logging.FileHandler(log_file, encoding="utf-8")
83
+ fileh.setFormatter(fmt)
84
+ lg.addHandler(fileh)
85
+ lg.propagate = False
86
+ return lg
87
+
88
+
89
+ # =============================================================================
90
+ # CONFIGURATION
91
+ # =============================================================================
92
+ @dataclass
93
+ class Config:
94
+ """Single source of truth for configuration."""
95
+ db_path: str = "autonomous_engineer.db"
96
+ workspace: str = "./workspace"
97
+ default_model: str = "llama3.1"
98
+ max_workers: int = 4
99
+ default_timeout: float = 30.0
100
+ benchmark_repeats: int = 5
101
+ benchmark_warmup: int = 2
102
+ sqlite_journal_mode: str = "WAL"
103
+ sandbox_memory_limit_mb: Optional[int] = 512 # None = no limit
104
+ require_correctness_test: bool = True
105
+ benchmark_target_sample_time: float = 0.001
106
+ benchmark_max_loops: int = 100_000
107
+ os_sandbox_command: Optional[List[str]] = None
108
+
109
+ def save(self, path: str = "config.json") -> None:
110
+ Path(path).write_text(json.dumps(asdict(self), indent=2),
111
+ encoding="utf-8")
112
+
113
+ @classmethod
114
+ def load(cls, path: str = "config.json") -> "Config":
115
+ if Path(path).exists():
116
+ data = json.loads(Path(path).read_text(encoding="utf-8"))
117
+ return cls(**data)
118
+ return cls()
119
+
120
+
121
+ # =============================================================================
122
+ # MEMORY ENGINE (SQLite)
123
+ # =============================================================================
124
+ class MemoryEngine:
125
+ """Persistent memory with SQLite. ACID, indexed, portable.
126
+
127
+ Thread-safety: the connection is opened with check_same_thread=False and
128
+ all writes are serialized through a single lock. This is the simplest
129
+ correct model for the Phase-1 worker pool. If write throughput ever
130
+ becomes the bottleneck, move to a connection-per-thread or a writer queue.
131
+ """
132
+
133
+ def __init__(self, db_path: str = "autonomous_engineer.db",
134
+ journal_mode: str = "WAL"):
135
+ self.db_path = db_path
136
+ self._lock = threading.RLock()
137
+ self._transaction_depth = 0
138
+ self._transaction_rollback_only = False
139
+ self.conn = sqlite3.connect(db_path, check_same_thread=False)
140
+ self.conn.row_factory = sqlite3.Row
141
+ self._configure(journal_mode)
142
+ self._init_schema()
143
+
144
+ def _configure(self, journal_mode: str) -> None:
145
+ """Apply validated SQLite pragmas."""
146
+ mode = str(journal_mode or "WAL").upper()
147
+ valid_modes = {"DELETE", "TRUNCATE", "PERSIST", "MEMORY", "WAL", "OFF"}
148
+ if mode not in valid_modes:
149
+ raise ValueError(f"invalid sqlite_journal_mode: {journal_mode!r}")
150
+
151
+ cursor = self.conn.cursor()
152
+ # WAL improves concurrent read/write behavior; honored from Config.
153
+ cursor.execute(f"PRAGMA journal_mode={mode};")
154
+ # Referential integrity is OFF by default in SQLite — turn it on so the
155
+ # session -> task -> attempt chain is actually enforced.
156
+ cursor.execute("PRAGMA foreign_keys=ON;")
157
+ cursor.execute("PRAGMA busy_timeout=5000;")
158
+ if mode == "WAL":
159
+ cursor.execute("PRAGMA synchronous=NORMAL;")
160
+ self.conn.commit()
161
+
162
+ def _init_schema(self) -> None:
163
+ """Core schema per spec (expandable)."""
164
+ cursor = self.conn.cursor()
165
+ cursor.execute("""
166
+ CREATE TABLE IF NOT EXISTS sessions (
167
+ id INTEGER PRIMARY KEY,
168
+ started_at TEXT DEFAULT CURRENT_TIMESTAMP,
169
+ goal TEXT,
170
+ strategy TEXT,
171
+ status TEXT DEFAULT 'running'
172
+ )
173
+ """)
174
+ cursor.execute("""
175
+ CREATE TABLE IF NOT EXISTS tasks (
176
+ id INTEGER PRIMARY KEY,
177
+ session_id INTEGER,
178
+ name TEXT,
179
+ status TEXT DEFAULT 'pending',
180
+ dependencies TEXT, -- JSON array
181
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
182
+ FOREIGN KEY(session_id) REFERENCES sessions(id)
183
+ )
184
+ """)
185
+ cursor.execute("""
186
+ CREATE TABLE IF NOT EXISTS attempts (
187
+ id INTEGER PRIMARY KEY,
188
+ task_id INTEGER,
189
+ worker_name TEXT,
190
+ code_snippet TEXT,
191
+ success BOOLEAN,
192
+ execution_time REAL,
193
+ score_vector TEXT, -- JSON {perf: 0.95, correctness: 1.0, ...}
194
+ reflection TEXT,
195
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
196
+ FOREIGN KEY(task_id) REFERENCES tasks(id)
197
+ )
198
+ """)
199
+ cursor.execute("""
200
+ CREATE TABLE IF NOT EXISTS benchmarks (
201
+ id INTEGER PRIMARY KEY,
202
+ attempt_id INTEGER,
203
+ median_time REAL,
204
+ std_dev REAL,
205
+ repeats INTEGER,
206
+ confidence REAL,
207
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
208
+ FOREIGN KEY(attempt_id) REFERENCES attempts(id)
209
+ )
210
+ """)
211
+ cursor.execute("""
212
+ CREATE TABLE IF NOT EXISTS reflections (
213
+ id INTEGER PRIMARY KEY,
214
+ attempt_id INTEGER,
215
+ what_happened TEXT,
216
+ why TEXT,
217
+ evidence TEXT,
218
+ lessons TEXT, -- JSON
219
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
220
+ FOREIGN KEY(attempt_id) REFERENCES attempts(id)
221
+ )
222
+ """)
223
+ cursor.execute("""
224
+ CREATE TABLE IF NOT EXISTS repositories (
225
+ id INTEGER PRIMARY KEY,
226
+ path TEXT UNIQUE,
227
+ last_updated TEXT,
228
+ git_commit TEXT
229
+ )
230
+ """)
231
+ cursor.execute("""
232
+ CREATE TABLE IF NOT EXISTS symbols (
233
+ id INTEGER PRIMARY KEY,
234
+ repo_id INTEGER,
235
+ file_path TEXT,
236
+ name TEXT,
237
+ type TEXT, -- function, class, etc.
238
+ calls TEXT, -- JSON
239
+ hash TEXT,
240
+ FOREIGN KEY(repo_id) REFERENCES repositories(id)
241
+ )
242
+ """)
243
+ cursor.execute("""
244
+ CREATE TABLE IF NOT EXISTS workers (
245
+ name TEXT PRIMARY KEY,
246
+ priority INTEGER DEFAULT 100,
247
+ capabilities TEXT -- JSON
248
+ )
249
+ """)
250
+ # Indexes on foreign keys / common lookup columns. Cheap to create, and
251
+ # they matter as soon as the read path runs over a non-trivial history.
252
+ for stmt in (
253
+ "CREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_id)",
254
+ "CREATE INDEX IF NOT EXISTS idx_attempts_task ON attempts(task_id)",
255
+ "CREATE INDEX IF NOT EXISTS idx_attempts_worker ON attempts(worker_name)",
256
+ "CREATE INDEX IF NOT EXISTS idx_bench_attempt ON benchmarks(attempt_id)",
257
+ "CREATE INDEX IF NOT EXISTS idx_reflect_attempt ON reflections(attempt_id)",
258
+ "CREATE INDEX IF NOT EXISTS idx_symbols_repo ON symbols(repo_id)",
259
+ "CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name)",
260
+ ):
261
+ cursor.execute(stmt)
262
+ self.conn.commit()
263
+ logger.info("[OK] MemoryEngine initialized: %s", self.db_path)
264
+
265
+ def _commit_now(self) -> None:
266
+ """Commit immediately; split out so tests can count real commits."""
267
+ self.conn.commit()
268
+
269
+ def _rollback_now(self) -> None:
270
+ """Rollback immediately; split out so tests can count rollbacks."""
271
+ self.conn.rollback()
272
+
273
+ def _commit_if_needed(self) -> None:
274
+ """Commit single writes, but defer inside MemoryEngine.batch()."""
275
+ if self._transaction_depth == 0:
276
+ self._commit_now()
277
+
278
+ def batch(self) -> "_MemoryBatch":
279
+ """Batch multiple writes into one SQLite transaction.
280
+
281
+ Nested batches are safe: only the outermost context opens/closes the
282
+ transaction. Any exception in a nested batch marks the outer transaction
283
+ rollback-only so caught inner errors cannot accidentally commit partial
284
+ state.
285
+ """
286
+ return _MemoryBatch(self)
287
+
288
+ # ---- write helpers (all lock-guarded) ----
289
+
290
+ def start_session(self, goal: str, strategy: Optional[str] = None) -> int:
291
+ with self._lock:
292
+ cursor = self.conn.cursor()
293
+ cursor.execute(
294
+ "INSERT INTO sessions (goal, strategy) VALUES (?, ?)",
295
+ (goal, strategy),
296
+ )
297
+ self._commit_if_needed()
298
+ return cursor.lastrowid
299
+
300
+ def _dependencies_satisfied_locked(self, dependencies: List[int]) -> bool:
301
+ """Return True only when every dependency task exists and completed."""
302
+ if not dependencies:
303
+ return True
304
+ placeholders = ",".join("?" for _ in dependencies)
305
+ cur = self.conn.execute(
306
+ f"SELECT id, status FROM tasks WHERE id IN ({placeholders})",
307
+ tuple(dependencies),
308
+ )
309
+ statuses = {int(row["id"]): row["status"] for row in cur.fetchall()}
310
+ return all(statuses.get(int(dep)) == "completed" for dep in dependencies)
311
+
312
+ def create_task(self, session_id: int, name: str,
313
+ dependencies: Optional[List[int]] = None) -> int:
314
+ deps = [int(dep) for dep in (dependencies or [])]
315
+ with self._lock:
316
+ cursor = self.conn.cursor()
317
+ status = (
318
+ "running" if self._dependencies_satisfied_locked(deps)
319
+ else "blocked"
320
+ )
321
+ cursor.execute(
322
+ "INSERT INTO tasks (session_id, name, status, dependencies) "
323
+ "VALUES (?, ?, ?, ?)",
324
+ (session_id, name, status, json.dumps(deps)),
325
+ )
326
+ self._commit_if_needed()
327
+ return cursor.lastrowid
328
+
329
+ def log_attempt(self, task_id: int, worker: str, data: Dict) -> int:
330
+ with self._lock:
331
+ cursor = self.conn.cursor()
332
+ cursor.execute("""
333
+ INSERT INTO attempts
334
+ (task_id, worker_name, code_snippet, success,
335
+ execution_time, score_vector, reflection)
336
+ VALUES (?, ?, ?, ?, ?, ?, ?)
337
+ """, (
338
+ task_id, worker, data.get("code"), data.get("success"),
339
+ data.get("time"), json.dumps(data.get("score_vector", {})),
340
+ data.get("reflection"),
341
+ ))
342
+ self._commit_if_needed()
343
+ return cursor.lastrowid
344
+
345
+ def log_benchmark(self, attempt_id: int, stats: Dict) -> int:
346
+ with self._lock:
347
+ cursor = self.conn.cursor()
348
+ cursor.execute("""
349
+ INSERT INTO benchmarks
350
+ (attempt_id, median_time, std_dev, repeats, confidence)
351
+ VALUES (?, ?, ?, ?, ?)
352
+ """, (
353
+ attempt_id, stats.get("median"), stats.get("stdev"),
354
+ stats.get("repeats"), stats.get("confidence"),
355
+ ))
356
+ self._commit_if_needed()
357
+ return cursor.lastrowid
358
+
359
+ def register_worker(self, name: str, priority: int,
360
+ capabilities: List[str]) -> None:
361
+ with self._lock:
362
+ cursor = self.conn.cursor()
363
+ cursor.execute(
364
+ "INSERT INTO workers (name, priority, capabilities) "
365
+ "VALUES (?, ?, ?) "
366
+ "ON CONFLICT(name) DO UPDATE SET "
367
+ "priority=excluded.priority, "
368
+ "capabilities=excluded.capabilities",
369
+ (name, priority, json.dumps(capabilities)),
370
+ )
371
+ self._commit_if_needed()
372
+
373
+ def complete_task(self, task_id: int) -> None:
374
+ with self._lock:
375
+ cursor = self.conn.cursor()
376
+ cursor.execute(
377
+ "UPDATE tasks SET status='completed' WHERE id = ?",
378
+ (task_id,))
379
+ self._commit_if_needed()
380
+
381
+ def fail_task(self, task_id: int) -> None:
382
+ with self._lock:
383
+ cursor = self.conn.cursor()
384
+ cursor.execute(
385
+ "UPDATE tasks SET status='failed' WHERE id = ?",
386
+ (task_id,))
387
+ self._commit_if_needed()
388
+
389
+ def complete_session(self, session_id: int) -> None:
390
+ with self._lock:
391
+ cursor = self.conn.cursor()
392
+ cursor.execute(
393
+ "UPDATE sessions SET status='completed' WHERE id = ?",
394
+ (session_id,))
395
+ self._commit_if_needed()
396
+
397
+ def fail_session(self, session_id: int) -> None:
398
+ with self._lock:
399
+ cursor = self.conn.cursor()
400
+ cursor.execute(
401
+ "UPDATE sessions SET status='failed' WHERE id = ?",
402
+ (session_id,))
403
+ self._commit_if_needed()
404
+
405
+ def block_session(self, session_id: int) -> None:
406
+ with self._lock:
407
+ cursor = self.conn.cursor()
408
+ cursor.execute(
409
+ "UPDATE sessions SET status='blocked' WHERE id = ?",
410
+ (session_id,))
411
+ self._commit_if_needed()
412
+
413
+ # ---- read helpers (lock-guarded; single shared connection) ----
414
+ # Reads are serialized through the same lock as writes because the
415
+ # connection is shared across threads. WAL's reader/writer concurrency only
416
+ # pays off with separate connections — the upgrade path if reads ever
417
+ # become hot is a connection-per-thread pool.
418
+
419
+ @staticmethod
420
+ def _rows(cursor) -> List[Dict]:
421
+ return [dict(r) for r in cursor.fetchall()]
422
+
423
+ def get_session(self, session_id: int) -> Optional[Dict]:
424
+ with self._lock:
425
+ cur = self.conn.execute(
426
+ "SELECT * FROM sessions WHERE id = ?", (session_id,))
427
+ row = cur.fetchone()
428
+ return dict(row) if row else None
429
+
430
+ def get_task(self, task_id: int) -> Optional[Dict]:
431
+ with self._lock:
432
+ cur = self.conn.execute(
433
+ "SELECT * FROM tasks WHERE id = ?", (task_id,))
434
+ row = cur.fetchone()
435
+ return dict(row) if row else None
436
+
437
+ def get_tasks(self, session_id: int) -> List[Dict]:
438
+ with self._lock:
439
+ cur = self.conn.execute(
440
+ "SELECT * FROM tasks WHERE session_id = ? ORDER BY id",
441
+ (session_id,))
442
+ return self._rows(cur)
443
+
444
+ def get_attempts(self, task_id: int) -> List[Dict]:
445
+ with self._lock:
446
+ cur = self.conn.execute(
447
+ "SELECT * FROM attempts WHERE task_id = ? ORDER BY id",
448
+ (task_id,))
449
+ return self._rows(cur)
450
+
451
+ def best_attempt(self, task_id: int) -> Optional[Dict]:
452
+ """Fastest SUCCESSFUL attempt for a task — the selection primitive.
453
+
454
+ Orders by measured median time when a benchmark row exists, else by the
455
+ attempt's own execution_time. Incorrect candidates are success=0 and so
456
+ are excluded automatically.
457
+ """
458
+ with self._lock:
459
+ cur = self.conn.execute("""
460
+ SELECT a.*, b.median_time, b.confidence
461
+ FROM attempts a
462
+ LEFT JOIN benchmarks b ON b.attempt_id = a.id
463
+ WHERE a.task_id = ? AND a.success = 1
464
+ ORDER BY COALESCE(b.median_time, a.execution_time) ASC
465
+ LIMIT 1
466
+ """, (task_id,))
467
+ row = cur.fetchone()
468
+ return dict(row) if row else None
469
+
470
+ def recent_attempts(self, limit: int = 10) -> List[Dict]:
471
+ with self._lock:
472
+ cur = self.conn.execute(
473
+ "SELECT * FROM attempts ORDER BY id DESC LIMIT ?", (limit,))
474
+ return self._rows(cur)
475
+
476
+ def close(self) -> None:
477
+ with self._lock:
478
+ self.conn.close()
479
+
480
+
481
+ class _MemoryBatch:
482
+ """Re-entrant SQLite transaction scope for MemoryEngine writes."""
483
+
484
+ def __init__(self, memory: MemoryEngine):
485
+ self.memory = memory
486
+
487
+ def __enter__(self) -> MemoryEngine:
488
+ memory = self.memory
489
+ memory._lock.acquire()
490
+ if memory._transaction_depth == 0:
491
+ memory.conn.execute("BEGIN")
492
+ memory._transaction_rollback_only = False
493
+ memory._transaction_depth += 1
494
+ return memory
495
+
496
+ def __exit__(self, exc_type, exc, tb) -> bool:
497
+ memory = self.memory
498
+ if exc_type is not None:
499
+ memory._transaction_rollback_only = True
500
+ memory._transaction_depth -= 1
501
+ try:
502
+ if memory._transaction_depth == 0:
503
+ if memory._transaction_rollback_only:
504
+ memory._rollback_now()
505
+ else:
506
+ memory._commit_now()
507
+ memory._transaction_rollback_only = False
508
+ finally:
509
+ memory._lock.release()
510
+ return False
511
+
512
+
513
+ # =============================================================================
514
+ # WORKER BASE
515
+ # =============================================================================
516
+ class Worker:
517
+ """Base class for all pluggable workers."""
518
+ NAME = "base"
519
+ PRIORITY = 100
520
+ CAPABILITIES: List[str] = []
521
+
522
+ def __init__(self, memory: MemoryEngine, config: Config):
523
+ self.memory = memory
524
+ self.config = config
525
+
526
+ def can_run(self, context: Dict) -> bool:
527
+ """Determine if this worker is relevant."""
528
+ return True
529
+
530
+ def run(self, context: Dict) -> Dict:
531
+ """Main execution. Must return an evidence-based result."""
532
+ raise NotImplementedError("Worker must implement run()")
533
+
534
+
535
+ # =============================================================================
536
+ # WORKER: PerformanceWorker
537
+ # =============================================================================
538
+ class PerformanceWorker(Worker):
539
+ """Benchmark candidate code with strict correctness gates.
540
+
541
+ Safety model: the candidate process is isolated and timeout-limited, but it
542
+ is not a security boundary. Parent-owned harness code controls timing and
543
+ result writing; candidate and baseline code run in separate namespaces.
544
+ """
545
+ NAME = "performance"
546
+ PRIORITY = 80
547
+ CAPABILITIES = ["optimization", "benchmarking", "loop_transform"]
548
+
549
+ def __init__(self, memory: MemoryEngine, config: Config):
550
+ super().__init__(memory, config)
551
+ self.sandbox = ExecutionSandbox(
552
+ config.workspace,
553
+ config.sandbox_memory_limit_mb,
554
+ config.os_sandbox_command,
555
+ )
556
+
557
+ @staticmethod
558
+ def _indent(text: str, spaces: int = 4) -> str:
559
+ pad = " " * spaces
560
+ return "\n".join(
561
+ (pad + line) if line.strip() else line
562
+ for line in text.splitlines()
563
+ )
564
+
565
+ def _build_harness(self, ctx: Dict) -> "tuple[Optional[str], Optional[str], Optional[str]]":
566
+ """Build a single-candidate benchmark harness.
567
+
568
+ Returns (script, error, result_file). Candidate code never receives the
569
+ result-file path in its namespace. Candidate and baseline run in fresh
570
+ setup-derived namespaces so baseline definitions cannot clobber the
571
+ candidate under test.
572
+ """
573
+ call = ctx.get("call")
574
+ if not call:
575
+ return None, "no 'call' expression provided to time", None
576
+
577
+ code = ctx.get("code") or ctx.get("initial_code") or ""
578
+ setup = ctx.get("setup") or ""
579
+ test = ctx.get("test")
580
+ baseline_code = ctx.get("baseline_code") or ""
581
+ baseline_call = ctx.get("baseline_call")
582
+ warmup = max(0, int(self.config.benchmark_warmup))
583
+ repeats = max(1, int(self.config.benchmark_repeats))
584
+ target = max(0.0, float(self.config.benchmark_target_sample_time))
585
+ max_loops = max(1, int(self.config.benchmark_max_loops))
586
+
587
+ fd, result_file = tempfile.mkstemp(prefix="_ae_result_", suffix=".json")
588
+ os.close(fd)
589
+
590
+ p: List[str] = [
591
+ "import builtins as _ae_builtins",
592
+ "import json as _ae_json",
593
+ "import time as _ae_time",
594
+ "_ae_perf_counter = _ae_time.perf_counter",
595
+ "_ae_open = _ae_builtins.open",
596
+ f"_ae_result_file = {result_file!r}",
597
+ f"_ae_setup_source = {setup!r}",
598
+ f"_ae_code_source = {code!r}",
599
+ f"_ae_test_source = {test!r}",
600
+ f"_ae_call = {call!r}",
601
+ f"_ae_baseline_source = {baseline_code!r}",
602
+ f"_ae_baseline_call = {baseline_call!r}",
603
+ f"_ae_warmup = {warmup}",
604
+ f"_ae_repeats = {repeats}",
605
+ f"_ae_target_sample_time = {target!r}",
606
+ f"_ae_max_loops = {max_loops}",
607
+ "",
608
+ "def _ae_indent(_ae_text):",
609
+ " return '\\n'.join((' ' + _ae_line) if _ae_line.strip() else _ae_line for _ae_line in _ae_text.splitlines())",
610
+ "",
611
+ "def _ae_build_ns(_ae_code_source, _ae_label):",
612
+ " _ae_ns = {'__builtins__': __builtins__}",
613
+ " if _ae_setup_source:",
614
+ " exec(compile(_ae_setup_source, '<setup>', 'exec'), _ae_ns)",
615
+ " if _ae_code_source:",
616
+ " exec(compile(_ae_code_source, _ae_label, 'exec'), _ae_ns)",
617
+ " return _ae_ns",
618
+ "",
619
+ "def _ae_make_bench(_ae_ns, _ae_expr, _ae_label):",
620
+ " _ae_src = 'def _ae_bench():\\n' + _ae_indent(_ae_expr)",
621
+ " exec(compile(_ae_src, _ae_label, 'exec'), _ae_ns)",
622
+ " return _ae_ns['_ae_bench']",
623
+ "",
624
+ "def _ae_calibrate(_ae_fn):",
625
+ " for _ in range(_ae_warmup):",
626
+ " _ae_fn()",
627
+ " _ae_loops = 1",
628
+ " while _ae_loops < _ae_max_loops:",
629
+ " _ae_t0 = _ae_perf_counter()",
630
+ " for _ in range(_ae_loops):",
631
+ " _ae_fn()",
632
+ " _ae_elapsed = _ae_perf_counter() - _ae_t0",
633
+ " if _ae_elapsed >= _ae_target_sample_time or _ae_target_sample_time <= 0:",
634
+ " break",
635
+ " _ae_loops = min(_ae_loops * 2, _ae_max_loops)",
636
+ " return max(1, _ae_loops)",
637
+ "",
638
+ "def _ae_measure(_ae_fn):",
639
+ " _ae_loops = _ae_calibrate(_ae_fn)",
640
+ " _ae_times = []",
641
+ " for _ in range(_ae_repeats):",
642
+ " _ae_t0 = _ae_perf_counter()",
643
+ " for _ in range(_ae_loops):",
644
+ " _ae_fn()",
645
+ " _ae_times.append((_ae_perf_counter() - _ae_t0) / _ae_loops)",
646
+ " return _ae_times, _ae_loops",
647
+ "",
648
+ "_ae_payload = {'times': [], 'correct': False, 'base_times': None, 'error': None}",
649
+ "try:",
650
+ " _ae_candidate_ns = _ae_build_ns(_ae_code_source, '<candidate>')",
651
+ " _ae_correct = None",
652
+ " if _ae_test_source:",
653
+ " try:",
654
+ " exec(compile(_ae_test_source, '<test>', 'exec'), _ae_candidate_ns)",
655
+ " _ae_correct = True",
656
+ " except Exception:",
657
+ " _ae_correct = False",
658
+ " _ae_fn = _ae_make_bench(_ae_candidate_ns, _ae_call, '<bench-candidate>')",
659
+ " _ae_times, _ae_loops = _ae_measure(_ae_fn)",
660
+ " _ae_base_times = None",
661
+ " _ae_base_loops = None",
662
+ " if _ae_baseline_call:",
663
+ " _ae_base_ns = _ae_build_ns(_ae_baseline_source, '<baseline>')",
664
+ " _ae_base_fn = _ae_make_bench(_ae_base_ns, _ae_baseline_call, '<bench-baseline>')",
665
+ " _ae_base_times, _ae_base_loops = _ae_measure(_ae_base_fn)",
666
+ " _ae_payload = {",
667
+ " 'times': _ae_times,",
668
+ " 'correct': _ae_correct,",
669
+ " 'base_times': _ae_base_times,",
670
+ " 'loops_per_sample': _ae_loops,",
671
+ " 'base_loops_per_sample': _ae_base_loops,",
672
+ " 'error': None,",
673
+ " }",
674
+ "except BaseException as _ae_exc:",
675
+ " _ae_payload = {'times': [], 'correct': False, 'base_times': None, 'error': repr(_ae_exc)}",
676
+ "with _ae_open(_ae_result_file, 'w', encoding='utf-8') as _ae_f:",
677
+ " _ae_f.write(_ae_json.dumps(_ae_payload))",
678
+ ]
679
+ return "\n".join(p), None, result_file
680
+
681
+ def _build_batch_harness(self, ctx: Dict,
682
+ candidates: List[str]) -> "tuple[str, Optional[str], Optional[str]]":
683
+ """Build a parent-controlled batch benchmark harness."""
684
+ call = ctx.get("call")
685
+ if not call:
686
+ return "", "no 'call' expression provided to time", None
687
+ test = ctx.get("test")
688
+ setup = ctx.get("setup") or ""
689
+ warmup = max(0, int(self.config.benchmark_warmup))
690
+ repeats = max(1, int(self.config.benchmark_repeats))
691
+ target = max(0.0, float(self.config.benchmark_target_sample_time))
692
+ max_loops = max(1, int(self.config.benchmark_max_loops))
693
+
694
+ fd, result_file = tempfile.mkstemp(prefix="_ae_batch_", suffix=".json")
695
+ os.close(fd)
696
+
697
+ p: List[str] = [
698
+ "import builtins as _ae_builtins",
699
+ "import json as _ae_json",
700
+ "import time as _ae_time",
701
+ "_ae_perf_counter = _ae_time.perf_counter",
702
+ "_ae_open = _ae_builtins.open",
703
+ f"_ae_result_file = {result_file!r}",
704
+ f"_ae_setup_source = {setup!r}",
705
+ f"_ae_candidates = {candidates!r}",
706
+ f"_ae_call = {call!r}",
707
+ f"_ae_test_source = {test!r}",
708
+ f"_ae_warmup = {warmup}",
709
+ f"_ae_repeats = {repeats}",
710
+ f"_ae_target_sample_time = {target!r}",
711
+ f"_ae_max_loops = {max_loops}",
712
+ "",
713
+ "def _ae_indent(_ae_text):",
714
+ " return '\\n'.join((' ' + _ae_line) if _ae_line.strip() else _ae_line for _ae_line in _ae_text.splitlines())",
715
+ "",
716
+ "def _ae_build_ns(_ae_code_source, _ae_label):",
717
+ " _ae_ns = {'__builtins__': __builtins__}",
718
+ " if _ae_setup_source:",
719
+ " exec(compile(_ae_setup_source, '<setup>', 'exec'), _ae_ns)",
720
+ " exec(compile(_ae_code_source, _ae_label, 'exec'), _ae_ns)",
721
+ " return _ae_ns",
722
+ "",
723
+ "def _ae_make_bench(_ae_ns):",
724
+ " _ae_src = 'def _ae_bench():\\n' + _ae_indent(_ae_call)",
725
+ " exec(compile(_ae_src, '<bench>', 'exec'), _ae_ns)",
726
+ " return _ae_ns['_ae_bench']",
727
+ "",
728
+ "def _ae_calibrate(_ae_fn):",
729
+ " for _ in range(_ae_warmup):",
730
+ " _ae_fn()",
731
+ " _ae_loops = 1",
732
+ " while _ae_loops < _ae_max_loops:",
733
+ " _ae_t0 = _ae_perf_counter()",
734
+ " for _ in range(_ae_loops):",
735
+ " _ae_fn()",
736
+ " _ae_elapsed = _ae_perf_counter() - _ae_t0",
737
+ " if _ae_elapsed >= _ae_target_sample_time or _ae_target_sample_time <= 0:",
738
+ " break",
739
+ " _ae_loops = min(_ae_loops * 2, _ae_max_loops)",
740
+ " return max(1, _ae_loops)",
741
+ "",
742
+ "def _ae_measure(_ae_fn):",
743
+ " _ae_loops = _ae_calibrate(_ae_fn)",
744
+ " _ae_times = []",
745
+ " for _ in range(_ae_repeats):",
746
+ " _ae_t0 = _ae_perf_counter()",
747
+ " for _ in range(_ae_loops):",
748
+ " _ae_fn()",
749
+ " _ae_times.append((_ae_perf_counter() - _ae_t0) / _ae_loops)",
750
+ " return _ae_times, _ae_loops",
751
+ "",
752
+ "_ae_all_results = {}",
753
+ "for _ae_idx, _ae_code in enumerate(_ae_candidates):",
754
+ " try:",
755
+ " _ae_ns = _ae_build_ns(_ae_code, f'<candidate-{_ae_idx}>')",
756
+ " _ae_correct = None",
757
+ " if _ae_test_source:",
758
+ " try:",
759
+ " exec(compile(_ae_test_source, '<test>', 'exec'), _ae_ns)",
760
+ " _ae_correct = True",
761
+ " except Exception:",
762
+ " _ae_correct = False",
763
+ " _ae_fn = _ae_make_bench(_ae_ns)",
764
+ " _ae_times, _ae_loops = _ae_measure(_ae_fn)",
765
+ " _ae_all_results[_ae_idx] = {'times': _ae_times, 'correct': _ae_correct, 'loops_per_sample': _ae_loops, 'error': None}",
766
+ " except BaseException as _ae_exc:",
767
+ " _ae_all_results[_ae_idx] = {'times': [], 'correct': False, 'loops_per_sample': None, 'error': repr(_ae_exc)}",
768
+ "",
769
+ "with _ae_open(_ae_result_file, 'w', encoding='utf-8') as _ae_f:",
770
+ " _ae_f.write(_ae_json.dumps(_ae_all_results))",
771
+ ]
772
+ return "\n".join(p), None, result_file
773
+
774
+ def _parse_bench(self, result_file: str) -> Optional[Dict]:
775
+ """Read benchmark results from the temp JSON file."""
776
+ try:
777
+ with open(result_file, "r", encoding="utf-8") as f:
778
+ return json.loads(f.read())
779
+ except (json.JSONDecodeError, OSError):
780
+ return None
781
+
782
+ @staticmethod
783
+ def _cleanup_result(result_file: Optional[str]) -> None:
784
+ """Remove the temp result file if it exists."""
785
+ if result_file:
786
+ try:
787
+ Path(result_file).unlink(missing_ok=True)
788
+ except OSError:
789
+ pass
790
+
791
+ @staticmethod
792
+ def _summarize(times: List[float]) -> Dict[str, float]:
793
+ n = len(times)
794
+ median = statistics.median(times)
795
+ stdev = statistics.stdev(times) if n >= 2 else 0.0
796
+ rsd = (stdev / median) if median > 0 else 0.0
797
+ return {
798
+ "median": median,
799
+ "mean": statistics.fmean(times),
800
+ "stdev": stdev,
801
+ "min": min(times),
802
+ "repeats": n,
803
+ "rsd": rsd,
804
+ "confidence": max(0.0, 1.0 - rsd),
805
+ }
806
+
807
+ def _fail(self, ctx: Dict, reflection: str) -> Dict:
808
+ result = {
809
+ "success": False,
810
+ "code": ctx.get("code") or ctx.get("initial_code"),
811
+ "time": None,
812
+ "score_vector": {},
813
+ "reflection": reflection,
814
+ }
815
+ task_id = ctx.get("task_id")
816
+ if task_id is not None:
817
+ self.memory.log_attempt(task_id, self.NAME, result)
818
+ return result
819
+
820
+ @staticmethod
821
+ def _describe(stats: Dict, correct, speedup) -> str:
822
+ ms = stats["median"] * 1e3
823
+ sd = stats["stdev"] * 1e3
824
+ parts = [f"median {ms:.4f} ms over {stats['repeats']} runs (±{sd:.4f} ms)"]
825
+ parts.append(
826
+ "correctness not checked" if correct is None
827
+ else ("correct" if correct else "INCORRECT (test failed)")
828
+ )
829
+ if speedup:
830
+ parts.append(f"{speedup:.2f}x vs baseline")
831
+ return "; ".join(parts)
832
+
833
+ def _success_from_correctness(self, correct) -> bool:
834
+ """Strict by default: unknown correctness is not success."""
835
+ if self.config.require_correctness_test:
836
+ return correct is True
837
+ return correct is not False
838
+
839
+ def run(self, context: Dict) -> Dict:
840
+ script, err, result_file = self._build_harness(context)
841
+ if err:
842
+ return self._fail(context, f"harness error: {err}")
843
+
844
+ exec_result = self.sandbox.run_code(
845
+ script, timeout=self.config.default_timeout
846
+ )
847
+ if not exec_result.get("success"):
848
+ reason = (exec_result.get("error")
849
+ or (exec_result.get("stderr") or "").strip()
850
+ or "unknown failure")
851
+ self._cleanup_result(result_file)
852
+ return self._fail(context, f"execution failed: {reason}")
853
+
854
+ payload = self._parse_bench(result_file)
855
+ self._cleanup_result(result_file)
856
+ if not payload or not payload.get("times"):
857
+ detail = payload.get("error") if isinstance(payload, dict) else None
858
+ return self._fail(
859
+ context,
860
+ "no benchmark payload returned" + (f": {detail}" if detail else ""),
861
+ )
862
+
863
+ stats = self._summarize(payload["times"])
864
+ correct = payload.get("correct")
865
+ speedup = None
866
+ base = payload.get("base_times")
867
+ if base:
868
+ base_stats = self._summarize(base)
869
+ if stats["median"] > 0:
870
+ speedup = base_stats["median"] / stats["median"]
871
+
872
+ score_vector = {
873
+ "median_s": round(stats["median"], 9),
874
+ "mean_s": round(stats["mean"], 9),
875
+ "stdev_s": round(stats["stdev"], 9),
876
+ "min_s": round(stats["min"], 9),
877
+ "repeats": stats["repeats"],
878
+ "loops_per_sample": payload.get("loops_per_sample"),
879
+ "correct": correct,
880
+ "speedup_vs_baseline": round(speedup, 4) if speedup else None,
881
+ }
882
+ success = self._success_from_correctness(correct)
883
+ reflection = self._describe(stats, correct, speedup)
884
+ if correct is None and self.config.require_correctness_test:
885
+ reflection += "; correctness not checked; refusing success"
886
+ result = {
887
+ "success": success,
888
+ "code": context.get("code") or context.get("initial_code"),
889
+ "time": stats["median"],
890
+ "score_vector": score_vector,
891
+ "reflection": reflection,
892
+ }
893
+ task_id = context.get("task_id")
894
+ if task_id is not None:
895
+ attempt_id = self.memory.log_attempt(task_id, self.NAME, result)
896
+ if success:
897
+ self.memory.log_benchmark(attempt_id, {
898
+ "median": stats["median"], "stdev": stats["stdev"],
899
+ "repeats": stats["repeats"],
900
+ "confidence": stats["confidence"],
901
+ })
902
+ return result
903
+
904
+ def batch_run(self, context: Dict, candidates: List[str]) -> List[Dict]:
905
+ """Benchmark multiple candidates in a single subprocess."""
906
+ if not candidates:
907
+ return []
908
+
909
+ script, err, result_file = self._build_batch_harness(context, candidates)
910
+ if err:
911
+ return [self._fail(context, f"harness error: {err}")
912
+ for _ in candidates]
913
+
914
+ exec_result = self.sandbox.run_code(
915
+ script, timeout=self.config.default_timeout
916
+ )
917
+ if not exec_result.get("success"):
918
+ reason = (exec_result.get("error")
919
+ or (exec_result.get("stderr") or "").strip()
920
+ or "unknown failure")
921
+ self._cleanup_result(result_file)
922
+ return [self._fail(context, f"execution failed: {reason}")
923
+ for _ in candidates]
924
+
925
+ payload = self._parse_bench(result_file)
926
+ self._cleanup_result(result_file)
927
+ if not payload:
928
+ return [self._fail(context, "no benchmark payload returned")
929
+ for _ in candidates]
930
+
931
+ results = []
932
+ task_id = context.get("task_id")
933
+ batch_scope = self.memory.batch() if task_id is not None else None
934
+ if batch_scope is not None:
935
+ batch_scope.__enter__()
936
+ try:
937
+ for i, code in enumerate(candidates):
938
+ entry = payload.get(str(i), {})
939
+ times = entry.get("times", [])
940
+ correct = entry.get("correct")
941
+ if not times:
942
+ detail = entry.get("error")
943
+ results.append(self._fail(
944
+ {**context, "code": code},
945
+ f"candidate {i}: no times" + (f": {detail}" if detail else ""),
946
+ ))
947
+ continue
948
+
949
+ stats = self._summarize(times)
950
+ score_vector = {
951
+ "median_s": round(stats["median"], 9),
952
+ "mean_s": round(stats["mean"], 9),
953
+ "stdev_s": round(stats["stdev"], 9),
954
+ "min_s": round(stats["min"], 9),
955
+ "repeats": stats["repeats"],
956
+ "loops_per_sample": entry.get("loops_per_sample"),
957
+ "correct": correct,
958
+ "speedup_vs_baseline": None,
959
+ }
960
+ success = self._success_from_correctness(correct)
961
+ reflection = self._describe(stats, correct, None)
962
+ if correct is None and self.config.require_correctness_test:
963
+ reflection += "; correctness not checked; refusing success"
964
+ result = {
965
+ "success": success,
966
+ "code": code,
967
+ "time": stats["median"],
968
+ "score_vector": score_vector,
969
+ "reflection": reflection,
970
+ }
971
+ if task_id is not None:
972
+ attempt_id = self.memory.log_attempt(task_id, self.NAME, result)
973
+ if success:
974
+ self.memory.log_benchmark(attempt_id, {
975
+ "median": stats["median"], "stdev": stats["stdev"],
976
+ "repeats": stats["repeats"],
977
+ "confidence": stats["confidence"],
978
+ })
979
+ results.append(result)
980
+ except Exception:
981
+ if batch_scope is not None:
982
+ batch_scope.__exit__(*sys.exc_info())
983
+ raise
984
+ else:
985
+ if batch_scope is not None:
986
+ batch_scope.__exit__(None, None, None)
987
+ return results
988
+
989
+
990
+ # =============================================================================
991
+ # LLM ROUTER
992
+ # =============================================================================
993
+ class LLMRouter:
994
+ """Provider-agnostic model router.
995
+
996
+ For testability and offline use, an optional non-streaming `engine` and a
997
+ streaming `stream_engine` can be injected. Each is a callable:
998
+ engine(prompt: str, model: str) -> str
999
+ stream_engine(prompt: str, model: str) -> Iterator[str]
1000
+ When neither is given, the ollama provider is used if available, else a
1001
+ stub. This mirrors the pluggable candidate_provider used by optimize_loop.
1002
+ """
1003
+
1004
+ def __init__(self, config: Config, engine=None, stream_engine=None):
1005
+ self.config = config
1006
+ self._engine = engine
1007
+ self._stream_engine = stream_engine
1008
+
1009
+ def generate(self, prompt: str, model: Optional[str] = None) -> str:
1010
+ model = model or self.config.default_model
1011
+ if self._engine is not None:
1012
+ return self._engine(prompt, model)
1013
+ if HAS_OLLAMA:
1014
+ try:
1015
+ resp = ollama.chat(
1016
+ model=model,
1017
+ messages=[{"role": "user", "content": prompt}],
1018
+ )
1019
+ return resp["message"]["content"]
1020
+ except Exception as e: # noqa: BLE001 - router must not crash caller
1021
+ logger.warning("LLM call failed: %s", e)
1022
+ return f"[LLM Error: {e}]"
1023
+ return "[LLM Stub - install ollama]"
1024
+
1025
+ def stream(self, prompt: str,
1026
+ model: Optional[str] = None) -> Iterator[str]:
1027
+ """Yield response text in chunks as they arrive.
1028
+
1029
+ This is the path that lets a display update incrementally, so the
1030
+ time-to-first-display becomes the model's time-to-first-token rather
1031
+ than its full generation time.
1032
+ """
1033
+ model = model or self.config.default_model
1034
+ if self._stream_engine is not None:
1035
+ yield from self._stream_engine(prompt, model)
1036
+ return
1037
+ if HAS_OLLAMA:
1038
+ try:
1039
+ for part in ollama.chat(
1040
+ model=model,
1041
+ messages=[{"role": "user", "content": prompt}],
1042
+ stream=True,
1043
+ ):
1044
+ chunk = (part.get("message") or {}).get("content", "")
1045
+ if chunk:
1046
+ yield chunk
1047
+ except Exception as e: # noqa: BLE001
1048
+ logger.warning("LLM stream failed: %s", e)
1049
+ yield f"[LLM Error: {e}]"
1050
+ return
1051
+ yield "[LLM Stub - install ollama]"
1052
+
1053
+
1054
+ # =============================================================================
1055
+ # LATENCY PROBE (call -> display)
1056
+ # =============================================================================
1057
+ def make_simulated_stream(n_tokens: int = 30, ttft: float = 0.10,
1058
+ per_token: float = 0.010, token: str = "lorem "):
1059
+ """Build a fake STREAMING engine that mimics a model: an initial think
1060
+ delay (time-to-first-token) then tokens at a steady rate. Offline demos /
1061
+ tests only -- real numbers come from a real model."""
1062
+ def _engine(prompt: str, model: str) -> Iterator[str]:
1063
+ time.sleep(ttft)
1064
+ for _ in range(n_tokens):
1065
+ time.sleep(per_token)
1066
+ yield token
1067
+ return _engine
1068
+
1069
+
1070
+ def make_simulated_blocking(n_tokens: int = 30, ttft: float = 0.10,
1071
+ per_token: float = 0.010, token: str = "lorem "):
1072
+ """Non-streaming counterpart with the SAME total cost as the streaming
1073
+ engine above, but it returns only once fully done. Pairing the two shows
1074
+ that streaming changes *when* output is visible, not total compute."""
1075
+ def _engine(prompt: str, model: str) -> str:
1076
+ time.sleep(ttft + n_tokens * per_token)
1077
+ return token * n_tokens
1078
+ return _engine
1079
+
1080
+
1081
+ def measure_latency(router: "LLMRouter", prompt: str, *,
1082
+ model: Optional[str] = None, repeats: int = 5,
1083
+ stream: bool = True, sink=None) -> Dict[str, Any]:
1084
+ """Measure call->display latency over `repeats` runs.
1085
+
1086
+ Reports median/stdev/min for:
1087
+ ttfd - time to first displayed output (the perceived-latency metric).
1088
+ total - call -> fully displayed.
1089
+ In blocking mode nothing is visible until the whole response arrives, so
1090
+ ttfd == total by construction; that contrast is the point of the test.
1091
+ `sink(chunk)` is where display happens; default is a no-op for clean timing.
1092
+ """
1093
+ sink = sink or (lambda s: None)
1094
+ ttfd: List[float] = []
1095
+ total: List[float] = []
1096
+ for _ in range(max(1, repeats)):
1097
+ t0 = time.perf_counter()
1098
+ first = None
1099
+ if stream:
1100
+ for chunk in router.stream(prompt, model):
1101
+ if first is None:
1102
+ first = time.perf_counter()
1103
+ sink(chunk)
1104
+ else:
1105
+ text = router.generate(prompt, model)
1106
+ first = time.perf_counter() # nothing visible until full text ready
1107
+ sink(text)
1108
+ end = time.perf_counter()
1109
+ if first is None:
1110
+ first = end
1111
+ ttfd.append(first - t0)
1112
+ total.append(end - t0)
1113
+
1114
+ def _stats(xs: List[float]) -> Dict[str, float]:
1115
+ n = len(xs)
1116
+ return {
1117
+ "median": statistics.median(xs),
1118
+ "stdev": statistics.stdev(xs) if n >= 2 else 0.0,
1119
+ "min": min(xs),
1120
+ "repeats": n,
1121
+ }
1122
+
1123
+ return {
1124
+ "mode": "stream" if stream else "blocking",
1125
+ "ttfd": _stats(ttfd),
1126
+ "total": _stats(total),
1127
+ }
1128
+
1129
+
1130
+ # =============================================================================
1131
+ # EXECUTION SANDBOX
1132
+ # =============================================================================
1133
+ class ExecutionSandbox:
1134
+ """Process-isolated code execution with an enforced timeout.
1135
+
1136
+ IMPORTANT — this is ISOLATION, not a SECURITY BOUNDARY. For model-generated
1137
+ code, configure ``Config.os_sandbox_command`` with an OS-level sandbox
1138
+ wrapper (container/VM/sandbox tool). This class enforces timeout, cleans up
1139
+ process trees, and optionally applies POSIX memory limits; it does not
1140
+ prevent deliberate filesystem/network access by itself.
1141
+ """
1142
+
1143
+ def __init__(self, workspace: str = "./workspace",
1144
+ memory_limit_mb: Optional[int] = 512,
1145
+ os_sandbox_command: Optional[List[str]] = None):
1146
+ self.workspace = Path(workspace)
1147
+ self.workspace.mkdir(parents=True, exist_ok=True)
1148
+ self.memory_limit_mb = memory_limit_mb
1149
+ if isinstance(os_sandbox_command, str):
1150
+ self.os_sandbox_command = [os_sandbox_command]
1151
+ else:
1152
+ self.os_sandbox_command = list(os_sandbox_command or [])
1153
+
1154
+ def _preexec(self) -> None:
1155
+ """POSIX-only: cap address space so runaway allocations die fast."""
1156
+ if self.memory_limit_mb and HAS_RESOURCE:
1157
+ limit = self.memory_limit_mb * 1024 * 1024
1158
+ resource.setrlimit(resource.RLIMIT_AS, (limit, limit))
1159
+
1160
+ def _command_for_script(self, script: Path) -> List[str]:
1161
+ python_cmd = [sys.executable, str(script)]
1162
+ if not self.os_sandbox_command:
1163
+ return python_cmd
1164
+ mapping = {
1165
+ "{python}": sys.executable,
1166
+ "{script}": str(script),
1167
+ "{workspace}": str(self.workspace),
1168
+ }
1169
+ expanded = [mapping.get(part, part) for part in self.os_sandbox_command]
1170
+ if any(part in self.os_sandbox_command for part in ("{python}", "{script}")):
1171
+ return expanded
1172
+ return expanded + python_cmd
1173
+
1174
+ @staticmethod
1175
+ def _kill_process_tree(proc: subprocess.Popen) -> None:
1176
+ if proc.poll() is not None:
1177
+ return
1178
+ if os.name == "nt":
1179
+ try:
1180
+ subprocess.run(
1181
+ ["taskkill", "/F", "/T", "/PID", str(proc.pid)],
1182
+ capture_output=True, text=True, timeout=5,
1183
+ )
1184
+ except Exception:
1185
+ try:
1186
+ proc.kill()
1187
+ except OSError:
1188
+ pass
1189
+ return
1190
+ try:
1191
+ os.killpg(proc.pid, signal.SIGKILL)
1192
+ except Exception:
1193
+ try:
1194
+ proc.kill()
1195
+ except OSError:
1196
+ pass
1197
+
1198
+ def run_code(self, code: str, timeout: float = 30.0) -> Dict[str, Any]:
1199
+ # Absolute path: subprocess cwd is the workspace, so a relative script
1200
+ # path would be resolved against it twice. resolve() avoids that.
1201
+ script = (self.workspace / f"_exec_{uuid.uuid4().hex}.py").resolve()
1202
+ script.write_text(code, encoding="utf-8")
1203
+ start = time.perf_counter()
1204
+ proc: Optional[subprocess.Popen] = None
1205
+ try:
1206
+ popen_kwargs: Dict[str, Any] = {
1207
+ "args": self._command_for_script(script),
1208
+ "stdout": subprocess.PIPE,
1209
+ "stderr": subprocess.PIPE,
1210
+ "text": True,
1211
+ "cwd": str(self.workspace),
1212
+ }
1213
+ if os.name == "posix":
1214
+ popen_kwargs["preexec_fn"] = self._preexec
1215
+ popen_kwargs["start_new_session"] = True
1216
+ elif os.name == "nt":
1217
+ popen_kwargs["creationflags"] = getattr(
1218
+ subprocess, "CREATE_NEW_PROCESS_GROUP", 0
1219
+ )
1220
+
1221
+ proc = subprocess.Popen(**popen_kwargs)
1222
+ try:
1223
+ stdout, stderr = proc.communicate(timeout=timeout)
1224
+ except subprocess.TimeoutExpired:
1225
+ self._kill_process_tree(proc)
1226
+ try:
1227
+ stdout, stderr = proc.communicate(timeout=2)
1228
+ except subprocess.TimeoutExpired:
1229
+ stdout, stderr = "", ""
1230
+ elapsed = time.perf_counter() - start
1231
+ return {
1232
+ "success": False,
1233
+ "time": elapsed,
1234
+ "returncode": proc.returncode,
1235
+ "stdout": stdout,
1236
+ "stderr": stderr,
1237
+ "error": f"timeout after {timeout}s",
1238
+ }
1239
+
1240
+ elapsed = time.perf_counter() - start
1241
+ return {
1242
+ "success": proc.returncode == 0,
1243
+ "time": elapsed,
1244
+ "returncode": proc.returncode,
1245
+ "stdout": stdout,
1246
+ "stderr": stderr,
1247
+ }
1248
+ except Exception as e: # noqa: BLE001
1249
+ if proc is not None:
1250
+ self._kill_process_tree(proc)
1251
+ return {"success": False, "error": str(e)}
1252
+ finally:
1253
+ try:
1254
+ script.unlink(missing_ok=True)
1255
+ except OSError:
1256
+ pass
1257
+
1258
+
1259
+ # =============================================================================
1260
+ # OPTIMIZE SPEC
1261
+ # =============================================================================
1262
+ @dataclass
1263
+ class OptimizeSpec:
1264
+ """Inputs for an optimization loop.
1265
+
1266
+ Assumptions made explicit:
1267
+ - Every candidate must define the SAME callable that `call` invokes, so a
1268
+ single `call` and `test` apply to the reference and all variants.
1269
+ - `test` is REQUIRED: selecting an unverified candidate is unsafe, so the
1270
+ loop refuses to run without one.
1271
+ """
1272
+ name: str
1273
+ call: str
1274
+ reference_code: str = ""
1275
+ setup: str = ""
1276
+ test: str = ""
1277
+ n_variants: int = 3
1278
+ model: Optional[str] = None
1279
+
1280
+
1281
+ # =============================================================================
1282
+ # SCHEDULER (Core Kernel)
1283
+ # =============================================================================
1284
+ def _optimize_sequential_env_enabled() -> bool:
1285
+ """Return True when the legacy sequential optimize loop is requested."""
1286
+ raw = os.environ.get("ALGO_CLI_OPTIMIZE_SEQUENTIAL", "")
1287
+ return raw.strip().lower() in {"1", "true", "yes", "on"}
1288
+
1289
+
1290
+ class Scheduler:
1291
+ """Central operating system. Coordinates tasks and workers."""
1292
+
1293
+ def __init__(self, config: Config):
1294
+ self.config = config
1295
+ self.memory = MemoryEngine(config.db_path, config.sqlite_journal_mode)
1296
+ self.router = LLMRouter(config)
1297
+ self.sandbox = ExecutionSandbox(
1298
+ config.workspace, config.sandbox_memory_limit_mb,
1299
+ config.os_sandbox_command,
1300
+ )
1301
+ self.workers: Dict[str, Worker] = {}
1302
+ self._discover_workers()
1303
+ self.active_session: Optional[int] = None
1304
+
1305
+ @staticmethod
1306
+ def _iter_subclasses(cls) -> List[type]:
1307
+ """Recursively collect all subclasses (not just direct ones)."""
1308
+ found: List[type] = []
1309
+ for sub in cls.__subclasses__():
1310
+ found.append(sub)
1311
+ found.extend(Scheduler._iter_subclasses(sub))
1312
+ return found
1313
+
1314
+ def _discover_workers(self) -> None:
1315
+ """Auto-register Worker subclasses (deduplicated, recursive).
1316
+
1317
+ Each worker is also persisted to the `workers` table with its priority
1318
+ and capabilities, so routing decisions are introspectable from the DB.
1319
+ """
1320
+ with self.memory.batch():
1321
+ for worker_cls in dict.fromkeys(self._iter_subclasses(Worker)):
1322
+ w = worker_cls(self.memory, self.config)
1323
+ self.workers[w.NAME] = w
1324
+ self.memory.register_worker(w.NAME, w.PRIORITY, list(w.CAPABILITIES))
1325
+ logger.info("[OK] Registered worker: %s (priority=%d, caps=%s)",
1326
+ w.NAME, w.PRIORITY, ",".join(w.CAPABILITIES) or "-")
1327
+
1328
+ def start_session(self, goal: str, strategy: Optional[str] = None) -> int:
1329
+ self.active_session = self.memory.start_session(goal, strategy)
1330
+ return self.active_session
1331
+
1332
+ def _select_worker(self, context: Dict) -> Optional[Worker]:
1333
+ """Pick a worker by precedence:
1334
+
1335
+ 1. context['worker'] — explicit name override.
1336
+ 2. context['capability'] — any worker advertising that capability.
1337
+ 3. otherwise — any worker that can_run.
1338
+
1339
+ Among capability/fallback candidates the lowest PRIORITY value wins
1340
+ (more specific workers use lower numbers); ties break by name for
1341
+ determinism. can_run() is always respected.
1342
+ """
1343
+ name = context.get("worker")
1344
+ if name:
1345
+ w = self.workers.get(name)
1346
+ return w if (w and w.can_run(context)) else None
1347
+
1348
+ candidates = [w for w in self.workers.values() if w.can_run(context)]
1349
+ cap = context.get("capability")
1350
+ if cap:
1351
+ candidates = [w for w in candidates if cap in w.CAPABILITIES]
1352
+ if not candidates:
1353
+ return None
1354
+ candidates.sort(key=lambda w: (w.PRIORITY, w.NAME))
1355
+ return candidates[0]
1356
+
1357
+ def run_task(self, task_name: str, context: Dict) -> Dict:
1358
+ """Create a task row, route to a worker by capability, and execute."""
1359
+ logger.info("[TASK] Running task: %s", task_name)
1360
+ if self.active_session is None:
1361
+ self.start_session(f"adhoc:{task_name}")
1362
+
1363
+ dependencies = context.get("dependencies") or []
1364
+ task_id = self.memory.create_task(
1365
+ self.active_session, task_name, dependencies=dependencies
1366
+ )
1367
+ task = self.memory.get_task(task_id) or {}
1368
+ if task.get("status") == "blocked":
1369
+ return {
1370
+ "success": False,
1371
+ "status": "blocked",
1372
+ "task_id": task_id,
1373
+ "error": "task dependencies are not completed",
1374
+ }
1375
+
1376
+ worker = self._select_worker(context)
1377
+ if worker is None:
1378
+ requested = (context.get("worker") or context.get("capability")
1379
+ or "any")
1380
+ logger.warning("No suitable worker for '%s'", requested)
1381
+ self.memory.fail_task(task_id)
1382
+ return {"success": False,
1383
+ "error": f"No suitable worker for '{requested}'"}
1384
+
1385
+ logger.info("[ROUTE] routed to worker: %s", worker.NAME)
1386
+ result = worker.run({**context, "task_id": task_id})
1387
+ if result.get("success"):
1388
+ self.memory.complete_task(task_id)
1389
+ else:
1390
+ self.memory.fail_task(task_id)
1391
+ return result
1392
+
1393
+ # ---- optimize loop (candidates -> benchmark -> select fastest correct) --
1394
+
1395
+ def optimize_loop(self, spec: "OptimizeSpec",
1396
+ candidate_provider=None,
1397
+ *,
1398
+ sequential: bool = False) -> Dict:
1399
+ """Generate variants, benchmark each, return the fastest CORRECT one.
1400
+
1401
+ Flow:
1402
+ 0. Benchmark the reference implementation. This guarantees a correct
1403
+ fallback: if no variant wins, the original is returned rather than
1404
+ a regression.
1405
+ 1. Ask the provider (LLM by default) for candidate sources.
1406
+ 2. Benchmark each valid, de-duplicated candidate against the reference.
1407
+ 3. best_attempt() selects the fastest attempt with success=1 — the
1408
+ correctness gate has already excluded wrong-but-fast candidates.
1409
+
1410
+ SECURITY: candidates are model-generated code executed in the sandbox,
1411
+ which is ISOLATION, not a security boundary, and strictly more exposed
1412
+ than running your own code. Do not point this at an untrusted model or
1413
+ host without an OS-level sandbox underneath.
1414
+ """
1415
+ if not sequential and not _optimize_sequential_env_enabled():
1416
+ return self.optimize_loop_batch(spec, candidate_provider=candidate_provider)
1417
+
1418
+ return self.optimize_loop_sequential(spec, candidate_provider=candidate_provider)
1419
+
1420
+ def optimize_loop_sequential(self, spec: "OptimizeSpec",
1421
+ candidate_provider=None) -> Dict:
1422
+ """Sequential optimize-loop implementation kept as an explicit fallback."""
1423
+ if not spec.call:
1424
+ return {"success": False, "error": "optimize_loop requires a 'call'"}
1425
+ if not spec.test:
1426
+ return {"success": False,
1427
+ "error": "optimize_loop requires a 'test' (cannot select "
1428
+ "an unverified candidate)"}
1429
+
1430
+ worker = self._select_worker({"capability": "benchmarking"})
1431
+ if worker is None:
1432
+ return {"success": False, "error": "no benchmarking worker available"}
1433
+
1434
+ if self.active_session is None:
1435
+ self.start_session(f"optimize:{spec.name}")
1436
+ task_id = self.memory.create_task(self.active_session, spec.name)
1437
+
1438
+ base_ctx = {
1439
+ "task_id": task_id,
1440
+ "setup": spec.setup,
1441
+ "call": spec.call,
1442
+ "test": spec.test,
1443
+ }
1444
+
1445
+ # 0. reference implementation (correct fallback + baseline timing)
1446
+ logger.info("optimize[%s]: benchmarking reference", spec.name)
1447
+ ref_res = worker.run({**base_ctx, "code": spec.reference_code})
1448
+ attempts0 = self.memory.get_attempts(task_id)
1449
+ original_id = attempts0[-1]["id"] if attempts0 else None
1450
+ original_median = (ref_res.get("score_vector") or {}).get("median_s")
1451
+ if not ref_res.get("success"):
1452
+ logger.warning("optimize[%s]: reference failed its own test (%s)",
1453
+ spec.name, ref_res.get("reflection"))
1454
+ self.memory.fail_task(task_id)
1455
+ return {
1456
+ "success": False,
1457
+ "error": "reference implementation failed its own test",
1458
+ "reflection": ref_res.get("reflection"),
1459
+ }
1460
+
1461
+ # 1. candidate sources
1462
+ provider = candidate_provider or self._llm_candidates
1463
+ try:
1464
+ raw = list(provider(spec))
1465
+ except Exception as e: # noqa: BLE001
1466
+ logger.warning("optimize[%s]: candidate provider error: %s",
1467
+ spec.name, e)
1468
+ raw = []
1469
+ logger.info("optimize[%s]: provider returned %d raw candidate(s)",
1470
+ spec.name, len(raw))
1471
+ if raw:
1472
+ logger.warning("optimize[%s]: executing model-generated code in the "
1473
+ "sandbox (isolation, NOT a security boundary)",
1474
+ spec.name)
1475
+ if candidate_provider is None and raw and not self.config.os_sandbox_command:
1476
+ self.memory.fail_task(task_id)
1477
+ return {
1478
+ "success": False,
1479
+ "task_id": task_id,
1480
+ "error": ("model-generated candidates require "
1481
+ "Config.os_sandbox_command for OS-level sandboxing"),
1482
+ }
1483
+
1484
+ # 2. benchmark each valid, unique candidate against the reference
1485
+ seen = {self._norm(spec.reference_code)} if spec.reference_code else set()
1486
+ accepted = 0
1487
+ for i, item in enumerate(raw, 1):
1488
+ code = self._extract_code(item)
1489
+ if not code:
1490
+ logger.warning("optimize[%s]: candidate %d not valid Python; "
1491
+ "skipped", spec.name, i)
1492
+ continue
1493
+ key = self._norm(code)
1494
+ if key in seen:
1495
+ logger.info("optimize[%s]: candidate %d duplicate; skipped",
1496
+ spec.name, i)
1497
+ continue
1498
+ seen.add(key)
1499
+ accepted += 1
1500
+ # No baseline_code here: candidates are drop-in replacements that
1501
+ # share the reference's function name, so injecting the reference
1502
+ # into the same namespace would clobber the candidate (and silently
1503
+ # re-benchmark the reference). Speedup vs the original is computed by
1504
+ # the loop from stored medians instead.
1505
+ worker.run({**base_ctx, "code": code})
1506
+
1507
+ # 3. select fastest correct attempt (reference + variants)
1508
+ winner = self.memory.best_attempt(task_id)
1509
+ all_attempts = self.memory.get_attempts(task_id)
1510
+ correct = sum(1 for a in all_attempts if a["success"])
1511
+ result: Dict[str, Any] = {
1512
+ "success": winner is not None,
1513
+ "task_id": task_id,
1514
+ "candidates_total": len(all_attempts), # reference + variants
1515
+ "variants_accepted": accepted,
1516
+ "correct": correct,
1517
+ "winner": winner,
1518
+ "winner_is_original": bool(winner and winner["id"] == original_id),
1519
+ "original_median_s": original_median,
1520
+ }
1521
+ if winner is None:
1522
+ result["summary"] = ("no correct candidate (reference and all "
1523
+ "variants failed their test)")
1524
+ logger.warning("optimize[%s]: %s", spec.name, result["summary"])
1525
+ self.memory.fail_task(task_id)
1526
+ return result
1527
+
1528
+ wmed = winner.get("median_time")
1529
+ speedup = (original_median / wmed) if (original_median and wmed) else None
1530
+ result["winner_median_s"] = wmed
1531
+ result["speedup_vs_original"] = round(speedup, 4) if speedup else None
1532
+ which = "original" if result["winner_is_original"] else "a variant"
1533
+ result["summary"] = (
1534
+ f"selected {which}: median {wmed * 1e3:.4f} ms"
1535
+ + (f"; {speedup:.2f}x vs original" if speedup else "")
1536
+ + f" ({correct}/{len(all_attempts)} correct)"
1537
+ )
1538
+ logger.info("optimize[%s]: %s", spec.name, result["summary"])
1539
+ self.memory.complete_task(task_id)
1540
+ return result
1541
+
1542
+ # ---- batch optimize: all candidates in one subprocess ----
1543
+
1544
+ def optimize_loop_batch(self, spec: "OptimizeSpec",
1545
+ candidate_provider=None) -> Dict:
1546
+ """Optimized optimize_loop: benchmarks all candidates in a single
1547
+ subprocess (3x faster on Windows by eliminating N-1 interpreter
1548
+ startups).
1549
+
1550
+ Same interface and return shape as optimize_loop, plus
1551
+ result['batch_mode'] = True.
1552
+ """
1553
+ if not spec.call:
1554
+ return {"success": False, "error": "optimize_loop requires a 'call'"}
1555
+ if not spec.test:
1556
+ return {"success": False,
1557
+ "error": "optimize_loop requires a 'test'"}
1558
+
1559
+ worker = self._select_worker({"capability": "benchmarking"})
1560
+ if worker is None:
1561
+ return {"success": False, "error": "no benchmarking worker available"}
1562
+
1563
+ if self.active_session is None:
1564
+ self.start_session(f"optimize:{spec.name}")
1565
+ task_id = self.memory.create_task(self.active_session, spec.name)
1566
+
1567
+ base_ctx = {
1568
+ "task_id": task_id,
1569
+ "setup": spec.setup,
1570
+ "call": spec.call,
1571
+ "test": spec.test,
1572
+ }
1573
+
1574
+ # Collect all candidate codes (reference first)
1575
+ all_codes = [spec.reference_code]
1576
+
1577
+ # Get variants from provider
1578
+ provider = candidate_provider or self._llm_candidates
1579
+ try:
1580
+ raw = list(provider(spec))
1581
+ except Exception as e:
1582
+ logger.warning("optimize[%s]: candidate provider error: %s",
1583
+ spec.name, e)
1584
+ raw = []
1585
+
1586
+ if candidate_provider is None and raw and not self.config.os_sandbox_command:
1587
+ self.memory.fail_task(task_id)
1588
+ return {
1589
+ "success": False,
1590
+ "task_id": task_id,
1591
+ "batch_mode": True,
1592
+ "error": ("model-generated candidates require "
1593
+ "Config.os_sandbox_command for OS-level sandboxing"),
1594
+ }
1595
+
1596
+ # Filter valid, unique candidates
1597
+ seen = {self._norm(spec.reference_code)} if spec.reference_code else set()
1598
+ accepted = 0
1599
+ for i, item in enumerate(raw, 1):
1600
+ code = self._extract_code(item)
1601
+ if not code:
1602
+ logger.warning("optimize[%s]: candidate %d not valid Python; skipped",
1603
+ spec.name, i)
1604
+ continue
1605
+ key = self._norm(code)
1606
+ if key in seen:
1607
+ continue
1608
+ seen.add(key)
1609
+ accepted += 1
1610
+ all_codes.append(code)
1611
+
1612
+ logger.info("optimize[%s]: batch benchmarking %d candidates in 1 subprocess",
1613
+ spec.name, len(all_codes))
1614
+
1615
+ # Benchmark ALL candidates in one subprocess
1616
+ results = worker.batch_run(base_ctx, all_codes)
1617
+
1618
+ # Record original (reference) info
1619
+ original_median = ((results[0].get("score_vector") or {}).get("median_s")
1620
+ if results else None)
1621
+ original_attempt_id = None
1622
+ attempts0 = self.memory.get_attempts(task_id)
1623
+ if attempts0:
1624
+ original_attempt_id = attempts0[0]["id"]
1625
+
1626
+ # Check reference correctness
1627
+ if results and not results[0].get("success"):
1628
+ logger.warning("optimize[%s]: reference failed its own test (%s)",
1629
+ spec.name, results[0].get("reflection"))
1630
+ self.memory.fail_task(task_id)
1631
+ return {
1632
+ "success": False,
1633
+ "error": "reference implementation failed its own test",
1634
+ "reflection": results[0].get("reflection"),
1635
+ }
1636
+
1637
+ # Select fastest correct attempt
1638
+ winner = self.memory.best_attempt(task_id)
1639
+ all_attempts = self.memory.get_attempts(task_id)
1640
+ correct = sum(1 for a in all_attempts if a["success"])
1641
+ result: Dict[str, Any] = {
1642
+ "success": winner is not None,
1643
+ "task_id": task_id,
1644
+ "candidates_total": len(all_attempts),
1645
+ "variants_accepted": accepted,
1646
+ "correct": correct,
1647
+ "winner": winner,
1648
+ "winner_is_original": bool(winner and winner["id"] == original_attempt_id),
1649
+ "original_median_s": original_median,
1650
+ "batch_mode": True,
1651
+ }
1652
+ if winner is None:
1653
+ result["summary"] = ("no correct candidate (reference and all "
1654
+ "variants failed their test)")
1655
+ logger.warning("optimize[%s]: %s", spec.name, result["summary"])
1656
+ self.memory.fail_task(task_id)
1657
+ return result
1658
+
1659
+ wmed = winner.get("median_time")
1660
+ speedup = (original_median / wmed) if (original_median and wmed) else None
1661
+ result["winner_median_s"] = wmed
1662
+ result["speedup_vs_original"] = round(speedup, 4) if speedup else None
1663
+ which = "original" if result["winner_is_original"] else "a variant"
1664
+ result["summary"] = (
1665
+ f"selected {which}: median {wmed * 1e3:.4f} ms"
1666
+ + (f"; {speedup:.2f}x vs original" if speedup else "")
1667
+ + f" ({correct}/{len(all_attempts)} correct)"
1668
+ )
1669
+ logger.info("optimize[%s]: %s", spec.name, result["summary"])
1670
+ self.memory.complete_task(task_id)
1671
+ return result
1672
+
1673
+ def _llm_candidates(self, spec: "OptimizeSpec") -> List[str]:
1674
+ """Default provider: ask the LLM for n_variants drop-in replacements."""
1675
+ prompt = (
1676
+ "You are optimizing a Python function for speed.\n"
1677
+ "Return ONLY a single Python code block containing an optimized, "
1678
+ "drop-in replacement. It MUST define the same function name(s) and "
1679
+ "signature and be a correct, faithful replacement. No explanations, "
1680
+ "no tests, no examples — only the implementation.\n\n"
1681
+ "Reference implementation:\n```python\n"
1682
+ f"{spec.reference_code}\n```\n"
1683
+ f"It is invoked as: {spec.call}\n"
1684
+ )
1685
+ return [self.router.generate(prompt, spec.model)
1686
+ for _ in range(max(1, spec.n_variants))]
1687
+
1688
+ @staticmethod
1689
+ def _extract_code(text: str) -> Optional[str]:
1690
+ """Pull a code block out of an LLM reply; return None if not valid
1691
+ Python (this is what rejects the ollama stub and prose-only replies)."""
1692
+ if not text:
1693
+ return None
1694
+ m = re.search(r"```(?:python)?\s*(.*?)```", text, re.DOTALL)
1695
+ code = (m.group(1) if m else text).strip()
1696
+ if not code:
1697
+ return None
1698
+ try:
1699
+ ast.parse(code)
1700
+ except SyntaxError:
1701
+ return None
1702
+ return code
1703
+
1704
+ @staticmethod
1705
+ def _norm(code: str) -> str:
1706
+ return "\n".join(ln.rstrip()
1707
+ for ln in (code or "").strip().splitlines())
1708
+
1709
+ def shutdown(self) -> None:
1710
+ if self.active_session is not None:
1711
+ tasks = self.memory.get_tasks(self.active_session)
1712
+ if any(t["status"] == "failed" for t in tasks):
1713
+ self.memory.fail_session(self.active_session)
1714
+ elif any(t["status"] == "blocked" for t in tasks):
1715
+ self.memory.block_session(self.active_session)
1716
+ else:
1717
+ self.memory.complete_session(self.active_session)
1718
+ self.memory.close()
1719
+
1720
+
1721
+
1722
+ def _demo_candidate_provider(spec: "OptimizeSpec") -> List[str]:
1723
+ """Built-in stand-in for the LLM, used when ollama is unavailable so the
1724
+ optimize-loop demo is runnable out of the box.
1725
+
1726
+ Returns three variants of the demo `total` function: one faster + correct
1727
+ (builtin sum), one slower + correct (builds an intermediate list), and one
1728
+ INCORRECT (off-by-one) to show the correctness gate excluding it.
1729
+ """
1730
+ return [
1731
+ "def total(xs):\n return sum(xs)",
1732
+ "def total(xs):\n return sum([x for x in xs])",
1733
+ "def total(xs):\n return sum(xs) + 1", # wrong on purpose
1734
+ ]
1735
+
1736
+
1737
+ # =============================================================================
1738
+ # CLI / MAIN
1739
+ # =============================================================================
1740
+ def main() -> None:
1741
+ import argparse
1742
+
1743
+ # Force UTF-8 on Windows consoles that default to cp1252
1744
+ try:
1745
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
1746
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
1747
+ except AttributeError:
1748
+ pass # older Python without reconfigure
1749
+
1750
+ parser = argparse.ArgumentParser(description="Autonomous Engineer v1.0")
1751
+ parser.add_argument(
1752
+ "command", choices=["optimize", "optimize-loop", "latency", "status"],
1753
+ default="optimize", nargs="?",
1754
+ )
1755
+ parser.add_argument("--target", default="matmul_demo")
1756
+ parser.add_argument("--model", default="llama3.1")
1757
+ parser.add_argument("--variants", type=int, default=3,
1758
+ help="candidates to generate in optimize-loop")
1759
+ parser.add_argument("--repeats", type=int, default=5,
1760
+ help="timed runs per mode in latency")
1761
+ parser.add_argument("--log-level", default="INFO",
1762
+ help="DEBUG, INFO, WARNING, ERROR (default: INFO)")
1763
+ parser.add_argument("--log-file", default=None,
1764
+ help="optional path to also write logs to")
1765
+ parser.add_argument("--sequential", action="store_true",
1766
+ help="use legacy sequential optimize-loop instead of batch mode")
1767
+ args = parser.parse_args()
1768
+
1769
+ setup_logging(args.log_level, args.log_file)
1770
+ if args.command == "status":
1771
+ worker_names = sorted(cls.NAME for cls in Scheduler._iter_subclasses(Worker))
1772
+ print("Status: Kernel running. Workers:", worker_names)
1773
+ return
1774
+
1775
+ config = Config(default_model=args.model)
1776
+ scheduler = Scheduler(config)
1777
+
1778
+ try:
1779
+ if args.command == "optimize":
1780
+ scheduler.start_session(f"Optimize {args.target}")
1781
+ # Demo: replace a hand-rolled summation loop (baseline) with the
1782
+ # built-in sum (candidate) and measure the real speedup. Swap these
1783
+ # keys to benchmark your own code.
1784
+ context = {
1785
+ "setup": "data = list(range(10000))",
1786
+ "baseline_code": (
1787
+ "def total(xs):\n"
1788
+ " s = 0\n"
1789
+ " for x in xs:\n"
1790
+ " s += x\n"
1791
+ " return s"
1792
+ ),
1793
+ "baseline_call": "total(data)",
1794
+ "call": "sum(data)",
1795
+ "test": "assert sum([1, 2, 3]) == 6",
1796
+ "capability": "optimization", # route by capability, not name
1797
+ "target": args.target,
1798
+ }
1799
+ result = scheduler.run_task("performance_optimize", context)
1800
+ print("[OK] Optimization complete:", result)
1801
+ elif args.command == "optimize-loop":
1802
+ spec = OptimizeSpec(
1803
+ name="optimize_total",
1804
+ setup="data = list(range(10000))",
1805
+ reference_code=(
1806
+ "def total(xs):\n"
1807
+ " s = 0\n"
1808
+ " for x in xs:\n"
1809
+ " s += x\n"
1810
+ " return s"
1811
+ ),
1812
+ call="total(data)",
1813
+ test="assert total([1, 2, 3]) == 6",
1814
+ n_variants=args.variants,
1815
+ )
1816
+ # Real LLM when ollama is present; deterministic demo otherwise.
1817
+ provider = None if HAS_OLLAMA else _demo_candidate_provider
1818
+ if provider is not None:
1819
+ logger.info("ollama unavailable; using built-in demo candidate "
1820
+ "provider (stand-in for the LLM)")
1821
+ result = scheduler.optimize_loop(
1822
+ spec, candidate_provider=provider, sequential=args.sequential
1823
+ )
1824
+ print("[OK] Optimize-loop:", result.get("summary"))
1825
+ print(" winner_is_original:", result.get("winner_is_original"),
1826
+ "| speedup_vs_original:", result.get("speedup_vs_original"))
1827
+ elif args.command == "latency":
1828
+ # Real model if ollama is present; a SIMULATED model otherwise so
1829
+ # the test runs offline (numbers then illustrate behavior only).
1830
+ simulated = not HAS_OLLAMA
1831
+ if simulated:
1832
+ logger.info("ollama unavailable; using a SIMULATED model "
1833
+ "(numbers illustrate behavior, not a real model)")
1834
+ router = LLMRouter(
1835
+ config,
1836
+ engine=make_simulated_blocking(),
1837
+ stream_engine=make_simulated_stream(),
1838
+ )
1839
+ else:
1840
+ router = LLMRouter(config)
1841
+
1842
+ prompt = ("Write one short paragraph on why streaming reduces "
1843
+ "perceived latency.")
1844
+
1845
+ # 1) one visible streamed run so the display can be seen updating
1846
+ print("--- streamed display (tokens appear as they arrive) ---")
1847
+ t0 = time.perf_counter()
1848
+ first = None
1849
+ for chunk in router.stream(prompt, args.model):
1850
+ if first is None:
1851
+ first = time.perf_counter()
1852
+ sys.stdout.write(chunk)
1853
+ sys.stdout.flush()
1854
+ print()
1855
+ if first is not None:
1856
+ print("(first token visible after %.1f ms)"
1857
+ % ((first - t0) * 1e3))
1858
+
1859
+ # 2) timed comparison with a no-op sink (clean numbers)
1860
+ s = measure_latency(router, prompt, model=args.model,
1861
+ repeats=args.repeats, stream=True)
1862
+ b = measure_latency(router, prompt, model=args.model,
1863
+ repeats=args.repeats, stream=False)
1864
+ tag = " (simulated)" if simulated else ""
1865
+ print("\n--- call->display latency, %d runs%s ---"
1866
+ % (args.repeats, tag))
1867
+ print(" streaming TTFD median: %8.1f ms | total median: %8.1f ms"
1868
+ % (s["ttfd"]["median"] * 1e3, s["total"]["median"] * 1e3))
1869
+ print(" blocking TTFD median: %8.1f ms | total median: %8.1f ms"
1870
+ % (b["ttfd"]["median"] * 1e3, b["total"]["median"] * 1e3))
1871
+ if s["ttfd"]["median"] > 0:
1872
+ ratio = b["ttfd"]["median"] / s["ttfd"]["median"]
1873
+ print(" -> streaming shows first output %.1fx sooner "
1874
+ "(total compute ~unchanged)" % ratio)
1875
+ else:
1876
+ print("Status: Kernel running. Workers:",
1877
+ list(scheduler.workers.keys()))
1878
+ finally:
1879
+ scheduler.shutdown()
1880
+
1881
+
1882
+ if __name__ == "__main__":
1883
+ main()
1884
+
1885
+
1886
+ # =============================================================================
1887
+ # CHANGELOG (hardening pass)
1888
+ # =============================================================================
1889
+ # 1. Shebang fixed: "!/usr/bin/env python3" -> "#!/usr/bin/env python3".
1890
+ # 2. ExecutionSandbox: enforces timeout via subprocess; optional POSIX memory
1891
+ # cap; captures stdout/stderr/returncode; cleans up temp scripts. Now an
1892
+ # honest isolation boundary (documented as NOT a security boundary).
1893
+ # 3. MemoryEngine: applies PRAGMA journal_mode (WAL) from Config; enables
1894
+ # PRAGMA foreign_keys=ON; check_same_thread=False with a write lock;
1895
+ # added start_session/create_task/close helpers.
1896
+ # 4. Scheduler: creates real session + task rows so the FK chain validates;
1897
+ # wires Config.workspace / timeout / memory limit into the sandbox;
1898
+ # recursive, deduplicated worker discovery; guarded main() with try/finally.
1899
+ # 5. Pruned unused imports (ast, random, traceback, datetime, numpy,
1900
+ # importlib.util, field, Type, Callable, Set).
1901
+ #
1902
+ # Deferred (recommended, not done to limit scope):
1903
+ # - Replace print() with the logging module for level control + file output.
1904
+ # - Add query helpers + indexes to MemoryEngine for the read path.
1905
+ # - Capability-based routing instead of name fallback.
1906
+ #
1907
+ # Phase-2 update — PerformanceWorker now executes + benchmarks for real:
1908
+ # - Builds a single measurement harness, runs it once in the sandbox (so
1909
+ # interpreter startup is paid once, not per repeat), times each call with
1910
+ # perf_counter, and parses raw timings off a sentinel stdout line.
1911
+ # - Computes median/mean/stdev/min; persists a benchmarks row per attempt.
1912
+ # - Optional `test` => real correctness (True/False), else None ("not
1913
+ # checked"). Optional baseline => measured speedup. No fabricated scores.
1914
+ # - MemoryEngine.log_benchmark added; Config gained benchmark_warmup.
1915
+ #
1916
+ # Known limits of the benchmark path (by design, documented for honesty):
1917
+ # - Wall-clock on one machine; default_timeout covers the WHOLE harness, so a
1918
+ # too-low timeout yields no data rather than partial data.
1919
+ # - 'confidence' = 1 - relative stdev (measurement stability), NOT a
1920
+ # statistical CI. Default 5 repeats is low; raise benchmark_repeats.
1921
+ # - Harness injects caller-provided code as text; safe only because the
1922
+ # sandbox is isolation, NOT a security boundary (see ExecutionSandbox).
1923
+ #
1924
+ # Phase-2.1 update — cleared the deferred list:
1925
+ # - Logging: print() replaced by a package logger (NullHandler by default;
1926
+ # setup_logging() wires stderr + optional file). CLI gains --log-level /
1927
+ # --log-file. Diagnostics -> logger (stderr); results stay on stdout.
1928
+ # - Read path: indexes on FK/lookup columns; query helpers get_session,
1929
+ # get_tasks, get_attempts, recent_attempts, and best_attempt() (fastest
1930
+ # SUCCESSFUL attempt — the selection primitive for a future optimize loop).
1931
+ # - Routing: capability-based via Scheduler._select_worker (explicit name >
1932
+ # capability > can_run fallback; lowest PRIORITY wins, name breaks ties).
1933
+ # Workers are now persisted to the `workers` table on discovery, so routing
1934
+ # inputs are introspectable instead of the table being dead.
1935
+ #
1936
+ # Phase-2.2 update — the optimize loop is wired up:
1937
+ # - Scheduler.optimize_loop(spec, candidate_provider=None): benchmarks the
1938
+ # reference (candidate 0, the correct fallback), generates variants via the
1939
+ # provider (LLMRouter by default; pluggable for testing / no-ollama use),
1940
+ # benchmarks each valid+unique one vs the reference, then best_attempt()
1941
+ # selects the fastest CORRECT result. Wrong candidates are excluded by the
1942
+ # correctness gate; if nothing beats the original, the original is returned.
1943
+ # - _extract_code (ast-validated, fence-aware) rejects prose/stub replies;
1944
+ # _norm de-dupes; candidates routed via capability ("benchmarking").
1945
+ # - CLI: `optimize-loop` command (+ --variants); OptimizeSpec dataclass with a
1946
+ # required `test`. _demo_candidate_provider stands in for the LLM offline.
1947
+ # - SECURITY: this runs MODEL-GENERATED code in the sandbox — isolation, not a
1948
+ # security boundary, and more exposed than running your own code.
1949
+ #
1950
+ # Phase-2.3 update — call->display latency probe + streaming:
1951
+ # - LLMRouter gained stream() (ollama stream=True) plus injectable `engine` /
1952
+ # `stream_engine` for offline testing, mirroring the candidate_provider
1953
+ # pattern. generate() is unchanged for existing callers.
1954
+ # - measure_latency() reports TTFD (time to first displayed output) and total
1955
+ # call->display, median/stdev/min, for streaming vs blocking. TTFD is the
1956
+ # perceived-latency metric; streaming collapses it to time-to-first-token
1957
+ # while total compute is unchanged.
1958
+ # - make_simulated_stream / make_simulated_blocking: matched-cost fakes so the
1959
+ # `latency` CLI command runs offline; real numbers come from a real model.
1960
+ # - CLI: `latency` command (+ --repeats). All new output is ASCII to match the
1961
+ # console encoding fix.
1962
+ #
1963
+ # Phase-3 update — harness integration + hardening (algo_cli):
1964
+ # - Copied to algo_cli/intelligence/autonomous_engineer.py (clean module name).
1965
+ # - Exported from algo_cli/intelligence/__init__.py as AEConfig, MemoryEngine,
1966
+ # ExecutionSandbox, PerformanceWorker, LLMRouter, AEScheduler, OptimizeSpec.
1967
+ # - Fixed: emoji -> ASCII tags ([OK], [TASK], [ROUTE]) + UTF-8 reconfigure.
1968
+ # - Fixed: optimize_loop hard-fails when reference fails its own test.
1969
+ # - Fixed: task/session status transitions (complete_task, fail_task,
1970
+ # complete_session) at all exit paths.
1971
+ # - Fixed: benchmark harness uses _ae_ prefixed internals + temp JSON file
1972
+ # instead of stdout sentinel (prevents spoofing by model-generated code).
1973
+ # - Fixed: Config save/load uses encoding="utf-8".
1974
+ # - Fixed: result file path uses .resolve() for subprocess cwd compatibility.
1975
+ # - Added: 17 tests in tests/test_autonomous_engineer.py.
1976
+ # - Added: 10 empirical algorithm benchmarks (B178-B187) in ALGO.md.