> ## Documentation Index
> Fetch the complete documentation index at: https://docs.niadra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK de TypeScript

> Cada método da biblioteca @niadra/sdk, com parâmetros, retorno e exemplo.

`@niadra/sdk` é o SDK de TypeScript. Roda no Node 18 ou mais novo e em runtimes de borda, precisa só de `fetch` e vem em ESM e CommonJS, com as definições de tipo completas. É de código aberto, sob Apache 2.0. Cada método desta página corresponde a uma rota da [referência da API](/api).

## Instalação

```sh theme={null}
npm install @niadra/sdk
```

## O cliente

```typescript theme={null}
import { Niadra, handles } from "@niadra/sdk";

const niadra = new Niadra(); // reads NIADRA_API_KEY
```

```typescript theme={null}
new Niadra(options?: ClientOptions)
```

| Opção            | Tipo                               | Padrão                                      | Descrição                                                                                      |
| ---------------- | ---------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `apiKey`         | `string`                           | `NIADRA_API_KEY`                            | Uma chave de fonte, `nia_sk_<live\|test>_<region>_<space>_<key_id>_<secret>`.                  |
| `baseURL`        | `string`                           | `NIADRA_BASE_URL`, depois derivado da chave | A chave diz a região e o espaço, então o endereço é `https://<space>.<region>.api.niadra.com`. |
| `timeouts`       | `Partial<Timeouts>`                | veja abaixo                                 | O tempo máximo de cada método, em milissegundos.                                               |
| `cache`          | `Partial<CacheOptions>` ou `false` | veja abaixo                                 | O cache de contexto por conversa; `false` desliga.                                             |
| `queue`          | `Partial<QueueOptions>`            | veja abaixo                                 | O envio em lote de `track()` e `action()`.                                                     |
| `strict`         | `boolean`                          | `false`                                     | Lança erro em vez de registrar em log e resolver com resultado vazio. Use nos testes.          |
| `flushOnExit`    | `boolean`                          | `true`                                      | Esvazia a fila quando um processo Node fica sem trabalho.                                      |
| `fetch`          | `typeof fetch`                     | o `fetch` global                            | Uma implementação sua.                                                                         |
| `logger`         | `Logger`                           | `consoleLogger`                             | Qualquer objeto com `debug`, `warn` e `error`. `silentLogger` também é exportado.              |
| `defaultHeaders` | `Record<string, string>`           | `{}`                                        | Cabeçalhos extras em toda requisição à API.                                                    |

`enabled` é `false` quando o cliente foi criado sem chave utilizável; ele então não manda nada. Crie um cliente por processo e compartilhe: ele é dono da fila, do cache e das conexões.

### Seguro por padrão, estrito quando você pede

Por padrão, todo método segue em frente quando algo falha. As leituras resolvem com resultado vazio, `track()` devolve `null` para um item que não pôde aceitar, e o motivo vai para o log. Os logs levam status, código de erro e id da requisição, nunca handle, texto de mensagem nem a chave. Com `strict: true`, o construtor lança erros de configuração, `track()` lança erros de validação, as leituras lançam erros de requisição e `flush()` lança os lotes perdidos.

### Tempo máximo

```typescript theme={null}
const DEFAULT_TIMEOUTS = {
  context: 300,         // context(), every view except voice
  contextVoice: 150,    // context() with view: "voice"
  navigation: 600,      // search(), timeline(), open(), objectState(), objectTimeline()
  navigationVoice: 300, // navigation through voice conversations and voice-bound tools
  write: 5_000,         // each attempt of a batch, feedback() or an upload reservation
  token: 2_000,         // subjectToken()
  upload: 60_000,       // each attempt of an uploadMedia() transfer
};
```

Troque por cliente com `timeouts`, ou por chamada com `{ timeout }`. Passe `{ signal }` para cancelar uma chamada. As leituras só são repetidas no 421 (o espaço mudou de célula), na hora, até três tentativas. As escritas são repetidas no 408, 421, 429 e 5xx, com espera exponencial e variação aleatória; as outras respostas 4xx nunca são repetidas.

