Delfhos — AI agent SDK with typed connections and tool orchestration
Project description
Delfhos
Python SDK for building AI agents that use real tools — Gmail, SQL, Drive, Sheets, Calendar, Docs, REST APIs, web search, and your own functions — with safe, human-in-the-loop execution.
Full documentation in DOCS.md · delfhos.com/docs
How it works
You describe a task in plain English. Delfhos:
- Picks the relevant tools from the ones you configured
- Writes Python code to accomplish the task
- Executes that code in a sandbox against your real services
- Retries automatically if something fails, and can replan mid-task
You stay in control: restrict which actions each tool can take, and require human approval before any write, send, or delete.
Key features
- Real tools, not just chat — first-class Gmail, SQL, Google Drive/Sheets/Docs/Calendar, web search, and any REST API via OpenAPI. Plus your own functions with a
@tooldecorator. - Code-writing agent — the LLM writes and runs Python, so it can loop, branch, and chain tools in one task instead of one-call-at-a-time.
- Human-in-the-loop — per-action
allowandconfirmcontrols; approve or reject sends/writes/deletes from code, a callback, or the terminal. - Multi-provider — Gemini, OpenAI, and Anthropic out of the box, plus any OpenAI-compatible endpoint (Ollama, vLLM, Groq, Together…). Mix a fast model with a strong one via dual-LLM.
- Concurrent by default — fire many tasks at once on a single agent; each runs in parallel and is tracked independently.
- Serve over HTTP — expose an agent as an authenticated HTTP API in one line, to drive it from any language or service.
- Memory — short-term session chat plus long-term semantic memory (100+ embedding models).
- Sandboxed execution — runs locally or in a disposable Docker container with OS-level isolation.
Install
pip install delfhos
API keys
Export the key for the provider you want to use:
export GOOGLE_API_KEY="..." # Gemini
export OPENAI_API_KEY="..." # OpenAI
export ANTHROPIC_API_KEY="..." # Anthropic (Claude)
Quickstart — try it instantly (no credentials needed)
The sandbox tools come pre-loaded with dummy data, so you can run your first agent right now:
from delfhos import Agent
from delfhos.sandbox import MockEmail, MockDatabase
agent = Agent(
tools=[MockEmail(confirm=False), MockDatabase(confirm=False)],
llm="gemini-3.5-flash",
)
agent.run(
"Read my unread emails. If any mention a support ticket, "
"look it up in the database and summarise the customer name, "
"open tickets, and total order value."
)
agent.stop()
Or run the included example:
python examples/hello_delfhos.py
What it looks like end-to-end:
Input ──────────────────────────────────────────────────────────
"Read my unread emails. If any mention a support ticket,
look it up in the database and reply with a short summary of
the customer's name, their open tickets, and their total order value."
Agent ──────────────────────────────────────────────────────────
[tool] MockEmail.list_unread_emails()
[tool] MockDatabase.query("SELECT * FROM tickets WHERE id = 'TCK8843'")
[tool] MockDatabase.query("SELECT * FROM users WHERE email = 'alice@example.com'")
[tool] MockDatabase.query("SELECT SUM(amount) FROM orders WHERE user_id = 1")
[tool] MockEmail.send_email(to="alice@example.com", subject="Re: Overdue invoice")
Output ─────────────────────────────────────────────────────────
Sent a reply to alice@example.com.
Summary:
Customer: Alice (alice@example.com)
Open tickets: TCK8843 — "Invoice #1042 overdue" (open)
Total orders: $2,340.00
agent.run() returns a Response:
r = agent.run("...")
print(r.text) # the agent's answer
print(r.status) # True if the task succeeded
print(r.cost_usd) # cost in dollars, e.g. 0.00021
print(r.duration_ms) # wall-clock time in milliseconds
Your first real agent
Configure built-in tools with credentials, scope their actions with allow, and gate risky ones with confirm:
from delfhos import Agent, Gmail, SQL, Drive
gmail = Gmail(oauth_credentials="client_secrets.json", allow=["read", "send"], confirm=["send"])
db = SQL(url="postgresql://user:pass@host/db", allow=["schema", "query"])
drive = Drive(oauth_credentials="client_secrets.json", confirm=True)
agent = Agent(tools=[gmail, db, drive], llm="gemini-3.5-flash")
agent.run("Check unread emails and log any order mentions to the database.")
agent.stop()
allow— restrict which actions the tool exposes (["read", "send"],["schema", "query"], …).confirm— when human approval is required:True(all actions),False(none), or a list of specific actions.
Built-in tools:
from delfhos import Gmail, SQL, Sheets, Drive, Calendar, Docs, WebSearch, APITool
Custom tools
Decorate any Python function with @tool and the agent can call it. The docstring and type hints tell the agent how to use it:
from delfhos import Agent, tool
@tool
def calculate_discount(price: float, pct: float) -> float:
"""Return the price after applying a percentage discount."""
return price * (1 - pct / 100)
agent = Agent(tools=[calculate_discount], llm="gemini-3.1-flash-lite")
agent.run("What is the price of a $120 item with a 15% discount?")
agent.stop()
Connect any REST API (APITool)
Point APITool at an OpenAPI 3.x spec and every endpoint becomes callable — no custom code:
from delfhos import Agent, APITool
petstore = APITool(
spec="https://petstore3.swagger.io/api/v3/openapi.json",
allow=["list_pets", "get_pet_by_id"],
confirm=["create_pet", "delete_pet"],
)
# Private API with auth — credentials are injected, never seen by the agent
internal = APITool(
spec="./openapi.yaml",
base_url="https://api.internal.corp/v1",
headers={"Authorization": "Bearer sk_..."},
)
agent = Agent(tools=[petstore, internal], llm="gemini-3.5-flash")
agent.run("List all pets and create a new one named 'Buddy'")
headers=, params=, and path_params= are injected automatically; $ref schemas are resolved; specs are compiled once and cached. Inspect endpoints with petstore.inspect().
Run many tasks at once
A single agent runs tasks concurrently. Submit with submit() (returns a task_id immediately) and poll each one independently — they never interfere:
import time
from delfhos import Agent, Gmail
agent = Agent(tools=[Gmail(oauth_credentials="client_secrets.json")], llm="gemini-3.5-flash")
task_ids = [
agent.submit("Summarise today's unread emails"),
agent.submit("Find any pending invoices"),
agent.submit("Draft a reply to Ana's last email"),
]
pending = set(task_ids)
while pending:
for tid in list(pending):
snap = agent.poll(tid) # state, events, output, cost, tokens
if snap.is_terminal:
print(tid, "->", snap.result or snap.error)
pending.discard(tid)
time.sleep(0.3)
agent.stop()
For a single blocking call use run(); inside async code use await agent.arun(...).
Serve an agent over HTTP
Expose an agent as an authenticated HTTP API in one line — call it from any language or service:
from delfhos import Agent, WebSearch
agent = Agent(tools=[WebSearch(llm="gpt-5.4-mini", confirm=False)], llm="gpt-5.4-mini")
agent.serve(host="0.0.0.0", port=8080, api_key="sk-my-secret")
| Endpoint | Purpose |
|---|---|
POST /run |
Body {"task": "..."} → {"task_id": "..."} |
GET /tasks/{id} |
JSON snapshot — state, events, output, cost, tokens |
GET /health |
{"ok": true} (always public) |
curl -H "Authorization: Bearer sk-my-secret" \
-X POST localhost:8080/run -H 'content-type: application/json' \
-d '{"task": "Find this week's AI news"}'
# {"task_id": "..."}
curl -H "X-API-Key: sk-my-secret" localhost:8080/tasks/<task_id> # poll until is_terminal
- Auth — pass
api_key(a string or list of keys) or setDELFHOS_API_KEY. Clients sendAuthorization: Bearer <key>orX-API-Key: <key>. - Fail-closed — binding to a public interface without a key is refused. Put HTTPS (Caddy/Nginx/Cloudflare) in front in production.
- Mount it —
app.mount("/agent", agent.asgi_app(api_key="sk-my-secret"))to compose with an existing FastAPI app.
Model support
Cloud providers — Gemini, OpenAI, or Anthropic:
agent = Agent(tools=[...], llm="gemini-3.5-flash") # or gemini-3.1-flash-lite, gemini-3.1-pro
agent = Agent(tools=[...], llm="gpt-5.5") # or gpt-5.4-mini
agent = Agent(tools=[...], llm="claude-sonnet-4-6") # or claude-opus-4-8
Local & custom models — LLMConfig for any OpenAI-compatible endpoint:
from delfhos import Agent, LLMConfig
# Local Ollama
agent = Agent(tools=[...], llm=LLMConfig(model="llama3.2", base_url="http://localhost:11434/v1"))
# Enterprise vLLM / hosted providers (Groq, Together, …)
agent = Agent(tools=[...], llm=LLMConfig(
model="meta-llama/Llama-3-70b-chat-hf",
base_url="https://api.together.xyz/v1",
api_key="...",
))
Dual-LLM — pair a fast model for routing with a strong one for code:
agent = Agent(
tools=[...],
light_llm=LLMConfig(model="qwen2.5:7b", base_url="http://localhost:11434/v1"),
heavy_llm="gemini-3.5-flash",
)
Memory & interactive chat
Add short-term session memory and long-term semantic memory:
from delfhos import Agent, Chat, Memory
agent = Agent(
tools=[...],
llm="gemini-3.5-flash",
chat=Chat(keep=8, summarize=True, namespace="my_agent"), # short-term
memory=Memory(namespace="my_agent"), # long-term semantic
)
agent.run_chat() # interactive terminal session — type /help for commands
Semantic memory supports 100+ embedding models (OpenAI, Cohere, Google, Sentence-Transformers, BGE, Jina, Nomic, NV-Embed) and local-first backends via Ollama or Hugging Face. See EMBEDDING_MODELS_GUIDE.md.
Automatic cleanup
Use the agent as a context manager and it shuts down on exit:
with Agent(tools=[...], llm="gemini-3.5-flash") as agent:
agent.run("Summarise last week's sales and email it to the team.")
For the full API reference and advanced guides, see DOCS.md or delfhos.com/docs.
License
Apache-2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file delfhos-0.8.7.1.tar.gz.
File metadata
- Download URL: delfhos-0.8.7.1.tar.gz
- Upload date:
- Size: 343.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
917404873c5ea51739a8b4fca080b9776f75aee2e2f7e3b8af6f99d21796ed31
|
|
| MD5 |
04c983ccec7f0012a222c9360410f1ba
|
|
| BLAKE2b-256 |
eea5f8a2d90a0e75d2b26aec0a067453bd1c9755d4be684a060ddfca2c49899e
|
File details
Details for the file delfhos-0.8.7.1-py3-none-any.whl.
File metadata
- Download URL: delfhos-0.8.7.1-py3-none-any.whl
- Upload date:
- Size: 356.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2fea6e24da30796e1a3d454b3e83e7c17e0963dde5fb3f180a2a3c1c00d73d18
|
|
| MD5 |
f19b61c8f668acf27a3049ebeae958a2
|
|
| BLAKE2b-256 |
b3367eaca4abefcf0ea0b8c730f8aec9c0741afb06e967bcd7b78f7019f0252f
|