feat(sdk): extract SmartHopper.ProviderSdk + cryptographic provider trust model#475
Open
devin-ai-integration[bot] wants to merge 4 commits into
Open
feat(sdk): extract SmartHopper.ProviderSdk + cryptographic provider trust model#475devin-ai-integration[bot] wants to merge 4 commits into
devin-ai-integration[bot] wants to merge 4 commits into
Conversation
…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.
Contributor
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Implements the full SmartHopper Provider SDK — Definitive Plan (phases 0 → 6) in one PR.
A standalone MIT-licensed
SmartHopper.ProviderSdkassembly is extracted fromSmartHopper.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 existingAIRuntimeMessagepipeline.Phase 0 — Host abstractions
Eight host-injected interfaces in
SmartHopper.ProviderSdk.Hosting/:IProviderTrustHost,IProviderRegistryHost,IPolicyPipelineHost,IContextProviderHost,IToolRegistryHost,IProviderSettingsStore,IProviderLogger,IProviderHttpClientFactory,IProviderDiagnostics. Static composition rootProviderSdkHostholds replaceable references with safe no-op defaults.AIProvider,AIRequestCall,AIRequestBase,SystemPromptBuilder, runtime-message helpers all consumeProviderSdkHost.*instead ofSmartHopperSettings.Instance,ProviderManager.Instance,PolicyPipeline.Default,AIContextManager, orAIToolManagerdirectly.Phase 0.5 — Per-provider AssemblyLoadContext + SDK type-identity validation
ProviderAssemblyLoaderloads provider DLLs into a dedicatedAssemblyLoadContextthat delegates shared assemblies (SmartHopper.ProviderSdk,SmartHopper.Infrastructure,Newtonsoft.Json,System.Drawing.Common) to the default ALC. Providers whoseIAIProviderFactorytype identity does not match the host's SDK are rejected with a clear diagnostic.Phase 1 — SDK extraction with
SmartHopper.ProviderSdk.*namespacessrc/SmartHopper.ProviderSdk/project (net7.0;net7.0-windows, strong-named, XML docs, source link, MIT).AICall/Core/{Base,Interactions,Requests,Returns},AICall/Metrics, minimalAICall/JsonSchemas,AICall/Batch/AIBatchTypes,AIModels/*(ModelManager consolidated intoAIModelCapabilityRegistry),Settings/*,Streaming/*,Utils/*, runtime-message types, metadata attributes.SmartHopper.Infrastructurenow referencesSmartHopper.ProviderSdk.Phase 2 — SemVer attributes + pre-activation compatibility check
SmartHopperProviderSdkVersionAttribute,BuiltAgainstSdkAttribute,MinHostSdkAttribute,SmartHopperProviderIdAttribute,SdkCompatibility.CheckenforceBuiltAgainstSdk.MAJOR == HostSdk.MAJORandHostSdk >= MinHostSdkat load. Mismatch ⇒Invalid.Phase 3 — Trust policy refactor
ProviderClassifierproducesOfficial | OfficialTampered | Community | Invalidfrom strong-name token + Authenticode (Windows) + SHA-256 manifest. File names and provider ids never affect classification.SmartHopperSettingsproperties:AllowCommunityProviders(defaultfalse),BlockNonOfficialProviders(defaultfalse).TrustedProviderRecordschema; legacy booleanTrustedProvidersentries migrated automatically on first load.SmartHopperProviderTrustHostadapter wiresProviderManager⇆ProviderSdkHost.ProviderTrustso SDK validation can reason about trust without depending on Infrastructure singletons.Phase 4 — Visible warnings
ProviderManagerexposesIsProviderCommunity,IsProviderUnsigned,GetProviderClassification,GetProviderTrustRecord.AIRequestCallvalidation 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
%AppData%/SmartHopper/Providersin addition to the app-local directory.Officialprovider are rejected.InitializeProviderAsyncruns under a 30-second per-provider timeout; a hanging or crashing provider does not affect discovery of other providers.Phase 6 — Docs, sample, CHANGELOG
SmartHopper.ProviderSdkonly — a template for community authors.[Unreleased]with Added/Changed/Removed/Security sections.Phase 4.3 — Provider IVTs removed
InternalsVisibleTo SmartHopper.Providers.*entries removed fromSmartHopper.Infrastructure.csproj. Built-in providers now compile against the public SDK surface only, just like community providers.Breaking Changes
SmartHopper.ProviderSdk.*namespaces. Allusing SmartHopper.Infrastructure.AICall.*,using SmartHopper.Infrastructure.AIProviders.*,using SmartHopper.Infrastructure.AIModels.*,using SmartHopper.Infrastructure.Settings.*(for descriptor types),using SmartHopper.Infrastructure.Streaming.*usingdirectives in external consumers must be updated toSmartHopper.ProviderSdk.*.TrustedProviderssetting migrated. LegacyDictionary<string,bool>entries are read once and re-encoded asTrustedProviderRecordentries. 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-partySmartHopper.Providers.*.dllfiles dropped into the app folder must opt in viaSmartHopperSettings.json(or settings dialog) to keep using them. This is a deliberate security gate.InternalsVisibleToremoved. Any out-of-tree provider that was relying onSmartHopper.Infrastructureinternals 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.Testsnot restored locally). These do not surface on Windows CI.dotnet build SmartHopper.Infrastructure.Tests -f net7.0 -c Debug— clean (0 errors).CI (Windows + macOS) will validate the full solution once this PR is opened.
Checklist
Link to Devin session: https://app.devin.ai/sessions/3459a4436b2644158a53428a956c9a32
Requested by: @marc-romu