-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix: add auth-aware first-run onboarding to prevent cryptic failures #2126
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
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -63,50 +63,6 @@ def _parse_permissions(allow: Optional[List[str]], deny: Optional[List[str]], pe | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return config if config else None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _check_api_key_available() -> bool: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Check if an API key is available from environment or stored credentials. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Also injects stored credentials into environment if no env key is present. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| True if an API key is available, False otherwise | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check all known provider env vars first | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| known_keys = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GOOGLE_API_KEY", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "GEMINI_API_KEY", "GROQ_API_KEY", "COHERE_API_KEY", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if any(os.environ.get(k) for k in known_keys): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Try to inject stored credentials into env, then re-check any known provider key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ...llm.credentials import inject_credentials_into_env | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inject_credentials_into_env() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except ImportError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Fallback if credential module not available | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check all known provider env vars after potential injection | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if any(os.environ.get(k) for k in known_keys): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Final check using LLM resolution with credential fallback | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ...llm.credentials import resolve_llm_endpoint_with_credentials | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endpoint = resolve_llm_endpoint_with_credentials() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return bool(endpoint.api_key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except ImportError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Fallback to basic env check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return bool(os.environ.get("OPENAI_API_KEY")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @app.callback(invoke_without_command=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def run_main( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ctx: typer.Context, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -156,6 +112,50 @@ def run_main( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output = get_output_controller() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _ = get_current_context() # Initialize context | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Early credential check before any processing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if target: # Only check if we actually have something to run | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ...llm.credentials import is_configured | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check if credentials are configured (use model if provided, else check general) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not is_configured(model): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # In non-interactive mode, show clear error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not sys.stdin.isatty() or output.is_json_mode: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.print_error( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "No API key configured. Run: praisonai setup\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "or set environment variables like OPENAI_API_KEY" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # In interactive mode, offer to run setup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typer.echo(f"No API key configured{f' for model {model}' if model else ''}.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run_setup = typer.confirm("Would you like to run the setup wizard now?") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if run_setup: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ..commands.setup import _run_setup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit_code = _run_setup( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| non_interactive=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| provider=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api_key=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model=None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if exit_code != 0: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.print_error("Setup failed. Exiting.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(exit_code) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.print_success("Setup complete! Continuing with your run...") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Re-check after setup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not is_configured(model): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.print_error("Setup completed but credentials still not detected.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+121
to
+150
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.
When a user passes The failure scenario is even worse on the re-check at line 96: if the user runs
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.print_info( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "To configure credentials:\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| " - Run: praisonai setup\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| " - Or set environment variables like OPENAI_API_KEY" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Resolve configuration if model not explicitly provided | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if model is None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -374,12 +374,7 @@ def _run_from_file( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Run agents from a YAML file.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output = get_output_controller() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Preflight check for API key availability | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not _check_api_key_available(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.print_error( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "No API key configured. Run: praisonai auth login" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Note: Credential check already done in run_main() entry point | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Use existing PraisonAI class | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -489,12 +484,7 @@ def _run_prompt( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Run a direct prompt.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output = get_output_controller() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Preflight check for API key availability | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not _check_api_key_available(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.print_error( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "No API key configured. Run: praisonai auth login" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Note: Credential check already done in run_main() entry point | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Handle session continuity first (before any execution mode) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -699,9 +689,35 @@ def _run_from_file_profiled( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| praison.config_list[0]['model'] = model | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Apply session continuity if requested | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id, auto_save_name = resolve_session_params( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue_session, session, fork, no_save | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto_save_name = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if continue_session or session or fork: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ..state.project_sessions import get_project_session_store, find_last_session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if continue_session: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = find_last_session() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not session_id: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typer.echo("Warning: No previous sessions found. Starting new session.", err=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif session: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| project_store = get_project_session_store() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if project_store.session_exists(session): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if fork: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from praisonaiagents.session.hierarchy import HierarchicalSessionStore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ..utils.project import get_project_sessions_dir | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hierarchical_store = HierarchicalSessionStore(str(get_project_sessions_dir())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| forked_session_id = hierarchical_store.fork_session(session_id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = forked_session_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
greptile-apps[bot] marked this conversation as resolved.
Comment on lines
+702
to
+713
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. Silent failure when specified session does not exist. When This inconsistency could cause confusing behavior where profiled runs silently ignore session flags. Proposed fix to add error handling if continue_session or session or fork:
from ..state.project_sessions import get_project_session_store, find_last_session
if continue_session:
session_id = find_last_session()
+ if not session_id:
+ typer.echo("Warning: No previous sessions found. Starting new session.", err=True)
elif session:
project_store = get_project_session_store()
if project_store.session_exists(session):
session_id = session
if fork:
from praisonaiagents.session.hierarchy import HierarchicalSessionStore
from ..utils.project import get_project_sessions_dir
hierarchical_store = HierarchicalSessionStore(str(get_project_sessions_dir()))
forked_session_id = hierarchical_store.fork_session(session_id)
session_id = forked_session_id
+ else:
+ typer.echo(f"Error: Session not found: {session}", err=True)
+ raise typer.Exit(1)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typer.echo(f"Error: Session not found: {session}", err=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not no_save: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import uuid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto_save_name = session_id or "session-" + str(uuid.uuid4())[:8] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if session_id or auto_save_name: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -866,9 +882,35 @@ def _run_prompt_profiled( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| agent_config["llm"] = model | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Apply session continuity if requested | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id, auto_save_name = resolve_session_params( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue_session, session, fork, no_save | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto_save_name = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if continue_session or session or fork: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ..state.project_sessions import get_project_session_store, find_last_session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if continue_session: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = find_last_session() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not session_id: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typer.echo("Warning: No previous sessions found. Starting new session.", err=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif session: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| project_store = get_project_session_store() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if project_store.session_exists(session): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if fork: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from praisonaiagents.session.hierarchy import HierarchicalSessionStore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ..utils.project import get_project_sessions_dir | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hierarchical_store = HierarchicalSessionStore(str(get_project_sessions_dir())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| forked_session_id = hierarchical_store.fork_session(session_id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_id = forked_session_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+895
to
+906
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. Same silent failure issue as This code has the identical missing error handling when Proposed fix to add error handling if continue_session or session or fork:
from ..state.project_sessions import get_project_session_store, find_last_session
if continue_session:
session_id = find_last_session()
+ if not session_id:
+ typer.echo("Warning: No previous sessions found. Starting new session.", err=True)
elif session:
project_store = get_project_session_store()
if project_store.session_exists(session):
session_id = session
if fork:
from praisonaiagents.session.hierarchy import HierarchicalSessionStore
from ..utils.project import get_project_sessions_dir
hierarchical_store = HierarchicalSessionStore(str(get_project_sessions_dir()))
forked_session_id = hierarchical_store.fork_session(session_id)
session_id = forked_session_id
+ else:
+ typer.echo(f"Error: Session not found: {session}", err=True)
+ raise typer.Exit(1)🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typer.echo(f"Error: Session not found: {session}", err=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise typer.Exit(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not no_save: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import uuid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto_save_name = session_id or "session-" + str(uuid.uuid4())[:8] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if session_id or auto_save_name: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ..state.project_sessions import build_cli_memory_config, apply_cli_session_continuity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -104,4 +104,69 @@ def inject_credentials_into_env() -> bool: | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||||||||||||
| # Ignore errors to avoid breaking the application | ||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def is_configured(model: Optional[str] = None) -> bool: | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
| Check if credentials are configured for the specified or default model. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| This checks both environment variables and stored credentials to determine | ||||||||||||||||||||||||||||||||||
| if the user has configured any usable API keys. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||
| model: Optional model name to check for specific provider credentials. | ||||||||||||||||||||||||||||||||||
| If not provided, checks for any configured credentials. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||
| True if credentials are available, False otherwise | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Check environment variables first | ||||||||||||||||||||||||||||||||||
| known_keys = ( | ||||||||||||||||||||||||||||||||||
| "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GOOGLE_API_KEY", | ||||||||||||||||||||||||||||||||||
| "GEMINI_API_KEY", "GROQ_API_KEY", "COHERE_API_KEY", | ||||||||||||||||||||||||||||||||||
| "OLLAMA_HOST", # Ollama doesn't need an API key | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # If any env var is set, consider it configured | ||||||||||||||||||||||||||||||||||
| if any(os.environ.get(k) for k in known_keys): | ||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Check stored credentials | ||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| store = CredentialStore() | ||||||||||||||||||||||||||||||||||
| providers = store.list_providers() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # If we have any stored credentials, we're configured | ||||||||||||||||||||||||||||||||||
| if providers: | ||||||||||||||||||||||||||||||||||
| # If model is specified, check for that specific provider | ||||||||||||||||||||||||||||||||||
| if model: | ||||||||||||||||||||||||||||||||||
| # Map model prefixes to providers | ||||||||||||||||||||||||||||||||||
| model_lower = model.lower() | ||||||||||||||||||||||||||||||||||
| if model_lower.startswith("gpt"): | ||||||||||||||||||||||||||||||||||
| return "openai" in [p.lower() for p in providers] | ||||||||||||||||||||||||||||||||||
| elif model_lower.startswith("claude"): | ||||||||||||||||||||||||||||||||||
| return "anthropic" in [p.lower() for p in providers] | ||||||||||||||||||||||||||||||||||
| elif model_lower.startswith("gemini"): | ||||||||||||||||||||||||||||||||||
| return "google" in [p.lower() for p in providers] or "gemini" in [p.lower() for p in providers] | ||||||||||||||||||||||||||||||||||
| elif model_lower.startswith("llama") or model_lower.startswith("mistral"): | ||||||||||||||||||||||||||||||||||
| # Could be Ollama or Groq | ||||||||||||||||||||||||||||||||||
| return "ollama" in [p.lower() for p in providers] or "groq" in [p.lower() for p in providers] | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Any stored credential means we're configured | ||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
Comment on lines
+126
to
+160
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. Model-specific gate is bypassed by unrelated credentials. Line 134 treats any credential signal (including Suggested fix (model-aware credential checks) def is_configured(model: Optional[str] = None) -> bool:
import os
+ provider_env = {
+ "openai": ("OPENAI_API_KEY",),
+ "anthropic": ("ANTHROPIC_API_KEY",),
+ "google": ("GOOGLE_API_KEY", "GEMINI_API_KEY"),
+ "gemini": ("GOOGLE_API_KEY", "GEMINI_API_KEY"),
+ "groq": ("GROQ_API_KEY",),
+ "cohere": ("COHERE_API_KEY",),
+ "ollama": ("OLLAMA_HOST",),
+ }
+
+ def providers_for_model(m: Optional[str]) -> Optional[set[str]]:
+ if not m:
+ return None
+ ml = m.lower()
+ if ml.startswith("gpt"):
+ return {"openai"}
+ if ml.startswith("claude"):
+ return {"anthropic"}
+ if ml.startswith("gemini"):
+ return {"google", "gemini"}
+ if ml.startswith("llama") or ml.startswith("mistral"):
+ return {"ollama", "groq"}
+ return set() # unknown: don't auto-pass; defer to resolver fallback
+
+ target = providers_for_model(model)
- known_keys = (
- "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GOOGLE_API_KEY",
- "GEMINI_API_KEY", "GROQ_API_KEY", "COHERE_API_KEY",
- "OLLAMA_HOST",
- )
- if any(os.environ.get(k) for k in known_keys):
- return True
+ if target is None:
+ known_keys = tuple(k for keys in provider_env.values() for k in keys)
+ if any(os.environ.get(k) for k in known_keys):
+ return True
+ elif target:
+ target_keys = tuple(k for p in target for k in provider_env[p])
+ if any(os.environ.get(k) for k in target_keys):
+ return True
try:
store = CredentialStore()
- providers = store.list_providers()
- if providers:
- ...
- return True
+ providers = {p.lower() for p in store.list_providers()}
+ if target is None:
+ return any((p == "ollama" and os.environ.get("OLLAMA_HOST")) or store.has_credential(p) for p in providers)
+ if target:
+ return any((p == "ollama" and os.environ.get("OLLAMA_HOST")) or store.has_credential(p) for p in (providers & target))
+ # unknown model: continue to resolver fallback
except Exception:
pass🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||||||||||||
| # If we can't check stored credentials, fall back to env check | ||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # Finally, check if we can resolve an endpoint with credentials | ||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| endpoint = resolve_llm_endpoint_with_credentials() | ||||||||||||||||||||||||||||||||||
| return bool(endpoint.api_key) | ||||||||||||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+165
to
+172
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.
Suggested change
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! |
||||||||||||||||||||||||||||||||||
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.
Missing credential re-check after setup completion.
Unlike the parallel implementation in
run.py(lines 137-140), this code path does not re-validate credentials after the setup wizard completes. If the user configures a provider other than OpenAI (which the hardcodedgpt-4o-minicheck requires), the TUI will launch and fail at the first LLM call.Proposed fix to add post-setup verification
if exit_code != 0: typer.echo("Setup failed. Exiting.", err=True) raise typer.Exit(exit_code) - # After successful setup, continue to TUI - typer.echo("\nSetup complete! Starting interactive mode...\n") + # Re-check credentials after setup + if not is_configured(model="gpt-4o-mini"): + typer.echo("Setup completed but credentials for gpt-4o-mini not detected.", err=True) + raise typer.Exit(1) + + typer.echo("\nSetup complete! Starting interactive mode...\n")📝 Committable suggestion
🤖 Prompt for AI Agents