### O cache de contexto

Dentro de uma conversa ou tarefa, os contextos ficam em memória:

* com menos de 10 s: devolvidos sem requisição;
* até 10 minutos mais velhos: devolvidos na hora, enquanto uma requisição em segundo plano atualiza;
* quando uma requisição falha: o último contexto bom, se tiver menos de 30 minutos;
* no máximo 1.000 contextos, saindo primeiro o usado há mais tempo.

A atualização manda o ETag guardado, então um contexto que não mudou custa uma resposta `not_modified` em vez do texto inteiro, e só uma atualização por contexto roda de cada vez. Um 401 ou 403 não é indisponibilidade: os contextos guardados saem (todos no 401, o pedido no 403), então cortar o acesso de um fornecedor corta também o que ele tinha em cache. Uma leitura comum e uma leitura com `delta` da mesma conversa dividem a mesma entrada, e cada delta é entregue uma vez só.

```typescript theme={null}
new Niadra({ cache: { ttlMs: 10_000, staleWhileRevalidateMs: 600_000, maxStaleMs: 1_800_000, maxEntries: 1000 } });
```

### A fila de escrita

`track()` e `action()` voltam na hora. Os eventos saem em lote: quando 15 estão esperando ou a cada segundo, até 100 por requisição, com três tentativas cada. Com 10.000 eventos esperando, os novos são descartados e registrados no log.

```typescript theme={null}
new Niadra({ queue: { flushAt: 15, flushIntervalMs: 1000, maxBatchSize: 100, maxQueueSize: 10_000, maxAttempts: 3 } });
```

## Handles

Um handle identifica um sujeito num canal ou sistema. Os construtores definem o tipo e o escopo; o servidor normaliza o valor.

| Construtor                                                            | Handle                                             |
| --------------------------------------------------------------------- | -------------------------------------------------- |
| `handles.phone(e164)`                                                 | `phone_e164`                                       |
| `handles.email(address)`                                              | `email`                                            |
| `handles.waId(value)`, `handles.waJid(value)`, `handles.waLid(value)` | ids do WhatsApp                                    |
| `handles.waBsuid(value, businessAccount)`                             | `wa_bsuid`, com escopo da conta Business           |
| `handles.appUserId(value)`                                            | `app_user_id`                                      |
| `handles.systemId(value, system)`                                     | `system_id`, com escopo do sistema que emitiu o id |
| `handles.govIdHmac(value, country)`                                   | `gov_id_hmac`                                      |
| `handles.orgRegistryHmac(value, country)`                             | `org_registry_hmac`, uma organização               |
| `handles.emailDomain(domain)`                                         | `email_domain`, uma organização                    |
| `handles.anonId(value)`                                               | `anon_id`                                          |

Os construtores de pessoa aceitam `{ subjectKind }` opcional para marcar uma organização. `toObjectRef("invoice:erp:0823")` transforma a forma curta num `ObjectRef`; o id pode ter dois-pontos.

## context()

O contexto de uma pessoa, de uma organização ou de um objeto de negócio. Corresponde a [`POST /v1/context`](/api/context).

```typescript theme={null}
niadra.context(params: ContextParams, options?: ContextOptions): Promise<ContextResult>
```

| Parâmetro         | Tipo                    | Padrão   | Descrição                                                                          |
| ----------------- | ----------------------- | -------- | ---------------------------------------------------------------------------------- |
| `subject`         | `Handle`                | nenhum   | De quem é o contexto. Passe `subject` ou `object`, exatamente um.                  |
| `object`          | `ObjectRef` ou `string` | nenhum   | Centra o contexto num objeto de negócio, como `"invoice:erp:0823"`.                |
| `about`           | `Handle`                | nenhum   | A conta ou o parceiro em nome de quem a pessoa age. Exige vínculo ativo.           |
| `view`            | `View`                  | `"chat"` | `voice`, `chat`, `brief`, `full`, `custom`, `account`, `partner` ou `task:<nome>`. |
| `verification`    | `Verification`          | `"V0"`   | O que a conversa provou, de `V0` a `V4`, ou `no_customer`.                         |
| `conversation_id` | `string`                | nenhum   | Fixa o contexto e liga o cache.                                                    |
| `task_id`         | `string`                | nenhum   | O mesmo, para a tarefa de um agente interno.                                       |
| `query`           | `string`                | nenhum   | O assunto do turno, até 2.000 caracteres.                                          |
| `delta`           | `boolean`               | `false`  | Pede só o que mudou desde a última leitura desta fonte.                            |
| `target`          | `TargetModel`           | nenhum   | `{ provider, model }` do modelo que vai ler o contexto.                            |

