fix(agent): stop tool-use hooks pinning copilot/kiro/cline sessions to needs_input#2594
fix(agent): stop tool-use hooks pinning copilot/kiro/cline sessions to needs_input#2594xOAviOx wants to merge 2 commits into
Conversation
…o needs_input The copilot, kiro, and cline adapters wired the agent's per-tool `preToolUse`/`PreToolUse` event to the `permission-request` hook sub-command, which `StandardDeriveActivityState` maps to the sticky `ActivityWaitingInput` state. But that event fires before EVERY tool invocation, not just ones that gate on a user decision — and never at all when the agent runs in an autonomous approval mode (Copilot `--allow-all-tools`/`--allow-all`, Cline `--auto-approve`/`--yolo`, Kiro auto/bypass), where it auto-runs every tool without ever pausing. Because `waiting_input` is sticky and `deriveStatus` returns `needs_input` before it ever consults PR facts, an actively-working session was pinned to `needs_input` for its whole turn: its real PR-derived status was masked and a spurious "needs input" notification fired on the active->waiting transition. This is the same failure mode fixed for Claude Code's `idle_prompt` in the activity-state cleanup: `waiting_input` must mean the agent is genuinely blocked on the user, per docs/architecture.md. Introduce a `tool-use` activity signal (-> active) in the shared `StandardDeriveActivityState` deriver and route the three adapters' per-tool event to it: an agent about to run a tool is working, not blocked. This mirrors how the agy adapter already treats tool activity (`after-tool` -> active); `permission-request` stays reserved for events that genuinely gate on a user decision (e.g. Cursor's `beforeShellExecution`). Tradeoff: in interactive modes these agents no longer surface a genuine per-tool approval pause as `waiting_input`. That signal was already noise-dominated (it fired on every tool, approval-gated or not), so dropping the false positives is a net improvement, and it matches how Claude Code and Codex avoid deriving a blocking state from tool use. Adds a regression test per adapter asserting the per-tool event derives `active`, plus a `tool-use` case in the deriver test.
|
Hi @xOAviOx , I can see you’re interested in contributing—we really appreciate it! We’ll take a look at your contribution. In the meantime, please join our Discord https://discord.gg/QpyVWcyn7. We have a community call every day at 10:00 PM IST, except Saturdays. Feel free to join the call, interact with the team, ask questions, and get to know the project. It’s the best place to discuss ideas, get guidance, and stay up to date with what’s happening. |
Resolve conflict in backend/internal/adapters/agent/activitystate/activitystate.go. Both branches appended a different explanatory paragraph to the StandardDeriveActivityState doc comment in the same location: - ours (PR): why tool-use maps to active - main: why permission-request maps to waiting_input, not blocked The merged switch retains both the tool-use and permission-request cases, so both paragraphs describe live behavior and are non-contradictory. Kept both, tool-use first (it segues into the permission-request note).
|
this changes are already fixed |
|
Thanks for contributing to Agent Orchestrator. This PR is being picked up by the current external contributor on-call pair: If someone is already working on this, please continue as usual. You are also welcome to join the AO Discord community. We do daily Discord calls at 10 PM IST, except Saturday. Join the session here: Come by if you want to see what is being built, ask questions, or just hang around with the community. |
Summary
This fixes an activity-state regression where Copilot, Kiro, and Cline sessions could become incorrectly stuck in
needs_inputwhile they were actively executing tools.The root cause was that each adapter mapped its per-tool
preToolUse/PreToolUseevent to the permission-request hook. SinceStandardDeriveActivityStatetreats permission requests as the stickywaiting_inputstate, every tool invocation looked like the agent was waiting for user approval—even when it wasn't.This was especially visible in autonomous approval modes (
--allow-all-tools,--allow-all,--auto-approve,--yolo, Kiro auto/bypass), where no user interaction occurs at all. The session would remain pinned toneeds_input, masking the real PR-derived state and triggering false "needs input" notifications.Changes
active.beforeShellExecution).This matches the existing behavior of the
agyadapter and aligns with the architecture principle thatwaiting_inputshould only represent an agent that is actually blocked on the user.Tradeoff
Interactive approval prompts generated from these generic per-tool events will no longer appear as
waiting_input.This is intentional: the previous signal fired before every tool invocation, regardless of whether approval was actually required, making it overwhelmingly noisy. Removing these false positives results in more accurate activity reporting and is consistent with how Claude Code and Codex avoid inferring a blocking state from generic tool-use events.
Testing
Added regression coverage for:
StandardDeriveActivityStatederivingactivefrom tool-use events.Validation completed successfully:
go build ./...go test ./...go test -race ./internal/adapters/agent/...gofmtgo vetgolangci-lint v2.12.2