Skip to content

50/50 RevShare Integration: Mercury & AIML API - #117

Open
hugoaimlapi wants to merge 5 commits into
cosmicstack-labs:mainfrom
aimlapi:main
Open

50/50 RevShare Integration: Mercury & AIML API#117
hugoaimlapi wants to merge 5 commits into
cosmicstack-labs:mainfrom
aimlapi:main

Conversation

@hugoaimlapi

Copy link
Copy Markdown

Hi! I'm Hugo from aimlapi.com — an AI aggregator that gives access to 1000+ models in one API, trusted by 400k+ users.

We'd love to be available as a verified provider option inside Mercury — so we went ahead and did all the technical work on our side.

To build our partnership, we offer a 50/50 revenue share on all traffic from this integration. (P.S.: tracking starts as soon as this release goes live, so no earnings will be lost during setup)

My contacts: hugo@aimlapi.com (email / Slack), Telegram: @hug0the


Why

Mercury has no AI/ML API preset. It can be reached through "OpenAI Compilations" (openaiCompat) with a hand-typed base URL, but model discovery there keeps every id in the listing — image, video and speech models included — and requests carry no attribution.

Summary

  • config.ts: aimlapi added to ProviderName and the default config — AIMLAPI_API_KEY / AIMLAPI_BASE_URL (default https://api.aimlapi.com/v1) / AIMLAPI_MODEL (default anthropic/claude-sonnet-4.6) / AIMLAPI_ENABLED. Without a key it is not configured and not registered. DEFAULT_PROVIDER stays deepseek.
  • registry.ts: served by OpenAICompatProvider over Chat Completions, registered right after mercuryCloud.
  • aimlapi-attribution.ts + openai-compat.ts: X-AIMLAPI-Partner-ID, X-AIMLAPI-Source, HTTP-Referer, X-Title passed as headers to createOpenAI. Only when the parsed base URL hostname is exactly api.aimlapi.com; every other host gets no extra headers. The check is on the host, so it also applies if openaiCompat points at api.aimlapi.com.
  • provider-models.ts: discovery keeps the rows with type: "openai/chat-completions" (353 chat models today) and collapses repeated ids; 4 preferred ids checked against the live catalogue.
  • index.ts: CLI setup (mercury setup / mercury doctor) lists AI/ML API first; picking it asks for the key, validates it by fetching models and offers a model pick — same flow as Atlas Cloud.
  • Web: aimlapi added to validNames in POST /api/providers/:name; GET /api/providers returns recommended (true only for aimlapi), shown as a "Recommended" badge on the Providers page; provider color in Usage.
  • .env.example: AIMLAPI_* vars.
  • Tests: aimlapi-attribution.test.ts, openai-compat.aimlapi.test.ts, provider-models.aimlapi.test.ts.

Before / After

  • Before: AI/ML API only via "OpenAI Compilations" with a manual base URL; the model list includes every id in the listing; no attribution.
  • After: AI/ML API is a named provider in CLI setup and the web UI; the key is validated by fetching its chat models, with anthropic/claude-sonnet-4.6 recommended; requests to api.aimlapi.com carry the attribution headers. Other providers: no extra headers, default provider unchanged.

How to Test

npm ci && npm run typecheck
npx vitest run src/providers/aimlapi-attribution.test.ts src/providers/openai-compat.aimlapi.test.ts src/utils/provider-models.aimlapi.test.ts

npm run build
node dist/index.js setup   # Offline / BYOK → 1. AI/ML API → paste key → pick a model

Web UI: Providers → AI/ML API → paste key → Save → Test Connection returns the chat model list with anthropic/claude-sonnet-4.6 as recommended.

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

  • Follows the Atlas Cloud preset (Add Atlas Cloud provider preset #94): config entry, registry, model discovery, CLI setup, validNames, .env.example. No new dependencies, no breaking changes; previously saved configs load unchanged — aimlapi comes from the defaults and stays unconfigured until a key is set.
  • Placement: first in the CLI picker and on the Providers page, with the "Recommended" badge; in the registry (fallback order) it sits after mercuryCloud. The badge is one constant (RECOMMENDED_PROVIDER) and the picker entry is one line, if you'd rather keep the ordering neutral.

aimlapihello and others added 5 commits September 10, 2026 12:19
One key reaches 350+ chat models from OpenAI, Anthropic, Google, DeepSeek,
Alibaba and others through a single OpenAI-compatible surface, which fits the
existing `OpenAICompatProvider` without a new client.

- `aimlapi` joins `ProviderName`, the config block and the registry, routed
  through Chat Completions — the catalogue is mostly third-party models
  reached that way.
- Configured by `AIMLAPI_API_KEY` / `AIMLAPI_BASE_URL` / `AIMLAPI_MODEL` like
  every other provider here. The default model is
  `anthropic/claude-sonnet-4.6`; the preferred list was checked against the
  live catalogue rather than copied from another provider's shape, since ids
  there are namespaced by lab.
- Listed first in `PROVIDER_OPTIONS`, the picker a user reads.

Two placement decisions worth stating rather than leaving to review:

- In `ProviderRegistry.create` the entry sits AFTER `mercuryCloud`. That array
  is the fallback order, and moving a first-party hosted provider off the
  front of it changes behaviour for existing installs, which is a different
  thing from where a name appears in a list.
- The picker position is the opposite call and is deliberate; revert that one
  line if the ordering there is meant to stay fixed.

The gateway attributes traffic by header. `aimlapi-attribution.ts` supplies
them, and returns `undefined` for every other host, so nothing else routed
through `OpenAICompatProvider` sends anything extra.

The host check parses the URL and compares `hostname` instead of matching a
prefix. That is the whole point of the module: a request carrying the wrong
partner id is served normally and attributed to nobody, so a leak to
`api.aimlapi.com.example.test` would never surface at runtime — and users can
point a base URL anywhere. Tests cover the lookalikes, not just the hit.

Verified: `tsc --noEmit` clean; 55 test files, 325 passing. Replacing the URL
parse with a substring check, tests kept, fails the lookalike case.
…eb UI

Four defects, all found by opening the Providers page rather than by reading
the diff. The first made the integration unusable from the UI.

**Model discovery returned nothing.** With no branch of its own, `aimlapi`
fell through to the default filter, which keeps ids starting with `gpt-` or
`o<digit>`. Ids here are namespaced by lab — `anthropic/claude-sonnet-4.6`,
`alibaba/qwen3.8-max` — so all 353 chat models were dropped and the page said
"Mercury could not find any supported chat models for this provider" against a
listing that had them. The listing carries `type` naming the surface each row
belongs to, so the chat set is the rows on the OpenAI-compatible one; ids
repeat across surfaces and `uniq` already collapses them.

**Saving from the UI was rejected.** `POST /api/providers/:name` validates
against a hardcoded `validNames` that nobody updated, so the Save button
returned an error for a provider the rest of the app already knew.

**The provider was fourth in the UI.** That list is built from
`Object.entries(config.providers)`, so its order is the key order of the
defaults object, not the picker array in `index.ts`. Moved to the front.

**No badge.** `GET /api/providers` now returns `recommended`, and the card
renders it next to Active/Disabled. One constant names the provider rather
than a list, so the claim stays reviewable and reverting it is one line.

Verified end to end against production, not just in tests: Test Connection
returns `success: true` with a populated model list and
`anthropic/claude-sonnet-4.6` as recommended; the API lists `aimlapi` first
with `recommended: true`; a message sent through the web channel reaches
`api.aimlapi.com` with all four attribution headers and answers 200.

57 test files, 329 passing. Removing the discovery branch with the tests kept
fails both new tests with the exact message the UI showed.
feat(providers): add AI/ML API as an OpenAI-compatible provider
`mercury setup` / `mercury doctor` list AI/ML API as option 1, but the
per-provider loop had no `aimlapi` branch, so picking it prompted for
nothing and setup ended with "No LLM provider configured yet". Added the
branch, same shape as Atlas Cloud: ask for the key, validate it by
fetching the model list, let the user pick a model.
Adds AIMLAPI_API_KEY / AIMLAPI_BASE_URL / AIMLAPI_MODEL to `.env.example`
and `aimlapi` to the DEFAULT_PROVIDER comment, as for Atlas Cloud.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants