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:
@@ -10,11 +10,7 @@ String agUiEventLabel(AgUiEventType type) {
|
||||
AgUiEventType.stepStarted => l10n.agUiEventStepStarted,
|
||||
AgUiEventType.stepFinished => l10n.agUiEventStepFinished,
|
||||
AgUiEventType.textMessageEnd => l10n.agUiEventTextMessageEnd,
|
||||
AgUiEventType.toolCallStart => l10n.agUiEventToolCallStart,
|
||||
AgUiEventType.toolCallArgs => l10n.agUiEventToolCallArgs,
|
||||
AgUiEventType.toolCallEnd => l10n.agUiEventToolCallEnd,
|
||||
AgUiEventType.toolCallResult => l10n.agUiEventToolCallResult,
|
||||
AgUiEventType.toolCallError => l10n.agUiEventToolCallError,
|
||||
AgUiEventType.unknown => l10n.agUiEventUnknown,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -257,7 +257,17 @@ class ChatBloc extends Cubit<ChatState> implements ChatOrchestrator {
|
||||
bool _shouldRefreshCalendarForTool(ToolCallResultEvent event) {
|
||||
final name = event.toolName.trim().toLowerCase();
|
||||
final status = event.status.trim().toLowerCase();
|
||||
if (name != 'calendar_write') {
|
||||
if (name != 'project_cli') {
|
||||
return false;
|
||||
}
|
||||
final args = event.toolCallArgs;
|
||||
if (args == null) {
|
||||
return false;
|
||||
}
|
||||
final command = (args['command'] as String?)?.trim().toLowerCase();
|
||||
final subcommand = (args['subcommand'] as String?)?.trim().toLowerCase();
|
||||
const mutationSubcommands = {'create', 'update', 'delete'};
|
||||
if (command != 'calendar' || !mutationSubcommands.contains(subcommand)) {
|
||||
return false;
|
||||
}
|
||||
return status == 'success' || status == 'partial';
|
||||
|
||||
@@ -24,24 +24,13 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
case AgUiEventType.runFinished:
|
||||
_trackChatCompleted();
|
||||
_clearRunMetrics();
|
||||
emit(
|
||||
_resetRunState().copyWith(items: _removeToolCallItems(state.items)),
|
||||
);
|
||||
emit(_resetRunState());
|
||||
case AgUiEventType.runError:
|
||||
final errorEvent = event as RunErrorEvent;
|
||||
_clearRunMetrics();
|
||||
final isCanceledByUser = errorEvent.code == 'RUN_CANCELED';
|
||||
emit(
|
||||
_resetRunState(
|
||||
error: isCanceledByUser ? null : errorEvent.message,
|
||||
).copyWith(
|
||||
items: _markActiveToolCallsFailed(
|
||||
state.items,
|
||||
reason: isCanceledByUser
|
||||
? L10n.current.chatRunCanceled
|
||||
: L10n.current.chatRunFailed,
|
||||
),
|
||||
),
|
||||
_resetRunState(error: isCanceledByUser ? null : errorEvent.message),
|
||||
);
|
||||
case AgUiEventType.stepStarted:
|
||||
_handleStepStarted(event as StepStartedEvent);
|
||||
@@ -49,12 +38,6 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
_handleStepFinished(event as StepFinishedEvent);
|
||||
case AgUiEventType.textMessageEnd:
|
||||
_handleTextMessageEnd(event as TextMessageEndEvent);
|
||||
case AgUiEventType.toolCallStart:
|
||||
_handleToolCallStart(event as ToolCallStartEvent);
|
||||
case AgUiEventType.toolCallArgs:
|
||||
_handleToolCallArgs(event as ToolCallArgsEvent);
|
||||
case AgUiEventType.toolCallEnd:
|
||||
_handleToolCallEnd(event as ToolCallEndEvent);
|
||||
case AgUiEventType.toolCallResult:
|
||||
_handleToolCallResult(event as ToolCallResultEvent);
|
||||
case AgUiEventType.unknown:
|
||||
@@ -84,12 +67,13 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
state.items,
|
||||
event.messageId,
|
||||
event.answer,
|
||||
event.suggestedActions,
|
||||
timestamp,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
items: _removeToolCallItems(items),
|
||||
items: items,
|
||||
currentMessageId: null,
|
||||
isWaitingFirstToken: false,
|
||||
isStreaming: false,
|
||||
@@ -101,6 +85,7 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
List<ChatListItem> items,
|
||||
String messageId,
|
||||
String content,
|
||||
List<String> suggestedActions,
|
||||
DateTime timestamp,
|
||||
) {
|
||||
final result = List<ChatListItem>.from(items);
|
||||
@@ -110,7 +95,11 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
|
||||
if (index >= 0) {
|
||||
final existing = result[index] as TextMessageItem;
|
||||
result[index] = existing.copyWith(content: content, isStreaming: false);
|
||||
result[index] = existing.copyWith(
|
||||
content: content,
|
||||
isStreaming: false,
|
||||
suggestedActions: suggestedActions,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -121,73 +110,18 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
timestamp: timestamp,
|
||||
sender: MessageSender.ai,
|
||||
isStreaming: false,
|
||||
suggestedActions: suggestedActions,
|
||||
),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
void _handleToolCallStart(ToolCallStartEvent event) {
|
||||
final exists = state.items.any(
|
||||
(item) => item is ToolCallItem && item.id == event.toolCallId,
|
||||
);
|
||||
if (exists) {
|
||||
return;
|
||||
}
|
||||
emit(
|
||||
state.copyWith(
|
||||
items: [
|
||||
...state.items,
|
||||
ToolCallItem(
|
||||
id: event.toolCallId,
|
||||
callId: event.toolCallId,
|
||||
toolName: event.toolCallName,
|
||||
args: const {},
|
||||
status: ToolCallStatus.pending,
|
||||
timestamp: DateTime.now(),
|
||||
sender: MessageSender.ai,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleToolCallArgs(ToolCallArgsEvent event) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
items: state.items.map((item) {
|
||||
if (item is ToolCallItem && item.id == event.toolCallId) {
|
||||
return item.copyWith(args: event.args);
|
||||
}
|
||||
return item;
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleToolCallEnd(ToolCallEndEvent event) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
items: state.items.map((item) {
|
||||
if (item is ToolCallItem && item.id == event.toolCallId) {
|
||||
return item.copyWith(status: ToolCallStatus.executing);
|
||||
}
|
||||
return item;
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleToolCallResult(ToolCallResultEvent event) {
|
||||
if (_shouldRefreshCalendarForTool(event)) {
|
||||
unawaited(_refreshCalendarAfterToolMutation());
|
||||
}
|
||||
final timestamp = DateTime.now();
|
||||
final items = state.items.map((item) {
|
||||
if (item is ToolCallItem && item.id == event.toolCallId) {
|
||||
return item.copyWith(status: ToolCallStatus.completed);
|
||||
}
|
||||
return item;
|
||||
}).toList();
|
||||
final items = List<ChatListItem>.from(state.items);
|
||||
|
||||
final uiSchema = event.uiSchema;
|
||||
if (uiSchema != null) {
|
||||
@@ -219,30 +153,12 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
items.add(uiItem);
|
||||
}
|
||||
|
||||
List<ChatListItem> _removeToolCallItems(List<ChatListItem> items) {
|
||||
return items.where((item) => item is! ToolCallItem).toList();
|
||||
}
|
||||
|
||||
List<ChatListItem> _markActiveToolCallsFailed(
|
||||
List<ChatListItem> items, {
|
||||
required String reason,
|
||||
}) {
|
||||
return items.map((item) {
|
||||
if (item is! ToolCallItem ||
|
||||
item.status == ToolCallStatus.error ||
|
||||
item.status == ToolCallStatus.completed) {
|
||||
return item;
|
||||
}
|
||||
return item.copyWith(status: ToolCallStatus.error, errorMessage: reason);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<ChatListItem> _convertHistoryMessages(List<HistoryMessage> messages) {
|
||||
final converted = <ChatListItem>[];
|
||||
for (final msg in messages) {
|
||||
final normalizedRole = msg.role.toLowerCase();
|
||||
final isUser = normalizedRole == 'user';
|
||||
final isTool = normalizedRole == 'tool' || normalizedRole == 'tools';
|
||||
final isTool = normalizedRole == 'tool';
|
||||
final sender = isUser ? MessageSender.user : MessageSender.ai;
|
||||
final attachments = msg.attachments
|
||||
.map(
|
||||
@@ -262,11 +178,12 @@ extension _ChatBlocEvents on ChatBloc {
|
||||
sender: sender,
|
||||
isLocalEcho: false,
|
||||
attachments: attachments,
|
||||
suggestedActions: msg.suggestedActions,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!isTool && msg.uiSchema != null) {
|
||||
if (isTool && msg.uiSchema != null) {
|
||||
converted.add(
|
||||
ToolResultItem(
|
||||
id: '${msg.id}-ui',
|
||||
|
||||
Reference in New Issue
Block a user