Turn counts differ between the two agent loops: three messages one persists and the other only emits
- 主要语言
- Rust
- 星标
- 54.2k
- 派生
- 6.2k
- 平均合并
- 3 天 2 小时
- 30 天内合并 PR
- 262
描述
**Describe the bug**
The two agent loops persist different messages, so the same delegate run reports a different turn count depending on which loop executed it. `durable_assistant_turn_count` (`summon.rs:44`) derives turns from the persisted conversation, and `MaxTurnsOperation` charges the budget the same way, so anything one loop writes and the other only emits shifts the number by one.
Three cases, all on current main:
**1. The inference after a stop-hook denial**
The legacy loop deliberately does not charge it: `retrying_after_stop_hook_denial` skips the increment (`agent.rs:2639`). But the denial context is a `Message::user()` that is persisted without being emitted (`agent.rs:163`), so a conversation-derived count sees a user message closing the assistant block and charges the retry as a new turn.
**2. `MAX_TURNS_MESSAGE` on an exhausted budget**
The state machine persists it through `yielded_with` (`ops_maxturns.rs:66`); the legacy loop yields it and breaks without persisting (`agent.rs:2648`). It is an assistant, user-visible message, so an exhausted budget reports `max_turns + 1` on one path and `max_turns` on the other.
**3. A provider error that ends the turn**
The state machine persists every provider error: `error_outcome` builds `Message::from_provider_error` and returns it as a conversation effect (`goose-agent/src/inference.rs:305-310`), which is how `ExitOnErrorOperation` and `trailing_error` can see it at all. The legacy loop persists only `ProviderError::Authentication` (`agent.rs:3281`); refusal (`:3265`), network errors (`:3296`) and the general arm (`:3308`) are emitted and then `break` without being written. `with_error` marks the message `user_only`, so where it is persisted it is user-visible and counted.
**Expected behavior**
The same run reports the same number of turns regardless of `GOOSE_STATE_MACHINE`, and the budget charges what the telemetry reports.
**Why this is not fixable in the counter**
Both `durable_assistant_turn_count` and `MaxTurnsOperation` read the persisted conversation, which is the right source. The divergence is in what each loop writes to it, so it has to be settled by deciding, per case, whether the message belongs in the conversation.
**Please provide the following information**
- **OS & Arch:** Windows 11 x64
- **Interface:** both, this is loop-level
- **Version:** current main (e0e8625)
These came out of the review rounds on #11843, which I closed in favour of #11841; I put them on #11802 at the time but that issue closed with the merge, so they are here instead. I can fix whichever direction is chosen once this is Ready.
贡献指南
评估
这个 Issue 还没有评估数据。