zwarm 2.0.2__py3-none-any.whl → 2.3__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/sessions/manager.py CHANGED
@@ -301,9 +301,18 @@ class CodexSessionManager:
301
301
  session.messages = messages
302
302
  session.token_usage = usage
303
303
 
304
- if error:
304
+ # Check if we got actual assistant responses
305
+ has_response = any(m.role == "assistant" for m in messages)
306
+
307
+ if error and not has_response:
308
+ # Only mark as failed if we have an error AND no response
305
309
  session.status = SessionStatus.FAILED
306
310
  session.error = error
311
+ elif error and has_response:
312
+ # Got response but also an error (e.g., network disconnect at end)
313
+ # Treat as completed but note the error
314
+ session.status = SessionStatus.COMPLETED
315
+ session.error = f"Completed with error: {error}"
307
316
  else:
308
317
  session.status = SessionStatus.COMPLETED
309
318
  else:
@@ -634,6 +643,9 @@ Continue from where you left off, addressing the user's new message."""
634
643
  turn_usage = event.get("usage", {})
635
644
  for key, value in turn_usage.items():
636
645
  usage[key] = usage.get(key, 0) + value
646
+ # Compute total_tokens if not present
647
+ if "total_tokens" not in usage:
648
+ usage["total_tokens"] = usage.get("input_tokens", 0) + usage.get("output_tokens", 0)
637
649
 
638
650
  elif event_type == "error":
639
651
  error = event.get("message", str(event))
zwarm/tools/delegation.py CHANGED
@@ -83,6 +83,14 @@ def _format_session_header(session) -> str:
83
83
  return f"[{session.short_id}] codex ({session.status.value})"
84
84
 
85
85
 
