meshcode 2.6.7__tar.gz → 2.6.8__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.
Files changed (31) hide show
  1. {meshcode-2.6.7 → meshcode-2.6.8}/PKG-INFO +1 -1
  2. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/__init__.py +1 -1
  3. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/server.py +51 -42
  4. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.6.7 → meshcode-2.6.8}/pyproject.toml +1 -1
  6. {meshcode-2.6.7 → meshcode-2.6.8}/README.md +0 -0
  7. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/cli.py +0 -0
  8. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/comms_v4.py +0 -0
  9. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/invites.py +0 -0
  10. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/launcher.py +0 -0
  11. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/launcher_install.py +0 -0
  12. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/__init__.py +0 -0
  13. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/__main__.py +0 -0
  14. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/backend.py +0 -0
  15. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/realtime.py +0 -0
  16. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/test_backend.py +0 -0
  17. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  18. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  19. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/preferences.py +0 -0
  20. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/protocol_v2.py +0 -0
  21. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/run_agent.py +0 -0
  22. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/secrets.py +0 -0
  23. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/self_update.py +0 -0
  24. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/setup_clients.py +0 -0
  25. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/SOURCES.txt +0 -0
  26. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/dependency_links.txt +0 -0
  27. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/entry_points.txt +0 -0
  28. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/requires.txt +0 -0
  29. {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/top_level.txt +0 -0
  30. {meshcode-2.6.7 → meshcode-2.6.8}/setup.cfg +0 -0
  31. {meshcode-2.6.7 → meshcode-2.6.8}/tests/test_status_enum_coverage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.6.7
3
+ Version: 2.6.8
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -1,2 +1,2 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.6.7"
2
+ __version__ = "2.6.8"
@@ -1335,10 +1335,16 @@ def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
1335
1335
  @mcp.tool()
1336
1336
  @with_working_status
1337
1337
  async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False) -> Dict[str, Any]:
1338
- """Block until a mesh message arrives or timeout. Your idle state.
1338
+ """Block until a mesh message arrives or a task needs attention.
1339
+
1340
+ INTERNAL LOOP: This function loops internally and only returns when
1341
+ there is real work (message, task, or done signal). The agent NEVER
1342
+ needs to decide whether to call meshcode_wait() again — it just stays
1343
+ blocked here until something happens. This prevents agents from
1344
+ accidentally using ScheduleWakeup or exiting the loop.
1339
1345
 
1340
1346
  Args:
