Skip to content

♻️ refactor: move agent engine to pkg/agent with Runner abstraction + cleanup#81

Merged
vaayne merged 8 commits intomainfrom
refactor-agent-tool
Apr 5, 2026
Merged

♻️ refactor: move agent engine to pkg/agent with Runner abstraction + cleanup#81
vaayne merged 8 commits intomainfrom
refactor-agent-tool

Conversation

@vaayne
Copy link
Copy Markdown
Owner

@vaayne vaayne commented Apr 5, 2026

Summary

  • Move internal/agent/engine/pkg/agent/ so plugins no longer need internal/ imports
  • Add Runner type that encapsulates model, tools, system prompt, hooks — replaces repeated Engine + LoopConfig boilerplate
  • Add ToolSetFromRegistry, ToolSetFromRegistryFiltered, WrapTool helpers to eliminate duplicated closure-wrapping across consumers
  • Simplify all 3 consumers: GoRunner (6 fields → 1), Reviewer (5 fields → 1), Agent tool (Engine → Providers + per-task Runner)
  • Extract helper functions from GoRunner constructor (buildProviderRegistry, buildToolRegistry, buildAgentPresets, buildHookSet)
  • Simplify Reviewer to use tools.Registry + ToolSetFromRegistry instead of manual ToolSet, remove redundant reviewTool interface
  • Unexport ExecuteToolCalls/ToolCallbacks — internal implementation details, not public API
  • Split pool.go (510 lines) into 4 focused files: pool.go, pool_session.go, pool_chat.go, pool_runner.go
  • Split preset.go (250 lines) into preset.go (types/registry) and preset_loader.go (filesystem/parsing) with 18 new tests

Test plan

  • go build ./... passes
  • mise run format — clean
  • mise run lint — 0 issues
  • mise run test — all tests pass with -race
  • No remaining internal/agent/engine imports
  • 18 new tests for preset loading (parsing, file loading, deduplication, registry)

vaayne added 3 commits April 5, 2026 19:43
Move internal/agent/engine/ to pkg/agent/ to eliminate internal package
dependency from plugins. Introduce Runner type that encapsulates engine
configuration (model, tools, system prompt, hooks) and provides Run/Continue
methods, replacing the repeated Engine + LoopConfig boilerplate across
GoRunner, Reviewer, and the Agent tool.

Add ToolSetFromRegistry, ToolSetFromRegistryFiltered, and WrapTool helpers
to eliminate duplicated closure-wrapping code in all three consumers.
Split the monolithic NewGoRunner() into focused helpers:
- buildProviderRegistry: provider setup
- buildToolRegistry: core + extra tool registration
- buildAgentPresets: builtin skill extraction + preset loading
- buildHookSet: hook construction

