Skip to content

feat(llm): add aimlapi.com as an LLM endpoint with partner attribution - #1

Open
Lookoff-AIMLAPI wants to merge 4 commits into
mainfrom
feat/llm-aimlapi-provider
Open

feat(llm): add aimlapi.com as an LLM endpoint with partner attribution#1
Lookoff-AIMLAPI wants to merge 4 commits into
mainfrom
feat/llm-aimlapi-provider

Conversation

@Lookoff-AIMLAPI

Copy link
Copy Markdown
Member

Summary

Makes aimlapi.com a first-class OpenAI-protocol endpoint for EverOS.

EverOS has no LLM provider registry — component/llm/client.py builds one
OpenAI-compatible client from base_url, and everything (OpenRouter, OpenAI,
vLLM, DeepInfra) goes through it. So an aimlapi.com key already worked before
this PR by setting base_url alone. Two things did not:

  1. Attribution. aimlapi.com credits the project that sent the traffic only
    when the request carries partner headers. A missing header fails silently
    the call succeeds and the credit is simply lost.
  2. Documentation. The Quick Start reads as though OpenRouter were a
    dependency rather than one choice of endpoint.

1. feat(llm): attribute traffic sent to aimlapi.com2d0ace6

New everos/component/utils/attribution.py. Four headers —
X-AIMLAPI-Partner-ID, X-AIMLAPI-Source, HTTP-Referer, X-Title — with
HTTP-Referer/X-Title naming EverOS, not the provider.

The headers are origin-scoped, which is the whole design constraint here:
the same client class talks to every other provider, so the helper parses the
configured base_url and returns {} for any host that is not aimlapi.com.
Matching is on the parsed hostname at a dot boundary, so
api.aimlapi.com.example.net gets nothing. A fresh dict is returned per call;
no shared constant is handed out for mutation.

Wired at all three client construction sites:

Site Mechanism
component/llm/client.py ([llm] + [multimodal]) LLMConfig.extra = {"extra_headers": ...} — everalgo's OpenAICompatClient splats config.extra into the request, and the openai SDK forwards extra_headers as headers, not body fields. Empty dict for every other provider, so no key is added to the request at all (some upstreams 400 on a null-valued option).
component/llm/openai_provider.py AsyncOpenAI(default_headers=...), merged into the SDK's own defaults rather than over them.
component/embedding/openai_provider.py Same.

Tests (25 new): the partner id is asserted against ^part_[A-Za-z0-9]{1,64}$
(a malformed id is accepted by the API and then earns nothing, silently);
every non-aimlapi host — OpenRouter, OpenAI, DeepInfra, a lookalike domain, a
proxy with our host in a query string — must yield an empty mapping; and each
construction site is checked to actually forward them, because a client built
without them still works, just unattributed.

2. docs(config): document aimlapi.com as an LLM endpoint81eb32f

docs/configuration.md, config.example.toml, config/default.toml,
templates/env.template (and .env.example, which make docs-check requires
to match the template). The shipped [llm] and [multimodal] model slugs are
already spelled the way aimlapi.com spells them, so this is a base_url + key
change with no model rewriting.

3. chore(aimlapi): fork-only placement — do not send upstreamcb397ff

Leads the README/QUICKSTART Quick Start with aimlapi.com. Separated so it can
be dropped wholesale
before the docs commit is offered upstream — picking a
default provider is a maintainer call. EverOS has no provider registry, no
provider list, and no featured-badge convention, so there was nothing to
reorder and no badge mechanism to reuse; the provider-endpoints table in
docs/configuration.md is alphabetical.

Area

  • Documentation
  • Developer experience

Verification

Baseline (2a3136f, pristine tree):   make ci -> exit 0
  make lint         all gates pass (import-linter 3/3 contracts kept)
  make test         2092 passed
  make integration  183 passed, 7 deselected
  make package      wheel built + import-smoked (everos 1.2.3)

After this branch:                   make ci -> exit 0
  make lint         all gates pass
  make test         2117 passed        (+25 new)
  make integration  183 passed, 7 deselected   (identical)
  make package      wheel built + import-smoked (everos 1.2.3)
  make docs-check   pass
  make check-commits RANGE=origin/main..HEAD   pass

LIVE calls through everos.component.llm (not curl, not a mock), with an
httpx request hook recording what actually went on the wire:

[1] plain chat via get_llm_client()          model openai/gpt-4.1-mini
    content       : 'EverOS memory online.'
    model echoed  : gpt-4.1-mini-2025-04-14
    finish_reason : stop
    usage         : prompt_tokens=16 completion_tokens=5

[2] structured output (beta.chat.completions.parse — the path the
    everalgo extractors use)
    content       : '{"subject":"Ada Lovelace","predicate":"wrote",
                      "obj":"the first algorithm"}'
    parsed        : subject='Ada Lovelace' predicate='wrote'
                    obj='the first algorithm'
    finish_reason : stop

[3] text call via get_multimodal_llm_client()
    model         : google/gemini-3-flash-preview
    content       : 'multimodal client up.'

