alpiecode 10.5.7__tar.gz → 10.5.9__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.
- {alpiecode-10.5.7 → alpiecode-10.5.9}/PKG-INFO +7 -5
- {alpiecode-10.5.7 → alpiecode-10.5.9}/pyproject.toml +9 -3
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/alpiecode.egg-info/PKG-INFO +7 -5
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/alpiecode.egg-info/SOURCES.txt +1 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/alpiecode.egg-info/requires.txt +4 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/__init__.py +1 -1
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/cache.py +13 -10
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/config.py +30 -6
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/dream_rsi.py +27 -8
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/local_model.py +14 -7
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/memory.py +10 -3
- alpiecode-10.5.9/src/codeagent/paths.py +40 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/updater.py +13 -5
- {alpiecode-10.5.7 → alpiecode-10.5.9}/test/test_dream_rsi.py +32 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/README.md +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/setup.cfg +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/alpiecode/__init__.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/alpiecode.egg-info/dependency_links.txt +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/alpiecode.egg-info/entry_points.txt +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/alpiecode.egg-info/top_level.txt +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/agent.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/assessment.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/backends/__init__.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/backends/base.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/backends/local_backend.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/backends/openai_backend.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/cli.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/client.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/compaction.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/context.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/discovery.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/doctor.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/executor.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/extension/alpiecode.vsix +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/git_ops.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/github.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/guardian.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/guardrails.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/ipython_ext.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/media.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/metrics.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/orchestrator.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/progress.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/prompt.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/rephraser.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/server.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/session.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/system1.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/tools.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/verifier.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/src/codeagent/vscode_installer.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/test/test_adaptive_resilience.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/test/test_cli_ui.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/test/test_context_and_trajectory.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/test/test_task_assessment.py +0 -0
- {alpiecode-10.5.7 → alpiecode-10.5.9}/test/test_verifier.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alpiecode
|
|
3
|
-
Version: 10.5.
|
|
3
|
+
Version: 10.5.9
|
|
4
4
|
Summary: AlpieCode
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Requires-Dist: huggingface_hub>=0.20.0
|
|
@@ -9,7 +9,9 @@ Requires-Dist: click>=8.0
|
|
|
9
9
|
Requires-Dist: httpx[http2]>=0.24.0
|
|
10
10
|
Requires-Dist: beautifulsoup4>=4.12.0
|
|
11
11
|
Requires-Dist: yt-dlp>=2024.0.0
|
|
12
|
-
|
|
13
|
-
Requires-Dist: fastapi>=0.100.0
|
|
14
|
-
Requires-Dist: uvicorn>=0.20.0
|
|
15
|
-
Requires-Dist: sse-starlette>=2.0.0
|
|
12
|
+
Provides-Extra: server
|
|
13
|
+
Requires-Dist: fastapi>=0.100.0; extra == "server"
|
|
14
|
+
Requires-Dist: uvicorn>=0.20.0; extra == "server"
|
|
15
|
+
Requires-Dist: sse-starlette>=2.0.0; extra == "server"
|
|
16
|
+
Provides-Extra: ffmpeg
|
|
17
|
+
Requires-Dist: imageio-ffmpeg>=0.4.0; extra == "ffmpeg"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "alpiecode"
|
|
7
|
-
version = "10.5.
|
|
7
|
+
version = "10.5.9"
|
|
8
8
|
description = "AlpieCode"
|
|
9
9
|
requires-python = ">=3.9"
|
|
10
10
|
dependencies = [
|
|
@@ -14,12 +14,19 @@ dependencies = [
|
|
|
14
14
|
"httpx[http2]>=0.24.0",
|
|
15
15
|
"beautifulsoup4>=4.12.0",
|
|
16
16
|
"yt-dlp>=2024.0.0",
|
|
17
|
-
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
server = [
|
|
18
21
|
"fastapi>=0.100.0",
|
|
19
22
|
"uvicorn>=0.20.0",
|
|
20
23
|
"sse-starlette>=2.0.0",
|
|
21
24
|
]
|
|
22
25
|
|
|
26
|
+
ffmpeg = [
|
|
27
|
+
"imageio-ffmpeg>=0.4.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
23
30
|
[project.scripts]
|
|
24
31
|
alpiecode = "codeagent.cli:main"
|
|
25
32
|
codeagent = "codeagent.cli:main"
|
|
@@ -29,4 +36,3 @@ where = ["src"]
|
|
|
29
36
|
|
|
30
37
|
[tool.setuptools.package-data]
|
|
31
38
|
codeagent = ["extension/*.vsix"]
|
|
32
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alpiecode
|
|
3
|
-
Version: 10.5.
|
|
3
|
+
Version: 10.5.9
|
|
4
4
|
Summary: AlpieCode
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Requires-Dist: huggingface_hub>=0.20.0
|
|
@@ -9,7 +9,9 @@ Requires-Dist: click>=8.0
|
|
|
9
9
|
Requires-Dist: httpx[http2]>=0.24.0
|
|
10
10
|
Requires-Dist: beautifulsoup4>=4.12.0
|
|
11
11
|
Requires-Dist: yt-dlp>=2024.0.0
|
|
12
|
-
|
|
13
|
-
Requires-Dist: fastapi>=0.100.0
|
|
14
|
-
Requires-Dist: uvicorn>=0.20.0
|
|
15
|
-
Requires-Dist: sse-starlette>=2.0.0
|
|
12
|
+
Provides-Extra: server
|
|
13
|
+
Requires-Dist: fastapi>=0.100.0; extra == "server"
|
|
14
|
+
Requires-Dist: uvicorn>=0.20.0; extra == "server"
|
|
15
|
+
Requires-Dist: sse-starlette>=2.0.0; extra == "server"
|
|
16
|
+
Provides-Extra: ffmpeg
|
|
17
|
+
Requires-Dist: imageio-ffmpeg>=0.4.0; extra == "ffmpeg"
|
|
@@ -17,7 +17,7 @@ Supports:
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from typing import Optional, Any, Dict
|
|
19
19
|
|
|
20
|
-
__version__ = "10.5.
|
|
20
|
+
__version__ = "10.5.9"
|
|
21
21
|
|
|
22
22
|
def run(task: str, workdir: str = ".", reasoning_level: str = "thinking", **kwargs):
|
|
23
23
|
"""Run an autonomous coding task programmatically."""
|
|
@@ -17,7 +17,14 @@ import time
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from typing import Any, Dict, Optional
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
from .paths import ensure_dir, get_alpiecode_dir
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_cache_dir() -> Path:
|
|
24
|
+
return get_alpiecode_dir() / "cache"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
CACHE_DIR = get_alpiecode_dir() / "cache"
|
|
21
28
|
MAX_ENTRIES = 500
|
|
22
29
|
TTL_SECONDS = 7 * 24 * 3600 # 7 days
|
|
23
30
|
|
|
@@ -27,22 +34,17 @@ class ResponseCache:
|
|
|
27
34
|
|
|
28
35
|
def __init__(
|
|
29
36
|
self,
|
|
30
|
-
cache_dir: Path =
|
|
37
|
+
cache_dir: Optional[Path] = None,
|
|
31
38
|
max_entries: int = MAX_ENTRIES,
|
|
32
39
|
ttl: int = TTL_SECONDS,
|
|
33
40
|
):
|
|
34
|
-
self.cache_dir = cache_dir
|
|
41
|
+
self.cache_dir = ensure_dir(cache_dir or get_cache_dir())
|
|
35
42
|
self.max_entries = max_entries
|
|
36
43
|
self.ttl = ttl
|
|
37
44
|
self._mem: Dict[str, Dict[str, Any]] = {}
|
|
38
45
|
self._hits = 0
|
|
39
46
|
self._misses = 0
|
|
40
47
|
|
|
41
|
-
try:
|
|
42
|
-
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
43
|
-
except OSError:
|
|
44
|
-
pass
|
|
45
|
-
|
|
46
48
|
self._warm_up()
|
|
47
49
|
|
|
48
50
|
# ── Public API ──────────────────────────────────────────────────────
|
|
@@ -253,7 +255,8 @@ class TestResultCache:
|
|
|
253
255
|
|
|
254
256
|
def __init__(self, max_entries: int = 100):
|
|
255
257
|
self.max_entries = max_entries
|
|
256
|
-
self.
|
|
258
|
+
self.cache_dir = ensure_dir(get_cache_dir())
|
|
259
|
+
self.disk_file = self.cache_dir / "test_cache.json"
|
|
257
260
|
self._cache: Dict[str, Dict[str, Any]] = {}
|
|
258
261
|
self.hits = 0
|
|
259
262
|
self.misses = 0
|
|
@@ -268,7 +271,7 @@ class TestResultCache:
|
|
|
268
271
|
|
|
269
272
|
def _save_disk(self):
|
|
270
273
|
try:
|
|
271
|
-
|
|
274
|
+
ensure_dir(self.disk_file.parent)
|
|
272
275
|
self.disk_file.write_text(json.dumps(self._cache, indent=2), encoding="utf-8")
|
|
273
276
|
except Exception:
|
|
274
277
|
pass
|
|
@@ -14,8 +14,30 @@ from dataclasses import dataclass, asdict, fields
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Optional
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
from .paths import ensure_dir, get_alpiecode_dir
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_config_dir() -> Path:
|
|
21
|
+
return get_alpiecode_dir()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_config_path() -> Path:
|
|
25
|
+
# 1. Check local/custom ALPIECODE_HOME directory first
|
|
26
|
+
local_cfg = get_alpiecode_dir() / "config.json"
|
|
27
|
+
if local_cfg.exists():
|
|
28
|
+
return local_cfg
|
|
29
|
+
# 2. Check legacy ~/.alpiecode/config.json if it exists
|
|
30
|
+
try:
|
|
31
|
+
home_cfg = Path.home() / ".alpiecode" / "config.json"
|
|
32
|
+
if home_cfg.exists():
|
|
33
|
+
return home_cfg
|
|
34
|
+
except Exception:
|
|
35
|
+
pass
|
|
36
|
+
return local_cfg
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
CONFIG_DIR = get_alpiecode_dir()
|
|
40
|
+
CONFIG_PATH = get_config_path()
|
|
19
41
|
|
|
20
42
|
# Config version — bump this when defaults change to trigger auto-migration
|
|
21
43
|
CONFIG_VERSION = 8 # v7: autonomous discovery engine (zero-flag flow)
|
|
@@ -116,9 +138,10 @@ class Config:
|
|
|
116
138
|
def load_config() -> Config:
|
|
117
139
|
data = dict(DEFAULTS)
|
|
118
140
|
needs_save = False
|
|
119
|
-
|
|
141
|
+
cfg_file = get_config_path()
|
|
142
|
+
if cfg_file.exists():
|
|
120
143
|
try:
|
|
121
|
-
saved_data = json.loads(
|
|
144
|
+
saved_data = json.loads(cfg_file.read_text())
|
|
122
145
|
# Skip null values so they don't override smart defaults (e.g. base_url)
|
|
123
146
|
data.update({k: v for k, v in saved_data.items() if v is not None})
|
|
124
147
|
|
|
@@ -198,8 +221,9 @@ def load_config() -> Config:
|
|
|
198
221
|
|
|
199
222
|
|
|
200
223
|
def save_config(cfg: Config) -> None:
|
|
201
|
-
|
|
202
|
-
|
|
224
|
+
target_dir = ensure_dir(get_config_dir())
|
|
225
|
+
target_path = target_dir / "config.json"
|
|
226
|
+
target_path.write_text(json.dumps(asdict(cfg), indent=2))
|
|
203
227
|
|
|
204
228
|
|
|
205
229
|
def interactive_init() -> Config:
|
|
@@ -18,10 +18,28 @@ from dataclasses import asdict, dataclass, field
|
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
from typing import Any, Dict, List, Optional, Tuple
|
|
20
20
|
|
|
21
|
+
from .paths import ensure_dir, get_alpiecode_dir
|
|
22
|
+
|
|
21
23
|
logger = logging.getLogger(__name__)
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
|
|
26
|
+
_INITIAL_TRAJECTORY_DIR = get_alpiecode_dir() / "trajectories"
|
|
27
|
+
_INITIAL_POLICY_PATH = get_alpiecode_dir() / "dream_policy.json"
|
|
28
|
+
|
|
29
|
+
TRAJECTORY_DIR = _INITIAL_TRAJECTORY_DIR
|
|
30
|
+
POLICY_PATH = _INITIAL_POLICY_PATH
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_trajectory_dir() -> Path:
|
|
34
|
+
if TRAJECTORY_DIR != _INITIAL_TRAJECTORY_DIR:
|
|
35
|
+
return TRAJECTORY_DIR
|
|
36
|
+
return get_alpiecode_dir() / "trajectories"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_policy_path() -> Path:
|
|
40
|
+
if POLICY_PATH != _INITIAL_POLICY_PATH:
|
|
41
|
+
return POLICY_PATH
|
|
42
|
+
return get_alpiecode_dir() / "dream_policy.json"
|
|
25
43
|
|
|
26
44
|
|
|
27
45
|
# ?? 1. Trajectory Data Models ??????????????????????????????????????????
|
|
@@ -70,12 +88,13 @@ class TrajectoryStore:
|
|
|
70
88
|
"""Local persistent repository of discovery trajectories."""
|
|
71
89
|
|
|
72
90
|
def __init__(self, storage_dir: Optional[Path] = None):
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
if storage_dir is None:
|
|
92
|
+
storage_dir = get_trajectory_dir()
|
|
93
|
+
self.storage_dir = ensure_dir(Path(storage_dir))
|
|
75
94
|
|
|
76
95
|
def save_trajectory(self, record: TrajectoryRecord) -> Path:
|
|
77
96
|
"""Save a completed trajectory atomically to disk."""
|
|
78
|
-
self.storage_dir
|
|
97
|
+
ensure_dir(self.storage_dir)
|
|
79
98
|
file_path = self.storage_dir / f"{record.session_id}.json"
|
|
80
99
|
temp_path = self.storage_dir / f"{record.session_id}.json.tmp"
|
|
81
100
|
|
|
@@ -164,7 +183,7 @@ class DreamStrategyProfile:
|
|
|
164
183
|
|
|
165
184
|
def load_active_dream_profile(path: Optional[Path] = None) -> DreamStrategyProfile:
|
|
166
185
|
"""Load the current active dream policy profile."""
|
|
167
|
-
target = path or
|
|
186
|
+
target = path or get_policy_path()
|
|
168
187
|
if not target.exists():
|
|
169
188
|
return DreamStrategyProfile()
|
|
170
189
|
try:
|
|
@@ -177,8 +196,8 @@ def load_active_dream_profile(path: Optional[Path] = None) -> DreamStrategyProfi
|
|
|
177
196
|
|
|
178
197
|
def save_active_dream_profile(profile: DreamStrategyProfile, path: Optional[Path] = None) -> None:
|
|
179
198
|
"""Save a synthesized dream policy profile."""
|
|
180
|
-
target = path or
|
|
181
|
-
target.parent
|
|
199
|
+
target = path or get_policy_path()
|
|
200
|
+
ensure_dir(target.parent)
|
|
182
201
|
tmp = target.with_suffix(".tmp")
|
|
183
202
|
try:
|
|
184
203
|
with open(tmp, "w", encoding="utf-8") as f:
|
|
@@ -12,7 +12,14 @@ import sys
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Any, Dict, List, Optional
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
from .paths import ensure_dir, get_alpiecode_dir
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_model_cache_dir() -> Path:
|
|
19
|
+
return get_alpiecode_dir() / "models"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
CACHE_DIR = get_alpiecode_dir() / "models"
|
|
16
23
|
DEFAULT_REPO = "169Pi/Alpie_learn_prototype_GGUF_NEW"
|
|
17
24
|
DEFAULT_CTX_SIZE = 32768 # 32k tokens default for fast loading (supports up to 256k)
|
|
18
25
|
|
|
@@ -117,11 +124,11 @@ def download_model(repo_id: str = DEFAULT_REPO, token: Optional[str] = None) ->
|
|
|
117
124
|
|
|
118
125
|
OFFLINE-FIRST: Checks local cache before any network call.
|
|
119
126
|
"""
|
|
120
|
-
|
|
127
|
+
cache_dir = ensure_dir(get_model_cache_dir())
|
|
121
128
|
hf_token = token or os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN")
|
|
122
129
|
|
|
123
130
|
# ── STEP 1: Check local cache FIRST (zero network) ───────────────
|
|
124
|
-
local_gguf = list(
|
|
131
|
+
local_gguf = list(cache_dir.glob("*.gguf"))
|
|
125
132
|
# Filter out mmproj files for main model
|
|
126
133
|
local_main = [f for f in local_gguf if "mmproj" not in f.name.lower()]
|
|
127
134
|
if local_main:
|
|
@@ -185,7 +192,7 @@ def download_model(repo_id: str = DEFAULT_REPO, token: Optional[str] = None) ->
|
|
|
185
192
|
main_gguf_files = gguf_files
|
|
186
193
|
|
|
187
194
|
target_file = main_gguf_files[0]
|
|
188
|
-
cached_file =
|
|
195
|
+
cached_file = cache_dir / target_file
|
|
189
196
|
|
|
190
197
|
if not cached_file.exists():
|
|
191
198
|
print(f"📥 Downloading local model from HuggingFace ({repo_id}/{target_file})...")
|
|
@@ -194,7 +201,7 @@ def download_model(repo_id: str = DEFAULT_REPO, token: Optional[str] = None) ->
|
|
|
194
201
|
hf_hub_download(
|
|
195
202
|
repo_id=repo_id,
|
|
196
203
|
filename=target_file,
|
|
197
|
-
local_dir=
|
|
204
|
+
local_dir=cache_dir,
|
|
198
205
|
token=hf_token,
|
|
199
206
|
)
|
|
200
207
|
except Exception as e:
|
|
@@ -210,14 +217,14 @@ def download_model(repo_id: str = DEFAULT_REPO, token: Optional[str] = None) ->
|
|
|
210
217
|
# Download mmproj file if available (for vision features)
|
|
211
218
|
if mmproj_files:
|
|
212
219
|
mmproj_target = mmproj_files[0]
|
|
213
|
-
mmproj_cached =
|
|
220
|
+
mmproj_cached = cache_dir / mmproj_target
|
|
214
221
|
if not mmproj_cached.exists():
|
|
215
222
|
try:
|
|
216
223
|
print(f"📥 Downloading vision projector ({repo_id}/{mmproj_target})...")
|
|
217
224
|
hf_hub_download(
|
|
218
225
|
repo_id=repo_id,
|
|
219
226
|
filename=mmproj_target,
|
|
220
|
-
local_dir=
|
|
227
|
+
local_dir=cache_dir,
|
|
221
228
|
token=hf_token,
|
|
222
229
|
)
|
|
223
230
|
except Exception as e:
|
|
@@ -17,7 +17,14 @@ import time
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from typing import List, Optional
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
from .paths import ensure_dir, get_alpiecode_dir
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_memory_dir() -> Path:
|
|
24
|
+
return get_alpiecode_dir() / "memories"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
MEMORY_DIR = get_alpiecode_dir() / "memories"
|
|
21
28
|
|
|
22
29
|
|
|
23
30
|
def _project_key(workdir: Path) -> str:
|
|
@@ -27,7 +34,7 @@ def _project_key(workdir: Path) -> str:
|
|
|
27
34
|
|
|
28
35
|
def _memory_path(workdir: Path) -> Path:
|
|
29
36
|
"""Get the memory file path for a project."""
|
|
30
|
-
return
|
|
37
|
+
return get_memory_dir() / f"{_project_key(workdir)}.json"
|
|
31
38
|
|
|
32
39
|
|
|
33
40
|
def load_memories(workdir: Path) -> List[dict]:
|
|
@@ -58,7 +65,7 @@ def save_memories_batch(workdir: Path, entries: List[dict]) -> None:
|
|
|
58
65
|
if not entries:
|
|
59
66
|
return
|
|
60
67
|
|
|
61
|
-
|
|
68
|
+
ensure_dir(get_memory_dir())
|
|
62
69
|
path = _memory_path(workdir)
|
|
63
70
|
|
|
64
71
|
existing = load_memories(workdir)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cross-platform path resolution for AlpieCode.
|
|
3
|
+
|
|
4
|
+
Supports iOS, Android, Linux, macOS, and Windows without hardcoded home directories.
|
|
5
|
+
Resolution order:
|
|
6
|
+
1. ALPIECODE_HOME environment variable (override)
|
|
7
|
+
2. Project/working directory: Path.cwd() / ".alpiecode"
|
|
8
|
+
3. Resilient fallback to Path.home() / ".alpiecode" or tempfile
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import tempfile
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_alpiecode_dir() -> Path:
|
|
18
|
+
"""
|
|
19
|
+
Return the base directory for AlpieCode state, caches, and trajectories.
|
|
20
|
+
User can override the location if needed via ALPIECODE_HOME.
|
|
21
|
+
Default: project/current working directory (.alpiecode).
|
|
22
|
+
"""
|
|
23
|
+
custom_dir = os.environ.get("ALPIECODE_HOME")
|
|
24
|
+
if custom_dir:
|
|
25
|
+
return Path(custom_dir).expanduser()
|
|
26
|
+
return Path.cwd() / ".alpiecode"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def ensure_dir(path: Path) -> Path:
|
|
30
|
+
"""Safely create directory with resilient fallback if path is not writable."""
|
|
31
|
+
try:
|
|
32
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
return path
|
|
34
|
+
except (PermissionError, OSError):
|
|
35
|
+
fallback = Path(tempfile.gettempdir()) / ".alpiecode" / path.name
|
|
36
|
+
try:
|
|
37
|
+
fallback.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
return fallback
|
|
39
|
+
except Exception:
|
|
40
|
+
return path
|
|
@@ -17,16 +17,23 @@ import urllib.request
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
19
19
|
import threading
|
|
20
|
+
from .paths import ensure_dir, get_alpiecode_dir
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
def get_updater_cache_file() -> Path:
|
|
24
|
+
return get_alpiecode_dir() / "update_cache.json"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
CACHE_FILE = get_alpiecode_dir() / "update_cache.json"
|
|
22
28
|
CHECK_INTERVAL_SECONDS = 1800 # Check every 30 minutes
|
|
23
29
|
|
|
24
30
|
|
|
25
31
|
def _get_cache() -> dict:
|
|
26
32
|
"""Read update cache data."""
|
|
27
|
-
|
|
33
|
+
cache_file = get_updater_cache_file()
|
|
34
|
+
if cache_file.exists():
|
|
28
35
|
try:
|
|
29
|
-
return json.loads(
|
|
36
|
+
return json.loads(cache_file.read_text())
|
|
30
37
|
except Exception:
|
|
31
38
|
pass
|
|
32
39
|
return {}
|
|
@@ -35,8 +42,9 @@ def _get_cache() -> dict:
|
|
|
35
42
|
def _save_cache(sha: str, updated: bool = False) -> None:
|
|
36
43
|
"""Save last checked commit SHA and timestamp."""
|
|
37
44
|
try:
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
cache_file = get_updater_cache_file()
|
|
46
|
+
ensure_dir(cache_file.parent)
|
|
47
|
+
cache_file.write_text(json.dumps({
|
|
40
48
|
"sha": sha,
|
|
41
49
|
"timestamp": time.time(),
|
|
42
50
|
"updated": updated,
|
|
@@ -31,6 +31,9 @@ from codeagent.dream_rsi import (
|
|
|
31
31
|
DreamOptimizer,
|
|
32
32
|
load_active_dream_profile,
|
|
33
33
|
save_active_dream_profile,
|
|
34
|
+
get_alpiecode_dir,
|
|
35
|
+
get_trajectory_dir,
|
|
36
|
+
get_policy_path,
|
|
34
37
|
)
|
|
35
38
|
|
|
36
39
|
|
|
@@ -254,6 +257,35 @@ class TestTrajectoryStore:
|
|
|
254
257
|
tmp_files = list(store.storage_dir.glob("*.tmp"))
|
|
255
258
|
assert len(tmp_files) == 0
|
|
256
259
|
|
|
260
|
+
def test_default_storage_dir_with_alpiecode_home(self, tmp_path, monkeypatch):
|
|
261
|
+
custom_home = tmp_path / "custom_alpie_home"
|
|
262
|
+
monkeypatch.setenv("ALPIECODE_HOME", str(custom_home))
|
|
263
|
+
assert get_alpiecode_dir() == custom_home
|
|
264
|
+
assert get_trajectory_dir() == custom_home / "trajectories"
|
|
265
|
+
|
|
266
|
+
default_store = TrajectoryStore()
|
|
267
|
+
assert default_store.storage_dir == custom_home / "trajectories"
|
|
268
|
+
assert default_store.storage_dir.exists()
|
|
269
|
+
|
|
270
|
+
def test_default_storage_dir_without_alpiecode_home(self, monkeypatch):
|
|
271
|
+
monkeypatch.delenv("ALPIECODE_HOME", raising=False)
|
|
272
|
+
expected_dir = Path.cwd() / ".alpiecode"
|
|
273
|
+
assert get_alpiecode_dir() == expected_dir
|
|
274
|
+
assert get_trajectory_dir() == expected_dir / "trajectories"
|
|
275
|
+
|
|
276
|
+
def test_default_policy_path_with_alpiecode_home(self, tmp_path, monkeypatch):
|
|
277
|
+
custom_home = tmp_path / "custom_policy_home"
|
|
278
|
+
monkeypatch.setenv("ALPIECODE_HOME", str(custom_home))
|
|
279
|
+
expected_policy_file = custom_home / "dream_policy.json"
|
|
280
|
+
assert get_policy_path() == expected_policy_file
|
|
281
|
+
|
|
282
|
+
profile = DreamStrategyProfile(syntax_loop_threshold=3)
|
|
283
|
+
save_active_dream_profile(profile)
|
|
284
|
+
assert expected_policy_file.exists()
|
|
285
|
+
|
|
286
|
+
loaded = load_active_dream_profile()
|
|
287
|
+
assert loaded.syntax_loop_threshold == 3
|
|
288
|
+
|
|
257
289
|
|
|
258
290
|
# ── 3. DreamStrategyProfile ─────────────────────────────────────────────
|
|
259
291
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|