Skip to content

feat(sdk): extract SmartHopper.ProviderSdk + cryptographic provider trust model#475

Open
devin-ai-integration[bot] wants to merge 4 commits into
feature/2.0.0-text2jsonfrom
devin/1778710261-provider-sdk
Open

feat(sdk): extract SmartHopper.ProviderSdk + cryptographic provider trust model#475
devin-ai-integration[bot] wants to merge 4 commits into
feature/2.0.0-text2jsonfrom
devin/1778710261-provider-sdk

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

Description

Implements the full SmartHopper Provider SDK — Definitive Plan (phases 0 → 6) in one PR.

A standalone MIT-licensed SmartHopper.ProviderSdk assembly is extracted from SmartHopper.Infrastructure. Community provider authors can now compile against the SDK NuGet on a clean machine without cloning SmartHopper. On the host side, provider classification becomes purely cryptographic (strong-name + Authenticode + SHA-256 manifest — never file name or provider id), and runtime warnings for non-official providers are surfaced through the existing AIRuntimeMessage pipeline.

Phase 0 — Host abstractions

Eight host-injected interfaces in SmartHopper.ProviderSdk.Hosting/: IProviderTrustHost, IProviderRegistryHost, IPolicyPipelineHost, IContextProviderHost, IToolRegistryHost, IProviderSettingsStore, IProviderLogger, IProviderHttpClientFactory, IProviderDiagnostics. Static composition root ProviderSdkHost holds replaceable references with safe no-op defaults. AIProvider, AIRequestCall, AIRequestBase, SystemPromptBuilder, runtime-message helpers all consume ProviderSdkHost.* instead of SmartHopperSettings.Instance, ProviderManager.Instance, PolicyPipeline.Default, AIContextManager, or AIToolManager directly.

Phase 0.5 — Per-provider AssemblyLoadContext + SDK type-identity validation

ProviderAssemblyLoader loads provider DLLs into a dedicated AssemblyLoadContext that delegates shared assemblies (SmartHopper.ProviderSdk, SmartHopper.Infrastructure, Newtonsoft.Json, System.Drawing.Common) to the default ALC. Providers whose IAIProviderFactory type identity does not match the host's SDK are rejected with a clear diagnostic.

