beplus-mcp 0.33.0 → 0.35.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
@@ -86,6 +86,9 @@ Reinicie o cliente. Rode a tool **`whoami`** para confirmar o vínculo.
86
86
  | `upscale` | Melhora a resolução de uma imagem ou vídeo que já existe (Topaz). Detecta o tipo pelo arquivo. Imagem até 4x (~20s, a partir de 6💎); vídeo até 30s e saída até 1080p, custa por bloco de 10s e **descarta o áudio**. Mede o arquivo sozinho para o preço sair certo. ⚠️ Vídeo é restrito à equipe. |
87
87
  | `generate_audio` | Sintetiza fala (Gemini TTS, multi-locutor). Padrão `gemini-3.8-flash-lite-tts`; os modelos 3.8 aceitam vozes da biblioteca, tags vocais (`<laugh>`, `<sigh>`...) e `style` por locutor; os legados só as 30 vozes clássicas. Síncrono. |
88
88
  | `list_tts_voices` | Lista as vozes da biblioteca do TTS 3.8 (filtros: idioma, gênero, tom, contexto, busca) com o id para usar em `voice`. Somente leitura. |
89
+ | `list_custom_voices` | Lista suas vozes próprias do TTS 3.8 (máx. 3) com o `voice_xxx` para usar em `voice`. Clonar a própria voz só no app web. Somente leitura. |
90
+ | `design_voice` | Cria uma voz própria a partir de uma descrição. Gasta 💎 e leva ~30 s. |
91
+ | `delete_custom_voice` | Apaga uma voz própria (destrutivo, sem volta). |
89
92
  | `generate_music` | Gera música completa (Suno v5.5 / v4.5) — modo descrição ou letra própria, tags, instrumental, vocal_gender, controles criativos. Async. |
90
93
  | `check_generation` | Status de uma geração async por id. |
91
94
  | `cancel_generation` | Cancela uma geração em fila/processamento (estorna diamantes). |
