Kitto.Chat.Provider.Claude
Claude-backed help-chat provider (name claude). It sends the conversation to Anthropic's Messages API (POST /v1/messages) with stream: true and forwards each token to the runner via the AOnToken callback as it arrives, so the poll endpoint returns the growing partial reply and the drawer fills in incrementally with no server-push (SSE-to-the-browser) machinery — the existing 1.2s client poll is enough. There is no official Anthropic SDK for Delphi, so the call is made with System.Net.HttpClient and the Anthropic Server-Sent-Events response is parsed by TKXAnthropicStream as bytes arrive.
Answers are grounded on the bundled documentation index (RAG): the pages best matching the question are injected into the system prompt via KXSearchHelpPages so the model answers from the real docs and cites the published page instead of inventing details.
Configuration (Config.yaml, all under HelpChat/Claude/): <code> HelpChat: Provider: claude Claude: ApiKey: %ENV(ANTHROPIC_API_KEY)% # or the key directly; env var is the fallback Model: claude-haiku-4-5 # default MaxTokens: 1024 Version: 2023-06-01 # anthropic-version header BaseUrl: https://api.anthropic.com GroundingMaxPages: 3 # doc pages injected as context (0 = off) SystemPrompt: '' # optional override of the base instruction ConnectTimeoutMs: 15000 ResponseTimeoutMs: 120000 </code> The API key is read from HelpChat/Claude/ApiKey (macro-expanded, so %ENV(...)% works) and falls back to the ANTHROPIC_API_KEY environment variable. When neither is set the provider raises a clear configuration error (surfaced in the chat as an error bubble).
TKClaudeProviderConfig class
Typed reader for the Claude help-chat provider settings (Provider: claude). Two roles in one class, co-located with the provider it configures: (1) runtime — reads every HelpChat/Claude/* value ONCE at construction into fields, so the provider accesses them as FConfig.Model instead of repeated Config.GetString/GetInteger tree lookups; (2) design-time — the [YamlNode] attributes let KIDE discover the schema via RTTI, and the class-level [YamlConfigNode('HelpChat/Claude')] binds it to that YAML node WITHOUT the parent config class referencing it by type (KIDE finds it by scanning the linked types). It is a plain reader (not a TEFNode): it reads from the config tree, it does not live in it.
HelpChat:
Provider: claude
Claude:
ApiKey: %ENV(ANTHROPIC_API_KEY)%
Model: claude-haiku-4-5
MaxTokens: 1024
GroundingMaxPages: 3constructor Create(const AConfig: TEFTree);Reads HelpChat/Claude/* from AConfig once. ApiKey is macro-expanded and falls back to the ANTHROPIC_API_KEY env var when empty; BaseUrl is normalized (no trailing slash); SystemPrompt is the raw override ('' means the provider applies its localized default). AConfig is normally TKConfig.Instance.Config.
TKXClaudeProvider class
Streams assistant replies from Anthropic's Claude Messages API.
constructor Create;Reads the HelpChat/Claude/* config once (the provider is created per chat request), so Generate accesses typed fields instead of the tree.
