import 'dart:async'; import 'dart:convert'; import 'package:social_app/core/config/env.dart'; import '../ai/ai_decision_engine.dart'; import '../models/ag_ui_event.dart'; import '../models/tool_result.dart'; import '../tools/tool_registry.dart'; typedef EventCallback = void Function(AgUiEvent event); class AgUiService { EventCallback onEvent; final AiDecisionEngine _decisionEngine; AgUiService({EventCallback? onEvent}) : onEvent = onEvent ?? ((_) {}), _decisionEngine = AiDecisionEngine(); Future sendMessage(String content) async { if (Env.isMockApi) { await _mockEventStream(content); } else { throw UnimplementedError('Real API not implemented'); } } Future _mockEventStream(String content) async { final threadId = 'thread_${DateTime.now().millisecondsSinceEpoch}'; final runId = 'run_${DateTime.now().millisecondsSinceEpoch}'; onEvent(RunStartedEvent(threadId: threadId, runId: runId)); final forceTrigger = _decisionEngine.tryForceTrigger(content); if (forceTrigger != null) { await _mockToolCallFlowWithArgs(forceTrigger.toolName, forceTrigger.args); } else if (_decisionEngine.shouldTriggerToolCall(content)) { await _mockToolCallFlow(content); } final replies = _generateReplies(content); if (replies.isNotEmpty) { await _mockTextMessageStream(replies); } onEvent(RunFinishedEvent(threadId: threadId, runId: runId)); } Future _mockToolCallFlow(String content) async { final args = _decisionEngine.getToolCallArgs(content); if (args == null) return; await _mockToolCallFlowWithArgs('create_calendar_event', args); } Future _mockToolCallFlowWithArgs( String toolName, Map args, ) async { final toolCallId = 'tc_${DateTime.now().millisecondsSinceEpoch}'; onEvent(ToolCallStartEvent(toolCallId: toolCallId, toolCallName: toolName)); onEvent(ToolCallArgsEvent(toolCallId: toolCallId, delta: jsonEncode(args))); onEvent(ToolCallEndEvent(toolCallId: toolCallId)); final validation = ToolRegistry.validateArgs(toolName, args); if (!validation.ok) { onEvent( ToolCallErrorEvent( toolCallId: toolCallId, error: validation.error ?? 'Validation failed', code: 'VALIDATION_ERROR', ), ); return; } try { ToolRegistry.initialize(); final result = await ToolRegistry.execute(toolName, args); final ui = _buildUiCard(toolName, result); final messageId = 'msg_${DateTime.now().millisecondsSinceEpoch}'; onEvent( ToolCallResultEvent( messageId: messageId, toolCallId: toolCallId, result: result, ui: ui, ), ); } catch (e) { onEvent( ToolCallErrorEvent( toolCallId: toolCallId, error: e.toString(), code: 'EXECUTION_ERROR', ), ); } } UiCard? _buildUiCard(String toolName, Map result) { if (toolName == 'create_calendar_event') { return UiCard( cardType: 'calendar', data: CalendarCardData( id: result['eventId'] ?? '', title: result['title'] ?? '', description: result['description'], startAt: result['startAt'] ?? '', endAt: result['endAt'], timezone: result['timezone'], location: result['location'], color: result['color'], sourceType: result['sourceType'], ).toJson(), actions: [ CardAction( type: 'link', label: '查看详情', target: '/calendar/${result['eventId']}', ), ], ); } return null; } List _generateReplies(String content) { final intent = _decisionEngine.matchIntent(content); switch (intent) { case Intent.createEvent: return ['好的,我已经为您创建了日程安排。']; case Intent.searchEvent: return ['您今天有以下日程:\n- 10:00 团队会议\n- 14:00 产品评审']; case Intent.unknown: return ['我理解了您的问题,让我来帮您处理。']; } } Future _mockTextMessageStream(List replies) async { for (final reply in replies) { final messageId = 'msg_${DateTime.now().millisecondsSinceEpoch}'; onEvent(TextMessageStartEvent(messageId: messageId, role: 'assistant')); const chunkSize = 10; for (var i = 0; i < reply.length; i += chunkSize) { final end = (i + chunkSize < reply.length) ? i + chunkSize : reply.length; final chunk = reply.substring(i, end); onEvent(TextMessageContentEvent(messageId: messageId, delta: chunk)); await Future.delayed(const Duration(milliseconds: 50)); } onEvent(TextMessageEndEvent(messageId: messageId)); } } }