Phase 1 — SDK extraction with SmartHopper.ProviderSdk.* namespaces

  • New src/SmartHopper.ProviderSdk/ project (net7.0;net7.0-windows, strong-named, XML docs, source link, MIT).
  • All provider-facing types moved with new namespaces: contracts, base classes, AICall/Core/{Base,Interactions,Requests,Returns}, AICall/Metrics, minimal AICall/JsonSchemas, AICall/Batch/AIBatchTypes, AIModels/* (ModelManager consolidated into AIModelCapabilityRegistry), Settings/*, Streaming/*, Utils/*, runtime-message types, metadata attributes.
  • SmartHopper.Infrastructure now references SmartHopper.ProviderSdk.
  • All 6 in-tree providers (Anthropic, DeepSeek, Gemini, MistralAI, OpenAI, OpenRouter) migrated to SDK-only references.

Phase 2 — SemVer attributes + pre-activation compatibility check

SmartHopperProviderSdkVersionAttribute, BuiltAgainstSdkAttribute, MinHostSdkAttribute, SmartHopperProviderIdAttribute, SdkCompatibility.Check enforce BuiltAgainstSdk.MAJOR == HostSdk.MAJOR and HostSdk >= MinHostSdk at load. Mismatch ⇒ Invalid.

Phase 3 — Trust policy refactor

  • ProviderClassifier produces Official | OfficialTampered | Community | Invalid from strong-name token + Authenticode (Windows) + SHA-256 manifest. File names and provider ids never affect classification.
  • New SmartHopperSettings properties: AllowCommunityProviders (default false), BlockNonOfficialProviders (default false).
  • New structured TrustedProviderRecord schema; legacy boolean TrustedProviders entries migrated automatically on first load.
  • SmartHopperProviderTrustHost adapter wires ProviderManagerProviderSdkHost.ProviderTrust so SDK validation can reason about trust without depending on Infrastructure singletons.

Phase 4 — Visible warnings

ProviderManager exposes IsProviderCommunity, IsProviderUnsigned, GetProviderClassification, GetProviderTrustRecord. AIRequestCall validation now emits runtime warning messages for community/unsigned providers in addition to the existing mismatched/unavailable/unknown warnings — these appear on every AI component using the affected provider.

Phase 5 — User-local discovery, duplicate id resolution, init isolation

  • Discovery scans %AppData%/SmartHopper/Providers in addition to the app-local directory.
  • Duplicate provider ids: subsequent registrations of an id already held by an Official provider are rejected.
  • InitializeProviderAsync runs under a 30-second per-provider timeout; a hanging or crashing provider does not affect discovery of other providers.

Phase 6 — Docs, sample, CHANGELOG

Phase 4.3 — Provider IVTs removed

InternalsVisibleTo SmartHopper.Providers.* entries removed from SmartHopper.Infrastructure.csproj. Built-in providers now compile against the public SDK surface only, just like community providers.

Breaking Changes

  • Provider-facing types moved to SmartHopper.ProviderSdk.* namespaces. All using SmartHopper.Infrastructure.AICall.*, using SmartHopper.Infrastructure.AIProviders.*, using SmartHopper.Infrastructure.AIModels.*, using SmartHopper.Infrastructure.Settings.* (for descriptor types), using SmartHopper.Infrastructure.Streaming.* using directives in external consumers must be updated to SmartHopper.ProviderSdk.*.
  • TrustedProviders setting migrated. Legacy Dictionary<string,bool> entries are read once and re-encoded as TrustedProviderRecord entries. Existing user trust decisions are preserved; classification is filled in on next discovery.
  • AllowCommunityProviders=false (default) blocks community providers from loading. Users currently relying on third-party SmartHopper.Providers.*.dll files dropped into the app folder must opt in via SmartHopperSettings.json (or settings dialog) to keep using them. This is a deliberate security gate.
  • Provider InternalsVisibleTo removed. Any out-of-tree provider that was relying on SmartHopper.Infrastructure internals will fail to compile until it switches to the SDK public surface.

Testing Done

  • dotnet build SmartHopper.Infrastructure -f net7.0 -c Debug — clean (0 errors, 0 warnings on the post-Phase-6 tree).
  • dotnet build SmartHopper.sln -f net7.0 -c Debug /p:SignAssembly=true — all remaining errors are pre-existing environment issues (RhinoCodePlatform/IScriptComponent Rhino DLLs not resolvable on Linux; SmartHopper.Core.Grasshopper.Tests not restored locally). These do not surface on Windows CI.
  • dotnet build SmartHopper.Infrastructure.Tests -f net7.0 -c Debug — clean (0 errors).
  • Manual review of every file in the touched namespaces for correctness of the namespace migration, SDK API surface boundaries, and IVT removal.

CI (Windows + macOS) will validate the full solution once this PR is opened.

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

Link to Devin session: https://app.devin.ai/sessions/3459a4436b2644158a53428a956c9a32
Requested by: @marc-romu

…tractions

Phase 0+1 of the SmartHopper Provider SDK plan:

- Create new SmartHopper.ProviderSdk project (MIT-licensed) carrying the
  provider-facing types: contracts (IAIProvider, IAIProviderFactory,
  IAIProviderSettings, IAIProviderModels), base classes (AIProvider,
  AIProviderSettings, AIProviderModels, AIProviderStreamingAdapter),
  AICall/Core/{Base,Interactions,Requests,Returns}, AICall/Metrics,
  minimal AICall/JsonSchemas, AICall/Batch/AIBatchTypes, AIModels/*,
  Settings/*, Streaming/*, Utils/* and diagnostics/runtime-message types.
- Introduce Hosting abstraction layer so SDK code never directly touches
  host singletons:
  - IProviderTrustHost, IProviderRegistryHost, IPolicyPipelineHost,
    IContextProviderHost, IToolRegistryHost (with ProviderToolDefinition),
    IProviderSettingsStore (+ InMemoryProviderSettingsStore),
    IProviderLogger (+ DebugProviderLogger),
    IProviderHttpClientFactory (+ DefaultProviderHttpClientFactory),
    IProviderDiagnostics (+ NullProviderDiagnostics).
  - Static composition root ProviderSdkHost holds replaceable references;
    every interface ships a safe no-op default so the SDK runs standalone.
- Move ProviderIntegrityCheckMode into the SDK so DTOs can reference it.
- Consolidate model registry: AIModelCapabilityRegistry singleton in SDK
  replaces the host-side ModelManager.
- Rewire AIProvider, AIProviderSettings, AIRequestCall, AIRequestBase,
  SystemPromptBuilder, RuntimeMessageUtility, ToolCallResultRuntimeMessage
  extensions to go through ProviderSdkHost.* abstractions instead of
  SmartHopperSettings.Instance / ProviderManager.Instance /
  PolicyPipeline.Default / AIContextManager / AIToolManager.
- Update SmartHopper.Infrastructure to ProjectReference the SDK, drop the
  Core/{Base,Interactions,Requests,Returns}, Metrics, AIModels,
  Diagnostics, JsonSchemas, Streaming, Utilities, Utils folders, and add
  the necessary using SmartHopper.ProviderSdk.* directives back into
  ProviderManager, ProviderHashVerifier, SmartHopperSettings, SettingsDialog,
  ProvidersSettingsPage.
- Update all six official providers (Anthropic, DeepSeek, Gemini,
  MistralAI, OpenAI, OpenRouter) and the test components to reference
  the new SmartHopper.ProviderSdk namespaces; consolidate duplicate
  using directives and alphabetise them via tools/scripts.
- Promote SmartHopper.Infrastructure.Dialogs.StyledMessageDialog to
  public so providers (which no longer have InternalsVisibleTo to
  Infrastructure once Phase 4.3 lands) can still surface validation
  errors during settings configuration.
- ModelManagerTests now exercise the SDK-side singleton.

Builds clean: SmartHopper.ProviderSdk, SmartHopper.Infrastructure and
all six official providers compile against the SDK-only API surface
under net7.0 with strong-name signing enabled.
…ettings, user-local discovery

Phase 0.5: ProviderAssemblyLoader with per-provider AssemblyLoadContext that
delegates SDK/Infrastructure/Newtonsoft.Json/System.Drawing.Common to the
default ALC and rejects providers whose IAIProviderFactory type identity does
not match the host. Initialization is wrapped in a 30s timeout.

Phase 2: SmartHopperProviderSdkVersionAttribute, BuiltAgainstSdkAttribute,
MinHostSdkAttribute, SmartHopperProviderIdAttribute + SdkCompatibility.Check
to enforce SemVer MAJOR match and HostSdk >= MinHostSdk at load time.

Phase 3: ProviderClassifier (cryptographic, name-blind) + ProviderClassification
{Official, OfficialTampered, Community, Invalid}. AllowCommunityProviders /
BlockNonOfficialProviders settings. TrustedProviderRecord schema + migration
from legacy bool dict. SmartHopperProviderTrustHost adapter wires ProviderManager
into ProviderSdkHost.ProviderTrust.

Phase 4 (partial): Visible warning APIs on ProviderManager (IsProviderCommunity,
IsProviderUnsigned, GetProviderClassification, GetProviderTrustRecord) +
AIRequestCall runtime messages for community/unsigned providers.

Phase 5: User-local provider directory (%AppData%/SmartHopper/Providers) scanned
in addition to app-local. Duplicate provider id resolution rejects subsequent
registrations of an id already held by an Official provider.

Phase 4.3: Provider InternalsVisibleTo entries removed from
SmartHopper.Infrastructure.csproj. Providers now compile against the public SDK
surface only.

Build verified on Linux for SmartHopper.Infrastructure (clean) and the rest of
the solution (all remaining errors are pre-existing RhinoCodePlatform/IScriptComponent
issues that resolve on Windows). Bug fix in csproj: missing ProjectReference to
SmartHopper.ProviderSdk added.
- docs/Providers/ProviderSdk.md: new community-facing reference covering
  SDK contents/exclusions, target frameworks, license (MIT), naming convention,
  minimal provider skeleton, SemVer / compat rules, trust model.
- docs/Providers/index.md: link the new SDK doc; replace the old
  'Authenticode/strong-name must match host' Security paragraph with the
  new cryptographic classification + trust gates model.
- docs/Providers/ProviderManager.md: rewrite the Key features section to
  document discovery, classification, trust settings, duplicate id rules,
  init timeout, and new accessor APIs.
- CHANGELOG.md [Unreleased]: Added/Changed/Removed/Security sections covering
  the SDK package, host abstractions, ALC, SemVer attributes, classifier,
  trust settings + schema migration, warning APIs, runtime messages,
  user-local discovery, init isolation, and IVT removal.
- samples/SmartHopper.Providers.Sample/: starter csproj + README that builds
  against SmartHopper.ProviderSdk only (no host references) so community
  authors have a working template.
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant