""" Command-line interface for oracle_answer tool. Uses NVIDIA's free API (build.nvidia.com) for actual LLM responses. NOTE FOR AUTOMATION: - All CLI arguments must be defined ONLY in build_parser(). - When changing CLI flags, rewrite build_parser() entirely. - Do not define duplicate flags like --question in other functions. """ import argparse import asyncio import json import sys from typing import List, Optional from .tool import OracleAnswerTool def build_parser() -> argparse.ArgumentParser: """ Build argument parser. RULE: This function is the single source of truth for CLI args. Never append args elsewhere. """ parser = argparse.ArgumentParser( prog="oracle-answer", description="Sovereign compliance oracle powered by NVIDIA AI.", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: oracle-answer --question "Are we GDPR compliant?" --frameworks GDPR ISO-27001 oracle-answer --question "Incident response time SLA?" --mode advisory oracle-answer --question "Test?" --local-only (skip NVIDIA API) """, ) parser.add_argument( "--question", required=True, type=str, help="Compliance / security question to answer.", ) parser.add_argument( "--frameworks", nargs="*", default=["NIST-CSF", "ISO-27001"], type=str, help="Frameworks to reference (space-separated).", ) parser.add_argument( "--mode", default="strict", choices=["strict", "advisory"], help="strict = conservative, advisory = more exploratory.", ) parser.add_argument( "--json", action="store_true", help="Output ToolResponse as JSON instead of pretty text.", ) parser.add_argument( "--local-only", action="store_true", help="Skip NVIDIA API calls (for testing).", ) return parser async def main_async(args: Optional[List[str]] = None) -> int: """Async main entry point.""" parser = build_parser() ns = parser.parse_args(args=args) tool = OracleAnswerTool( default_frameworks=ns.frameworks, use_local_only=ns.local_only, ) resp = await tool.answer( question=ns.question, frameworks=ns.frameworks, mode=ns.mode, ) if ns.json: print( json.dumps( { "answer": resp.answer, "framework_hits": resp.framework_hits, "reasoning": resp.reasoning, "model": resp.model, }, indent=2, ) ) else: print("\n" + "=" * 80) print("ORACLE ANSWER (Powered by NVIDIA AI)") print("=" * 80 + "\n") print(resp.answer) if resp.reasoning: print("\n--- Reasoning ---\n") print(resp.reasoning) if resp.framework_hits: print("\n--- Framework Hits ---\n") for framework, hits in resp.framework_hits.items(): if hits: print(f"{framework}:") for hit in hits: print(f" • {hit}") print(f"\n[Model: {resp.model}]") print() return 0 def main() -> None: """Sync wrapper for CLI entry point.""" try: sys.exit(asyncio.run(main_async())) except KeyboardInterrupt: sys.exit(1) if __name__ == "__main__": main()