beplus-mcp 0.22.0 → 0.24.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
@@ -21293,11 +21293,12 @@ var BeplusClient = class {
21293
21293
  calculateCost(query) {
21294
21294
  return this.request("GET", "/calculate-cost", { query });
21295
21295
  }
21296
- balance() {
21297
- return this.request("GET", "/balance");
21296
+ /** `billing: 'personal'` pula o budget do projeto ativo no preview do saldo. */
21297
+ balance(billing) {
21298
+ return this.request("GET", "/balance", { query: { billing } });
21298
21299
  }
21299
- me() {
21300
- return this.request("GET", "/me");
21300
+ me(billing) {
21301
+ return this.request("GET", "/me", { query: { billing } });
21301
21302
  }
21302
21303
  readProvenance(body) {
21303
21304
  return this.request("POST", "/read-provenance", { body, timeoutMs: 3e4 });
@@ -21529,6 +21530,63 @@ function budgetLine(b) {
21529
21530
  if (exhausted) line += " \u2014 pe\xE7a a um admin para recarregar";
21530
21531
  return line;
21531
21532
  }
21533
+ var TIER_ORDER = ["economy", "mid", "top"];
21534
+ var TIER_LABEL = {
21535
+ economy: "\u{1F49A} Econ\xF4mico (r\xE1pido e barato)",
21536
+ mid: "\u{1F49B} M\xE9dio (equil\xEDbrio)",
21537
+ top: "\u2764\uFE0F Top (mais capaz, mais caro)"
21538
+ };
21539
+ var TIER_ALIAS = {
21540
+ economico: "economy",
21541
+ medio: "mid"
21542
+ };
21543
+ function normalizeTier(tier) {
21544
+ if (!tier) return "";
21545
+ const normalized = tier.normalize("NFD").replace(/[̀-ͯ]/g, "").trim().toLowerCase();
21546
+ return TIER_ALIAS[normalized] ?? normalized;
21547
+ }
21548
+ function usd(value) {
21549
+ return `$${value.toFixed(2)}`;
21550
+ }
21551
+ function acceptsLine(accepts) {
21552
+ const parts = [];
21553
+ if (accepts.images > 0) parts.push(`imagem (at\xE9 ${accepts.images})`);
21554
+ if (accepts.videos > 0) parts.push(`v\xEDdeo (at\xE9 ${accepts.videos})`);
21555
+ if (accepts.audios > 0) parts.push(`\xE1udio (at\xE9 ${accepts.audios})`);
21556
+ if (accepts.pdfs > 0) parts.push(`PDF (at\xE9 ${accepts.pdfs})`);
21557
+ return parts.length ? parts.join(", ") : "s\xF3 texto";
21558
+ }
21559
+ function analyzeModelLine(m) {
21560
+ const provider = m.provider ? ` \xB7 ${m.provider}` : "";
21561
+ return ` \u2022 ${m.model} \xB7 ${m.label}${provider}
21562
+ ${usd(m.inputCostPerMillion)} entrada / ${usd(m.outputCostPerMillion)} sa\xEDda por 1M tokens \xB7 aceita ${acceptsLine(m.accepts)}`;
21563
+ }
21564
+ function analyzeCatalogBlock(models) {
21565
+ if (!models?.length) return "";
21566
+ const groups = /* @__PURE__ */ new Map();
21567
+ for (const m of models) {
21568
+ const key = normalizeTier(typeof m.tier === "string" ? m.tier : void 0);
21569
+ const bucket = groups.get(key);
21570
+ if (bucket) bucket.push(m);
21571
+ else groups.set(key, [m]);
21572
+ }
21573
+ const known = TIER_ORDER.filter((t) => groups.has(t));
21574
+ const unknown2 = [...groups.keys()].filter((k) => !TIER_ORDER.includes(k));
21575
+ const untiered = groups.size === 1 && groups.has("");
21576
+ const sections = [...known, ...unknown2].map((key) => {
21577
+ const bucket = groups.get(key);
21578
+ const lines = bucket.map(analyzeModelLine).join("\n");
21579
+ if (untiered) return lines;
21580
+ const fallback = bucket[0]?.tierLabel?.trim();
21581
+ const heading = TIER_LABEL[key] ?? (fallback || (key ? `Faixa ${key}` : "Sem faixa definida"));
21582
+ return `${heading}:
21583
+ ${lines}`;
21584
+ });
21585
+ const videoAliases = models.filter((m) => m.accepts.videos > 0).map((m) => m.model);
21586
+ const videoHint = videoAliases.length && videoAliases.length < models.length ? `
21587
+ V\xEDdeo e \xE1udio s\xF3 em: ${videoAliases.join(", ")}.` : "";
21588
+ return "\n\nAn\xE1lise multimodal (tool analyze_media \xB7 prompt + m\xEDdia \u2192 texto):\n" + sections.join("\n") + "\nPasse o apelido em `model`." + videoHint;
21589
+ }
21532
21590
  function textResult(s) {
21533
21591
  return { content: [{ type: "text", text: s }] };
21534
21592
  }
@@ -21542,6 +21600,10 @@ function compact(obj) {
21542
21600
  }
21543
21601
  return out;
21544
21602
  }
21603
+ function resolveProjectArg(project, billing, activeProject) {
21604
+ if (billing === "personal") return void 0;
21605
+ return project ?? activeProject ?? void 0;
21606
+ }
21545
21607
  var CHARGED_FROM_LABEL = {
21546
21608
  budget: "do budget do projeto",
21547
21609
  weekly_allowance: "do cr\xE9dito semanal da equipe",
@@ -21708,6 +21770,9 @@ var DEFAULTS = {
21708
21770
  // src/tools/generation.ts
21709
21771
  var IMAGE_BUDGET_MS = 9e4;
21710
21772
  var VIDEO_BUDGET_MS = 12e4;
21773
+ var BILLING_FIELD = external_exports.enum(["personal"]).optional().describe(
21774
+ '"personal" = cobra do seu diamante pessoal, IGNORANDO o projeto ativo (mesmo se houver um). Use quando quiser garantir que isto N\xC3O sai do budget de nenhum projeto. Incompat\xEDvel com `project`.'
21775
+ );
21711
21776
  function flagsLine(g) {
21712
21777
  const parts = [
21713
21778
  g.is_favorite ? "\u2B50 like" : null,
@@ -21774,7 +21839,8 @@ function registerGenerationTools(server, client, cfg) {
21774
21839
  character_reference: external_exports.string().optional().describe("Midjourney: refer\xEAncia de PERSONAGEM (URL/arquivo). v7 usa --oref, v6 usa --cref (autom\xE1tico)."),
21775
21840
  character_weight: external_exports.number().int().min(0).max(1e3).optional().describe("Midjourney: peso do character ref (--ow v7 / --cw v6)."),
21776
21841
  image_weight: external_exports.number().min(0).max(3).optional().describe("Midjourney: --iw peso das reference_images (image-prompts) 0-3. Padr\xE3o 1."),
21777
- project: external_exports.string().max(64).optional().describe('Projeto (uuid OU code curto, ex.: "VRAO-26"). S\xF3 omita se o usu\xE1rio J\xC1 confirmou o projeto ativo nesta sess\xE3o.')
21842
+ project: external_exports.string().max(64).optional().describe('Projeto (uuid OU code curto, ex.: "VRAO-26"). S\xF3 omita se o usu\xE1rio J\xC1 confirmou o projeto ativo nesta sess\xE3o.'),
21843
+ billing: BILLING_FIELD
21778
21844
  }
21779
21845
  },
21780
21846
  async (args) => {
@@ -21859,7 +21925,12 @@ function registerGenerationTools(server, client, cfg) {
21859
21925
  image_weight: args.image_weight
21860
21926
  });
21861
21927
  const start = await client.startGeneration(
21862
- compact({ model: args.model, input, project: args.project ?? cfg.activeProject ?? void 0 })
21928
+ compact({
21929
+ model: args.model,
21930
+ input,
21931
+ project: resolveProjectArg(args.project, args.billing, cfg.activeProject),
21932
+ billing: args.billing
21933
+ })
21863
21934
  );
21864
21935
  if (!start.success || !start.generation_id) {
21865
21936
  if (isTeamGatingError(start.message)) return errorResult(await buildPickProjectMessage(client));
@@ -21909,7 +21980,8 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
21909
21980
  zoom_ratio: external_exports.enum(["1.5", "2"]).optional().describe("Zoom out (outpaint)."),
21910
21981
  mask: external_exports.string().optional().describe("M\xE1scara base64 B/W PNG (inpaint) \u2014 \xE1rea branca = repintar."),
21911
21982
  prompt: external_exports.string().max(2e3).optional().describe("Prompt opcional (inpaint)."),
21912
- project: external_exports.string().max(64).optional().describe("Projeto (uuid OU code curto).")
21983
+ project: external_exports.string().max(64).optional().describe("Projeto (uuid OU code curto)."),
21984
+ billing: BILLING_FIELD
21913
21985
  }
21914
21986
  },
21915
21987
  async (args) => {
@@ -21924,7 +21996,12 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
21924
21996
  prompt: args.prompt
21925
21997
  });
21926
21998
  const start = await client.startGeneration(
21927
- compact({ model: "midjourney", input, project: args.project ?? cfg.activeProject ?? void 0 })
21999
+ compact({
22000
+ model: "midjourney",
22001
+ input,
22002
+ project: resolveProjectArg(args.project, args.billing, cfg.activeProject),
22003
+ billing: args.billing
22004
+ })
21928
22005
  );
21929
22006
  if (!start.success || !start.generation_id) {
21930
22007
  if (isTeamGatingError(start.message)) return errorResult(await buildPickProjectMessage(client));
@@ -21965,7 +22042,9 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
21965
22042
  inputSchema: {
21966
22043
  // Sem teto local — ver nota em generate_image. O Seedance não publica
21967
22044
  // limite; o Kling publica 2500 e o backend recusa dizendo quanto cortar.
21968
- prompt: external_exports.string().min(1).describe("Descri\xE7\xE3o do v\xEDdeo desejado."),
22045
+ // Opcional só por causa de `draft_task_id` (upscale de um draft não
22046
+ // manda prompt — é herdado do draft original); validado no handler.
22047
+ prompt: external_exports.string().optional().describe("Descri\xE7\xE3o do v\xEDdeo desejado. Omita s\xF3 ao usar `draft_task_id`."),
21969
22048
  model: external_exports.enum(VIDEO_MODELS).default(DEFAULTS.videoModel).describe(
21970
22049
  "seedance-2.0-fast = barato/r\xE1pido; seedance-2.5 = at\xE9 30s num take, 50 refs e at\xE9 1080p; seedance-2.0 = \xFAnico com 4K; kling-v3-video = alternativa."
21971
22050
  ),
@@ -21995,7 +22074,14 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
21995
22074
  video_task_type: external_exports.enum(["auto", "reference", "edit", "extend"]).optional().describe(
21996
22075
  "O que fazer com os v\xEDdeos de refer\xEAncia (s\xF3 seedance-2.5): `reference` gera um v\xEDdeo novo; `edit` edita o original (exige 1 v\xEDdeo de 4-30s, a dura\xE7\xE3o vira a dele); `extend` estende o original. Sem isto o modelo adivinha e um par\xE2metro incompat\xEDvel s\xF3 falha DEPOIS da fila."
21997
22076
  ),
21998
- project: external_exports.string().max(64).optional().describe('Projeto (uuid OU code curto, ex.: "VRAO-26"). S\xF3 omita se o usu\xE1rio J\xC1 confirmou o projeto ativo nesta sess\xE3o.')
22077
+ project: external_exports.string().max(64).optional().describe('Projeto (uuid OU code curto, ex.: "VRAO-26"). S\xF3 omita se o usu\xE1rio J\xC1 confirmou o projeto ativo nesta sess\xE3o.'),
22078
+ billing: BILLING_FIELD,
22079
+ draft: external_exports.boolean().optional().describe(
22080
+ 'Draft Mode (s\xF3 seedance-2.5, lan\xE7ado pela BytePlus em 22/set/2026): gera um preview 480p barato para validar composi\xE7\xE3o/movimento antes de pagar o 1080p. Depois de check_generation mostrar "completed", o `draft_task_id` vem no retorno \u2014 \xE9 o que voc\xEA passa no pr\xF3ximo generate_video para render a vers\xE3o final, a mesma tomada, sem regenerar do zero.'
22081
+ ),
22082
+ draft_task_id: external_exports.string().min(1).optional().describe(
22083
+ "Gera a vers\xE3o 1080p de um draft j\xE1 pronto (feito com `draft: true`). Passe aqui o `draft_task_id` que check_generation devolveu para aquele draft \u2014 N\xC3O o generation_id. Prompt/refs/seed/ratio/\xE1udio s\xE3o HERDADOS do draft, n\xE3o os reenvie. `duration` \xE9 OBRIGAT\xD3RIO e tem que ser exatamente a dura\xE7\xE3o do draft original (\xE9 o que precifica certo); `resolution` \xE9 sempre 1080p. Drafts expiram em 7 dias."
22084
+ )
21999
22085
  }
22000
22086
  },
22001
22087
  async (args) => {
@@ -22015,6 +22101,20 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22015
22101
  if (!isSeedance25 && args.output_format && args.output_format !== "mp4") {
22016
22102
  return errorResult(`output_format ${args.output_format} s\xF3 existe no seedance-2.5 (voc\xEA pediu ${args.model}).`);
22017
22103
  }
22104
+ if ((args.draft || args.draft_task_id) && !isSeedance25) {
22105
+ return errorResult(`Draft Mode s\xF3 existe no seedance-2.5 (voc\xEA pediu ${args.model}).`);
22106
+ }
22107
+ if (!args.draft_task_id && !args.prompt) {
22108
+ return errorResult("`prompt` \xE9 obrigat\xF3rio (s\xF3 pode faltar ao usar `draft_task_id`).");
22109
+ }
22110
+ if (args.draft_task_id) {
22111
+ if (args.duration == null) {
22112
+ return errorResult("Ao usar `draft_task_id`, `duration` \xE9 obrigat\xF3rio \u2014 a mesma dura\xE7\xE3o do draft original.");
22113
+ }
22114
+ if (args.resolution && args.resolution !== "1080p") {
22115
+ return errorResult('O upscale de um draft s\xF3 gera em 1080p \u2014 omita `resolution` ou use "1080p".');
22116
+ }
22117
+ }
22018
22118
  if (!isSeedance25 && args.video_task_type && args.video_task_type !== "auto") {
22019
22119
  return errorResult(`Editar e estender v\xEDdeo s\xF3 existe no seedance-2.5 (voc\xEA pediu ${args.model}).`);
22020
22120
  }
@@ -22048,7 +22148,12 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22048
22148
  const referenceAudios = await resolveRefs(cfg, args.reference_audios);
22049
22149
  const motionVideo = await resolveRef(cfg, args.motion_video);
22050
22150
  const refVideos = await resolveRefs(cfg, args.reference_videos);
22051
- const input = compact({
22151
+ const input = args.draft_task_id ? compact({
22152
+ draft_task_id: args.draft_task_id,
22153
+ resolution: "1080p",
22154
+ duration: args.duration,
22155
+ output_format: args.output_format
22156
+ }) : compact({
22052
22157
  prompt: args.prompt,
22053
22158
  aspect_ratio: args.aspect_ratio ?? DEFAULTS.videoAspect,
22054
22159
  resolution: args.resolution ?? DEFAULTS.videoResolution,
@@ -22067,10 +22172,16 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22067
22172
  keep_original_sound: args.keep_original_sound,
22068
22173
  seed: args.seed,
22069
22174
  output_format: args.output_format,
22070
- omni_reference_task_type: args.video_task_type
22175
+ omni_reference_task_type: args.video_task_type,
22176
+ draft: args.draft
22071
22177
  });
22072
22178
  const start = await client.startGeneration(
22073
- compact({ model: args.model, input, project: args.project ?? cfg.activeProject ?? void 0 })
22179
+ compact({
22180
+ model: args.model,
22181
+ input,
22182
+ project: resolveProjectArg(args.project, args.billing, cfg.activeProject),
22183
+ billing: args.billing
22184
+ })
22074
22185
  );
22075
22186
  if (!start.success || !start.generation_id) {
22076
22187
  if (isTeamGatingError(start.message)) return errorResult(await buildPickProjectMessage(client));
@@ -22120,8 +22231,11 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22120
22231
  const urls = outputUrls(status);
22121
22232
  const blocks = await buildImageBlocks(urls, cfg);
22122
22233
  const list = urls.map((u, i) => `${i + 1}. ${u}`).join("\n") || "(sem URLs)";
22234
+ const draftHint = status.draft_task_id ? `
22235
+
22236
+ \u{1F3AC} Draft pronto \u2014 pra gerar em 1080p, chame generate_video de novo com draft_task_id: "${status.draft_task_id}" (mesma duration deste draft).` : "";
22123
22237
  return { content: [{ type: "text", text: `\u2705 Pronto.
22124
- ${list}${flagsLine(status)}` }, ...blocks] };
22238
+ ${list}${flagsLine(status)}${draftHint}` }, ...blocks] };
22125
22239
  }
22126
22240
  if (status.status === "failed") {
22127
22241
  return errorResult(`Gera\xE7\xE3o falhou: ${status.error_message || "erro desconhecido"}.`);
@@ -22549,6 +22663,9 @@ function registerUpscaleTools(server, client, cfg) {
22549
22663
  "Modelo do Topaz. Imagem: Wonder 3 (padr\xE3o, serve para quase tudo), Wonder 3.5 (detalhe fino), Wonder 2, Wonder, Recover 3 (imagem muito danificada), Standard MAX (fiel ao original), Redefine (usa a descri\xE7\xE3o), Recovery V2, Recovery. V\xEDdeo: Starlight Precise 2.6 (padr\xE3o), Starlight HQ, Starlight Mini, Starlight Sharp, Starlight Fast 2 (mais r\xE1pido e custa metade)."
22550
22664
  ),
22551
22665
  project: external_exports.string().max(64).optional().describe('Projeto de destino (uuid OU code curto, ex.: "VRAO-26"). Ausente \u2192 projeto ativo.'),
22666
+ billing: external_exports.enum(["personal"]).optional().describe(
22667
+ '"personal" = cobra do seu diamante pessoal, IGNORANDO o projeto ativo (mesmo se houver um). Use quando quiser garantir que isto N\xC3O sai do budget de nenhum projeto. Incompat\xEDvel com `project`.'
22668
+ ),
22552
22669
  // ── só imagem ────────────────────────────────────────────────────────
22553
22670
  output_format: external_exports.enum(["jpeg", "png"]).optional().describe("[imagem] Formato da sa\xEDda. Padr\xE3o png."),
22554
22671
  subject_detection: external_exports.enum(["All", "Foreground", "Background"]).optional().describe("[imagem] Onde aplicar: imagem toda, s\xF3 o primeiro plano ou s\xF3 o fundo. Padr\xE3o All."),
@@ -22666,7 +22783,8 @@ function registerUpscaleTools(server, client, cfg) {
22666
22783
  compact({
22667
22784
  model: isVideo ? VIDEO_MODEL : IMAGE_MODEL,
22668
22785
  input,
22669
- project: args.project ?? cfg.activeProject ?? void 0
22786
+ project: resolveProjectArg(args.project, args.billing, cfg.activeProject),
22787
+ billing: args.billing
22670
22788
  })
22671
22789
  );
22672
22790
  if (!start.success || !start.generation_id) {
@@ -22787,7 +22905,10 @@ function registerMusicTools(server, client, cfg) {
22787
22905
  negative_tags: external_exports.string().max(1e3).optional().describe("Estilos/elementos a evitar."),
22788
22906
  style_weight: external_exports.number().min(0).max(1).optional().describe("Peso do estilo (0\u20131). Maior = segue mais as tags. Omita para o modelo decidir."),
22789
22907
  weirdness_constraint: external_exports.number().min(0).max(1).optional().describe("Criatividade/imprevisibilidade (0\u20131). Omita para o modelo decidir."),
22790
- project: external_exports.string().max(64).optional().describe('Projeto (uuid OU code curto, ex.: "VRAO-26"). S\xF3 omita se o usu\xE1rio J\xC1 confirmou o projeto ativo nesta sess\xE3o.')
22908
+ project: external_exports.string().max(64).optional().describe('Projeto (uuid OU code curto, ex.: "VRAO-26"). S\xF3 omita se o usu\xE1rio J\xC1 confirmou o projeto ativo nesta sess\xE3o.'),
22909
+ billing: external_exports.enum(["personal"]).optional().describe(
22910
+ '"personal" = cobra do seu diamante pessoal, IGNORANDO o projeto ativo (mesmo se houver um). Use quando quiser garantir que isto N\xC3O sai do budget de nenhum projeto. Incompat\xEDvel com `project`.'
22911
+ )
22791
22912
  }
22792
22913
  },
22793
22914
  async (args) => {
@@ -22817,7 +22938,12 @@ function registerMusicTools(server, client, cfg) {
22817
22938
  input.prompt = desc;
22818
22939
  }
22819
22940
  const start = await client.startGeneration(
22820
- compact({ model: args.model, input, project: args.project ?? cfg.activeProject ?? void 0 })
22941
+ compact({
22942
+ model: args.model,
22943
+ input,
22944
+ project: resolveProjectArg(args.project, args.billing, cfg.activeProject),
22945
+ billing: args.billing
22946
+ })
22821
22947
  );
22822
22948
  if (!start.success || !start.generation_id) {
22823
22949
  if (isTeamGatingError(start.message)) return errorResult(await buildPickProjectMessage(client));
@@ -22904,7 +23030,7 @@ ${budget}` : "")
22904
23030
  "list_models",
22905
23031
  {
22906
23032
  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.",
23033
+ 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
23034
  inputSchema: {
22909
23035
  kind: external_exports.enum(["image", "video", "audio", "all"]).default("all").optional().describe("Filtrar por tipo.")
22910
23036
  }
@@ -22916,13 +23042,7 @@ ${budget}` : "")
22916
23042
  const price = typeof x.pricing === "number" ? `$${x.pricing}` : JSON.stringify(x.pricing);
22917
23043
  return `\u2022 ${x.model} \u2014 ${price} (base USD)`;
22918
23044
  });
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")}` : "";
23045
+ const analyzeBlock = analyzeCatalogBlock(m.analyze);
22926
23046
  const txt = `Modelos de gera\xE7\xE3o:
22927
23047
  ${lines.join("\n") || "(nenhum)"}` + analyzeBlock + `
22928
23048
 
@@ -23009,16 +23129,23 @@ function registerAnalyzeTools(server, client, cfg) {
23009
23129
  server.registerTool(
23010
23130
  "analyze_media",
23011
23131
  {
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.",
23132
+ title: "Analisar m\xEDdia (Gemini, Claude e GPT)",
23133
+ 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
23134
  inputSchema: {
23015
23135
  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
23136
  media_urls: external_exports.array(external_exports.string().min(1)).max(50).optional().describe(
23017
23137
  "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
23138
  ),
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)."),
23139
+ // String livre, não z.enum: quem valida o apelido é o backend, então um
23140
+ // modelo novo no catálogo passa a valer sem republicar o pacote.
23141
+ model: external_exports.string().min(1).default("gemini-flash").optional().describe(
23142
+ "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."
23143
+ ),
23020
23144
  project: external_exports.string().optional().describe(
23021
23145
  'Projeto (uuid ou code curto, ex.: "ICONS") de cujo budget cobrar. Omitido \u2192 usa o projeto ativo da conta.'
23146
+ ),
23147
+ billing: external_exports.enum(["personal"]).optional().describe(
23148
+ '"personal" = cobra do seu diamante pessoal, IGNORANDO o projeto ativo (mesmo se houver um). Use quando quiser garantir que isto N\xC3O sai do budget de nenhum projeto. Incompat\xEDvel com `project`.'
23022
23149
  )
23023
23150
  }
23024
23151
  },
@@ -23030,7 +23157,8 @@ function registerAnalyzeTools(server, client, cfg) {
23030
23157
  prompt: args.prompt,
23031
23158
  media_urls,
23032
23159
  model: args.model,
23033
- project: args.project
23160
+ project: args.project,
23161
+ billing: args.billing
23034
23162
  })
23035
23163
  );
23036
23164
  const origem = res.chargedFrom === "budget" ? "restam no budget do projeto" : res.chargedFrom === "weekly_allowance" ? "restam no cr\xE9dito semanal" : res.chargedFrom === "unlimited" ? "limite livre" : "saldo pessoal";
@@ -23320,7 +23448,7 @@ ${calls.map(callLine).join("\n\n")}`);
23320
23448
  import { createRequire } from "module";
23321
23449
  var require2 = createRequire(import.meta.url);
23322
23450
  function readVersion() {
23323
- if ("0.22.0") return "0.22.0";
23451
+ if ("0.24.0") return "0.24.0";
23324
23452
  try {
23325
23453
  const pkg = require2("../package.json");
23326
23454
  return pkg.version ?? "0.0.0-unknown";