feat: 添加自动化任务(automation_jobs)功能模块

This commit is contained in:
qzl
2026-03-24 12:38:11 +08:00
parent f4b7eb7e09
commit 23359c2d01
43 changed files with 4266 additions and 1139 deletions
@@ -0,0 +1,417 @@
int _parseInt(dynamic v, {required String field, required int fallback}) {
if (v == null) {
return fallback;
}
if (v is int) {
return v;
}
if (v is String) {
return int.tryParse(v) ?? (throw FormatException('$field invalid'));
}
throw FormatException('$field invalid type');
}
List<String> _parseStringList(dynamic v, {required String field}) {
if (v == null) {
return const [];
}
if (v is List && v.every((e) => e is String)) {
return v.cast<String>();
}
throw FormatException('$field invalid type');
}
String _parseString(
dynamic v, {
required String field,
required String fallback,
}) {
if (v == null) {
return fallback;
}
if (v is String) {
return v;
}
throw FormatException('$field invalid type');
}
class MessageContextConfigModel {
final String source;
final String windowMode;
final int windowCount;
MessageContextConfigModel({
required this.source,
required this.windowMode,
required this.windowCount,
});
factory MessageContextConfigModel.fromJson(Map<String, dynamic>? json) {
if (json == null) {
return MessageContextConfigModel(
source: 'latest_chat',
windowMode: 'day',
windowCount: 2,
);
}
return MessageContextConfigModel(
source: _parseString(
json['source'],
field: 'source',
fallback: 'latest_chat',
),
windowMode: _parseString(
json['window_mode'],
field: 'window_mode',
fallback: 'day',
),
windowCount: _parseInt(
json['window_count'],
field: 'window_count',
fallback: 2,
),
);
}
Map<String, dynamic> toJson() => {
'source': source,
'window_mode': windowMode,
'window_count': windowCount,
};
MessageContextConfigModel copyWith({
String? source,
String? windowMode,
int? windowCount,
}) {
return MessageContextConfigModel(
source: source ?? this.source,
windowMode: windowMode ?? this.windowMode,
windowCount: windowCount ?? this.windowCount,
);
}
}
class AutomationJobConfigModel {
final String inputTemplate;
final List<String> enabledTools;
final MessageContextConfigModel context;
AutomationJobConfigModel({
required this.inputTemplate,
required this.enabledTools,
required this.context,
});
factory AutomationJobConfigModel.fromJson(Map<String, dynamic>? json) {
if (json == null) {
return AutomationJobConfigModel(
inputTemplate: '',
enabledTools: const [],
context: MessageContextConfigModel.fromJson(null),
);
}
return AutomationJobConfigModel(
inputTemplate: _parseString(
json['input_template'],
field: 'input_template',
fallback: '',
),
enabledTools: _parseStringList(
json['enabled_tools'],
field: 'enabled_tools',
),
context: json['context'] != null
? MessageContextConfigModel.fromJson(
json['context'] as Map<String, dynamic>?,
)
: MessageContextConfigModel.fromJson(null),
);
}
Map<String, dynamic> toJson() => {
'input_template': inputTemplate,
'enabled_tools': enabledTools,
'context': context.toJson(),
};
AutomationJobConfigModel copyWith({
String? inputTemplate,
List<String>? enabledTools,
MessageContextConfigModel? context,
}) {
return AutomationJobConfigModel(
inputTemplate: inputTemplate ?? this.inputTemplate,
enabledTools: enabledTools ?? this.enabledTools,
context: context ?? this.context,
);
}
}
class AutomationJobModel {
final String id;
final String ownerId;
final String? bootstrapKey;
final String title;
final String scheduleType;
final String runAt;
final String timezone;
final String status;
final bool isSystem;
final AutomationJobConfigModel config;
final DateTime nextRunAt;
final DateTime? lastRunAt;
final DateTime createdAt;
final DateTime updatedAt;
AutomationJobModel({
required this.id,
required this.ownerId,
this.bootstrapKey,
required this.title,
required this.scheduleType,
required this.runAt,
required this.timezone,
required this.status,
required this.isSystem,
required this.config,
required this.nextRunAt,
this.lastRunAt,
required this.createdAt,
required this.updatedAt,
});
factory AutomationJobModel.fromJson(Map<String, dynamic> json) {
return AutomationJobModel(
id: _parseString(json['id'], field: 'id', fallback: ''),
ownerId: _parseString(json['owner_id'], field: 'owner_id', fallback: ''),
bootstrapKey: json['bootstrap_key'] == null
? null
: _parseString(
json['bootstrap_key'],
field: 'bootstrap_key',
fallback: '',
),
title: _parseString(json['title'], field: 'title', fallback: ''),
scheduleType: _parseString(
json['schedule_type'],
field: 'schedule_type',
fallback: 'daily',
),
runAt: _parseString(
json['run_at'],
field: 'run_at',
fallback: '08:00:00',
),
timezone: _parseString(
json['timezone'],
field: 'timezone',
fallback: 'UTC',
),
status: _parseString(json['status'], field: 'status', fallback: 'active'),
isSystem: json['is_system'] == null
? false
: (json['is_system'] is bool
? json['is_system'] as bool
: throw FormatException('is_system invalid type')),
config: json['config'] != null
? AutomationJobConfigModel.fromJson(
json['config'] as Map<String, dynamic>?,
)
: AutomationJobConfigModel.fromJson(null),
nextRunAt: json['next_run_at'] != null
? DateTime.parse(
_parseString(
json['next_run_at'],
field: 'next_run_at',
fallback: '',
),
)
: throw FormatException('next_run_at is required'),
lastRunAt: json['last_run_at'] != null
? DateTime.parse(
_parseString(
json['last_run_at'],
field: 'last_run_at',
fallback: '',
),
)
: null,
createdAt: json['created_at'] != null
? DateTime.parse(
_parseString(
json['created_at'],
field: 'created_at',
fallback: '',
),
)
: throw FormatException('created_at is required'),
updatedAt: json['updated_at'] != null
? DateTime.parse(
_parseString(
json['updated_at'],
field: 'updated_at',
fallback: '',
),
)
: throw FormatException('updated_at is required'),
);
}
Map<String, dynamic> toJson() => {
'id': id,
'owner_id': ownerId,
'bootstrap_key': bootstrapKey,
'title': title,
'schedule_type': scheduleType,
'run_at': runAt,
'timezone': timezone,
'status': status,
'is_system': isSystem,
'config': config.toJson(),
'next_run_at': nextRunAt.toIso8601String(),
'last_run_at': lastRunAt?.toIso8601String(),
'created_at': createdAt.toIso8601String(),
'updated_at': updatedAt.toIso8601String(),
};
AutomationJobModel copyWith({
String? id,
String? ownerId,
String? bootstrapKey,
String? title,
String? scheduleType,
String? runAt,
String? timezone,
String? status,
bool? isSystem,
AutomationJobConfigModel? config,
DateTime? nextRunAt,
DateTime? lastRunAt,
DateTime? createdAt,
DateTime? updatedAt,
}) {
return AutomationJobModel(
id: id ?? this.id,
ownerId: ownerId ?? this.ownerId,
bootstrapKey: bootstrapKey ?? this.bootstrapKey,
title: title ?? this.title,
scheduleType: scheduleType ?? this.scheduleType,
runAt: runAt ?? this.runAt,
timezone: timezone ?? this.timezone,
status: status ?? this.status,
isSystem: isSystem ?? this.isSystem,
config: config ?? this.config,
nextRunAt: nextRunAt ?? this.nextRunAt,
lastRunAt: lastRunAt ?? this.lastRunAt,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
bool get isActive => status.toLowerCase() == 'active';
bool get isDaily => scheduleType.toLowerCase() == 'daily';
bool get isWeekly => scheduleType.toLowerCase() == 'weekly';
}
class AutomationJobListResponse {
final List<AutomationJobModel> items;
AutomationJobListResponse({required this.items});
factory AutomationJobListResponse.fromJson(Map<String, dynamic>? json) {
if (json == null) {
return AutomationJobListResponse(items: const []);
}
final itemsJson = json['items'];
if (itemsJson == null) {
return AutomationJobListResponse(items: const []);
}
if (itemsJson is List) {
return AutomationJobListResponse(
items: itemsJson
.map((e) => AutomationJobModel.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
throw FormatException('items invalid type');
}
}
class AutomationJobCreateRequest {
final String title;
final String scheduleType;
final String runAt;
final String timezone;
final String status;
final AutomationJobConfigModel config;
AutomationJobCreateRequest({
required this.title,
required this.scheduleType,
required this.runAt,
required this.timezone,
required this.status,
required this.config,
});
Map<String, dynamic> toJson() => {
'title': title,
'schedule_type': scheduleType,
'run_at': runAt,
'timezone': timezone,
'status': status,
'config': config.toJson(),
};
}
class AutomationJobConfigPatchModel {
final String? inputTemplate;
final List<String>? enabledTools;
final MessageContextConfigModel? context;
AutomationJobConfigPatchModel({
this.inputTemplate,
this.enabledTools,
this.context,
});
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
if (inputTemplate != null) map['input_template'] = inputTemplate;
if (enabledTools != null) map['enabled_tools'] = enabledTools;
if (context != null) map['context'] = context!.toJson();
return map;
}
}
class AutomationJobUpdateRequest {
final String? title;
final String? scheduleType;
final String? runAt;
final String? timezone;
final String? status;
final AutomationJobConfigPatchModel? config;
AutomationJobUpdateRequest({
this.title,
this.scheduleType,
this.runAt,
this.timezone,
this.status,
this.config,
});
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
if (title != null) map['title'] = title;
if (scheduleType != null) map['schedule_type'] = scheduleType;
if (runAt != null) map['run_at'] = runAt;
if (timezone != null) map['timezone'] = timezone;
if (status != null) map['status'] = status;
if (config != null) map['config'] = config!.toJson();
return map;
}
}