[5] headers actually put on the wire (authorization dropped):
    {'http-referer': 'https://github.com/EverMind-AI/EverOS',
     'x-aimlapi-partner-id': 'part_everos',
     'x-aimlapi-source': 'agent/everos',
     'x-title': 'EverOS', ...}
    — present on all four requests, chat-completions and beta.parse alike.

Both model ids shipped in the docs (openai/gpt-4.1-mini,
google/gemini-3-flash-preview) pass the catalog id-or-alias check and were
called live
. Catalog membership alone is not treated as proof in either
direction: the catalog is known to omit ids that work and to list at least one
that 404s. No model id was removed.

Known limitation — recorded, not papered over

[multimodal] image requests fail against aimlapi.com. everalgo's
ImageUrlInner.detail defaults to None and model_dump() emits it, so every
image part goes out as {"url": ..., "detail": null}, which aimlapi.com rejects:

400  error.details: [{"path": "messages.0.content",
                      "reason": "Invalid input", "code": "invalid_union"}]

Isolated by direct probe with an otherwise identical, valid data-URI image:
detail omitted → 200 'Red'; detail: "auto" → 200 'Red';
detail: null → 400. OpenAI and OpenRouter accept the null. The serialisation
lives in the everalgo dependency, not in this repo, so it is documented rather
than worked around here. Text-only [multimodal] calls are unaffected.

Checklist

  • I kept the change scoped to the relevant area.
  • I am opening this from a separate branch, not pushing directly to main.
  • I updated docs, examples, or setup notes when behavior changed.
  • I added or updated tests when the change affects behavior.
  • I did not commit secrets, .env files, dependency folders, or generated output.
  • Active relative links in Markdown files resolve (make docs-check).

Notes for Reviewers

  • The extra_headers-through-LLMConfig.extra route is the only way to attach
    headers without forking everalgo; it is worth a look, since a future
    everalgo release could start validating extra as body-only.
  • component/llm/factory.py / OpenAIProvider are currently referenced only by
    their own unit test — the live path is client.pyeveralgo.build_client.
    Both were wired anyway so the exported public surface behaves consistently.
  • max_tokens does not reliably bound reasoning tokens on every upstream, so it
    should not be presented anywhere as a cost bound. Observed here:
    google/gemini-3-flash-preview with max_tokens: 16 returns HTTP 200 whose
    choices[0] has no message key at all (only finish_reason: "length"),
    and a usage object with no completion_tokens. everalgo's _chat_create
    guards choices being empty but not a choice without a message.

By submitting this pull request, I agree that my contribution is licensed under
the Apache License 2.0.

aimlapi and others added 4 commits September 3, 2026 12:54
EverOS reaches every model through the same OpenAI-protocol clients, so
an aimlapi.com key already works today by setting base_url alone. What
does not work is attribution: aimlapi.com credits the project that sent
the traffic only when the request carries partner headers, and a missing
header fails silently — the call succeeds, the credit is simply lost.

The headers cannot be pinned to the SDK layer, because the same client
class is what talks to OpenRouter, OpenAI, DeepInfra and vLLM. So the
helper is origin-scoped: it parses the configured base_url and returns
an empty mapping for any host that is not aimlapi.com, which is why the
LLM, multimodal and embedding clients can all call it unconditionally.

Matching on the parsed hostname at a dot boundary keeps a lookalike host
(api.aimlapi.com.example.net) from collecting headers meant for us, and
returning a fresh dict each call keeps callers from mutating a shared
constant. Where a client accepts only per-request options — the everalgo
LLMConfig passthrough — the headers ride extra_headers, which the openai
SDK forwards as headers rather than as body fields; for other providers
no key is added to the request at all, since some upstreams reject a
null-valued option outright.

Tests pin the partner id against ^part_[A-Za-z0-9]{1,64}$, because a
malformed id is accepted by the API and then earns nothing.
The shipped `[llm]` and `[multimodal]` model slugs are already spelled the
way aimlapi.com spells them, so pointing EverOS at it is a base_url and
key change with no model rewriting — worth saying out loud, because the
docs currently read as if OpenRouter were a dependency rather than one
choice of OpenAI-protocol endpoint.

Both shipped default models were called live through the component/llm
client path before this was written, structured-output path included.

The multimodal caveat is recorded rather than papered over: the image
parts EverOS sends carry `image_url.detail = null`, which aimlapi.com
rejects with a 400 while OpenAI and OpenRouter accept it. Anyone who
switches `[multimodal]` over would otherwise hit it with no explanation.

`.env.example` is regenerated from the template it must match, per the
`make docs-check` gate.
Leads the Quick Start with aimlapi.com instead of OpenRouter. This is a
placement preference, not a correctness change: both endpoints spell the
shipped model slugs identically, so the walkthrough works either way and
the alternative stays one line below.

Separated from the preceding commits so it can be dropped wholesale
before the docs change is offered upstream, where choosing a default
provider is the maintainers' call and not a contributor's.

EverOS has no provider registry, list, or featured-badge mechanism, so
there is nothing to reorder and no badge convention to follow — the
Quick Start is the only place a provider is named prominently.
The placeholder part_everos was a readable stand-in chosen before the
partner was registered. Registration mints the id server-side, so the
real value is part_VxTyAUvoIVbl30dPrB7kbRZk. 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