AI Coding / From Assistants to Agents
Autocomplete grew into something that acts.
Reviewed by Yuvaraj
In under a decade, AI assistance for writing code has moved through three distinct generations, and the thing separating them is not model size or training data, it is how much of the loop the model is trusted to close. A completion model guesses the next few tokens of the file in front of you. A chat model rewrites code you hand it. A coding agent is given a goal and a keyboard: it reads your project, edits files, runs your tests, reads the failures, and tries again. This lesson traces that trajectory and pins down what changed at each step, because the tradeoffs you weigh today depend on knowing which generation you are actually using.
Each generation sees more of your world and is trusted to do more in it. The table below is the shape of the whole lesson.
| Generation | What it sees | What it does | Human role |
|---|---|---|---|
| Autocomplete | Nearby code, the prefix, and often the suffix, of the open file | Predicts the next tokens inline | Accept, reject, or keep typing every few keystrokes |
| Chat / instruct | The snippet you paste or reference, plus your instruction | Explains or rewrites code and returns it | Frame each request, apply the result, drive the next step |
| Coding agent | Files, command output, and test results, the live workspace | Reads, edits, runs commands, observes, and iterates | Set the goal, review the diff, approve risky actions |
The first two generations share a mechanism: a language model returns text conditioned on the context you gave it. Autocomplete is tuned for latency and fires on your keystrokes with a short context window; chat is instruction-tuned and takes a richer prompt. Neither has a goal of its own, and neither can find out whether its output was correct.
Ask about this lesson, or about anything in AI. Answers cite the lessons they draw on.
Finished this lesson?
Mark it complete to earn XP, keep your streak, and schedule a review.
The third generation wraps a similar model in a control loop and hands it tools. This is the ReAct pattern, interleaving reasoning with actions and feeding the results back in.
The jump is from producing a plausible continuation to taking an action in a real environment and using the feedback. That single change, a loop plus tools plus environment feedback, is what turns a predictor into an agent.
The task: add input validation to a function and its test.
Autocomplete finishes the line you started. You type if not, and it proposes the guard:
def set_age(age):
if not isinstance(age, int): # suggested inline as you type
raise ValueError("age must be an int")
return age
Chat rewrites the whole function on request. You paste it and ask it to reject negative values with a ValueError; it returns a new version you copy back into the file:
def set_age(age):
if not isinstance(age, int) or age < 0:
raise ValueError("age must be a non-negative int")
return age
A coding agent works the task end to end. It edits the file, runs the suite, reads a real failure, and fixes it:
edit src/user.py # add the isinstance / negative-value guard
run pytest -q
FAILED test_user.py::test_negative, DID NOT RAISE ValueError
read test_user.py # the test passed age=-1 and expected ValueError
edit src/user.py # the guard used `and`; widen it to `or`
run pytest -q # 4 passed
Same task; the scope the model owns widens from a line, to a function, to the whole edit-run-observe-fix cycle.
More autonomy buys capability and costs oversight. The agent that can run your tests can also run any command, so the guardrails move from "read the suggestion" to "sandbox the environment and review the diff."
Common mistakes