Prompt API em Chrome Extensions — Guia para Desenvolvedores

A Prompt API tá disponível em Chrome Extensions desde o Chrome 138 — antes mesmo do lançamento pra web (Chrome 148). Extensions ainda têm acesso a topK e temperature via LanguageModel.params(), mas cuidado: esses parâmetros estão depreciados e podem ser removidos. A recomendação atual da spec é samplingMode, um enum de presets que funciona tanto na web quanto em Extensions.

⚠️ Antes de tudo: topK e temperature estão depreciados

A spec do Prompt API depreciou o controle numérico direto de sampling. Vale entender o que isso significa antes de usar qualquer coisa desta página:

// ❌ Depreciado — ainda funciona em Extensions, mas será removido
const session = await LanguageModel.create({ temperature: 0.8, topK: 10 });

// ✅ Recomendado
const session = await LanguageModel.create({ samplingMode: 'creative' });

O que muda na prática, por contexto:

Contexto topK / temperature samplingMode
Web page Aceitos mas silenciosamente ignorados. Loga warning de depreciação no console; session.topK e session.temperature ficam undefined ✅ Disponível (via Origin Trial)
Extension Funcionam, mas depreciados ✅ Disponível

Duas regras que valem para quem usa os parâmetros legados em Extensions:

  • Se passar samplingMode junto com topK ou temperature, create() rejeita com TypeError.
  • Uma sessão criada com topK/temperature tem session.samplingMode === null.

Se você já tem topK/temperature no seu código de extensão, migrar para samplingMode é o caminho — e funciona nas duas plataformas.

samplingMode — o controle de sampling recomendado

samplingMode substitui o ajuste numérico por presets que fazem sentido entre modelos diferentes. O enum tem 7 valores, do mais determinístico ao mais criativo:

Valor Comportamento Use para
"most-predictable" Máxima determinismo e reprodutibilidade Testes, geração de código, extração de dados
"predictable" Focado, variação mínima Classificação, extração
"slightly-predictable" Focado com um pouco mais de variação Classificação com julgamento
"balanced" Equilíbrio entre previsibilidade e criatividade (padrão) Conversação em geral
"slightly-creative" Criativo, mas mais contido que "creative" Copy com direção
"creative" Variedade e criatividade sobre reprodutibilidade Brainstorming, ideias
"most-creative" Máxima diversidade Brainstorming aberto
// Funciona na web (com Origin Trial) e em Extensions
const session = await LanguageModel.create({
  samplingMode: 'creative',
});

// O modo resolvido é exposto como atributo read-only
console.log(session.samplingMode); // "creative"

O modo configurado é exposto na sessão como atributo read-only, então dá pra confirmar o que foi aplicado.

Diferenças entre Extensions e Web

Funcionalidade Chrome Extensions Web (Chrome 148+)
Disponível desde Chrome 138 Chrome 148
samplingMode ✅ Disponível ✅ Via Origin Trial de sampling parameters
LanguageModel.params() ✅ Disponível (depreciado) ❌ Não disponível
topK / temperature ⚠️ Depreciado, ainda funcional ❌ Ignorados silenciosamente
Namespace window.LanguageModel (ou self.ai.languageModel legado) window.LanguageModel
Contexto de execução Background, popup, content script Apenas top-level window e iframes
Permissão necessária Nenhuma permissão especial no manifest Permission Policy (iframes)

LanguageModel.params() (depreciado)

⚠️ Esta seção documenta uma API depreciada. params(), topK e temperature só funcionam em Extensions e podem ser removidas em uma release futura. Para código novo, use samplingMode. Mantenho a referência aqui porque boa parte das extensões publicadas ainda usa esses parâmetros.

O método params() retorna informações sobre os parâmetros de sampling do modelo:

// Disponível APENAS em Chrome Extensions
const params = await LanguageModel.params();

console.log(params);
// {
//   defaultTopK: 3,
//   maxTopK: 128,
//   defaultTemperature: 1,
//   maxTemperature: 2
// }
Parâmetro Tipo Descrição
defaultTopK number Valor padrão de top-K (geralmente 3)
maxTopK number Valor máximo permitido para top-K (geralmente 128)
defaultTemperature number Temperatura padrão (geralmente 1.0)
maxTemperature number Temperatura máxima permitida (geralmente 2.0)

O que são topK e temperature

  • top-K: Controla quantos tokens candidatos são considerados a cada passo da geração. Valores menores = mais determinístico. Valores maiores = mais diverso.
  • temperature: Controla a aleatoriedade da distribuição de probabilidade. Valores menores = mais previsível. Valores maiores = mais criativo.

