docs/AMBIENT_MODE.md documents an adaptive wake interval driven by provider rate-limit headers. The algorithm exists in scheduler.rs and is unit-tested, but nothing ever supplies it with data: both call sites pass None, and RateLimitInfo has no producer anywhere in the workspace. The documented behavior is therefore unreachable.
Checked against master at be248c6 (v0.85.0), which is current as of writing.
Expected
docs/AMBIENT_MODE.md#L344-L356:
Rate Limit Discovery
Rate limits are learned from provider response headers:
x-ratelimit-limit-tokens: 100000
x-ratelimit-remaining-tokens: 85000
x-ratelimit-reset-requests: 2026-02-08T15:00:00Z
The interval is then derived from the remaining window and budget.
Actual
ambient/scheduler.rs#L187 implements exactly that algorithm and returns early when it gets nothing:
let info = match rate_limit_info {
Some(i) => i,
None => return self.apply_backoff(max),
};
Both callers pass None, and they are the only callers in the workspace:
$ rg -n 'calculate_interval' --type rust | rg -v 'scheduler.rs'
crates/jcode-app-core/src/ambient/runner.rs:681: .calculate_interval(None)
crates/jcode-app-core/src/ambient/runner.rs:814: let interval = scheduler.calculate_interval(None);
RateLimitInfo is declared and consumed by the scheduler, but never constructed with real values anywhere.
No provider runtime reads x-ratelimit-*. The two rate-limit modules that do exist serve other purposes:
crates/jcode-app-core/src/update_rate_limit.rs — GitHub API limits for update checks.
crates/jcode-provider-core/src/retry_after.rs — per-request Retry-After handling, carried through anyhow::Error, not surfaced to ambient scheduling.
Consequence
With rate_limit_info = None, calculate_interval returns apply_backoff(max), and apply_backoff clamps to max_interval_minutes. So:
- Ambient wakes on a fixed cadence of
max_interval_minutes (default 120) regardless of quota state, rather than adapting to the window.
min_interval_minutes never takes effect.
- The exponential backoff in
on_rate_limit_hit is inert, because the interval is already clamped at max.
user_budget_reserve never takes effect, so there is no reservation of headroom for the interactive user.
Separately, runner.rs#L800-L802 calls on_rate_limit_hit() in the generic cycle-error branch, so any failure is treated as a rate-limit hit.
Question before sending a patch
The existing usage plumbing does not fit RateLimitInfo as-is: ProviderUsage/UsageLimit carry usage_percent: f32 and resets_at: String behind a 120s cache, not token counts. Capturing x-ratelimit-* per provider runtime touches a dozen crates, so I would rather ask first than guess:
- Should the capture live in each provider runtime, or behind one shared response hook?
- Is reusing the existing
ProviderUsage snapshot acceptable instead, which would mean widening RateLimitInfo (or the algorithm) to accept a percentage plus reset time?
Happy to send a PR once the direction is clear.
Related
Environment
v0.85.0, be248c6, macOS 26.6.2 (arm64).
docs/AMBIENT_MODE.mddocuments an adaptive wake interval driven by provider rate-limit headers. The algorithm exists inscheduler.rsand is unit-tested, but nothing ever supplies it with data: both call sites passNone, andRateLimitInfohas no producer anywhere in the workspace. The documented behavior is therefore unreachable.Checked against
masterat be248c6 (v0.85.0), which is current as of writing.Expected
docs/AMBIENT_MODE.md#L344-L356:The interval is then derived from the remaining window and budget.
Actual
ambient/scheduler.rs#L187implements exactly that algorithm and returns early when it gets nothing:Both callers pass
None, and they are the only callers in the workspace:ambient/runner.rs#L681ambient/runner.rs#L814RateLimitInfois declared and consumed by the scheduler, but never constructed with real values anywhere.No provider runtime reads
x-ratelimit-*. The two rate-limit modules that do exist serve other purposes:crates/jcode-app-core/src/update_rate_limit.rs— GitHub API limits for update checks.crates/jcode-provider-core/src/retry_after.rs— per-requestRetry-Afterhandling, carried throughanyhow::Error, not surfaced to ambient scheduling.Consequence
With
rate_limit_info = None,calculate_intervalreturnsapply_backoff(max), andapply_backoffclamps tomax_interval_minutes. So:max_interval_minutes(default 120) regardless of quota state, rather than adapting to the window.min_interval_minutesnever takes effect.on_rate_limit_hitis inert, because the interval is already clamped atmax.user_budget_reservenever takes effect, so there is no reservation of headroom for the interactive user.Separately,
runner.rs#L800-L802callson_rate_limit_hit()in the generic cycle-error branch, so any failure is treated as a rate-limit hit.Question before sending a patch
The existing usage plumbing does not fit
RateLimitInfoas-is:ProviderUsage/UsageLimitcarryusage_percent: f32andresets_at: Stringbehind a 120s cache, not token counts. Capturingx-ratelimit-*per provider runtime touches a dozen crates, so I would rather ask first than guess:ProviderUsagesnapshot acceptable instead, which would mean wideningRateLimitInfo(or the algorithm) to accept a percentage plus reset time?Happy to send a PR once the direction is clear.
Related
AMBIENT_MODE.mdand citesscheduler.rsas evidence the feature shipped; this is the one documented piece of that file that is not reached at runtime.Environment
v0.85.0,
be248c6, macOS 26.6.2 (arm64).