zwarm 2.0.0__py3-none-any.whl → 2.0.2__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/main.py CHANGED
@@ -1375,7 +1375,7 @@ def interactive(
1375
1375
 
1376
1376
  def do_spawn(args: list[str]):
1377
1377
  """Spawn a new coding agent session using CodexSessionManager (same as orchestrator)."""
1378
- from zwarm.sessions import CodexSessionManager
1378
+ from zwarm.sessions import CodexSessionManager, SessionStatus as SessStatus
1379
1379
  import time
1380
1380
 
1381
1381
  parsed = parse_spawn_args(args)
@@ -1425,20 +1425,24 @@ def interactive(
1425
1425
  timeout = 300.0
1426
1426
  start = time.time()
1427
1427
  while time.time() - start < timeout:
1428
+ # get_session() auto-updates status based on output completion
1428
1429
  session = manager.get_session(session.id)
1429
- if not session.is_running:
1430
+ if session.status != SessStatus.RUNNING:
1430
1431
  break
1431
1432
  time.sleep(1.0)
1432
1433
 
1433
- # Get the response
1434
+ # Get all assistant responses
1434
1435
  messages = manager.get_messages(session.id)
1435
- for msg in messages:
1436
- if msg.role == "assistant":
1437
- response_preview = msg.content[:300]
1436
+ assistant_msgs = [m for m in messages if m.role == "assistant"]
1437
+ if assistant_msgs:
1438
+ console.print(f"\n[bold]Response ({len(assistant_msgs)} message{'s' if len(assistant_msgs) > 1 else ''}):[/]")
1439
+ for msg in assistant_msgs:
1440
+ preview = msg.content[:300]
1438
1441
  if len(msg.content) > 300:
1439
- response_preview += "..."
1440
- console.print(f"\n[bold]Response:[/]\n{response_preview}")
1441
- break
1442
+ preview += "..."
1443
+ console.print(preview)
1444
+ if len(assistant_msgs) > 1:
1445
+ console.print() # Blank line between multiple messages
1442
1446
 
1443
1447
  console.print(f"\n[dim]Use 'show {session.short_id}' to see full details[/]")
1444
1448
  console.print(f"[dim]Use 'c {session.short_id} \"message\"' to continue[/]")
@@ -1579,6 +1583,10 @@ def interactive(
1579
1583
  console.print(f"[dim]Source:[/] {session.source_display} [dim]│[/] [dim]Runtime:[/] {session.runtime}")
1580
1584
  if session.pid:
1581
1585
  console.print(f"[dim]PID:[/] {session.pid}")
1586
+
1587
+ # Show log file path
1588
+ log_path = default_dir / ".zwarm" / "sessions" / session.id / "turns" / f"turn_{session.turn}.jsonl"
1589
+ console.print(f"[dim]Log:[/] {log_path}")
1582
1590
  console.print()
1583
1591
 
1584
1592
  # Get messages from manager
@@ -1663,8 +1671,9 @@ def interactive(
1663
1671
  timeout = 300.0
1664
1672
  start = time.time()
1665
1673
  while time.time() - start < timeout:
1674
+ # get_session() auto-updates status based on output completion
1666
1675
  session = manager.get_session(session.id)
1667
- if not session.is_running:
1676
+ if session.status != SessStatus.RUNNING:
1668
1677
  break
1669
1678
  time.sleep(1.0)
1670
1679
 
zwarm/orchestrator.py CHANGED
@@ -20,6 +20,8 @@ import weave
20
20
  from pydantic import Field, PrivateAttr
21
21
  from wbal.agents.yaml_agent import YamlAgent
22
22
  from wbal.helper import TOOL_CALL_TYPE, format_openai_tool_response
23
+ from wbal.lm import LM as wbalLMGeneric
24
+ from wbal.lm import GPT5LargeVerbose
23
25
 
24
26
  from zwarm.adapters import ExecutorAdapter, get_adapter
25
27
  from zwarm.core.compact import compact_messages, should_compact
@@ -29,9 +31,9 @@ from zwarm.core.models import ConversationSession
29
31
  from zwarm.core.state import StateManager
30
32
  from zwarm.prompts import get_orchestrator_prompt
31
33
  from zwarm.watchers import (
32
- WatcherManager,
33
- WatcherContext,
34
34
  WatcherAction,
35
+ WatcherContext,
36
+ WatcherManager,
35
37
  build_watcher_manager,
36
38
  )
37
39
 
@@ -48,6 +50,9 @@ class Orchestrator(YamlAgent):
48
50
  - Weave integration
49
51
  """
50
52
 
53
+ # LM definition override:
54
+ lm: wbalLMGeneric = Field(default_factory=GPT5LargeVerbose)
55
+
51
56
  # Configuration
52
57
  config: ZwarmConfig = Field(default_factory=ZwarmConfig)
53
58
  working_dir: Path = Field(default_factory=Path.cwd)
@@ -71,11 +76,13 @@ class Orchestrator(YamlAgent):
71
76
  _watcher_manager: WatcherManager | None = PrivateAttr(default=None)
72
77
  _resumed: bool = PrivateAttr(default=False)
73
78
  _total_tokens: int = PrivateAttr(default=0) # Cumulative orchestrator tokens
74
- _executor_usage: dict[str, int] = PrivateAttr(default_factory=lambda: {
75
- "input_tokens": 0,
76
- "output_tokens": 0,
77
- "total_tokens": 0,
78
- })
79
+ _executor_usage: dict[str, int] = PrivateAttr(
80
+ default_factory=lambda: {
81
+ "input_tokens": 0,
82
+ "output_tokens": 0,
83
+ "total_tokens": 0,
84
+ }
85
+ )
79
86
 
80
87
  def model_post_init(self, __context: Any) -> None:
81
88
  """Initialize state and adapters after model creation."""
@@ -93,6 +100,7 @@ class Orchestrator(YamlAgent):
93
100
  # Register instance if using instance isolation
94
101
  if self.instance_id:
95
102
  from zwarm.core.state import register_instance
103
+
96
104
  register_instance(
97
105
  instance_id=self.instance_id,
98
106
  name=self.instance_name,
@@ -149,7 +157,9 @@ class Orchestrator(YamlAgent):
149
157
  if not config_path.exists():
150
158
  config_path = None # Fallback to adapter defaults
151
159
 
152
- self._adapters[name] = get_adapter(name, model=model, config_path=config_path)
160
+ self._adapters[name] = get_adapter(
161
+ name, model=model, config_path=config_path
162
+ )
153
163
  return self._adapters[name]
154
164
 
155
165
  def get_executor_usage(self) -> dict[str, int]:
@@ -253,15 +263,18 @@ class Orchestrator(YamlAgent):
253
263
 
254
264
  # Log compaction event
255
265
  from zwarm.core.models import Event
256
- self._state.log_event(Event(
257
- kind="context_compacted",
258
- payload={
259
- "step": self._step_count,
260
- "original_count": result.original_count,
261
- "new_count": len(result.messages),
262
- "removed_count": result.removed_count,
263
- },
264
- ))
266
+
267
+ self._state.log_event(
268
+ Event(
269
+ kind="context_compacted",
270
+ payload={
271
+ "step": self._step_count,
272
+ "original_count": result.original_count,
273
+ "new_count": len(result.messages),
274
+ "removed_count": result.removed_count,
275
+ },
276
+ )
277
+ )
265
278
 
266
279
  return True
267
280
 
@@ -377,17 +390,20 @@ Review what was accomplished in the previous session and delegate new tasks as n
377
390
 
378
391
  # Log watcher execution to events
379
392
  from zwarm.core.models import Event
393
+
380
394
  watcher_names = [w.name for w in self.config.watchers.watchers if w.enabled]
381
- self.state.log_event(Event(
382
- kind="watchers_run",
383
- payload={
384
- "step": self._step_count,
385
- "watchers": watcher_names,
386
- "action": result.action.value,
387
- "triggered_by": result.metadata.get("triggered_by"),
388
- "reason": result.metadata.get("reason"),
389
- },
390
- ))
395
+ self.state.log_event(
396
+ Event(
397
+ kind="watchers_run",
398
+ payload={
399
+ "step": self._step_count,
400
+ "watchers": watcher_names,
401
+ "action": result.action.value,
402
+ "triggered_by": result.metadata.get("triggered_by"),
403
+ "reason": result.metadata.get("reason"),
404
+ },
405
+ )
406
+ )
391
407
 
392
408
  # Handle watcher result
393
409
  if result.action == WatcherAction.NUDGE and result.guidance:
zwarm/tools/delegation.py CHANGED
@@ -53,14 +53,17 @@ def _wait_for_completion(manager, session_id: str, timeout: float = 300.0, poll_
53
53
  Returns:
54
54
  True if completed, False if timed out
55
55
  """
56
+ from zwarm.sessions import SessionStatus
57
+
56
58
  start = time.time()
57
59
  while time.time() - start < timeout:
60
+ # get_session() auto-updates status based on output completion markers
58
61
  session = manager.get_session(session_id)
59
62
  if not session:
60
63
  return False
61
64
 
62
- # Check if process is still running
63
- if not session.is_running:
65
+ # Check status (not is_running - PID check is unreliable due to reuse)
66
+ if session.status in (SessionStatus.COMPLETED, SessionStatus.FAILED, SessionStatus.KILLED):
64
67
  return True
65
68
 
66
69
  time.sleep(poll_interval)
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zwarm
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: Multi-Agent CLI Orchestration Research Platform
5
5
  Requires-Python: <3.14,>=3.13
6
6
  Requires-Dist: python-dotenv>=1.0.0
7
7
  Requires-Dist: pyyaml>=6.0
8
8
  Requires-Dist: rich>=13.0.0
9
9
  Requires-Dist: typer>=0.9.0
10
- Requires-Dist: wbal>=0.4.0
10
+ Requires-Dist: wbal>=0.5.8
11
11
  Description-Content-Type: text/markdown
12
12
 
13
13
  # zwarm
@@ -1,5 +1,5 @@
1
1
  zwarm/__init__.py,sha256=3i3LMjHwIzE-LFIS2aUrwv3EZmpkvVMe-xj1h97rcSM,837
2
- zwarm/orchestrator.py,sha256=FGr-_MpG_UGUFAa19oenh7MVifE6frK6URS8ii0x0IA,22952
2
+ zwarm/orchestrator.py,sha256=IdOd7xNH6IKfvpajh6pOKh2nwTjopS2nQ8GYrj7OsSc,23307
3
3
  zwarm/test_orchestrator_watchers.py,sha256=QpoaehPU7ekT4XshbTOWnJ2H0wRveV3QOZjxbgyJJLY,807
4
4
  zwarm/adapters/__init__.py,sha256=O0b-SfZpb6txeNqFkXZ2aaf34yLFYreznyrAV25jF_Q,656
5
5
  zwarm/adapters/base.py,sha256=fZlQviTgVvOcwnxduTla6WuM6FzQJ_yoHMW5SxwVgQg,2527
@@ -9,7 +9,7 @@ zwarm/adapters/registry.py,sha256=EdyHECaNA5Kv1od64pYFBJyA_r_6I1r_eJTNP1XYLr4,17
9
9
  zwarm/adapters/test_codex_mcp.py,sha256=0qhVzxn_KF-XUS30gXSJKwMdR3kWGsDY9iPk1Ihqn3w,10698
10
10
  zwarm/adapters/test_registry.py,sha256=otxcVDONwFCMisyANToF3iy7Y8dSbCL8bTmZNhxNuF4,2383
11
11
  zwarm/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- zwarm/cli/main.py,sha256=-kxDul3cPv9vqLLS9ePTjSf1TXo8E3TCuS6p-t4u4hQ,87985
12
+ zwarm/cli/main.py,sha256=fQT9oP03zsru1_80WfVBdX48kdpLIVfEgS8eJQxRxUM,88668
13
13
  zwarm/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  zwarm/core/compact.py,sha256=Y8C7Gs-5-WOU43WRvQ863Qzd5xtuEqR6Aw3r2p8_-i8,10907
15
15
  zwarm/core/config.py,sha256=331i4io9uEnloFwUMjTPJ5_lQFKJR1nhTpA4SPfSpiI,11748
@@ -24,14 +24,14 @@ zwarm/prompts/orchestrator.py,sha256=-VZ3B5t-2ALOTpdZyNZGSjjzaHiTufAuLzrTLgwg70M
24
24
  zwarm/sessions/__init__.py,sha256=jRibY8IfmNcnkgNmrgK2T81oa1w71wP_KQp9A1hPL7Q,568
25
25
  zwarm/sessions/manager.py,sha256=slCDE0n9-pw6iZ08YZMjxZRwH0aoEi6MAAChLlAsuPw,22212
26
26
  zwarm/tools/__init__.py,sha256=FpqxwXJA6-fQ7C-oLj30jjK_0qqcE7MbI0dQuaB56kU,290
27
- zwarm/tools/delegation.py,sha256=axGuDROdJM9xYDG8IscfyQpNGrkDQSFPi9_ElfL0Fzw,20661
27
+ zwarm/tools/delegation.py,sha256=2NI9J2VArVUbqOTZJY8Vgz5Rd5nI7BdZ8GNaYVIR_JU,20886
28
28
  zwarm/watchers/__init__.py,sha256=yYGTbhuImQLESUdtfrYbHYBJNvCNX3B-Ei-vY5BizX8,760
29
29
  zwarm/watchers/base.py,sha256=r1GoPlj06nOT2xp4fghfSjxbRyFFFQUB6HpZbEyO2OY,3834
30
30
  zwarm/watchers/builtin.py,sha256=IL5QwwKOIqWEfJ_uQWb321Px4i5OLtI_vnWQMudqKoA,19064
31
31
  zwarm/watchers/manager.py,sha256=XZjBVeHjgCUlkTUeHqdvBvHoBC862U1ik0fG6nlRGog,5587
32
32
  zwarm/watchers/registry.py,sha256=A9iBIVIFNtO7KPX0kLpUaP8dAK7ozqWLA44ocJGnOw4,1219
33
33
  zwarm/watchers/test_watchers.py,sha256=zOsxumBqKfR5ZVGxrNlxz6KcWjkcdp0QhW9WB0_20zM,7855
34
- zwarm-2.0.0.dist-info/METADATA,sha256=v94KN8eICvONW3-UvteIdL0suEu6Pu3ur3FMxGd9lS0,7680
35
- zwarm-2.0.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
36
- zwarm-2.0.0.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
37
- zwarm-2.0.0.dist-info/RECORD,,
34
+ zwarm-2.0.2.dist-info/METADATA,sha256=1V6Ceu1nSd_HK9mDD2saHTqF3efZ8bV4Ip06X1lHoqw,7680
35
+ zwarm-2.0.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
36
+ zwarm-2.0.2.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
37
+ zwarm-2.0.2.dist-info/RECORD,,
File without changes