pyforjs home

The AI engineering capstone

Typed tool schemas from Pydantic, cosine similarity over embeddings with numpy, and an agent loop that dispatches through a tool registry, all assembled in the browser.

Everything so far pointed here. An agent is three parts, and you now have the pieces for all of them: a schema generator, a retrieval function, and a dispatch loop.

Structured output

An LLM tool call is a JSON schema plus a validator for whatever comes back. Pydantic gives you both from one class. One class covers both the schema and the validation.

tool_schema.py
Starting Python…

That schema is what you hand to the model. When it answers, the same class parses the response, so a malformed tool call fails at the boundary with a field-level error rather than three frames deeper:

call = SearchDocs.model_validate_json(raw_arguments_from_model)
result = registry[name](call)

Vector search is one line of numpy

You do not need a vector database to retrieve over a few thousand chunks. Cosine similarity on a normalised matrix is a dot product.

cosine.py
Starting Python…

matrix @ vector computes every score at once in C. The keepdims=True is what makes the row-wise division broadcast correctly, dropping it is the most common bug in hand-rolled retrieval code.

The agent loop

Three steps, repeated until the model stops asking for tools:

  1. Send the conversation plus the tool schemas.
  2. If the reply is a tool call, look the tool up in a registry, validate the arguments, run it.
  3. Append the result to the conversation and go back to step 1.
agent_loop.py
Starting Python…

Notice what the loop leaves out. There is no framework, no orchestration DSL, no callback graph. A dict of tools, a validator per tool, and a bounded for. Every production agent is this plus error handling, retries and observability.

Kata

Wire the registry yourself.

kata_05.py
Starting Python…

That is the whole job

A production agent adds retries, streaming, tracing and a real embedding model. The control flow does not change. If you can read the loop above you can read any agent framework's source, and usually decide you did not need it.

You are done. Every runner, kata, and quiz answer on this site ran as CPython compiled to WebAssembly, in your browser tab the whole time.

On this page