connect: ai& is a provider of its own, and one key reaches four labs - #1737
Open
fenilmodi00 wants to merge 3 commits into
Open
fenilmodi00 wants to merge 3 commits into
fenilmodi00 wants to merge 3 commits into
Conversation
ai& (api.aiand.com) is a Japan-hosted, OpenAI- and Anthropic-compatible inference service selling one prepaid credit per token. Its list reaches models from several labs at once, so one key covers what would otherwise take four accounts. The PROVIDER is one row in modelsource.Vendored(). Everything else the person touches is already derived from that catalog: the connect panel, the providers group, the picker group, the Providers tab and `codeaf connect aiand`. Config.Direct already switches off the router's lane sheet, generation-receipt fetch, price ceiling and routing vocabulary for a vendor reached directly, so a direct vendor stays a base-URL swap. internal/session needed no change either — clientdoor.go keys its adapter pool on the resolved connection and strips the service segment from the id it sends, which is why ai&'s own two-segment ids already reach it whole. WHAT MAKES THIS ROW NAME SIX VENDORS RATHER THAN ONE IS THAT AI& IS NOT ONE LAB. Every other direct connection here is one vendor with one model family, which is why the existing rows need no vendor list: their own Written prefix already names their only family. ai& reaches GLM, DeepSeek, Qwen and Kimi at once, so the crew is given the CATALOG vendor words it actually serves — crewVendors["aiand"] names deepseek, z-ai, moonshotai, qwen, openai and google — and one key can carry a planner and a checker sitting on DIFFERENT labs in the same task. That is the shape the provider exists for, and it is proved on the SEATS rather than on the catalog, because a row that quietly collapsed to one family would still pass every send assertion. `google` is in that list even though no other connection carries it, because what the crew needs is a CATALOG vendor and the catalog has a gemma family; the seventh organisation on the listing, motif-technologies, is in no catalog row, so the crew cannot weigh Motif 3 however good its own numbers are. TWO FACTS THE CATALOG ALONE DOES NOT GIVE, and both are about that send. ai& is the first connection here that is ITSELF A ROUTER: its ids already name the lab that built the model (`zai-org/glm-5.3`, `deepseek-ai/deepseek-v4.1- flash`), so a send is the provider segment over the vendor's OWN id rather than a bare name. crewVendorWire spells the catalog's vendor the way ai& spells it. This is not a tidiness fix. Asked on 2026-10-02 for the bare names that table exists to avoid sending — `deepseek-v4-flash`, `glm-5.3-flash`, `kimi-k3` — api.aiand.com answered 404 `model_not_found` for every one, while `deepseek-ai/deepseek-v4-flash` and `zai-org/glm-5.3-flash` answered 200. So a send without the rename is a call that fails, not a spelling somebody might prefer. A vendor the two spell the same way keeps the catalog's own segment, so `moonshotai/kimi-k3` is sent as `aiand/moonshotai/kimi-k3` rather than being renamed to some other organisation's name. Note this is NOT crewroute's vendorOrgs table read backwards: that one maps `moonshot` to the catalog's `moonshotai`, and folding the two together would rename a send that works into one that 404s. THE PREFERENCE MOVED, and the vendor's own manifest is why. https://api.aiand.com/v1/api.json answers 200 without a key and publishes cost, limits, modalities and capabilities per model. It says the flagship, `zai-org/glm-5.3`, is `attachment: false` with `input: [text]` — so a person who dropped a screenshot into their first ai& conversation was refused by the model codeaf had just seated them on. The preference is now `zai-org/glm-5.3-flash`: same family, same million tokens (1048550 against 1048576), `input: [text, image, video]`, and $0.15/$0.50 against $1.00/$4.00. It is the cheapest of the four rows that take attachments and hold 1M, which is the rule Source already states — the vendor's best model, not simply its flagship. DELIBERATELY NOT COPIED FROM ALIBABA'S ROW. DashScope declares two regions and two billing doors because it genuinely runs an international and a China host and sells a coding plan beside metered traffic. ai& is Japan-only on one endpoint and sells one prepaid credit, so there is no region to choose and no second billing product to tell apart — and a test already holds that law: a second door is legal only with wire evidence distinguishing the billing products, which is why MiniMax declares none either. Offering a choice that does not exist is worse than offering none. The one-door claim says why in the row for the same reason: nothing on the wire separates a plan from metered credit. A 402 insufficient_credits is already read correctly by paymentrefusal's generic 402 rule. ai& collides with no model author, so it keeps the name `aiand` and never becomes `aiand-direct`. DELIBERATELY NOT FIXED HERE, AND IT IS NOT A BUG IN THIS ROW. ai& publishes the effort words per model (`reasoning_efforts` on every row of /v1/models) and only `high` is universal across the thirteen: kimi-k2.7-code takes `high` alone, qwen3.8-27b takes none/low/medium/xhigh and so NOT `high`, and glm-5.3 takes low/high/max and so neither `none` nor `medium`. The listing parse keeps only the `id`, and the adapter's ReasoningProfile seam is fed by the ROUTER's catalog, so a direct provider's profile reads unknown and the requested word goes out unclamped. Teaching a direct provider to publish its own reasoning profile means changing internal/catalog, internal/config and internal/provider together, and it would move effort handling for every direct connection rather than this one. It wants its own change and a live key; the change entry records the measurements so they are not rediscovered. The rest of the diff is what the row forces. The vendored-row test pins the table's order and its Ollama-is-the-only-optional-key law, so both move and the Ollama lookup stops being an index — inserting a row above it must not have to be re-counted. The three test helpers that clear provider key variables gain AIAND_API_KEY, because connect/key.go resolves a connection straight from the environment and a stray variable would otherwise leak a CONNECTED ai& into those panels. A listing test holds that a model the catalog cannot weigh still reaches the picker with its vendor segment whole, which is the other half of the motif story and the wrong fix twice over. The manual gains the provider in the two places that named the group and counted it, where leaving the old list would have made the page false; the crew page needed no edit, because it already says every model a connected provider serves is a candidate, and that sentence is now true of ai& rather than needing one written for it. Verified live against the API on 2026-10-02: the listing, a streamed reply with its usage frame, tool calling, max_tokens, stream_options, the refusal of a bare model name, and the manifest every cost and modality figure above is read from. Also observed: X-Cost is advertised in access-control-expose-headers and never sent, so a direct provider's cost cannot be read off a response.
docs/rules/changelog.md puts the order plainly: push the branch, open the pull request, let `check` go red once, then add the entry with the number that failure names. The entry was written against a guessed 1736, and the pull request is 1. Renaming the file is the whole change. `make changelog-check` reads 9 entries, all well formed. One sentence inside it was also untrue once the crew tables landed: it still said the change was one row and nothing else, which stopped being the case when internal/config/crew.go grew two. It now says which two files carry production code.
The entry was first written against a guessed 1736, then renamed to 1 when the pull request was opened on the fork. It is now opened upstream, where the number is 1737, and that is the number the entry has to carry: the file name is what the roll-up reads, and a merge takes the upstream number. `make changelog-check` reads 9 entries, all well formed.
Member
|
Hey, thanks for the PR. Could you sign the CLA when you get a chance so we can review it? |
Closed
4 tasks done
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 changed
ai& (
api.aiand.com) is now a provider of its own. One key reaches models from four labs, so it covers ground that would otherwise take four accounts.The provider is one row in
modelsource.Vendored(). The connect panel, the providers group, the picker group, the Providers tab andcodeaf connect aiandall derive from that catalog, so nothing else needed wiring.internal/config/crew.gogrew two tables, because ai& is the first connection here that is itself a router:var crewVendors = map[string][]string{ "moonshot": {"moonshotai"}, "codex": {"openai"}, + "aiand": {"deepseek", "z-ai", "moonshotai", "qwen", "openai", "google"}, } + +var crewVendorWire = map[string]map[string]string{ + "aiand": {"deepseek": "deepseek-ai", "z-ai": "zai-org"}, +}The first row is what makes one key serve several labs. The second is a spelling, and it is load-bearing: ai& publishes
deepseek-ai/deepseek-v4-flashwhere the catalog saysdeepseek/deepseek-v4-flash, and asked on 2026-10-02 for the bare names it answered404 model_not_foundfor every one.moonshotaiis deliberately left alone, because ai& servesmoonshotai/kimi-k3and renaming it would break a send that works.The row's preferred model moved.
https://api.aiand.com/v1/api.jsonanswers 200 without a key and publishes per-model cost, limits and modalities; it says the flagshipzai-org/glm-5.3isattachment: false, so the model codeaf seated a new connection on refused their first screenshot. The preference is nowzai-org/glm-5.3-flash: same family, same million tokens, takes image and video, and $0.15/$0.50 against $1.00/$4.00.The manual gained ai& in the two places that named the provider group and counted it, where leaving the old list would have made the page false. The crew page needed no edit, since it already says every model a connected provider serves is a candidate, and that sentence is now true of ai&.
Merge danger. Two-way door, and the revert is clean. The one thing worth a reviewer's attention is
crewVendorWire: it reads close tocrewroute.vendorOrgs, which holds the inverse mappings, and the two disagree on moonshot. Folding them together would renameaiand/moonshotai/kimi-k3into a send that 404s. The commit message says so at the point of the table.How it was checked
Live against the API on 2026-10-02: the listing, a streamed reply with its usage frame, tool calling,
max_tokens,stream_options, the refusal of a bare model name, and the manifest every cost figure above is read from.The multi-family claim is proved on the seats rather than the catalog, because a row that collapsed to one family would still pass every send assertion:
go build ./...,go vetandgofmt -lare clean. One earlier run showedTestADecisionTakesUnderTwoMillisecondsat 2.11ms against a 2ms budget while five packages ran at once;internal/crewrouteis not in this diff and the test passes 3/3 focused and green on its own.Not in this change
The effort words are per-model and do not line up with codeaf's ladder. Only
highis universal across the thirteen:kimi-k2.7-codetakeshighalone,qwen3.8-27btakesnone,low,medium,xhighand so nothigh. ai& publishesreasoning_effortsper model, butconfig.listedOutcomekeeps only theidand the adapter'sReasoningProfileseam is fed by the router's catalog, so a direct provider's profile reads unknown and the requested word goes out unclamped. Fixing that means changinginternal/catalog,internal/configandinternal/providertogether and would move effort handling for every direct connection, so it wants its own change and a live key. The change entry records the measurements.motif-technologies/motif-3reaches the picker and sends correctly, and the crew cannot weigh it because no catalog row names that vendor.TestAModelTheCatalogCannotWeighStillReachesThePickerholds that split so it is not later "fixed" by dropping the row from the listing.Checklist
docs/changes/unreleased/1737-aiand-native-provider.md, named for this pull request and carrying the four beliefs it contradicts.commands.mdandservices.mdcorrected where they named the group and counted it. No slash command, key, tool, default, limit or refusal moved, and no gate asks for more..github/known-red.txt— the file does not exist.