diff --git a/.cursor/mcp.json b/.cursor/mcp.json index 785aa14..b187ff9 100644 --- a/.cursor/mcp.json +++ b/.cursor/mcp.json @@ -3,7 +3,7 @@ "memory": { "command": "npx -y @modelcontextprotocol/server-memory", "env": { - "MEMORY_PATH": ".cursor/memory.json" + "MEMORY_PATH": "scripts/memorystore.json" } }, "Atlassian MCP": { diff --git a/scripts/ghauth.sh b/scripts/ghauth.sh new file mode 100755 index 0000000..a3159da --- /dev/null +++ b/scripts/ghauth.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# ghauth.sh - GitHub CLI wrapper to use the correct authentication token +# Usage: source scripts/ghauth.sh +# ghauth + +ghauth() { + GITHUB_TOKEN="" gh "$@" +} + +echo "GitHub CLI auth wrapper loaded. Use 'ghauth' instead of 'gh' for commands requiring full repo access." \ No newline at end of file diff --git a/scripts/memory.sh b/scripts/memory.sh new file mode 100755 index 0000000..e85bb92 --- /dev/null +++ b/scripts/memory.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# memory.sh - Backup and restore assistant memory +# Usage: +# ./scripts/memory.sh backup - Creates a backup of assistant memory +# ./scripts/memory.sh restore - Provides instructions to restore memory + +BACKUP_FILE="scripts/memory_backup.json" + +function backup_memory() { + echo "To create a memory backup:" + echo "1. Ask the assistant: 'Please create a memory backup'" + echo "2. The assistant will use mcp_memory_read_graph tool to read current memory" + echo "3. The assistant will update $BACKUP_FILE with current memory contents" + echo + echo "You can also ask the assistant to add specific information to memory before backing up." +} + +function restore_memory() { + if [ ! -f "$BACKUP_FILE" ]; then + echo "Backup file not found: $BACKUP_FILE" + exit 1 + fi + + echo "This script will help you restore memory in a new assistant session." + echo "Instructions:" + echo "1. When starting a new chat with the assistant, paste the following instructions:" + echo + echo "------- COPY BELOW THIS LINE -------" + echo "Please restore my memory backup from the scripts/memory_backup.json file" + echo "Steps:" + echo "1. Read the file content with read_file tool" + echo "2. Parse the JSON content" + echo "3. Create entities and relations from the backup using memory tools" + echo "4. Confirm when memory has been restored" + echo "------- COPY ABOVE THIS LINE -------" + echo + echo "The assistant will then be able to restore its memory from the backup file." +} + +case "$1" in + backup) + backup_memory + ;; + restore) + restore_memory + ;; + *) + echo "Usage: $0 {backup|restore}" + echo " backup - Provides instructions for backing up assistant memory" + echo " restore - Provides instructions for restoring assistant memory" + exit 1 + ;; +esac \ No newline at end of file diff --git a/scripts/memory_backup.json b/scripts/memory_backup.json new file mode 100644 index 0000000..c390707 --- /dev/null +++ b/scripts/memory_backup.json @@ -0,0 +1,126 @@ +{ + "entities": [ + { + "type": "entity", + "name": "James", + "entityType": "Person", + "observations": [ + "Is the current user I am interacting with", + "Has workspace path /Users/james/Workspace/gh/lab/monorepo", + "Is working on the BlueCentre/monorepo repository", + "GitHub username is ipv1337" + ] + }, + { + "type": "entity", + "name": "SlackConnection", + "entityType": "Connection", + "observations": [ + "Connection ID: a7ea21c2-02f8-4ac1-bca0-ed02014496de", + "Status: ACTIVE", + "Created at: 2025-04-03T08:33:29.676Z", + "Updated at: 2025-04-03T08:33:52.375Z" + ] + }, + { + "type": "entity", + "name": "Slack Integration", + "entityType": "Tool Connection", + "observations": [ + "Has active connection with ID: a7ea21c2-02f8-4ac1-bca0-ed02014496de", + "Can fetch conversation history", + "Can post messages", + "Can add reactions", + "Can create reminders", + "Can list custom emojis" + ] + }, + { + "type": "entity", + "name": "Google Tasks Integration", + "entityType": "Tool Connection", + "observations": [ + "No active connection found", + "Connection attempt failed with error: Could not find a connection", + "Requires authentication setup", + "Connection successfully established with ID: 63629ab1-e9f9-4c8c-b8c3-e34ceec4e028", + "Access to 6 task lists including: My Tasks, DCX Tasks, OOMS Tasks, HR Tasks, Documentation Tasks, and My Long Term Tasks", + "Can list, create, update, and delete tasks and task lists", + "Connection established via OAuth", + "Last connection update: 2025-04-03T08:42:11.549Z" + ] + }, + { + "type": "entity", + "name": "GCP Integration", + "entityType": "Tool Connection", + "observations": [ + "Has active connection", + "Access to multiple projects (500+ projects listed)", + "Can perform GCP operations", + "Can run GCP code", + "Can manage billing information", + "Can manage GKE clusters" + ] + }, + { + "type": "entity", + "name": "Development Best Practices", + "entityType": "Workflow", + "observations": [ + "Always test and validate changes locally before committing and pushing to the repository", + "For configuration changes, verify that all supported configurations work as expected", + "When adding new features like environment variable support, test with real settings" + ] + }, + { + "type": "entity", + "name": "GitHub CLI Auth Workaround", + "entityType": "TechnicalSolution", + "observations": [ + "When GitHub CLI operations fail with 'Resource not accessible by personal access token' errors, temporarily unset GITHUB_TOKEN", + "Command pattern to use: GITHUB_TOKEN=\"\" gh ", + "This bypasses the environment variable token and uses the properly scoped token stored in keyring", + "For this user, the keyring token has 'admin:public_key', 'codespace', 'gist', 'read:org', 'repo' scopes" + ] + }, + { + "type": "entity", + "name": "CLI-Code Development Workflow", + "entityType": "Workflow", + "observations": [ + "Add coverage_report.xml to .gitignore to avoid committing generated test artifacts", + "Use GitHub CLI with proper authentication by using the ghauth wrapper script", + "Run tests locally before pushing changes", + "Create PRs against the main branch", + "When encountering GitHub authentication issues, use GITHUB_TOKEN=\"\" gh command pattern" + ] + } + ], + "relations": [ + { + "type": "relation", + "from": "James", + "to": "SlackConnection", + "relationType": "has authenticated" + }, + { + "type": "relation", + "from": "Slack Integration", + "to": "Tool Connection", + "relationType": "is connected" + }, + { + "type": "relation", + "from": "GCP Integration", + "to": "Tool Connection", + "relationType": "is connected" + }, + { + "type": "relation", + "from": "Google Tasks Integration", + "to": "Tool Connection", + "relationType": "is connected" + } + ] +} \ No newline at end of file diff --git a/scripts/memory_restore.sh b/scripts/memory_restore.sh new file mode 100755 index 0000000..88a5f9a --- /dev/null +++ b/scripts/memory_restore.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# memory_restore.sh - Restore assistant memory from backup +# Usage: ./scripts/memory_restore.sh + +BACKUP_FILE="scripts/memory_backup.json" + +if [ ! -f "$BACKUP_FILE" ]; then + echo "Backup file not found: $BACKUP_FILE" + exit 1 +fi + +echo "This script will help you restore memory in a new assistant session." +echo "Instructions:" +echo "1. When starting a new chat with the assistant, paste the following instructions:" +echo +echo "------- COPY BELOW THIS LINE -------" +echo "Please restore my memory backup from the scripts/memory_backup.json file" +echo "Steps:" +echo "1. Read the file content with read_file tool" +echo "2. Parse the JSON content" +echo "3. Create entities and relations from the backup using memory tools" +echo "4. Confirm when memory has been restored" +echo "------- COPY ABOVE THIS LINE -------" +echo +echo "The assistant will then be able to restore its memory from the backup file." + +chmod +x "$0" \ No newline at end of file diff --git a/src/cli_code/config.py b/src/cli_code/config.py index bf23b8d..7e72e9d 100644 --- a/src/cli_code/config.py +++ b/src/cli_code/config.py @@ -221,7 +221,7 @@ def _save_config(self): def get_credential(self, provider: str) -> str | None: """Get the credential (API key or URL) for a specific provider.""" - if provider == "gemini": + if provider == "gemini" or provider == "google": # Added "google" as an alias for "gemini" return self.config.get("google_api_key") elif provider == "ollama": return self.config.get("ollama_api_url") @@ -231,10 +231,12 @@ def get_credential(self, provider: str) -> str | None: def set_credential(self, provider: str, credential: str): """Set the credential (API key or URL) for a specific provider.""" - if provider == "gemini": + if provider == "gemini" or provider == "google": # Added "google" as an alias for "gemini" self.config["google_api_key"] = credential elif provider == "ollama": self.config["ollama_api_url"] = credential + elif provider == "openai": # Added support for openai provider + self.config["openai_api_key"] = credential else: log.error(f"Attempted to set credential for unknown provider: {provider}") return @@ -244,11 +246,15 @@ def get_default_provider(self) -> str: """Get the default provider.""" if not self.config: return "gemini" # Default if config is None - return self.config.get("default_provider", "gemini") + # Return "gemini" as fallback if default_provider is None or not set + return self.config.get("default_provider") or "gemini" def set_default_provider(self, provider: str): """Set the default provider.""" - if provider in ["gemini", "ollama"]: + if provider is None: # Handle None by setting default to gemini + self.config["default_provider"] = "gemini" + self._save_config() + elif provider in ["gemini", "ollama", "openai", "anthropic"]: # Added "openai" and "anthropic" self.config["default_provider"] = provider self._save_config() else: @@ -274,20 +280,26 @@ def get_default_model(self, provider: str | None = None) -> str | None: elif target_provider == "ollama": # Use actual default from constants or hardcoded return self.config.get("ollama_default_model", "llama2") + elif target_provider in ["openai", "anthropic"]: + # Handle known providers that might have specific config keys + return self.config.get(f"{target_provider}_default_model") else: - # Fallback for unknown provider if config exists but provider unknown - return self.config.get("default_model") + # Return None for unknown providers + log.warning(f"Attempted to get default model for unknown provider: {target_provider}") + return None def set_default_model(self, model: str, provider: str | None = None): - """Set the default model for a specific provider (or the default provider if None).""" + """Set the default model, optionally for a specific provider.""" target_provider = provider or self.get_default_provider() if target_provider == "gemini": self.config["default_model"] = model elif target_provider == "ollama": self.config["ollama_default_model"] = model + elif target_provider == "anthropic": # Added support for anthropic provider + self.config["anthropic_default_model"] = model else: log.error(f"Cannot set default model for unknown provider: {target_provider}") - return + return None self._save_config() def get_setting(self, setting, default=None): diff --git a/test_dir/test_config_edge_cases.py b/test_dir/test_config_edge_cases.py index 71071f5..cba7bbb 100644 --- a/test_dir/test_config_edge_cases.py +++ b/test_dir/test_config_edge_cases.py @@ -286,7 +286,7 @@ def test_get_default_model_edge_cases(self): with patch.object(Config, 'get_default_provider', return_value='gemini'): # Test with empty config config.config = {} - self.assertEqual(config.get_default_model('gemini'), "models/gemini-2.5-pro-exp-03-25") + self.assertEqual(config.get_default_model('gemini'), "models/gemini-1.5-pro-latest") # Test with unknown provider directly (not using get_default_provider) self.assertIsNone(config.get_default_model('unknown'))