Coding agents & orchestrators
Agentic coding tools — OpenCode, Cline, Roo Code, Continue, Goose, Kilo Code, Zed, Aider, Crush — run on DirectInference the same way your application does: one base URL, one llm_live_… key, any model id. The difference from a plain SDK swap is that these tools don’t model an endpoint as “a base URL and a key.” They model it as a provider with per-model settings, and they decide what a model is allowed to do — call tools, stream reasoning, accept images — from the model id. The id di-fusion is new to them, so you turn those capabilities on yourself. This page has the exact block to paste for each tool.
Why these tools need a little more
Section titled “Why these tools need a little more”A tool’s “does this model support tools / reasoning / vision?” answer normally comes from a built-in catalog keyed by model id (models.dev, a bundled allowlist, or name-matching). DirectInference exposes one model — di-fusion — and it is on no tool’s catalog, so for an unknown id those capabilities can default off. With DirectInference, capability is a property of the request shape, not the model id: send tools and they are served; send an image and it is served as a vision request. So the rule for every tool below is the same — when it offers a tool / reasoning / vision switch or a per-model capability field, turn it on, and give it a context-window number so its prompt budgeting works.
Which id to use
Section titled “Which id to use”There is one model; the id is a label that is read as intent and echoed back unchanged. Use whichever fits the slot:
| Id | Use it for |
|---|---|
di-fusion | The default. The single model, effort chosen automatically per request. |
di-saver | A tool’s small / background / weak slot (titles, commit messages, summaries) — effort pinned low. |
di-max | A tool’s large / main slot for hard work — effort pinned high. |
Tools with two model slots (a fast background model and a main model) map cleanly to di-saver and di-max; single-slot tools should use di-fusion.
Per-tool setup
Section titled “Per-tool setup”Add a provider to opencode.json (project root) or ~/.config/opencode/opencode.json. OpenCode auto-installs the @ai-sdk/openai-compatible package referenced by npm; you do not add it to a package.json.
{ "$schema": "https://opencode.ai/config.json", "model": "directinference/di-fusion", "small_model": "directinference/di-saver", "provider": { "directinference": { "npm": "@ai-sdk/openai-compatible", "name": "DirectInference", "options": { "baseURL": "https://api.directinference.com/di/v1", "apiKey": "{env:DIRECTINFERENCE_API_KEY}", "headers": { "X-Title": "opencode" } }, "models": { "di-fusion": { "name": "DirectInference", "tool_call": true, "reasoning": true, "attachment": true, "limit": { "context": 200000, "output": 32000 } }, "di-saver": { "name": "DirectInference (saver)", "tool_call": true, "reasoning": false, "attachment": true, "limit": { "context": 200000, "output": 16000 } }, "di-max": { "name": "DirectInference (max)", "tool_call": true, "reasoning": true, "attachment": true, "limit": { "context": 200000, "output": 64000 } } } } }}Then export DIRECTINFERENCE_API_KEY=llm_live_… (or run opencode auth login). Enable: tool_call, reasoning, and attachment per model, plus limit — for an unknown id OpenCode otherwise leaves reasoning/vision off and the context at zero. Gotcha: keep npm as @ai-sdk/openai-compatible (not @ai-sdk/openai) so requests go to /v1/chat/completions.
Cline is configured in its panel (settings are stored by the extension, not in a file). Settings → API Configuration → API Provider → OpenAI Compatible, then fill:
- Base URL —
https://api.directinference.com/di/v1 - API Key —
llm_live_… - Model ID — type
di-fusion(free-text; use a separate config fordi-saver/di-max) - Expand Model Configuration:
- Supports Images — on, if you want vision routed through
di-fusion - Context Window Size — e.g.
200000· Max Output Tokens — e.g.8192(or-1to leave it uncapped) - Enable R1 messages format — leave unchecked (it merges messages for DeepSeek-R1-style models and would distort normal requests)
- Supports Images — on, if you want vision routed through
Tools are not gated by the model id: for an id it doesn’t recognize, Cline drives edits and commands through its own structured (XML) tool protocol embedded in the system prompt, so di-fusion works as a full agent without native function calling being involved. Gotcha: the Base URL must end in /di/v1 (Cline appends /chat/completions); model id + capabilities are stored per mode, so set the model in both Plan and Act if one looks unconfigured.
Roo Code (a Cline fork) is configured in a provider profile. Settings → Providers → + (new profile) → API Provider → OpenAI Compatible:
- Base URL —
https://api.directinference.com/di/v1 - API Key —
llm_live_… - Model — type
di-fusionin the search box, then pick the “Use custom: di-fusion” entry (do the same in separate profiles fordi-saver/di-max) - Model Capabilities — Image Support on for vision; Context Window Size e.g.
200000; Max Output Tokens e.g.8192(or-1) - Leave Enable streaming on and Enable R1 model parameters off
Capability is on your declared fields, not the id: vision and context window come from the toggles above. Tool use is the one place current Roo Code (3.37+) differs from Cline — it uses native OpenAI tool calling exclusively (the XML fallback was removed), which DirectInference serves (a tool-bearing request returns usable tool_calls or a clear error, never a bad 200), so di-fusion is fully agentic. Gotcha: Base URL ends in /di/v1; on Roo 3.36 you may instead see a Native/XML protocol selector — either works with di-fusion.
Add a model to your config.yaml (~/.continue/config.yaml, or a workspace .continue/config.yaml):
name: DirectInferenceversion: 0.0.1schema: v1models: - name: DirectInference provider: openai model: di-fusion apiBase: https://api.directinference.com/di/v1 apiKey: llm_live_... # or ${{ secrets.DIRECTINFERENCE_API_KEY }} roles: [chat, edit, apply] capabilities: - tool_use # required for Agent mode on an unknown id - image_input # vision defaultCompletionOptions: maxTokens: 4096 # Optional second entry for the background/heavy slot: model: di-saver / di-maxEnable: the explicit capabilities: [tool_use, image_input] — Continue only auto-detects these for ids it recognizes, so Agent mode tools stay dark on di-fusion without it. Gotcha: apiBase must include /di/v1; don’t give di-fusion the autocomplete role — it is a chat model, not a fill-in-the-middle completion model, so point autocomplete at a dedicated endpoint instead.
The quickest path uses Goose’s built-in OpenAI provider via environment variables. Goose builds the request URL as OPENAI_HOST + / + OPENAI_BASE_PATH, so split DirectInference’s path across the two:
export OPENAI_API_KEY=llm_live_...export OPENAI_HOST=https://api.directinference.comexport OPENAI_BASE_PATH=di/v1/chat/completions# then: goose configure → Configure Providers → OpenAI → model: di-fusionFor a named entry instead, drop ~/.config/goose/custom_providers/directinference.json:
{ "name": "directinference", "engine": "openai", "display_name": "DirectInference", "api_key_env": "DIRECTINFERENCE_API_KEY", "base_url": "https://api.directinference.com/di/v1", "models": [ { "name": "di-fusion", "context_limit": 200000 }, { "name": "di-saver", "context_limit": 200000 }, { "name": "di-max", "context_limit": 200000 } ], "requires_auth": true, "supports_streaming": true}Enable: nothing special — Goose inherits tool calling from the OpenAI engine for any id; just set context_limit. Gotcha: the host/path split is the trap — don’t put /di/v1 on OPENAI_HOST and leave the default OPENAI_BASE_PATH, or the version segment doubles.
In the Kilo Code sidebar: Settings → Providers → API Provider → OpenAI Compatible:
- Base URL —
https://api.directinference.com/di/v1 - API Key —
llm_live_… - Model ID — type
di-fusion, then Use custom (alsodi-saver/di-max) - Model Configuration — Context Window (e.g.
200000), Max Output Tokens (e.g.8192), Image Support on for vision, Computer Use off
Enable: tool calling is not gated by the id, so di-fusion is agentic immediately; set Image Support for vision and the context/output numbers so prompts are sized correctly. Gotcha: the Base URL is the /di/v1 root; keep Computer Use off.
Open the Zed settings file (zed: open settings) and add an openai_compatible provider — note openai_compatible, not openai:
{ "language_models": { "openai_compatible": { "DirectInference": { "api_url": "https://api.directinference.com/di/v1", "available_models": [ { "name": "di-fusion", "display_name": "DirectInference", "max_tokens": 200000, "max_completion_tokens": 8192, "capabilities": { "tools": true, "images": true } } ] } } }}Add di-saver / di-max as more available_models entries if you want them. The key does not go in settings — set the env var DIRECT_INFERENCE_API_KEY=llm_live_… (Zed upper-snake-cases the provider name) or paste it into the Agent Panel settings (stored in the OS keychain). Enable: a model must be listed in available_models, and capabilities.tools / capabilities.images gate tool use and vision — set both true. Gotcha: api_url ends in /di/v1; use the openai_compatible node so the custom api_url is honored.
Aider talks to DirectInference through its OpenAI-compatible path; the model id carries an openai/ prefix.
export OPENAI_API_BASE=https://api.directinference.com/di/v1export OPENAI_API_KEY=llm_live_...aider --model openai/di-fusion # openai/di-saver, openai/di-max also workAider warns on an unknown id until you describe it. Add .aider.model.metadata.json (home dir or repo root), keyed by the full prefixed id:
{ "openai/di-fusion": { "max_input_tokens": 200000, "max_output_tokens": 8192, "input_cost_per_token": 0, "output_cost_per_token": 0, "litellm_provider": "openai", "mode": "chat", "supports_function_calling": true, "supports_vision": true }}Enable: Aider edits via text edit formats, so tool calling isn’t load-bearing for the core loop — set a good edit_format (e.g. diff) and, optionally in .aider.model.settings.yml, weak_model_name: openai/di-saver for cheap commit messages. Vision turns on with supports_vision: true in the metadata. Gotcha: the metadata key must be the prefixed openai/di-fusion, and litellm_provider must be openai; costs are 0 here because billing is handled by DirectInference, not Aider.
Add a provider to crush.json / .crush.json (project root) or ~/.config/crush/crush.json. Crush doesn’t auto-discover models for a custom provider — a provider with no models is skipped — so declare each one:
{ "$schema": "https://charm.land/crush.json", "providers": { "directinference": { "name": "DirectInference", "type": "openai-compat", "base_url": "https://api.directinference.com/di/v1", "api_key": "$DIRECTINFERENCE_API_KEY", "models": [ { "id": "di-fusion", "name": "DirectInference", "cost_per_1m_in": 0, "cost_per_1m_out": 0, "cost_per_1m_in_cached": 0, "cost_per_1m_out_cached": 0, "context_window": 200000, "default_max_tokens": 16000, "can_reason": true, "reasoning_levels": ["low", "medium", "high"], "default_reasoning_effort": "medium", "supports_attachments": true }, { "id": "di-saver", "name": "DirectInference (saver)", "cost_per_1m_in": 0, "cost_per_1m_out": 0, "cost_per_1m_in_cached": 0, "cost_per_1m_out_cached": 0, "context_window": 200000, "default_max_tokens": 16000, "can_reason": true, "reasoning_levels": ["low", "medium", "high"], "default_reasoning_effort": "low", "supports_attachments": true }, { "id": "di-max", "name": "DirectInference (max)", "cost_per_1m_in": 0, "cost_per_1m_out": 0, "cost_per_1m_in_cached": 0, "cost_per_1m_out_cached": 0, "context_window": 200000, "default_max_tokens": 16000, "can_reason": true, "reasoning_levels": ["low", "medium", "high"], "default_reasoning_effort": "high", "supports_attachments": true } ] } }, "models": { "large": { "model": "di-max", "provider": "directinference" }, "small": { "model": "di-saver", "provider": "directinference" } }}Then export DIRECTINFERENCE_API_KEY=llm_live_…. Enable: use type: "openai-compat" (the most-tested path; "openai" targets the Responses API, which DirectInference now serves statelessly, so it also works); set can_reason: true plus reasoning_levels so reasoning shows, and supports_attachments: true for vision. The cost_* fields are required by the schema — 0 is valid (billing is handled by DirectInference). Tool calls are served for any id with no extra field. Gotcha: the base_url ends in /di/v1; api_key takes a $ENV reference (it is expanded at load, as are ${VAR} and $(cmd) — keep crush.json trusted).
Confirm it’s working
Section titled “Confirm it’s working”Two signals prove the tool is actually reaching DirectInference and not silently falling back to a previous provider:
- The model echo — responses carry back the exact id you configured (
di-fusion). - The header — every DirectInference response carries
X-DI-Request-Type(pro,code,vision,document,long,json,reason, orflash). It is the one customer-visible signal and only DirectInference sets it. Prove the base URL and key independently of any tool:
curl -s -o /dev/null -D - https://api.directinference.com/di/v1/chat/completions \ -H "Authorization: Bearer llm_live_..." \ -H "Content-Type: application/json" \ -d '{ "model": "di-fusion", "messages": [{ "role": "user", "content": "ping" }] }' \ | grep -i x-di-request-type# x-di-request-type: flashThe request also appears in Traces and Usage; set X-Title (where a tool exposes custom headers) to give it its own line in per-application usage. To bias every request the tool sends toward cost or quality, send X-DI-Effort (fast … max) — details in Effort.
Known limitations
Section titled “Known limitations”- Computer-use tools are not served. Tools that expose a “Computer Use” toggle (Kilo Code, others) drive a provider’s hosted computer-use tool, which DirectInference does not serve — leave it off. Client-defined function tools and the tools’ own edit/command protocols are fully served.
di-fusionis a chat model, not a tab-autocomplete (FIM) model. Where a tool has a separate inline-completion / autocomplete slot, point it at a dedicated completion endpoint rather thandi-fusion.- Provider server-side tools stay on their origin. Web search / grounding, code execution, and URL context are rejected with a descriptive
400; keep those call sites on their original provider. The full served / not-served list is in Capabilities.
For the field-by-field reference behind any “custom provider” form, see Custom providers; for the underlying SDK swaps these tools are built on, see Frameworks.