Suyash-18/Coding-Agent-Assignment:带人工审批的 AI 编码智能体
Suyash-18/Coding-Agent-Assignment
一个 AI 编码智能体接收自然语言编码请求,扫描项目定位相关文件、生成计划、编写改动并运行测试,最后展示 diff,在你批准前不会写入仓库。它基于 LangGraph 构建,含计划审批和应用审批两处人工中断,测试失败会把输出回传模型重试。CLI、FastAPI 后端和 Streamlit 前端共用同一事件流,默认模型为 openai/gpt-oss-120b。
An AI coding agent that takes a coding request in plain language, finds the relevant files in a project, proposes a plan, writes the change, runs the tests and shows a diff. Nothing is written to the repository until you approve it.
| Live app | https://coding-agent-frontend.onrender.com/ |
| API (Swagger UI) | <backend URL>/docs (see Deployment) |
| API spec | docs/openapi.yaml |
| Approach, assumptions, limitations | docs/APPROACH.md |
| Source | https://github.com/Suyash-18/Coding-Agent-Assignment |
The app runs on Render's free tier. If nobody has used it for 15 minutes it goes to sleep, so the first page load can take up to a minute. After a wake-up, open Scripts → reset_demo once to recreate the demo repository (the free tier does not keep files).
What it does
Example request: "Ensure that newly created users always have their email stored in lowercase. Add a test proving that an uppercase email is normalized correctly."
- Checks the task (input guardrails: length, non-coding requests, prompt injection, secret-extraction).
- Scans the repository and asks the model which files matter.
- Reads those files and writes a plan (files to change, actions, assumptions).
- You approve or reject the plan, optionally with a note for the model.
- Generates the changes, validates them (output guardrails) and runs the tests in a temporary copy. If the tests fail, the failure output goes back to the model for another attempt (a small, fixed number of retries).
- Shows the diff, test results and an explanation of what changed and why.
- You approve or decline applying the change. Unverified changes (tests failed or none ran) are clearly marked.
Architecture
The CLI, the API and the Streamlit app all consume the same event stream from
stream_agent() / resume_agent(), so there is one agent engine and three ways to use it.
Agent graph (LangGraph, with two human-approval interrupts):
input_guard → scan_repo → select_files → read_files → make_plan ⇄ expand_files
→ plan_approval ⏸ → generate_changes → output_guard → run_tests
↳ failed and retries left → generate_changes (with test output)
→ build_diff → explain → apply_approval ⏸ → apply_changes
LangGraph Diagram
The following is the graph of LangGraph:
Project layout
src/
coding_agent/
runner.py stream_agent / resume_agent and the AgentEvent contract
cli.py command-line interface
api/ FastAPI backend (app, runs, jobs, repos, history, safety, schemas, settings)
ui/ Streamlit front end (app.py, client.py, timeline.py)
... graph, nodes, prompts, guardrails, tools, llm, config, run logs
sample_project/ small FastAPI user manager used as the target of the demos
demo/sample_project/ working copy the agent edits (recreated by reset_demo)
docs/ openapi.yaml, APPROACH.md
Run it locally
Requirements: Python 3.10 or newer (see .python-version), uv, and a
Groq API key.
git clone [https://github.com/Suyash-18/Coding-Agent-Assignment.git](https://github.com/Suyash-18/Coding-Agent-Assignment.git)
cd Coding-Agent-Assignment
uv syncCreate a .env file in the project root (never commit it):
GROQ_API_KEY=your-key-here MODEL_NAME=openai/gpt-oss-120b
The agent works on a copy of the sample project in demo/sample_project. If that folder does not exist
yet, start the backend (Option B below) and run Scripts → reset_demo (or POST /repos/demo/reset).
Scripts → smoke makes one model call to check your key and model name.
Option A: command line
uv run python -m coding_agent run \ --repo demo/sample_project \ --model "openai/gpt-oss-120b" \ --task "Add a /health endpoint with a test"
Flags: --yes (auto-approve; applies only if tests passed), --dry-run (never writes).
Exit codes: 0 finished, 1 error or guardrail block, 2 tests did not pass (unverified), 130 Ctrl-C.
Option B: web app (backend + Streamlit)
Terminal 1, the API:
uv run uvicorn --factory coding_agent.api.app:create_app --port 8000
Terminal 2, the UI:
uv run streamlit run src/coding_agent/ui/app.py
The UI finds the API through the CODING_AGENT_API_URL environment variable
(default http://localhost:8000). Open http://localhost:8501, and the API docs at http://localhost:8000/docs.
Tests
uv run pytest
Wherever the model is involved the tests use a fake LLM, so they need no API key.
Using the web app
| Page | What it is for |
|---|---|
| Run agent | Enter a task (or click an example), watch the live timeline, approve the plan, review tests, diff and explanation, then apply or decline. |
| Repositories | Browse files, see changes compared with the pristine sample, reset the demo repo. |
| History | Every past run listed by its prompt; open one to see the plan, tests, diff and explanation again. |
| Scripts | smoke (check key and model), reset_demo, check_demo (run the demo repo's tests), dev_run (run the agent end to end with automatic approvals). |
| About | Short in-app guide to the pages. |
The sidebar chooses the model for new runs.
Configuration
| Variable | Used by | Meaning |
|---|---|---|
GROQ_API_KEY |
backend, CLI | Groq API key (required) |
MODEL_NAME |
backend, CLI | Default model (openai/gpt-oss-120b) |
MODEL_NAME2 |
UI, evals | Second model offered in the sidebar (qwen/qwen3.8-27b) |
CODING_AGENT_API_URL |
UI | Where the backend lives (default https://coding-agent-assignment-kpyt.onrender.com) |
AGENT_ROOT |
backend | Project root; set it on hosted services |
AGENT_RUNS_DIR |
backend | Run-log folder (runs), or off to disable logs |
API_MAX_RUNS_PER_HOUR / API_MAX_RUNS_PER_DAY |
backend | Rate limits (20 per client per hour, 100 per day overall) |
API_DECISION_TTL_S |
backend | Seconds a paused run waits for a decision (1800) |
API_CORS_ORIGINS |
backend | Comma-separated origins allowed by CORS |
The models the API accepts are listed in ALLOWED_MODELS in src/coding_agent/api/settings.py.
API
The backend exposes runs, repositories, scripts and run history. Typical flow:
# 1. start a run curl -X POST $API/runs -H "Content-Type: application/json" \ -d '{"task": "Add a /health endpoint with a test", "repo_id": "demo"}' # 2. follow it (Server-Sent Events); stops at each approval curl -N $API/runs/$RUN_ID/events # 3. approve the plan, then later the apply step curl -X POST $API/runs/$RUN_ID/decision -H "Content-Type: application/json" \ -d '{"approved": true, "feedback": ""}' # 4. read the result or download the patch curl $API/runs/$RUN_ID/result curl -OJ $API/runs/$RUN_ID/patch
Full reference: docs/openapi.yaml. Paste it into https://editor.swagger.io, or open /docs on the running backend.
Safety
- Path safety: file access is confined to the repository (no
.., absolute paths or symlink escapes);.git,.env, binaries and oversized files are ignored. - Input guard: blocks over-long, non-coding, injection and secret-extraction requests, before any model call.
- Output guard: checks the model's output schema, paths, file and diff size, secret patterns and protected files.
- Human approval: two interrupts (plan, apply);
--yesnever applies a change whose tests failed. - Secrets: event payloads are redacted before they are stored or streamed; no keys are in the repository.
- Hosted limits: per-client and global run limits, one writer per repository, and a time limit on paused runs.
Deployment
Both services run on Render as Python web services from this repository:
| Service | Start command |
|---|---|
| Backend | uv run --no-sync uvicorn --factory coding_agent.api.app:create_app --host 0.0.0.0 --port $PORT |
| Frontend | uv run --no-sync streamlit run src/coding_agent/ui/app.py --server.port $PORT --server.address 0.0.0.0 --server.headless true |
Build command for both: uv sync --frozen. Backend environment: GROQ_API_KEY, MODEL_NAME, AGENT_ROOT.
Frontend environment: CODING_AGENT_API_URL set to the backend's public https:// URL.
Health check: /health.
Known limits
See docs/APPROACH.md for the approach, assumptions and limitations. In short:
the hosted demo edits one shared demo repository, state is kept in memory (a restart ends running runs),
and the free Groq tier can rate-limit model calls.
来源:GitHub · github.com
