# 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