fix(server): webhook reviews fall back to hot-applied server LLM configs (0.10.1) - #152
Merged
Conversation
…igs (0.10.1) The webhook review path (run_review_common, shared by the GitLab and GitHub handlers) resolved LLM providers from only the config file [[llm]] section and the LLM_CONFIG env, never the hot-applied state.llm_configs (DB llm_providers / WebUI). Providers configured in the WebUI had no effect on webhook-dispatched reviews, which failed with "LLM config 'default' has no api_base set". Both webhook handlers now snapshot state.llm_configs at dispatch time and pass it down to run_review_common. Precedence: config file [[llm]] > server (hot-applied) > LLM_CONFIG env; an empty server list counts as not provided (0.9.1 API-path semantics); the CLI path (no state) is unchanged. When all three sources are empty a clear ERROR is logged pointing at the WebUI provider configuration before the task fails. Tests: 4 unit tests for the resolution precedence plus a full-stack integration test (mock GitLab + mock LLM, provider added via POST /api/v1/llm/providers, no LLM_CONFIG env / config file) asserting the webhook-dispatched review completes via the hot-applied provider.
… lazy config snapshot Self-review follow-ups to the 0.10.1 fix: - The all-sources-empty ERROR log in run_review_common pointed at the WebUI unconditionally, which is misleading on the CLI/legacy path (server_llm_configs=None, no WebUI exists). The guidance now matches the caller: server-state callers are pointed at the WebUI, stateless callers at the config file [[llm]] / LLM_CONFIG env. Log-only; the failure semantics are unchanged. - Both webhook handlers snapshotted state.llm_configs (RwLock read + deep Vec clone including API keys) at handle_event entry, even for ping/push/ignored events. The snapshot now happens lazily inside the review-dispatching arms only (gitlab: Merge Request/Note/System Hook; github: pull_request/issue_comment), so non-review events pay zero cost.
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.
Root cause
The webhook review path (
run_review_commoninsrc/server/mod.rs, shared by the GitLab handlersrc/server/gitlab/hooks.rsand the GitHub handlersrc/server/github.rs) resolved LLM providers from onlyconfig::resolve_config(None)(the config file[[llm]]section) andllm_configs_from_env()(LLM_CONFIG). It never read the hot-appliedstate.llm_configs(populated from the DBllm_providerstable at startup and updated live by the WebUI /PUT /api/v1/config).Result: providers configured in the WebUI had no effect on webhook-dispatched reviews — e.g. NAS deployments where every MR review failed with
all experts failed: ... LLM config 'default' has no api_base set.Fix
run_review_commongains a trailingserver_llm_configs: Option<Vec<LLMConfig>>parameter; resolution extracted into a pure helperresolve_webhook_llm_configswith precedence config file[[llm]]> server (hot-applied) >LLM_CONFIGenv. An empty server vec counts as "not provided" (same semantics as the 0.9.1 API-path fix);None(CLI/legacy, noAppState) keeps the exact pre-0.10.1 behavior.state.llm_configs(via the existingWeak<AppState>upgrade pattern) and thread it down to the review task. The GitHub handler previously kept only the task store fromwith_app_state; it now also holds aWeak<AppState>, mirroring the GitLab handler. The snapshot is taken lazily inside the review-dispatching arms (GitLab: Merge Request / Note / System Hook; GitHub: pull_request / issue_comment) so ping/push/ignored events pay zero cost.LLM_CONFIGenv. Log-only — failure semantics unchanged.Tests
Some(vec![])falls through to env;Nonekeeps config-file → env behavior.llm_configs::webhook_review_uses_hot_applied_server_llm_configs(tests/server/llm_configs.rs) reproduces the reported scenario end-to-end: real spawned server with noLLM_CONFIGenv and no config file, provider added viaPOST /api/v1/llm/providers(the WebUI flow) pointing at a wiremock LLM, a GitLab MR webhook fired against a wiremock GitLab instance. Asserts the webhook-dispatched review settlescompletedand the hot-applied provider was actually called (/chat/completionshits ≥ 1). Pre-fix this task failed with "no api_base".Verification (run in the fix worktree)
cargo fmt --check— cleancargo clippy --all-targets --all-features— 0 warningscargo test— all green: lib 1525 passed / 0 failed (2 ignored), bin 58, cli 31, server integration 49 (incl. the new webhook test), doc 4Version
Cargo.tomlbumped to 0.10.1;CHANGELOG.mdgains[0.10.1] - 2026-09-07. No CLI behavior change; no API/schema change.