Ligar
Os registros de turno são a funcionalidadeturns do espaço, desligada por padrão, ligada no documento features por um diff aprovado do papel security. Com ela desligada, POST /v1/turns e as rotas de replay respondem 404, e os SDKs não gravam nada, mesmo com a captura ligada no código. O documento recording, do papel integration, diz o modo de conteúdo do espaço e de cada fonte, os pinos exigidos, quanto tempo a camada guardada mantém um turno (kept_days, 30 por padrão, de 7 a 90), quanto tempo um cenário de replay guarda os turnos dele (scenario_days, 180 por padrão), se o modelo de dado pessoal passa nos registros guardados (pii_model) e a fração das conversas guardadas inteiras por amostra (sample_rate, 5% por padrão). Mudar o modo de conteúdo para um que guarda mais pede também o papel security.
O que é um turno
Um turno vai da entrada dele até a última coisa que emitiu à pessoa ou a um documento. A entrada pode ser uma mensagem (kind: message), uma ação de interface, como um toque num item ou num “ver mais” (action), um evento de sistema (event) ou um temporizador que disparou (timer). Uma ação de interface é um turno por si, mesmo sem chamada de modelo. Um subagente, ou um agente chamado como ferramenta, abre um subturno, com turn_id próprio e o turno que o abriu em agent.parent_turn_id.
Capturar
O SDK captura no processo do agente, no momento em que cada coisa acontece, por cópia: os argumentos e o resultado de uma ferramenta são copiados como JSON quando a chamada volta, o que custa a um resultado de 25 KB 0,05 ms no percentil 95; o digest é calculado depois, no envio. Quando um resultado existe em duas formas, as duas são gravadas: a que o modelo viu (result_model) e a que a interface recebeu (result_ui). Um gerador é gravado depois de consumido por inteiro. A captura nunca atrasa a resposta: o envio acontece depois e à parte do turno, e uma falha na gravação marca o registro completeness: incomplete sem tocar no agente.
turn_id é criado quando o turno começa e segue o turno através de tarefas assíncronas e sessões filhas, então toda chamada feita em nome dele cai no mesmo registro; em Python, um framework que roda ferramentas num pool de threads usa niadra.turns.bind(fn), e em TypeScript o turno em andamento segue o AsyncLocalStorage. Os adaptadores de framework abrem e fecham o turno por você com turns=True (turns: true): Google ADK, OpenAI Agents, LangGraph e LangChain em Python; LangChain e LangGraph, Mastra, o Vercel AI SDK, OpenAI Agents JS, Google ADK e VoltAgent em TypeScript. Uma ferramenta envolvida com tool() dentro de uma ferramenta do framework toma a chamada que o adaptador já gravou, então cada chamada é gravada uma vez; num replay, as ferramentas do LangGraph, do Google ADK e do Mastra respondem do registro, e as do OpenAI Agents e do VoltAgent precisam estar envolvidas com tool(), porque os ganchos deles não param uma ferramenta. Uma chamada de modelo é gravada pelo adaptador que vê os tokens dela. provenance transforma o resultado de uma ferramenta nos objetos que ele mostrou, cada um com a referência, os campos e a proveniência; sem proveniência, uma observação é só para exibição e nunca atualiza o estado tipado.
O registro também guarda o que o turno leu da memória, pela versão (o contexto pelo ETag, um bloco pela versão dele), as decisões de coordenação em que se apoiou e os efeitos com o estado de cada um, o que a pessoa viu ou fez (as interações) e os vereditos do contrato de afirmação. O que o turno disse não é repetido: output.event_keys aponta para os eventos que track() já enviou.
A build e os pinos
build.pins guarda o que precisa ser igual para um replay reproduzir o turno: prompts (nome e versão de cada prompt), corpus_digest (um digest dos arquivos que o agente consulta, calculado por você, nunca os arquivos), model (o modelo exato), assembler (a versão do seu montador de contexto) e tool_schemas (o digest do esquema de cada ferramenta). O SDK preenche sozinho os pinos da Niadra: a versão do compilador de contexto e o hash do pacote que o turno leu. O documento recording diz quais pinos são exigidos (prompts e model por padrão); um turno sem um deles é guardado, marcado como não reproduzível, e o SDK avisa uma vez.
Modos de conteúdo
O modo é configuração do espaço, por fonte, e o SDK o segue. Um blob é um valor grande do registro: os argumentos de uma ferramenta, um resultado, o texto de uma leitura, um documento que o turno escreveu.
Uma fonte pode sempre mandar um modo que guarda menos, nunca mais: um turno recusado com
content_mode_refused sai de novo só com digests. O digest é sha256: e o SHA-256 do JSON canônico do valor (RFC 8785), então o mesmo valor tem o mesmo digest em qualquer produtor, e um replay casa as chamadas pelo args_hash dos argumentos normalizados. Um turno grande demais é enviado com os blobs reduzidos a hashes, então um 413 turn_too_large nunca entra em laço. Um registro em pointer ou hash_only é aceito mesmo com o armazenamento da Niadra indisponível, porque o quadro é tudo o que ele tem. Veja Só metadado.
Fidelidade e completude
completeness diz quanto do turno está no registro: complete, partial (o SDK descartou blobs para proteger a fila; o quadro fica), incomplete (a gravação falhou durante o turno) ou unknown (um registro bronze).
A fila e o envio
Os turnos têm fila própria, separada da fila de eventos, limitada por bytes (64 MB por padrão) e por quantidade (2.000 turnos). Quando ela enche, o SDK descarta primeiro os blobs dos turnos sem marca, do mais antigo para o mais novo, marcando os registrospartial, e só depois os quadros mais antigos inteiros; os dois são contados. Um turno marcado fica com os blobs por mais tempo, porque é ele que alguém vai reproduzir. O envio vai em lotes de até 50 registros e 4 MB comprimidos, por POST /v1/turns, com o escopo track; a resposta é 200 quando todos entraram, 207 com um erro por registro recusado. Um turno que a Niadra já tem, pelo turn_id, é duplicata: o mesmo turno enviado duas vezes é um turno só. Um processo de escrita segura poucos corpos grandes (acima de 1 MB, enviados ou descomprimidos) ao mesmo tempo; passado esse limite, o lote volta com 429 e Retry-After, e o SDK o manda de novo.
O mesmo código está em examples/turn_records.py e, em TypeScript, em examples/claim-guard.ts, que abre o turno e passa a resposta pelo contrato de afirmação.
Camadas e promoção
Todo turno fica numa camada curta, por 7 dias. Um turno passa à camada guardada, porkept_days, por um de três motivos: uma marca posta na captura (error, guard_acted, handoff, assertion_failed, synthetic, incomplete ou negative_feedback), um pedido posterior, por POST /v1/turns/promote, nomeando uma conversa ou ids de turno com o motivo (complaint, bug_report, review ou other), porque a reclamação chega dias depois do turno, ou a amostra determinística de conversas inteiras. Depois da retenção da camada, nada de um turno resta além dos totais do dia, que não nomeiam ninguém. Uma retenção legal mantém os turnos de uma conversa fora do expurgo até ser liberada.
O webhook turn.flagged sai para cada turno guardado por uma marca, para os endpoints que o assinam: só ids e as marcas, nunca o que o turno disse ou leu.
O visualizador
No Console, a tela Turnos dos agentes lista os turnos guardados, do mais novo para o mais antigo, e abre cada um: o que leu, chamou, afirmou e disse, com as marcas, os pinos ereplay_blockers, por que o turno não pode ser reproduzido quando não pode (content_mode hash_only, fidelidade bronze ou silver, completude partial, incomplete ou unknown, ou um pino exigido que falta). Pela API, GET /v1/turns/{turn_id} e POST /v1/turns/search, com o id da conversa no corpo, pedem uma chave com o escopo replay ou uma pessoa com o papel integration ou security.
Replay
Um cenário guarda até 50 turnos com as asserções que eles devem continuar passando; o seu CI roda cada turno N vezes com a build fixada, dentro da sua empresa, e a Niadra decide o veredito estatístico. As ferramentas respondem do registro, os valores nunca saem, e o resultado nunca é enviado como turno. Veja Replay no seu CI.Custo e orçamento
Cada registro leva o custo do turno em dólares e os tokens de cada chamada de modelo. O blocobudget de uma leitura de contexto (include: ["budget"]) mostra o que o pacote custa em tokens estimados, por seção, e o que os turnos gravados deste agente já somaram na conversa ou no caso (turnos, chamadas de modelo e de ferramenta, tokens de entrada, do cache e de saída, custo); counted: false diz que os contadores não puderam ser lidos, e um número que falta nunca é zero. O bloco é mostrado, nunca imposto. O aproveitamento traz em cost chamadas, tokens e dinheiro por turno, por fonte e agente, contra o custo sem memória que a sua empresa mediu e declarou no documento measurement.
Privacidade
- O registro repete nenhum texto da conversa:
output.event_keysaponta para os eventos. - No modo
pointer, nenhum valor gravado chega à Niadra; nohash_only, nenhum valor é gravado. - A Niadra nunca põe um id de conversa numa URL nem numa chave de armazenamento em claro: os turnos ficam sob um hash com chave da conversa, e o apagamento de uma pessoa apaga os turnos dela por esse prefixo.
- Os registros servem à finalidade
quality, com a retenção da camada. Uma retenção legal os segura; apagado o titular,retainedno comprovante conta os turnos que uma retenção ainda mantém. - O índice da camada guardada entra na sua cadeia de auditoria: cada linha guardada tem uma entrada (id, fonte, agente, tipo, hora, modo, hash da build) com um digest SHA-256, as linhas de um dia UTC formam uma raiz de Merkle, e o evento diário
audit.roota leva comoturns.root, ao lado da raiz dos comprovantes.GET /v1/turns/index/{day}lista as linhas com os digests para a sua empresa recalcular a raiz; uma linha que vence ou é apagada depois deixa a raiz ancorada como estava.
Próximos passos
Replay no seu CI
cenários, asserções e o veredito estatístico.
Só metadado
o modo
pointer: os valores no seu bucket.Afirmações
os vereditos que cada turno carrega.
Registrar turnos
a referência de
POST /v1/turns.
