zwarm 3.10.2__py3-none-any.whl → 3.10.5__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
@@ -34,17 +34,43 @@ if TYPE_CHECKING:
34
34
  ADAPTERS = ["codex", "claude"]
35
35
 
36
36
 
37
- def _get_session_manager(orchestrator: "Orchestrator"):
37
+ def _get_all_adapter_managers(orchestrator: "Orchestrator") -> dict:
38
38
  """
39
- Get the default session manager for list/get operations.
39
+ Get session managers for ALL adapters.
40
40
 
41
- Uses CodexSessionManager as the default since all adapters share
42
- the same .zwarm/sessions/ directory structure.
41
+ This ensures we can find sessions regardless of which adapter created them.
42
+ Returns a dict of {adapter_name: manager}.
43
43
  """
44
- if not hasattr(orchestrator, "_session_manager") or orchestrator._session_manager is None:
45
- from zwarm.sessions import CodexSessionManager
46
- orchestrator._session_manager = CodexSessionManager(orchestrator.working_dir / ".zwarm")
47
- return orchestrator._session_manager
44
+ # Initialize adapter managers dict if needed
45
+ if not hasattr(orchestrator, "_adapter_managers"):
46
+ orchestrator._adapter_managers = {}
47
+
48
+ # Ensure all adapters have managers
49
+ from zwarm.sessions import get_session_manager
50
+ for adapter in ADAPTERS:
51
+ if adapter not in orchestrator._adapter_managers:
52
+ manager = get_session_manager(adapter, str(orchestrator.working_dir / ".zwarm"))
53
+ orchestrator._adapter_managers[adapter] = manager
54
+
55
+ return orchestrator._adapter_managers
56
+
57
+
58
+ def _get_session_with_manager(orchestrator: "Orchestrator", session_id: str):
59
+ """
60
+ Find a session across all adapters and return (session, manager).
61
+
62
+ Since sessions are adapter-scoped, we need to check each adapter's
63
+ manager to find where the session lives.
64
+
65
+ Returns:
66
+ (session, manager) if found, (None, None) if not found
67
+ """
68
+ managers = _get_all_adapter_managers(orchestrator)
69
+ for adapter, manager in managers.items():
70
+ session = manager.get_session(session_id)
71
+ if session:
72
+ return session, manager
73
+ return None, None
48
74
 
49
75
 
50
76
  def _get_adapter_manager(orchestrator: "Orchestrator", adapter: str):
