meshcode 2.5.6__tar.gz → 2.5.7__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.5.6 → meshcode-2.5.7}/PKG-INFO +1 -1
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/__init__.py +1 -1
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/server.py +113 -6
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.5.6 → meshcode-2.5.7}/pyproject.toml +1 -1
- {meshcode-2.5.6 → meshcode-2.5.7}/README.md +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/cli.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/comms_v4.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/invites.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/launcher.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/launcher_install.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/preferences.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/run_agent.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/secrets.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/self_update.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode/setup_clients.py +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/setup.cfg +0 -0
- {meshcode-2.5.6 → meshcode-2.5.7}/tests/test_status_enum_coverage.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "2.5.
|
|
2
|
+
__version__ = "2.5.7"
|
|
@@ -748,9 +748,10 @@ SESSION START (do these IMMEDIATELY — don't wait for user input):
|
|
|
748
748
|
1. meshcode_set_status(status="online", task="ready")
|
|
749
749
|
2. meshcode_check() — read pending messages
|
|
750
750
|
3. meshcode_tasks() — check for assigned/pending tasks and claim any unclaimed ones
|
|
751
|
-
4.
|
|
752
|
-
5.
|
|
753
|
-
6.
|
|
751
|
+
4. meshcode_auto_wake() — scan meshwork health, create tasks for issues found
|
|
752
|
+
5. meshcode_status() — see who's online
|
|
753
|
+
6. If other agents are online → meshcode_send them a greeting
|
|
754
|
+
7. meshcode_wait() — enter the loop
|
|
754
755
|
|
|
755
756
|
CRITICAL: You communicate by CALLING TOOLS, not by thinking or writing text.
|
|
756
757
|
To talk to another agent → call meshcode_send(to="agent", message="...")
|
|
@@ -792,6 +793,9 @@ COMMANDER PROTOCOL (you are the team lead):
|
|
|
792
793
|
- Keep the human informed with brief status updates at milestones.
|
|
793
794
|
- You are autonomous: fix small issues yourself, delegate big ones.
|
|
794
795
|
- After each sprint: consolidate learnings, update scratchpad, save to memory.
|
|
796
|
+
- PROACTIVE MAINTENANCE: call meshcode_auto_wake() on session start and after
|
|
797
|
+
completing sprints. It scans meshwork health (stale agents, task backlog,
|
|
798
|
+
empty memories). Turn suggestions into real tasks — quality over quantity.
|
|
795
799
|
"""
|
|
796
800
|
return base
|
|
797
801
|
|
|
@@ -1132,10 +1136,27 @@ def meshcode_send(to: str, message: Any, in_reply_to: Optional[str] = None,
|
|
|
1132
1136
|
# Cross-mesh routing: if 'to' contains '@', parse as agent@meshwork
|
|
1133
1137
|
if "@" in to:
|
|
1134
1138
|
target_agent, target_meshwork = to.split("@", 1)
|
|
1135
|
-
if sensitive
|
|
1136
|
-
return {"error": "sensitive
|
|
1139
|
+
if sensitive and not encrypted:
|
|
1140
|
+
return {"error": "sensitive messages must use encrypted=True for cross-mesh"}
|
|
1137
1141
|
api_key = _get_api_key()
|
|
1138
|
-
|
|
1142
|
+
|
|
1143
|
+
# Bridge re-encryption: encrypt payload with the TARGET mesh key so
|
|
1144
|
+
# the receiving agent decrypts normally. Uses mc_get_cross_mesh_key
|
|
1145
|
+
# RPC which validates the link exists before returning the key.
|
|
1146
|
+
if encrypted:
|
|
1147
|
+
key_result = be.sb_rpc("mc_get_cross_mesh_key", {
|
|
1148
|
+
"p_api_key": api_key,
|
|
1149
|
+
"p_source_project": PROJECT_NAME,
|
|
1150
|
+
"p_target_project": target_meshwork,
|
|
1151
|
+
})
|
|
1152
|
+
if not isinstance(key_result, dict) or not key_result.get("ok"):
|
|
1153
|
+
err = key_result.get("error", "unknown") if isinstance(key_result, dict) else "RPC failed"
|
|
1154
|
+
return {"error": f"cross-mesh encryption failed: {err}"}
|
|
1155
|
+
tgt_key = key_result["key"]
|
|
1156
|
+
encrypted_data = be.encrypt_payload(payload, tgt_key)
|
|
1157
|
+
payload = {"_encrypted": encrypted_data}
|
|
1158
|
+
|
|
1159
|
+
result = be.sb_rpc("mc_send_cross_mesh", {
|
|
1139
1160
|
"p_api_key": api_key,
|
|
1140
1161
|
"p_from_project": PROJECT_NAME,
|
|
1141
1162
|
"p_from_agent": AGENT_NAME,
|
|
@@ -1144,6 +1165,9 @@ def meshcode_send(to: str, message: Any, in_reply_to: Optional[str] = None,
|
|
|
1144
1165
|
"p_payload": payload,
|
|
1145
1166
|
"p_type": "msg",
|
|
1146
1167
|
})
|
|
1168
|
+
if isinstance(result, dict) and result.get("ok") and encrypted:
|
|
1169
|
+
result["encrypted"] = True
|
|
1170
|
+
return result
|
|
1147
1171
|
|
|
1148
1172
|
return be.send_message(_PROJECT_ID, AGENT_NAME, to, payload, msg_type="msg",
|
|
1149
1173
|
parent_msg_id=in_reply_to, sensitive=sensitive,
|
|
@@ -1578,6 +1602,89 @@ def meshcode_task_reject(task_id: str, feedback: str = "") -> Dict[str, Any]:
|
|
|
1578
1602
|
})
|
|
1579
1603
|
|
|
1580
1604
|
|
|
1605
|
+
# ----------------- PROACTIVE HEALTH SCAN -----------------
|
|
1606
|
+
|
|
1607
|
+
@mcp.tool()
|
|
1608
|
+
@with_working_status
|
|
1609
|
+
def meshcode_auto_wake() -> Dict[str, Any]:
|
|
1610
|
+
"""Scan meshwork health and suggest maintenance tasks.
|
|
1611
|
+
|
|
1612
|
+
Checks: stale agents, task backlog, empty memories, unlinked meshworks.
|
|
1613
|
+
Returns a list of suggested tasks the commander can create.
|
|
1614
|
+
Call this on session start or periodically to keep the meshwork healthy.
|
|
1615
|
+
"""
|
|
1616
|
+
api_key = _get_api_key()
|
|
1617
|
+
suggestions: List[Dict[str, str]] = []
|
|
1618
|
+
|
|
1619
|
+
# 1. Check for stale agents (heartbeat >10 min, not offline/sleeping)
|
|
1620
|
+
try:
|
|
1621
|
+
agents = be.get_board(_PROJECT_ID)
|
|
1622
|
+
import datetime as _dt
|
|
1623
|
+
now = _dt.datetime.now(_dt.timezone.utc)
|
|
1624
|
+
for a in agents:
|
|
1625
|
+
if a.get("status") in ("offline", "sleeping", "done", "needs_setup"):
|
|
1626
|
+
continue
|
|
1627
|
+
hb = a.get("last_heartbeat")
|
|
1628
|
+
if hb:
|
|
1629
|
+
try:
|
|
1630
|
+
dt = _dt.datetime.fromisoformat(str(hb).replace("Z", "+00:00"))
|
|
1631
|
+
age_min = (now - dt).total_seconds() / 60
|
|
1632
|
+
if age_min > 10:
|
|
1633
|
+
suggestions.append({
|
|
1634
|
+
"title": f"Stale agent: {a['name']} ({int(age_min)}min no heartbeat)",
|
|
1635
|
+
"priority": "high",
|
|
1636
|
+
"assignee": "mesh-commander",
|
|
1637
|
+
"description": f"Agent {a['name']} shows status '{a.get('status')}' but last heartbeat was {int(age_min)} min ago. Force disconnect or investigate.",
|
|
1638
|
+
})
|
|
1639
|
+
except Exception:
|
|
1640
|
+
pass
|
|
1641
|
+
except Exception:
|
|
1642
|
+
pass
|
|
1643
|
+
|
|
1644
|
+
# 2. Check task backlog — open tasks with no assignee
|
|
1645
|
+
try:
|
|
1646
|
+
task_result = be.task_list(api_key, _PROJECT_ID, AGENT_NAME, status_filter="open")
|
|
1647
|
+
if isinstance(task_result, dict) and task_result.get("ok"):
|
|
1648
|
+
open_tasks = task_result.get("tasks", [])
|
|
1649
|
+
unassigned = [t for t in open_tasks if not t.get("assigned_to") or t.get("assigned_to") == "*"]
|
|
1650
|
+
if len(unassigned) > 3:
|
|
1651
|
+
suggestions.append({
|
|
1652
|
+
"title": f"Task backlog: {len(unassigned)} unassigned open tasks",
|
|
1653
|
+
"priority": "normal",
|
|
1654
|
+
"assignee": "mesh-commander",
|
|
1655
|
+
"description": "Review and assign or close stale tasks to keep the board clean.",
|
|
1656
|
+
})
|
|
1657
|
+
except Exception:
|
|
1658
|
+
pass
|
|
1659
|
+
|
|
1660
|
+
# 3. Check for agents with zero memories
|
|
1661
|
+
try:
|
|
1662
|
+
for a in agents:
|
|
1663
|
+
mem_result = be.sb_rpc("mc_recall_all", {
|
|
1664
|
+
"p_api_key": api_key,
|
|
1665
|
+
"p_project_id": _PROJECT_ID,
|
|
1666
|
+
"p_agent_name": a["name"],
|
|
1667
|
+
})
|
|
1668
|
+
if isinstance(mem_result, dict) and mem_result.get("ok"):
|
|
1669
|
+
memories = mem_result.get("memories", [])
|
|
1670
|
+
if len(memories) == 0 and a.get("status") not in ("needs_setup",):
|
|
1671
|
+
suggestions.append({
|
|
1672
|
+
"title": f"Agent {a['name']} has zero memories",
|
|
1673
|
+
"priority": "normal",
|
|
1674
|
+
"assignee": a["name"],
|
|
1675
|
+
"description": "Agent should save learnings, patterns, and preferences to memory for cross-session persistence.",
|
|
1676
|
+
})
|
|
1677
|
+
except Exception:
|
|
1678
|
+
pass
|
|
1679
|
+
|
|
1680
|
+
return {
|
|
1681
|
+
"ok": True,
|
|
1682
|
+
"suggestions": suggestions,
|
|
1683
|
+
"total": len(suggestions),
|
|
1684
|
+
"note": "Use meshcode_task_create to turn suggestions into assigned tasks.",
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
|
|
1581
1688
|
# ----------------- MESH LINK TOOLS -----------------
|
|
1582
1689
|
|
|
1583
1690
|
@mcp.tool()
|
|
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
|