beplus-mcp 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -88,7 +88,7 @@ Reinicie o cliente. Rode a tool **`whoami`** para confirmar o vínculo.
88
88
  | `check_generation` | Status de uma geração async por id. |
89
89
  | `cancel_generation` | Cancela uma geração em fila/processamento (estorna diamantes). |
90
90
  | `estimate_cost` | Custo em diamantes antes de gerar. |
91
- | `read_image_metadata` / `analyze_media` | Lê a proveniência embutida numa imagem / analisa mídia (imagem/vídeo/áudio/PDF) com prompt. |
91
+ | `read_image_metadata` / `analyze_media` | Lê a proveniência embutida numa imagem / analisa mídia (imagem/vídeo/áudio/PDF) com prompt, em Gemini, Claude ou GPT. O apelido do modelo vai em `model` e o catálogo por faixa de preço (econômico, médio, top) sai no `list_models`. Vídeo e áudio só nos `gemini-*`. |
92
92
 
93
93
  > **Referências de arquivo local (desde 0.8.1):** os campos de mídia — `reference_images`,
94
94
  > `first_frame_image`, `last_frame_image`, `reference_videos`, `reference_audios`, `motion_video`
package/dist/index.js CHANGED
@@ -21529,6 +21529,63 @@ function budgetLine(b) {
21529
21529
  if (exhausted) line += " \u2014 pe\xE7a a um admin para recarregar";
21530
21530
  return line;
21531
21531
  }
21532
+ var TIER_ORDER = ["economy", "mid", "top"];
21533
+ var TIER_LABEL = {
21534
+ economy: "\u{1F49A} Econ\xF4mico (r\xE1pido e barato)",
21535
+ mid: "\u{1F49B} M\xE9dio (equil\xEDbrio)",
21536
+ top: "\u2764\uFE0F Top (mais capaz, mais caro)"
21537
+ };
21538
+ var TIER_ALIAS = {
21539
+ economico: "economy",
21540
+ medio: "mid"
21541
+ };
21542
+ function normalizeTier(tier) {
21543
+ if (!tier) return "";
21544
+ const normalized = tier.normalize("NFD").replace(/[̀-ͯ]/g, "").trim().toLowerCase();
21545
+ return TIER_ALIAS[normalized] ?? normalized;
21546
+ }
21547
+ function usd(value) {
21548
+ return `$${value.toFixed(2)}`;
21549
+ }
21550
+ function acceptsLine(accepts) {
21551
+ const parts = [];
21552
+ if (accepts.images > 0) parts.push(`imagem (at\xE9 ${accepts.images})`);
21553
+ if (accepts.videos > 0) parts.push(`v\xEDdeo (at\xE9 ${accepts.videos})`);
21554
+ if (accepts.audios > 0) parts.push(`\xE1udio (at\xE9 ${accepts.audios})`);
21555
+ if (accepts.pdfs > 0) parts.push(`PDF (at\xE9 ${accepts.pdfs})`);
21556
+ return parts.length ? parts.join(", ") : "s\xF3 texto";
21557
+ }
21558
+ function analyzeModelLine(m) {
21559
+ const provider = m.provider ? ` \xB7 ${m.provider}` : "";
21560
+ return ` \u2022 ${m.model} \xB7 ${m.label}${provider}
21561
+ ${usd(m.inputCostPerMillion)} entrada / ${usd(m.outputCostPerMillion)} sa\xEDda por 1M tokens \xB7 aceita ${acceptsLine(m.accepts)}`;
21562
+ }
21563
+ function analyzeCatalogBlock(models) {
21564
+ if (!models?.length) return "";
21565
+ const groups = /* @__PURE__ */ new Map();
21566
+ for (const m of models) {
21567
+ const key = normalizeTier(typeof m.tier === "string" ? m.tier : void 0);
21568
+ const bucket = groups.get(key);
21569
+ if (bucket) bucket.push(m);
21570
+ else groups.set(key, [m]);
21571
+ }
21572
+ const known = TIER_ORDER.filter((t) => groups.has(t));
21573
+ const unknown2 = [...groups.keys()].filter((k) => !TIER_ORDER.includes(k));
21574
+ const untiered = groups.size === 1 && groups.has("");
21575
+ const sections = [...known, ...unknown2].map((key) => {
21576
+ const bucket = groups.get(key);
21577
+ const lines = bucket.map(analyzeModelLine).join("\n");
21578
+ if (untiered) return lines;
21579
+ const fallback = bucket[0]?.tierLabel?.trim();
21580
+ const heading = TIER_LABEL[key] ?? (fallback || (key ? `Faixa ${key}` : "Sem faixa definida"));
21581
+ return `${heading}:
21582
+ ${lines}`;
21583
+ });
21584
+ const videoAliases = models.filter((m) => m.accepts.videos > 0).map((m) => m.model);
21585
+ const videoHint = videoAliases.length && videoAliases.length < models.length ? `
21586
+ V\xEDdeo e \xE1udio s\xF3 em: ${videoAliases.join(", ")}.` : "";
21587
+ return "\n\nAn\xE1lise multimodal (tool analyze_media \xB7 prompt + m\xEDdia \u2192 texto):\n" + sections.join("\n") + "\nPasse o apelido em `model`." + videoHint;
21588
+ }
21532
21589
  function textResult(s) {
21533
21590
  return { content: [{ type: "text", text: s }] };
21534
21591
  }
@@ -22904,7 +22961,7 @@ ${budget}` : "")
22904
22961
  "list_models",
22905
22962
  {
22906
22963
  title: "Listar modelos",
22907
- description: "Lista os modelos dispon\xEDveis com pre\xE7o-base e limites por usu\xE1rio. Use quando estiver em d\xFAvida sobre qual modelo/params usar ou quanto custa. \xC9 a fonte de verdade em runtime.",
22964
+ description: "Lista os modelos dispon\xEDveis com pre\xE7o-base e limites por usu\xE1rio, e o cat\xE1logo de an\xE1lise multimodal (Gemini, Claude e GPT) agrupado por faixa de pre\xE7o. Use quando estiver em d\xFAvida sobre qual modelo/params usar ou quanto custa. \xC9 a fonte de verdade em runtime.",
22908
22965
  inputSchema: {
22909
22966
  kind: external_exports.enum(["image", "video", "audio", "all"]).default("all").optional().describe("Filtrar por tipo.")
22910
22967
  }
@@ -22916,13 +22973,7 @@ ${budget}` : "")
22916
22973
  const price = typeof x.pricing === "number" ? `$${x.pricing}` : JSON.stringify(x.pricing);
22917
22974
  return `\u2022 ${x.model} \u2014 ${price} (base USD)`;
22918
22975
  });
