From 827b7ae1ee7b30e400700c55c474ad939fb388b2 Mon Sep 17 00:00:00 2001 From: d-claro Date: Thu, 30 Jul 2026 09:51:17 +0100 Subject: [PATCH 1/3] feat: add Bitbucket setup and config.json structure --- .gitignore | 3 ++- agent/menu.py | 5 ++++- config.example.json | 8 ++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 config.example.json diff --git a/.gitignore b/.gitignore index feea328..4ef37e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ venv/ __pycache__/ *.pyc -.DS_Store \ No newline at end of file +.DS_Store +config.json \ No newline at end of file diff --git a/agent/menu.py b/agent/menu.py index e765ab6..6d9866a 100644 --- a/agent/menu.py +++ b/agent/menu.py @@ -19,7 +19,7 @@ def create_pull_request(): # Select platform platform = questionary.select( "Select platform:", - choices=["GitHub", "GitLab", "Cancel"] + choices=["GitHub", "GitLab", "Bitbucket", "Cancel"] ).ask() if platform == "Cancel": @@ -111,6 +111,9 @@ def create_pull_request(): elif platform == "GitLab": print("\n⚠️ GitLab integration coming soon.\n") + elif platform == "Bitbucket": + print("\n⚠️ Bitbucket integration coming soon.\n") + def main(): while True: print("\n🤖 QA Agent\n") diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..26ed377 --- /dev/null +++ b/config.example.json @@ -0,0 +1,8 @@ +{ + "project": "Your Project Name", + "platform": "GitHub", + "available_platforms": ["GitHub", "GitLab", "Bitbucket"], + "base_branch": "main", + "slack_channel": "#your-channel", + "slack_token": "your-slack-token-here" +} \ No newline at end of file From f4c7399e2a746a25b1fe1e986640552a4ed22bd4 Mon Sep 17 00:00:00 2001 From: d-claro Date: Wed, 16 Sep 2026 14:38:14 +0100 Subject: [PATCH 2/3] merge: bring config.example.json from bitbucket-setup branch --- agent/menu.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/agent/menu.py b/agent/menu.py index fa91e3d..40865db 100644 --- a/agent/menu.py +++ b/agent/menu.py @@ -235,7 +235,6 @@ def create_pull_request(platform="GitHub"): elif platform == "GitLab": print("\n⚠️ GitLab integration coming soon.\n") -<<<<<<< HEAD def pull_requests_menu(): """Submenu for Pull Requests.""" while True: @@ -415,10 +414,6 @@ def roadmap_menu(): elif choice == "⬅️ Back": break -======= - elif platform == "Bitbucket": - print("\n⚠️ Bitbucket integration coming soon.\n") ->>>>>>> feature/bitbucket-setup def main(): while True: From a2a88ef02a2acd2896d95152e7a88d2f3d727404 Mon Sep 17 00:00:00 2001 From: d-claro Date: Wed, 16 Sep 2026 15:04:58 +0100 Subject: [PATCH 3/3] feat: add configurable AI provider support --- agent/cli.py | 89 +++++++++++++++++++++++++++++++++++++-------- agent/menu.py | 15 -------- config.example.json | 6 ++- config.json | 8 ++-- 4 files changed, 82 insertions(+), 36 deletions(-) diff --git a/agent/cli.py b/agent/cli.py index 1b08fab..eceaff2 100644 --- a/agent/cli.py +++ b/agent/cli.py @@ -7,6 +7,57 @@ TEST_CASES_PATH = os.path.join(BASE_DIR, "knowledge_base", "test_cases", "test_cases.json") HISTORY_PATH = os.path.join(BASE_DIR, "knowledge_base", "history.json") +CONFIG_PATH = os.path.join(BASE_DIR, "config.json") + +def load_config(): + """Loads the project configuration. Falls back to defaults if not found.""" + defaults = { + "ai_provider": "ollama", + "ai_model": "llama3.2", + "api_key": "" + } + + if not os.path.exists(CONFIG_PATH): + return defaults + + try: + with open(CONFIG_PATH, "r") as f: + config = json.load(f) + return {**defaults, **config} + except Exception: + return defaults + +def ask_ai(prompt): + """Sends a prompt to the configured AI provider and returns the response text.""" + config = load_config() + provider = config.get("ai_provider", "ollama").lower() + model = config.get("ai_model", "llama3.2") + + if provider == "ollama": + import ollama + response = ollama.chat( + model=model, + messages=[{"role": "user", "content": prompt}] + ) + return response["message"]["content"] + + elif provider == "claude": + raise NotImplementedError( + "Claude integration is not enabled yet.\n" + " It requires an Anthropic API key (console.anthropic.com).\n" + " Set 'ai_provider' to 'ollama' in config.json to continue." + ) + + elif provider == "openai": + raise NotImplementedError( + "OpenAI integration is not enabled yet.\n" + " It requires an OpenAI API key.\n" + " Set 'ai_provider' to 'ollama' in config.json to continue." + ) + + else: + raise ValueError(f"Unknown AI provider: '{provider}'. Use: ollama, claude, openai") + def log_event(event_type, test_id, details): """Logs an event to the project history.""" from datetime import datetime @@ -677,8 +728,6 @@ def export_tests_history(): @cli.command() def generate_test(): """Generate a test case automatically using AI.""" - import ollama - click.echo("\n🤖 AI Test Case Generator") click.echo(" 💡 Type 'cancel' at any point to abort.\n") @@ -718,16 +767,20 @@ def generate_test(): Generate between 3 and 5 steps. Be specific and technical. """ - click.echo("\n⏳ Generating test case...\n") + config = load_config() + click.echo(f"\n⏳ Generating test case... (using {config['ai_provider']} / {config['ai_model']})\n") - response = ollama.chat( - model="llama3.2", - messages=[{"role": "user", "content": prompt}] - ) + try: + raw = ask_ai(prompt) + except NotImplementedError as e: + click.echo(f"\n⚠️ {e}\n") + return + except Exception as e: + click.echo(f"\n❌ Error contacting the AI provider: {e}\n") + return import json as json_module try: - raw = response["message"]["content"] start = raw.find("{") end = raw.rfind("}") + 1 generated = json_module.loads(raw[start:end]) @@ -781,8 +834,6 @@ def generate_test(): @click.argument("question") def ask(question): """Ask a question to the AI agent based on the Knowledge Base.""" - import ollama - with open(TEST_CASES_PATH, "r") as f: test_cases = json.load(f) @@ -809,14 +860,20 @@ def ask(question): Answer the following question: {question} """ - click.echo("\n🤖 Thinking...\n") + config = load_config() + click.echo(f"\n🤖 Thinking... (using {config['ai_provider']} / {config['ai_model']})\n") + + try: + answer = ask_ai(context) + except NotImplementedError as e: + click.echo(f"\n⚠️ {e}\n") + return + except Exception as e: + click.echo(f"\n❌ Error contacting the AI provider: {e}\n") + return - response = ollama.chat( - model="llama3.2", - messages=[{"role": "user", "content": context}] - ) + click.echo(f"{answer}\n") - click.echo(f"{response['message']['content']}\n") if __name__ == "__main__": cli() \ No newline at end of file diff --git a/agent/menu.py b/agent/menu.py index 40865db..e8345bd 100644 --- a/agent/menu.py +++ b/agent/menu.py @@ -152,22 +152,7 @@ def create_pull_request(platform="GitHub"): os.system("clear") print(f"\n🔀 Create Pull Request — {platform}\n") -<<<<<<< HEAD title = questionary.text("PR Title (leave blank to cancel):").ask() -======= - # Select platform - platform = questionary.select( - "Select platform:", - choices=["GitHub", "GitLab", "Bitbucket", "Cancel"] - ).ask() - - if platform == "Cancel": - print("\n❌ PR creation cancelled.\n") - return - - # PR Title - title = questionary.text("PR Title:").ask() ->>>>>>> feature/bitbucket-setup if not title: print("\n❌ PR creation cancelled.\n") return diff --git a/config.example.json b/config.example.json index 26ed377..8c7009d 100644 --- a/config.example.json +++ b/config.example.json @@ -3,6 +3,8 @@ "platform": "GitHub", "available_platforms": ["GitHub", "GitLab", "Bitbucket"], "base_branch": "main", - "slack_channel": "#your-channel", - "slack_token": "your-slack-token-here" + "ai_provider": "ollama", + "available_ai_providers": ["ollama", "claude", "openai"], + "ai_model": "llama3.2", + "api_key": "" } \ No newline at end of file diff --git a/config.json b/config.json index 33a3935..4555686 100644 --- a/config.json +++ b/config.json @@ -1,8 +1,10 @@ { - "project": "QA Agent", + "project": "Team Allocator", "platform": "GitHub", "available_platforms": ["GitHub", "GitLab", "Bitbucket"], "base_branch": "main", - "slack_channel": "", - "slack_token": "" + "ai_provider": "ollama", + "available_ai_providers": ["ollama", "claude", "openai"], + "ai_model": "llama3.2", + "api_key": "" } \ No newline at end of file