TheFocus.AI TheFocus.AI
03 advanced Lesson 11

Chapter 11: Polish & Introspection

Clean up tool implementations, add session compaction, self-analysis, and document known issues.

TUTOR WITH THEFOCUS.AI

Agent Integration

Copy this prompt into Claude, ChatGPT, or any external AI assistant. It points the assistant to the course instructions and links it to your student profile to track your progress and customize observations.

Please tutor me in this lesson using the following context. First, read the instructions at: https://courses.thefocus.ai/llms.txt My Student ID is: <none> The lesson markdown source is at: https://courses.thefocus.ai/build-ai-coding-agent/03-advanced/11-polish.md

You are not enrolled yet. Enroll to generate a Student ID to track lesson completions and store learning notes.

Chapter 11: Polish & Introspection

What We’re Building

The final chapter is about making everything work well together. We’ll:

  • Clean up tool implementations
  • Add response limits to prevent context overflow
  • Implement session compaction (summarize old context)
  • Add session introspection (analyze your own logs)
  • Document known issues and future roadmap

Step 1: Clean Up Tools

Paste:

look through the tools implementations and make sure that it’s clean, and make sure that we are using ripgrep for searching

add a limit to the size of the response for search_files to make sure that it doesn’t return more than 50 lines. also add a 500 line limit to read_file and add some offset parameters to it. remove git commit command also

The Limit System

search_files — max 50 matches:

const lines = result.trim().split("\n");
if (lines.length > 50) {
  return (
    lines.slice(0, 50).join("\n") +
    `\n... (and ${lines.length - 50} more matches)`
  );
}

read_file — max 500 lines with start/limit:

const start = Math.max(0, startLine - 1);
const safeLimit = Math.min(limit, 500);
const end = Math.min(lines.length, start + safeLimit);

if (lines.length > end - start) {
  result += `\n\n(Showing lines ${start + 1}-${end} of ${lines.length}. Use startLine and limit to see more.)`;
}

No Auto-Commit

The system prompt explicitly forbids auto-commit:

6. **No Auto-Commit**: NEVER automatically commit changes. You may use
   'git_diff' to verify changes, but you must ask the user for confirmation
   before committing, or wait for the user to commit manually.

Step 2: Session Compaction

As conversations grow, the context window fills up. Compaction summarizes the conversation history into a concise format, preserving essential context while freeing up tokens.

Paste:

Add session compaction — when the context gets too large, summarize the conversation history into a compact form that preserves the key decisions, code changes, and current state.

The compaction flow:

  1. Detect: When total tokens exceed ~80% of the context window
  2. Summarize: An agent (or subagent) reads the conversation and produces a summary
  3. Replace: Old messages are replaced with a single system message containing the summary
  4. Continue: The agent continues with fresh context

The summary format:

## Session Summary
### Current State
- Branch: main
- Last action: Completed tool refactoring
- Files modified: src/tools/files.ts, src/tools/search.ts

### Key Decisions
1. Use ripgrep for all text search
2. 50-line limit on search results
3. 500-line limit on file reads

### Pending Work
- Session logging needs subagent parent tracking
- TUI improvements pending

Step 3: Session Introspection

Paste:

add a session-analysis agent that reads the session logs, identifies patterns (which tools are used most, where errors occur, what costs the most), and generates a report with recommendations

The introspection agent:

  1. Reads .session_logs/ files
  2. Counts tool usage, error rates, costs
  3. Identifies patterns: “You use read_file 3× more than search_files — consider searching first”
  4. Generates recommendations: “Most errors happen in replace_in_file — consider adding a preview step”

Step 4: The ask_user Tool

Paste:

We need a way for subagents to query the user for questions. Create a subagent who makes a poem about your name, and asks you first what your name is and then a follow up question about a color, and then writes a poem. Then lets test out the subagent to make sure that the main loop handles the handoff correctly, and knows what the final answer is.

The ask_user tool in src/tools/user.ts:

import { askQuestion } from "../lib/readline";

export async function askUser(
  question: string,
  agentName = "system",
): Promise<string> {
  const answer = await askQuestion(`\n[${agentName}] ${question}\n> `);
  return answer;
}

This shows labeled prompts like:

[poet] What is your name?
> Will

[poet] What is your favorite color?
> blue

[poem about Will and the color blue...]

Step 5: Known Issues & Roadmap

Things to Be Aware Of

  • Subagent readline: Multiple subagents using ask_user simultaneously can be confusing. The current implementation serializes them.
  • Context overflow: Without compaction, long sessions degrade. Model behavior at the context limit varies — some get confused, some start repeating.
  • Tool result truncation: Results over 1,000 characters are truncated in the console display but the full result goes to the LLM.
  • Model selection: Gemini is cheaper but can be less precise than Opus for complex refactoring. Experiment to find your sweet spot.

Future Improvements

AreaWhat Could Be Better
StreamingShow partial LLM output as it generates (currently waits for full response)
MCP IntegrationConnect to the Model Context Protocol ecosystem for reusable tools
EvaluationAutomated test suite that validates agent behavior doesn’t regress
Undo/RollbackGit-based recovery from agent mistakes
OpenRouter AlternativesDirect Anthropic/Google/OpenAI connections for provider-specific features

Step 6: Final Verification

run the full test suite and lint everything
mise run check

Everything should pass:

✓ sanity.test.ts — all tests pass
✓ tools.test.ts — all tools tested
✓ agent.test.ts — agent loop verified
✓ api.test.ts — API client tested
✓ search.test.ts — ripgrep search tested
✓ web.test.ts — URL download tested
✓ tavily.test.ts — Tavily search tested
✓ subagent.test.ts — subagent spawning tested

Checked 24 files in 85ms. No errors.

The Complete Architecture

weekend-coding-agent/
├── src/
│   ├── index.ts              # REPL, session setup, cost display
│   ├── agent.ts              # runTurn loop, subagent runner
│   ├── lib/
│   │   ├── api.ts            # OpenRouter client, model stats
│   │   ├── logger.ts         # JSONL session logging
│   │   ├── readline.ts       # Terminal I/O
│   │   └── types.ts          # Message, CompletionResponse
│   ├── tools/
│   │   ├── index.ts          # Tool definitions + dispatch
│   │   ├── files.ts          # listFiles, readFile, writeFile, replaceInFile
│   │   ├── search.ts         # ripgrep search
│   │   ├── system.ts         # bash execution
│   │   ├── web.ts            # URL → markdown
│   │   ├── tavily.ts         # Web search
│   │   ├── git.ts            # git diff
│   │   ├── user.ts           # ask_user (human-in-the-loop)
│   │   └── types.ts          # CommandExecutor, AgentRunner
│   └── prompts/
│       ├── index.ts          # Prompt loader, skill loader
│       ├── default.md        # Main coding agent
│       ├── code-map.md       # Codebase documentation agent
│       ├── tech-researcher.md # Web research agent
│       ├── feature-planner.md # Feature planning agent
│       └── poet.md           # Interactive poem agent
├── skills/
│   ├── big_text/SKILL.md     # figlet ASCII art
│   ├── generate_image/SKILL.md # Image generation
│   └── generate_video/SKILL.md # Video generation
├── tests/                    # Full test suite
├── .session_logs/            # JSONL recording
├── docs/                     # Code maps
├── reports/                  # Research reports
├── .env                      # API keys
├── mise.toml                 # Tasks and tools
└── biome.json                # Linter config

← Chapter 10 · Course Home →

Previous Lesson 11 of 11