Commit Graph
555 Commits
Author SHA1 Message Date
LizandroandClaude Sonnet 4.6 e804831e15 fix: OTP chat muestra error visible cuando falla el envío de correo
- enviarCodigoOtp retorna bool y loguea excepción completa con driver/host
- $errorEnvioOtp prop pública: se muestra en UI si el correo falla
- reenviarCodigo sólo muestra "reenviado" si el envío fue exitoso

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 21:11:21 +00:00
LizandroandClaude Sonnet 4.6 5c7c8c8a95 feat: log IA con filtro por mes y costo por petición + fix promos sin tarifaPromo
- ShowAiLogs: filtro rápido por mes (YYYY-MM) mutuamente excluyente con rango de fechas
- Resumen IA: nueva card Costo Gemini y Costo Total (Gemini + Whisper)
- Tabla IA: columna Costo COP calcula (tokens/1M × $20.000) para Gemini, costo guardado para Whisper
- PublicChat + TelegramBotService: quita whereHas('tarifaPromo') que ocultaba promos sin tarifa por rol

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 21:08:40 +00:00
LizandroandClaude Sonnet 4.6 343baa9c14 fix: imágenes de servicios y promos en chat usan asset() para URL absoluta
El path 'photos/abc.webp' desde /chat/ se resolvía como /chat/photos/...
que no existe. asset() genera la URL absoluta correcta desde la raíz del sitio.
Se preservan URLs absolutas (http//) sin modificar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 19:48:44 +00:00
LizandroandClaude Sonnet 4.6 a9d0787076 fix: limpiarChat crea conversación nueva en lugar de dejar convId null
Antes: limpiar → convId=null → 'Iniciando chat...' → refresh recuperaba la conv vieja.
Ahora: limpiar → nueva conversación → menú principal inmediato, sin refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 19:00:13 +00:00
LizandroandClaude Sonnet 4.6 7307d87c80 fix: chat bloqueado en 'Iniciando chat...' cuando sesión pierde chat_conv_id
Si el usuario tiene chat_user_id en sesión pero no chat_conv_id (sesión
expirada o servidor reiniciado), mount() ahora busca la conversación activa
del contacto en la BD o crea una nueva. Antes quedaba sin convId y el enviar
no hacía nada.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 18:56:16 +00:00
LizandroandClaude Sonnet 4.6 3ee850776b fix: UNIQUE en pagos_confirmados.email_hash previene doble crédito por race condition
Sin este índice, dos procesos PHP simultáneos podían pasar el check yaUsado()
ambos con false y marcar el mismo hash dos veces, aplicando la recarga doble.
Con UNIQUE, el segundo INSERT falla y el catch existente lo bloquea (falla cerrado).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 15:45:15 +00:00
LizandroandClaude Sonnet 4.6 bb311e7dcd feat: validación exacta de hora + remitente obligatorio + nombres guardados
- Hora exacta: tolerancia 0 (timestamp comprobante = timestamp email)
- Remitente bloquea: si el email trae el nombre del remitente y no coincide, rechaza
- Nuevo paso antes de mostrar datos bancarios: bot pide nombre completo del titular
- Nombres aceptados se guardan en solicitudes_recarga.nombre_remitente
- Próxima recarga: muestra botones con nombres anteriores confirmados o ingresa uno nuevo
- Funciona igual en Telegram y web chat

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 15:27:31 +00:00
LizandroandClaude Sonnet 4.6 b66b828ded fix: tolerancia de hora reducida de ±15 min a ±2 min
El timestamp del correo Bancolombia registra la hora exacta de la transacción,
igual que el comprobante. El retraso es en la llegada al inbox, no en el contenido.
±2 min cubre desfases menores sin permitir cruces entre transacciones cercanas.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 15:20:54 +00:00
LizandroandClaude Sonnet 4.6 65d4155f02 fix: ya_usado no bloquea a otros usuarios con el mismo monto
Con return inmediato, si Usuario A usaba email_A ($20k), Usuario B
(también $20k) encontraba ese email ya_usado y se bloqueaba sin revisar
el email_B que le pertenecía.

Ahora: ya_usado → continue (sigue iterando); solo retorna ya_usado
al final del loop si todos los emails coincidentes estaban agotados
(caso real de comprobante reutilizado).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 15:18:08 +00:00
LizandroandClaude Sonnet 4.6 e42dd40d74 feat: registrar recarga en tabla recargas al auto-aplicar (Telegram y web chat)
Usa el mismo modelo recarga que el flujo admin, con status='Confirmado'
y reference='breb-bot/chat-{solicitud_id}' para trazabilidad.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 15:14:14 +00:00
LizandroandClaude Sonnet 4.6 4b2eb7c709 fix: ya_usado solo dispara cuando el email coincide en fecha, hora y llave
Antes: monto coincide → hash ya_usado → retorna "reutilizado" (falso positivo
si había un email viejo del mismo valor en la ventana IMAP de 120 min).
Ahora: monto + fecha + hora + llave deben coincidir primero; solo entonces
se verifica el hash — garantizando que es el mismo comprobante exacto.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 14:53:49 +00:00
LizandroandClaude Sonnet 4.6 437adc531f fix: verificar solicitud de recarga antes de llamar Gemini Vision e IMAP
Sin solicitud activa el bot mostraba el análisis completo (Gemini + IMAP) antes de rechazar.
Ahora se valida primero: si no hay solicitud pendiente, se rechaza de inmediato sin gastar API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 14:46:21 +00:00
LizandroandClaude Sonnet 4.6 a7d7c32350 feat: sistema de solicitud de recarga con auto-aplicación y botón Reintentar
- SolicitudRecarga: modelo + migración para atar cada intento de recarga al usuario (previene cruce de pagos entre usuarios)
- PublicChat: mostrarTransferencia crea solicitud, updatedFotoComprobante valida contra ella, auto-aplica sin botón extra
- Botón Reintentar en web chat cuando el correo aún no llega (pago_pendiente en flujoData)
- aplicarRecargaValidada corregido: error de sintaxis por fragmento duplicado eliminado

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 14:40:52 +00:00
LizandroandClaude Sonnet 4.6 d5e497bfc5 fix: aviso 15 min va en instrucciones de transferencia, no al recibir foto
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 14:24:27 +00:00
LizandroandClaude Sonnet 4.6 28d3b1c719 feat: botón Reintentar en web chat + aviso de 15 min en ambos canales
- PublicChat: sin_coincidencia guarda datosPago en flujoData, muestra Reintentar
- PublicChat: pago.reintentar re-corre validación sin reenviar foto
- Telegram y web chat: aviso al recibir comprobante (15 min visibles, 30 reales)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 14:19:31 +00:00
LizandroandClaude Sonnet 4.6 d408674e03 feat: botón Reintentar cuando el correo de pago aún no llega
- sin_coincidencia muestra mensaje explicativo + botón Reintentar
- datosPago guardado en estado para reintentar sin reenviar foto
- pay_retry callback: re-corre validación con datos guardados
- Si confirma: limpia pendiente y muestra botón aplicar recarga
- Si sigue sin llegar: mantiene botón Reintentar disponible

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 14:18:00 +00:00
LizandroandClaude Sonnet 4.6 2972891974 fix: tabla pagos_confirmados — nombre explícito en el modelo
Laravel derivaba 'pago_confirmados' pero la migración crea 'pagos_confirmados'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 14:04:51 +00:00
LizandroandClaude Sonnet 4.6 9a8e07cb8a fix: ventana IMAP ampliada a 120 min y límite a 30 correos
Default de 5 min causaba que pagos enviados minutos después del correo
de Bancolombia quedaran fuera de la ventana si había otros correos recientes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 13:58:41 +00:00
LizandroandClaude Sonnet 4.6 b7572a0fb9 fix: bot no improvisa soporte humano — rutas correctas para problemas de acceso
- Keywords: captura "no inicia sesión Netflix", "no abre", "error de acceso" → credenciales.listar
- GeminiAgent prompt: bot no pide pantallazos ni promete revisiones; problemas de acceso → credenciales.listar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 13:47:17 +00:00
LizandroandClaude Sonnet 4.6 a134ad54a6 fix: notificación de vencimiento por todos los canales del cliente
Si el cliente tiene Telegram → mensaje por Telegram.
Si el cliente tiene chat web activo → mensaje en la conversación.
Ambos canales pueden coexistir.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 02:18:57 +00:00
LizandroandClaude Sonnet 4.6 dafe435e69 feat: notificación de vencimiento por Telegram
Cuando el servicio de un cliente vence mañana, además del email existente
se envía mensaje por Telegram si el cliente tiene el bot vinculado.
Busca en chat_contacts canal=telegram con el user_id del cliente.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 02:17:54 +00:00
LizandroandClaude Sonnet 4.6 656b32c706 feat: agente conversacional con extracción de parámetros (GeminiAgentService)
- Nuevo GeminiAgentService: entiende lenguaje natural, responde conversacionalmente
  y extrae acción + parámetros (ej: servicio:"Netflix", monto:50000)
- handleFreeText usa GeminiAgentService en lugar de GeminiIntentService
- dispatchAction acepta accion_data: va directo a Netflix sin pasar por el listado
- viewServiceByName: busca servicio por nombre (ILIKE) y abre sus planes
- Keywords simplificadas: solo intents genéricos sin parámetros

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 01:13:21 +00:00
LizandroandClaude Sonnet 4.6 1adfffd907 fix(telegram): keyword matching antes de Gemini para frases coloquiales de voz
'vamos a hacer una recarga' no era detectado por Gemini (thinkingBudget=0
+ frases coloquiales). Agrega detectarPorKeywords() con regex para las 6
acciones principales. Gemini queda como fallback para casos ambiguos.
También elimina asesor.solicitar del prompt de GeminiIntentService.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 00:30:10 +00:00
LizandroandClaude Sonnet 4.6 aaf395af34 fix(telegram): eliminar checks de estado agente que silenciaban mensajes de voz
Con el asesor removido, el estado 'agente' en conversación bloqueaba
handleText y handleFreeText silenciosamente. Audio transcripto como
'hacer una recarga' no generaba respuesta por este return prematuro.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-19 00:18:26 +00:00
LizandroandClaude Sonnet 4.6 eb448794c5 fix(chat): limpiarChat no cierra sesión, solo borra mensajes
mount() ahora solo requiere chat_user_id (no chat_conv_id) para mantener
al usuario logueado. limpiarChat() borra mensajes y convId pero preserva
userId, nombreUsuario, saldoUsuario y paso='chat'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 19:31:20 +00:00
LizandroandClaude Sonnet 4.6 c3f9984a9d feat(chat): menú tres puntos con Limpiar chat y Cerrar sesión
- Reemplaza botón suelto de logout por dropdown (Alpine.js) con dos opciones
- limpiarChat(): limpia mensajes visibles y cierra conversación actual
- cerrarSesion(): ya existía, se mantiene igual
- Cierra el dropdown al hacer clic fuera (x-click.outside)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 19:27:17 +00:00
LizandroandClaude Sonnet 4.6 4a58b800dc feat(telegram): quitar opción 'Hablar con asesor'
- Eliminar botón del menú principal, pago confirmado, pago no confirmado
- callback 'agent' redirige al menú principal en vez de transferToAgent
- asesor.solicitar del intent también redirige al menú
- Limpiar textos 'contacta a un asesor' en mensajes de error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 19:17:23 +00:00
LizandroandClaude Sonnet 4.6 20d15a640c fix(telegram): await_amount ignorado cuando conversación está en modo agente
El check 'agente' devolvía silenciosamente antes de leer el step,
descartando el texto '1000' del usuario. Si el bot está esperando
input específico (await_amount, await_email, etc.) tiene prioridad
sobre el estado agente de la conversación.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 18:08:53 +00:00
LizandroandClaude Sonnet 4.6 5ea4f3c9e5 fix(seguridad): falla cerrado si anti-duplicado no puede verificar/registrar
Si pagos_confirmados no existe o falla la BD, NO confirmar el pago (fail-closed).
Antes fallaba abierto: ignoraba el error y confirmaba igual, permitiendo
recargar con el mismo comprobante múltiples veces.
Agrega motivo error_sistema en Telegram para casos de error interno.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 17:20:27 +00:00
LizandroandClaude Sonnet 4.6 8da7a9fdb4 fix(pago): try/catch en PagoConfirmado.yaUsado/marcar por tabla faltante
Si pagos_confirmados no existe en producción (migración pendiente), la excepción
escapaba hasta handlePhoto y mostraba "Error analizando el comprobante".
Safety catch permite que la confirmación proceda aunque la tabla no esté.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 17:17:17 +00:00
LizandroandClaude Sonnet 4.6 507281e56e fix(pago): detectar IMAP por host configurado, no por toggle correo_imap_enabled
El toggle puede no estar guardado como '1' en BD aunque el panel lo muestre activo.
Verificar correo_imap_host es más confiable: si hay host → intentar IMAP.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 17:14:26 +00:00
LizandroandClaude Sonnet 4.6 5e20155ae4 fix(gemini): deshabilitar thinking y subir maxOutputTokens a 8192/2048
Con thinkingBudget=0 el modelo no consume tokens en razonamiento interno,
evitando que el JSON de respuesta quede truncado (bug: '{"banco":"Nu",...').
maxOutputTokens 2048→8192 en Vision, 1024→2048 en Intent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 17:11:55 +00:00
LizandroandClaude Sonnet 4.6 31ba26ee33 fix(pago): correo_imap_enabled check usa truthy en vez de === '1'
Livewire checkbox con value="1" puede guardar '1','on','true' según el navegador.
PagoValidadorService ahora acepta cualquier valor truthy en vez de comparación estricta.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 17:09:44 +00:00
LizandroandClaude Sonnet 4.6 811b360939 fix(pago): valor $1,000.00 → 100000 en vez de 1000 causaba sin_coincidencia
preg_replace('/[^0-9]/', '', '1,000.00') = '100000' porque el .00 aporta 00.
Fix: primero quitar la parte decimal (/[.,]\d{1,2}$/) antes de limpiar separadores.
Aplicado en BancolombiaParser::normalizarValor() y como doble defensa en PagoValidadorService.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 17:05:16 +00:00
LizandroandClaude Sonnet 4.6 595c75837f fix(pago): diagnose and harden IMAP email validation
- PagoValidadorService: add detailed Log::info at every step (emails count,
  body preview, parser result, which filter fails) so failures are visible in laravel.log
- CorreoImapService::cleanBody: detect and decode base64-encoded BODY[1] before
  QP decoding — critical fix when Bancolombia sends HTML part as base64
- BancolombiaParser: make esBancolombia() broader (includes 'valor','$','abono' etc.),
  add extraerPrimero() helper, add multiple regex fallbacks for remitente/fecha/hora/valor
  to handle different Bancolombia email HTML formats beyond the SMS text pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 17:01:34 +00:00
LizandroandClaude Sonnet 4.6 1fd9a92afa Remove manual payment application button for unconfirmed receipts
Only email-confirmed payments get the apply button. Unconfirmed payments
show the failure reason and direct the user to an advisor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 16:44:28 +00:00
LizandroandClaude Sonnet 4.6 6c0396d3c0 Show validation failure reason and allow manual payment application
When email validation fails (IMAP disabled, no emails, no match), show the
specific reason instead of a generic "No confirmado". Also add a manual
"Aplicar de todas formas" button so the user isn't stuck — they can still
apply the recharge after visually verifying the receipt.

Also show banco/fecha/hora in the Telegram analysis result for context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 16:27:56 +00:00
LizandroandClaude Sonnet 4.6 b26f6f1130 Services and promos purchasable only with balance; redirect to recharge if short
Remove MercadoPago as a direct payment option for services and promotions.
If the user has enough balance: show only "Pagar con saldo".
If not: show current balance, amount missing, and a "Recargar saldo" button
that leads to the recharge flow (where MercadoPago and Bre-B remain available).

Applies to both TelegramBotService (startPurchase, viewPromo) and
PublicChat (iniciarCompra, verPromocion).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 16:15:45 +00:00
LizandroandClaude Sonnet 4.6 2f5be9253b Fix 5 bugs in chat and Telegram purchase flows
1. PublicChat::comprarPromoConSaldo — double saldo subtraction: $saldo->update()
   already updates the model in memory, so $this->saldoUsuario = $saldo->valor - precio
   was subtracting twice. Fixed by computing $nuevoSaldo before the update.
   Also wrapped in DB::transaction (was missing unlike pagarConSaldo).

2. TelegramBotService::listServices — showed all services without filtering by the
   user's rol_id, so users could see services with no plans for their role.
   Now uses whereHas('tarifas', rol_id) like PublicChat and the web.

3. TelegramBotService::payWithSaldo — no DB::transaction; if saldo update failed
   after historial was created, user got a free service. Now wrapped atomically.

4. TelegramBotService::buyPromoSaldo — same missing transaction + fecha_final was
   hardcoded to 30 days instead of promo->dias. Both fixed.

5. TelegramBotService::showCredentials — N+1 queries loading cuentas lazily per
   historial. Added cuentas to the eager-load list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 16:06:20 +00:00
LizandroandClaude Sonnet 4.6 1f25c31603 Fix "sin cuentas disponibles" and wrong pricing in bot/chat
Three bugs fixed:

1. TelegramBotService queried Cuentas by tarifa_id + estado=activo which
   never matched. Now uses CuentasHelper::contar/buscar — same date-range
   + historial-count logic as the web (pendiente for full accounts,
   activo + slot check for per-screen accounts).

2. efectivePrice in TelegramBotService and PublicChat used the Preferencial
   table (legacy) instead of Usuario_tarifa (used by the web admin panel).
   CuentasHelper::precio checks Usuario_tarifa first, Preferencial as fallback.

3. payWithSaldo compared saldo against tarifa->valor (base price) instead of
   the effective price stored in state. Also registered the purchase with the
   wrong amount.

Extract shared logic to CuentasHelper (contar, buscar, precio) to avoid
duplication between TelegramBotService and PublicChat.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 16:02:54 +00:00
LizandroandClaude Sonnet 4.6 ba4ec8b6cf Prevent double-confirmation of same payment by different users
- Create pagos_confirmados table to track consumed email receipts
- PagoValidadorService now validates: valor + fecha + hora (±10min) + llave Bancolombia
- Each matched email is hashed (sha1 body+date) and marked as used; a second
  match returns estado=ya_usado instead of confirmado
- Add partial remitente name matching against the registered user's name
- GeminiVisionService prompt now extracts llave (@xxx) from the receipt image
- TelegramBotService shows distinct message for ya_usado state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 03:30:20 +00:00
LizandroandClaude Sonnet 4.6 157691e166 Fix maxOutputTokens too low for gemini-3.5-flash thinking model
gemini-3.5-flash uses thinking tokens that share the same budget as output
tokens. With maxOutputTokens=200 (vision) or 100 (intent), the model would
exhaust the budget on thinking (~288-1043 tokens) and truncate the actual
response to 8-11 tokens, producing garbage output like "040825".

Fix: 2048 for vision (needs full JSON), 1024 for intent, 512 for connection test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-15 18:09:45 +00:00
LizandroandClaude Sonnet 4.6 5c15f9f3fe fix: skip thinking parts in Gemini vision response + extract JSON from any position
gemini-3.x models return thinking blocks with thought:true flag in parts[].
Filter those out so only actual response text is used.
Also extract the first {...} JSON object from the text so stray content
before or after (like '040825') doesn't break parsing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-15 18:01:32 +00:00
Lizandro bd93ef2029 debug: show raw Gemini vision response in Telegram when JSON parse fails 2026-07-15 17:47:07 +00:00
LizandroandClaude Sonnet 4.6 2acb80a7d2 fix: GeminiVisionService tries v1+v1beta, shows real API error in Telegram
- Rewrote extraerPago() to try v1 then v1beta for model compatibility
- Returns __error key with actual API message when both fail
- TelegramBotService shows that error in chat instead of generic message
- Also ensures model is read fresh from config (no hardcoded URL in constructor)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-15 16:13:10 +00:00
LizandroandClaude Sonnet 4.6 cfa38e51df fix: change default Gemini model to gemini-3.5-flash
gemini-2.5-flash and gemini-2.0-flash-lite are restricted/unavailable.
gemini-3.5-flash is confirmed working on this account.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-15 04:21:55 +00:00
LizandroandClaude Sonnet 4.6 13199b1de4 fix: remove thinkingConfig entirely — field does not exist in Gemini API
The API returned: Unknown name "thinkingConfig": Cannot find field.
gemini-2.5-flash works with a plain generateContent request, no special config needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-15 04:15:06 +00:00
LizandroandClaude Sonnet 4.6 54736a8742 fix: use v1 API for Gemini 2.5+/3.x models; show real error + generateContent filter
- GeminiIntentService/VisionService: auto-select v1 for 2.5+ models, v1beta for older
- probarGemini: tries v1 then v1beta, shows actual API error message, filters model
  list to only those supporting generateContent so the user sees usable options

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-15 04:13:09 +00:00
Lizandro aa57f64e4f debug: show mail error message in Telegram for diagnosis 2026-07-15 04:07:19 +00:00
LizandroandClaude Sonnet 4.6 612cdaa81e fix: use backticks for masked email in OTP message
Asterisks in the masked email (liza*****@domain) broke Telegram Markdown
parsing, causing the message to silently fail. Backticks (inline code)
render correctly regardless of the email content.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-15 04:04:58 +00:00