alpiecode 10.5.6__tar.gz → 10.5.7__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 (55) hide show
  1. {alpiecode-10.5.6 → alpiecode-10.5.7}/PKG-INFO +1 -2
  2. {alpiecode-10.5.6 → alpiecode-10.5.7}/pyproject.toml +1 -2
  3. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/alpiecode.egg-info/PKG-INFO +1 -2
  4. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/alpiecode.egg-info/requires.txt +0 -1
  5. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/__init__.py +1 -1
  6. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/backends/openai_backend.py +135 -11
  7. {alpiecode-10.5.6 → alpiecode-10.5.7}/README.md +0 -0
  8. {alpiecode-10.5.6 → alpiecode-10.5.7}/setup.cfg +0 -0
  9. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/alpiecode/__init__.py +0 -0
  10. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/alpiecode.egg-info/SOURCES.txt +0 -0
  11. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/alpiecode.egg-info/dependency_links.txt +0 -0
  12. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/alpiecode.egg-info/entry_points.txt +0 -0
  13. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/alpiecode.egg-info/top_level.txt +0 -0
  14. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/agent.py +0 -0
  15. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/assessment.py +0 -0
  16. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/backends/__init__.py +0 -0
  17. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/backends/base.py +0 -0
  18. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/backends/local_backend.py +0 -0
  19. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/cache.py +0 -0
  20. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/cli.py +0 -0
  21. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/client.py +0 -0
  22. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/compaction.py +0 -0
  23. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/config.py +0 -0
  24. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/context.py +0 -0
  25. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/discovery.py +0 -0
  26. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/doctor.py +0 -0
  27. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/dream_rsi.py +0 -0
  28. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/executor.py +0 -0
  29. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/extension/alpiecode.vsix +0 -0
  30. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/git_ops.py +0 -0
  31. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/github.py +0 -0
  32. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/guardian.py +0 -0
  33. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/guardrails.py +0 -0
  34. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/ipython_ext.py +0 -0
  35. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/local_model.py +0 -0
  36. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/media.py +0 -0
  37. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/memory.py +0 -0
  38. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/metrics.py +0 -0
  39. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/orchestrator.py +0 -0
  40. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/progress.py +0 -0
  41. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/prompt.py +0 -0
  42. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/rephraser.py +0 -0
  43. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/server.py +0 -0
  44. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/session.py +0 -0
  45. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/system1.py +0 -0
  46. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/tools.py +0 -0
  47. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/updater.py +0 -0
  48. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/verifier.py +0 -0
  49. {alpiecode-10.5.6 → alpiecode-10.5.7}/src/codeagent/vscode_installer.py +0 -0
  50. {alpiecode-10.5.6 → alpiecode-10.5.7}/test/test_adaptive_resilience.py +0 -0
  51. {alpiecode-10.5.6 → alpiecode-10.5.7}/test/test_cli_ui.py +0 -0
  52. {alpiecode-10.5.6 → alpiecode-10.5.7}/test/test_context_and_trajectory.py +0 -0
  53. {alpiecode-10.5.6 → alpiecode-10.5.7}/test/test_dream_rsi.py +0 -0
  54. {alpiecode-10.5.6 → alpiecode-10.5.7}/test/test_task_assessment.py +0 -0
  55. {alpiecode-10.5.6 → alpiecode-10.5.7}/test/test_verifier.py +0 -0
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alpiecode
3
- Version: 10.5.6
3
+ Version: 10.5.7
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
@@ -4,14 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "alpiecode"
7
- version = "10.5.6"
7
+ version = "10.5.7"
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",
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alpiecode
3
- Version: 10.5.6
3
+ Version: 10.5.7
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
@@ -1,7 +1,6 @@
1
1
  huggingface_hub>=0.20.0
2
2
  rich>=13.0
3
3
  click>=8.0
4
- openai>=1.0.0
5
4
  httpx[http2]>=0.24.0
6
5
  beautifulsoup4>=4.12.0
7
6
  yt-dlp>=2024.0.0
@@ -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.6"
20
+ __version__ = "10.5.7"
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 openai import OpenAI, NotFoundError
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[OpenAI] = None
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) -> OpenAI:
273
+ def _ensure_client(self) -> Any:
147
274
  if self._client is None:
148
- self._client = OpenAI(
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: OpenAI) -> str:
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
- # Use a dedicated short-timeout client for model discovery only.
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.id == self._cfg.model or getattr(m, "root", None) == self._cfg.model:
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