fastevolve 0.2.1__tar.gz → 0.3.0__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.
Files changed (35) hide show
  1. {fastevolve-0.2.1 → fastevolve-0.3.0}/.claude/settings.local.json +2 -1
  2. fastevolve-0.3.0/PKG-INFO +237 -0
  3. fastevolve-0.3.0/README.md +207 -0
  4. fastevolve-0.3.0/fastevolve/checkpoint.py +62 -0
  5. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/config.py +1 -0
  6. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/controller.py +23 -4
  7. fastevolve-0.3.0/fastevolve/llm_ensemble/anthropic_llm.py +25 -0
  8. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/llm_ensemble/config.py +1 -0
  9. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/llm_ensemble/ensemble.py +15 -3
  10. fastevolve-0.3.0/fastevolve/llm_ensemble/openai_llm.py +28 -0
  11. {fastevolve-0.2.1 → fastevolve-0.3.0}/pyproject.toml +4 -1
  12. {fastevolve-0.2.1 → fastevolve-0.3.0}/uv.lock +165 -2
  13. fastevolve-0.2.1/PKG-INFO +0 -47
  14. fastevolve-0.2.1/README.md +0 -24
  15. {fastevolve-0.2.1 → fastevolve-0.3.0}/.gitignore +0 -0
  16. {fastevolve-0.2.1 → fastevolve-0.3.0}/.python-version +0 -0
  17. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/__init__.py +0 -0
  18. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/evaluator/__init__.py +0 -0
  19. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/evaluator/config.py +0 -0
  20. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/evaluator/evaluator.py +0 -0
  21. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/evaluator/result.py +0 -0
  22. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/llm_ensemble/__init__.py +0 -0
  23. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/llm_ensemble/base.py +0 -0
  24. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/llm_ensemble/ollama.py +0 -0
  25. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/program_database/__init__.py +0 -0
  26. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/program_database/config.py +0 -0
  27. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/program_database/database.py +0 -0
  28. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/program_database/embedder.py +0 -0
  29. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/program_database/program.py +0 -0
  30. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/prompt_sampler/__init__.py +0 -0
  31. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/prompt_sampler/config.py +0 -0
  32. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/prompt_sampler/sampler.py +0 -0
  33. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/prompt_sampler/template_library.py +0 -0
  34. {fastevolve-0.2.1 → fastevolve-0.3.0}/fastevolve/telemetry.py +0 -0
  35. {fastevolve-0.2.1 → fastevolve-0.3.0}/main.py +0 -0
@@ -9,7 +9,8 @@
9
9
  "Bash(uv run *)",
10
10
  "Bash(.venv/Scripts/python.exe -m pip install \"rich>=13.7\" -q)",
11
11
  "Bash(uv add *)",
12
- "Bash(.venv/Scripts/python.exe -c 'from fastevolve.controller import Controller; from fastevolve.telemetry import setup, span, log; setup\\(\\); log.info\\('\\\\''telemetry [bold green]ok[/]'\\\\''\\); *)"
12
+ "Bash(.venv/Scripts/python.exe -c 'from fastevolve.controller import Controller; from fastevolve.telemetry import setup, span, log; setup\\(\\); log.info\\('\\\\''telemetry [bold green]ok[/]'\\\\''\\); *)",
13
+ "Bash(.venv/Scripts/python.exe -c ' *)"
13
14
  ]
14
15
  }
15
16
  }
