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.
- {meshcode-2.6.7 → meshcode-2.6.8}/PKG-INFO +1 -1
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/__init__.py +1 -1
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/server.py +51 -42
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.6.7 → meshcode-2.6.8}/pyproject.toml +1 -1
- {meshcode-2.6.7 → meshcode-2.6.8}/README.md +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/cli.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/comms_v4.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/invites.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/launcher.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/launcher_install.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/preferences.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/run_agent.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/secrets.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/self_update.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode/setup_clients.py +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/setup.cfg +0 -0
- {meshcode-2.6.7 → meshcode-2.6.8}/tests/test_status_enum_coverage.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "2.6.
|
|
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
|
|
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
|
|
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
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
if
|
|
1394
|
-
#
|
|
1395
|
-
|
|
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
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
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
|
|
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
|
|
|
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
|
|
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
|