sgcWebSockets AI and LLM
Fifteen components for talking to language models, turning speech into text and
back, storing and searching embeddings, and exposing or consuming MCP tools.
They all live in one unit, sgcAI.
Start with TsgcAIChat unless you have a reason not to. It is the
provider-agnostic component, and switching model vendors later is then a
one-line change rather than a rewrite.
When to use this skill
- Send a prompt to OpenAI, Anthropic, Gemini, DeepSeek, Ollama, Grok or Mistral
- Stream a model's reply token by token instead of waiting for all of it
- Keep conversation history and a system prompt across turns
- Create embeddings and search them, in a local file or in Pinecone
- Speak text aloud, or record audio to send to a model
- Expose your Delphi application's functions to an AI agent as MCP tools
- Call someone else's MCP server from Delphi
Install and uses clause
uses
sgcAI;
That is the whole of it for every component in this skill. Some of them return
richer objects that carry their own types, and each API page names those under
reference/types/.
Before you start, ask the developer
Use a structured question tool if your host has one, for example Claude Code's
AskUserQuestion. Otherwise ask in chat:
- Which provider, and is the key already available? Every provider needs an API key except Ollama, which runs locally. Never hardcode a key into the source you generate; read it from configuration or an environment variable.
- Streaming or a single reply?
Chatblocks and returns the whole answer.ChatStreamdelivers it in pieces throughOnChatStream. A responsive UI almost always wants the second. - Does the conversation need memory?
TsgcAIChatkeeps history and has aSystemMessage. If the developer wants one-shot calls, say so explicitly and callClearHistorybetween them. - Which model?
ChatOptions.Modelis a plain string and the valid values depend on the provider. Ask rather than guessing a model name, because a wrong one fails at the API with an unhelpful message.
Components in this skill
| Component | Use it for |
|---|---|
TsgcAIChat |
Provider-agnostic chat, seven vendors, history, streaming |
TsgcAIOpenAIChatBot |
OpenAI-specific chat bot |
TsgcAIOpenAIAssistant |
OpenAI Assistants: assistants, threads, runs |
TsgcAIOpenAITranslator |
Translation through OpenAI |
TsgcAIOpenAIEmbeddings |
Turn text into embedding vectors |
TsgcAIDatabaseVectorFile |
Store and query vectors in a local file |
TsgcAIDatabaseVectorPinecone |
Store and query vectors in Pinecone |
TsgcTextToSpeechSystem |
Speak text using the OS voice |
TsgcTextToSpeechGoogle |
Speak text using Google |
TsgcTextToSpeechAmazon |
Speak text using Amazon Polly |
TsgcAudioRecorderMCI / TsgcAudioRecorderWave |
Record microphone audio |
TsgcAudioPlayerMCI |
Play audio back |
TsgcWSAPIServer_MCP |
Expose your own functions as MCP tools |
TsgcWSAPIClient_MCP |
Call an MCP server's tools |
Quickstart, chat
uses
sgcAI;
procedure TForm1.FormCreate(Sender: TObject);
begin
FChat := TsgcAIChat.Create(Self);
FChat.Provider := aicpAnthropic;
FChat.ChatOptions.ApiKey := GetApiKeyFromConfig; // never hardcode this
FChat.ChatOptions.Model := 'claude-sonnet-4-5';
FChat.ChatOptions.MaxTokens := 1024;
FChat.ChatOptions.Temperature := 0.7;
FChat.SystemMessage := 'You answer in one short paragraph.';
FChat.MaxHistoryMessages := 20;
FChat.OnChatStream := ChatStream;
end;
// blocking, returns the whole reply
vAnswer := FChat.Chat('Summarise what a WebSocket handshake does.');
// streaming, pieces arrive on OnChatStream
FChat.ChatStream('Now explain it to a beginner.');
TsgcAIChatProvider is (aicpOpenAI, aicpAnthropic, aicpGemini, aicpDeepSeek, aicpOllama, aicpGrok, aicpMistral). Switching vendor means changing that value
and the Model string, nothing else.
ChatAsync returns an IsgcFuture<string> if you would rather await the result
than handle an event. ChatWithSystem overrides the system prompt for one call
without disturbing the stored SystemMessage.
ChatOptions.BaseUrl points the component at a compatible endpoint that is not
the vendor's own, which is how you reach a local Ollama instance or a proxy.
Quickstart, embeddings and search
Embeddings and the vector store are separate components. You create the vector with one and store it with the other:
FEmbeddings := TsgcAIOpenAIEmbeddings.Create(Self);
FVectors := TsgcAIDatabaseVectorFile.Create(Self);
FVectors.BeginAddData;
try
FVectors.AddData('the original text', FEmbeddings.GetEmbedding('the original text', ''));
finally
FVectors.EndAddData;
end;
vHits := FVectors.QueryData(FEmbeddings.GetEmbedding('a question', ''));
BeginAddData and EndAddData bracket a batch of additions, so wrap a bulk
load in them rather than calling AddData bare in a loop.
TsgcAIDatabaseVectorPinecone has the same shape, so moving from the local file
to Pinecone is mostly a component swap.
Quickstart, MCP
MCP has two sides and this skill has both. As a client you connect to a server and call its tools:
FMCP := TsgcWSAPIClient_MCP.Create(Self);
// ... transport setup ...
if FMCP.Initialize then
begin
FMCP.ListTools;
FMCP.RequestTool('search_docs', vArgumentsJson);
end;
Initialize performs the MCP handshake and must succeed before anything else.
As a server, TsgcWSAPIServer_MCP publishes your own tools, prompts and
resources, and notifies connected agents when the list changes with
SendNotificationToolsListChanged.
Things that catch people out
- Never write an API key into generated source. Read it from configuration. A key committed to a repository has to be rotated, not deleted.
Chatblocks the calling thread. In a GUI that freezes the window for the whole round trip, which can be many seconds. UseChatStreamorChatAsync.MaxHistoryMessagescaps what is resent each turn. Setting it high raises cost on every single call, because the whole history goes with each request.- Model names are provider-specific strings, not an enumeration, so nothing catches a typo at compile time. A wrong name surfaces as an API error.
- The MCP client must
Initializebefore listing or calling tools. CallingRequestToolfirst gets you a protocol error rather than a result.
Routing
- Find a component:
reference/components-index.mdlists every component, itsunit, and its edition, grouped by Reg module. - Uses clause: add the component's
unit:value (shown on its API page) to yourusesclause. Nothing compiles without it. - API detail:
reference/api/<Component>.mdhas the Properties, Events and Methods, each in both Delphi and C++Builder form. - Option / enum / event types: property and event types link to
reference/types/<TypeName>.md, which documents the sub-properties of option classes, the values of enums, and the parameter list of event handlers. - Examples:
examples/index.mdis the full demo catalog;examples/<Component>.mdis a focused, real usage snippet for the most-used components. - Concepts:
concepts/overview.md(getting started + uses-clause rule) andconcepts/editions-and-features.md(which components your edition includes). - Bundled resources:
concepts/resources.mdlists the browser-side assets (JavaScript, HTML, CSS) the server components serve or embed, so a browser client works without an external CDN. - Version history:
reference/history.mdlists what changed in each sgcWebSockets release.
Editions
Components are gated by edition (Professional, Enterprise, All-Access) or by a feature define. Check the edition column in the components index, or concepts/editions-and-features.md, before relying on a component.
Only public and published members are documented. Method bodies, private fields and protected members are intentionally not included.