Skip to content

EN Course 01 Minimal Agent Loop

lloydzhou edited this page May 29, 2026 · 1 revision

Minimal Agent Loop

The smallest useful agent loop has four steps:

  1. accept user input
  2. append it to conversation state
  3. call the model with the accumulated messages
  4. stream the assistant response back

In bash-agent this grows into agent_loop, but the core shape stays simple.

Minimal Shape

store_conv_add_user "$user_input"
messages="$(store_conv_get_messages)"
llm_call "$messages"

The real loop adds retries, tool calls, compaction, stats, display events, and stop handling. Those are layers around the same center: a user turn becomes a request, and the response is either final text or a request to run tools.

CLI to Runtime

The command-line entrypoint only decides configuration and input source. It does not own agent behavior.

main() {
    parse_args "$@"
    util_find_awk_dir
    validate_config
    store_session_init
    util_load_tool_defs
    if [[ "$INTERACTIVE" == true ]]; then
        interactive_mode
    elif [[ -n "$USER_INPUT" || ! -t 0 ]]; then
        local input="$USER_INPUT"
        [[ -z "$input" ]] && input=$(cat)
        ( exec 5> "$INPUT_FIFO"; util_write_msg "USER_INPUT" "0" "$input" >&5 ) &
        agent_main_loop
    else
        INTERACTIVE=true
        interactive_mode
    fi
}

--print is parsed as stream-json:

--print) OUTPUT_FORMAT="stream-json"; shift ;;

That keeps one execution path. Interactive input, prompt arguments, stdin input, and --print all enter the runtime through the same message queue and agent loop.

Why Persist Before Calling the Model

The user message is written before the model call:

store_conv_add_user() {
    local content; content=$(util_json_escape "$1")
    printf '{"role":"user","content":"%s"}\n' "$content" >> "$CONV_FILE"
}

That makes the conversation file the durable state of the session. If a later model call fails, the user turn is still present and the session can continue from the same state.

Loop Boundary

The loop boundary is not the terminal prompt. It is the semantic turn:

user input -> model request -> optional tools -> assistant result

Interactive mode, --print, and sub-agent continuation all drive the same loop. This keeps the runtime behavior aligned even when the input source changes.

Next

Streaming Transport explains how the model response is streamed and normalized before the loop consumes it.

Clone this wiki locally