agentic-comms 0.9.0__tar.gz → 0.9.2__tar.gz
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.
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/PKG-INFO +1 -1
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/hook.py +22 -6
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/monitor.py +24 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/PKG-INFO +1 -1
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/pyproject.toml +1 -1
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/README.md +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/__init__.py +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/__main__.py +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/api.py +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/cli.py +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/config.py +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/install.py +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/SOURCES.txt +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/dependency_links.txt +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/entry_points.txt +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/requires.txt +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/top_level.txt +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/setup.cfg +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/tests/test_cli.py +0 -0
- {agentic_comms-0.9.0 → agentic_comms-0.9.2}/tests/test_install_codex.py +0 -0
|
@@ -677,9 +677,15 @@ def _build_wrong_handle_warning(armed_handle: str, armed_pid: int, current_handl
|
|
|
677
677
|
)
|
|
678
678
|
|
|
679
679
|
|
|
680
|
-
def _check_wrong_handle_monitors(current_handle: str) -> list[tuple[str, int]]:
|
|
680
|
+
def _check_wrong_handle_monitors(current_handle: str, claude_pid: int | None) -> list[tuple[str, int]]:
|
|
681
681
|
"""Scan ~/.cache/agent-comms/monitor-armed-* for any live Monitor (last_beat
|
|
682
|
-
within 60s) whose handle != current_handle
|
|
682
|
+
within 60s) whose handle != current_handle AND whose process is a child of
|
|
683
|
+
THIS Claude session.
|
|
684
|
+
|
|
685
|
+
The claude_pid ancestry filter eliminates the false-positive where two
|
|
686
|
+
Claude sessions share a host: each session has its own legitimate Monitor
|
|
687
|
+
with its own (correct-for-that-session) handle. Without the filter we'd
|
|
688
|
+
flag the OTHER session's perfectly-valid Monitor as wrong.
|
|
683
689
|
|
|
684
690
|
A file present but stale (>60s since last_beat) means the Monitor crashed
|
|
685
691
|
without atexit cleanup — ignored here, the regular `monitor_not_armed`
|
|
@@ -695,12 +701,22 @@ def _check_wrong_handle_monitors(current_handle: str) -> list[tuple[str, int]]:
|
|
|
695
701
|
except Exception:
|
|
696
702
|
continue
|
|
697
703
|
last_beat = float(data.get("last_beat") or 0)
|
|
698
|
-
if now - last_beat > 60:
|
|
704
|
+
if now - last_beat > 60:
|
|
699
705
|
continue
|
|
700
706
|
armed_handle = data.get("handle") or ""
|
|
701
707
|
armed_pid = int(data.get("pid") or 0)
|
|
702
|
-
if armed_handle
|
|
703
|
-
|
|
708
|
+
if not armed_handle or armed_handle == current_handle:
|
|
709
|
+
continue
|
|
710
|
+
# Ancestry filter: walk armed_pid's PPID chain. Only flag as "wrong"
|
|
711
|
+
# if our claude_pid appears in that ancestry — meaning this Monitor
|
|
712
|
+
# was spawned by THIS Claude session but somehow got the wrong handle.
|
|
713
|
+
# If claude_pid isn't found, the Monitor belongs to a sibling Claude
|
|
714
|
+
# session (legitimate, leave it alone).
|
|
715
|
+
if claude_pid and armed_pid:
|
|
716
|
+
chain = config._ppid_chain(armed_pid)
|
|
717
|
+
if claude_pid not in chain:
|
|
718
|
+
continue
|
|
719
|
+
wrong.append((armed_handle, armed_pid))
|
|
704
720
|
return wrong
|
|
705
721
|
|
|
706
722
|
|
|
@@ -861,7 +877,7 @@ def main() -> int:
|
|
|
861
877
|
# then loop forever as the operator re-armed-with-stale-handle and
|
|
862
878
|
# re-armed-with-stale-handle.
|
|
863
879
|
try:
|
|
864
|
-
wrong_monitors = _check_wrong_handle_monitors(handle)
|
|
880
|
+
wrong_monitors = _check_wrong_handle_monitors(handle, claude_pid)
|
|
865
881
|
for armed_handle, armed_pid in wrong_monitors:
|
|
866
882
|
early_pieces.append(_build_wrong_handle_warning(armed_handle, armed_pid, handle))
|
|
867
883
|
except Exception:
|
|
@@ -187,6 +187,15 @@ def main() -> int:
|
|
|
187
187
|
if not args.quiet:
|
|
188
188
|
sys.stderr.write(f"agent_comms.monitor: startup pending failed: {e}\n")
|
|
189
189
|
|
|
190
|
+
# Dedicated monitor_heartbeat POST cadence (every ~10s). Separate from the
|
|
191
|
+
# inbox poll so we don't spam the server with metadata at 1Hz. The endpoint
|
|
192
|
+
# stores {pid, version, handle} in identities.meta.monitor server-side —
|
|
193
|
+
# used for wrong-handle detection across machines and version-drift
|
|
194
|
+
# diagnostics. Wrapped in try/except so a server that doesn't have the
|
|
195
|
+
# endpoint (pre-0.9 deployments) doesn't break the poll loop.
|
|
196
|
+
last_meta_beat = 0.0
|
|
197
|
+
META_BEAT_INTERVAL = 10.0
|
|
198
|
+
|
|
190
199
|
# Main loop. Refresh self-handle file every iteration so stale files (Monitor
|
|
191
200
|
# crashed mid-loop) are detectable by mtime / last_beat.
|
|
192
201
|
while True:
|
|
@@ -202,6 +211,21 @@ def main() -> int:
|
|
|
202
211
|
except Exception as e:
|
|
203
212
|
if not args.quiet:
|
|
204
213
|
sys.stderr.write(f"agent_comms.monitor: poll failed (will retry): {e}\n")
|
|
214
|
+
# Send dedicated metadata heartbeat every ~10s (Phil's review note:
|
|
215
|
+
# version=unknown showed up server-side because we were only piggybacking
|
|
216
|
+
# on ?monitor=true inbox poll and never POSTing the new endpoint).
|
|
217
|
+
now = time.time()
|
|
218
|
+
if now - last_meta_beat >= META_BEAT_INTERVAL:
|
|
219
|
+
try:
|
|
220
|
+
client.monitor_heartbeat(args.handle, pid=os.getpid())
|
|
221
|
+
last_meta_beat = now
|
|
222
|
+
except ClientTooOldError:
|
|
223
|
+
sys.stderr.write(_too_old_message() + "\n")
|
|
224
|
+
return 2
|
|
225
|
+
except Exception:
|
|
226
|
+
# Server may be pre-0.9 (no endpoint) — fall back silently;
|
|
227
|
+
# the inbox poll's monitor=true bump still keeps online=True.
|
|
228
|
+
last_meta_beat = now # back off so we don't spam-fail
|
|
205
229
|
time.sleep(max(0.1, args.interval))
|
|
206
230
|
|
|
207
231
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|