@@ -0,0 +1,237 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastevolve
3
+ Version: 0.3.0
4
+ Summary: Minimal open-source AlphaEvolve: LLM-driven program evolution with MAP-Elites islands, cascade evaluation, and a local Ollama ensemble.
5
+ Project-URL: Homepage, https://github.com/tiagomonteiro0715/fastevolve
6
+ Project-URL: Repository, https://github.com/tiagomonteiro0715/fastevolve
7
+ Project-URL: Issues, https://github.com/tiagomonteiro0715/fastevolve/issues
8
+ Author-email: Tiago Monteiro <monteiro.t@northeastern.edu>
9
+ License: MIT
10
+ Keywords: alphaevolve,evolutionary-search,llm,map-elites,ollama,program-synthesis
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Requires-Python: >=3.12
17
+ Requires-Dist: ollama>=0.4.0
18
+ Requires-Dist: rich>=13.7
19
+ Provides-Extra: all
20
+ Requires-Dist: anthropic>=0.30; extra == 'all'
21
+ Requires-Dist: openai>=1.0; extra == 'all'
22
+ Provides-Extra: anthropic
23
+ Requires-Dist: anthropic>=0.30; extra == 'anthropic'
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=8; extra == 'dev'
26
+ Requires-Dist: ruff>=0.6; extra == 'dev'
27
+ Provides-Extra: openai
28
+ Requires-Dist: openai>=1.0; extra == 'openai'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # fastevolve
32
+
33
+ Minimal open-source AlphaEvolve: LLM-driven program evolution with MAP-Elites islands, cascade evaluation, and a local Ollama ensemble.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ uv sync
39
+ ```
40
+
41
+ The core install ships with Ollama support only. OpenAI and Anthropic SDKs are optional extras — install whichever you need:
42
+
43
+ ```bash
44
+ uv sync --extra openai # adds the OpenAI SDK
45
+ uv sync --extra anthropic # adds the Anthropic SDK
46
+ uv sync --extra all # both
47
+ ```
48
+
49
+ If you only use Ollama, skip the extras — neither SDK will be imported.
50
+
51
+ ## Quick start in code
52
+
53
+ ### Local (with Ollama)
54
+
55
+ Assumes `ollama serve` is running and you've pulled the model.
56
+
57
+ ```python
58
+ from fastevolve import Config, Controller
59
+ from fastevolve.llm_ensemble import ModelConfig
60
+
61
+ INITIAL = "def solve(x):\n return x\n"
62
+
63
+ def correctness(p):
64
+ ns = {}
65
+ try: exec(p.code, ns)
66
+ except Exception: return 0.0
67
+ fn = ns.get("solve")
68
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
69
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
70
+
71
+ cfg = Config()
72
+ cfg.iterations = 20
73
+ cfg.checkpoint_path = "run.log" # optional — resume if killed mid-run
74
+ cfg.ensemble.models = [
75
+ ModelConfig(name="gemma3:e4b", provider="ollama", temperature=0.7, weight=1.0, role="fast"),
76
+ ]
77
+ cfg.evaluator.cascade = [(correctness, 0.0)]
78
+
79
+ result = Controller(cfg, initial_program=INITIAL).run()
80
+ print(result.best.code)
81
+ ```
82
+
83
+ ### Google Colab (with OpenAI or Anthropic)
84
+
85
+ Ollama isn't practical on Colab — use an API provider instead. Paste this into a Colab cell:
86
+
87
+ ```python
88
+ !pip install -q "fastevolve[openai]"
89
+
90
+ import os
91
+ from google.colab import userdata
92
+ os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY") # store in Colab Secrets first
93
+
94
+ from fastevolve import Config, Controller
95
+ from fastevolve.llm_ensemble import ModelConfig
96
+
97
+ INITIAL = "def solve(x):\n return x\n"
98
+
99
+ def correctness(p):
100
+ ns = {}
101
+ try: exec(p.code, ns)
102
+ except Exception: return 0.0
103
+ fn = ns.get("solve")
104
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
105
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
106
+
107
+ cfg = Config()
108
+ cfg.iterations = 20
109
+ cfg.ensemble.models = [
110
+ ModelConfig(name="gpt-4o-mini", provider="openai", temperature=0.7, weight=1.0, role="fast"),
111
+ ]
112
+ cfg.evaluator.cascade = [(correctness, 0.0)]
113
+
114
+ result = Controller(cfg, initial_program=INITIAL).run()
115
+ print(result.best.code)
116
+ ```
117
+
118
+ ### Google Colab (with Claude)
119
+
120
+ ```python
121
+ !pip install -q "fastevolve[anthropic]"
122
+
123
+ import os
124
+ from google.colab import userdata
125
+ os.environ["ANTHROPIC_API_KEY"] = userdata.get("ANTHROPIC_API_KEY") # store in Colab Secrets first
126
+
127
+ from fastevolve import Config, Controller
128
+ from fastevolve.llm_ensemble import ModelConfig
129
+
130
+ INITIAL = "def solve(x):\n return x\n"
131
+
132
+ def correctness(p):
133
+ ns = {}
134
+ try: exec(p.code, ns)
135
+ except Exception: return 0.0
136
+ fn = ns.get("solve")
137
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
138
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
139
+
140
+ cfg = Config()
141
+ cfg.iterations = 20
142
+ cfg.ensemble.models = [
143
+ ModelConfig(name="claude-haiku-4-5-20251001", provider="anthropic",
144
+ temperature=0.7, weight=1.0, role="fast",
145
+ options={"max_tokens": 4096}),
146
+ ]
147
+ cfg.evaluator.cascade = [(correctness, 0.0)]
148
+
149
+ result = Controller(cfg, initial_program=INITIAL).run()
150
+ print(result.best.code)
151
+ ```
152
+
153
+ ### Google Colab (with Ollama)
154
+
155
+ Ollama can run on Colab if you install it, start the daemon in the background, and pull a small model. Use a GPU runtime (`Runtime → Change runtime type → T4 GPU`) for any model bigger than ~1B parameters.
156
+
157
+ ```python
158
+ # 1. Install ollama and fastevolve
159
+ !curl -fsSL https://ollama.com/install.sh | sh
160
+ !pip install -q fastevolve
161
+
162
+ # 2. Start the ollama daemon in the background
163
+ import subprocess, time
164
+ subprocess.Popen(["ollama", "serve"])
165
+ time.sleep(5) # give it a moment to bind to port 11434
166
+
167
+ # 3. Pull a small model (qwen2.5:0.5b is ~400 MB and fits the free CPU runtime)
168
+ !ollama pull qwen2.5:0.5b
169
+
170
+ # 4. Run fastevolve as usual
171
+ from fastevolve import Config, Controller
172
+ from fastevolve.llm_ensemble import ModelConfig
173
+
174
+ INITIAL = "def solve(x):\n return x\n"
175
+
176
+ def correctness(p):
177
+ ns = {}
178
+ try: exec(p.code, ns)
179
+ except Exception: return 0.0
180
+ fn = ns.get("solve")
181
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
182
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
183
+
184
+ cfg = Config()
185
+ cfg.iterations = 20
186
+ cfg.ensemble.models = [
187
+ ModelConfig(name="qwen2.5:0.5b", provider="ollama",
188
+ temperature=0.7, weight=1.0, role="fast"),
189
+ ]
190
+ cfg.evaluator.cascade = [(correctness, 0.0)]
191
+
192
+ result = Controller(cfg, initial_program=INITIAL).run()
193
+ print(result.best.code)
194
+ ```
195
+
196
+ Colab sessions are disconnected after ~90 min idle and the VM is wiped — set `cfg.checkpoint_path = "/content/drive/MyDrive/run.log"` after mounting Drive if you want resume across sessions.
197
+
198
+ ## Run the demo
199
+
200
+ Start Ollama and pull the model first:
201
+
202
+ ```bash
203
+ ollama serve
204
+ ollama pull gemma3:e4b
205
+ ```
206
+
207
+ Then:
208
+
209
+ ```bash
210
+ uv run python main.py
211
+ ```
212
+
213
+ ## Using OpenAI or Claude in the ensemble
214
+
215
+ Set the API key for whichever provider(s) you plan to use:
216
+
217
+ ```bash
218
+ export OPENAI_API_KEY=sk-...
219
+ export ANTHROPIC_API_KEY=sk-ant-...
220
+ ```
221
+
222
+ On Windows (cmd.exe): `set OPENAI_API_KEY=sk-...`
223
+
224
+ Then pick a `provider` per model in your config. You can freely mix providers in one ensemble:
225
+
226
+ ```python
227
+ from fastevolve.llm_ensemble import ModelConfig
228
+
229
+ cfg.ensemble.models = [
230
+ ModelConfig(name="gemma3:e4b", provider="ollama", temperature=0.6, weight=1.0, role="fast"),
231
+ ModelConfig(name="gpt-4o-mini", provider="openai", temperature=0.6, weight=1.0, role="fast"),
232
+ ModelConfig(name="claude-opus-4-7", provider="anthropic", temperature=0.7, weight=1.0,
233
+ role="deep", options={"max_tokens": 4096}),
234
+ ]
235
+ ```
236
+
237
+ `provider` defaults to `"ollama"`, so existing configs keep working unchanged.
@@ -0,0 +1,207 @@
1
+ # fastevolve
2
+
3
+ Minimal open-source AlphaEvolve: LLM-driven program evolution with MAP-Elites islands, cascade evaluation, and a local Ollama ensemble.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ uv sync
9
+ ```
10
+
11
+ The core install ships with Ollama support only. OpenAI and Anthropic SDKs are optional extras — install whichever you need:
12
+
13
+ ```bash
14
+ uv sync --extra openai # adds the OpenAI SDK
15
+ uv sync --extra anthropic # adds the Anthropic SDK
16
+ uv sync --extra all # both
17
+ ```
18
+
19
+ If you only use Ollama, skip the extras — neither SDK will be imported.
20
+
21
+ ## Quick start in code
22
+
23
+ ### Local (with Ollama)
24
+
25
+ Assumes `ollama serve` is running and you've pulled the model.
26
+
27
+ ```python
28
+ from fastevolve import Config, Controller
29
+ from fastevolve.llm_ensemble import ModelConfig
30
+
31
+ INITIAL = "def solve(x):\n return x\n"
32
+
33
+ def correctness(p):
34
+ ns = {}
35
+ try: exec(p.code, ns)
36
+ except Exception: return 0.0
37
+ fn = ns.get("solve")
38
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
39
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
40
+
41
+ cfg = Config()
42
+ cfg.iterations = 20
43
+ cfg.checkpoint_path = "run.log" # optional — resume if killed mid-run
44
+ cfg.ensemble.models = [
45
+ ModelConfig(name="gemma3:e4b", provider="ollama", temperature=0.7, weight=1.0, role="fast"),
46
+ ]
47
+ cfg.evaluator.cascade = [(correctness, 0.0)]
48
+
49
+ result = Controller(cfg, initial_program=INITIAL).run()
50
+ print(result.best.code)
51
+ ```
52
+
53
+ ### Google Colab (with OpenAI or Anthropic)
54
+
55
+ Ollama isn't practical on Colab — use an API provider instead. Paste this into a Colab cell:
56
+
57
+ ```python
58
+ !pip install -q "fastevolve[openai]"
59
+
60
+ import os
61
+ from google.colab import userdata
62
+ os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY") # store in Colab Secrets first
63
+
64
+ from fastevolve import Config, Controller
65
+ from fastevolve.llm_ensemble import ModelConfig
66
+
67
+ INITIAL = "def solve(x):\n return x\n"
68
+
69
+ def correctness(p):
70
+ ns = {}
71
+ try: exec(p.code, ns)
72
+ except Exception: return 0.0
73
+ fn = ns.get("solve")
74
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
75
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
76
+
77
+ cfg = Config()
78
+ cfg.iterations = 20
79
+ cfg.ensemble.models = [
80
+ ModelConfig(name="gpt-4o-mini", provider="openai", temperature=0.7, weight=1.0, role="fast"),
81
+ ]
82
+ cfg.evaluator.cascade = [(correctness, 0.0)]
83
+
84
+ result = Controller(cfg, initial_program=INITIAL).run()
85
+ print(result.best.code)
86
+ ```
87
+
88
+ ### Google Colab (with Claude)
89
+
90
+ ```python
91
+ !pip install -q "fastevolve[anthropic]"
92
+
93
+ import os
94
+ from google.colab import userdata
95
+ os.environ["ANTHROPIC_API_KEY"] = userdata.get("ANTHROPIC_API_KEY") # store in Colab Secrets first
96
+
97
+ from fastevolve import Config, Controller
98
+ from fastevolve.llm_ensemble import ModelConfig
99
+
100
+ INITIAL = "def solve(x):\n return x\n"
101
+
102
+ def correctness(p):
103
+ ns = {}
104
+ try: exec(p.code, ns)
105
+ except Exception: return 0.0
106
+ fn = ns.get("solve")
107
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
108
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
109
+
110
+ cfg = Config()
111
+ cfg.iterations = 20
112
+ cfg.ensemble.models = [
113
+ ModelConfig(name="claude-haiku-4-5-20251001", provider="anthropic",
114
+ temperature=0.7, weight=1.0, role="fast",
115
+ options={"max_tokens": 4096}),
116
+ ]
117
+ cfg.evaluator.cascade = [(correctness, 0.0)]
118
+
119
+ result = Controller(cfg, initial_program=INITIAL).run()
120
+ print(result.best.code)
121
+ ```
122
+
123
+ ### Google Colab (with Ollama)
124
+
125
+ Ollama can run on Colab if you install it, start the daemon in the background, and pull a small model. Use a GPU runtime (`Runtime → Change runtime type → T4 GPU`) for any model bigger than ~1B parameters.
126
+
127
+ ```python
128
+ # 1. Install ollama and fastevolve
129
+ !curl -fsSL https://ollama.com/install.sh | sh
130
+ !pip install -q fastevolve
131
+
132
+ # 2. Start the ollama daemon in the background
133
+ import subprocess, time
134
+ subprocess.Popen(["ollama", "serve"])
135
+ time.sleep(5) # give it a moment to bind to port 11434
136
+
137
+ # 3. Pull a small model (qwen2.5:0.5b is ~400 MB and fits the free CPU runtime)
138
+ !ollama pull qwen2.5:0.5b
139
+
140
+ # 4. Run fastevolve as usual
141
+ from fastevolve import Config, Controller
142
+ from fastevolve.llm_ensemble import ModelConfig
143
+
144
+ INITIAL = "def solve(x):\n return x\n"
145
+
146
+ def correctness(p):
147
+ ns = {}
148
+ try: exec(p.code, ns)
149
+ except Exception: return 0.0
150
+ fn = ns.get("solve")
151
+ cases = [(2, 4), (3, 9), (4, 16), (5, 25)]
152
+ return sum(1 for x, y in cases if fn and fn(x) == y) / len(cases)
153
+
154
+ cfg = Config()
155
+ cfg.iterations = 20
156
+ cfg.ensemble.models = [
157
+ ModelConfig(name="qwen2.5:0.5b", provider="ollama",
158
+ temperature=0.7, weight=1.0, role="fast"),
159
+ ]
160
+ cfg.evaluator.cascade = [(correctness, 0.0)]
161
+
162
+ result = Controller(cfg, initial_program=INITIAL).run()
163
+ print(result.best.code)
164
+ ```
165
+
166
+ Colab sessions are disconnected after ~90 min idle and the VM is wiped — set `cfg.checkpoint_path = "/content/drive/MyDrive/run.log"` after mounting Drive if you want resume across sessions.
167
+
168
+ ## Run the demo
169
+
170
+ Start Ollama and pull the model first:
171
+
172
+ ```bash
173
+ ollama serve
174
+ ollama pull gemma3:e4b
175
+ ```
176
+
177
+ Then:
178
+
179
+ ```bash
180
+ uv run python main.py
181
+ ```
182
+
183
+ ## Using OpenAI or Claude in the ensemble
184
+
185
+ Set the API key for whichever provider(s) you plan to use:
186
+
187
+ ```bash
188
+ export OPENAI_API_KEY=sk-...
189
+ export ANTHROPIC_API_KEY=sk-ant-...
190
+ ```
191
+
192
+ On Windows (cmd.exe): `set OPENAI_API_KEY=sk-...`
193
+
194
+ Then pick a `provider` per model in your config. You can freely mix providers in one ensemble:
195
+
196
+ ```python
197
+ from fastevolve.llm_ensemble import ModelConfig
198
+
199
+ cfg.ensemble.models = [
200
+ ModelConfig(name="gemma3:e4b", provider="ollama", temperature=0.6, weight=1.0, role="fast"),
201
+ ModelConfig(name="gpt-4o-mini", provider="openai", temperature=0.6, weight=1.0, role="fast"),
202
+ ModelConfig(name="claude-opus-4-7", provider="anthropic", temperature=0.7, weight=1.0,
203
+ role="deep", options={"max_tokens": 4096}),
204
+ ]
205
+ ```
206
+
207
+ `provider` defaults to `"ollama"`, so existing configs keep working unchanged.
@@ -0,0 +1,62 @@
1
+ import os
2
+ import pickle
3
+ import struct
4
+ import threading
5
+ from pathlib import Path
6
+ from queue import Queue
7
+
8
+ from .telemetry import log
9
+
10
+ _SENTINEL = object()
11
+
12
+
13
+ class Checkpointer:
14
+ """Append-only background log: O(1) main-thread cost per iteration."""
15
+
16
+ def __init__(self, path: str | None):
17
+ self.path = Path(path) if path else None
18
+ self._q: Queue = Queue()
19
+ self._thread: threading.Thread | None = None
20
+ if self.path:
21
+ self._thread = threading.Thread(target=self._worker, daemon=True)
22
+ self._thread.start()
23
+
24
+ def append(self, record) -> None:
25
+ if self.path:
26
+ self._q.put(record)
27
+
28
+ def close(self) -> None:
29
+ if self._thread:
30
+ self._q.put(_SENTINEL)
31
+ self._thread.join(timeout=5)
32
+
33
+ def load(self) -> list:
34
+ records: list = []
35
+ if not (self.path and self.path.exists()):
36
+ return records
37
+ try:
38
+ with open(self.path, "rb") as f:
39
+ while True:
40
+ hdr = f.read(4)
41
+ if len(hdr) < 4:
42
+ break
43
+ (n,) = struct.unpack("!I", hdr)
44
+ records.append(pickle.loads(f.read(n)))
45
+ except Exception:
46
+ log.exception("checkpoint load failed: %s", self.path)
47
+ return records
48
+
49
+ def _worker(self) -> None:
50
+ try:
51
+ with open(self.path, "ab") as f:
52
+ while True:
53
+ rec = self._q.get()
54
+ if rec is _SENTINEL:
55
+ return
56
+ data = pickle.dumps(rec, protocol=pickle.HIGHEST_PROTOCOL)
57
+ f.write(struct.pack("!I", len(data)))
58
+ f.write(data)
59
+ f.flush()
60
+ os.fsync(f.fileno())
61
+ except Exception:
62
+ log.exception("checkpoint worker died")
@@ -12,3 +12,4 @@ class Config:
12
12
  evaluator: EvaluatorConfig = field(default_factory=EvaluatorConfig)
