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/cli/main.py +735 -310
- zwarm/sessions/__init__.py +24 -0
- zwarm/sessions/manager.py +589 -0
- zwarm/tools/delegation.py +143 -1
- {zwarm-1.3.5.dist-info → zwarm-1.3.8.dist-info}/METADATA +1 -1
- {zwarm-1.3.5.dist-info → zwarm-1.3.8.dist-info}/RECORD +8 -6
- {zwarm-1.3.5.dist-info → zwarm-1.3.8.dist-info}/WHEEL +0 -0
- {zwarm-1.3.5.dist-info → zwarm-1.3.8.dist-info}/entry_points.txt +0 -0
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
|
|
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))
|
|
@@ -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=
|
|
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=
|
|
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.
|
|
33
|
-
zwarm-1.3.
|
|
34
|
-
zwarm-1.3.
|
|
35
|
-
zwarm-1.3.
|
|
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
|
|
File without changes
|