ags-cli 0.1.0__py3-none-any.whl
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.
- ags_cli-0.1.0.dist-info/METADATA +332 -0
- ags_cli-0.1.0.dist-info/RECORD +156 -0
- ags_cli-0.1.0.dist-info/WHEEL +5 -0
- ags_cli-0.1.0.dist-info/entry_points.txt +2 -0
- ags_cli-0.1.0.dist-info/top_level.txt +2 -0
- cli/__init__.py +0 -0
- cli/__main__.py +4 -0
- cli/client.py +145 -0
- cli/commands/__init__.py +0 -0
- cli/commands/adapter.py +33 -0
- cli/commands/artifact.py +21 -0
- cli/commands/ask.py +212 -0
- cli/commands/chat.py +649 -0
- cli/commands/diff.py +49 -0
- cli/commands/doctor.py +93 -0
- cli/commands/gui.py +45 -0
- cli/commands/init.py +20 -0
- cli/commands/mcp.py +50 -0
- cli/commands/memory.py +65 -0
- cli/commands/model.py +73 -0
- cli/commands/policy.py +52 -0
- cli/commands/project.py +122 -0
- cli/commands/quota.py +107 -0
- cli/commands/run.py +84 -0
- cli/commands/serve.py +171 -0
- cli/commands/service.py +236 -0
- cli/commands/session.py +219 -0
- cli/commands/stats.py +96 -0
- cli/commands/status.py +36 -0
- cli/commands/task.py +37 -0
- cli/commands/usage.py +86 -0
- cli/local.py +84 -0
- cli/main.py +149 -0
- harness/__init__.py +4 -0
- harness/adapters/__init__.py +26 -0
- harness/adapters/antigravity.py +301 -0
- harness/adapters/claude_code.py +522 -0
- harness/adapters/local_openai.py +534 -0
- harness/adapters/mock.py +112 -0
- harness/adapters/probe.py +65 -0
- harness/adapters/registry.py +56 -0
- harness/adapters/warm_pool.py +255 -0
- harness/api/__init__.py +0 -0
- harness/api/router.py +38 -0
- harness/api/v1/__init__.py +0 -0
- harness/api/v1/adapters.py +105 -0
- harness/api/v1/approvals.py +173 -0
- harness/api/v1/artifacts.py +44 -0
- harness/api/v1/attachments.py +48 -0
- harness/api/v1/doctor.py +22 -0
- harness/api/v1/health.py +37 -0
- harness/api/v1/mcp.py +131 -0
- harness/api/v1/memory.py +80 -0
- harness/api/v1/policies.py +49 -0
- harness/api/v1/project.py +302 -0
- harness/api/v1/runs.py +98 -0
- harness/api/v1/sessions.py +248 -0
- harness/api/v1/stream.py +110 -0
- harness/api/v1/tasks.py +30 -0
- harness/api/v1/usage.py +58 -0
- harness/bootstrap.py +216 -0
- harness/db.py +164 -0
- harness/deps.py +58 -0
- harness/eventbus/__init__.py +20 -0
- harness/eventbus/inprocess_bus.py +85 -0
- harness/main.py +144 -0
- harness/mcp/__init__.py +22 -0
- harness/mcp/client.py +139 -0
- harness/mcp/config_gen.py +77 -0
- harness/mcp/registry.py +156 -0
- harness/mcp/tools.py +81 -0
- harness/memory/__init__.py +13 -0
- harness/memory/context_budget.py +116 -0
- harness/memory/embed.py +217 -0
- harness/memory/extract.py +74 -0
- harness/memory/ingest.py +106 -0
- harness/memory/namespaces.py +57 -0
- harness/memory/ranking.py +31 -0
- harness/memory/redact.py +37 -0
- harness/memory/service.py +320 -0
- harness/memory/sqlite_vec_backend.py +266 -0
- harness/memory/summarize.py +68 -0
- harness/models/__init__.py +35 -0
- harness/models/adapter_health.py +27 -0
- harness/models/approval.py +37 -0
- harness/models/artifact.py +35 -0
- harness/models/audit_log.py +33 -0
- harness/models/comparison.py +33 -0
- harness/models/enums.py +146 -0
- harness/models/mcp_server_config.py +49 -0
- harness/models/memory.py +76 -0
- harness/models/policy.py +29 -0
- harness/models/provider_config.py +35 -0
- harness/models/run.py +46 -0
- harness/models/run_event.py +35 -0
- harness/models/session.py +50 -0
- harness/models/task.py +30 -0
- harness/models/types.py +63 -0
- harness/models/workspace.py +27 -0
- harness/observability/__init__.py +4 -0
- harness/observability/audit.py +88 -0
- harness/observability/logging.py +47 -0
- harness/observability/metrics.py +43 -0
- harness/observability/tracing.py +38 -0
- harness/orchestrator/__init__.py +19 -0
- harness/orchestrator/engine.py +821 -0
- harness/orchestrator/handoff.py +33 -0
- harness/orchestrator/lifecycle.py +69 -0
- harness/orchestrator/native_resume.py +93 -0
- harness/orchestrator/policies.py +101 -0
- harness/orchestrator/reconcile.py +39 -0
- harness/orchestrator/run_graph.py +62 -0
- harness/orchestrator/snapshot.py +49 -0
- harness/schemas/__init__.py +1 -0
- harness/schemas/adapter.py +26 -0
- harness/schemas/approval.py +25 -0
- harness/schemas/artifact.py +17 -0
- harness/schemas/common.py +20 -0
- harness/schemas/memory.py +50 -0
- harness/schemas/policy.py +39 -0
- harness/schemas/run.py +116 -0
- harness/schemas/session.py +93 -0
- harness/schemas/task.py +24 -0
- harness/security/__init__.py +5 -0
- harness/security/approval_policy.py +107 -0
- harness/security/auth.py +106 -0
- harness/security/permissions.py +59 -0
- harness/security/risk.py +59 -0
- harness/security/secrets.py +49 -0
- harness/services/__init__.py +1 -0
- harness/services/adapters_health.py +212 -0
- harness/services/approvals.py +84 -0
- harness/services/artifacts.py +78 -0
- harness/services/attachments.py +228 -0
- harness/services/comparison.py +345 -0
- harness/services/doctor.py +156 -0
- harness/services/files.py +287 -0
- harness/services/mcp_servers.py +179 -0
- harness/services/project_git.py +101 -0
- harness/services/retention.py +97 -0
- harness/services/runs.py +155 -0
- harness/services/runs_diff.py +201 -0
- harness/services/sessions.py +242 -0
- harness/services/ssh.py +300 -0
- harness/services/stats.py +132 -0
- harness/services/tasks.py +41 -0
- harness/services/workspaces.py +184 -0
- harness/services/worktrees.py +439 -0
- harness/settings.py +186 -0
- harness/skills/__init__.py +11 -0
- harness/skills/manager.py +141 -0
- harness/tools/__init__.py +1 -0
- harness/tools/fs_tools.py +295 -0
- harness/workers/__init__.py +0 -0
- harness/workers/dispatch.py +26 -0
- harness/workers/inprocess.py +135 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ags-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AgentS: one unified interface over Claude Code, Google CLI (agy), and OpenAI-compatible local LLMs.
|
|
5
|
+
Author: Platform Engineering
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: fastapi>=0.115
|
|
10
|
+
Requires-Dist: uvicorn[standard]>=0.32
|
|
11
|
+
Requires-Dist: pydantic>=2.9
|
|
12
|
+
Requires-Dist: pydantic-settings>=2.5
|
|
13
|
+
Requires-Dist: python-dotenv>=1.0
|
|
14
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.35
|
|
15
|
+
Requires-Dist: aiosqlite>=0.20
|
|
16
|
+
Requires-Dist: httpx>=0.27
|
|
17
|
+
Requires-Dist: typer>=0.12
|
|
18
|
+
Requires-Dist: rich>=13.9
|
|
19
|
+
Requires-Dist: structlog>=24.4
|
|
20
|
+
Requires-Dist: prometheus-client>=0.21
|
|
21
|
+
Requires-Dist: opentelemetry-api>=1.27
|
|
22
|
+
Requires-Dist: opentelemetry-sdk>=1.27
|
|
23
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.48b0
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Dist: mcp>=1.2
|
|
26
|
+
Requires-Dist: python-multipart>=0.0.12
|
|
27
|
+
Requires-Dist: bcrypt>=4.2
|
|
28
|
+
Requires-Dist: pyjwt>=2.9
|
|
29
|
+
Requires-Dist: ags-sdk>=0.1.0
|
|
30
|
+
Provides-Extra: embed
|
|
31
|
+
Requires-Dist: fastembed>=0.4; extra == "embed"
|
|
32
|
+
Provides-Extra: vec
|
|
33
|
+
Requires-Dist: sqlite-vec>=0.1.6; extra == "vec"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=8.3; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
38
|
+
Requires-Dist: anyio>=4.6; extra == "dev"
|
|
39
|
+
Requires-Dist: ruff>=0.7; extra == "dev"
|
|
40
|
+
Requires-Dist: mypy>=1.13; extra == "dev"
|
|
41
|
+
Requires-Dist: respx>=0.21; extra == "dev"
|
|
42
|
+
|
|
43
|
+
# AgentS
|
|
44
|
+
|
|
45
|
+
One agent over many AI coding agents. AgentS gives you a single interface
|
|
46
|
+
over **Claude Code**, **Antigravity** (Google's `agy`), and any
|
|
47
|
+
**OpenAI-compatible local LLM** (Ollama / LM Studio / vLLM / OpenRouter / …).
|
|
48
|
+
It keeps a shared, vendor-neutral **memory** and an append-only **run ledger**
|
|
49
|
+
in your own database, so the same task can run on one provider or several, be
|
|
50
|
+
compared and merged, and pick up where another agent left off — without sharing
|
|
51
|
+
vendor credentials.
|
|
52
|
+
|
|
53
|
+
# Install & Getting Started
|
|
54
|
+
|
|
55
|
+
AgentS ships as a single desktop application for **Windows**, **macOS**, and
|
|
56
|
+
**Linux**. This guide covers installing the app, satisfying its two
|
|
57
|
+
prerequisites (the **Antigravity** and **Claude Code** CLIs), fixing the most
|
|
58
|
+
common startup problem (agents not found on `PATH`), and taking your first
|
|
59
|
+
steps in the GUI.
|
|
60
|
+
|
|
61
|
+
> This guide covers the **GUI (desktop) application only**. The desktop app is
|
|
62
|
+
> self-contained: it bundles the AgentS engine and starts it for you in the
|
|
63
|
+
> background — there is nothing else to install or run from a terminal.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 1. Prerequisites
|
|
68
|
+
|
|
69
|
+
AgentS is an orchestrator: it drives the **official Antigravity and Claude Code
|
|
70
|
+
CLIs** as subprocesses. It does **not** ship, replace, or embed them, and it
|
|
71
|
+
never reads, stores, or reuses your credentials — each agent uses its own login.
|
|
72
|
+
|
|
73
|
+
Before installing AgentS, both agent binaries must be **installed** *and*
|
|
74
|
+
**authenticated** on your machine:
|
|
75
|
+
|
|
76
|
+
| Agent | Binary | Install | Authenticate | Verify |
|
|
77
|
+
|---|---|---|---|---|
|
|
78
|
+
| **Claude Code** | `claude` | `npm i -g @anthropic-ai/claude-code` (or the official installer) | Run `claude` once and log in (or set `ANTHROPIC_API_KEY`) | `claude --version` |
|
|
79
|
+
| **Antigravity** | `agy` | Follow Google's official Antigravity install guide | Run `agy` once and sign in (or set `ANTIGRAVITY_API_KEY`) | `agy --version` |
|
|
80
|
+
|
|
81
|
+
Both checks must succeed in a terminal **before** you launch AgentS:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
claude --version # e.g. 1.x.x
|
|
85
|
+
agy --version # e.g. 0.x.x
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If either command prints a version but the agent later fails **inside AgentS**,
|
|
89
|
+
it is almost always a `PATH` problem — see [§4](#4-fixing-path-issues-agents-not-found)
|
|
90
|
+
below.
|
|
91
|
+
|
|
92
|
+
> You only need the agent(s) you intend to use. If you install just `claude`,
|
|
93
|
+
> the Claude Code agent works and Antigravity simply shows as unavailable (and
|
|
94
|
+
> vice-versa).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 2. Download
|
|
99
|
+
|
|
100
|
+
Download the installer for your operating system from the
|
|
101
|
+
**[latest release](https://github.com/farookmfk/AgentS/releases/latest)**:
|
|
102
|
+
|
|
103
|
+
| OS | Download | Notes |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| **Windows** | `AgentS_<version>_x64-setup.exe` (or the `.msi`) | 64-bit Windows 10/11 |
|
|
106
|
+
| **macOS** | `AgentS_<version>_aarch64.dmg` | Apple Silicon (M-series) |
|
|
107
|
+
| **Linux** | `AgentS_<version>_amd64.AppImage` or `.deb` | AppImage runs anywhere; `.deb` for Debian/Ubuntu |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 3. Install
|
|
112
|
+
|
|
113
|
+
### Windows
|
|
114
|
+
|
|
115
|
+
1. Run the downloaded `.exe` (or `.msi`) installer and follow the prompts.
|
|
116
|
+
2. Launch **AgentS** from the Start menu.
|
|
117
|
+
3. If SmartScreen shows a "Windows protected your PC" dialog, click
|
|
118
|
+
**More info → Run anyway** (the app is signed on official releases; this can
|
|
119
|
+
appear on first launch).
|
|
120
|
+
|
|
121
|
+
### macOS
|
|
122
|
+
|
|
123
|
+
1. Open the `.dmg` and drag **AgentS** into **Applications**.
|
|
124
|
+
2. Launch it from **Applications** (or Spotlight).
|
|
125
|
+
3. Official releases are signed and notarized, so Gatekeeper clears the app on
|
|
126
|
+
first launch (an online check — the first launch needs network). If a
|
|
127
|
+
download is still flagged, clear the quarantine attribute once:
|
|
128
|
+
```bash
|
|
129
|
+
xattr -d com.apple.quarantine /Applications/AgentS.app
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Linux
|
|
133
|
+
|
|
134
|
+
**AppImage** (no install — runs anywhere):
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
chmod +x AgentS_*_amd64.AppImage
|
|
138
|
+
./AgentS_*_amd64.AppImage
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Debian / Ubuntu (`.deb`):**
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
sudo apt install ./AgentS_*_amd64.deb
|
|
145
|
+
# then launch "AgentS" from your app menu, or run:
|
|
146
|
+
agents
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
On first launch AgentS creates its local state under `~/.ags/`
|
|
150
|
+
(`%USERPROFILE%\.ags\` on Windows) — a configuration file, a SQLite database,
|
|
151
|
+
and logs. Everything stays on your machine; there are no daemons or servers to
|
|
152
|
+
manage.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 4. Fixing PATH issues (agents not found)
|
|
157
|
+
|
|
158
|
+
**The single most common problem.** Everything works in your terminal, but
|
|
159
|
+
inside AgentS the Claude Code or Antigravity agent shows as unavailable or its
|
|
160
|
+
runs fail with something like *"binary not on PATH"*.
|
|
161
|
+
|
|
162
|
+
**Why it happens:** a desktop app launched from the Start menu, the macOS Dock,
|
|
163
|
+
or an app menu does **not** inherit the `PATH` from your shell startup files
|
|
164
|
+
(`.bashrc`, `.zshrc`, `.profile`). So agents installed to a non-standard
|
|
165
|
+
location — npm's global prefix, `nvm`, Homebrew on Apple Silicon
|
|
166
|
+
(`/opt/homebrew/bin`), a custom `~/.local/bin`, etc. — are visible in your
|
|
167
|
+
terminal but invisible to AgentS.
|
|
168
|
+
|
|
169
|
+
You have two ways to fix it. **Either one** works — pick whichever you prefer.
|
|
170
|
+
|
|
171
|
+
### Option A — Put the agents on a system-wide PATH
|
|
172
|
+
|
|
173
|
+
First, find where each agent actually lives:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# macOS / Linux
|
|
177
|
+
which claude
|
|
178
|
+
which agy
|
|
179
|
+
|
|
180
|
+
# Windows (PowerShell)
|
|
181
|
+
where.exe claude
|
|
182
|
+
where.exe agy
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Then make that location visible to GUI apps:
|
|
186
|
+
|
|
187
|
+
- **macOS / Linux** — symlink (or move) each binary into a standard system
|
|
188
|
+
directory that GUI apps always see:
|
|
189
|
+
```bash
|
|
190
|
+
sudo ln -sf "$(which claude)" /usr/local/bin/claude
|
|
191
|
+
sudo ln -sf "$(which agy)" /usr/local/bin/agy
|
|
192
|
+
```
|
|
193
|
+
- **Windows** — add the folder that contains `claude.exe` / `agy.exe` (or the
|
|
194
|
+
npm global folder, e.g. `%APPDATA%\npm`) to the **System** `PATH`:
|
|
195
|
+
*Settings → System → About → Advanced system settings → Environment
|
|
196
|
+
Variables → System variables → Path → Edit → New*. Then **log out and back
|
|
197
|
+
in** so the desktop environment picks up the change.
|
|
198
|
+
|
|
199
|
+
### Option B — Set the full path explicitly in `config.yaml`
|
|
200
|
+
|
|
201
|
+
If you'd rather not touch your system `PATH`, tell AgentS exactly where each
|
|
202
|
+
binary is. Edit the config file:
|
|
203
|
+
|
|
204
|
+
| OS | Config file |
|
|
205
|
+
|---|---|
|
|
206
|
+
| macOS / Linux | `~/.ags/config.yaml` |
|
|
207
|
+
| Windows | `%USERPROFILE%\.ags\config.yaml` |
|
|
208
|
+
|
|
209
|
+
Find the `providers:` section and set each agent's `params.bin` to the **full
|
|
210
|
+
absolute path** you got from `which` / `where.exe` above:
|
|
211
|
+
|
|
212
|
+
```yaml
|
|
213
|
+
providers:
|
|
214
|
+
- name: claude
|
|
215
|
+
kind: claude_code
|
|
216
|
+
enabled: true
|
|
217
|
+
model: claude-opus-4-8
|
|
218
|
+
params:
|
|
219
|
+
bin: /usr/local/bin/claude # ← full path instead of just "claude"
|
|
220
|
+
permission_mode: plan
|
|
221
|
+
timeout_s: 600
|
|
222
|
+
|
|
223
|
+
- name: antigravity
|
|
224
|
+
kind: antigravity
|
|
225
|
+
enabled: true
|
|
226
|
+
model: gemini-1.5-pro
|
|
227
|
+
params:
|
|
228
|
+
bin: /opt/homebrew/bin/agy # ← full path instead of just "agy"
|
|
229
|
+
pty: true
|
|
230
|
+
timeout_s: 600
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Windows path note:** use the full path including the extension, and prefer
|
|
234
|
+
forward slashes or a quoted string, e.g.
|
|
235
|
+
`bin: "C:/Users/you/AppData/Roaming/npm/claude.cmd"`. npm-installed CLIs on
|
|
236
|
+
Windows are usually `claude.cmd` / `agy.cmd`, not `.exe`.
|
|
237
|
+
|
|
238
|
+
### After either fix
|
|
239
|
+
|
|
240
|
+
**Fully quit and reopen AgentS** so it restarts its engine and re-reads the
|
|
241
|
+
config. Then confirm the agents are healthy in the GUI:
|
|
242
|
+
|
|
243
|
+
- Open **Settings → Adapters** and click **Test** next to `claude` and
|
|
244
|
+
`antigravity`. A green result means the binary was found and responded.
|
|
245
|
+
|
|
246
|
+
If it still fails, check the diagnostic logs for the exact error:
|
|
247
|
+
|
|
248
|
+
- `~/.ags/sidecar.log` — did the engine start? (`%USERPROFILE%\.ags\sidecar.log`)
|
|
249
|
+
- `~/.ags/server.log` — runtime errors from the engine.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 5. Getting started with the GUI
|
|
254
|
+
|
|
255
|
+
When AgentS opens you get a dashboard with a left sidebar:
|
|
256
|
+
**Dashboard**, **New session**, **Sessions**, and a **Settings** group
|
|
257
|
+
(**Project selection**, **Remote hosts**, **Adapters**, **MCP**, **Usage**,
|
|
258
|
+
**Approvals**).
|
|
259
|
+
|
|
260
|
+
### 5.1 Add a project (local or remote)
|
|
261
|
+
|
|
262
|
+
Agents work inside a **project folder**. Set it under
|
|
263
|
+
**Settings → Project selection**:
|
|
264
|
+
|
|
265
|
+
- **Local** — keep the **Local** tab selected and browse to the folder on this
|
|
266
|
+
machine you want agents to read and edit. Click a folder to choose it.
|
|
267
|
+
- **Remote** — run agents against a folder on another machine over SSH:
|
|
268
|
+
1. First save the machine under **Settings → Remote hosts**: give it a label
|
|
269
|
+
and an SSH target (e.g. `user@build-box`). AgentS uses your existing
|
|
270
|
+
`~/.ssh` config, keys, and agent. The agent CLI (`claude` / `agy`) must be
|
|
271
|
+
installed **on the remote host** too. Use **Test** to verify the
|
|
272
|
+
connection and that the CLI is present.
|
|
273
|
+
2. Back on **Project selection**, switch to the **Remote** tab, pick the saved
|
|
274
|
+
host, and browse to the folder on that host.
|
|
275
|
+
|
|
276
|
+
Changes apply to the **next turn** — no restart needed. The current project
|
|
277
|
+
(and whether it's local or remote) is shown at the top of the page.
|
|
278
|
+
|
|
279
|
+
### 5.2 Start a session — pick an agent and model
|
|
280
|
+
|
|
281
|
+
Click **New session** in the sidebar:
|
|
282
|
+
|
|
283
|
+
1. **Agent** — choose **Antigravity** (`antigravity`) or **Claude Code**
|
|
284
|
+
(`claude`) from the dropdown. Only installed, healthy agents appear here.
|
|
285
|
+
2. **Model (optional override)** — pick a specific model for the chosen agent
|
|
286
|
+
(e.g. `claude-opus-4-8` for Claude Code, `gemini-1.5-pro` for Antigravity), or
|
|
287
|
+
leave it to use the agent's default.
|
|
288
|
+
3. **First message** — type your task (e.g. *"Audit the cache layer and propose
|
|
289
|
+
the safest fix"*). You can also drag-and-drop or paste files to attach them.
|
|
290
|
+
4. **Mode** — **Plan** (read-only; the agent proposes but doesn't write) is the
|
|
291
|
+
default. Switch to **Edit** to let the agent modify files.
|
|
292
|
+
5. **Private workspace** — leave checked to work on an isolated git branch and
|
|
293
|
+
merge back when you're happy; uncheck to edit the project folder directly.
|
|
294
|
+
6. Click **Start session** (or press ⌘/Ctrl+Enter).
|
|
295
|
+
|
|
296
|
+
Responses stream live with Markdown rendering, and tool calls (file reads,
|
|
297
|
+
edits, commands) show compactly as the agent works. You can switch the active
|
|
298
|
+
agent mid-conversation from within the session.
|
|
299
|
+
|
|
300
|
+
### 5.3 Add MCP servers (external tools)
|
|
301
|
+
|
|
302
|
+
MCP (Model Context Protocol) servers give agents extra tools — filesystems,
|
|
303
|
+
GitHub, databases, and more. Manage them under **Settings → MCP**:
|
|
304
|
+
|
|
305
|
+
1. Click **Add server** and choose a transport:
|
|
306
|
+
- **stdio** — a local command, e.g. command `npx` with args
|
|
307
|
+
`-y @modelcontextprotocol/server-filesystem /path/to/project`.
|
|
308
|
+
- **http** — a remote endpoint URL, e.g.
|
|
309
|
+
`https://api.githubcopilot.com/mcp/`. Provide the token via an environment
|
|
310
|
+
variable reference (stored as a `0600` secret file, never inline).
|
|
311
|
+
2. Optionally set a **tool allowlist** (empty = all tools) and mark the server
|
|
312
|
+
**read-only** so its tools are offered even in Plan mode.
|
|
313
|
+
3. **Enable** the server, then click **Test** to connect and list the tools it
|
|
314
|
+
advertises. Tools appear to agents namespaced as `mcp__<server>__<tool>`.
|
|
315
|
+
|
|
316
|
+
Changes take effect immediately on the next run — no restart required.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 6. Where things live
|
|
321
|
+
|
|
322
|
+
| Path | What it is |
|
|
323
|
+
|---|---|
|
|
324
|
+
| `~/.ags/config.yaml` | Providers (agents), models, MCP servers, memory settings |
|
|
325
|
+
| `~/.ags/harness.db` | Local SQLite database (sessions, run ledger, memory) |
|
|
326
|
+
| `~/.ags/sidecar.log` | Desktop-app ↔ engine startup diagnostics |
|
|
327
|
+
| `~/.ags/server.log` | Engine runtime log |
|
|
328
|
+
|
|
329
|
+
On Windows these live under `%USERPROFILE%\.ags\`.
|
|
330
|
+
|
|
331
|
+
To fully reset AgentS, quit the app and delete the `~/.ags` folder — it is
|
|
332
|
+
recreated with defaults on the next launch.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
cli/__main__.py,sha256=dPjp912dL0OMqmqWZyWm7H14z8nq0epiRI6Tr2IadeY,63
|
|
3
|
+
cli/client.py,sha256=lFOgyuVloEcIQfrrEnmyXUMhtf_LctrVEGqDtlo87iY,6418
|
|
4
|
+
cli/local.py,sha256=C1nw0kcfwTKFZOUCz-Ug-7wXdcfgTTgImgvmFRkkNk8,3048
|
|
5
|
+
cli/main.py,sha256=RJAgv0pdMcYqH9N79ZULloFFXyzypZVMGGsMiXaNTXY,4819
|
|
6
|
+
cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
cli/commands/adapter.py,sha256=ND5LiZTX-ZLs09t_5DOG0unXCeEAIdo8qX4sZ9eQjl8,1092
|
|
8
|
+
cli/commands/artifact.py,sha256=VylM1duKGJmLFPYBxwEC0g_URXrrjSRlxlAQnip4wxU,678
|
|
9
|
+
cli/commands/ask.py,sha256=q2VoLDsv_MQEnDnPRw-ogxspUG9dn3gJSPpYy70raoY,7898
|
|
10
|
+
cli/commands/chat.py,sha256=dcjvDjdDy7zNvpxIjcJGpQzajnAFOQ2O8OsIc0QMogw,31066
|
|
11
|
+
cli/commands/diff.py,sha256=NXGYmTcglm_iVuuprzXcYosIWxf_8ZmtzYxQ766bfXc,1568
|
|
12
|
+
cli/commands/doctor.py,sha256=QQxGf64s5etd0qysuQzvU2vVLogoTFT0rS_WqojmPG0,2776
|
|
13
|
+
cli/commands/gui.py,sha256=1ZUtQKzVmCSECij1qxqERr4rGtEX-9k0G983dylwHrA,1340
|
|
14
|
+
cli/commands/init.py,sha256=_RC-ObHw0pzRMvDOUeH_K4ZjTuCfFEqtCXSYKLm8HCs,648
|
|
15
|
+
cli/commands/mcp.py,sha256=-6LFZ4amFGgZ1xS88B00N98InWFkPoM8Tfxgnevkgtw,1700
|
|
16
|
+
cli/commands/memory.py,sha256=R_8JW_d4aHAZbxCZ1N9G_FBGsPjFgU9ZtWB29a-KgZo,2307
|
|
17
|
+
cli/commands/model.py,sha256=QtEGXKlJY0Qw3MsPkcmvcoJ7lO858snBIya5t36Si_I,2932
|
|
18
|
+
cli/commands/policy.py,sha256=3vRzfy5Gp9dKeJKSwra9FM5JAHgzaYssLHQi3RErRJk,1604
|
|
19
|
+
cli/commands/project.py,sha256=ki1MehVU3Nt0JhGgbzsGFUZPDbBn-eJ3hK71KTIrg5Q,4866
|
|
20
|
+
cli/commands/quota.py,sha256=z8nAsG1X5845g6qFfMMwvKdP-XwviYkKNKly_cL2N_A,4344
|
|
21
|
+
cli/commands/run.py,sha256=JHEFRC3IuEJZ5hBQlwnGqNx9eKcJxFwuiIGLEoadIK4,3165
|
|
22
|
+
cli/commands/serve.py,sha256=gmV89t3Iro87QyvibELjyM450X425LuNReojtkFxfTQ,8211
|
|
23
|
+
cli/commands/service.py,sha256=1anfl19V_PXKFdqLngdZZtpOJGQe4BlGBQdHVXDz5-g,7645
|
|
24
|
+
cli/commands/session.py,sha256=VvUI46PXNDITEYGsIJMveIB8HRhkxJGB3GN1WR7p8Go,9067
|
|
25
|
+
cli/commands/stats.py,sha256=JVe7JpYSmLvllGrj1Vvl6fIN-hPSHDfU0TT1CeXvvD4,3406
|
|
26
|
+
cli/commands/status.py,sha256=FchjFH5S_MfGW6OkwFAk0S2BTmtRABfVyY5SdySlvF0,1381
|
|
27
|
+
cli/commands/task.py,sha256=w6hebmqsmGA1KfhvPRwOpxaRx6UtZ_pMXytvri5vWgw,1109
|
|
28
|
+
cli/commands/usage.py,sha256=EAaDAvaIHPvYE6DZiu4mszhQR1rb8NJCKdm8tFQy7JU,2630
|
|
29
|
+
harness/__init__.py,sha256=lppaVKQ-IoXDncVdCB7EEX2n9aPjjPkTcJ8rkjE96xc,163
|
|
30
|
+
harness/bootstrap.py,sha256=LLNTXXKXAQ-LILUk0tGbkgxJZ3_xQzrpHoUizkbUZNY,9014
|
|
31
|
+
harness/db.py,sha256=KU_IXyG9lWpCAa1T_SWqnq5gPuREeReLh7BrZTn8jsk,6007
|
|
32
|
+
harness/deps.py,sha256=bYTmGfcgF0yfO6WsZkdIsFbZRCGMdiiAJvq53UY7USg,1860
|
|
33
|
+
harness/main.py,sha256=oodk4KDWfClQ0FldOZkrq5TRR7PpHoS_yLMWqx44q-U,5138
|
|
34
|
+
harness/settings.py,sha256=OV9GcHIepuaYM15WxW-6T4tFAVcrBCj8EbBu9uMBAjg,7356
|
|
35
|
+
harness/adapters/__init__.py,sha256=pFxdj9YlkBbAuisPo7LlhFNSMkJA8S54Qd1RZTw7gV4,492
|
|
36
|
+
harness/adapters/antigravity.py,sha256=M7KckHTwtnoyyoA4sX3kKnk_FVcIoJWgpe989bK1br8,14436
|
|
37
|
+
harness/adapters/claude_code.py,sha256=-e30Klf3CIWYYNY3UOk77LlFqQd_f-PE-WERJjGXvrw,24108
|
|
38
|
+
harness/adapters/local_openai.py,sha256=PeEruIQvx17JmPtr3WqbqKT64VRZIPXQBtb15DPZ-6Q,23929
|
|
39
|
+
harness/adapters/mock.py,sha256=6pcufTGbGWU-gfB08A67AzGAlVuMtRnwRgi7hEQvGXU,3616
|
|
40
|
+
harness/adapters/probe.py,sha256=XOgeouVF2hEaJ6J3BwMBWoZc8sumTC3nEPa0C5EaUxU,2156
|
|
41
|
+
harness/adapters/registry.py,sha256=myyAj6t2wvMY3ew5G7Aep-WHp85TafbCzEtMkW24-Sc,2197
|
|
42
|
+
harness/adapters/warm_pool.py,sha256=QsQASV0XPsVm2Ik5ktOJCjELYHBFCN9yaCa9o3x194g,10838
|
|
43
|
+
harness/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
+
harness/api/router.py,sha256=cUMgvrdorx6xJs-Pzl16cie4eiml2ufcCayqsVriJlk,957
|
|
45
|
+
harness/api/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
|
+
harness/api/v1/adapters.py,sha256=MAEWYceTtYSm-2e4eDM6B4EFgYXMCXUFNTGp0I-BCJg,3499
|
|
47
|
+
harness/api/v1/approvals.py,sha256=w_nyR1xxRy_XZHBSnR1IjkJCa0g9_WRHB6KnBSmZDIY,7665
|
|
48
|
+
harness/api/v1/artifacts.py,sha256=oaHrJunmQj9pkb4PnH5OkCzNzSjnkEQD-yQ6oN8INqQ,1782
|
|
49
|
+
harness/api/v1/attachments.py,sha256=1ASOedzwn3zOhYA-qE2JyMQ_iyiyYbq2nLvddhB-Kyo,1652
|
|
50
|
+
harness/api/v1/doctor.py,sha256=xcYDilo4CXI6Pcn-327zCYvqT4Wrq2xb8c0YCBE3seU,764
|
|
51
|
+
harness/api/v1/health.py,sha256=Z3DDivINA1-Wq3AgaAAvPDDsGkPALafMEkUegdcrdTU,1295
|
|
52
|
+
harness/api/v1/mcp.py,sha256=28SsCIzD21i1Wk8w1-4CfQIlypwo3Gxb-bdwGmlGJJI,4220
|
|
53
|
+
harness/api/v1/memory.py,sha256=nzn3MrdX2sdihAGJgy_DHXciRDXjVsCjr2FuWDs5wQI,2740
|
|
54
|
+
harness/api/v1/policies.py,sha256=jov7dqaL81aOMVLRrEbJsLWlInNhyN_rPMe1U3wUDsk,1992
|
|
55
|
+
harness/api/v1/project.py,sha256=zJeVOyo5BY-wKB-35FosEiOsryZaDzUSitbP1-b4opU,11127
|
|
56
|
+
harness/api/v1/runs.py,sha256=iNBt7tcxoBqXL01ubZyKg0086ndWNR3kD-uEN-uhq5w,3367
|
|
57
|
+
harness/api/v1/sessions.py,sha256=kCd0lqeizwubiDbE6Zz1Ue3DZGe1Vu7-Ri393Q9_rMQ,9727
|
|
58
|
+
harness/api/v1/stream.py,sha256=cxAe-DQx0lje4nk2d06aIzMxlvUmqKXNRLNF6jplrxI,3846
|
|
59
|
+
harness/api/v1/tasks.py,sha256=k_6183jcO-uNpDR3ZWe2fdwJUIhsi6UwkqoZZgi4w5g,1086
|
|
60
|
+
harness/api/v1/usage.py,sha256=_a6cm1iUD5NXDCutTamaYZKPMfoz1jgqSmP8pmJCCCk,2289
|
|
61
|
+
harness/eventbus/__init__.py,sha256=vGZZxrANu8TB2kZJ23S71A6EhNrNE7tPbeaX9EeTiwA,465
|
|
62
|
+
harness/eventbus/inprocess_bus.py,sha256=ym_GCTMagyHF--8yu8vJjnjeEee5ObqAzf0B9HyNLMY,3013
|
|
63
|
+
harness/mcp/__init__.py,sha256=nsZJ31jRmvwoULSd5HnHdNzhFqjKA4to6sGFM0p4xuM,746
|
|
64
|
+
harness/mcp/client.py,sha256=2WS7imUSYbNoCpni-U9-32Ow4uKgMb4LkpsPTFeGshE,5667
|
|
65
|
+
harness/mcp/config_gen.py,sha256=3vlcOYhVrhkqWTcaQ_w2OSXGOKxSkUkGsiwYXXPQgLE,2966
|
|
66
|
+
harness/mcp/registry.py,sha256=yHMfUOSYJsGe43mtGFMCzl9b_s1z-RMTPuBa2cCvsUo,6342
|
|
67
|
+
harness/mcp/tools.py,sha256=rMojkFxcFtLlp76_GKOBtwh_eSYcxRxVg5Mhcf7rxdE,2806
|
|
68
|
+
harness/memory/__init__.py,sha256=E75V_vRCajkSetcCBcXYyA9Fl-q_HJ4vFbfHTZwr02w,398
|
|
69
|
+
harness/memory/context_budget.py,sha256=wUmEH-lAjJdoB8-py6aRWIdGpG4oW6hu1cz4EAvSBdQ,4354
|
|
70
|
+
harness/memory/embed.py,sha256=2NMt1nvqnCh2F5tSKR55V9uqIPhrqeBoaoml_moWkY0,8297
|
|
71
|
+
harness/memory/extract.py,sha256=QDE5TIlE3b46_iDrFOTolYlryR2vtSmsUoezB4JjISk,2756
|
|
72
|
+
harness/memory/ingest.py,sha256=VQlxsqvk6Tio2bg8j-211BuRQKLoIRyb-meqCnbhmx8,3424
|
|
73
|
+
harness/memory/namespaces.py,sha256=yydks9VKBigfOfuqL6A3H5ieQylq3EAVuodZY1ipSho,1971
|
|
74
|
+
harness/memory/ranking.py,sha256=ek_1Go6fopvVrEVCdjFYm2-Dx70RH9odpeVXrsqtt-c,1047
|
|
75
|
+
harness/memory/redact.py,sha256=2tciIKRYtpP8CURPRAv62Q4jpMV5Fvi3DCt_SmUmsEI,1505
|
|
76
|
+
harness/memory/service.py,sha256=Ph17Mgf0BYC7tGwy86oahLvM_CpeRq2BWQ7lXeDGBR0,12893
|
|
77
|
+
harness/memory/sqlite_vec_backend.py,sha256=ftadqBOqkvbZcVTHN_h8iWMCMQQc5YgSMiO1x0WJJhE,10465
|
|
78
|
+
harness/memory/summarize.py,sha256=56HkdW5kFxtgutV-u8FVmHs5fQ93FZ28lqNxsUnwkgE,2381
|
|
79
|
+
harness/models/__init__.py,sha256=K1KDTuKrreYl52jrWqRR_qjNKEY2xeLTFexnJiHLNMM,1096
|
|
80
|
+
harness/models/adapter_health.py,sha256=NmtthKuIeQFnSl4kTPddNdA9lc66IDm0qBgWy7IhMBw,942
|
|
81
|
+
harness/models/approval.py,sha256=kpYEF4TnAzH1_b_u75tomHfpAbTSypcYORMcEOw8y2U,1476
|
|
82
|
+
harness/models/artifact.py,sha256=Y3SoK4gy6qEpfw55aqUbiVuTsPbjqAu5jQmn0Whteh0,1380
|
|
83
|
+
harness/models/audit_log.py,sha256=KqihxlbZ8i0U0Olpg1-j5DOIgR5JAB1-teWEAhZgPPI,1268
|
|
84
|
+
harness/models/comparison.py,sha256=olKQKL-VlIwVEqroe51H08SiAj6dSUv8hhFTb1lu8Dc,1218
|
|
85
|
+
harness/models/enums.py,sha256=slOOVj96JgJbZg68FyvTTn3xRw6K6hm9e1fs-oSrv6Q,3559
|
|
86
|
+
harness/models/mcp_server_config.py,sha256=hH8cOje_12QreusU_lE17mIwR9N0IJ27XfoiQ4oSSWQ,2429
|
|
87
|
+
harness/models/memory.py,sha256=l9QdR2GuvtVVt7R9j4-T-XML_pLKv_0f3g2kjhL39_Q,2759
|
|
88
|
+
harness/models/policy.py,sha256=361TzNd9NvDOEILHbrSd5PrtKodIOwSslLHuTOrh3VY,1058
|
|
89
|
+
harness/models/provider_config.py,sha256=xfrWhVPjkUg13RFSEOeHFWK4_rlLa9rlQrjBSB8386Y,1620
|
|
90
|
+
harness/models/run.py,sha256=f0XeDlD3S4AOZbudiQK7gmDFOJFSAcgeOqccDYPgDJE,2057
|
|
91
|
+
harness/models/run_event.py,sha256=HyAiWoG_O6DH44AsBG0KLcaFX1HFNoWb7dC95D7cvAk,1285
|
|
92
|
+
harness/models/session.py,sha256=mJcfQGrrrZy6QDOsXjSU1Ug_034y4pPPwuAE21w2nLc,2221
|
|
93
|
+
harness/models/task.py,sha256=gknnwYVviS-aB5VAda83GOMui8MEtgCPHjnzxFaLEDM,1047
|
|
94
|
+
harness/models/types.py,sha256=Tzk07kPbPMFyGWXmllQEw8fKRupoTWUALmecj8xehzg,1758
|
|
95
|
+
harness/models/workspace.py,sha256=Koe_eUJ-KSgt27cN97RTRPR2gRoLIYAGKcZVli6NCX8,946
|
|
96
|
+
harness/observability/__init__.py,sha256=JU3tP_e1z5bAGu2HaZlA5kRo1d7Y1byjd9Ktu3a8TGM,216
|
|
97
|
+
harness/observability/audit.py,sha256=9437e_uE00qI69jKWpLAR-XhkmCDTzgz-c0Xo1IFLJw,2506
|
|
98
|
+
harness/observability/logging.py,sha256=R-8Ts3Er9nUCgJrlqdINb96MpBPJ0IekyC7_d9XU2Fc,1337
|
|
99
|
+
harness/observability/metrics.py,sha256=nI04K9eHp909rwyLh6yfBnd0_kLfn_7CqOHu9ENmqko,1388
|
|
100
|
+
harness/observability/tracing.py,sha256=2QGOCQlOh6wZe__f2IssiG_mn7HHOHkJVUYOYnB3iI4,1175
|
|
101
|
+
harness/orchestrator/__init__.py,sha256=se64wEHwDMBRcw1UVdSaWxLawiKE5Jg6zv0hArt2zHs,440
|
|
102
|
+
harness/orchestrator/engine.py,sha256=SJp99IrTGFnPnaXYbeZf30YKG7A3MC0Bi25I-d0K4X0,37054
|
|
103
|
+
harness/orchestrator/handoff.py,sha256=wEYFPCHJEM2PWFHZJ0SCrewA5yJllbbmft5p0_dwvOw,1159
|
|
104
|
+
harness/orchestrator/lifecycle.py,sha256=ftNGSVq0OrIsAZ1JT61SOitBXaXJZBYcOypXSnZqkMk,2057
|
|
105
|
+
harness/orchestrator/native_resume.py,sha256=j6ytXOPSRHrlibBsc5MfLYwHhVl3G699KP_nuaFnGjM,3243
|
|
106
|
+
harness/orchestrator/policies.py,sha256=4BeKbtIqG04eDWAa0oV4eWcvNAgaZGVHCW2lOR4LKio,3269
|
|
107
|
+
harness/orchestrator/reconcile.py,sha256=ScF3gKWMH-1hEQToINc156mim4pbMa1j43usI7cc9fs,1519
|
|
108
|
+
harness/orchestrator/run_graph.py,sha256=woo2f_Zgqb7Ximc_Egm1u-Afum_kzVoVwJPJxAQk28Y,2173
|
|
109
|
+
harness/orchestrator/snapshot.py,sha256=WBaAex4G2pZi7SVaw8NkY5j-IVr9RjHM6MgZLi7v-ok,1715
|
|
110
|
+
harness/schemas/__init__.py,sha256=KQoa7duyjPTpEET4F6NKInF5x264Kv9qH36QbRe5igw,88
|
|
111
|
+
harness/schemas/adapter.py,sha256=8h3yARV_UIBouBZ0dUUK_yO1rQZcv62GrKb5ynKMi2E,523
|
|
112
|
+
harness/schemas/approval.py,sha256=YKIML6PTDbulG20OreYLS-4nKaRds0h3YL5dZlj3qYQ,599
|
|
113
|
+
harness/schemas/artifact.py,sha256=ABl1iQ2qgwRI9PAXvlNUng8znemnzUyU644QdFG_B5A,353
|
|
114
|
+
harness/schemas/common.py,sha256=X2WYRV7xPMj4qnSvv47eBTBpTUM3HVf3JV742YCBgfc,371
|
|
115
|
+
harness/schemas/memory.py,sha256=kDmTcjKcSu_fgM9-kyTcZpmchxotX9-p-WJKlEuhn00,1016
|
|
116
|
+
harness/schemas/policy.py,sha256=9wAQBjtuYupWDei2DtRxQs-T-UY5rN99FES0tDu2xzE,767
|
|
117
|
+
harness/schemas/run.py,sha256=oY3syF3F7UqVfz3Rqe4FWE1tTAwS0y0-iVMb8yhIhKc,3988
|
|
118
|
+
harness/schemas/session.py,sha256=-X0dI1WaerCRgEflY1mV0Y2jmMoHmsh0jBDRaHJeH58,2307
|
|
119
|
+
harness/schemas/task.py,sha256=Wrq1cFOU0QTPNVSaFeOcENHHUeegwYVkoB5aymiIb2c,522
|
|
120
|
+
harness/security/__init__.py,sha256=MAJlj1qcf2sbizh2fvOmkmVpJBySGO7Wb7N52U4rK4M,255
|
|
121
|
+
harness/security/approval_policy.py,sha256=l1lY7qjN16vEAnoAFS9IpuYi_64_4IXbpUuq425cL08,4100
|
|
122
|
+
harness/security/auth.py,sha256=spB64o0GLx6FMtT69E2hN4E1sTRgBQlvbIfj8slKNpw,3825
|
|
123
|
+
harness/security/permissions.py,sha256=HPwVvMe65m9IW5P0QzdqoOZ8toHZzpim8--pOUiUJX8,2169
|
|
124
|
+
harness/security/risk.py,sha256=4_ihRIt-fiYpixiQCSWGtLibDRPlFgyAtR0KMyub_vI,2058
|
|
125
|
+
harness/security/secrets.py,sha256=zH89znNizPU9zk0f44PY996naaw0TdPFTBVLNbUewqw,1638
|
|
126
|
+
harness/services/__init__.py,sha256=xEZgBBUOES34DrFkYdPLrwasLa9NX-W1lRxh6hu2iDI,80
|
|
127
|
+
harness/services/adapters_health.py,sha256=v7J_O8no-tO8wAnijuAsYprk3vgjQ-yOj7P4VbZMLGE,8424
|
|
128
|
+
harness/services/approvals.py,sha256=wbwE7OfRE8Hw7Nslc9qAmsMc9xuDbZGVwZBfyzvzZNU,2426
|
|
129
|
+
harness/services/artifacts.py,sha256=ud76kbktnZ5e2dIwvQHRaMheWPtx-MrlbzSAson4lBw,3307
|
|
130
|
+
harness/services/attachments.py,sha256=Fzw2nJ6GrADP7ami_qpopdzhA_pFiSVG17qAuvFMQxk,8332
|
|
131
|
+
harness/services/comparison.py,sha256=mvZT_WtKEi353ICLgkm1tDL1Ybodq55pohWj2OUaNpI,12110
|
|
132
|
+
harness/services/doctor.py,sha256=dwFHrjObB687sIXfjvkkJqs1OXdUYAZXUTOOScFYdMo,5751
|
|
133
|
+
harness/services/files.py,sha256=xA03L05_8ZTNzaKBVtPmpwm3iCnlTzQTkLz0XIXpIE8,12372
|
|
134
|
+
harness/services/mcp_servers.py,sha256=UY2L6p07CkaCT2cA2pM2bPGGW5WIaI69z9OF96OiMnQ,7353
|
|
135
|
+
harness/services/project_git.py,sha256=T332U4cygbtCeXZiC5CS0NYMtvlwEPQxc1DTNWMaNjg,4289
|
|
136
|
+
harness/services/retention.py,sha256=uUGZzwN62ADy5WykGxtFZ0Lkl6-ig2_U4d9kSMvXwrg,3148
|
|
137
|
+
harness/services/runs.py,sha256=157W99csIAXc_sxUhsotsc8hGLloXLuKgmBaebF_9yY,6918
|
|
138
|
+
harness/services/runs_diff.py,sha256=ul8pzMdi5KKoZjTxIeXwr_WzKcYbvwrknsK_fIpYpUc,7983
|
|
139
|
+
harness/services/sessions.py,sha256=iTrJZrk4e7VcgSL7L23EoOtVQ0QG6WL1t0Jd1IPOxc8,9021
|
|
140
|
+
harness/services/ssh.py,sha256=LAAgKxAv4v8zk2o4kS9PHGN4sLNbq80a-1cj-f8VsdM,11416
|
|
141
|
+
harness/services/stats.py,sha256=ItXDnu7HN3t_7Ck3EEBwojS9n-qYcYoTR1IP0SbItoo,4321
|
|
142
|
+
harness/services/tasks.py,sha256=xT_iHQvh50r40sJF2oWYiD5C4BRWG3QUYJL9kae2Kt4,1293
|
|
143
|
+
harness/services/workspaces.py,sha256=IbLAbC4Xl0v17uOIn80QM02UT5l5hQiEOyvPOCYpxks,8095
|
|
144
|
+
harness/services/worktrees.py,sha256=BIoPNgwKJ_PeGX4eMK-jdOSriYRxXVmOwcgxsjoYuF4,18051
|
|
145
|
+
harness/skills/__init__.py,sha256=IxxsbP29LrGFrTxPJOZkjm9Ybt17cOakuwTyVhzjNqw,303
|
|
146
|
+
harness/skills/manager.py,sha256=rKsW9RTrZRq2DOXfHPUJ6qRlcgje6tUUSNFp-DGVvS4,5101
|
|
147
|
+
harness/tools/__init__.py,sha256=bmPE6AMB1fDv70WRlGb9YKPcS-EOSh7vMWrJQKqyNYo,74
|
|
148
|
+
harness/tools/fs_tools.py,sha256=Hve5chc-Hvs644E7TKGFfl5e1dJLG-B0TEZ3VRQtgR4,12309
|
|
149
|
+
harness/workers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
150
|
+
harness/workers/dispatch.py,sha256=NaGM-aqwqEW8D88ANtZG-XKDwCmyycwSlm8Wf5Z6j-4,794
|
|
151
|
+
harness/workers/inprocess.py,sha256=Gjg4tjsSSH950qkBE5zoriG-BpgJJgU2txoDHxmc8PU,5834
|
|
152
|
+
ags_cli-0.1.0.dist-info/METADATA,sha256=-SQcIq-C5RokRzgDK-spYuY8Z7bLVFUWwiTi7Gd7h24,12681
|
|
153
|
+
ags_cli-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
154
|
+
ags_cli-0.1.0.dist-info/entry_points.txt,sha256=r19gV57ahT3XT9AxRtxYFwsCnDZHTL0YxtMR9xp_Gjw,38
|
|
155
|
+
ags_cli-0.1.0.dist-info/top_level.txt,sha256=o1Col3u-amx5Ry6wEbAkJzb39qDlYn38y_kGECKVvbg,12
|
|
156
|
+
ags_cli-0.1.0.dist-info/RECORD,,
|
cli/__init__.py
ADDED
|
File without changes
|
cli/__main__.py
ADDED
cli/client.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Thin synchronous HTTP client to the AgentS API used by all CLI commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
# `ags serve` (via cli.local._write_api_url, on auto-start or explicit launch)
|
|
14
|
+
# records the live API URL here so `ags` works in any terminal without
|
|
15
|
+
# exporting env vars.
|
|
16
|
+
_API_URL_FILE = Path.home() / ".ags" / "api_url"
|
|
17
|
+
|
|
18
|
+
# Inline agent runs (agy reading a whole repo, a slow local LLM) can take many
|
|
19
|
+
# minutes, so the read timeout is generous; connect stays short so a down API
|
|
20
|
+
# fails fast with a clear message instead of hanging. Override with HARNESS_API_TIMEOUT.
|
|
21
|
+
_READ_TIMEOUT = float(os.environ.get("HARNESS_API_TIMEOUT", "1800")) # 30 min
|
|
22
|
+
_LONG = httpx.Timeout(connect=5.0, read=_READ_TIMEOUT, write=30.0, pool=5.0)
|
|
23
|
+
_SHORT = httpx.Timeout(connect=5.0, read=30.0, write=30.0, pool=5.0)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _default_base_url() -> str:
|
|
27
|
+
if env := os.environ.get("HARNESS_API_BASE_URL"):
|
|
28
|
+
return env
|
|
29
|
+
# Find or auto-spawn the daemonless `ags serve` server.
|
|
30
|
+
try:
|
|
31
|
+
from cli.local import LOCAL_BASE_URL, ensure_local_server
|
|
32
|
+
|
|
33
|
+
if url := ensure_local_server():
|
|
34
|
+
return url
|
|
35
|
+
return LOCAL_BASE_URL
|
|
36
|
+
except Exception: # noqa: BLE001 - fall back to recorded URL / default below
|
|
37
|
+
pass
|
|
38
|
+
if _API_URL_FILE.exists() and (url := _API_URL_FILE.read_text().strip()):
|
|
39
|
+
return url
|
|
40
|
+
return "http://localhost:8000"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class APIError(RuntimeError):
|
|
44
|
+
"""A user-facing API/transport failure — carries a clean message, no traceback.
|
|
45
|
+
Caught centrally in ``cli.main.main`` so commands never dump httpx internals."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class HarnessClient:
|
|
49
|
+
def __init__(self, base_url: str | None = None, token: str | None = None) -> None:
|
|
50
|
+
self.base_url = (base_url or _default_base_url()).rstrip("/")
|
|
51
|
+
self.token = token or os.environ.get("HARNESS_API_TOKEN")
|
|
52
|
+
|
|
53
|
+
def _headers(self) -> dict[str, str]:
|
|
54
|
+
return {"Authorization": f"Bearer {self.token}"} if self.token else {}
|
|
55
|
+
|
|
56
|
+
def _url(self, path: str) -> str:
|
|
57
|
+
return f"{self.base_url}/api/v1{path}"
|
|
58
|
+
|
|
59
|
+
def _send(self, method: str, path: str, *, timeout, **kw: Any) -> Any:
|
|
60
|
+
try:
|
|
61
|
+
r = httpx.request(
|
|
62
|
+
method, self._url(path), headers=self._headers(), timeout=timeout, **kw
|
|
63
|
+
)
|
|
64
|
+
r.raise_for_status()
|
|
65
|
+
return r.json()
|
|
66
|
+
except httpx.ConnectError as exc:
|
|
67
|
+
raise APIError(
|
|
68
|
+
f"Can't reach the AgentS API at {self.base_url}.\n"
|
|
69
|
+
f"Is it running? Start it with: ags serve"
|
|
70
|
+
) from exc
|
|
71
|
+
except httpx.ReadTimeout as exc:
|
|
72
|
+
raise APIError(
|
|
73
|
+
f"The run is taking longer than {int(_READ_TIMEOUT)}s on the client side. "
|
|
74
|
+
"It may still be completing on the server — check `ags session list` "
|
|
75
|
+
"in a moment, or raise the limit with HARNESS_API_TIMEOUT."
|
|
76
|
+
) from exc
|
|
77
|
+
except httpx.HTTPStatusError as exc:
|
|
78
|
+
detail = ""
|
|
79
|
+
try:
|
|
80
|
+
detail = exc.response.json().get("detail", "")
|
|
81
|
+
except Exception: # noqa: BLE001
|
|
82
|
+
detail = exc.response.text[:300]
|
|
83
|
+
raise APIError(f"API error {exc.response.status_code}: {detail}") from exc
|
|
84
|
+
except httpx.HTTPError as exc:
|
|
85
|
+
raise APIError(f"Request failed: {exc}") from exc
|
|
86
|
+
|
|
87
|
+
def get(self, path: str, **params: Any) -> Any:
|
|
88
|
+
return self._send("GET", path, params=params, timeout=_SHORT)
|
|
89
|
+
|
|
90
|
+
def post(self, path: str, json: Any = None, **params: Any) -> Any:
|
|
91
|
+
# POSTs drive runs (inline can be slow) -> long read timeout.
|
|
92
|
+
return self._send("POST", path, json=json, params=params, timeout=_LONG)
|
|
93
|
+
|
|
94
|
+
def put(self, path: str, json: Any = None, **params: Any) -> Any:
|
|
95
|
+
return self._send("PUT", path, json=json, params=params, timeout=_SHORT)
|
|
96
|
+
|
|
97
|
+
def delete(self, path: str, **params: Any) -> Any:
|
|
98
|
+
return self._send("DELETE", path, params=params, timeout=_SHORT)
|
|
99
|
+
|
|
100
|
+
def _stream_once(self, run_id: str, *, after_seq: int, timeout_s: int):
|
|
101
|
+
"""Open one SSE connection and yield raw data-frame strings; stop on event:end."""
|
|
102
|
+
sse_timeout = httpx.Timeout(connect=5.0, read=timeout_s + 30, write=30.0, pool=5.0)
|
|
103
|
+
with httpx.stream(
|
|
104
|
+
"GET", self._url(f"/stream/{run_id}"),
|
|
105
|
+
params={"timeout_s": timeout_s, "after_seq": after_seq},
|
|
106
|
+
headers=self._headers(),
|
|
107
|
+
timeout=sse_timeout,
|
|
108
|
+
) as r:
|
|
109
|
+
# Buffer across raw byte chunks so we can detect the end-of-frame marker
|
|
110
|
+
# and the special "event: end" event type before yielding.
|
|
111
|
+
pending_event: list[str] = []
|
|
112
|
+
for line in r.iter_lines():
|
|
113
|
+
if line == "":
|
|
114
|
+
# Blank line = end of one SSE event block
|
|
115
|
+
event_lines = pending_event
|
|
116
|
+
pending_event = []
|
|
117
|
+
is_end = any(l == "event: end" for l in event_lines)
|
|
118
|
+
if is_end:
|
|
119
|
+
return
|
|
120
|
+
for l in event_lines:
|
|
121
|
+
if l.startswith("data:"):
|
|
122
|
+
yield l[len("data:"):].strip()
|
|
123
|
+
else:
|
|
124
|
+
pending_event.append(line)
|
|
125
|
+
|
|
126
|
+
def stream(self, run_id: str, timeout_s: int = 600):
|
|
127
|
+
"""Yield SSE data frames for a run, reconnecting up to 3 times on transport errors.
|
|
128
|
+
|
|
129
|
+
Reconnect counter is 3 for the stream's lifetime (deliberate — a persistently
|
|
130
|
+
broken connection should surface as an error, not loop forever).
|
|
131
|
+
httpx.RemoteProtocolError is a TransportError subclass and is therefore covered.
|
|
132
|
+
"""
|
|
133
|
+
last_seq, attempts = -1, 0 # -1 = nothing seen yet; seq=0 user event must not be skipped
|
|
134
|
+
while True:
|
|
135
|
+
try:
|
|
136
|
+
for frame in self._stream_once(run_id, after_seq=last_seq, timeout_s=timeout_s):
|
|
137
|
+
ev = json.loads(frame)
|
|
138
|
+
last_seq = max(last_seq, int(ev.get("seq", last_seq)))
|
|
139
|
+
yield frame
|
|
140
|
+
return # clean end (event: end received)
|
|
141
|
+
except httpx.TransportError:
|
|
142
|
+
attempts += 1
|
|
143
|
+
if attempts > 3:
|
|
144
|
+
raise APIError("stream dropped and could not reconnect")
|
|
145
|
+
time.sleep(0.5 * attempts) # linear backoff: 0.5 s × attempt
|
cli/commands/__init__.py
ADDED
|
File without changes
|