alpiecode 10.5.6__tar.gz → 10.5.8__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.6 → alpiecode-10.5.8}/PKG-INFO +7 -6
- {alpiecode-10.5.6 → alpiecode-10.5.8}/pyproject.toml +9 -4
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/alpiecode.egg-info/PKG-INFO +7 -6
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/alpiecode.egg-info/requires.txt +4 -1
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/__init__.py +1 -1
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/backends/openai_backend.py +135 -11
- {alpiecode-10.5.6 → alpiecode-10.5.8}/README.md +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/setup.cfg +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/alpiecode/__init__.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/alpiecode.egg-info/SOURCES.txt +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/alpiecode.egg-info/dependency_links.txt +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/alpiecode.egg-info/entry_points.txt +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/alpiecode.egg-info/top_level.txt +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/agent.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/assessment.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/backends/__init__.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/backends/base.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/backends/local_backend.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/cache.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/cli.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/client.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/compaction.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/config.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/context.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/discovery.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/doctor.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/dream_rsi.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/executor.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/extension/alpiecode.vsix +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/git_ops.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/github.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/guardian.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/guardrails.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/ipython_ext.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/local_model.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/media.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/memory.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/metrics.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/orchestrator.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/progress.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/prompt.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/rephraser.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/server.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/session.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/system1.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/tools.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/updater.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/verifier.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/src/codeagent/vscode_installer.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/test/test_adaptive_resilience.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/test/test_cli_ui.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/test/test_context_and_trajectory.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/test/test_dream_rsi.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/test/test_task_assessment.py +0 -0
- {alpiecode-10.5.6 → alpiecode-10.5.8}/test/test_verifier.py +0 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alpiecode
|
|
3
|
-
Version: 10.5.
|
|
3
|
+
Version: 10.5.8
|
|
4
4
|
Summary: AlpieCode
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Requires-Dist: huggingface_hub>=0.20.0
|
|
7
7
|
Requires-Dist: rich>=13.0
|
|
8
8
|
Requires-Dist: click>=8.0
|
|
9
|
-
Requires-Dist: openai>=1.0.0
|
|
10
9
|
Requires-Dist: httpx[http2]>=0.24.0
|
|
11
10
|
Requires-Dist: beautifulsoup4>=4.12.0
|
|
12
11
|
Requires-Dist: yt-dlp>=2024.0.0
|
|
13
|
-
|
|
14
|
-
Requires-Dist: fastapi>=0.100.0
|
|
15
|
-
Requires-Dist: uvicorn>=0.20.0
|
|
16
|
-
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,23 +4,29 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "alpiecode"
|
|
7
|
-
version = "10.5.
|
|
7
|
+
version = "10.5.8"
|
|
8
8
|
description = "AlpieCode"
|
|
9
9
|
requires-python = ">=3.9"
|
|
10
10
|
dependencies = [
|
|
11
11
|
"huggingface_hub>=0.20.0",
|
|
12
12
|
"rich>=13.0",
|
|
13
13
|
"click>=8.0",
|
|
14
|
-
"openai>=1.0.0",
|
|
15
14
|
"httpx[http2]>=0.24.0",
|
|
16
15
|
"beautifulsoup4>=4.12.0",
|
|
17
16
|
"yt-dlp>=2024.0.0",
|
|
18
|
-
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
server = [
|
|
19
21
|
"fastapi>=0.100.0",
|
|
20
22
|
"uvicorn>=0.20.0",
|
|
21
23
|
"sse-starlette>=2.0.0",
|
|
22
24
|
]
|
|
23
25
|
|
|
26
|
+
ffmpeg = [
|
|
27
|
+
"imageio-ffmpeg>=0.4.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
24
30
|
[project.scripts]
|
|
25
31
|
alpiecode = "codeagent.cli:main"
|
|
26
32
|
codeagent = "codeagent.cli:main"
|
|
@@ -30,4 +36,3 @@ where = ["src"]
|
|
|
30
36
|
|
|
31
37
|
[tool.setuptools.package-data]
|
|
32
38
|
codeagent = ["extension/*.vsix"]
|
|
33
|
-
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alpiecode
|
|
3
|
-
Version: 10.5.
|
|
3
|
+
Version: 10.5.8
|
|
4
4
|
Summary: AlpieCode
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Requires-Dist: huggingface_hub>=0.20.0
|
|
7
7
|
Requires-Dist: rich>=13.0
|
|
8
8
|
Requires-Dist: click>=8.0
|
|
9
|
-
Requires-Dist: openai>=1.0.0
|
|
10
9
|
Requires-Dist: httpx[http2]>=0.24.0
|
|
11
10
|
Requires-Dist: beautifulsoup4>=4.12.0
|
|
12
11
|
Requires-Dist: yt-dlp>=2024.0.0
|
|
13
|
-
|
|
14
|
-
Requires-Dist: fastapi>=0.100.0
|
|
15
|
-
Requires-Dist: uvicorn>=0.20.0
|
|
16
|
-
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.8"
|
|
21
21
|
|
|
22
22
|
def run(task: str, workdir: str = ".", reasoning_level: str = "thinking", **kwargs):
|
|
23
23
|
"""Run an autonomous coding task programmatically."""
|
|
@@ -7,11 +7,138 @@ import json
|
|
|
7
7
|
import logging
|
|
8
8
|
import re
|
|
9
9
|
from typing import Any, List, Optional
|
|
10
|
-
from
|
|
10
|
+
from types import SimpleNamespace
|
|
11
|
+
from typing import Any, Dict, Generator, List, Optional
|
|
12
|
+
import httpx
|
|
11
13
|
|
|
12
14
|
logger = logging.getLogger(__name__)
|
|
13
15
|
|
|
14
16
|
|
|
17
|
+
class NotFoundError(Exception):
|
|
18
|
+
"""Raised when remote endpoint returns 404 Not Found."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class APIError(Exception):
|
|
23
|
+
"""Raised when remote endpoint returns non-200 HTTP status."""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _Namespace(SimpleNamespace):
|
|
28
|
+
"""SimpleNamespace subclass that safely returns None for missing attributes instead of raising AttributeError."""
|
|
29
|
+
def __getattr__(self, name: str) -> Any:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _dict_to_obj(d: Any) -> Any:
|
|
34
|
+
"""Recursively wraps a dict into a _Namespace so attribute access works seamlessly."""
|
|
35
|
+
if isinstance(d, dict):
|
|
36
|
+
return _Namespace(**{k: _dict_to_obj(v) for k, v in d.items()})
|
|
37
|
+
if isinstance(d, list):
|
|
38
|
+
return [_dict_to_obj(item) for item in d]
|
|
39
|
+
return d
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class _HTTPXChatCompletions:
|
|
43
|
+
def __init__(self, client: "_HTTPXClient"):
|
|
44
|
+
self._client = client
|
|
45
|
+
|
|
46
|
+
def create(self, **kwargs: Any) -> Any:
|
|
47
|
+
stream = kwargs.get("stream", False)
|
|
48
|
+
timeout = kwargs.get("timeout", 90.0)
|
|
49
|
+
|
|
50
|
+
payload: Dict[str, Any] = {
|
|
51
|
+
"model": kwargs.get("model"),
|
|
52
|
+
"messages": kwargs.get("messages", []),
|
|
53
|
+
"temperature": kwargs.get("temperature", 0.1),
|
|
54
|
+
"max_tokens": kwargs.get("max_tokens", 8192),
|
|
55
|
+
"stream": stream,
|
|
56
|
+
}
|
|
57
|
+
if "tools" in kwargs and kwargs["tools"]:
|
|
58
|
+
payload["tools"] = kwargs["tools"]
|
|
59
|
+
payload["tool_choice"] = kwargs.get("tool_choice", "auto")
|
|
60
|
+
if "extra_body" in kwargs and isinstance(kwargs["extra_body"], dict):
|
|
61
|
+
payload.update(kwargs["extra_body"])
|
|
62
|
+
|
|
63
|
+
headers = {
|
|
64
|
+
"Content-Type": "application/json",
|
|
65
|
+
"Authorization": f"Bearer {self._client.api_key}",
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
base = self._client.base_url.rstrip("/")
|
|
69
|
+
url = f"{base}/chat/completions"
|
|
70
|
+
|
|
71
|
+
if stream:
|
|
72
|
+
return self._stream_request(url, headers, payload, timeout)
|
|
73
|
+
return self._sync_request(url, headers, payload, timeout)
|
|
74
|
+
|
|
75
|
+
def _stream_request(self, url: str, headers: dict, payload: dict, timeout: float) -> Generator[Any, None, None]:
|
|
76
|
+
http_client = self._client.http_client
|
|
77
|
+
req = http_client.build_request("POST", url, headers=headers, json=payload, timeout=timeout)
|
|
78
|
+
resp = http_client.send(req, stream=True)
|
|
79
|
+
if resp.status_code == 404:
|
|
80
|
+
resp.close()
|
|
81
|
+
raise NotFoundError("Model or endpoint not found")
|
|
82
|
+
if resp.status_code != 200:
|
|
83
|
+
err_text = resp.read().decode("utf-8", errors="replace")
|
|
84
|
+
resp.close()
|
|
85
|
+
raise APIError(f"HTTP {resp.status_code}: {err_text}")
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
for line in resp.iter_lines():
|
|
89
|
+
line = line.strip()
|
|
90
|
+
if not line or not line.startswith("data: "):
|
|
91
|
+
continue
|
|
92
|
+
data_str = line[6:].strip()
|
|
93
|
+
if data_str == "[DONE]":
|
|
94
|
+
break
|
|
95
|
+
try:
|
|
96
|
+
chunk_dict = json.loads(data_str)
|
|
97
|
+
except Exception:
|
|
98
|
+
continue
|
|
99
|
+
yield _dict_to_obj(chunk_dict)
|
|
100
|
+
finally:
|
|
101
|
+
resp.close()
|
|
102
|
+
|
|
103
|
+
def _sync_request(self, url: str, headers: dict, payload: dict, timeout: float) -> Any:
|
|
104
|
+
resp = self._client.http_client.post(url, headers=headers, json=payload, timeout=timeout)
|
|
105
|
+
if resp.status_code == 404:
|
|
106
|
+
raise NotFoundError("Model or endpoint not found")
|
|
107
|
+
if resp.status_code != 200:
|
|
108
|
+
raise APIError(f"HTTP {resp.status_code}: {resp.text}")
|
|
109
|
+
data = json.loads(resp.text)
|
|
110
|
+
return _dict_to_obj(data)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class _HTTPXModels:
|
|
114
|
+
def __init__(self, client: "_HTTPXClient"):
|
|
115
|
+
self._client = client
|
|
116
|
+
|
|
117
|
+
def list(self) -> Any:
|
|
118
|
+
base = self._client.base_url.rstrip("/")
|
|
119
|
+
url = f"{base}/models"
|
|
120
|
+
headers = {
|
|
121
|
+
"Authorization": f"Bearer {self._client.api_key}",
|
|
122
|
+
}
|
|
123
|
+
try:
|
|
124
|
+
resp = self._client.http_client.get(url, headers=headers, timeout=3.0)
|
|
125
|
+
if resp.status_code != 200:
|
|
126
|
+
return _Namespace(data=[])
|
|
127
|
+
data = json.loads(resp.text)
|
|
128
|
+
return _dict_to_obj(data)
|
|
129
|
+
except Exception:
|
|
130
|
+
return _Namespace(data=[])
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class _HTTPXClient:
|
|
134
|
+
def __init__(self, base_url: str, api_key: str, http_client: Any = None):
|
|
135
|
+
self.base_url = base_url
|
|
136
|
+
self.api_key = api_key or "not-needed"
|
|
137
|
+
self.http_client = http_client if http_client is not None else get_shared_http_client()
|
|
138
|
+
self.chat = _Namespace(completions=_HTTPXChatCompletions(self))
|
|
139
|
+
self.models = _HTTPXModels(self)
|
|
140
|
+
|
|
141
|
+
|
|
15
142
|
def _repair_and_parse_json_arguments(raw_args: str) -> dict:
|
|
16
143
|
"""
|
|
17
144
|
Robustly parse tool call arguments from potentially partial or malformed streaming strings.
|
|
@@ -125,7 +252,7 @@ class OpenAIBackend:
|
|
|
125
252
|
|
|
126
253
|
def __init__(self, cfg: Config):
|
|
127
254
|
self._cfg = cfg
|
|
128
|
-
self._client: Optional[
|
|
255
|
+
self._client: Optional[Any] = None
|
|
129
256
|
self._resolved_model: Optional[str] = None
|
|
130
257
|
self._max_model_len: Optional[int] = None
|
|
131
258
|
|
|
@@ -143,16 +270,16 @@ class OpenAIBackend:
|
|
|
143
270
|
return self._max_model_len
|
|
144
271
|
return 262_144
|
|
145
272
|
|
|
146
|
-
def _ensure_client(self) ->
|
|
273
|
+
def _ensure_client(self) -> Any:
|
|
147
274
|
if self._client is None:
|
|
148
|
-
self._client =
|
|
275
|
+
self._client = _HTTPXClient(
|
|
149
276
|
base_url=self._cfg.base_url,
|
|
150
277
|
api_key=self._cfg.api_key or "not-needed",
|
|
151
278
|
http_client=get_shared_http_client(),
|
|
152
279
|
)
|
|
153
280
|
return self._client
|
|
154
281
|
|
|
155
|
-
def _get_available_model(self, client:
|
|
282
|
+
def _get_available_model(self, client: Any) -> str:
|
|
156
283
|
"""Auto-discover the served model name from /v1/models.
|
|
157
284
|
|
|
158
285
|
Uses a dedicated short-timeout (3s) probe to avoid blocking the agent
|
|
@@ -163,18 +290,15 @@ class OpenAIBackend:
|
|
|
163
290
|
return self._resolved_model
|
|
164
291
|
try:
|
|
165
292
|
import httpx
|
|
166
|
-
|
|
167
|
-
# The shared HTTP client has a 120s read timeout which causes
|
|
168
|
-
# multi-minute hangs when /v1/models is slow or unresponsive.
|
|
169
|
-
probe_client = OpenAI(
|
|
293
|
+
probe_client = _HTTPXClient(
|
|
170
294
|
base_url=self._cfg.base_url,
|
|
171
295
|
api_key=self._cfg.api_key or "not-needed",
|
|
172
296
|
http_client=httpx.Client(timeout=httpx.Timeout(3.0, connect=2.0)),
|
|
173
297
|
)
|
|
174
298
|
models_list = probe_client.models.list()
|
|
175
|
-
if models_list.data:
|
|
299
|
+
if hasattr(models_list, "data") and models_list.data:
|
|
176
300
|
for m in models_list.data:
|
|
177
|
-
if m
|
|
301
|
+
if getattr(m, "id", None) == self._cfg.model or getattr(m, "root", None) == self._cfg.model:
|
|
178
302
|
self._resolved_model = m.id
|
|
179
303
|
self._max_model_len = getattr(m, "max_model_len", None)
|
|
180
304
|
logger.info("Resolved model: %s (max_len=%s)", self._resolved_model, self._max_model_len)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|