feat(agent): complete middleware pipeline with config-driven ordering - #11
Merged
Conversation
- Create middleware interface and pipeline runner - Extract existing behavior into 5 middleware: steer, followup, compaction, approval, loop detection - Add AgentMode config gate (legacy/middleware) - Fix message persistence bug in middleware mode (CompactionMiddleware) - Add loop detection test for middleware mode - Update docs with middleware pipeline plan Entire-Checkpoint: 4d6891baff7d
…ugin Remove .opencode/plugins/entire.ts which was previously tracked, and add both .pi/ and .opencode/ directories to .gitignore to keep local agent tooling artifacts out of the repo. Entire-Checkpoint: 3983f6023812
…ipeline - Move approval deny/ask logic from ApprovalMiddleware into executeAndCollect - Fix ToolResult.Args to use actual args instead of result content - Simplify CompactionMiddleware by removing unused provider fields - Make LoopDetectionMiddleware.toolCallHash a package-level function - Remove redundant compaction call from runMiddleware (handled by middleware) - Add ~ path expansion via expandHomeDir to all file tools - Include working directory in environment detection - Suppress MCP startup stderr in agent sessions - Remove stale planning docs The middleware pipeline is now always-on; AgentMode == "middleware" routes to the legacy code path.
- Display tool args and duration on the same line as the tool name - Add formatDuration helper showing ms for <1s durations - Add leading/trailing newlines before provider info and after streaming - Show spinner newline before first token for cleaner output
Phase 2 — Config wiring: - MiddlewareConfig with enabled/disabled lists in config.yaml - builtinMiddleware registry maps names to constructors - resolvedPipelineNames() applies config overrides Phase 3 — New middleware: - PermissionMiddleware: path-glob allow/deny tool filtering - ToolConcurrencyMiddleware: semaphore-capped goroutine pool - SubAgentMiddleware: task depth cap enforcement - PromptCachingMiddleware: Anthropic cache-control breakpoints Phase 3e — Compaction enhancements: - CompactionMiddleware accepts configurable threshold - compactContext now takes threshold float64 parameter Cleanup: - Remove legacy code path (runLegacy, executeToolsParallel, denyTool) - Remove AgentMode field, unified single pipeline path - Add CacheControl to types.Message (omitempty, no-op for non-Anthropic) Docs: - README: development section, config docs, remove "test commit" - docs/architecture.md: full architecture documentation - .kilo/agent-loop-comparison.md: status updates for all recommendations Entire-Checkpoint: 6933fbdd5279
buchenberg
added a commit
that referenced
this pull request
Aug 7, 2026
Task #11: Split newAgentSessionWithOptions into focused builders - wiring_otel.go: initOtel + wrapProviderWithOtel (extracted inline provider wrapping) - wiring_mcp.go: initMCP (moved to its own file) - wiring_prompt.go: buildSystemPrompt + buildMainPrompt (extracted inline prompt layers, memory enrichment, guidelines, directive injection, and quick-ref assembly) - wiring.go slimmed from 396 to ~210 lines; removed dead layers.Skills assignment (was set after prompts.Build, never read) Task #12: Complete ContextManager extraction — eliminate state sync dance - Added State *LoopState pointer to ContextManager; compaction methods now read/write mutable state (Messages, PreviousSummary, token counts, compaction tracking) directly through the pointer instead of copy-in/copy-out - Removed 9 duplicate state fields from ContextManager (Messages, PreviousSummary, LastPromptTokens, LastCachedPromptTokens, IneffectiveCompactions, LastCompactionTokens, CompactionBudgetMultiplier, CompactionSavingsHistory, CompactionForcedByOverflow) - Eliminated 19-line sync dance in Loop.compactContext and 3-line dance in Loop.trimContext - Removed redundant CtxMgr.Messages assignments in loop.go, tools.go, turn.go (now no-ops since CtxMgr.State points to Loop.State) - ctxMgr() lazily sets State = &l.State when nil (backward compatible with tests)
buchenberg
added a commit
that referenced
this pull request
Aug 7, 2026
#174) * Split wiring.go builders and eliminate ContextManager state sync dance Task #11: Split newAgentSessionWithOptions into focused builders - wiring_otel.go: initOtel + wrapProviderWithOtel (extracted inline provider wrapping) - wiring_mcp.go: initMCP (moved to its own file) - wiring_prompt.go: buildSystemPrompt + buildMainPrompt (extracted inline prompt layers, memory enrichment, guidelines, directive injection, and quick-ref assembly) - wiring.go slimmed from 396 to ~210 lines; removed dead layers.Skills assignment (was set after prompts.Build, never read) Task #12: Complete ContextManager extraction — eliminate state sync dance - Added State *LoopState pointer to ContextManager; compaction methods now read/write mutable state (Messages, PreviousSummary, token counts, compaction tracking) directly through the pointer instead of copy-in/copy-out - Removed 9 duplicate state fields from ContextManager (Messages, PreviousSummary, LastPromptTokens, LastCachedPromptTokens, IneffectiveCompactions, LastCompactionTokens, CompactionBudgetMultiplier, CompactionSavingsHistory, CompactionForcedByOverflow) - Eliminated 19-line sync dance in Loop.compactContext and 3-line dance in Loop.trimContext - Removed redundant CtxMgr.Messages assignments in loop.go, tools.go, turn.go (now no-ops since CtxMgr.State points to Loop.State) - ctxMgr() lazily sets State = &l.State when nil (backward compatible with tests) * Address PR #174 review: OTel env flag, memoryGuidelines scope, budget multiplier init - wiring_otel.go: evaluate YAAH_OTEL_ENABLED before the early return so the env flag can enable OTel when config disables it (pre-existing bug) - wiring_prompt.go: move memoryGuidelines from package-level const into buildSystemPrompt function scope (no globals per AGENTS.md) - lifecycle_init.go: initialize CompactionBudgetMultiplier=1.0 in ctxMgr() lazy path so Loop.Compact has a nonzero preservation budget before applyDefaults() runs * docs: remove completed plans and implemented ADRs Delete plan files for fully-implemented features (max iterations dialog, TUI-MCP bridge, quiet mode, task pane separation) and the four ADRs (engine-view separation, middleware pipeline, functional options, event-driven architecture) whose content is now covered by docs/architecture.md. Update doc references across CONTRIBUTING.md, architecture.md, and code-organization.md to point at architecture.md in place of the retired ADRs, and fix stale file paths to reflect the recent runner refactor (cmd/yaah/subagent_runner.go -> internal/agent/runner/). * Delete implemented ADRs and plan docs, fix stale references - Deleted 4 implemented ADRs (0001-0004: engine-view separation, middleware pipeline, functional options, event-driven architecture) — all Accepted and fully implemented; content covered by architecture.md - Deleted 5 implemented plan docs from .agents/plans/ (tui-mcp-bridge #159, tui-quiet-mode #159, tui2-task-pane-separation #160, max-iterations-dialog, web-ui-commands #162) — all features shipped - Updated docs/adr/README.md and CONTRIBUTING.md to remove dead ADR links - Fixed stale references to cmd/yaah/subagent_runner.go in architecture.md, PROMPT-INJECTION.md, and code-organization.md (now internal/agent/runner)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the middleware pipeline plan (Phases 2-3), removes the legacy code path, and adds comprehensive documentation.
Phase 2 — Config-driven middleware
MiddlewareConfigwithenabled/disabledlists in config.yamlbuiltinMiddlewareregistry maps canonical names to constructors viaMiddlewareBuilder func(l *Loop) MiddlewareresolvedPipelineNames()applies config overrides to default setcreate.goPhase 3 — New middleware (4 files)
middleware_permission.gomiddleware_toolconcurrency.goLoop.toolSemmiddleware_subagent.gomiddleware_promptcaching.goPhase 3e — Compaction enhancements
threshold(default 0.8)compactContext()signature changed to acceptthreshold float64Cleanup
runLegacy()(115 lines),executeToolsParallel()(97 lines),denyTool()(23 lines)AgentModefield from Loop — single unified middleware pipelineCacheControltotypes.Message(omitempty, no-op for non-Anthropic)Docs
docs/architecture.md: full architecture reference covering agent loop, middleware pipeline, tool execution, streaming, compaction, hook events, provider interfaceREADME.md: new Development section (build, test, lint, cross-compile, repo layout, architecture link), updated config docs.kilo/agent-loop-comparison.md: implementation status for all 10 recommendationsVerification