-
Notifications
You must be signed in to change notification settings - Fork 791
feat(wren-ai-service): create Streamlit UI for configuring LLM models #1690
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…_state.py; combine init and override behaviors (import yaml files)
1. Rename custom_llm_ui.py to app.py for better naming convention 2. Extract Embedder and Document Store configuration from app.py to ui_components.py to improve code organization 3. Fix data type issue: ensure "timeout" value is properly converted to integer 4. Optimize alias handling: only include alias field in dictionary when it has a value
- Implemented pipeline configuration UI. - Set init_pipeline in session_state.py to manage pipeline state.
…and embedding models
…guration handling - Removed the document store configuration section and its associated rendering logic. - Updated the embedder configuration to include dimension input for embedding models. - Simplified the rendering of pipeline configurations and improved the selection process for LLM models. - Enhanced the preview and generation functionality for configuration files. - Adjusted the layout and organization of UI components for better clarity and usability.
… component integration - Refactored configuration path retrieval by introducing dedicated functions for fetching paths to config.yaml, config.done, and .env files. - Updated UI components to utilize the new configuration path functions, enhancing maintainability and clarity. - Simplified file operations in the API key management section to ensure consistent access to the environment file.
…prove error handling - Implemented validation for required configuration blocks (LLM, Embedder, Document Store, Pipeline) to ensure they are present and not empty. - Enhanced error handling by replacing print statements with Streamlit error messages for better user feedback during configuration loading failures. - Improved user experience by warning users about missing configuration blocks and indicating that default values will be used.
…ontainer launch logging - Updated the config extraction logic to return the first block of each type, improving clarity and efficiency. - Modified the launch command to dynamically find and log the available port for the Streamlit UI, enhancing user feedback during startup.
…tecture support and digest handling
…ing configurations fix(ui): update save button key to include original index for correct LLM updates
WalkthroughThis update introduces a new provider setup workflow for Wren AI, including a Streamlit-based UI for configuring custom LLM providers. It adds a Dockerfile, supporting Python modules, and a GitHub Actions workflow for building and publishing multi-architecture images. The launcher and utility code are updated to integrate the interactive setup flow using Docker containers and session state management. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Launcher (CLI)
participant Docker
participant Streamlit UI
participant Local FS
User->>Launcher (CLI): Run launch command with custom provider
Launcher (CLI)->>Local FS: Check for ~/.wrenai directory
alt Directory exists
Launcher (CLI)->>Docker: Remove existing setup container (if any)
Launcher (CLI)->>Docker: Build Streamlit UI image
Launcher (CLI)->>Local FS: Ensure config.yaml, .env, config.done exist
Launcher (CLI)->>Docker: Run Streamlit UI container with mounted configs
User->>Streamlit UI: Open browser and configure provider
Streamlit UI->>Local FS: Write config.yaml, .env, set config.done=true
Launcher (CLI)->>Local FS: Poll config.done until ready
Launcher (CLI)->>Docker: Remove setup container
else Directory missing
Launcher (CLI)->>Launcher (CLI): Log warning and skip UI setup
end
Launcher (CLI)->>Docker: Continue with main Wren AI Docker Compose launch
Suggested labels
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🧹 Nitpick comments (9)
wren-ai-service/tools/providers-setup/constants.py (1)
2-2
: Remove unused import.The
os
module is imported but never used in this file.-import os
🧰 Tools
🪛 Ruff (0.11.9)
2-2:
os
imported but unusedRemove unused import:
os
(F401)
wren-launcher/commands/launch.go (1)
251-251
: Fix the typo in the comment.There's a spelling error in the comment.
- // chech if ~/.wrenai is exist + // check if ~/.wrenai exists.github/workflows/setup-provider-image.yaml (2)
29-29
: Remove trailing spaces.Static analysis detected trailing spaces that should be removed for cleaner code.
- - runner: ubuntu-latest + - runner: ubuntu-latest platform: linux/amd64 - - runner: ubuntu-24.04-arm + - runner: ubuntu-24.04-arm platform: linux/arm64Also applies to: 31-31
🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 29-29: trailing spaces
(trailing-spaces)
130-131
: Remove extra blank line.There's an unnecessary blank line at the end of the file.
$(printf '${{ env.REGISTRY }}/${{ env.PROVIDER_UI_IMAGE }}@sha256:%s ' *) \ $TAGS -
🧰 Tools
🪛 YAMLlint (1.37.1)
[warning] 130-130: too many blank lines
(1 > 0) (empty-lines)
wren-ai-service/tools/providers-setup/config_loader.py (2)
88-99
: Clarify the fallback logic in group_blocks function.The logic for handling blocks without a "type" field could be more explicit and documented.
def group_blocks(blocks: List[Dict[str, Any]]) -> Dict[str, Any]: """ Group YAML blocks by their 'type' field. If multiple blocks share the same type, they are stored as a list. + Falls back to 'settings' key if 'type' field is missing. """ save_blocks = {} for block in blocks: - key = block.get("type") or ("settings" if "settings" in block else None) + key = block.get("type") + if not key and "settings" in block: + key = "settings" if not key: continue
47-48
: Improve error message consistency.The error message format should be consistent with other error messages in the function.
if not config_list: - raise ValueError(f"⚠️ Received empty YAML content from: {url}") + raise ValueError(f"Received empty YAML content from: {url}")wren-ai-service/tools/providers-setup/session_state.py (1)
167-167
: Consider making the .env path configurable.The hardcoded path
/app/data/.env
assumes a containerized environment. Consider making this configurable or using a constant to improve portability.Consider importing the path from the constants module:
+from constants import get_env_path +env_path = get_env_path() -env_path = Path("/app/data/.env")wren-ai-service/tools/providers-setup/ui_components.py (2)
219-220
: Remove unnecessary f-string prefix.The f-string on line 220 doesn't contain any placeholders.
- with st.expander(f"{default_name}", expanded=False): + with st.expander(default_name, expanded=False):🧰 Tools
🪛 Ruff (0.11.9)
220-220: f-string without any placeholders
Remove extraneous
f
prefix(F541)
294-342
: Remove commented code block.This large block of commented code should be removed to keep the codebase clean. If this functionality might be needed later, consider tracking it in version control history or a separate feature branch.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
wren-ai-service/tools/providers-setup/poetry.lock
is excluded by!**/*.lock
📒 Files selected for processing (11)
.github/workflows/setup-provider-image.yaml
(1 hunks)wren-ai-service/tools/providers-setup/Dockerfile
(1 hunks)wren-ai-service/tools/providers-setup/app.py
(1 hunks)wren-ai-service/tools/providers-setup/config_loader.py
(1 hunks)wren-ai-service/tools/providers-setup/constants.py
(1 hunks)wren-ai-service/tools/providers-setup/dry_run_test.py
(1 hunks)wren-ai-service/tools/providers-setup/pyproject.toml
(1 hunks)wren-ai-service/tools/providers-setup/session_state.py
(1 hunks)wren-ai-service/tools/providers-setup/ui_components.py
(1 hunks)wren-launcher/commands/launch.go
(1 hunks)wren-launcher/utils/docker.go
(4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
wren-launcher/commands/launch.go (2)
wren-launcher/utils/docker.go (4)
TryGetWrenAIDir
(552-564)RemoveContainerIfExists
(657-674)RunStreamlitUIContainer
(576-606)IsCustomConfigReady
(678-693)wren-launcher/utils/network.go (1)
FindAvailablePort
(16-34)
wren-ai-service/tools/providers-setup/app.py (3)
wren-ai-service/tools/providers-setup/config_loader.py (2)
load_config_yaml_blocks
(9-22)group_blocks
(82-99)wren-ai-service/tools/providers-setup/session_state.py (2)
ConfigState
(5-206)init
(17-27)wren-ai-service/tools/providers-setup/ui_components.py (7)
render_llm_config
(143-206)render_embedder_config
(210-291)render_import_yaml
(9-32)render_pipeline_config
(343-379)render_preview
(383-390)render_apikey
(35-141)render_generate_button
(392-412)
wren-ai-service/tools/providers-setup/dry_run_test.py (1)
wren-ai-service/tools/providers-setup/session_state.py (1)
ConfigState
(5-206)
wren-ai-service/tools/providers-setup/session_state.py (2)
wren-ai-service/src/config.py (1)
config_loader
(87-97)wren-ai-service/tools/providers-setup/config_loader.py (2)
fetch_yaml_from_url
(37-54)fetch_example_yaml_filenames
(101-113)
🪛 actionlint (1.7.7)
.github/workflows/setup-provider-image.yaml
61-61: got unexpected character '/' while lexing expression, expecting 'a'..'z', 'A'..'Z', '_', '0'..'9', ''', '}', '(', ')', '[', ']', '.', '!', '<', '>', '=', '&', '|', '*', ',', ' '
(expression)
🪛 YAMLlint (1.37.1)
.github/workflows/setup-provider-image.yaml
[error] 29-29: trailing spaces
(trailing-spaces)
[error] 31-31: trailing spaces
(trailing-spaces)
[warning] 130-130: too many blank lines
(1 > 0) (empty-lines)
🪛 Ruff (0.11.9)
wren-ai-service/tools/providers-setup/ui_components.py
220-220: f-string without any placeholders
Remove extraneous f
prefix
(F541)
wren-ai-service/tools/providers-setup/constants.py
2-2: os
imported but unused
Remove unused import: os
(F401)
🔇 Additional comments (16)
wren-ai-service/tools/providers-setup/constants.py (1)
9-28
: LGTM! Well-implemented GitHub API function.The function correctly handles the GitHub API request with proper timeout, error handling, and fallback logic. The print statements provide useful debugging information.
wren-ai-service/tools/providers-setup/pyproject.toml (1)
1-18
: LGTM! Well-configured Poetry project.The project configuration is appropriate for a Streamlit-based provider setup tool. The dependency version ranges are reasonable and the build system configuration is correct.
wren-ai-service/tools/providers-setup/Dockerfile (2)
1-58
: LGTM! Well-structured Dockerfile with good practices.The Dockerfile follows best practices with proper layer caching, minimal base image, and appropriate environment configuration for Streamlit. The multi-stage approach and dependency installation strategy are well-implemented.
34-35
:❌ Incorrect review comment
Verify poetry.lock file exists.
The Dockerfile copies
poetry.lock
but this file isn't included in the PR. This could cause build failures if the lock file doesn't exist.
🏁 Script executed:
#!/bin/bash # Check if poetry.lock exists in the providers-setup directory fd -t f "poetry.lock" wren-ai-service/tools/providers-setup/Length of output: 110
poetry.lock exists – no action needed
The
poetry.lock
file is present atwren-ai-service/tools/providers-setup/poetry.lock
, so theCOPY poetry.lock
instruction in the Dockerfile is valid. No changes required.Likely an incorrect or invalid review comment.
wren-ai-service/tools/providers-setup/app.py (3)
1-12
: LGTM! Clean and well-organized imports.The imports are well-structured, importing only the necessary functions from each module. The modular approach promotes good separation of concerns.
33-49
: Excellent validation logic for configuration blocks.The validation properly checks both type and content of required configuration blocks, providing clear user feedback when blocks are missing. This helps users understand what needs to be configured.
59-88
: Well-designed UI layout with logical organization.The two-column layout effectively separates input controls from preview functionality. The component rendering is modular and follows a logical flow from API keys through configuration to final generation.
wren-ai-service/tools/providers-setup/dry_run_test.py (1)
6-31
: LGTM! Well-structured LLM completion test function.The function properly handles the completion API call with good error handling and response validation.
wren-ai-service/tools/providers-setup/config_loader.py (2)
9-23
: LGTM! Excellent configuration loading structure.The functions provide robust configuration loading with proper error handling, fallback mechanisms, and clear separation of concerns.
Also applies to: 24-36, 37-55
115-127
: LGTM! Clean integration with session state.The
apply_config_blocks
function properly integrates the loaded configuration with the Streamlit session state management.wren-ai-service/tools/providers-setup/session_state.py (3)
16-28
: LGTM!The initialization orchestration method is well-structured and provides appropriate control over state overwriting.
30-68
: Well-implemented form initialization logic.The method properly handles form creation with unique IDs and correctly flattens kwargs for the model list.
121-130
:✅ Verification successful
Consider handling empty response from remote config fetch.
When
fetch_yaml_from_url
returns an empty list (indicating a fetch error), the code continues as if there's no latest pipeline configuration. Consider adding explicit error handling to distinguish between fetch failures and legitimate empty configurations.
🏁 Script executed:
#!/bin/bash # Check how fetch_yaml_from_url handles errors ast-grep --pattern 'def fetch_yaml_from_url($_) -> $_: $$$ 'Length of output: 1745
No additional empty-response handling needed.
The fetch_yaml_from_url function already raises a ValueError on empty YAML content, logs the error via st.error, and returns an empty list only on failure. In init_pipeline, receiving an empty list (and thus latest_pipeline remaining None) correctly reflects a fetch/parsing error and skips the update as intended.
wren-launcher/utils/docker.go (2)
298-344
: Great improvement to custom provider setup!The automatic downloading of missing configuration files and USER_UUID injection significantly improves the user experience compared to the previous strict error returns.
576-693
: Well-implemented container management functions.The new functions for Streamlit UI container management are properly structured with good error handling, appropriate volume mounts, and clear separation of concerns.
wren-ai-service/tools/providers-setup/ui_components.py (1)
35-142
: Well-implemented API key management.The API key configuration section properly handles CRUD operations on the .env file with appropriate error handling and file format preservation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
wren-ai-service/tools/providers-setup/ui_components.py (1)
431-437
:⚠️ Potential issueCritical: Remove eval() to prevent code injection.
Using
eval()
on user input is a serious security vulnerability that could allow arbitrary code execution.
🧹 Nitpick comments (4)
wren-ai-service/tools/providers-setup/ui_components.py (4)
25-33
: Add success message after YAML upload.The YAML upload section is missing a success message after successfully processing the uploaded file, unlike the GitHub import section.
uploaded_file = st.file_uploader("Upload your own YAML file", type=["yaml", "yml"]) if uploaded_file is not None and st.button("Import.yaml", key="import_own_yaml"): try: blocks = list(yaml.safe_load_all(uploaded_file)) apply_config_blocks(blocks) + st.success("YAML import succeeded. Settings updated.") except Exception as e: st.error(f"Failed to import YAML file: {e}")
221-221
: Remove unnecessary f-string prefix.The f-string prefix is not needed here since there are no placeholders.
- with st.expander(f"{default_name}", expanded=False): + with st.expander(default_name, expanded=False):
233-233
: Fix typo in comment.There's a typo in the comment: "doucument_store" should be "document_store".
- document_store_dim = st.text_input("Embedding_model_dim (placed in doucument_store)", key="embedding_model_dim", value="3072") + document_store_dim = st.text_input("Embedding_model_dim (placed in document_store)", key="embedding_model_dim", value="3072")
296-344
: Remove commented-out code.This entire function is commented out and marked for deletion. Dead code should be removed to maintain code cleanliness.
Remove lines 296-344 entirely instead of keeping them as comments.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
wren-ai-service/tools/providers-setup/session_state.py
(1 hunks)wren-ai-service/tools/providers-setup/ui_components.py
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- wren-ai-service/tools/providers-setup/session_state.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
wren-ai-service/tools/providers-setup/ui_components.py (5)
wren-ai-service/tools/providers-setup/session_state.py (1)
ConfigState
(5-208)wren-ai-service/src/config.py (1)
config_loader
(87-97)wren-ai-service/tools/providers-setup/config_loader.py (2)
load_selected_example_yaml
(24-35)apply_config_blocks
(115-127)wren-ai-service/tools/providers-setup/dry_run_test.py (2)
llm_completion_test
(6-31)llm_embedding_test
(34-63)wren-ai-service/tools/providers-setup/constants.py (3)
get_env_path
(80-87)get_config_path
(69-77)get_config_done_path
(59-67)
🪛 Ruff (0.11.9)
wren-ai-service/tools/providers-setup/ui_components.py
222-222: f-string without any placeholders
Remove extraneous f
prefix
(F541)
… timeout for user configuration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (7)
wren-ai-service/tools/providers-setup/constants.py (1)
59-87
: The directory naming is now consistent.All path utility functions correctly use the
.wrenai
directory name (lowercase), which resolves the previous naming inconsistency concern.🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 64-67: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
[refactor] 74-77: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
[refactor] 84-87: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
wren-ai-service/tools/providers-setup/dry_run_test.py (2)
44-48
: Excellent bounds checking implementation.The code now properly checks for empty models list before accessing the first element, addressing the previous IndexError concern.
74-77
: Good error handling for session state.The function now uses
.get()
with a default value and checks for non-empty API keys, addressing the previous KeyError concern..github/workflows/setup-provider-image.yaml (2)
11-13
: Permissions are correctly configured.The permissions section is now properly uncommented and configured for GitHub Container Registry access.
62-62
: String replacement syntax is now correct.The expression now uses the proper
tr
command syntax instead of the invalid//
operator.wren-launcher/utils/docker.go (1)
613-615
: Path validation is now properly implemented.The build path is now validated before attempting to build, addressing the previous robustness concern.
wren-ai-service/tools/providers-setup/ui_components.py (1)
435-438
: Security improvement confirmed - eval() replaced with ast.literal_eval().Great work addressing the previous security concern! The code now safely evaluates literals using
ast.literal_eval()
instead of the dangerouseval()
function, preventing potential code injection attacks.
🧹 Nitpick comments (10)
wren-ai-service/tools/providers-setup/constants.py (2)
2-2
: Remove unused import.The
os
module is imported but never used in this file.-import os
🧰 Tools
🪛 Ruff (0.11.9)
2-2:
os
imported but unusedRemove unused import:
os
(F401)
19-28
: Consider simplifying control flow.The
else
clause afterreturn
statements can be removed to reduce nesting levels.- if response.status_code == 200: - data = response.json() - return data["tag_name"] - else: - print(f"Failed to get latest release: {response.status_code}") + if response.status_code == 200: + data = response.json() + return data["tag_name"] + print(f"Failed to get latest release: {response.status_code}")🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 20-24: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
wren-ai-service/tools/providers-setup/dry_run_test.py (1)
25-28
: Consider simplifying control flow.The
else
clauses afterreturn
statements can be removed to reduce nesting levels.- if choices and choices[0].get("message", {}).get("content"): - return True, response_completion["choices"][0]["message"]["content"] - else: - return False, "No valid response content" + if choices and choices[0].get("message", {}).get("content"): + return True, response_completion["choices"][0]["message"]["content"] + return False, "No valid response content"- if isinstance(embedding_vector, list) and len(embedding_vector) > 0: - return True, f"Embedding length: {len(embedding_vector)}" - else: - return False, "Embedding vector is empty or invalid" + if isinstance(embedding_vector, list) and len(embedding_vector) > 0: + return True, f"Embedding length: {len(embedding_vector)}" + return False, "Embedding vector is empty or invalid"Also applies to: 58-61
🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 25-28: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
.github/workflows/setup-provider-image.yaml (1)
29-29
: Fix formatting issues.Remove trailing spaces and extra blank lines to comply with YAML formatting standards.
- - runner: ubuntu-latest + - runner: ubuntu-latest - - runner: ubuntu-24.04-arm + - runner: ubuntu-24.04-arm - +Also applies to: 31-31, 130-130
🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 29-29: trailing spaces
(trailing-spaces)
wren-launcher/utils/docker.go (1)
662-681
: Consider adding logging for container removal operations.The function properly handles container existence checking, but consider adding more detailed logging for troubleshooting.
func RemoveContainerIfExists(name string) error { // Check if the container exists (inspect will fail if not) err := exec.Command("docker", "inspect", name).Run() if err != nil { - pterm.Info.Println("🔍 Container does not exist, skipping:", name) + pterm.Debug.Println("🔍 Container does not exist, skipping:", name) return nil } + pterm.Info.Println("🧹 Removing existing container:", name) // Remove container forcefully cmd := exec.Command("docker", "rm", "-f", name) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("❌ Failed to force-remove container: %v\n%s", err, string(out)) } pterm.Info.Println("🧹 Container forcibly removed:", name) return nil }wren-ai-service/tools/providers-setup/ui_components.py (5)
30-34
: Add success message for custom YAML import.The success message is missing when importing a custom YAML file, unlike the example YAML import which shows a success message on line 24.
try: blocks = list(yaml.safe_load_all(uploaded_file)) apply_config_blocks(blocks) - + st.success("YAML import succeeded. Settings updated.") except Exception as e: st.error(f"Failed to import YAML file: {e}")
37-143
: Consider refactoring this function to reduce complexity.This function handles too many responsibilities (adding, editing, saving, deleting API keys) and has high complexity according to static analysis (21 local variables, 18 branches, 62 statements).
Consider breaking this into smaller functions:
_render_api_key_form()
for form rendering_save_api_keys()
for save logic_delete_api_key()
for deletion logicThis would improve maintainability and testability.
🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 37-37: Too many local variables (21/15)
(R0914)
[refactor] 37-37: Too many branches (18/12)
(R0912)
[refactor] 37-37: Too many statements (62/50)
(R0915)
224-224
: Remove unnecessary f-string prefix.The f-string has no placeholders, making the
f
prefix unnecessary.- st.markdown(f"**type:** `embedder`") + st.markdown("**type:** `embedder`")🧰 Tools
🪛 Ruff (0.11.9)
224-224: f-string without any placeholders
Remove extraneous
f
prefix(F541)
298-346
: Remove commented-out code.This large block of commented code should be removed to keep the codebase clean, unless there's a specific reason to keep it for reference.
-# DELETE -# def render_document_store_config(): -# """ -# Render the document store configuration section. -# Displays current settings and allows updating index location, dimensions, timeout, etc. -# """ -# with st.expander("Document Store Configuration", expanded=False): - [... rest of commented code ...]
460-466
: Remove unnecessary else clause after return.The else clause is unnecessary since the previous block contains a return statement.
existing_ids = [m.get("id") for m in st.session_state[ConfigState.LLM_MODELS_KEY]] if form_id in existing_ids: index = existing_ids.index(form_id) st.session_state[ConfigState.LLM_MODELS_KEY][index] = {**saved_entry, "id": form_id} return True, f"Updated model: {form['model']}" - else: - st.session_state[ConfigState.LLM_MODELS_KEY].append({**saved_entry, "id": form_id}) - return True, f"Added new model: {form['model']}" + + st.session_state[ConfigState.LLM_MODELS_KEY].append({**saved_entry, "id": form_id}) + return True, f"Added new model: {form['model']}"🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 460-466: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
.github/workflows/setup-provider-image.yaml
(1 hunks)wren-ai-service/tools/providers-setup/constants.py
(1 hunks)wren-ai-service/tools/providers-setup/dry_run_test.py
(1 hunks)wren-ai-service/tools/providers-setup/ui_components.py
(1 hunks)wren-launcher/commands/launch.go
(1 hunks)wren-launcher/utils/docker.go
(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- wren-launcher/commands/launch.go
🧰 Additional context used
🪛 Ruff (0.11.9)
wren-ai-service/tools/providers-setup/ui_components.py
224-224: f-string without any placeholders
Remove extraneous f
prefix
(F541)
wren-ai-service/tools/providers-setup/constants.py
2-2: os
imported but unused
Remove unused import: os
(F401)
🪛 Pylint (3.3.7)
wren-ai-service/tools/providers-setup/ui_components.py
[refactor] 37-37: Too many local variables (21/15)
(R0914)
[refactor] 37-37: Too many branches (18/12)
(R0912)
[refactor] 37-37: Too many statements (62/50)
(R0915)
[refactor] 145-145: Too many branches (14/12)
(R0912)
[refactor] 214-214: Too many branches (15/12)
(R0912)
[error] 382-382: Possibly using variable 'selected_llm' before assignment
(E0606)
[refactor] 460-466: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
wren-ai-service/tools/providers-setup/constants.py
[refactor] 20-24: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
[refactor] 64-67: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
[refactor] 74-77: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
[refactor] 84-87: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
wren-ai-service/tools/providers-setup/dry_run_test.py
[refactor] 25-28: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
[refactor] 58-61: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it
(R1705)
🪛 YAMLlint (1.37.1)
.github/workflows/setup-provider-image.yaml
[error] 29-29: trailing spaces
(trailing-spaces)
[error] 31-31: trailing spaces
(trailing-spaces)
[warning] 130-130: too many blank lines
(1 > 0) (empty-lines)
🔇 Additional comments (3)
wren-launcher/utils/docker.go (3)
297-344
: Excellent improvement to custom provider handling.The logic now gracefully handles missing configuration files by downloading defaults instead of failing with errors. This provides a much better user experience for the custom provider setup flow.
573-606
: Well-structured Streamlit UI container management.The
RunStreamlitUIContainer
function properly orchestrates the container lifecycle with good error handling and clear separation of concerns.
683-700
: Robust configuration readiness checking.The
IsCustomConfigReady
function implements proper error handling and case-insensitive comparison for the configuration state check.
The selected_llm variable may be used before assignment if the pipeline has no llm key or if the current LLM value is not in the options list. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
wren-ai-service/tools/providers-setup/ui_components.py (1)
298-346
: Remove commented-out code to improve maintainability.Large blocks of commented-out code should be removed rather than left in the codebase. If this functionality might be needed in the future, consider documenting the decision or using version control history instead.
-# DELETE -# def render_document_store_config(): -# """ -# Render the document store configuration section. -# Displays current settings and allows updating index location, dimensions, timeout, etc. -# """ -# with st.expander("Document Store Configuration", expanded=False): -# st.markdown(f"**type:** `document_store`") -# st.markdown(f"**provider:** `{st.session_state[ConfigState.DOC_STORE_KEY].get('provider')}`") -# st.markdown(f"**location:** `{st.session_state[ConfigState.DOC_STORE_KEY].get('location')}`") - -# document_store_timeout = st.text_input("Timeout (default: 120)", key="document_store_timeout", value="120") -# st.markdown(f"**timeout:** `120`") -# st.markdown(f"**recreate_index:** `{st.session_state[ConfigState.DOC_STORE_KEY].get('recreate_index')}`") - -# document_store_dim = st.text_input("Embedding_model_dim", value="3072") - -# if st.button("💾 save", key="save_document_store"): -# errors = [] -# if not document_store_dim: -# errors.append("Embedding model dim is required.") -# else: -# try: -# int(document_store_dim) -# except ValueError: -# errors.append("Embedding model dim must be an integer.") - -# if not document_store_timeout: -# errors.append("Timeout is required.") -# else: -# try: -# int(document_store_timeout) -# except ValueError: -# errors.append("Timeout must be an integer.") - -# if errors: -# for error in errors: -# st.error(error) -# else: -# st.session_state.document_store = { -# "type": "document_store", -# "provider": st.session_state[ConfigState.DOC_STORE_KEY].get("provider"), -# "location": st.session_state[ConfigState.DOC_STORE_KEY].get("location"), -# "embedding_model_dim": document_store_dim, -# "timeout": document_store_timeout, -# "recreate_index": st.session_state[ConfigState.DOC_STORE_KEY].get("recreate_index") -# } -# st.success("Updated document store configuration")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
wren-ai-service/tools/providers-setup/ui_components.py
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
wren-ai-service/tools/providers-setup/ui_components.py (5)
wren-ai-service/tools/providers-setup/session_state.py (1)
ConfigState
(5-208)wren-ai-service/src/config.py (1)
config_loader
(87-97)wren-ai-service/tools/providers-setup/config_loader.py (2)
load_selected_example_yaml
(24-35)apply_config_blocks
(115-127)wren-ai-service/tools/providers-setup/dry_run_test.py (2)
llm_completion_test
(6-31)llm_embedding_test
(34-66)wren-ai-service/tools/providers-setup/constants.py (3)
get_env_path
(80-87)get_config_path
(69-77)get_config_done_path
(59-67)
🪛 Ruff (0.11.9)
wren-ai-service/tools/providers-setup/ui_components.py
370-371: SyntaxError: Expected an indented block after if
statement
395-395: SyntaxError: Unexpected indentation
399-399: SyntaxError: Expected a statement
🪛 Pylint (3.3.7)
wren-ai-service/tools/providers-setup/ui_components.py
[error] 371-371: Parsing failed: 'expected an indented block after 'if' statement on line 370 (ui_components, line 371)'
(E0001)
🔇 Additional comments (7)
wren-ai-service/tools/providers-setup/ui_components.py (7)
1-9
: LGTM: Clean and appropriate imports.The imports are well-organized and include the necessary modules for the Streamlit UI functionality. The
ast
import indicates proper security practices for safe evaluation.
10-35
: LGTM: Secure YAML loading with proper error handling.The function correctly uses
yaml.safe_load_all()
for secure YAML parsing and includes appropriate error handling for both GitHub examples and user uploads.
37-143
: LGTM: Comprehensive API key management with proper validation.The function provides robust API key management with appropriate validation, duplicate checking, and secure .env file handling. The logic for updating existing keys and adding new ones is well-implemented.
145-211
: LGTM: Well-structured LLM configuration interface.The function provides a comprehensive interface for managing LLM models with dynamic form handling, validation, and testing capabilities. The separation of concerns with validation in a separate function is good practice.
214-296
: LGTM: Robust embedding model configuration with validation.The function provides comprehensive embedding model configuration with proper input validation, type checking, and testing capabilities. The error handling for integer conversion is well-implemented.
399-429
: LGTM: Clean preview and configuration generation logic.Both functions are well-implemented with proper error handling and clear separation of concerns between preview display and configuration saving.
🧰 Tools
🪛 Ruff (0.11.9)
399-399: SyntaxError: Expected a statement
432-563
: LGTM: Security issue resolved and comprehensive validation.The utility functions are well-implemented with proper validation and error handling. Notably, the security concern from previous reviews has been addressed by using
ast.literal_eval()
instead ofeval()
on line 448, which safely evaluates string literals without the risk of code injection.
def render_pipeline_config(): | ||
""" | ||
Render the pipeline configuration section. | ||
Allows selecting LLM models for each defined pipeline step. | ||
""" | ||
pipeline_llm_options = [] | ||
all_pipelines = st.session_state[ConfigState.PIPELINE_KEY].get("pipes", []) | ||
|
||
# set all LLM models options | ||
for model in st.session_state[ConfigState.LLM_MODELS_KEY]: | ||
if model.get("alias"): | ||
pipeline_llm_options.append("litellm_llm." + model["alias"]) | ||
elif model.get("model"): | ||
pipeline_llm_options.append("litellm_llm." + model["model"]) | ||
|
||
# enumerate all pipelines, record original index | ||
for original_idx, pipe in enumerate(all_pipelines): | ||
if not pipe.get("llm"): | ||
continue | ||
|
||
pipe_name = pipe.get("name", f"Unnamed Pipeline {original_idx}") | ||
with st.expander(f"🔧 Pipeline: {pipe_name}", expanded=False): | ||
for key, value in pipe.items(): | ||
if key == "llm": | ||
for key, value in pipe.items(): | ||
if key == "llm": | ||
# Ensure we have a default value | ||
default_index = 0 | ||
if value in pipeline_llm_options: | ||
default_index = pipeline_llm_options.index(value) | ||
|
||
selected_llm = st.selectbox( | ||
"LLM Model", | ||
options=pipeline_llm_options, | ||
index=default_index, | ||
key=f"llm_{original_idx}" | ||
) | ||
else: | ||
st.markdown(f"**{key}:** `{value}`") | ||
|
||
if st.button("💾 Save this llm", key=f"save_{pipe_name}_{original_idx}"): | ||
# Only proceed if we have a selected LLM | ||
if 'selected_llm' in locals(): | ||
# ✅ use original index to update llm | ||
st.session_state[ConfigState.PIPELINE_KEY]["pipes"][original_idx]["llm"] = selected_llm | ||
st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`") | ||
else: | ||
st.error("No LLM selected for this pipeline.") | ||
st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Fix syntax errors and restructure pipeline configuration logic.
This section contains multiple critical syntax errors that prevent the code from running:
- Syntax Error: The for loop at line 369 has no body (missing indented block)
- Duplicate Code: The for loop is duplicated at lines 369 and 371
- Incorrect Indentation: Lines 371-396 have wrong indentation levels
- Duplicate Code: Line 395 duplicates the success message from line 392
Apply this diff to fix the syntax errors and logic:
- for key, value in pipe.items():
- if key == "llm":
-for key, value in pipe.items():
- if key == "llm":
- # Ensure we have a default value
- default_index = 0
- if value in pipeline_llm_options:
- default_index = pipeline_llm_options.index(value)
-
- selected_llm = st.selectbox(
- "LLM Model",
- options=pipeline_llm_options,
- index=default_index,
- key=f"llm_{original_idx}"
- )
- else:
- st.markdown(f"**{key}:** `{value}`")
-
-if st.button("💾 Save this llm", key=f"save_{pipe_name}_{original_idx}"):
- # Only proceed if we have a selected LLM
- if 'selected_llm' in locals():
- # ✅ use original index to update llm
- st.session_state[ConfigState.PIPELINE_KEY]["pipes"][original_idx]["llm"] = selected_llm
- st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`")
- else:
- st.error("No LLM selected for this pipeline.")
- st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`")
+ selected_llm = None
+ for key, value in pipe.items():
+ if key == "llm":
+ # Ensure we have a default value
+ default_index = 0
+ if value in pipeline_llm_options:
+ default_index = pipeline_llm_options.index(value)
+
+ selected_llm = st.selectbox(
+ "LLM Model",
+ options=pipeline_llm_options,
+ index=default_index,
+ key=f"llm_{original_idx}"
+ )
+ else:
+ st.markdown(f"**{key}:** `{value}`")
+
+ if st.button("💾 Save this llm", key=f"save_{pipe_name}_{original_idx}"):
+ # Only proceed if we have a selected LLM
+ if selected_llm is not None:
+ # ✅ use original index to update llm
+ st.session_state[ConfigState.PIPELINE_KEY]["pipes"][original_idx]["llm"] = selected_llm
+ st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`")
+ else:
+ st.error("No LLM selected for this pipeline.")
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
def render_pipeline_config(): | |
""" | |
Render the pipeline configuration section. | |
Allows selecting LLM models for each defined pipeline step. | |
""" | |
pipeline_llm_options = [] | |
all_pipelines = st.session_state[ConfigState.PIPELINE_KEY].get("pipes", []) | |
# set all LLM models options | |
for model in st.session_state[ConfigState.LLM_MODELS_KEY]: | |
if model.get("alias"): | |
pipeline_llm_options.append("litellm_llm." + model["alias"]) | |
elif model.get("model"): | |
pipeline_llm_options.append("litellm_llm." + model["model"]) | |
# enumerate all pipelines, record original index | |
for original_idx, pipe in enumerate(all_pipelines): | |
if not pipe.get("llm"): | |
continue | |
pipe_name = pipe.get("name", f"Unnamed Pipeline {original_idx}") | |
with st.expander(f"🔧 Pipeline: {pipe_name}", expanded=False): | |
for key, value in pipe.items(): | |
if key == "llm": | |
for key, value in pipe.items(): | |
if key == "llm": | |
# Ensure we have a default value | |
default_index = 0 | |
if value in pipeline_llm_options: | |
default_index = pipeline_llm_options.index(value) | |
selected_llm = st.selectbox( | |
"LLM Model", | |
options=pipeline_llm_options, | |
index=default_index, | |
key=f"llm_{original_idx}" | |
) | |
else: | |
st.markdown(f"**{key}:** `{value}`") | |
if st.button("💾 Save this llm", key=f"save_{pipe_name}_{original_idx}"): | |
# Only proceed if we have a selected LLM | |
if 'selected_llm' in locals(): | |
# ✅ use original index to update llm | |
st.session_state[ConfigState.PIPELINE_KEY]["pipes"][original_idx]["llm"] = selected_llm | |
st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`") | |
else: | |
st.error("No LLM selected for this pipeline.") | |
st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`") | |
def render_pipeline_config(): | |
""" | |
Render the pipeline configuration section. | |
Allows selecting LLM models for each defined pipeline step. | |
""" | |
pipeline_llm_options = [] | |
all_pipelines = st.session_state[ConfigState.PIPELINE_KEY].get("pipes", []) | |
# set all LLM models options | |
for model in st.session_state[ConfigState.LLM_MODELS_KEY]: | |
if model.get("alias"): | |
pipeline_llm_options.append("litellm_llm." + model["alias"]) | |
elif model.get("model"): | |
pipeline_llm_options.append("litellm_llm." + model["model"]) | |
# enumerate all pipelines, record original index | |
for original_idx, pipe in enumerate(all_pipelines): | |
if not pipe.get("llm"): | |
continue | |
pipe_name = pipe.get("name", f"Unnamed Pipeline {original_idx}") | |
with st.expander(f"🔧 Pipeline: {pipe_name}", expanded=False): | |
# initialize selection | |
selected_llm = None | |
for key, value in pipe.items(): | |
if key == "llm": | |
# Ensure we have a default value | |
default_index = 0 | |
if value in pipeline_llm_options: | |
default_index = pipeline_llm_options.index(value) | |
selected_llm = st.selectbox( | |
"LLM Model", | |
options=pipeline_llm_options, | |
index=default_index, | |
key=f"llm_{original_idx}" | |
) | |
else: | |
st.markdown(f"**{key}:** `{value}`") | |
if st.button("💾 Save this llm", key=f"save_{pipe_name}_{original_idx}"): | |
# Only proceed if we have a selected LLM | |
if selected_llm is not None: | |
st.session_state[ConfigState.PIPELINE_KEY]["pipes"][original_idx]["llm"] = selected_llm | |
st.success(f"✅ Updated pipeline `{pipe_name}` LLM to `{selected_llm}`") | |
else: | |
st.error("No LLM selected for this pipeline.") |
🧰 Tools
🪛 Ruff (0.11.9)
370-371: SyntaxError: Expected an indented block after if
statement
395-395: SyntaxError: Unexpected indentation
🪛 Pylint (3.3.7)
[error] 371-371: Parsing failed: 'expected an indented block after 'if' statement on line 370 (ui_components, line 371)'
(E0001)
🤖 Prompt for AI Agents
In wren-ai-service/tools/providers-setup/ui_components.py around lines 347 to
396, fix the syntax errors by removing the duplicated for loop at line 371 and
ensuring the for loop at line 369 has a proper indented body. Correct the
indentation of lines 371 to 396 so they are nested correctly inside the pipeline
expander and the for loop. Remove the duplicate success message on line 395.
This will resolve the missing block error, eliminate duplicate code, and
properly structure the pipeline configuration rendering logic.
Create a UI to help users set up the model.
Summary by CodeRabbit
New Features
Chores