Skip to content

feat(provider/aimlapi): add aimlapi.com LLM support - #1

Open
Lookoff-AIMLAPI wants to merge 3 commits into
developfrom
feat/aimlapi-provider
Open

feat(provider/aimlapi): add aimlapi.com LLM support#1
Lookoff-AIMLAPI wants to merge 3 commits into
developfrom
feat/aimlapi-provider

Conversation

@Lookoff-AIMLAPI

@Lookoff-AIMLAPI Lookoff-AIMLAPI commented Sep 3, 2026

Copy link
Copy Markdown
Member

What type of change does this PR introduce?

  • Bugfix
  • Feature
  • Refactor
  • Documentation
  • Not Sure?

Does this PR introduce breaking changes?

  • Yes
  • No

List any relevant issue numbers:

None. Shape copied from leon-ai#579 and leon-ai#580 (the MiniMax provider)
and from the Celeris
provider, which is the most recently added one.

Description:

Adds aimlapi.com as a remote LLM provider. It is an aggregator — one
OpenAI-compatible Chat Completions endpoint in front of many upstream vendors —
so a single key covers the OpenAI, Anthropic, Google, DeepSeek and Moonshot
families a user would otherwise configure one at a time.

The provider itself is a thin subclass of AISDKRemoteLLMProvider with
flavor: 'openai-compatible'. No base-class change was needed.

Two commits, deliberately separated:

Commit Contents
18eb95a feat(provider/aimlapi): add aimlapi.com LLM support the provider, config, schema, samples, catalog entries, tests
6488453 chore(aimlapi): fork-only placement — do not send upstream list ordering only — drop this commit before offering the provider upstream

Gateway behaviour that shaped the code

1. The gateway returns HTTP 400 for a null-valued optional field that the
upstream OpenAI API accepts. Verified today against
POST https://api.aimlapi.com/v1/chat/completions:

null → 400 null → 200
temperature, top_p, seed, reasoning_effort, tools, tool_choice, response_format, stream, stream_options, parallel_tool_calls, max_tokens, max_completion_tokens stop, presence_penalty, frequency_penalty, n, user, logprobs, logit_bias, verbosity

An OpenAI SDK that serialises an unset optional parameter as literal null
therefore fails on every real call while a mocked test suite stays green.
Leon's base class already omits unset options (typeof x === 'number' ? {...} : {}), so this PR does not change that behaviour — it pins it. The captured
request body for a default call is exactly:

{"model":"openai/gpt-5.6-sol","messages":[{"role":"system","content":""},{"role":"user","content":""}]}

test/agent/unit/aimlapi-llm-provider.spec.ts asserts no top-level field is
null, and separately that temperature, seed and max_tokens are
forwarded when they are set — so a future refactor to x ?? null fails here
instead of in production.

2. The reasoning switch differs per upstream vendor. As with Celeris, the
empty buildProviderOptions stops the generic compatible adapter from attaching
a vendor field this gateway would reject, and the catalog entries expose auto
reasoning only.

Model ids

Every id was checked against the live catalog
(GET https://api.aimlapi.com/v1/models?include=all, filtered to
type == "openai/chat-completions"; 936 rows / 785 distinct ids / 353 chat
models) and made to answer a real completion. Nothing was copied from another
aggregator's list.

The dotted spelling is used deliberately: anthropic/claude-sonnet-4-6,
claude-opus-4-7 and claude-opus-4-8 (dashed) publish only streaming in
capabilities, while the identical dotted ids publish the full set.

Catalog id HTTP model echoed back
openai/gpt-5.6-sol 200 gpt-5.6-sol (vendor prefix dropped)
anthropic/claude-opus-4.8 200 anthropic/claude-opus-4.8
anthropic/claude-sonnet-4.6 200 anthropic/claude-sonnet-4.6
google/gemini-3.8-flash 200 google/gemini-3.8-flash
deepseek/deepseek-v4-pro 200 deepseek-v4-pro-202606 (dated snapshot)
moonshot/kimi-k3 200 kimi-k3 (vendor prefix dropped)

Three ids echo back a name that is not byte-identical to the request. Leon does
not record or pin "the model that actually served the request", so this is
cosmetic here — noted because it would matter for a host that does. No existing
id was removed by this PR, so the "never delete on catalog absence alone" rule
did not come into play.

Attribution

AISDKRemoteLLMProvider already exposes a headers hook, so this uses the
mechanism the repo has rather than adding one. HTTP-Referer and X-Title
follow the OpenRouter convention and identify Leon, not the gateway:

HTTP-Referer:         https://github.com/leon-ai/leon
X-Title:              Leon
X-AIMLAPI-Source:     agent/leon
X-AIMLAPI-Partner-ID: part_leon

The Base URL is user-configurable, so the headers are scoped to the official
host
: buildAIMLAPIHeaders() returns {} for any other hostname, so a
self-hosted gateway or a third-party proxy fronting the same schema never
receives them. A fresh object is returned per call, and a test mutates the
returned object to prove the module constant cannot be modified through it.
Another test asserts the partner id matches ^part_[A-Za-z0-9]{1,64}$ — a
malformed id is not rejected at request time, it just silently stops counting,
so an assertion is the only thing that catches a typo.

Fork-only placement commit (6488453)

Both lists it touches are hand-ordered and both feed the first choice a new user
sees: getLLMModelCatalogProviders() derives the setup wizard's provider order
from the catalog's array order, and LLM_PROVIDER_ACCOUNT_CONFIGS is the order
used wherever providers are listed. The commit moves aimlapi.com to the front of
each and changes nothing else.

Leon already has a featured concept — recommended, used exactly once per
provider — so openai/gpt-5.6-sol carries it in the provider commit like every
other provider's lead model. No badge mechanism was invented.