13
13
  database: DatabaseConfig = field(default_factory=DatabaseConfig)
14
14
  iterations: int = 100
15
+ checkpoint_path: str | None = None
@@ -1,3 +1,4 @@
1
+ import itertools
1
2
  import re
2
3
  from dataclasses import dataclass, field
3
4
  from typing import Optional
@@ -7,11 +8,13 @@ from rich.progress import (
7
8
  TimeElapsedColumn, TimeRemainingColumn,
8
9
  )
9
10
 
11
+ from .checkpoint import Checkpointer
10
12
  from .config import Config
11
13
  from .prompt_sampler import PromptSampler, TemplateLibrary
12
14
  from .llm_ensemble import LLMEnsemble
13
15
  from .evaluator import Evaluator
14
16
  from .program_database import ProgramDatabase, Program
17
+ from .program_database import program as _program
15
18
  from .telemetry import setup, span, timings, log
16
19
 
17
20
 
@@ -39,9 +42,22 @@ class Controller:
39
42
  self.sampler = PromptSampler(config.prompt, library=lib)
40
43
  self.ensemble = LLMEnsemble(config.ensemble, system_prompts=lib.system_prompts)
41
44
  self.evaluator = Evaluator(config.evaluator)
45
+ self.checkpoint = Checkpointer(config.checkpoint_path)
46
+ records = self.checkpoint.load()
42
47
  self.database = ProgramDatabase(config.database)
43
- seed = self.database.seed(initial_program)
44
- self.database.add(seed, self.evaluator.execute(seed))
48
+ if records:
49
+ for prog, res in records:
50
+ self.database.add(prog, res)
51
+ _program._ids = itertools.count(max(self.database.by_id, default=-1) + 1)
52
+ self._start = max(0, len(records) - 1)
53
+ log.info("resumed: [bold]%d[/] records replayed (population=%d)",
54
+ len(records), len(self.database.by_id))
55
+ else:
56
+ seed = self.database.seed(initial_program)
57
+ seed_result = self.evaluator.execute(seed)
58
+ self.database.add(seed, seed_result)
59
+ self.checkpoint.append((seed, seed_result))
60
+ self._start = 0
45
61
 
