750 lines
18 KiB
TypeScript
750 lines
18 KiB
TypeScript
export type Role = 'user' | 'assistant';
|
|
|
|
export type MessageContent =
|
|
| { type: 'text'; text: string }
|
|
| { type: 'thinking'; thinking: string; signature?: string }
|
|
| {
|
|
type: 'systemNotification';
|
|
notificationType: string;
|
|
msg: string;
|
|
data?: Record<string, unknown>;
|
|
}
|
|
| { type: 'toolRequest'; id: string; toolCall: { functionName: string; arguments: unknown } }
|
|
| { type: 'toolResponse'; id: string; toolResult: { value: unknown } }
|
|
| {
|
|
type: 'actionRequired';
|
|
data: {
|
|
actionType: 'toolConfirmation';
|
|
id: string;
|
|
toolName: string;
|
|
arguments: Record<string, unknown>;
|
|
prompt?: string | null;
|
|
};
|
|
};
|
|
|
|
export type Message = {
|
|
id?: string | null;
|
|
role: Role;
|
|
created: number;
|
|
content: MessageContent[];
|
|
metadata: {
|
|
userVisible: boolean;
|
|
agentVisible: boolean;
|
|
displayText?: string;
|
|
imageUrls?: string[];
|
|
previewImageUrls?: string[];
|
|
};
|
|
};
|
|
|
|
export type MindSpaceChatView = 'home' | 'category' | 'page';
|
|
|
|
export type MindSpaceChatContext = {
|
|
spaceId: string;
|
|
spaceName: string;
|
|
ownerUsername?: string;
|
|
view: MindSpaceChatView;
|
|
route: string;
|
|
category?: {
|
|
code: MindSpaceCategory['code'];
|
|
name: string;
|
|
itemCount?: number;
|
|
assets?: Array<{
|
|
id: string;
|
|
displayName: string;
|
|
mimeType: string;
|
|
}>;
|
|
};
|
|
page?: {
|
|
id: string;
|
|
title: string;
|
|
summary?: string;
|
|
status?: string;
|
|
versionNo?: number;
|
|
categoryCode?: MindSpaceCategory['code'];
|
|
templateId?: string;
|
|
contentFormat?: MindSpaceContentFormat;
|
|
pageType?: string;
|
|
contentExcerpt?: string;
|
|
publicationUrl?: string | null;
|
|
};
|
|
focusedAsset?: {
|
|
id: string;
|
|
displayName: string;
|
|
mimeType: string;
|
|
};
|
|
homeCategories?: Array<{
|
|
code: MindSpaceCategory['code'];
|
|
name: string;
|
|
itemCount: number;
|
|
}>;
|
|
recentPages?: Array<{
|
|
id: string;
|
|
title: string;
|
|
status: string;
|
|
categoryCode: MindSpaceCategory['code'];
|
|
}>;
|
|
agentSessionId?: string;
|
|
h5ApiBase?: string;
|
|
pageEditMode?: boolean;
|
|
parentAgentSessionId?: string;
|
|
};
|
|
|
|
export type TokenState = {
|
|
inputTokens: number;
|
|
outputTokens: number;
|
|
totalTokens: number;
|
|
accumulatedInputTokens?: number;
|
|
accumulatedOutputTokens?: number;
|
|
accumulatedTotalTokens?: number;
|
|
accumulatedCost?: number | null;
|
|
};
|
|
|
|
export type SessionEvent =
|
|
| { type: 'Message'; message: Message; token_state: TokenState }
|
|
| { type: 'Finish'; reason: string; token_state: TokenState }
|
|
| { type: 'Error'; error: string }
|
|
| { type: 'UpdateConversation'; conversation: Message[] }
|
|
| { type: 'Ping' }
|
|
| { type: 'ActiveRequests'; request_ids: string[] };
|
|
|
|
export type Session = {
|
|
id: string;
|
|
name: string;
|
|
working_dir: string;
|
|
message_count: number;
|
|
created_at?: string;
|
|
updated_at?: string;
|
|
user_set_name?: boolean;
|
|
recipe?: { title?: string | null } | null;
|
|
conversation?: Message[] | null;
|
|
};
|
|
|
|
export type SessionListResponse = {
|
|
sessions: Session[];
|
|
};
|
|
|
|
export type HarnessBootstrapResponse = {
|
|
summary: string;
|
|
source: string;
|
|
refreshed: boolean;
|
|
};
|
|
|
|
export type ChatState = 'idle' | 'loading' | 'connecting' | 'streaming' | 'waiting' | 'error';
|
|
|
|
export type ToolConfirmation = {
|
|
id: string;
|
|
toolName: string;
|
|
arguments: Record<string, unknown>;
|
|
prompt?: string | null;
|
|
};
|
|
|
|
export type BillingConfig = {
|
|
wechatEnabled: boolean;
|
|
tiersCents: number[];
|
|
minRechargeCents: number;
|
|
balanceCents: number;
|
|
};
|
|
|
|
export type UserNotification = {
|
|
id: string;
|
|
userId: string;
|
|
channel: 'web' | 'wechat';
|
|
notificationType: string;
|
|
title: string;
|
|
body: string;
|
|
data?: Record<string, unknown> | null;
|
|
status: 'unread' | 'read';
|
|
readAt: number | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
export type JsapiPayParams = {
|
|
appId: string;
|
|
timeStamp: string;
|
|
nonceStr: string;
|
|
package: string;
|
|
signType: 'MD5' | 'RSA';
|
|
paySign: string;
|
|
};
|
|
|
|
export type RechargeOrder = {
|
|
id: string;
|
|
amountCents: number;
|
|
status: 'pending' | 'paid' | 'failed' | 'expired' | 'refunded';
|
|
payMode: 'native' | 'h5' | 'jsapi';
|
|
expireAt: number;
|
|
codeUrl?: string | null;
|
|
h5Url?: string | null;
|
|
jsapiParams?: JsapiPayParams | null;
|
|
};
|
|
|
|
export type InsufficientBalanceDetails = {
|
|
code: 'INSUFFICIENT_BALANCE';
|
|
balanceCents: number;
|
|
minRechargeCents: number;
|
|
suggestedTiers: number[];
|
|
};
|
|
|
|
export type ActiveSubscription = {
|
|
id: string;
|
|
planType: string;
|
|
status: 'active' | 'expired' | 'cancelled';
|
|
periodTokensLimit: number;
|
|
periodTokensUsed: number;
|
|
periodStart: number;
|
|
periodEnd: number;
|
|
expiresAt: number;
|
|
overageRate: number;
|
|
autoRenew: boolean;
|
|
};
|
|
|
|
export type PlanDefinition = {
|
|
key: string;
|
|
name: string;
|
|
priceCents: number;
|
|
periodDays: number;
|
|
periodTokens: number;
|
|
modelTier: string;
|
|
overageRate: number;
|
|
};
|
|
|
|
export type PortalUser = {
|
|
id: string;
|
|
username: string;
|
|
slug?: string;
|
|
email?: string | null;
|
|
displayName: string;
|
|
role: 'user' | 'admin';
|
|
status: 'active' | 'suspended' | 'disabled';
|
|
planType?: string;
|
|
workspaceRoot: string;
|
|
balanceCents: number;
|
|
totalCreditCents?: number;
|
|
tokensUsed: number;
|
|
subscription?: ActiveSubscription | null;
|
|
spaceQuotaBytes?: number;
|
|
spaceUsedBytes?: number;
|
|
spaceReservedBytes?: number;
|
|
spaceAvailableBytes?: number;
|
|
publishSlug?: string;
|
|
publishUrl?: string;
|
|
publishSkillName?: string;
|
|
};
|
|
|
|
export type MindSpaceQuota = {
|
|
quotaBytes: number;
|
|
usedBytes: number;
|
|
reservedBytes: number;
|
|
availableBytes: number;
|
|
maxFileBytes: number;
|
|
publicPageLimit: number;
|
|
publicPageUsed: number;
|
|
aiDailyLimit: number;
|
|
aiDailyUsed: number;
|
|
monthlyViewLimit: number;
|
|
monthlyViewUsed: number;
|
|
};
|
|
|
|
export type MindSpaceCategory = {
|
|
id: string;
|
|
code: 'oa' | 'private' | 'public' | 'draft' | 'archive';
|
|
name: string;
|
|
visibilityPolicy: string;
|
|
aiAccessPolicy: string;
|
|
publishPolicy: string;
|
|
isSystem: boolean;
|
|
sortOrder: number;
|
|
itemCount: number;
|
|
};
|
|
|
|
export type MindSpaceScheduleItem = {
|
|
id: string;
|
|
kind: 'task' | 'event';
|
|
title: string;
|
|
description?: string | null;
|
|
status: 'active' | 'completed' | 'cancelled' | 'deleted';
|
|
startAt?: number | null;
|
|
endAt?: number | null;
|
|
dueAt?: number | null;
|
|
allDay: boolean;
|
|
timezone: string;
|
|
location?: string | null;
|
|
sourceChannel?: 'h5' | 'wechat' | 'agent' | 'api';
|
|
sourceMessageId?: string | null;
|
|
sourceText?: string | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
export type MindSpaceDigestSubscription = {
|
|
id: string;
|
|
hour: number;
|
|
minute: number;
|
|
timezone: string;
|
|
channel: 'wechat' | 'in_app';
|
|
status: 'active' | 'locked' | 'failed' | 'cancelled';
|
|
nextRunAt: number;
|
|
lastRunAt?: number | null;
|
|
attempts?: number;
|
|
};
|
|
|
|
export type MindSpaceSchedule = {
|
|
todayTodoItems: MindSpaceScheduleItem[];
|
|
digestSubscriptions: MindSpaceDigestSubscription[];
|
|
};
|
|
|
|
export type MindSpace = {
|
|
id: string;
|
|
userId: string;
|
|
name: string;
|
|
status: 'active' | 'locked' | 'deleted';
|
|
quota: MindSpaceQuota;
|
|
categories: MindSpaceCategory[];
|
|
schedule?: MindSpaceSchedule | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
export type MindSpaceAsset = {
|
|
id: string;
|
|
categoryId: string;
|
|
categoryCode: MindSpaceCategory['code'];
|
|
assetType: string;
|
|
mimeType: string;
|
|
filename: string;
|
|
displayName: string;
|
|
sizeBytes: number;
|
|
checksum: string;
|
|
riskLevel: 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
visibility: 'private' | 'internal' | 'public_candidate';
|
|
status: 'uploaded' | 'processing' | 'ready' | 'quarantined' | 'archived';
|
|
scanStatus?: 'pending' | 'passed' | 'warned' | 'blocked';
|
|
sourceType: 'upload' | 'chat' | 'agent' | 'template' | 'generated' | 'workspace';
|
|
hasThumbnail?: boolean;
|
|
publicUrl?: string | null;
|
|
sourcePageId?: string | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
export type MindSpaceUpload = {
|
|
id: string;
|
|
filename: string;
|
|
expectedSize: number;
|
|
uploadUrl: string;
|
|
expiresAt: number;
|
|
reservedBytes: number;
|
|
};
|
|
|
|
export type MindSpacePageVersion = {
|
|
id: string;
|
|
versionNo: number;
|
|
changeNote: string | null;
|
|
immutable: boolean;
|
|
createdAt: number;
|
|
};
|
|
|
|
export type MindSpaceSecurityFinding = {
|
|
id: string;
|
|
type: string;
|
|
riskLevel: 'low' | 'medium' | 'high' | 'critical';
|
|
occurrenceCount: number;
|
|
sampleMasked: string;
|
|
blocking: boolean;
|
|
};
|
|
|
|
export type MindSpacePublishCheck = {
|
|
pageVersionId: string;
|
|
urlSlug: string;
|
|
accessMode:
|
|
| 'public'
|
|
| 'password'
|
|
| 'private_link'
|
|
| 'time_limited'
|
|
| 'login_required'
|
|
| 'owner_only';
|
|
expiresAt: number | null;
|
|
slugAvailable: boolean;
|
|
slugConflict?: { pageId: string; title: string } | null;
|
|
suggestedUrlSlug?: string | null;
|
|
status: 'passed' | 'warned' | 'blocked';
|
|
riskLevel: 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
findings: MindSpaceSecurityFinding[];
|
|
allowed: boolean;
|
|
};
|
|
|
|
export type MindSpaceRedactionChange = {
|
|
field: 'title' | 'summary' | 'content';
|
|
fieldLabel: string;
|
|
type: string;
|
|
label: string;
|
|
count: number;
|
|
};
|
|
|
|
export type MindSpaceRedactedCopyResult = {
|
|
page: MindSpacePage;
|
|
originalScan: MindSpacePrivacyScan;
|
|
redactedScan: MindSpacePrivacyScan;
|
|
redactionsApplied: number;
|
|
changes: MindSpaceRedactionChange[];
|
|
};
|
|
|
|
export type MindSpaceCleanupItem = {
|
|
id: string;
|
|
kind: 'stale_upload' | 'orphan_tmp' | 'workspace_temp' | 'stale_page_version';
|
|
label: string;
|
|
path: string;
|
|
sizeBytes: number;
|
|
createdAt: number | null;
|
|
detail: string;
|
|
};
|
|
|
|
export type MindSpacePublication = {
|
|
id: string;
|
|
pageId: string;
|
|
pageVersionId: string;
|
|
urlSlug: string;
|
|
publicUrl: string;
|
|
accessMode: MindSpacePublishCheck['accessMode'];
|
|
expiresAt: number | null;
|
|
userConfirmedAt: number | null;
|
|
status: 'online' | 'offline' | 'expired' | 'blocked';
|
|
viewCount: number;
|
|
publishedAt: number;
|
|
offlineAt: number | null;
|
|
};
|
|
|
|
export type MindSpacePublicationStats = {
|
|
publicationId: string;
|
|
status: string;
|
|
totalViews: number;
|
|
publishedAt: number;
|
|
daily: Array<{ day: string; views: number }>;
|
|
devices: Array<{ deviceType: string; views: number }>;
|
|
sources: Array<{ source: string; views: number }>;
|
|
};
|
|
|
|
export type PlazaCategory = {
|
|
id: string;
|
|
name: string;
|
|
slug: string;
|
|
icon: string;
|
|
post_count: number;
|
|
};
|
|
|
|
export type PlazaPostBrief = {
|
|
id: string;
|
|
status: string;
|
|
};
|
|
|
|
export type MindSpaceAgentJobAsset = {
|
|
assetId: string;
|
|
assetVersionId: string;
|
|
permission: 'read' | 'write' | 'create_derivative';
|
|
displayName: string;
|
|
mimeType: string;
|
|
status: string;
|
|
scanStatus: string;
|
|
};
|
|
|
|
export type MindSpaceAgentJob = {
|
|
id: string;
|
|
sessionId: string | null;
|
|
jobType: string;
|
|
instruction: string;
|
|
status: 'queued' | 'running' | 'completed' | 'failed' | 'cancelled' | 'timed_out';
|
|
outputType: 'page_draft' | 'html_page' | 'markdown';
|
|
outputCategoryId: string;
|
|
outputCategoryCode: string | null;
|
|
progress: { stage: string; message?: string };
|
|
permissionScope: Record<string, unknown>;
|
|
userContext: { locale?: string; timezone?: string };
|
|
resultPageId: string | null;
|
|
resultAssetId: string | null;
|
|
errorCode: string | null;
|
|
errorMessage: string | null;
|
|
retryable: boolean;
|
|
queuedAt: number;
|
|
startedAt: number | null;
|
|
completedAt: number | null;
|
|
expiresAt: number | null;
|
|
assets: MindSpaceAgentJobAsset[];
|
|
};
|
|
|
|
export type MindSpaceContentFormat = 'markdown' | 'html';
|
|
|
|
export type MindSpaceSaveCategory = 'draft' | 'oa' | 'private' | 'public';
|
|
|
|
export type MindSpacePrivacyFinding = {
|
|
id: string;
|
|
type: string;
|
|
label?: string;
|
|
riskLevel: 'low' | 'medium' | 'high' | 'critical';
|
|
occurrenceCount: number;
|
|
sampleMasked: string;
|
|
blocking: boolean;
|
|
};
|
|
|
|
export type MindSpacePrivacyScan = {
|
|
status: 'passed' | 'warned' | 'blocked';
|
|
riskLevel: 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
findings: MindSpacePrivacyFinding[];
|
|
allowed: boolean;
|
|
};
|
|
|
|
export type ChatSaveContentMode = 'markdown' | 'static_html';
|
|
|
|
export type ChatSaveAnalysis = {
|
|
contentMode: ChatSaveContentMode;
|
|
links: Array<{
|
|
publicUrl: string;
|
|
owner: string;
|
|
relativePath: string;
|
|
filename: string;
|
|
}>;
|
|
selectedLinkIndex: number;
|
|
suggestedTitle: string;
|
|
suggestedSummary: string;
|
|
previewUrl: string | null;
|
|
previewFrameUrl: string | null;
|
|
localPreviewUrl: string | null;
|
|
localThumbnailUrl: string | null;
|
|
thumbnailUrl: string | null;
|
|
thumbnailReady: boolean;
|
|
relativePath: string | null;
|
|
filename: string | null;
|
|
hasHtmlContent: boolean;
|
|
privacyScan: MindSpacePrivacyScan;
|
|
existingPage: { id: string; title: string; categoryCode: string } | null;
|
|
};
|
|
|
|
export type ChatSaveResult =
|
|
| { kind: 'page'; categoryCode: 'draft'; page: MindSpacePage }
|
|
| { kind: 'asset'; categoryCode: Exclude<MindSpaceSaveCategory, 'draft'>; asset: MindSpaceAsset };
|
|
|
|
export type MindSpacePage = {
|
|
id: string;
|
|
categoryId: string;
|
|
categoryCode: MindSpaceCategory['code'];
|
|
sourceSessionId: string | null;
|
|
sourceMessageId: string | null;
|
|
sourceAssetId: string | null;
|
|
title: string;
|
|
summary: string;
|
|
pageType: string;
|
|
contentFormat?: MindSpaceContentFormat;
|
|
hasThumbnail?: boolean;
|
|
templateId: string;
|
|
status: 'draft' | 'reviewing' | 'risk_found' | 'ready' | 'published' | 'protected' | 'expired' | 'offline';
|
|
visibility: 'private' | 'internal' | 'public';
|
|
publicationAccessMode?: 'public' | 'password' | 'private_link' | 'time_limited' | 'login_required' | 'owner_only' | null;
|
|
publicationUrl?: string | null;
|
|
currentVersionId: string;
|
|
versionNo: number;
|
|
content?: string;
|
|
versions?: MindSpacePageVersion[];
|
|
publication?: MindSpacePublication | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
export type MindSpacePageDeletePreview = {
|
|
page: {
|
|
id: string;
|
|
title: string;
|
|
status: MindSpacePage['status'];
|
|
versionCount: number;
|
|
};
|
|
onlinePublication: {
|
|
id: string;
|
|
publicUrl: string;
|
|
accessMode: MindSpacePublication['accessMode'];
|
|
viewCount: number;
|
|
} | null;
|
|
offlinePublicationCount: number;
|
|
linkedAssets: Array<{
|
|
id: string;
|
|
displayName: string;
|
|
sizeBytes: number;
|
|
kind: 'content' | 'bundle';
|
|
}>;
|
|
linkedAssetBytes: number;
|
|
linkedAgentJobCount: number;
|
|
preservesSourceAsset: boolean;
|
|
summaryLines: string[];
|
|
};
|
|
|
|
export type MindSpacePageDeleteResult = {
|
|
deleted: boolean;
|
|
pageId: string;
|
|
title: string;
|
|
offlinedPublicationCount: number;
|
|
deletedAssetCount: number;
|
|
freedBytes: number;
|
|
clearedAgentJobCount: number;
|
|
quota?: MindSpaceQuota;
|
|
};
|
|
|
|
export type MindSpaceRefreshOptions = {
|
|
quota?: MindSpaceQuota;
|
|
freedBytes?: number;
|
|
};
|
|
|
|
export type CapabilityDefinition = {
|
|
key: string;
|
|
label: string;
|
|
description: string;
|
|
risk: 'low' | 'medium' | 'high';
|
|
category: string;
|
|
};
|
|
|
|
export type CapabilityMap = Record<string, boolean>;
|
|
|
|
export type PolicyValue = string | boolean;
|
|
|
|
export type PolicyMap = Record<string, PolicyValue>;
|
|
|
|
export type SkillMap = Record<string, boolean>;
|
|
|
|
export type SkillDefinition = {
|
|
name: string;
|
|
dirName: string;
|
|
label: string;
|
|
description: string;
|
|
category: string;
|
|
requiresPublish?: boolean;
|
|
};
|
|
|
|
export type PolicyDefinition = {
|
|
key: string;
|
|
label: string;
|
|
description: string;
|
|
type: 'select' | 'boolean';
|
|
options?: Array<{ value: string; label: string }>;
|
|
defaultValue: PolicyValue;
|
|
category: string;
|
|
risk: 'low' | 'medium' | 'high';
|
|
};
|
|
|
|
export type AuthStatus = {
|
|
authenticated: boolean;
|
|
mode?: 'user' | 'legacy' | 'none';
|
|
user?: PortalUser | null;
|
|
capabilities?: CapabilityMap;
|
|
grantedSkills?: string[];
|
|
unrestricted?: boolean;
|
|
};
|
|
|
|
export type PathGrant = {
|
|
path: string;
|
|
mode: 'read' | 'readwrite';
|
|
};
|
|
|
|
export type AdminUserRow = PortalUser & {
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
export type LlmProviderDefinition = {
|
|
id: string;
|
|
label: string;
|
|
kind?: 'builtin' | 'custom';
|
|
apiKeyEnv: string | null;
|
|
defaultModel: string;
|
|
models: string[];
|
|
};
|
|
|
|
export type LlmProviderKeyRow = {
|
|
id: string;
|
|
providerId: string;
|
|
providerKind: 'builtin' | 'custom';
|
|
providerLabel: string;
|
|
name: string;
|
|
defaultModel: string;
|
|
models: string[];
|
|
apiUrl: string | null;
|
|
basePath: string | null;
|
|
engine: string;
|
|
relayProvider: string | null;
|
|
goosedProviderId: string | null;
|
|
status: 'active' | 'disabled';
|
|
isSelected: boolean;
|
|
apiKeyMasked: string;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
export type LlmGlobalSettings = {
|
|
keyId: string | null;
|
|
keyName: string | null;
|
|
providerLabel: string | null;
|
|
globalModel: string | null;
|
|
availableModels: string[];
|
|
};
|
|
|
|
export type LlmConnectionTestResult = {
|
|
ok: boolean;
|
|
latencyMs?: number;
|
|
reply?: string;
|
|
model?: string;
|
|
message?: string;
|
|
};
|
|
|
|
export type UsageRecord = {
|
|
id: number;
|
|
userId: string;
|
|
username: string;
|
|
agentSessionId: string;
|
|
requestId: string | null;
|
|
inputTokens: number;
|
|
outputTokens: number;
|
|
costCents: number;
|
|
balanceAfterCents: number;
|
|
createdAt: number;
|
|
};
|
|
|
|
export type BalanceUpdate = {
|
|
balanceCents: number;
|
|
tokensUsed?: number;
|
|
lastUsage?: Pick<UsageRecord, 'inputTokens' | 'outputTokens' | 'costCents'>;
|
|
};
|
|
|
|
export type LedgerEntry = {
|
|
id: number;
|
|
userId: string;
|
|
username: string;
|
|
type: 'recharge' | 'deduct' | 'refund' | 'adjust';
|
|
amountCents: number;
|
|
tokens: number;
|
|
sessionId: string | null;
|
|
note: string | null;
|
|
createdAt: number;
|
|
};
|
|
|
|
export type AdminDashboardSummary = {
|
|
users: {
|
|
total: number;
|
|
active: number;
|
|
lowBalance: number;
|
|
totalBalanceCents: number;
|
|
};
|
|
usage24h: {
|
|
count: number;
|
|
costCents: number;
|
|
};
|
|
lowBalanceUsers: Array<{
|
|
id: string;
|
|
username: string;
|
|
displayName: string;
|
|
balanceCents: number;
|
|
}>;
|
|
recentUsage: UsageRecord[];
|
|
recentLedger: LedgerEntry[];
|
|
llm: {
|
|
keyCount: number;
|
|
selectedKeyName: string | null;
|
|
globalModel: string | null;
|
|
} | null;
|
|
};
|