`options` aceita `timeout`, `signal`, `headers` (como um `traceparent`) e `cache: false`, para pular o cache nesta chamada.

Resolve com um `ContextResult`, sempre utilizável:

| Campo       | Descrição                                                                                                                                 |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `text`      | O contexto, para o prompt de sistema. Vazio quando não há nada para injetar.                                                              |
| `suffix`    | O que muda a cada turno: o delta e os turnos ao vivo de outros canais. Vai no fim do prompt.                                              |
| `variables` | Valores nomeados do contexto, para templates.                                                                                             |
| `source`    | `network`, `cache`, `stale`, `fallback` ou `none`.                                                                                        |
| `response`  | A resposta da API que deu origem ao resultado, com `withheld`, `verification`, `etag`, `path` e o resto; `null` quando `source` é `none`. |
| `error`     | O que deu errado, quando `source` é `fallback` ou `none`.                                                                                 |

```typescript theme={null}
const ctx = await niadra.context({
  subject: handles.phone("+14155550123"),
  view: "voice",
  verification: "V1",
  conversation_id: "call-4471",
});

const system = `${AGENT_INSTRUCTIONS}\n\n${ctx.text}`;
const messages = [...history, { role: "user", content: `${ctx.suffix}\n\n${userTurn}` }];
```

`renderSuffix(response)` e `renderLive(response)` montam o mesmo sufixo a partir de uma resposta crua.

## search()

Busca no histórico inteiro de um sujeito, por palavra e por significado. Corresponde a [`POST /v1/history/search`](/api/history-search).

```typescript theme={null}
niadra.search(params: SearchRequest, options?: RequestOptions): Promise<Result<SearchResponse>>
```

| Parâmetro                    | Tipo             | Padrão      | Descrição                                                                      |
| ---------------------------- | ---------------- | ----------- | ------------------------------------------------------------------------------ |
| `subject`                    | `Handle`         | obrigatório | De quem é o histórico.                                                         |
| `query`                      | `string`         | obrigatório | Linguagem natural ou palavras, até 2.000 caracteres.                           |
| `about`                      | `Handle`         | nenhum      | A organização em nome de quem a pessoa age.                                    |
| `filters`                    | `HistoryFilters` | nenhum      | `since`, `until`, `channels`, `categories`, `item_kinds`, `outcome`, `object`. |
| `max_tokens`                 | `number`         | `800`       | Orçamento da resposta, de 50 a 4.000. Use 300 na voz.                          |
| `verification`               | `Verification`   | `"V0"`      | O mesmo nível do contexto.                                                     |
| `conversation_id`, `task_id` | `string`         | nenhum      | Quem pergunta.                                                                 |

Toda chamada de navegação resolve com um `Result`: `{ data, error }`, com exatamente um dos dois preenchido. `data` traz `items`, `recurrence`, `withheld`, `as_of`, `tokens_used` e `degraded`.

```typescript theme={null}
const { data, error } = await niadra.search({
  subject: handles.phone("+14155550123"),
  query: "credit for missed technician visit",
  max_tokens: 300,
});
if (data?.recurrence) console.log(data.recurrence.occurrences, data.recurrence.last_resolution);
```

## timeline()

Uma página do histórico do sujeito, do mais recente para o mais antigo. Corresponde a [`POST /v1/history/timeline`](/api/history-timeline).

```typescript theme={null}
niadra.timeline(params: TimelineRequest, options?: RequestOptions): Promise<Result<TimelineResponse>>
```

