@floez-werk/piagent-realtime-provider-maxtokens0.1.4
Pi extension: clamps max_completion_tokens for OpenRouter requests to the smallest provider endpoint limit, so OpenRouter's length filter stops excluding providers.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
piagent-realtime-provider-maxtokens
Rewrites the output limit of OpenRouter requests to the smallest limit among the
model's provider endpoints, so OpenRouter stops filtering out endpoints that
publish a lower limit than the catalogue maximum. Routing itself stays with
OpenRouter: no provider is pinned and models.json is never touched.
Table of contents
Behavior
OpenRouter only routes a request to providers that can serve a response of the
requested length. Pi sends max_completion_tokens (or max_tokens, depending on
the model's compat.maxTokensField) from model.maxTokens, and for OpenRouter
models that value is the model-wide maximum from the catalogue. Every endpoint
with a lower output limit is therefore removed before routing.
The extension rewrites that field in the outgoing payload to the smallest output limit among the model's provider endpoints. The limit is read from OpenRouter's public model endpoints route and cached per model on disk, so a request never waits for a lookup.
Example, deepseek/deepseek-v4.1-flash (31 endpoints, catalogue maximum 943718):
| before | after | |
|---|---|---|
max_completion_tokens sent |
943718 | 131072 |
| endpoints OpenRouter may route to | only those publishing the maximum | all 31 |
Nothing else changes: the request keeps its provider routing object, other
providers are untouched, and a failed or missing lookup falls back to the
configured cap instead of blocking the request.
Status line
| Text | Meaning |
|---|---|
MT:131k |
Limit that will be sent: the smallest output limit across the model's endpoints |
MT:131k* |
No fresh cache entry - the fallback cap is in use while a lookup runs |
MT:131k (Dig 944k) |
Provider that served the last response (Dig) and its own limit (944k) |
MT:off |
The extension is disabled |
The value is colour-coded by how much the request was reduced:
| Band | Colour setting | Default |
|---|---|---|
Nothing reduced, or below clampWarnPercent |
color |
white |
Reduced by clampWarnPercent up to clampAlertPercent |
colorClamped |
136 (dark yellow) |
Reduced by more than clampAlertPercent |
colorClampedHeavy |
orange |
Reduced by more than clampCriticalPercent |
colorClampedCritical |
#ff8080 |
The deviation is (value Pi would send - value sent) / value Pi would send, in
percent. Colours accept palette names (white, yellow, orange, red,
green, cyan, magenta, blue, gray, none), #rgb / #rrggbb, a
256-colour number, and bold: / reverse: prefixes.
The parenthetical is controlled by statusProviderLimit (on/off) and
statusProviderLimitTag (show or hide the three-letter tag). It stays empty
until a response reported the serving provider.
Showing the colour in pi-powerline-footer
The aggregate extension_statuses segment applies its own colour and drops these
escape codes, so the status needs its own item with selfColorize: true:
"powerline": {
"customItems": [
{ "id": "maxtokens", "statusKey": "provider-maxtokens", "position": "right",
"hideWhenMissing": true, "excludeFromExtensionStatuses": true, "selfColorize": true }
]
}
excludeFromExtensionStatuses keeps the status out of the aggregate segment, so
it is rendered once, with its own colour. Without Powerline the status is rendered
by Pi itself and the colour always applies.
Diagnostic log
With log: true the extension appends one line per event to
~/.pi/agent/provider-maxtokens.log:
2026-10-06T23:36:08.657Z lookup.start {"modelId":"...","url":"https://openrouter.ai/api/v1/models/.../endpoints"}
2026-10-06T23:36:08.676Z cache.expired {"modelId":"...","cap":131072,"ageMinutes":120,"ttlMinutes":60}
2026-10-06T23:36:08.676Z request.decision {"modelId":"...","field":"max_completion_tokens","from":943718,"cap":131072,"reduced":true}
2026-10-06T23:36:08.690Z response.provider {"modelId":"...","provider":"DigitalOcean","providerLimit":943718}
2026-10-06T23:36:08.738Z lookup.response {"modelId":"...","status":200,"durationMs":81,"endpointCount":30,"cap":131072,"providers":{"digitalocean":943718,...}}
2026-10-06T23:36:08.738Z cache.stored {"modelId":"...","cap":131072,"endpointCount":30}
Events: cache.hit, cache.miss, cache.expired, lookup.start,
lookup.skipped, lookup.response, lookup.http-error, lookup.no-limits,
lookup.failed, cache.stored, request.decision, response.provider.
Logging never blocks a request, and a write that fails is ignored.
Installation
Local (development):
pi -e ./extensions/realtime-provider-maxtokens.ts
As a pi package (GitHub or npm):
pi install git:git@github.com:FloezWerk/piagent-realtime-provider-maxtokens.git
# or
pi install npm:@floez-werk/piagent-realtime-provider-maxtokens
The npm package is listed in the pi package catalog
automatically (keyword pi-package).
Commands
| Command | Effect |
|---|---|
/provider-maxtokens or /provider-maxtokens status |
State, TTL, fallback cap, log state, cache size, the selected model's cached limit, the cap in use, the value that will be sent, the serving provider with its own limit, the last clamp and the reduction count of this session |
/provider-maxtokens on |
Rewrite outgoing payloads (persisted) |
/provider-maxtokens off |
Leave payloads untouched (persisted) |
/provider-maxtokens toggle |
Toggle (persisted) |
/provider-maxtokens refresh |
Re-resolve the limits of the session's scoped OpenRouter models |
/provider-maxtokens clear |
Drop the cache; requests use the fallback cap until the next lookup |
/provider-maxtokens ttl <minutes> |
Cache TTL in minutes (persisted, default 60) |
/provider-maxtokens cap <tokens> |
Fallback cap (persisted, default 131072) |
/provider-maxtokens min |
List the configured per-model minimums |
/provider-maxtokens min <model-id> |
Show the minimum of one model |
/provider-maxtokens min <model-id> <tokens> |
Never send less than this for that model (persisted) |
/provider-maxtokens min <model-id> none |
Remove the minimum (persisted) |
/provider-maxtokens log on / off |
Write the diagnostic log (persisted, default off) |
After changes in a running session: /reload.
Configuration
Settings live under the root key provider-maxtokens in Pi's shared
~/.pi/agent/settings.json and are written by the commands above:
| Key | Default | Meaning |
|---|---|---|
enabled |
true |
Rewrite the outgoing output limit |
ttlMinutes |
60 |
Age after which a cached limit is refreshed |
fallbackCap |
131072 |
Limit used when no fresh entry exists or a lookup fails |
minByModel |
{} |
Per-model lower bound for the limit that is sent, keyed by model id |
log |
false |
Append the diagnostic log |
statusProviderLimit |
true |
Show the serving provider's own limit in the status line |
statusProviderLimitTag |
true |
Include the three-letter provider tag in that parenthetical |
color |
white |
Colour while nothing is reduced |
colorClamped |
136 |
Colour while the reduction is at or below clampAlertPercent |
colorClampedHeavy |
orange |
Colour while the reduction is above clampAlertPercent |
clampWarnPercent |
1 |
Reduction in percent from which the warning colour applies |
clampAlertPercent |
10 |
Reduction in percent above which the heavy colour applies |
colorClampedCritical |
#ff8080 |
Colour while the reduction is above clampCriticalPercent |
clampCriticalPercent |
50 |
Reduction in percent above which the critical colour applies |
The per-model cache is stored in ~/.pi/agent/provider-maxtokens-cache.json, the
diagnostic log in ~/.pi/agent/provider-maxtokens.log. Only the extension's own
keys are written; the rest of settings.json is preserved.
Dependencies
@earendil-works/pi-ai, @earendil-works/pi-coding-agent and
@earendil-works/pi-tui are bundled by pi and are therefore only declared as
peerDependencies.
Changelog
Notable changes per version are documented in CHANGELOG.md.
Every tagged release (vX.Y.Z) is published to npm and appears as a
GitHub release with the
package tarball.
0.1.4 - 2026-10-13
Fixed
- The status line now shows the serving provider for Claude models routed through OpenRouter (Anthropic message API).
Full history and all versions: CHANGELOG.md