mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-11-04 02:40:20 +00:00 
			
		
		
		
	Show LLM provider issues to the user (#384)
	
		
			
	
		
	
	
		
	
		
			Some checks are pending
		
		
	
	
		
			
				
	
				Build and Release / Read metadata (push) Waiting to run
				
			
		
			
				
	
				Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Blocked by required conditions
				
			
		
			
				
	
				Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Blocked by required conditions
				
			
		
			
				
	
				Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Blocked by required conditions
				
			
		
			
				
	
				Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis updater) (push) Blocked by required conditions
				
			
		
			
				
	
				Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage deb updater) (push) Blocked by required conditions
				
			
		
			
				
	
				Build and Release / Build app (linux-arm64) (push) Blocked by required conditions
				
			
		
			
				
	
				Build and Release / Prepare & create release (push) Blocked by required conditions
				
			
		
			
				
	
				Build and Release / Publish release (push) Blocked by required conditions
				
			
		
		
	
	
				
					
				
			
		
			Some checks are pending
		
		
	
	Build and Release / Read metadata (push) Waiting to run
				
			Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Blocked by required conditions
				
			Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Blocked by required conditions
				
			Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Blocked by required conditions
				
			Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis updater) (push) Blocked by required conditions
				
			Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage deb updater) (push) Blocked by required conditions
				
			Build and Release / Build app (linux-arm64) (push) Blocked by required conditions
				
			Build and Release / Prepare & create release (push) Blocked by required conditions
				
			Build and Release / Publish release (push) Blocked by required conditions
				
			This commit is contained in:
		
							parent
							
								
									c56232cba7
								
							
						
					
					
						commit
						f97612de0e
					
				@ -107,7 +107,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        // Register this component with the message bus:
 | 
					        // Register this component with the message bus:
 | 
				
			||||||
        this.MessageBus.RegisterComponent(this);
 | 
					        this.MessageBus.RegisterComponent(this);
 | 
				
			||||||
        this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE, Event.CONFIGURATION_CHANGED, Event.COLOR_THEME_CHANGED ]);
 | 
					        this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE, Event.CONFIGURATION_CHANGED, Event.COLOR_THEME_CHANGED, Event.SHOW_ERROR ]);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // Set the snackbar for the update service:
 | 
					        // Set the snackbar for the update service:
 | 
				
			||||||
        UpdateService.SetBlazorDependencies(this.Snackbar);
 | 
					        UpdateService.SetBlazorDependencies(this.Snackbar);
 | 
				
			||||||
@ -170,6 +170,12 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis
 | 
				
			|||||||
            case Event.COLOR_THEME_CHANGED:
 | 
					            case Event.COLOR_THEME_CHANGED:
 | 
				
			||||||
                this.StateHasChanged();
 | 
					                this.StateHasChanged();
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            case Event.SHOW_ERROR:
 | 
				
			||||||
 | 
					                if (data is Error error)
 | 
				
			||||||
 | 
					                    error.Show(this.Snackbar);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -117,8 +117,49 @@ public abstract class BaseProvider : IProvider, ISecretId
 | 
				
			|||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (nextResponse.StatusCode is HttpStatusCode.Forbidden)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Block, $"Tried to communicate with the LLM provider '{this.InstanceName}'. You might not be able to use this provider from your location. The provider message is: '{nextResponse.ReasonPhrase}'"));
 | 
				
			||||||
 | 
					                this.logger.LogError($"Failed request with status code {nextResponse.StatusCode} (message = '{nextResponse.ReasonPhrase}').");
 | 
				
			||||||
 | 
					                errorMessage = nextResponse.ReasonPhrase;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            if(nextResponse.StatusCode is HttpStatusCode.BadRequest)
 | 
					            if(nextResponse.StatusCode is HttpStatusCode.BadRequest)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, $"Tried to communicate with the LLM provider '{this.InstanceName}'. The required message format might be changed. The provider message is: '{nextResponse.ReasonPhrase}'"));
 | 
				
			||||||
 | 
					                this.logger.LogError($"Failed request with status code {nextResponse.StatusCode} (message = '{nextResponse.ReasonPhrase}').");
 | 
				
			||||||
 | 
					                errorMessage = nextResponse.ReasonPhrase;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if(nextResponse.StatusCode is HttpStatusCode.NotFound)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, $"Tried to communicate with the LLM provider '{this.InstanceName}'. Something was not found. The provider message is: '{nextResponse.ReasonPhrase}'"));
 | 
				
			||||||
 | 
					                this.logger.LogError($"Failed request with status code {nextResponse.StatusCode} (message = '{nextResponse.ReasonPhrase}').");
 | 
				
			||||||
 | 
					                errorMessage = nextResponse.ReasonPhrase;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if(nextResponse.StatusCode is HttpStatusCode.Unauthorized)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Key, $"Tried to communicate with the LLM provider '{this.InstanceName}'. The API key might be invalid. The provider message is: '{nextResponse.ReasonPhrase}'"));
 | 
				
			||||||
 | 
					                this.logger.LogError($"Failed request with status code {nextResponse.StatusCode} (message = '{nextResponse.ReasonPhrase}').");
 | 
				
			||||||
 | 
					                errorMessage = nextResponse.ReasonPhrase;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if(nextResponse.StatusCode is HttpStatusCode.InternalServerError)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, $"Tried to communicate with the LLM provider '{this.InstanceName}'. The server might be down or having issues. The provider message is: '{nextResponse.ReasonPhrase}'"));
 | 
				
			||||||
 | 
					                this.logger.LogError($"Failed request with status code {nextResponse.StatusCode} (message = '{nextResponse.ReasonPhrase}').");
 | 
				
			||||||
 | 
					                errorMessage = nextResponse.ReasonPhrase;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if(nextResponse.StatusCode is HttpStatusCode.ServiceUnavailable)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, $"Tried to communicate with the LLM provider '{this.InstanceName}'. The provider is overloaded. The message is: '{nextResponse.ReasonPhrase}'"));
 | 
				
			||||||
                this.logger.LogError($"Failed request with status code {nextResponse.StatusCode} (message = '{nextResponse.ReasonPhrase}').");
 | 
					                this.logger.LogError($"Failed request with status code {nextResponse.StatusCode} (message = '{nextResponse.ReasonPhrase}').");
 | 
				
			||||||
                errorMessage = nextResponse.ReasonPhrase;
 | 
					                errorMessage = nextResponse.ReasonPhrase;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@ -134,7 +175,10 @@ public abstract class BaseProvider : IProvider, ISecretId
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        if(retry >= MAX_RETRIES || !string.IsNullOrWhiteSpace(errorMessage))
 | 
					        if(retry >= MAX_RETRIES || !string.IsNullOrWhiteSpace(errorMessage))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, $"Tried to communicate with the LLM provider '{this.InstanceName}'. Even after {MAX_RETRIES} retries, there were some problems with the request. The provider message is: '{errorMessage}'"));
 | 
				
			||||||
            return new HttpRateLimitedStreamResult(false, true, errorMessage ?? $"Failed after {MAX_RETRIES} retries; no provider message available", response);
 | 
					            return new HttpRateLimitedStreamResult(false, true, errorMessage ?? $"Failed after {MAX_RETRIES} retries; no provider message available", response);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return new HttpRateLimitedStreamResult(true, false, string.Empty, response);
 | 
					        return new HttpRateLimitedStreamResult(true, false, string.Empty, response);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -160,6 +204,7 @@ public abstract class BaseProvider : IProvider, ISecretId
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        catch(Exception e)
 | 
					        catch(Exception e)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, $"Tried to communicate with the LLM provider '{this.InstanceName}'. There were some problems with the request. The provider message is: '{e.Message}'"));
 | 
				
			||||||
            this.logger.LogError($"Failed to stream chat completion from {providerName} '{this.InstanceName}': {e.Message}");
 | 
					            this.logger.LogError($"Failed to stream chat completion from {providerName} '{this.InstanceName}': {e.Message}");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -176,6 +221,7 @@ public abstract class BaseProvider : IProvider, ISecretId
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception e)
 | 
					            catch (Exception e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, $"Tried to stream the LLM provider '{this.InstanceName}' answer. There were some problems with the stream. The message is: '{e.Message}'"));
 | 
				
			||||||
                this.logger.LogWarning($"Failed to read the end-of-stream state from {providerName} '{this.InstanceName}': {e.Message}");
 | 
					                this.logger.LogWarning($"Failed to read the end-of-stream state from {providerName} '{this.InstanceName}': {e.Message}");
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -196,6 +242,7 @@ public abstract class BaseProvider : IProvider, ISecretId
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception e)
 | 
					            catch (Exception e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, $"Tried to stream the LLM provider '{this.InstanceName}' answer. Was not able to read the stream. The message is: '{e.Message}'"));
 | 
				
			||||||
                this.logger.LogError($"Failed to read the stream from {providerName} '{this.InstanceName}': {e.Message}");
 | 
					                this.logger.LogError($"Failed to read the stream from {providerName} '{this.InstanceName}': {e.Message}");
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								app/MindWork AI Studio/Tools/Error.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/MindWork AI Studio/Tools/Error.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					namespace AIStudio.Tools;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public readonly record struct Error(string Icon, string Message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public void Show(ISnackbar snackbar)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var icon = this.Icon;
 | 
				
			||||||
 | 
					        snackbar.Add(this.Message, Severity.Error, config =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config.Icon = icon;
 | 
				
			||||||
 | 
					            config.IconSize = Size.Large;
 | 
				
			||||||
 | 
					            config.HideTransitionDuration = 600;
 | 
				
			||||||
 | 
					            config.VisibleStateDuration = 14_000;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -9,6 +9,7 @@ public enum Event
 | 
				
			|||||||
    CONFIGURATION_CHANGED,
 | 
					    CONFIGURATION_CHANGED,
 | 
				
			||||||
    COLOR_THEME_CHANGED,
 | 
					    COLOR_THEME_CHANGED,
 | 
				
			||||||
    PLUGINS_RELOADED,
 | 
					    PLUGINS_RELOADED,
 | 
				
			||||||
 | 
					    SHOW_ERROR,
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Update events:
 | 
					    // Update events:
 | 
				
			||||||
    USER_SEARCH_FOR_UPDATE,
 | 
					    USER_SEARCH_FOR_UPDATE,
 | 
				
			||||||
 | 
				
			|||||||
@ -66,6 +66,8 @@ public sealed class MessageBus
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Task SendError(Error error) => this.SendMessage(null, Event.SHOW_ERROR, error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void DeferMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data = default)
 | 
					    public void DeferMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (this.deferredMessages.TryGetValue(triggeredEvent, out var queue))
 | 
					        if (this.deferredMessages.TryGetValue(triggeredEvent, out var queue))
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
# v0.9.39, build 214 (2025-04-xx xx:xx UTC)
 | 
					# v0.9.39, build 214 (2025-04-xx xx:xx UTC)
 | 
				
			||||||
 | 
					- Added UI for error handling to display any LLM provider issues.
 | 
				
			||||||
- Added a feature flag for the plugin system. This flag is disabled by default and can be enabled inside the app settings. Please note that this feature is still in development; there are no plugins available yet.
 | 
					- Added a feature flag for the plugin system. This flag is disabled by default and can be enabled inside the app settings. Please note that this feature is still in development; there are no plugins available yet.
 | 
				
			||||||
- Added the Lua library we use for the plugin system to the about page.
 | 
					- Added the Lua library we use for the plugin system to the about page.
 | 
				
			||||||
- Added the plugin overview page. This page shows all installed plugins and allows you to enable or disable them. It is only available when the plugin preview feature is enabled.
 | 
					- Added the plugin overview page. This page shows all installed plugins and allows you to enable or disable them. It is only available when the plugin preview feature is enabled.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user