Criando sessão com parâmetros personalizados

Em Extensions, você pode ajustar os parâmetros de sampling ao criar uma sessão:

// Obter parâmetros do modelo
const params = await LanguageModel.params();

// Sessão com temperatura mais alta (mais criativa)
const sessaoCreativa = await LanguageModel.create({
  temperature: Math.min(params.defaultTemperature * 1.5, params.maxTemperature),
  topK: params.maxTopK,
  initialPrompts: [
    { role: 'system', content: 'You are a creative writing assistant.' }
  ]
});

// Sessão com temperatura baixa (mais determinística)
const sessaoPrecisa = await LanguageModel.create({
  temperature: 0.1,
  topK: 3,
  initialPrompts: [
    { role: 'system', content: 'You are a data extraction tool. Be precise.' }
  ]
});

Regra: Ao especificar parâmetros, você deve definir ambos (topK E temperature) ou nenhum. Não é possível definir apenas um.

Configuração do manifest.json

A Prompt API em Extensions não requer permissão especial no manifest. O acesso é automático:

{
  "manifest_version": 3,
  "name": "Minha Extensão com IA",
  "version": "1.0.0",
  "description": "Extensão que usa a Prompt API para análise de texto",

  "background": {
    "service_worker": "background.js"
  },

  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },

  "permissions": [
    "activeTab"
  ]
}

Nota sobre permissão legada

Se sua extensão usava a permissão experimental anterior "aiLanguageModelOriginTrial", remova-a:

{
  "permissions": [
    "aiLanguageModelOriginTrial"
  ]
}

Essa permissão está expirada e não é mais necessária.

Exemplos de extensões

Extensão 1: Extrator de contatos

Extrai informações de contato de páginas web automaticamente:

background.js

chrome.action.onClicked.addListener(async (tab) => {
  // Injeta content script para capturar texto da página
  const [result] = await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: () => document.body.innerText
  });

  const textoPagina = result.result;

  // Criar sessão com alta precisão
  const params = await LanguageModel.params();
  const session = await LanguageModel.create({
    temperature: 0.1,
    topK: params.defaultTopK,
    initialPrompts: [
      {
        role: 'system',
        content: 'Extract contact information from web pages. Return structured JSON.'
      }
    ]
  });

  const schema = {
    type: 'object',
    properties: {
      contacts: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            name: { type: 'string' },
            email: { type: 'string' },
            phone: { type: 'string' },
            company: { type: 'string' }
          }
        }
      }
    }
  };

  const resultado = await session.prompt(
    `Extract all contact information from this page:\n\n${textoPagina.substring(0, 3000)}`,
    { responseConstraint: schema }
  );

  const contatos = JSON.parse(resultado);

  // Enviar resultado para o popup
  chrome.storage.local.set({ lastContacts: contatos });
  session.destroy();
});

Extensão 2: Criador de eventos de calendário

Detecta datas e horários em páginas e sugere eventos:

content-script.js

async function extrairEventos() {
  const textoSelecionado = window.getSelection().toString();

  if (!textoSelecionado) return;

  const session = await LanguageModel.create({
    temperature: 0.2,
    topK: 5,
    initialPrompts: [
      {
        role: 'system',
        content: 'Extract calendar events from text. Include date, time, title, and location when available.'
      }
    ]
  });

  const schema = {
    type: 'array',
    items: {
      type: 'object',
      properties: {
        title: { type: 'string' },
        date: { type: 'string' },
        time: { type: 'string' },
        location: { type: 'string' }
      },
      required: ['title', 'date']
    }
  };

  const resultado = await session.prompt(
    `Extract events from: "${textoSelecionado}"`,
    { responseConstraint: schema }
  );

  const eventos = JSON.parse(resultado);
  session.destroy();

  // Mostrar UI com os eventos encontrados
  mostrarEventosDetectados(eventos);
}

// Ativar com menu de contexto ou atalho
document.addEventListener('mouseup', () => {
  if (window.getSelection().toString().length > 20) {
    extrairEventos();
  }
});

Extensão 3: Resumidor de artigos

popup.js

document.getElementById('btn-resumir').addEventListener('click', async () => {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

  const [result] = await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: () => {
      // Extrair texto principal do artigo
      const article = document.querySelector('article') || document.body;
      return article.innerText.substring(0, 5000);
    }
  });

  const textoArtigo = result.result;
  const outputEl = document.getElementById('resumo');
  outputEl.textContent = 'Gerando resumo...';

  const params = await LanguageModel.params();
  const session = await LanguageModel.create({
    temperature: 0.5,
    topK: params.defaultTopK,
    initialPrompts: [
      {
        role: 'system',
        content: 'Summarize articles in 3-5 bullet points. Be concise and capture key insights.'
      }
    ]
  });

  const stream = session.promptStreaming(
    `Summarize this article:\n\n${textoArtigo}`
  );

  outputEl.textContent = '';
  for await (const chunk of stream) {
    outputEl.textContent += chunk;
  }

  session.destroy();
});

