Skip to content

feat(quota): Moonshot Open Platform balance and TPD lock for custom nodes - #12590

Open
HouMinXi wants to merge 10 commits into
diegosouzapw:release/v3.8.51from
HouMinXi:feat/moonshot-native-quota
Open

feat(quota): Moonshot Open Platform balance and TPD lock for custom nodes#12590
HouMinXi wants to merge 10 commits into
diegosouzapw:release/v3.8.51from
HouMinXi:feat/moonshot-native-quota

Conversation

@HouMinXi

@HouMinXi HouMinXi commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Custom OpenAI-compatible nodes aimed at api.moonshot.cn / api.moonshot.ai showed no balance on the dashboard. TPD and empty-wallet 429s also failed to stick, so combo strict-random kept drawing prepaid keys that were already dead for the day.

This change treats those hosts as Moonshot Open Platform: GET /v1/users/me/balance, classify TPD and insufficient-balance 429s as quota, and lock the connection until the node daily-reset clock (IANA timezone + hour) or a Reset header. No clock and no header uses the short 429 cooldown. The TPD ceiling is read from limit: N in the error text.

Test plan

DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm \
  --import ./open-sse/utils/setupPolyfill.ts \
  --import ./tests/_setup/isolateDataDir.ts \
  --test --test-force-exit \
  tests/unit/moonshot-open-platform.test.ts \
  tests/unit/classify429.test.ts \
  tests/unit/daily-quota-reset.test.ts \
  tests/unit/account-fallback-service.test.ts \
  tests/unit/moonshot-quota-fetcher.test.ts \
  tests/unit/provider-quota-visibility.test.ts \
  tests/unit/qoder-usage-quota.test.ts \
  tests/unit/provider-node-daily-reset-schema.test.ts \
  tests/unit/moonshot-quota-writeback.test.ts \
  tests/unit/api-key-self-service.test.ts

135/135 pass on upstream/release/v3.8.51 @ 2a6d45abe. Dropping providerSpecificData from self-service, or forcing USD on .cn, turns the two new tests red.

Notes for reviewers

  • Custom node ids are uuids. Quota support is host-based (api.moonshot.cn / api.moonshot.ai), not a static provider-id list.
  • Migration 172 adds nullable daily_quota_reset_timezone / daily_quota_reset_hour on provider_nodes. An empty clock is valid.
  • File-size ratchet bump is own growth at existing chokepoints. Host predicates, the reset clock, and the fetcher are new files under cap.
  • .cn balance is labeled CNY; .ai stays USD.

Not in this PR

  • Expanding combo strict-random to one target per key (account pick stays in auth)
  • Hardcoding a 1.5M TPD ceiling
  • Guessing host midnight when the node clock is empty

Identify prepaid Open Platform keys by api.moonshot.cn / api.moonshot.ai
on the connection baseUrl. Custom compatible-node uuids stay out of the
static usage tables. Coding Plan (api.kimi.com/coding) is not this host.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
Organization TPD rate limit is a daily cap, not a short 429. Put it
in both QUOTA_PATTERNS and TERMINAL_QUOTA_PATTERNS so a Retry-After
hint cannot downgrade it. Engine overloaded stays rate_limit.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
IANA timezone + local hour, no default. Convert via Intl parts so the
endpoint is the operator's wall clock, not process-local midnight.
parseTpdLimitFromText reads limit: from the 429 body.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
Custom openai-compatible-* ids used to skip creditsExhausted. Open
Platform empty-wallet text now still marks the account exhausted.
TPD cooldown uses the node clock or Reset header; without either it
falls through to short 429 instead of process-local midnight.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
GET {origin}/v1/users/me/balance before the usage switch so custom
compatible-node uuids do not fall through to 'not implemented'.
Register moonshot/kimi fetchers at chat and instrumentation startup.
Origin stays on the connection host (.cn vs .ai).

Signed-off-by: Minxi Hou <houminxi@gmail.com>
supportsProviderQuota now matches Open Platform hosts, not just the
static usage list. Provider Limits and the home widget use that
predicate so mnative uuid connections appear. Apikey allowlist stays
for other providers.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
Add provider_nodes.daily_quota_reset_timezone/hour (migration 172).
Operator fills IANA timezone + local hour in the compatible-node editor.
Unknown timezone and hour 24 are rejected. Empty clock stays valid.

Signed-off-by: HouMinXi <houminxi@gmail.com>
Signed-off-by: Minxi Hou <houminxi@gmail.com>
Startup scans provider_nodes and registers id+prefix fetchers when
the baseUrl host is api.moonshot.cn/.ai. Create/update re-register.
markAccountUnavailable forwards the node daily-reset clock into
checkFallbackError so TPD cools until the configured hour.

Signed-off-by: HouMinXi <houminxi@gmail.com>
Signed-off-by: Minxi Hou <houminxi@gmail.com>
Self-service dropped providerSpecificData, so uuid nodes always
looked unsupported. Keep the host on the connection, await fetcher
register on node create, label .cn balance as CNY.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
Own growth at existing chokepoints: migration 172 guard, Moonshot
fetcher registration, TPD node-clock lock, and TPD tests.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant