Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions agents/hermes/plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"""

import atexit
import inspect
import ipaddress
import json
import os
Expand Down Expand Up @@ -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

Expand Down
57 changes: 57 additions & 0 deletions test/hermes-plugin-handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading