synth-optimizers 0.2.4__tar.gz → 0.2.6.dev20260622__tar.gz
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.
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/Cargo.lock +3 -3
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/Cargo.toml +1 -1
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/PKG-INFO +7 -21
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/README.md +6 -20
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/pyproject.toml +1 -1
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/openapi/gepa-service-v1.yaml +34 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/codex_app_server.rs +73 -26
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/lib.rs +1610 -163
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/runtime.rs +53 -73
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/service.rs +279 -7
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/daytona.rs +234 -1
- synth_optimizers-0.2.6.dev20260622/rust/crates/synth_optimizer_platform/src/agent_runtime/local.rs +32 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/mod.rs +4 -1
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/session.rs +174 -1
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/artifacts.rs +3 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/checkpoints.rs +54 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/config.rs +15 -6
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/event_visualization.rs +3 -1
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/http.rs +2 -2
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/lib.rs +17 -7
- synth_optimizers-0.2.6.dev20260622/rust/crates/synth_optimizer_platform/src/observability.rs +91 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/registry.rs +9 -0
- synth_optimizers-0.2.6.dev20260622/rust/crates/synth_optimizer_platform/src/storage_maintenance.rs +1075 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/workspace.rs +311 -1
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizers_py/src/lib.rs +80 -6
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/__init__.py +18 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/_synth_optimizers.pyi +18 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/board_server.py +262 -12
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/cli.py +351 -8
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gelo/00-index.md +2 -2
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gelo/10-cli.md +4 -3
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gelo/20-sdk.md +27 -20
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gelo/30-hosted.md +6 -4
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gelo/containers/00-overview.md +11 -3
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gelo/containers/20-contract.md +4 -3
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/10-cli.md +56 -2
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/20-sdk.md +12 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/containers/00-overview.md +3 -3
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/containers/20-contract.md +2 -3
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/gelo.py +222 -39
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/gepa.py +31 -3
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/hosted.py +191 -6
- synth_optimizers-0.2.6.dev20260622/src/synth_optimizers/hosted_config.py +12 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/o11y.py +218 -9
- synth_optimizers-0.2.6.dev20260622/src/synth_optimizers/observability.py +161 -0
- synth_optimizers-0.2.4/rust/crates/synth_optimizer_platform/src/agent_runtime/local.rs +0 -19
- synth_optimizers-0.2.4/rust/crates/synth_optimizer_platform/src/storage_maintenance.rs +0 -318
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/Cargo.toml +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/README.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/machines.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/pipeline.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/planner.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_gepa/src/prompting_best_practices.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/Cargo.toml +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/README.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/README.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/app_server.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/codex_home.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/docker.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/jsonrpc_read_window.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/limits.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/role_agent.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/substrate.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/supervisor.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/agent_runtime/usage.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/artifact_store.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/cache.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/candidates.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/configured_limits.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/container_contract.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/data_models.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/disk_budget.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/error.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/events.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/evidence.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/failures.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/fsm.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/invariants.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/jobs.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/levers.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/limit_engine.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/limits.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/operations.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/process.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/projections.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/prompt_program.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/resources.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/rollouts.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/runtime_records.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/scores.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/sensors.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/state_machine.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/stopper.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizer_platform/src/usage.rs +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizers_py/Cargo.toml +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/rust/crates/synth_optimizers_py/README.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/README.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/discovery.py +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/00-index.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/algorithms/00-overview.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/algorithms/10-pipeline-modes.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/algorithms/20-proposer-and-policies.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/assets/synth-logo.png +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs/gepa/containers/10-catalog.md +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/docs_server.py +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/eval_stats.py +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/py.typed +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/sdk.py +0 -0
- {synth_optimizers-0.2.4 → synth_optimizers-0.2.6.dev20260622}/src/synth_optimizers/tunnels.py +0 -0
|
@@ -1192,7 +1192,7 @@ dependencies = [
|
|
|
1192
1192
|
|
|
1193
1193
|
[[package]]
|
|
1194
1194
|
name = "synth_gepa"
|
|
1195
|
-
version = "0.2.
|
|
1195
|
+
version = "0.2.5"
|
|
1196
1196
|
dependencies = [
|
|
1197
1197
|
"base64",
|
|
1198
1198
|
"reqwest",
|
|
@@ -1206,7 +1206,7 @@ dependencies = [
|
|
|
1206
1206
|
|
|
1207
1207
|
[[package]]
|
|
1208
1208
|
name = "synth_optimizer_platform"
|
|
1209
|
-
version = "0.2.
|
|
1209
|
+
version = "0.2.5"
|
|
1210
1210
|
dependencies = [
|
|
1211
1211
|
"fs2",
|
|
1212
1212
|
"libc",
|
|
@@ -1223,7 +1223,7 @@ dependencies = [
|
|
|
1223
1223
|
|
|
1224
1224
|
[[package]]
|
|
1225
1225
|
name = "synth_optimizers_py"
|
|
1226
|
-
version = "0.2.
|
|
1226
|
+
version = "0.2.5"
|
|
1227
1227
|
dependencies = [
|
|
1228
1228
|
"pyo3",
|
|
1229
1229
|
"serde_json",
|
|
@@ -3,7 +3,7 @@ members = ["rust/crates/synth_optimizer_platform", "rust/crates/synth_gepa", "ru
|
|
|
3
3
|
resolver = "2"
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "0.2.
|
|
6
|
+
version = "0.2.5"
|
|
7
7
|
edition = "2021"
|
|
8
8
|
license = "Apache-2.0"
|
|
9
9
|
authors = ["Synth Laboratories <josh@usesynth.ai>"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: synth-optimizers
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6.dev20260622
|
|
4
4
|
Requires-Dist: pydantic>=2.0.0
|
|
5
5
|
Requires-Dist: synth-containers==0.2.0.20260604
|
|
6
6
|
Requires-Dist: websocket-client>=1.8.0
|
|
@@ -24,14 +24,13 @@ Project-URL: Repository, https://github.com/synth-laboratories/optimizers
|
|
|
24
24
|
<p align="center">A shared optimizer platform for AI applications — starting with open-source GEPA on a language-agnostic task contract.</p>
|
|
25
25
|
<p align="center">
|
|
26
26
|
<a href="https://pypi.org/project/synth-optimizers/">PyPI</a> ·
|
|
27
|
-
<a href="
|
|
27
|
+
<a href="src/synth_optimizers/docs/gepa/containers/20-contract.md">Task contract</a> ·
|
|
28
28
|
<a href="https://github.com/synth-laboratories/synth-cookbooks-public/tree/main/cookbooks/optimizers/gepa">Cookbooks</a> ·
|
|
29
29
|
<a href="docs/hosted-optimizers.md">Hosted jobs</a>
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
32
|
`synth-optimizers` provides a shared Rust optimizer core for running search
|
|
33
|
-
algorithms against any task exposed through the
|
|
34
|
-
[`synth-containers`](https://github.com/synth-laboratories/containers) HTTP
|
|
33
|
+
algorithms against any task exposed through the public optimizer HTTP task
|
|
35
34
|
contract.
|
|
36
35
|
|
|
37
36
|
- **Shared platform core** — reusable Rust machinery for container I/O, workspaces, cache profiles, budgets, telemetry, failure handling, and replayable evidence.
|
|
@@ -47,7 +46,8 @@ contract.
|
|
|
47
46
|
|
|
48
47
|
The shared [`synth_optimizer_platform`](rust/crates/synth_optimizer_platform/)
|
|
49
48
|
crate is the substrate for optimizer implementations; GEPA is the first public
|
|
50
|
-
local algorithm; GELO is hosted-only in the public package
|
|
49
|
+
local algorithm; GELO is hosted-only in the public package and runs on Synth
|
|
50
|
+
hosted optimizer infrastructure.
|
|
51
51
|
Hosted GEPA/GELO submission is covered in [`docs/hosted-optimizers.md`](docs/hosted-optimizers.md).
|
|
52
52
|
|
|
53
53
|
## Install
|
|
@@ -58,29 +58,15 @@ pip install synth-optimizers
|
|
|
58
58
|
uv add synth-optimizers
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
Latest daily dev build:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
pip install --pre \
|
|
65
|
-
synth-containers==0.2.0.dev202605312141 \
|
|
66
|
-
synth-optimizers==0.2.0.dev202606010003
|
|
67
|
-
|
|
68
|
-
uv add --prerelease allow \
|
|
69
|
-
synth-containers==0.2.0.dev202605312141 \
|
|
70
|
-
synth-optimizers==0.2.0.dev202606010003
|
|
71
|
-
```
|
|
72
|
-
|
|
73
61
|
Install [`uv`](https://github.com/astral-sh/uv) for local development and editable installs.
|
|
74
62
|
|
|
75
63
|
## Local development
|
|
76
64
|
|
|
77
|
-
|
|
78
|
-
at matching dev versions, then sync and install editable:
|
|
65
|
+
Sync the repo and install the local Python/Rust extension in editable mode:
|
|
79
66
|
|
|
80
67
|
```bash
|
|
81
68
|
cd optimizers
|
|
82
69
|
uv sync --group dev
|
|
83
|
-
uv pip install -e ../containers
|
|
84
70
|
uv pip install -e .
|
|
85
71
|
uv run maturin develop --manifest-path rust/crates/synth_optimizers_py/Cargo.toml
|
|
86
72
|
```
|
|
@@ -201,7 +187,7 @@ Agent docs: [skills/gepa/SKILL.md](skills/gepa/SKILL.md).
|
|
|
201
187
|
- [GEPA docs (gepa-ai)](https://gepa-ai.github.io/gepa/) — algorithm overview, case studies, and adapter guides
|
|
202
188
|
- [GEPA paper](https://arxiv.org/abs/2507.19457) — *GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning*
|
|
203
189
|
- [Cookbooks](https://github.com/synth-laboratories/synth-cookbooks-public/tree/main/cookbooks/optimizers/gepa) — runnable GEPA examples
|
|
204
|
-
- [
|
|
190
|
+
- [GEPA task contract](src/synth_optimizers/docs/gepa/containers/20-contract.md) — the public HTTP task contract
|
|
205
191
|
- [uv](https://github.com/astral-sh/uv) — Python package and project manager
|
|
206
192
|
- [GEPA service OpenAPI](rust/crates/synth_gepa/openapi/gepa-service-v1.yaml)
|
|
207
193
|
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
<p align="center">A shared optimizer platform for AI applications — starting with open-source GEPA on a language-agnostic task contract.</p>
|
|
3
3
|
<p align="center">
|
|
4
4
|
<a href="https://pypi.org/project/synth-optimizers/">PyPI</a> ·
|
|
5
|
-
<a href="
|
|
5
|
+
<a href="src/synth_optimizers/docs/gepa/containers/20-contract.md">Task contract</a> ·
|
|
6
6
|
<a href="https://github.com/synth-laboratories/synth-cookbooks-public/tree/main/cookbooks/optimizers/gepa">Cookbooks</a> ·
|
|
7
7
|
<a href="docs/hosted-optimizers.md">Hosted jobs</a>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
10
|
`synth-optimizers` provides a shared Rust optimizer core for running search
|
|
11
|
-
algorithms against any task exposed through the
|
|
12
|
-
[`synth-containers`](https://github.com/synth-laboratories/containers) HTTP
|
|
11
|
+
algorithms against any task exposed through the public optimizer HTTP task
|
|
13
12
|
contract.
|
|
14
13
|
|
|
15
14
|
- **Shared platform core** — reusable Rust machinery for container I/O, workspaces, cache profiles, budgets, telemetry, failure handling, and replayable evidence.
|
|
@@ -25,7 +24,8 @@ contract.
|
|
|
25
24
|
|
|
26
25
|
The shared [`synth_optimizer_platform`](rust/crates/synth_optimizer_platform/)
|
|
27
26
|
crate is the substrate for optimizer implementations; GEPA is the first public
|
|
28
|
-
local algorithm; GELO is hosted-only in the public package
|
|
27
|
+
local algorithm; GELO is hosted-only in the public package and runs on Synth
|
|
28
|
+
hosted optimizer infrastructure.
|
|
29
29
|
Hosted GEPA/GELO submission is covered in [`docs/hosted-optimizers.md`](docs/hosted-optimizers.md).
|
|
30
30
|
|
|
31
31
|
## Install
|
|
@@ -36,29 +36,15 @@ pip install synth-optimizers
|
|
|
36
36
|
uv add synth-optimizers
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Latest daily dev build:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
pip install --pre \
|
|
43
|
-
synth-containers==0.2.0.dev202605312141 \
|
|
44
|
-
synth-optimizers==0.2.0.dev202606010003
|
|
45
|
-
|
|
46
|
-
uv add --prerelease allow \
|
|
47
|
-
synth-containers==0.2.0.dev202605312141 \
|
|
48
|
-
synth-optimizers==0.2.0.dev202606010003
|
|
49
|
-
```
|
|
50
|
-
|
|
51
39
|
Install [`uv`](https://github.com/astral-sh/uv) for local development and editable installs.
|
|
52
40
|
|
|
53
41
|
## Local development
|
|
54
42
|
|
|
55
|
-
|
|
56
|
-
at matching dev versions, then sync and install editable:
|
|
43
|
+
Sync the repo and install the local Python/Rust extension in editable mode:
|
|
57
44
|
|
|
58
45
|
```bash
|
|
59
46
|
cd optimizers
|
|
60
47
|
uv sync --group dev
|
|
61
|
-
uv pip install -e ../containers
|
|
62
48
|
uv pip install -e .
|
|
63
49
|
uv run maturin develop --manifest-path rust/crates/synth_optimizers_py/Cargo.toml
|
|
64
50
|
```
|
|
@@ -179,7 +165,7 @@ Agent docs: [skills/gepa/SKILL.md](skills/gepa/SKILL.md).
|
|
|
179
165
|
- [GEPA docs (gepa-ai)](https://gepa-ai.github.io/gepa/) — algorithm overview, case studies, and adapter guides
|
|
180
166
|
- [GEPA paper](https://arxiv.org/abs/2507.19457) — *GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning*
|
|
181
167
|
- [Cookbooks](https://github.com/synth-laboratories/synth-cookbooks-public/tree/main/cookbooks/optimizers/gepa) — runnable GEPA examples
|
|
182
|
-
- [
|
|
168
|
+
- [GEPA task contract](src/synth_optimizers/docs/gepa/containers/20-contract.md) — the public HTTP task contract
|
|
183
169
|
- [uv](https://github.com/astral-sh/uv) — Python package and project manager
|
|
184
170
|
- [GEPA service OpenAPI](rust/crates/synth_gepa/openapi/gepa-service-v1.yaml)
|
|
185
171
|
|
|
@@ -143,6 +143,24 @@ paths:
|
|
|
143
143
|
'404': { $ref: '#/components/responses/RunNotFound' }
|
|
144
144
|
'409': { $ref: '#/components/responses/NotTerminal' }
|
|
145
145
|
|
|
146
|
+
/runs/{run_id}/storage:
|
|
147
|
+
parameters:
|
|
148
|
+
- $ref: '#/components/parameters/RunId'
|
|
149
|
+
get:
|
|
150
|
+
operationId: getRunStorage
|
|
151
|
+
summary: Inspect local storage for a Run
|
|
152
|
+
description: |
|
|
153
|
+
Returns a read-only local storage report for the Run directory:
|
|
154
|
+
artifact sizes, SQLite hot spots when available, existing compaction
|
|
155
|
+
state, safe actions, and cleanup recommendation.
|
|
156
|
+
responses:
|
|
157
|
+
'200':
|
|
158
|
+
description: Run storage report.
|
|
159
|
+
content:
|
|
160
|
+
application/json:
|
|
161
|
+
schema: { type: object }
|
|
162
|
+
'404': { $ref: '#/components/responses/RunNotFound' }
|
|
163
|
+
|
|
146
164
|
/runs/{run_id}/state:
|
|
147
165
|
parameters: [ { $ref: '#/components/parameters/RunId' } ]
|
|
148
166
|
get:
|
|
@@ -525,6 +543,22 @@ paths:
|
|
|
525
543
|
run_id: { type: string }
|
|
526
544
|
bytes: { type: integer }
|
|
527
545
|
|
|
546
|
+
/workspace/storage:
|
|
547
|
+
get:
|
|
548
|
+
operationId: getWorkspaceStorage
|
|
549
|
+
summary: Workspace storage health report
|
|
550
|
+
description: |
|
|
551
|
+
Returns root-level storage health for the local workspace: total bytes,
|
|
552
|
+
reclaimable bytes, stale partial artifacts, threshold configuration, and
|
|
553
|
+
alerts for oversized roots/runs or stale partials. This route is
|
|
554
|
+
read-only and never deletes or compacts artifacts.
|
|
555
|
+
responses:
|
|
556
|
+
'200':
|
|
557
|
+
description: Workspace storage health report.
|
|
558
|
+
content:
|
|
559
|
+
application/json:
|
|
560
|
+
schema: { type: object }
|
|
561
|
+
|
|
528
562
|
/workspace/prune:
|
|
529
563
|
post:
|
|
530
564
|
operationId: pruneWorkspace
|
|
@@ -24,6 +24,9 @@ const OPENROUTER_GROK43_CACHED_INPUT_USD_PER_MILLION: f64 = 0.20;
|
|
|
24
24
|
const OPENROUTER_GROK43_OUTPUT_USD_PER_MILLION: f64 = 2.50;
|
|
25
25
|
const DEEPSEEK_INPUT_USD_PER_MILLION: f64 = 0.27;
|
|
26
26
|
const DEEPSEEK_OUTPUT_USD_PER_MILLION: f64 = 1.10;
|
|
27
|
+
const CHAT_COMPLETIONS_PROPOSER_MAX_TOKENS: u64 = 8_192;
|
|
28
|
+
const CHAT_COMPLETIONS_PROPOSER_MAX_EVIDENCE_CHARS_PER_FILE: usize = 32_000;
|
|
29
|
+
const CHAT_COMPLETIONS_PROPOSER_MAX_TOTAL_EVIDENCE_CHARS: usize = 160_000;
|
|
27
30
|
|
|
28
31
|
pub(crate) struct CodexProposerInput<'a> {
|
|
29
32
|
pub config: &'a SynthOptimizerConfig,
|
|
@@ -186,9 +189,10 @@ pub(crate) fn run_deepseek_chat_proposer(input: CodexProposerInput<'_>) -> Resul
|
|
|
186
189
|
}
|
|
187
190
|
],
|
|
188
191
|
"response_format": {"type": "json_object"},
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
+
// Keep OpenRouter-compatible requests inside common 128k context windows.
|
|
193
|
+
// Two GEPA proposals fit comfortably in 8k while 32k can make the
|
|
194
|
+
// provider reject otherwise-valid evidence packets before generation.
|
|
195
|
+
"max_tokens": CHAT_COMPLETIONS_PROPOSER_MAX_TOKENS,
|
|
192
196
|
"stream": false
|
|
193
197
|
});
|
|
194
198
|
// DeepSeek-specific switch that suppresses its reasoning channel so `content` is the
|
|
@@ -238,7 +242,7 @@ pub(crate) fn run_deepseek_chat_proposer(input: CodexProposerInput<'_>) -> Resul
|
|
|
238
242
|
Some(pair) => pair,
|
|
239
243
|
None => {
|
|
240
244
|
return Err(OptimizerError::Proposer(format!(
|
|
241
|
-
"
|
|
245
|
+
"chat-completions proposer failed after 3 attempts: {}",
|
|
242
246
|
last_err.unwrap_or_else(|| "unknown error".to_string())
|
|
243
247
|
)))
|
|
244
248
|
}
|
|
@@ -250,13 +254,13 @@ pub(crate) fn run_deepseek_chat_proposer(input: CodexProposerInput<'_>) -> Resul
|
|
|
250
254
|
let proposals = proposals_from_manifest(&manifest)?;
|
|
251
255
|
let evidence_warnings = manifest_evidence_warnings(&input, &manifest, &proposals);
|
|
252
256
|
let usage = chat_response.get("usage").cloned().ok_or_else(|| {
|
|
253
|
-
OptimizerError::Proposer("
|
|
257
|
+
OptimizerError::Proposer("chat-completions proposer response missing usage".to_string())
|
|
254
258
|
})?;
|
|
255
259
|
let usage = normalize_proposer_usage(input.config, &model, usage);
|
|
256
260
|
write_deepseek_chat_artifacts(&input, &request, &chat_response)?;
|
|
257
261
|
write_workspace_pack_manifest(&input.workspace_dir)?;
|
|
258
262
|
Ok(json!({
|
|
259
|
-
"backend":
|
|
263
|
+
"backend": input.config.proposer.backend,
|
|
260
264
|
"runtime_substrate": "local",
|
|
261
265
|
"workspace": input.workspace_dir,
|
|
262
266
|
"manifest": manifest,
|
|
@@ -275,6 +279,7 @@ fn deepseek_chat_prompt(input: &CodexProposerInput<'_>) -> Result<String> {
|
|
|
275
279
|
prompt.push_str("\n\nManifest schema:\n");
|
|
276
280
|
prompt.push_str(&proposal_schema(input));
|
|
277
281
|
prompt.push_str("\n\nUse these workspace files as the complete evidence packet.\n");
|
|
282
|
+
let mut remaining_evidence_chars = CHAT_COMPLETIONS_PROPOSER_MAX_TOTAL_EVIDENCE_CHARS;
|
|
278
283
|
for path in [
|
|
279
284
|
"state/proposer_metadata.json",
|
|
280
285
|
"state/task_info.json",
|
|
@@ -290,14 +295,17 @@ fn deepseek_chat_prompt(input: &CodexProposerInput<'_>) -> Result<String> {
|
|
|
290
295
|
let file_path = input.workspace_dir.join(path);
|
|
291
296
|
let text = fs::read_to_string(&file_path)
|
|
292
297
|
.map_err(|source| OptimizerError::io(&file_path, source))?;
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
298
|
+
let file_budget =
|
|
299
|
+
remaining_evidence_chars.min(CHAT_COMPLETIONS_PROPOSER_MAX_EVIDENCE_CHARS_PER_FILE);
|
|
300
|
+
let text_char_count = text.chars().count();
|
|
301
|
+
let text = if file_budget == 0 {
|
|
302
|
+
"[omitted: chat-completions proposer evidence budget exhausted]".to_string()
|
|
303
|
+
} else if text_char_count > file_budget {
|
|
304
|
+
let head: String = text.chars().take(file_budget).collect();
|
|
305
|
+
remaining_evidence_chars = remaining_evidence_chars.saturating_sub(file_budget);
|
|
306
|
+
format!("{head}\n…[truncated to {file_budget} chars to fit context budget]…")
|
|
300
307
|
} else {
|
|
308
|
+
remaining_evidence_chars = remaining_evidence_chars.saturating_sub(text_char_count);
|
|
301
309
|
text
|
|
302
310
|
};
|
|
303
311
|
prompt.push_str("\n\n--- ");
|
|
@@ -1198,6 +1206,8 @@ Rules:
|
|
|
1198
1206
|
- Do not leave required evidence fields empty. `evidence.candidate_comparison` must be a non-empty summary of the parent prompt against observed reflection evidence, and `evidence.example_ids_used` must include at least one concrete example id inspected from the state files.
|
|
1199
1207
|
- Proposals should aim to generalize. Add structural sections (role, task, output rules, examples) and domain-specific rules only when they are task-valid.
|
|
1200
1208
|
- {proposal_policy}
|
|
1209
|
+
- `proposed_payload` keys must be exactly the mutable target module ids from `state/run_context.json`. Do not use chat-message keys such as `content`, `role`, or `modules` unless one of those strings is literally listed as a target module id.
|
|
1210
|
+
- For a single target module, write the target module id directly as the only `proposed_payload` key. For example, if `state/run_context.json.target_modules == ["stage2_system"]`, write `"proposed_payload": {{"stage2_system": "<full replacement instruction>"}}`, not `"content"` and not a `modules` array.
|
|
1201
1211
|
- At most one proposal may be conservative. The remaining proposals must be very ambitious, high-variance, task-specific updates that could plausibly produce substantially better task performance than the parent, and each rationale must name the failure clusters it attacks.
|
|
1202
1212
|
- Shoot for large wins. Mild parent clarifications are wasted candidate budget unless they are the single conservative control.
|
|
1203
1213
|
- Do not waste candidates on generic output-contract polish, canonical-label reminders, or baseline paraphrases unless the dominant failures are actually output-format failures.
|
|
@@ -1290,7 +1300,7 @@ fn proposer_visible_frame(
|
|
|
1290
1300
|
}
|
|
1291
1301
|
if !matches!(
|
|
1292
1302
|
frame.evaluation_stage.as_str(),
|
|
1293
|
-
"candidate_minibatch" | "parent_minibatch_reference" | "reflection"
|
|
1303
|
+
"seed_full_train" | "candidate_minibatch" | "parent_minibatch_reference" | "reflection"
|
|
1294
1304
|
) {
|
|
1295
1305
|
return false;
|
|
1296
1306
|
}
|
|
@@ -1298,6 +1308,45 @@ fn proposer_visible_frame(
|
|
|
1298
1308
|
visible_task_ids.is_empty() || visible_task_ids.contains(&frame.task_id)
|
|
1299
1309
|
}
|
|
1300
1310
|
|
|
1311
|
+
fn frame_rollout_trace(
|
|
1312
|
+
input: &CodexProposerInput<'_>,
|
|
1313
|
+
frame: &synth_optimizer_platform::SensorFrame,
|
|
1314
|
+
) -> Value {
|
|
1315
|
+
let inline = frame
|
|
1316
|
+
.metadata
|
|
1317
|
+
.get("rollout_trace")
|
|
1318
|
+
.cloned()
|
|
1319
|
+
.unwrap_or(Value::Null);
|
|
1320
|
+
if rollout_trace_has_proposer_evidence(&inline) {
|
|
1321
|
+
return inline;
|
|
1322
|
+
}
|
|
1323
|
+
read_frame_rollout_trace_artifact(input, frame).unwrap_or(inline)
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
fn rollout_trace_has_proposer_evidence(trace: &Value) -> bool {
|
|
1327
|
+
json_path(trace, &["task_payload", "example"])
|
|
1328
|
+
.and_then(Value::as_object)
|
|
1329
|
+
.is_some()
|
|
1330
|
+
|| string_path(trace, &["summary", "expected"]).is_some()
|
|
1331
|
+
|| string_path(trace, &["summary", "prediction"]).is_some()
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
fn read_frame_rollout_trace_artifact(
|
|
1335
|
+
input: &CodexProposerInput<'_>,
|
|
1336
|
+
frame: &synth_optimizer_platform::SensorFrame,
|
|
1337
|
+
) -> Option<Value> {
|
|
1338
|
+
let sensor_frame_id = frame.sensor_frame_id.trim();
|
|
1339
|
+
if sensor_frame_id.is_empty() {
|
|
1340
|
+
return None;
|
|
1341
|
+
}
|
|
1342
|
+
let run_dir = input.workspace_dir.parent()?.parent()?;
|
|
1343
|
+
let path = run_dir
|
|
1344
|
+
.join("rollout_traces")
|
|
1345
|
+
.join(format!("{sensor_frame_id}.json"));
|
|
1346
|
+
let raw = fs::read_to_string(path).ok()?;
|
|
1347
|
+
serde_json::from_str(&raw).ok()
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1301
1350
|
fn rollouts_read_model(input: &CodexProposerInput<'_>) -> Value {
|
|
1302
1351
|
let mut rows = Vec::new();
|
|
1303
1352
|
for candidate in input.candidates {
|
|
@@ -1310,11 +1359,11 @@ fn rollouts_read_model(input: &CodexProposerInput<'_>) -> Value {
|
|
|
1310
1359
|
if !proposer_visible_frame(input, frame) {
|
|
1311
1360
|
continue;
|
|
1312
1361
|
}
|
|
1313
|
-
let rollout_trace = frame
|
|
1314
|
-
let summary = json_path(rollout_trace, &["summary"])
|
|
1362
|
+
let rollout_trace = frame_rollout_trace(input, frame);
|
|
1363
|
+
let summary = json_path(&rollout_trace, &["summary"])
|
|
1315
1364
|
.cloned()
|
|
1316
1365
|
.unwrap_or(Value::Null);
|
|
1317
|
-
let outcome = json_path(rollout_trace, &["outcome"])
|
|
1366
|
+
let outcome = json_path(&rollout_trace, &["outcome"])
|
|
1318
1367
|
.cloned()
|
|
1319
1368
|
.unwrap_or_else(|| {
|
|
1320
1369
|
json!({
|
|
@@ -1323,7 +1372,7 @@ fn rollouts_read_model(input: &CodexProposerInput<'_>) -> Value {
|
|
|
1323
1372
|
"reward": frame.reward,
|
|
1324
1373
|
})
|
|
1325
1374
|
});
|
|
1326
|
-
let example = json_path(rollout_trace, &["task_payload", "example"])
|
|
1375
|
+
let example = json_path(&rollout_trace, &["task_payload", "example"])
|
|
1327
1376
|
.cloned()
|
|
1328
1377
|
.unwrap_or_else(|| {
|
|
1329
1378
|
json!({
|
|
@@ -1474,11 +1523,11 @@ fn proposer_example_row(
|
|
|
1474
1523
|
candidate: &CandidateRecord,
|
|
1475
1524
|
frame: &synth_optimizer_platform::SensorFrame,
|
|
1476
1525
|
) -> Value {
|
|
1477
|
-
let rollout_trace = frame
|
|
1478
|
-
let summary = json_path(rollout_trace, &["summary"])
|
|
1526
|
+
let rollout_trace = frame_rollout_trace(input, frame);
|
|
1527
|
+
let summary = json_path(&rollout_trace, &["summary"])
|
|
1479
1528
|
.cloned()
|
|
1480
1529
|
.unwrap_or(Value::Null);
|
|
1481
|
-
let outcome = json_path(rollout_trace, &["outcome"])
|
|
1530
|
+
let outcome = json_path(&rollout_trace, &["outcome"])
|
|
1482
1531
|
.cloned()
|
|
1483
1532
|
.unwrap_or_else(|| {
|
|
1484
1533
|
json!({
|
|
@@ -1487,7 +1536,7 @@ fn proposer_example_row(
|
|
|
1487
1536
|
"reward": frame.reward,
|
|
1488
1537
|
})
|
|
1489
1538
|
});
|
|
1490
|
-
let example = json_path(rollout_trace, &["task_payload", "example"])
|
|
1539
|
+
let example = json_path(&rollout_trace, &["task_payload", "example"])
|
|
1491
1540
|
.cloned()
|
|
1492
1541
|
.unwrap_or_else(|| {
|
|
1493
1542
|
json!({
|
|
@@ -2251,10 +2300,8 @@ fn reflective_frame_value(
|
|
|
2251
2300
|
.find(|value| !value.trim().is_empty())
|
|
2252
2301
|
.unwrap_or_default()
|
|
2253
2302
|
.to_string();
|
|
2254
|
-
let rollout_trace = frame
|
|
2255
|
-
|
|
2256
|
-
.get("rollout_trace")
|
|
2257
|
-
.and_then(Value::as_object);
|
|
2303
|
+
let rollout_trace = frame_rollout_trace(input, frame);
|
|
2304
|
+
let rollout_trace = rollout_trace.as_object();
|
|
2258
2305
|
let trace_summary = rollout_trace
|
|
2259
2306
|
.and_then(|trace| trace.get("summary"))
|
|
2260
2307
|
.cloned()
|