Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR expands SharpClaw’s “control-plane” surface area by making session/workspace preferences, provider auth, scheduling, research mode, and guided evolution durable and host-aware, while also laying groundwork for multimodal (image) prompt references.
Changes:
- Adds durable scheduled prompts + runner/service layer, backed by SQLite or workspace-local JSON.
- Adds durable session preferences (trust, approvals, permission mode, model selection) and guided evolution proposal storage + apply/reject flows.
- Introduces research mode and multimodal prompt reference support (directory/image references + structured content blocks), plus user-scoped provider credential storage.
Reviewed changes
Copilot reviewed 79 out of 79 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/SharpClaw.Code.Sessions/Storage/SqliteSessionStoreDatabase.cs | Adds SQLite tables/indexes for schedules/evolution. |
| src/SharpClaw.Code.Sessions/Storage/SqliteScheduledPromptStore.cs | SQLite scheduled prompt persistence. |
| src/SharpClaw.Code.Sessions/Storage/SqliteEvolutionProposalStore.cs | SQLite evolution proposal persistence. |
| src/SharpClaw.Code.Sessions/Storage/HostAwareScheduledPromptStore.cs | Host-aware store selection (file vs SQLite). |
| src/SharpClaw.Code.Sessions/Storage/HostAwareEvolutionProposalStore.cs | Host-aware evolution store selection. |
| src/SharpClaw.Code.Sessions/Storage/FileScheduledPromptStore.cs | File-backed scheduled prompt persistence. |
| src/SharpClaw.Code.Sessions/Storage/FileEvolutionProposalStore.cs | File-backed evolution proposal persistence. |
| src/SharpClaw.Code.Sessions/Abstractions/IScheduledPromptStore.cs | Scheduled prompt store abstraction. |
| src/SharpClaw.Code.Sessions/Abstractions/IEvolutionProposalStore.cs | Evolution proposal store abstraction. |
| src/SharpClaw.Code.Runtime/Workflow/WorkspaceBootstrapService.cs | Workspace init scaffolding for .sharpclaw. |
| src/SharpClaw.Code.Runtime/Workflow/SessionPreferenceService.cs | Durable session preference management. |
| src/SharpClaw.Code.Runtime/Workflow/ScheduledPromptService.cs | Schedule lifecycle + execution orchestration. |
| src/SharpClaw.Code.Runtime/Workflow/ScheduledPromptRunner.cs | Hosted service polling due schedules. |
| src/SharpClaw.Code.Runtime/Workflow/ScheduleCronExpression.cs | Minimal cron parsing/next-run calculation. |
| src/SharpClaw.Code.Runtime/Workflow/ResearchWorkflowService.cs | Research-mode prompt execution flow. |
| src/SharpClaw.Code.Runtime/Workflow/EvolutionProposalService.cs | Proposal analysis/apply/reject workflows. |
| src/SharpClaw.Code.Runtime/Turns/DefaultTurnRunner.cs | Plumbs structured user content into turns. |
| src/SharpClaw.Code.Runtime/Prompts/PromptReferenceResolver.cs | Adds directory/image refs + structured content. |
| src/SharpClaw.Code.Runtime/Context/PromptExecutionContext.cs | Adds UserContent for structured blocks. |
| src/SharpClaw.Code.Runtime/Context/PromptContextAssembler.cs | Builds durable metadata + research prompt + user blocks. |
| src/SharpClaw.Code.Runtime/Configuration/SharpClawConfigService.cs | Moves workspace config to .sharpclaw/config.jsonc (with legacy fallback). |
| src/SharpClaw.Code.Runtime/Composition/RuntimeServiceCollectionExtensions.cs | Registers new workflow/services + hosted runner. |
| src/SharpClaw.Code.Runtime/Abstractions/IWorkspaceBootstrapService.cs | Abstraction for workspace initialization. |
| src/SharpClaw.Code.Runtime/Abstractions/ISessionPreferenceService.cs | Abstraction for durable session preferences. |
| src/SharpClaw.Code.Runtime/Abstractions/IScheduledPromptService.cs | Abstraction for schedule management/execution. |
| src/SharpClaw.Code.Runtime/Abstractions/IResearchWorkflowService.cs | Abstraction for research-mode prompts. |
| src/SharpClaw.Code.Runtime/Abstractions/IEvolutionProposalService.cs | Abstraction for evolution proposal workflows. |
| src/SharpClaw.Code.Providers/Services/ProviderCredentialStore.cs | User-scoped provider credential storage. |
| src/SharpClaw.Code.Providers/Services/ProviderCatalogService.cs | Exposes image-input capability in catalog. |
| src/SharpClaw.Code.Providers/ProvidersServiceCollectionExtensions.cs | Registers provider credential store. |
| src/SharpClaw.Code.Providers/OpenAiCompatibleProvider.cs | Resolves credentials + image-input capability. |
| src/SharpClaw.Code.Providers/Models/ProviderCredentialModels.cs | Models for stored/resolved provider creds. |
| src/SharpClaw.Code.Providers/Internal/ProviderAuthStatusFactory.cs | Enriches auth status with source/details. |
| src/SharpClaw.Code.Providers/Internal/OpenAiMessageBuilder.cs | Maps image content blocks to MEAI content. |
| src/SharpClaw.Code.Providers/Internal/AnthropicMessageBuilder.cs | Maps image blocks to Anthropic SDK types. |
| src/SharpClaw.Code.Providers/Configuration/OpenAiCompatibleProviderOptions.cs | Adds SupportsImageInput option. |
| src/SharpClaw.Code.Providers/Configuration/AnthropicProviderOptions.cs | Adds SupportsImageInput option. |
| src/SharpClaw.Code.Providers/AnthropicProvider.cs | Resolves credentials + image-input capability. |
| src/SharpClaw.Code.Providers/Abstractions/IProviderCredentialStore.cs | Credential store abstraction. |
| src/SharpClaw.Code.Providers/Abstractions/IModelProvider.cs | Adds SupportsImageInput requirement. |
| src/SharpClaw.Code.Protocol/Serialization/ProtocolJsonContext.cs | Adds source-gen types for new protocol models. |
| src/SharpClaw.Code.Protocol/Models/SharpClawWorkflowMetadataKeys.cs | Adds metadata keys for preferences/trust/model. |
| src/SharpClaw.Code.Protocol/Models/ProviderRequest.cs | Adds ContainsImageInput marker. |
| src/SharpClaw.Code.Protocol/Models/PromptReferences.cs | Adds directory/image reference kinds + metadata. |
| src/SharpClaw.Code.Protocol/Models/OpenCodeParityModels.cs | Adds provider catalog SupportsImageInput. |
| src/SharpClaw.Code.Protocol/Models/ContentBlock.cs | Adds Image block kind + media/data/uri. |
| src/SharpClaw.Code.Protocol/Models/AuthStatus.cs | Adds auth source/detail/local-runtime flags. |
| src/SharpClaw.Code.Protocol/Models/AdaLGapModels.cs | Adds trust/schedule/evolution/research models. |
| src/SharpClaw.Code.Protocol/Enums/PrimaryMode.cs | Adds Research mode. |
| src/SharpClaw.Code.Protocol/Commands/RunPromptRequest.cs | Adds structured UserContent support. |
| src/SharpClaw.Code.Permissions/Rules/PrimaryModeMutationRule.cs | Treats research as read-only for mutations. |
| src/SharpClaw.Code.Infrastructure/Services/RuntimeStoragePathResolver.cs | Adds scheduled/evolution JSON + lock paths. |
| src/SharpClaw.Code.Infrastructure/Services/PlatformSecretProtector.cs | Adds DPAPI-backed secret protection (Windows). |
| src/SharpClaw.Code.Infrastructure/InfrastructureServiceCollectionExtensions.cs | Registers secret protector. |
| src/SharpClaw.Code.Infrastructure/Abstractions/ISecretProtector.cs | Secret protection abstraction. |
| src/SharpClaw.Code.Infrastructure/Abstractions/IRuntimeStoragePathResolver.cs | Adds scheduled/evolution path APIs. |
| src/SharpClaw.Code.Commands/Repl/ReplInteractionState.cs | Adds permission override + clear helper. |
| src/SharpClaw.Code.Commands/Repl/ReplHost.cs | Threads permission override into runtime context. |
| src/SharpClaw.Code.Commands/Options/GlobalCliOptions.cs | Adds research mode to CLI option parsing. |
| src/SharpClaw.Code.Commands/Models/CommandExecutionContext.cs | Adds permission override parameter plumbing. |
| src/SharpClaw.Code.Commands/Handlers/ScheduleCommandHandler.cs | Adds schedule command + slash surface. |
| src/SharpClaw.Code.Commands/Handlers/ResumeSlashCommandHandler.cs | Adds /resume alias + clears overrides. |
| src/SharpClaw.Code.Commands/Handlers/ResearchCommandHandler.cs | Adds research command + slash surface. |
| src/SharpClaw.Code.Commands/Handlers/PermissionsCommandHandler.cs | Adds durable permissions/trust/approvals CLI. |
| src/SharpClaw.Code.Commands/Handlers/NewSessionSlashCommandHandler.cs | Adds /new session creation helper. |
| src/SharpClaw.Code.Commands/Handlers/ModeSlashCommandHandler.cs | Adds research mode to REPL mode switch. |
| src/SharpClaw.Code.Commands/Handlers/ModelSlashCommandHandler.cs | Adds /model alias for models commands. |
| src/SharpClaw.Code.Commands/Handlers/ModelsCommandHandler.cs | Adds show/use/clear model preference commands. |
| src/SharpClaw.Code.Commands/Handlers/InitCommandHandler.cs | Adds workspace init command + slash surface. |
| src/SharpClaw.Code.Commands/Handlers/EvolutionCommandHandler.cs | Adds evolution analyze/apply/reject commands. |
| src/SharpClaw.Code.Commands/Handlers/ClearSlashCommandHandler.cs | Adds /clear to reset overrides + screen. |
| src/SharpClaw.Code.Commands/Handlers/AuthCommandHandler.cs | Adds auth status + credential management commands. |
| src/SharpClaw.Code.Commands/Handlers/ApprovalsSlashCommandHandler.cs | Redirects approvals alias to durable permissions surface. |
| src/SharpClaw.Code.Commands/Abstractions/IReplTerminal.cs | Adds ClearScreen() API. |
| src/SharpClaw.Code.Cli/Terminal/SpectreReplTerminal.cs | Implements screen clearing via Spectre. |
| src/SharpClaw.Code.Cli/Composition/CliServiceCollectionExtensions.cs | Registers new commands/slash handlers. |
| src/SharpClaw.Code.Agents/Services/AgentFrameworkBridge.cs | Plumbs trust + permission preference into tools. |
| src/SharpClaw.Code.Agents/Models/AgentRunContext.cs | Adds structured UserContent to run context. |
| src/SharpClaw.Code.Agents/Internal/ProviderBackedAgentKernel.cs | Enforces image support + sends structured content. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1
to
+16
| namespace SharpClaw.Code.Providers.Abstractions; | ||
|
|
||
| /// <summary> | ||
| /// Resolves and persists user-scoped provider credentials without writing plaintext workspace state. | ||
| /// </summary> | ||
| public interface IProviderCredentialStore | ||
| { | ||
| /// <summary> | ||
| /// Resolves the effective API key for a provider, if available. | ||
| /// </summary> | ||
| Task<ResolvedProviderCredential> ResolveAsync(string providerName, CancellationToken cancellationToken); | ||
|
|
||
| /// <summary> | ||
| /// Lists stored credential descriptors without exposing secret material. | ||
| /// </summary> | ||
| Task<IReadOnlyList<ProviderCredentialDescriptor>> ListAsync(CancellationToken cancellationToken); |
Comment on lines
9
to
+20
| public interface IModelProvider | ||
| { | ||
| /// <summary> | ||
| /// Gets the provider name used for resolution. | ||
| /// </summary> | ||
| string ProviderName { get; } | ||
|
|
||
| /// <summary> | ||
| /// Gets whether the provider accepts structured image input. | ||
| /// </summary> | ||
| bool SupportsImageInput { get; } | ||
|
|
Comment on lines
+110
to
+121
| private async Task<StoredCredentialDocument> LoadAsync(CancellationToken cancellationToken) | ||
| { | ||
| var path = GetPath(); | ||
| var text = await fileSystem.ReadAllTextIfExistsAsync(path, cancellationToken).ConfigureAwait(false); | ||
| if (string.IsNullOrWhiteSpace(text)) | ||
| { | ||
| return new StoredCredentialDocument(new Dictionary<string, StoredCredentialEntry>(StringComparer.OrdinalIgnoreCase)); | ||
| } | ||
|
|
||
| return JsonSerializer.Deserialize<StoredCredentialDocument>(text, JsonOptions) | ||
| ?? new StoredCredentialDocument(new Dictionary<string, StoredCredentialEntry>(StringComparer.OrdinalIgnoreCase)); | ||
| } |
Comment on lines
+290
to
+303
| var files = Directory.EnumerateFiles(directoryPath, "*", SearchOption.AllDirectories) | ||
| .Where(static path => !ShouldSkipPath(path)) | ||
| .OrderBy(static path => path, StringComparer.OrdinalIgnoreCase) | ||
| .ToArray(); | ||
|
|
||
| var included = new List<(string RelativePath, string Content)>(); | ||
| var totalBytes = 0; | ||
| foreach (var file in files) | ||
| { | ||
| cancellationToken.ThrowIfCancellationRequested(); | ||
| if (included.Count >= MaxDirectoryReferenceFiles) | ||
| { | ||
| break; | ||
| } |
Comment on lines
+231
to
+260
| if (ImageExtensions.Contains(Path.GetExtension(resolvedFull))) | ||
| { | ||
| var bytes = await File.ReadAllBytesAsync(resolvedFull, cancellationToken).ConfigureAwait(false); | ||
| var mediaType = ResolveMediaType(resolvedFull); | ||
| var placeholder = | ||
| $"[Referenced image: {display} ({mediaType})]" + Environment.NewLine | ||
| + $"[End referenced image: {display}]"; | ||
| return ( | ||
| placeholder, | ||
| new PromptReference( | ||
| PromptReferenceKind.Image, | ||
| rawToken, | ||
| pathPart, | ||
| resolvedFull, | ||
| display, | ||
| outsideWorkspace, | ||
| placeholder, | ||
| MediaType: mediaType, | ||
| IncludedEntryCount: 1), | ||
| new ContentBlock( | ||
| ContentBlockKind.Image, | ||
| Text: display, | ||
| ToolUseId: null, | ||
| ToolName: null, | ||
| ToolInputJson: null, | ||
| IsError: null, | ||
| MediaType: mediaType, | ||
| Data: Convert.ToBase64String(bytes), | ||
| Uri: resolvedFull)); | ||
| } |
Comment on lines
60
to
109
| @@ -84,29 +94,18 @@ private async IAsyncEnumerable<ProviderEvent> StreamEventsAsync( | |||
| } | |||
| } | |||
|
|
|||
| private OpenAIClient GetOrCreateOpenAiClient(LocalRuntimeProfileOptions? profile) | |||
| private OpenAIClient CreateOpenAiClient(LocalRuntimeProfileOptions? profile, string? resolvedApiKey) | |||
| { | |||
| if (profile is null && _cachedOpenAiClient is not null) | |||
| { | |||
| return _cachedOpenAiClient; | |||
| } | |||
|
|
|||
| var openAiOptions = new OpenAIClientOptions(); | |||
| var normalized = Internal.ProviderHttpHelpers.NormalizeBaseUrl(profile?.BaseUrl ?? _options.BaseUrl); | |||
| if (normalized is not null) | |||
| { | |||
| openAiOptions.Endpoint = new Uri(normalized); | |||
| } | |||
|
|
|||
| var apiKey = profile?.ApiKey ?? _options.ApiKey ?? "local-runtime"; | |||
| var apiKey = profile?.ApiKey ?? resolvedApiKey ?? _options.ApiKey ?? "local-runtime"; | |||
| var credential = new ApiKeyCredential(apiKey); | |||
| var client = new OpenAIClient(credential, openAiOptions); | |||
| if (profile is null) | |||
| { | |||
| _cachedOpenAiClient = client; | |||
| } | |||
|
|
|||
| return client; | |||
| return new OpenAIClient(credential, openAiOptions); | |||
| } | |||
Comment on lines
112
to
115
| refs.Reverse(); | ||
| return new PromptReferenceResolution(original, expanded.ToString(), refs); | ||
| structuredContent.Reverse(); | ||
| return new PromptReferenceResolution(original, expanded.ToString(), refs, structuredContent); | ||
| } |
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.
What changed
Why it changed
This brings SharpClaw closer to the AdaL-inspired operator surface without rewriting the existing runtime. The goal is to make session behavior, model selection, approvals, auth, scheduling, and evolution workflows first-class and durable.
User and developer impact
Validation