diff --git a/agents/hermes/plugin/__init__.py b/agents/hermes/plugin/__init__.py index 24aff8969cb..8b4a221e7bb 100644 --- a/agents/hermes/plugin/__init__.py +++ b/agents/hermes/plugin/__init__.py @@ -22,6 +22,7 @@ """ import atexit +import inspect import ipaddress import json import os @@ -1149,17 +1150,40 @@ def _install_messaging_response_patch(): if agent_cls is None or getattr(agent_cls, _MESSAGING_RESPONSE_PATCH_ATTR, False): return False + raw_original = inspect.getattr_static(agent_cls, "_strip_think_blocks", None) original = getattr(agent_cls, "_strip_think_blocks", None) if not callable(original): return False - def _strip_think_blocks(content): - return _normalize_raw_messaging_tool_response( - original(content), - current_platform=_get_current_messaging_platform(), - ) + if isinstance(raw_original, staticmethod): + original_func = raw_original.__func__ + + def _strip_think_blocks(content): + return _normalize_raw_messaging_tool_response( + original_func(content), + current_platform=_get_current_messaging_platform(), + ) + + agent_cls._strip_think_blocks = staticmethod(_strip_think_blocks) + elif isinstance(raw_original, classmethod): + original_func = raw_original.__func__ + + def _strip_think_blocks(cls, content): + return _normalize_raw_messaging_tool_response( + original_func(cls, content), + current_platform=_get_current_messaging_platform(), + ) + + agent_cls._strip_think_blocks = classmethod(_strip_think_blocks) + else: + def _strip_think_blocks(self, content): + return _normalize_raw_messaging_tool_response( + original(self, content), + current_platform=_get_current_messaging_platform(), + ) + + agent_cls._strip_think_blocks = _strip_think_blocks - agent_cls._strip_think_blocks = staticmethod(_strip_think_blocks) setattr(agent_cls, _MESSAGING_RESPONSE_PATCH_ATTR, True) return True diff --git a/test/hermes-plugin-handlers.test.ts b/test/hermes-plugin-handlers.test.ts index d84e5fdc6d2..dcb4b2bf988 100644 --- a/test/hermes-plugin-handlers.test.ts +++ b/test/hermes-plugin-handlers.test.ts @@ -328,6 +328,63 @@ print(json.dumps(result)) ); }); + it("preserves instance-method strip_think_blocks binding", () => { + const output = runPython(` +import importlib.util +import json +import pathlib +import sys +import types + +plugin_path = pathlib.Path(sys.argv[1]) +yaml_stub = types.ModuleType("yaml") +yaml_stub.safe_load = lambda *_args, **_kwargs: {} +sys.modules.setdefault("yaml", yaml_stub) + +run_agent = types.ModuleType("run_agent") +class AIAgent: + def __init__(self): + self.calls = 0 + + def _strip_think_blocks(self, content): + self.calls += 1 + return content +run_agent.AIAgent = AIAgent +sys.modules["run_agent"] = run_agent + +spec = importlib.util.spec_from_file_location("hermes_plugin", plugin_path) +plugin = importlib.util.module_from_spec(spec) +spec.loader.exec_module(plugin) + +patched = plugin._install_messaging_response_patch() +plugin._set_current_messaging_platform("telegram") +agent = AIAgent() +normalized = agent._strip_think_blocks( + 'send_message: "to telegram: Hello from an instance method."' +) +plain = agent._strip_think_blocks("plain response") + +print(json.dumps({ + "patched": patched, + "normalized": normalized, + "plain": plain, + "calls": agent.calls, +})) +`); + + const result = JSON.parse(output) as { + patched: boolean; + normalized: string; + plain: string; + calls: number; + }; + + expect(result.patched).toBe(true); + expect(result.normalized).toBe("Hello from an instance method."); + expect(result.plain).toBe("plain response"); + expect(result.calls).toBe(2); + }); + it("anchors the strip_think_blocks patch via _pre_llm_call gateway hook", () => { const output = runPython(` import importlib.util