SDK JavaScript e TypeScript para código que roda dentro de uma Server Function da Mitra: dados do app, outras Functions, queries, integrações, agentes e notificações, sempre no escopo do app da Function. Para app de browser, use @mitralab.io/platform-sdk.
npm install @mitralab.io/functions-sdkNo runtime de Server Functions da Mitra o pacote já vem instalado; instale no projeto para ter os tipos ou para rodar fora do runtime. Node 18 ou mais novo, ou outro runtime com fetch global.
const { createClient } = require("@mitralab.io/functions-sdk")
exports.handler = async (event, context) => {
const mitra = createClient()
const order = await mitra.entities.Order.get(event.orderId)
const { data: items } = await mitra.entities.OrderItem.filter({ order_id: event.orderId })
return { order, items }
}Dentro do runtime, createClient() lê a URL, o token e o app das variáveis de ambiente que a Mitra injeta, então não precisa de argumento.
Fora do runtime, num processo seu, autentique com uma API key criada em Configurações, API keys. createClientFromApiKey() lê MITRA_API_URL, MITRA_APP_ID e MITRA_API_KEY e já troca a chave por um token, para uma chave errada falhar ali:
const { createClientFromApiKey } = require("@mitralab.io/functions-sdk")
async function loadOrder(orderId) {
const mitra = await createClientFromApiKey()
return mitra.entities.Order.get(orderId)
}entities.<Tabela>:list,filter,get,create,bulkCreate,update,deleteedeleteManynas tabelas do app.queries,customQueries,sqleschema: queries salvas, SQL parametrizado e estrutura das tabelas.functions,publicFunctionseworkflows: chamar outras Server Functions e workflows do app.integration.executeByAlias(alias, request): chama uma API externa configurada no app, com a credencial guardada na Mitra.messenger.notify(texto): manda uma notificação ao usuário autenticado.agentTasks.session(...): chat com agente, com envio durante a resposta, a fila do T3, subagentes e o histórico ao vivo. Veja Sessão de agente.aiProviders.get(): consulta os provedores e a quota de Included AI pelo Copilot, com o token e o app da Function. O retorno tipadoAiProvidersincluimanagedAiProfilequando o servidor ofereceIMMERSION,nullquando inelegível e pode omitir o campo em servidores anteriores. A consulta não cria chave, não retorna segredo e não muda preferências; o perfil gerenciado é independente da disponibilidade de Included AI.currentApp: definição, arquivos, build e publicação do app da Function.functionsAdmin,integrationAdmin,agents,agentConnections,agentCredentials,importsedataSources: administração dos recursos do app.agentCredentials.providers(agentId?)devolve numa chamada só os provedores em que o próximo turno pode rodar, com modelos e a última leitura da assinatura.
A sessão vem do @mitralab.io/sdk-core e segue o T3, o harness que roda o agente. A box é o ambiente isolado onde o agente e o T3 rodam, um por chat, e é a fonte da verdade da conversa. A sessão não guarda fila própria: queue, subagents e backgroundTasks são o que a box informou por último.
const { createClient } = require("@mitralab.io/functions-sdk")
exports.handler = async (event, context) => {
const mitra = createClient()
const session = mitra.agentTasks.session({ taskId: event.taskId })
try {
const result = await session.sendAndWait(event.prompt, { timeoutMs: 120000 })
return { answer: result.content }
} finally {
session.close()
}
}Function que só dispara o prompt usa send e espera o evento accepted antes de chamar session.close() e retornar; antes dele, o prompt pode se perder.
send(prompt, options?)manda na hora e devolve oclientMessageIdda mensagem, ouundefinedpara texto em branco, que não sai. Sem turno rodando, a mensagem abre um turno. Com turno rodando e semmode, o T3 decide como no composer dele: entra no turno em andamento quando o provedor aceita steer, ou espera na fila do T3.mode: "steer"pede o turno em andamento (o T3 recusa enquanto ele ainda não está rodando) emode: "queue"pede a fila. Quando a mensagem vai pelo Copilot (socket reconectando ou chat sem canal direto), ela leva o mesmomode, e semmodeo Copilot faz steer.sendAndWaitaceita as mesmas opções e resolve com o turno que respondeu a mensagem. Se a sessão fecha com a mensagem ainda sem sair, ela vai ao Copilot uma vez, com o mesmomode, e osendAndWaitdela é rejeitado com a sessão fechada.queueé a fila do T3 como a box informa, de qualquer cliente do chat, comid(oclientMessageId),text,positionequeueHeld; o eventoqueueChangeavisa quando ela muda.steerQueueItem(id)leva um item para o turno em andamento,editQueueItem(id, text),removeQueueItem(id)eclearQueue()mexem na fila, eresumeQueue()retoma a fila que o Stop segurou. A fila muda quando a box responde, não antes.- Quando o T3 coloca a mensagem no turno em andamento, sai o evento
steered, comtextemessageId, sem turno novo; oturnEnddaquele turno responde a ela. backgroundTasksé o trabalho que o provedor mantém em segundo plano (comando, Monitor ou subagente), como a box informou por último, com o eventobackgroundTasks. É estado, não histórico.subagentsguarda o último estado de cada subagente, com os eventossubagent,subagentDeltaesubagentTool.stopSubagent(subagentId)para só ele e deixa o turno seguir.- Os comandos da fila e o
stopSubagentvão só pelo canal da box: com ele fora, sai um eventoerrore nada é enviado. historycresce ao vivo enquanto o turno roda, uma peça por item na ordem da box, e é o mesmo que volta ao recarregar o chat. A pergunta entra no ponto em que a box a pegou; até lá ela está emqueue. Os kinds que já existiam mantêm o formato da 0.2.13, com a chamada e o resultado de uma ferramenta em dois itenstool. A 0.3.0 soma os kindsreasoning,approvaleuserInputRequest, e o texto de subagente como itemagentcomparentToolId: quem filtra o histórico por kind precisa tratar os novos. A 0.3.3 soma o kindnotification(CoreAgentTimelineItemcomkind: "notification"): o fim de um trabalho em segundo plano, como o T3 o reporta, compayloadno lugar detext(source,outcome,summaryedetail). Também chega como eventonotification; desde a 0.3.4 o item traz tambémsource,outcome,summaryedetailsoltos, iguais aos do evento. Quem lêitem.textnum ramo genérico precisa tratar esse kind.loadOlder()lê a página anterior à linha mais antiga dehistory, com o tamanho queloadHistoryusou, e põe antes dela, emitindohistoryLoaded.hasOlderdiz se a última página lida tinha mais. Precisa do Copilot com mitra-copilot#549.
Os tipos AgentQueueItem, AgentBackgroundTask, AgentSubagent, AgentSubagentFrame e AgentSendOptions saem deste pacote. O comportamento completo, com reconexão e replay, está no README do Core.
createClient(config?) usa o campo de config e, quando ele falta, a variável de ambiente. Em teste, createClientFromEnvironment(env) lê só do objeto que você passar.
| Campo | Variável | Obrigatório | Uso |
|---|---|---|---|
apiUrl |
MITRA_API_URL ou MITRA_BASE_URL |
sim | URL HTTP ou HTTPS do API gateway da Mitra, sem credencial, query ou fragmento |
accessToken |
MITRA_PLATFORM_ACCESS_TOKEN ou MITRA_TOKEN |
sim, exceto com API key | token do runtime, enviado como Bearer |
appId |
MITRA_APP_ID ou MITRA_PROJECT_ID |
sim | app em que o cliente atua |
apiKey |
MITRA_API_KEY |
só em createClientFromApiKey |
chave do app, para processo fora do runtime |
timeoutMs |
não | prazo por requisição; sem ele, o SDK não impõe prazo, e dentro de uma Function vale o limite de tempo dela | |
fetch |
não | implementação de fetch; sem ela, usa a global |
|
WebSocket |
não | implementação de WebSocket, como a do pacote ws, para a sessão de agente usar socket; sem ela, vale o WebSocket global, se houver, ou HTTP |
MitraApiError traz status, code, details, requestId, retryable e retryAfterSeconds. O token não aparece na mensagem nem nos detalhes. retryAfterSeconds é quanto o servidor pediu para esperar, lido de retry_after_seconds no corpo ou do header Retry-After em segundos; sem valor inteiro válido, fica vazio.
| Erro | Quando | O que fazer |
|---|---|---|
MitraConfigurationError |
configuração ausente ou inválida, ou apps usado com outro app |
confira variáveis e argumentos; para o próprio app, use currentApp |
MitraApiError 401 ou 403 |
o token não dá acesso ao recurso | confira as permissões do app; nem todo módulo está liberado para o token do runtime |
MitraApiError 429 ou 5xx |
limite de requisições ou falha no servidor | repita só se a operação puder ser repetida; espere retryAfterSeconds, se vier |
REQUEST_TIMEOUT, NETWORK_ERROR |
prazo estourado ou falha de rede, com status 0 |
aumente timeoutMs ou repita, se a operação permitir |
INVALID_CREDENTIALS, AUTHENTICATION_FAILED |
a troca da API key falhou | confira a chave e o appId |
INVALID_RESPONSE |
resposta fora do formato esperado | atualize o SDK; se continuar, abra uma issue |
AgentTaskTurnError |
o turno do agente foi recusado ou terminou com erro | leia o code e decida se manda de novo |
- Crie o cliente dentro do handler. O token do runtime vale para aquela execução e dura pouco.
- O SDK faz uma tentativa por requisição e não repete, para não gravar duas vezes.
retryableé só uma dica. O cliente por API key é a exceção: num401, ele pega um token novo e repete aquela requisição uma vez. - Para o app da Function, use
currentApp.appssó aceita o próprio app, eapps.list()eapps.create()não existem aqui. - Function que só dispara um prompt para um agente pode retornar depois do evento
accepted. Antes dele, o prompt pode se perder. cancel()chamado enquanto o prompt ainda está a caminho espera a box aceitar a mensagem e só então interrompe o turno; aguarde a promessa dele antes de dar o chat por parado. Se a box recusar a mensagem, nenhum stop sai e o eventocancellednão é emitido, então o stop não interrompe um turno seguinte.- API key fica em variável de ambiente de processo de servidor, nunca em código de browser nem no repositório.
Os exports do SDK legado continuam neste pacote, marcados @deprecated, para código de Function existente trocar a dependência sem reescrever os imports. createClient() configura o legado com o mesmo token e o mesmo app. Os tipos do Core que têm nome igual a um tipo legado saem com prefixo Core, como CoreAgentConnection.
Esta atualização fixa @mitralab.io/sdk-core em 0.3.8, já publicado, para oferecer aiProviders.get() tipado. A versão própria do Functions não muda neste trabalho. O Core também remove APIs públicas de administração de e-mail e login, conforme mitra-core-sdk#135, e o Functions herda essas quebras:
- Templates de e-mail: saem de
messengeros métodoslistEmailTemplates,getEmailTemplateType,getEmailTemplate,upsertEmailTemplate,previewEmailTemplateedeleteEmailTemplate. - Remetentes e configurações: saem
listEmailSenders,registerEmailSender,resendEmailSenderVerification,confirmEmailSender,getEmailSettingseupdateEmailSettings. - Tipos de e-mail: deixam de ser exportados
EmailTemplate,EmailTemplateInput,EmailTemplatePreview,EmailTemplateType,EmailTemplateTypeCatalog,EmailTemplateUpsertResult,EmailTemplateVariable,EmailSender,EmailSenderInput,EmailSettings,EmailSettingsInputeEffectiveEmailSender. - Login do app:
emailLoginEnabledepasswordLoginEnabledsaem deAppUpdateInput, usado porapps.update()ecurrentApp.update(), e deAppDefinitioneAppSummary. O servidor pode continuar retornando esses campos, mas o SDK não os tipa nem valida.allowSignupcontinua disponível.
Antes de atualizar, migre as chamadas administrativas de e-mail para as rotas REST do Messenger e a configuração de login para as do Code Studio. Nos apps do editor Infusion, essas chamadas usam o token de sessão obtido no login (allTokens), conforme o PR do Core. Não substitua esse token pelo token da Function: a autorização de cada rota continua sendo a do serviço. Remova os imports dos tipos retirados e use os contratos das rotas REST na integração administrativa. messenger.notify() e messenger.sendEmail() continuam no SDK para o backend do app.
Se você também usa o Core diretamente, troque createMessengerModule(transport, errors, getAppId) por createMessengerModule(transport, errors). Essa factory não é exportada pelo Functions, que usa createSdkCore; os argumentos de createClient, createClientFromEnvironment e createClientFromApiKey não mudam.
npm ci
npm run checkO check roda format, lint, typecheck, testes, build, a conferência dos exports e do contrato com o Core, e um smoke test do pacote. A publicação no npm sai do workflow Release.