86
+ def _get_total_tokens(session) -> int:
87
+ """Get total tokens, computing from input+output if not present."""
88
+ usage = session.token_usage
89
+ if "total_tokens" in usage:
90
+ return usage["total_tokens"]
91
+ return usage.get("input_tokens", 0) + usage.get("output_tokens", 0)
92
+
93
+
86
94
  def _validate_working_dir(
87
95
  requested_dir: Path | str | None,
88
96
  default_dir: Path,
@@ -238,6 +246,25 @@ def delegate(
238
246
  response_text = msg.content
239
247
  break # Take first assistant message
240
248
 
249
+ # Build log path for debugging
250
+ log_path = str(manager._output_path(session.id, session.turn))
251
+
252
+ # Check if session failed
253
+ from zwarm.sessions import SessionStatus
254
+ if session.status == SessionStatus.FAILED:
255
+ return {
256
+ "success": False,
257
+ "session": _format_session_header(session),
258
+ "session_id": session.id,
259
+ "status": "failed",
260
+ "task": _truncate(task, 100),
261
+ "error": session.error or "Unknown error",
262
+ "response": response_text or "(no response captured)",
263
+ "tokens": _get_total_tokens(session),
264
+ "log_file": log_path,
265
+ "hint": "Check log_file for raw codex output. Use bash('cat <log_file>') to inspect.",
266
+ }
267
+
241
268
  return {
242
269
  "success": True,
243
270
  "session": _format_session_header(session),
@@ -245,7 +272,8 @@ def delegate(
245
272
  "status": session.status.value,
246
273
  "task": _truncate(task, 100),
247
274
  "response": response_text or "(no response captured)",
248
- "tokens": session.token_usage.get("total_tokens", 0),
275
+ "tokens": _get_total_tokens(session),
276
+ "log_file": log_path,
249
277
  "hint": "Use converse(session_id, message) to send follow-up messages",
250
278
  }
251
279
  else:
@@ -382,7 +410,7 @@ def converse(
382
410
  "turn": session.turn,
383
411
  "you_said": _truncate(message, 100),
384
412
  "response": response_text or "(no response captured)",
385
- "tokens": session.token_usage.get("total_tokens", 0),
413
+ "tokens": _get_total_tokens(session),
386
414
  }
387
415
 
388
416
 
@@ -423,7 +451,10 @@ def check_session(
423
451
  response_text = msg.content
424
452
  break
425
453
 
426
- return {
454
+ # Build log path
455
+ log_path = str(manager._output_path(session.id, session.turn))
456
+
457
+ result = {
427
458
  "success": True,
428
459
  "session": _format_session_header(session),
429
460
  "session_id": session_id,
@@ -433,10 +464,19 @@ def check_session(
433
464
  "message_count": len(messages),
434
465
  "task": _truncate(session.task, 80),
435
466
  "response": _truncate(response_text, 500) if response_text else "(no response yet)",
436
- "tokens": session.token_usage.get("total_tokens", 0),
467
+ "tokens": _get_total_tokens(session),
437
468
  "runtime": session.runtime,
469
+ "log_file": log_path,
438
470
  }
439
471
 
472
+ # Add error info if failed
473
+ from zwarm.sessions import SessionStatus
474
+ if session.status == SessionStatus.FAILED:
475
+ result["success"] = False
476
+ result["error"] = session.error or "Unknown error"
477
+
478
+ return result
479
+
440
480
 
441
481
  @weaveTool
442
482
  def peek_session(
@@ -539,7 +579,7 @@ def end_session(
539
579
  "status": session.status.value,
540
580
  "reason": reason or "ended by orchestrator",
541
581
  "turn": session.turn,
542
- "tokens": session.token_usage.get("total_tokens", 0),
582
+ "tokens": _get_total_tokens(session),
543
583
  }
544
584
 
545
585
 
@@ -646,7 +686,7 @@ def list_sessions(
646
686
  "updated_secs": int(updated_secs),
647
687
  "last_message": _truncate(last_message, 100) if last_message else "(no response yet)",
648
688
  "needs_attention": needs_attention,
649
- "tokens": s.token_usage.get("total_tokens", 0),
689
+ "tokens": _get_total_tokens(s),
650
690
  })
651
691
 
652
692
  # Summary counts
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zwarm
3
- Version: 2.0.2
3
+ Version: 2.3
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
@@ -22,16 +22,16 @@ zwarm/core/test_models.py,sha256=sWTIhMZvuLP5AooGR6y8OR2EyWydqVfhmGrE7NPBBnk,845
22
22
  zwarm/prompts/__init__.py,sha256=FiaIOniLrIyfD3_osxT6I7FfyKjtctbf8jNs5QTPs_s,213
23
23
  zwarm/prompts/orchestrator.py,sha256=-VZ3B5t-2ALOTpdZyNZGSjjzaHiTufAuLzrTLgwg70M,15442
24
24
  zwarm/sessions/__init__.py,sha256=jRibY8IfmNcnkgNmrgK2T81oa1w71wP_KQp9A1hPL7Q,568
25
- zwarm/sessions/manager.py,sha256=slCDE0n9-pw6iZ08YZMjxZRwH0aoEi6MAAChLlAsuPw,22212
25
+ zwarm/sessions/manager.py,sha256=XDwXXZKJwxgBXOl4Mf61_BCdYoKU7lpJHxE_7Lyzuy4,22946
26
26
  zwarm/tools/__init__.py,sha256=FpqxwXJA6-fQ7C-oLj30jjK_0qqcE7MbI0dQuaB56kU,290
27
- zwarm/tools/delegation.py,sha256=2NI9J2VArVUbqOTZJY8Vgz5Rd5nI7BdZ8GNaYVIR_JU,20886
27
+ zwarm/tools/delegation.py,sha256=FFfZvDnppbbqsTeoYUned6gjqwE9m1gkJ09jSkiiWps,22307
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.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,,
34
+ zwarm-2.3.dist-info/METADATA,sha256=fBqubqwFUeool8DcYfqk66WQsG42plPI27JLbrTpg3Q,7678
35
+ zwarm-2.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
36
+ zwarm-2.3.dist-info/entry_points.txt,sha256=u0OXq4q8d3yJ3EkUXwZfkS-Y8Lcy0F8cWrcQfoRxM6Q,46
37
+ zwarm-2.3.dist-info/RECORD,,
File without changes