@autonomoss/chat-core
v2.0.0
Published
Headless TypeScript client for embedding Autonomoss AI chat: sessions, secure attributes, SSE streaming, threads.
Readme
@autonomoss/chat-core
Cliente headless do Autonomoss Web SDK — sem UI, sem framework. Sessão,
atributos seguros/públicos, streaming SSE e histórico de conversas. Use
diretamente se você vai construir sua própria interface; se quiser um chat
pronto, veja @autonomoss/chat ou
@autonomoss/chat-react.
Instalação
Pacote público — instala normalmente, sem autenticação:
npm install @autonomoss/chat-core
# ou
pnpm add @autonomoss/chat-core
# ou
yarn add @autonomoss/chat-coreTambém publicado em espelho no
GitHub Packages
— útil se sua organização já centraliza dependências ali; requer um
.npmrc com token read:packages (ver
documentação do GitHub Packages).
Quickstart
import { Autonomoss } from '@autonomoss/chat-core'
const client = Autonomoss({
publishableKey: 'pk_...',
baseUrl: 'https://sua-api.exemplo.com/v1/embed',
attributes: {
secure: {
access_token: { format: 'bearer_token', value: () => keycloak.token! },
},
},
})
for await (const event of client.sendMessage({ message: 'Olá!' })) {
if (event.type === 'text') process.stdout.write(event.text)
}baseUrl é obrigatório — aponte para a API de embed do seu próprio backend
Autonomoss. O SDK não embute nenhum endereço padrão.
Referência de API
Autonomoss(config) / new EmbedClient(config)
Fábrica (ou construtor direto) que recebe um AutonomossConfig:
| Campo | Tipo | Obrigatório | Descrição |
| ---------------- | ------------------ | ----------- | -------------------------------------------------------------------------------------------- |
| publishableKey | string | sim | Chave pública do widget (pk_...). Nunca a sk_ — essa é só server-side. |
| baseUrl | string | sim | Base da API de embed do seu backend Autonomoss (ex: https://sua-api.exemplo.com/v1/embed). |
| attributes | AttributesConfig | sim | Atributos seguros/públicos da sessão — ver Atributos. |
| telemetry | TelemetryConfig | não | Opt-in, ver Telemetria. |
EmbedClient
| Membro | Assinatura | Descrição |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| connect() | (): Promise<void> | Faz o bootstrap da sessão adiantado. Opcional — sendMessage/threads.* fazem sob demanda. |
| sendMessage(input, options?) | (input: SendMessageInput, options?: { signal?: AbortSignal }): AsyncGenerator<EmbedStreamEvent> | Envia uma mensagem; itere o generator para receber o stream incremental (também emitido via on('message', ...)). |
| setAttributes(patch) | (patch: { public?: Record<string, unknown> }): void | Atualiza atributos públicos (contexto de orquestração) sem recriar a sessão. Atributos seguros são sempre resolvidos on-demand a cada bootstrap/refresh — não há como "setá-los" fora do config inicial. |
| on(event, handler) / off(event, handler) | ver Eventos | Assina/cancela eventos do client. on retorna uma função de unsubscribe. |
| threads | ThreadsApi | Histórico de conversas — ver Threads. |
| destroy() | (): void | Remove todos os listeners registrados via on. |
SendMessageInput
interface SendMessageInput {
message: string
chatId?: string // continua uma conversa existente; omitido cria uma nova
attachments?: ChatAttachment[] // até 3, 2 MB cada, efêmeros — o SDK não os persiste
}EmbedStreamEvent
União discriminada por type, o que sendMessage produz a cada iteração:
type EmbedStreamEvent =
| { type: 'meta'; chatId: string; senderName: string; modelBadge: string }
| { type: 'text'; text: string } // token incremental da resposta
| {
type: 'status'
stepId: string
title: string
description: string
status: 'loading' | 'complete' | 'error'
}
| { type: 'error'; reason: string; message?: string }Threads (histórico)
client.threads expõe:
| Método | Retorno | Descrição |
| ---------------------- | ------------------------ | ----------------------------------- |
| list() | Promise<ChatSummary[]> | Lista as conversas da sessão atual. |
| create() | Promise<ChatSummary> | Cria uma conversa nova. |
| listMessages(chatId) | Promise<ChatMessage[]> | Histórico de uma conversa. |
| reopen(chatId) | Promise<ChatSummary> | Reabre uma conversa arquivada. |
Eventos
client.on('message', (event: EmbedStreamEvent) => {})
client.on('session', (event: { type: 'bootstrapped' | 'refreshed' | 'expired' }) => {})
client.on('error', (event: { reason: string; message: string }) => {})Atributos
Dois tipos, declarados em config.attributes:
secure— nunca persistidos entre chamadas. Cada valor pode ser estático ou um callback (síncrono ou assíncrono); o callback é reavaliado a cada bootstrap/refresh de sessão, o que cobre renovação de token (ex. Keycloak) de forma transparente, sem você precisar gerenciar isso manualmente.attributes: { secure: { access_token: { format: 'bearer_token', value: () => keycloak.token! }, }, }formaté'bearer_token' | 'api_key' | 'string' | 'json'— descreve o tipo do valor que você está enviando; quem decide como esse valor é usado no destino (ex. prefixoBearer, nome do header) é configurado do lado do Autonomoss Studio, na tela de Integrações — não aqui.public— contexto não sensível (ex.{ cidade: 'Recife' }), enviado junto de cada bootstrap/refresh. Atualizável a qualquer momento viaclient.setAttributes({ public: {...} }), sem recriar a sessão.
Cookbook de erros
Toda falha de rede/API vira uma das classes abaixo (nunca uma exceção crua
do fetch):
| Classe | Quando |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| AutonomossConfigError | Erro de configuração/uso do SDK detectado no client antes de qualquer chamada de rede (ex. publishableKey vazio, callback de atributo que lançou). |
| AutonomossNetworkError | Falha de transporte — rede indisponível, CORS, DNS. Nunca chegou a uma resposta HTTP. |
| AutonomossApiError | Erro nomeado do contrato de embed. Tem .reason (string estável, ver tabela abaixo) e .status (HTTP). |
| AutonomossStreamError | O stream SSE caiu no meio de uma resposta. |
import { AutonomossApiError, isSessionExpiredError } from '@autonomoss/chat-core'
try {
await client.connect()
} catch (error) {
if (isSessionExpiredError(error)) {
// error.reason === 'token_expired' — o SDK já tenta um retry automático
// internamente antes de propagar; se chegou aqui, os dois tentaram e falharam.
} else if (error instanceof AutonomossApiError) {
console.error(error.reason, error.status)
}
}Se você não quer lidar com as classes diretamente, use normalizeFriendlyError
(o que @autonomoss/chat e @autonomoss/chat-react já fazem internamente)
para obter uma mensagem pronta para exibir ao usuário final, em pt-BR, sem
nunca vazar detalhes internos:
import { normalizeFriendlyError } from '@autonomoss/chat-core'
const { reason, message } = normalizeFriendlyError(error)
// reason: FriendlyErrorReason — inclui todos os ApiErrorReason do contrato
// + 'config_error' | 'insufficient_scope' | 'network_error' | 'server_error' | 'stream_interrupted'
// message: string já traduzida, segura para mostrar ao usuárioTelemetria (opt-in)
Desligada por padrão. Se habilitada, recebe somente estados e razões fechadas — nunca mensagem, anexo, atributo ou token:
telemetry: {
enabled: true,
onEvent: (event) => {
// { type: 'session', state: 'bootstrapped' | 'refreshed' | 'expired' }
// { type: 'message', state: 'started' | 'completed' }
// { type: 'error', reason: string }
},
}Segurança
- A
pk_é pública e pode ficar no frontend. O SDK nunca pedesk_. - Nada é persistido em
localStorage,sessionStorageou cookies — sessão e atributos seguros vivem só em memória, pelo tempo de vida da página. - Atributos seguros são resolvidos sob demanda a cada bootstrap/refresh e nunca cacheados entre chamadas.
- O contrato de tipos (
generated/api.d.ts) é gerado a partir decontract/openapi.yaml— nunca escrito à mão, para não haver deriva entre SDK e backend.
Browser / runtime
- Requer
fetch,AsyncGenerator/for await,ReadableStream(para SSE) eURL— presentes em todos os browsers modernos (últimas 2 versões de Chrome/Firefox/Safari/Edge) e em runtimes Node ≥ 20. - Sem dependência de DOM:
@autonomoss/chat-coreroda igualmente em Node (ex. testes, scripts) e no browser.
Troubleshooting
- CORS: o backend valida o
Originda requisição contra os domínios permitidos configurados no widget (tela de admin do Autonomoss Studio). Um erroorigin_not_allowednormalmente significa que o domínio atual não está na allowlist do widget. - Sessão expirando em loop: o SDK já tenta renovar a sessão uma vez
automaticamente em
token_expired(verwithSessionRefreshRetry); se isso persistir, o atributo seguro (ex. token Keycloak) provavelmente está expirado/inválido no callback — confira o que ele está retornando. - Streaming não chega: confirme que nada no caminho (proxy reverso,
CDN) está bufferizando a resposta SSE —
Content-Type: text/event-streamprecisa passar sem buffer.
Versionamento
Este pacote segue Changesets.
Mudanças entram via pnpm changeset na raiz do monorepo; o
CHANGELOG.md
é gerado a partir disso.
