{"repo": "akios-ai/akios", "files": {"src/akios/cli/commands/init.py": {"f65c3c742e9f8e1809a3371445b7a1fdfee8e320": {"t": 1785674545.0187573, "n": 44912, "h": "adf9efce08ecdd59", "c": "# Copyright (C) 2025-2026 AKIOUD AI, SAS \n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program. If not, see .\n\n\"\"\"\nCLI init command - akios init\n\nCreate basic project structure (config, example template).\n\"\"\"\n\nimport os\nfrom pathlib import Path\nimport argparse\nimport logging\n\ntry:\n from rich.console import Console\n _console = Console()\nexcept ImportError:\n _console = None\n\nlogger = logging.getLogger(__name__)\n\nfrom ...config import get_settings\nfrom ..helpers import CLIError, output_result\nfrom ..rich_helpers import output_with_mode, is_json_mode, is_quiet_mode\nfrom ...core.ui.commands import (\n SETUP_COMMAND, HELLO_WORKFLOW_COMMAND, DOCUMENT_INGESTION_COMMAND,\n BATCH_PROCESSING_COMMAND, FILE_ANALYSIS_COMMAND, STATUS_COMMAND, HELP_COMMAND,\n get_command_prefix, suggest_command\n)\n\n\ndef register_init_command(subparsers: argparse._SubParsersAction) -> None:\n \"\"\"\n Register the init command with the argument parser.\n\n Args:\n subparsers: Subparsers action from main parser\n \"\"\"\n parser = subparsers.add_parser(\n \"init\",\n help=\"Create project structure with templates (optionally in subdirectory)\"\n )\n\n parser.add_argument(\n \"project_name\",\n nargs=\"?\",\n default=None,\n help=\"Project name (optional - creates subdirectory, defaults to current directory)\"\n )\n\n parser.add_argument(\n \"--force\",\n action=\"store_true\",\n help=\"Overwrite existing files\"\n )\n\n parser.add_argument(\n \"--json\",\n action=\"store_true\",\n help=\"Output in JSON format\"\n )\n\n parser.add_argument(\n \"--quiet\",\n action=\"store_true\",\n help=\"Suppress welcome message and success output\"\n )\n\n parser.add_argument(\n \"--wizard\",\n action=\"store_true\",\n help=\"Run the setup wizard after project initialization\"\n )\n\n parser.set_defaults(func=run_init_command)\n\n\ndef run_init_command(args: argparse.Namespace) -> int:\n \"\"\"\n Execute the init command.\n\n Args:\n args: Parsed command line arguments\n\n Returns:\n Exit code\n \"\"\"\n try:\n # Show logo on first init (before any output)\n if not getattr(args, 'json', False):\n try:\n from ...core.ui.logo import should_show_logo, show_logo, mark_initialized\n if should_show_logo():\n show_logo()\n mark_initialized()\n except Exception:\n # Silent fail - never break CLI on logo display\n pass\n\n result = create_project_structure(project_name=args.project_name, force=args.force, json_mode=getattr(args, 'json', False))\n \n # Only output raw result in JSON mode to keep CLI clean\n if getattr(args, 'json', False):\n output_result(result, json_mode=True, success_message=\"Project initialized successfully\")\n\n # Run setup wizard if requested\n if getattr(args, 'wizard', False):\n output_with_mode(\n message=\"Initializing Security Configuration Wizard...\",\n json_mode=is_json_mode(getattr(args, 'json', False)),\n quiet_mode=False,\n output_type=\"info\"\n )\n try:\n from ...core.config.first_run import SetupWizard\n from pathlib import Path\n import os\n\n # Find the project directory\n project_dir = Path.cwd()\n if args.project_name:\n project_dir = project_dir / args.project_name\n\n wizard = SetupWizard(project_dir)\n if wizard.run_wizard():\n output_with_mode(\n message=\"Security configuration completed successfully.\",\n json_mode=is_json_mode(getattr(args, 'json', False)),\n quiet_mode=False,\n output_type=\"success\"\n )\n else:\n output_with_mode(\n message=\"Security configuration cancelled or incomplete.\",\n json_mode=is_json_mode(getattr(args, 'json', False)),\n quiet_mode=False,\n output_type=\"warning\"\n )\n return 1\n except Exception as e:\n output_with_mode(\n message=\"Security configuration failed.\",\n details=[str(e)],\n json_mode=is_json_mode(getattr(args, 'json', False)),\n quiet_mode=False,\n output_type=\"error\"\n )\n return 1\n\n # Add welcoming post-init message for better UX (unless --quiet or --json)\n if not getattr(args, 'quiet', False) and not getattr(args, 'json', False):\n # Minimalist welcome message\n from ...core.ui.rich_output import get_theme_color\n cyan = get_theme_color(\"info\")\n \n # Determine next steps based on whether we created a subdirectory\n project_dir = args.project_name\n \n steps = []\n if project_dir and project_dir != \".\":\n steps.append(f\"[{cyan}]cd {project_dir}[/{cyan}] [dim]Enter project directory[/dim]\")\n \n # Use dynamic prefix detection (Docker vs pip) for accurate instructions\n from ...core.ui.commands import get_command_prefix, suggest_command as _suggest\n cmd_prefix = get_command_prefix()\n steps.append(f\"[{cyan}]{_suggest('setup')}[/{cyan}] [dim]Configure API provider[/dim]\")\n steps.append(f\"[{cyan}]{_suggest('run templates/hello-workflow.yml')}[/{cyan}] [dim]Run first workflow[/dim]\")\n \n steps_text = \"\\n • \".join(steps)\n \n welcome_message = f\"\"\"[bold]Your secure AI workspace is ready.[/bold]\n\n[bold {cyan}]Quick Start[/bold {cyan}]\n • {steps_text}\n\n[dim]Run '{_suggest('setup')}' to get started.[/dim]\"\"\"\n\n output_with_mode(\n title=\"AKIOS Initialized\",\n message=welcome_message,\n json_mode=False,\n quiet_mode=False,\n output_type=\"panel\"\n )\n\n return 0\n\n except CLIError as e:\n output_with_mode(\n message=f\"Error: {e}\",\n json_mode=is_json_mode(getattr(args, 'json', False)),\n quiet_mode=False,\n output_type=\"error\"\n )\n return e.exit_code\n except Exception as e:\n from ..helpers import handle_cli_error\n return handle_cli_error(e, json_mode=args.json)\n\n\ndef create_project_structure(project_name: str = None, force: bool = False, json_mode: bool = False) -> dict:\n \"\"\"\n Create minimal project structure.\n\n Args:\n project_name: Name of project directory (optional)\n force: If True, overwrite existing files\n json_mode: If True, suppress console output for warnings\n \"\"\"\n # Determine base path\n base_path = Path(project_name) if project_name else Path(\".\")\n\n # Check if project already exists\n config_path = base_path / \"config.yaml\"\n templates_dir = base_path / \"templates\"\n\n # Check for actual user-created project\n # A real project has config.yaml (templates are installed by package, not user-created)\n config_exists = config_path.exists()\n\n project_exists = config_exists\n\n if project_exists and not force:\n raise CLIError(\n \"Project already exists. Use --force to overwrite.\",\n exit_code=1\n )\n\n created_files = []\n skipped_files = []\n\n # Create directories\n dirs_to_create = [\"templates\", \"workflows\", \"data/input\", \"data/output\", \"audit\"]\n for dir_path in dirs_to_create:\n dir_obj = base_path / dir_path\n dir_obj.mkdir(parents=True, exist_ok=True)\n created_files.append(str(dir_obj))\n\n # Create config.yaml\n if not config_path.exists() or force:\n config_content = create_default_config()\n config_path.write_text(config_content)\n created_files.append(str(config_path))\n else:\n skipped_files.append(str(config_path))\n\n # Create project launcher script ONLY in Docker environments.\n # On native Linux (pip install), the `akios` command is already on PATH —\n # creating a ./akios wrapper would shadow it and break the experience.\n _is_docker = (\n os.environ.get('AKIOS_DOCKER_WRAPPER') == '1'\n or os.path.exists('/.dockerenv')\n or os.path.exists('/run/.containerenv')\n )\n\n if _is_docker:\n from ..._version import __version__\n launcher_script = base_path / \"akios\"\n if not launcher_script.exists() or force:\n # Copy wrapper from Docker image location (/app/akios)\n docker_wrapper_path = Path(\"/app/akios\")\n if docker_wrapper_path.exists():\n try:\n import shutil\n shutil.copy2(docker_wrapper_path, launcher_script)\n launcher_script.chmod(0o755)\n created_files.append(str(launcher_script))\n except shutil.SameFileError:\n # Source and destination are the same file (e.g., /app/akios → ./akios)\n # This is expected when running init from the project root — silently skip\n skipped_files.append(str(launcher_script))\n except (OSError, IOError) as e:\n output_with_mode(\n message=f\"Could not copy launcher script from Docker image: {e}\",\n json_mode=json_mode,\n quiet_mode=False,\n output_type=\"warning\"\n )\n else:\n # Fallback: Read wrapper from package data\n try:\n try:\n from importlib.resources import files\n wrapper_content = files('akios.cli.data').joinpath('wrapper.sh').read_text()\n except (ImportError, AttributeError):\n from importlib.resources import read_text\n wrapper_content = read_text('akios.cli.data', 'wrapper.sh')\n\n launcher_script.write_text(wrapper_content)\n launcher_script.chmod(0o755)\n created_files.append(str(launcher_script))\n except Exception as e:\n # Last-resort minimal wrapper with dynamic version\n minimal_wrapper = f'''#!/bin/bash\nset -e\nif ! command -v docker >/dev/null 2>&1; then\n echo \"Docker is required to run AKIOS from this project.\"\n exit 1\nfi\nexec docker run --rm -v \"$(pwd):/app\" -w /app akiosai/akios:v{__version__} \"$@\"\n'''\n launcher_script.write_text(minimal_wrapper)\n launcher_script.chmod(0o755)\n created_files.append(str(launcher_script))\n else:\n skipped_files.append(str(launcher_script))\n\n # Create example workflows (copy from source templates)\n import shutil\n\n # Copy templates from package data using importlib.resources (Python 3.9+)\n try:\n from importlib.resources import files as _pkg_files\n\n templates_pkg = _pkg_files('akios.templates')\n template_files = []\n\n # List template files from package\n try:\n for item in templates_pkg.iterdir():\n if item.name.endswith(('.yml', '.yaml', '.md')) and item.is_file():\n template_files.append(item)\n except Exception:\n template_files = []\n\n if template_files:\n for item in template_files:\n dest_file = base_path / \"templates\" / item.name\n if not dest_file.exists() or force:\n try:\n content = item.read_bytes()\n dest_file.parent.mkdir(parents=True, exist_ok=True)\n with open(dest_file, 'wb') as f:\n f.write(content)\n created_files.append(str(dest_file))\n except Exception as e:\n output_with_mode(\n message=f\"Could not copy template {item.name}: {e}\",\n details=[f\"Will create basic template instead for {item.name}\"],\n json_mode=json_mode,\n quiet_mode=False,\n output_type=\"warning\"\n )\n else:\n # Fallback: create basic templates inline\n create_basic_templates(base_path, created_files, force)\n except Exception as e:\n # If copying fails, create basic templates inline\n output_with_mode(\n message=f\"Could not copy built-in templates ({e})\",\n details=[\"Creating basic example templates instead. You can customize them as needed.\"],\n json_mode=json_mode,\n quiet_mode=False,\n output_type=\"warning\"\n )\n create_basic_templates(base_path, created_files, force)\n\n # Create .gitignore if it doesn't exist\n gitignore_path = base_path / \".gitignore\"\n if not gitignore_path.exists():\n gitignore_content = create_gitignore()\n gitignore_path.write_text(gitignore_content)\n created_files.append(str(gitignore_path))\n\n # Create .env file with starter content (API keys commented out)\n akios_env_path = base_path / \".env\"\n if not akios_env_path.exists():\n akios_env_content = create_akios_env()\n akios_env_path.write_text(akios_env_content)\n created_files.append(str(akios_env_path))\n\n # Create .env.example template\n env_example_path = base_path / \".env.example\"\n if not env_example_path.exists():\n env_example_content = create_env_example()\n env_example_path.write_text(env_example_content)\n created_files.append(str(env_example_path))\n\n # Create README.md with project documentation\n readme_path = base_path / \"README.md\"\n if not readme_path.exists():\n readme_content = create_readme()\n readme_path.write_text(readme_content)\n created_files.append(str(readme_path))\n\n # Create sample documents for testing document_ingestion template (supported formats)\n sample_formats = ['.txt', '.pdf', '.docx']\n for ext in sample_formats:\n sample_doc_path = base_path / \"data\" / \"input\" / f\"document_example{ext}\"\n if not sample_doc_path.exists():\n try:\n # Try to copy from package sample files first\n try:\n from importlib import resources\n except ImportError:\n import importlib_resources as resources\n\n sample_content = resources.files('akios.cli.data.samples.document_examples').joinpath(f'sample{ext}').read_bytes()\n sample_doc_path.write_bytes(sample_content)\n created_files.append(str(sample_doc_path))\n except Exception as e:\n # Fallback to generating content dynamically\n sample_doc_content = create_sample_document()\n sample_doc_path.write_text(sample_doc_content)\n created_files.append(str(sample_doc_path))\n\n # Create sample analysis target files for file_analysis template (supported formats)\n analysis_formats = ['.txt', '.pdf', '.docx']\n for ext in analysis_formats:\n analysis_target_path = base_path / \"data\" / \"input\" / f\"analysis_target{ext}\"\n if not analysis_target_path.exists():\n try:\n # Try to copy from package sample files first\n try:\n from importlib import resources\n except ImportError:\n import importlib_resources as resources\n\n analysis_content = resources.files('akios.cli.data.samples.analysis_targets').joinpath(f'sample{ext}').read_bytes()\n if ext == '.txt':\n analysis_target_path.write_text(analysis_content.decode('utf-8'))\n else:\n # For binary files (PDF, DOCX)\n analysis_target_path.write_bytes(analysis_content)\n created_files.append(str(analysis_target_path))\n except Exception as e:\n # Fallback to generating content dynamically (only for .txt)\n if ext == '.txt':\n analysis_content = create_sample_analysis_file()\n analysis_target_path.write_text(analysis_content)\n created_files.append(str(analysis_target_path))\n\n # Create sample batch input data for batch_processing template\n batch_dir = base_path / \"data\" / \"input\" / \"batch\"\n batch_dir.mkdir(parents=True, exist_ok=True)\n \n # Create sample business documents\n sample_files = [\n (\"customer_feedback.txt\", \"Customer feedback for Q4 2024:\\n- Product quality excellent\\n- Customer service responsive\\n- Pricing competitive\\n- Would recommend to colleagues\"),\n (\"sales_report.json\", '{\"quarter\": \"Q4\", \"revenue\": 250000, \"growth\": \"15%\", \"top_products\": [\"Widget A\", \"Widget B\"]}'),\n (\"employee_notes.md\", \"# Team Meeting Notes\\n## Action Items\\n- Complete project documentation\\n- Schedule client review\\n- Update security protocols\\n## Decisions\\n- Approved budget increase\\n- New hire starting next month\")\n ]\n \n for filename, content in sample_files:\n file_path = batch_dir / filename\n if not file_path.exists():\n file_path.write_text(content)\n created_files.append(str(file_path))\n\n return {\n \"created_files\": created_files,\n \"skipped_files\": skipped_files,\n \"message\": \"AKIOS project initialized\"\n }\n\n\ndef create_default_config() -> str:\n \"\"\"Create default config.yaml content\"\"\"\n return \"\"\"# AKIOS Configuration\n# Security-first defaults - modify carefully\n\n# Security cage essentials\nsandbox_enabled: true\ncpu_limit: 0.8\nmemory_limit_mb: 256\nmax_open_files: 100\n\n# Network control\n# LLM API calls always pass through (AI orchestration is the purpose).\n# This setting controls the HTTP agent for arbitrary web requests only.\nnetwork_access_allowed: false\n# Whitelist specific domains for HTTP agent when network_access_allowed is false:\n# allowed_domains: [\"api.salesforce.com\", \"api.example.com\"]\n\n# PII & compliance\npii_redaction_enabled: true\nredaction_strategy: \"mask\"\n\n# Cost & loop protection\ncost_kill_enabled: true\nmax_tokens_per_call: 1000\nbudget_limit_per_run: 1.0\n\n# Audit & paths\naudit_enabled: true\naudit_export_enabled: true\naudit_storage_path: \"./audit/\"\naudit_export_format: \"json\"\n\n# General\nenvironment: \"development\"\nlog_level: \"INFO\"\n\"\"\"\n\n\ndef create_example_workflow() -> str:\n \"\"\"Create example workflow content\"\"\"\n return \"\"\"name: example_workflow\ndescription: Example AKIOS workflow demonstrating LLM and filesystem agents\n\nsteps:\n - step: 1\n agent: llm\n action: generate\n parameters:\n prompt: \"Write a brief summary of artificial intelligence and its current applications.\"\n max_tokens: 200\n\n - step: 2\n agent: filesystem\n action: write\n parameters:\n path: \"./data/output/ai_summary.txt\"\n content: \"This file will contain the AI summary from the LLM agent.\"\n\n - step: 3\n agent: filesystem\n action: list\n parameters:\n path: \"./data\"\n\"\"\"\n\n\ndef create_basic_templates(base_path: Path, created_files: list, force: bool = False) -> None:\n \"\"\"Create basic template files inline\"\"\"\n templates_dir = base_path / \"templates\"\n\n # Basic hello workflow\n hello_template = templates_dir / \"hello-workflow.yml\"\n if not hello_template.exists() or force:\n hello_content = \"\"\"name: Hello World Workflow\ndescription: |\n A simple introductory workflow demonstrating basic AKIOS functionality.\n Creates a greeting file, reads it back, and shows audit logging.\n\n This is the \"Hello World\" example for new AKIOS users.\n\nsteps:\n # Step 1: Create a simple greeting file\n - step: 1\n agent: filesystem\n config:\n allowed_paths: [\"./data/output\"]\n read_only: false\n action: write\n parameters:\n path: \"./data/output/hello.txt\"\n content: \"Hello, World from AKIOS!\"\n\n # Step 2: Read the file back to verify it was created\n - step: 2\n agent: filesystem\n config:\n allowed_paths: [\"./data/output\"]\n action: read\n parameters:\n path: \"./data/output/hello.txt\"\n\"\"\"\n hello_template.write_text(hello_content)\n created_files.append(str(hello_template))\n\n # Basic LLM workflow\n llm_template = templates_dir / \"document_ingestion.yml\"\n if not llm_template.exists() or force:\n llm_content = \"\"\"name: Secure Document Processing\ndescription: |\n Hero example demonstrating AKIOS's security cage: PII redaction, Merkle audit trail,\n and sandboxed execution. This workflow reads a document, automatically redacts PII,\n generates a summary, and exports a tamper-evident audit report.\n\n Shows: Security-first design, real-time PII protection, cryptographic integrity.\n\nsteps:\n # Step 1: Read document from secure filesystem (path whitelisted)\n - step: 1\n agent: filesystem\n config:\n allowed_paths: [\"./data/input\"]\n action: read\n parameters:\n path: \"./data/input/document.txt\"\n # Security: Path is whitelisted, read-only access enforced\n\n # Step 2: Automatic PII redaction (enforced by security layer)\n # Note: PII redaction happens automatically before LLM processing\n # This step shows the redaction in action via audit logs\n\n # Step 3: LLM analysis with cost controls (max tokens, budget limits)\n - step: 2\n agent: llm\n config:\n provider: grok # Options: openai, anthropic, grok, mistral, gemini, bedrock, ollama\n api_key: \"${GROK_API_KEY}\" # Or ${OPENAI_API_KEY}, ${ANTHROPIC_API_KEY}, ${MISTRAL_API_KEY}, ${GEMINI_API_KEY}\n model: \"grok-3\" # Or gpt-4o-mini, claude-3.5-sonnet\n action: complete\n parameters:\n prompt: |\n Analyze this document and provide a concise summary.\n Focus on key facts, entities, and main points.\n Document content will be provided with any sensitive information automatically redacted.\n max_tokens: 300\n # Security: Token limits prevent runaway costs, automatic kill-switches\n\n # Step 4: Store processed result (path whitelisted, controlled access)\n - step: 3\n agent: filesystem\n config:\n allowed_paths: [\"./data/output\"]\n read_only: false\n action: write\n parameters:\n path: \"./data/output/summary.txt\"\n content: \"{previous_output}\"\n # Security: Write access controlled, path restrictions enforced\n\"\"\"\n llm_template.write_text(llm_content)\n created_files.append(str(llm_template))\n\n\ndef create_akios_env() -> str:\n \"\"\"Create sample .env content\"\"\"\n return \"\"\"# AKIOS Environment Configuration\n# Edit this file with your API keys and settings\n# This file is automatically loaded when running akios commands\n# WARNING: Contains sensitive API keys - NEVER commit to version control!\n\n# === API KEYS ===\n# Get your API keys from the respective providers:\n\n# OpenAI: https://platform.openai.com/api-keys\n# OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic: https://console.anthropic.com/\n# ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Grok/xAI: https://console.x.ai/\n# GROK_API_KEY=xai-your-grok-key-here\n\n# Mistral AI: https://console.mistral.ai/\n# MISTRAL_API_KEY=your-mistral-key-here\n\n# Gemini/Google: https://makersuite.google.com/app/apikey\n# GEMINI_API_KEY=your-gemini-key-here\n\n# AWS Bedrock: https://aws.amazon.com/bedrock/ (uses IAM — no API key needed on EC2/ECS)\n# AWS_ACCESS_KEY_ID=your-access-key\n# AWS_SECRET_ACCESS_KEY=your-secret-key\n# AWS_DEFAULT_REGION=us-east-1\n# AKIOS_BEDROCK_MODEL_ID=anthropic.claude-3-sonnet-20240229-v1:0\n# AKIOS_BEDROCK_REGION=us-east-1\n\n# Ollama (local): https://ollama.com/ (no API key needed — runs locally)\n# OLLAMA_BASE_URL=http://localhost:11434\n# AKIOS_LLM_PROVIDER=ollama\n# AKIOS_LLM_MODEL=llama3\n\n# === LLM SETTINGS ===\n# Default LLM provider and model\n# AKIOS_LLM_PROVIDER=openai # Options: openai, anthropic, grok, mistral, gemini, bedrock, ollama\n# AKIOS_LLM_MODEL=gpt-4o-mini # Or claude-3.5-sonnet, grok-4.1-fast\n\n# === DEVELOPMENT ===\n# Use mock responses for testing (no API calls) - WARNING: Not for production!\nAKIOS_MOCK_LLM=1\n\n# NOTE: For local development, edit the LOCAL_DEV_MODE variable in the wrapper script\n# Set LOCAL_DEV_MODE=1 in ./akios wrapper to use akios:latest (local dev build)\n# Default LOCAL_DEV_MODE=0 uses akiosai/akios:vX.X.X (stable Docker Hub release)\n\n# === SECURITY ===\n# PII redaction settings\n# AKIOS_PII_REDACTION_ENABLED=true\n\"\"\"\n\n\ndef create_env_example() -> str:\n \"\"\"Create .env.example template content\"\"\"\n return \"\"\"# AKIOS Environment Configuration Example\n# Copy this file to .env and fill in your actual API keys\n# WARNING: Never commit .env to version control!\n\n# === API KEYS ===\n# Get your API keys from the respective providers:\n\n# OpenAI: https://platform.openai.com/api-keys\n# OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic: https://console.anthropic.com/\n# ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Grok/xAI: https://console.x.ai/\n# GROK_API_KEY=xai-your-grok-key-here\n\n# Mistral AI: https://console.mistral.ai/\n# MISTRAL_API_KEY=your-mistral-key-here\n\n# Gemini/Google: https://makersuite.google.com/app/apikey\n# GEMINI_API_KEY=your-gemini-key-here\n\n# AWS Bedrock: https://aws.amazon.com/bedrock/ (uses IAM — no API key needed on EC2/ECS)\n# AWS_ACCESS_KEY_ID=your-access-key\n# AWS_SECRET_ACCESS_KEY=your-secret-key\n# AWS_DEFAULT_REGION=us-east-1\n# AKIOS_BEDROCK_MODEL_ID=anthropic.claude-3-sonnet-20240229-v1:0\n# AKIOS_BEDROCK_REGION=us-east-1\n\n# Ollama (local): https://ollama.com/ (no API key needed — runs locally)\n# OLLAMA_BASE_URL=http://localhost:11434\n# AKIOS_LLM_PROVIDER=ollama\n# AKIOS_LLM_MODEL=llama3\n\n# === AKIOS SETTINGS ===\n# Default LLM provider and model (Options: openai, anthropic, grok, mistral, gemini, bedrock, ollama)\n# Provider is auto-detected from your API key — these are optional overrides.\n# AKIOS_LLM_PROVIDER=grok\n# AKIOS_LLM_MODEL=grok-3\n\n# Development/Testing\n# AKIOS_MOCK_LLM=1\n# AKIOS_MOCK_LLM=0\n\n# Security & Performance\n# AKIOS_BUDGET_LIMIT_PER_RUN=1.0\n# AKIOS_MAX_TOKENS_PER_CALL=500\n\n# === SECURITY CAGE ===\n# These settings are managed by 'akios cage up/down' but can be set manually.\n# Auto PII masking on inputs/outputs\nAKIOS_PII_REDACTION_ENABLED=true\n# Block external HTTPS (LLM API calls always pass through)\nAKIOS_NETWORK_ACCESS_ALLOWED=false\n# Process isolation (always recommended)\nAKIOS_SANDBOX_ENABLED=true\n# Cryptographic audit logging\nAKIOS_AUDIT_ENABLED=true\n\n# Whitelisted domains (comma-separated, allowed even when network is locked)\n# AKIOS_ALLOWED_DOMAINS=api.example.com,data.example.org\n\"\"\"\n\n\ndef create_gitignore() -> str:\n \"\"\"Create .gitignore content\"\"\"\n return \"\"\"# AKIOS project\n__pycache__/\n*.pyc\n*.pyo\n*.pyd\n.Python\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Environment variables (contains API keys)\n.env\n\n# Audit logs (contain sensitive data)\naudit/\n*.pdf\n*.json\n\n# Data directories\ndata/output/\ndata/input/private/\n\n# Config overrides\nconfig.local.yaml\n\n# OS files\n.DS_Store\nThumbs.db\n\"\"\"\n\n\ndef create_readme() -> str:\n \"\"\"Create README.md content for the project\"\"\"\n return f\"\"\"# AKIOS Project\n\nWelcome to your AKIOS (AI Knowledge & Intelligence Operating System) project! This is a secure, sandboxed environment for running AI workflows with military-grade security.\n\n## 🚀 Quick Start\n\n1. **Test immediately** (mock mode enabled by default):\n ```bash\n # Test workflows without API keys first:\n {HELLO_WORKFLOW_COMMAND}\n {DOCUMENT_INGESTION_COMMAND}\n ```\n\n **Direct Docker (if you do not have `{get_command_prefix()}`):**\n ```bash\n docker run --rm -v \"$(pwd):/app\" -w /app akiosai/akios:v1.5.0 run templates/hello-workflow.yml\n ```\n\n2. **Configure for API workflows** (if using batch_processing.yml):\n ```bash\n # Edit config.yaml to allow network access:\n network_access_allowed: true # Required for external API calls\n ```\n\n3. **Configure real API Keys** for production use:\n ```bash\n # Edit .env file and set AKIOS_MOCK_LLM=0, then add your API key:\n # For OpenAI: OPENAI_API_KEY=sk-your-key-here\n # For Anthropic: ANTHROPIC_API_KEY=sk-ant-your-key-here\n # For Grok: GROK_API_KEY=xai-your-key-here\n # For Mistral: MISTRAL_API_KEY=your-mistral-key-here\n # For Gemini: GEMINI_API_KEY=your-gemini-key-here\n # For Bedrock: AWS_DEFAULT_REGION=us-east-1 (uses IAM)\n # For Ollama: OLLAMA_BASE_URL=http://localhost:11434 (local, no key needed)\n ```\n\n## 📁 Project Structure\n\n```\nyour-project/\n├── README.md # This file - project documentation\n├── workflow.yml # ← YOUR active workflow (created by templates)\n├── .env # API keys and configuration (edit this!)\n├── .env.example # Template with placeholder keys (copy to .env)\n├── config.yaml # 🔐 SECURITY SETTINGS - controls network access, sandboxing, costs\n├── .gitignore # Git ignore rules\n├── templates/ # Pre-built workflow templates\n│ ├── hello-workflow.yml\n│ ├── batch_processing.yml\n│ └── ...\n├── data/ # Data files and workflow outputs\n│ ├── input/ # Input data for workflows\n│ │ ├── document_example.txt # Sample documents for testing\n│ │ ├── document_example.pdf # (.txt, .pdf, .docx supported)\n│ │ ├── document_example.docx # Replace with your real files\n│ │ └── document_example.jpg #\n│ └── output/ # Workflow results saved here\n└── audit/ # Security audit logs and reports\n```\n\n**Note**: AKIOS organizes outputs in timestamped directories (like `run_20240124_143022`) to keep each workflow run separate and prevent accidental overwrites. Use `run_*` wildcards to access the latest results.\n\n## 🚀 Available Templates\n\nAKIOS comes with 4 pre-built workflow templates. Here's what each one does:\n\n| Template | Purpose | Input Required | Output | Network Access | Security Features |\n|----------|---------|----------------|--------|---------------|-------------------|\n| **hello-workflow.yml** | Generate creative AI greetings | None (uses prompt only) | `data/output/run_*/hello-ai.txt` | LLM API calls | LLM sandboxing, audit logging |\n| **document_ingestion.yml** | Analyze documents with PII redaction | `data/input/[filename]` (.txt, .pdf, .docx supported) | `data/output/run_*/summary.txt` + audit | LLM API calls | PII redaction, Merkle audit trail |\n| **file_analysis.yml** | Analyze files with container isolation | `data/input/[filename]` | `data/output/run_*/analysis.txt` | None | Container sandboxing, safe tool execution |\n| **batch_processing.yml** | Multi-file AI analysis with aggregation | `data/input/batch/` (directory) | `data/output/run_*/batch-summary.json` | LLM API calls | Cost tracking, batch PII protection |\n\n### Quick Start Examples\n\n```bash\n# Hello world example\n{HELLO_WORKFLOW_COMMAND}\n\n# Batch processing workflow\n{BATCH_PROCESSING_COMMAND}\n\n# Document analysis\n{FILE_ANALYSIS_COMMAND}\n\n# Direct Docker (if you do not have {get_command_prefix()})\ndocker run --rm -v \"$(pwd):/app\" -w /app akiosai/akios:v1.5.0 run templates/hello-workflow.yml\n```\n\n### Creating Custom Workflows\n\n1. Run a template: {HELLO_WORKFLOW_COMMAND}\n2. Edit the created workflow.yml: `nano workflow.yml`\n3. Run your customized version: {get_command_prefix()} run workflow.yml\n\n## 📖 Command Reference\n\nAKIOS provides 21 commands organized by function:\n\n### Project Management\n| Command | Description |\n|---------|-------------|\n| `{get_command_prefix()} init` | Create a new AKIOS project with config, templates, and sample data |\n| `{get_command_prefix()} setup` | Interactive setup wizard for API keys and preferences |\n| `{get_command_prefix()} status` | Show system status, last run summary, and budget info |\n| `{get_command_prefix()} doctor` | Run diagnostics and security checks |\n\n### Workflow Execution\n| Command | Description |\n|---------|-------------|\n| `{get_command_prefix()} run ` | Execute a workflow with full security sandboxing |\n| `{get_command_prefix()} templates list` | List available workflow templates |\n| `{get_command_prefix()} templates select` | Interactively select and run a template |\n\n### Security Cage\n| Command | Description |\n|---------|-------------|\n| `{get_command_prefix()} cage up` | Activate full security cage (PII redaction, HTTPS lock, sandbox) |\n| `{get_command_prefix()} cage down` | Relax security for development (sandbox stays on) |\n| `{get_command_prefix()} cage status` | Show current cage posture and protection status |\n| `{get_command_prefix()} security` | Alias for `cage` — same commands available |\n\n### PII Protection\n| Command | Description |\n|---------|-------------|\n| `{get_command_prefix()} protect preview ` | Preview PII detection on a workflow file |\n| `{get_command_prefix()} protect scan ` | Scan a file for PII and show redaction results |\n\n### Audit & Compliance\n| Command | Description |\n|---------|-------------|\n| `{get_command_prefix()} audit export` | Export cryptographic audit reports (JSON) |\n| `{get_command_prefix()} audit verify` | Verify Merkle-chain integrity of audit trail |\n| `{get_command_prefix()} audit log` | View recent audit log entries |\n| `{get_command_prefix()} compliance report ` | Security posture check (basic/detailed/executive) |\n| `{get_command_prefix()} logs` | Show recent workflow execution logs |\n\n### File Management\n| Command | Description |\n|---------|-------------|\n| `{get_command_prefix()} files` | Show available input and output files |\n| `{get_command_prefix()} output list` | List workflow outputs |\n| `{get_command_prefix()} output clean ` | Clean old outputs |\n| `{get_command_prefix()} output archive ` | Archive outputs to tarball |\n\n### Utilities\n| Command | Description |\n|---------|-------------|\n| `{get_command_prefix()} clean` | Remove old workflow runs (default: >7 days) |\n| `{get_command_prefix()} docs` | View documentation with Markdown rendering |\n| `{get_command_prefix()} timeline` | View workflow execution timeline |\n| `{get_command_prefix()} testing` | View environment notes and testing context |\n\n## 🔑 API Configuration\n\n**Environment Setup:**\n- `.env.example` - Template file with placeholder keys (safe to commit)\n- `.env` - Your working file with real API keys (NEVER commit this!)\n\nCopy `.env.example` to `.env` and fill in your real API keys:\n\n```bash\ncp .env.example .env\n# Then edit .env with your actual keys\n```\n\nEdit the `.env` file to configure your LLM provider:\n\n### OpenAI\n```bash\nOPENAI_API_KEY=sk-your-openai-key-here\nAKIOS_LLM_PROVIDER=openai\nAKIOS_LLM_MODEL=gpt-4o-mini # or gpt-4o\n```\n\n### Anthropic\n```bash\nANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\nAKIOS_LLM_PROVIDER=anthropic\nAKIOS_LLM_MODEL=claude-3.5-sonnet # or claude-3.5-haiku\n```\n\n### Grok (xAI)\n```bash\nGROK_API_KEY=xai-your-grok-key-here\nAKIOS_LLM_PROVIDER=grok\nAKIOS_LLM_MODEL=grok-3 # or grok-4.1\n```\n\n### Mistral AI\n```bash\nMISTRAL_API_KEY=your-mistral-key-here\nAKIOS_LLM_PROVIDER=mistral\nAKIOS_LLM_MODEL=mistral-small # or mistral-medium\n```\n\n### Gemini (Google)\n```bash\nGEMINI_API_KEY=your-gemini-key-here\nAKIOS_LLM_PROVIDER=gemini\nAKIOS_LLM_MODEL=gemini-1.5-flash # or gemini-1.5-pro\n```\n\n## 🚨 PRODUCTION WARNING: Mock Mode\n\n**⚠️ NEVER use AKIOS_MOCK_LLM=1 in production environments!**\n\nMock mode provides simulated AI responses for **testing only**. Production deployments must use real API keys and disable mock mode:\n\n### ❌ What Mock Mode Does:\n- Returns fake AI responses instead of real LLM calls\n- Bypasses actual API authentication and costs\n- Provides no real AI intelligence or analysis\n- Audit logs will show mock mode usage warnings\n\n### ✅ Production Requirements:\n- Set `AKIOS_MOCK_LLM=0` in `.env`\n- Configure real API keys for your chosen provider\n- Enable `network_access_allowed: true` in `config.yaml`\n- Monitor actual API costs and usage\n\n### 🔍 How to Verify Production Readiness:\n```bash\n# Check configuration\n{suggest_command('status')}\n\n# Look for:\n# ✅ Real API keys detected\n# ❌ Mock mode: Disabled (should NOT appear)\n# ✅ Network access: Enabled\n```\n\n## ⚙️ Configuration Settings\n\nAKIOS uses a `config.yaml` file to control security and runtime behavior. **Edit this file carefully** - these settings control your security cage.\n\n### 🔐 Network Access Control\n\n**`network_access_allowed`** - Controls ALL external network access:\n- `false` (default): **Blocks all external API calls** (HTTP + LLM)\n- `true`: **Allows external API calls** (required for most workflows)\n\n```yaml\n# Security-first default - no external access\nnetwork_access_allowed: false\n```\n\n**When to change:**\n- Set to `true` if using templates that call external APIs (batch_processing.yml)\n- Keep `false` for maximum security when only processing local data\n\n**Security Impact:**\n- `false`: Complete network isolation, maximum security\n- `true`: Allows HTTP requests and LLM API calls\n\n### 🛡️ Other Security Settings\n\n```yaml\n# Process isolation and resource limits\nsandbox_enabled: true # Required for security\ncpu_limit: 0.8 # CPU usage limit (0.0-1.0)\nmemory_limit_mb: 256 # Memory limit in MB\nmax_open_files: 100 # Maximum open file descriptors\n\n# Data protection\npii_redaction_enabled: true # Auto PII masking\nredaction_strategy: \"mask\" # How to redact sensitive data\n\n# Cost protection (LLM calls)\ncost_kill_enabled: true # Enable cost limits\nmax_tokens_per_call: 1000 # Token limit per LLM call\nbudget_limit_per_run: 1.0 # Max cost per workflow ($)\n\n# Audit and compliance\naudit_enabled: true # Enable audit logging\naudit_storage_path: \"./audit/\" # Where to store audit logs\naudit_export_format: \"pdf\" # Audit report format\n```\n\n### 🚨 Critical Security Notes\n\n1. **Never set `network_access_allowed: true` unnecessarily** - it allows external API calls\n2. **Keep `sandbox_enabled: true`** - this provides process isolation\n3. **Monitor costs** - set reasonable `budget_limit_per_run` values\n4. **PII redaction is automatic** - sensitive data is masked in logs and responses\n\n### 📋 Configuration Examples\n\n**Maximum Security** (default):\n```yaml\nnetwork_access_allowed: false # No external access\nsandbox_enabled: true\npii_redaction_enabled: true\nbudget_limit_per_run: 1.0\n```\n\n**API Workflows** (required for batch_processing.yml):\n```yaml\nnetwork_access_allowed: true # Allow external API calls\nsandbox_enabled: true\npii_redaction_enabled: true\nbudget_limit_per_run: 5.0 # Higher budget for API work\n```\n\n## 🏃 Running Workflows\n\n### Using Templates\n```bash\n# Hello world example\n{HELLO_WORKFLOW_COMMAND}\n\n# Batch processing workflow\n{BATCH_PROCESSING_COMMAND}\n\n# Document analysis\n{FILE_ANALYSIS_COMMAND}\n```\n\n### Creating Custom Workflows\n1. Run a template: {HELLO_WORKFLOW_COMMAND}\n2. Edit the created workflow.yml: `nano workflow.yml`\n3. Run your customized version: {get_command_prefix()} run workflow.yml\n\n### Workflow Format\n```yaml\nname: \"My Workflow\"\ndescription: \"What this workflow does\"\n\nsteps:\n - name: \"LLM Task\"\n type: \"llm\"\n prompt: \"Your prompt here\"\n model: \"grok-3\" # optional, uses AKIOS_LLM_MODEL if not set\n\n - name: \"Save Result\"\n type: \"save\"\n path: \"data/output/result.txt\"\n```\n\n## 🔒 Security Features\n\nAKIOS provides **military-grade security**:\n\n- **Sandboxing**: Complete process isolation\n- **PII Redaction**: Automatic sensitive data masking\n- **Audit Logging**: Cryptographic audit trail\n- **Resource Limits**: CPU, memory, and cost controls\n- **Command Allowlisting**: Only approved operations permitted\n\n### Deployment Options\n\n**🐳 Docker (Cross-platform)**: Policy-based security, recommended for most users\n- Works on macOS, Windows, Linux\n- Command allowlisting + PII redaction\n- No kernel modifications needed\n\n**🐧 Native Linux (Maximum Security)**: Full kernel-hard sandboxing\n- Linux-only, maximum protection\n- cgroups v2 + seccomp-bpf syscall filtering\n- For production/high-security environments\n\n## 📊 Monitoring & Status\n\n```bash\n# Check system status\n{suggest_command('status')}\n\n# View audit logs\n{suggest_command('audit')}\n\n# Export audit reports\n{suggest_command('audit export --format pdf')}\n```\n\n## 🆘 Troubleshooting\n\n### Common Issues\n\n**\"API key not found\"**\n- Check that you've uncommented and set the correct API key in `.env`\n- Verify the key format (starts with `sk-` for OpenAI, `sk-ant-` for Anthropic, `xai-` for Grok, or provider-specific formats for Mistral/Gemini)\n\n**\"Workflow not found\"**\n- Use relative paths: `templates/hello-workflow.yml`\n- Check that the file exists in the `templates/` directory or that `workflow.yml` exists in the project root\n\n**\"Permission denied\"**\n- Check that Docker is running\n\n**\"Security warnings\"**\n- These are normal - AKIOS shows security status\n- Docker deployment uses policy-based security (weaker than native Linux)\n- For maximum security, deploy on native Linux\n\n### Getting Help\n\n- **Documentation**: Check `templates/README.md` for workflow examples\n- **Status Check**: Run `{suggest_command('status')}` for system diagnostics\n- **Logs**: Recent activity in `audit/` directory\n\n## 🎯 Next Steps\n\n1. **Test the templates**: Try all workflows with mock responses\n2. **Explore multi-format support**: Test with sample files (document_example.*) in .txt, .pdf, or .docx formats\n3. **Configure real API keys** in `.env` (set `AKIOS_MOCK_LLM=0`)\n4. **Customize workflows** by editing `workflow.yml` after running templates\n5. **Check security status**: `{suggest_command('status')}`\n\nHappy AI workflow building with AKIOS! 🚀🤖\n\"\"\"\n\n\ndef create_sample_document() -> str:\n \"\"\"Create sample document content for testing document_ingestion template\"\"\"\n return \"\"\"Sample Business Document - Q4 2025 Financial Report\n\nDear Mr. John Smith,\n\nThis confidential document contains sensitive information about our company's Q4 2025 performance.\n\nContact Information:\n- Email: john.smith@company.com\n- Phone: (555) 123-4567\n- Address: 123 Business Street, Suite 456, New York, NY 10001\n\nFinancial Summary:\nRevenue: $2.5 million\nExpenses: $1.8 million\nNet Profit: $700,000\n\nKey Achievements:\n1. Increased market share by 15%\n2. Launched 3 new products\n3. Expanded to 5 new international markets\n\nEmployee Information:\n- CEO: Sarah Johnson (sarah.johnson@company.com)\n- CFO: Michael Davis (michael.davis@company.com, phone: 555-987-6543)\n- HR Director: Emily Chen (emily.chen@company.com)\n\nStrategic Initiatives for 2026:\n- AI implementation across all departments\n- Expansion into European markets\n- Development of sustainable product lines\n- Digital transformation completion\n\nPlease treat this information as confidential and do not share with unauthorized personnel.\n\nBest regards,\nBoard of Directors\nCompany Inc.\nDate: January 4, 2026\"\"\"\n\n\ndef create_sample_analysis_file() -> str:\n \"\"\"Create sample file content for testing file_analysis template\"\"\"\n return \"\"\"Sample Analysis Target File - Security Intelligence Test Data\n\nContact Information:\nEmail: john.doe@company.com\nPhone: (555) 123-4567\nBackup Email: admin@security.example.org\n\nNetwork Data:\nIP Address: 192.168.1.100\nExternal IP: 203.0.113.45\nDomain: https://secure-api.company.com/v1/data\nURL: http://malicious-site.ru/download.exe\n\nFinancial Data:\nCredit Card: 4111 1111 1111 1111 (Visa test card)\nAccount Number: 1234567890123456\nTransaction Amount: $2,459.99\n\nSystem Logs:\nTimestamp: 2024-01-15 14:30:22 UTC\nError Code: 500\nUser ID: 987654\nSession ID: abc123def456\n\nSecurity Events:\nLogin attempt from IP 10.0.0.1 at 2024-01-15 09:15:33\nSuspicious activity detected: 47 failed login attempts\nFile hash: a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3\n\nBusiness Metrics:\nTotal Revenue: $1,250,000\nActive Users: 15,432\nConversion Rate: 3.45%\nGrowth Rate: 127.8%\n\nThis file contains various patterns for testing automated security analysis, pattern detection, and threat assessment capabilities.\"\"\"\n"}}, "src/akios/config/modes.py": {"f65c3c742e9f8e1809a3371445b7a1fdfee8e320": {"t": 1785674546.2229652, "n": 11377, "h": "b9031245e2dce1be", "c": "# Copyright (C) 2025-2026 AKIOUD AI, SAS \n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program. If not, see .\n\n\"\"\"\nMode switching utilities for AKIOS\n\nProvides automatic configuration switching between mock and real API modes.\nHandles interactive API key setup and validation.\n\"\"\"\n\nimport os\nimport sys\nfrom pathlib import Path\nfrom typing import Dict, Optional\n\nfrom .settings import Settings\nfrom .loader import get_settings\nfrom .validation import validate_config\n\n\ndef switch_to_real_api_mode() -> None:\n \"\"\"\n Switch to real API mode by modifying environment and configuration.\n\n This function:\n 1. Sets AKIOS_MOCK_LLM=0 (disable mock mode)\n 2. Sets network_access_allowed=true in config\n 3. Prompts for missing API keys interactively\n 4. Validates the configuration\n\n Raises:\n ValueError: If configuration cannot be switched or validated\n \"\"\"\n # Modify environment variables\n os.environ['AKIOS_MOCK_LLM'] = '0'\n\n # Modify configuration file if it exists\n config_path = Path('config.yaml')\n if config_path.exists():\n try:\n import yaml\n with open(config_path, 'r', encoding='utf-8') as f:\n config = yaml.safe_load(f) or {}\n\n # Set network access to enabled\n config['network_access_allowed'] = True\n\n with open(config_path, 'w', encoding='utf-8') as f:\n yaml.dump(config, f, default_flow_style=False, sort_keys=False)\n\n except Exception as e:\n raise ValueError(f\"Failed to update config.yaml: {e}\")\n\n # Check for required API keys and prompt if missing\n _ensure_api_keys_available()\n\n # Validate the new configuration\n try:\n settings = get_settings()\n validate_config(settings)\n except Exception as e:\n raise ValueError(f\"Real API mode configuration validation failed: {e}\")\n\n\ndef _ensure_api_keys_available() -> None:\n \"\"\"\n Ensure required API keys are available, prompting user if needed.\n\n Checks for API keys in this priority order:\n 1. Environment variables (highest priority)\n 2. .env file\n 3. Interactive prompt (fallback)\n\n Raises:\n ValueError: If required API keys cannot be obtained\n \"\"\"\n # Define supported providers and their key requirements\n providers = {\n 'openai': ['OPENAI_API_KEY'],\n 'anthropic': ['ANTHROPIC_API_KEY'],\n 'grok': ['GROK_API_KEY'],\n 'mistral': ['MISTRAL_API_KEY'],\n 'gemini': ['GEMINI_API_KEY']\n }\n\n # Get current LLM provider setting\n provider = os.environ.get('AKIOS_LLM_PROVIDER', 'grok') # Default to grok\n\n if provider not in providers:\n raise ValueError(f\"Unsupported LLM provider: {provider}. Supported: {', '.join(providers.keys())}\")\n\n required_keys = providers[provider]\n\n # Check if all required keys are available\n missing_keys = []\n for key in required_keys:\n if not os.environ.get(key):\n missing_keys.append(key)\n\n if missing_keys:\n # Try to load from .env file first\n env_file = Path('.env')\n if env_file.exists():\n _load_keys_from_env_file(env_file, missing_keys)\n\n # Check again after loading from file\n still_missing = []\n for key in missing_keys:\n if not os.environ.get(key):\n still_missing.append(key)\n missing_keys = still_missing\n\n # If still missing, prompt interactively\n if missing_keys:\n _prompt_for_api_keys(missing_keys, provider)\n\n\ndef _load_keys_from_env_file(env_file: Path, keys_to_load: list) -> None:\n \"\"\"\n Load specific API keys from .env file into environment.\n\n Args:\n env_file: Path to .env file\n keys_to_load: List of environment variable names to load\n \"\"\"\n try:\n with open(env_file, 'r', encoding='utf-8') as f:\n for line in f:\n line = line.strip()\n if not line or line.startswith('#'):\n continue\n\n if '=' in line:\n key, value = line.split('=', 1)\n key = key.strip()\n value = value.strip()\n\n if key in keys_to_load and value:\n os.environ[key] = value\n if key in keys_to_load:\n keys_to_load.remove(key)\n\n except Exception:\n # Silently continue if .env file cannot be read\n pass\n\n\ndef _prompt_for_api_keys(missing_keys: list, provider: str) -> None:\n \"\"\"\n Interactively prompt user for missing API keys.\n\n Works in both native terminal and Docker container environments.\n Handles TTY availability and provides graceful fallbacks.\n\n Args:\n missing_keys: List of environment variable names needed\n provider: LLM provider name for context\n\n Raises:\n ValueError: If user cancels or provides invalid input\n \"\"\"\n print(f\"\\n🔑 API Key Setup for {provider.title()}\", file=sys.stderr)\n print(\"The following API keys are required but not found:\", file=sys.stderr)\n print(file=sys.stderr)\n\n provider_docs = {\n 'openai': 'https://platform.openai.com/api-keys',\n 'anthropic': 'https://console.anthropic.com/',\n 'grok': 'https://console.x.ai/',\n 'mistral': 'https://console.mistral.ai/',\n 'gemini': 'https://makersuite.google.com/app/apikey'\n }\n\n doc_url = provider_docs.get(provider, 'provider documentation')\n print(f\"Get your API key from: {doc_url}\", file=sys.stderr)\n print(file=sys.stderr)\n\n # Check if we have TTY access (important for Docker containers)\n try:\n has_tty = sys.stdin.isatty() and sys.stdout.isatty()\n except Exception:\n has_tty = False\n\n if not has_tty:\n print(\"❌ Interactive input not available (no TTY access)\", file=sys.stderr)\n print(\"Please set API keys manually using environment variables or .env file\", file=sys.stderr)\n print(f\"Required keys: {', '.join(missing_keys)}\", file=sys.stderr)\n raise ValueError(\"Cannot prompt for API keys: no interactive terminal available\")\n\n for key in missing_keys:\n while True:\n try:\n # Use stderr for prompts to avoid interfering with stdout\n prompt = f\"Enter {key}: \"\n value = input(prompt).strip()\n\n if not value:\n print(\"API key cannot be empty. Please try again.\", file=sys.stderr)\n continue\n\n # Basic validation\n if len(value) < 10:\n print(\"API key seems too short. Please verify and try again.\", file=sys.stderr)\n continue\n\n if not _validate_api_key_format(key, value):\n print(\"API key format appears invalid. Please check and try again.\", file=sys.stderr)\n continue\n\n os.environ[key] = value\n\n # Optionally save to .env file\n _offer_to_save_to_env(key, value)\n break\n\n except (EOFError, KeyboardInterrupt):\n print(\"\\n❌ API key setup cancelled.\", file=sys.stderr)\n raise ValueError(\"API key setup was cancelled by user\")\n\n\ndef _validate_api_key_format(key: str, value: str) -> bool:\n \"\"\"\n Perform basic format validation for API keys.\n\n Args:\n key: Environment variable name\n value: API key value\n\n Returns:\n bool: True if format appears valid\n \"\"\"\n # Basic checks - these are not foolproof but catch obvious errors\n if not value.replace('-', '').replace('_', '').replace('.', '').isalnum():\n return False\n\n # Provider-specific checks\n if key == 'OPENAI_API_KEY' and not value.startswith('sk-'):\n return False\n elif key == 'ANTHROPIC_API_KEY' and not value.startswith('sk-ant-'):\n return False\n # Grok keys can have various formats\n\n return True\n\n\ndef _offer_to_save_to_env(key: str, value: str) -> None:\n \"\"\"\n Offer to save the API key to .env file for persistence.\n\n Args:\n key: Environment variable name\n value: API key value\n \"\"\"\n try:\n response = input(\"Save this API key to .env file for future use? (y/N): \").strip().lower()\n if response in ['y', 'yes']:\n env_file = Path('.env')\n # Check if .env exists and has the key\n existing_content = \"\"\n if env_file.exists():\n with open(env_file, 'r', encoding='utf-8') as f:\n existing_content = f.read()\n\n # Add or update the key\n lines = existing_content.split('\\n') if existing_content else []\n key_found = False\n\n for i, line in enumerate(lines):\n if line.strip().startswith(f'{key}='):\n lines[i] = f'{key}={value}'\n key_found = True\n break\n\n if not key_found:\n if lines and not lines[-1].strip(): # Remove empty last line\n lines.pop()\n lines.append(f'{key}={value}')\n lines.append('') # Add trailing newline\n\n with open(env_file, 'w', encoding='utf-8') as f:\n f.write('\\n'.join(lines))\n\n print(f\"✅ API key saved to .env file\", file=sys.stderr)\n\n except Exception as e:\n print(f\"⚠️ Could not save to .env file: {e}\", file=sys.stderr)\n print(\"Your API key is set for this session only.\", file=sys.stderr)\n\n\ndef get_current_mode() -> Dict[str, any]:\n \"\"\"\n Get information about the current operating mode.\n\n Returns:\n dict: Mode information including mock status, provider, etc.\n \"\"\"\n try:\n settings = get_settings()\n return {\n 'mock_mode': os.environ.get('AKIOS_MOCK_LLM', '1') == '1',\n 'llm_provider': os.environ.get('AKIOS_LLM_PROVIDER', 'grok'),\n 'network_access': settings.network_access_allowed,\n 'has_api_keys': _check_api_keys_available()\n }\n except Exception:\n return {\n 'mock_mode': True,\n 'llm_provider': 'unknown',\n 'network_access': False,\n 'has_api_keys': False\n }\n\n\ndef _check_api_keys_available() -> bool:\n \"\"\"\n Check if the required API keys for current provider are available.\n\n Returns:\n bool: True if all required API keys are present\n \"\"\"\n provider = os.environ.get('AKIOS_LLM_PROVIDER', 'grok')\n providers = {\n 'openai': ['OPENAI_API_KEY'],\n 'anthropic': ['ANTHROPIC_API_KEY'],\n 'grok': ['GROK_API_KEY']\n }\n\n required_keys = providers.get(provider, [])\n return all(os.environ.get(key) for key in required_keys)\n"}}}}