22919
- const analyzeLines = (m.analyze ?? []).map(
22920
- (a) => `\u2022 ${a.model} (${a.label}) \u2014 $${a.inputCostPerMillion}/$${a.outputCostPerMillion} por 1M tok in/out \xB7 aceita img=${a.accepts.images} vid=${a.accepts.videos} \xE1udio=${a.accepts.audios} pdf=${a.accepts.pdfs}`
22921
- );
22922
- const analyzeBlock = analyzeLines.length ? `
22923
-
22924
- Modelos de an\xE1lise multimodal (tool analyze_media \u2014 prompt + m\xEDdia \u2192 texto):
22925
- ${analyzeLines.join("\n")}` : "";
22976
+ const analyzeBlock = analyzeCatalogBlock(m.analyze);
22926
22977
  const txt = `Modelos de gera\xE7\xE3o:
22927
22978
  ${lines.join("\n") || "(nenhum)"}` + analyzeBlock + `
22928
22979
 
@@ -23009,14 +23060,18 @@ function registerAnalyzeTools(server, client, cfg) {
23009
23060
  server.registerTool(
23010
23061
  "analyze_media",
23011
23062
  {
23012
- title: "Analisar m\xEDdia (Gemini)",
23013
- description: "Envia um prompt + m\xEDdia (imagem, v\xEDdeo, \xE1udio ou PDF) para o Gemini e devolve uma resposta em texto. Use para descrever/analisar/transcrever/resumir/extrair informa\xE7\xE3o de m\xEDdia, ou perguntar algo sobre ela. A m\xEDdia entra como `media_urls` (URLs p\xFAblicas \u2014 tudo que o Google aceita: imagens, v\xEDdeos, \xE1udios, PDFs). V\xEDdeo/\xE1udio grandes funcionam (v\xE3o pela Files API do Google). Consome diamantes (reembolsados se falhar). Veja custo/limites com list_models.",
23063
+ title: "Analisar m\xEDdia (Gemini, Claude e GPT)",
23064
+ description: "Envia um prompt + m\xEDdia (imagem, v\xEDdeo, \xE1udio ou PDF) para um modelo de texto e devolve a resposta. Use para descrever/analisar/transcrever/resumir/extrair informa\xE7\xE3o de m\xEDdia, ou perguntar algo sobre ela. Tamb\xE9m funciona s\xF3 com texto, sem m\xEDdia. Tr\xEAs faixas de pre\xE7o: econ\xF4mica, m\xE9dia e top. A m\xEDdia entra como `media_urls` (URLs p\xFAblicas ou caminhos locais). V\xEDdeo e \xE1udio s\xF3 nos modelos Gemini, que leem arquivos grandes pela Files API do Google. Consome diamantes (reembolsados se falhar). O cat\xE1logo vivo, com pre\xE7o por 1M de tokens e m\xEDdia aceita por modelo, sai no list_models.",
23014
23065
  inputSchema: {
23015
23066
  prompt: external_exports.string().min(1).max(5e4).describe('O que voc\xEA quer do modelo sobre a m\xEDdia (ex.: "descreva este v\xEDdeo", "transcreva este \xE1udio").'),
23016
23067
  media_urls: external_exports.array(external_exports.string().min(1)).max(50).optional().describe(
23017
23068
  "M\xEDdia (imagem/v\xEDdeo/\xE1udio/PDF): URLs p\xFAblicas OU caminhos de arquivo local (o MCP sobe pro R2 automaticamente). Pode misturar tipos. Opcional (prompt s\xF3-texto tamb\xE9m funciona)."
23018
23069
  ),
23019
- model: external_exports.enum(["gemini-flash", "gemini-pro"]).default("gemini-flash").optional().describe("gemini-flash = r\xE1pido/barato (Gemini 3.5 Flash); gemini-pro = mais capaz (Gemini 3.1 Pro)."),
23070
+ // String livre, não z.enum: quem valida o apelido é o backend, então um
23071
+ // modelo novo no catálogo passa a valer sem republicar o pacote.
23072
+ model: external_exports.string().min(1).default("gemini-flash").optional().describe(
23073
+ "Apelido do modelo. Econ\xF4micos: gemini-lite, gpt-mini, claude-haiku. M\xE9dios: gemini-flash (padr\xE3o), gpt, claude-sonnet. Top: gemini-pro, claude-opus, gpt-pro, claude-fable. V\xEDdeo e \xE1udio s\xF3 nos gemini-*; PDF nos gemini-* e claude-*; os gpt-* leem s\xF3 imagem. Lista autoritativa, com pre\xE7os: list_models."
23074
+ ),
23020
23075
  project: external_exports.string().optional().describe(
23021
23076
  'Projeto (uuid ou code curto, ex.: "ICONS") de cujo budget cobrar. Omitido \u2192 usa o projeto ativo da conta.'
23022
23077
  )
@@ -23320,7 +23375,7 @@ ${calls.map(callLine).join("\n\n")}`);
23320
23375
  import { createRequire } from "module";
23321
23376
  var require2 = createRequire(import.meta.url);
23322
23377
  function readVersion() {
23323
- if ("0.22.0") return "0.22.0";
23378
+ if ("0.23.0") return "0.23.0";
23324
23379
  try {
23325
23380
  const pkg = require2("../package.json");
23326
23381
  return pkg.version ?? "0.0.0-unknown";