Skip to content

Estendendo a Configuração do Agente

Este guia descreve o padrão recomendado para adicionar uma nova feature de agente que varia por affiliate (ex.: FAQ customizado, saudação customizada, seleção de sub-agentes). Ele complementa Affiliate → Configuração (que descreve o mecanismo atual) e Como Adicionar Novo Agente (que descreve o padrão de feature flags globais, que não se aplica aqui).

Por que não usar feature flags globais

ifriend_agent/config/feature_flags.py (_FLAG_REGISTRY) e _FLAG_TO_AGENT em agent_builder.py controlam o root_agent via variáveis de ambiente — o mesmo valor vale para todos os affiliates e todas as sessões do deployment. Isso não serve para "affiliate X tem FAQ customizado, affiliate Y não": não existe hoje nenhum registro de capabilities por affiliate no repositório.

Padrão recomendado

  1. Modele a feature como um campo opcional dentro de affiliate_config. A API externa (GET /affiliates/{id}/root_agent) já retorna um dict por affiliate — a presença/ausência de um campo novo (ex.: faq: [...]) já funciona como o "toggle" por affiliate. Não crie uma flag global para uma feature que é inerentemente por affiliate.

  2. Não é preciso alterar o callback de carregamento. inject_affiliate_config (ifriend_agent/callbacks/affiliate_config_callback.py:16) já carrega o dict completo em session.state["affiliate_config"]. Um campo novo retornado pela API aparece automaticamente ali, sem qualquer mudança de código nesse ponto.

  3. Leia o campo defensivamente, com .get() e fallback. Siga o padrão já usado em get_affiliate_config_tool.py e transform_product_url_tool.py:41-53: nunca acesse a chave diretamente — o dict é de propriedade de um serviço externo (ver seção "Dependência do backend externo" abaixo) e pode não trazer o campo.

  4. Crie um tool dedicado para consumir o campo novo. Espelhe get_affiliate_config_tool.py: um tool pequeno que lê tool_context.state.get("affiliate_config", {}).get("<campo>") e retorna ao LLM (ou usa o valor para transformar algo, como transform_product_url_tool.py faz com os templates de URL).

  5. Decida onde plugar o tool: agente existente vs. novo agente. Duas opções, análogas às já usadas no repo:

  6. Adaptar um agente genérico existente para checar primeiro a versão do affiliate e cair para o comportamento padrão se não houver (ex.: faq_agent passaria a chamar um tool de FAQ do affiliate antes de usar o conhecimento genérico do help-center).
  7. Criar um sub-agent dedicado, always-on ou behind uma flag global de "a feature existe no deployment" (não "existe para este affiliate") — o mesmo modelo do custom_affiliate_booking_agent (ENABLE_CUSTOM_AFFILIATE_BOOKING).

Essa escolha depende do escopo da feature específica e deve ser decidida no design da implementação — este guia só define como o dado chega e é lido.

  1. Considere um schema tipado se o número de campos crescer. Hoje affiliate_config é um dict sem schema (e já tem uma inconsistência de casing conhecida — bookingUrlTemplate vs bookingUrltemplate, ver configuration.md). Ao adicionar campos novos, avalie introduzir um TypedDict/dataclass em ifriend_agent/models/ para centralizar nomes e tipos, em vez de repetir .get("chave_com_typo_provavel") em cada tool.

  2. Teste o tool isoladamente. Siga ifriend_agent/tests/test_custom_affiliate_booking_agent.py: mocke tool_context.state["affiliate_config"] com e sem o campo novo, sem depender de uma chamada real à API externa.

Dependência do backend externo

O schema retornado por GET /affiliates/{id}/root_agent é de propriedade de um serviço fora deste repositório (api.theifriend.com). Este repo (ifriend-agents) não controla nome, tipo ou versionamento desses campos.

Antes de depender de um campo novo em produção:

  • Alinhe o nome exato e o formato do campo com quem mantém esse endpoint — não assuma um contrato aqui.
  • Trate o dict sempre defensivamente (.get() com default), já que o backend pode não enviar o campo para affiliates antigos ou não migrados.
  • Esta lacuna é conhecida e intencionalmente não resolvida neste guia — é trabalho de coordenação entre times, não uma tarefa de código neste repo.

Ver também

  • Affiliate → Configuração — mecanismo atual, campos reais observados no código, inconsistências conhecidas.
  • Affiliate → Whitelabel — camada de branding/domínio, conceito relacionado mas distinto.
  • Affiliate → Knowledge Base — exemplo concreto deste padrão aplicado (campo knowledgeBaseCollection, threshold determinístico, cache, coordenação de modelo de embedding com a indexação externa).
  • ifriend_agent/config/agent_persona.py — outro exemplo do padrão, mas com uma variação: em vez de um tool dedicado, os campos (agentName, agentCompanyName, agentGreeting, agentTone) são injetados direto na instrução do orquestrador via placeholders {{...}} (mesmo mecanismo de {{current_date}}), sempre sanitizados/truncados e com enum fechado para agentTone — cuidado extra por serem texto vindo do affiliate encaixado direto no system prompt (superfície de prompt injection maior que um retorno de tool).
  • Como Adicionar Novo Agente — padrão de extensão para agentes/flags globais (não por affiliate).