From f36167586a155ea890c4ee578e08f8846bac72bc Mon Sep 17 00:00:00 2001 From: Keith Mac Mini Date: Mon, 27 Jul 2026 18:05:44 +0800 Subject: [PATCH] fix: stop @_all from triggering bot mention; coerce MCP enum types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove @_all short-circuit in Feishu mention detection: @所有人都 no longer treated as mentioning the bot. Only individual @ with bot's open_id in mentions[] counts. - Add no-op handler for user_status_change events to suppress 56/day 'processor not found' ERROR log spam. - Coerce MCP enum values to match declared property type (string '10' -> int 10) for Kimi/Moonshot compatibility. --- plugins/platforms/feishu/adapter.py | 11 +++--- tools/mcp_tool.py | 55 +++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/plugins/platforms/feishu/adapter.py b/plugins/platforms/feishu/adapter.py index 751c2bf76dfd..88cf4f254d1b 100644 --- a/plugins/platforms/feishu/adapter.py +++ b/plugins/platforms/feishu/adapter.py @@ -1675,6 +1675,10 @@ def _build_event_handler(self) -> Any: "vc.bot.meeting_invited_v1", self._on_meeting_invited_event, ) + .register_p2_customized_event( + "user_status_change", + lambda data: None, # ponytail: no-op, suppress "processor not found" ERROR spam (56/day) + ) .build() ) @@ -4384,13 +4388,12 @@ def _allow_group_message( # --- Mention detection ---------------------------------------------------- def _mentions_self(self, message: Any) -> bool: - # @_all is Feishu's @everyone placeholder. - raw_content = getattr(message, "content", "") or "" - if "@_all" in raw_content: - return True + # @_all (Feishu @所有人) does NOT count as mentioning the bot. + # Only check mentions array for bot's open_id. mentions = getattr(message, "mentions", None) or [] if mentions and self._message_mentions_bot(mentions): return True + raw_content = getattr(message, "content", "") or "" normalized = normalize_feishu_message( message_type=getattr(message, "message_type", "") or "", raw_content=raw_content, diff --git a/tools/mcp_tool.py b/tools/mcp_tool.py index 28dd5e917419..9e932da326d1 100644 --- a/tools/mcp_tool.py +++ b/tools/mcp_tool.py @@ -5133,6 +5133,60 @@ def _strip_nullable_union(node): return strip_nullable_unions(node, keep_nullable_hint=True) + def _coerce_enum_types(node): + """Coerce enum values to match their declared type. + + Moonshot / Kimi strictly validates that ``enum`` array elements + match the property's ``type``. MCP servers commonly produce + ``enum: ["10", "20"]`` on an ``integer`` property, which OpenAI + and Anthropic tolerate but Kimi rejects with + ````. + + This repair is a JSON Schema sanity fix: if ``type`` says + ``integer``, enum values should be ints, not strings; if ``type`` + says ``number``, they should be floats/ints, not strings. + """ + if isinstance(node, list): + return [_coerce_enum_types(item) for item in node] + if not isinstance(node, dict): + return node + + repaired = {k: _coerce_enum_types(v) for k, v in node.items()} + + enum_vals = repaired.get("enum") + type_str = repaired.get("type") + if isinstance(enum_vals, list) and isinstance(type_str, str): + if type_str == "integer": + fixed = [] + for v in enum_vals: + if isinstance(v, int): + fixed.append(v) + elif isinstance(v, str): + try: + fixed.append(int(v)) + except (ValueError, TypeError): + fixed.append(v) + else: + fixed.append(v) + if fixed != enum_vals: + repaired["enum"] = fixed + elif type_str == "number": + fixed = [] + for v in enum_vals: + if isinstance(v, (int, float)): + fixed.append(v) + elif isinstance(v, str): + try: + fixed.append(float(v)) + except (ValueError, TypeError): + fixed.append(v) + else: + fixed.append(v) + if fixed != enum_vals: + repaired["enum"] = fixed + + return repaired + def _repair_object_shape(node): """Recursively repair object-shaped nodes: fill type, prune required.""" if isinstance(node, list): @@ -5173,6 +5227,7 @@ def _repair_object_shape(node): normalized = _rewrite_local_refs(schema) normalized = _strip_nullable_union(normalized) + normalized = _coerce_enum_types(normalized) normalized = _repair_object_shape(normalized) # Ensure top-level is a well-formed object schema