Skip to content

feat: add aimlapi.com provider (rebased onto current upstream) - #4

Merged
Lookoff-AIMLAPI merged 16 commits into
mainfrom
aimlapi-provider-rebased-2026-08-18
Aug 18, 2026
Merged

feat: add aimlapi.com provider (rebased onto current upstream)#4
Lookoff-AIMLAPI merged 16 commits into
mainfrom
aimlapi-provider-rebased-2026-08-18

Conversation

@Lookoff-AIMLAPI

Copy link
Copy Markdown
Member

Summary

  • Rebases Nikolay Grinko's aimlapi.com provider (original PR feat: add aimlapi.com provider #1, feat/aimlapi-provider, 17 commits) onto the now-current upstream main (this fork's main was 3,453 commits behind before #3 synced it).
  • Adds the aimlapi provider (OpenAI-compatible, https://api.aimlapi.com/v1) with dynamic catalog fetch, guided TUI onboarding (paste-key or email/passwordless sign-up + hosted checkout), pricing/capability/modality mapping, and attribution headers on every request.
  • Endpoints default to production, each overridable via AIMLAPI_*_URL — no staging URLs baked in.
  • Original PR feat: add aimlapi.com provider #1 stays open on the stale branch for reference / in case the author wants to review this rebase first — can be closed once this one is merged.

Rebase notes

  • 16 of 17 commits carried real changes; 1 (chore: revert incidental dependency-sync churn in package.json/bun.lock) became a genuine no-op against the fresh base and was dropped.
  • 4 real conflicts resolved:
    • bun.lock / packages/opencode/package.json: kept upstream's current lockfile/deps — the two conflicting commits were literally reverting this same incidental churn.
    • packages/opencode/src/provider/models.ts: preserved upstream's newer Object.keys(fetched) cache-refresh check (was models) while keeping the addAimlapi() wiring.
    • packages/opencode/src/server/routes/instance/httpapi/server.ts: the original patch would have added a second, duplicate ModelsDev import — replaced the existing @opencode-ai/core/models-dev import in place with the overlay @/provider/models one instead (matches what the equivalent, cleanly-auto-merged change did in app-runtime.ts).
    • packages/opencode/src/provider/model-cache.ts: purely additive import conflict, kept both sides.

Test plan

  • bun test test/kilocode/aimlapi-client.test.ts test/kilocode/aimlapi-flow.test.ts — 21 pass
  • bun test test/provider/provider.test.ts test/kilocode/model-cache-org.test.ts test/kilocode/model-cache-effect.test.ts test/server/httpapi-provider.test.ts test/kilocode/provider-cost.test.ts test/kilocode/provider-model-metadata.test.ts (regression coverage for the conflicted shared files) — 131 pass, 1 skip
  • bun run typecheck (tsgo, packages/opencode) — clean
  • Full-monorepo turbo typecheck — all 29 TS packages clean; only @kilocode/kilo-jetbrains (Kotlin/Gradle, needs JDK 21 toolchain) fails locally, unrelated to this change since it isn't touched

ngrink and others added 16 commits August 18, 2026 16:09
- inject aimlapi provider into the models.dev overlay (openai-compatible,
  AIMLAPI_API_KEY, dynamic model list from GET /models filtered to chat
  models; coding-tagged models carry recommendedIndex)
- ModelCache: aimlapi fetcher with config/auth/env resolution
  (AIMLAPI_API_KEY, AIMLAPI_INFERENCE_URL overrides)
- provider picker: aimlapi.com in Popular right after Kilo Gateway with
  "(1000+ models, one-click setup)"
- settings metadata + en i18n note; changeset

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Selecting aimlapi.com now opens a guided setup instead of the generic
API-key prompt:
- paste an existing key (validated with a live balance probe), or
- sign in by email: existing accounts get a 6-digit code and an
  auto-issued key; new accounts register passwordless, top up via the
  hosted checkout (browser + fallback link, session polling, idempotent
  retry) and receive their key automatically
- reconfigure screen when the provider is already connected

Implementation lives in the kilocode overlay (src/kilocode/aimlapi/):
config with prod defaults + AIMLAPI_*_URL env overrides, HTTP client,
UI-agnostic flow state machine (unit-tested), SolidJS TUI screens; wired
through the existing KiloProvider.selectProvider hook.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Provider.list drops catalog providers whose model list is empty, so
requiring a key for the models fetch hid aimlapi.com from the connect
picker for unauthenticated users. GET /models is public; attach the
bearer only when a key is present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The HTTP provider-list handler resolved the core models.dev layer, so
overlay-injected providers (kilo catalog, apertis, aimlapi) were missing
from the connect picker until connected. Wire the kilocode overlay layer
(same service tag, superset catalog) into the server and app runtimes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dialog inserts replacement components through a tracked render effect
that unwraps function roots, so a bare <Switch> root re-created the whole
component on every phase change — and the onMount start transition drove
that re-creation into unbounded update-loop recursion (frozen TUI, eventual
'Maximum call stack size exceeded'). Wrap the screens in a static <box>
root and enter the flow state machine before the first render.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The aimlapi /models endpoint exposes opt-in metadata sections via
?include=…; request capabilities+modalities and map them onto the model:
reasoning (unlocks the host-generated reasoning-effort variants),
image-input attachment, real input/output modalities, and the true output
token limit. tool_call stays enabled across the board — the catalog's
tools capability has false negatives that would hide working models.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…artup

The public aimlapi catalog was fetched eagerly inside ModelsDev.get(), a hot
path that runs at startup, on one-shot runs, and in tests — so every one of
those blocked up to 10s on a live api.aimlapi.com request (e.g. tool-task-model
timed out in CI). Mirror apertis: fetch eagerly only when the provider is
configured (key via env/config/auth). Keyless, read whatever the cache holds
and let the connect picker (provider.list) warm the public catalog on demand —
that is the one place the pre-connect model list is actually needed, so the
provider still appears there without any hot-path phone-home.
… order

Adding aimlapi at order index 1 (second, right after kilo) shifts every
following provider down one; openai's settings priority is now 4, not 3.
settings.providers.note.aimlapi existed only in en; the locale-completeness
test (kilo-vscode i18n-keys) requires every English key in all 19 other
locales. Add the translated note to each.
- submitKey: only treat a 401/403 as an invalid key; report network/timeout/
  5xx as transport errors instead of blaming the pasted key (+ test).
- Drop the unreached topUpByKey client method (S12 existing-key top-up is not
  wired yet; re-add it when that path lands).
- Use the DEFAULT_AMOUNT_USD_MINOR constant for the credits screen default
  instead of a hard-coded "25".
- Changeset: 1000+ models, matching the picker/i18n copy.
- Run prettier 3.6.2 over the touched files.
Models showed as "Free" because the fetcher never requested or mapped the
pricing section. Request `?include=...,pricing` and translate `pricing.units`
to models-dev cost (USD per 1M tokens): the unit `origin` is the discriminator
(provided→input, generated→output, cached→cache_read, cache_write→cache_write),
only text token charges count (audio/tool-call units are skipped), the first
unit per origin wins, and price is normalized by `per`. Tiered pricing
(thresholds/variants) is left to the base rate for now. Validated across the
live catalog: 339/341 chat models resolve real prices, 2 are genuinely free.
The model-info panel reads its blurb from `options.description` (Kilo's
convention — models.dev catalog entries carry none), which aimlapi models
never set, so the panel showed no description. Decode `info.description` from
the catalog (already in the default projection) and pass it through as
`options.description`. 177/341 chat models carry a description.
Send X-AIMLAPI-Source: agent and X-AIMLAPI-Partner-ID on all traffic to
aimlapi.com — inference, catalog, auth and checkout — not just sign-up, so
the backend can attribute the traffic and mark agent-sourced accounts.

- config: shared aimlapiAttributionHeaders() (source always; partner id when
  known, overridable via AIMLAPI_PARTNER_ID)
- client: onboarding requests carry them via the shared request()
- model-cache: catalog fetch carries them, and every model gets model.headers
- provider overlay: patchModelsDevModel carries model.headers onto the
  resolved model so getSDK stamps them on inference calls
Set DefaultPartnerID to the partner provisioned with the same id on both the
staging and production backends, so one build attributes correctly against
either (only the AIMLAPI_*_URL endpoints differ); AIMLAPI_PARTNER_ID still
overrides. Update the client test to assert the compiled-in default flows.
Some image models (openai/gpt-5-image, google/gemini-3.1-flash-image aka Nano Banana 2, etc.) reach /v1/models as type=openai/chat-completions but reject tool use, so a coding agent errors at runtime ("No endpoints found that support tool use"). Filter them out by id in the aimlapi model fetcher (+ unit test). Temporary until the catalog marks these models.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the AIMLAPI_PARTNER_ID env override and the resolvePartnerId indirection — the partner id is fixed for the aimlapi.com provider (same id on both backends), so it is now a plain constant used directly in the attribution headers and checkout. Updates the client/model-cache tests to assert the constant instead of an injected override.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Lookoff-AIMLAPI
Lookoff-AIMLAPI merged commit 71a238d into main Aug 18, 2026
8 of 12 checks passed
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.

2 participants