1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//! Shared state for the goal-driven loop.
//!
//! In `--goal` mode, the agent runs autonomously for multiple turns until the goal is
//! reached. The mechanism:
//! - `goal_done` tool ([`crate::tool::GoalDoneTool`]) — called when the AI believes the
//! goal is reached, sets [`GoalState::reached`].
//! - `goal-gate` hook ([`crate::hooks::builtin::GoalGate`]) — when a turn voluntarily
//! stops (`before_turn_end`), reads [`GoalState::is_reached`]: if reached, allows the
//! loop to end; otherwise, extends the turn (injects a "continue working" feedback) and
//! loops back for another round.
//!
//! Both share the same `Arc<GoalState>` across turn phases: the tool writes in one turn,
//! the hook reads in a later turn.
//!
//! ## Why a named struct instead of a generic state bag
//!
//! Following the existing pattern in [`crate::session::DefaultSession`] (where
//! `background`, `compaction_slot`, etc. are all purpose-specific named structs, not a
//! catch-all `HashMap<String, Value>`). It currently has only two fields, but it's a
//! struct —
//! future additions like `summary`, `reached_at`, sub-goal lists, etc. can be added as
//! fields. Since `ToolContext` and builtins hold an `Arc<GoalState>`, adding or removing
//! fields does not break the interface.
use ;
/// Shared state for one goal-driven loop.