wxMaxima
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Protected Attributes
AiProvider Class Referenceabstract

Talks to one external AI provider's chat completion HTTP API. More...

#include <AiProvider.h>

Public Member Functions

 AiProvider (wxString baseUrl, wxString apiKey, wxString model)
 
virtual AiProviderKind Kind () const =0
 
wxString Name () const
 AiProviderKindName(Kind()) for a built-in provider, or the user's own chosen name for a custom one (Kind() == Custom doesn't carry a name by itself) – SetDisplayName() is called by MakeAiProviderForShape() for exactly this reason.
 
void SetDisplayName (const wxString &name)
 
virtual wxString RequestUrl () const
 The full URL SendChat() will POST to. Virtual so Google's provider can append the model id (its endpoint is per-model, unlike the others).
 
virtual std::vector< std::pair< wxString, wxString > > AuthHeaders () const =0
 Any additional headers this provider's auth scheme needs, name/value pairs, beyond the "POST JSON" content-type SendChat() always sets.
 
virtual wxString BuildRequestBody (const wxString &context, const std::vector< AiChatMessage > &history) const =0
 Builds the JSON request body for one chat turn.
 
virtual wxString ParseReply (const wxString &responseBody) const =0
 Extracts the assistant's reply text from a successful (2xx) response body.
 

Static Public Member Functions

static bool SecretStoreAvailable ()
 True if this build of wxWidgets has a working wxSecretStore backend (>= 3.1.1, compiled with wxUSE_SECRETSTORE, AND an actual OS keyring service reachable at runtime – e.g. gnome-keyring/kwallet on Linux, always true on Windows/macOS). API keys are only ever stored here, never in plain Configuration/wxConfig, so the whole AI Chat feature (Options tab, sidebar, menu entry) stays hidden whenever this is false rather than falling back to storing a key in plain text.
 
static void SaveApiKey (const wxString &service, const wxString &apiKey)
 Saves (or, for an empty key, deletes) an API key for service – a stable identifier: AiProviderKindName(kind) for a built-in provider, or CustomProviderSecretService(id) for a custom one. No-op (and never called by any code path that matters) if !SecretStoreAvailable().
 
static wxString LoadApiKey (const wxString &service)
 Returns the stored key for service, or an empty string if none is stored (also the result if !SecretStoreAvailable() – there is nowhere a key could have been saved to).
 
static void DeleteApiKey (const wxString &service)
 
static wxString CustomProviderSecretService (const wxString &id)
 The secret-store service name for a custom provider's own id – kept distinct from a bare built-in kind name so a custom provider a user happens to name e.g. "OpenAI" can never collide with the real built-in OpenAI entry's stored key.
 
static wxString BuiltinProviderSecretService (AiProviderKind kind)
 The secret-store service name for one of the four built-in kinds – just AiProviderKindName(kind), given its own name so every call site that needs it (Configuration's four AiApiKeyX() accessors, the plain-text-key migration in Configuration::ReadConfig()) shares one definition instead of separately hardcoding the same string.
 
static void SendChat (std::shared_ptr< const AiProvider > self, wxEvtHandler *owner, const wxString &context, const std::vector< AiChatMessage > &history, std::function< void(bool ok, const wxString &replyOrError)> callback)
 Sends one chat turn asynchronously via wxWebRequest and calls callback(ok, replyOrError) exactly once, on the GUI thread, once the HTTP request completes, fails, or errors out.
 
static bool NetworkingAvailable ()
 True if this build of wxWidgets has wxWebRequest at all (>= 3.1.5, built with a working backend) – if false, the whole chat sidebar feature has nothing to talk to and should say so rather than silently failing every request.
 

Protected Attributes

wxString m_baseUrl
 
wxString m_apiKey
 
wxString m_model
 
wxString m_displayName
 

Detailed Description

Talks to one external AI provider's chat completion HTTP API.

Deliberately split into a stateless, directly-testable half (BuildRequestBody()/ ParseReply(), pure string/JSON in and out, no networking – see test/unit_tests/test_AiProvider.cpp) and the actual network call (SendChat()), which needs a live wxWebRequest and can only really be verified against a real or fake HTTP server (done live, see AGENTS.md).

Member Function Documentation

◆ BuildRequestBody()

virtual wxString AiProvider::BuildRequestBody ( const wxString &  context,
const std::vector< AiChatMessage > &  history 
) const
pure virtual

Builds the JSON request body for one chat turn.

context is a read-only worksheet snapshot (from McpTools), sent as a system/context message ahead of the actual conversation; history is every prior turn plus the new user message as its last entry. Pure function, no I/O – unit-tested directly.

◆ ParseReply()

virtual wxString AiProvider::ParseReply ( const wxString &  responseBody) const
pure virtual

Extracts the assistant's reply text from a successful (2xx) response body.

Throws AiProviderError (see below) if the body doesn't parse or doesn't have the shape this provider expects. Pure function, no I/O.

◆ SendChat()

void AiProvider::SendChat ( std::shared_ptr< const AiProvider self,
wxEvtHandler *  owner,
const wxString &  context,
const std::vector< AiChatMessage > &  history,
std::function< void(bool ok, const wxString &replyOrError)>  callback 
)
static

Sends one chat turn asynchronously via wxWebRequest and calls callback(ok, replyOrError) exactly once, on the GUI thread, once the HTTP request completes, fails, or errors out.

owner is the wxEvtHandler the completion event is delivered to – must outlive the request; the sidebar itself is the intended owner. No-op (calls back with ok=false immediately) if wxUSE_WEBREQUEST is off in this build.

Static, taking self as an explicit shared_ptr rather than being a plain instance method: the completion lambda needs the provider object (for ParseReply()/Name(), both virtual) to still exist whenever the response actually arrives, which can outlast the caller doing something else entirely – e.g. the user changing the configured provider/model in Options while a request is still in flight. Capturing a shared_ptr keeps the exact instance that sent the request alive for the callback regardless of what AiChatSidebar does to its own current-provider pointer in the meantime; capturing a raw this would not.


The documentation for this class was generated from the following files: