-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix: resolve three high-impact gaps in praisonai wrapper layer #1736
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
Changes from all commits
8a690c6
b815a0d
fb255a3
17a580c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -549,12 +549,13 @@ def prepare_modelfile_content(self): | |
| """ | ||
|
|
||
| def create_and_push_ollama_model(self): | ||
| from ._ollama import create_and_push_ollama_model | ||
| modelfile_content = self.prepare_modelfile_content() | ||
| with open("Modelfile", "w") as file: | ||
| file.write(modelfile_content) | ||
| subprocess.run(["ollama", "serve"]) | ||
| subprocess.run(["ollama", "create", f"{self.config['ollama_model']}:{self.config['model_parameters']}", "-f", "Modelfile"]) | ||
| subprocess.run(["ollama", "push", f"{self.config['ollama_model']}:{self.config['model_parameters']}"]) | ||
| create_and_push_ollama_model( | ||
| self.config['ollama_model'], | ||
| self.config['model_parameters'], | ||
| modelfile_content | ||
| ) | ||
|
Comment on lines
551
to
+558
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The correct approach for a script file is to use an absolute/path-based import, e.g. |
||
|
|
||
| def run(self): | ||
| self.print_system_info() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| """Shared Ollama daemon management utilities. | ||
|
|
||
| This module provides utilities to start and check Ollama daemon status, | ||
| fixing the blocking subprocess.run(["ollama", "serve"]) issue present | ||
| in multiple files. | ||
| """ | ||
| import contextlib | ||
| import shutil | ||
| import socket | ||
| import subprocess | ||
| import time | ||
| from typing import Optional | ||
|
|
||
|
|
||
| def _ollama_ready(host: str = "127.0.0.1", port: int = 11434, timeout: float = 0.2) -> bool: | ||
| """Check if Ollama daemon is ready to accept connections. | ||
|
|
||
| Args: | ||
| host: Ollama host (default 127.0.0.1) | ||
| port: Ollama port (default 11434) | ||
| timeout: Connection timeout in seconds | ||
|
|
||
| Returns: | ||
| True if Ollama is ready, False otherwise | ||
| """ | ||
| with contextlib.suppress(OSError): | ||
| with socket.create_connection((host, port), timeout): | ||
| return True | ||
| return False | ||
|
|
||
|
|
||
| def ensure_ollama_running(max_wait_seconds: float = 5.0) -> Optional[subprocess.Popen]: | ||
| """Ensure Ollama daemon is running, start it if necessary. | ||
|
|
||
| Args: | ||
| max_wait_seconds: Maximum time to wait for daemon to become ready | ||
|
|
||
| Returns: | ||
| Process object if we started the daemon, None if it was already running | ||
|
|
||
| Raises: | ||
| RuntimeError: If ollama CLI not found or daemon doesn't become ready | ||
| """ | ||
| # Check if already running | ||
| if _ollama_ready(): | ||
| return None | ||
|
|
||
| # Check if ollama CLI is available | ||
| if shutil.which("ollama") is None: | ||
| raise RuntimeError("`ollama` CLI not found; install from https://ollama.com") | ||
|
|
||
| # Start daemon in detached mode | ||
| proc = subprocess.Popen( | ||
| ["ollama", "serve"], | ||
| stdout=subprocess.DEVNULL, | ||
| stderr=subprocess.DEVNULL, | ||
| start_new_session=True, # Detach from parent | ||
| ) | ||
|
|
||
| # Poll until ready or timeout | ||
| wait_interval = 0.1 | ||
| max_polls = int(max_wait_seconds / wait_interval) | ||
|
|
||
| for _ in range(max_polls): | ||
| if _ollama_ready(): | ||
| return proc | ||
| time.sleep(wait_interval) | ||
|
|
||
| # If we get here, daemon didn't become ready in time | ||
| proc.terminate() | ||
| raise RuntimeError(f"ollama serve did not become ready in {max_wait_seconds} seconds") | ||
|
|
||
|
|
||
| def create_and_push_ollama_model(ollama_model: str, model_parameters: str, modelfile_content: str) -> None: | ||
| """Create and push an Ollama model with proper daemon management. | ||
|
|
||
| Args: | ||
| ollama_model: Name of the Ollama model | ||
| model_parameters: Model parameters/tag | ||
| modelfile_content: Content for the Modelfile | ||
|
|
||
| Raises: | ||
| RuntimeError: If ollama operations fail | ||
| subprocess.CalledProcessError: If create/push commands fail | ||
| """ | ||
| # Write Modelfile | ||
| with open("Modelfile", "w") as f: | ||
| f.write(modelfile_content) | ||
|
Comment on lines
+86
to
+88
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Writing to a hardcoded 🛠️ Proposed fix using tempfile+import tempfile
+
def create_and_push_ollama_model(ollama_model: str, model_parameters: str, modelfile_content: str) -> None:
...
- # Write Modelfile
- with open("Modelfile", "w") as f:
- f.write(modelfile_content)
+ # Write Modelfile to a temporary file
+ with tempfile.NamedTemporaryFile(mode="w", suffix="_Modelfile", delete=False) as f:
+ f.write(modelfile_content)
+ modelfile_path = f.name
# Ensure daemon is running
ensure_ollama_running()
# Create and push model
tag = f"{ollama_model}:{model_parameters}"
- subprocess.run(["ollama", "create", tag, "-f", "Modelfile"], check=True)
+ subprocess.run(["ollama", "create", tag, "-f", modelfile_path], check=True)
subprocess.run(["ollama", "push", tag], check=True)
+
+ # Cleanup
+ os.unlink(modelfile_path)🤖 Prompt for AI Agents |
||
|
|
||
| # Ensure daemon is running | ||
| ensure_ollama_running() | ||
|
|
||
| # Create and push model | ||
| tag = f"{ollama_model}:{model_parameters}" | ||
|
|
||
| subprocess.run(["ollama", "create", tag, "-f", "Modelfile"], check=True) | ||
| subprocess.run(["ollama", "push", tag], check=True) | ||
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.
threading.Lockblocks the event loop under contention in async contextself._client_lockis athreading.Lock. Inside an async method, if two coroutines concurrently pass the outerNonecheck and then race towith self._client_lock:, the second coroutine blocks the entire event loop thread until the lock is released. A dedicatedasyncio.Lockfor the async client would be the idiomatic fix.