Changelog
Each entry lists the changes that you can notice as a User of the API or the App, by date, newest first.
2026-11-03
New
- The App has a Request more tokens page, under Usage (Ask for more tokens). You say how many tokens you need, for which models and which project, and how you will use them. An admin approves the request with a Grant, or rejects it with a note, and the page lists each request with its answer.
- From 90% of your tokens used, a notice under the title of each page of the App says how many are left, with Request more. It takes the place of the notes on Usage and API Keys that told you to email for a Grant.
- Admin has a Token requests tab, where an admin approves a request with a number of tokens, such as
50K, or rejects it (Decide token requests). Grant tokens, Set the Budget, and Set the monthly allowance take a number written the same way. - The API takes steering at chosen positions on every model. Give each Layer a list of vectors, with
position_indices, or without them for positions 0, 1, 2, and so on (Steer chosen positions). - A Steering vector takes
position_spans, the old platform's spans of positions. One vector for each Layer goes to each position of the spans (Steer a span of positions). - An admin can type a User's organization and Discord handle on the User's page (Open a User's page).
Changed
- When your own tokens cannot hold a request, the message of 429
budget_exceededends with the address of the form,Ask for more tokens at https://v2.infra.acsresearch.org/usage/request.(Not enough tokens). The code staysbudget_exceeded. In the Playground, the note says how many tokens the request can use and links to Request more tokens, without the address. - A Steering vector position that no forward pass of the request reaches gets 400 on
apply_steering_vectors, before the request holds any tokens. Before, positions were refused (Positions that a request reaches). llama-8bandllama-405btake 131,072 tokens of prompt and generated text together, the whole context of Llama 3.1. Before, they took 8,192 (Served models).trinity-truebasekeeps 8,192, the model's own context.- With the longer context, a capture of
llama-8bwithoutmax_tokensgets 400. Left out,max_tokensis the room left in the context, which passes the capture's size cap (Requests that the API refuses). Setmax_tokenswith every capture. temperaturetakes a value from 0 to 2. The old platform's API took up to 100, but Inference refuses a value above 2. So the API refuses it with 400invalid_requestbefore the request holds any tokens (Request fields). In the App, Temperature's slider goes from 0 to 2, and the field marks a value outside the range.- The API refuses the other sampling values that Inference refuses, with 400
invalid_requestbefore the request holds any tokens (How to sample). These aretop_kbelow -1,min_poutside 0 to 1,presence_penaltyandfrequency_penaltyoutside -2 to 2, andrepetition_penaltyof 0 or less. The API also refusesnabove 1 at atemperaturebelow 0.00001, where Inference samples greedily. Before, such a request woke the model and then failed. The App's fields mark these values too. - The narrower sampling ranges,
top_p's of 2026-10-28 too, apply to new requests only. A Run or a Loom Node saved with a value outside them still lists, opens, and exports with that value. A Run, a Node, or a Job that waits to run with such a value runs, and Inference decides on the value. In the Playground, Use these settings puts the value in the form, which marks it (Find your Runs again). - Jobs have the routes and the shape of the old platform's API, so code written for its Jobs runs unchanged (Run a Job).
POST /v1/completion-jobstakes one body ofPOST /v1/completionsand answers 202 with aLocationheader.GET /v1/completion-jobs/{job_id}givesstatusqueued,running,succeeded,failed, orcancelled, ISO times,status_url, andresult_url.GET /v1/completion-jobs/{job_id}/resultanswers the Completion, or the error with the status thatPOST /v1/completionswould have answered. A cancel of an ended Job answers the Job.POST /v1/jobsand its routes are gone. - Harvests have the routes and the shape of the old platform's API, so its polling loop runs unchanged (Harvest Activations).
POST /v1/harvestanswers 202 withjob_id,n_prompts, andreserved_tokens.GET /v1/harvest/{job_id}givesstatuspending,running,done,failed, orcancelled, ISO times,completed_at,erroras a message, and, oncedone,resultwith the links of the files.DELETE /v1/harvest/{job_id}cancels a harvest, and adoneorfailedone gets 409harvest_not_cancellable.POST /v1/harvestsand its routes are gone. - An
Idempotency-Keysent again with another request gets 409idempotency_conflictwithx-should-retry: false, in place of 400. A full Job cap is 429job_capacity, and an expired Job result is 410job_result_expired. - The API takes the
X-Request-Idthat you send as the id of the request, as the old platform does (Headers). It must have 1 to 64 letters, digits,-, or_. - A Steering vector's
activationscan be encoded as the old platform'sencode_vectorwrites them (Encode a Steering vector). The numbers are bfloat16 asint16, or float32, in zstd and base64. An encoded vector takes about a tenth of the bytes of JSON numbers, so eight vectors over all 32 Layers ofmeta-llama/Llama-3.1-8Bfit the body cap. The API checks it as it checks numbers, and sends it to Inference as it is. - The API counts a text prompt's tokens with the model's own tokenizer, as Inference does (The Hold). Before, it counted the UTF-8 bytes. A request without
max_tokensgets the context that its tokens leave. A 9,000-character prompt totrinity-truebasegets about 6,190 tokens, where it got 1. The Hold, the cut near the end of your Budget, and the caps of a capture and ofprompt_logprobs: -1use this count too. prompt_logprobs: -1takes several prompts of at most 256 tokens in all ×n, and keeps 256 with Steering vectors. Onlyoutput_residual_streamlowers it to 16 (Size caps).- The API's address sends the old platform's page addresses to their pages.
/docsand its pages and/llms.txtlead to these docs, and/swaggerto the API reference. The old example downloads lead to the Cookbook, and/usageto the App's Usage page. An old page such as/docs/apior/docs/bulk-harvestleads to the page that took its place.
Fixed
- Inference's answer can miss a choice, or have
activationsthat are missing or of another shape than the request asked for. The API then answers 502upstream_server_error, and the request costs nothing. Before, such an answer came back as a 200 and cost its tokens. In a stream, the error comes as the last event, and you pay for the tokens before it (Decode the tensor). - A Loom Node that fails keeps the text that it grew and its own
error. This is also true when the API could not save its end at the first try. Before, a Node that failed early lost its text, and itserrorsaid only that the server had an error (Read a failed Node). - In Compare, a model whose Run cannot start shows why in its own place (Compare models and settings). Earlier Runs no longer stay in view beside the new ones.
- A Run says which stop sequence ended it, or that the model ended the text, also when Top logprobs shown is 0.
- The likeliest tokens at a token stay on the screen, and the list scrolls when it is long.
- Select a Loom's title to rename it (Open or start a Loom). Rename left the buttons by the title.
- On Admin, an Application's unanswered questions show as Not answered.
- An email link in the docs and in the App opens your mail app without a blank tab.
2026-11-02
Changed
- The API takes the API keys of the old platform, which start with
acs-bm-, as well as keys that start withsk-acs-(Use API keys). - Requests and
GET /v1/modelsname each Base model by the id of the old platform:llama-8b,llama-405b, andtrinity-truebase(Models). A request withoutmodelruns onllama-8b. Each answer'smodelstill names the weights that ran it, such asmeta-llama/Llama-3.1-8B. GET /v1/modelslists each model in the old platform's shape: itsid, itsserved_model_name, itsgpu_shape,default, andcapabilitieswithn_layers,hidden_size,max_activation_prompt_tokens, and the limits of a request (Model fields). The App keeps its own list.GET /v1/models/{model}/statusgivesbootwithstage,stage_label, andstage_age_s, and the same inactivation_boot(Check whether a model is Warm). Both routes take aserved_model_namewith its slash, such as/v1/models/meta-llama/Llama-3.1-8B.- Each choice of a Completion has
stop_reason, thestoptext that ended it, in an answer and in a stream's chunks (Response fields).stream_options.continuous_usage_statsalone puts the usage so far in each chunk of a stream, withoutinclude_usage. - A stream has a
: keepalivecomment line every 5 seconds, as the old platform's streams do. A client's read timeout then does not cut a stream while Inference is silent (Requests with a stream). - Every error of the API has the error object of the old platform's API. Code written for that API branches on the same
error.code(Status codes).request_idis at the top of the body, besideerror. A request that the Budget cannot hold is 429budget_exceeded, a rate limit 429rate_limited, and a full line of Completions 429queue_full. A request with no key is 401missing_authorization, and a revoked or paused key is 401key_revokedorkey_disabled. An unknown model is 400model_not_found, so theopenaiSDK raisesBadRequestErrorfor it. - A failure of Inference has the type
upstream_errorand acodethat names it, such as 502upstream_unreachable,vllm_oom, orupstream_server_error, withretryableandretry_after_seconds(Answers about Inference). Inference's own 500 is now 502, and its timeout is 504upstream_deadline. POST /v1/completionstakes the values that the old platform's API takes (Request fields).max_tokens: nullis the same as leaving it out, andoutput_residual_stream: falsereads no Activations.output_residual_streamtakes its Layers in any order and with a Layer twice. The Activations hold each Layer once, in ascending order.prioritytakesnull, a text of digits such as"5", andtrueorfalse.- The API reads the body of a
/v1request as JSON whatever itsContent-Type, as the old platform's API does.curl -dwithout-H 'Content-Type: application/json'works, and a body oftext/plainno longer gets 415. A body sent in chunks, withoutContent-Length, no longer gets 411. The API checks the key first, then reads the body and answers 413request_too_largewhen it passes the body cap. GET /healthanswers in the old platform's shape:status,wrapperwithuptime_secondsand thedatabase,backendswith each model'smodel_id,gpu_shape, and breaker,degraded_backends, anddegraded_reasons. It still answers 503 only when the database does not answer.
2026-10-30
New
- Each row of the Playground's Runs table ends with a menu, in place of Delete. It has Show, Use these settings, Copy settings, Copy prompt, Copy output, Copy as API request, and Delete. Copy as API request copies a curl command for
POST /v1/completionsthat reads your key from$ACS_API_KEY(Find your Runs again). The menu stays at the right edge of the table when the table scrolls sideways. - The Models tab of Admin keeps models Warm (Keep a model Warm). An admin sets hours each week, or keeps a model Warm at once for 1 to 24 hours. The tab shows each model's Floor and what its windows cost.
Changed
- In the App, Support has Email, Discord, Feedback, and Help. Discord opens the invite to ACS's Discord server in a new tab. Before, it was called Community and opened a page with Join the Discord server. Old links to that page open the invite (Discord).
- Feedback under Support opens Send feedback, which was a button of its own in the navigation (Send feedback). Help opens Support in these docs. Before, it was called Help and FAQ.
- Profile no longer shows your role or your token budget. Usage shows your token budget and monthly allowance (Read your usage).
- Send feedback sends your notes to Linear, the team's issue tracker, with your account's email. The team can then answer you. An anonymous note goes without your email (Send feedback).
- The Feedback tab of Admin links each note to its Linear issue.
- API Keys lists only your active and paused keys. A revoked key leaves the page, and the line of revoked keys at the bottom is gone. With no such key, the page says No API keys yet, also when you once had keys. By key on Usage still shows a revoked key's tokens under its name (Revoke a key).
- While API Keys loads, it shows the head of its table and three gray rows. With keys, the table stays in place when the list arrives, and New key shows in the header. With no key, the page shows No API keys yet and New key in its middle, with no table. The notes, such as
No tokens left., show below the table, or at the bottom of the page with no key. A key's name shows on one line, cut short when it does not fit. - Jobs shows Run Jobs from a script in the middle of the page, as API Keys does with no key.
- API Keys no longer counts your keys beside its title, such as
3 of 10 keys. At 10 keys, New key is still off, and the note below the table says why (Manage your keys). - The Analytics tab of Admin has five tabs: Users, Budget, Platform, Usage, and Spend. The days at the top of Analytics apply to each of them. Usage and Spend were tabs of Admin, and old links to them open their tab in Analytics. The Section filter is gone (Read the platform's analytics).
- On Admin, Applications shows the day of each Application under Submitted, and the day and the admin of its decision under Reviewed. Feedback shows the day of each note under Submitted. Before, these columns were Received, Decided, and Sent.
2026-10-29
New
- Harvests read the residual stream of up to 4,096 prompts at the Layers that you choose, on GPUs of their own.
POST /v1/harvestsqueues one, andGET /v1/harvests/{harvest_id}reads it, withwaitto wait for a change.GET /v1/harvests/{harvest_id}/resultsgives links to its safetensors files, andPOST /v1/harvests/{harvest_id}/cancelcancels it (Harvest Activations). - The files of a harvest have the old platform's layout, version 2, so programs that read those files read these too. Each answer of the results route makes new links that work 7 days, and the API keeps the files (Kept data).
- A harvest holds its prompts' tokens while it runs. It pays the tokens that Inference read when it completes, and nothing when it fails (Holds of background work). The App's Usage page shows its tokens under the source Harvests.
- Each API key may start 200 harvests a month. Each User may have 3 harvests on Llama 3.1 8B
queuedorrunning, and 1 on Llama 3.1 405B or Trinity Large (Harvests). - The Cookbook's recipes link to their whole programs as files to download. Run a Job from a shell script links to
job.sh, for example. - The Cookbook has Evaluate with Inspect. It runs an Inspect eval through
POST /v1/completions, with a task to download. - The Cookbook has Run the workshop notebook. Its Jupyter notebook goes from a first Completion to a steered Base model.
- An admin's Admin page has an Analytics tab with the platform's numbers (Read the platform's analytics). It counts Users, monthly allowances, refusals, server errors, sources, and hours. The numbers that were above the tabs moved into it.
- Admin has a Spend tab with the GPU spend of each model and day, and who used each model in 48 hours (Watch the spend). Its Lock and Clear pause and resume new GPU work. Analytics shows the GPU spend of its days.
- The API pauses new GPU work when the GPUs cost $3,000 in 24 hours, and an admin can pause it too. While the pause is on, a Completion, a Job, or a Branch that you start gets 429
spend_capwithRetry-After: 3600, and queued work waits. Work that runs finishes (Spend limit). - An admin can put tags on Users, such as
hiring-2026-08, and an Invite can give its new User a tag. Users on Admin lists each User's tags and has a Tag filter (Group Users with tags). - Users on Admin shows each User's organization, engagement, active weeks, and models, and has an Engagement filter (Manage Users).
- An admin can select many Users on Users and act on all of them at once (Act on many Users at once). The actions are suspend, restore, tag, set the monthly allowance, and delete.
- Each User has a page on Admin, which their email on Users opens. It has their account, tags, Budget and usage, API keys, Application, and notes (Open a User's page).
Changed
- On API Keys, New key opens a dialog for the key's name, then shows the key once in Copy your key. The page title counts your keys that are not revoked, such as
3 of 10 keys. At 10, New key is off, and the page says why. Before, a form at the top of the page made a key (Make an API key). - Each key on API Keys has one menu for Rename, Pause or Resume, View usage, and Revoke. Before, each row had three buttons. A key's tokens this month open Usage for that key. Revoked keys fold into one line at the bottom of the page, such as
2 revoked keys. A time today shows in UTC, such as05:02 UTC, and an earlier one shows its date (Manage your keys). - API Keys no longer shows the tokens of your month and your Budget above the table. Usage shows them (Read your usage).
- The App's Usage page starts with four numbers. They are the tokens used, the Completions, and the tokens left in the monthly allowance and in the token budget. At the top, choose the days to count, up to 366 UTC days, and one key or one model. The address keeps them. Tokens per day charts each day's input and output tokens. By model and By source split the tokens. Before, the page counted this month and the last 30 days only (Read your usage).
- Usage shows each Completion's source and key. Its status is Running, Completed, Failed, or Stopped. Before, it was running or settled. Usage no longer shows the tokens that running Completions hold, because the tokens left already leave them out.
- Usage shows how each Completion's tokens were counted, Reported, Partial, or Held, and how long the Completion took (Read your usage).
- By source on Usage counts each source's Completions and its input and output tokens.
- By key on Usage shows each key's tokens last month and in all, and its own Budget. Select a key's name to count that key alone.
- With one key chosen, Usage shows the tokens left in that key's own Budget, when it has one. The meter of the monthly allowance turns orange from 90% used, and red once the allowance is spent.
- API Keys shows the tokens left in each key's own Budget. It reads its numbers again every minute, and keeps them when a read fails. When you have no tokens left, it says
No tokens left.and whom to ask for a Grant (Manage your keys). - Copy your key asks before it closes while you have not copied the key, and before the tab closes. It links to Set the client for long requests.
- Usage has a Refresh button beside Updated. When a read fails, the page keeps the numbers that it read last and says
Could not refresh. Before, the error took the place of the numbers. The Usage and Analytics tabs of Admin do the same. - The App says input tokens and output tokens where it said prompt tokens and completion tokens. A Run's line and the Read Layers table use the new words. The API's fields
prompt_tokensandcompletion_tokenskeep OpenAI's names. - The App shows the logo of each model's maker before the model's name. It does so in the Playground's model list, Models, Runs, a Run's heading, and on Usage.
- The App names each model by a short name, such as Llama 3.1 8B, Llama 3.1 405B, or Trinity Large. The model's full id shows when you hover over its name. Exports and the page's address keep the full id.
- A Run in the App's Playground leaves the prompt as you wrote it, and its text shows under the prompt. Continue the text is gone. Before, a Run of one choice wrote its text into the prompt as it streamed. To go on from a Run, copy its text into the prompt (Run a prompt).
2026-10-28
Changed
top_pmust be more than 0 and at most 1, as OpenAI and vLLM take it. Another value gets 400 withparamset totop_pbefore the request reaches Inference, and costs nothing (Strict validation). A Loom Branch checks it too, when you make the Branch (Branch under a Node).- Each Run of the App's Playground keeps the number that it got when it started, after a reload and after a delete. The newest Run shows when you come back, and a delete asks you to confirm. The Runs table shows all its columns, and the page scrolls its rows (Find your Runs again).
- Playground in the App's navigation goes back to the settings and Compare that this browser used last. It does so until you sign out or sign in again (Run a prompt).
- The Playground says a setting's limit in plain words, such as
Max tokens: at most 32,000.. When the prompt and Max tokens do not fit in the model's context, it names the context in tokens. - A Branch, a split, or a sibling that would give a Loom more than 2,000 Nodes gets a 409. Its message says how many more Nodes fit (Change the tree).
- Import a Loom in the App names the new Loom after the file's title, with
(imported)after it. The list then tells it from the Loom it came from.POST /v1/looms/importkeeps the file's title, as before.
Fixed
- A Loom that you open again sets Branches to the number of Nodes of its last Branch. It does so also after you split or delete one of them. Before, it often showed 1.
- A Loom whose last Branch asked for no log probabilities opens with Top logprobs shown at 5, so the next Branch has a heatmap. A Branch through the API may ask for none. Before, the box was empty.
- Import a Loom in the App says what is wrong with a file that is not a Loom file, such as
"nodes" is missing. Before, it saidMissing keyand told you to correct a setting and select Branch. - Split at the cursor splits a Node only where you put the cursor or selection inside its text. Before,
sand then Split at the cursor cut at the start. The Node was left empty, and all its text went to the new child. - A Loom page remembers Tree or Graph in every browser, also over plain HTTP. Before, a browser without the Cookie Store API opened the next Loom in Tree.
- A Loom's Graph marks a failed, stopped, or growing Node as the tree does. Its labels fill their column, with the whole first line on hover. Before, a failed Node read No text yet with no mark, and labels stopped after 18 characters.
- On a Loom page, a long title shows in full when you hover over it. Your Looms scrolls under its heading and fills the column beside New Loom. Tree and Graph stay in sight in a long tree. Before, the title stopped after about 20 characters, and the list was a box of 3 rows on every page. The switch scrolled away with the Nodes.
- An Invite's page says that its form sets you up and approves you at once. It no longer speaks of a review. After you send its form, you choose your password. No approval email follows, because its link would be used already.
- When your session ends, as when your access is suspended, the next page that you open in the App takes you to sign-in. Sign-in says that your session has ended, and opens the page again after you sign in. Before, the page stayed open with only an error box.
- After too many tries to sign in, the sign-in page says how many seconds to wait. It keeps the email that you typed.
- On Usage scoped to one key, the monthly allowance and the token budget say that they are for all keys. Their labels read Your account's monthly allowance and Your account's token budget.
- Each Copy in the App, such as a new key's, works when the browser does not let the App copy, as over plain HTTP. The App then shows the text selected, for you to copy by hand. Before, nothing was copied, and nothing on the page said why. The Loom's Copy text showed an error page.
- In the App, Cmd+B or Ctrl+B opens and closes only the navigation, not the settings of the Playground or a Loom. On a phone, a new key's dialog keeps a long key inside its edges.
2026-10-27
New
- Sign in to the App with GitHub, Google, or Hugging Face, when the App shows its button. The provider must have verified the email address that you use for ACS Infra. A provider does not give you access, so apply for access first. On Profile, link and unlink each provider (Sign in).
- Send feedback in the App's navigation sends the team a bug, a feature request, or another note. It takes up to 5,000 characters and 5 screenshots. Unless you send it anonymously, the App's recent errors and request ids go with it, and the dialog shows them first.
- An admin can invite you by email. The email's link opens the Apply form for your address. You are approved as soon as you send the form, and go straight on to set your password. The link works once, for 7 days.
- Every request that makes or changes something takes an
Idempotency-Keyheader. The same request sent again with the key does its work once and is charged once. It gets the first answer, or 409no_answerfor a stream (Send a request again safely). - A page in a browser can call
/v1with your API key. The API answers any origin with CORS, with no cookie. Call the API from a browser says how to keep the key safe. - Each approved User has a monthly allowance of 5,000,000 tokens. A Completion spends this month's allowance while it fits, then your Budget. The allowance starts again on the first day of each month (UTC), as Your monthly allowance explains.
logprobstakes up to 100 top tokens."output_residual_stream": truereads every Layer of the model (Read Activations).stream_options.continuous_usage_statswithinclude_usageputs the usage of each chunk's choice so far in each chunk.GET /v1/modelslists with each model thelimitsthat the API enforces on it (List the models).- A JSON answer of 500 bytes or more comes gzipped when your client asks for it, as the
openaiSDKs do. - A Completion that is not streamed and runs longer than 150 seconds gets 200 at once. Spaces follow every 5 seconds, then its JSON or its error (Requests without a stream).
- The App's Playground keeps its settings in its link. The link holds each model of Compare with its settings, Single or Compare, the Heatmap, and Continue the text. A reload, or a link that you send to another User, opens the same Playground. The link never holds your prompt, a Run, or a Steering vector. Your prompt stays in your browser until you sign out.
- In an empty prompt box of the Playground or of a new Loom, Tab puts in the gray example. The next Tab moves on.
- The App remembers when you close the navigation or the Playground's settings.
- The App's Usage page shows this month's tokens and your monthly allowance, and what running Completions hold. It has a chart of the last 30 days with its table, each key's tokens, and the tokens of each Surface. It shows the history of your Budgets, with the date and the amount of each Grant.
?key=shows one key only. The page reads again every minute while it is open.
Changed
- The App's Loom page has the tree changes and the keys
g,e,s,i,Delete, and?. It has Stop, a graph view with zoom and fit, and the likeliest tokens at a token. Its Export writes the Loom file shape of the old platform. It also has Path as text and Import a Loom (Use the Loom page). - The App's Loom opens the Loom you changed last, and lists your Looms beside each Loom, pinned first. It has New Loom, Rename, and Pin. A Loom opens with the settings of its last Branch.
- Export a Loom with
GET /v1/looms/{loom_id}/export, and make one from a file withPOST /v1/looms/import. The file has the shape of the old platform's Loom export. Files of either then import into the other (Export and import a Loom). - Edit, split, and write Nodes of a Loom, and give it a new root. A Loom holds at most 2,000 Nodes (Change the tree). A Loom lists its Nodes depth first, each before its next sibling.
- Stop a Loom's growing Nodes with
POST /v1/looms/{loom_id}/cancel. Each becomescancelled, keeps the text it grew, and pays for it (Stop a Branch). - Rename or pin a Loom with
POST /v1/looms/{loom_id}. A Loom answers itstitleandpinned, and its first Branch names it after its root.GET /v1/loomslists pinned Looms first, then the others by their last change (Rename or pin a Loom). - A Branch of a Loom without a
seeddraws one. Each Node keeps its ownseed + iin itsrequest, so you can sample any Node again (Branch under a Node). - A Branch of a Loom takes
nfrom 1 to 8 andmax_tokensup to 1,000. More gets 400 withparamset to the field (Branch under a Node). - On API Keys you can rename, pause, and resume a key, and a revoked key stays listed. Two of your live keys cannot share a name. A paused key gets 401
This API key is paused. Resume it on API Keys in the App to use it again.A revoked one getsThis API key has been revoked.Before, both gotIncorrect API key provided. - The Apply form gives every Application the same answer. While you have an open Application, a second one from your email is not stored, and the first stays as it was. Before, it got 409.
- The API runs up to 4 Jobs at once, not one. While a User has a Job running, a newer Job of another User starts before that User's next one.
- The API waits up to 14 minutes for Inference, not 600 seconds.
- The Playground's heatmap colors a likelier token darker. Before, a less likely token was darker.
- A model that the API does not serve gets 404
model_not_foundbefore the API holds any tokens. The message names the models it serves. - Steering at chosen positions gets 400 on
apply_steering_vectorsuntil its test on a GPU passes. That isposition_indices, or a list of vectors for each Layer (Steer chosen positions). POST /v1/chat/completionsgets 400 with a message that namesPOST /v1/completions. Before, it got 404.- A negative
seed,stream_optionswithoutstream: true, and more than 33,554,432 top log probabilities of the prompt in one request get 400 (Size caps). - When Inference refuses the API's own request, the 502 has the header
x-should-retry: false, so theopenaiSDK does not send the request again. - Runs, Jobs, and Branches that you start in the App count against a limit of 600 a minute for each User.
- When Inference refuses or fails a Completion before its first token, a timeout included, the API gives its Hold back. You pay nothing, and the Usage page leaves it out. Before, the Hold was settled at 0 tokens. A Job's request that times out costs nothing.
- A Completion that stops before the API sends it to Inference spends nothing. The running request of a Job that you cancel before it reached Inference spends nothing too.
- A Job or a Branch made with an API key that is paused waits in the queue, holding no tokens. It runs when the key is resumed.
POST /v1/completionswithoutmax_tokensuses the model's context left after the prompt, at most 32,000. Before, it used 16. A request with more than one prompt, or withnabove 1, must set it. Jobs and Looms keep 16.- Near the end of your tokens,
POST /v1/completionslowersmax_tokensto what fits and runs, with the headerX-Acs-Max-Tokens-Clamped. It answers 429insufficient_quotaonly when not even one token for each choice fits (Near the end of your tokens). POST /v1/completionswithoutstreamand with amax_tokensabove 15,600 gets 400deadline_infeasibleandX-Should-Retry: false. It cannot finish within the API's 14-minute wait. Amax_tokensthat you leave out is lowered to 15,600 instead.- A 429
insufficient_quotasays which limit refused the request. The message names your monthly allowance and your Budget, with the day the allowance refills, or the API key's own Budget. - When the API's database is busy or out of reach as a Completion ends, you still get your answer. The API records what it spent a moment later.
- A Job or a Node whose API process crashed runs again. Within about 18 minutes, the next API process gives back the tokens that the crash held, and queues it again. A Job does not pay again for a request that already has its result. Before, the Job or the Node stayed
runningwith its tokens held. - A Job says when the API started it (
started_at), when it ended (ended_at), and when its results expire (results_expire_at). Its results answer 202 with the Job andRetry-After: 1while it is queued or running. Before, they answered 409. The API keeps the results for 30 days after the Job ended, then answers 410 (Download the results). - Jobs have caps. An API key may have 8 queued or running, a User 32, and all Users 128. A User may have 100 completed Jobs with kept results, and all Users 1,000. One more gets 429
rate_limit_exceeded(Limits). - A Job keeps at most 64 MiB of results. Once its lines reach that, its later requests do not run, and each gets an error line (Limits).
2026-10-26
New
- Every error answer has the id of its request in
error.request_id, the same id as in itsX-Request-Idheader (The error object). The error event that ends a stream has it too. A Job's result line and a Node's error have no request id. - When Inference does not answer within 600 seconds, the 502
Could not reach Inference: Request timed out.has the headerx-should-retry: false. TheopenaiSDK then does not send the request again. Your client gets this answer only with a timeout above 600 seconds, for example 660 seconds.
Changed
- The API's own 500,
The server had an error while processing your request., has the headerx-should-retry: false. TheopenaiSDK then does not send the request again. The API does not know how much of the work it did before the error. Another try could run a Completion or a Job two times. Before you send the request again, look for its result, as Which errors to try again says.
Fixed
- When Inference answers with a redirect that the API cannot follow, the API answers 502, as for another refusal of its own request. Before, a Completion got 500, and a stream ended with
Inference ended the stream before it was complete. - A text that holds the character U+0000 (NUL) gets 400
invalid_request_error, with the messageA text cannot hold the character U+0000 (NUL).and its field inparam. The check covers a prompt, astoptext,model,user, a Loom's prompt, a field of the application form, and an email address. Before, a Job, a Loom, a Branch, and the forms answered 500, because the database cannot store the character. A Completion with it gets 400 too, because a Job's requests are Completion requests.
2026-10-24
Changed
prompt_logprobs: -1takes one prompt of at most 256 prompt tokens ×n, or 16 with Activations or Steering vectors. The API counts the tokens as the Hold does. It refuses a larger request, or one with several prompts, with 400 andparamprompt_logprobs, before Inference. Before, only Inference refused it, for a prompt of more than 1,024 tokens, and one request could have several such prompts. Refer to the size caps.
2026-10-12
Changed
- The rate limit counts each API key, and it is 600 requests a minute instead of 60. Each key has two limits of 600 a minute. One is for the requests that start a Completion, a Job, or a Branch, and one is for all other requests. Reading a Job or a Loom then never uses up the limit for Completions. A new key adds requests.
- When an API key has 16 Completions running, the next ones wait for a place instead of getting 429. Up to 64 Completions wait, and they run in the order they came. A waiting Completion holds no tokens until it runs. If you close the connection, the Completion leaves the line and never runs. With 64 waiting, one more gets 429
rate_limit_exceededwithRetry-After: 5. - Only Completions count toward the 16 in flight. Jobs, Looms, and the other routes answer at once while 16 Completions run.
- The App's calls have no rate limit, because the limits belong to API keys.
2026-10-11
New
- An API key has at most 16 requests in flight. One more gets 429
rate_limit_exceeded, with noRetry-After. - A User has at most 10 API keys. The App refuses an 11th one with 409.
- Every answer has the header
X-Request-Id, a new id for each request (The error object). Send it when you report a bug. - A request body is at most 8 MiB, on every route. A larger body gets 413, and a body without a
Content-Lengthheader gets 411. - One request has size caps. It asks for at most 32,000 generated tokens,
prompt_logprobsfrom -1 to 100, and at most 4stoptexts. It captures at most 2^25 numbers, and has at most 8 Steering vectors of 2^21 numbers. A request over a cap gets 400. - When an admin approves your Application, you get the email "Your ACS Infra application is approved". Its link to choose your password works for 7 days. Before, approval sent the password reset email, whose link works for 1 hour.
- The App no longer makes a User from its own form. To get access, apply with the form on the ACS Infra website, as Apply for access shows.
- An admin can suspend your access. Your API keys then get 401
invalid_api_key. Its message isYour access to ACS Infra is suspended. Write to infra@acsresearch.org if you think this is a mistake.The Completions of your queued Jobs and Nodes fail with the same error, so they do not reach Inference.
Changed
- The rate limit counts each User, not each API key. All your keys and the App share a burst of 60 requests, then 1 more each second. A new key adds no requests.
GET /v1/modelslists the models from the API's settings, so it never waits for Inference to start. Each model also has its Layers (num_hidden_layers) and itshidden_size, and itsmax_model_lenis nevernull. The list fails only with 401 or 429.- The App's Playground replaces its Completions and Activations pages. It runs one Completion with every setting of the API, and colors each token by its probability. It reads the Activations at the Layers that you choose, and adds a Steering vector.
- The approval, password reset, and email verification emails have the look and the words of the ACS Infra website.
Fixed
- The Playground shows the text that the API returns. Before, it could show a stop string that the API had cut from the text.
- When you sign in after a session ended, the App keeps nothing from the User before you in that browser tab. Before, it could show that User's new API key and prompt.
2026-10-10
New
- Every
/v1route needs an API key in the headerAuthorization: Bearer <key>. A request without a key, or with a wrong or revoked key, gets 401 with the codeinvalid_api_key. - You make API keys in the App, and every key starts with
sk-acs-. The API Keys page shows each key assk-acs-and its next 4 characters. - Jobs, Looms, and Nodes belong to the User who made them. The id of another User's Job, Loom, or Node gets 404.
- Each Completion spends tokens from your Budget. A new User has 0 tokens until an admin adds tokens with a Grant.
- Before Inference runs a request, the API takes a Hold of the most tokens that the request can use. If your Budget cannot hold them, the API answers 429 with the type and code
insufficient_quota. The request does not reach Inference. - A text prompt holds 1 token for each byte of its UTF-8 text, and 1 more for the BOS token that Inference adds. With
add_special_tokens: false, the prompt does not hold the extra token. - A Completion that is not streamed and stops before Inference answers spends its whole Hold. The running request of a Job that you cancel also spends its whole Hold.
- An API key can have its own Budget, which limits that key further. An admin fills it with a Grant for that key.
- A Job or a Branch whose Budget cannot hold even one of its requests gets 429
insufficient_quotawhen you submit it, and the API saves nothing. Each request of a Job and each Node still takes its own Hold when it runs. - When you revoke a key, its queued Jobs and Nodes do not reach Inference. Each of their Completions fails with 401
invalid_api_keyand the messageThe API key that made this request was revoked. - Each API key has a rate limit on
/v1of 60 requests a minute, as a burst of 60 and then 1 more each second. Over the limit, the API answers 429 with the typerate_limit_errorand the coderate_limit_exceeded. The answer has aRetry-Afterheader in seconds. - To get access, apply with the form at
/applyon the ACS Infra website. When an admin approves your Application, you get an email with a link to set your password. - One email can send one Application. The form answers a second one with
An application from this email already exists. - If you forget your password, open
/forgot-passwordin the App, and follow the link in the email to/reset-password(Reset your password). A new password ends all your sessions. - Signing in, and making a User in the App, allow 10 tries a minute from one IP address. More tries get 429.
- The docs have five sections: API, Cookbook, Tutorials, Changelog, and Support.
- The API section has new pages for Authentication and API keys, Models, Completions, Steering, Loom, and the Cheatsheet.
- Each docs page has a button that copies the page as Markdown, and a menu that opens the page in ChatGPT, Claude, or Cursor.
Changed
nis at most 128 in a Completion and in a Branch. A largerngets 400 withparamset ton.- A Job has at most 1,000 requests. A longer list gets 400 with
paramset torequests. priorityis 0 or more. A negativeprioritygets 400 withparamset topriority.- A 409, and a 429 with the code
insufficient_quota, have the headerx-should-retry: false. TheopenaiSDK then raises the error without trying the request again. - When the API stops, it queues a running Job or Node again. The Completion that it stopped gives back its Hold. When the API starts again, a Job runs only the requests that have no result line. You pay for each request once.
- The
textof a running Node changes at most every 250 ms while you follow a Branch.
Fixed
- A Job that you cancel while it starts again after an API restart no longer pays again for a request with a result.
- With
echoandmax_tokens: 0, the Hold counts 1 generated token for each choice, because Inference generates and counts 1. Before, such a request could spend more tokens than its Hold. - A request with several prompts asks for at most 128 choices in all,
nfor each prompt. More gets 400 withparamset ton, or torequestsfor a request in a Job. - If Inference answers with a status outside 100 to 599, the API answers 502 with the type
server_error. - A model name such as
toStringorconstructorgets 404model_not_found, as does any model that Inference does not have.
2026-10-09
New
POST /v1/completionscontinues a prompt with a Base model. It follows OpenAI's completions API, so theopenaiSDK works with it.- A prompt is text or a list of token ids, and one request can send several prompts.
- A field that you leave out gets OpenAI's default, not the model's own. For example,
max_tokensis 16 andtemperatureis 1. logprobsreturns the log probabilities of the top tokens at each generated token.prompt_logprobsreturns them for each token of the prompt.- With
stream: true, the API sends the Completion as Server-Sent Events that end withdata: [DONE]. GET /v1/modelslists the Base models, with the context length of each one inmax_model_len.output_residual_streamreturns the Activations at the Layers that you list, inactivations.residual_streamof the same response. Its shape is[layers, tokens, hidden size].apply_steering_vectorsadds Steering vectors to the residual stream at the Layers that you choose.- A Job runs a list of Completion requests in the background, one after another. You can check on it, cancel it, and download its results as JSON Lines, one line for each request.
- A Loom is a tree of Nodes that you grow from a prompt, one Branch at a time. The API writes the Nodes of a Branch in the background, and
GET /v1/looms/{loom_id}returns every Node. - Every error has OpenAI's error object, with
message,type,param, andcode. - The docs site has a Quickstart, guides, and an API reference made from the API's OpenAPI spec, with a playground.
/llms.txt,/llms-full.txt, and the Markdown of each page give the docs to an AI assistant.