@veriax/sdk · v0.0.5
SDK JavaScript di VERIAX
@veriax/sdk permette a qualsiasi applicazione JavaScript, nel browser o in un'app nativa, di usare gli agenti VERIAX. La tua applicazione può conversare con un agente, lasciare che usi i suoi strumenti, ottenere output strutturati basati sulla tua base di conoscenza, inviargli file e ricevere ciò che produce.
La chiave API resta sul tuo server, che chiede a VERIAX token di breve durata: la tua applicazione lavora solo con quelli. Un token può agire in tre modi:
- con un account applicativo, creato apposta per l'integrazione, ad esempio per rispondere a visitatori anonimi;
- con il tuo utente VERIAX, per un'integrazione che lavora per conto tuo;
- per conto dei tuoi utenti, quando la tua applicazione li autentica e in VERIAX hanno un utente con la stessa email.
I tre casi sono descritti in Modalità di accesso.
Primi passi
Questa guida ti porta da un progetto vuoto a una conversazione funzionante. Ti servono un account VERIAX e almeno un agente.
1. Crea una chiave API
Ogni integrazione parte da una chiave API. Dove crearla dipende dall'identità con cui agiranno i token; per una prima prova usa il tuo utente:
- In VERIAX apri il tuo Profilo.
- Nel riquadro Credenziali di accesso apri la scheda Chiavi API e scegli Crea chiave API.
- Assegna un nome e una data di scadenza, poi conferma.
- Copia la chiave: viene mostrata una sola volta.
Per gli altri due casi vedi Modalità di accesso. Conserva la chiave sul tuo server, in una variabile d'ambiente o in un gestore di segreti.
2. Installa l'SDK
npm install @veriax/sdk
Il pacchetto è distribuito solo come modulo ESM e non ha dipendenze a runtime.
3. Genera i token sul tuo server
Aggiungi al tuo server un endpoint che chiede un token a VERIAX e lo restituisce alla tua applicazione. VERIAX risponde 201 {"token", "expires_at", "expires_in"}: inoltra la risposta così com'è, con Cache-Control: no-store.
# Django: settings.VERIAX_URL e settings.VERIAX_API_KEY arrivano dall'ambiente
import requests
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.views.decorators.http import require_POST
@require_POST
@login_required
def veriax_token(request):
answer = requests.post(
f"{settings.VERIAX_URL}/api/v1/ai/get-token/",
headers={"Authorization": f"Api-Key {settings.VERIAX_API_KEY}"},
timeout=8,
)
response = HttpResponse(answer.content, status=answer.status_code, content_type="application/json")
response["Cache-Control"] = "no-store"
return response
4. Scegli un agente e invia un messaggio
getAssistants() elenca gli agenti che il token può usare, con id, name e description. Lascia scegliere l'agente all'utente, oppure decidilo nel codice, poi apri una conversazione:
import { VeriaxClient } from '@veriax/sdk'
const client = new VeriaxClient({
baseUrl: 'https://veriax.example.com',
tokenUrl: '/api/veriax-token',
})
const picker = document.querySelector<HTMLSelectElement>('#agent')!
const agents = await client.getAssistants()
picker.replaceChildren(...agents.map((agent) => new Option(agent.name, String(agent.id))))
async function start(agentId: number) {
const thread = await client.createThread({ assistant: agentId })
const chat = client.chat(thread)
const { text } = await chat.send('Ciao').result
console.log(text)
}
picker.onchange = () => start(Number(picker.value))
createThread apre la conversazione con l'agente, chat si collega e send restituisce la risposta. Nei passi successivi agentId indica l'agente scelto.
5. Mostra la risposta mentre arriva
Le risposte arrivano in streaming. A ogni aggiornamento mostra il testo ricevuto finora e, alla fine, le fonti citate dall'agente:
import { renderMarkdown } from '@veriax/sdk/markdown'
const out = document.querySelector<HTMLElement>('#answer')!
const reply = chat.send('Cosa dice la nostra politica sui resi?', {
onDelta: (_delta, text) => out.replaceChildren(renderMarkdown(text)),
})
const { citations } = await reply.result
chat.stop() interrompe la risposta, che si chiude con stopped: true.
6. Riprendi la conversazione
L'SDK ricorda l'ultima conversazione: al caricamento successivo puoi riprenderla invece di crearne una nuova.
const thread = client.lastThread() ?? (await client.createThread({ assistant: agentId }))
const chat = client.chat(thread)
const history = await chat.getMessages()
Di default il token e l'ultima conversazione sono salvati in sessionStorage. Le altre opzioni sono in Token e storage.
7. Altre funzionalità
- Strumenti. Non serve configurare nulla: l'agente usa da solo strumenti, retriever e abilità quando servono. Se nella tua interfaccia vuoi far indicare all'utente strumenti precisi, come nel menu strumenti della chat VERIAX,
client.getTools(agentId)restituisce quel menu esend(text, { selectedTools })chiede all'agente di usare gli strumenti scelti per quel messaggio. - File.
client.uploadArtifact(chat.threadToken, file)aggiunge un file alla conversazione; l'agente può leggerlo se ha un'abilità per i file.chat.getArtifacts()elenca i file eclient.downloadArtifact(id, chat.threadToken)li scarica, compresi quelli generati dall'agente. - Input e output strutturati. Se un agente definisce un
input_schema, invia l'oggetto come testo JSON:chat.send(JSON.stringify(value)). Se definisce unostructured_output, la risposta è un JSON con quella struttura. Trovi entrambi gli schemi nei risultati digetAssistants()ecreateThread().
Modalità di accesso
Il codice dell'SDK è lo stesso nei tre casi: cambiano solo la chiave API e ciò che il tuo server invia a get-token/.
Account applicativo
È la scelta giusta quando chi usa la tua applicazione non ha un utente VERIAX, ad esempio i visitatori di un sito pubblico. Tutti i token agiscono come lo stesso account, che accede solo alle risorse che condividi con lui.
- In Impostazioni > Utenti scegli Nuovo utente e imposta Tipo utente su Applicativo.
- Condividi con l'account gli agenti che deve poter usare e le basi di conoscenza da cui attingono.
- Nella pagina dell'account, nel riquadro Credenziali di accesso, crea una chiave API.
VERIAX non permette di condividere con un account applicativo un agente che potrebbe agire con la sua identità, ad esempio tramite connettori o strumenti MCP: la finestra di condivisione indica cosa lo impedisce. Ogni conversazione è accessibile solo con il proprio thread token, quindi un visitatore non vede mai le conversazioni degli altri.
Il tuo utente
Adatto a un'integrazione che lavora per conto tuo, come uno strumento interno o uno script. Crea la chiave dal tuo Profilo, come al passo 1. I token agiscono come te, con i tuoi agenti e le tue conversazioni.
Per conto dei tuoi utenti
Adatto a un'applicazione che autentica i propri utenti, come un ERP o una intranet, quando le stesse persone hanno in VERIAX un utente con la stessa email. Ognuno lavora così con i propri agenti e le proprie conversazioni.
- Crea un account applicativo e la sua chiave API, come sopra.
- Un superutente apre la pagina dell'account, attiva Apri la chat come qualunque utente nel riquadro Credenziali di accesso e salva.
- Il tuo server aggiunge alla richiesta l'email dell'utente autenticato:
@require_POST
@login_required
def veriax_token(request):
answer = requests.post(
f"{settings.VERIAX_URL}/api/v1/ai/get-token/",
headers={"Authorization": f"Api-Key {settings.VERIAX_API_KEY}"},
json={"email": request.user.email},
timeout=8,
)
response = HttpResponse(answer.content, status=answer.status_code, content_type="application/json")
response["Cache-Control"] = "no-store"
return response
Prendi l'email dalla sessione del tuo server, mai da dati inviati dal client. VERIAX la confronta senza distinguere maiuscole e minuscole; se non corrisponde a nessun utente attivo, la risposta è 404 unknown_user. Il profilo di un utente può essere diverso da user: leggilo con client.getProfiles() e passalo nell'opzione profile.
App native
L'SDK funziona ovunque siano disponibili fetch, WebSocket e AbortSignal.timeout, quindi anche in React Native e nelle WebView. Rispetto al browser cambiano due cose:
- Storage. Senza
sessionStoragel'SDK tiene il token in memoria. Per conservare la conversazione tra un avvio e l'altro, passa nell'opzionestorageun oggetto di storage sincrono (getItem,setItem,removeItem). - Endpoint dei token. Un'app non ha i cookie del sito: autentica la chiamata con il tuo sistema di login, ad esempio tramite l'opzione
headersditokenUrl.
import { tokenUrl } from '@veriax/sdk/helpers'
const client = new VeriaxClient({
baseUrl: 'https://veriax.example.com',
getToken: tokenUrl('https://api.example.com/veriax-token', {
headers: () => ({ Authorization: `Bearer ${session.accessToken}` }),
}),
})
Non inserire mai la chiave API nell'app: un'app installata può essere decompilata.
Errori e riconnessione
L'SDK gestisce da solo la maggior parte dei problemi:
- Cadute di rete. La chat si riconnette a intervalli crescenti. Se una risposta si è interrotta, l'SDK rilegge la conversazione: una risposta completata nel frattempo arriva con
resynced: true, mentre una domanda che non era arrivata viene inviata di nuovo. - Token scaduti. All'80% della durata del token, e dopo ogni
401, l'SDK chiede un nuovo token al tuo endpoint e prosegue.
Tutti gli altri errori arrivano come VeriaxError con un code (vedi Codici di errore). Gli errori di una risposta fanno fallire reply.result, quelli di connessione arrivano su chat.on('error') e quelli REST fanno fallire la promise del metodo chiamato.
Riferimento API
Entry point
| Import | Contenuto |
|---|---|
@veriax/sdk | VeriaxClient, ChatSession, Reply, VeriaxError e i tipi (Thread, Assistant, Citation, TokenResponse, ...) |
@veriax/sdk/helpers | tokenUrl, handleError e il tipo TokenUrlOptions |
@veriax/sdk/markdown | renderMarkdown |
VeriaxClient
new VeriaxClient(options):
| Opzione | Default | Note |
|---|---|---|
baseUrl | obbligatoria | L'istanza VERIAX. Deve essere https://; http:// solo verso localhost |
tokenUrl o getToken | una delle due | tokenUrl: il tuo endpoint dei token, chiamato con POST. getToken: una tua funzione che restituisce {token, expires_at, expires_in} |
profile | user | Il profilo VERIAX nei percorsi dell'API |
storage | 'session' | Dove tenere il token e l'ultima conversazione: vedi Token e storage |
key | default | Suffisso della chiave di storage, per usare più client nella stessa pagina |
fetch, WebSocket | globali | Implementazioni alternative |
timeoutMs | 10 s | Timeout delle chiamate a VERIAX |
| Metodo | Cosa fa |
|---|---|
getAssistants() | Gli agenti su cui il token può aprire una conversazione, con input_schema e structured_output |
createThread({ assistant, name? }) | Apre una conversazione. Restituisce { id, token, name, assistant, input_schema, structured_output, date_create, date_last_modify } |
getThread(threadToken) | La conversazione di quel thread token |
revokeThread(threadToken) | Chiude la conversazione per ogni token |
chat(thread, options?) | Si collega alla conversazione e restituisce la sua ChatSession |
lastThread() | { token } dell'ultima conversazione aperta con chat(), se c'è |
getTools(assistantId) | Il menu strumenti dell'agente: { tools: [{ name, display_name, icon, priority, visible }], total_count } |
getProfiles() | I profili dell'utente per cui agisce il token: [{ value, label }] |
uploadArtifact(threadToken, file, filename?) | Aggiunge un file alla conversazione |
downloadArtifact(id, threadToken), downloadPreview(id, threadToken) | Un file, o la sua anteprima, come Blob |
tokens.clear() | Dimentica il token e l'ultima conversazione, ad esempio al logout |
dispose() | Ferma il rinnovo automatico del token e il controllo sulla visibilità della pagina |
ChatSession
Opzioni di chat(): backoffBaseMs (1 s), backoffMaxMs (30 s), maxReconnectAttempts (10, Infinity per nessun limite), WebSocket.
| Membro | Cosa fa |
|---|---|
send(content, { onDelta?, selectedTools? }) | Invia un messaggio e restituisce una Reply. Un secondo send durante una risposta lancia busy |
stop() | Interrompe la risposta in corso |
getMessages() | La cronologia della conversazione: messaggi human e ai con le loro citations |
getArtifacts() | I file della conversazione |
connect() | Apre la connessione; send lo fa da solo |
close() | Chiude la connessione e smette di riconnettersi |
state | idle, connecting, open, reconnecting o closed |
replying | Se una risposta inviata da questa sessione è in corso |
threadToken | Il thread token della conversazione |
on(event, fn) | Aggiunge un listener e restituisce la funzione che lo rimuove |
| Evento | Quando scatta |
|---|---|
ready | La connessione è pronta, a ogni connessione e riconnessione. { threadToken, replying } |
state | Cambia lo stato della connessione |
sources | Una risposta ha citato delle fonti: { threadToken, citations } |
human-message | Nella stessa conversazione è arrivato un messaggio inviato altrove, ad esempio da un'altra scheda del browser |
stream-finished | È finita una risposta non inviata da questa sessione |
frame | Ogni messaggio ricevuto dal server |
error | Un errore di connessione |
Reply
Membro di Reply | Cosa contiene |
|---|---|
for await (const delta of reply) | Le porzioni di testo, man mano che arrivano |
reply.text | Il testo ricevuto fin qui |
reply.result | Promise di { text, stopped, resynced, messageId, citations? } |
Token e storage
storage | Effetto |
|---|---|
'session' | sessionStorage: sopravvive al ricaricamento della scheda |
'local' | localStorage: condiviso tra le schede e conservato dopo averle chiuse |
'memory' | Non salva nulla: a ogni caricamento chiede un nuovo token e inizia una nuova conversazione |
un oggetto { getItem, setItem, removeItem } | Il tuo storage sincrono |
La chiave di storage è veriax.session.<key>. Se lo storage non è disponibile, l'SDK lavora in memoria. Con 'local', un tokens.clear() in una scheda disconnette tutte le altre.
renderMarkdown
renderMarkdown(text, doc?) restituisce un DocumentFragment costruito solo con le API del DOM, quindi il testo del modello non viene mai interpretato come HTML. In Node passa un document come secondo argomento. Supporta paragrafi, grassetto, corsivo, codice in linea, blocchi di codice, elenchi puntati e numerati su un livello e link http:, https: e mailto:, che si aprono in una nuova scheda. Titoli, tabelle, immagini e HTML vengono mostrati come testo.
Codici di errore
Ogni errore è un VeriaxError con code, recoverable, message (tecnico, in inglese, non da mostrare agli utenti) e, quando presenti, status, serverCode, closeCode e serverMessage (testo pensato per gli utenti, come il messaggio di un limite d'uso).
code | Quando | Recuperabile |
|---|---|---|
session_unavailable | Il tuo endpoint non dà un token valido, oppure VERIAX rifiuta il token due volte | no |
thread_closed | La conversazione è stata chiusa con revokeThread | no |
assistant_not_allowed | Il token non può usare quell'agente | no |
not_found | Conversazione o file sconosciuti | no |
forbidden | Azione non permessa | no |
invalid_input | Messaggio vuoto o troppo lungo (4000 caratteri di default), file troppo grande (10 MiB di default), richiesta malformata | in chat sì, su REST no |
handshake_refused | La connessione alla conversazione è stata rifiutata due volte | sì |
limit_reached | È stato raggiunto un limite d'uso dell'agente; vedi serverMessage | no |
rate_limited | Troppe richieste, ad esempio più di 10 messaggi al minuto nella stessa conversazione | sì |
unavailable | La licenza di VERIAX non è attiva | no |
connection_lost | Rete, timeout o errore del server, dopo i tentativi di riconnessione | sì |
model_error | Errore del modello o dell'agente | sì |
action_not_allowed | Il server ha rifiutato un'azione sul socket | no |
busy | send mentre è in corso una risposta | no |
closed | È stato chiamato close(), oppure tokens.clear() durante una richiesta di token | dipende |
Codici di chiusura del socket
| Chiusura | Cosa fa l'SDK |
|---|---|
| Handshake rifiutato | Prende un token nuovo e riprova; un secondo rifiuto dà handshake_refused |
4401 (token scaduto, conversazione chiusa, chiave revocata) | Si riconnette subito con il token corrente; se viene rifiutato di nuovo, thread_closed |
1000 dopo un messaggio di limite o di errore | Fatale: limit_reached o l'errore ricevuto |
Altri codici, o nessun ready entro 15 s | Si riconnette dopo 1, 2, 4… secondi, fino a 30, per al massimo maxReconnectAttempts tentativi, poi connection_lost |
Chiavi API e sicurezza
- Tieni la chiave sul server. Mai nel codice del browser, in un'app, in un repository, negli URL o nei log.
- Una chiave per ogni integrazione, con scadenza. Così puoi revocarne una senza fermare le altre. La revoca invalida subito tutti i token della chiave.
- Proteggi l'endpoint dei token. Chiunque lo raggiunga ottiene un token. Esponilo solo in HTTPS, richiedi il login se la tua applicazione lo prevede, limita le richieste per utente o per IP e non abilitare CORS per altre origini.
- Tratta il thread token come un segreto. Dà accesso alla conversazione: non inserirlo in URL, log o strumenti di analytics.
- Mostra le risposte in modo sicuro. Usa
renderMarkdowno testo semplice, maiinnerHTML, e non incorporare nella pagina i file di una conversazione: provengono dagli utenti o dal modello. - Informa i tuoi utenti. Conversazioni e file vengono salvati in VERIAX, nell'account con cui agisce il token.
Requisiti dell'istanza VERIAX
Per chi gestisce l'istanza:
- Chiavi API attive (
THX_AI_API_KEYS_ENABLED) e token di chat attivi (THX_AI_CHAT_SESSIONS_ENABLED, attivo di default). - Le classi di autenticazione
ApiKeyAuthentication, poiChatSessionAuthentication, prima diSessionAuthentication, eApiKeyOrSessionAuthStackper i WebSocket. django-cors-headersinstallato, senzaCORS_ALLOW_CREDENTIALS: l'SDK non invia mai cookie.
Versione e licenza
Questa pagina documenta @veriax/sdk 0.0.5. L'SDK è distribuito con licenza MIT.
FAQ
La chiave API finisce mai nel browser o nell'app?
No. La chiave resta sul tuo server, che la usa per chiedere a VERIAX un token di breve durata e inoltra solo quello. L'SDK lavora con il token e non vede mai la chiave.
L'SDK disegna un'interfaccia?
No. Fornisce dati ed eventi: l'interfaccia la costruisci tu. Per mostrare le risposte puoi usare renderMarkdown, che crea nodi DOM senza passare da innerHTML.
Funziona in React Native?
Sì. L'SDK richiede solo fetch, WebSocket e AbortSignal.timeout. Senza sessionStorage tiene il token in memoria: per conservarlo tra un avvio e l'altro dell'app, passa un oggetto di storage sincrono.
Quanto dura un token?
30 minuti, se non configuri diversamente. Prima della scadenza l'SDK ne chiede uno nuovo al tuo server, e le conversazioni restano accessibili anche con i token successivi.