zwarm 3.2.1__py3-none-any.whl → 3.6.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.
- zwarm/cli/interactive.py +346 -30
- zwarm/cli/main.py +221 -90
- zwarm/cli/pilot.py +107 -9
- zwarm/core/config.py +26 -9
- zwarm/core/costs.py +55 -183
- zwarm/core/registry.py +329 -0
- zwarm/core/test_config.py +2 -3
- zwarm/orchestrator.py +17 -43
- zwarm/sessions/__init__.py +48 -9
- zwarm/sessions/base.py +501 -0
- zwarm/sessions/claude.py +481 -0
- zwarm/sessions/manager.py +233 -486
- zwarm/tools/delegation.py +93 -31
- {zwarm-3.2.1.dist-info → zwarm-3.6.0.dist-info}/METADATA +73 -21
- {zwarm-3.2.1.dist-info → zwarm-3.6.0.dist-info}/RECORD +17 -21
- zwarm/adapters/__init__.py +0 -21
- zwarm/adapters/base.py +0 -109
- zwarm/adapters/claude_code.py +0 -357
- zwarm/adapters/codex_mcp.py +0 -1262
- zwarm/adapters/registry.py +0 -69
- zwarm/adapters/test_codex_mcp.py +0 -274
- zwarm/adapters/test_registry.py +0 -68
- {zwarm-3.2.1.dist-info → zwarm-3.6.0.dist-info}/WHEEL +0 -0
- {zwarm-3.2.1.dist-info → zwarm-3.6.0.dist-info}/entry_points.txt +0 -0
zwarm/tools/delegation.py
CHANGED
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
Delegation tools for the orchestrator.
|
|
3
3
|
|
|
4
4
|
These are the core tools that orchestrators use to delegate work to executors.
|
|
5
|
-
They use the
|
|
5
|
+
They use the same session managers that `zwarm interactive` uses - no special
|
|
6
6
|
MCP integration, no separate code path.
|
|
7
7
|
|
|
8
8
|
The orchestrator LLM has access to the exact same tools a human would use.
|
|
9
9
|
|
|
10
|
+
Supports multiple adapters:
|
|
11
|
+
- codex: OpenAI's Codex CLI (default)
|
|
12
|
+
- claude: Anthropic's Claude Code CLI
|
|
13
|
+
|
|
10
14
|
Tools:
|
|
11
|
-
- delegate: Start a new
|
|
15
|
+
- delegate: Start a new session (with adapter selection)
|
|
12
16
|
- converse: Continue a conversation (inject follow-up message)
|
|
13
17
|
- check_session: Check status of a session
|
|
14
18
|
- end_session: End/kill a session
|
|
@@ -26,24 +30,53 @@ from wbal.helper import weaveTool
|
|
|
26
30
|
if TYPE_CHECKING:
|
|
27
31
|
from zwarm.orchestrator import Orchestrator
|
|
28
32
|
|
|
33
|
+
# Available adapters
|
|
34
|
+
ADAPTERS = ["codex", "claude"]
|
|
35
|
+
|
|
29
36
|
|
|
30
37
|
def _get_session_manager(orchestrator: "Orchestrator"):
|
|
31
38
|
"""
|
|
32
|
-
Get the
|
|
39
|
+
Get the default session manager for list/get operations.
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
The session manager is created eagerly in Orchestrator.model_post_init()
|
|
38
|
-
and shared with the environment for observe() visibility.
|
|
41
|
+
Uses CodexSessionManager as the default since all adapters share
|
|
42
|
+
the same .zwarm/sessions/ directory structure.
|
|
39
43
|
"""
|
|
40
|
-
# Should already exist from model_post_init, but create if not
|
|
41
44
|
if not hasattr(orchestrator, "_session_manager") or orchestrator._session_manager is None:
|
|
42
45
|
from zwarm.sessions import CodexSessionManager
|
|
43
46
|
orchestrator._session_manager = CodexSessionManager(orchestrator.working_dir / ".zwarm")
|
|
44
47
|
return orchestrator._session_manager
|
|
45
48
|
|
|
46
49
|
|
|
50
|
+
def _get_adapter_manager(orchestrator: "Orchestrator", adapter: str):
|
|
51
|
+
"""
|
|
52
|
+
Get the session manager for a specific adapter.
|
|
53
|
+
|
|
54
|
+
Each adapter has its own manager for start_session/inject_message,
|
|
55
|
+
but they all share the same .zwarm/sessions/ directory.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
orchestrator: The orchestrator instance
|
|
59
|
+
adapter: Adapter name ("codex" or "claude")
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Session manager for the specified adapter
|
|
63
|
+
"""
|
|
64
|
+
# Initialize adapter managers dict if needed
|
|
65
|
+
if not hasattr(orchestrator, "_adapter_managers"):
|
|
66
|
+
orchestrator._adapter_managers = {}
|
|
67
|
+
|
|
68
|
+
# Return cached manager if exists
|
|
69
|
+
if adapter in orchestrator._adapter_managers:
|
|
70
|
+
return orchestrator._adapter_managers[adapter]
|
|
71
|
+
|
|
72
|
+
# Create new manager for this adapter
|
|
73
|
+
from zwarm.sessions import get_session_manager
|
|
74
|
+
manager = get_session_manager(adapter, str(orchestrator.working_dir / ".zwarm"))
|
|
75
|
+
orchestrator._adapter_managers[adapter] = manager
|
|
76
|
+
|
|
77
|
+
return manager
|
|
78
|
+
|
|
79
|
+
|
|
47
80
|
def _truncate(text: str, max_len: int = 200) -> str:
|
|
48
81
|
"""Truncate text with ellipsis."""
|
|
49
82
|
if len(text) <= max_len:
|
|
@@ -53,7 +86,8 @@ def _truncate(text: str, max_len: int = 200) -> str:
|
|
|
53
86
|
|
|
54
87
|
def _format_session_header(session) -> str:
|
|
55
88
|
"""Format a nice session header."""
|
|
56
|
-
|
|
89
|
+
adapter = getattr(session, "adapter", "codex")
|
|
90
|
+
return f"[{session.short_id}] {adapter} ({session.status.value})"
|
|
57
91
|
|
|
58
92
|
|
|
59
93
|
def _get_total_tokens(session) -> int:
|
|
@@ -129,11 +163,15 @@ def delegate(
|
|
|
129
163
|
task: str,
|
|
130
164
|
model: str | None = None,
|
|
131
165
|
working_dir: str | None = None,
|
|
166
|
+
adapter: str = "codex",
|
|
132
167
|
) -> dict[str, Any]:
|
|
133
168
|
"""
|
|
134
|
-
Delegate work to
|
|
169
|
+
Delegate work to an executor agent.
|
|
170
|
+
|
|
171
|
+
Supports multiple adapters:
|
|
172
|
+
- codex: OpenAI's Codex CLI (default, fast, good for code tasks)
|
|
173
|
+
- claude: Claude Code CLI (powerful, good for complex reasoning)
|
|
135
174
|
|
|
136
|
-
This spawns a codex session - the exact same way `zwarm interactive` does.
|
|
137
175
|
All sessions run async - you get a session_id immediately and poll for results.
|
|
138
176
|
|
|
139
177
|
Workflow pattern:
|
|
@@ -145,17 +183,27 @@ def delegate(
|
|
|
145
183
|
|
|
146
184
|
Args:
|
|
147
185
|
task: Clear description of what to do. Be specific about requirements.
|
|
148
|
-
model: Model override (
|
|
149
|
-
working_dir: Directory for
|
|
186
|
+
model: Model override (codex: gpt-5.1-codex-mini, claude: sonnet).
|
|
187
|
+
working_dir: Directory for executor to work in (default: orchestrator's dir).
|
|
188
|
+
adapter: Which executor to use - "codex" (default) or "claude".
|
|
150
189
|
|
|
151
190
|
Returns:
|
|
152
|
-
{session_id, status: "running", task, hint}
|
|
191
|
+
{session_id, status: "running", task, adapter, hint}
|
|
153
192
|
|
|
154
|
-
Example:
|
|
193
|
+
Example with codex (default):
|
|
155
194
|
delegate(task="Add a logout button to the navbar")
|
|
156
|
-
|
|
157
|
-
|
|
195
|
+
|
|
196
|
+
Example with claude for complex tasks:
|
|
197
|
+
delegate(task="Refactor the auth system to use OAuth2", adapter="claude")
|
|
158
198
|
"""
|
|
199
|
+
# Validate adapter
|
|
200
|
+
if adapter not in ADAPTERS:
|
|
201
|
+
return {
|
|
202
|
+
"success": False,
|
|
203
|
+
"error": f"Unknown adapter: {adapter}. Available: {ADAPTERS}",
|
|
204
|
+
"hint": f"Use one of: {ADAPTERS}",
|
|
205
|
+
}
|
|
206
|
+
|
|
159
207
|
# Validate working directory
|
|
160
208
|
effective_dir, dir_error = _validate_working_dir(
|
|
161
209
|
working_dir,
|
|
@@ -170,24 +218,28 @@ def delegate(
|
|
|
170
218
|
"hint": "Use the default working directory or ask user to update allowed_dirs config",
|
|
171
219
|
}
|
|
172
220
|
|
|
173
|
-
# Get the session manager
|
|
174
|
-
manager =
|
|
221
|
+
# Get the session manager for this adapter
|
|
222
|
+
manager = _get_adapter_manager(self, adapter)
|
|
175
223
|
|
|
176
|
-
# Determine model
|
|
177
|
-
|
|
224
|
+
# Determine model (defaults vary by adapter)
|
|
225
|
+
if model:
|
|
226
|
+
effective_model = model
|
|
227
|
+
elif self.config.executor.model:
|
|
228
|
+
effective_model = self.config.executor.model
|
|
229
|
+
else:
|
|
230
|
+
# Use adapter-specific defaults
|
|
231
|
+
effective_model = manager.default_model
|
|
178
232
|
|
|
179
233
|
# Determine sandbox mode
|
|
180
234
|
sandbox = self.config.executor.sandbox or "workspace-write"
|
|
181
235
|
|
|
182
|
-
# Start the session
|
|
183
|
-
# This is the SAME method that `zwarm interactive` uses
|
|
236
|
+
# Start the session
|
|
184
237
|
session = manager.start_session(
|
|
185
238
|
task=task,
|
|
186
239
|
working_dir=effective_dir,
|
|
187
240
|
model=effective_model,
|
|
188
241
|
sandbox=sandbox,
|
|
189
242
|
source=f"orchestrator:{self.instance_id or 'default'}",
|
|
190
|
-
adapter="codex",
|
|
191
243
|
)
|
|
192
244
|
|
|
193
245
|
# Return immediately - session runs in background
|
|
@@ -197,6 +249,8 @@ def delegate(
|
|
|
197
249
|
"session_id": session.id,
|
|
198
250
|
"status": "running",
|
|
199
251
|
"task": _truncate(task, 100),
|
|
252
|
+
"adapter": adapter,
|
|
253
|
+
"model": effective_model,
|
|
200
254
|
"hint": "Use sleep() then check_session(session_id) to monitor progress",
|
|
201
255
|
}
|
|
202
256
|
|
|
@@ -208,15 +262,18 @@ def converse(
|
|
|
208
262
|
message: str,
|
|
209
263
|
) -> dict[str, Any]:
|
|
210
264
|
"""
|
|
211
|
-
Continue a conversation with a
|
|
265
|
+
Continue a conversation with a session.
|
|
212
266
|
|
|
213
267
|
This injects a follow-up message into the session, providing the
|
|
214
268
|
conversation history as context. Like chatting with a developer.
|
|
215
269
|
Returns immediately - use sleep() + check_session() to poll for the response.
|
|
216
270
|
|
|
271
|
+
Works with any adapter (codex or claude) - automatically uses the
|
|
272
|
+
correct adapter based on the session's original adapter.
|
|
273
|
+
|
|
217
274
|
Args:
|
|
218
275
|
session_id: The session to continue (from delegate() result).
|
|
219
|
-
message: Your next message
|
|
276
|
+
message: Your next message.
|
|
220
277
|
|
|
221
278
|
Returns:
|
|
222
279
|
{session_id, turn, status: "running"}
|
|
@@ -226,10 +283,10 @@ def converse(
|
|
|
226
283
|
sleep(30)
|
|
227
284
|
check_session(session_id) # Get response
|
|
228
285
|
"""
|
|
229
|
-
|
|
286
|
+
# First get session to determine adapter
|
|
287
|
+
default_manager = _get_session_manager(self)
|
|
288
|
+
session = default_manager.get_session(session_id)
|
|
230
289
|
|
|
231
|
-
# Get current session
|
|
232
|
-
session = manager.get_session(session_id)
|
|
233
290
|
if not session:
|
|
234
291
|
return {
|
|
235
292
|
"success": False,
|
|
@@ -253,8 +310,12 @@ def converse(
|
|
|
253
310
|
"hint": "Start a new session with delegate()",
|
|
254
311
|
}
|
|
255
312
|
|
|
313
|
+
# Get the correct adapter manager for this session
|
|
314
|
+
adapter = getattr(session, "adapter", "codex")
|
|
315
|
+
manager = _get_adapter_manager(self, adapter)
|
|
316
|
+
|
|
256
317
|
# Inject the follow-up message
|
|
257
|
-
# This uses
|
|
318
|
+
# This uses the adapter's inject_message() which:
|
|
258
319
|
# 1. Builds context from previous messages
|
|
259
320
|
# 2. Starts a new turn with the context + new message (background process)
|
|
260
321
|
updated_session = manager.inject_message(session_id, message)
|
|
@@ -273,6 +334,7 @@ def converse(
|
|
|
273
334
|
"session_id": session_id,
|
|
274
335
|
"turn": updated_session.turn,
|
|
275
336
|
"status": "running",
|
|
337
|
+
"adapter": adapter,
|
|
276
338
|
"you_said": _truncate(message, 100),
|
|
277
339
|
"hint": "Use sleep() then check_session(session_id) to see the response",
|
|
278
340
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zwarm
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.0
|
|
4
4
|
Summary: Multi-Agent CLI Orchestration Research Platform
|
|
5
5
|
Requires-Python: <3.14,>=3.13
|
|
6
6
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
@@ -13,26 +13,30 @@ Description-Content-Type: text/markdown
|
|
|
13
13
|
|
|
14
14
|
# zwarm
|
|
15
15
|
|
|
16
|
-
Multi-agent CLI for orchestrating coding agents. Spawn, manage, and converse with multiple
|
|
16
|
+
Multi-agent CLI for orchestrating coding agents. Spawn, manage, and converse with multiple coding agent sessions in parallel.
|
|
17
|
+
|
|
18
|
+
**Supports both [Codex CLI](https://github.com/openai/codex) and [Claude Code CLI](https://claude.com/claude-code).**
|
|
17
19
|
|
|
18
20
|
## Installation
|
|
19
21
|
|
|
20
22
|
```bash
|
|
21
|
-
# From
|
|
22
|
-
|
|
23
|
-
uv sync
|
|
23
|
+
# From PyPI
|
|
24
|
+
pip install zwarm
|
|
24
25
|
|
|
25
|
-
# Or
|
|
26
|
-
uv pip install
|
|
26
|
+
# Or with uv
|
|
27
|
+
uv pip install zwarm
|
|
27
28
|
```
|
|
28
29
|
|
|
29
30
|
**Requirements:**
|
|
30
31
|
- Python 3.13+
|
|
31
|
-
-
|
|
32
|
+
- At least one of:
|
|
33
|
+
- `codex` CLI installed and authenticated (OpenAI)
|
|
34
|
+
- `claude` CLI installed and authenticated (Anthropic)
|
|
32
35
|
|
|
33
36
|
**Environment:**
|
|
34
37
|
```bash
|
|
35
38
|
export OPENAI_API_KEY="sk-..." # Required for Codex
|
|
39
|
+
export ANTHROPIC_API_KEY="sk-..." # Required for Claude
|
|
36
40
|
export WEAVE_PROJECT="entity/zwarm" # Optional: Weave tracing
|
|
37
41
|
```
|
|
38
42
|
|
|
@@ -78,6 +82,19 @@ zwarm interactive
|
|
|
78
82
|
|
|
79
83
|
---
|
|
80
84
|
|
|
85
|
+
## Multi-Adapter Support
|
|
86
|
+
|
|
87
|
+
zwarm supports multiple executor backends:
|
|
88
|
+
|
|
89
|
+
| Adapter | CLI | Models | Config |
|
|
90
|
+
|---------|-----|--------|--------|
|
|
91
|
+
| **Codex** | `codex` | gpt-5.1-codex-mini, etc. | `.zwarm/codex.toml` |
|
|
92
|
+
| **Claude** | `claude` | sonnet, opus, haiku | `.zwarm/claude.toml` |
|
|
93
|
+
|
|
94
|
+
You can mix adapters in the same session - for example, use Claude Opus for complex reasoning tasks and Codex Mini for quick edits.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
81
98
|
## Pilot Mode
|
|
82
99
|
|
|
83
100
|
**You chat with an LLM that delegates to coding agents.** Best of both worlds - LLM intelligence with human oversight.
|
|
@@ -85,12 +102,14 @@ zwarm interactive
|
|
|
85
102
|
```bash
|
|
86
103
|
zwarm pilot
|
|
87
104
|
zwarm pilot --task "Add user authentication"
|
|
105
|
+
zwarm pilot --resume # Resume previous session
|
|
88
106
|
```
|
|
89
107
|
|
|
90
108
|
### Features
|
|
91
109
|
|
|
92
110
|
- **Conversational**: Chat naturally, the LLM handles delegation
|
|
93
111
|
- **Checkpoints**: Every turn is saved, time-travel with `:goto`
|
|
112
|
+
- **Resume**: Continue where you left off with `--resume`
|
|
94
113
|
- **Multiline input**: Use `"""` for pasting large prompts
|
|
95
114
|
- **Status bar**: See token usage, cost estimates, context window
|
|
96
115
|
|
|
@@ -103,7 +122,8 @@ zwarm pilot --task "Add user authentication"
|
|
|
103
122
|
| `:history` | Show turn checkpoints |
|
|
104
123
|
| `:goto T3` | Jump back to turn 3 |
|
|
105
124
|
| `:sessions` | List executor sessions |
|
|
106
|
-
| `:
|
|
125
|
+
| `:save` | Save current state |
|
|
126
|
+
| `:quit` | Exit (auto-saves) |
|
|
107
127
|
|
|
108
128
|
### Example
|
|
109
129
|
|
|
@@ -161,8 +181,8 @@ zwarm interactive
|
|
|
161
181
|
|
|
162
182
|
| Command | Description |
|
|
163
183
|
|---------|-------------|
|
|
164
|
-
| `spawn "task"` | Start a new session |
|
|
165
|
-
| `ls` | Dashboard of all sessions (with costs) |
|
|
184
|
+
| `spawn "task" [--search]` | Start a new session (--search enables web) |
|
|
185
|
+
| `ls` | Dashboard of all sessions (with costs, models) |
|
|
166
186
|
| `? ID` / `peek ID` | Quick status check |
|
|
167
187
|
| `show ID` | Full session details |
|
|
168
188
|
| `traj ID` | Show trajectory (steps taken) |
|
|
@@ -170,6 +190,7 @@ zwarm interactive
|
|
|
170
190
|
| `c ID "msg"` | Continue conversation |
|
|
171
191
|
| `kill ID \| all` | Stop session(s) |
|
|
172
192
|
| `rm ID \| all` | Delete session(s) |
|
|
193
|
+
| `!command` | Run shell command (e.g., `!git status`) |
|
|
173
194
|
| `help` | Show all commands |
|
|
174
195
|
| `quit` | Exit |
|
|
175
196
|
|
|
@@ -188,9 +209,9 @@ $ zwarm interactive
|
|
|
188
209
|
> ls
|
|
189
210
|
⟳ 2 running
|
|
190
211
|
|
|
191
|
-
ID │ │ Task │ Tokens │ Cost
|
|
192
|
-
abc123 │ ⟳ │ Add tests for the auth... │ 5,234 │ $0.052
|
|
193
|
-
def456 │ ⟳ │ Fix type errors in utils... │ 2,100 │ $0.021
|
|
212
|
+
ID │ │ Task │ Model │ Tokens │ Cost
|
|
213
|
+
abc123 │ ⟳ │ Add tests for the auth... │ codex-mini │ 5,234 │ $0.052
|
|
214
|
+
def456 │ ⟳ │ Fix type errors in utils... │ codex-mini │ 2,100 │ $0.021
|
|
194
215
|
|
|
195
216
|
> watch abc123
|
|
196
217
|
Watching abc123... (Ctrl+C to stop)
|
|
@@ -201,6 +222,11 @@ Watching abc123... (Ctrl+C to stop)
|
|
|
201
222
|
> c abc123 "Also add edge case tests"
|
|
202
223
|
✓ Injected message, session running
|
|
203
224
|
|
|
225
|
+
> !git status
|
|
226
|
+
On branch main
|
|
227
|
+
Changes not staged for commit:
|
|
228
|
+
...
|
|
229
|
+
|
|
204
230
|
> kill all
|
|
205
231
|
✓ Killed abc123
|
|
206
232
|
✓ Killed def456
|
|
@@ -225,7 +251,7 @@ The orchestrator LLM has access to:
|
|
|
225
251
|
|
|
226
252
|
| Tool | Description |
|
|
227
253
|
|------|-------------|
|
|
228
|
-
| `delegate(task)` | Start a new coding session |
|
|
254
|
+
| `delegate(task, adapter="codex")` | Start a new coding session |
|
|
229
255
|
| `converse(id, msg)` | Continue a session |
|
|
230
256
|
| `check_session(id)` | Get full session details |
|
|
231
257
|
| `peek_session(id)` | Quick status check |
|
|
@@ -235,6 +261,10 @@ The orchestrator LLM has access to:
|
|
|
235
261
|
|
|
236
262
|
**Async-first**: All sessions run in the background. The orchestrator uses `sleep()` to wait, then checks on progress.
|
|
237
263
|
|
|
264
|
+
**Multi-adapter**: Pass `adapter="claude"` or `adapter="codex"` to `delegate()` to choose the backend.
|
|
265
|
+
|
|
266
|
+
**Web Search**: Enable `web_search=True` in config for tasks needing current info (API docs, latest releases, etc.).
|
|
267
|
+
|
|
238
268
|
### Watchers
|
|
239
269
|
|
|
240
270
|
Watchers monitor the orchestrator and intervene when needed:
|
|
@@ -283,9 +313,9 @@ spawn → running → completed/failed/killed
|
|
|
283
313
|
|
|
284
314
|
```
|
|
285
315
|
.zwarm/sessions/<uuid>/
|
|
286
|
-
├── meta.json # Status, task, model, tokens, cost
|
|
316
|
+
├── meta.json # Status, task, model, adapter, tokens, cost
|
|
287
317
|
└── turns/
|
|
288
|
-
├── turn_1.jsonl # Raw
|
|
318
|
+
├── turn_1.jsonl # Raw executor output for turn 1
|
|
289
319
|
├── turn_2.jsonl # Output after continue
|
|
290
320
|
└── ...
|
|
291
321
|
```
|
|
@@ -303,6 +333,7 @@ zwarm init
|
|
|
303
333
|
This creates:
|
|
304
334
|
- `.zwarm/config.toml` - Runtime settings (Weave, watchers)
|
|
305
335
|
- `.zwarm/codex.toml` - Codex CLI settings (model, reasoning)
|
|
336
|
+
- `.zwarm/claude.toml` - Claude CLI settings (model, permissions)
|
|
306
337
|
- `zwarm.yaml` - Project context (optional, with `--with-project`)
|
|
307
338
|
|
|
308
339
|
### Config Files
|
|
@@ -316,7 +347,10 @@ project = "your-entity/zwarm"
|
|
|
316
347
|
max_steps = 50
|
|
317
348
|
|
|
318
349
|
[executor]
|
|
319
|
-
|
|
350
|
+
web_search = false # Enable web search for all delegated sessions
|
|
351
|
+
|
|
352
|
+
[pilot]
|
|
353
|
+
max_steps_per_turn = 25
|
|
320
354
|
|
|
321
355
|
[watchers]
|
|
322
356
|
enabled = ["progress", "budget", "delegation", "delegation_reminder"]
|
|
@@ -326,6 +360,13 @@ enabled = ["progress", "budget", "delegation", "delegation_reminder"]
|
|
|
326
360
|
```toml
|
|
327
361
|
model = "gpt-5.1-codex-mini"
|
|
328
362
|
model_reasoning_effort = "high" # low | medium | high
|
|
363
|
+
full_auto = true
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**`.zwarm/claude.toml`** - Controls the Claude Code CLI:
|
|
367
|
+
```toml
|
|
368
|
+
model = "sonnet" # sonnet | opus | haiku
|
|
369
|
+
full_danger = true # Skip permission prompts
|
|
329
370
|
```
|
|
330
371
|
|
|
331
372
|
**`zwarm.yaml`** - Project-specific context:
|
|
@@ -352,6 +393,7 @@ zwarm init --yes # Quick setup with defaults
|
|
|
352
393
|
|
|
353
394
|
# Interfaces
|
|
354
395
|
zwarm pilot # Conversational LLM guidance (recommended)
|
|
396
|
+
zwarm pilot --resume # Resume previous session
|
|
355
397
|
zwarm interactive # Direct session control REPL
|
|
356
398
|
zwarm orchestrate # Fully autonomous LLM
|
|
357
399
|
|
|
@@ -374,13 +416,15 @@ zwarm reset # Reset .zwarm/ state
|
|
|
374
416
|
zwarm/
|
|
375
417
|
├── src/zwarm/
|
|
376
418
|
│ ├── sessions/ # Session substrate
|
|
377
|
-
│ │
|
|
419
|
+
│ │ ├── base.py # BaseSessionManager (ABC)
|
|
420
|
+
│ │ ├── manager.py # CodexSessionManager
|
|
421
|
+
│ │ └── claude.py # ClaudeSessionManager
|
|
378
422
|
│ ├── cli/
|
|
379
423
|
│ │ ├── main.py # CLI commands
|
|
380
424
|
│ │ ├── pilot.py # Pilot REPL
|
|
381
425
|
│ │ └── interactive.py # Interactive REPL
|
|
382
426
|
│ ├── tools/
|
|
383
|
-
│ │ └── delegation.py # Orchestrator tools
|
|
427
|
+
│ │ └── delegation.py # Orchestrator tools (multi-adapter)
|
|
384
428
|
│ ├── core/
|
|
385
429
|
│ │ ├── config.py # Configuration
|
|
386
430
|
│ │ ├── checkpoints.py # Time-travel primitives
|
|
@@ -389,5 +433,13 @@ zwarm/
|
|
|
389
433
|
│ ├── watchers/ # Trajectory alignment
|
|
390
434
|
│ ├── prompts/ # System prompts
|
|
391
435
|
│ └── orchestrator.py # Orchestrator agent
|
|
392
|
-
└──
|
|
436
|
+
└── docs/
|
|
437
|
+
├── CONCEPTS.md # Architecture diagrams
|
|
438
|
+
└── INTERNALS.md # Developer documentation
|
|
393
439
|
```
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## License
|
|
444
|
+
|
|
445
|
+
MIT
|
|
@@ -1,35 +1,31 @@
|
|
|
1
1
|
zwarm/__init__.py,sha256=3i3LMjHwIzE-LFIS2aUrwv3EZmpkvVMe-xj1h97rcSM,837
|
|
2
|
-
zwarm/orchestrator.py,sha256=
|
|
2
|
+
zwarm/orchestrator.py,sha256=1IitiuhlCRGd512p3ObwiwI8c2zDzq1yzLTs_y6Mv_o,22803
|
|
3
3
|
zwarm/test_orchestrator_watchers.py,sha256=QpoaehPU7ekT4XshbTOWnJ2H0wRveV3QOZjxbgyJJLY,807
|
|
4
|
-
zwarm/adapters/__init__.py,sha256=O0b-SfZpb6txeNqFkXZ2aaf34yLFYreznyrAV25jF_Q,656
|
|
5
|
-
zwarm/adapters/base.py,sha256=fZlQviTgVvOcwnxduTla6WuM6FzQJ_yoHMW5SxwVgQg,2527
|
|
6
|
-
zwarm/adapters/claude_code.py,sha256=vAjsjD-_JjARmC4_FBSILQZmQCBrk_oNHo18a9ubuqk,11481
|
|
7
|
-
zwarm/adapters/codex_mcp.py,sha256=EhdkM3gj5hc01AcM1ERhtfZbydK390yN4Pg3dawKIGU,48791
|
|
8
|
-
zwarm/adapters/registry.py,sha256=EdyHECaNA5Kv1od64pYFBJyA_r_6I1r_eJTNP1XYLr4,1781
|
|
9
|
-
zwarm/adapters/test_codex_mcp.py,sha256=0qhVzxn_KF-XUS30gXSJKwMdR3kWGsDY9iPk1Ihqn3w,10698
|
|
10
|
-
zwarm/adapters/test_registry.py,sha256=otxcVDONwFCMisyANToF3iy7Y8dSbCL8bTmZNhxNuF4,2383
|
|
11
4
|
zwarm/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
zwarm/cli/interactive.py,sha256=
|
|
13
|
-
zwarm/cli/main.py,sha256=
|
|
14
|
-
zwarm/cli/pilot.py,sha256=
|
|
5
|
+
zwarm/cli/interactive.py,sha256=zNxaU7U3PwHyx04-aiGqxyxwCsKhX-0jG0tzMlvrV24,39031
|
|
6
|
+
zwarm/cli/main.py,sha256=vQGgbAkg_8ei5UTF-IvTtRv3Vxb85NNApVECwT1ghlg,77443
|
|
7
|
+
zwarm/cli/pilot.py,sha256=my0j6-YpWRTFZ8tMrsh2wtJ2n9BP58JokvP7K8ssl7Q,42403
|
|
15
8
|
zwarm/core/__init__.py,sha256=nEdpEHMFo0gEEKgX-eKHabyOdrOI6UXfWqLu3FfZDao,376
|
|
16
9
|
zwarm/core/checkpoints.py,sha256=D6sXCMB7Sa1kchQ9_lQx_rabwc5-_7jbuynWgA1nkNY,6560
|
|
17
10
|
zwarm/core/compact.py,sha256=Y8C7Gs-5-WOU43WRvQ863Qzd5xtuEqR6Aw3r2p8_-i8,10907
|
|
18
|
-
zwarm/core/config.py,sha256=
|
|
19
|
-
zwarm/core/costs.py,sha256=
|
|
11
|
+
zwarm/core/config.py,sha256=m3Vm6U_BNtEDu_cz2d6E3p_RNQfRHWaq-946mDru9-8,12656
|
|
12
|
+
zwarm/core/costs.py,sha256=Z-5o-ZQWRCfFv0mTHev4Ke1AzyXKhXWO6ss7S8eBX9U,1485
|
|
20
13
|
zwarm/core/environment.py,sha256=zrgh0N3Ng4HI2F1gCYkcQVGzjQPKiIFWuRe1OPRuRn0,6558
|
|
21
14
|
zwarm/core/models.py,sha256=PrC3okRBVJxISUa1Fax4KkagqLT6Xub-kTxC9drN0sY,10083
|
|
15
|
+
zwarm/core/registry.py,sha256=-3mwW4MZ8LKM9SuNBR-r5KWFcQx5F7gqnKfghikxzAI,9484
|
|
22
16
|
zwarm/core/state.py,sha256=MzrvODKEiJovI7YI1jajW4uukineZ3ezmW5oQinMgjg,11563
|
|
23
17
|
zwarm/core/test_compact.py,sha256=WSdjCB5t4YMcknsrkmJIUsVOPY28s4y9GnDmu3Z4BFw,11878
|
|
24
|
-
zwarm/core/test_config.py,sha256=
|
|
18
|
+
zwarm/core/test_config.py,sha256=bXXd3OHhK-ndC7wAxePWIdpu73s4O1eScxi3xDzrZwA,4828
|
|
25
19
|
zwarm/core/test_models.py,sha256=sWTIhMZvuLP5AooGR6y8OR2EyWydqVfhmGrE7NPBBnk,8450
|
|
26
20
|
zwarm/prompts/__init__.py,sha256=DI307o712F8qQyDt5vwnFgpVBrxpKwjhr0MaBHLzr9E,334
|
|
27
21
|
zwarm/prompts/orchestrator.py,sha256=AkVbEpT91QbYFjUYOzm0d37wXrpm0esLBD1MG_W-3FI,15367
|
|
28
22
|
zwarm/prompts/pilot.py,sha256=BcaV04-43FZyrtmoqCbA7DqnTlQ330TcDp9wNGhRojo,5586
|
|
29
|
-
zwarm/sessions/__init__.py,sha256=
|
|
30
|
-
zwarm/sessions/
|
|
23
|
+
zwarm/sessions/__init__.py,sha256=5fPkl6JRS_GwPn9hi5iv3dzIpGWu_yghPtvPZdujhnM,1728
|
|
24
|
+
zwarm/sessions/base.py,sha256=UA5E39xDx5q4qX2rUcvhSX7cfrCEqTS3F9Tj-ubmrJA,16538
|
|
25
|
+
zwarm/sessions/claude.py,sha256=hBP_TpNFJjR29IRGJFB3rlG7Z9uWEYSbBGV61tpIr00,16672
|
|
26
|
+
zwarm/sessions/manager.py,sha256=Vq5PePzKfy658EVG24SFsUMXQc1OGgOm8vdOX_WPMF8,18530
|
|
31
27
|
zwarm/tools/__init__.py,sha256=FpqxwXJA6-fQ7C-oLj30jjK_0qqcE7MbI0dQuaB56kU,290
|
|
32
|
-
zwarm/tools/delegation.py,sha256=
|
|
28
|
+
zwarm/tools/delegation.py,sha256=FM8CIqm3ic6mHjVmY1DkOpTdMIYi21TniMclhdtPRn4,23424
|
|
33
29
|
zwarm/watchers/__init__.py,sha256=a96s7X6ruYkF2ItWWOZ3Q5QUOMOoeCW4Vz8XXcYLXPM,956
|
|
34
30
|
zwarm/watchers/base.py,sha256=r1GoPlj06nOT2xp4fghfSjxbRyFFFQUB6HpZbEyO2OY,3834
|
|
35
31
|
zwarm/watchers/builtin.py,sha256=IL5QwwKOIqWEfJ_uQWb321Px4i5OLtI_vnWQMudqKoA,19064
|
|
@@ -37,7 +33,7 @@ zwarm/watchers/llm_watcher.py,sha256=yJGpE3BGKNZX3qgPsiNtJ5d3UJpiTT1V-A-Rh4AiMYM
|
|
|
37
33
|
zwarm/watchers/manager.py,sha256=XZjBVeHjgCUlkTUeHqdvBvHoBC862U1ik0fG6nlRGog,5587
|
|
38
34
|
zwarm/watchers/registry.py,sha256=A9iBIVIFNtO7KPX0kLpUaP8dAK7ozqWLA44ocJGnOw4,1219
|
|
39
35
|
zwarm/watchers/test_watchers.py,sha256=zOsxumBqKfR5ZVGxrNlxz6KcWjkcdp0QhW9WB0_20zM,7855
|
|
40
|
-
zwarm-3.
|
|
41
|
-
zwarm-3.
|
|
42
|
-
zwarm-3.
|
|
43
|
-
zwarm-3.
|
|
36
|
+
zwarm-3.6.0.dist-info/METADATA,sha256=5nkx2jC93DRcLohSvGdZk-W1XWeOc1DModIazvr0gwI,11311
|
|
37
|
+
zwarm-3.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
38
|
+
zwarm-3.6.0.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
|
|
39
|
+
zwarm-3.6.0.dist-info/RECORD,,
|
zwarm/adapters/__init__.py
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Adapters: Executor wrappers for CLI coding agents.
|
|
3
|
-
|
|
4
|
-
Adapters provide a unified interface to different coding CLIs (Codex, Claude Code).
|
|
5
|
-
Use the registry to discover and instantiate adapters by name.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from zwarm.adapters.base import ExecutorAdapter
|
|
9
|
-
from zwarm.adapters.registry import register_adapter, get_adapter, list_adapters, adapter_exists
|
|
10
|
-
|
|
11
|
-
# Import built-in adapters to register them
|
|
12
|
-
from zwarm.adapters import codex_mcp as _codex_mcp # noqa: F401
|
|
13
|
-
from zwarm.adapters import claude_code as _claude_code # noqa: F401
|
|
14
|
-
|
|
15
|
-
__all__ = [
|
|
16
|
-
"ExecutorAdapter",
|
|
17
|
-
"register_adapter",
|
|
18
|
-
"get_adapter",
|
|
19
|
-
"list_adapters",
|
|
20
|
-
"adapter_exists",
|
|
21
|
-
]
|
zwarm/adapters/base.py
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Base adapter protocol for executor agents.
|
|
3
|
-
|
|
4
|
-
All CLI coding agent adapters (codex, claude-code, gemini) implement this protocol.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from abc import ABC, abstractmethod
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from typing import Literal
|
|
12
|
-
|
|
13
|
-
from zwarm.core.models import ConversationSession, SessionMode
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class ExecutorAdapter(ABC):
|
|
17
|
-
"""
|
|
18
|
-
Abstract base class for CLI coding agent adapters.
|
|
19
|
-
|
|
20
|
-
Adapters handle the mechanics of:
|
|
21
|
-
- Starting sessions (sync or async)
|
|
22
|
-
- Sending messages in sync mode
|
|
23
|
-
- Checking status in async mode
|
|
24
|
-
- Stopping sessions
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
name: str = "base"
|
|
28
|
-
|
|
29
|
-
@abstractmethod
|
|
30
|
-
async def start_session(
|
|
31
|
-
self,
|
|
32
|
-
task: str,
|
|
33
|
-
working_dir: Path,
|
|
34
|
-
mode: Literal["sync", "async"] = "sync",
|
|
35
|
-
model: str | None = None,
|
|
36
|
-
**kwargs,
|
|
37
|
-
) -> ConversationSession:
|
|
38
|
-
"""
|
|
39
|
-
Start a new session with the executor.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
task: The task description/prompt
|
|
43
|
-
working_dir: Directory to work in
|
|
44
|
-
mode: "sync" for conversational, "async" for fire-and-forget
|
|
45
|
-
model: Optional model override
|
|
46
|
-
**kwargs: Adapter-specific options
|
|
47
|
-
|
|
48
|
-
Returns:
|
|
49
|
-
A ConversationSession with initial response (if sync)
|
|
50
|
-
"""
|
|
51
|
-
...
|
|
52
|
-
|
|
53
|
-
@abstractmethod
|
|
54
|
-
async def send_message(
|
|
55
|
-
self,
|
|
56
|
-
session: ConversationSession,
|
|
57
|
-
message: str,
|
|
58
|
-
) -> str:
|
|
59
|
-
"""
|
|
60
|
-
Send a message to a sync session and get response.
|
|
61
|
-
|
|
62
|
-
Args:
|
|
63
|
-
session: The active session
|
|
64
|
-
message: Message to send
|
|
65
|
-
|
|
66
|
-
Returns:
|
|
67
|
-
The agent's response
|
|
68
|
-
|
|
69
|
-
Raises:
|
|
70
|
-
ValueError: If session is not in sync mode or not active
|
|
71
|
-
"""
|
|
72
|
-
...
|
|
73
|
-
|
|
74
|
-
@abstractmethod
|
|
75
|
-
async def check_status(
|
|
76
|
-
self,
|
|
77
|
-
session: ConversationSession,
|
|
78
|
-
) -> dict:
|
|
79
|
-
"""
|
|
80
|
-
Check the status of an async session.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
session: The session to check
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
Status dict with at least {"status": "running"|"completed"|"failed"}
|
|
87
|
-
"""
|
|
88
|
-
...
|
|
89
|
-
|
|
90
|
-
@abstractmethod
|
|
91
|
-
async def stop(
|
|
92
|
-
self,
|
|
93
|
-
session: ConversationSession,
|
|
94
|
-
) -> None:
|
|
95
|
-
"""
|
|
96
|
-
Stop/kill a session.
|
|
97
|
-
|
|
98
|
-
Args:
|
|
99
|
-
session: The session to stop
|
|
100
|
-
"""
|
|
101
|
-
...
|
|
102
|
-
|
|
103
|
-
async def cleanup(self) -> None:
|
|
104
|
-
"""
|
|
105
|
-
Clean up adapter resources (e.g., MCP server).
|
|
106
|
-
|
|
107
|
-
Called when the orchestrator shuts down.
|
|
108
|
-
"""
|
|
109
|
-
pass
|