@@ -177,7 +203,7 @@ def delegate(
177
203
  WORKFLOW:
178
204
  1. delegate(task="...", model="5.2") -> session_id
179
205
  2. sleep(30)
180
- 3. peek_session(session_id) -> {is_running: true/false}
206
+ 3. list_sessions() -> check which are done (needs_attention=True)
181
207
  4. If is_running, goto 2
182
208
  5. check_session(session_id) -> FULL response
183
209
 
@@ -295,9 +321,8 @@ def converse(
295
321
  sleep(30)
296
322
  check_session(session_id) # Get response
297
323
  """
298
- # First get session to determine adapter
299
- default_manager = _get_session_manager(self)
300
- session = default_manager.get_session(session_id)
324
+ # Find session across all adapters
325
+ session, manager = _get_session_with_manager(self, session_id)
301
326
 
302
327
  if not session:
303
328
  return {
@@ -322,9 +347,8 @@ def converse(
322
347
  "hint": "Start a new session with delegate()",
323
348
  }
324
349
 
325
- # Get the correct adapter manager for this session
350
+ # Use the manager that found the session (correct adapter)
326
351
  adapter = getattr(session, "adapter", "codex")
327
- manager = _get_adapter_manager(self, adapter)
328
352
 
329
353
  # Inject the follow-up message
330
354
  # This uses the adapter's inject_message() which:
@@ -356,25 +380,22 @@ def converse(
356
380
  def check_session(
357
381
  self: "Orchestrator",
358
382
  session_id: str,
383
+ latest: bool = True,
359
384
  ) -> dict[str, Any]:
360
385
  """
361
- Check the status of a session and get the FULL response.
386
+ Check the status of a session and get the response.
362
387
 
363
388
  This is your primary tool for seeing what an executor accomplished.
364
- Returns the complete, untruncated response from the agent.
365
-
366
- Use this after peek_session() shows the session is done, or when
367
- you need to see the full details of what was accomplished.
368
389
 
369
390
  Args:
370
391
  session_id: The session to check.
392
+ latest: If True (default), only return the latest assistant message.
393
+ If False, return full conversation history.
371
394
 
372
395
  Returns:
373
- {session_id, status, response (FULL), tokens, runtime}
396
+ {session_id, status, response, tokens, runtime}
374
397
  """
375
- manager = _get_session_manager(self)
376
-
377
- session = manager.get_session(session_id)
398
+ session, manager = _get_session_with_manager(self, session_id)
378
399
  if not session:
379
400
  return {
380
401
  "success": False,
@@ -382,13 +403,22 @@ def check_session(
382
403
  "hint": "Use list_sessions() to see available sessions",
383
404
  }
384
405
 
385
- # Get latest response - FULL, not truncated
386
- response_text = ""
387
406
  messages = manager.get_messages(session_id)
388
- for msg in reversed(messages):
389
- if msg.role == "assistant":
390
- response_text = msg.content # Full content, no truncation
391
- break
407
+
408
+ if latest:
409
+ # Only get the latest assistant message
410
+ response_text = ""
411
+ for msg in reversed(messages):
412
+ if msg.role == "assistant":
413
+ response_text = msg.content
414
+ break
415
+ response_content = response_text if response_text else "(no response yet)"
416
+ else:
417
+ # Return full conversation history
418
+ response_content = [
419
+ {"role": msg.role, "content": msg.content}
420
+ for msg in messages
421
+ ]
392
422
 
393
423
  # Build log path
394
424
  log_path = str(manager._output_path(session.id, session.turn))
@@ -401,8 +431,8 @@ def check_session(
401
431
  "is_running": session.is_running,
402
432
  "turn": session.turn,
403
433
  "message_count": len(messages),
404
- "task": _truncate(session.task, 80), # Task can stay truncated
405
- "response": response_text if response_text else "(no response yet)", # FULL response
434
+ "task": _truncate(session.task, 80),
435
+ "response": response_content,
406
436
  "tokens": _get_total_tokens(session),
407
437
  "runtime": session.runtime,
408
438
  "log_file": log_path,
@@ -417,51 +447,6 @@ def check_session(
417
447
  return result
418
448
 
419
449
 
420
- @weaveTool
421
- def peek_session(
422
- self: "Orchestrator",
423
- session_id: str,
424
- ) -> dict[str, Any]:
425
- """
426
- Quick peek at a session - minimal info for FAST POLLING.
427
-
428
- Use this in your polling loop to check if a session is done:
429
- 1. delegate() -> start work
430
- 2. sleep(30)
431
- 3. peek_session() -> is_running? If yes, goto 2
432
- 4. check_session() -> get FULL response
433
-
434
- Returns truncated preview only. Once done, use check_session() for full response.
435
-
436
- Args:
437
- session_id: The session to peek at.
438
-
439
- Returns:
440
- {session_id, status, is_running, latest_message (truncated preview)}
441
- """
442
- manager = _get_session_manager(self)
443
-
444
- session = manager.get_session(session_id)
445
- if not session:
446
- return {"success": False, "error": f"Unknown session: {session_id}"}
447
-
448
- # Get latest assistant message only
449
- latest = ""
450
- messages = manager.get_messages(session_id)
451
- for msg in reversed(messages):
452
- if msg.role == "assistant":
453
- latest = msg.content.replace("\n", " ")
454
- break
455
-
456
- return {
457
- "success": True,
458
- "session_id": session.short_id,
459
- "status": session.status.value,
460
- "is_running": session.status.value == "running",
461
- "latest_message": _truncate(latest, 150) if latest else None,
462
- }
463
-
464
-
465
450
  @weaveTool
466
451
  def get_trajectory(
467
452
  self: "Orchestrator",
@@ -487,9 +472,7 @@ def get_trajectory(
487
472
  - check_session() -> what did the agent conclude? (FULL response)
488
473
  - get_trajectory() -> what steps did the agent take? (step-by-step)
489
474
  """
490
- manager = _get_session_manager(self)
491
-
492
- session = manager.get_session(session_id)
475
+ session, manager = _get_session_with_manager(self, session_id)
493
476
  if not session:
494
477
  return {"success": False, "error": f"Unknown session: {session_id}"}
495
478
 
@@ -565,9 +548,7 @@ def end_session(
565
548
  Returns:
566
549
  {session_id, status}
567
550
  """
568
- manager = _get_session_manager(self)
569
-
570
- session = manager.get_session(session_id)
551
+ session, manager = _get_session_with_manager(self, session_id)
571
552
  if not session:
572
553
  return {
573
554
  "success": False,
@@ -594,7 +575,7 @@ def end_session(
594
575
  "session_id": session_id,
595
576
  }
596
577
 
597
- # Refresh
578
+ # Refresh - use same manager
598
579
  session = manager.get_session(session_id)
599
580
 
600
581
  return {
@@ -633,7 +614,8 @@ def list_sessions(
633
614
  """
634
615
  from datetime import datetime
635
616
 
636
- manager = _get_session_manager(self)
617
+ # Get managers for ALL adapters to aggregate sessions
618
+ managers = _get_all_adapter_managers(self)
637
619
 
638
620
  # Map string status to enum
639
621
  from zwarm.sessions import SessionStatus
@@ -648,7 +630,13 @@ def list_sessions(
648
630
  }
649
631
  status_filter = status_map.get(status.lower())
650
632
 
651
- sessions = manager.list_sessions(status=status_filter)
633
+ # Aggregate sessions from ALL adapters
634
+ sessions = []
635
+ for manager in managers.values():
636
+ sessions.extend(manager.list_sessions(status=status_filter))
637
+
638
+ # Sort by created_at descending (newest first)
639
+ sessions.sort(key=lambda s: s.created_at, reverse=True)
652
640
 
653
641
  def time_ago(iso_str: str) -> tuple[str, float]:
654
642
  """Convert ISO timestamp to ('Xm ago', seconds)."""
@@ -681,13 +669,16 @@ def list_sessions(
681
669
 
682
670
  updated_str, updated_secs = time_ago(s.updated_at)
683
671
 
684
- # Get last assistant message
685
- messages = manager.get_messages(s.id)
672
+ # Get last assistant message using the correct adapter's manager
673
+ session_adapter = getattr(s, "adapter", "codex")
674
+ session_manager = managers.get(session_adapter)
686
675
  last_message = ""
687
- for msg in reversed(messages):
688
- if msg.role == "assistant":
689
- last_message = msg.content.replace("\n", " ")
690
- break
676
+ if session_manager:
677
+ messages = session_manager.get_messages(s.id)
678
+ for msg in reversed(messages):
679
+ if msg.role == "assistant":
680
+ last_message = msg.content.replace("\n", " ")
681
+ break
691
682
 
692
683
  # Flag sessions that need attention:
693
684
  # - Recently completed (< 60s)
@@ -739,10 +730,11 @@ def sleep(self, seconds: float) -> dict[str, Any]:
739
730
  give them time to complete before checking their status. This lets you
740
731
  manage your own polling loop:
741
732
 
742
- 1. delegate(task, wait=False) -> start background work
743
- 2. sleep(10) -> wait a bit
744
- 3. peek_session(id) -> check if done
733
+ 1. delegate(task) -> start background work
734
+ 2. sleep(30) -> wait a bit
735
+ 3. list_sessions() -> check which are done (needs_attention=True)
745
736
  4. Repeat 2-3 if still running
737
+ 5. check_session(id) -> get result
746
738
 
747
739
  Args:
748
740
  seconds: Number of seconds to sleep (max 300 = 5 minutes)
@@ -58,7 +58,7 @@ def _extract_tool_call_summary(tc: Any) -> str:
58
58
  elif name == "bash":
59
59
  cmd = args.get("command", "")[:60]
60
60
  return f"$ {cmd}"
61
- elif name in ("check_session", "peek_session", "end_session"):
61
+ elif name in ("check_session", "end_session"):
62
62
  sid = args.get("session_id", "")[:8]
63
63
  return f"{name}({sid})"
64
64
  elif name == "list_sessions":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zwarm
3
- Version: 3.10.2
3
+ Version: 3.10.5
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
@@ -87,14 +87,18 @@ Want a 3-minute walkthrough? See `docs/DEMO.md` for a pilot + interactive demo.
87
87
 
88
88
  ## Multi-Adapter Support
89
89
 
90
- zwarm supports multiple executor backends:
90
+ zwarm supports multiple executor backends with simple model shortcuts:
91
91
 
92
- | Adapter | CLI | Models | Config |
93
- |---------|-----|--------|--------|
94
- | **Codex** | `codex` | gpt-5.1-codex-mini, etc. | `.zwarm/codex.toml` |
95
- | **Claude** | `claude` | sonnet, opus, haiku | `.zwarm/claude.toml` |
92
+ | Model | Alias | Description |
93
+ |-------|-------|-------------|
94
+ | `gpt-5.2-codex` | `5.2` | GPT-5.2 Codex - fast, great for code (default) |
95
+ | `gpt-5.2` | `5.2-think` | GPT-5.2 with extended reasoning |
96
+ | `sonnet` | - | Claude Sonnet - balanced |
97
+ | `opus` | - | Claude Opus - most capable |
96
98
 
97
- You can mix adapters in the same session - for example, use Claude Opus for complex reasoning tasks and Codex Mini for quick edits.
99
+ **Adapter is auto-detected from model name** - just use `model="opus"` and zwarm handles the rest.
100
+
101
+ Mix models freely - use Opus for complex reasoning, 5.2 for quick edits.
98
102
 
99
103
  ---
100
104
 
@@ -184,7 +188,7 @@ zwarm interactive
184
188
 
185
189
  | Command | Description |
186
190
  |---------|-------------|
187
- | `spawn "task" [--search]` | Start a new session (--search enables web) |
191
+ | `spawn "task" [--model M]` | Start a new session (model: 5.2, opus, sonnet) |
188
192
  | `ls` | Dashboard of all sessions (with costs, models) |
189
193
  | `? ID` / `peek ID` | Quick status check |
190
194
  | `show ID` | Full session details |
@@ -213,8 +217,8 @@ $ zwarm interactive
213
217
  ⟳ 2 running
214
218
 
215
219
  ID │ │ Task │ Model │ Tokens │ Cost
216
- abc123 │ ⟳ │ Add tests for the auth... │ codex-mini │ 5,234 │ $0.052
217
- def456 │ ⟳ │ Fix type errors in utils... │ codex-mini │ 2,100 │ $0.021
220
+ abc123 │ ⟳ │ Add tests for the auth... │ 5.2-codex │ 5,234 │ $0.052
221
+ def456 │ ⟳ │ Fix type errors in utils... │ 5.2-codex │ 2,100 │ $0.021
218
222
 
219
223
  > watch abc123
220
224
  Watching abc123... (Ctrl+C to stop)
@@ -254,17 +258,20 @@ The orchestrator LLM has access to:
254
258
 
255
259
  | Tool | Description |
256
260
  |------|-------------|
257
- | `delegate(task, adapter="codex")` | Start a new coding session |
261
+ | `delegate(task, model="5.2")` | Start a new coding session |
258
262
  | `converse(id, msg)` | Continue a session |
259
263
  | `check_session(id)` | Get full session details |
260
264
  | `peek_session(id)` | Quick status check |
265
+ | `get_trajectory(id)` | See what steps the agent took |
261
266
  | `list_sessions()` | List all sessions |
262
267
  | `end_session(id)` | Kill/delete a session |
263
268
  | `sleep(seconds)` | Wait before checking again |
269
+ | `bash(cmd)` | Run verification commands (tests, linters) |
270
+ | `exit()` | Signal task completion |
264
271
 
265
272
  **Async-first**: All sessions run in the background. The orchestrator uses `sleep()` to wait, then checks on progress.
266
273
 
267
- **Multi-adapter**: Pass `adapter="claude"` or `adapter="codex"` to `delegate()` to choose the backend.
274
+ **Model shortcuts**: Just use `model="5.2"` or `model="opus"` - the adapter is auto-detected.
268
275
 
269
276
  **Web Search**: Enable `web_search=True` in config for tasks needing current info (API docs, latest releases, etc.).
270
277
 
@@ -361,14 +368,14 @@ enabled = ["progress", "budget", "delegation", "delegation_reminder"]
361
368
 
362
369
  **`.zwarm/codex.toml`** - Controls the Codex CLI:
363
370
  ```toml
364
- model = "gpt-5.1-codex-mini"
371
+ model = "gpt-5.2-codex" # or gpt-5.2 for extended reasoning
365
372
  model_reasoning_effort = "high" # low | medium | high
366
- full_auto = true
373
+ full_danger = true # Skip approval prompts
367
374
  ```
368
375
 
369
376
  **`.zwarm/claude.toml`** - Controls the Claude Code CLI:
370
377
  ```toml
371
- model = "sonnet" # sonnet | opus | haiku
378
+ model = "opus" # opus | sonnet
372
379
  full_danger = true # Skip permission prompts
373
380
  ```
374
381
 
@@ -1,39 +1,42 @@
1
1
  zwarm/__init__.py,sha256=3i3LMjHwIzE-LFIS2aUrwv3EZmpkvVMe-xj1h97rcSM,837
2
- zwarm/orchestrator.py,sha256=CqZpe4h8-Z7rpy-boN2W9-sZdFfLONOnNMp2MJP2pbc,25292
2
+ zwarm/orchestrator.py,sha256=1nQmFTUKzrtvrKi08gg9ow6UHt-KvNozXz1td-yrCbA,26878
3
3
  zwarm/test_orchestrator_watchers.py,sha256=QpoaehPU7ekT4XshbTOWnJ2H0wRveV3QOZjxbgyJJLY,807
4
4
  zwarm/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- zwarm/cli/interactive.py,sha256=81aeiZIrPv5XquEkgDPkl_yYUYSGGhjvtcIVFV7jK_c,41716
6
- zwarm/cli/main.py,sha256=xQb004Bdm5ghOGqnBvlUIceuR4A8SSSxF3wJcx_aFZU,77369
7
- zwarm/cli/pilot.py,sha256=ABqPftf3maXhVrvmklpgZuPUELhseM0Tvjdn2_DANXM,42532
5
+ zwarm/cli/interactive.py,sha256=Bd2lBKV1qnVjEx3-swCBl0U0T7JlFaCX9JmSxhffr84,41704
6
+ zwarm/cli/main.py,sha256=WlEpdsdGacoJcSOk3_Rhr9athUGvYcDjixsrFsXg8fE,77251
7
+ zwarm/cli/pilot.py,sha256=zq7p-R4dflY2UocbDNdDOpok4Lqu97CmzTTxM5Ji1Ow,42331
8
+ zwarm/compression/__init__.py,sha256=tMx9jBVwrxKBtim8l4DdKllsE77yoq0kcYn7KG7tFAU,936
9
+ zwarm/compression/rollout_compression.py,sha256=Y5xjIkLDaCdTilzagbjpS7cpCoAuKpoyG9TC5jR4Hu8,9647
10
+ zwarm/compression/tc_compression.py,sha256=_qBKOWcCmqsU3EIg8_rJzeEgUL9lo4JcOnl2yPleTKQ,4867
8
11
  zwarm/core/__init__.py,sha256=nEdpEHMFo0gEEKgX-eKHabyOdrOI6UXfWqLu3FfZDao,376
9
12
  zwarm/core/checkpoints.py,sha256=D6sXCMB7Sa1kchQ9_lQx_rabwc5-_7jbuynWgA1nkNY,6560
10
13
  zwarm/core/compact.py,sha256=Y8C7Gs-5-WOU43WRvQ863Qzd5xtuEqR6Aw3r2p8_-i8,10907
11
- zwarm/core/config.py,sha256=m3Vm6U_BNtEDu_cz2d6E3p_RNQfRHWaq-946mDru9-8,12656
14
+ zwarm/core/config.py,sha256=jjn-BV5CME_PgIB8gW3o20b5qSNUdPoWWMZp22jnVmg,13813
12
15
  zwarm/core/costs.py,sha256=Z-5o-ZQWRCfFv0mTHev4Ke1AzyXKhXWO6ss7S8eBX9U,1485
13
16
  zwarm/core/environment.py,sha256=v7wwVCTIOt_qfiJEe774oM4vIYnlb28s6LJXucJdjoo,8735
14
17
  zwarm/core/models.py,sha256=PrC3okRBVJxISUa1Fax4KkagqLT6Xub-kTxC9drN0sY,10083
15
- zwarm/core/registry.py,sha256=MwVWpn9HWC8jwwkv94PFFbul-oY-vO0sTUKocGUNVx8,9551
18
+ zwarm/core/registry.py,sha256=ZRN2vCUU-XSVnAibGefHOb9B5hEPc-i0uh-Vr04bsHU,8935
16
19
  zwarm/core/state.py,sha256=MzrvODKEiJovI7YI1jajW4uukineZ3ezmW5oQinMgjg,11563
17
20
  zwarm/core/test_compact.py,sha256=WSdjCB5t4YMcknsrkmJIUsVOPY28s4y9GnDmu3Z4BFw,11878
18
21
  zwarm/core/test_config.py,sha256=bXXd3OHhK-ndC7wAxePWIdpu73s4O1eScxi3xDzrZwA,4828
19
22
  zwarm/core/test_models.py,sha256=sWTIhMZvuLP5AooGR6y8OR2EyWydqVfhmGrE7NPBBnk,8450
20
23
  zwarm/prompts/__init__.py,sha256=DI307o712F8qQyDt5vwnFgpVBrxpKwjhr0MaBHLzr9E,334
21
- zwarm/prompts/orchestrator.py,sha256=rfxpVCNAlTdQN8h0hgtU1OOr_9Io62ULZFisBjNUZVs,15076
22
- zwarm/prompts/pilot.py,sha256=LHo9JwOmCXcPvxXBqztYFVBt6djUhenTIW-QjppQ1vg,6041
24
+ zwarm/prompts/orchestrator.py,sha256=HPoJxtH4_4yLHv4sS2SCYRsUjQo5S7_uGCodm-K97gA,6979
25
+ zwarm/prompts/pilot.py,sha256=ZKrxJHIni3cnT-oWQmRV-S-X_PkdiJnEiLGgCjism3E,6412
23
26
  zwarm/sessions/__init__.py,sha256=5fPkl6JRS_GwPn9hi5iv3dzIpGWu_yghPtvPZdujhnM,1728
24
27
  zwarm/sessions/base.py,sha256=3YBd-WWKslQvsBtu03Blth8cEGc_4k4H3GOoKJoTcgg,16976
25
28
  zwarm/sessions/claude.py,sha256=hBP_TpNFJjR29IRGJFB3rlG7Z9uWEYSbBGV61tpIr00,16672
26
- zwarm/sessions/manager.py,sha256=Vq5PePzKfy658EVG24SFsUMXQc1OGgOm8vdOX_WPMF8,18530
29
+ zwarm/sessions/manager.py,sha256=g_QQM9sGdpQ1MK1jdwWMrADeJZY2AqfGDBLVtQasUxg,18520
27
30
  zwarm/tools/__init__.py,sha256=FpqxwXJA6-fQ7C-oLj30jjK_0qqcE7MbI0dQuaB56kU,290
28
- zwarm/tools/delegation.py,sha256=NFMX-f05r28A1OgzYaSMdrq_8VPpP1pJ_nfouYr_2zA,24690
31
+ zwarm/tools/delegation.py,sha256=UTDueeLIpYWMbCN1klPWBUno1zvkhPwqfzO4OtTQiNw,24765
29
32
  zwarm/watchers/__init__.py,sha256=a96s7X6ruYkF2ItWWOZ3Q5QUOMOoeCW4Vz8XXcYLXPM,956
30
33
  zwarm/watchers/base.py,sha256=r1GoPlj06nOT2xp4fghfSjxbRyFFFQUB6HpZbEyO2OY,3834
31
34
  zwarm/watchers/builtin.py,sha256=IL5QwwKOIqWEfJ_uQWb321Px4i5OLtI_vnWQMudqKoA,19064
32
- zwarm/watchers/llm_watcher.py,sha256=yJGpE3BGKNZX3qgPsiNtJ5d3UJpiTT1V-A-Rh4AiMYM,11029
35
+ zwarm/watchers/llm_watcher.py,sha256=bj7snjMdSbarZA9YSPHa660pTU3TnJ6RQ8rSf6YX8ys,11013
33
36
  zwarm/watchers/manager.py,sha256=XZjBVeHjgCUlkTUeHqdvBvHoBC862U1ik0fG6nlRGog,5587
34
37
  zwarm/watchers/registry.py,sha256=A9iBIVIFNtO7KPX0kLpUaP8dAK7ozqWLA44ocJGnOw4,1219
35
38
  zwarm/watchers/test_watchers.py,sha256=zOsxumBqKfR5ZVGxrNlxz6KcWjkcdp0QhW9WB0_20zM,7855
36
- zwarm-3.10.2.dist-info/METADATA,sha256=GPtjlVc851Hj_7-81_svlrLhdMz0ZpHptPrMjFnkrrs,11422
37
- zwarm-3.10.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
38
- zwarm-3.10.2.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
39
- zwarm-3.10.2.dist-info/RECORD,,
39
+ zwarm-3.10.5.dist-info/METADATA,sha256=XiRWnNB4N5oHNFaweJbjoDT4-5BHiNSdcBniJTk1lFE,11761
40
+ zwarm-3.10.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
41
+ zwarm-3.10.5.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
42
+ zwarm-3.10.5.dist-info/RECORD,,
File without changes