NewGoRunner now reads as a clean orchestration sequence.
Replace manual ToolSet/defs construction with tools.Registry +
agent.ToolSetFromRegistry. Remove the redundant reviewTool interface
(identical to tools.Tool). ReviewerConfig now accepts tools.Tool directly.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8398d67bc5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/agent/selfimprove/reviewer.go Outdated
}
return ai.TextContent{Text: result}, nil
}
runner, _ := agent.NewRunner(agent.RunnerConfig{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle runner construction failure in NewReviewer

NewReviewer currently discards the error from agent.NewRunner, so invalid config (for example Providers == nil) leaves r.runner as nil; the subsequent r.runner.Run(...) in Review will panic instead of returning a normal review error. Before this refactor, the same misconfiguration path returned an error from engine.Run, so this introduces a crash-on-misconfig regression.

Useful? React with 👍 / 👎.

vaayne added 3 commits April 5, 2026 20:14
These are internal implementation details of the agent loop, not part of
the public Runner API. Rename to executeToolCalls/toolCallbacks to reduce
the exported API surface.
Extract the 510-line Pool god object into 4 files:
- pool.go (~90 lines): struct, constructor, admin methods (SetFactory, Close)
- pool_session.go (~170 lines): session lifecycle (Create, Resolve, Rotate, Archive, Get, List, History)
- pool_chat.go (~155 lines): Chat streaming orchestration + streamEvents helper
- pool_runner.go (~90 lines): getOrCreateRunner (runner lifecycle, liveness, model switching)

No type or API changes — pure file split. All 77 existing tests pass.
Separate preset.go (250 lines) into:
- preset.go (~65 lines): AgentPreset type, agentFrontmatter, PresetRegistry
- preset_loader.go (~175 lines): filesystem discovery, YAML parsing, file loading

Add preset_loader_test.go with 18 tests covering:
- YAML frontmatter parsing (basic, tools, timeout, CRLF, errors)
- File loading (valid, name fallback, missing description, invalid timeout)
- Directory scanning (filters non-md, hidden, subdirs)
- Multi-directory deduplication with priority ordering
- PresetRegistry lookup/names/all
@vaayne vaayne changed the title ♻️ refactor: move agent engine to pkg/agent with Runner abstraction ♻️ refactor: move agent engine to pkg/agent with Runner abstraction + cleanup Apr 5, 2026
vaayne added 2 commits April 5, 2026 20:43
- WrapTool: propagate tool errors instead of swallowing them as text
- NewRunner: defensively clone Tools map and ToolDefs slice for
  concurrency safety
- NewReviewer: return (*Reviewer, error) to surface construction failures
- getOrCreateRunner: re-check under lock before assigning runner to
  prevent duplicate runner creation race
- Rename RunnerConfig.ToolDefs → ToolDefinitions for consistency
- Remove unused AnnaHome field from LoadAgentPresetsConfig
- Add preset loader tests for all 4 precedence tiers and path dedup
- Fix double user message: move mem.Ingest after mem.Assemble in
  pool_chat.go so GoRunner.Chat is the only place the user message
  is appended to the transcript
- Fix silent error swallowing: streamAssistant now returns an error
  when StopReason=Error, so provider errors propagate to the user
  instead of showing "(empty response)"
- Fix spurious stream errors: all three provider consumers
  (anthropic, openai, openai-response) now track terminal events
  and ignore benign sdkStream.Err() after successful completion
- Merge consecutive same-role messages in Anthropic convertMessages
  to satisfy the alternating-role API requirement
- Add trace hook plugin for LLM call and tool execution observability
- Add Hooks section to admin plugins page
- Populate HookMeta with session/agent/user context from GoRunner.Chat
@vaayne vaayne merged commit 43d9f83 into main Apr 5, 2026
4 of 6 checks passed
@vaayne vaayne deleted the refactor-agent-tool branch April 5, 2026 15:08
vaayne added a commit that referenced this pull request Apr 17, 2026
… cleanup (#81)

* ♻️ refactor: move agent engine to pkg/agent with Runner abstraction

Move internal/agent/engine/ to pkg/agent/ to eliminate internal package
dependency from plugins. Introduce Runner type that encapsulates engine
configuration (model, tools, system prompt, hooks) and provides Run/Continue
methods, replacing the repeated Engine + LoopConfig boilerplate across
GoRunner, Reviewer, and the Agent tool.

Add ToolSetFromRegistry, ToolSetFromRegistryFiltered, and WrapTool helpers
to eliminate duplicated closure-wrapping code in all three consumers.

* ♻️ refactor: extract helper functions from GoRunner constructor

Split the monolithic NewGoRunner() into focused helpers:
- buildProviderRegistry: provider setup
- buildToolRegistry: core + extra tool registration
- buildAgentPresets: builtin skill extraction + preset loading
- buildHookSet: hook construction

NewGoRunner now reads as a clean orchestration sequence.

* ♻️ refactor: simplify Reviewer to use tools.Registry

Replace manual ToolSet/defs construction with tools.Registry +
agent.ToolSetFromRegistry. Remove the redundant reviewTool interface
(identical to tools.Tool). ReviewerConfig now accepts tools.Tool directly.

* ♻️ refactor: unexport ExecuteToolCalls and ToolCallbacks in pkg/agent

These are internal implementation details of the agent loop, not part of
the public Runner API. Rename to executeToolCalls/toolCallbacks to reduce
the exported API surface.

* ♻️ refactor: split pool.go into focused files by responsibility

Extract the 510-line Pool god object into 4 files:
- pool.go (~90 lines): struct, constructor, admin methods (SetFactory, Close)
- pool_session.go (~170 lines): session lifecycle (Create, Resolve, Rotate, Archive, Get, List, History)
- pool_chat.go (~155 lines): Chat streaming orchestration + streamEvents helper
- pool_runner.go (~90 lines): getOrCreateRunner (runner lifecycle, liveness, model switching)

No type or API changes — pure file split. All 77 existing tests pass.

* ♻️ refactor: split preset.go into types and loader with tests

Separate preset.go (250 lines) into:
- preset.go (~65 lines): AgentPreset type, agentFrontmatter, PresetRegistry
- preset_loader.go (~175 lines): filesystem discovery, YAML parsing, file loading

Add preset_loader_test.go with 18 tests covering:
- YAML frontmatter parsing (basic, tools, timeout, CRLF, errors)
- File loading (valid, name fallback, missing description, invalid timeout)
- Directory scanning (filters non-md, hidden, subdirs)
- Multi-directory deduplication with priority ordering
- PresetRegistry lookup/names/all

* 🐛 fix: address review findings from Codex code review

- WrapTool: propagate tool errors instead of swallowing them as text
- NewRunner: defensively clone Tools map and ToolDefs slice for
  concurrency safety
- NewReviewer: return (*Reviewer, error) to surface construction failures
- getOrCreateRunner: re-check under lock before assigning runner to
  prevent duplicate runner creation race
- Rename RunnerConfig.ToolDefs → ToolDefinitions for consistency
- Remove unused AnnaHome field from LoadAgentPresetsConfig
- Add preset loader tests for all 4 precedence tiers and path dedup

* 🐛 fix: resolve empty telegram responses and add trace hook

- Fix double user message: move mem.Ingest after mem.Assemble in
  pool_chat.go so GoRunner.Chat is the only place the user message
  is appended to the transcript
- Fix silent error swallowing: streamAssistant now returns an error
  when StopReason=Error, so provider errors propagate to the user
  instead of showing "(empty response)"
- Fix spurious stream errors: all three provider consumers
  (anthropic, openai, openai-response) now track terminal events
  and ignore benign sdkStream.Err() after successful completion
- Merge consecutive same-role messages in Anthropic convertMessages
  to satisfy the alternating-role API requirement
- Add trace hook plugin for LLM call and tool execution observability
- Add Hooks section to admin plugins page
- Populate HookMeta with session/agent/user context from GoRunner.Chat
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.

1 participant