refactor: clean CLI taxonomy — canonical subcommands, merged memory.update, no aliases
- calendar: split write → create/read/update/delete/share - contacts: rename lookup → read - memory: merge write+forget → update (unified action field in operations) - Remove all alias/normalization logic from adapter and handlers - Update tool_postprocessor ui_hints builders to canonical keys - Remove frontend legacy TOOL_CALL_START/ARGS/END events and ToolCallItem - Update SKILL.md files and protocol docs - Update tests and settings screens
This commit is contained in:
@@ -5,9 +5,6 @@ class AgUiEventTypeWire {
|
||||
static const stepStarted = 'STEP_STARTED';
|
||||
static const stepFinished = 'STEP_FINISHED';
|
||||
static const textMessageEnd = 'TEXT_MESSAGE_END';
|
||||
static const toolCallStart = 'TOOL_CALL_START';
|
||||
static const toolCallArgs = 'TOOL_CALL_ARGS';
|
||||
static const toolCallEnd = 'TOOL_CALL_END';
|
||||
static const toolCallResult = 'TOOL_CALL_RESULT';
|
||||
}
|
||||
|
||||
@@ -18,9 +15,6 @@ enum AgUiEventType {
|
||||
stepStarted,
|
||||
stepFinished,
|
||||
textMessageEnd,
|
||||
toolCallStart,
|
||||
toolCallArgs,
|
||||
toolCallEnd,
|
||||
toolCallResult,
|
||||
unknown,
|
||||
}
|
||||
@@ -32,9 +26,6 @@ const _wireToTypeMap = {
|
||||
AgUiEventTypeWire.stepStarted: AgUiEventType.stepStarted,
|
||||
AgUiEventTypeWire.stepFinished: AgUiEventType.stepFinished,
|
||||
AgUiEventTypeWire.textMessageEnd: AgUiEventType.textMessageEnd,
|
||||
AgUiEventTypeWire.toolCallStart: AgUiEventType.toolCallStart,
|
||||
AgUiEventTypeWire.toolCallArgs: AgUiEventType.toolCallArgs,
|
||||
AgUiEventTypeWire.toolCallEnd: AgUiEventType.toolCallEnd,
|
||||
AgUiEventTypeWire.toolCallResult: AgUiEventType.toolCallResult,
|
||||
};
|
||||
|
||||
@@ -45,9 +36,6 @@ const _typeToWireMap = {
|
||||
AgUiEventType.stepStarted: AgUiEventTypeWire.stepStarted,
|
||||
AgUiEventType.stepFinished: AgUiEventTypeWire.stepFinished,
|
||||
AgUiEventType.textMessageEnd: AgUiEventTypeWire.textMessageEnd,
|
||||
AgUiEventType.toolCallStart: AgUiEventTypeWire.toolCallStart,
|
||||
AgUiEventType.toolCallArgs: AgUiEventTypeWire.toolCallArgs,
|
||||
AgUiEventType.toolCallEnd: AgUiEventTypeWire.toolCallEnd,
|
||||
AgUiEventType.toolCallResult: AgUiEventTypeWire.toolCallResult,
|
||||
AgUiEventType.unknown: '',
|
||||
};
|
||||
@@ -74,9 +62,6 @@ abstract class AgUiEvent {
|
||||
AgUiEventType.stepStarted => StepStartedEvent.fromJson(json),
|
||||
AgUiEventType.stepFinished => StepFinishedEvent.fromJson(json),
|
||||
AgUiEventType.textMessageEnd => TextMessageEndEvent.fromJson(json),
|
||||
AgUiEventType.toolCallStart => ToolCallStartEvent.fromJson(json),
|
||||
AgUiEventType.toolCallArgs => ToolCallArgsEvent.fromJson(json),
|
||||
AgUiEventType.toolCallEnd => ToolCallEndEvent.fromJson(json),
|
||||
AgUiEventType.toolCallResult => ToolCallResultEvent.fromJson(json),
|
||||
AgUiEventType.unknown => UnknownAgUiEvent(rawJson: json),
|
||||
};
|
||||
@@ -157,12 +142,14 @@ class TextMessageEndEvent extends AgUiEvent {
|
||||
required this.answer,
|
||||
required this.role,
|
||||
required this.status,
|
||||
this.suggestedActions = const <String>[],
|
||||
}) : super(type: AgUiEventType.textMessageEnd);
|
||||
|
||||
final String messageId;
|
||||
final String answer;
|
||||
final String role;
|
||||
final String status;
|
||||
final List<String> suggestedActions;
|
||||
|
||||
factory TextMessageEndEvent.fromJson(Map<String, dynamic> json) =>
|
||||
TextMessageEndEvent(
|
||||
@@ -170,53 +157,17 @@ class TextMessageEndEvent extends AgUiEvent {
|
||||
answer: _asString(json['answer']),
|
||||
role: _asString(json['role'], fallback: 'assistant'),
|
||||
status: _asString(json['status'], fallback: 'success'),
|
||||
suggestedActions: _asStringList(json['suggested_actions']),
|
||||
);
|
||||
}
|
||||
|
||||
class ToolCallStartEvent extends AgUiEvent {
|
||||
ToolCallStartEvent({required this.toolCallId, required this.toolCallName})
|
||||
: super(type: AgUiEventType.toolCallStart);
|
||||
|
||||
final String toolCallId;
|
||||
final String toolCallName;
|
||||
|
||||
factory ToolCallStartEvent.fromJson(Map<String, dynamic> json) =>
|
||||
ToolCallStartEvent(
|
||||
toolCallId: _asString(json['toolCallId']),
|
||||
toolCallName: _asString(json['toolCallName']),
|
||||
);
|
||||
}
|
||||
|
||||
class ToolCallArgsEvent extends AgUiEvent {
|
||||
ToolCallArgsEvent({required this.toolCallId, required this.args})
|
||||
: super(type: AgUiEventType.toolCallArgs);
|
||||
|
||||
final String toolCallId;
|
||||
final Map<String, dynamic> args;
|
||||
|
||||
factory ToolCallArgsEvent.fromJson(Map<String, dynamic> json) =>
|
||||
ToolCallArgsEvent(
|
||||
toolCallId: _asString(json['toolCallId']),
|
||||
args: _asMap(json['args']) ?? const {},
|
||||
);
|
||||
}
|
||||
|
||||
class ToolCallEndEvent extends AgUiEvent {
|
||||
ToolCallEndEvent({required this.toolCallId})
|
||||
: super(type: AgUiEventType.toolCallEnd);
|
||||
|
||||
final String toolCallId;
|
||||
|
||||
factory ToolCallEndEvent.fromJson(Map<String, dynamic> json) =>
|
||||
ToolCallEndEvent(toolCallId: _asString(json['toolCallId']));
|
||||
}
|
||||
|
||||
class ToolCallResultEvent extends AgUiEvent {
|
||||
ToolCallResultEvent({
|
||||
required this.messageId,
|
||||
required this.toolCallId,
|
||||
required this.toolName,
|
||||
required this.resultSummary,
|
||||
this.toolCallArgs,
|
||||
this.result,
|
||||
required this.status,
|
||||
required this.uiSchema,
|
||||
}) : super(type: AgUiEventType.toolCallResult);
|
||||
@@ -224,7 +175,8 @@ class ToolCallResultEvent extends AgUiEvent {
|
||||
final String messageId;
|
||||
final String toolCallId;
|
||||
final String toolName;
|
||||
final String resultSummary;
|
||||
final Map<String, dynamic>? toolCallArgs;
|
||||
final Object? result;
|
||||
final String status;
|
||||
final Map<String, dynamic>? uiSchema;
|
||||
|
||||
@@ -233,7 +185,8 @@ class ToolCallResultEvent extends AgUiEvent {
|
||||
messageId: _asString(json['messageId']),
|
||||
toolCallId: _asString(json['tool_call_id']),
|
||||
toolName: _asString(json['tool_name']),
|
||||
resultSummary: _asString(json['result']),
|
||||
toolCallArgs: _asMap(json['tool_call_args']),
|
||||
result: json['result'],
|
||||
status: _asString(json['status'], fallback: 'success'),
|
||||
uiSchema: _asMap(json['ui_schema']),
|
||||
);
|
||||
@@ -280,6 +233,7 @@ class HistoryMessage {
|
||||
required this.content,
|
||||
required this.timestamp,
|
||||
this.attachments = const <HistoryAttachment>[],
|
||||
this.suggestedActions = const <String>[],
|
||||
this.uiSchema,
|
||||
});
|
||||
|
||||
@@ -289,6 +243,7 @@ class HistoryMessage {
|
||||
final String content;
|
||||
final DateTime timestamp;
|
||||
final List<HistoryAttachment> attachments;
|
||||
final List<String> suggestedActions;
|
||||
final Map<String, dynamic>? uiSchema;
|
||||
|
||||
factory HistoryMessage.fromJson(Map<String, dynamic> json) => HistoryMessage(
|
||||
@@ -298,6 +253,7 @@ class HistoryMessage {
|
||||
content: _asString(json['content']),
|
||||
timestamp: _parseTimestamp(_asString(json['timestamp'])),
|
||||
attachments: _parseHistoryAttachments(json['attachments']),
|
||||
suggestedActions: _asStringList(json['suggestedActions']),
|
||||
uiSchema: _asMap(json['ui_schema']),
|
||||
);
|
||||
}
|
||||
@@ -374,3 +330,14 @@ List<HistoryAttachment> _parseHistoryAttachments(Object? value) {
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<String> _asStringList(Object? value) {
|
||||
if (value is! List) {
|
||||
return const <String>[];
|
||||
}
|
||||
return value
|
||||
.whereType<String>()
|
||||
.map((item) => item.trim())
|
||||
.where((item) => item.isNotEmpty)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ class ChatHistoryRepository extends CachedRepository<HistorySnapshot> {
|
||||
},
|
||||
)
|
||||
.toList(growable: false),
|
||||
'suggestedActions': message.suggestedActions,
|
||||
'ui_schema': message.uiSchema,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
enum ChatItemType { message, toolCall, toolResult }
|
||||
enum ChatItemType { message, toolResult }
|
||||
|
||||
enum MessageSender { user, ai }
|
||||
|
||||
enum ToolCallStatus { pending, executing, completed, error }
|
||||
|
||||
abstract class ChatListItem {
|
||||
String get id;
|
||||
DateTime get timestamp;
|
||||
@@ -22,6 +20,7 @@ class TextMessageItem extends ChatListItem {
|
||||
final bool isStreaming;
|
||||
final bool isLocalEcho;
|
||||
final List<Map<String, dynamic>> attachments;
|
||||
final List<String> suggestedActions;
|
||||
|
||||
TextMessageItem({
|
||||
required this.id,
|
||||
@@ -31,6 +30,7 @@ class TextMessageItem extends ChatListItem {
|
||||
this.isStreaming = false,
|
||||
this.isLocalEcho = false,
|
||||
this.attachments = const [],
|
||||
this.suggestedActions = const [],
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -44,6 +44,7 @@ class TextMessageItem extends ChatListItem {
|
||||
bool? isStreaming,
|
||||
bool? isLocalEcho,
|
||||
List<Map<String, dynamic>>? attachments,
|
||||
List<String>? suggestedActions,
|
||||
}) => TextMessageItem(
|
||||
id: id ?? this.id,
|
||||
content: content ?? this.content,
|
||||
@@ -52,54 +53,7 @@ class TextMessageItem extends ChatListItem {
|
||||
isStreaming: isStreaming ?? this.isStreaming,
|
||||
isLocalEcho: isLocalEcho ?? this.isLocalEcho,
|
||||
attachments: attachments ?? this.attachments,
|
||||
);
|
||||
}
|
||||
|
||||
class ToolCallItem extends ChatListItem {
|
||||
@override
|
||||
final String id;
|
||||
final String callId;
|
||||
final String toolName;
|
||||
final Map<String, dynamic> args;
|
||||
final ToolCallStatus status;
|
||||
final String? errorMessage;
|
||||
@override
|
||||
final DateTime timestamp;
|
||||
@override
|
||||
final MessageSender sender;
|
||||
|
||||
ToolCallItem({
|
||||
required this.id,
|
||||
required this.callId,
|
||||
required this.toolName,
|
||||
required this.args,
|
||||
required this.status,
|
||||
this.errorMessage,
|
||||
required this.timestamp,
|
||||
required this.sender,
|
||||
});
|
||||
|
||||
@override
|
||||
ChatItemType get type => ChatItemType.toolCall;
|
||||
|
||||
ToolCallItem copyWith({
|
||||
String? id,
|
||||
String? callId,
|
||||
String? toolName,
|
||||
Map<String, dynamic>? args,
|
||||
ToolCallStatus? status,
|
||||
String? errorMessage,
|
||||
DateTime? timestamp,
|
||||
MessageSender? sender,
|
||||
}) => ToolCallItem(
|
||||
id: id ?? this.id,
|
||||
callId: callId ?? this.callId,
|
||||
toolName: toolName ?? this.toolName,
|
||||
args: args ?? this.args,
|
||||
status: status ?? this.status,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
timestamp: timestamp ?? this.timestamp,
|
||||
sender: sender ?? this.sender,
|
||||
suggestedActions: suggestedActions ?? this.suggestedActions,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
import '../l10n/l10n.dart';
|
||||
|
||||
const Map<String, String> _toolNameAliases = {
|
||||
'calendar_read': 'calendar.read',
|
||||
'calendar_write': 'calendar.write',
|
||||
'calendar_share': 'calendar.share',
|
||||
'user_lookup': 'user.lookup',
|
||||
'memory_write': 'memory.write',
|
||||
'memory_forget': 'memory.forget',
|
||||
};
|
||||
|
||||
const List<String> automationToolOptions = [
|
||||
'calendar.create',
|
||||
'calendar.read',
|
||||
'calendar.write',
|
||||
'calendar.update',
|
||||
'calendar.delete',
|
||||
'calendar.share',
|
||||
'user.lookup',
|
||||
'memory.write',
|
||||
'memory.forget',
|
||||
'contacts.read',
|
||||
'memory.update',
|
||||
];
|
||||
|
||||
String localizeToolName(String rawName) {
|
||||
@@ -23,20 +15,21 @@ String localizeToolName(String rawName) {
|
||||
if (normalized.isEmpty) {
|
||||
return rawName;
|
||||
}
|
||||
final canonical = _toolNameAliases[normalized] ?? normalized;
|
||||
switch (canonical) {
|
||||
switch (normalized) {
|
||||
case 'calendar.create':
|
||||
return L10n.current.toolCalendarWrite;
|
||||
case 'calendar.read':
|
||||
return L10n.current.toolCalendarRead;
|
||||
case 'calendar.write':
|
||||
case 'calendar.update':
|
||||
return L10n.current.toolCalendarWrite;
|
||||
case 'calendar.delete':
|
||||
return L10n.current.toolCalendarWrite;
|
||||
case 'calendar.share':
|
||||
return L10n.current.toolCalendarShare;
|
||||
case 'user.lookup':
|
||||
case 'contacts.read':
|
||||
return L10n.current.toolUserLookup;
|
||||
case 'memory.write':
|
||||
case 'memory.update':
|
||||
return L10n.current.toolMemoryWrite;
|
||||
case 'memory.forget':
|
||||
return L10n.current.toolMemoryForget;
|
||||
default:
|
||||
return rawName;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user