Skip to content

fix(core): add macOS compatibility for provider loading and URL handling#382

Open
nofcfy-fanqi wants to merge 1 commit intoarchitects-toolkit:263-compatibility-with-macfrom
nofcfy-fanqi:fix/macos-compat
Open

fix(core): add macOS compatibility for provider loading and URL handling#382
nofcfy-fanqi wants to merge 1 commit intoarchitects-toolkit:263-compatibility-with-macfrom
nofcfy-fanqi:fix/macos-compat

Conversation

@nofcfy-fanqi
Copy link

@nofcfy-fanqi nofcfy-fanqi commented Feb 13, 2026

fix(core): add macOS compatibility for provider loading and URL handling

Description

SmartHopper currently does not work on macOS due to three platform-specific issues that cause crashes or incorrect behavior. This PR addresses all three issues to enable cross-platform compatibility.

Issue 1: VerifySignature crashes on macOS

ProviderManager.VerifySignature() calls X509Certificate.CreateFromSignedFile(), which is a Windows-only API. On macOS, this throws PlatformNotSupportedException, preventing any AI provider from loading.

Fix: Wrap the Authenticode verification block in a RuntimeInformation.IsOSPlatform(OSPlatform.Windows) guard. Strong-name verification (which is cross-platform) remains active on all platforms.

Issue 2: BuildFullUrl produces file:// URLs on macOS

AIProvider<T>.BuildFullUrl() uses Uri.TryCreate(endpoint, UriKind.Absolute, out var abs) to detect whether endpoint is already an absolute URL. On Windows, relative paths like /chat/completions return false from TryCreate with UriKind.Absolute. However, on macOS, the same call returns true and produces a file:///chat/completions URI, causing the base URL concatenation logic to be skipped entirely. This results in HTTP requests being sent to file:// URLs, which fail silently.

Fix: Add an additional scheme check: abs.Scheme == Uri.UriSchemeHttp || abs.Scheme == Uri.UriSchemeHttps. This ensures only actual HTTP/HTTPS URLs are treated as absolute, and relative paths like /chat/completions are correctly appended to the provider's base URL.

Issue 3: ComponentStateManager deadlock on macOS

ProcessTransitionQueue() fires state transition events (StateExited, StateEntered, TransitionCompleted) while holding stateLock. On macOS, Grasshopper's threading model can cause event handlers to re-enter methods that also acquire stateLock, leading to a deadlock. This manifests as the UI freezing when components attempt state transitions.

Fix: Refactor the transition logic to collect events inside the lock but fire them outside:

  • Extract event-firing logic from ExecuteTransition into a new ExecuteTransitionCore that returns transition info without firing events.
  • Collect all transition results in a list while holding the lock.
  • Release the lock via Monitor.Exit, fire all collected events, then re-acquire via Monitor.Enter.
  • Add a new FireTransitionEvents helper method for clarity.

Issue 4 (NOT FIXED): WebChatDialog crashes when opening Chat UI on macOS

WebChatDialog.LoadInitialHtmlIntoWebView() calls this._webView.LoadHtml(html, new Uri("https://smarthopper.local/")). On macOS, the Eto.Forms WKWebViewHandler.LoadHtml() implementation calls WKWebView.LoadFileUrl(baseNSUrl, baseNSUrl) for any non-null baseUri, but WKWebView.LoadFileUrl() only accepts file:// URLs. Passing https://smarthopper.local/ triggers an NSInvalidArgumentException: https://smarthopper.local/ is not a file URL, crashing Rhino.

This affects the CanvasButton chat window (the icon in the top-right corner of the Grasshopper canvas). The crash occurs when the WebView is first initialized.

Root cause: Eto.Forms macOS WKWebViewHandler.LoadHtml() (line 323-330 in the Eto source):

public void LoadHtml(string html, Uri baseUri)
{
    var baseNSUrl = baseUri.ToNS();
    if (baseNSUrl != null)
        Control.LoadFileUrl(baseNSUrl, baseNSUrl);  // BUG: only works with file:// URLs
    Control.LoadHtmlString(html, baseNSUrl);
}

Possible fix: In WebChatDialog.cs line 970, pass null as baseUri on non-Windows platforms (or pass a file:// temp directory URI). This would cause LoadHtmlString to use about:blank as the origin, which should be sufficient since JS-to-C# communication uses WKUserContentController.AddScriptMessageHandler() (not origin-dependent). However, this fix has not been tested yet and is NOT included in this PR.

Testing Done

  • Built the entire solution on macOS (Apple Silicon, .NET 9.0.304 SDK, targeting net7.0) with 0 errors.
  • Deployed all compiled assemblies to Grasshopper Libraries on macOS Rhino 8.27.
  • Verified AI provider loading succeeds (DeepSeek provider loaded and functional).
  • Tested AI chat interaction via Grasshopper Button → AiStatefulAsyncComponent pipeline, confirmed successful API responses and GhJSON output.
  • Verified that the BuildFullUrl fix correctly constructs URLs like https://api.deepseek.com/chat/completions instead of file:///chat/completions.
  • Known issue: The CanvasButton chat UI (WebChatDialog) still crashes on macOS due to an Eto.Forms WKWebView.LoadFileUrl() bug when passed an https:// base URI. This is documented as Issue 4 above but is NOT fixed in this PR.

Checklist

  • This PR is focused on a single feature or bug fix
  • Version in Solution.props was updated, if necessary, and follows semantic versioning
  • CHANGELOG.md has been updated
  • PR title follows Conventional Commits format
  • PR description follows Pull Request Description Template

@marc-romu marc-romu added this to the 1.4.0-alpha milestone Feb 13, 2026
@marc-romu marc-romu linked an issue Feb 13, 2026 that may be closed by this pull request
5 tasks
@marc-romu marc-romu changed the title fix(core): add macOS/Linux compatibility for provider loading and URL handling fix(core): add macOS compatibility for provider loading and URL handling Feb 13, 2026
@marc-romu
Copy link
Member

Hi @nofcfy-fanqi , I just updated the title and description to not mention Linux as a potential compatible environment since Rhino is not available for Linux. This will avoid confusion. I'll test your changes soon, but they look good!

@marc-romu marc-romu added the status: in progress Issue is currently being worked on label Feb 13, 2026
@marc-romu marc-romu self-assigned this Feb 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: in progress Issue is currently being worked on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compatibility with Mac

3 participants