Skip to content

feat(callbacks): Integrate callback hooks into agent execution flow#118

Merged
edenreich merged 7 commits intomainfrom
claude/issue-71-20251122-1641
Dec 3, 2025
Merged

feat(callbacks): Integrate callback hooks into agent execution flow#118
edenreich merged 7 commits intomainfrom
claude/issue-71-20251122-1641

Conversation

@edenreich
Copy link
Copy Markdown
Contributor

This PR integrates the callback infrastructure (from PR #94) into the actual agent execution flow.

Changes

  • Add WithCallbacks() method to AgentBuilder
  • Integrate all 6 callback hooks (BeforeAgent, AfterAgent, BeforeModel, AfterModel, BeforeTool, AfterTool)
  • Create comprehensive callbacks example
  • Add documentation

Closes #71

🤖 Generated with Claude Code

This commit integrates the callback infrastructure (from PR #94) into the actual
agent execution flow. Callbacks are now invoked at key execution points:

- BeforeAgent/AfterAgent: Hook into overall agent execution lifecycle
- BeforeModel/AfterModel: Hook into LLM calls for caching, guardrails, etc.
- BeforeTool/AfterTool: Hook into tool execution for authorization, logging, etc.

Changes include:
- Add WithCallbacks() method to AgentBuilder for fluent callback configuration
- Integrate BeforeAgent callback at start of RunWithStream (can skip execution)
- Integrate AfterAgent callback at completion (can modify final output)
- Integrate BeforeModel callback before LLM calls (can skip and return cached response)
- Integrate AfterModel callback after LLM responses (can modify response)
- Integrate BeforeTool/AfterTool callbacks around tool execution
- Add AgentName field to AgentConfig for callback context
- Add helper methods createCallbackContext and createToolContext
- Create callbacks example with comprehensive documentation
- Regenerate AgentBuilder mock

Closes #71

Co-authored-by: Eden Reich <edenreich@users.noreply.github.com>
@edenreich
Copy link
Copy Markdown
Contributor Author

@claude Fix the CI. Please also remove all the self-explanatory functions body inline comments.

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Nov 23, 2025

Claude finished @edenreich's task —— View job


Fixing CI and Removing Self-Explanatory Comments

  • Check CI status and identify failures
  • Fix formatting issues in examples/callbacks/README.md (prettier formatting)
  • Fix formatting issues in server/agent_builder.go (trailing whitespace)
  • Remove self-explanatory inline comments from function bodies
  • Commit changes

Summary:

Fixed CI failures and cleaned up the code:

  1. Formatting fixes (CI "Check dirty" failure):

    • Fixed markdown table alignment in examples/callbacks/README.md
    • Added blank lines before code blocks/lists per prettier style
    • Fixed struct field alignment in server/agent_builder.go (gofmt)
  2. Removed self-explanatory inline comments from:

    • server/agent_streamable.go - Removed ~15 redundant comments explaining callback execution flow
    • examples/callbacks/server/main.go - Removed ~12 section header comments

Commit: f44b85f


|

- Fix markdown table alignment in README.md (prettier formatting)
- Add blank lines before code blocks/lists per prettier style
- Fix struct field alignment in agent_builder.go (gofmt)
- Remove redundant inline comments from agent_streamable.go
- Remove section comments from callbacks example main.go

Co-authored-by: Eden Reich <edenreich@users.noreply.github.com>
@edenreich
Copy link
Copy Markdown
Contributor Author

@claude CI is still failing - fix it.

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Nov 23, 2025

Claude finished @edenreich's task —— View job


Fixing CI Failures

  • Check CI status and identify failures
    • "Check dirty" step failing - prettier needs blank lines before lists in examples/callbacks/README.md
  • Fix identified issues
    • Added blank lines before bullet lists in CallbackContext and ToolContext sections
  • Commit changes

Summary:

Fixed the CI "Check dirty" failure by adding the required blank lines before bullet lists in examples/callbacks/README.md per prettier's markdown formatting rules.
|

🤖 Generated with [Claude Code](https://claude.ai/claude-code)

Co-authored-by: Eden Reich <edenreich@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@Joshswooft Joshswooft left a comment

Choose a reason for hiding this comment

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

It looks like the AI has followed the implementation of how the callbacks have been designed to work i.e. skipping the calls or using the overidded values. What I'm not certain about is the surrounding logic in the RunWithStream and if it has correctly followed it.

I think overall if this PR goes in a refactor of this function is probably going to be required otherwise it's far too messy to work with.

@Joshswooft
Copy link
Copy Markdown
Contributor

@edenreich No serious change requests from my side 👍

@edenreich
Copy link
Copy Markdown
Contributor Author

@edenreich No serious change requests from my side 👍

Awesome! thanks for taking the time to look at it - I'll make those adjustments and merge it.

@edenreich
Copy link
Copy Markdown
Contributor Author

edenreich commented Dec 3, 2025

@claude Can you go over the comments to addresse those issues and prepare the PR for a final review? I want to merge this.

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Dec 3, 2025

Claude finished @edenreich's task —— View job


Addressing Review Comments for Final Review

All review comments have been addressed and changes are committed:

  • Read review comments and understand changes needed
  • Remove repetitive "Use Cases" section in examples/callbacks/README.md (lines 60-80)
  • Add GetTool(name string) (Tool, bool) method to ToolBox interface
  • Update agent_streamable.go:512 to use the new GetTool method
  • Regenerate mocks
  • Run linting and tests (all passed ✅)
  • Commit changes

Summary

Successfully addressed both review comments from @Joshswooft:

  1. Removed repetitive "Use Cases" section - The section in examples/callbacks/README.md was duplicating information already present in the callback types table, so it has been removed for better clarity.

  2. Added GetTool method to ToolBox interface - Added a cleaner interface method GetTool(toolName string) (Tool, bool) to the ToolBox interface and updated agent_streamable.go:512 to use this new method instead of type assertion and direct field access. This makes the code more maintainable and respects the interface abstraction.

All changes have been tested:

  • ✅ Linting passed with 0 issues
  • ✅ All tests passed with 82.4% coverage
  • ✅ Mocks regenerated successfully

Commit: 07dd1eb

The PR is now ready for final review and merge! 🚀


|

claude bot and others added 4 commits December 3, 2025 11:56
- Remove repetitive "Use Cases" section from callbacks README
- Add GetTool method to ToolBox interface for cleaner tool access
- Simplify agent_streamable.go to use new GetTool method
- Regenerate mocks for updated interface

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Eden Reich <edenreich@users.noreply.github.com>
Signed-off-by: Eden Reich <eden.reich@gmail.com>
@edenreich
Copy link
Copy Markdown
Contributor Author

Ok tested in the example and it looks good to me:

server-1  | [GIN] 2025/12/03 - 22:39:53 | 200 |     563.333µs |    192.168.65.1 | POST     "/a2a"
server-1  | 2025-12-03T22:39:53.159Z    INFO    server/storage.go:777   task dequeued for processing    {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "context_id": "a420faa5-fe8b-40b9-bba7-cf852f8c7f6d", "remaining_queue_length": 0}
server-1  | 2025-12-03T22:39:53.159Z    INFO    server/server.go:582    processing task {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "context_id": "a420faa5-fe8b-40b9-bba7-cf852f8c7f6d"}
server-1  | 2025-12-03T22:39:53.159Z    DEBUG   server/storage.go:182   active task updated     {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "context_id": "a420faa5-fe8b-40b9-bba7-cf852f8c7f6d", "state": "working"}
server-1  | 2025-12-03T22:39:53.159Z    DEBUG   server/task_manager.go:290      task state updated      {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "context_id": "a420faa5-fe8b-40b9-bba7-cf852f8c7f6d", "state": "working"}
server-1  | 2025-12-03T22:39:53.159Z    DEBUG   server/task_manager.go:143      registered cancel function for task     {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6"}
server-1  | 2025-12-03T22:39:53.160Z    INFO    server/main.go:201      🔵 BeforeAgent: Starting agent execution        {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6"}
server-1  | 2025-12-03T22:39:53.160Z    DEBUG   server/agent_streamable.go:72   starting streaming iteration    {"iteration": 1, "message_count": 1}
server-1  | 2025-12-03T22:39:53.160Z    INFO    server/main.go:210      🟢 BeforeModel: About to call LLM       {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "message_count": 1}
server-1  | 2025-12-03T22:39:55.872Z    INFO    server/main.go:220      🟡 AfterModel: Received LLM response    {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6"}
server-1  | 2025-12-03T22:39:55.872Z    DEBUG   server/agent_streamable.go:321  tool call accumulator   {"key": "0", "id": "call_00_QoOz2ppGIqv4b6WwHvwoGHoe", "name": "echo", "arguments": "{\"message\": \"Hello!\"}"}
server-1  | 2025-12-03T22:39:55.873Z    INFO    server/main.go:229      🟣 BeforeTool: About to execute tool    {"tool_name": "echo", "task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "args": {"message":"Hello!"}}
server-1  | 2025-12-03T22:39:55.873Z    INFO    server/main.go:240      🟠 AfterTool: Tool execution completed  {"tool_name": "echo", "task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "result": {"result":"Echo: Hello!"}}
server-1  | 2025-12-03T22:39:55.873Z    DEBUG   server/agent_streamable.go:378  persisted tool result messages  {"iteration": 1, "tool_result_count": 1}
server-1  | 2025-12-03T22:39:55.873Z    DEBUG   server/agent_streamable.go:424  tool calls executed, continuing to next iteration       {"iteration": 1, "message_count": 3, "tool_results_count": 1, "unique_tool_calls": 1}
server-1  | 2025-12-03T22:39:55.873Z    DEBUG   server/agent_streamable.go:72   starting streaming iteration    {"iteration": 2, "message_count": 3}
server-1  | 2025-12-03T22:39:55.873Z    INFO    server/main.go:210      🟢 BeforeModel: About to call LLM       {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "message_count": 3}
server-1  | 2025-12-03T22:39:55.873Z    INFO    server/main.go:60       AI agent completed iteration
server-1  | 2025-12-03T22:39:57.818Z    INFO    server/main.go:220      🟡 AfterModel: Received LLM response    {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6"}
server-1  | 2025-12-03T22:39:57.818Z    DEBUG   server/agent_streamable.go:394  streaming completed - no tool calls executed    {"iteration": 2, "final_message_count": 4, "has_assistant_message": true}
server-1  | 2025-12-03T22:39:57.818Z    INFO    server/main.go:251      🔴 AfterAgent: Agent execution completed        {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6"}
server-1  | 2025-12-03T22:39:57.818Z    INFO    server/main.go:60       AI agent completed iteration
server-1  | 2025-12-03T22:39:57.818Z    DEBUG   server/task_manager.go:151      unregistered cancel function for task   {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6"}
server-1  | 2025-12-03T22:39:57.818Z    DEBUG   server/storage.go:220   task stored in dead letter queue        {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "context_id": "a420faa5-fe8b-40b9-bba7-cf852f8c7f6d", "state": "completed"}
server-1  | 2025-12-03T22:39:57.818Z    DEBUG   server/task_manager.go:327      task updated completely {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "context_id": "a420faa5-fe8b-40b9-bba7-cf852f8c7f6d", "state": "completed", "history_count": 2}
server-1  | 2025-12-03T22:39:57.818Z    INFO    server/server.go:632    task processed successfully     {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6", "context_id": "a420faa5-fe8b-40b9-bba7-cf852f8c7f6d"}
server-1  | 2025-12-03T22:39:57.818Z    DEBUG   server/task_manager.go:151      unregistered cancel function for task   {"task_id": "f57bb015-3941-4283-b47d-fefe575ad9a6"}

@edenreich edenreich merged commit b69b34b into main Dec 3, 2025
3 checks passed
@edenreich edenreich deleted the claude/issue-71-20251122-1641 branch December 3, 2025 22:46
ig-semantic-release-bot bot added a commit that referenced this pull request Dec 3, 2025
## [0.16.0](v0.15.3...v0.16.0) (2025-12-03)

### ✨ Features

* **callbacks:** Integrate callback hooks into agent execution flow ([#118](#118)) ([b69b34b](b69b34b)), closes [#94](#94) [#71](#71)

### 🔧 Miscellaneous

* Add infer agent ([0963b3e](0963b3e))
@ig-semantic-release-bot
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 0.16.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Support callbacks

2 participants