Recebe `subject`, `about`, `filters`, `cursor`, `limit` (de 1 a 100, padrão 20), `verification` e `conversation_id`. `data` traz `items`, `next_cursor`, `withheld` e `as_of`.

```typescript theme={null}
const { data: page } = await niadra.timeline({ subject: handles.phone("+14155550123"), limit: 20 });
```

## open()

Abre um item do histórico vindo de `search()` ou `timeline()`. Corresponde a [`GET /v1/history/items/{item_id}`](/api/history-item).

```typescript theme={null}
niadra.open(id: string, params?: OpenParams, options?: RequestOptions): Promise<Result<OpenedItem>>
```

`params` aceita `verification`, `conversation_id` e `task_id`. O trecho literal, `excerpt`, só volta para chaves com escopo elevado.

```typescript theme={null}
const { data: item } = await niadra.open("ep_01J2", { conversation_id: "call-4471" });
```

## objectState() e objectTimeline()

Leituras de um objeto de negócio. Correspondem a [`GET /v1/objects/{object_type}/{namespace}/{external_id}`](/api/object) e à [linha do tempo](/api/object-timeline) dele.

```typescript theme={null}
niadra.objectState(object: ObjectRef | string, options?: RequestOptions): Promise<Result<ObjectState>>
niadra.objectTimeline(
  object: ObjectRef | string,
  params?: { cursor?: string; limit?: number },
  options?: RequestOptions,
): Promise<Result<ObjectTimeline>>
```

O estado vem só do que os sistemas de registro informaram; a ação de um agente conta quando um sistema a confirma. A linha do tempo lista eventos de sistema e ações de agente, do mais recente para o mais antigo, nunca o que alguém disse. Ids de objeto são ids de registro, não dado pessoal, então vão na URL; um id com barra não pode ser endereçado assim. `limit` vai de 1 a 100, padrão 20.

```typescript theme={null}
const { data: invoice } = await niadra.objectState("invoice:erp:0823");
const { data: page } = await niadra.objectTimeline("invoice:erp:0823", { limit: 20 });
```

## track()

Registra uma mensagem, um evento de sistema ou uma ação. Volta na hora com a chave de idempotência do item, ou `null` quando o item foi descartado. Corresponde a [`POST /v1/batch`](/api/batch).

```typescript theme={null}
niadra.track(event: TrackEvent): string | null
```

| Campo                                | Tipo                      | Descrição                                                                                               |
| ------------------------------------ | ------------------------- | ------------------------------------------------------------------------------------------------------- |
| `channel`                            | `string`                  | Onde aconteceu: `whatsapp`, `voice`, `app`, `erp`. Obrigatório.                                         |
| `speaker`                            | `Speaker` ou `SpeakerRef` | `customer`, `ai_agent`, `human_agent` ou `system`; o papel sozinho vale por `{ role }`. Obrigatório.    |
| `kind`                               | `EventKind`               | `message` (padrão), `system_event` ou `action`.                                                         |
| `text`                               | `string`                  | Forma curta de `content: { type: "text", text }`.                                                       |
| `content`                            | `Content`                 | Texto, transcrição ou referência de mídia.                                                              |
| `idempotency_key`                    | `string`                  | O id da mensagem no provedor. Um UUIDv7 é criado quando você não passa.                                 |
| `conversation_id`, `task_id`         | `string`                  | A conversa ou a tarefa.                                                                                 |
| `handles`, `subjects`, `object_refs` | listas                    | De quem e do que o evento trata. Pelo menos um é obrigatório. `object_refs` aceita `type:namespace:id`. |
| `canonical_type`, `fields`           | `string`, objeto          | Obrigatório em evento de sistema, como `invoice.credited`.                                              |
| `action`                             | `ActionInfo`              | Obrigatório com `kind: "action"`, e só vale nele.                                                       |
| `occurred_at`                        | `string` ou `Date`        | Agora, por padrão.                                                                                      |
| `context_stamp`                      | `ContextStamp`            | Qual contexto estava no prompt do agente. Conversas e tarefas preenchem depois de `markInjected()`.     |

