Skip to content

feat(providers): support DwarfStar (ds4) via openai-compatible backend strategy#1349

Open
GiuseppePatane wants to merge 9 commits into
netclaw-dev:devfrom
GiuseppePatane:feat/ds4-provider
Open

feat(providers): support DwarfStar (ds4) via openai-compatible backend strategy#1349
GiuseppePatane wants to merge 9 commits into
netclaw-dev:devfrom
GiuseppePatane:feat/ds4-provider

Conversation

@GiuseppePatane

@GiuseppePatane GiuseppePatane commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds support for DwarfStar (ds4) — antirez's native C inference engine for DeepSeek V4 Flash/PRO — through the existing openai-compatible provider type, with a dedicated backend strategy for context-window detection.

ds4 speaks the same protocol as every other OpenAI-compatible backend: same chat client, same endpoints, endpoint-only auth (ds4-server enforces no token), native tool_calls. The only real difference is metadata shape — /v1/models emits OpenRouter-shaped context_length / top_provider.context_length, fields neither the vLLM strategy (max_model_len) nor the llama.cpp strategy (meta.n_ctx / /props) reads. Without dedicated parsing, the context window — ds4's defining feature, long contexts backed by compressed KV cache on SSD — would never be auto-detected and compaction would size against a default.

Note on branch history: the first iteration added ds4 as a dedicated provider type (descriptor + plugin + resolver + DI wiring + TUI picker row). Review concluded the capability resolver's strategy chain is the seam built for exactly this case, so the provider type was removed and replaced by a strategy. The removal and the replacement are separate commits for reviewability.

Changes

  • Ds4BackendStrategy in the openai-compatible resolver chain (vLLM → ds4 → llama.cpp → generic)
    • Matches on owned_by: "ds4.c" — exact vendor marker verified against ds4_server.c, mirroring the vLLM owned_by check
    • Reads context_length, falling back to top_provider.context_length
    • Reports text-in/text-out modalities (ds4 is text-only, and its model ids are not HuggingFace ids, so downstream resolvers have nothing to fill in)
    • Ordered before llama.cpp so a proxy answering /props in front of ds4 cannot steal the match
  • Descriptor probe fallback: OpenAiCompatibleDescriptor.TryReadContextWindow now also reads the OpenRouter-shaped fields, so the model picker shows the context window for any backend emitting them
  • Discoverability: picker row display name is now llama.cpp / vLLM / ds4
  • Docs & skills: README, SPEC-008, docs/spec/configuration.md example (Type: "openai-compatible", endpoint http://127.0.0.1:8000), netclaw-operations skill row updated + version bump per the System Skills Sync Rule

Unrelated CI fix riding along

  • Transitive pin MessagePack 2.5.301 (GHSA-hv8m-jj95-wg3x, pulled at 2.5.192 by Aspire 13.4.x in the samples). The advisory was published mid-PR and breaks restore on every branch under warnings-as-errors — worth cherry-picking to dev independently of this PR.

Testing

  • Ds4BackendStrategyTests: match on owned_by, non-match for other vendors/missing model, top-level and nested context fields, missing-context → null
  • Resolver dispatch test: ds4 shape wins over llama.cpp even with a /props response present
  • Descriptor probe theory rows for both OpenRouter-shaped fields
  • Build clean (0 errors / 0 warnings), Netclaw.Daemon.Tests 698/698, Netclaw.Cli.Tests 790/790, dotnet slopwatch analyze 0 issues
  • Smoke: provider-add tape green (SMOKE_RID=osx-arm64). init-wizard tape fails only on a host-environment leak (the wizard detects the developer machine's ~/.claude/skills and shows an extra External Skills screen) — unrelated to this change; provider/endpoint/model steps pass.

Usage

# ds4-server running on its default port
netclaw provider add ds4 openai-compatible --endpoint http://127.0.0.1:8000
# model ids: deepseek-v4-flash / deepseek-v4-pro — context window auto-detected

…provider

The `ds4` DeepSeek V4 local engine uses an OpenAI-compatible API but emits
OpenRouter-shaped model metadata (e.g., `context_length` fields), which
requires a dedicated `IProviderDescriptor` and `IModelCapabilityResolver`
to correctly detect capabilities.

This change introduces `ds4` as a first-class LLM provider, enabling
Netclaw to leverage the local DeepSeek V4 engine with accurate context
window detection and chat client integration. It includes:
- `ds4` provider descriptor with default endpoint and auth.
- Capability resolver for `ds4`'s model listing.
- CLI display and daemon service integration.
- Documentation in `SKILL.md`.
…provider

The `ds4` DeepSeek V4 local engine uses an OpenAI-compatible API but emits
OpenRouter-shaped model metadata (e.g., `context_length` fields), which
requires a dedicated `IProviderDescriptor` and `IModelCapabilityResolver`
to correctly detect capabilities.

This change introduces `ds4` as a first-class LLM provider, enabling
Netclaw to leverage the local DeepSeek V4 engine with accurate context
window detection and chat client integration. It includes:
- `ds4` provider configuration with a default local endpoint.
- Capability resolver integration for `ds4`'s model listing in the CLI doctor.
- Updated documentation in the configuration spec, provider abstraction spec, and `README.md`.
Adding the ds4 provider type inserts a "DwarfStar (ds4)" row between
anthropic and github-copilot in the alphabetical-by-TypeKey provider
list. The init-wizard, init-wizard-reverse-proxy, provider-add, and
wizard-screens tapes navigated to Ollama with `Down 2` (ollama at
index 2); it now sits at index 3, so they landed on github-copilot
(OAuth, no endpoint step) and timed out waiting for the endpoint
screen. Bump those to `Down 3`.

Also refresh the provider-manager-empty screenshot baseline (captured
from CI) to include the new ds4 row.
@Aaronontheweb

Copy link
Copy Markdown
Collaborator

The ds4 plugin uses the same chat client, same endpoints, same auth, and same tool calling as openai-compatible — the only difference is which JSON field name holds the context window in the /v1/models response. Can this just be a new backend strategy on the existing openai-compatible provider instead of a whole new provider type?

ds4 duplicates the openai-compatible provider end to end: same chat client
(OpenAiCompatibleChatClient), same endpoints, same EndpointOnlyAuth, same
native tool calling. The only real difference — which JSON field of
/v1/models holds the context window — belongs in the capability resolver's
backend strategy chain, not in a parallel provider type with its own
descriptor, plugin, DI wiring, doctor probe, and TUI picker row.

Removes the Ds4 descriptor/resolver/plugin, their registrations, the
doctor wiring, and reverts the TUI picker row and smoke tapes to dev.
The replacement Ds4BackendStrategy lands in the follow-up commit.
…end strategy

Adds Ds4BackendStrategy to the openai-compatible capability resolver chain.
ds4 is recognized by owned_by "ds4.c" on the /v1/models entry (mirroring
the vLLM owned_by marker) and its OpenRouter-shaped context window is read
from context_length / top_provider.context_length. Ordered before llama.cpp
so a proxy answering /props in front of ds4 cannot steal the match.
Modalities are reported Text/Text: ds4 serves text-only DeepSeek V4 models
and its model ids are not HuggingFace ids, so downstream resolvers have
nothing to fill in.

The descriptor probe gains the same context_length fallback so the model
picker shows the context window for any OpenRouter-shaped backend.

ds4 setup now goes through the openai-compatible provider type
(endpoint http://127.0.0.1:8000); docs and the netclaw-operations skill
updated accordingly.
Users scanning the provider picker had no signal that DwarfStar (ds4) is
supported after its dedicated provider type was folded into
openai-compatible.
Aspire 13.4.x pulls MessagePack 2.5.192 into the Demo.AppHost samples; the
newly published advisory (LZ4 decompression AccessViolationException on bad
input) trips NU1903 under warnings-as-errors and breaks restore in CI.
Transitive pinning is already enabled, so a central PackageVersion entry on
the first patched release is enough. Remove once the Aspire line ships a
patched MessagePack.
@GiuseppePatane GiuseppePatane changed the title feat(providers): add DwarfStar (ds4) DeepSeek V4 local engine as LLM provider feat(providers): support DwarfStar (ds4) via openai-compatible backend strategy Jun 12, 2026
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.

2 participants