mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-08 03:01:47 +00:00
test+docs: cover transform_llm_output hook + release author map
- tests/test_transform_llm_output_hook.py: dispatch semantics (kwargs contract, first-non-empty-string-wins, empty-string pass-through, raising-plugin fail-open, no-plugins = no-op) - tests/hermes_cli/test_plugins.py: assert the new hook name is in VALID_HOOKS alongside the other transform_* hooks - website/docs/user-guide/features/hooks.md: summary-table entry + full section mirroring transform_tool_result / transform_terminal_output - scripts/release.py: map barnacleboy.jezzahehn@agentmail.to -> JezzaHehn (existing entry only covers the gmail address)
This commit is contained in:
parent
c3be6ec184
commit
47bf5d7ecb
4 changed files with 205 additions and 0 deletions
|
|
@ -387,6 +387,7 @@ def register(ctx):
|
|||
| [`post_approval_response`](#post_approval_response) | User responded to an approval prompt (or it timed out) | ignored |
|
||||
| [`transform_tool_result`](#transform_tool_result) | After any tool returns, before the result is handed back to the model | `str` to replace the result, `None` to leave unchanged |
|
||||
| [`transform_terminal_output`](#transform_terminal_output) | Inside the `terminal` tool, before truncation/ANSI-strip/redact | `str` to replace the raw output, `None` to leave unchanged |
|
||||
| [`transform_llm_output`](#transform_llm_output) | After the tool-calling loop completes, before the final response is delivered | `str` to replace the response text, `None`/empty to leave unchanged |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1093,6 +1094,49 @@ Pairs well with `transform_tool_result` (which covers every other tool).
|
|||
|
||||
---
|
||||
|
||||
### `transform_llm_output`
|
||||
|
||||
Fires **once per turn** after the tool-calling loop completes and the model has produced a final response, **before** that response is delivered to the user (CLI, gateway, or programmatic caller). Lets a plugin rewrite the assistant's final text using classical-programming methods — no extra inference tokens burned on SOUL flavor text or a skill-driven transform.
|
||||
|
||||
**Callback signature:**
|
||||
|
||||
```python
|
||||
def my_callback(
|
||||
response_text: str,
|
||||
session_id: str,
|
||||
model: str,
|
||||
platform: str,
|
||||
**kwargs,
|
||||
) -> str | None:
|
||||
```
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `response_text` | `str` | The assistant's final response text for this turn. |
|
||||
| `session_id` | `str` | Session ID for this conversation (may be empty for one-shot runs). |
|
||||
| `model` | `str` | Model name that produced the response (e.g. `anthropic/claude-sonnet-4.6`). |
|
||||
| `platform` | `str` | Delivery platform (`cli`, `telegram`, `discord`, …; empty when unset). |
|
||||
|
||||
**Return value:** Non-empty `str` to replace the response text, `None` or empty string to leave it unchanged. **First non-empty string wins** when multiple plugins register — mirroring `transform_tool_result`.
|
||||
|
||||
**Use cases:** Apply a personality/vocabulary transform (pirate-speak, Spongebob), redact user-specific identifiers from the final text, append a project-specific signature footer, enforce a house style guide without burning tokens on SOUL instructions.
|
||||
|
||||
```python
|
||||
import os, re
|
||||
|
||||
def spongebob(response_text, **kwargs):
|
||||
if os.environ.get("SPONGEBOB_MODE") != "on":
|
||||
return None # pass through unchanged
|
||||
return re.sub(r"!", "!! Tartar sauce!", response_text)
|
||||
|
||||
def register(ctx):
|
||||
ctx.register_hook("transform_llm_output", spongebob)
|
||||
```
|
||||
|
||||
The hook is guarded on a non-empty, non-interrupted response — it will not fire on stop-button interrupts or empty turns. Exceptions are logged as warnings and do not break agent execution.
|
||||
|
||||
---
|
||||
|
||||
## Shell Hooks
|
||||
|
||||
Declare shell-script hooks in your `cli-config.yaml` and Hermes will run them as subprocesses whenever the corresponding plugin-hook event fires — in both CLI and gateway sessions. No Python plugin authoring required.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue