Back to Goose

goose-agent

crates/goose-agent/README.md

1.48.02.6 KB
Original Source

goose-agent

The GDK's agent loop, unrolled into a state machine you assemble yourself.

Instead of a fixed "call the model, run the tools, repeat" loop, an agent here is an ordered list of steps. Each step gets a chance to look at the conversation and either decline or produce effects. The machine walks the list, applies the first step that applies, and starts over from the top — so the whole agent's behavior is a function of the persisted conversation, not of in-memory loop state.

The pieces

  • Operation<S, E> — one step. Implement run to act on the conversation, plus any of inference_tools, prompt_parts, and moim_parts to contribute to the model request. Returns OperationResult::NotApplicable to pass, or applied(..) / yielded(..) to take the step. Helpers: not_applicable(), applied(), yielded(), yielded_with().
  • Inference<S, E> — the step that reaches the provider. Before calling it, the machine collects tools and prompt parts from every operation in the list into an InferenceInput.
  • StateMachine<'a, S, E> — holds Vec<Step<..>> and a CancellationToken. step() runs one pass, apply() writes effects back, run() loops until a step yields to the client or no step applies.
  • ConversationEffect — the default effect type: AppendMessage, ReplaceConversation, PatchToolRequestMeta, SetMessageVisibility. Bring your own by implementing MachineEffect.
  • Emitter — streams AgentEvents (Message, Usage, MessageUsage, McpNotification, HistoryReplaced) to the client while a step runs, and carries the cancellation token.
  • SessionLoader / EffectHandler / MachineSession — the traits your runtime implements so the machine can load a session by id and persist effects. The machine reloads the session between passes; it never caches it.

Reading the conversation

Because steps re-derive their decisions from history, the crate ships the predicates they need: messages_since_kickoff, last_effective_role, assistant_turn_count, ends_turn, and trailing_error. When a step must remember that it already did something, it records that on the message itself via Operation::set_message_meta / message_meta rather than in memory.

Cancellation

Cancellation is cooperative. Once the token fires, remaining steps are treated as not-applicable and each step's cancel hook gets a chance to rewrite its result; anything applied while cancelled yields to the client.

The reference assembly of these pieces is goose::agents::state_machine in the goose crate.