Extensão 4: Classificador de spam em tempo real

background.js (service worker)

// Classificar conteúdo conforme o usuário navega
chrome.webNavigation.onCompleted.addListener(async (details) => {
  if (details.frameId !== 0) return; // Apenas frame principal

  const [result] = await chrome.scripting.executeScript({
    target: { tabId: details.tabId },
    func: () => document.title + ' ' + (document.querySelector('meta[name="description"]')?.content || '')
  });

  const conteudo = result.result;

  const session = await LanguageModel.create({
    temperature: 0.1,
    topK: 3
  });

  const schema = {
    type: 'object',
    properties: {
      isSpam: { type: 'boolean' },
      confidence: { type: 'number' },
      reason: { type: 'string' }
    },
    required: ['isSpam', 'confidence']
  };

  try {
    const resultado = await session.prompt(
      `Is this webpage spam or potentially dangerous? Title and description: "${conteudo}"`,
      { responseConstraint: schema }
    );

    const analise = JSON.parse(resultado);

    if (analise.isSpam && analise.confidence > 0.8) {
      // Mostrar aviso ao usuário
      chrome.action.setBadgeText({ text: '⚠️', tabId: details.tabId });
      chrome.action.setBadgeBackgroundColor({ color: '#FF0000', tabId: details.tabId });
    }
  } finally {
    session.destroy();
  }
});

Contextos de execução em Extensions

A Prompt API funciona nos seguintes contextos de uma extensão:

Contexto Funciona Observação
Background (Service Worker) ✅ Principal contexto de execução
Popup ✅ Fechado quando popup é fechado
Content Script ✅ Roda no contexto da página
Side Panel ✅ Persistente enquanto aberto
Options page ✅ Página de configurações
DevTools panel ✅ Ferramentas de desenvolvimento

Boas práticas para Extensions

1. Gerenciar ciclo de vida da sessão

Em service workers, a sessão pode ser perdida quando o worker é desativado. Recrie quando necessário:

let session = null;

async function getSession() {
  if (!session) {
    session = await LanguageModel.create({
      temperature: 0.3,
      topK: 10,
      initialPrompts: [
        { role: 'system', content: 'You are a helpful browser assistant.' }
      ]
    });
  }
  return session;
}

// Limpar quando não necessário
chrome.runtime.onSuspend.addListener(() => {
  if (session) {
    session.destroy();
    session = null;
  }
});

2. Usar topK baixo para classificação

// Mais determinístico = melhor para classificação
const sessaoClassificacao = await LanguageModel.create({
  temperature: 0.1,
  topK: 3
});

3. Usar temperature alta para criatividade

// Mais diverso = melhor para geração criativa
const params = await LanguageModel.params();
const sessaoCreativa = await LanguageModel.create({
  temperature: Math.min(1.8, params.maxTemperature),
  topK: params.maxTopK
});

4. Respeitar limites de content scripts

Content scripts rodam no contexto da página. Não envie texto sensível do DOM diretamente — filtre primeiro.


Perguntas frequentes

Preciso declarar alguma permissão especial no manifest para usar a Prompt API?

Não. A Prompt API é automaticamente disponível em Chrome Extensions sem permissões adicionais no manifest.json.

A Prompt API funciona no service worker da extensão?

Sim. O service worker (background script) tem acesso total à Prompt API, incluindo params(), topK e temperature.

Posso usar topK e temperature na versão web da API?

Não recomendo. Esses parâmetros estão depreciados: em web pages são aceitos mas silenciosamente ignorados (com warning no console), e em Extensions funcionam mas podem ser removidos. O caminho atual na web é o Origin Trial de sampling parameters, que expõe samplingMode — um enum de presets que também funciona em Extensions.

A sessão persiste quando o service worker é desativado?

Não. Quando o Chrome suspende o service worker por inatividade, a sessão é perdida. Você precisa recriar a sessão quando o worker é reativado. Considere salvar o contexto da conversa em chrome.storage.session.

Qual a diferença de performance entre Extensions e Web?

Não há diferença de performance de inferência. Ambos usam o mesmo Gemini Nano. A diferença é funcional: topK/temperature (depreciados) só têm efeito em Extensions, enquanto samplingMode funciona nas duas plataformas.


Referências