meshcode 2.10.53__tar.gz → 2.10.54__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.10.53 → meshcode-2.10.54}/PKG-INFO +1 -1
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/__init__.py +1 -1
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/server.py +119 -4
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.10.53 → meshcode-2.10.54}/pyproject.toml +1 -1
- {meshcode-2.10.53 → meshcode-2.10.54}/README.md +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/ascii_art.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/cli.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/comms_v4.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/invites.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/launcher.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/launcher_install.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/preferences.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/run_agent.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/secrets.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/self_update.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode/setup_clients.py +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/setup.cfg +0 -0
- {meshcode-2.10.53 → meshcode-2.10.54}/tests/test_status_enum_coverage.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "2.10.
|
|
2
|
+
__version__ = "2.10.54"
|
|
@@ -721,6 +721,52 @@ def with_working_status(func):
|
|
|
721
721
|
# to prevent cascade through FastMCP into the event loop.
|
|
722
722
|
# Return an error dict instead of propagating BaseException.
|
|
723
723
|
log.debug(f"[meshcode] tool {name} cancelled by client (ESC)")
|
|
724
|
+
# 2.10.54 deaf-agent fix: for meshcode_wait specifically, the
|
|
725
|
+
# inner cancel handler already tries to drain pending messages.
|
|
726
|
+
# If we still got CancelledError here, the inner drain failed —
|
|
727
|
+
# do a last-ditch DB read so the LLM sees pending mail instead
|
|
728
|
+
# of a generic error and goes silent.
|
|
729
|
+
if name == "meshcode_wait":
|
|
730
|
+
try:
|
|
731
|
+
_t = asyncio.current_task()
|
|
732
|
+
if _t is not None and hasattr(_t, "uncancel"):
|
|
733
|
+
_t.uncancel()
|
|
734
|
+
except Exception:
|
|
735
|
+
pass
|
|
736
|
+
try:
|
|
737
|
+
_ak = _get_api_key()
|
|
738
|
+
if _ak:
|
|
739
|
+
_raw = be.read_inbox(
|
|
740
|
+
_PROJECT_ID, AGENT_NAME, mark_read=True, api_key=_ak
|
|
741
|
+
)
|
|
742
|
+
if _raw:
|
|
743
|
+
_msgs = [
|
|
744
|
+
{
|
|
745
|
+
"from": m["from_agent"],
|
|
746
|
+
"type": m.get("type", "msg"),
|
|
747
|
+
"ts": m.get("created_at"),
|
|
748
|
+
"payload": m.get("payload", {}),
|
|
749
|
+
"id": m.get("id"),
|
|
750
|
+
"parent_id": m.get("parent_msg_id"),
|
|
751
|
+
}
|
|
752
|
+
for m in _raw
|
|
753
|
+
]
|
|
754
|
+
_filter_and_mark(_msgs)
|
|
755
|
+
_split = _split_messages(_msgs)
|
|
756
|
+
if _split["messages"] or _split["done_signals"]:
|
|
757
|
+
log.info(
|
|
758
|
+
f"[meshcode] wrapper-level cancel-drain rescued "
|
|
759
|
+
f"{_split['count']} messages"
|
|
760
|
+
)
|
|
761
|
+
return {
|
|
762
|
+
"got_message": True,
|
|
763
|
+
"cancelled_during_wait": True,
|
|
764
|
+
**_split,
|
|
765
|
+
}
|
|
766
|
+
except Exception as _final_err:
|
|
767
|
+
log.debug(
|
|
768
|
+
f"[meshcode] wrapper cancel-drain failed: {_final_err}"
|
|
769
|
+
)
|
|
724
770
|
return {"error": "cancelled_by_client", "tool": name}
|
|
725
771
|
except Exception as e:
|
|
726
772
|
if not skip:
|
|
@@ -2120,10 +2166,79 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
|
|
|
2120
2166
|
try:
|
|
2121
2167
|
result = await _meshcode_wait_inner(actual_timeout=capped_timeout, include_acks=include_acks)
|
|
2122
2168
|
except asyncio.CancelledError:
|
|
2123
|
-
#
|
|
2124
|
-
#
|
|
2125
|
-
|
|
2126
|
-
|
|
2169
|
+
# 2.10.54 deaf-agent fix: when ESC fires during meshcode_wait,
|
|
2170
|
+
# Python keeps the task in cancelled state — every subsequent
|
|
2171
|
+
# await re-raises CancelledError, even if we caught the first
|
|
2172
|
+
# one. That trapped us in a loop that eventually returned
|
|
2173
|
+
# `{"error": "cancelled_by_client"}` to the LLM, which never
|
|
2174
|
+
# saw the messages that arrived during the cancel window —
|
|
2175
|
+
# they sat in the queue/DB unread (the "deaf agents" bug).
|
|
2176
|
+
#
|
|
2177
|
+
# Fix: uncancel the current task so we can run a final drain
|
|
2178
|
+
# cycle without re-raising. Then aggressively pull from BOTH
|
|
2179
|
+
# the realtime buffer AND the DB and return whatever we find
|
|
2180
|
+
# to the LLM. If nothing is pending, return cancelled-timeout
|
|
2181
|
+
# cleanly so the LLM's wait loop continues normally.
|
|
2182
|
+
log.info("[meshcode] meshcode_wait caught CancelledError — uncancelling + final drain")
|
|
2183
|
+
try:
|
|
2184
|
+
_t = asyncio.current_task()
|
|
2185
|
+
if _t is not None and hasattr(_t, "uncancel"):
|
|
2186
|
+
_t.uncancel()
|
|
2187
|
+
except Exception:
|
|
2188
|
+
pass
|
|
2189
|
+
|
|
2190
|
+
_final_msgs: List[Dict[str, Any]] = []
|
|
2191
|
+
# 1) Drain realtime buffer (messages received during cancel window)
|
|
2192
|
+
if _REALTIME:
|
|
2193
|
+
try:
|
|
2194
|
+
_rt_buf = _REALTIME.drain()
|
|
2195
|
+
if _rt_buf:
|
|
2196
|
+
_final_msgs.extend(_rt_buf)
|
|
2197
|
+
except Exception as _drain_err:
|
|
2198
|
+
log.debug(f"[meshcode] cancel-drain realtime failed: {_drain_err}")
|
|
2199
|
+
# 2) Pull from DB (catches messages realtime missed)
|
|
2200
|
+
try:
|
|
2201
|
+
_api_key = _get_api_key()
|
|
2202
|
+
if _api_key:
|
|
2203
|
+
_db_unread = be.read_inbox(
|
|
2204
|
+
_PROJECT_ID, AGENT_NAME, mark_read=True, api_key=_api_key
|
|
2205
|
+
)
|
|
2206
|
+
if _db_unread:
|
|
2207
|
+
_final_msgs.extend([
|
|
2208
|
+
{
|
|
2209
|
+
"from": m["from_agent"],
|
|
2210
|
+
"type": m.get("type", "msg"),
|
|
2211
|
+
"ts": m.get("created_at"),
|
|
2212
|
+
"payload": m.get("payload", {}),
|
|
2213
|
+
"id": m.get("id"),
|
|
2214
|
+
"parent_id": m.get("parent_msg_id"),
|
|
2215
|
+
}
|
|
2216
|
+
for m in _db_unread
|
|
2217
|
+
])
|
|
2218
|
+
except Exception as _db_err:
|
|
2219
|
+
log.debug(f"[meshcode] cancel-drain DB failed: {_db_err}")
|
|
2220
|
+
|
|
2221
|
+
if _final_msgs:
|
|
2222
|
+
# Dedupe + filter, then return as got_message so the LLM
|
|
2223
|
+
# processes them instead of seeing a generic cancel error.
|
|
2224
|
+
_filter_and_mark(_final_msgs)
|
|
2225
|
+
_split = _split_messages(_final_msgs)
|
|
2226
|
+
if not include_acks:
|
|
2227
|
+
_split["acks"] = []
|
|
2228
|
+
if _split["messages"] or _split["done_signals"]:
|
|
2229
|
+
log.info(
|
|
2230
|
+
f"[meshcode] cancel-drain rescued {_split['count']} pending "
|
|
2231
|
+
f"messages from going deaf"
|
|
2232
|
+
)
|
|
2233
|
+
result = {
|
|
2234
|
+
"got_message": True,
|
|
2235
|
+
"cancelled_during_wait": True,
|
|
2236
|
+
**_split,
|
|
2237
|
+
}
|
|
2238
|
+
else:
|
|
2239
|
+
result = {"timed_out": True, "reason": "cancelled_by_client"}
|
|
2240
|
+
else:
|
|
2241
|
+
result = {"timed_out": True, "reason": "cancelled_by_client"}
|
|
2127
2242
|
|
|
2128
2243
|
if result.get("got_message"):
|
|
2129
2244
|
# Real message arrived — return to agent for processing
|
|
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
|
|
File without changes
|