Add first-party DeepSeek provider support - #1725
Conversation
There was a problem hiding this comment.
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.
Aaronontheweb
left a comment
There was a problem hiding this comment.
Works great locally but there's some smell here that needs addressing
| return parsed with { Models = models }; | ||
| } | ||
|
|
||
| private static bool IsCurrentModel(string modelId) => |
There was a problem hiding this comment.
hard coding this is yucky
|
|
||
| public IProviderAuth Auth { get; } = new ApiKeyAuth | ||
| { | ||
| GuidanceUrl = new Uri("https://platform.deepseek.com/api_keys"), |
| public enum OpenAiCompatibleWireProfile | ||
| { | ||
| Generic, | ||
| DeepSeek, |
There was a problem hiding this comment.
Need to add a comment explaining why this is necessary
| GitHubCopilotDescriptor gitHubCopilot, | ||
| VeniceAiDescriptor veniceAi) | ||
| VeniceAiDescriptor veniceAi, | ||
| DeepSeekDescriptor deepSeek) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
thinkingtodisabledvia AdditionalProperties, butApplyDeepSeekReasoningcan still leavereasoning_effortset (for non-None efforts). Removereasoning_effortwhen the final payload hasthinking.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-flashanddeepseek-v4-pro). Limit enrichment to those IDs so futuredeepseek-v4-*models stay unresolved until documented.
private static bool IsCurrentModelFamily(string modelId) =>
modelId.StartsWith(CurrentModelFamilyPrefix, StringComparison.Ordinal);
Summary
Microsoft.Extensions.AIthrough the existing OpenAI-compatible clientreasoning_contentacross tool-call turnsProvider behavior
deepseekhttps://api.deepseek.com/v1deepseek-v4-proanddeepseek-v4-flashValidation
./scripts/smoke/run-smoke.sh screenshotspassed all 9 framesdotnet slopwatch analyzereported no new issues./scripts/Add-FileHeaders.ps1 -VerifypassedNotes
The behavioral eval suite requires operator provider credentials. It did not start because the required eval environment variables were absent.
Closes #1723