Repository navigation
fix(llm): refresh demo provider configs on page load - #378
JesusMan0529 wants to merge 3 commits into
Conversation
|
😊 |
bitflicker64
left a comment
There was a problem hiding this comment.
Blocking: yes. Summary: The page-load reload works for valid .env edits, but the five provider renders lost their implicit load trigger, so any .env value that LLMConfig rejects leaves the Chat, mini_tasks, text2gql, Embedding and Reranker sections empty after a refresh. Score 7/10. Evidence: read the full exact-head diff, BaseConfig.__init__, LLMConfig field types and gradio 5.20.1 renderable.py; ran uv run pytest hugegraph-llm/src/tests/config/test_demo_config_refresh.py (3 passed); replayed the load event with CHAT_LLM_TYPE=ollama in .env and saw refresh_llm_config raise a pydantic literal_error, with only vector_engine_settings rendering. All latest-head checks pass.
|
|
||
| def refresh_llm_config(revision): | ||
| with runtime_config_lock: | ||
| llm_settings.__init__() # type: ignore[misc] # pylint: disable=C2801 |
There was a problem hiding this comment.
Important: If .env holds any value LLMConfig rejects, the page loads with every provider form missing. With explicit triggers, gradio 5.20 no longer adds the implicit page-load trigger to @gr.render (gradio/renderable.py, lines 137-150). The five forms now render only when config_revision changes, and that happens only when this function returns. When llm_settings.__init__() raises, the load event fails, config_revision stays at 0, and Chat, mini_tasks, text2gql, Embedding and Reranker show no fields and no Apply button. Before this PR, those renders also ran on load and showed the in-memory values.
Reproduced on this head with gradio 5.20.1: I wrote a .env that differs only by CHAT_LLM_TYPE=ollama (the valid value is ollama/local) and replayed the load event the way test_demo_config_refresh.py does. refresh_llm_config raised a pydantic literal_error, and the only render that fired was vector_engine_settings. A mistyped Literal value or a non-integer token or port count is a likely mistake in the edit-then-refresh workflow this PR adds, and it now removes the config UI instead of leaving the old values editable.
Please keep the renders firing when the reload fails and tell the user why, for example:
def refresh_llm_config(revision):
with runtime_config_lock:
try:
llm_settings.__init__() # type: ignore[misc] # pylint: disable=C2801
except Exception as e: # pylint: disable=broad-except
log.error("Failed to reload LLM settings from %s: %s", env_path, e)
gr.Warning(f"Could not reload {env_path}, keeping the current settings: {e}")
return (Also add a case to test_demo_config_refresh.py with an invalid value, and assert that the provider textboxes still render.
There was a problem hiding this comment.
Thanks for catching this! Fixed in e5c4cba. A failed reload now keeps the current settings, shows a warning, and still renders all five provider forms and their Apply buttons. Added regression tests for invalid provider/token/port values and recovery after correcting the file; all 13 refresh tests pass.
imbajin
left a comment
There was a problem hiding this comment.
Blocking: no. Summary: Refreshing after removing an LLM setting can restore the stale value from the previous .env contents. Evidence: On this head the page-load callback reinitializes llm_settings, while BaseConfig copies .env entries into os.environ and writes missing model fields back to the file.
|
|
||
| def refresh_llm_config(revision): | ||
| with runtime_config_lock: | ||
| llm_settings.__init__() # type: ignore[misc] # pylint: disable=C2801 |
There was a problem hiding this comment.
There was a problem hiding this comment.
Fixed in e5c4cba. Reloads now read .env directly without copying its values into os.environ, so deleted keys fall back to process settings or defaults. Added regression tests for removing model, API key and provider settings, including the environment fallback.
imbajin
left a comment
There was a problem hiding this comment.
Blocking: no. Summary: The exact-head review found two runtime regressions in configuration reload. Evidence: the new dotenv source no longer exposes the standalone Thin API write flag to os.getenv, and provider construction can read the shared settings object while it is only partially refreshed.
| os.environ[k] = v | ||
|
|
||
| # Step 2: Init the parent class with loaded environment variables | ||
| # Load and validate settings directly from the current sources. |
There was a problem hiding this comment.
There was a problem hiding this comment.
Fixed in 76a8ea0. The .env-only write opt-in now works for both endpoints without exporting it into the process environment. Added production-router tests for authentication, source precedence and removing the flag. Also checked the other standalone file settings and preserved their dotenv support.
| with runtime_config_lock: | ||
| try: | ||
| reloaded = type(llm_settings)() | ||
| _restore_config(llm_settings, reloaded.model_dump()) |
There was a problem hiding this comment.
Fixes #91.
When
.envchanges while the demo is running, refreshing the page reloads the shared LLM settings and updates all five provider forms, including when the provider type stays the same. The SiliconFlow form honors the configured model. Invalid or failed reloads retain the previous settings, show a warning, and still render the forms and Apply buttons.Settings load directly from the current file without copying values into
os.environ, so deleted keys use genuine process settings or defaults. Standalone file settings remain supported through an explicit dotenv lookup: the Thin API write opt-in, development reload, and NLTK data/cache paths. The Thin API still requires login and bearer authentication for writes.Provider functions and factories capture the provider type and parameters together under
runtime_config_lock, including chat, extraction, Text2Gremlin, embedding, and reranking clients. Client construction and embedding dimension probes run after releasing the lock. Provider form rendering uses the same lock for its shared settings updates. The two LiteLLM embedding entry points now supply the required initial dimension.Validation:
0xC0000005, as previously reproduced on the original PR head; this local run is not a clean process exit.git diff --checkpass.tycheck retains 726 diagnostics, down from 728 before this follow-up. Comparing file/rule/message pairs found no new diagnostics; the two missing embedding-dimension arguments were removed.Upstream validation for
76a8ea04dbc41969dcfb7e49e6ccb4243b6da7bb: all 20 checks succeeded, including the LLM unit/contract, HugeGraph boundary and core smoke jobs on Python 3.10/3.11, client checks, builds, Ruff and security/license checks. The Linux Python 3.11 unit/contract log confirms 486 passed, 3 skipped and 18 deselected with a normal exit. Thetyjobs remain configured as non-blocking. CI run.