@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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/OMG-setup.sh +33 -0
- package/README.md +43 -0
- package/claude_experimental/__init__.py +27 -0
- package/claude_experimental/_compat.py +12 -0
- package/claude_experimental/_degradation.py +210 -0
- package/claude_experimental/_flags.py +35 -0
- package/claude_experimental/_lifecycle.py +122 -0
- package/claude_experimental/integration/__init__.py +16 -0
- package/claude_experimental/integration/_placeholder.py +7 -0
- package/claude_experimental/integration/autotuner.py +182 -0
- package/claude_experimental/integration/checkpoints.py +327 -0
- package/claude_experimental/integration/experiments.py +302 -0
- package/claude_experimental/integration/openapi_gen.py +428 -0
- package/claude_experimental/integration/streaming.py +131 -0
- package/claude_experimental/integration/telemetry.py +287 -0
- package/claude_experimental/memory/__init__.py +16 -0
- package/claude_experimental/memory/_placeholder.py +7 -0
- package/claude_experimental/memory/api.py +434 -0
- package/claude_experimental/memory/augmented_generation.py +142 -0
- package/claude_experimental/memory/episodic.py +190 -0
- package/claude_experimental/memory/failure_learning.py +183 -0
- package/claude_experimental/memory/migrate.py +169 -0
- package/claude_experimental/memory/procedural.py +212 -0
- package/claude_experimental/memory/semantic.py +376 -0
- package/claude_experimental/memory/store.py +310 -0
- package/claude_experimental/parallel/__init__.py +17 -0
- package/claude_experimental/parallel/_placeholder.py +7 -0
- package/claude_experimental/parallel/aggregation.py +131 -0
- package/claude_experimental/parallel/api.py +244 -0
- package/claude_experimental/parallel/executor.py +110 -0
- package/claude_experimental/parallel/ralph_bridge.py +164 -0
- package/claude_experimental/parallel/sandbox.py +314 -0
- package/claude_experimental/parallel/scaling.py +171 -0
- package/claude_experimental/parallel/ultraworker.py +285 -0
- package/claude_experimental/patterns/__init__.py +16 -0
- package/claude_experimental/patterns/_placeholder.py +7 -0
- package/claude_experimental/patterns/antipatterns.py +454 -0
- package/claude_experimental/patterns/api.py +196 -0
- package/claude_experimental/patterns/extractor.py +163 -0
- package/claude_experimental/patterns/mining.py +219 -0
- package/claude_experimental/patterns/refactoring.py +234 -0
- package/hooks/_common.py +3 -1
- package/package.json +1 -1
- package/runtime/subagent_dispatcher.py +109 -9
- package/settings.json +6 -1
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""ExperimentTracker - A/B experiment tagging framework with variant assignment and metric comparison.
|
|
2
|
+
|
|
3
|
+
Design decisions:
|
|
4
|
+
- Shared SQLite DB with TelemetryCollector (.omg/state/telemetry.db)
|
|
5
|
+
- Connection-per-invocation (hooks are short-lived subprocesses, no pooling)
|
|
6
|
+
- WAL mode for concurrent multi-session access
|
|
7
|
+
- Deterministic variant assignment via hash-based default, random fallback
|
|
8
|
+
- Feature-gated via ADVANCED_INTEGRATION flag
|
|
9
|
+
- Schema versioning from day one
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import hashlib
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
import random
|
|
17
|
+
import sqlite3
|
|
18
|
+
from datetime import datetime, timezone
|
|
19
|
+
from typing import cast
|
|
20
|
+
|
|
21
|
+
SCHEMA_VERSION = 1
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _default_db_path() -> str:
|
|
25
|
+
"""Return default experiments DB path (shared with telemetry)."""
|
|
26
|
+
project_dir = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
27
|
+
return os.path.join(project_dir, ".omg", "state", "telemetry.db")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ExperimentTracker:
|
|
31
|
+
"""A/B experiment tagging framework with variant assignment and metric comparison.
|
|
32
|
+
|
|
33
|
+
Supports defining experiments with multiple variants, deterministically assigning
|
|
34
|
+
subjects to variants, and collecting per-variant metrics for comparison.
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
tracker = ExperimentTracker()
|
|
38
|
+
exp_id = tracker.define_experiment("pool_size", ["small", "large"])
|
|
39
|
+
variant = tracker.assign_variant(exp_id, "user_123")
|
|
40
|
+
tracker.tag_metric(exp_id, variant, "latency_ms", 42.5)
|
|
41
|
+
results = tracker.compare(exp_id)
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, db_path: str | None = None):
|
|
45
|
+
from claude_experimental.integration import _require_enabled
|
|
46
|
+
_require_enabled()
|
|
47
|
+
|
|
48
|
+
self.db_path: str = db_path or _default_db_path()
|
|
49
|
+
self._ensure_dir()
|
|
50
|
+
self._shared_memory_conn: sqlite3.Connection | None = None
|
|
51
|
+
if self.db_path == ":memory:":
|
|
52
|
+
self._shared_memory_conn = sqlite3.connect("file::memory:?cache=shared", uri=True, check_same_thread=False)
|
|
53
|
+
self._shared_memory_conn.row_factory = sqlite3.Row
|
|
54
|
+
self._init_schema(self._shared_memory_conn)
|
|
55
|
+
|
|
56
|
+
def _ensure_dir(self) -> None:
|
|
57
|
+
if self.db_path != ":memory:":
|
|
58
|
+
os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
|
|
59
|
+
|
|
60
|
+
def _connect(self) -> sqlite3.Connection:
|
|
61
|
+
"""Open a new connection and initialize the schema if needed."""
|
|
62
|
+
if self.db_path == ":memory:":
|
|
63
|
+
if self._shared_memory_conn is None:
|
|
64
|
+
raise RuntimeError("Shared memory connection not initialized")
|
|
65
|
+
return self._shared_memory_conn
|
|
66
|
+
conn = sqlite3.connect(self.db_path, check_same_thread=False)
|
|
67
|
+
conn.row_factory = sqlite3.Row
|
|
68
|
+
self._init_schema(conn)
|
|
69
|
+
return conn
|
|
70
|
+
|
|
71
|
+
def _init_schema(self, conn: sqlite3.Connection) -> None:
|
|
72
|
+
"""Create schema if not exists."""
|
|
73
|
+
_ = conn.executescript("""
|
|
74
|
+
PRAGMA journal_mode=WAL;
|
|
75
|
+
PRAGMA busy_timeout=5000;
|
|
76
|
+
|
|
77
|
+
CREATE TABLE IF NOT EXISTS schema_info (
|
|
78
|
+
key TEXT PRIMARY KEY,
|
|
79
|
+
value TEXT NOT NULL
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
CREATE TABLE IF NOT EXISTS experiments (
|
|
83
|
+
id TEXT PRIMARY KEY,
|
|
84
|
+
name TEXT NOT NULL,
|
|
85
|
+
variants TEXT NOT NULL,
|
|
86
|
+
assignment TEXT NOT NULL,
|
|
87
|
+
created_at TEXT NOT NULL,
|
|
88
|
+
schema_version INTEGER NOT NULL DEFAULT 1
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
CREATE TABLE IF NOT EXISTS experiment_metrics (
|
|
92
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
93
|
+
experiment_id TEXT NOT NULL,
|
|
94
|
+
variant TEXT NOT NULL,
|
|
95
|
+
metric_name TEXT NOT NULL,
|
|
96
|
+
value REAL NOT NULL,
|
|
97
|
+
recorded_at TEXT NOT NULL,
|
|
98
|
+
schema_version INTEGER NOT NULL DEFAULT 1,
|
|
99
|
+
FOREIGN KEY (experiment_id) REFERENCES experiments(id)
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
CREATE INDEX IF NOT EXISTS idx_experiment_metrics_exp_id ON experiment_metrics(experiment_id);
|
|
103
|
+
CREATE INDEX IF NOT EXISTS idx_experiment_metrics_variant ON experiment_metrics(variant);
|
|
104
|
+
CREATE INDEX IF NOT EXISTS idx_experiment_metrics_name ON experiment_metrics(metric_name);
|
|
105
|
+
""")
|
|
106
|
+
|
|
107
|
+
# Set schema version if not present
|
|
108
|
+
row = cast(
|
|
109
|
+
sqlite3.Row | None,
|
|
110
|
+
conn.execute(
|
|
111
|
+
"SELECT value FROM schema_info WHERE key='schema_version'"
|
|
112
|
+
).fetchone(),
|
|
113
|
+
)
|
|
114
|
+
if row is None:
|
|
115
|
+
_ = conn.execute(
|
|
116
|
+
"INSERT OR REPLACE INTO schema_info (key, value) VALUES ('schema_version', ?)",
|
|
117
|
+
(str(SCHEMA_VERSION),),
|
|
118
|
+
)
|
|
119
|
+
conn.commit()
|
|
120
|
+
|
|
121
|
+
def define_experiment(
|
|
122
|
+
self,
|
|
123
|
+
name: str,
|
|
124
|
+
variants: list[str],
|
|
125
|
+
assignment: str = "random",
|
|
126
|
+
) -> str:
|
|
127
|
+
"""Define a new A/B experiment.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
name: Experiment name (e.g. "pool_size").
|
|
131
|
+
variants: List of variant names (e.g. ["small", "large"]).
|
|
132
|
+
assignment: Assignment strategy - "random" or "hash" (default "random").
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Experiment ID (UUID-like string).
|
|
136
|
+
"""
|
|
137
|
+
from claude_experimental.integration import _require_enabled
|
|
138
|
+
_require_enabled()
|
|
139
|
+
|
|
140
|
+
if not variants or len(variants) < 2:
|
|
141
|
+
raise ValueError("Experiment must have at least 2 variants")
|
|
142
|
+
|
|
143
|
+
if assignment not in ("random", "hash"):
|
|
144
|
+
raise ValueError("Assignment must be 'random' or 'hash'")
|
|
145
|
+
|
|
146
|
+
# Generate experiment ID from name + timestamp
|
|
147
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
148
|
+
exp_id = hashlib.sha256(f"{name}:{now}".encode()).hexdigest()[:16]
|
|
149
|
+
|
|
150
|
+
conn = self._connect()
|
|
151
|
+
try:
|
|
152
|
+
_ = conn.execute(
|
|
153
|
+
"INSERT INTO experiments (id, name, variants, assignment, created_at, schema_version) VALUES (?, ?, ?, ?, ?, ?)",
|
|
154
|
+
(
|
|
155
|
+
exp_id,
|
|
156
|
+
name,
|
|
157
|
+
json.dumps(variants),
|
|
158
|
+
assignment,
|
|
159
|
+
now,
|
|
160
|
+
SCHEMA_VERSION,
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
conn.commit()
|
|
164
|
+
finally:
|
|
165
|
+
if self.db_path != ":memory:":
|
|
166
|
+
conn.close()
|
|
167
|
+
|
|
168
|
+
return exp_id
|
|
169
|
+
|
|
170
|
+
def assign_variant(self, experiment_id: str, subject_id: str) -> str:
|
|
171
|
+
"""Assign a subject to a variant in an experiment.
|
|
172
|
+
|
|
173
|
+
Deterministic for hash-based assignment (same subject always gets same variant).
|
|
174
|
+
Random for random-based assignment.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
experiment_id: Experiment ID from define_experiment().
|
|
178
|
+
subject_id: Subject identifier (e.g. user ID, session ID).
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Assigned variant name.
|
|
182
|
+
"""
|
|
183
|
+
from claude_experimental.integration import _require_enabled
|
|
184
|
+
_require_enabled()
|
|
185
|
+
|
|
186
|
+
conn = self._connect()
|
|
187
|
+
try:
|
|
188
|
+
row = cast(
|
|
189
|
+
sqlite3.Row | None,
|
|
190
|
+
conn.execute(
|
|
191
|
+
"SELECT variants, assignment FROM experiments WHERE id = ?",
|
|
192
|
+
(experiment_id,),
|
|
193
|
+
).fetchone(),
|
|
194
|
+
)
|
|
195
|
+
if row is None:
|
|
196
|
+
raise ValueError(f"Experiment not found: {experiment_id}")
|
|
197
|
+
|
|
198
|
+
variants = json.loads(row["variants"])
|
|
199
|
+
assignment = row["assignment"]
|
|
200
|
+
|
|
201
|
+
if assignment == "hash":
|
|
202
|
+
# Deterministic: hash subject_id to select variant
|
|
203
|
+
hash_val = int(
|
|
204
|
+
hashlib.sha256(f"{experiment_id}:{subject_id}".encode()).hexdigest(),
|
|
205
|
+
16,
|
|
206
|
+
)
|
|
207
|
+
variant = variants[hash_val % len(variants)]
|
|
208
|
+
else:
|
|
209
|
+
# Random assignment
|
|
210
|
+
variant = random.choice(variants)
|
|
211
|
+
|
|
212
|
+
return variant
|
|
213
|
+
finally:
|
|
214
|
+
if self.db_path != ":memory:":
|
|
215
|
+
conn.close()
|
|
216
|
+
|
|
217
|
+
def tag_metric(
|
|
218
|
+
self,
|
|
219
|
+
experiment_id: str,
|
|
220
|
+
variant: str,
|
|
221
|
+
metric_name: str,
|
|
222
|
+
value: float,
|
|
223
|
+
) -> None:
|
|
224
|
+
"""Record a metric observation for a variant in an experiment.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
experiment_id: Experiment ID from define_experiment().
|
|
228
|
+
variant: Variant name.
|
|
229
|
+
metric_name: Metric name (e.g. "latency_ms").
|
|
230
|
+
value: Numeric value.
|
|
231
|
+
"""
|
|
232
|
+
from claude_experimental.integration import _require_enabled
|
|
233
|
+
_require_enabled()
|
|
234
|
+
|
|
235
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
236
|
+
conn = self._connect()
|
|
237
|
+
try:
|
|
238
|
+
_ = conn.execute(
|
|
239
|
+
"INSERT INTO experiment_metrics (experiment_id, variant, metric_name, value, recorded_at, schema_version) VALUES (?, ?, ?, ?, ?, ?)",
|
|
240
|
+
(
|
|
241
|
+
experiment_id,
|
|
242
|
+
variant,
|
|
243
|
+
metric_name,
|
|
244
|
+
value,
|
|
245
|
+
now,
|
|
246
|
+
SCHEMA_VERSION,
|
|
247
|
+
),
|
|
248
|
+
)
|
|
249
|
+
conn.commit()
|
|
250
|
+
finally:
|
|
251
|
+
if self.db_path != ":memory:":
|
|
252
|
+
conn.close()
|
|
253
|
+
|
|
254
|
+
def compare(self, experiment_id: str) -> dict[str, dict[str, object]]:
|
|
255
|
+
"""Compare metrics across variants in an experiment.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
experiment_id: Experiment ID from define_experiment().
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Dict mapping variant name to summary dict with keys:
|
|
262
|
+
- count: number of observations
|
|
263
|
+
- mean: average value
|
|
264
|
+
- min: minimum value
|
|
265
|
+
- max: maximum value
|
|
266
|
+
"""
|
|
267
|
+
from claude_experimental.integration import _require_enabled
|
|
268
|
+
_require_enabled()
|
|
269
|
+
|
|
270
|
+
conn = self._connect()
|
|
271
|
+
try:
|
|
272
|
+
rows = cast(
|
|
273
|
+
list[sqlite3.Row],
|
|
274
|
+
conn.execute(
|
|
275
|
+
"""
|
|
276
|
+
SELECT variant,
|
|
277
|
+
COUNT(*) as cnt,
|
|
278
|
+
AVG(value) as avg_val,
|
|
279
|
+
MIN(value) as min_val,
|
|
280
|
+
MAX(value) as max_val
|
|
281
|
+
FROM experiment_metrics
|
|
282
|
+
WHERE experiment_id = ?
|
|
283
|
+
GROUP BY variant
|
|
284
|
+
ORDER BY variant
|
|
285
|
+
""",
|
|
286
|
+
(experiment_id,),
|
|
287
|
+
).fetchall(),
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
result: dict[str, dict[str, object]] = {}
|
|
291
|
+
for row in rows:
|
|
292
|
+
result[row["variant"]] = {
|
|
293
|
+
"count": row["cnt"],
|
|
294
|
+
"mean": row["avg_val"],
|
|
295
|
+
"min": row["min_val"],
|
|
296
|
+
"max": row["max_val"],
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return result
|
|
300
|
+
finally:
|
|
301
|
+
if self.db_path != ":memory:":
|
|
302
|
+
conn.close()
|