package/dist/index.js CHANGED
@@ -21624,6 +21624,16 @@ var BeplusClient = class {
21624
21624
  ttsVoices(query) {
21625
21625
  return this.request("GET", "/tts/voices", { query, timeoutMs: 2e4 });
21626
21626
  }
21627
+ customVoices() {
21628
+ return this.request("GET", "/tts/custom-voices", { timeoutMs: 2e4 });
21629
+ }
21630
+ // Leva ~30 s no Google; 90 s cobre a espera com folga.
21631
+ designVoice(body2) {
21632
+ return this.request("POST", "/tts/custom-voices/design", { body: body2, timeoutMs: 9e4 });
21633
+ }
21634
+ deleteCustomVoice(id) {
21635
+ return this.request("DELETE", `/tts/custom-voices/${encodeURIComponent(id)}`, { timeoutMs: 3e4 });
21636
+ }
21627
21637
  models() {
21628
21638
  return this.request("GET", "/models");
21629
21639
  }
@@ -22188,6 +22198,7 @@ var TTS_MODELS = [
22188
22198
  "gemini-2.5-pro-preview-tts"
22189
22199
  ];
22190
22200
  var TTS_MODELS_38 = ["gemini-3.8-flash-lite-tts", "gemini-3.8-flash-tts"];
22201
+ var CUSTOM_VOICE_ID = /^voice_[a-z0-9]{6,64}$/;
22191
22202
  var LIBRARY_VOICE_ID = /^[a-z]{2,3}-[a-z0-9]{2,4}-[a-z0-9-]{1,60}$/;
22192
22203
  var VOICES = [
22193
22204
  "Zephyr",
@@ -22535,7 +22546,7 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22535
22546
  "generate_video",
22536
22547
  {
22537
22548
  title: "Gerar v\xEDdeo",
22538
- description: "Gera um v\xEDdeo curto usando o IA Lab da BePlus. LENTO (geralmente 1-5+ min). Aguarda at\xE9 ~2 min; se n\xE3o terminar, retorna o generation_id e o status \u2014 ent\xE3o use check_generation. Consome diamantes (mais caro para dura\xE7\xF5es/resolu\xE7\xF5es maiores). Suporta image-to-video (`first_frame_image`), \xFAltimo frame (`last_frame_image`), refer\xEAncias de imagem/v\xEDdeo/\xE1udio, prompt negativo, \xE1udio gerado e mais \u2014 os campos aceitos variam por modelo (consulte list_models). `kling-v2.6-motion-control` usa `first_frame_image` + `motion_video`. Nos modelos Seedance, refer\xEAncia com rosto de pessoa REAL \xE9 bloqueada pelo provedor padr\xE3o (BytePlus) \u2014 use `real_people_references: true` para rotear pra fal.ai, que aceita (custa mais caro). Kling e outros provedores n\xE3o t\xEAm essa op\xE7\xE3o." + TEAM_GATING_NOTE,
22549
+ description: "Gera um v\xEDdeo curto usando o IA Lab da BePlus. LENTO (geralmente 1-5+ min). Aguarda at\xE9 ~2 min; se n\xE3o terminar, retorna o generation_id e o status \u2014 ent\xE3o use check_generation. Consome diamantes (mais caro para dura\xE7\xF5es/resolu\xE7\xF5es maiores). Suporta image-to-video (`first_frame_image`), \xFAltimo frame (`last_frame_image`), refer\xEAncias de imagem/v\xEDdeo/\xE1udio, prompt negativo, \xE1udio gerado e mais \u2014 os campos aceitos variam por modelo (consulte list_models). `kling-v2.6-motion-control` usa `first_frame_image` + `motion_video`. Nos modelos Seedance d\xE1 pra escolher o provedor com `provider`: `byteplus` (padr\xE3o) ou `fal`. A BytePlus bloqueia refer\xEAncia com rosto de pessoa REAL; a fal.ai aceita (custa mais caro) e \xE9 a alternativa quando a BytePlus estiver inst\xE1vel. Kling e outros modelos n\xE3o t\xEAm essa op\xE7\xE3o." + TEAM_GATING_NOTE,
22539
22550
  inputSchema: {
22540
22551
  // Sem teto local — ver nota em generate_image. O Seedance não publica
22541
22552
  // limite; o Kling publica 2500 e o backend recusa dizendo quanto cortar.
@@ -22571,16 +22582,17 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22571
22582
  video_task_type: external_exports.enum(["auto", "reference", "edit", "extend"]).optional().describe(
22572
22583
  "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."
22573
22584
  ),
22574
- real_people_references: external_exports.boolean().optional().describe(
22575
- 'S\xF3 Seedance (2.0/2.0-fast/2.0-mini/2.5): quando true, roteia pra fal.ai em vez da BytePlus \u2014 a BytePlus recusa refer\xEAncia com pessoa real, a fal aceita (mais caro). `first_frame_image` + `last_frame_image` continuam funcionando (viram image-to-video da fal, com end frame). Com isto ligado, `output_format` e `video_task_type` (edit/extend) n\xE3o t\xEAm equivalente na fal e s\xE3o recusados antes de cobrar \u2014 e `seedance-2.0-fast` com `resolution: "480p"` tamb\xE9m, porque a fal n\xE3o publica pre\xE7o para essa combina\xE7\xE3o.'
22585
+ provider: external_exports.enum(["byteplus", "fal"]).optional().describe(
22586
+ "S\xF3 Seedance (2.0/2.0-fast/2.0-mini/2.5): qual empresa gera o v\xEDdeo. `byteplus` (padr\xE3o) \xE9 a API oficial da ByteDance. `fal` usa a fal.ai: aceita refer\xEAncia com pessoa real (a BytePlus recusa) e custa mais caro. Na fal, `first_frame_image` + `last_frame_image` funcionam (image-to-video com end frame) e o Draft Mode funciona no seedance-2.5; `output_format` e `video_task_type` (edit/extend) n\xE3o t\xEAm equivalente e s\xE3o recusados antes de cobrar, assim como `seedance-2.0-fast` em 480p (a fal n\xE3o publica pre\xE7o para essa combina\xE7\xE3o)."
22576
22587
  ),
22588
+ real_people_references: external_exports.boolean().optional().describe('OBSOLETO: use `provider: "fal"`. `true` aqui equivale a `provider: "fal"`.'),
22577
22589
  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.'),
22578
22590
  billing: BILLING_FIELD,
22579
22591
  draft: external_exports.boolean().optional().describe(
22580
- '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.'
22592
+ 'Draft Mode (s\xF3 seedance-2.5, nos dois provedores): gera um preview 480p barato para validar composi\xE7\xE3o/movimento antes de pagar o 1080p. `resolution` fica em 480p (omita ou use "480p"). Depois de check_generation mostrar "completed", o `draft_task_id` e o provedor v\xEAm 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.'
22581
22593
  ),
22582
22594
  draft_task_id: external_exports.string().min(1).optional().describe(
22583
- "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."
22595
+ "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 \u2014 e o MESMO `provider` do draft (o id s\xF3 vale no provedor que gerou). 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."
22584
22596
  )
22585
22597
  }
22586
22598
  },
@@ -22607,6 +22619,12 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22607
22619
  if (!args.draft_task_id && !args.prompt) {
22608
22620
  return errorResult("`prompt` \xE9 obrigat\xF3rio (s\xF3 pode faltar ao usar `draft_task_id`).");
22609
22621
  }
22622
+ if (args.draft && args.draft_task_id) {
22623
+ return errorResult("Use `draft` OU `draft_task_id`, n\xE3o os dois no mesmo pedido.");
22624
+ }
22625
+ if (args.draft && args.resolution && args.resolution !== "480p") {
22626
+ return errorResult('O Draft Mode s\xF3 gera em 480p \u2014 omita `resolution` ou use "480p".');
22627
+ }
22610
22628
  if (args.draft_task_id) {
22611
22629
  if (args.duration == null) {
22612
22630
  return errorResult("Ao usar `draft_task_id`, `duration` \xE9 obrigat\xF3rio \u2014 a mesma dura\xE7\xE3o do draft original.");
@@ -22618,21 +22636,24 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22618
22636
  if (!isSeedance25 && args.video_task_type && args.video_task_type !== "auto") {
22619
22637
  return errorResult(`Editar e estender v\xEDdeo s\xF3 existe no seedance-2.5 (voc\xEA pediu ${args.model}).`);
22620
22638
  }
22621
- if (args.real_people_references && !args.model?.startsWith("bytedance/seedance-")) {
22622
- return errorResult(`real_people_references s\xF3 existe nos modelos Seedance (voc\xEA pediu ${args.model}).`);
22639
+ const isSeedance = !!args.model?.startsWith("bytedance/seedance-");
22640
+ if ((args.provider || args.real_people_references) && !isSeedance) {
22641
+ return errorResult(`A escolha de provedor (provider/real_people_references) s\xF3 existe nos modelos Seedance (voc\xEA pediu ${args.model}).`);
22642
+ }
22643
+ if (args.provider === "byteplus" && args.real_people_references) {
22644
+ return errorResult('`real_people_references: true` usa a fal.ai e contradiz `provider: "byteplus"`. Use s\xF3 `provider`.');
22623
22645
  }
22624
- if (args.real_people_references) {
22646
+ const seedanceProvider = args.provider ?? (args.real_people_references ? "fal" : void 0);
22647
+ if (seedanceProvider === "fal") {
22625
22648
  const unsupported = [];
22626
22649
  if (args.output_format && args.output_format !== "mp4") unsupported.push("output_format");
22627
22650
  if (args.video_task_type && args.video_task_type !== "auto") unsupported.push("video_task_type (edit/extend)");
22628
22651
  if (args.model === "bytedance/seedance-2.0-fast" && args.resolution === "480p") {
22629
22652
  unsupported.push("resolution 480p (a fal n\xE3o publica pre\xE7o para seedance-2.0-fast nesta resolu\xE7\xE3o)");
22630
22653
  }
22631
- if (args.draft) unsupported.push("draft (Modo Rascunho \u2014 s\xF3 existe na BytePlus)");
22632
- if (args.draft_task_id) unsupported.push("draft_task_id (upscale de rascunho \u2014 s\xF3 existe na BytePlus)");
22633
22654
  if (unsupported.length > 0) {
22634
22655
  return errorResult(
22635
- `Com real_people_references, a fal.ai n\xE3o suporta: ${unsupported.join(", ")}. Remova essas op\xE7\xF5es.`
22656
+ `Com provider "fal", a fal.ai n\xE3o suporta: ${unsupported.join(", ")}. Remova essas op\xE7\xF5es.`
22636
22657
  );
22637
22658
  }
22638
22659
  }
@@ -22670,11 +22691,12 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22670
22691
  draft_task_id: args.draft_task_id,
22671
22692
  resolution: "1080p",
22672
22693
  duration: args.duration,
22673
- output_format: args.output_format
22694
+ output_format: args.output_format,
22695
+ seedanceProvider
22674
22696
  }) : compact({
22675
22697
  prompt: args.prompt,
22676
22698
  aspect_ratio: args.aspect_ratio ?? DEFAULTS.videoAspect,
22677
- resolution: args.resolution ?? DEFAULTS.videoResolution,
22699
+ resolution: args.resolution ?? (args.draft ? "480p" : DEFAULTS.videoResolution),
22678
22700
  duration: args.duration ?? DEFAULTS.videoDuration,
22679
22701
  negative_prompt: args.negative_prompt,
22680
22702
  mode: args.mode,
@@ -22692,7 +22714,7 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22692
22714
  output_format: args.output_format,
22693
22715
  omni_reference_task_type: args.video_task_type,
22694
22716
  draft: args.draft,
22695
- realPeopleReferences: args.real_people_references
22717
+ seedanceProvider
22696
22718
  });
22697
22719
  const start = await client.startGeneration(
22698
22720
  compact({
@@ -22750,9 +22772,10 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
22750
22772
  const urls = outputUrls(status);
22751
22773
  const blocks = await buildImageBlocks(urls, cfg);
22752
22774
  const list = urls.map((u, i) => `${i + 1}. ${u}`).join("\n") || "(sem URLs)";
22775
+ const draftProvider = status.seedance_provider ?? "byteplus";
22753
22776
  const draftHint = status.draft_task_id ? `
22754
22777
 
22755
- \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).` : "";
22778
+ \u{1F3AC} Draft pronto (provedor: ${draftProvider === "fal" ? "fal.ai" : "BytePlus"}) \u2014 pra gerar em 1080p, chame generate_video de novo com draft_task_id: "${status.draft_task_id}", provider: "${draftProvider}" e a mesma duration deste draft.` : "";
22756
22779
  return { content: [{ type: "text", text: `\u2705 Pronto.
22757
22780
  ${list}${flagsLine(status)}${draftHint}` }, ...blocks] };
22758
22781
  }
@@ -23471,9 +23494,16 @@ ${BUDGET_BLOCKED_GUIDANCE}`);
23471
23494
 
23472
23495
  // src/tools/audio.ts
23473
23496
  var VOICE_HELP = "Uma das 30 vozes cl\xE1ssicas (Kore, Puck, Charon...) OU o id de uma voz da biblioteca (ex.: pt-br-advisor-10, s\xF3 nos modelos 3.8; descubra ids com list_tts_voices).";
23497
+ var VOICE_HELP_TOP = `${VOICE_HELP} Ou o id de uma voz pr\xF3pria (voice_xxx, de list_custom_voices; s\xF3 3.8 e sem multi_speaker).`;
23474
23498
  var voiceSchema = external_exports.string().refine((v) => VOICES.includes(v) || LIBRARY_VOICE_ID.test(v), {
23475
23499
  message: "Voz inv\xE1lida: use uma das 30 vozes cl\xE1ssicas (ex.: Kore) ou um id da biblioteca (ex.: pt-br-advisor-10)."
23476
23500
  });
23501
+ var topVoiceSchema = external_exports.string().refine((v) => VOICES.includes(v) || LIBRARY_VOICE_ID.test(v) || CUSTOM_VOICE_ID.test(v), {
23502
+ message: "Voz inv\xE1lida: use uma das 30 vozes cl\xE1ssicas (ex.: Kore), um id da biblioteca (ex.: pt-br-advisor-10) ou uma voz pr\xF3pria (voice_xxx)."
23503
+ });
23504
+ function isCustomVoice(v) {
23505
+ return CUSTOM_VOICE_ID.test(v);
23506
+ }
23477
23507
  function isLibraryVoice(v) {
23478
23508
  return !VOICES.includes(v) && LIBRARY_VOICE_ID.test(v);
23479
23509
  }
@@ -23487,10 +23517,10 @@ function registerAudioTools(server, client, cfg) {
23487
23517
  "generate_audio",
23488
23518
  {
23489
23519
  title: "Gerar \xE1udio (TTS)",
23490
- description: 'Sintetiza fala a partir de texto (s\xEDncrono \u2014 retorna a URL na hora) usando o IA Lab da BePlus. Modelos Gemini 3.8 (`gemini-3.8-flash-lite-tts`, padr\xE3o, r\xE1pido e barato; `gemini-3.8-flash-tts`, qualidade de est\xFAdio, melhor para di\xE1logo e narra\xE7\xE3o longa) aceitam: vozes da biblioteca (milhares, por idioma; liste com `list_tts_voices` e passe o id em `voice`), tags vocais no texto como <laugh> <chuckle> <sigh> <breath> <gasp> <cough> <sneeze> <throat-clearing> <yawn> <groan> <scream> <whimper> <argh> <short pause> <long pause> (viram som de verdade), e estilo por locutor (`style` em cada speaker). No 3.8, `style_instruction` \xE9 dire\xE7\xE3o e N\xC3O \xE9 lida em voz alta. Os modelos legados (`gemini-3.1-flash-tts-preview`, `gemini-2.5-pro-preview-tts`) s\xF3 aceitam as 30 vozes cl\xE1ssicas (Kore, Puck, Charon...) e n\xE3o t\xEAm voz da biblioteca. Opcional `style_instruction` (ex.: "fale animado e pausado") e di\xE1logo com 2 locutores via `multi_speaker`. Consome diamantes por segundo de \xE1udio.' + TEAM_GATING_NOTE,
23520
+ description: 'Sintetiza fala a partir de texto (s\xEDncrono \u2014 retorna a URL na hora) usando o IA Lab da BePlus. Modelos Gemini 3.8 (`gemini-3.8-flash-lite-tts`, padr\xE3o, r\xE1pido e barato; `gemini-3.8-flash-tts`, qualidade de est\xFAdio, melhor para di\xE1logo e narra\xE7\xE3o longa) aceitam: vozes da biblioteca (milhares, por idioma; liste com `list_tts_voices` e passe o id em `voice`), tags vocais no texto como <laugh> <chuckle> <sigh> <breath> <gasp> <cough> <sneeze> <throat-clearing> <yawn> <groan> <scream> <whimper> <argh> <short pause> <long pause> (viram som de verdade), e estilo por locutor (`style` em cada speaker). No 3.8, `style_instruction` \xE9 dire\xE7\xE3o e N\xC3O \xE9 lida em voz alta. Os modelos legados (`gemini-3.1-flash-tts-preview`, `gemini-2.5-pro-preview-tts`) s\xF3 aceitam as 30 vozes cl\xE1ssicas (Kore, Puck, Charon...) e n\xE3o t\xEAm voz da biblioteca. Vozes pr\xF3prias (voice_xxx; liste com `list_custom_voices`, crie com `design_voice`) s\xF3 no 3.8 e sem `multi_speaker`. No 3.8, dire\xE7\xE3o por linha: `(sussurrando) texto` no in\xEDcio da linha vale at\xE9 a pr\xF3xima dire\xE7\xE3o; no di\xE1logo, `Ana (rindo): fala`; rea\xE7\xF5es `|hmm|` `|aham|` no meio da fala (s\xF3 di\xE1logo). Opcional `style_instruction` (ex.: "fale animado e pausado") e di\xE1logo com 2 locutores via `multi_speaker`. Consome diamantes por segundo de \xE1udio.' + TEAM_GATING_NOTE,
23491
23521
  inputSchema: {
23492
23522
  text: external_exports.string().min(1).max(1e4).describe("Texto a ser falado."),
23493
- voice: voiceSchema.default(DEFAULTS.voice).describe(VOICE_HELP),
23523
+ voice: topVoiceSchema.default(DEFAULTS.voice).describe(VOICE_HELP_TOP),
23494
23524
  model: external_exports.enum(TTS_MODELS).default(DEFAULTS.ttsModel).describe("Modelo TTS."),
23495
23525
  style_instruction: external_exports.string().max(2e3).optional().describe("Instru\xE7\xE3o de estilo/tom aplicada \xE0 fala."),
23496
23526
  multi_speaker: external_exports.object({
@@ -23504,6 +23534,14 @@ function registerAudioTools(server, client, cfg) {
23504
23534
  try {
23505
23535
  const ms = args.multi_speaker;
23506
23536
  const voices = [args.voice, ms?.speaker1.voice, ms?.speaker2.voice].filter((v) => !!v);
23537
+ if (isCustomVoice(args.voice)) {
23538
+ if (!TTS_MODELS_38.includes(args.model)) {
23539
+ return errorResult("Vozes pr\xF3prias s\xF3 funcionam nos modelos Gemini 3.8 (gemini-3.8-flash-lite-tts, gemini-3.8-flash-tts).");
23540
+ }
23541
+ if (ms) {
23542
+ return errorResult("Vozes pr\xF3prias n\xE3o funcionam no modo di\xE1logo (multi_speaker). Use uma voz da biblioteca ou cl\xE1ssica.");
23543
+ }
23544
+ }
23507
23545
  if (!TTS_MODELS_38.includes(args.model)) {
23508
23546
  if (voices.some(isLibraryVoice)) {
23509
23547
  return errorResult(
@@ -23586,6 +23624,80 @@ Contextos: ${res.contexts.join(", ")}.`
23586
23624
  }
23587
23625
  }
23588
23626
  );
23627
+ server.registerTool(
23628
+ "list_custom_voices",
23629
+ {
23630
+ title: "Listar vozes pr\xF3prias",
23631
+ description: "Lista as suas vozes pr\xF3prias do TTS 3.8 (m\xE1x. 3, guardadas por 1 ano). Passe o campo `voice` (voice_xxx) em `voice` do generate_audio com um modelo 3.8, sem multi_speaker. Crie com `design_voice`. Clonar a pr\xF3pria voz exige grava\xE7\xE3o de consentimento ao vivo e s\xF3 existe no app web. Somente leitura, sem custo.",
23632
+ inputSchema: {}
23633
+ },
23634
+ async () => {
23635
+ try {
23636
+ const res = await client.customVoices();
23637
+ const head = `Vozes pr\xF3prias: ${res.used} de ${res.limit}. Criar uma voz custa ${res.design_cost} \u{1F48E}.`;
23638
+ if (!res.voices.length) return textResult(`${head}
23639
+ Nenhuma ainda. Use design_voice para criar.`);
23640
+ const lines = res.voices.map(
23641
+ (v) => `${v.id} | ${v.voice} | ${v.name} | ${v.kind} | expira ${v.expires_at.slice(0, 10)}`
23642
+ );
23643
+ return textResult(
23644
+ `${head} (id | voice | nome | tipo | validade):
23645
+ ${lines.join("\n")}
23646
+
23647
+ Use o valor de "voice" (voice_xxx) no generate_audio. Para apagar, use o "id" em delete_custom_voice.`
23648
+ );
23649
+ } catch (e) {
23650
+ return errorResult(apiErrorToUserMessage(e));
23651
+ }
23652
+ }
23653
+ );
23654
+ server.registerTool(
23655
+ "design_voice",
23656
+ {
23657
+ title: "Criar voz pr\xF3pria por descri\xE7\xE3o",
23658
+ description: "Cria uma voz pr\xF3pria a partir de uma descri\xE7\xE3o em texto (idade, timbre, sotaque, jeito de falar). GASTA diamantes (o custo aparece em list_custom_voices; estorna se falhar) e leva cerca de 30 s. M\xE1x. 3 vozes por pessoa; a voz fica guardada por 1 ano. Depois use o `voice` retornado no generate_audio (modelos 3.8, sem multi_speaker).",
23659
+ inputSchema: {
23660
+ name: external_exports.string().min(1).max(40).describe("Nome da voz (1 a 40 caracteres)."),
23661
+ description: external_exports.string().min(10).max(500).describe("Como \xE9 a voz: idade, g\xEAnero, timbre, sotaque, jeito de falar (10 a 500 caracteres)."),
23662
+ language: external_exports.string().max(12).optional().describe("Idioma BCP-47. Padr\xE3o pt-BR."),
23663
+ gender: external_exports.enum(["female", "male", "neutral"]).optional()
23664
+ }
23665
+ },
23666
+ async (args) => {
23667
+ try {
23668
+ const res = await client.designVoice(compact(args));
23669
+ const v = res.voice;
23670
+ return textResult(
23671
+ `\u2705 Voz criada: ${v.name} (${v.kind}).
23672
+ voice: ${v.voice}
23673
+ id: ${v.id}
23674
+ ` + (v.sample_url ? `Amostra: ${v.sample_url}
23675
+ ` : "") + `Custo: ${res.diamond_cost} \u{1F48E} \xB7 Saldo: ${res.new_balance} \u{1F48E} \xB7 Expira em ${v.expires_at.slice(0, 10)}.
23676
+ Use o valor de "voice" no generate_audio com um modelo 3.8 (sem multi_speaker).`
23677
+ );
23678
+ } catch (e) {
23679
+ return errorResult(apiErrorToUserMessage(e));
23680
+ }
23681
+ }
23682
+ );
23683
+ server.registerTool(
23684
+ "delete_custom_voice",
23685
+ {
23686
+ title: "Apagar voz pr\xF3pria",
23687
+ description: "DESTRUTIVO e sem volta: apaga uma voz pr\xF3pria (aqui e no Google) e libera 1 vaga das 3. \xC1udios j\xE1 gerados com ela continuam tocando, mas n\xE3o d\xE1 para gerar novos com essa voz. N\xE3o devolve diamantes. Passe o `id` (uuid) de list_custom_voices, n\xE3o o voice_xxx. Confirme com o usu\xE1rio antes.",
23688
+ inputSchema: {
23689
+ id: external_exports.string().uuid().describe('Campo "id" (uuid) da voz em list_custom_voices.')
23690
+ }
23691
+ },
23692
+ async (args) => {
23693
+ try {
23694
+ await client.deleteCustomVoice(args.id);
23695
+ return textResult(`\u2705 Voz ${args.id} apagada. Uma vaga foi liberada.`);
23696
+ } catch (e) {
23697
+ return errorResult(apiErrorToUserMessage(e));
23698
+ }
23699
+ }
23700
+ );
23589
23701
  }
23590
23702
 
23591
23703
  // src/tools/music.ts
@@ -23771,6 +23883,7 @@ Limites simult\xE2neos por usu\xE1rio: imagem=${m.limits.perUserMaxImage}, v\xED
23771
23883
  quality: external_exports.string().optional(),
23772
23884
  aspect_ratio: external_exports.string().optional().describe("Seedream Pro: a propor\xE7\xE3o muda os pixels e a faixa de pre\xE7o."),
23773
23885
  num_images: external_exports.number().int().min(1).optional().describe("Seedream Pro: imagens por pedido; cada uma \xE9 cobrada."),
23886
+ provider: external_exports.enum(["byteplus", "fal"]).optional().describe("Seedance: provedor que vai gerar (padr\xE3o byteplus). `fal` tem pre\xE7o pr\xF3prio, mais caro."),
23774
23887
  // Upscale: o preço não sai de uma chave fixa — vem das medidas do
23775
23888
  // arquivo (megapixel de saída na imagem, bloco de 10s no vídeo). Sem
23776
23889
  // elas o backend responde pelo padrão de 1024²/10s, que não é o preço
@@ -23814,6 +23927,7 @@ Limites simult\xE2neos por usu\xE1rio: imagem=${m.limits.perUserMaxImage}, v\xED
23814
23927
  quality: args.quality,
23815
23928
  aspect_ratio: args.aspect_ratio,
23816
23929
  num_images: args.num_images,
23930
+ seedance_provider: args.provider === "fal" ? "fal" : void 0,
23817
23931
  upscale_factor: args.upscale_factor,
23818
23932
  model_variant: args.model_variant,
23819
23933
  source_width: width2,
@@ -26937,7 +27051,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
26937
27051
  import { createRequire } from "module";
26938
27052
  var require2 = createRequire(import.meta.url);
26939
27053
  function readVersion() {
26940
- if ("0.33.0") return "0.33.0";
27054
+ if ("0.35.0") return "0.35.0";
26941
27055
  try {
26942
27056
  const pkg = require2("../package.json");
26943
27057
  return pkg.version ?? "0.0.0-unknown";