Skip to content

feat(providers): proveedor agregador CPAMC (CLI Proxy API) #167

Open

Description

@Rafaeldelinares

Pre-flight checks

  • I searched the existing issues and the roadmap: no duplicates or overlap.
  • I understand that this proposal requires product review before implementation.

Problem to solve

Quorb supports aggregators such as 9Router and OpenRouter, but it has no integration with CLIProxyAPI (router-for-me/CLIProxyAPI), the local gateway used to unify, balance and manage access to Gemini, Claude, OpenAI and Vertex AI models without the noise of individual OAuth accounts in every client.

Note on naming: CPAMC is the management Web UI of CLIProxyAPI, not the service itself. This issue originally named the provider cpamc, which was wrong — the provider is named cliproxy below.

Proposed solution

A native cliproxy provider (Kind::Api, like the 9Router aggregator), against the versioned Management API v8 of CLIProxyAPI:

  • Endpoints (Authorization: Bearer <management_key> or X-Management-Key):
    • GET /v8/management/credentials → per-credential health: status, disabled, unavailable. This is the real health/cooldown signal.
    • GET /v8/management/credentials/models?name=<file-or-id> and GET /v8/management/routing/model-definitions/:channel → model catalogs per credential and per channel.
    • GET /v8/management/plugins/:id/quota?auth_index=… → quota figures, only when a quota plugin is installed (a base installation exposes no quota numbers).
  • Health is per credential, aggregated per channel: cooldown and degradation live on the credential (auth_index), while models are grouped by channel. The provider therefore watches credentials and rolls their health up into the channels shown in the widget.
  • The ring needs numbers, so the provider reports two layers:
    1. Always: credential health as UsageReport.status + message (Ok / Warning / Error) — state without figures.
    2. When available: the quota numbers from the plugin endpoint, as percent / used / limit.
      Without a quota plugin the widget must be able to render a state-only meter (status + message, no percentage). That is a small change to the meter rendering and is part of this scope.
  • Configuration and UI:
    • Parameters: base_url (default http://127.0.0.1:8317), the management key in the secure store (secrets::CLIPROXY_MANAGEMENT_KEY), and the credentials/channels to watch.
    • Section in Settings.tsx with a live connection test against a read-only endpoint (GET /v8/management/credentials).
    • HTTPS is required outside loopback: the management key grants full control of the proxy, so a remote base_url over plain HTTP is refused, or explicitly warned about in Settings.
  • Assets and tests:
    • Vector SVG logo cliproxy.svg in the asset catalog.
    • Rust unit tests over fixtures: healthy credential, credential in cooldown, credential disabled, and the state-only case (no quota plugin).

Affected area

Application behavior

Scope and non-goals

  • Scope: Monitoring the health of the credentials —and, when a quota plugin is present, the quota— of a local or remote CLIProxyAPI instance.
  • Non-goals: Mutating the proxy. No PATCH /credentials/status, no POST /routing/cooldown/reset, no credential management from Quorb.

Open question

The v8 Management API does not exist in CLIProxyAPI v7: on my own instances /v8/management/credentials returns 404, and only v8 serves it. Should the provider detect the version and degrade to an "unsupported" state, or is v8 a hard requirement?

Alternatives considered

  • Adapting the 9Router provider: its auth schemes and endpoints differ significantly.
  • Scoping the provider to plugin quota only: it would make the integration useless on a base installation, where no quota figures exist.

Activity

  1. egdev6 commented on Oct 21, 2026

    @egdev6
    Owner

    ¡Gracias por la propuesta, @Rafaeldelinares! La idea encaja con el hueco real (Quorb ya cubre 9Router y OpenRouter como gateways), pero he verificado la propuesta contra el proyecto de router-for-me y la spec necesita reelaborarse sobre la API actual antes de aprobarse. Detalles:

    1. Nomenclatura: CPAMC no es el servicio ⚠️
    CPAMC (CLI Proxy API Management Center) es la Web UI de administración; el servicio real es CLIProxyAPI (router-for-me/CLIProxyAPI). El proveedor integraría la Management API de CLIProxyAPI — sugiero nombrar el provider cliproxy (o similar) y describirlo así en la ficha para no confundir ambos proyectos.

    2. El endpoint propuesto no existe en la API vigente ⚠️
    GET <base_url>/management/api/models no aparece en la documentación actual. La Management API actual está versionada bajo /v8/management/… (con Authorization: Bearer <management_key> o X-Management-Key; /v0/management está cerca de su deprecación). Los endpoints reales y relevantes son:

    • GET /v8/management/credentials → estado de cada credencial (status, disabled, unavailable): es la señal real de salud/cooldown del pool.
    • GET /v8/management/credentials/models?name=<file-or-id> y GET /v8/management/routing/model-definitions/:channel → catálogos de modelos por credencial/canal.
    • GET /v8/management/plugins/:id/quota?auth_index=… → cuota, dependiente de plugins (no hay números de cuota en la instalación base).

    3. La salud es por credencial, no por modelo ⚠️
    El cooldown y la degradación en CLIProxyAPI son por credencial (auth_index), y los modelos se agrupan por canal. El monitoreo target_models por modelo concreto, tal como está planteado, no mapea directamente con lo que expone la API. La spec debería decidir entre: (a) monitorizar credenciales y agregar salud por canal, y/o (b) exponer la cuota de plugins cuando exista.

    4. El anillo necesita números ⚠️ (cuestión de producto)
    El widget de Quorb se alimenta de medidores numéricos (percent, used, limit en Meter). Sin plugin de cuota, CLIProxyAPI solo da estado — eso mapea a UsageReport.status + message, pero habría que definir qué muestra el anillo cuando no hay datos numéricos (o acotar el scope a la cuota vía plugins). Este es el punto que más me gustaría ver resuelto en la ficha.

    5. Kind ℹ️
    Sugiero Kind::Api en lugar de Kind::Subscription, como el agregador 9Router: el proxy no es una suscripción, enruta cuentas propias.

    6. Seguridad ⚠️
    La management key da control total del proxy (puede deshabilitar credenciales, resetear cooldown…). Con base_url local (http://127.0.0.1:8317) es correcto, pero si el usuario apunta a un host remoto el Bearer viajaría en claro: la spec debería exigir HTTPS fuera de loopback (o avisar explícitamente en Ajustes), y el test de conexión debe usar un endpoint de solo lectura.

    7. Non-goals ✓
    Bien trazados: nada de mutaciones (PATCH /credentials/status, POST /routing/cooldown/reset quedan fuera).

    Conclusión: prometedora y con demanda real, pero necesita una reespeccificación sobre /v8/management (puntos 2–4) antes de pasar a status:approved. Si reescribes la issue con esos matices, la re-reviso con gusto.

  2. egdev6 commented on Oct 21, 2026

    @egdev6
    Owner

    @Rafaeldelinares te dejo aquí el resumen accionable de la revisión: la propuesta tiene demanda real, pero antes de poder aprobarla necesita una reescritura de la spec sobre la Management API v8 real de CLIProxyAPI:

    1. Renombra la integración al servicio real (CLIProxyAPI) — CPAMC es solo su Web UI.
    2. Sustituye GET /management/api/models por los endpoints vigentes: GET /v8/management/credentials (salud por credencial), GET /v8/management/credentials/models?name= y GET /v8/management/routing/model-definitions/:channel.
    3. Redefine el monitoreo por credencial/canal en lugar de por modelo (target_models tal cual no mapea).
    4. Define qué muestra el anillo sin cuota numérica (o acota el scope a la cuota de plugins: /v8/management/plugins/:id/quota).
    5. Cambia a Kind::Api (precedente 9Router) y exige HTTPS fuera de loopback con test de conexión de solo lectura.

    Cuando actualices la issue con estos puntos, la re-reviso y, si todo cuadra, pasa a status:approved. ¡Gracias!

  3. Rafaeldelinares commented on Oct 23, 2026

    @Rafaeldelinares
    ContributorAuthor

    @egdev6 He reescrito la spec en el cuerpo de la issue con los siete puntos de tu review. Lo que cambia de fondo:

    • Nomenclatura: el proveedor pasa a cliproxy, como sugeriste —CPAMC es la Web UI, no el servicio— y el tipo queda en Kind::Api.
    • Endpoints: GET /management/api/models → GET /v8/management/credentials (salud por credencial), GET /v8/management/credentials/models?name= y GET /v8/management/routing/model-definitions/:channel. Ninguna mutación: PATCH /credentials/status y POST /routing/cooldown/reset quedan fuera de alcance.
    • Salud por credencial, agregada por canal: el cooldown vive en la credencial (auth_index) y los modelos se agrupan por canal, así que el provider vigila credenciales y agrega su salud en los canales que muestra el widget.
    • El anillo necesita números (tu punto 4, el que más querías ver resuelto): el provider reporta dos capas. Siempre, el estado de la credencial como UsageReport.status + message; y cuando existe, la cuota del plugin de cuota como percent / used / limit. Sin plugin de cuota, el widget tiene que poder pintar un medidor solo de estado (estado + mensaje, sin porcentaje), y eso es un cambio acotado en el render del medidor, dentro del alcance de esta issue.
    • Cuota: GET /v8/management/plugins/:id/quota?auth_index=… depende de plugins instalados, así que queda como capa opcional, no como parte del anillo principal.
    • Seguridad: HTTPS obligatorio fuera de loopback, porque la management key da control total del proxy, y el test de conexión usa un endpoint de solo lectura (GET /v8/management/credentials).

    Una pregunta de entorno que dejé abierta en la spec: la Management API v8 no existe en la v7.3.3 —en mis instancias /v8/management/credentials devuelve 404 y solo la v8 lo sirve—. ¿El provider debe detectar la versión y degradar a un estado "no soportado", o damos la v8 por supuesto como requisito mínimo?

  4. egdev6 commented on Oct 23, 2026

    @egdev6
    Owner

    @Rafaeldelinares revisada la spec reescrita — aprobada sobre lo que queda del issue. Los siete puntos están bien integrados: nomenclatura real (cliproxy, Kind::Api), endpoints v8 correctos, salud por credencial agregada por canal, anillo de dos capas sin inventar números, quota plugin como capa opcional, sin mutaciones, y HTTPS fuera de loopback. El diseño de dos capas resuelve lo que motivó tu punto 4: un provider de salud no puede pintar un anillo sin números, y estado+mensaje siempre disponible es lo correcto.

    Decisión sobre la pregunta abierta: detectar y degradar, no v8 como requisito.

    • El provider sondea GET /v8/management/credentials como primer request (es el mismo que usa el test de conexión). Si responde 404, el reporte va con Status::Warning/mensaje accionable: «tu CLIProxyAPI no expone la Management API v8 — actualiza el proxy para ver el estado».
    • No se finge salud ni se rompe: es exactamente el patrón que ya usamos cuando el formato no coincide (cf. el guard de medidores vacíos de MiniMax en feat(providers): anillo de uso y saldo PAYG de MiniMax (#165) #172).
    • Obligar v8 dejaría fuera a los usuarios de v7 — tus propias instancias son el caso. La detección es gratis porque el primer request ya la revela.
    • Añade a los fixtures el caso 404 en /v8/management/* (versión sin v8) junto a los cuatro que ya listas.

    Con esto, la spec queda cerrada y la issue elegible para su ODD (fase observar/decidir → plan de tareas) según el flujo de CONTRIBUTING. Recuerda el flujo: abre el ODD del task, lo reviso, y con aprobación arranca implementación. Sin assignee todavía — asígnate cuando empieces, como siempre.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

enhancementNew feature or requestquestionFurther information is requested

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions