alpiecode 0.8.2__tar.gz → 0.9.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.
- {alpiecode-0.8.2 → alpiecode-0.9.0}/PKG-INFO +1 -1
- {alpiecode-0.8.2 → alpiecode-0.9.0}/pyproject.toml +1 -1
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/alpiecode.egg-info/PKG-INFO +1 -1
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/alpiecode.egg-info/SOURCES.txt +1 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/agent.py +36 -14
- alpiecode-0.9.0/src/codeagent/client.py +131 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/README.md +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/setup.cfg +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/alpiecode.egg-info/dependency_links.txt +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/alpiecode.egg-info/entry_points.txt +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/alpiecode.egg-info/requires.txt +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/alpiecode.egg-info/top_level.txt +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/__init__.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/backends/__init__.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/backends/base.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/backends/local_backend.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/backends/openai_backend.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/cli.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/compaction.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/config.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/context.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/executor.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/github.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/guardian.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/local_model.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/media.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/memory.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/orchestrator.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/prompt.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/server.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/session.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/tools.py +0 -0
- {alpiecode-0.8.2 → alpiecode-0.9.0}/src/codeagent/updater.py +0 -0
|
@@ -149,28 +149,50 @@ def run_agent(
|
|
|
149
149
|
video_path: str = None,
|
|
150
150
|
url: str = None,
|
|
151
151
|
github_repo: str = None,
|
|
152
|
+
server_url: str = None,
|
|
152
153
|
) -> list:
|
|
153
154
|
"""Run non-interactive agent task with Rich presentation."""
|
|
154
155
|
workdir = workdir.resolve()
|
|
155
156
|
_ensure_git(workdir)
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
# CLI-as-Client check: auto-detect if local/remote server is running
|
|
159
|
+
from .client import AlpieCodeClient
|
|
160
|
+
target_server = server_url or getattr(cfg, "server_url", None)
|
|
161
|
+
if not target_server:
|
|
162
|
+
# Check default local server
|
|
163
|
+
local_client = AlpieCodeClient("http://127.0.0.1:7169")
|
|
164
|
+
if local_client.health().get("status") == "online":
|
|
165
|
+
target_server = "http://127.0.0.1:7169"
|
|
166
|
+
|
|
167
|
+
if target_server:
|
|
168
|
+
client = AlpieCodeClient(target_server)
|
|
169
|
+
event_stream = client.stream_chat(
|
|
170
|
+
task=task,
|
|
171
|
+
workdir=str(workdir),
|
|
172
|
+
image_path=image_path,
|
|
173
|
+
video_path=video_path,
|
|
174
|
+
url=url,
|
|
175
|
+
github_repo=github_repo,
|
|
176
|
+
)
|
|
177
|
+
else:
|
|
178
|
+
backend = resolve_backend(cfg)
|
|
179
|
+
orchestrator = AgentOrchestrator(backend)
|
|
180
|
+
session_mgr = SessionManager()
|
|
181
|
+
session = session_mgr.create_session(workdir, max_tokens=cfg.n_ctx if not backend.is_available else 262_144)
|
|
182
|
+
event_stream = orchestrator.run_task(
|
|
183
|
+
session=session,
|
|
184
|
+
task=task,
|
|
185
|
+
cfg=cfg,
|
|
186
|
+
image_path=image_path,
|
|
187
|
+
video_path=video_path,
|
|
188
|
+
url=url,
|
|
189
|
+
github_repo=github_repo,
|
|
190
|
+
)
|
|
161
191
|
|
|
162
192
|
_checkpoint(workdir, "checkpoint: start")
|
|
163
193
|
|
|
164
194
|
current_turn = 0
|
|
165
|
-
for event in
|
|
166
|
-
session=session,
|
|
167
|
-
task=task,
|
|
168
|
-
cfg=cfg,
|
|
169
|
-
image_path=image_path,
|
|
170
|
-
video_path=video_path,
|
|
171
|
-
url=url,
|
|
172
|
-
github_repo=github_repo,
|
|
173
|
-
):
|
|
195
|
+
for event in event_stream:
|
|
174
196
|
if event.type == "start" and verbose:
|
|
175
197
|
data = event.data
|
|
176
198
|
if HAS_RICH:
|
|
@@ -254,7 +276,7 @@ def run_agent(
|
|
|
254
276
|
elif event.type == "max_turns_reached" and verbose:
|
|
255
277
|
console.print(f"\n⚠️ Max turns ({event.data['max_turns']}) reached without completion.", style="bold yellow")
|
|
256
278
|
|
|
257
|
-
return session.context.messages
|
|
279
|
+
return session.context.messages if "session" in locals() else []
|
|
258
280
|
|
|
259
281
|
|
|
260
282
|
def run_chat(workdir: Path, cfg: Config, verbose: bool = True) -> None:
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Client SDK for AlpieCode API server.
|
|
3
|
+
|
|
4
|
+
Provides a clean, typed interface for connecting to an AlpieCode server (`alpiecode serve`),
|
|
5
|
+
streaming SSE events, managing sessions, and canceling tasks.
|
|
6
|
+
Used by the CLI client mode and future IDE/remote Python integrations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import urllib.parse
|
|
11
|
+
import urllib.request
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, Iterator, Optional
|
|
15
|
+
|
|
16
|
+
from .orchestrator import AgentEvent
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AlpieCodeClient:
|
|
20
|
+
"""Client for interacting with a running AlpieCode API server."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, base_url: str = "http://127.0.0.1:7169", timeout: float = 120.0):
|
|
23
|
+
self.base_url = base_url.rstrip("/")
|
|
24
|
+
self.timeout = timeout
|
|
25
|
+
|
|
26
|
+
def health(self) -> Dict[str, Any]:
|
|
27
|
+
"""Check server health and backend status."""
|
|
28
|
+
req = urllib.request.Request(f"{self.base_url}/health")
|
|
29
|
+
try:
|
|
30
|
+
with urllib.request.urlopen(req, timeout=3.0) as resp:
|
|
31
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
32
|
+
except Exception as e:
|
|
33
|
+
return {"status": "offline", "error": str(e)}
|
|
34
|
+
|
|
35
|
+
def metrics(self) -> Dict[str, Any]:
|
|
36
|
+
"""Get server observability metrics."""
|
|
37
|
+
req = urllib.request.Request(f"{self.base_url}/metrics")
|
|
38
|
+
try:
|
|
39
|
+
with urllib.request.urlopen(req, timeout=3.0) as resp:
|
|
40
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
41
|
+
except Exception as e:
|
|
42
|
+
return {"error": str(e)}
|
|
43
|
+
|
|
44
|
+
def list_sessions(self) -> list:
|
|
45
|
+
"""List active server sessions."""
|
|
46
|
+
req = urllib.request.Request(f"{self.base_url}/sessions")
|
|
47
|
+
try:
|
|
48
|
+
with urllib.request.urlopen(req, timeout=5.0) as resp:
|
|
49
|
+
data = json.loads(resp.read().decode("utf-8"))
|
|
50
|
+
return data.get("sessions", [])
|
|
51
|
+
except Exception:
|
|
52
|
+
return []
|
|
53
|
+
|
|
54
|
+
def cancel_task(self, session_id: str) -> bool:
|
|
55
|
+
"""Request cancellation of an in-progress task session."""
|
|
56
|
+
req = urllib.request.Request(
|
|
57
|
+
f"{self.base_url}/cancel/{session_id}",
|
|
58
|
+
method="POST",
|
|
59
|
+
headers={"Content-Type": "application/json"},
|
|
60
|
+
)
|
|
61
|
+
try:
|
|
62
|
+
with urllib.request.urlopen(req, timeout=5.0) as resp:
|
|
63
|
+
return resp.status == 200
|
|
64
|
+
except Exception:
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
def stream_chat(
|
|
68
|
+
self,
|
|
69
|
+
task: str,
|
|
70
|
+
workdir: str = ".",
|
|
71
|
+
session_id: Optional[str] = None,
|
|
72
|
+
image_path: Optional[str] = None,
|
|
73
|
+
video_path: Optional[str] = None,
|
|
74
|
+
url: Optional[str] = None,
|
|
75
|
+
github_repo: Optional[str] = None,
|
|
76
|
+
) -> Iterator[AgentEvent]:
|
|
77
|
+
"""
|
|
78
|
+
Stream agent events from POST /chat using Server-Sent Events (SSE).
|
|
79
|
+
Yields AgentEvent instances.
|
|
80
|
+
"""
|
|
81
|
+
endpoint = f"{self.base_url}/chat"
|
|
82
|
+
payload = json.dumps({
|
|
83
|
+
"task": task,
|
|
84
|
+
"workdir": str(workdir),
|
|
85
|
+
"session_id": session_id,
|
|
86
|
+
"image": image_path,
|
|
87
|
+
"video": video_path,
|
|
88
|
+
"url": url,
|
|
89
|
+
"github": github_repo,
|
|
90
|
+
}).encode("utf-8")
|
|
91
|
+
|
|
92
|
+
req = urllib.request.Request(
|
|
93
|
+
endpoint,
|
|
94
|
+
data=payload,
|
|
95
|
+
headers={
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
"Accept": "text/event-stream",
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
103
|
+
current_event_type = "message"
|
|
104
|
+
current_data_str = ""
|
|
105
|
+
|
|
106
|
+
for raw_line in resp:
|
|
107
|
+
line = raw_line.decode("utf-8").strip()
|
|
108
|
+
if not line:
|
|
109
|
+
if current_data_str:
|
|
110
|
+
try:
|
|
111
|
+
event_data = json.loads(current_data_str)
|
|
112
|
+
except Exception:
|
|
113
|
+
event_data = {"content": current_data_str}
|
|
114
|
+
yield AgentEvent(type=current_event_type, data=event_data)
|
|
115
|
+
current_event_type = "message"
|
|
116
|
+
current_data_str = ""
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
if line.startswith("event:"):
|
|
120
|
+
current_event_type = line[6:].strip()
|
|
121
|
+
elif line.startswith("data:"):
|
|
122
|
+
current_data_str = line[5:].strip()
|
|
123
|
+
|
|
124
|
+
if current_data_str:
|
|
125
|
+
try:
|
|
126
|
+
event_data = json.loads(current_data_str)
|
|
127
|
+
except Exception:
|
|
128
|
+
event_data = {"content": current_data_str}
|
|
129
|
+
yield AgentEvent(type=current_event_type, data=event_data)
|
|
130
|
+
except Exception as e:
|
|
131
|
+
yield AgentEvent(type="error", data={"error": f"Server connection failed: {e}"})
|
|
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
|