Files
2026-06-05 21:20:37 +08:00

187 lines
9.0 KiB
Markdown

# Coding Mentor Agent
[![Node.js](https://img.shields.io/badge/Node.js-24.x-3c873a?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178c6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
[![React](https://img.shields.io/badge/React-19-149eca?style=flat-square&logo=react&logoColor=white)](https://react.dev)
[![Docker sandbox](https://img.shields.io/badge/Docker-Python_sandbox-2496ed?style=flat-square&logo=docker&logoColor=white)](https://www.docker.com)
A local-first AI coding mentor for a Chinese-language Python course. The app combines a React learning interface, a TypeScript HTTP/SSE backend, a Practical Python knowledge base, adaptive diagnostics, progress tracking, and a Docker-backed Python sandbox.
[Features](#features) • [Getting Started](#getting-started) • [Configuration](#configuration) • [Architecture](#architecture) • [Development](#development) • [Troubleshooting](#troubleshooting)
## Features
- **Tutor chat for Python learners**: explains concepts, reviews code, and guides debugging without bypassing the learning process.
- **Course-grounded knowledge base**: ships with a curated Practical Python catalog containing 9 units, 34 concepts, 25 exercises, mistake tags, and prerequisite relations.
- **Adaptive diagnostic flow**: places learners by concept readiness before unlocking structured practice.
- **Structured practice and project workflows**: selects exercises, creates practice contracts, reviews submissions, and records learning evidence.
- **Isolated Python execution**: runs student code and public tests in a Docker container with no network, dropped capabilities, memory limits, PID limits, and output truncation.
- **Local learning state**: stores sessions, mastery, evidence, practice reviews, and audit summaries in a local SQLite database under `.app` by default.
- **Tool policy and auditing**: gates model-visible tools by intent, caller, capability, and risk level, with redaction for secrets and local paths.
> [!IMPORTANT]
> Model-backed tutoring requires AI provider settings. Without `AI_PROVIDER` and `AI_API_KEY`, model-dependent chat turns return `MODEL_UNAVAILABLE`, although local catalog and diagnostic data can still initialize.
## Getting Started
### Prerequisites
- Node.js 24.x recommended. The Docker Compose setup uses `node:24.14.0-bookworm-slim`.
- npm.
- Docker Desktop or Docker Engine for code execution and grading.
- Python 3 if you plan to run the Python-based student-loop test harness.
- An AI provider API key for tutor responses.
### Run locally
```bash
npm install
cp .env.example .env
docker build -t coding-mentor-python-runner:0.1.0 -f sandbox-runner.Dockerfile .
npm start
```
Open [http://127.0.0.1:3000](http://127.0.0.1:3000).
On Windows PowerShell, use this instead of `cp`:
```powershell
Copy-Item .env.example .env
```
Then edit `.env` with your AI settings:
```ini
AI_PROVIDER=openai
AI_API=openai-responses
AI_BASE_URL=https://api.openai.com/v1
AI_MODEL=gpt-5.5
AI_API_KEY=your-api-key
```
### Run with Docker Compose
```bash
docker compose up --build
```
The Compose setup starts the app at [http://127.0.0.1:3000](http://127.0.0.1:3000), starts a sandbox service on the internal Compose network, and mounts the Docker socket so the sandbox service can launch isolated runner containers.
## Configuration
The app loads `.env` and `.env.local` from the repository root. Useful settings:
| Variable | Default | Purpose |
| --- | --- | --- |
| `PORT` | `3000` | Local HTTP server port. |
| `APP_DATA_DIR` | `.app` | SQLite database, Pi session files, backups, and test artifacts. |
| `COURSE_KB_ROOT` | `kb/python-course-kb-practical-python/wiki` | Course catalog and source content root. |
| `COURSE_KB_VERSION` | `kb-local` | Version label included in tutor prompts and catalog identity. |
| `ENABLED_BATCH` | `full` | Tool allowlist: `batch-a`, `batch-b`, `batch-c`, or `full`. |
| `SANDBOX_IMAGE` | `coding-mentor-python-runner:0.1.0` | Docker image used for Python execution. |
| `SANDBOX_SERVICE_URL` | empty | Optional HTTP sandbox service URL. Empty uses local Docker directly. |
| `SANDBOX_TIMEOUT_MS` | `3000` | Max runtime for simple Python execution. |
| `SANDBOX_PYTEST_TIMEOUT_MS` | `8000` | Max runtime for pytest grading. |
| `SANDBOX_MEMORY_MB` | `128` | Container memory limit. |
| `AI_PROVIDER` | empty | Provider name used by `@earendil-works/pi-ai`. |
| `AI_API` | empty | Set to `openai-responses` for the built-in Responses-compatible adapter. |
| `AI_BASE_URL` | `https://api.openai.com/v1` | HTTPS model API base URL. |
| `AI_MODEL` | `gpt-5.5` | Model id passed to the provider adapter. |
| `AI_API_KEY` | empty | API key for tutor responses. |
## Architecture
```mermaid
flowchart LR
UI["React + CodeMirror UI"] --> API["TypeScript HTTP/SSE server"]
API --> DB["Local SQLite progress DB"]
API --> KB["Course knowledge base"]
API --> Tutor["Pi AI tutor session"]
API --> Gate["Tool policy gate"]
Gate --> Sandbox["Docker Python sandbox"]
Gate --> Tools["KB, progress, exercise, project tools"]
```
Key paths:
| Path | Purpose |
| --- | --- |
| `src/frontend` | React app, CodeMirror editor, SSE state handling, safe Markdown rendering. |
| `src/server` | HTTP API, sessions, diagnostics, progress policy, recommendations, project flow, local data management. |
| `src/agent` | Tutor prompt construction and Pi AI / Pi coding-agent integration. |
| `src/tools` | Course tools, schemas, envelopes, tool registry, and capability policy. |
| `src/sandbox` | Docker runner and optional HTTP sandbox service. |
| `src/db` | SQLite schema, migrations, bootstrap, and validators. |
| `src/security` | Redaction, path validation, ids, and in-memory rate limits. |
| `kb/python-course-kb-practical-python` | Bundled Practical Python source material, summaries, concepts, exercises, and catalog manifest. |
| `tests` | Vitest unit/integration coverage plus Playwright and Python student-loop harnesses. |
## API Surface
The backend serves the React app and exposes local JSON/SSE endpoints:
- `POST /api/sessions` creates or resumes a local tutor session.
- `GET /api/sessions/:id/events` streams assistant messages and tool events over SSE.
- `GET /api/sessions/:id/snapshot` returns the current conversation, practice, progress, and tutor state.
- `POST /api/sessions/:id/messages` sends a learner message and optional code.
- `GET /api/diagnostics/next` and `POST /api/diagnostics/:id/answers` drive the adaptive diagnostic flow.
- `GET /api/progress/me` returns local mastery and evidence summaries.
- `POST /api/code/run` executes Python through the gated sandbox.
- `GET /api/exercises/next` and `POST /api/exercises/:id/submissions` handle structured practice.
- `GET /api/data/export`, `POST /api/data/delete`, and `POST /api/data/backups` manage local learning data.
## Development
Common scripts:
| Command | Description |
| --- | --- |
| `npm start` | Build the Vite client and run the local server on `127.0.0.1`. |
| `npm run dev` | Same server entry point as `npm start`. |
| `npm run dev:frontend` | Start Vite for frontend-only iteration. |
| `npm run build` | Type-check and build the client into `dist/client`. |
| `npm run lint` | Run TypeScript type-checking with `tsc --noEmit`. |
| `npm test` | Run Vitest tests under `tests/**/*.test.ts`. |
| `npm run start:sandbox` | Start the optional HTTP sandbox service. |
| `npm run test:student-loop:realistic` | Run the realistic Python student-loop discovery harness. |
| `npm run test:student-loop:release` | Run the release-profile student-loop harness. |
| `npm run test:student-loop:security` | Run the security-profile student-loop harness. |
For UI-oriented checks, Playwright is configured to build the app and preview it at `http://127.0.0.1:4173`.
## Local Data
By default, all learner state lives under `.app`:
- `progress.db` stores profile, sessions, mastery, exercises, diagnostics, practice reviews, projects, audit logs, and security events.
- `pi-sessions` stores Pi agent session files.
- `student-loop` stores e2e harness artifacts.
Use `GET /api/data/export` for a redacted JSON export, `POST /api/data/backups` for an encrypted database backup, and `POST /api/data/delete` with `{"confirm":"DELETE_LOCAL_LEARNING_DATA"}` to clear local learner state.
## Troubleshooting
**`MODEL_UNAVAILABLE`**
Set `AI_PROVIDER`, `AI_MODEL`, and `AI_API_KEY` in `.env`. If using the built-in OpenAI-compatible Responses adapter, also set `AI_API=openai-responses`.
**Docker sandbox errors**
Make sure Docker is running and the runner image exists:
```bash
docker build -t coding-mentor-python-runner:0.1.0 -f sandbox-runner.Dockerfile .
```
**Port already in use**
Change `PORT` in `.env`, then restart the server.
**Practice is locked**
Complete the initial diagnostic first. The backend intentionally blocks structured practice until it has enough placement evidence.
**Reset local progress**
Delete `.app` while the server is stopped, or use the data deletion endpoint with the explicit confirmation token shown above.