meshcode 1.2.3__tar.gz → 1.2.5__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 (24) hide show
  1. {meshcode-1.2.3 → meshcode-1.2.5}/PKG-INFO +1 -1
  2. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/__init__.py +1 -1
  3. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/meshcode_mcp/server.py +192 -1
  4. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-1.2.3 → meshcode-1.2.5}/pyproject.toml +1 -1
  6. {meshcode-1.2.3 → meshcode-1.2.5}/README.md +0 -0
  7. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/cli.py +0 -0
  8. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/comms_v4.py +0 -0
  9. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/launcher.py +0 -0
  10. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/launcher_install.py +0 -0
  11. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/meshcode_mcp/__init__.py +0 -0
  12. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/meshcode_mcp/__main__.py +0 -0
  13. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/meshcode_mcp/backend.py +0 -0
  14. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/meshcode_mcp/realtime.py +0 -0
  15. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/meshcode_mcp/test_backend.py +0 -0
  16. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  17. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/protocol_v2.py +0 -0
  18. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode/setup_clients.py +0 -0
  19. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode.egg-info/SOURCES.txt +0 -0
  20. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode.egg-info/dependency_links.txt +0 -0
  21. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode.egg-info/entry_points.txt +0 -0
  22. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode.egg-info/requires.txt +0 -0
  23. {meshcode-1.2.3 → meshcode-1.2.5}/meshcode.egg-info/top_level.txt +0 -0
  24. {meshcode-1.2.3 → meshcode-1.2.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 1.2.3
3
+ Version: 1.2.5
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__ = "1.2.3"
2
+ __version__ = "1.2.5"
@@ -67,6 +67,125 @@ except Exception as _e:
67
67
  print(f"[meshcode-mcp] WARNING: could not flip status to online: {_e}", file=sys.stderr)
68
68
 
69
69
 
70
+ # ============================================================
71
+ # Agent identity from Supabase profile (for system instructions)
72
+ # ============================================================
73
+
74
+ _LAUNCH_PROMPT = ""
75
+ _ROLE_DESCRIPTION = AGENT_ROLE or ""
76
+ try:
77
+ _profile = be.sb_rpc("mc_agent_get_profile", {
78
+ "p_project_id": _PROJECT_ID,
79
+ "p_agent_name": AGENT_NAME,
80
+ })
81
+ if isinstance(_profile, list) and _profile:
82
+ _profile = _profile[0]
83
+ if isinstance(_profile, dict):
84
+ _inner = _profile.get("profile") if isinstance(_profile.get("profile"), dict) else _profile
85
+ _LAUNCH_PROMPT = (_inner.get("launch_prompt") or _profile.get("launch_prompt") or "") if isinstance(_inner, dict) else ""
86
+ _ROLE_DESCRIPTION = (
87
+ (_inner.get("role_description") if isinstance(_inner, dict) else None)
88
+ or _profile.get("role_description")
89
+ or _profile.get("role")
90
+ or AGENT_ROLE
91
+ or "(unspecified)"
92
+ )
93
+ except Exception as _e:
94
+ log.warning(f"could not fetch agent profile: {_e}")
95
+
96
+
97
+ def _build_instructions() -> str:
98
+ """Build the system-instructions block injected via the MCP InitializeResult.
99
+
100
+ Per the MCP spec, servers may return an `instructions` field that compatible
101
+ clients (Claude Code, Cursor, Cline, etc.) merge into the model's system
102
+ context at session start. This is how we make the mesh "be" the agent — no
103
+ user setup, no launch_prompt fiddling, no per-session prompt engineering.
104
+ """
105
+ role_block = f"\nROLE: {_ROLE_DESCRIPTION}\n" if _ROLE_DESCRIPTION else ""
106
+ launch_block = (
107
+ f"\nUSER-PROVIDED ROLE PROMPT (from the dashboard):\n---\n{_LAUNCH_PROMPT}\n---\n"
108
+ if _LAUNCH_PROMPT else ""
109
+ )
110
+ return f"""You are an autonomous AI agent inside a MeshCode meshwork.
111
+
112
+ IDENTITY (this is who you are — you cannot leave or change this):
113
+ - Meshwork (project): {PROJECT_NAME}
114
+ - Your agent name: {AGENT_NAME}{role_block}{launch_block}
115
+
116
+ THE MESH PROTOCOL — READ CAREFULLY, THIS IS YOUR PRIMARY BEHAVIOR LOOP:
117
+
118
+ You are connected in real time to other AI agents in this meshwork. You can
119
+ send them messages and they can send you messages at any moment, including
120
+ while you are idle. You don't need to "join" the mesh — the MCP connection
121
+ already made you a member. The mesh tools are part of your body now.
122
+
123
+ YOUR DEFAULT BEHAVIOR LOOP (do this without being asked):
124
+
125
+ 1. When the user gives you an initial task or you receive a mesh message,
126
+ read it, decide what to do, and act.
127
+ 2. Whenever your work depends on another agent's expertise, output, or
128
+ review, send them a message via the meshcode_send tool. Do not wait
129
+ for the user to tell you to coordinate — collaborating with the other
130
+ mesh agents is your job.
131
+ 3. When you would normally finish a turn and return to the user, INSTEAD
132
+ call the meshcode_wait tool. It blocks for up to 4 minutes inside the
133
+ MCP server, listening for incoming mesh messages. While inside this
134
+ call you ARE listening — your turn never actually ends.
135
+ 4. When meshcode_wait returns with a message, treat it exactly like a new
136
+ user prompt. Read it, decide if it requires action or a reply, take
137
+ action, send a reply via meshcode_send if appropriate, then call
138
+ meshcode_wait AGAIN to keep listening.
139
+ 5. When meshcode_wait returns timed_out (no message in 4 min), call it
140
+ AGAIN immediately. Do not return to the user. The loop is your
141
+ default state — you are a long-running mesh agent, not a one-shot
142
+ chatbot.
143
+
144
+ YOU SHOULD ONLY BREAK OUT OF THE meshcode_wait LOOP IF:
145
+ - The human user explicitly says "stop" or pressed Ctrl+C.
146
+ - A mesh message explicitly says "tell the human X" — in that case,
147
+ return to the user with that message AND then re-enter the loop.
148
+ - A fatal error happens that requires user intervention.
149
+
150
+ LOOP-SAFETY RULES (IMPORTANT — prevent token-burning ping-pong):
151
+ - Do NOT reply "Done" / "OK" / "Got it" to every message. If a message
152
+ is a status update or pure ack, just process it and call meshcode_wait
153
+ again WITHOUT sending a reply.
154
+ - Do NOT bounce the same message back to the sender.
155
+ - Only send a message if you have substantive new information, a real
156
+ question, or a real action result to share.
157
+ - If you find yourself sending more than ~10 messages on the same topic
158
+ in a row, stop and reassess — you may be in a feedback loop.
159
+
160
+ YOUR FIRST ACTIONS WHEN THIS SESSION STARTS:
161
+ 1. Call meshcode_status() once to see who else is in the meshwork.
162
+ 2. Call meshcode_set_status(status="online", task="ready") to announce
163
+ your presence on the dashboard.
164
+ 3. If the human user has given you an initial task, do it now.
165
+ 4. When you have nothing else to do (or right after sending a mesh
166
+ message that expects a reply), call meshcode_wait() to enter your
167
+ idle/listening state. Stay there forever unless one of the
168
+ break-out conditions above fires.
169
+
170
+ AVAILABLE MESH TOOLS (all from this MCP server):
171
+ meshcode_wait — block until a mesh message arrives (your idle state)
172
+ meshcode_send — send a message to another mesh agent
173
+ meshcode_check — non-blocking peek at the inbox count
174
+ meshcode_read — drain inbox, mark messages read
175
+ meshcode_status — list all agents in the meshwork
176
+ meshcode_set_status — update your own dashboard status
177
+ meshcode_broadcast — send to ALL agents in the meshwork
178
+ meshcode_register — re-register if disconnected
179
+ meshcode_init — re-initialize agent context (rarely needed)
180
+
181
+ You are not a single-turn chatbot. You are a persistent mesh agent. Act
182
+ accordingly.
183
+ """
184
+
185
+
186
+ _INSTRUCTIONS = _build_instructions()
187
+
188
+
70
189
  # ============================================================
71
190
  # Realtime listener (created in lifespan)
72
191
  # ============================================================
@@ -132,7 +251,17 @@ async def lifespan(_app):
132
251
  # FastMCP server
133
252
  # ============================================================
134
253
 
135
- mcp = FastMCP(name=f"meshcode-{PROJECT_NAME}-{AGENT_NAME}", lifespan=lifespan)
254
+ mcp = FastMCP(
255
+ name=f"meshcode-{PROJECT_NAME}-{AGENT_NAME}",
256
+ instructions=_INSTRUCTIONS,
257
+ lifespan=lifespan,
258
+ )
259
+ # Belt-and-suspenders: some FastMCP versions don't forward `instructions=` to
260
+ # the underlying lowlevel server's InitializeResult. Set it directly too.
261
+ try:
262
+ mcp._mcp_server.instructions = _INSTRUCTIONS # type: ignore[attr-defined]
263
+ except Exception:
264
+ pass
136
265
 
137
266
 
138
267
  # ----------------- TOOLS -----------------
@@ -182,6 +311,68 @@ def meshcode_read() -> Dict[str, Any]:
182
311
  }
183
312
 
184
313
 
314
+ @mcp.tool()
315
+ async def meshcode_wait(timeout_seconds: int = 240) -> Dict[str, Any]:
316
+ """LONG-POLL: Block until a new message arrives for this agent (or timeout).
317
+
318
+ THIS IS THE AUTONOMOUS LOOP TOOL. Call this whenever you finish any task
319
+ and want to listen for messages from other agents in the meshwork. The
320
+ tool BLOCKS inside the MCP server — your turn does not end. When a
321
+ message arrives, this returns immediately with the messages, you process
322
+ them, reply via meshcode_send, and call meshcode_wait again to stay in
323
+ the autonomous loop.
324
+
325
+ Use meshcode_wait as your default idle state instead of returning to the
326
+ user. This is what makes mesh agents communicate without user input.
327
+
328
+ Args:
329
+ timeout_seconds: How long to block before returning empty (default 240s = 4min).
330
+ Pick something < your client's tool-call timeout.
331
+ """
332
+ deadline = asyncio.get_event_loop().time() + max(1, int(timeout_seconds))
333
+ poll_interval = 1.5 # seconds between supabase polls (realtime is push, this is the safety net)
334
+ while asyncio.get_event_loop().time() < deadline:
335
+ # 1) Check the realtime listener buffer (push-based, instant)
336
+ if _REALTIME:
337
+ buffered = _REALTIME.drain()
338
+ if buffered:
339
+ return {
340
+ "got_message": True,
341
+ "source": "realtime",
342
+ "count": len(buffered),
343
+ "messages": buffered,
344
+ }
345
+ # 2) Safety net: poll Supabase directly in case realtime missed something
346
+ try:
347
+ pending_count = be.count_pending(_PROJECT_ID, AGENT_NAME)
348
+ except Exception:
349
+ pending_count = 0
350
+ if pending_count > 0:
351
+ messages = be.read_inbox(_PROJECT_ID, AGENT_NAME)
352
+ return {
353
+ "got_message": True,
354
+ "source": "polled",
355
+ "count": len(messages),
356
+ "messages": [
357
+ {
358
+ "from": m["from_agent"],
359
+ "type": m.get("type", "msg"),
360
+ "ts": m.get("created_at"),
361
+ "payload": m.get("payload", {}),
362
+ }
363
+ for m in messages
364
+ ],
365
+ }
366
+ await asyncio.sleep(poll_interval)
367
+
368
+ return {
369
+ "got_message": False,
370
+ "timed_out": True,
371
+ "agent": AGENT_NAME,
372
+ "hint": "No messages arrived. Call meshcode_wait again to keep listening.",
373
+ }
374
+
375
+
185
376
  @mcp.tool()
186
377
  def meshcode_check() -> Dict[str, Any]:
187
378
  """Quick poll: returns pending message count + any messages buffered by the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 1.2.3
3
+ Version: 1.2.5
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 = "1.2.3"
7
+ version = "1.2.5"
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