Skip to content

Conversation

@ak684
Copy link
Contributor

@ak684 ak684 commented Dec 30, 2025

follow up to: #1467

fixes #1527

  • Implement additional_context injection in UserPromptSubmit hooks

    • Hook context is appended to MessageEvent.extended_content
    • Context is appended to MessageEvent.extended_content and included in LLM messages
  • Implement stop hook integration in conversation run loop

    • Stop hooks can deny premature agent completion
    • Feedback from hooks is injected as a user message
    • Agent continues running after stop hook denial
  • Add comprehensive tests for both features

    • Tests for context appearing in extended_content
    • Tests for context appearing in to_llm_message() output
    • Tests for stop hook denial with feedback injection
    • Integration tests for full conversation loop with stop hooks
  • Add advanced hooks example (34_hooks_advanced.py)

    • Demonstrates UserPromptSubmit with additional_context
    • Demonstrates Stop hook with conditional denial

Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.12-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:ab9d4ec-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-ab9d4ec-python \
  ghcr.io/openhands/agent-server:ab9d4ec-python

All tags pushed for this build

ghcr.io/openhands/agent-server:ab9d4ec-golang-amd64
ghcr.io/openhands/agent-server:ab9d4ec-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:ab9d4ec-golang-arm64
ghcr.io/openhands/agent-server:ab9d4ec-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:ab9d4ec-java-amd64
ghcr.io/openhands/agent-server:ab9d4ec-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:ab9d4ec-java-arm64
ghcr.io/openhands/agent-server:ab9d4ec-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:ab9d4ec-python-amd64
ghcr.io/openhands/agent-server:ab9d4ec-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-amd64
ghcr.io/openhands/agent-server:ab9d4ec-python-arm64
ghcr.io/openhands/agent-server:ab9d4ec-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-arm64
ghcr.io/openhands/agent-server:ab9d4ec-golang
ghcr.io/openhands/agent-server:ab9d4ec-java
ghcr.io/openhands/agent-server:ab9d4ec-python

About Multi-Architecture Support

  • Each variant tag (e.g., ab9d4ec-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., ab9d4ec-python-amd64) are also available if needed

@github-actions
Copy link
Contributor

github-actions bot commented Dec 30, 2025

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-sdk/openhands/sdk/conversation/impl
   local_conversation.py2599762%148, 150–151, 172, 202, 205–206, 220–221, 244, 249, 291–292, 296–297, 342, 350, 353–357, 364–365, 368, 377–378, 381, 388, 409, 412, 416–418, 425–427, 430, 439, 455, 457, 459, 463, 465–467, 469, 471, 477–478, 491–492, 494, 496, 500–503, 520–521, 527, 532, 535, 537, 547, 549–551, 569, 571, 575, 580, 585, 590–593, 599, 602, 606, 609, 611–613, 615, 633, 635, 649, 653, 661, 677–678, 682, 684, 686, 692–693
openhands-sdk/openhands/sdk/hooks
   conversation_hooks.py13411315%35–37, 41, 46, 49–50, 53–54, 57–58, 61–62, 66–67, 69–70, 73–77, 79, 84–86, 90–92, 94, 102–103, 106–114, 116–117, 119–121, 124–128, 131–135, 137, 144–146, 154–155, 158–162, 164, 168–170, 174–176, 178, 185–187, 191, 200, 204–206, 210–212, 216–219, 223–226, 230–231, 233, 236–238, 241–245, 248–251, 253, 263, 269, 274
TOTAL14671699052% 

@ak684 ak684 force-pushed the ak684/featsdk-complete-hooks-implementation-with-additional-context-and-stop-hook-13 branch from 322a14d to 4c36ba1 Compare December 30, 2025 15:41
…stop hook

- Implement additional_context injection in UserPromptSubmit hooks
  - Hook context is appended to MessageEvent.extended_content
  - Context flows through condensation and is included in LLM messages

- Implement stop hook integration in conversation run loop
  - Stop hooks can deny premature agent completion
  - Feedback from hooks is injected as user message with [Stop hook feedback] prefix
  - Agent continues running after stop hook denial

- Add comprehensive tests for both features
  - Tests for context appearing in extended_content and to_llm_message()
  - Tests for stop hook denial with feedback injection
  - Integration tests for full conversation loop with stop hooks

- Add advanced hooks example (34_hooks_advanced.py)
@ak684 ak684 force-pushed the ak684/featsdk-complete-hooks-implementation-with-additional-context-and-stop-hook-13 branch from 4c36ba1 to bda858e Compare December 30, 2025 15:46
@enyst enyst self-requested a review December 30, 2025 15:59
@rbren
Copy link
Contributor

rbren commented Dec 30, 2025

This likely solves #1527!

Comment on lines 76 to 91
config = HookConfig.from_dict(
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [{"type": "command", "command": str(context_script)}],
}
],
"Stop": [
{
"hooks": [{"type": "command", "command": str(stop_script)}],
}
],
}
}
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: could we make this a HookConfig a pydantic class that contains UserPromptSubmit Stop, etc, which are other pydantic class, so we can have stricter type check instead of putting together a dict like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a great idea. I’ll plan on implementing it in a follow-up PR so that we can keep this PR’s scope focused.

ak684 and others added 3 commits January 2, 2026 04:11
- Move 33_hooks.py to 33_hooks/ folder with separate scripts
- Split into basic_hooks.py and advanced_hooks.py
- Remove main() wrapper to match codebase convention (31/33 examples)
- Extract shell scripts to scripts/ directory for reusability
- Add README.md documenting hook types and usage

Addresses review feedback:
- Consolidate hook examples into folder structure
- Simplify examples by removing main() wrapper
xingyaoww pushed a commit to OpenHands/docs that referenced this pull request Jan 2, 2026
Update the hooks documentation to reflect the new 33_hooks.py example that
demonstrates all four hook types:
- PreToolUse: Block dangerous commands
- PostToolUse: Log tool usage
- UserPromptSubmit: Inject context into user messages
- Stop: Enforce task completion criteria

The new example uses external hook scripts in a hook_scripts/ directory
and includes a Hook Types reference table.

Related to: OpenHands/software-agent-sdk#1547

Co-authored-by: openhands <[email protected]>
ak684 and others added 3 commits January 3, 2026 04:10
Added tests verifying LocalConversation correctly wires hook callbacks
to event persistence via original_callback parameter.
Use grep on raw JSON input instead of jq for detecting dangerous commands.
This makes the example work out of the box without requiring jq installation.
@openhands-ai
Copy link

openhands-ai bot commented Jan 6, 2026

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • [Optional] Docs example

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #1547 at branch `ak684/featsdk-complete-hooks-implementation-with-additional-context-and-stop-hook-13`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

Copy link
Collaborator

@xingyaoww xingyaoww left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you!

@xingyaoww
Copy link
Collaborator

@ak684
PR looks good to me - just need to get these doc merged as well OpenHands/docs#230

ak684 pushed a commit to OpenHands/docs that referenced this pull request Jan 6, 2026
Update the hooks documentation to reflect the new 33_hooks.py example that
demonstrates all four hook types:
- PreToolUse: Block dangerous commands
- PostToolUse: Log tool usage
- UserPromptSubmit: Inject context into user messages
- Stop: Enforce task completion criteria

The new example uses external hook scripts in a hook_scripts/ directory
and includes a Hook Types reference table.

Related to: OpenHands/software-agent-sdk#1547

Co-authored-by: openhands <[email protected]>
@ak684 ak684 merged commit 877b4fe into main Jan 6, 2026
21 of 22 checks passed
@ak684 ak684 deleted the ak684/featsdk-complete-hooks-implementation-with-additional-context-and-stop-hook-13 branch January 6, 2026 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Add Stop Hook to prevent early agent termination

5 participants