kiln-agents
A native Python port of kiln — build and orchestrate AI
agents. Same primitives as the TypeScript/npm package (@abhishekvardanbotta/kiln), reimplemented
natively in Python: no Node runtime involved.
pip install kiln-agents
What's ported
- Unified providers — OpenAI, Groq, and Ollama via one shared
httpx-based adapter (same design as the TS version: one class, three providers, swap a base URL + env var name). Gemini and Claude are declared but not implemented yet, matching the TS package's current status. ctx.ai.run()— the tool-calling loop: call the model, execute any requested tool calls, feed the results back, repeat, up tomax_steps.ctx.ai.object()— self-correcting structured output. Takes a pydantic model as the schema (Python's equivalent of the TS version's zod schema), writes the schema instruction into the prompt, validates the response, and retries with the exact validation error fed back on failure.connect_mcp()— real Model Context Protocol support via the officialmcpPython SDK. Any MCP server's tools become normal kilnToolobjects.orchestrate()— the DAG orchestrator:depends_on, per-step retries, a concurrency pool (asyncio.Semaphore-based), and cascading"skipped"status for steps whose dependency failed — ported line-for-line from the TSOrchestrator.
What's not ported (by design, this release)
The kiln CLI — kiln init/pack/install/serve/logs, the .agent package format, and
~/.kiln project/registry management — is TypeScript-only for now. This package is the embeddable
SDK: you define_agent(...) directly in your own Python code and run it in-process, the same pattern
the TS SDK uses when embedded in a Node backend (no CLI, no separate project folder). If you need a
long-running HTTP surface for a non-Python caller, run the TS package's kiln serve instead — this
package is for using kiln from Python, not for running the CLI.
Quickstart
import asyncio
from pydantic import BaseModel
from kiln_agents import create_kiln, define_agent
class Forecast(BaseModel):
city: str
temperature_c: float
summary: str
async def forecast_execute(ctx):
city = ctx.input["city"]
return await ctx.ai.object(
messages=[{"role": "user", "content": f"Give a short weather forecast for {city}."}],
schema=Forecast,
)
forecaster = define_agent(
name="forecaster",
provider="groq", # "openai" | "groq" | "ollama"
model="llama-3.3-70b-versatile",
execute=forecast_execute,
)
async def main():
kiln = create_kiln()
result = await kiln.run_inline_agent(forecaster, {"city": "Tokyo"})
print(result.output)
asyncio.run(main())
Orchestrating multiple agents
from kiln_agents import create_kiln, PipelineStep, PipelineRunContext
kiln = create_kiln()
result = await kiln.orchestrate([
PipelineStep(id="forecaster", agent=forecaster, input={"city": "Paris"}),
PipelineStep(
id="advisor",
agent=advisor,
depends_on=["forecaster"],
retries=2,
input=lambda ctx: {"forecast": ctx.outputs["forecaster"]},
),
])
print(result.outputs["advisor"])
print([step.status for step in result.steps]) # "succeeded" | "failed" | "skipped"
Tools
from pydantic import BaseModel
from kiln_agents import define_tool
class GetForecastInput(BaseModel):
city: str
async def get_forecast(input: GetForecastInput, ctx):
return {"city": input.city, "temperature_c": 21.0, "summary": "Clear skies."}
get_forecast_tool = define_tool(
name="get_forecast",
description="Fetch a real weather forecast for a city.",
parameters=GetForecastInput,
execute=get_forecast,
)
# Pass tools=[get_forecast_tool] into define_agent(...), then either:
# await ctx.tools["get_forecast"]({"city": "Tokyo"}) # call it directly
# await ctx.ai.run(messages=[...]) # or let the model decide to call it
MCP
from kiln_agents import connect_mcp
mcp = await connect_mcp("npx", args=["-y", "@some/mcp-server"])
# mcp.tools is list[Tool] — pass straight into define_agent(tools=[...])
...
await mcp.close() # always close when done
Provider setup
| provider | env var | notes |
|---|---|---|
openai |
OPENAI_API_KEY |
base URL https://api.openai.com/v1 |
groq |
GROQ_API_KEY |
base URL https://api.groq.com/openai/v1 |
ollama |
OLLAMA_HOST (optional) |
defaults to localhost:11434; give it bare host:port |
gemini, claude |
— | stub only, raises KilnError("<name> is not implemented yet.") |
License
MIT
Metadata
Release files for kiln-agents 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kiln_agents-0.1.0.tar.gz | 17.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kiln_agents-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.3 kB
Release files / kiln_agents-0.1.0.tar.gz
| Download URL | kiln_agents-0.1.0.tar.gz |
|---|---|
| Size | 17.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6416d02207cd41e4762ae12284ec26e73b42652c935eb603394c2a54c2bb859a
|
|
BLAKE2b-256 checksum How to use checksums |
fce1da06f93394c0a24a369f26b1d1365be95f7b031d9a438b0fe990b40f0fa4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|
Release files / kiln_agents-0.1.0-py3-none-any.whl
| Download URL | kiln_agents-0.1.0-py3-none-any.whl |
|---|---|
| Size | 20.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fa4f6c17edd79436d4111e697764cc5658c82492a9f51357572019f8ce058736
|
|
BLAKE2b-256 checksum How to use checksums |
28fda8872cafe81682372de3b20e1df5e899a58849cd36601b0e001052ba5435
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|