Configuration
Every setting lives in Settings, a published property you can fill at design time, in code, or from a JSON file. The file is what lets an installed application be changed without a new build: the API key, the model, even moving the engine to a server.
helpchatai.json
With ConfigFileName empty (the default) the component merges, in this order, on activation:
| # | File | Meant for |
|---|---|---|
| 1 | %APPDATA%\HelpChatAI\helpchatai.json | Settings shared by every HelpChatAI application of this user — typically the API key |
| 2 | helpchatai.json next to the executable | What the application ships or what IT deploys |
| 3 | %APPDATA%\<YourApp>\helpchatai.json | This application, this user: wins over the others |
Only the keys present in a file are applied, so each file can carry just what it needs to change.
One file instead of three
Name a file in ConfigFileName and that file is the configuration: the three above are not read at all. A relative path is resolved against the executable.
HelpChatAI.ConfigFileName := 'config\helpchatai.json';A file named here and not found raises EHelpChatConfigError when the component activates. That is deliberate: an application that asked for a configuration and quietly runs without it is an application shipped with the wrong settings, and nobody finds out until a customer does.
{
"Provider": "claude",
"Language": "it",
"DocIndexFile": "help-index.json",
"DocBaseUrl": "https://help.mycompany.com/myapp/",
"Claude": {
"ApiKey": "sk-ant-...",
"Model": "claude-haiku-4-5",
"GroundingMaxPages": 3
}
}One section per model provider — Claude, OpenAI, Gemini — all with the same keys, plus the few that belong to one of them (Claude.ApiVersion, the OpenAI.Azure* trio). Only the section of the configured Provider is read, and an empty Model or BaseUrl means the default of that provider, so a file that never mentions them keeps following the library.
Never ship a file with a key in it
helpchatai.json is in the repository's ignore list for a reason, and the installer excludes it from what it packages. A key in an installer is a key on every customer's disk.
The settings that matter most
| Setting | Default | What it does |
|---|---|---|
Provider | stub | Which provider answers |
Language | hclAuto | Interface and reply language: auto (OS locale), en, it |
Greeting | (localized) | The first bubble of an empty conversation |
DocIndexFile | help-index.json next to the exe | The documentation index |
DocBaseUrl | (empty) | Prefix of the documentation links |
PersistConversation | True | Save and restore the conversation between runs |
ConversationMaxAgeDays | 30 | Older saved conversations are discarded |
MaxStoredMessages | 200 | Kept in the store (older ones are pruned) |
HistoryMaxMessages | 50 | Sent to the provider as context |
MessageMaxLength | 4000 | A user message longer than this is cut |
PoolSize | 2 | Worker threads answering in parallel |
The complete list, with the JSON key of every one of them, is in the Settings reference.
Checking a configuration
HelpChatAI.Diagnostics answers "would this work?" without sending a question: it reports the provider (registered? configured?), the documentation index, the folder of the pages, or the server when Settings.Remote names one.
uses HelpChatAI.Diagnostics;
LIssues := HelpChatCheckSettings(HelpChat1.Settings);
if HelpChatHasErrors(LIssues) then
ShowMessage(HelpChatIssuesToText(LIssues));What a provider needs is the provider's own business: the check asks it through ConfigurationIssue instead of knowing about it, so a provider of yours is checked like the built-in ones. The same code runs behind Check configuration... in the component editor.
Where files are written
| File | Where | What |
|---|---|---|
helpchatai-conversation.json | %APPDATA%\<YourApp>\ | The saved conversation |
helpchatai-ui.json | %APPDATA%\<YourApp>\ | Position and size of the chat window |
WebView2\ | %APPDATA%\<YourApp>\ | The WebView2 user data folder |
Nothing is written to the installation folder, so the application runs under a limited account.
Changing settings at runtime
Settings are snapshotted per request: a provider works on a private copy, so changing Provider or Model while a reply is streaming does not corrupt it — the change applies to the next message. That is how the demo can switch provider from a combo box while the chat is open.
HelpChatAI.Settings.Provider := ProviderCombo.Text; // next question uses itReading and writing the file from code
HelpChatAI.Settings.LoadFromFile('C:\Deploy\helpchatai.json');
HelpChatAI.Settings.SaveToFile(THelpChatSettings.UserConfigFile); // %APPDATA%\<YourApp>\THelpChatSettings.SharedUserConfigFile, AppConfigFile and UserConfigFile give you the three standard locations, so an "advanced settings" dialog of yours can write the right one.
Moving the engine to a server
The same file decides where the engine runs:
{
"Remote": {
"BaseUrl": "https://help.acme.com",
"AppKey": "the-key-of-this-application",
"UserId": ""
}
}With a BaseUrl the component talks to a HelpChatAI server instead of running the engine in process — no recompilation, no code change.