```typescript theme={null}
niadra.track({
  channel: "whatsapp",
  conversation_id: "wa-8812",
  idempotency_key: "wamid.HBgLMTQxNTU1NTAxMjMVAgASGBQzQUQ",
  handles: [handles.phone("+14155550123")],
  speaker: "customer",
  text: "The technician never showed up. I am calling you.",
});
```

## action()

Registra o que um agente fez num sistema de registro. Vai para a fila, como `track()`; registrar ação exige o escopo `act`.

```typescript theme={null}
niadra.action(event: ActionEvent): string | null
```

`ActionEvent` aceita os mesmos campos de `track()` e mais `operation` (obrigatório, como `credit`), `result` (até 2.000 caracteres), `purpose`, `closes` (a pendência que a ação cumpre, por `item_id` ou por `object` e `operation`) e `corrects_action_id`. `speaker` é `ai_agent` por padrão. A ação fica `declared` até o sistema de registro confirmar.

```typescript theme={null}
niadra.action({
  channel: "erp",
  task_id: "billing-7741",
  handles: [handles.systemId("48213", "crm")],
  object_refs: ["invoice:erp:0823"],
  operation: "credit",
  result: "$40 credit on the August bill",
  closes: { object: { type: "invoice", namespace: "erp", id: "0823" }, operation: "dispute" },
});
```

## identify(), verify() e handoff()

Esses três saem na hora, sem fila, e resolvem com um `WriteResult`: `{ ok: true, idempotency_key, error: null }` ou `{ ok: false, idempotency_key, error }`. Um `context()` feito depois que `identify()` ou `verify()` resolveu já enxerga a mudança.

```typescript theme={null}
niadra.identify(params: IdentifyParams): Promise<WriteResult>
niadra.verify(params: VerifyParams): Promise<WriteResult>
niadra.handoff(params: HandoffParams): Promise<WriteResult>
```

| Método     | Parâmetros                                                                                                                                                    |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `identify` | `handles` (de 2 a 16), `method` (padrão `explicit_identify`), `subject_kind` (padrão `person`), `conversation_id`.                                            |
| `verify`   | `handle`, `method` (`otp_whatsapp`, `otp_sms`, `login`, `kba`, `network_attestation`, `human_agent`), `level`, `conversation_id` ou `task_id`, `valid_until`. |
| `handoff`  | `conversation_id`, `target` (`human` ou `agent`), `target_source`, `reason`, `mode` (`warm`, o padrão, ou `cold`).                                            |

Um nível em `verify()` acima do teto da fonte falha com `verification_not_allowed`.

```typescript theme={null}
await niadra.verify({
  handle: handles.phone("+14155550123"),
  method: "otp_whatsapp",
  level: "V3",
  conversation_id: "wa-8812",
});
```

## feedback()

Corrige o que a Niadra derivou sobre um sujeito. Sai na hora e vira evento, então é auditado como qualquer outro. Corresponde a [`POST /v1/feedback`](/api/feedback).

```typescript theme={null}
niadra.feedback(params: FeedbackParams): Promise<WriteResult>
```

| `action`               | Exige                                   |
| ---------------------- | --------------------------------------- |
| `retract_fact`         | `fact_id`. O fato sai de todo contexto. |
| `correct_fact`         | `fact_id` e `value`, o valor certo.     |
| `resolve_open_item`    | `open_item_id`.                         |
| `conversation_outcome` | `conversation_id` e `value`.            |

`subject` é sempre obrigatório; `value` vai até 2.000 caracteres e `reason` até 500.

```typescript theme={null}
await niadra.feedback({
  subject: handles.phone("+14155550123"),
  action: "resolve_open_item",
  open_item_id: "oi_01J8ZK",
  reason: "Visit rescheduled",
});
```

## uploadMedia()

Entrega um arquivo à Niadra, como a gravação de uma ligação, e resolve com a referência para o evento. Mídia nunca viaja dentro do evento. Corresponde a [`POST /v1/media/uploads`](/api/media-uploads).

