Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

1
resposta

Estou enfrentando um erro, acho que o curso ficou defasado.

Pelo visto funções não são mais declaradas da mesma forma

meu chat.js

import { chat, funcoes, inicializaChat } from './inicializaChat.js';
export async function executaChat(mensagem) {
  if (!chat) {
    inicializaChat();
  }

  console.log("Tamanho do histórico: " + (await chat.getHistory()).length);
  const result = await chat.sendMessage(mensagem);
  const response = await result.response;
  
  const content = response.candidates[0].content;
 
  const fc = content.parts[0].functionCall;
  const text = content.parts.map(({ text }) => text).join("");
  console.log(text);
  console.log(fc);
 
  if (fc) {
    const { name, args } = fc;
    const fn = funcoes[name];
    if (!fn) {
      throw new Error(`Unknown function "${name}"`);
    }
    const fr = {
      functionResponse: {
          name,
          response: {
            name,
            content: funcoes[name](args),
          }
      },
    }

    console.log(fr)

    const request2 = [fr];
    const response2 = await chat.sendMessage(request2);
    const result2 = response2.response;
    return result2.text();
  } else if (text) {
    return text;
  }

}

meu inicializaChat.ts

import { GoogleGenerativeAI, FunctionDeclarationSchemaType } from '@google/generative-ai';

const genAI = new GoogleGenerativeAI("AQ.Ab8RN6LSyXK0dxxiX7B5ZEmX4tOJQLAsLGBQ6V59DmRz4iW1Iw");

const funcoes = {
  taxaJurosParcelamento: ({ value }) => {
    const meses = typeof value === "string" ? parseInt(value) : value;
    if (meses <= 6) {
      return 3;
    } else if (meses <= 12) {
      return 5;
    } else if (meses <= 24) {
      return 7;
    }
  }
};

const tools = [
  {
    functionDeclarations: [
      {
        name: "taxaJurosParcelamento",
        description: "Retorna a taxa de juros para parcelamento baseado na quantidade de meses",
        parameters: {
          type: FunctionDeclarationSchemaType.OBJECT,
          properties: {
            value: { type: FunctionDeclarationSchemaType.NUMBER },
          },
          required: ["value"],
        } 
      }
    ]
  }
];


const model = genAI.getGenerativeModel(
  { model: "gemini-3.5-flash-lite", tools},
  { apiVersion: "v1beta"});

let chat;

function inicializaChat() {
  chat = model.startChat({
    history: [
      {
        role: "user",
        parts: [{ text: `Você é Jordi, um chatbot amigável que representa 
        a empresa Jornada Viagens, que vende pacotes turísticos para
        destinos nacionais e internacionais. Você pode responder mensagens 
        que tenham relação com viagens.` }],
      },
      {
        role: "model",
        parts: [{ text: `Olá! Obrigado por entrar em contato com o Jornada Viagens. 
        Antes de começar a responder sobre suas dúvidas, preciso do seu nome e 
        endereço de e-mail.` }],
      },
    ],
    generationConfig: {
      maxOutputTokens: 1000,
    },
  });
}

export { chat, funcoes, inicializaChat}

meu erro:

{
name: 'taxaJurosParcelamento',
args: { value: 4 },
id: 'call_1507556'
}
{
functionResponse: {
name: 'taxaJurosParcelamento',
response: { name: 'taxaJurosParcelamento', content: 3 }
}
}
Error no endpoint do chat: GoogleGenerativeAIError: [400 Bad Request] Role 'function' is not supported. Please use a valid role: SYSTEM, SYSTEM_1, USER, ASSISTANT, DEVELOPER, CONTEXT, USER_CONTEXT, MODEL, USER.
at _makeRequestInternal (file:///C:/Users/Refri/OneDrive/js/3752-gemini-com-node-main/node_modules/@google/generative-ai/dist/index.mjs:301:19)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async generateContent (file:///C:/Users/Refri/OneDrive/js/3752-gemini-com-node-main/node_modules/@google/generative-ai/dist/index.mjs:690:22)
at async ChatSession.sendMessage (file:///C:/Users/Refri/OneDrive/js/3752-gemini-com-node-main/node_modules/@google/generative-ai/dist/index.mjs:951:9)
at async executaChat (file:///C:/Users/Refri/OneDrive/js/3752-gemini-com-node-main/chat.js:37:23)
at async file:///C:/Users/Refri/OneDrive/js/3752-gemini-com-node-main/app.js:29:22

1 resposta

Oi, Phelipe! Tudo bem?

Sobre o Function Calling no Gemini e Node.js, seu diagnóstico faz sentido: o curso utiliza uma abordagem da SDK antiga @google/generative-ai, enquanto a documentação atual recomenda a migração para a Google GenAI SDK, @google/genai.

Por bem ou mal, as ferramentas de IA atualizam numa velocidade totalmente desigual com as outras ferramentas usuais, então coisas como essa é comum de acontecer.

O erro não está na execução da função taxaJurosParcelamento. Isso fica claro porque ela foi chamada corretamente e retornou 3. O problema acontece no momento em que esse resultado é enviado novamente para o Gemini.

No seu código, você está fazendo:

const fr = {
  functionResponse: {
    name,
    response: {
      name,
      content: funcoes[name](args),
    }
  },
};

const request2 = [fr];
const response2 = await chat.sendMessage(request2);

Esse formato faz a SDK interpretar a mensagem de uma maneira incompatível com o endpoint/modelo utilizado, resultando no erro Role 'function' is not supported.

Na API atual, uma resposta de função precisa ser enviada como uma functionResponse dentro de uma mensagem com role: "user", além de ser recomendável informar o id da chamada de função. A documentação atual mostra exatamente esse fluxo.

Se você quiser manter a abordagem da SDK antiga apenas para acompanhar a atividade do curso, o ajuste fica neste ponto:

const resultFunction = funcoes[name](args);

const request2 = [
  {
    functionResponse: {
      name,
      response: {
        result: resultFunction,
      },
      id: fc.id,
    },
  },
];

const response2 = await chat.sendMessage(request2);

Esse trecho executa a função, coloca o resultado dentro de response.result e associa a resposta ao id retornado pelo functionCall.

Também vale observar outro ponto no seu código. Você está utilizando:

import { GoogleGenerativeAI } from '@google/generative-ai';

A documentação atual do Google recomenda migrar para: npm install @google/genai

Esse comando instala a SDK atual do Google GenAI. A própria documentação informa que @google/generative-ai é uma biblioteca legada e recomenda a migração para @google/genai.

Na SDK atual, a estrutura de Function Calling também mudou. Por exemplo, a declaração da ferramenta passa a seguir uma estrutura como:

import { GoogleGenAI, Type } from "@google/genai";

const ai = new GoogleGenAI({
  apiKey: process.env.GEMINI_API_KEY
});

const taxaJurosParcelamento = {
  name: "taxaJurosParcelamento",
  description: "Retorna a taxa de juros para parcelamento baseado na quantidade de meses",
  parameters: {
    type: Type.OBJECT,
    properties: {
      value: {
        type: Type.NUMBER,
        description: "Quantidade de meses do parcelamento"
      }
    },
    required: ["value"]
  }
};

Essa mudança é relevante porque o curso que você está acompanhando pode ter sido produzido com uma versão anterior da API. A documentação atual recomenda a Google GenAI SDK e apresenta exemplos de Function Calling usando @google/genai.

Dica: não é necessário reescrever todo o projeto imediatamente se seu objetivo é concluir a atividade do curso. Primeiro, você pode testar o ajuste da functionResponse. Depois, se quiser deixar o projeto alinhado com a API atual, vale fazer a migração de @google/generative-ai para @google/genai.

Outro ponto de segurança: a chave da API aparece diretamente no seu código. Como ela foi exposta na publicação, recomendo revogar/rotacionar essa chave no Google AI Studio e utilizar uma variável de ambiente, por exemplo, process.env.GEMINI_API_KEY.

Você pretende apenas concluir a atividade mantendo a SDK utilizada no curso ou quer aproveitar o momento para migrar o projeto inteiro para @google/genai?

Alura Conte com o apoio da comunidade Alura na sua jornada. Abraços e bons estudos!