zwarm 1.3.5__py3-none-any.whl → 1.3.8__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/tools/delegation.py CHANGED
@@ -6,11 +6,15 @@ These are the core tools that orchestrators use to delegate work to executors:
6
6
  - converse: Continue a sync conversation
7
7
  - check_session: Check status of an async session
8
8
  - end_session: End a session
9
+
10
+ Sessions are also registered with CodexSessionManager for unified visibility
11
+ in `zwarm interactive`.
9
12
  """
10
13
 
11
14
  from __future__ import annotations
12
15
 
13
16
  import asyncio
17
+ from datetime import datetime
14
18
  from pathlib import Path
15
19
  from typing import TYPE_CHECKING, Any, Literal
16
20
 
@@ -20,6 +24,106 @@ if TYPE_CHECKING:
20
24
  from zwarm.orchestrator import Orchestrator
21
25
 
22
26
 
27
+ def _get_session_manager(orchestrator: "Orchestrator"):
28
+ """Get or create the CodexSessionManager for unified session tracking."""
29
+ if not hasattr(orchestrator, "_session_manager"):
30
+ from zwarm.sessions import CodexSessionManager
31
+ orchestrator._session_manager = CodexSessionManager(orchestrator.working_dir / ".zwarm")
32
+ return orchestrator._session_manager
33
+
34
+
35
+ def _register_session_for_visibility(
36
+ orchestrator: "Orchestrator",
37
+ session_id: str,
38
+ task: str,
39
+ adapter: str,
40
+ model: str,
41
+ working_dir: Path,
42
+ status: str = "running",
43
+ pid: int | None = None,
44
+ ):
45
+ """
46
+ Register an orchestrator session with CodexSessionManager for visibility.
47
+
48
+ This allows `zwarm interactive` to show orchestrator-delegated sessions
49
+ in its unified dashboard.
50
+ """
51
+ from zwarm.sessions import CodexSession, SessionStatus, SessionMessage
52
+
53
+ manager = _get_session_manager(orchestrator)
54
+ now = datetime.now().isoformat()
55
+
56
+ # Map status
57
+ status_map = {
58
+ "running": SessionStatus.RUNNING,
59
+ "active": SessionStatus.RUNNING,
60
+ "completed": SessionStatus.COMPLETED,
61
+ "failed": SessionStatus.FAILED,
62
+ }
63
+
64
+ session = CodexSession(
65
+ id=session_id,
66
+ task=task,
67
+ status=status_map.get(status, SessionStatus.RUNNING),
68
+ working_dir=working_dir,
69
+ created_at=now,
70
+ updated_at=now,
71
+ model=model or "unknown",
72
+ pid=pid,
73
+ source=f"orchestrator:{orchestrator.instance_id or 'unknown'}",
74
+ adapter=adapter,
75
+ messages=[SessionMessage(role="user", content=task, timestamp=now)],
76
+ )
77
+
78
+ # Save to disk
79
+ manager._save_session(session)
80
+ return session
81
+
82
+
83
+ def _update_session_visibility(
84
+ orchestrator: "Orchestrator",
85
+ session_id: str,
86
+ status: str | None = None,
87
+ messages: list | None = None,
88
+ token_usage: dict | None = None,
89
+ error: str | None = None,
90
+ ):
91
+ """Update a session's visibility record."""
92
+ manager = _get_session_manager(orchestrator)
93
+ session = manager._load_session(session_id)
94
+
95
+ if not session:
96
+ return
97
+
98
+ from zwarm.sessions import SessionStatus, SessionMessage
99
+
100
+ if status:
101
+ status_map = {
102
+ "running": SessionStatus.RUNNING,
103
+ "active": SessionStatus.RUNNING,
104
+ "completed": SessionStatus.COMPLETED,
105
+ "failed": SessionStatus.FAILED,
106
+ }
107
+ session.status = status_map.get(status, session.status)
108
+
109
+ if messages:
110
+ for msg in messages:
111
+ if hasattr(msg, "role") and hasattr(msg, "content"):
112
+ session.messages.append(SessionMessage(
113
+ role=msg.role,
114
+ content=msg.content,
115
+ timestamp=datetime.now().isoformat(),
116
+ ))
117
+
118
+ if token_usage:
119
+ session.token_usage = token_usage
120
+
121
+ if error:
122
+ session.error = error
123
+
124
+ manager._save_session(session)
125
+
126
+
23
127
  def _truncate(text: str, max_len: int = 200) -> str:
24
128
  """Truncate text with ellipsis."""
25
129
  if len(text) <= max_len:
@@ -161,6 +265,18 @@ def delegate(
161
265
  self._sessions[session.id] = session
162
266
  self.state.add_session(session)
163
267
 
268
+ # Register for unified visibility in zwarm interactive
269
+ _register_session_for_visibility(
270
+ orchestrator=self,
271
+ session_id=session.id,
272
+ task=task,
273
+ adapter=adapter_name,
274
+ model=model or self.config.executor.model,
275
+ working_dir=effective_dir,
276
+ status="running" if mode == "async" else "active",
277
+ pid=getattr(session, "process", None) and session.process.pid,
278
+ )
279
+
164
280
  # Log events
165
281
  from zwarm.core.models import event_session_started, event_message_sent, Message
166
282
  self.state.log_event(event_session_started(session))
@@ -299,8 +415,17 @@ def converse(
299
415
  # Update state
300
416
  self.state.update_session(session)
301
417
 
418
+ # Update visibility record
419
+ from zwarm.core.models import Message
420
+ _update_session_visibility(
421
+ orchestrator=self,
422
+ session_id=session_id,
423
+ messages=[Message(role="user", content=message), Message(role="assistant", content=response)],
424
+ token_usage=session.token_usage,
425
+ )
426
+
302
427
  # Log both messages
303
- from zwarm.core.models import event_message_sent, Message
428
+ from zwarm.core.models import event_message_sent
304
429
  self.state.log_event(event_message_sent(session, Message(role="user", content=message)))
305
430
  self.state.log_event(event_message_sent(session, Message(role="assistant", content=response)))
306
431
 
@@ -367,6 +492,14 @@ def check_session(
367
492
  # Update state if status changed
368
493
  self.state.update_session(session)
369
494
 
495
+ # Sync visibility record
496
+ _update_session_visibility(
497
+ orchestrator=self,
498
+ session_id=session_id,
499
+ status=session.status.value,
500
+ token_usage=session.token_usage,
501
+ )
502
+
370
503
  header = _format_session_header(session.id, session.adapter, session.mode.value)
371
504
 
372
505
  return {
@@ -426,6 +559,15 @@ def end_session(
426
559
  # Update state
427
560
  self.state.update_session(session)
428
561
 
562
+ # Update visibility record
563
+ _update_session_visibility(
564
+ orchestrator=self,
565
+ session_id=session_id,
566
+ status=verdict,
567
+ token_usage=session.token_usage,
568
+ error=summary if verdict == "failed" else None,
569
+ )
570
+
429
571
  # Log event
430
572
  from zwarm.core.models import event_session_completed
431
573
  self.state.log_event(event_session_completed(session))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zwarm
3
- Version: 1.3.5
3
+ Version: 1.3.8
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
@@ -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=GstswIKfmwD1thNBfP0vOzKHaOq3PjRuu3PYe5rLVnc,59082
12
+ zwarm/cli/main.py,sha256=kGrwxAHkpJqF6YCki1DLJpOzjkk05P-1AXGzPBuUOnw,73266
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=7mzxrWvHmTjwiUWAoE4NYS_1yWj85-vWkpT6X6kiMIg,11579
@@ -21,15 +21,17 @@ zwarm/core/test_config.py,sha256=26ozyiFOdjFF2c9Q-HDfFM6GOLfgw_5FZ55nTDMNYA8,488
21
21
  zwarm/core/test_models.py,sha256=sWTIhMZvuLP5AooGR6y8OR2EyWydqVfhmGrE7NPBBnk,8450
22
22
  zwarm/prompts/__init__.py,sha256=FiaIOniLrIyfD3_osxT6I7FfyKjtctbf8jNs5QTPs_s,213
23
23
  zwarm/prompts/orchestrator.py,sha256=af5547L2g6HwGz-PxlKCAXJzqXEdjcwSAIdVH7_4LSk,15412
24
+ zwarm/sessions/__init__.py,sha256=NOOkyspJ2lpr5LwlZw2e9wvJPdRgSCQRkULgayrio5U,526
25
+ zwarm/sessions/manager.py,sha256=0CrexNwMKiaKYESlWM_oDePj7xL8BRk-9XY5NS2ONlc,19391
24
26
  zwarm/tools/__init__.py,sha256=FpqxwXJA6-fQ7C-oLj30jjK_0qqcE7MbI0dQuaB56kU,290
25
- zwarm/tools/delegation.py,sha256=PeB0W7x2TcGCZ9rGBYDlIIFr7AT1TOdc1SLe7BKCUoM,15332
27
+ zwarm/tools/delegation.py,sha256=dV-fDoxA01RqjW90SLCLhBFQ2kVn8-68JdL0ssYYg_k,19583
26
28
  zwarm/watchers/__init__.py,sha256=yYGTbhuImQLESUdtfrYbHYBJNvCNX3B-Ei-vY5BizX8,760
27
29
  zwarm/watchers/base.py,sha256=r1GoPlj06nOT2xp4fghfSjxbRyFFFQUB6HpZbEyO2OY,3834
28
30
  zwarm/watchers/builtin.py,sha256=k1pCnQBEmLHeuCo8t6UXoenJUpfWY7AuGt_aEk8syew,15828
29
31
  zwarm/watchers/manager.py,sha256=XZjBVeHjgCUlkTUeHqdvBvHoBC862U1ik0fG6nlRGog,5587
30
32
  zwarm/watchers/registry.py,sha256=A9iBIVIFNtO7KPX0kLpUaP8dAK7ozqWLA44ocJGnOw4,1219
31
33
  zwarm/watchers/test_watchers.py,sha256=zOsxumBqKfR5ZVGxrNlxz6KcWjkcdp0QhW9WB0_20zM,7855
32
- zwarm-1.3.5.dist-info/METADATA,sha256=9boM7ysJGr-hfN_0YrNZfWD_Lwi8B9iF-BJWorrmNXs,16114
33
- zwarm-1.3.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
34
- zwarm-1.3.5.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
35
- zwarm-1.3.5.dist-info/RECORD,,
34
+ zwarm-1.3.8.dist-info/METADATA,sha256=rRucfiwEyCky2bDJNY_SwxiKLHKaqQiHERGBuulBSUM,16114
35
+ zwarm-1.3.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
36
+ zwarm-1.3.8.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
37
+ zwarm-1.3.8.dist-info/RECORD,,
File without changes