```typescript theme={null}
niadra.uploadMedia(
  params: { data: Uint8Array | ArrayBuffer | Blob; content_type: string; subject?: Handle },
  options?: { signal?: AbortSignal },
): Promise<Result<MediaUpload>>
```

O método calcula o hash dos bytes com Web Crypto, reserva o upload e manda os bytes direto para o armazenamento pela URL assinada. Ele envia exatamente os `upload_headers` que a API devolveu, que são os cabeçalhos cobertos pela assinatura, e nada além: nunca a sua chave nem os `defaultHeaders`. A URL precisa ser HTTPS, a não ser contra um endpoint local servido por HTTP. O armazenamento confere o corpo contra o tamanho e o hash declarados. Com `subject`, o arquivo fica guardado sob aquela pessoa, então apagar a pessoa apaga o arquivo, mesmo que nenhum evento o cite. No Node 18, Web Crypto só existe atrás de uma flag.

`data` traz `media_ref`, `media_sha256`, `content_type`, `size_bytes` e `expires_at`.

```typescript theme={null}
const { data: upload } = await niadra.uploadMedia({
  data: recording,
  content_type: "audio/wav",
  subject: handles.phone("+14155550123"),
});
if (upload) {
  niadra.track({
    channel: "voice",
    conversation_id: "call-4471",
    handles: [handles.phone("+14155550123")],
    speaker: "customer",
    content: { type: "audio", media_ref: upload.media_ref, media_sha256: upload.media_sha256, transcript },
  });
}
```

## conversation()

Um ajudante para a conversa com um cliente: lê o contexto que o servidor fixa, guarda os deltas, captura os turnos e encerra a conversa.

```typescript theme={null}
niadra.conversation(params: ConversationParams): Conversation
```

| Parâmetro         | Tipo                    | Padrão                                     | Descrição                   |
| ----------------- | ----------------------- | ------------------------------------------ | --------------------------- |
| `subject`         | `Handle`                | obrigatório                                | O cliente.                  |
| `channel`         | `string`                | obrigatório                                | Como `whatsapp` ou `voice`. |
| `conversation_id` | `string`                | um UUIDv7                                  | O seu id da conversa.       |
| `view`            | `View`                  | `voice` no canal de voz, `chat` nos outros | A view do contexto.         |
| `verification`    | `Verification`          | `"V0"`                                     | O nível já provado.         |
| `about`, `target` | `Handle`, `TargetModel` | nenhum                                     | Como em `context()`.        |

| Membro                                                                       | Descrição                                                                                                     |
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `context(options?)`                                                          | O `text` fixado, mais um `suffix` com cada delta recebido desde a fixação e os turnos ao vivo do momento.     |
| `markInjected(context?, at?)`                                                | Registra que o contexto entrou no prompt; os próximos turnos e ações do agente levam isso em `context_stamp`. |
| `customer(text, options?)`, `agent(text, options?)`, `human(text, options?)` | Registram um turno. `agent()` leva o carimbo.                                                                 |
| `track(event)`, `action(event)`                                              | Como no cliente, com a conversa amarrada.                                                                     |
| `verify({ method, level, handle? })`                                         | Eleva o nível e passa a ler no nível novo.                                                                    |
| `handoff({ target, target_source?, reason?, mode? })`                        | Registra uma transferência.                                                                                   |
| `tools()`                                                                    | O kit do histórico amarrado a este cliente e a esta conversa.                                                 |
| `end()`                                                                      | Emite `conversation.ended`.                                                                                   |
| `verification`, `timings`, `contextStamp`, `lastContext`                     | O nível atual, a primeira injeção e o primeiro turno do agente, o último carimbo, o último resultado.         |

Depois do primeiro contexto, cada leitura pede também o delta, e a conversa guarda cada delta que chega, em ordem, no `suffix`, antes dos turnos ao vivo. Quando o servidor fixa um contexto novo, depois de `verify()` por exemplo, os deltas guardados saem: o contexto novo já os contém. Uma leitura com `query` é avulsa e não mexe neles. Chame `markInjected()` toda vez que puser o contexto num prompt: é assim que a Niadra distingue um contexto que chegou depois de o agente falar de um contexto que o agente tinha e não usou.

