Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ The course follows a four-week learning path:
the scheduler does not rebuild dense history on every step.
- **Week 4: Build a Coding Agent.** Start with a bounded, validated agent loop,
then connect it to a small workspace. The course is publishing one reviewed
checkpoint at a time; Days 1 through 7 now cover inspection, approved edits,
checkpoint at a time; Days 1 through 8 now cover inspection, approved edits,
one validation command, simple effect receipts, and one visible
checkpoint-and-resume boundary, receipt-backed context compaction, and one
visible inspect-and-steer pause, and deterministic evaluation of observable
outcomes.
outcomes, then tokenizer/KV-prefix reuse for two isolated steered branches
and one explicit evidence-backed selection.

## Why MLX and Qwen3?

Expand Down Expand Up @@ -74,7 +75,7 @@ implementation, test, and publication readiness is tracked below.

## Roadmap

The table tracks implementation (`Code`), tests (`Test`), rendered chapters (`Doc`), and Chi's review of learner-facing material (`Audit`). Week 4 is publishing one reviewed day at a time; Days 1 through 7 are currently available to learners. The Audit column reflects Chi's personal editorial pass on the published course content and is independent of code/test/doc readiness.
The table tracks implementation (`Code`), tests (`Test`), rendered chapters (`Doc`), and Chi's review of learner-facing material (`Audit`). Week 4 is publishing one reviewed day at a time; Days 1 through 8 are currently available to learners. The Audit column reflects Chi's personal editorial pass on the published course content and is independent of code/test/doc readiness.

Day 3 can send file contents to the model, modify files after approval, and run
one exact configured command. Use a disposable workspace without secrets and
Expand All @@ -88,6 +89,10 @@ Day 6 inspects one complete-observation checkpoint, appends one visible operator
instruction, and resumes a fresh model without replaying the completed effect.
Day 7 evaluates one completed run from declared final, file, result, and receipt
facts without grading hidden reasoning or exact transcript shape.
Day 8 reuses one real tokenizer/KV checkpoint for two differently steered,
effect-isolated continuations, evaluates both with Day 7's harness, and makes
one explicit passing selection without pretending completed effects were
rewound.

| Week + Chapter | Topic | Code | Test | Doc | Audit |
|---|---|---|---|---|---|
Expand Down Expand Up @@ -119,6 +124,7 @@ facts without grading hidden reasoning or exact transcript shape.
| 4.5 | Compact Completed Work | ✅ | ✅ | ✅ | 🚧 |
| 4.6 | Inspect and Steer a Paused Agent | ✅ | ✅ | ✅ | 🚧 |
| 4.7 | Evaluate Observable Outcomes | ✅ | ✅ | ✅ | 🚧 |
| 4.8 | Fork, Steer, and Select | ✅ | ✅ | ✅ | 🚧 |

Other topics not covered include quantized or compressed KV caches,
cross-request prefix caching, fine-tuning, and long-context techniques.
Expand Down
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
- [🚧 Day 5: Compact Completed Work](./week4-05-compaction.md)
- [🚧 Day 6: Inspect and Steer a Paused Agent](./week4-06-steering.md)
- [🚧 Day 7: Evaluate Observable Outcomes](./week4-07-evaluation.md)
- [🚧 Day 8: Fork, Steer, and Select](./week4-08-fork-steer-select.md)
- [🚧 Appendix: Performance Evidence Ledger](./appendix-performance.md)
- [Sponsored by Raft.build](./sponsor.md)

Expand Down
8 changes: 4 additions & 4 deletions book/src/week4-07-evaluation.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ observable outcomes. This harness samples the facts a particular case names. It
does not prove general task correctness, model quality, security, or production
safety, and it is not a hidden grader, benchmark suite, or LLM-as-judge system.

