feat(aimlapi): add aimlapi.com provider - #1
Open
Lookoff-AIMLAPI wants to merge 2 commits into
Open
Conversation
Crush users who buy their inference through aimlapi.com currently have to hand-write a custom provider block; catwalk is where that belongs so the model list, prices and context windows stay maintained in one place. The endpoint is OpenAI-compatible, so `openai-compat` covers it. Nine chat models are curated by hand rather than generated: the catalog carries 353 chat entries, which is not a useful model picker, and importing it wholesale would churn on every upstream catalog change. Attribution rides in `default_headers`, the seam the repo already uses for this (aihubmix's APP-Code, openrouter's HTTP-Referer/X-Title). HTTP-Referer and X-Title name Crush, matching openrouter.json and vercel.json, because they identify the calling application, not the gateway. The partner id is covered by a regex test: the gateway ignores a malformed value instead of rejecting the request, so a typo would never show up at runtime. The same test asserts no other provider carries an X-AIMLAPI-* header, so attribution cannot ride along to somebody else's API.
Moves aimlapi.com to the head of providerRegistry so it lands first in
/v2/providers and therefore first in Crush's provider picker.
This is a partnership placement decision, not a correctness change, and it
contradicts the comment the registry already carries ("Let's keep the main
providers at the top", then alphabetical). It is kept as its own commit so
it can be dropped before anything is offered upstream, where the entry
belongs in its alphabetical slot after aihubmix.
catwalk has no "recommended" or "featured" flag on a provider, so there is
nothing to badge; ordering is the only prominence mechanism that exists.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds aimlapi.com as a provider to the catwalk database, so Crush users on
AI/ML API get a maintained model list instead of hand-writing a custom
openai-compatblock.Two commits, deliberately separable:
feat(aimlapi): add aimlapi.com providerchore(aimlapi): fork-only placement — do not send upstreamproviderRegistryThe provider commit
internal/providers/configs/aimlapi.json—type: openai-compat,api_endpoint: https://api.aimlapi.com/v1,api_key: $AIMLAPI_API_KEY,9 hand-curated chat models.
internal/providers/providers.go—//go:embed, loader func and registryentry, in the alphabetical slot after
aihubmix.pkg/catwalk/provider.go—InferenceProviderAIMLAPIconst and itsKnownProviders()entry. (atlascloudprovider: add atlas cloud charmbracelet/catwalk#463 andneuralwattfeat(neuralwatt): add neuralwatt.com charmbracelet/catwalk#247 both didthis;
coralbrickschore: add coralbricks provider charmbracelet/catwalk#502 did not, which looks like an oversight.)internal/providers/providers_test.go—TestAIMLAPIDefaultHeaders.Shape follows the last three provider additions. No
cmd/aimlapi/main.goauto-updater:
GET /v1/modelsreturns 353 chat entries, which is not a usefulmodel picker, and regenerating it would churn the config on every catalog
change. The curated route is the
coralbricks(charmbracelet#502) shape.Why a hand-curated list of nine
353 chat models are reachable. The nine here are the coding-relevant flagships
plus a cheap small model, each one checked live.
Attribution headers
default_headersis the seam the repo already uses for exactly this —aihubmix.jsonshipsAPP-Code: IUFF7106, andopenrouter.json,vercel.jsonandhuggingface.jsonall shipHTTP-Referer/X-Title.HTTP-RefererandX-Titlename Crush, not us — they identify the callingapplication, matching the values
openrouter.jsonandvercel.jsonalreadycarry. The two
X-AIMLAPI-*headers are ours and are scoped to this providerentry only; nothing else in the database carries them, and
TestAIMLAPIDefaultHeadersasserts that no other provider ever does, soattribution cannot ride along to somebody else's API or to a proxy fronting
ours.
The partner id is regex-tested against
^part_[A-Za-z0-9]{1,64}$. This mattersbecause the gateway ignores a malformed value rather than rejecting the
request — a typo would be invisible at runtime and simply earn nothing.
Verification
Build:
go build ./...→ exit 0.Lint:
gofumpt -l .→ clean.golangci-lint run ./...(v2.13.1, theversion pinned in
mise.toml) →0 issues.Tests (
go test ./... -v, subtest counts):mainTestAIMLAPIDefaultHeaders)The single failure is identical before and after and is not ours:
It is already fixed upstream in
155f0c2 fix(copilot): fix default model, threecommits ahead of where this fork's
maincurrently sits.Model ids: all 9 checked against the live catalog as id or alias, and
filtered to
type == "openai/chat-completions"— 9/9 present as canonical idson the chat surface, 0 stale. Each was additionally called live: all 9 returned
HTTP 200 for a plain completion, accepted
reasoning_effort, and produced areal
tool_callsresponse.One real inference call, through the added code path — not curl, not a
mock. A small program imports
charm.land/catwalk/pkg/embedded, looks upInferenceProviderAIMLAPI, and takes the endpoint, the model ids, the API-keyenv var name and the headers entirely from the entry this PR adds:
Server:
go run .thenGET /v2/providers→ 42 providers,aimlapi.compresent with 9 models and all four headers intact through JSON round-trip.
What could not be verified
reasoning_levelsis["low","medium","high"]for every model. Thosethree were each confirmed to return HTTP 200.
xhigh,max,noneandminimalappear on other providers in this repo but were not tested here, sothey are not claimed.
cost_per_1m_out_cachedis the cache read price andcost_per_1m_in_cachedthe cache write price, perCRUSH.md. Write pricesare published for the Anthropic and GPT-5.6 entries only; the rest are left at
0 rather than guessed.
supports_attachmentsis set from live probes, not from the publishedcatalog. For
anthropic/claude-opus-5andanthropic/claude-sonnet-5thecatalog's
modalities.inputsays["text"], but both models in fact acceptand correctly describe an inline image;
deepseek/deepseek-v4-procorrectlyrejects one with HTTP 400. This is an upstream metadata bug on the aimlapi.com
side and has been reported there.
GET /v1/models?include=pricingand are a point-in-timesnapshot. Without a
cmd/aimlapiupdater they will drift; refreshing them isa manual edit.