@trac3er/oh-my-god 2.0.0-beta.2 → 2.1.0-alpha

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 (47) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/OMG-setup.sh +33 -0
  4. package/README.md +43 -0
  5. package/claude_experimental/__init__.py +27 -0
  6. package/claude_experimental/_compat.py +12 -0
  7. package/claude_experimental/_degradation.py +210 -0
  8. package/claude_experimental/_flags.py +35 -0
  9. package/claude_experimental/_lifecycle.py +122 -0
  10. package/claude_experimental/integration/__init__.py +16 -0
  11. package/claude_experimental/integration/_placeholder.py +7 -0
  12. package/claude_experimental/integration/autotuner.py +182 -0
  13. package/claude_experimental/integration/checkpoints.py +327 -0
  14. package/claude_experimental/integration/experiments.py +302 -0
  15. package/claude_experimental/integration/openapi_gen.py +428 -0
  16. package/claude_experimental/integration/streaming.py +131 -0
  17. package/claude_experimental/integration/telemetry.py +287 -0
  18. package/claude_experimental/memory/__init__.py +16 -0
  19. package/claude_experimental/memory/_placeholder.py +7 -0
  20. package/claude_experimental/memory/api.py +434 -0
  21. package/claude_experimental/memory/augmented_generation.py +142 -0
  22. package/claude_experimental/memory/episodic.py +190 -0
  23. package/claude_experimental/memory/failure_learning.py +183 -0
  24. package/claude_experimental/memory/migrate.py +169 -0
  25. package/claude_experimental/memory/procedural.py +212 -0
  26. package/claude_experimental/memory/semantic.py +376 -0
  27. package/claude_experimental/memory/store.py +310 -0
  28. package/claude_experimental/parallel/__init__.py +17 -0
  29. package/claude_experimental/parallel/_placeholder.py +7 -0
  30. package/claude_experimental/parallel/aggregation.py +131 -0
  31. package/claude_experimental/parallel/api.py +244 -0
  32. package/claude_experimental/parallel/executor.py +110 -0
  33. package/claude_experimental/parallel/ralph_bridge.py +164 -0
  34. package/claude_experimental/parallel/sandbox.py +314 -0
  35. package/claude_experimental/parallel/scaling.py +171 -0
  36. package/claude_experimental/parallel/ultraworker.py +285 -0
  37. package/claude_experimental/patterns/__init__.py +16 -0
  38. package/claude_experimental/patterns/_placeholder.py +7 -0
  39. package/claude_experimental/patterns/antipatterns.py +454 -0
  40. package/claude_experimental/patterns/api.py +196 -0
  41. package/claude_experimental/patterns/extractor.py +163 -0
  42. package/claude_experimental/patterns/mining.py +219 -0
  43. package/claude_experimental/patterns/refactoring.py +234 -0
  44. package/hooks/_common.py +3 -1
  45. package/package.json +1 -1
  46. package/runtime/subagent_dispatcher.py +109 -9
  47. package/settings.json +6 -1
@@ -0,0 +1,182 @@
1
+ """AutoTuner — Automatic parameter tuning from telemetry signals.
2
+
3
+ Reads P99 latency and pool utilization from TelemetryCollector,
4
+ adjusts DynamicPool worker count using simple threshold-based rules:
5
+ - Scale up: P99 > 2× target_p99_ms → increase workers (up to max_workers)
6
+ - Scale down: utilization < 30% for >30s → decrease workers (down to min_workers)
7
+
8
+ All tuning decisions are logged as ``autotuner_adjustment`` counter metrics.
9
+
10
+ Feature-gated via OMG_ADVANCED_INTEGRATION_ENABLED.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import math
15
+ import time
16
+ from typing import TYPE_CHECKING, cast
17
+
18
+ if TYPE_CHECKING:
19
+ from claude_experimental.integration.telemetry import TelemetryCollector
20
+ from claude_experimental.parallel.scaling import DynamicPool
21
+
22
+
23
+ class AutoTuner:
24
+ """Automatic parameter tuning from telemetry signals.
25
+
26
+ Monitors P99 latency of ``task_duration_ms`` histogram metrics and
27
+ pool utilization, adjusting DynamicPool worker count with simple
28
+ threshold rules. No Bayesian optimization — just reliable thresholds.
29
+
30
+ Args:
31
+ pool: DynamicPool instance to tune.
32
+ telemetry: TelemetryCollector for reading metrics and logging decisions.
33
+ min_workers: Minimum worker count floor (default 1).
34
+ max_workers: Maximum worker count ceiling (default 8).
35
+ target_p99_ms: Target P99 latency in milliseconds (default 5000).
36
+ """
37
+
38
+ _SUSTAINED_LOW_UTIL_SECONDS: float = 30.0
39
+ _LOW_UTIL_THRESHOLD: float = 0.30 # 30%
40
+
41
+ def __init__(
42
+ self,
43
+ pool: "DynamicPool",
44
+ telemetry: "TelemetryCollector",
45
+ min_workers: int = 1,
46
+ max_workers: int = 8,
47
+ target_p99_ms: float = 5000,
48
+ ) -> None:
49
+ from claude_experimental.integration import _require_enabled
50
+
51
+ _require_enabled()
52
+
53
+ if min_workers < 1:
54
+ raise ValueError("min_workers must be >= 1")
55
+ if max_workers < min_workers:
56
+ raise ValueError("max_workers must be >= min_workers")
57
+ if target_p99_ms <= 0:
58
+ raise ValueError("target_p99_ms must be > 0")
59
+
60
+ self._pool = pool
61
+ self._telemetry = telemetry
62
+ self._min_workers = min_workers
63
+ self._max_workers = max_workers
64
+ self._target_p99_ms = target_p99_ms
65
+
66
+ # Hysteresis for sustained low-utilization scale-down
67
+ self._low_util_since: float | None = None
68
+
69
+ def tune_cycle(self) -> dict[str, int]:
70
+ """Run one tuning cycle.
71
+
72
+ Reads P99 latency and pool utilization, applies scaling rules,
73
+ and returns a dict of parameter changes applied.
74
+
75
+ Returns:
76
+ ``{"max_workers": N}`` when an adjustment was made.
77
+ Empty dict ``{}`` if no adjustment was needed.
78
+ """
79
+ from claude_experimental.integration import _require_enabled
80
+
81
+ _require_enabled()
82
+
83
+ stats = self._pool.pool_stats()
84
+ current_size: int = stats["pool_size"]
85
+
86
+ # --- Rule 1: P99 > 2× target → scale UP ---
87
+ p99 = self._compute_p99()
88
+ if p99 is not None and p99 > 2 * self._target_p99_ms:
89
+ new_size = min(current_size + 1, self._max_workers)
90
+ if new_size > current_size:
91
+ self._apply_resize(
92
+ new_size,
93
+ direction="up",
94
+ reason=f"p99={p99:.0f}ms > 2x target={self._target_p99_ms:.0f}ms",
95
+ )
96
+ self._low_util_since = None
97
+ return {"max_workers": new_size}
98
+
99
+ # --- Rule 2: utilization < 30% sustained → scale DOWN ---
100
+ utilization = self._compute_utilization(stats)
101
+ if utilization < self._LOW_UTIL_THRESHOLD and current_size > self._min_workers:
102
+ now = time.monotonic()
103
+ if self._low_util_since is None:
104
+ self._low_util_since = now
105
+ elif now - self._low_util_since >= self._SUSTAINED_LOW_UTIL_SECONDS:
106
+ new_size = max(current_size - 1, self._min_workers)
107
+ if new_size < current_size:
108
+ self._apply_resize(
109
+ new_size,
110
+ direction="down",
111
+ reason=(
112
+ f"utilization={utilization:.0%} < 30% "
113
+ f"for >{self._SUSTAINED_LOW_UTIL_SECONDS:.0f}s"
114
+ ),
115
+ )
116
+ self._low_util_since = None
117
+ return {"max_workers": new_size}
118
+ else:
119
+ # Reset hysteresis if utilization recovered
120
+ self._low_util_since = None
121
+
122
+ return {}
123
+
124
+ def get_current_params(self) -> dict[str, object]:
125
+ """Return current tunable parameters.
126
+
127
+ Returns:
128
+ Dict with ``min_workers``, ``max_workers``, ``current_workers``,
129
+ and ``target_p99_ms``.
130
+ """
131
+ from claude_experimental.integration import _require_enabled
132
+
133
+ _require_enabled()
134
+
135
+ stats = self._pool.pool_stats()
136
+ return {
137
+ "min_workers": self._min_workers,
138
+ "max_workers": self._max_workers,
139
+ "current_workers": stats["pool_size"],
140
+ "target_p99_ms": self._target_p99_ms,
141
+ }
142
+
143
+ # ------------------------------------------------------------------
144
+ # Internal helpers
145
+ # ------------------------------------------------------------------
146
+
147
+ def _compute_p99(self) -> float | None:
148
+ """Compute P99 latency from ``task_duration_ms`` histogram metrics.
149
+
150
+ Queries the last 5 minutes of histogram data and computes the
151
+ 99th percentile from raw values.
152
+
153
+ Returns:
154
+ P99 latency in milliseconds, or ``None`` if no data available.
155
+ """
156
+ rows = self._telemetry.query(
157
+ "task_duration_ms", metric_type="histogram", since_minutes=5
158
+ )
159
+ if not rows:
160
+ return None
161
+
162
+ values = sorted(cast(float, row["value"]) for row in rows)
163
+ # 99th percentile: ceiling-based index
164
+ idx = int(math.ceil(len(values) * 0.99)) - 1
165
+ idx = max(0, min(idx, len(values) - 1))
166
+ return values[idx]
167
+
168
+ def _compute_utilization(self, stats: dict[str, int]) -> float:
169
+ """Compute pool utilization as ``active / pool_size``."""
170
+ pool_size = stats["pool_size"]
171
+ if pool_size == 0:
172
+ return 0.0
173
+ return stats["active"] / pool_size
174
+
175
+ def _apply_resize(self, new_size: int, *, direction: str, reason: str) -> None:
176
+ """Resize the pool and log the tuning decision as telemetry."""
177
+ self._pool._resize(new_size)
178
+ self._telemetry.record_counter(
179
+ "autotuner_adjustment",
180
+ value=1,
181
+ tags={"direction": direction, "reason": reason},
182
+ )
@@ -0,0 +1,327 @@
1
+ """Human-in-the-loop checkpoint system for pausing execution at critical decision points.
2
+
3
+ Provides a polling-based checkpoint mechanism that allows agents to pause at
4
+ critical decision points (verification, decision, clarification) and wait for
5
+ human input before proceeding. Checkpoints are persisted as JSON files in
6
+ `.omg/state/checkpoints/` with atomic writes for crash safety.
7
+
8
+ Feature-gated behind OMG_ADVANCED_INTEGRATION_ENABLED=1.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import os
14
+ import tempfile
15
+ import uuid
16
+ from datetime import datetime, timezone
17
+ from enum import Enum
18
+ from typing import Any
19
+
20
+
21
+ # ---------------------------------------------------------------------------
22
+ # Constants
23
+ # ---------------------------------------------------------------------------
24
+
25
+ _CHECKPOINT_DIR = os.path.join(".omg", "state", "checkpoints")
26
+ _SCHEMA_VERSION = 1
27
+
28
+
29
+ class CheckpointType(str, Enum):
30
+ """Supported checkpoint types."""
31
+
32
+ VERIFICATION = "VERIFICATION"
33
+ DECISION = "DECISION"
34
+ CLARIFICATION = "CLARIFICATION"
35
+
36
+
37
+ class CheckpointStatus(str, Enum):
38
+ """Checkpoint lifecycle states."""
39
+
40
+ PENDING = "pending"
41
+ RESOLVED = "resolved"
42
+ EXPIRED = "expired"
43
+
44
+
45
+ # ---------------------------------------------------------------------------
46
+ # Helpers
47
+ # ---------------------------------------------------------------------------
48
+
49
+ def _require_integration() -> None:
50
+ """Gate all public operations behind the ADVANCED_INTEGRATION flag."""
51
+ from claude_experimental.integration import _require_enabled
52
+ _require_enabled()
53
+
54
+
55
+ def _now_iso() -> str:
56
+ return datetime.now(timezone.utc).isoformat()
57
+
58
+
59
+ def _parse_iso(iso_str: str) -> datetime:
60
+ # Handle both +00:00 and Z suffixes
61
+ s = iso_str.replace("Z", "+00:00")
62
+ return datetime.fromisoformat(s)
63
+
64
+
65
+ def _atomic_json_write(path: str, data: dict[str, Any]) -> None:
66
+ """Write JSON atomically: temp file → os.replace().
67
+
68
+ Creates parent directories if needed.
69
+ """
70
+ parent = os.path.dirname(path)
71
+ if parent:
72
+ os.makedirs(parent, exist_ok=True)
73
+ fd, tmp_path = tempfile.mkstemp(
74
+ dir=parent, suffix=".tmp", prefix=".ckpt_"
75
+ )
76
+ try:
77
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
78
+ json.dump(data, f, indent=2, sort_keys=True)
79
+ os.replace(tmp_path, path)
80
+ except BaseException:
81
+ # Clean up temp file on any failure
82
+ try:
83
+ os.unlink(tmp_path)
84
+ except OSError:
85
+ pass
86
+ raise
87
+
88
+
89
+ def _read_checkpoint_file(path: str) -> dict[str, Any] | None:
90
+ """Read and parse a checkpoint JSON file. Returns None on failure."""
91
+ try:
92
+ with open(path, "r", encoding="utf-8") as f:
93
+ return json.load(f) # type: ignore[no-any-return]
94
+ except (OSError, json.JSONDecodeError):
95
+ return None
96
+
97
+
98
+ # ---------------------------------------------------------------------------
99
+ # CheckpointManager
100
+ # ---------------------------------------------------------------------------
101
+
102
+ class CheckpointManager:
103
+ """Manages human-in-the-loop checkpoints for pausing execution.
104
+
105
+ Checkpoints are persisted as individual JSON files under
106
+ ``{base_dir}/.omg/state/checkpoints/{checkpoint_id}.json``.
107
+
108
+ Usage::
109
+
110
+ mgr = CheckpointManager()
111
+ cid = mgr.create_checkpoint(
112
+ checkpoint_type="DECISION",
113
+ description="Choose deployment target",
114
+ options=["staging", "production"],
115
+ )
116
+ # ... poll or wait ...
117
+ mgr.resume_checkpoint(cid, decision="staging")
118
+ """
119
+
120
+ def __init__(self, base_dir: str = ".") -> None:
121
+ self._checkpoint_dir = os.path.join(base_dir, _CHECKPOINT_DIR)
122
+
123
+ # -- public API ---------------------------------------------------------
124
+
125
+ def create_checkpoint(
126
+ self,
127
+ checkpoint_type: str,
128
+ description: str,
129
+ options: list[str] | None = None,
130
+ timeout_seconds: int = 3600,
131
+ ) -> str:
132
+ """Create a new pending checkpoint.
133
+
134
+ Args:
135
+ checkpoint_type: One of VERIFICATION, DECISION, CLARIFICATION.
136
+ description: Human-readable description of what needs attention.
137
+ options: Optional list of valid choices (useful for DECISION type).
138
+ timeout_seconds: Seconds until the checkpoint auto-expires (default 3600).
139
+
140
+ Returns:
141
+ checkpoint_id: UUID string for the new checkpoint.
142
+
143
+ Raises:
144
+ RuntimeError: If the feature flag is disabled.
145
+ ValueError: If checkpoint_type is invalid.
146
+ """
147
+ _require_integration()
148
+
149
+ # Validate type
150
+ try:
151
+ ct = CheckpointType(checkpoint_type)
152
+ except ValueError:
153
+ valid = ", ".join(t.value for t in CheckpointType)
154
+ raise ValueError(
155
+ f"Invalid checkpoint type '{checkpoint_type}'. "
156
+ f"Must be one of: {valid}"
157
+ ) from None
158
+
159
+ checkpoint_id = str(uuid.uuid4())
160
+ now = datetime.now(timezone.utc)
161
+ expires_at = datetime.fromtimestamp(
162
+ now.timestamp() + timeout_seconds, tz=timezone.utc
163
+ )
164
+
165
+ checkpoint_data: dict[str, Any] = {
166
+ "checkpoint_id": checkpoint_id,
167
+ "type": ct.value,
168
+ "description": description,
169
+ "options": options if options is not None else [],
170
+ "status": CheckpointStatus.PENDING.value,
171
+ "decision": None,
172
+ "created_at": now.isoformat(),
173
+ "expires_at": expires_at.isoformat(),
174
+ "schema_version": _SCHEMA_VERSION,
175
+ }
176
+
177
+ path = os.path.join(self._checkpoint_dir, f"{checkpoint_id}.json")
178
+ _atomic_json_write(path, checkpoint_data)
179
+ return checkpoint_id
180
+
181
+ def get_checkpoint(self, checkpoint_id: str) -> dict[str, Any]:
182
+ """Retrieve the current state of a checkpoint.
183
+
184
+ Args:
185
+ checkpoint_id: UUID of the checkpoint.
186
+
187
+ Returns:
188
+ Checkpoint dict with all fields.
189
+
190
+ Raises:
191
+ RuntimeError: If the feature flag is disabled.
192
+ KeyError: If checkpoint not found.
193
+ """
194
+ _require_integration()
195
+
196
+ path = os.path.join(self._checkpoint_dir, f"{checkpoint_id}.json")
197
+ data = _read_checkpoint_file(path)
198
+ if data is None:
199
+ raise KeyError(f"Checkpoint not found: {checkpoint_id}")
200
+
201
+ # Auto-expire if past deadline
202
+ if data.get("status") == CheckpointStatus.PENDING.value:
203
+ expires_at = _parse_iso(str(data["expires_at"]))
204
+ if datetime.now(timezone.utc) > expires_at:
205
+ data["status"] = CheckpointStatus.EXPIRED.value
206
+ _atomic_json_write(path, data)
207
+
208
+ return data
209
+
210
+ def resume_checkpoint(self, checkpoint_id: str, decision: str) -> bool:
211
+ """Resolve a pending checkpoint with a human decision.
212
+
213
+ Args:
214
+ checkpoint_id: UUID of the checkpoint to resume.
215
+ decision: The decision string from the human.
216
+
217
+ Returns:
218
+ True if the checkpoint was successfully resolved.
219
+ False if the checkpoint was not in pending state.
220
+
221
+ Raises:
222
+ RuntimeError: If the feature flag is disabled.
223
+ KeyError: If checkpoint not found.
224
+ """
225
+ _require_integration()
226
+
227
+ path = os.path.join(self._checkpoint_dir, f"{checkpoint_id}.json")
228
+ data = _read_checkpoint_file(path)
229
+ if data is None:
230
+ raise KeyError(f"Checkpoint not found: {checkpoint_id}")
231
+
232
+ # Can only resume pending checkpoints
233
+ if data.get("status") != CheckpointStatus.PENDING.value:
234
+ return False
235
+
236
+ # Check expiry
237
+ expires_at = _parse_iso(str(data["expires_at"]))
238
+ if datetime.now(timezone.utc) > expires_at:
239
+ data["status"] = CheckpointStatus.EXPIRED.value
240
+ _atomic_json_write(path, data)
241
+ return False
242
+
243
+ data["status"] = CheckpointStatus.RESOLVED.value
244
+ data["decision"] = decision
245
+ _atomic_json_write(path, data)
246
+ return True
247
+
248
+ def list_pending(self) -> list[dict[str, Any]]:
249
+ """List all checkpoints currently in pending state.
250
+
251
+ Returns:
252
+ List of checkpoint dicts with status=pending.
253
+ Expired checkpoints are auto-transitioned and excluded.
254
+
255
+ Raises:
256
+ RuntimeError: If the feature flag is disabled.
257
+ """
258
+ _require_integration()
259
+
260
+ pending: list[dict[str, Any]] = []
261
+
262
+ if not os.path.isdir(self._checkpoint_dir):
263
+ return pending
264
+
265
+ now = datetime.now(timezone.utc)
266
+
267
+ for filename in os.listdir(self._checkpoint_dir):
268
+ if not filename.endswith(".json"):
269
+ continue
270
+
271
+ path = os.path.join(self._checkpoint_dir, filename)
272
+ data = _read_checkpoint_file(path)
273
+ if data is None:
274
+ continue
275
+
276
+ if data.get("status") != CheckpointStatus.PENDING.value:
277
+ continue
278
+
279
+ # Auto-expire
280
+ expires_at = _parse_iso(str(data["expires_at"]))
281
+ if now > expires_at:
282
+ data["status"] = CheckpointStatus.EXPIRED.value
283
+ _atomic_json_write(path, data)
284
+ continue
285
+
286
+ pending.append(data)
287
+
288
+ return pending
289
+
290
+ def cleanup_expired(self) -> int:
291
+ """Remove checkpoint files that have expired.
292
+
293
+ Deletes files where expires_at < now, regardless of current status.
294
+
295
+ Returns:
296
+ Number of expired checkpoint files removed.
297
+
298
+ Raises:
299
+ RuntimeError: If the feature flag is disabled.
300
+ """
301
+ _require_integration()
302
+
303
+ removed = 0
304
+
305
+ if not os.path.isdir(self._checkpoint_dir):
306
+ return removed
307
+
308
+ now = datetime.now(timezone.utc)
309
+
310
+ for filename in os.listdir(self._checkpoint_dir):
311
+ if not filename.endswith(".json"):
312
+ continue
313
+
314
+ path = os.path.join(self._checkpoint_dir, filename)
315
+ data = _read_checkpoint_file(path)
316
+ if data is None:
317
+ continue
318
+
319
+ expires_at = _parse_iso(str(data["expires_at"]))
320
+ if now > expires_at:
321
+ try:
322
+ os.unlink(path)
323
+ removed += 1
324
+ except OSError:
325
+ pass
326
+
327
+ return removed