DEV Community

shashank ms
shashank ms

Posted on

Complex Coding Tutorial: From Simple to Complex

Today we are building an autonomous test-driven development agent that turns a plain-English specification into a passing Python module and pytest suite. It writes code, runs tests, reads failures, and repairs its own mistakes. Because Oxlo.ai uses flat per-request pricing, you can feed long tracebacks back into the model for multiple correction loops without the cost scaling with input length.

What you'll need

  • Python 3.10 or newer
  • The OpenAI SDK: pip install openai
  • An Oxlo.ai API key from https://portal.oxlo.ai
  • pytest: pip install pytest

Step 1: Configure the Oxlo.ai client

I create a small module that holds the client and selects a coding-capable model. Oxlo.ai exposes a fully OpenAI-compatible endpoint, so the import pattern is identical to what you already know. Because Oxlo.ai uses flat per-request pricing, feeding long tracebacks back into the model for several correction loops does not scale costs the way token-based billing would. See https://oxlo.ai/pricing for details.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.oxlo.ai/v1",
    api_key=os.getenv("OXLO_API_KEY", "YOUR_OXLO_API_KEY")
)

MODEL = "deepseek-v3.2"  # strong coding model, free tier available on Oxlo.ai

Step 2: Define the agent's system prompt

This prompt constrains the model to return JSON with exactly two keys: the implementation and the tests. Keeping the output structured means we can parse it without brittle regex.

SYSTEM_PROMPT = '''You are an expert Python engineer practicing strict test-driven development.

When given a feature specification, return a JSON object with exactly two keys:
- "implementation": a string containing the full content of the implementation file. Name the module task_queue. Do not include a file path, only the code.
- "tests": a string containing the full content of the test file. Import from task_queue using `from task_queue import ...` or `import task_queue`. Use pytest.

Rules:
- Use Python 3.10+ syntax.
- Include type hints and docstrings.
- If previous test output is provided, analyze the failures and fix the implementation or tests.
- Do not write markdown or explanations outside the JSON object.'''

Step 3: Add file I/O helpers

The helper below expects a JSON object from the model and writes the two files to disk. I keep everything in the working directory so pytest resolves imports without package gymnastics.

import json
import pathlib

IMPL_FILE = pathlib.Path("task_queue.py")
TEST_FILE = pathlib.Path("test_task_queue.py")

def write_files(artifacts: dict[str, str]) -> None:
    IMPL_FILE.write_text(artifacts.get("implementation", ""), encoding="utf-8")
    TEST_FILE.write_text(artifacts.get("tests", ""), encoding="utf-8")

Step 4: Generate the implementation and tests

I send the feature specification to Oxlo.ai and ask for the implementation and test suite in one shot. I use response_format={"type": "json_object"} to enforce valid JSON.

FEATURE_SPEC = """
Build a PriorityTaskQueue with the following behavior:
- Tasks are tuples of (priority: int, task_id: str, payload: dict).
- Lower integer means higher priority.
- Supports insertion, peeking at the highest priority item, and popping it.
- If priorities are equal, preserve FIFO order.
- Include a method to mark a task_id as cancelled so it is skipped on pop.
"""

def generate_artifacts(spec: str, previous_output: str = "") -> dict[str, str]:
    user_msg = f"Specification:\n{spec}\n"
    if previous_output:
        user_msg += f"\nPrevious test output:\n{previous_output}\n\nFix the code and tests."

    response = client.chat.completions.create(
        model=MODEL,
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_msg},
        ],
        response_format={"type": "json_object"},
        temperature=0.2,
    )
    content = response.choices[0].message.content
    return json.loads(content)

Step 5: Execute the test suite

A thin wrapper around subprocess captures stdout and the return code. Non-zero exit codes mean the agent needs another pass.

import subprocess

def run_tests() -> tuple[int, str]:
    result = subprocess.run(
        ["python", "-m", "pytest", str(TEST_FILE), "-v"],
        capture_output=True,
        text=True
    )
    return result.returncode, result.stdout + result.stderr

Step 6: Build the self-correction loop

If tests fail, I feed the traceback back into the same conversation context and request a corrected JSON payload. I cap retries at three to avoid runaway loops.

MAX_RETRIES = 3

def iterate_until_passing(spec: str) -> None:
    previous = ""
    for attempt in range(1, MAX_RETRIES + 1):
        print(f"\n--- Attempt {attempt} ---")
        artifacts = generate_artifacts(spec, previous)
        write_files(artifacts)
        code, output = run_tests()
        print(output)
        if code == 0:
            print("\nAll tests passed.")
            return
        previous = output
    print("\nMax retries reached. Review generated files manually.")

Step 7: Orchestrate the full pipeline

The main entry point stitches everything together: generate, write, test, and optionally repair until green.

if __name__ == "__main__":
    iterate_until_passing(FEATURE_SPEC)

Run it

Save the script as tdd_agent.py, export your key, and run it.

export OXLO_API_KEY="your_key_here"
python tdd_agent.py

You should see output similar to this:

--- Attempt 1 ---
============================= test session starts ==============================
collected 5 items

test_task_queue.py::test_insert_and_peek PASSED
test_task_queue.py::test_fifo_for_equal_priority PASSED
test_task_queue.py::test_pop_highest_priority PASSED
test_task_queue.py::test_cancel_task PASSED
test_task_queue.py::test_peek_empty_queue PASSED

============================== 5 passed in 0.02s ==============================

All tests passed.

If a test fails on the first attempt, the agent automatically prints the traceback and requests a fix from the model. On Oxlo.ai, that retry costs the same flat per-request rate as the first turn.

Wrap-up

Two concrete next steps. First, swap in kimi-k2.6 or qwen-3-32b for larger architectural specs that require advanced reasoning or agentic planning across multiple files. Second, add a file watcher with watchdog so the agent re-runs whenever you edit the spec in a local markdown file, turning it into a live coding companion.

Top comments (0)