Vai al contenuto
Indice
  1. App native
  2. Errori e riconnessione
  3. Chiavi API e sicurezza
  4. Requisiti dell'istanza VERIAX
  5. Versione e licenza
  6. FAQ

@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:

  1. In VERIAX apri il tuo Profilo.
  2. Nel riquadro Credenziali di accesso apri la scheda Chiavi API e scegli Crea chiave API.
  3. Assegna un nome e una data di scadenza, poi conferma.
  4. 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 e send(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 e client.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 uno structured_output, la risposta è un JSON con quella struttura. Trovi entrambi gli schemi nei risultati di getAssistants() e createThread().

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.

  1. In Impostazioni > Utenti scegli Nuovo utente e imposta Tipo utente su Applicativo.
  2. Condividi con l'account gli agenti che deve poter usare e le basi di conoscenza da cui attingono.
  3. 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.

  1. Crea un account applicativo e la sua chiave API, come sopra.
  2. Un superutente apre la pagina dell'account, attiva Apri la chat come qualunque utente nel riquadro Credenziali di accesso e salva.
  3. 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 sessionStorage l'SDK tiene il token in memoria. Per conservare la conversazione tra un avvio e l'altro, passa nell'opzione storage un 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 headers di tokenUrl.
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

ImportContenuto
@veriax/sdkVeriaxClient, ChatSession, Reply, VeriaxError e i tipi (Thread, Assistant, Citation, TokenResponse, ...)
@veriax/sdk/helperstokenUrl, handleError e il tipo TokenUrlOptions
@veriax/sdk/markdownrenderMarkdown

VeriaxClient

new VeriaxClient(options):

OpzioneDefaultNote
baseUrlobbligatoriaL'istanza VERIAX. Deve essere https://; http:// solo verso localhost
tokenUrl o getTokenuna delle duetokenUrl: il tuo endpoint dei token, chiamato con POST. getToken: una tua funzione che restituisce {token, expires_at, expires_in}
profileuserIl profilo VERIAX nei percorsi dell'API
storage'session'Dove tenere il token e l'ultima conversazione: vedi Token e storage
keydefaultSuffisso della chiave di storage, per usare più client nella stessa pagina
fetch, WebSocketglobaliImplementazioni alternative
timeoutMs10 sTimeout delle chiamate a VERIAX
MetodoCosa 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.

MembroCosa 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
stateidle, connecting, open, reconnecting o closed
replyingSe una risposta inviata da questa sessione è in corso
threadTokenIl thread token della conversazione
on(event, fn)Aggiunge un listener e restituisce la funzione che lo rimuove
EventoQuando scatta
readyLa connessione è pronta, a ogni connessione e riconnessione. { threadToken, replying }
stateCambia lo stato della connessione
sourcesUna risposta ha citato delle fonti: { threadToken, citations }
human-messageNella 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
frameOgni messaggio ricevuto dal server
errorUn errore di connessione

Reply

Membro di ReplyCosa contiene
for await (const delta of reply)Le porzioni di testo, man mano che arrivano
reply.textIl testo ricevuto fin qui
reply.resultPromise di { text, stopped, resynced, messageId, citations? }

Token e storage

storageEffetto
'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).

codeQuandoRecuperabile
session_unavailableIl tuo endpoint non dà un token valido, oppure VERIAX rifiuta il token due volteno
thread_closedLa conversazione è stata chiusa con revokeThreadno
assistant_not_allowedIl token non può usare quell'agenteno
not_foundConversazione o file sconosciutino
forbiddenAzione non permessano
invalid_inputMessaggio vuoto o troppo lungo (4000 caratteri di default), file troppo grande (10 MiB di default), richiesta malformatain chat sì, su REST no
handshake_refusedLa connessione alla conversazione è stata rifiutata due voltesì
limit_reachedÈ stato raggiunto un limite d'uso dell'agente; vedi serverMessageno
rate_limitedTroppe richieste, ad esempio più di 10 messaggi al minuto nella stessa conversazionesì
unavailableLa licenza di VERIAX non è attivano
connection_lostRete, timeout o errore del server, dopo i tentativi di riconnessionesì
model_errorErrore del modello o dell'agentesì
action_not_allowedIl server ha rifiutato un'azione sul socketno
busysend mentre è in corso una rispostano
closedÈ stato chiamato close(), oppure tokens.clear() durante una richiesta di tokendipende

Codici di chiusura del socket

ChiusuraCosa fa l'SDK
Handshake rifiutatoPrende 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 erroreFatale: limit_reached o l'errore ricevuto
Altri codici, o nessun ready entro 15 sSi 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 renderMarkdown o testo semplice, mai innerHTML, 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, poi ChatSessionAuthentication, prima di SessionAuthentication, e ApiKeyOrSessionAuthStack per i WebSocket.
  • django-cors-headers installato, senza CORS_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.