```typescript theme={null}
const conv = niadra.conversation({
  subject: handles.phone("+14155550123"),
  channel: "whatsapp",
  conversation_id: "wa-8812",
});

conv.customer("The technician never showed up. I am calling you.", { idempotency_key: "wamid.001" });
const ctx = await conv.context();
conv.markInjected(ctx);
conv.agent(await callModel(ctx.text, history, ctx.suffix));
await conv.verify({ method: "otp_whatsapp", level: "V3" });
await conv.handoff({ target: "human", reason: "asked for a person" });
await conv.end();
```

## task()

O mesmo para um agente interno (cobrança, recuperação de crédito, triagem). Uma tarefa centra o contexto no objeto dela, guarda deltas e carimbos como uma conversa, delimita o cache e termina com `task.ended`.

```typescript theme={null}
niadra.task(params: TaskParams): Task
```

`TaskParams` aceita `channel` (obrigatório, o agente interno ou o sistema, como `billing-agent`), `task_id` (um UUIDv7 quando não vem), `subject`, `object`, `about`, `view` (padrão `brief`; use uma view de tarefa como `task:billing`), `verification` e `target`. Uma tarefa tem `context()`, `markInjected()`, `agent()`, `track()`, `action()`, `verify()`, `tools()` (`null` sem sujeito) e `end()`.

```typescript theme={null}
const task = niadra.task({
  channel: "erp",
  task_id: "billing-7741",
  object: "invoice:erp:0823",
  view: "task:billing",
  verification: "no_customer",
});
const ctx = await task.context();
task.markInjected(ctx);
task.action({
  operation: "credit",
  result: "$40 credit on the August bill",
  closes: { object: { type: "invoice", namespace: "erp", id: "0823" }, operation: "dispute" },
});
await task.end();
```

## tools()

O kit de navegação como ferramentas de chamada de função, com o cliente amarrado no SDK e não nos argumentos da ferramenta. O modelo escolhe o que procurar, nunca de quem, então uma injeção de prompt não tem argumento para trocar de cliente.

```typescript theme={null}
niadra.tools(subject: Handle, binding?: ToolBinding): BoundTools
```

`binding` aceita `about`, `verification`, `conversation_id`, `task_id` e `voice` (usa o tempo máximo da voz).

| Membro             | Descrição                                                                                                                                                                                                                                  |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `definitions`      | `search_customer_history`, `get_customer_timeline` e `open_history_item`, no formato `{ type: "function", function: { name, description, parameters } }`.                                                                                  |
| `has(name)`        | Se `name` é uma dessas ferramentas.                                                                                                                                                                                                        |
| `call(name, args)` | Executa uma chamada de ferramenta e resolve com o texto para o modelo. `args` pode ser a string JSON que a maioria das APIs de modelo devolve. As falhas voltam como um erro JSON curto que o modelo consegue ler, ou lançam com `strict`. |

`TOOL_DEFINITIONS` e `TOOL_NAMES` também são exportados. Para APIs que esperam `{ name, description, input_schema }`, leve `function.parameters` para `input_schema`. As definições também saem em [`GET /v1/history/tools`](/api/history-tools).

```typescript theme={null}
const kit = niadra.tools(handles.phone("+14155550123"), { conversation_id: "call-4471" });
const response = await openai.chat.completions.create({ model, messages, tools: kit.definitions });
for (const call of response.choices[0].message.tool_calls ?? []) {
  if (kit.has(call.function.name)) {
    messages.push({ role: "tool", tool_call_id: call.id, content: await kit.call(call.function.name, call.function.arguments) });
  }
}
```

## subjectToken()

Emite um token assinado, válido por 15 minutos, que amarra um cliente, uma conversa e um nível de verificação. Chame do seu backend e entregue à conexão MCP. Corresponde a [`POST /v1/subject-tokens`](/api/subject-tokens).

```typescript theme={null}
niadra.subjectToken(params: SubjectTokenRequest, options?: RequestOptions): Promise<Result<SubjectToken>>
```

`params` aceita `subject`, `about`, `conversation_id`, `task_id` e `verification`. `data` traz `token` e `expires_at`. Mande o token no cabeçalho `Niadra-Subject-Token`, junto da chave da fonte. Veja [MCP com qualquer LLM](/guides/mcp).

```typescript theme={null}
const { data: token } = await niadra.subjectToken({
  subject: handles.phone("+14155550123"),
  conversation_id: "call-4471",
  verification: "V1",
});
```

## wrap()

Embrulha um cliente compatível com a OpenAI para toda chamada receber o contexto e registrar a resposta.

```typescript theme={null}
wrap<C extends object>(client: C, session: WrapSession | (() => WrapSession | null | undefined)): C
```

Toda chamada a `chat.completions.create` e `chat.completions.parse` pelo embrulho, com streaming ou sem, recebe o contexto depois das suas mensagens de sistema iniciais e o sufixo no fim. A injeção é carimbada, e a resposta do modelo (a primeira escolha) é registrada como turno do agente: na hora, ou quando o stream termina ou você para de ler. `.withResponse()` continua funcionando e também registra; `.asResponse()` devolve a resposta HTTP crua, então nada é registrado nesse caso. Passe uma função em vez de uma sessão para escolher uma a cada chamada; quando ela devolve `null`, a chamada passa intacta. Nada do que o embrulho faz derruba a sua chamada: um contexto que não chega fica de fora, e uma falha ao registrar a resposta vai para o log, sem conteúdo. `injectContext(context, messages)` faz só o posicionamento, sem embrulhar.

```typescript theme={null}
import OpenAI from "openai";
import { wrap } from "@niadra/sdk";

const openai = wrap(new OpenAI(), conv);
const completion = await openai.chat.completions.create({ model: "gpt-4.1", messages });
```

## flush() e shutdown()

```typescript theme={null}
niadra.flush(): Promise<void>
niadra.shutdown(): Promise<void>
```

`flush()` manda todo evento da fila. Chame antes de uma função serverless retornar, ou entregue à plataforma nos runtimes de borda (`ctx.waitUntil(niadra.flush())`). `shutdown()` esvazia a fila, para o temporizador de fundo e libera o gancho de saída; chame no seu tratador de SIGTERM em serviços de longa duração, porque `beforeExit` não dispara com sinais nem com `process.exit()`.

## Erros

Todo erro estende `NiadraError`.

| Classe                      | Quando                                                                            |
| --------------------------- | --------------------------------------------------------------------------------- |
| `NiadraConfigError`         | Sem chave utilizável, ou uma opção que o SDK não consegue atender.                |
| `NiadraValidationError`     | A requisição falhou na validação antes de sair do processo. Nada foi enviado.     |
| `NiadraTimeoutError`        | A chamada estourou o tempo máximo; `timeoutMs` diz qual.                          |
| `NiadraConnectionError`     | A chamada de rede falhou antes de uma resposta HTTP: DNS, TLS, conexão derrubada. |
| `NiadraAbortError`          | Cancelada pelo seu `AbortSignal`.                                                 |
| `NiadraAPIError`            | Um status de erro, com `status`, `code`, `requestId` e `problem`.                 |
| `NiadraAuthenticationError` | 401.                                                                              |
| `NiadraPermissionError`     | 403.                                                                              |
| `NiadraRateLimitError`      | 429, com `retryAfterMs`.                                                          |

O catálogo completo de códigos está em [Erros](/errors). Mande o `requestId` quando falar com o suporte.

## Próximos passos

<CardGroup cols={2}>
  <Card title="SDK de Python" href="/sdk/python">
    A mesma superfície, síncrona e assíncrona.
  </Card>

  <Card title="Início rápido" href="/quickstart">
    Da chave ao primeiro contexto entregue.
  </Card>

  <Card title="MCP com qualquer LLM" href="/guides/mcp">
    Sete ferramentas com o cliente amarrado por subject\_token.
  </Card>

  <Card title="Erros" href="/errors">
    O catálogo de códigos e o que fazer com cada um.
  </Card>
</CardGroup>