That closes the seven-day Week 4 path: build a bounded loop, inspect and change
a workspace with approvals and receipts, pause and resume, compact completed
evidence, steer at a safe boundary, and finally evaluate one run by what it
actually left behind.
You now have the evidence needed to compare continuations. Continue with [Day
8: Fork, Steer, and Select](week4-08-fork-steer-select.md) to reuse one real
token/KV prefix, steer two isolated branches, and explicitly choose a passing
outcome without rewinding completed effects.

{{#include copyright.md}}
202 changes: 202 additions & 0 deletions book/src/week4-08-fork-steer-select.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# Day 8: Fork, Steer, and Select

> 🚧 **Early-review WIP:** Use only pre-created disposable workspaces. A
> control-state fork does not undo a file edit or any other completed effect.

Days 4 and 6 paused one agent and resumed one continuation. Day 8 asks a new
question: after the model has inspected or changed the workspace, can we reuse
the same inference prefix, try two explicit directions, and select the branch
whose observable result is better?

The answer reconnects Week 4 to the inference system from Weeks 1–3. The course
tokenizer renders the checkpoint conversation once. `TinyKvFullCache` stores
the prefix keys and values for every model layer. Each branch gets a fresh
control object and cache handles that share only those immutable prefix arrays,
then decodes its own suffix. The branch report exposes the reused token count,
the layer offsets, and the full-prefix prefill that was avoided.

This is control-state reuse, not effect rollback. Copy the already-modified
disposable workspace and its completed receipt log before running either
branch. Both copies begin with the same files and evidence; later receipts stay
inside their branch.

## The Starter Surface

Day 8 adds one module and extends the approval result:

| File | Public names | Purpose |
| --- | --- | --- |
| `src/tiny_llm/agent/workspace.py` | `ApprovalDecision` | Carry an operator's denial reason back as one ordinary model-visible observation. |
| `src/tiny_llm/agent/branching.py` | `PrefixReuse`, `KvPrefixGenerator`, `BranchOutcome`, `run_branch`, `select_branch` | Reuse a dense KV prefix, run isolated steered continuations, evaluate them, and make one explicit choice. |
| `src/tiny_llm/agent/__init__.py` | the names above | Export the cumulative Day 8 API. |

Copy and run the five learner tasks:

```bash
pdm run copy-test --week 4 --day 8
pdm run test --week 4 --day 8
```

Use this command for the supplied implementation:

```bash
pdm run test-refsol --week 4 --day 8
```

Before you implement the TODOs, all five Day 8 tasks are expected to fail.

## Task 1: Return a Reason with a Denial

Add the immutable decision:

```python
ApprovalDecision(approved=False, reason="keep the requested answer at 2")
```

A structured denial requires a nonblank reason. `Workspace.execute` returns
that reason in its normal `error:` result so the next model turn can react to
the operator's instruction. It does not execute the effect or append a receipt.
Existing callbacks that return plain `True` or `False` remain compatible.

The reason is steering, not a secret channel. Keep it short and suitable for
the model-visible transcript.

## Task 2: Save One Real Token and KV Prefix

`KvPrefixGenerator.save_checkpoint(messages)` renders the checkpoint messages
without a generation prompt, tokenizes them with the course tokenizer, and
prefills one `TinyKvFullCache` per layer. It records the exact token IDs and
layer offsets in the existing Day 4 `ModelCheckpoint`.

The saved prompt must be an exact token prefix of every later steered prompt.
Reject a continuation if even a same-length token differs. This binds cache
reuse to content, not merely to a position.

`fork()` creates a fresh generator whose cache handles point at the frozen
prefix arrays. When one branch grows, `TinyKvFullCache` assigns newly
concatenated arrays to that branch. The frozen prefix and its sibling remain
unchanged. This lesson deliberately uses the dense compatibility path; paged
copy-on-write and radix serving are separate scaling topics.

## Task 3: Expose What Was Reused

Each continuation reports:

```python
PrefixReuse(
reused_tokens=prefix_length,
layer_offsets=(prefix_length, ...),
avoided_prefill_tokens=prefix_length,
)
```

The first suffix model call starts at `prefix_length`; it must not call the
model again at offset zero. These numbers make the inference boundary visible:
the branch is not cloning only a Python transcript and silently recomputing the
whole prompt.

## Task 4: Fork Effects and Evidence Explicitly

Suppose the completed prefix changed `app.py` from `answer = 1` to
`answer = 2` and wrote `call-1`, the edit receipt. Copy both the post-effect
workspace and `receipts.jsonl` into two roots:

```text
base after checkpoint
├── app.py answer = 2
└── receipts.jsonl call-1: edit_file

validate-only/ try-extra-edit/
├── app.py ├── app.py
└── receipts.jsonl └── receipts.jsonl
```

Both receipt files begin byte-identical and contain `call-1`. The
`validate-only` branch appends `call-2` after its exact allowed validation
command. The other branch asks to change the answer again; the operator denies
it with a reason, so its file and receipt bytes remain unchanged.

Construct each branch with its own `Workspace` and `ReceiptStore`, then call:

```python
outcome = run_branch(
"validate-only",
"validate without another edit",
checkpoint,
prefix_generator.fork(),
workspace,
receipts,
evaluation_case,
)
```

`run_branch` composes the Day 6 steered resume with the Day 7 observable-outcome
evaluator. It does not copy a directory, infer an evaluation case, or merge
effects for you.

## Task 5: Select One Passing Branch

Make the choice explicit:

```python
selected = select_branch(outcomes, "validate-only")
```

The name must identify exactly one outcome, and that outcome must pass its Day
7 report. Reject an absent selected name, a selected name that matches multiple
outcomes, or a failing branch. Day 8 does not invent a hidden score or ask
another model to judge the traces.

## Manual Qwen/MLX Walkthrough

Complete Weeks 1–3 and the Day 8 TODOs first. Use a cached local Qwen model and
the same dense compatibility path:

```python
from mlx_lm import load
from tiny_llm import Qwen3ModelWeek3
from tiny_llm.agent import KvPrefixGenerator, create_checkpoint

mlx_model, tokenizer = load("Qwen/Qwen3-0.6B-MLX-4bit")
model = Qwen3ModelWeek3(mlx_model, enable_paged_attention=False)
prefix_generator = KvPrefixGenerator(model, tokenizer, max_tokens=128)
```

First create a Day 4 checkpoint named `paused` after a complete tool
observation. Its messages are the control boundary you want to share, while its
model field belongs to the generator that created it. Rebind those exact
messages to the real tokenizer and dense KV cache before resuming:

```python
messages = [
{"role": role, "content": content}
for role, content in paused.messages
]
model_checkpoint = prefix_generator.save_checkpoint(messages)
checkpoint = create_checkpoint(paused.task, messages, model_checkpoint)
```

Now fork two fresh generators with `prefix_generator.fork()`. Give them
different visible steering messages and the two workspace/receipt copies
described above, passing the rebound `checkpoint` to each `run_branch` call.
Print each `outcome.reuse`, render both evaluation reports, and select the
passing name.

Model responses are nondeterministic, so this walkthrough is manual. Inspect
the actual proposed actions, approval reason, final file bytes, receipt logs,
and evaluation reports. The deterministic learner test covers the same public
boundary with a tiny tokenizer/model and no download.

## Checkpoint

You can now connect a Day 4 control checkpoint to the actual tokenizer and KV
cache path, reuse one immutable prefix for two isolated continuations, expose a
denial reason to the model without recording an effect, evaluate both branches
from declared evidence, and choose one passing result.

Completed effects were copied, not rewound. The two branches do not run
concurrently, share a mutable workspace, merge receipts, or provide a session
server/tree. Day 8 teaches the boundary visibly before adding any serving-scale
machinery.

{{#include copyright.md}}
18 changes: 14 additions & 4 deletions book/src/week4-overview.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 🚧 Week 4: Build a Coding Agent

> **Course status:** Week 4 is being published one checkpoint at a time. Days 1
> through 7 are ready to learn and review. Additional capabilities will appear
> through 8 are ready to learn and review. Additional capabilities will appear
> only after their implementation, starter, and reviews are ready.

Weeks 1 through 3 turn tokens into text and make serving that text efficient.
Expand All @@ -18,6 +18,9 @@ adds one visible operator steering message, and resumes a fresh model without
replaying the completed effect. Day 7 evaluates one completed run from declared
final, file, result, and receipt facts without grading hidden reasoning or exact
transcript shape.
Day 8 reconnects the agent to the inference system from Weeks 1–3: it saves one
real tokenizer/KV prefix, forks two isolated steered continuations without
rewinding completed effects, evaluates both, and makes one explicit selection.

## What Day 1 Builds

Expand Down Expand Up @@ -115,8 +118,15 @@ Outcomes](week4-07-evaluation.md). Its cumulative command is:
pdm run test --week 4 --day 7
```

Only the Day 1 through Day 7 starter modules are published. Do not add session
trees, rewind, reconciliation, an LLM judge, or other later public APIs to your
solution.
After Day 7 passes, continue with [Day 8: Fork, Steer, and
Select](week4-08-fork-steer-select.md). Its cumulative command is:

```bash
pdm run test --week 4 --day 8
```

Only the Day 1 through Day 8 starter modules are published. Do not add session
trees, effect rewind, reconciliation, an LLM judge, radix serving, or other
later public APIs to your solution.

{{#include copyright.md}}
24 changes: 13 additions & 11 deletions docs/week4-day-split.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Week 4 Day Split (reference for reviewers)

Status: Days 1--4 are published checkpoints. Days 2--4 follow Chi's approved
simplified agent-loop cycle, with each day shipping as one cumulative learner
PR so reviewers can see exactly what belongs to that checkpoint.
Status: Days 1--8 are published checkpoints. Each day ships as one cumulative
learner PR so reviewers can see exactly what belongs to that checkpoint.

## 7-day structure
## 8-day structure

| Day | Theme | Features (PRs) | Modules |
|---|---|---|---|
| 1 | Validated agent loop + tool protocol | feat1 | `protocol.py`, `loop.py` |
| 2 | Inspect a workspace | read-only list/read tools | `workspace.py` |
| 3 | Edit, validate, and record | approved edits, one command, simple receipts | `workspace.py`, `receipts.py` |
| 4 | Checkpoint and resume | one conversation + fake-model cache snapshot | `checkpoint.py`, `loop.py` |
| 5 | Reserved learner checkpoint | unpublished | — |
| 6 | Reserved learner checkpoint | unpublished | — |
| 7 | Reserved learner checkpoint | unpublished | — |
| 5 | Compact completed work | bounded receipt-backed transcript view | `compaction.py` |
| 6 | Inspect and steer | safe-boundary status and one visible steering message | `steering.py` |
| 7 | Evaluate outcomes | declared final/file/result/receipt facts | `evaluation.py` |
| 8 | Fork, steer, and select | dense tokenizer/KV prefix reuse, isolated branches, explicit selection | `branching.py`, `workspace.py` |

Extension (not a day): COW/radix cache — `docs/week4-cow-radix-extension-plan.md`.

Expand All @@ -26,8 +26,10 @@ Extension (not a day): COW/radix cache — `docs/week4-cow-radix-extension-plan.
- Days are implemented sequentially. A later day does not leak API or prose
into the current starter.

## Why 7 days
## Why 8 days

The existing `week4-01..07` chapter numbering stays stable. Each remaining day
adds one visible agent-loop concept; scaling and production-hardening machinery
stay outside the core course unless a later checkpoint explicitly teaches it.
The first seven days establish the agent loop and its observable evidence. Day
8 reconnects that control path to the tokenizer and KV cache built in Weeks
1--3. Each day adds one visible concept; scaling and production-hardening
machinery stay outside the core course unless a later checkpoint explicitly
teaches it.
Loading
Loading