feat: add attachment storage config model
This commit is contained in:
@@ -20,7 +20,34 @@ export type MessageKind =
|
||||
| "video_intent"
|
||||
| "forward_notice"
|
||||
| "forward_single"
|
||||
| "forward_bundle";
|
||||
| "forward_bundle"
|
||||
| "attachment"
|
||||
| "analysis_card";
|
||||
export type AttachmentKind = "image" | "video" | "pdf" | "text" | "office" | "binary";
|
||||
export type AttachmentStorageBackend = "server_file" | "aliyun_oss";
|
||||
export type AttachmentAnalysisState =
|
||||
| "not_applicable"
|
||||
| "queued_auto"
|
||||
| "ready_manual"
|
||||
| "processing"
|
||||
| "completed"
|
||||
| "failed";
|
||||
|
||||
export interface MessageAttachment {
|
||||
attachmentId: string;
|
||||
fileName: string;
|
||||
mimeType: string;
|
||||
fileSizeBytes: number;
|
||||
attachmentKind: AttachmentKind;
|
||||
storageBackend: AttachmentStorageBackend;
|
||||
storagePath: string;
|
||||
previewAvailable: boolean;
|
||||
uploadedAt: string;
|
||||
uploadedBy: string;
|
||||
analysisState: AttachmentAnalysisState;
|
||||
analysisSummary?: string;
|
||||
analysisCardId?: string;
|
||||
}
|
||||
|
||||
export interface ForwardSource {
|
||||
sourceProjectId: string;
|
||||
@@ -150,6 +177,23 @@ export interface Message {
|
||||
forwardBundle?: ForwardBundlePayload;
|
||||
}
|
||||
|
||||
export interface UserAttachmentStorageConfig {
|
||||
account: string;
|
||||
mode: "server_file" | "oss";
|
||||
ossProvider?: "aliyun_oss";
|
||||
aliyunOss?: {
|
||||
enabled: boolean;
|
||||
accessKeyId: string;
|
||||
accessKeySecretEncrypted: string;
|
||||
bucket: string;
|
||||
endpoint: string;
|
||||
region: string;
|
||||
prefix?: string;
|
||||
};
|
||||
updatedAt: string;
|
||||
validatedAt?: string;
|
||||
}
|
||||
|
||||
export interface GoalItem {
|
||||
id: string;
|
||||
text: string;
|
||||
@@ -609,6 +653,7 @@ export interface BossState {
|
||||
otaUpdateLogs: OtaUpdateLog[];
|
||||
deviceSkills: DeviceSkill[];
|
||||
appLogs: AppLogEntry[];
|
||||
userAttachmentStorageConfigs: UserAttachmentStorageConfig[];
|
||||
threadContextSnapshots: ThreadContextSnapshot[];
|
||||
threadHandoffPackages: ThreadHandoffPackage[];
|
||||
threadContextAlerts: ThreadContextAlert[];
|
||||
@@ -1016,6 +1061,13 @@ const initialState: BossState = {
|
||||
reason: "初始化默认主控身份",
|
||||
},
|
||||
],
|
||||
userAttachmentStorageConfigs: [
|
||||
{
|
||||
account: PRIMARY_ADMIN_ACCOUNT,
|
||||
mode: "server_file",
|
||||
updatedAt: "2026-03-29T00:00:00+08:00",
|
||||
},
|
||||
],
|
||||
masterAgentTasks: [],
|
||||
otaUpdates: [
|
||||
{
|
||||
@@ -1847,6 +1899,33 @@ function normalizeMessage(raw: Partial<Message>): Message {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeAttachmentStorageConfig(
|
||||
raw: Partial<UserAttachmentStorageConfig>,
|
||||
fallback: UserAttachmentStorageConfig,
|
||||
): UserAttachmentStorageConfig {
|
||||
return {
|
||||
account: raw.account ?? fallback.account,
|
||||
mode: raw.mode ?? fallback.mode,
|
||||
ossProvider: raw.ossProvider ?? fallback.ossProvider,
|
||||
aliyunOss: raw.aliyunOss
|
||||
? {
|
||||
enabled: raw.aliyunOss.enabled ?? fallback.aliyunOss?.enabled ?? false,
|
||||
accessKeyId: raw.aliyunOss.accessKeyId ?? fallback.aliyunOss?.accessKeyId ?? "",
|
||||
accessKeySecretEncrypted:
|
||||
raw.aliyunOss.accessKeySecretEncrypted ??
|
||||
fallback.aliyunOss?.accessKeySecretEncrypted ??
|
||||
"",
|
||||
bucket: raw.aliyunOss.bucket ?? fallback.aliyunOss?.bucket ?? "",
|
||||
endpoint: raw.aliyunOss.endpoint ?? fallback.aliyunOss?.endpoint ?? "",
|
||||
region: raw.aliyunOss.region ?? fallback.aliyunOss?.region ?? "",
|
||||
prefix: raw.aliyunOss.prefix ?? fallback.aliyunOss?.prefix,
|
||||
}
|
||||
: fallback.aliyunOss,
|
||||
updatedAt: raw.updatedAt ?? fallback.updatedAt,
|
||||
validatedAt: raw.validatedAt ?? fallback.validatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeProject(raw: Partial<Project>, fallback?: Project): Project {
|
||||
const base = fallback ?? cloneInitialState().projects[0];
|
||||
const projectId = raw.id ?? base.id;
|
||||
@@ -2034,6 +2113,15 @@ function normalizeState(raw: Partial<BossState> | undefined): BossState {
|
||||
mirroredToProject: log.mirroredToProject ?? false,
|
||||
createdAt: log.createdAt ?? nowIso(),
|
||||
})),
|
||||
userAttachmentStorageConfigs: ensureArray(
|
||||
raw.userAttachmentStorageConfigs,
|
||||
base.userAttachmentStorageConfigs,
|
||||
).map((config, index) =>
|
||||
normalizeAttachmentStorageConfig(
|
||||
config,
|
||||
base.userAttachmentStorageConfigs[index % base.userAttachmentStorageConfigs.length],
|
||||
),
|
||||
),
|
||||
threadContextSnapshots: ensureArray(raw.threadContextSnapshots, base.threadContextSnapshots).map(
|
||||
(snapshot, index) => ({
|
||||
...base.threadContextSnapshots[index % base.threadContextSnapshots.length],
|
||||
@@ -2573,7 +2661,12 @@ export async function readState(): Promise<BossState> {
|
||||
|
||||
try {
|
||||
const state = normalizeState(JSON.parse(raw) as Partial<BossState>);
|
||||
lastPersistedStateText = JSON.stringify(state, null, 2);
|
||||
const normalizedText = JSON.stringify(state, null, 2);
|
||||
lastPersistedStateText = normalizedText;
|
||||
if (normalizedText !== raw) {
|
||||
await fs.writeFile(dataFile, normalizedText, "utf8");
|
||||
await fs.writeFile(backupFile, normalizedText, "utf8");
|
||||
}
|
||||
return state;
|
||||
} catch {
|
||||
const fallbackText =
|
||||
@@ -2582,7 +2675,12 @@ export async function readState(): Promise<BossState> {
|
||||
JSON.stringify(syncDerivedState(cloneInitialState()), null, 2);
|
||||
await fs.writeFile(dataFile, fallbackText, "utf8");
|
||||
const state = normalizeState(JSON.parse(fallbackText) as Partial<BossState>);
|
||||
lastPersistedStateText = JSON.stringify(state, null, 2);
|
||||
const normalizedText = JSON.stringify(state, null, 2);
|
||||
lastPersistedStateText = normalizedText;
|
||||
if (normalizedText !== fallbackText) {
|
||||
await fs.writeFile(dataFile, normalizedText, "utf8");
|
||||
await fs.writeFile(backupFile, normalizedText, "utf8");
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -2627,6 +2725,31 @@ export async function getDevice(deviceId: string) {
|
||||
return state.devices.find((device) => device.id === deviceId) ?? null;
|
||||
}
|
||||
|
||||
export async function getAttachmentStorageConfig(account: string) {
|
||||
const state = await readState();
|
||||
return (
|
||||
state.userAttachmentStorageConfigs.find((item) => item.account === account) ?? {
|
||||
account,
|
||||
mode: "server_file" as const,
|
||||
updatedAt: nowIso(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function upsertAttachmentStorageConfig(config: UserAttachmentStorageConfig) {
|
||||
return mutateState((state) => {
|
||||
const index = state.userAttachmentStorageConfigs.findIndex(
|
||||
(item) => item.account === config.account,
|
||||
);
|
||||
if (index >= 0) {
|
||||
state.userAttachmentStorageConfigs[index] = config;
|
||||
} else {
|
||||
state.userAttachmentStorageConfigs.push(config);
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
function preferredDeviceForAccount(
|
||||
state: BossState,
|
||||
account: string,
|
||||
|
||||
Reference in New Issue
Block a user