Require explicit main model configuration for degraded startup#1540
Merged
Aaronontheweb merged 16 commits intoJul 2, 2026
Merged
Conversation
OpenSpec change scaffolding the No-Op IChatClient fallback path so the daemon starts in a degraded-but-operational mode when no valid inference provider/model configuration is detected, instead of failing host startup. Includes proposal, design (tri-state validation outcome, provider-level branch, fixed-message contract, doctor warn item, restart-required recovery), spec deltas for netclaw-model-providers and netclaw-onboarding, and the implementation task list.
When Netclaw starts without a valid inference provider/model configuration, the daemon now launches in degraded mode with a No-Op IChatClient instead of failing host startup. Chat turns return a fixed banner beginning with "No valid model configuration detected." plus recovery steps (netclaw doctor, netclaw model, edit netclaw.json) so operators can discover and fix the configuration problem. Validation is now tri-state (Valid / NoProviderConfigured / Invalid): malformed configuration (declared provider missing credentials, schema violations, model points to an unconfigured provider) still fails startup loudly — only the genuinely-not-configured case selects the No-Op fallback. The previous silent local-ollama default in Program.cs is removed. - IChatClientProvider.IsDegraded default interface method (false on real providers, true on NoOpChatClientProvider) so doctor and diagnostics can query the state without sniffing concrete types - netclaw doctor: new Chat Client check reporting pass/warn/fail - Init wizard: provider health check emits warn-level item (not fail) when no provider is configured; daemon still starts in degraded mode - netclaw-operations skill, PRD-004, PRD-005 updated; skill version 2.9.0
Operator typo in Models:Main.Provider (e.g. "ollama-local1" vs configured "ollama-local") previously crashed the daemon with a raw ProviderPluginFactory stack trace because the validation classified the mismatch as Invalid but the DI extension fell through to lazy factory construction instead of pre-throwing. Two fixes: - ProviderRuntimeValidation: "model references unknown provider" now returns NoProviderConfigured. From the operator's standpoint this is the same remediation as genuinely-no-provider (fix the model section via `netclaw model` or edit netclaw.json); the No-Op banner's "Available providers:" line surfaces the configured names so the typo is obvious. The doctor check correspondingly reports warn instead of error for this case. - DaemonProviderServiceExtensions: when validation does return Invalid (currently unreachable in practice, but a real path for future stricter validation), register an IChatClientProvider factory that throws immediately with the validation reason — no more raw factory stack traces deep in the DI graph. Includes regression tests at the validation, DI-registration, and doctor layers exercising the exact "ollama-local1" scenario from the user report.
…value
When the daemon is running in No-Op degraded mode, `ncl chat` previously
showed the stale/invalid model name from netclaw.json (e.g. "gemma4" even
though that model lives on an unconfigured provider). The CLI builds its
own ModelCapabilities locally from netclaw.json without consulting the
daemon's actual chat-client state, so the broken config leaked into the
status bar.
CLI's ModelCapabilities factory now runs ProviderRuntimeValidation against
the same config it just loaded; when the validation outcome is non-Valid
it substitutes a sentinel ModelId ('(no model — run \`netclaw model\`)')
and zeros the context-window probe — matching the daemon's No-Op selection
without a round-trip.
…ealth ncl status previously reported overall=healthy and showed the configured (broken) model values when the daemon was running with the No-Op chat client — e.g. "model: gemma4 (provider: ollama-local1, ...)" — completely hiding the degraded state from operators. Wire-level: DaemonRuntimeStatus.Model gains Degraded + DegradedReason. DaemonRuntimeStatusService populates them from the running IChatClientProvider.IsDegraded and the ProviderRuntimeValidation singleton. ResolveOverallStatus now flips to "degraded" whenever the chat client is No-Op, regardless of other subsystem health (the daemon can't actually serve model responses). CLI formatter: when Degraded=true, the model section renders as "model: (none — No-Op chat client active)" with the validation reason and a recovery hint, instead of the stale ModelId/Provider line. Status service constructor takes the new dependencies as optional trailing parameters so the seven existing tests don't need touching.
6 tasks
Aaronontheweb
marked this pull request as draft
July 1, 2026 04:07
Filter Ollama embedding-only models during provider discovery so init selects a chat-capable model.
…iew/pr-1214-explicit-unconfigured-model
…ured-model' into review/pr-1214-explicit-unconfigured-model
…cit-unconfigured-model
Aaronontheweb
marked this pull request as ready for review
July 2, 2026 16:13
Aaronontheweb
marked this pull request as draft
July 2, 2026 16:33
Aaronontheweb
marked this pull request as ready for review
July 2, 2026 18:41
Aaronontheweb
commented
Jul 2, 2026
|
|
||
| if (status?.Model is { Degraded: true }) | ||
| { | ||
| return new ModelRuntimeResolution( |
Collaborator
Author
There was a problem hiding this comment.
Return explicit "model not configured" errors going forward if a user installs netclaw and launches the daemon without running netclaw init first - consistent theme you'll notice throughout all of these commands and APIs.
| daemon); | ||
|
|
||
| Assert.True(result.Degraded); | ||
| Assert.Equal("(no model - run `netclaw init`)", result.ModelId); |
This was referenced Jul 3, 2026
Merged
Aaronontheweb
added a commit
that referenced
this pull request
Jul 3, 2026
…tly remote (#1567) #1540's chat preflight blocks with 'daemon not configured' whenever the local netclaw.json is missing — but NETCLAW_DAEMON_ENDPOINT and paired-client (client.json) endpoints mean the daemon's config lives on the daemon host. This regressed paired/remote clients and broke the containerized eval harness (every case failed 0/5 with 'daemon not configured' from the host CLI). Preflight now stands down when either endpoint source is present — the same sources DaemonApi.ResolveEndpoint prefers over local daemon config.
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.
Summary
This PR supersedes #1214 and carries forward its No-Op chat client degraded-startup work on top of the current
devbranch.PR #1214 introduced a degraded startup path for missing or typoed provider configuration. During review, we found one remaining gap: bound object defaults such as
local-ollama/qwen3:30bcould still make a fresh or partially configured install look intentionally configured. This replacement PR makes explicit operator configuration the source of truth.What changed
upstream/dev.ProviderRuntimeConfigurationso bound defaults do not count as explicit model configuration.Models:Main, incompleteModels:Main, no providers, and typoedModels:Main:Provideras degradedNoProviderConfiguredstate.Type, incomplete explicitFallback/Compaction, and optional roles that reference unknown providers.netclaw model/ provider setup flows without a missing service graph.netclaw-operationsprovider guidance to document the degraded-vs-invalid split.Relationship to #1214
This branch is intended to replace #1214 rather than stack on it. It includes the original degraded No-Op client work plus the explicit-model-configuration follow-up fixes and additional regression coverage. #1214 should be closed in favor of this PR.
close #1214
Validation
dotnet test Netclaw.slnxopenspec validate add-noop-chat-client-fallback --strictdotnet slopwatch analyzepwsh ./scripts/Add-FileHeaders.ps1 -Verify./scripts/smoke/run-smoke.sh init-wizardgit diff --check upstream/dev..HEAD