46
62
  def run(self) -> RunResult:
47
63
  best: Optional[Program] = None
@@ -54,8 +70,9 @@ class Controller:
54
70
  TimeElapsedColumn(), TimeRemainingColumn(),
55
71
  ]
56
72
  with Progress(*cols, transient=False) as prog:
57
- task = prog.add_task("run", total=self.config.iterations, stage="init", fit=0.0, best=0.0)
58
- for _ in range(self.config.iterations):
73
+ task = prog.add_task("run", total=self.config.iterations, completed=self._start,
74
+ stage="init", fit=0.0, best=0.0)
75
+ for step in range(self._start, self.config.iterations):
59
76
  prog.update(task, stage="sample")
60
77
  with span("sample"):
61
78
  parent, insp = self.database.sample()
@@ -76,6 +93,8 @@ class Controller:
76
93
  best = child
77
94
  prog.update(task, advance=1, fit=child.fitness,
78
95
  best=best.fitness if best else 0.0)
96
+ self.checkpoint.append((child, result))
97
+ self.checkpoint.close()
79
98
  t = timings()
80
99
  log.info("done. population=%d best=%.3f", len(self.database.by_id),
81
100
  best.fitness if best else 0.0)
@@ -0,0 +1,25 @@
1
+ from anthropic import Anthropic
2
+
3
+ from ..telemetry import log
4
+ from .base import BaseLLM
5
+
6
+
7
+ class ClaudeLLM(BaseLLM):
8
+ def __init__(self, model_config, *, system_prompt: str | None = None, **_):
9
+ self.cfg = model_config
10
+ self.system_prompt = system_prompt
11
+ self.client = Anthropic() # reads ANTHROPIC_API_KEY
12
+
13
+ def generate(self, prompt: str) -> str:
14
+ try:
15
+ resp = self.client.messages.create(
16
+ model=self.cfg.name,
17
+ max_tokens=self.cfg.options.get("max_tokens", 4096),
18
+ temperature=self.cfg.temperature,
19
+ system=self.system_prompt or "",
20
+ messages=[{"role": "user", "content": prompt}],
21
+ )
22
+ return resp.content[0].text
23
+ except Exception:
24
+ log.exception("anthropic generate failed for model=%s", self.cfg.name)
25
+ raise
@@ -5,6 +5,7 @@ from typing import List, Literal
5
5
  @dataclass(kw_only=True)
6
6
  class ModelConfig:
7
7
  name: str
8
+ provider: Literal["ollama", "openai", "anthropic"] = "ollama"
8
9
  temperature: float = 0.7
9
10
  weight: float = 1.0
10
11
  role: Literal["fast", "deep"] = "fast"
@@ -1,17 +1,29 @@
1
1
  import random
2
- from .ollama import OllamaLLM
2
+
3
+
4
+ def _make_llm(mcfg, **kw):
5
+ if mcfg.provider == "ollama":
6
+ from .ollama import OllamaLLM
7
+ return OllamaLLM(mcfg, **kw)
8
+ if mcfg.provider == "openai":
9
+ from .openai_llm import OpenAILLM
10
+ return OpenAILLM(mcfg, **kw)
11
+ if mcfg.provider == "anthropic":
12
+ from .anthropic_llm import ClaudeLLM
13
+ return ClaudeLLM(mcfg, **kw)
14
+ raise ValueError(f"unknown provider: {mcfg.provider}")
3
15
 
4
16
 
5
17
  class LLMEnsemble:
6
18
  def __init__(self, config, *, system_prompts: dict | None = None):
7
19
  self.config = config
8
20
  sp = system_prompts or {}
