Repository navigation
Conversation
…, not failed Meta refuses a request with a 429 once a subscription window runs out, and Muse fails the turn with "API error 429: Subscription quota exhausted...". The adapter reported every failed turn as provider_error, so T3 showed a red Provider error and the thread as Failed, and Resume at reset, Snooze and auto-resume never applied. It now reports that refusal as usage_limit, with resetAt from the newest usage/changed report the host received: the latest reset among the windows that report showed used up. Fixes pingdotgg#18236. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a focused Muse adapter bug fix that maps subscription-quota stops to the existing Limited/usage-limit flow and derives reset times from validated provider data. The change is contained to the provider protocol and adapter, preserves ordinary failure handling, and adds targeted coverage for the new cases. You can add or adjust custom eligibility rules. Learn more. |
Dismissing prior approval to re-evaluate 4102621
|
Still waiting on a real Meta quota stop to confirm this end to end. It's hard to set one up on demand: the account has to actually use up a window. The refusal in the screenshots came from a local proxy answering with the 429 body that CLIProxyAPI's Meta executor tests use ( |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A real quota stop (Muse 1.4.6, 2026-10-13) left the thread Limited with
"Reset time unavailable": a fresh host has no usage report yet. The
refusal itself names the reset ("Your usage window resets at ..."), and
Muse can also type the stop as error.quota with resetsAtMs. The adapter
now treats a typed quota as a usage limit and takes the latest future
reset among the typed quota, the named time, and the last report.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the reset-time fix)
Dismissing prior approval to re-evaluate a16c2d4
|
Confirmed with a real quota stop on 2026-10-13 (macOS, Muse 1.4.6): the thread ends Limited, not Failed. The real refusal names its reset (
The exact refusal, and Muse's nine minutes of retries before it, are in the updated description. Created with Claude Opus 5.5 in Claude Code. |


Problem
When a Meta subscription window runs out, Meta refuses the next request with a 429, and Muse fails the turn with
API error 429: Subscription quota exhausted… (rate_limit_error). The Muse adapter reported every failed turn asprovider_error(ortransport_error). So T3 showed a red "Provider error" and marked the thread Failed, and Resume at reset, Snooze until reset and auto-resume never applied. Codex, Claude and Grok already report the same kind of stop asusage_limit. Fixes #18236.Change
In
packages/provider-muse:usage/changedreport its host sends. That is Meta's subscription windows after each response; it is account-wide, so the notification names no session. It is listed inINFORMATIONAL_NOTIFICATIONS, so an unreadable report is skipped instead of ending the session.usage_limit, titled "Usage limit reached". A refusal counts when Muse types it as a quota stop (error.quota) or when its text has429with "quota" or "usage limit"; the real refusal below arrived untyped, so the text check stays. ItsresetAtis the latest reset still ahead among the typedquota.resetsAtMs, the time the refusal names (Your usage window resets at 2026-10-13T10:45:52Z.), and the windows the last report showed used up, because every exhausted window has to reset before the turn can run. With none of those, the thread is Limited without a reset time.API error 429: Rate limit exceeded.) staysprovider_error.No user guide changes: Inspect agent work already describes Limited, Resume at reset and Snooze until reset without naming providers.
Scope and approval
Fixes #18236, which Julius confirmed as a bug on
main(Grok replying on Julius's behalf) and asked for this change: "A focused PR that classifies the quota refusal asusage_limit(and setsresetAtwhen a priorusage/changedreport has it) is welcome — include before/after of the Limited thread state per CONTRIBUTING.md." (comment). Showing Muse in Usage → Limits is separate (#18235) and not part of this PR.Verification
Tests (Windows desktop, Node 24; rerun on macOS after the reset-time follow-up):
vp test runinpackages/provider-muse: 96 passed on macOS. That includes the newusageLimits.test.tsand five new adapter tests:usage_limit, with the session window's reset; a laterRate limit exceeded429 staysprovider_error.usage_limitwith no reset time.usage_limitat that time, with no report.error.quotaisusage_limitat itsresetsAtMs, whatever the text says.These adapter tests fail on
main's adapter.The Muse replay fixtures in
OrchestratorReplayFixtures.integration.test.tspass.tsc --noEmitis clean forprovider-museandapps/server, andvp lintandvp fmt --checkpass.Before and after (2026-10-11): a dev server (
vp run devwith its own home directory) on Linux ranmained0f7b908for before and this branch for after. Muse 1.4.4 was signed in to Meta, with a config folder of its own, and answered real turns. A local proxy between Muse andapi.meta.ai(Muse'sendpoint_transport) passed traffic through. For after, it rewrote one report's 5-hour window to 100% used, keeping its reset time. In both runs it then answered the next turn with a 429 in the shape CLIProxyAPI's Meta executor tests use (code: rate_limit_exceeded, withresets_at); a real refusal is in the last section. Captured in T3's preview browser at 1280×800 and cropped.main)"Retry after 4:03 PM" is the rewritten report's 5-hour reset (21:03 UTC). The refusal is listed twice in both columns;
maindoes the same, and this PR doesn't change it.iOS (2026-10-11): the dev client, built from
mained0f7b908on an iPhone 17 simulator (iOS 27.0), paired with the same two servers. The app is the same in both columns; only the server changed. The iOS runs are separate threads with the same prompts, so their titles differ. (Xcode 27.0 needed a local edit to the compiler guard inT3LayoutMetricsView.swiftto buildmain; it is not part of this PR.)main)A real quota stop (2026-10-13): macOS, Muse 1.4.6, this branch's dev server, with an account whose Meta subscription window had actually run out. Meta refused every request with a 429. Muse made ten attempts, 60 seconds apart, without sending
turn/retryScheduled, so the thread showed Working for about nine minutes. Then it ended the turn witherror.kind: "modelError",retryable: true, noerror.quota, and this message (the "All credentials … cooling down" wrapper comes from a credential proxy in front of Meta):The thread ended Limited. Its host was new, so no usage report had arrived, and the first version showed "Reset time unavailable". With a16c2d4 the reset comes from the refusal itself (Retry after 5:45 AM local), and with auto-snooze on, the thread snoozes until then.
Not checked: Android, the desktop app (same web UI), and Muse 1.4.7 (out 2026-10-13), which may type this refusal as
error.quota.Created with Claude Opus 5.5 in Claude Code.
🤖 Generated with Claude Code