Part 6: Run the coding agent
Now we connect the copied Django project, the file tools, the developer
prompt, and the ToyAIKit runner. This is the first full version of the
coding agent.
Register the project tools
Create the AgentTools instance for the copied project:
from pathlib import Path
import tools
project_path = Path(project_name)
agent_tools = tools.AgentTools(project_path)
Give the methods to ToyAIKit:
from toyaikit.tools import Tools
tools_obj = Tools()
tools_obj.add_tools(agent_tools)
add_tools scans the public methods on agent_tools, reads the docstrings
and type hints, and creates the tool schemas that OpenAI expects.
Look at the schemas if you want to see what the model receives:
tools_obj.get_tools()
You should see tools for read_file, write_file, see_file_tree,
execute_bash_command, and search_in_files.
Create the coding runner
Use the same notebook chat interface as before:
from openai import OpenAI
from toyaikit.chat import IPythonChatInterface
from toyaikit.llm import OpenAIClient
from toyaikit.chat.runners import OpenAIResponsesRunner
chat_interface = IPythonChatInterface()
openai_client = OpenAIClient(client=OpenAI())
Create the runner:
runner = OpenAIResponsesRunner(
tools=tools_obj,
developer_prompt=DEVELOPER_PROMPT,
chat_interface=chat_interface,
llm_client=openai_client,
)
Start the chat:
runner.run()
Type the whole app request:
to-do list
The model should first produce a plan, then call tools. In the screenshot it
reads myapp/models.py, myapp/views.py, myproject/urls.py, and
myapp/templates/home.html, then writes updated versions.
Run the generated app
When the runner finishes, leave the notebook and run the generated project from a terminal:
cd todo-two
make run
Open http://127.0.0.1:8000/. If the model puts the app under a different
path, check myproject/urls.py and open that path. The first generated
version may land under /todo/.
Add an item like milk, then try completion and deletion. The first
version may not be perfect. That is expected with a small, cheap model like
gpt-4o-mini.
Iterate when something fails
A first generated todo app may mostly work while delete or form styling still needs a second pass. Use another chat message to the same agent:
make the forms more beautiful and delete doesn't work
After the agent edits files again, restart the Django server and test in the browser. This is expected: ask again, restart the server, and test again. You do not need the model to get everything right from the first prompt.
Shape of the generated todo app
The todo-tutorial folder in the workshop repo shows the kind of Django files
the agent can produce. A minimal model:
from django.db import models
class Todo(models.Model):
title = models.CharField(max_length=200)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
A ModelForm lets Django render and validate todo input:
from django import forms
from .models import Todo
class TodoForm(forms.ModelForm):
class Meta:
model = Todo
fields = ["title", "completed"]
widgets = {
"title": forms.TextInput(attrs={"class": "border rounded p-2 w-full"}),
"completed": forms.CheckboxInput(attrs={"class": "mr-2"}),
}
The view handles both adding and toggling todos:
from django.shortcuts import render, redirect
from .models import Todo
from .forms import TodoForm
def todo_list(request):
todos = Todo.objects.all()
if request.method == "POST":
if "complete" in request.POST:
todo_id = request.POST["complete"]
todo = Todo.objects.get(id=todo_id)
todo.completed = not todo.completed
todo.save()
return redirect("todo_list")
The same view handles creating new todos when the POST is not a completion toggle:
form = TodoForm(request.POST)
if form.is_valid():
form.save()
return redirect("todo_list")
form = TodoForm()
return render(request, "todo_list.html", {"todos": todos, "form": form})
def delete_todo(request, todo_id):
todo = Todo.objects.get(id=todo_id)
todo.delete()
return redirect("todo_list")
Then myproject/urls.py connects the views:
from django.contrib import admin
from django.urls import path
from myapp.views import todo_list, delete_todo
urlpatterns = [
path("admin/", admin.site.urls),
path("", todo_list, name="todo_list"),
path("delete/<int:todo_id>/", delete_todo, name="delete_todo"),
]
The generated version you get may differ. That is fine. What matters is that the agent had enough tools and context to add a model, view, template, URL route, and migration path from one short request.
Recap
Now we have the first complete coding agent:
- a copied Django template
- local file tools scoped to that copied folder
- a detailed developer prompt
ToyAIKitrunning the OpenAI Responses API tool loop- a notebook chat where the user can ask for an app
The next steps keep the same project idea and swap out the framework that runs the agent.
Continue with Part 7: OpenAI Agents SDK.