Getting started with Cloud AI
This page covers the shortest path to a working request: where the API keys live, how to pick a service, and how the answer comes back. For tools, file context, assistants, and audio, see the user guide.
Prerequisites
- Delphi 11 Alexandria or newer (or C++Builder) with TMS AI Studio installed.
- A VCL or FMX application with a
TTMSMCPCloudAIon a form, or created in code. - An account and API key for at least one hosted service, or a local Ollama or llama.cpp server. Local servers need no key.
Add TMS.MCP.CloudAI to your uses clause.
Store the keys outside the source
APIKeys holds one key per service. Never assign a literal key in code that
gets committed. Write the keys once — from a setup step, an environment
variable, or a configuration dialog — into an encrypted file, and load that
file at startup:
procedure TForm1.ImportKeysFromEnvironment;
begin
{ Run this once, from a setup utility - never ship the values in source. }
AI.APIKeys.OpenAI := GetEnvironmentVariable('OPENAI_API_KEY');
AI.APIKeys.Claude := GetEnvironmentVariable('ANTHROPIC_API_KEY');
AI.APIKeys.Gemini := GetEnvironmentVariable('GEMINI_API_KEY');
AI.APIKeys.Mistral := GetEnvironmentVariable('MISTRAL_API_KEY');
AI.APIKeys.OpenRouter := GetEnvironmentVariable('OPENROUTER_API_KEY');
AI.APIKeys.SaveToFile(KeyStoreFileName, KeyStorePassword);
end;
procedure TForm1.LoadKeysAtStartup;
begin
if TFile.Exists(KeyStoreFileName) then
AI.APIKeys.LoadFromFile(KeyStoreFileName, KeyStorePassword);
{ Settings - models, endpoints, generation parameters - persist separately
and carry no secrets, so they can live next to the application. }
if TFile.Exists(SettingsFileName) then
AI.Settings.LoadFromFile(SettingsFileName);
end;
APIKeys.SaveToFile and APIKeys.LoadFromFile take a password and encrypt the
file with it. Settings.SaveToFile / Settings.LoadFromFile persist the model
names and generation parameters, which contain no secrets and can be shipped or
edited freely.
Pick a service
Service selects which provider the next Execute call reaches:
| Value | Service | Key |
|---|---|---|
aiOpenAI |
OpenAI | APIKeys.OpenAI |
aiClaude |
Anthropic Claude | APIKeys.Claude |
aiGemini |
Google Gemini | APIKeys.Gemini |
aiGrok |
xAI Grok | APIKeys.Grok |
aiMistral |
Mistral | APIKeys.Mistral |
aiDeepSeek |
DeepSeek | APIKeys.DeepSeek |
aiPerplexity |
Perplexity | APIKeys.Perplexity |
aiOpenRouter |
OpenRouter | APIKeys.OpenRouter |
aiOllama |
Local Ollama server | none |
aiLlamaCpp |
Local llama.cpp server | none |
Each service reads its own model property on Settings — OpenAIModel,
ClaudeModel, GeminiModel, and so on — so you can configure them all once and
let Service alone decide which is used.
Send a prompt
Context is the user turn, SystemRole is the standing instruction, and
Execute sends the request. The call returns immediately; the answer arrives in
OnExecuted:
procedure TForm1.FormCreate(Sender: TObject);
begin
{ AI is a TTMSMCPCloudAI dropped on the form. Keys were saved earlier with
AI.APIKeys.SaveToFile, so nothing secret lives in the source. }
AI.APIKeys.LoadFromFile('aikeys.cfg', KeyStorePassword);
AI.Service := aiOpenAI;
AI.Settings.OpenAIModel := 'gpt-5.2';
AI.OnExecuted := AIExecuted;
end;
procedure TForm1.btnAskClick(Sender: TObject);
begin
if AI.Busy then
Exit;
AI.SystemRole.Text := 'You are a concise Delphi assistant.';
AI.Context.Text := memoPrompt.Lines.Text;
AI.Execute;
end;
procedure TForm1.AIExecuted(Sender: TObject; AResponse: TTMSMCPCloudAIResponse;
AHttpStatusCode: Integer; AHttpResult: string);
begin
if Assigned(AResponse) then
memoAnswer.Lines.Text := AResponse.Content.Text
else
memoAnswer.Lines.Text := Format('Request failed (%d): %s',
[AHttpStatusCode, AHttpResult]);
end;
AResponse is nil when the request itself failed — check it before reading
Content. Busy is True while a request is in flight, which is the simplest
way to keep a button from starting a second one.
What comes back
TTMSMCPCloudAIResponse carries the
answer plus its accounting:
| Property | Contains |
|---|---|
Content |
The answer text, as a TStrings. |
Id |
The id you passed to Execute, so one handler can serve several call sites. |
ServiceId |
The service's own identifier for this response. |
ServiceModel |
The exact model the service used — not necessarily the one you asked for. |
PromptTokens, CompletionTokens, TotalTokens |
Token counts for this request. |
Usage accumulates the same counters
across every request the component makes, plus audio seconds and spoken
characters, until you call Usage.Reset.
See also
- User guide — the full feature set
- Chat and prompting — roles, models, and generation settings
- Function calling — let the model call your code
- Files, assistants, speech, and transcription
- API reference