Before / after getLLMModelCatalogProviders():

celeris, openrouter, openai, anthropic, zai, minimax, moonshotai
aimlapi, celeris, openrouter, openai, anthropic, zai, minimax, moonshotai

Checks

Run on Node 26.7.0 / pnpm 11.20.0.

  • pnpm exec tsc --noEmit --pretty false — exit 0
  • pnpm exec eslint on all 14 changed files — exit 0, no output
  • pnpm run build:server — exit 0 (build:app builds the Electron desktop
    shell and was not run; nothing in this PR touches it)
  • pnpm run test:agent:unit76 passed (baseline 70; +6 from the new spec)
  • pnpm run test:core:unit71 passed / 1 failed, identical to a pristine
    checkout. The failure is network-helper.spec.ts > retries only the stalled remainder of a parallel range (expected […(8)] to have a length of 6), which
    is timing-dependent: it passed on the first pristine run and failed on every
    subsequent run, pristine tree included. Unrelated to this change.
  • pnpm run test:controlled:unit7 passed (baseline 7)
  • pnpm run test:controlled:e2e1 failed, identical to a pristine
    checkout: ENOENT … /.leon/tmp/controlled-skill-smoke-*.json, an environment
    prerequisite of the full postinstall setup, which was skipped here.

Real inference, through the provider

Not a mock and not a raw curl — AIMLAPILLMProvider.runChatCompletion() was
called directly with a real key in LEON_AIMLAPI_API_KEY.

aimlapi/openai/gpt-5.6-sol, plain completion:

{"choices":[{"finish_reason":"stop","message":{"content":"LEON AIMLAPI OK"}}],
 "usage":{"prompt_tokens":29,"completion_tokens":9}}

aimlapi/openai/gpt-5.6-sol, tool calling:

{"choices":[{"finish_reason":"tool-calls","message":{"content":"","tool_calls":[
  {"id":"call_qikIdtV1kLkiXK8LP3f1Ln0e","type":"function",
   "function":{"name":"get_weather","arguments":"{\"city\":\"Paris\"}"}}]}}],
 "usage":{"prompt_tokens":151,"completion_tokens":17}}

aimlapi/anthropic/claude-sonnet-4.6, plain completion — confirming the
aggregator path works across vendors:

{"choices":[{"finish_reason":"stop","message":{"content":"LEON AIMLAPI OK"}}],
 "usage":{"prompt_tokens":28,"completion_tokens":10}}

Not verified

  • The setup wizard was not driven interactively; its provider list, model list
    and "(Recommended)" suffix were verified by evaluating the exact functions it
    reads (getLLMModelCatalogProviders, getLLMModelCatalogEntries,
    getLLMProviderAccountConfig).
  • pnpm run test:agent:e2e requires the full postinstall environment and live
    keys for every provider in the matrix; the aimlapi row was added to
    PROVIDER_MATRIX but that suite was not run.
  • Streaming (shouldStream: true) was exercised only through the existing unit
    coverage, not against the live endpoint.

One repo rule worth flagging before this goes upstream

scripts/commit-msg.js:23 enumerates every valid provider scope. aimlapi is
added to that alternation in the provider commit, exactly as leon-ai#579
did for
minimax, so feat(provider/aimlapi): … passes the hook. The placement
commit's scope, chore(aimlapi), is not in the enum and would be rejected by
that hook — which is harmless, since that commit is meant to be dropped before
the provider change is offered upstream.

Leon can already reach one aggregator (OpenRouter) and several direct
vendors. aimlapi.com is a second aggregator: a single OpenAI-compatible
Chat Completions endpoint in front of many upstream vendors, so it lets
one key cover the OpenAI, Anthropic, Google, DeepSeek and Moonshot
families a user would otherwise configure separately.

The provider is a thin subclass of the shared AI SDK remote base class,
following the Celeris and MiniMax shape, and needs no base-class change.

Two gateway behaviours drive the parts of this that are not boilerplate:

- Its request validator rejects a null value for optional fields that the
  upstream OpenAI API accepts, answering HTTP 400 for temperature, top_p,
  seed, reasoning_effort, tools, tool_choice, response_format, stream and
  max_tokens. Leon's base class already omits unset options instead of
  serialising them as null, so the accompanying spec pins that: a future
  change to `x ?? null` there would break every real call while a mocked
  suite stayed green.
- The field that switches reasoning on and off differs per upstream
  vendor, so the empty provider-options builder stops the generic
  compatible adapter from attaching one the gateway would reject. The
  curated models therefore expose auto reasoning only.

Attribution follows the OpenRouter convention the base class already
supports through its headers hook, and is scoped to the official host so
a user-configured Base URL pointing at a proxy never receives it.

Every model id was checked against the live catalog and answered a real
completion. The dotted spelling is deliberate: the dashed
anthropic/claude-* ids publish a capability set reduced to streaming.
Both lists this touches are hand-ordered, and both feed the first choice
a new user sees: `getLLMModelCatalogProviders()` derives the setup
wizard's provider order from the catalog's own order, and the account
config array is the order used wherever providers are listed.

This moves aimlapi.com to the front of each. It is placement, not
function — nothing here changes behaviour once a provider is chosen —
so it is isolated in its own commit and must be dropped before the
provider change is offered upstream.

Leon already has a featured concept, `recommended`, used once per
provider; openai/gpt-5.6-sol carries it in the provider commit like
every other provider's lead model, so no badge is invented here.
The placeholder part_leon was a readable stand-in chosen before the
partner was registered. Registration mints the id server-side, so the
real value is part_lcAMsJBHJpF6eW4JFtT3pJfW. A wrong or unknown partner id is accepted with a
200 and silently not attributed, so this would not have surfaced at runtime.
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.

1 participant