aaif-goose / aaif-goose/goose

Turn counts differ between the two agent loops: three messages one persists and the other only emits

オープン
#11,939 コメント 0 件 リアクション 0 件 担当者 1 名 @DOsinga が担当を希望しています GitHub で見る
主要言語
Rust
スター
54.2k
フォーク
6.2k
平均マージ
3日 4時間
マージ済み PR(30日)
240

説明

**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.

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

The issue describes three cases where two agent loops (state machine and legacy) persist messages differently, affecting turn counts. Key files are `summon.rs:44`, `agent.rs` (lines 2639, 163, 2648, 3281, 3265, 3296, 3308), `ops_maxturns.rs:66`, and `goose-agent/src/inference.rs:305-310`. Start by understanding the conversation persistence logic in both loops for each case. Determine whether each disputed message should be in the conversation. Run tests to verify turn counts align after changes.

索引モデルが issue の本文から書いたものです。

評価

領域
backend-api-design
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
明確に書かれている
初心者へのやさしさ
45/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。