using ClawdDotNet.Core.Config; using ClawdDotNet.Core.Engine; using ClawdDotNet.UI; using Microsoft.Extensions.Logging; using Microsoft.Web.WebView2.Core; namespace ClawdDotNet; public partial class frm_chat : Form { private readonly AgentConfig _agentConfig; private readonly AgentEngine _engine; private readonly string _instanceId; private readonly ILogger _logger; private WebViewBridge? _bridge; public frm_chat(AgentConfig agentConfig, AgentEngine engine, string instanceId, ILoggerFactory loggerFactory) { _agentConfig = agentConfig; _engine = engine; _instanceId = instanceId; _logger = loggerFactory.CreateLogger($"ClawdDotNet.UI.Chat.{agentConfig.AgentId}"); InitializeComponent(); Text = $"Chat – {agentConfig.DisplayName}"; Load += async (_, _) => await InitWebViewAsync(); } public frm_chat() { _agentConfig = new AgentConfig(); _engine = null!; _instanceId = ""; _logger = LoggerFactory.Create(_ => { }).CreateLogger("Design"); InitializeComponent(); } private async Task InitWebViewAsync() { try { await webView_chat2.EnsureCoreWebView2Async(); var uiPath = EmbeddedUiManager.GetExtractedPath(); webView_chat2.CoreWebView2.SetVirtualHostNameToFolderMapping( "ui.clwd.internal", uiPath, CoreWebView2HostResourceAccessKind.DenyCors); _bridge = new WebViewBridge(webView_chat2, _logger); _bridge.MessageReceived += OnBridgeMessage; webView_chat2.CoreWebView2.Navigate( $"https://ui.clwd.internal/chat.html?agent={_agentConfig.AgentId}"); await Task.Delay(500); await _bridge.SendAsync(new BridgeMessage( Type: BridgeTypes.AgentListUpdate, AgentId: _agentConfig.AgentId, Extra: new { agents = new[] { new { agentId = _agentConfig.AgentId, displayName = _agentConfig.DisplayName, model = _agentConfig.Model } } })); await LoadChatHistoryAsync(); } catch (Exception ex) { _logger.LogError(ex, "frm_chat WebView2 init failed"); } } private async void OnBridgeMessage(BridgeMessage msg) { if (InvokeRequired) { Invoke(() => OnBridgeMessage(msg)); return; } switch (msg.Type) { case BridgeTypes.UserMessage: if (msg.Content is not null) await HandleUserMessageAsync(msg.Content); break; case BridgeTypes.RunNow: await HandleUserMessageAsync("Führe deine zugewiesenen Aufgaben aus."); break; case BridgeTypes.AbortRun: _engine.AbortChat(_agentConfig.AgentId); break; } } private async Task HandleUserMessageAsync(string text) { if (_bridge is null) return; await _bridge.SendAsync(new BridgeMessage( Type: BridgeTypes.ChatMessage, AgentId: _agentConfig.AgentId, Content: text, Extra: new { role = "user", timestamp = DateTime.Now })); await _bridge.SendAsync(new BridgeMessage( Type: BridgeTypes.ChatTyping, AgentId: _agentConfig.AgentId)); _ = Task.Run(async () => { try { var result = await _engine.ChatAsync( _agentConfig, text, _instanceId, CancellationToken.None, source: ChatSource.WebView); await _bridge.SendAsync(new BridgeMessage( Type: BridgeTypes.ChatMessage, AgentId: _agentConfig.AgentId, Content: result.FinalMessage ?? "[Keine Antwort]", Extra: new { role = "assistant", timestamp = DateTime.Now })); } catch (Exception ex) { _logger.LogError(ex, "Chat failed"); await _bridge!.SendAsync(new BridgeMessage( Type: BridgeTypes.ChatMessage, AgentId: _agentConfig.AgentId, Content: $"[Fehler: {ex.Message}]", Extra: new { role = "assistant", timestamp = DateTime.Now })); } }); } private async Task LoadChatHistoryAsync() { if (_bridge is null) return; var history = _engine.GetChatHistory(_agentConfig.AgentId); await _bridge.SendAsync(new BridgeMessage( Type: BridgeTypes.ChatHistory, AgentId: _agentConfig.AgentId, Extra: history.Select(e => new { role = e.Role, content = e.Content, timestamp = e.Timestamp }).ToArray())); } protected override void OnFormClosed(FormClosedEventArgs e) { _bridge?.Dispose(); base.OnFormClosed(e); } }