[PR #6298] feat: Add (z.ai) plan usage tracking in the sidebar #11821

Open
opened 2026-02-16 18:16:45 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/6298

State: open
Merged: No


Problem

When using LLM providers with quota limits (like zai-coding-plan), users have no visibility into their remaining quota or when it resets. This makes it difficult to track usage and avoid unexpected service interruptions.

Solution

Added plan usage display to the TUI sidebar that shows:

  • Current usage percentage (e.g., "65% used")
  • Time until quota resets (e.g., "Resets in 2h 15m")

Implementation

Core abstraction (src/provider/plan-usage.ts)

Generic PlanUsage interface that all providers implement:

export interface PlanUsage {
  used: number
  total: number
  resetAt?: Date
  percentage?: number  // Provider-supplied percentage if more accurate
}

Features:

  • Registry pattern - Provider handlers register themselves via registerProvider(id, handler)
  • Built-in caching - 60s TTL to avoid excessive API calls
  • Helpers - getPercentage(), formatResetTime()

Provider implementation (src/provider/plan-usage/zai.ts)

  • Fetches quota from /api/monitor/usage/quota/limit endpoint
  • Handles zai-specific response format with multiple limit types
  • Only displays TOKENS_LIMIT (ignores time-based limits)
  • Registers itself as zai-coding-plan handler

UI integration (sidebar.tsx)

  • Shows plan usage in session sidebar below context info
  • Auto-refreshes when new messages are exchanged (user or assistant)

Adding support for other providers

The pattern uses side-effect imports. The core module imports provider modules, which register themselves on load.

Step 1: Add import to src/provider/plan-usage.ts:

// Load built-in providers
import("./plan-usage/zai")
import("./plan-usage/your-provider")  // ← Add this

Step 2: Create src/provider/plan-usage/your-provider.ts:

import { registerProvider, type PlanUsageHandler } from "../plan-usage"

const handler: PlanUsageHandler = async ({ token, baseURL, timeout }) => {
  const response = await fetch(`${baseURL}/your-endpoint`, {
    headers: { Authorization: token },
    signal: AbortSignal.timeout(timeout)
  })

  if (!response.ok) {
    return { error: `HTTP ${response.status}` }
  }

  const data = await response.json()
  return {
    planUsage: {
      used: data.used,
      total: data.limit,
      resetAt: new Date(data.resetsAt),
    }
  }
}

registerProvider("your-provider-id", handler)  // ← Executes on import

The handler receives:

  • token - API key from auth
  • baseURL - Provider's base URL from config
  • timeout - Request timeout in ms (default 5000)

And returns:

{ planUsage: PlanUsage } | { error: string }
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/6298 **State:** open **Merged:** No --- ## Problem When using LLM providers with quota limits (like zai-coding-plan), users have no visibility into their remaining quota or when it resets. This makes it difficult to track usage and avoid unexpected service interruptions. ## Solution Added plan usage display to the TUI sidebar that shows: - Current usage percentage (e.g., "65% used") - Time until quota resets (e.g., "Resets in 2h 15m") ## Implementation ### Core abstraction (`src/provider/plan-usage.ts`) Generic `PlanUsage` interface that all providers implement: ```typescript export interface PlanUsage { used: number total: number resetAt?: Date percentage?: number // Provider-supplied percentage if more accurate } ``` Features: - **Registry pattern** - Provider handlers register themselves via `registerProvider(id, handler)` - **Built-in caching** - 60s TTL to avoid excessive API calls - **Helpers** - `getPercentage()`, `formatResetTime()` ### Provider implementation (`src/provider/plan-usage/zai.ts`) - Fetches quota from `/api/monitor/usage/quota/limit` endpoint - Handles zai-specific response format with multiple limit types - Only displays `TOKENS_LIMIT` (ignores time-based limits) - Registers itself as `zai-coding-plan` handler ### UI integration (`sidebar.tsx`) - Shows plan usage in session sidebar below context info - Auto-refreshes when new messages are exchanged (user or assistant) ## Adding support for other providers The pattern uses side-effect imports. The core module imports provider modules, which register themselves on load. **Step 1:** Add import to `src/provider/plan-usage.ts`: ```typescript // Load built-in providers import("./plan-usage/zai") import("./plan-usage/your-provider") // ← Add this ``` **Step 2:** Create `src/provider/plan-usage/your-provider.ts`: ```typescript import { registerProvider, type PlanUsageHandler } from "../plan-usage" const handler: PlanUsageHandler = async ({ token, baseURL, timeout }) => { const response = await fetch(`${baseURL}/your-endpoint`, { headers: { Authorization: token }, signal: AbortSignal.timeout(timeout) }) if (!response.ok) { return { error: `HTTP ${response.status}` } } const data = await response.json() return { planUsage: { used: data.used, total: data.limit, resetAt: new Date(data.resetsAt), } } } registerProvider("your-provider-id", handler) // ← Executes on import ``` The handler receives: - `token` - API key from auth - `baseURL` - Provider's base URL from config - `timeout` - Request timeout in ms (default 5000) And returns: ```typescript { planUsage: PlanUsage } | { error: string } ```
yindo added the pull-request label 2026-02-16 18:16:45 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#11821