9
- self.llms = [OllamaLLM(m, host=config.host, timeout=config.timeout,
21
+ self.llms = [_make_llm(m, host=config.host, timeout=config.timeout,
10
22
  system_prompt=sp.get(m.name)) for m in config.models]
11
23
  if not self.llms:
12
24
  raise ValueError("EnsembleConfig.models is empty")
13
25
 
14
- def select_model(self) -> OllamaLLM:
26
+ def select_model(self):
15
27
  return random.choices(self.llms, weights=[m.cfg.weight for m in self.llms], k=1)[0]
16
28
 
17
29
  def generate(self, prompt: str) -> str:
@@ -0,0 +1,28 @@
1
+ from openai import OpenAI
2
+
3
+ from ..telemetry import log
4
+ from .base import BaseLLM
5
+
6
+
7
+ class OpenAILLM(BaseLLM):
8
+ def __init__(self, model_config, *, system_prompt: str | None = None, **_):
9
+ self.cfg = model_config
10
+ self.system_prompt = system_prompt
11
+ self.client = OpenAI() # reads OPENAI_API_KEY
12
+
13
+ def generate(self, prompt: str) -> str:
14
+ try:
15
+ msgs = []
16
+ if self.system_prompt:
17
+ msgs.append({"role": "system", "content": self.system_prompt})
18
+ msgs.append({"role": "user", "content": prompt})
19
+ resp = self.client.chat.completions.create(
20
+ model=self.cfg.name,
21
+ messages=msgs,
22
+ temperature=self.cfg.temperature,
23
+ **self.cfg.options,
24
+ )
25
+ return resp.choices[0].message.content or ""
26
+ except Exception:
27
+ log.exception("openai generate failed for model=%s", self.cfg.name)
28
+ raise
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fastevolve"
3
- version = "0.2.1"
3
+ version = "0.3.0"
4
4
  description = "Minimal open-source AlphaEvolve: LLM-driven program evolution with MAP-Elites islands, cascade evaluation, and a local Ollama ensemble."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -21,6 +21,9 @@ dependencies = [
21
21
 
22
22
  [project.optional-dependencies]
23
23
  dev = ["pytest>=8", "ruff>=0.6"]
24
+ openai = ["openai>=1.0"]
25
+ anthropic = ["anthropic>=0.30"]
26
+ all = ["openai>=1.0", "anthropic>=0.30"]
24
27
 
25
28
  [project.scripts]
26
29
  fastevolve-demo = "main:main"
@@ -11,6 +11,25 @@ wheels = [
11
11
  { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
12
12
  ]
13
13
 
14
+ [[package]]
15
+ name = "anthropic"
16
+ version = "0.112.0"
17
+ source = { registry = "https://pypi.org/simple" }
18
+ dependencies = [
19
+ { name = "anyio" },
20
+ { name = "distro" },
21
+ { name = "docstring-parser" },
22
+ { name = "httpx" },
23
+ { name = "jiter" },
24
+ { name = "pydantic" },
25
+ { name = "sniffio" },
26
+ { name = "typing-extensions" },
27
+ ]
28
+ sdist = { url = "https://files.pythonhosted.org/packages/7b/dd/808c144d4a883fcfd12fe0d7689b1d86bbbea6666c1cc957ad19f1017c22/anthropic-0.112.0.tar.gz", hash = "sha256:e180cd91aa5b9b32e4007fe69892ab128d8a86b9f90825103b1903fbc977d0af", size = 937460, upload-time = "2026-06-24T18:45:56.844Z" }
29
+ wheels = [
30
+ { url = "https://files.pythonhosted.org/packages/a9/26/ea71185027956325be1903d4fcaf7461d5ef40ca8f0e64f992e24ea9db0e/anthropic-0.112.0-py3-none-any.whl", hash = "sha256:bcc6268612c716dbb77133dd60fc41d26016d1b81dee9a52314d210193638751", size = 931954, upload-time = "2026-06-24T18:45:58.205Z" },
31
+ ]
32
+
14
33
  [[package]]
15
34
  name = "anyio"
16
35
  version = "4.14.1"
@@ -42,9 +61,27 @@ wheels = [
42
61
  { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
43
62
  ]
44
63
 
64
+ [[package]]
65
+ name = "distro"
66
+ version = "1.9.0"
67
+ source = { registry = "https://pypi.org/simple" }
68
+ sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" }
69
+ wheels = [
70
+ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
71
+ ]
72
+
73
+ [[package]]
74
+ name = "docstring-parser"
75
+ version = "0.18.0"
76
+ source = { registry = "https://pypi.org/simple" }
77
+ sdist = { url = "https://files.pythonhosted.org/packages/e0/4d/f332313098c1de1b2d2ff91cf2674415cc7cddab2ca1b01ae29774bd5fdf/docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015", size = 29341, upload-time = "2026-04-14T04:09:19.867Z" }
78
+ wheels = [
79
+ { url = "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b", size = 22484, upload-time = "2026-04-14T04:09:18.638Z" },
80
+ ]
81
+
45
82
  [[package]]
46
83
  name = "fastevolve"
47
- version = "0.2.1"
84
+ version = "0.3.0"
48
85
  source = { editable = "." }
49
86
  dependencies = [
50
87
  { name = "ollama" },
@@ -52,19 +89,33 @@ dependencies = [
52
89
  ]
53
90
 
54
91
  [package.optional-dependencies]
92
+ all = [
93
+ { name = "anthropic" },
94
+ { name = "openai" },
95
+ ]
96
+ anthropic = [
97
+ { name = "anthropic" },
98
+ ]
55
99
  dev = [
56
100
  { name = "pytest" },
57
101
  { name = "ruff" },
58
102
  ]
103
+ openai = [
104
+ { name = "openai" },
105
+ ]
59
106
 
60
107
  [package.metadata]
61
108
  requires-dist = [
109
+ { name = "anthropic", marker = "extra == 'all'", specifier = ">=0.30" },
110
+ { name = "anthropic", marker = "extra == 'anthropic'", specifier = ">=0.30" },
62
111
  { name = "ollama", specifier = ">=0.4.0" },
112
+ { name = "openai", marker = "extra == 'all'", specifier = ">=1.0" },
113
+ { name = "openai", marker = "extra == 'openai'", specifier = ">=1.0" },
63
114
  { name = "pytest", marker = "extra == 'dev'", specifier = ">=8" },
64
115
  { name = "rich", specifier = ">=13.7" },
65
116
  { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6" },
66
117
  ]
67
- provides-extras = ["dev"]
118
+ provides-extras = ["dev", "openai", "anthropic", "all"]
68
119
 
69
120
  [[package]]
70
121
  name = "h11"
@@ -121,6 +172,78 @@ wheels = [
121
172
  { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
122
173
  ]
123
174
 
175
+ [[package]]
176
+ name = "jiter"
177
+ version = "0.15.0"
178
+ source = { registry = "https://pypi.org/simple" }
179
+ sdist = { url = "https://files.pythonhosted.org/packages/66/b5/55f06bb281d92fb3cc86d14e1def2bd908bb77693183e7cb1f5a3c388b0c/jiter-0.15.0.tar.gz", hash = "sha256:4251acc80e2b7c9b7b8823456ea0fceeb0734dac2df7636d3c711b38476b5a76", size = 166640, upload-time = "2026-05-19T10:09:48.361Z" }
180
+ wheels = [
181
+ { url = "https://files.pythonhosted.org/packages/44/53/4f6bddbcde3c71e56d0aa1337ec95950f3d27dd4153e25aadf0feac71751/jiter-0.15.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0e90a1c315a0226ec822d973817967f9223b7701546c8c2a7913e7ab0926294d", size = 308793, upload-time = "2026-05-19T10:07:35.25Z" },
182
+ { url = "https://files.pythonhosted.org/packages/01/84/c01099b59a285a1ebba64ae93f62bfa036675340fd1b0045ae65890a0442/jiter-0.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8c9004af7c8d67cce7f1aae1026fb55607f4aa600710d08ede3a3ce4aeefe7e0", size = 309570, upload-time = "2026-05-19T10:07:36.919Z" },
183
+ { url = "https://files.pythonhosted.org/packages/58/64/8fb7f9d45bb98190355454cd04dad8d8f27223d6bd52f83af07f637168a6/jiter-0.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c210f8b35dc6f30aafd4b4365ca89b9d1189f21ab49b8e68fa6322a847aef138", size = 336783, upload-time = "2026-05-19T10:07:38.694Z" },
184
+ { url = "https://files.pythonhosted.org/packages/c3/b6/f5739011d009b3a30f6a53c5240979030ba29ae46a8c67e3a15759f7c37d/jiter-0.15.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f30bae8bc1c2d613e28e5af3e8cceb09b742f1c8a8a5f839fb67afaffc03b61", size = 363555, upload-time = "2026-05-19T10:07:40.832Z" },
185
+ { url = "https://files.pythonhosted.org/packages/e5/12/98a9d9f766665e8a3b6252454e17cb0c464606a28cf2fa09399b003345fa/jiter-0.15.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60e71b6d10cfc284c9bf36bd885e8d44c46f688ce50aa91b5edd90181dea687", size = 452255, upload-time = "2026-05-19T10:07:42.62Z" },
186
+ { url = "https://files.pythonhosted.org/packages/e8/d5/60f972840f79c5e7544fce567c56f1e4e50468f996baba3e78d823dd62a6/jiter-0.15.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ab068bce62a45aa3e7367eceaffb5dde60b7eb853be8dece45132e3d0ff4879", size = 373559, upload-time = "2026-05-19T10:07:44.201Z" },
187
+ { url = "https://files.pythonhosted.org/packages/ee/cf/d46ef1234ba335aabc2f013210db8e0821a22f5e644a2e9449df199ecc23/jiter-0.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa248c9eb220197d363f688818dac2fd4b2f0cd7d843ca7105d652034823427d", size = 346055, upload-time = "2026-05-19T10:07:46.005Z" },
188
+ { url = "https://files.pythonhosted.org/packages/f0/63/4d2749d8d54d230bad9b3a6b0d00cc28c6ff6b2fdffc26a8ccf76cc5a974/jiter-0.15.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2a77aadd57cac1682e4401a72724d2796d89a4ba129b1a5812aa94ee480826eb", size = 351406, upload-time = "2026-05-19T10:07:47.855Z" },
189
+ { url = "https://files.pythonhosted.org/packages/d9/b9/9965b990035d8773328e0a8c8b457a87bf2b19f6c4126d9d99296be5d16a/jiter-0.15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ae901f3a55bfafdde31d289590fa25e3245735a2b1e8c7cc15871710a002871", size = 389357, upload-time = "2026-05-19T10:07:49.665Z" },
190
+ { url = "https://files.pythonhosted.org/packages/2d/55/9ddf903deda1413e87fed792f416b7123daee5b8efbad6a202a7421c36a5/jiter-0.15.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f0b271b462769543716f92d3a4f90527df6ef5ed05ee95ec4137f513e21e1b77", size = 517263, upload-time = "2026-05-19T10:07:51.537Z" },
191
+ { url = "https://files.pythonhosted.org/packages/e8/76/a0c40ad064d3a20a4fde231e35d56e9a01ce82164278180e82d5daf85469/jiter-0.15.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2fb6a5d26af81fc0f00f9360a891e05cf755e149bba391c4d563adc54812973d", size = 548646, upload-time = "2026-05-19T10:07:53.196Z" },
192
+ { url = "https://files.pythonhosted.org/packages/23/4f/eca9b954942916ba2f453891b8593ab444cd872396fe66a3936616f236f3/jiter-0.15.0-cp312-cp312-win32.whl", hash = "sha256:c2f6bb8b5216ab9e7873bc08b5d7bef2b8abbb578a3069bf1cd14a45d71d771d", size = 206427, upload-time = "2026-05-19T10:07:55.307Z" },
193
+ { url = "https://files.pythonhosted.org/packages/95/bf/8ead82a87495149542748e828d153fd232a512a22c83b02c4815c1a9c7d8/jiter-0.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:40b2c7e92c44a84d748d21706c68dc6ff8161d80b59c99d774721a0d2317d7c7", size = 197300, upload-time = "2026-05-19T10:07:56.651Z" },
194
+ { url = "https://files.pythonhosted.org/packages/f4/e4/9b8a78fb2d894471bc344e37f1949bdd784bd914d031dba0ba3a40c71dd7/jiter-0.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:cc0bc345cf2df9d1c00ac443f50d543c1ccfa8b0422cb85b1ab70d681c0b255b", size = 192702, upload-time = "2026-05-19T10:07:58.307Z" },
195
+ { url = "https://files.pythonhosted.org/packages/e5/f4/f708c900ecee41b2025ef8413d5351e5649eb2125c506f6720cc69b06f5c/jiter-0.15.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1c11465f97e2abf45a014b83b730222f8f1c5335e802c7055a67d50de6f1f4e3", size = 307829, upload-time = "2026-05-19T10:07:59.704Z" },
196
+ { url = "https://files.pythonhosted.org/packages/86/59/db537c0949e83668c38481d426b9f2fd5ab758c4ee53a811dd0a510626a0/jiter-0.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d1e7b1776f0797956c509e123d0952d10d293a9492dea9f288ab9570ec01d1a5", size = 308445, upload-time = "2026-05-19T10:08:01.184Z" },
197
+ { url = "https://files.pythonhosted.org/packages/37/38/ea0e13b18c30ef951da0d47d39e7fa9edb82a93a62990ffbd7cea9b622d4/jiter-0.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351a341c2105aa430b7047e30f1bf7975f6313b00165d3fc07be2edaf741f279", size = 336181, upload-time = "2026-05-19T10:08:02.688Z" },
198
+ { url = "https://files.pythonhosted.org/packages/58/fc/2303901b16c4ba05865588990a420c0b4156270b44379c20931544a1d962/jiter-0.15.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ab395feec8d249ec4044e228e98a7033f043426a265df439dc3698823f0a4e4", size = 362985, upload-time = "2026-05-19T10:08:04.394Z" },
199
+ { url = "https://files.pythonhosted.org/packages/5b/6f/11bace093c52e7d4d26c8e606ccd7ae8c972189622469ec0d9e28161e28b/jiter-0.15.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2a438005b6f22d0273413484d6094d7c2c5d10ec1b3a3bf128e0d1d3ba53258", size = 453292, upload-time = "2026-05-19T10:08:05.967Z" },
200
+ { url = "https://files.pythonhosted.org/packages/22/db/987f2f086ca4d7a6582eb4ccd513f9b26b42d9e4243a087609a3137a8fc7/jiter-0.15.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f18f85e4218d1b40f000f42a92239a7a61a902cd42c65e6c360dbd17dcb20894", size = 373501, upload-time = "2026-05-19T10:08:07.857Z" },
201
+ { url = "https://files.pythonhosted.org/packages/8f/7c/89fbcabb2739b7a5b8dc959a1b6c5761f6484f5fed3486854b3c789bb1de/jiter-0.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1aa62e277fc1cbd80e6deacae6f4d983b41b3d7728e0645c5d741a6149bba45", size = 344683, upload-time = "2026-05-19T10:08:09.431Z" },
202
+ { url = "https://files.pythonhosted.org/packages/30/6f/6cca7692e7dddfec6d8d76c54dc97f2af2a41df4ac0674b999df1f09a5f3/jiter-0.15.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:6550fa135c7deb8ead6af49ed7ff648532ea8334a1447fe34a36315ef79c5c29", size = 350892, upload-time = "2026-05-19T10:08:11.352Z" },
203
+ { url = "https://files.pythonhosted.org/packages/39/14/0338d6190cb8e6d22e677ab1d4eabd4117f67cca70c54cd04b82ff64e068/jiter-0.15.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:066f8f33f18b2419cd8213b2436fa7fbc9c499f315971cfa3ce1f9820c001b1b", size = 388723, upload-time = "2026-05-19T10:08:12.912Z" },
204
+ { url = "https://files.pythonhosted.org/packages/90/31/cc19f4a1bdb6afb09ce6a2f2615aa8d44d994eba0d8e6105ed1af920e736/jiter-0.15.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:75e8a04e91432dde9f1838373cf93d23726c79d3e908d319acf0e796f85592e7", size = 516648, upload-time = "2026-05-19T10:08:14.808Z" },
205
+ { url = "https://files.pythonhosted.org/packages/49/9f/833c541512cd091b63c10c0381973dfe11bc7a503a818c16384417e0c81e/jiter-0.15.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a97261f1fccb8e50ecd2890a96e46efdc3f57c80a197324c6777827231eca712", size = 547382, upload-time = "2026-05-19T10:08:16.927Z" },
206
+ { url = "https://files.pythonhosted.org/packages/d2/11/e7b70e91f90bc4477e8eee9e8a5f7cf3cb41b4525d6394dc98a714eb8f7f/jiter-0.15.0-cp313-cp313-win32.whl", hash = "sha256:c77496cb10bd7549690fbbab3e5ec05857b83e49276f4a9423a766ddd2afcd4c", size = 205845, upload-time = "2026-05-19T10:08:18.401Z" },
207
+ { url = "https://files.pythonhosted.org/packages/4b/23/5c20d9ad6f02c493e4023e5d2d09e1c1f15fe2753c9102c544aff068a88e/jiter-0.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b15741f501469009ae0ae90b7147958a664a7dede40aa7ff174a8a4645f546d0", size = 196842, upload-time = "2026-05-19T10:08:20.131Z" },
208
+ { url = "https://files.pythonhosted.org/packages/6b/11/1eb400ef248e8c925fd883fbe325daf5e42cd1b0d308539dd332bd4f7ffc/jiter-0.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d6a60072b44c3c2b797a7ddcbcbbf2b34ea3cfd4721580fbfd2a09d9d9b84ba", size = 192212, upload-time = "2026-05-19T10:08:21.807Z" },
209
+ { url = "https://files.pythonhosted.org/packages/8a/60/2fd8d7c79da8acf9b7b277c7616847773779356b92acfc9bb158452174da/jiter-0.15.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ef1fd24d9413f6209e00d3d5a453e67acfe004a25cc6c8e8484faed4311ab9e8", size = 315065, upload-time = "2026-05-19T10:08:23.218Z" },
210
+ { url = "https://files.pythonhosted.org/packages/46/f4/008fb7d65e8ac2abf00811651a661e025c4ba80bbc6f378450384ddd3aed/jiter-0.15.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:144f8e72cb53dab146347b91cceac01f5481237f2b93b4a339a1ee8f8878b67c", size = 339444, upload-time = "2026-05-19T10:08:24.701Z" },
211
+ { url = "https://files.pythonhosted.org/packages/00/55/90b0c7b9c6896c0f2a591dd36d36b71d22e09674bfef178fa03ba3f81499/jiter-0.15.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553fcac2ef2cb990877f9fc0833b8b629a3e6a5670b6b5fd58219b41a653ddc4", size = 347779, upload-time = "2026-05-19T10:08:26.408Z" },
212
+ { url = "https://files.pythonhosted.org/packages/51/6b/69666cec5000fd57734c118437394516c749ae8dbeea9fb66d6fef9c4775/jiter-0.15.0-cp313-cp313t-win_amd64.whl", hash = "sha256:774f93f65031856bf14ad9f59bdcab8b8cad501e5ceabd51ba3525f76937a25b", size = 200395, upload-time = "2026-05-19T10:08:28.055Z" },
213
+ { url = "https://files.pythonhosted.org/packages/39/04/a6aa62cd27e8149b0d28df5561f10f6cceaf7935a9ccf3f1c5a05f9a0cd8/jiter-0.15.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f1e1754960f38ec40613a07e5e372df67acb3b890fb383b6fb3de3e49ddbf3c7", size = 190516, upload-time = "2026-05-19T10:08:29.35Z" },
214
+ { url = "https://files.pythonhosted.org/packages/eb/d2/079f350ebf7859d081de30aa890f9e3be68516f754f3ba32366ffff4dcee/jiter-0.15.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:ac0d9ddea4350974be7a221fc25895f251a8fee748c889bdced2141c0fec1a49", size = 308884, upload-time = "2026-05-19T10:08:31.667Z" },
215
+ { url = "https://files.pythonhosted.org/packages/04/4e/a2c30a7f69b48c03b20935d647479106fe932f6e63f75faf53937197e05d/jiter-0.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:01a8222cf05ab1128e239421156c207949808acaaea2bdfd33130ae666786e86", size = 310028, upload-time = "2026-05-19T10:08:33.304Z" },
216
+ { url = "https://files.pythonhosted.org/packages/40/90/2e7cdfd3cf8ca967be38c48f5cf474d79f089efaf559a40f15984a77ae69/jiter-0.15.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:182226cbc930c9fab81bc2e41a4da672f89539906dadb05e75670ac07b94f71f", size = 337485, upload-time = "2026-05-19T10:08:35.259Z" },
217
+ { url = "https://files.pythonhosted.org/packages/9b/11/15a1aa28b120b8ee5b4f1fb894c125046225f09847738bd64233d3b84883/jiter-0.15.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:71683c38c825452999b5717fcae07ea708e8c93003e808be4319c1b02e3d176e", size = 364223, upload-time = "2026-05-19T10:08:36.694Z" },
218
+ { url = "https://files.pythonhosted.org/packages/b7/25/f442e8af5f3d0dcf47b39e83a0efd9ee45ea946aa6d04625dc3181eae3b6/jiter-0.15.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f2218e6a9e5c18bc10fe6d41ac189c442c88eacf11bad9f28ef95a9bef00e6", size = 456387, upload-time = "2026-05-19T10:08:38.143Z" },
219
+ { url = "https://files.pythonhosted.org/packages/da/f4/37f2d2c9f64f49af7da652ed7532bb5a2372e588e6927c3fdd76f911db65/jiter-0.15.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5157de9f76eb4bc5ea74a1219366a25f945ad305641d74e04f59c54087091aa9", size = 374461, upload-time = "2026-05-19T10:08:39.869Z" },
220
+ { url = "https://files.pythonhosted.org/packages/60/28/edcfbbbf0cb15436f36664a8908a0df47ab9006298d4cd937dc08ea932d6/jiter-0.15.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c5db5527c221249a876160663ab891ace358c17f7b9c93ec1478b7f0550e5c", size = 345924, upload-time = "2026-05-19T10:08:41.668Z" },
221
+ { url = "https://files.pythonhosted.org/packages/47/13/89fba6398dab7f202b7278c4b4aac122399d2c0183971c4a57a3b7088df5/jiter-0.15.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:3e4540b8e74e4268811ac05db226a6a128ff572e7e0ce3f1163b693cadb184cd", size = 352283, upload-time = "2026-05-19T10:08:43.091Z" },
222
+ { url = "https://files.pythonhosted.org/packages/1b/da/0f6af8cef2c565a1ab44d970f268c43ccaa72707386ea6388e6fe2b6cd26/jiter-0.15.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:62ebd14e47e9aed9df4472afcb2663668ce4d74891cd54f86bf6e44029d6dc89", size = 389985, upload-time = "2026-05-19T10:08:44.915Z" },
223
+ { url = "https://files.pythonhosted.org/packages/a1/ec/b9cb7d6d29e24ee14910266157d2a279d7a8f60ee0df7fa840882976ba64/jiter-0.15.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0be6f5ad41a809f303f416d17cec92a7a725902fb9b4f3de3d19362ac0ef8554", size = 517695, upload-time = "2026-05-19T10:08:46.486Z" },
224
+ { url = "https://files.pythonhosted.org/packages/64/5e/6d1bda880723aae0ad86b4b763f044362448efe31e3e819635d41cb03451/jiter-0.15.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:813dfbb17d65328bf86e5f0905dd277ba2265d3ca20556e86c0c7035b7182e5a", size = 548868, upload-time = "2026-05-19T10:08:48.026Z" },
225
+ { url = "https://files.pythonhosted.org/packages/0c/72/7de501cf38dcacaf35098796f3a50e0f2e338baba18a58946c618544b809/jiter-0.15.0-cp314-cp314-win32.whl", hash = "sha256:50e51156192722a9c58db112837d3f8ef96fb3c5ecc14e95f409134b08b158ec", size = 206380, upload-time = "2026-05-19T10:08:49.738Z" },
226
+ { url = "https://files.pythonhosted.org/packages/1e/a9/e19addf4b0c1bdce52c6da12351e6bc42c340c45e7c09e2158e46d293ccc/jiter-0.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:30ce1a5d16b5641dc935d50ef775af6a0871e3d14ab05d6fc54dff371b78e558", size = 197687, upload-time = "2026-05-19T10:08:51.088Z" },
227
+ { url = "https://files.pythonhosted.org/packages/f2/c9/776b1db01db25fc6c1d58d1979a37b0a9fe787e5f5b1d062d2eaacb77923/jiter-0.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:510c8b3c17a0ed9ac69850c0438dada3c9b82d9c4d589fcb62002a5a9cf3a866", size = 192571, upload-time = "2026-05-19T10:08:52.451Z" },
228
+ { url = "https://files.pythonhosted.org/packages/a0/f6/45bb4670bacf300fd2c7abadbfb3af376e5f1b6ae75fd9bc069891d15870/jiter-0.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7553333dd0930c104a5a0db8df72bf7219fe663d731383b576bb6ed6351c984d", size = 317151, upload-time = "2026-05-19T10:08:53.867Z" },
229
+ { url = "https://files.pythonhosted.org/packages/d7/68/ed635ad5acd7b73e454283083bbb7c8205ad10e88b0d9d7d793b09fe8226/jiter-0.15.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2143ab06181d2b029eedcb6af3cebe95f11bbac62441781860f98ee9330a6a6", size = 341243, upload-time = "2026-05-19T10:08:55.383Z" },
230
+ { url = "https://files.pythonhosted.org/packages/5d/db/3ff4176b817b8ea33879e71e13d8bc2b0d481a7ed3fe9e080f333d415c16/jiter-0.15.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eac374c5c975709b69c10f09afd199df74150172156ad10c8d4fd785b7da995", size = 363629, upload-time = "2026-05-19T10:08:56.928Z" },
231
+ { url = "https://files.pythonhosted.org/packages/ab/24/5f8270e0ba9c883582f96f722f8a0b58015c7ce1f8c6d4571cf394e99b6b/jiter-0.15.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3b3b775e33d3bfaec9899edc526ae97b0da0bf9d071a46124ba419149a414f8", size = 456198, upload-time = "2026-05-19T10:08:58.618Z" },
232
+ { url = "https://files.pythonhosted.org/packages/45/5b/76fc02b0b5c54c3d18c60653156e2f76fde1816f9b4722db68d6ee2c897e/jiter-0.15.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3071db3346334beae1360b46da4606da57bf3528c167b3c38533afaf9f2c5", size = 373710, upload-time = "2026-05-19T10:09:00.151Z" },
233
+ { url = "https://files.pythonhosted.org/packages/c4/52/4310821b0ea9277994d3e1f49fc6a4b34e4800caebacb2c0af81da59a454/jiter-0.15.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6694a173ecabc12eb60efbc0b474464ead1951ff65cd8b1e72100715c64512b", size = 349901, upload-time = "2026-05-19T10:09:01.621Z" },
234
+ { url = "https://files.pythonhosted.org/packages/93/fe/67648c35b3594fba8854ac64cc8a826d8bcd18324bbdb53d77697c60b6ef/jiter-0.15.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:a254e10b593624d230c365b6d616b22ca0ad65e63a16e6631c2b3466022e6ba8", size = 352438, upload-time = "2026-05-19T10:09:03.216Z" },
235
+ { url = "https://files.pythonhosted.org/packages/cb/28/0a1879d07ad6b3e025a2750027363452ced93c2d16d1c9d4b153ffd51c91/jiter-0.15.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8d2955167274e15d79a7a020afdd9b39c990eb80b2d89fca695d92dcfdd38ec", size = 388152, upload-time = "2026-05-19T10:09:04.741Z" },
236
+ { url = "https://files.pythonhosted.org/packages/c1/78/46c6f6b56ba85c90021f4afd72ed42f691f8f84daacb5fe27277070e3858/jiter-0.15.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:acf4ee4d1fc55917239fe72972fb292dd773055d05eb040d36f4326e02cc2c0e", size = 517707, upload-time = "2026-05-19T10:09:06.231Z" },
237
+ { url = "https://files.pythonhosted.org/packages/ca/cb/720662d4c88fcad606e826fef5424365527ba43ce4868a479aed8f8c507e/jiter-0.15.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:e7196e56f1cd69af1dbb07dff02dcfb260a50b45a82d409d92a06fedb32473b5", size = 548241, upload-time = "2026-05-19T10:09:08.093Z" },
238
+ { url = "https://files.pythonhosted.org/packages/60/e3/935b8034fd143f21125c87d51404a9e0e1449186a494405721ff5d1d695e/jiter-0.15.0-cp314-cp314t-win32.whl", hash = "sha256:7f6163c0f10b055245f814dcc59f4818da60dfe72f3e72ab89fc24b6bd5e9c52", size = 207950, upload-time = "2026-05-19T10:09:09.616Z" },
239
+ { url = "https://files.pythonhosted.org/packages/93/59/984fd9ece895953dad3e0880a650e766f5a2da2c5514f0eafdaaabbeb5f9/jiter-0.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:980c256edb05b78a111b99c4de3b1d32e31634b867fd1fc2cf726e7b7bba9854", size = 200055, upload-time = "2026-05-19T10:09:11.367Z" },
240
+ { url = "https://files.pythonhosted.org/packages/0e/a4/cf8d779feb133a27a2e3bc833bccb9e13aa332cdf820497ebf72c10ce8c3/jiter-0.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:66b1880df2d01e206e8339769d1c7c1753bcb653efd6289e203f6f24ebada0c0", size = 191244, upload-time = "2026-05-19T10:09:12.74Z" },
241
+ { url = "https://files.pythonhosted.org/packages/73/38/505941b2b092fd5bbbd60a52a880db1173f1690ae6751bed3af1c9ddcb4e/jiter-0.15.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:631f13a3d04e97d4e083993b10f4b99530e3a10d953e2eb5e196b7dc7f812ce0", size = 303769, upload-time = "2026-05-19T10:09:42.203Z" },
242
+ { url = "https://files.pythonhosted.org/packages/e7/95/a06692b29e77473f286e1ec1f426d3ca44d7b5843be8ad21d7a5f3fcdcc0/jiter-0.15.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:b6c0ffae686c39bf3737be60793783267628783ea42545632c10b291105aee45", size = 305128, upload-time = "2026-05-19T10:09:43.657Z" },
243
+ { url = "https://files.pythonhosted.org/packages/23/85/7270d7ad41d6061a25b950c6bf91d638bd9aacb113200a8c8d57a055fd67/jiter-0.15.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d54fb5b31dea401a41af3f8a7d2512e9b6a6a005491e6166c7e4ffab9639a9c", size = 340459, upload-time = "2026-05-19T10:09:45.452Z" },
244
+ { url = "https://files.pythonhosted.org/packages/c8/8d/302cb2057b7513327b4d575cff6b1d066ee6431a5357fc3f8867cd684406/jiter-0.15.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d5d6090cdc1b7c9e780dfb04949a990adb1e301a2fc0bbcee7de4638d33f9a", size = 344469, upload-time = "2026-05-19T10:09:46.864Z" },
245
+ ]
246
+
124
247
  [[package]]
125
248
  name = "markdown-it-py"
126
249
  version = "4.2.0"
@@ -155,6 +278,25 @@ wheels = [
155
278
  { url = "https://files.pythonhosted.org/packages/c4/ab/d6722beeb2d10f7a3b9ff49375708904fde18f82b5609a0bc4aeb5996a4d/ollama-0.6.2-py3-none-any.whl", hash = "sha256:3ad7daab28e5a973445c36a73882a3ef698c2ebb00e21e308652741577509f7d", size = 15115, upload-time = "2026-04-29T21:21:13.794Z" },
156
279
  ]
157
280
 
281
+ [[package]]
282
+ name = "openai"
283
+ version = "2.44.0"
284
+ source = { registry = "https://pypi.org/simple" }
285
+ dependencies = [
286
+ { name = "anyio" },
287
+ { name = "distro" },
288
+ { name = "httpx" },
289
+ { name = "jiter" },
290
+ { name = "pydantic" },
291
+ { name = "sniffio" },
292
+ { name = "tqdm" },
293
+ { name = "typing-extensions" },
294
+ ]
295
+ sdist = { url = "https://files.pythonhosted.org/packages/49/f5/7c7cb955305cb41f7f3c5fd7e0e38bf6bbf2658468863d4b7b868a5cb8df/openai-2.44.0.tar.gz", hash = "sha256:68a5a5ffad82b8ff7d451c437529fb64f7c3b8123aaf0c021966a882d9e3947d", size = 988753, upload-time = "2026-06-24T20:56:02.293Z" }
296
+ wheels = [
297
+ { url = "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl", hash = "sha256:0a2a3ab2e29aeda368700f662ff9ba0f9df17ba4c54577a64e08b8115a3cc0ad", size = 1366216, upload-time = "2026-06-24T20:55:58.882Z" },
298
+ ]
299
+
158
300
  [[package]]
159
301
  name = "packaging"
160
302
  version = "26.2"
@@ -326,6 +468,27 @@ wheels = [
326
468
  { url = "https://files.pythonhosted.org/packages/30/66/9a73695e31eaee04f35d8475998bf8ab354465f9c638936d76111603dcc5/ruff-0.15.19-py3-none-win_arm64.whl", hash = "sha256:6c6b607466e47349332eb1d9be52fb1467423fc07c217341af41cd0f3f0573be", size = 11376779, upload-time = "2026-06-24T01:10:34.465Z" },
327
469
  ]
328
470
 
471
+ [[package]]
472
+ name = "sniffio"
473
+ version = "1.3.1"
474
+ source = { registry = "https://pypi.org/simple" }
475
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
476
+ wheels = [
477
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
478
+ ]
479
+
480
+ [[package]]
481
+ name = "tqdm"
482
+ version = "4.68.3"
483
+ source = { registry = "https://pypi.org/simple" }
484
+ dependencies = [
485
+ { name = "colorama", marker = "sys_platform == 'win32'" },
486
+ ]
487
+ sdist = { url = "https://files.pythonhosted.org/packages/87/d7/0535a28b1f5f24f6612fb3ff1e89fb1a8d160fee0f976e0aa6803862134b/tqdm-4.68.3.tar.gz", hash = "sha256:00dfa48452b6b6cfae3dd9885636c23d3422d1ec97c66d96818cbd5e0821d482", size = 170596, upload-time = "2026-06-17T07:36:52.105Z" }
488
+ wheels = [
489
+ { url = "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl", hash = "sha256:39832cc2def2789a6f29df83f172db7416cea70052c0907a57801c5f2fdccb03", size = 78337, upload-time = "2026-06-17T07:36:50.132Z" },
490
+ ]
491
+
329
492
  [[package]]
330
493
  name = "typing-extensions"
331
494
  version = "4.15.0"
fastevolve-0.2.1/PKG-INFO DELETED
@@ -1,47 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: fastevolve
3
- Version: 0.2.1
4
- Summary: Minimal open-source AlphaEvolve: LLM-driven program evolution with MAP-Elites islands, cascade evaluation, and a local Ollama ensemble.
5
- Project-URL: Homepage, https://github.com/tiagomonteiro0715/fastevolve
6
- Project-URL: Repository, https://github.com/tiagomonteiro0715/fastevolve
7
- Project-URL: Issues, https://github.com/tiagomonteiro0715/fastevolve/issues
8
- Author-email: Tiago Monteiro <monteiro.t@northeastern.edu>
9
- License: MIT
10
- Keywords: alphaevolve,evolutionary-search,llm,map-elites,ollama,program-synthesis
11
- Classifier: Development Status :: 3 - Alpha
12
- Classifier: Intended Audience :: Science/Research
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
- Requires-Python: >=3.12
17
- Requires-Dist: ollama>=0.4.0
18
- Requires-Dist: rich>=13.7
19
- Provides-Extra: dev
20
- Requires-Dist: pytest>=8; extra == 'dev'
21
- Requires-Dist: ruff>=0.6; extra == 'dev'
22
- Description-Content-Type: text/markdown
23
-
24
- # fastevolve
25
-
26
- Minimal open-source AlphaEvolve: LLM-driven program evolution with MAP-Elites islands, cascade evaluation, and a local Ollama ensemble.
27
-
28
- ## Install
29
-
30
- ```bash
31
- uv sync
32
- ```
33
-
34
- ## Run the demo
35
-
36
- Start Ollama and pull the model first:
37
-
38
- ```bash
39
- ollama serve
40
- ollama pull gemma3:e4b
41
- ```
42
-
43
- Then:
44
-
45
- ```bash
46
- uv run python main.py
47
- ```
@@ -1,24 +0,0 @@
1
- # fastevolve
2
-
3
- Minimal open-source AlphaEvolve: LLM-driven program evolution with MAP-Elites islands, cascade evaluation, and a local Ollama ensemble.
4
-
5
- ## Install
6
-
7
- ```bash
8
- uv sync
9
- ```
10
-
11
- ## Run the demo
12
-
13
- Start Ollama and pull the model first:
14
-
15
- ```bash
16
- ollama serve
17
- ollama pull gemma3:e4b
18
- ```
19
-
20
- Then:
21
-
22
- ```bash
23
- uv run python main.py
24
- ```
File without changes
File without changes
File without changes