Skip to content

Add first-party DeepSeek provider support - #1725

Merged
Aaronontheweb merged 6 commits into
netclaw-dev:devfrom
Aaronontheweb:feature/1723-deepseek-provider
Aug 1, 2026
Merged

Add first-party DeepSeek provider support#1725
Aaronontheweb merged 6 commits into
netclaw-dev:devfrom
Aaronontheweb:feature/1723-deepseek-provider

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

Summary

  • add DeepSeek as a first-party hosted inference provider
  • use Microsoft.Extensions.AI through the existing OpenAI-compatible client
  • add a DeepSeek wire profile for thinking mode and reasoning effort
  • preserve reasoning_content across tool-call turns
  • require API-key authentication and reject OAuth tokens
  • register DeepSeek in the daemon, provider catalog, CLI, and TUI
  • add provider documentation and operational skill guidance
  • update native smoke tapes and approved provider screenshots

Provider behavior

  • provider type: deepseek
  • default endpoint: https://api.deepseek.com/v1
  • models: deepseek-v4-pro and deepseek-v4-flash
  • modalities: text input and text output
  • context window: 1,000,000 tokens
  • authentication: API key only
  • thinking mode: enabled or disabled through MEAI reasoning options

Validation

  • ./scripts/smoke/run-smoke.sh screenshots passed all 9 frames
  • the native init wizard smoke tape passed
  • dotnet slopwatch analyze reported no new issues
  • ./scripts/Add-FileHeaders.ps1 -Verify passed
  • OpenSpec validation passed
  • a local production-style binary swap started cleanly under systemd
  • one live DeepSeek session completed multiple turns and tool calls successfully

Notes

The behavioral eval suite requires operator provider credentials. It did not start because the required eval environment variables were absent.

Closes #1723

Copilot AI review requested due to automatic review settings July 31, 2026 23:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings July 31, 2026 23:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 1, 2026 00:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 25 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/Netclaw.Daemon/Configuration/ProviderPluginFactory.cs:167

  • The DeepSeek suppression dialect does not clear ChatOptions.Reasoning. OpenAiCompatibleChatClient can still emit reasoning_effort, and this can defeat suppression.
            case ReasoningSuppressionDialect.DeepSeekThinking:
                properties["thinking"] = new Dictionary<string, object?> { ["type"] = "disabled" };
                break;

src/Netclaw.Providers/DeepSeek/DeepSeekProviderPlugin.cs:27

  • This plugin does not explicitly reject OAuthAccessToken when ApiKey is present. Add a hard failure so the provider stays API-key only.
        var apiKey = entry.ApiKey?.Value;
        if (string.IsNullOrWhiteSpace(apiKey))
        {
            throw new InvalidOperationException(
                $"Provider type '{TypeKey}' requires an API key. Configure ApiKey in secrets.json.");

tests/smoke/tapes/provider-add.tape:35

  • This comment lists the provider types but omits veniceai. Update the list so the tape documentation stays accurate.
# Provider type list (alphabetical by TypeKey): anthropic, deepseek,
# github-copilot, ollama, openai, openai-compatible, openrouter. With
# Anthropic highlighted by default, three Downs land on Ollama.

Copilot AI review requested due to automatic review settings August 1, 2026 00:36
@Aaronontheweb Aaronontheweb added the providers Provider integrations and capability detection across OpenAI-compatible backends. label Aug 1, 2026

@Aaronontheweb Aaronontheweb left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works great locally but there's some smell here that needs addressing

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

return parsed with { Models = models };
}

private static bool IsCurrentModel(string modelId) =>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hard coding this is yucky


public IProviderAuth Auth { get; } = new ApiKeyAuth
{
GuidanceUrl = new Uri("https://platform.deepseek.com/api_keys"),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

public enum OpenAiCompatibleWireProfile
{
Generic,
DeepSeek,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add a comment explaining why this is necessary

GitHubCopilotDescriptor gitHubCopilot,
VeniceAiDescriptor veniceAi)
VeniceAiDescriptor veniceAi,
DeepSeekDescriptor deepSeek)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe the subject for a future PR, but doesn't this kind of suck? shouldn't we have a list or something we pass in here instead of more parameters?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 25 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Netclaw.Providers/DeepSeek/DeepSeekDescriptor.cs:57

  • DeepSeekDescriptor.ParseModels assigns context and modality metadata, but the daemon capability resolver chain does not consult provider descriptors for deepseek. At startup, Program.cs only adds provider-native resolvers for "ollama" and "openai-compatible". It then falls back to oracle resolvers and finally to the 32_768 default context window in ModelCapabilityResolution. This means a DeepSeek main model can run with an incorrect default context window and no visible failure, which contradicts the PR and issue requirements.
    internal static ProviderProbeResult ParseModels(string json)
    {
        var parsed = ProbeHelpers.ParseOpenAiStyleModels(json);
        var models = parsed.Models
            .Select(model => IsCurrentModel(model.ModelId.Value)

Copilot AI review requested due to automatic review settings August 1, 2026 01:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 25 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/Netclaw.Providers/SelfHosted/OpenAiCompatibleChatClient.cs:268

  • DeepSeek reasoning suppression can produce an inconsistent payload. ReasoningSuppressionChatClient can overwrite thinking to disabled via AdditionalProperties, but ApplyDeepSeekReasoning can still leave reasoning_effort set (for non-None efforts). Remove reasoning_effort when the final payload has thinking.type == "disabled" so the request stays coherent.
        if (options?.AdditionalProperties is { Count: > 0 } additional)
        {
            foreach (var (key, value) in additional)
            {
                body[key] = value is not null

src/Netclaw.Providers/DeepSeek/DeepSeekDescriptor.cs:74

  • DeepSeek model capability enrichment currently applies to any model that starts with deepseek-v4-. The issue requirements say Netclaw must assign context and modality only to the known current models (deepseek-v4-flash and deepseek-v4-pro). Limit enrichment to those IDs so future deepseek-v4-* models stay unresolved until documented.
    private static bool IsCurrentModelFamily(string modelId) =>
        modelId.StartsWith(CurrentModelFamilyPrefix, StringComparison.Ordinal);

@Aaronontheweb Aaronontheweb left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Aaronontheweb
Aaronontheweb enabled auto-merge (squash) August 1, 2026 01:56
@Aaronontheweb
Aaronontheweb merged commit a2177a0 into netclaw-dev:dev Aug 1, 2026
31 of 33 checks passed
@Aaronontheweb Aaronontheweb mentioned this pull request Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

providers Provider integrations and capability detection across OpenAI-compatible backends.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add first-party DeepSeek inference provider

2 participants