xworkmate-app/lib/runtime/assistant_artifacts.dart
2026-04-06 10:27:01 +08:00

240 lines
6.8 KiB
Dart

import 'runtime_models.dart';
enum AssistantArtifactEntryKind { file, object }
extension AssistantArtifactEntryKindCopy on AssistantArtifactEntryKind {
static AssistantArtifactEntryKind fromJsonValue(String? value) {
return AssistantArtifactEntryKind.values.firstWhere(
(item) => item.name == value,
orElse: () => AssistantArtifactEntryKind.file,
);
}
}
enum AssistantArtifactPreviewKind { markdown, html, text, unsupported, empty }
extension AssistantArtifactPreviewKindCopy on AssistantArtifactPreviewKind {
static AssistantArtifactPreviewKind fromJsonValue(String? value) {
return AssistantArtifactPreviewKind.values.firstWhere(
(item) => item.name == value,
orElse: () => AssistantArtifactPreviewKind.empty,
);
}
}
class AssistantArtifactEntry {
const AssistantArtifactEntry({
required this.id,
required this.label,
required this.relativePath,
required this.kind,
required this.mimeType,
required this.previewable,
required this.workspacePath,
this.sizeBytes,
this.updatedAtMs,
});
final String id;
final String label;
final String relativePath;
final AssistantArtifactEntryKind kind;
final String mimeType;
final int? sizeBytes;
final double? updatedAtMs;
final bool previewable;
final String workspacePath;
Map<String, dynamic> toJson() {
return <String, dynamic>{
'id': id,
'label': label,
'relativePath': relativePath,
'kind': kind.name,
'mimeType': mimeType,
'sizeBytes': sizeBytes,
'updatedAtMs': updatedAtMs,
'previewable': previewable,
'workspacePath': workspacePath,
};
}
factory AssistantArtifactEntry.fromJson(Map<String, dynamic> json) {
return AssistantArtifactEntry(
id: json['id']?.toString() ?? '',
label: json['label']?.toString() ?? '',
relativePath: json['relativePath']?.toString() ?? '',
kind: AssistantArtifactEntryKindCopy.fromJsonValue(
json['kind']?.toString(),
),
mimeType: json['mimeType']?.toString() ?? 'application/octet-stream',
sizeBytes: switch (json['sizeBytes']) {
final num value => value.toInt(),
_ => null,
},
updatedAtMs: switch (json['updatedAtMs']) {
final num value => value.toDouble(),
_ => null,
},
previewable: json['previewable'] as bool? ?? false,
workspacePath:
json['workspacePath']?.toString() ??
json['workspaceRef']?.toString() ??
'',
);
}
}
class AssistantArtifactChangeEntry {
const AssistantArtifactChangeEntry({
required this.path,
required this.changeType,
required this.displayLabel,
});
final String path;
final String changeType;
final String displayLabel;
Map<String, dynamic> toJson() {
return <String, dynamic>{
'path': path,
'changeType': changeType,
'displayLabel': displayLabel,
};
}
factory AssistantArtifactChangeEntry.fromJson(Map<String, dynamic> json) {
return AssistantArtifactChangeEntry(
path: json['path']?.toString() ?? '',
changeType: json['changeType']?.toString() ?? '',
displayLabel: json['displayLabel']?.toString() ?? '',
);
}
}
class AssistantArtifactPreview {
const AssistantArtifactPreview({
required this.kind,
this.title = '',
this.content = '',
this.message = '',
});
const AssistantArtifactPreview.empty({String message = ''})
: this(kind: AssistantArtifactPreviewKind.empty, message: message);
const AssistantArtifactPreview.unsupported({
String title = '',
String message = '',
}) : this(
kind: AssistantArtifactPreviewKind.unsupported,
title: title,
message: message,
);
final AssistantArtifactPreviewKind kind;
final String title;
final String content;
final String message;
Map<String, dynamic> toJson() {
return <String, dynamic>{
'kind': kind.name,
'title': title,
'content': content,
'message': message,
};
}
factory AssistantArtifactPreview.fromJson(Map<String, dynamic> json) {
return AssistantArtifactPreview(
kind: AssistantArtifactPreviewKindCopy.fromJsonValue(
json['kind']?.toString(),
),
title: json['title']?.toString() ?? '',
content: json['content']?.toString() ?? '',
message: json['message']?.toString() ?? '',
);
}
}
class AssistantArtifactSnapshot {
const AssistantArtifactSnapshot({
required this.workspacePath,
required this.workspaceKind,
this.resultEntries = const <AssistantArtifactEntry>[],
this.fileEntries = const <AssistantArtifactEntry>[],
this.changes = const <AssistantArtifactChangeEntry>[],
this.resultMessage = '',
this.filesMessage = '',
this.changesMessage = '',
});
final String workspacePath;
final WorkspaceRefKind workspaceKind;
final List<AssistantArtifactEntry> resultEntries;
final List<AssistantArtifactEntry> fileEntries;
final List<AssistantArtifactChangeEntry> changes;
final String resultMessage;
final String filesMessage;
final String changesMessage;
bool get hasAnyContent =>
resultEntries.isNotEmpty || fileEntries.isNotEmpty || changes.isNotEmpty;
Map<String, dynamic> toJson() {
return <String, dynamic>{
'workspacePath': workspacePath,
'workspaceKind': workspaceKind.name,
'resultEntries': resultEntries.map((item) => item.toJson()).toList(),
'fileEntries': fileEntries.map((item) => item.toJson()).toList(),
'changes': changes.map((item) => item.toJson()).toList(),
'resultMessage': resultMessage,
'filesMessage': filesMessage,
'changesMessage': changesMessage,
};
}
factory AssistantArtifactSnapshot.fromJson(Map<String, dynamic> json) {
List<T> decodeList<T>(
Object? value,
T Function(Map<String, dynamic>) mapper,
) {
if (value is! List) {
return <T>[];
}
return value
.whereType<Map>()
.map((item) => mapper(item.cast<String, dynamic>()))
.toList(growable: false);
}
return AssistantArtifactSnapshot(
workspacePath:
json['workspacePath']?.toString() ??
json['workspaceRef']?.toString() ??
'',
workspaceKind: WorkspaceRefKindCopy.fromJsonValue(
json['workspaceKind']?.toString() ??
json['workspaceRefKind']?.toString(),
),
resultEntries: decodeList(
json['resultEntries'],
AssistantArtifactEntry.fromJson,
),
fileEntries: decodeList(
json['fileEntries'],
AssistantArtifactEntry.fromJson,
),
changes: decodeList(
json['changes'],
AssistantArtifactChangeEntry.fromJson,
),
resultMessage: json['resultMessage']?.toString() ?? '',
filesMessage: json['filesMessage']?.toString() ?? '',
changesMessage: json['changesMessage']?.toString() ?? '',
);
}
}