Feat: Add z.ai usage tracking

This commit is contained in:
eclipxe
2026-01-20 14:34:15 -08:00
committed by gsxdsm
parent 1662c6bf0b
commit 7765a12868
23 changed files with 1331 additions and 55 deletions

View File

@@ -94,6 +94,10 @@ import {
type CodexRateLimitWindow,
type CodexUsage,
type CodexUsageResponse,
type ZaiPlanType,
type ZaiQuotaLimit,
type ZaiUsage,
type ZaiUsageResponse,
} from './types';
// Import utility functions from modular utils files
@@ -173,6 +177,10 @@ export type {
CodexRateLimitWindow,
CodexUsage,
CodexUsageResponse,
ZaiPlanType,
ZaiQuotaLimit,
ZaiUsage,
ZaiUsageResponse,
};
// Re-export values from ./types for backward compatibility
@@ -234,6 +242,7 @@ const initialState: AppState = {
anthropic: '',
google: '',
openai: '',
zai: '',
},
chatSessions: [],
currentChatSession: null,
@@ -314,6 +323,8 @@ const initialState: AppState = {
claudeUsageLastUpdated: null,
codexUsage: null,
codexUsageLastUpdated: null,
zaiUsage: null,
zaiUsageLastUpdated: null,
codexModels: [],
codexModelsLoading: false,
codexModelsError: null,
@@ -2400,6 +2411,9 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
// Codex Usage Tracking actions
setCodexUsage: (usage) => set({ codexUsage: usage, codexUsageLastUpdated: Date.now() }),
// z.ai Usage Tracking actions
setZaiUsage: (usage) => set({ zaiUsage: usage, zaiUsageLastUpdated: usage ? Date.now() : null }),
// Codex Models actions
fetchCodexModels: async (forceRefresh = false) => {
const state = get();

View File

@@ -112,6 +112,21 @@ export interface CodexAuthStatus {
error?: string;
}
// z.ai Auth Method
export type ZaiAuthMethod =
| 'api_key_env' // Z_AI_API_KEY environment variable
| 'api_key' // Manually stored API key
| 'none';
// z.ai Auth Status
export interface ZaiAuthStatus {
authenticated: boolean;
method: ZaiAuthMethod;
hasApiKey?: boolean;
hasEnvApiKey?: boolean;
error?: string;
}
// Claude Auth Method - all possible authentication sources
export type ClaudeAuthMethod =
| 'oauth_token_env'
@@ -189,6 +204,9 @@ export interface SetupState {
// Copilot SDK state
copilotCliStatus: CopilotCliStatus | null;
// z.ai API state
zaiAuthStatus: ZaiAuthStatus | null;
// Setup preferences
skipClaudeSetup: boolean;
}
@@ -229,6 +247,9 @@ export interface SetupActions {
// Copilot SDK
setCopilotCliStatus: (status: CopilotCliStatus | null) => void;
// z.ai API
setZaiAuthStatus: (status: ZaiAuthStatus | null) => void;
// Preferences
setSkipClaudeSetup: (skip: boolean) => void;
}
@@ -266,6 +287,8 @@ const initialState: SetupState = {
copilotCliStatus: null,
zaiAuthStatus: null,
skipClaudeSetup: shouldSkipSetup,
};
@@ -344,6 +367,9 @@ export const useSetupStore = create<SetupState & SetupActions>()((set, get) => (
// Copilot SDK
setCopilotCliStatus: (status) => set({ copilotCliStatus: status }),
// z.ai API
setZaiAuthStatus: (status) => set({ zaiAuthStatus: status }),
// Preferences
setSkipClaudeSetup: (skip) => set({ skipClaudeSetup: skip }),
}));

View File

@@ -2,4 +2,5 @@ export interface ApiKeys {
anthropic: string;
google: string;
openai: string;
zai: string;
}

View File

@@ -36,7 +36,7 @@ import type { ApiKeys } from './settings-types';
import type { ChatMessage, ChatSession, FeatureImage } from './chat-types';
import type { TerminalState, TerminalPanelContent, PersistedTerminalState } from './terminal-types';
import type { Feature, ProjectAnalysis } from './project-types';
import type { ClaudeUsage, CodexUsage } from './usage-types';
import type { ClaudeUsage, CodexUsage, ZaiUsage } from './usage-types';
/** State for worktree init script execution */
export interface InitScriptState {
@@ -297,6 +297,10 @@ export interface AppState {
codexUsage: CodexUsage | null;
codexUsageLastUpdated: number | null;
// z.ai Usage Tracking
zaiUsage: ZaiUsage | null;
zaiUsageLastUpdated: number | null;
// Codex Models (dynamically fetched)
codexModels: Array<{
id: string;
@@ -764,6 +768,9 @@ export interface AppActions {
// Codex Usage Tracking actions
setCodexUsage: (usage: CodexUsage | null) => void;
// z.ai Usage Tracking actions
setZaiUsage: (usage: ZaiUsage | null) => void;
// Codex Models actions
fetchCodexModels: (forceRefresh?: boolean) => Promise<void>;
setCodexModels: (

View File

@@ -58,3 +58,27 @@ export interface CodexUsage {
// Response type for Codex usage API (can be success or error)
export type CodexUsageResponse = CodexUsage | { error: string; message?: string };
// z.ai Usage types
export type ZaiPlanType = 'free' | 'basic' | 'standard' | 'professional' | 'enterprise' | 'unknown';
export interface ZaiQuotaLimit {
limitType: 'TOKENS_LIMIT' | 'TIME_LIMIT' | string;
limit: number;
used: number;
remaining: number;
usedPercent: number; // Percentage used (0-100)
nextResetTime: number; // Epoch milliseconds
}
export interface ZaiUsage {
quotaLimits: {
tokens?: ZaiQuotaLimit;
mcp?: ZaiQuotaLimit;
planType: ZaiPlanType;
} | null;
lastUpdated: string;
}
// Response type for z.ai usage API (can be success or error)
export type ZaiUsageResponse = ZaiUsage | { error: string; message?: string };