Funzionalità AI
Il layer AI di cMind è agnostico rispetto al provider. Ogni feature parla con una singola seam
provider-neutral (IAiClient.CompleteAsync); un routing client risolve la credenziale del provider
attivo e dispatcha all'adapter wire matching. Scegli un provider + modello + endpoint (e, se il provider
lo richiede, una chiave); ogni feature esistente funziona invariata con la stessa gated, crittografia,
resilience e degradation.
Batterie incluse: un LLM locale integrato spedisce con l'app ed è abilitato per default (Microsoft.ML.OnnxRuntimeGenAI, es. Phi-3-mini) — così ogni deployment ha AI funzionante senza API key e senza servizio esterno. Un deployment white-label può rimuoverlo e limitare quali provider gli utenti possono aggiungere. Oltre al built-in, connetti qualsiasi provider esterno.
Provider supportati:
- AI locale integrata (
BuiltInOnnx) — modello ONNX GenAI in-process, no key, spedito + default-on. - Anthropic (Claude — Messages API)
- OpenAI e Azure OpenAI (Chat Completions)
- Google Gemini (
generateContent) - Qualsiasi endpoint compatibile con OpenAI, inclusi modelli locali (Ollama, LM Studio, vLLM,
llama.cpp
server, LocalAI) e cloud compatibili con OpenAI (Kimi / Moonshot ahttps://api.moonshot.ai/v1/, OpenRouter, Groq, Together, Mistral, DeepSeek) — tutti tramite l'unico adapter compatibile OpenAI, differing solo per base URL + modello + key. La finestra di dialogo Add-provider offre preset one-click (Kimi, OpenAI, OpenRouter, Groq, DeepSeek, Mistral, Ollama, LM Studio) che compilano l'URL base + un modello di esempio.
Esattamente uno provider è attivo alla volta. Le credenziali sono memorizzate crittografate
(AiProviderCredential aggregate + IAiProviderStore + ISecretProtector, EncryptionPurposes.AiApiKey);
un endpoint locale non richiede nessuna key. Con nessun provider attivo, ogni feature restituisce il
risultato disabled e il resto dell'app funziona invariato (nessuna key necessaria per build, test o
run della piattaforma).
Back-compat: la App:Ai:ApiKey legacy di un deployment esistente (o la vecchia impostazione crittografata
ai.api_key) è onorata automaticamente come provider Anthropic attivo default — nessuna azione necessaria.
AI non configurata → le pagine AI dim actions e mostrano un banner più un prompt one-time per aggiungere un
provider in Settings → AI (AiFeatureNotice). Status a GET /api/ai/status ({ enabled, kind, model });
provider gestiti (solo owner) via GET/PUT /api/ai/providers, POST /api/ai/providers/{id}/activate,
DELETE /api/ai/providers/{id}, e un POST /api/ai/providers/test connectivity ping.
Deployment default vs il provider personale di un utente
Le credenziali AI hanno due scope:
- Deployment default (owner-managed). Il proprietario configura un provider (o ne spedisce uno via
App:Ai:Providers[]/ la legacyApp:Ai:ApiKey). Diventa il default condiviso per ogni utente — così un broker o provider di hosting può finanziare AI per tutti i loro utenti con nessun setup per-utente e nessun limite per-utente. Gestito tramite le route owner-only/api/ai/providerssopra. - Il provider personale di un utente (self-service). Qualsiasi utente loggato può aggiungere il proprio
provider sotto
GET/PUT /api/ai/my-providers,POST /api/ai/my-providers/{id}/activate,DELETE /api/ai/my-providers/{id}. Quando presente, il loro provider attivo proprio override il default del deployment per le loro funzionalità AI; rimuoverlo ripristina il default.
Ordine di risoluzione (in AiProviderStore, per request user): la credenziale attiva dell'utente →
il default del deployment → la chiave di configurazione legacy → none (AI disabled). Esattamente una
credenziale è attiva per scope (un partial unique index per OwnerUserId), e ogni scope è risolto
indipendentemente, quindi un utente che attiva la propria chiave non disturba mai il default condiviso.
Background/non-Web contexts (no request user) risolvono sempre il default del deployment.
Matrice capacità provider
Le capacità default per provider e sono owner-overridable. Quando una capacità è off la feature degrada, non lancia mai: ricerca web silently droppata; vision restituisce un typed capability-unsupported failure.
| Provider | Kind | Default base URL | Key richiesta | Web search | Vision | Note |
|---|---|---|---|---|---|---|
| AI locale integrata | BuiltInOnnx | n/a (in-process) | no | ✖ | ✖ | ONNX GenAI model spedito, default-on |
| Anthropic | Anthropic | https://api.anthropic.com/ | yes | ✅ | ✅ | Messages API, web_search tool |
| OpenAI | OpenAiCompatible | https://api.openai.com/v1/ | yes | opt-in | opt-in | Chat Completions |
| Azure OpenAI | AzureOpenAi | https://<resource>.openai.azure.com/ | yes | ✅ | ✅ | deployment path + api-version |
| Google Gemini | Gemini | https://generativelanguage.googleapis.com/ | yes | ✅ | ✅ | generateContent, google_search grounding |
| Ollama (locale) | OpenAiCompatible | http://localhost:11434/v1/ | no | ✖ | model-dependent | via adapter compatibile OpenAI |
| LM Studio (locale) | OpenAiCompatible | http://localhost:1234/v1/ | no | model-dependent | model-dependent | via adapter compatibile OpenAI |
| vLLM / llama.cpp / LocalAI | OpenAiCompatible | your served URL | no | ✖ | model-dependent | via adapter compatibile OpenAI |
| OpenRouter / Groq / Together / Mistral / DeepSeek | OpenAiCompatible | provider URL | yes | ✖ | model-dependent | via adapter compatibile OpenAI |
Guide di setup per-provider complete (chiavi, URL, id modello, passi UI): vedere Provider AI — catalogo di configurazione.
AI locale integrata (spedita, default-on)
cMind spedisce un vero LLM locale che gira in-process tramite Microsoft.ML.OnnxRuntimeGenAI (un compact instruct model come Phi-3.5-mini). Non ha bisogno di nessuna API key e nessun servizio esterno, e al primo avvio — quando nessun provider è configurato e il white-label gate lo permette — viene seeded e attivato automaticamente, così ogni deployment ha AI funzionante out of the box.
- La directory del modello (
genai_config.json+ tokenizer + pesi) è configurata daApp:Ai:BuiltIn:ModelPath(defaultmodels/onnx, relativo alla directory base dell'app). Quando i file del modello sono assenti il provider degrada a un failure typed con un hint di installazione — non lancia mai, e il resto dell'app non è affected. - Alimenta ogni feature AI testuale. Essendo un modello compact, è solo testo (no ricerca web lato server o vision) e la generazione è serializzata (una istanza modello, riusata dopo un lazy load).
- Più modelli integrati possono coesistere. Ogni modello scaricato risiede sotto
ModelPath/<key>; un catalogo curato (Phi-3.5-mini predefinito, più Phi-3-mini-128k) può essere scaricato e scambiato da Settings → AI. Selezionando un submodel integrato lo carica in-process. Acquisire/bundle un modello: vedere Provider AI → built-in.
Controlli white-label
Un deployment white-label restringe AI via App:Branding (applicato server-side su ogni provider upsert):
AllowBuiltInAi(defaulttrue) — impostarefalseper rimuovere completamente il modello integrato.AllowLocalProviders(defaulttrue) — impostarefalseper proibire endpoint locali/self-hosted (loopback / private OpenAI-compatible, es. Ollama/LM Studio/vLLM).AllowedAiProviderKinds(default empty = tutti) — elencare solo i tipi che il deployment sanziona (es.["Anthropic","OpenAiCompatible"]) per bloccare quali provider gli utenti possono aggiungere.AllowAiModelManagement(defaulttrue) — impostarefalseper nascondere navigazione modelli, lo selettore modello per-page, e binding modelli per-feature. Tutti sono owner-tunable a runtime da Settings → Deployment (sovrapposti live suIOptionsMonitor) e catalogati inWhiteLabelCatalog.
Estendere: futuri modelli integrati
Il layer AI è adapter-based e costruito per crescere. Ogni provider è un IAiProvider selezionato da
AiProviderKind; la seam feature-facing (IAiClient/AiFeatureService) non cambia mai. Aggiungere un
nuovo runtime modello integrato più tardi (un altro modello ONNX, un diverso engine in-process, GGUF/llama.cpp
in-proc, ecc.) è un cambiamento localizzato: aggiungere un AiProviderKind, implementare un adapter
IAiProvider, registrarlo, e (opzionalmente) cablare default seeding + un'opzione dialog — nessun cambiamento
di feature, endpoint o tool MCP. Il provider ONNX integrato è l'implementazione di riferimento di questo pattern.
Funzionalità
- Build cBot — un workshop basato su progetti a
/ai/build: creare un nuovo cBot (nome univoco + lingua) o migliorare uno esistente che ha source, poi chattare con un modello su/ai/build/{projectId}per scrivere e affinare il suo codice. Ogni prompt e risposta del modello viene persistito con timestamp e sopravvive a navigazione/ricarico; il source del modello viene applicato al progetto ad ogni turno. Build e Run il cBot dalla stessa pagina (o aprilo nell'editor completo). Ogni progetto appare nella lista con il suo ultimo tempo di modifica e controlli view/delete. - Selezione modello per-page — ogni pagina feature AI e dialog mostra un selettore modello che elenca i modelli che puoi usare (i tuoi provider + i default del deployment). Pre-seleziona il binding salvato della feature se impostato, altrimenti il modello default, e il modello che scegli si applica a quell'azione (inviato come
?modelId=e forzato daRoutingAiClientper quella chiamata). Nascosto quando il deployment disabilita la gestione del modello. - Sfoglia e seleziona modelli, per feature — sfoglia i modelli che un endpoint provider pubblicizza (
GET /v1/modelssu LM Studio / Ollama / vLLM / llama.cpp, o il catalogo integrato) invece di digitare manualmente un id, e vincolare ogni feature AI a un modello diverso così più modelli servono feature diverse contemporaneamente (una feature non vincolata ricade al provider dello scope predefinito). - Ottimizzazione parametri — closed loop: AI propone param set, ciascuno persistito + backtestato attraverso nodi (
optimize-run/optimize-params). - Agente portfolio autonomo — proposte mandate-driven con journal decisionale completo (
AgentMandate→AgentProposal). - Acting risk guard — servizio background
AiRiskGuardvaluta i bot in esecuzione, può auto-stop su rischio critico (opt-in). - Prop-firm exposure guardian — limiti drawdown/exposure con auto-flatten.
- Alert di mercato — motore
AlertRulecon sentiment AI (grounding ricerca web dove il provider lo supporta). - Analisi — revisione cBot, analisi backtest, post-mortem, sentiment di mercato, design chart-vision, curatela marketplace.
Superfici
- Endpoint Web sotto
/api/ai/*(la chat Buildbuild/{id}/prompt+build/{id}/messages, generate-project, review, analyze-backtest, optimize-params, optimize-run, post-mortem, sentiment, vision, curate, …). Ogni endpoint feature accetta un opzionale?modelId=<credential>per eseguire quella chiamata su un modello scelto. Plus scoperta modelli (/api/ai/models/probe,/api/ai/usable-models) e binding per-feature (/api/ai/feature-bindings,/api/ai/my-feature-bindings). I progetti cBot, build e run riutilizzano gli endpoint del builder (/api/builder/projects…). - Tool MCP (
AiTools) per client AI — vedere mcp.md. La selezione provider è trasparente ai client MCP. - Nav group AI — una Blazor page per feature: Build cBot (
/ai/build), Review (/ai/review), Debate (/ai/debate), Market Sentiment (/ai/sentiment), Exposure Check (/ai/exposure), Portfolio Digest (/ai/digest), Tune Advisor (/ai/tune), Optimize (/ai/optimize), più Portfolio Agent, Alerts, MCP Keys. Le pagine condividonoAiFeaturePageBase+AiOutputPanel+ unAiModelSelect; ciascuna mostraAiFeatureNoticequando nessun provider è configurato. - Settings → AI (
/settings/ai, solo owner) — lista provider con dialog Add / edit provider (kind, base URL con hint per-kind e preset one-click inclusi Kimi/Moonshot, Ollama e LM Studio, modello, key opzionale, toggle capacità, "set as default") e pulsante Test connection.
Configurazione
App:Ai supporta sia la legacy single key che il multi-provider seeding:
- Legacy:
ApiKey,Model(defaultclaude-opus-4-8),BaseUrl,MaxTokens— ancora onorati come provider Anthropic default. - Multi-provider:
ActiveProvider(kind) eProviders[]({ Kind, BaseUrl, Model, ApiKey?, MaxTokens?, Capabilities? }) — importati nell'archivio all'avvio se ancora non esistono credenziali, così un team ops può spedire un deployment configurato (incl. local-LLM) puramente via appsettings/env.
RiskGuardEnabled, RiskGuardAutoStop, RiskGuardInterval invariati. Per test/dev, una chiave di config
vive nel file dev-credentials unificato sotto Ai.
Affidabilità
Il provider è trattato come inaffidabile — nulla di ciò che fa può far andare giù l'app. Questo vale identicamente per endpoint cloud e locali (un Ollama morto ritenta poi degrada esattamente come un Anthropic throttled):
- Graceful degradation. Ogni failure mode (no provider, HTTP 4xx/5xx/429, timeout, body malformato,
content vuoto, capacità unsupported) restituisce un typed
AiResult.Fail(reason)— il client non lancia mai in una pagina, tool MCP o hosted service. - Pipeline di resilience.
AddAiHttpClientdà al singoloHttpClientAI condiviso un bounded retry su 5xx transitori / failure di rete (exponential backoff + jitter) più generosi per-attempt e total timeout (AiHttp), riutilizzato da ogni adapter.
Testing con il fake local LLM
Il layer AI è provato end-to-end senza nessuna dipendenza esterna da FakeLocalLlmServer — un tiny
endpoint OpenAI-compatible in-process che restituisce una canned reply deterministica, wire-identical a
Ollama/LM Studio/vLLM. Supporta:
- Unit — test di request-translation + response-parse per adapter, routing/capability degradation.
- Integration — adapter end-to-end compatibile OpenAI, la teoria di resilience parametrizzata attraverso ogni adapter, e gli MCP AI tools.
- E2E —
AiLocalFixtureboot dell'app puntata al fake server (o un provider reale quando lo sviluppatore impostaAI_E2E_BASEURL(+ opzionaleAI_E2E_API_KEY/AI_E2E_KIND/AI_E2E_MODEL) — credenziali reali vincono) e guida ogni feature AI attraverso l'UI reale. Aggiungere o cambiare qualsiasi feature AI richiede un test E2E attraverso questa fixture (vedere il mandate del repo test). Una lane opt-in (AI_LOCAL_LLM=1) esegue una completion reale attraverso un Ollama Testcontainer.
AI locale integrata — zero-setup per default
Il LLM locale ONNX integrato funziona out of the box: quando la sua directory modello è assente e
App:Ai:BuiltIn:AutoDownload è true (il default), l'app scarica il modello una volta in
background da App:Ai:BuiltIn:DownloadBaseUrl. Mentre il download gira, le chiamate AI (e Test
connection in Settings → AI) restituiscono un chiaro messaggio "model is downloading (first-time setup)"
piuttosto che un hard failure. Deployment air-gapped/metered impostano AutoDownload=false e
pre-provisionano la directory modello (App:Ai:BuiltIn:ModelPath). Il white-label gate
App:Branding:AllowBuiltInAi si applica ancora.
Lo scaricamento è anche pre-riscaldato all'avvio quando il modello integrato è il provider attivo, così è
pronto prima del primo click AI piuttosto che fallire quel click con "downloading…". Settings → AI
mostra lo stato di installazione live sulla scheda del provider integrato — Modello pronto / Download del modello in corso… /
Modello non installato / Download fallito — con un pulsante Scarica modello (o Riprova download) che
avvia il fetch in background one-time su richiesta (GET /api/ai/built-in/status, POST /api/ai/built-in/install).
Abilitare il provider integrato da Settings riusa la riga già seminata invece di aggiungerne una duplicata,
così non entra mai in conflitto con il vincolo single-active-provider.