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
  • ToyAIKit running 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.

Questions & Answers (0)

Sign in to ask questions