Files
memind/src/types.ts
T

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;
};