meshcode 2.0.8__tar.gz → 2.0.9__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 (29) hide show
  1. {meshcode-2.0.8 → meshcode-2.0.9}/PKG-INFO +1 -1
  2. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/__init__.py +1 -1
  3. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/meshcode_mcp/backend.py +67 -3
  4. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/meshcode_mcp/server.py +5 -0
  5. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode.egg-info/PKG-INFO +1 -1
  6. {meshcode-2.0.8 → meshcode-2.0.9}/pyproject.toml +1 -1
  7. {meshcode-2.0.8 → meshcode-2.0.9}/README.md +0 -0
  8. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/cli.py +0 -0
  9. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/comms_v4.py +0 -0
  10. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/invites.py +0 -0
  11. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/launcher.py +0 -0
  12. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/launcher_install.py +0 -0
  13. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/meshcode_mcp/__init__.py +0 -0
  14. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/meshcode_mcp/__main__.py +0 -0
  15. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/meshcode_mcp/realtime.py +0 -0
  16. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/meshcode_mcp/test_backend.py +0 -0
  17. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  18. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/preferences.py +0 -0
  19. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/protocol_v2.py +0 -0
  20. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/run_agent.py +0 -0
  21. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/secrets.py +0 -0
  22. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/self_update.py +0 -0
  23. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode/setup_clients.py +0 -0
  24. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode.egg-info/SOURCES.txt +0 -0
  25. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode.egg-info/dependency_links.txt +0 -0
  26. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode.egg-info/entry_points.txt +0 -0
  27. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode.egg-info/requires.txt +0 -0
  28. {meshcode-2.0.8 → meshcode-2.0.9}/meshcode.egg-info/top_level.txt +0 -0
  29. {meshcode-2.0.8 → meshcode-2.0.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.0.8
3
+ Version: 2.0.9
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.0.8"
2
+ __version__ = "2.0.9"
@@ -105,6 +105,29 @@ def sb_update(table: str, filters: str, updates: Dict) -> Any:
105
105
  return _request("PATCH", f"{table}?{filters}", data=updates, prefer="return=representation")
106
106
 
107
107
 
108
+ # Session recording config — set by MCP server at boot
109
+ _recording_enabled = False
110
+ _recording_api_key = ""
111
+ _recording_project_id = ""
112
+ _recording_agent_name = ""
113
+ _recording_session_id = ""
114
+
115
+ # RPCs that should NOT be recorded (internal/heartbeat/recording itself)
116
+ _SKIP_RECORDING = {"mc_heartbeat", "mc_record_event", "mc_agent_set_status_by_api_key",
117
+ "mc_acquire_agent_lease", "mc_release_agent_lease"}
118
+
119
+
120
+ def enable_recording(api_key: str, project_id: str, agent_name: str, session_id: str):
121
+ """Called by MCP server at boot to enable session recording."""
122
+ global _recording_enabled, _recording_api_key, _recording_project_id
123
+ global _recording_agent_name, _recording_session_id
124
+ _recording_enabled = True
125
+ _recording_api_key = api_key
126
+ _recording_project_id = project_id
127
+ _recording_agent_name = agent_name
128
+ _recording_session_id = session_id
129
+
130
+
108
131
  def sb_rpc(fn_name: str, params: Dict) -> Any:
109
132
  url = f"{SUPABASE_URL}/rest/v1/rpc/{fn_name}"
110
133
  body = json.dumps(params).encode("utf-8")
@@ -112,16 +135,57 @@ def sb_rpc(fn_name: str, params: Dict) -> Any:
112
135
  try:
113
136
  with urlopen(req, timeout=10) as resp:
114
137
  raw = resp.read().decode("utf-8")
115
- return json.loads(raw) if raw.strip() else None
138
+ result = json.loads(raw) if raw.strip() else None
116
139
  except HTTPError as e:
117
140
  err = e.read().decode("utf-8", errors="replace")
118
141
  try:
119
- return {"_error": json.loads(err).get("message", err[:200])}
142
+ result = {"_error": json.loads(err).get("message", err[:200])}
120
143
  except Exception:
121
- return {"_error": err[:200]}
144
+ result = {"_error": err[:200]}
145
+ # Record errors too
146
+ if _recording_enabled and fn_name not in _SKIP_RECORDING:
147
+ _bg_record("error", {"rpc": fn_name, "error": str(err)[:200]})
148
+ return result
122
149
  except URLError as e:
123
150
  return {"_error": str(e.reason)}
124
151
 
152
+ # Auto-record tool calls to session events (hot-reloadable)
153
+ if _recording_enabled and fn_name not in _SKIP_RECORDING:
154
+ _bg_record("tool_call", {"rpc": fn_name})
155
+
156
+ return result
157
+
158
+
159
+ def _bg_record(event_type: str, payload: dict):
160
+ """Background-thread recording — never blocks the caller."""
161
+ import threading
162
+ def _do():
163
+ try:
164
+ sb_rpc_raw("mc_record_event", {
165
+ "p_api_key": _recording_api_key,
166
+ "p_project_id": _recording_project_id,
167
+ "p_agent_name": _recording_agent_name,
168
+ "p_session_id": _recording_session_id,
169
+ "p_event_type": event_type,
170
+ "p_payload": payload,
171
+ })
172
+ except Exception:
173
+ pass
174
+ threading.Thread(target=_do, daemon=True).start()
175
+
176
+
177
+ def sb_rpc_raw(fn_name: str, params: Dict) -> Any:
178
+ """Raw RPC call without recording (to avoid infinite recursion)."""
179
+ url = f"{SUPABASE_URL}/rest/v1/rpc/{fn_name}"
180
+ body = json.dumps(params).encode("utf-8")
181
+ req = Request(url, data=body, method="POST", headers=_headers(content_profile=False))
182
+ try:
183
+ with urlopen(req, timeout=10) as resp:
184
+ raw = resp.read().decode("utf-8")
185
+ return json.loads(raw) if raw.strip() else None
186
+ except Exception:
187
+ return None
188
+
125
189
 
126
190
  # ============================================================
127
191
  # Project + agent helpers
@@ -762,6 +762,11 @@ async def lifespan(_app):
762
762
  hb_thread = _threading.Thread(target=_heartbeat_thread_fn, daemon=True, name="meshcode-heartbeat")
763
763
  hb_thread.start()
764
764
  log.info(f"lifespan started — Realtime + heartbeat thread active for {AGENT_NAME}")
765
+ # Enable session recording in backend.py (hot-reloadable)
766
+ try:
767
+ be.enable_recording(_get_api_key(), _PROJECT_ID, AGENT_NAME, _SESSION_ID)
768
+ except Exception:
769
+ pass
765
770
  _record_event_bg("boot", {"agent": AGENT_NAME, "project": PROJECT_NAME, "session_id": _SESSION_ID})
766
771
  try:
767
772
  yield {"realtime": _REALTIME}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.0.8
3
+ Version: 2.0.9
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.0.8"
7
+ version = "2.0.9"
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