# AI
The `deft/stdext/ai/` stack is a layered library: provider packages are
discovered and validated, config is built from metadata + workspace
overrides, and a registry resolves the ergonomic cfg-only API most apps
import. The orchestrator (`ai/ask` / `ai/chat`) drives the tool loop
through AI tools.
import "deft/stdext/ai/registry" as ai
## Layering
| Module | Role |
|---|---|
| `ai/plugins` | Discover packages tagged `"ai-provider"`, load + validate them |
| `ai/config` | Provider metadata (base URL, env var, default model), cfg construction |
| `ai/registry` | Resolve a provider from a cfg; the ergonomic `ask` / `chat` API |
| `ai/ai` | The `AiProvider` protocol and the low-level tool-use orchestrator |
| `ai/budget` | Context-window budgeting and in-place compaction |
## Registry API (the common entry)
| Def | Signature | Description |
|---|---|---|
| `ask` | `{| cfg user-text |}` | One-shot question → reply string or `%Err` |
| `chat` | `{| cfg messages user-text opts |}` | Multi-turn chat with the tool loop |
| `provider` / `provider-by-key` | `{| cfg |}` / `{| key |}` | Provider singleton |
| `provider-descriptor` / `provider-label` | `{| key |}` | Descriptor metadata / display name |
| `list-providers` / `providers` | `{||}` | Registered provider keywords |
| `models` / `provider-models` | `{| cfg |}` / `{| key |}` | Model lists |
| `tool-format` | `{| key |}` | `:openai` or `:anthropic` |
| `refresh` | `{||}` | Rescan package roots (picks up mid-session installs) |
| `discover-errors` | `{||}` | Errors from the last scan |
| `default-cfg` / `load-cfg` | `{||}` / `{| workspace-cfg |}` | Config helpers |
import "deft/stdext/ai/registry" as ai set cfg [ai/default-cfg] set reply [ai/ask $cfg "Explain this function."]
A cfg carries the provider choice (`:provider`), model, API key, base
URL, and generation options. `load-cfg` merges the workspace `:ai` map
from `.deft/prelude.dft` over defaults; an explicit `:provider` always
wins.
# .deft/prelude.dft :ai %{ :provider :anthropic :model "claude-3-5-sonnet-20241022" :system "You are a senior engineer." }
## Config API
| Def | Description |
|---|---|
| `provider-meta` | Map of provider key → `%{ base-url env-var default-model extensions }` |
| `default-provider-key` | `:deepseek` when installed, else first, else nil |
| `build-cfg` | Full cfg for a provider+model; opts override provider `extensions` |
## The Provider Protocol
An AI provider is a package tagged `"ai-provider"` whose entry
module declares `implements AiProviderExtension` (see
Types). The `AiProvider` protocol covers the wire details:
`models`, `url`, `headers`, `body`, `messages-with-user`,
`extract-content`, tool-use detection/extraction, tool-result
construction, reasoning extraction, usage, context window, tool format,
cost, and optional `balance` / `refresh-models`.
Because the VM conformance-checks the module at load time, a missing
contract field is a load error — `discover-errors` surfaces it.
## Budgeting
`ai/budget` protects the context window:
| Def | Description |
|---|---|
| `context-window` | Provider-reported window or a conservative fallback |
| `max-response-tokens` | 25% of the window, clamped `[512, 8192]` |
| `max-prompt-chars` | ~75% of the window at 3 chars/token |
| `trim-messages` | Drop oldest non-system messages until under the limit |
| `compact-history` / `compact-conv` | In-place compaction (reasoning shrunk, giant tool results trimmed, oldest dropped) |
Compaction is preferred over truncation to preserve the provider's
prefix cache.
## Providers
Provider packages live beside stdext (`deft/ai-deepseek`,
`deft/ai-openai`, `deft/ai-anthropic`, `deft/ai-ollama`, `deft/ai-zai`)
and can be installed at runtime — call `[ai/refresh]` to pick them up.
See AI Providers and the
Chat app help.
## See Also
- AI Tools — MCP/RPC tool surface and subagents
- AI Providers — writing a provider package
- MCP — the tool protocol
- Types — the provider extension schema