1341
- timeout_seconds: Max wait time in seconds (default 120, hard cap 120).
1347
+ timeout_seconds: Max wait time per poll cycle (default 120, hard cap 120).
1342
1348
  """
1343
1349
  global _IN_WAIT, _CONSECUTIVE_IDLE_SECONDS, _LAST_SEEN_TS
1344
1350
 
@@ -1353,13 +1359,9 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
1353
1359
  }
1354
1360
 
1355
1361
  # PRODUCT RULE 2: If agent has unread messages in DB, refuse to wait.
1356
- # The in-memory dedupe (_SEEN_MSG_IDS) can mark messages as "seen" via
1357
- # realtime without the agent actually processing them. Always check DB.
1358
1362
  try:
1359
1363
  db_pending = be.count_pending(_PROJECT_ID, AGENT_NAME, api_key=_get_api_key())
1360
1364
  if db_pending and db_pending > 0:
1361
- # Fetch and return the messages — mark_read=True so the next
1362
- # meshcode_wait() won't re-refuse with the same messages.
1363
1365
  raw = be.read_inbox(_PROJECT_ID, AGENT_NAME, mark_read=True, api_key=_get_api_key())
1364
1366
  msgs = [
1365
1367
  {"from": m["from_agent"], "type": m.get("type", "msg"),
@@ -1379,42 +1381,51 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
1379
1381
 
1380
1382
  _IN_WAIT = True
1381
1383
  _set_state("waiting", "listening for messages")
1382
- # Universal hard cap: even if a caller passes a larger value (e.g. 1800),
1383
- # clamp to 120s. Forces shorter iteration loops across all users so progress
1384
- # never hides behind a long wait. Per mesh-commander 2026-04-11.
1385
1384
  capped_timeout = min(max(1, int(timeout_seconds)), 120)
1386
1385
  try:
1387
- result = await _meshcode_wait_inner(actual_timeout=capped_timeout, include_acks=include_acks)
1388
- if result.get("got_message"):
1389
- _set_state("online", "")
1390
- _CONSECUTIVE_IDLE_SECONDS = 0 # reset on message received
1391
- elif result.get("timed_out"):
1392
- _CONSECUTIVE_IDLE_SECONDS += capped_timeout
1393
- if _AUTO_SLEEP_THRESHOLD > 0 and _CONSECUTIVE_IDLE_SECONDS >= _AUTO_SLEEP_THRESHOLD:
1394
- # Auto-sleep: set status to sleeping and signal the agent to exit
1395
- try:
1396
- api_key = _get_api_key()
1397
- if api_key:
1398
- be.sb_rpc("mc_agent_set_status_by_api_key", {
1399
- "p_api_key": api_key,
1400
- "p_project_id": _PROJECT_ID,
1401
- "p_agent_name": AGENT_NAME,
1402
- "p_status": "sleeping",
1403
- "p_task": f"auto-sleep after {_CONSECUTIVE_IDLE_SECONDS}s idle",
1404
- })
1405
- except Exception:
1406
- pass
1386
+ # ── INTERNAL LOOP ──────────────────────────────────────────
1387
+ # Keep polling until something actionable arrives.
1388
+ # The agent (LLM) is NOT called between iterations — zero token cost.
1389
+ while True:
1390
+ result = await _meshcode_wait_inner(actual_timeout=capped_timeout, include_acks=include_acks)
1391
+
1392
+ if result.get("got_message"):
1393
+ # Real message arrived return to agent for processing
1394
+ _set_state("online", "")
1407
1395
  _CONSECUTIVE_IDLE_SECONDS = 0
1408
- return {
1409
- "auto_sleep": True,
1410
- "idle_seconds": _CONSECUTIVE_IDLE_SECONDS,
1411
- "threshold": _AUTO_SLEEP_THRESHOLD,
1412
- "instruction": "You have been idle for a while. Status set to sleeping. Call meshcode_wait() again to keep listening — do NOT exit the loop or use ScheduleWakeup.",
1413
- }
1414
- # Auto-inject pending tasks so agents don't forget to check
1415
- pending_tasks = _get_pending_tasks_summary()
1416
- if pending_tasks:
1417
- result["pending_tasks"] = pending_tasks
1396
+ break
1397
+
1398
+ if result.get("timed_out"):
1399
+ _CONSECUTIVE_IDLE_SECONDS += capped_timeout
1400
+
1401
+ # Check if new tasks appeared while we waited
1402
+ pending_tasks = _get_pending_tasks_summary()
1403
+ if pending_tasks:
1404
+ result["pending_tasks"] = pending_tasks
1405
+ break # Return so agent can work tasks
1406
+
1407
+ # Update status to sleeping after threshold, but keep looping
1408
+ if _AUTO_SLEEP_THRESHOLD > 0 and _CONSECUTIVE_IDLE_SECONDS >= _AUTO_SLEEP_THRESHOLD:
1409
+ try:
1410
+ api_key = _get_api_key()
1411
+ if api_key:
1412
+ be.sb_rpc("mc_agent_set_status_by_api_key", {
1413
+ "p_api_key": api_key,
1414
+ "p_project_id": _PROJECT_ID,
1415
+ "p_agent_name": AGENT_NAME,
1416
+ "p_status": "sleeping",
1417
+ "p_task": f"idle {_CONSECUTIVE_IDLE_SECONDS}s — still listening",
1418
+ })
1419
+ except Exception:
1420
+ pass
1421
+ # Do NOT return — keep looping. Status says sleeping but
1422
+ # we are still listening for messages via realtime.
1423
+ _set_state("sleeping", f"idle {_CONSECUTIVE_IDLE_SECONDS}s — still listening")
1424
+
1425
+ # No messages, no tasks — loop back and wait again
1426
+ continue
1427
+ # ── END INTERNAL LOOP ──────────────────────────────────────
1428
+
1418
1429
  # Track last seen timestamp for message dedup
1419
1430
  if result.get("got_message"):
1420
1431
  msgs = result.get("messages", [])
@@ -1422,7 +1433,6 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
1422
1433
  latest_ts = max((m.get("ts", "") for m in msgs), default="")
1423
1434
  if latest_ts:
1424
1435
  _LAST_SEEN_TS = latest_ts
1425
- # Persist to mesh memory so next session resumes here
1426
1436
  try:
1427
1437
  be.sb_rpc("mc_memory_set", {
1428
1438
  "p_api_key": _get_api_key(),
@@ -1432,7 +1442,7 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
1432
1442
  "p_project_name": PROJECT_NAME,
1433
1443
  })
1434
1444
  except Exception:
1435
- pass # best-effort, never block wait loop
1445
+ pass
1436
1446
  return result
1437
1447
  finally:
1438
1448
  _IN_WAIT = False
@@ -1559,7 +1569,6 @@ async def _meshcode_wait_inner(actual_timeout: int, include_acks: bool) -> Dict[
1559
1569
  out["pending_tasks"] = pending_tasks
1560
1570
  else:
1561
1571
  out["no_work"] = True
1562
- out["hint"] = "No messages or tasks. Safe to sleep — launcher daemon will wake you on new messages."
1563
1572
  return out
1564
1573
 
1565
1574
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.6.7
3
+ Version: 2.6.8
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.6.7"
7
+ version = "2.6.8"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes