From b8f51660d80fb14ddad6490b9217d4f74704bb4f Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Wed, 14 May 2025 14:35:15 +0000 Subject: [PATCH 1/7] feat(aider): Initial Commit from PR#456 and Aider Branch at coder/modules --- .icons/aider.svg | 3 + registry/coder/modules/aider/README.md | 306 ++++++++++++++++ registry/coder/modules/aider/main.test.ts | 60 +++ registry/coder/modules/aider/main.tf | 425 ++++++++++++++++++++++ 4 files changed, 794 insertions(+) create mode 100644 .icons/aider.svg create mode 100644 registry/coder/modules/aider/README.md create mode 100644 registry/coder/modules/aider/main.test.ts create mode 100644 registry/coder/modules/aider/main.tf diff --git a/.icons/aider.svg b/.icons/aider.svg new file mode 100644 index 0000000..44e064f --- /dev/null +++ b/.icons/aider.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/registry/coder/modules/aider/README.md b/registry/coder/modules/aider/README.md new file mode 100644 index 0000000..306cb3c --- /dev/null +++ b/registry/coder/modules/aider/README.md @@ -0,0 +1,306 @@ +--- +display_name: Aider +description: Run Aider AI pair programming in your workspace +icon: ../../../../.icons/code.svg +maintainer_github: coder +verified: true +tags: [agent, aider] +--- + +# Aider + +Run [Aider](https://aider.chat) AI pair programming in your workspace. This module installs Aider and provides a persistent session using screen or tmux. + +```tf +module "aider" { + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id +} +``` + +## Features + +- **Interactive Parameter Selection**: Choose your AI provider, model, and configuration options when creating the workspace +- **Multiple AI Providers**: Supports Anthropic (Claude), OpenAI, DeepSeek, GROQ, and OpenRouter +- **Persistent Sessions**: Uses screen (default) or tmux to keep Aider running in the background +- **Optional Dependencies**: Install Playwright for web page scraping and PortAudio for voice coding +- **Project Integration**: Works with any project directory, including Git repositories +- **Browser UI**: Use Aider in your browser with a modern web interface instead of the terminal +- **Non-Interactive Mode**: Automatically processes tasks when provided via the `CODER_MCP_AIDER_TASK_PROMPT` environment variable + +## Module Parameters + +| Parameter | Description | Type | Default | +| ---------------------------------- | -------------------------------------------------------------------------- | -------- | ------------------- | +| `agent_id` | The ID of a Coder agent (required) | `string` | - | +| `folder` | The folder to run Aider in | `string` | `/home/coder` | +| `install_aider` | Whether to install Aider | `bool` | `true` | +| `aider_version` | The version of Aider to install | `string` | `"latest"` | +| `use_screen` | Whether to use screen for running Aider in the background | `bool` | `true` | +| `use_tmux` | Whether to use tmux instead of screen for running Aider in the background | `bool` | `false` | +| `session_name` | Name for the persistent session (screen or tmux) | `string` | `"aider"` | +| `order` | Position of the app in the UI presentation | `number` | `null` | +| `icon` | The icon to use for the app | `string` | `"/icon/aider.svg"` | +| `experiment_report_tasks` | Whether to enable task reporting | `bool` | `true` | +| `experiment_task_conventions` | Custom conventions for task reporting to be written to CONVENTIONS.md | `string` | See default in code | +| `experiment_pre_install_script` | Custom script to run before installing Aider | `string` | `null` | +| `experiment_post_install_script` | Custom script to run after installing Aider | `string` | `null` | +| `experiment_additional_extensions` | Additional extensions configuration in YAML format to append to the config | `string` | `null` | + +> **Note**: `use_screen` and `use_tmux` cannot both be enabled at the same time. By default, `use_screen` is set to `true` and `use_tmux` is set to `false`. + +## Usage Examples + +### Basic setup + +```tf +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" +} +``` + +This basic setup will: + +- Install Aider in the workspace +- Create a persistent screen session named "aider" +- Enable task reporting (configures Aider to report tasks to Coder MCP) + +### With tmux instead of screen + +```tf +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" + use_tmux = true +} +``` + +### With API key via environment variables + +```tf +variable "anthropic_api_key" { + type = string + description = "Anthropic API key" + sensitive = true +} + +variable "anthropic_model" { + type = string + description = "Anthropic Model" + default = "sonnet" +} + +resource "coder_agent" "main" { + # ... +} + +# Set API key and model using coder_env resource +resource "coder_env" "anthropic" { + agent_id = coder_agent.example.id + name = "ANTHROPIC_API_KEY" + value = var.anthropic_api_key +} + +resource "coder_env" "aider_model" { + agent_id = coder_agent.example.id + name = "AIDER_MODEL" + value = var.anthropic_model +} + +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" +} +``` + +### Adding Custom Extensions (Experimental) + +You can extend Aider's capabilities by adding custom extensions: + +```tf +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" + + experiment_pre_install_script = <<-EOT + pip install some-custom-dependency + EOT + + experiment_additional_extensions = <<-EOT + custom-extension: + args: [] + cmd: custom-extension-command + description: A custom extension for Aider + enabled: true + envs: {} + name: custom-extension + timeout: 300 + type: stdio + EOT +} +``` + +Note: The indentation in the heredoc is preserved, so you can write the YAML naturally. + +## Task Reporting (Experimental) + +> This functionality is in early access as of Coder v2.21 and is still evolving. +> For now, we recommend testing it in a demo or staging environment, +> rather than deploying to production +> +> Learn more in [the Coder documentation](https://coder.com/docs/tutorials/ai-agents) +> +> Join our [Discord channel](https://discord.gg/coder) or +> [contact us](https://coder.com/contact) to get help or share feedback. + +Your workspace must have either `screen` or `tmux` installed to use this. + +Task reporting is **enabled by default** in this module, allowing you to: + +- Send an initial prompt to Aider during workspace creation +- Monitor task progress in the Coder UI +- Use the `coder_parameter` resource to collect prompts from users + +### Setting up Task Reporting + +To use task reporting effectively: + +1. Add the Coder Login module to your template +2. Configure the necessary environment variables to pass the task prompt and status slug +3. Optionally add a coder_parameter to collect prompts from users + +Here's a complete example: + +```tf +module "coder-login" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/coder-login/coder" + version = "1.0.15" + agent_id = coder_agent.example.id +} + +variable "anthropic_api_key" { + type = string + description = "Anthropic API key" + sensitive = true +} + +variable "anthropic_model" { + type = string + description = "Anthropic Model" + default = "sonnet" +} + +data "coder_parameter" "ai_prompt" { + type = "string" + name = "AI Prompt" + default = "" + description = "Write a prompt for Aider" + mutable = true + ephemeral = true +} + +# Configure environment variables for API key, model and task prompt +resource "coder_env" "anthropic" { + agent_id = coder_agent.example.id + name = "ANTHROPIC_API_KEY" + value = var.anthropic_api_key +} + +resource "coder_env" "aider_model" { + agent_id = coder_agent.example.id + name = "AIDER_MODEL" + value = var.anthropic_model +} + +resource "coder_env" "task_prompt" { + agent_id = coder_agent.example.id + name = "CODER_MCP_AIDER_TASK_PROMPT" + value = data.coder_parameter.ai_prompt.value +} + +resource "coder_env" "app_status" { + agent_id = coder_agent.example.id + name = "CODER_MCP_APP_STATUS_SLUG" + value = "aider" +} + +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" +} +``` + +When a task prompt is provided, the module automatically: + +1. Executes the task during workspace creation using the `--message` and `--yes-always` flags +2. Creates a flag file to prevent duplicate execution if the Aider button is clicked later +3. Logs task output to `$HOME/.aider.log` for reference + +If you want to disable task reporting, set `experiment_report_tasks = false` in your module configuration. + +## Using Aider in Your Workspace + +After the workspace starts, Aider will be installed and configured according to your parameters. A persistent session will automatically be started during workspace creation. + +### Session Options + +You can run Aider in three different ways: + +1. **Direct Mode**: Aider starts directly in the specified folder when you click the app button + + - Simple setup without persistent context + - Suitable for quick coding sessions + +2. **Screen Mode** (Default): Run Aider in a screen session that persists across connections + + - Session name: "aider" (or configured via `session_name`) + +3. **Tmux Mode**: Run Aider in a tmux session instead of screen + - Set `use_tmux = true` to enable + - Session name: "aider" (or configured via `session_name`) + +Persistent sessions (screen/tmux) allow you to: + +- Disconnect and reconnect without losing context +- Run Aider in the background while doing other work +- Switch between terminal and browser interfaces + +### Available AI Providers and Models + +| Provider | Available Models | API Key Source | +| -------------- | ----------------------------------- | ----------------------------------------------------------- | +| **Anthropic** | Claude 3.7 Sonnet, Claude 3.7 Haiku | [console.anthropic.com](https://console.anthropic.com/) | +| **OpenAI** | o3-mini, o1, GPT-4o | [platform.openai.com](https://platform.openai.com/api-keys) | +| **DeepSeek** | DeepSeek R1, DeepSeek Chat V3 | [platform.deepseek.com](https://platform.deepseek.com/) | +| **GROQ** | Mixtral, Llama 3 | [console.groq.com](https://console.groq.com/keys) | +| **OpenRouter** | OpenRouter | [openrouter.ai](https://openrouter.ai/keys) | + +For a complete and up-to-date list of supported LLMs and models, please refer to the [Aider LLM documentation](https://aider.chat/docs/llms.html) and the [Aider LLM Leaderboards](https://aider.chat/docs/leaderboards.html) which show performance comparisons across different models. + +## Troubleshooting + +If you encounter issues: + +1. **Screen/Tmux issues**: If you can't reconnect to your session, check if the session exists with `screen -list` or `tmux list-sessions` +2. **API key issues**: Ensure you've entered the correct API key for your selected provider +3. **Browser mode issues**: If the browser interface doesn't open, check that you're accessing it from a machine that can reach your Coder workspace + +For more information on using Aider, see the [Aider documentation](https://aider.chat/docs/). diff --git a/registry/coder/modules/aider/main.test.ts b/registry/coder/modules/aider/main.test.ts new file mode 100644 index 0000000..99cf062 --- /dev/null +++ b/registry/coder/modules/aider/main.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from "bun:test"; +import { + findResourceInstance, + runTerraformApply, + runTerraformInit, + testRequiredVariables, +} from "~test"; + +describe("aider", async () => { + await runTerraformInit(import.meta.dir); + + testRequiredVariables(import.meta.dir, { + agent_id: "foo", + }); + + it("configures task prompt correctly", async () => { + const testPrompt = "Add a hello world function"; + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + }); + + const instance = findResourceInstance(state, "coder_script"); + expect(instance.script).toContain( + 'if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]', + ); + expect(instance.script).toContain( + "aider --architect --yes-always --read CONVENTIONS.md --message", + ); + }); + + it("handles pre and post install scripts", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + experiment_pre_install_script: "echo 'Pre-install script executed'", + experiment_post_install_script: "echo 'Post-install script executed'", + }); + + const instance = findResourceInstance(state, "coder_script"); + + expect(instance.script).toContain("Running pre-install script"); + expect(instance.script).toContain("Running post-install script"); + expect(instance.script).toContain("base64 -d > /tmp/pre_install.sh"); + expect(instance.script).toContain("base64 -d > /tmp/post_install.sh"); + }); + + it("validates that use_screen and use_tmux cannot both be true", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + use_screen: true, + use_tmux: true, + }); + + const instance = findResourceInstance(state, "coder_script"); + + expect(instance.script).toContain( + "Error: Both use_screen and use_tmux cannot be enabled at the same time", + ); + expect(instance.script).toContain("exit 1"); + }); +}); diff --git a/registry/coder/modules/aider/main.tf b/registry/coder/modules/aider/main.tf new file mode 100644 index 0000000..5ea4193 --- /dev/null +++ b/registry/coder/modules/aider/main.tf @@ -0,0 +1,425 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.17" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +variable "order" { + type = number + description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)." + default = null +} + +variable "icon" { + type = string + description = "The icon to use for the app." + default = "/icon/aider.svg" +} + +variable "folder" { + type = string + description = "The folder to run Aider in." + default = "/home/coder" +} + +variable "install_aider" { + type = bool + description = "Whether to install Aider." + default = true +} + +variable "aider_version" { + type = string + description = "The version of Aider to install." + default = "latest" +} + +variable "use_screen" { + type = bool + description = "Whether to use screen for running Aider in the background" + default = true +} + +variable "use_tmux" { + type = bool + description = "Whether to use tmux instead of screen for running Aider in the background" + default = false +} + +variable "session_name" { + type = string + description = "Name for the persistent session (screen or tmux)" + default = "aider" +} + +variable "experiment_report_tasks" { + type = bool + description = "Whether to enable task reporting." + default = true +} + +variable "experiment_task_conventions" { + type = string + description = "Custom conventions for task reporting to be written to CONVENTIONS.md" + default = <<-EOT +# Aider Coding Conventions + +## Task Reporting Requirements + +As you work on tasks, you MUST follow these task reporting conventions: + +1. ALWAYS report the status of each task to Coder before and after your steps. +2. Use the following format for reporting tasks: + ``` + TASK: [brief description of what you're doing] + STATUS: [one of: "started", "in progress", "done", "failed"] + ``` + +3. Send a task report in these specific situations: + - When you BEGIN working on a task + - When you make SIGNIFICANT PROGRESS on a task + - When you COMPLETE a task successfully + - When you ENCOUNTER AN ERROR or cannot complete a task + +4. Example sequence of task reporting: + ``` + TASK: Setting up project structure + STATUS: started + + [Your work and discussion here] + + TASK: Setting up project structure + STATUS: in progress + + [More work and discussion] + + TASK: Setting up project structure + STATUS: done + + TASK: Implementing feature X + STATUS: started + ``` + +5. Always include a brief but descriptive task name that clearly identifies what you're working on. + +These conventions ensure that Coder can properly track task status in the UI. +EOT +} + +variable "experiment_pre_install_script" { + type = string + description = "Custom script to run before installing Aider." + default = null +} + +variable "experiment_post_install_script" { + type = string + description = "Custom script to run after installing Aider." + default = null +} + +variable "experiment_additional_extensions" { + type = string + description = "Additional extensions configuration in YAML format to append to the config." + default = null +} + +locals { + base_extensions = <<-EOT +coder: + args: + - exp + - mcp + - server + cmd: coder + description: Report ALL tasks and statuses (in progress, done, failed) you are working on. + enabled: true + envs: + CODER_MCP_APP_STATUS_SLUG: aider + name: Coder + timeout: 3000 + type: stdio +developer: + display_name: Developer + enabled: true + name: developer + timeout: 300 + type: builtin +EOT + + formatted_base = " ${replace(trimspace(local.base_extensions), "\n", "\n ")}" + additional_extensions = var.experiment_additional_extensions != null ? "\n ${replace(trimspace(var.experiment_additional_extensions), "\n", "\n ")}" : "" + + combined_extensions = <<-EOT +extensions: +${local.formatted_base}${local.additional_extensions} +EOT + + encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : "" + encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : "" +} + +# Install and Initialize Aider +resource "coder_script" "aider" { + agent_id = var.agent_id + display_name = "Aider" + icon = var.icon + script = <<-EOT + #!/bin/bash + set -e + + command_exists() { + command -v "$1" >/dev/null 2>&1 + } + + echo "Setting up Aider AI pair programming..." + + if [ "${var.use_screen}" = "true" ] && [ "${var.use_tmux}" = "true" ]; then + echo "Error: Both use_screen and use_tmux cannot be enabled at the same time." + exit 1 + fi + + mkdir -p "${var.folder}" + + if [ "$(uname)" = "Linux" ]; then + echo "Checking dependencies for Linux..." + + if [ "${var.use_tmux}" = "true" ]; then + if ! command_exists tmux; then + echo "Installing tmux for persistent sessions..." + if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq tmux + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y -q tmux + else + echo "Warning: Unable to install tmux on this system." + fi + else + echo "tmux is already installed, skipping installation." + fi + elif [ "${var.use_screen}" = "true" ]; then + if ! command_exists screen; then + echo "Installing screen for persistent sessions..." + if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq screen + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y -q screen + else + echo "Warning: Unable to install screen on this system." + fi + else + echo "screen is already installed, skipping installation." + fi + fi + else + echo "This module currently only supports Linux workspaces." + exit 1 + fi + + if [ -n "${local.encoded_pre_install_script}" ]; then + echo "Running pre-install script..." + echo "${local.encoded_pre_install_script}" | base64 -d > /tmp/pre_install.sh + chmod +x /tmp/pre_install.sh + /tmp/pre_install.sh + fi + + if [ "${var.install_aider}" = "true" ]; then + echo "Installing Aider..." + + if ! command_exists python3 || ! command_exists pip3; then + echo "Installing Python dependencies required for Aider..." + if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq python3-pip python3-venv + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y -q python3-pip python3-virtualenv + else + echo "Warning: Unable to install Python on this system." + fi + else + echo "Python is already installed, skipping installation." + fi + + if ! command_exists aider; then + curl -LsSf https://aider.chat/install.sh | sh + fi + + if [ -f "$HOME/.bashrc" ]; then + if ! grep -q 'export PATH="$HOME/bin:$PATH"' "$HOME/.bashrc"; then + echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.bashrc" + fi + fi + + if [ -f "$HOME/.zshrc" ]; then + if ! grep -q 'export PATH="$HOME/bin:$PATH"' "$HOME/.zshrc"; then + echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.zshrc" + fi + fi + + fi + + if [ -n "${local.encoded_post_install_script}" ]; then + echo "Running post-install script..." + echo "${local.encoded_post_install_script}" | base64 -d > /tmp/post_install.sh + chmod +x /tmp/post_install.sh + /tmp/post_install.sh + fi + + if [ "${var.experiment_report_tasks}" = "true" ]; then + echo "Configuring Aider to report tasks via Coder MCP..." + + mkdir -p "$HOME/.config/aider" + + cat > "$HOME/.config/aider/config.yml" << EOL +${trimspace(local.combined_extensions)} +EOL + echo "Added Coder MCP extension to Aider config.yml" + + mkdir -p "${var.folder}" + cat > "${var.folder}/CONVENTIONS.md" << 'CONVENTIONS_EOF' +${var.experiment_task_conventions} +CONVENTIONS_EOF + echo "Created CONVENTIONS.md file with task reporting instructions" + fi + + echo "Starting persistent Aider session..." + + touch "$HOME/.aider.log" + + export LANG=en_US.UTF-8 + export LC_ALL=en_US.UTF-8 + + export PATH="$HOME/bin:$PATH" + + if [ "${var.use_tmux}" = "true" ]; then + if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]; then + echo "Running Aider with message in tmux session..." + tmux new-session -d -s ${var.session_name} -c ${var.folder} "echo \"Starting Aider with app status slug: aider\"; export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --architect --yes-always --read CONVENTIONS.md --message \"Report each step to Coder. Your task: $CODER_MCP_AIDER_TASK_PROMPT\"" + echo "Aider task started in tmux session '${var.session_name}'. Check the UI for progress." + else + tmux new-session -d -s ${var.session_name} -c ${var.folder} "echo \"Starting Aider with app status slug: aider\"; export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --read CONVENTIONS.md" + echo "Tmux session '${var.session_name}' started. Access it by clicking the Aider button." + fi + else + if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]; then + echo "Running Aider with message in screen session..." + + if [ ! -f "$HOME/.screenrc" ]; then + echo "Creating ~/.screenrc and adding multiuser settings..." + echo -e "multiuser on\nacladd $(whoami)" > "$HOME/.screenrc" + fi + + if ! grep -q "^multiuser on$" "$HOME/.screenrc"; then + echo "Adding 'multiuser on' to ~/.screenrc..." + echo "multiuser on" >> "$HOME/.screenrc" + fi + + if ! grep -q "^acladd $(whoami)$" "$HOME/.screenrc"; then + echo "Adding 'acladd $(whoami)' to ~/.screenrc..." + echo "acladd $(whoami)" >> "$HOME/.screenrc" + fi + + screen -U -dmS ${var.session_name} bash -c " + cd ${var.folder} + export PATH=\"$HOME/bin:$HOME/.local/bin:$PATH\" + export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\" + export CODER_MCP_APP_STATUS_SLUG=\"aider\" + echo \"Starting Aider with app status slug: aider\" + aider --architect --yes-always --read CONVENTIONS.md --message \"Report each step to Coder. Your task: $CODER_MCP_AIDER_TASK_PROMPT\" + /bin/bash + " + + echo "Aider task started in screen session '${var.session_name}'. Check the UI for progress." + else + + if [ ! -f "$HOME/.screenrc" ]; then + echo "Creating ~/.screenrc and adding multiuser settings..." + echo -e "multiuser on\nacladd $(whoami)" > "$HOME/.screenrc" + fi + + if ! grep -q "^multiuser on$" "$HOME/.screenrc"; then + echo "Adding 'multiuser on' to ~/.screenrc..." + echo "multiuser on" >> "$HOME/.screenrc" + fi + + if ! grep -q "^acladd $(whoami)$" "$HOME/.screenrc"; then + echo "Adding 'acladd $(whoami)' to ~/.screenrc..." + echo "acladd $(whoami)" >> "$HOME/.screenrc" + fi + + screen -U -dmS ${var.session_name} bash -c " + cd ${var.folder} + export PATH=\"$HOME/bin:$HOME/.local/bin:$PATH\" + export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\" + export CODER_MCP_APP_STATUS_SLUG=\"aider\" + echo \"Starting Aider with app status slug: aider\" + aider --read CONVENTIONS.md + /bin/bash + " + echo "Screen session '${var.session_name}' started. Access it by clicking the Aider button." + fi + fi + + echo "Aider setup complete!" + EOT + run_on_start = true +} + +# Aider CLI app +resource "coder_app" "aider_cli" { + agent_id = var.agent_id + slug = "aider" + display_name = "Aider" + icon = var.icon + command = <<-EOT + #!/bin/bash + set -e + + export PATH="$HOME/bin:$HOME/.local/bin:$PATH" + + export CODER_MCP_APP_STATUS_SLUG="aider" + + export LANG=en_US.UTF-8 + export LC_ALL=en_US.UTF-8 + + if [ "${var.use_tmux}" = "true" ]; then + if tmux has-session -t ${var.session_name} 2>/dev/null; then + echo "Attaching to existing Aider tmux session..." + tmux setenv -t ${var.session_name} CODER_MCP_APP_STATUS_SLUG "aider" + tmux attach-session -t ${var.session_name} + else + echo "Starting new Aider tmux session..." + tmux new-session -s ${var.session_name} -c ${var.folder} "export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --read CONVENTIONS.md; exec bash" + fi + elif [ "${var.use_screen}" = "true" ]; then + if ! screen -list | grep -q "${var.session_name}"; then + echo "Error: No existing Aider session found. Please wait for the script to start it." + exit 1 + fi + export CODER_MCP_APP_STATUS_SLUG="aider" + screen -xRR ${var.session_name} + else + cd "${var.folder}" + echo "Starting Aider directly..." + export CODER_MCP_APP_STATUS_SLUG="aider" + aider --read CONVENTIONS.md + fi + EOT + order = var.order +} From 639662fe984a15d908e4aa1109fc7e7f659e8016 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Thu, 15 May 2025 13:28:16 +0000 Subject: [PATCH 2/7] docs(aider): update README.md to enhance API integration details ## Changes made - Updated non-interactive mode description to use `task_prompt` variable - Added new parameters for AI provider, model, and API key configuration - Revised usage examples to include OpenAI and custom provider setups - Enhanced task reporting instructions and system prompt customization - Clarified available AI providers and models with default settings --- registry/coder/modules/aider/README.md | 211 +++++++++++++------------ 1 file changed, 109 insertions(+), 102 deletions(-) diff --git a/registry/coder/modules/aider/README.md b/registry/coder/modules/aider/README.md index 306cb3c..a0ca3b2 100644 --- a/registry/coder/modules/aider/README.md +++ b/registry/coder/modules/aider/README.md @@ -27,7 +27,7 @@ module "aider" { - **Optional Dependencies**: Install Playwright for web page scraping and PortAudio for voice coding - **Project Integration**: Works with any project directory, including Git repositories - **Browser UI**: Use Aider in your browser with a modern web interface instead of the terminal -- **Non-Interactive Mode**: Automatically processes tasks when provided via the `CODER_MCP_AIDER_TASK_PROMPT` environment variable +- **Non-Interactive Mode**: Automatically processes tasks when provided via the `task_prompt` variable ## Module Parameters @@ -43,7 +43,12 @@ module "aider" { | `order` | Position of the app in the UI presentation | `number` | `null` | | `icon` | The icon to use for the app | `string` | `"/icon/aider.svg"` | | `experiment_report_tasks` | Whether to enable task reporting | `bool` | `true` | -| `experiment_task_conventions` | Custom conventions for task reporting to be written to CONVENTIONS.md | `string` | See default in code | +| `system_prompt` | System prompt for instructing Aider on task reporting and behavior | `string` | See default in code | +| `task_prompt` | Task prompt to use with Aider | `string` | `""` | +| `ai_provider` | AI provider to use with Aider (openai, anthropic, azure, etc.) | `string` | `"anthropic"` | +| `ai_model` | AI model to use (can use Aider's built-in aliases like "sonnet", "4o") | `string` | `"sonnet"` | +| `ai_api_key` | API key for the selected AI provider | `string` | `""` | +| `custom_env_var_name` | Custom environment variable name when using custom provider | `string` | `""` | | `experiment_pre_install_script` | Custom script to run before installing Aider | `string` | `null` | | `experiment_post_install_script` | Custom script to run after installing Aider | `string` | `null` | | `experiment_additional_extensions` | Additional extensions configuration in YAML format to append to the config | `string` | `null` | @@ -52,15 +57,21 @@ module "aider" { ## Usage Examples -### Basic setup +### Basic setup with API key ```tf +variable "anthropic_api_key" { + type = string + description = "Anthropic API key" + sensitive = true +} + module "aider" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" - version = "1.0.0" - agent_id = coder_agent.example.id - folder = "/home/coder" + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + ai_api_key = var.anthropic_api_key } ``` @@ -68,59 +79,48 @@ This basic setup will: - Install Aider in the workspace - Create a persistent screen session named "aider" +- Configure Aider to use Anthropic Claude 3.7 Sonnet model - Enable task reporting (configures Aider to report tasks to Coder MCP) -### With tmux instead of screen +### Using OpenAI with tmux ```tf +variable "openai_api_key" { + type = string + description = "OpenAI API key" + sensitive = true +} + module "aider" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" - version = "1.0.0" - agent_id = coder_agent.example.id - folder = "/home/coder" - use_tmux = true + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + use_tmux = true + ai_provider = "openai" + ai_model = "4o" # Uses Aider's built-in alias for gpt-4o + ai_api_key = var.openai_api_key } ``` -### With API key via environment variables +### Using a custom provider ```tf -variable "anthropic_api_key" { +variable "custom_api_key" { type = string - description = "Anthropic API key" + description = "Custom provider API key" sensitive = true } -variable "anthropic_model" { - type = string - description = "Anthropic Model" - default = "sonnet" -} - -resource "coder_agent" "main" { - # ... -} - -# Set API key and model using coder_env resource -resource "coder_env" "anthropic" { - agent_id = coder_agent.example.id - name = "ANTHROPIC_API_KEY" - value = var.anthropic_api_key -} - -resource "coder_env" "aider_model" { - agent_id = coder_agent.example.id - name = "AIDER_MODEL" - value = var.anthropic_model -} - module "aider" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" - version = "1.0.0" - agent_id = coder_agent.example.id - folder = "/home/coder" + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + ai_provider = "custom" + custom_env_var_name = "MY_CUSTOM_API_KEY" + ai_model = "custom-model" + ai_api_key = var.custom_api_key } ``` @@ -130,11 +130,11 @@ You can extend Aider's capabilities by adding custom extensions: ```tf module "aider" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" - version = "1.0.0" - agent_id = coder_agent.example.id - folder = "/home/coder" + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + ai_api_key = var.anthropic_api_key experiment_pre_install_script = <<-EOT pip install some-custom-dependency @@ -180,7 +180,7 @@ Task reporting is **enabled by default** in this module, allowing you to: To use task reporting effectively: 1. Add the Coder Login module to your template -2. Configure the necessary environment variables to pass the task prompt and status slug +2. Configure the necessary variables to pass the task prompt 3. Optionally add a coder_parameter to collect prompts from users Here's a complete example: @@ -199,12 +199,6 @@ variable "anthropic_api_key" { sensitive = true } -variable "anthropic_model" { - type = string - description = "Anthropic Model" - default = "sonnet" -} - data "coder_parameter" "ai_prompt" { type = "string" name = "AI Prompt" @@ -214,44 +208,48 @@ data "coder_parameter" "ai_prompt" { ephemeral = true } -# Configure environment variables for API key, model and task prompt -resource "coder_env" "anthropic" { - agent_id = coder_agent.example.id - name = "ANTHROPIC_API_KEY" - value = var.anthropic_api_key -} - -resource "coder_env" "aider_model" { - agent_id = coder_agent.example.id - name = "AIDER_MODEL" - value = var.anthropic_model +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + ai_api_key = var.anthropic_api_key + task_prompt = data.coder_parameter.ai_prompt.value + + # Optionally customize the system prompt + system_prompt = <<-EOT +You are a helpful Coding assistant. Aim to autonomously investigate +and solve issues the user gives you and test your work, whenever possible. +Avoid shortcuts like mocking tests. When you get stuck, you can ask the user +but opt for autonomy. +YOU MUST REPORT ALL TASKS TO CODER. +When reporting tasks, you MUST follow these EXACT instructions: +- IMMEDIATELY report status after receiving ANY user message. +- Be granular. If you are investigating with multiple steps, report each step to coder. +Task state MUST be one of the following: +- Use "state": "working" when actively processing WITHOUT needing additional user input. +- Use "state": "complete" only when finished with a task. +- Use "state": "failure" when you need ANY user input, lack sufficient details, or encounter blockers. +Task summaries MUST: +- Include specifics about what you're doing. +- Include clear and actionable steps for the user. +- Be less than 160 characters in length. + EOT } +``` -resource "coder_env" "task_prompt" { - agent_id = coder_agent.example.id - name = "CODER_MCP_AIDER_TASK_PROMPT" - value = data.coder_parameter.ai_prompt.value -} +When a task prompt is provided via the `task_prompt` variable, the module automatically: -resource "coder_env" "app_status" { - agent_id = coder_agent.example.id - name = "CODER_MCP_APP_STATUS_SLUG" - value = "aider" -} +1. Combines the system prompt with the task prompt into a single message in the format: -module "aider" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" - version = "1.0.0" - agent_id = coder_agent.example.id - folder = "/home/coder" -} ``` +SYSTEM PROMPT: +[system_prompt content] -When a task prompt is provided, the module automatically: +This is your current task: [task_prompt] +``` -1. Executes the task during workspace creation using the `--message` and `--yes-always` flags -2. Creates a flag file to prevent duplicate execution if the Aider button is clicked later +2. Executes the task during workspace creation using the `--message` and `--yes-always` flags 3. Logs task output to `$HOME/.aider.log` for reference If you want to disable task reporting, set `experiment_report_tasks = false` in your module configuration. @@ -266,16 +264,18 @@ You can run Aider in three different ways: 1. **Direct Mode**: Aider starts directly in the specified folder when you click the app button - - Simple setup without persistent context - - Suitable for quick coding sessions +- Simple setup without persistent context +- Suitable for quick coding sessions 2. **Screen Mode** (Default): Run Aider in a screen session that persists across connections - - Session name: "aider" (or configured via `session_name`) +- Session name: "aider" (or configured via `session_name`) 3. **Tmux Mode**: Run Aider in a tmux session instead of screen - - Set `use_tmux = true` to enable - - Session name: "aider" (or configured via `session_name`) + +- Set `use_tmux = true` to enable +- Session name: "aider" (or configured via `session_name`) +- Configures tmux with mouse support for shared sessions Persistent sessions (screen/tmux) allow you to: @@ -285,15 +285,20 @@ Persistent sessions (screen/tmux) allow you to: ### Available AI Providers and Models -| Provider | Available Models | API Key Source | -| -------------- | ----------------------------------- | ----------------------------------------------------------- | -| **Anthropic** | Claude 3.7 Sonnet, Claude 3.7 Haiku | [console.anthropic.com](https://console.anthropic.com/) | -| **OpenAI** | o3-mini, o1, GPT-4o | [platform.openai.com](https://platform.openai.com/api-keys) | -| **DeepSeek** | DeepSeek R1, DeepSeek Chat V3 | [platform.deepseek.com](https://platform.deepseek.com/) | -| **GROQ** | Mixtral, Llama 3 | [console.groq.com](https://console.groq.com/keys) | -| **OpenRouter** | OpenRouter | [openrouter.ai](https://openrouter.ai/keys) | +Aider supports various providers and models, and this module integrates directly with Aider's built-in model aliases: + +| Provider | Example Models/Aliases | Default Model | +| -------------- | ------------------------------------------- | ----------------- | +| **anthropic** | "sonnet" (Claude 3.7 Sonnet), "opus", "haiku" | "sonnet" | +| **openai** | "4o" (GPT-4o), "4" (GPT-4), "3.5-turbo" | "4o" | +| **azure** | Azure OpenAI models | "gpt-4" | +| **google** | "gemini" (Gemini Pro), "gemini-2.5-pro" | "gemini-2.5-pro" | +| **cohere** | "command-r-plus", etc. | "command-r-plus" | +| **mistral** | "mistral-large-latest" | "mistral-large-latest" | +| **ollama** | "llama3", etc. | "llama3" | +| **custom** | Any model name with custom ENV variable | - | -For a complete and up-to-date list of supported LLMs and models, please refer to the [Aider LLM documentation](https://aider.chat/docs/llms.html) and the [Aider LLM Leaderboards](https://aider.chat/docs/leaderboards.html) which show performance comparisons across different models. +For a complete and up-to-date list of supported aliases and models, please refer to the [Aider LLM documentation](https://aider.chat/docs/llms.html) and the [Aider LLM Leaderboards](https://aider.chat/docs/leaderboards.html) which show performance comparisons across different models. ## Troubleshooting @@ -304,3 +309,5 @@ If you encounter issues: 3. **Browser mode issues**: If the browser interface doesn't open, check that you're accessing it from a machine that can reach your Coder workspace For more information on using Aider, see the [Aider documentation](https://aider.chat/docs/). + +``` From 382d221dd6c4bc3b526fe4d5eca1630a0814b21a Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Thu, 15 May 2025 13:28:36 +0000 Subject: [PATCH 3/7] feat(aider): enhance testing for Aider configuration and prompts ## Changes made - Added tests for handling task prompts and custom system prompts - Implemented tests for configuring Aider with known and custom AI providers, models, and API keys - Updated assertions to verify the correct environment variable exports and script outputs --- registry/coder/modules/aider/main.test.ts | 55 +++++++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/aider/main.test.ts b/registry/coder/modules/aider/main.test.ts index 99cf062..c25513a 100644 --- a/registry/coder/modules/aider/main.test.ts +++ b/registry/coder/modules/aider/main.test.ts @@ -17,15 +17,25 @@ describe("aider", async () => { const testPrompt = "Add a hello world function"; const state = await runTerraformApply(import.meta.dir, { agent_id: "foo", + task_prompt: testPrompt, }); const instance = findResourceInstance(state, "coder_script"); expect(instance.script).toContain( - 'if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]', - ); - expect(instance.script).toContain( - "aider --architect --yes-always --read CONVENTIONS.md --message", + `This is your current task: ${testPrompt}`, ); + expect(instance.script).toContain("aider --architect --yes-always"); + }); + + it("handles custom system prompt", async () => { + const customPrompt = "Report all tasks with state: working"; + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + system_prompt: customPrompt, + }); + + const instance = findResourceInstance(state, "coder_script"); + expect(instance.script).toContain(customPrompt); }); it("handles pre and post install scripts", async () => { @@ -57,4 +67,41 @@ describe("aider", async () => { ); expect(instance.script).toContain("exit 1"); }); + + it("configures Aider with known provider and model", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + ai_provider: "anthropic", + ai_model: "sonnet", + ai_api_key: "test-anthropic-key", + }); + + const instance = findResourceInstance(state, "coder_script"); + expect(instance.script).toContain( + 'export ANTHROPIC_API_KEY=\\"test-anthropic-key\\"', + ); + expect(instance.script).toContain("--model sonnet"); + expect(instance.script).toContain( + "Starting Aider using anthropic provider and model: sonnet", + ); + }); + + it("handles custom provider with custom env var and API key", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + ai_provider: "custom", + custom_env_var_name: "MY_CUSTOM_API_KEY", + ai_model: "custom-model", + ai_api_key: "test-custom-key", + }); + + const instance = findResourceInstance(state, "coder_script"); + expect(instance.script).toContain( + 'export MY_CUSTOM_API_KEY=\\"test-custom-key\\"', + ); + expect(instance.script).toContain("--model custom-model"); + expect(instance.script).toContain( + "Starting Aider using custom provider and model: custom-model", + ); + }); }); From 36c030df7f22030d51a1d7be2a27d5379d7750b0 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Thu, 15 May 2025 13:29:11 +0000 Subject: [PATCH 4/7] feat(aider): update Aider configuration for enhanced task reporting and AI integration ## Changes made - Replaced `experiment_task_conventions` variable with `system_prompt` for improved task reporting instructions - Introduced new variables for AI provider, model, and API key configuration - Enhanced task reporting logic to ensure accurate status updates and summaries - Updated installation scripts to handle package installations with or without sudo privileges - Improved tmux and screen session management for Aider execution --- registry/coder/modules/aider/main.tf | 237 ++++++++++++++++++--------- 1 file changed, 157 insertions(+), 80 deletions(-) diff --git a/registry/coder/modules/aider/main.tf b/registry/coder/modules/aider/main.tf index 5ea4193..77639df 100644 --- a/registry/coder/modules/aider/main.tf +++ b/registry/coder/modules/aider/main.tf @@ -72,54 +72,35 @@ variable "experiment_report_tasks" { default = true } -variable "experiment_task_conventions" { +variable "system_prompt" { type = string - description = "Custom conventions for task reporting to be written to CONVENTIONS.md" + description = "System prompt for instructing Aider on task reporting and behavior" default = <<-EOT -# Aider Coding Conventions - -## Task Reporting Requirements - -As you work on tasks, you MUST follow these task reporting conventions: - -1. ALWAYS report the status of each task to Coder before and after your steps. -2. Use the following format for reporting tasks: - ``` - TASK: [brief description of what you're doing] - STATUS: [one of: "started", "in progress", "done", "failed"] - ``` - -3. Send a task report in these specific situations: - - When you BEGIN working on a task - - When you make SIGNIFICANT PROGRESS on a task - - When you COMPLETE a task successfully - - When you ENCOUNTER AN ERROR or cannot complete a task - -4. Example sequence of task reporting: - ``` - TASK: Setting up project structure - STATUS: started - - [Your work and discussion here] - - TASK: Setting up project structure - STATUS: in progress - - [More work and discussion] - - TASK: Setting up project structure - STATUS: done - - TASK: Implementing feature X - STATUS: started - ``` - -5. Always include a brief but descriptive task name that clearly identifies what you're working on. - -These conventions ensure that Coder can properly track task status in the UI. +You are a helpful Coding assistant. Aim to autonomously investigate +and solve issues the user gives you and test your work, whenever possible. +Avoid shortcuts like mocking tests. When you get stuck, you can ask the user +but opt for autonomy. +YOU MUST REPORT ALL TASKS TO CODER. +When reporting tasks, you MUST follow these EXACT instructions: +- IMMEDIATELY report status after receiving ANY user message. +- Be granular. If you are investigating with multiple steps, report each step to coder. +Task state MUST be one of the following: +- Use "state": "working" when actively processing WITHOUT needing additional user input. +- Use "state": "complete" only when finished with a task. +- Use "state": "failure" when you need ANY user input, lack sufficient details, or encounter blockers. +Task summaries MUST: +- Include specifics about what you're doing. +- Include clear and actionable steps for the user. +- Be less than 160 characters in length. EOT } +variable "task_prompt" { + type = string + description = "Task prompt to use with Aider" + default = "" +} + variable "experiment_pre_install_script" { type = string description = "Custom script to run before installing Aider." @@ -138,6 +119,35 @@ variable "experiment_additional_extensions" { default = null } +variable "ai_provider" { + type = string + description = "AI provider to use with Aider (openai, anthropic, azure, google, etc.)" + default = "anthropic" + validation { + condition = contains(["openai", "anthropic", "azure", "google", "cohere", "mistral", "ollama", "custom"], var.ai_provider) + error_message = "ai_provider must be one of: openai, anthropic, azure, google, cohere, mistral, ollama, custom" + } +} + +variable "ai_model" { + type = string + description = "AI model to use with Aider. Can use Aider's built-in aliases like '4o' (gpt-4o), 'sonnet' (claude-3-7-sonnet), 'opus' (claude-3-opus), etc." + default = "sonnet" +} + +variable "ai_api_key" { + type = string + description = "API key for the selected AI provider. This will be set as the appropriate environment variable based on the provider." + default = "" + sensitive = true +} + +variable "custom_env_var_name" { + type = string + description = "Custom environment variable name when using custom provider" + default = "" +} + locals { base_extensions = <<-EOT coder: @@ -171,6 +181,33 @@ EOT encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : "" encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : "" + + # Combine system prompt and task prompt for aider + combined_prompt = trimspace(<<-EOT +SYSTEM PROMPT: +${var.system_prompt} + +This is your current task: ${var.task_prompt} +EOT + ) + + # Map providers to their environment variable names + provider_env_vars = { + openai = "OPENAI_API_KEY" + anthropic = "ANTHROPIC_API_KEY" + azure = "AZURE_OPENAI_API_KEY" + google = "GOOGLE_API_KEY" + cohere = "COHERE_API_KEY" + mistral = "MISTRAL_API_KEY" + ollama = "OLLAMA_HOST" + custom = var.custom_env_var_name + } + + # Get the environment variable name for selected provider + env_var_name = local.provider_env_vars[var.ai_provider] + + # Model flag for aider command + model_flag = var.ai_provider == "ollama" ? "--ollama-model" : "--model" } # Install and Initialize Aider @@ -202,12 +239,21 @@ resource "coder_script" "aider" { if ! command_exists tmux; then echo "Installing tmux for persistent sessions..." if command -v apt-get >/dev/null 2>&1; then - sudo apt-get update -qq - sudo apt-get install -y -qq tmux + if command -v sudo >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq tmux + else + apt-get update -qq || echo "Warning: Cannot update package lists without sudo privileges" + apt-get install -y -qq tmux || echo "Warning: Cannot install tmux without sudo privileges" + fi elif command -v dnf >/dev/null 2>&1; then - sudo dnf install -y -q tmux + if command -v sudo >/dev/null 2>&1; then + sudo dnf install -y -q tmux + else + dnf install -y -q tmux || echo "Warning: Cannot install tmux without sudo privileges" + fi else - echo "Warning: Unable to install tmux on this system." + echo "Warning: Unable to install tmux on this system. Neither apt-get nor dnf found." fi else echo "tmux is already installed, skipping installation." @@ -216,12 +262,21 @@ resource "coder_script" "aider" { if ! command_exists screen; then echo "Installing screen for persistent sessions..." if command -v apt-get >/dev/null 2>&1; then - sudo apt-get update -qq - sudo apt-get install -y -qq screen + if command -v sudo >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq screen + else + apt-get update -qq || echo "Warning: Cannot update package lists without sudo privileges" + apt-get install -y -qq screen || echo "Warning: Cannot install screen without sudo privileges" + fi elif command -v dnf >/dev/null 2>&1; then - sudo dnf install -y -q screen + if command -v sudo >/dev/null 2>&1; then + sudo dnf install -y -q screen + else + dnf install -y -q screen || echo "Warning: Cannot install screen without sudo privileges" + fi else - echo "Warning: Unable to install screen on this system." + echo "Warning: Unable to install screen on this system. Neither apt-get nor dnf found." fi else echo "screen is already installed, skipping installation." @@ -245,12 +300,21 @@ resource "coder_script" "aider" { if ! command_exists python3 || ! command_exists pip3; then echo "Installing Python dependencies required for Aider..." if command -v apt-get >/dev/null 2>&1; then - sudo apt-get update -qq - sudo apt-get install -y -qq python3-pip python3-venv + if command -v sudo >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq python3-pip python3-venv + else + apt-get update -qq || echo "Warning: Cannot update package lists without sudo privileges" + apt-get install -y -qq python3-pip python3-venv || echo "Warning: Cannot install Python packages without sudo privileges" + fi elif command -v dnf >/dev/null 2>&1; then - sudo dnf install -y -q python3-pip python3-virtualenv + if command -v sudo >/dev/null 2>&1; then + sudo dnf install -y -q python3-pip python3-virtualenv + else + dnf install -y -q python3-pip python3-virtualenv || echo "Warning: Cannot install Python packages without sudo privileges" + fi else - echo "Warning: Unable to install Python on this system." + echo "Warning: Unable to install Python on this system. Neither apt-get nor dnf found." fi else echo "Python is already installed, skipping installation." @@ -290,12 +354,6 @@ resource "coder_script" "aider" { ${trimspace(local.combined_extensions)} EOL echo "Added Coder MCP extension to Aider config.yml" - - mkdir -p "${var.folder}" - cat > "${var.folder}/CONVENTIONS.md" << 'CONVENTIONS_EOF' -${var.experiment_task_conventions} -CONVENTIONS_EOF - echo "Created CONVENTIONS.md file with task reporting instructions" fi echo "Starting persistent Aider session..." @@ -308,16 +366,41 @@ CONVENTIONS_EOF export PATH="$HOME/bin:$PATH" if [ "${var.use_tmux}" = "true" ]; then - if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]; then + if [ -n "${var.task_prompt}" ]; then echo "Running Aider with message in tmux session..." - tmux new-session -d -s ${var.session_name} -c ${var.folder} "echo \"Starting Aider with app status slug: aider\"; export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --architect --yes-always --read CONVENTIONS.md --message \"Report each step to Coder. Your task: $CODER_MCP_AIDER_TASK_PROMPT\"" + + # Configure tmux for shared sessions + if [ ! -f "$HOME/.tmux.conf" ]; then + echo "Creating ~/.tmux.conf with shared session settings..." + echo "set -g mouse on" > "$HOME/.tmux.conf" + fi + + if ! grep -q "^set -g mouse on$" "$HOME/.tmux.conf"; then + echo "Adding 'set -g mouse on' to ~/.tmux.conf..." + echo "set -g mouse on" >> "$HOME/.tmux.conf" + fi + + echo "Starting Aider using ${var.ai_provider} provider and model: ${var.ai_model}" + tmux new-session -d -s ${var.session_name} -c ${var.folder} "export ${local.env_var_name}=\"${var.ai_api_key}\"; aider --architect --yes-always ${local.model_flag} ${var.ai_model} --message \"${local.combined_prompt}\"" echo "Aider task started in tmux session '${var.session_name}'. Check the UI for progress." else - tmux new-session -d -s ${var.session_name} -c ${var.folder} "echo \"Starting Aider with app status slug: aider\"; export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --read CONVENTIONS.md" + # Configure tmux for shared sessions + if [ ! -f "$HOME/.tmux.conf" ]; then + echo "Creating ~/.tmux.conf with shared session settings..." + echo "set -g mouse on" > "$HOME/.tmux.conf" + fi + + if ! grep -q "^set -g mouse on$" "$HOME/.tmux.conf"; then + echo "Adding 'set -g mouse on' to ~/.tmux.conf..." + echo "set -g mouse on" >> "$HOME/.tmux.conf" + fi + + echo "Starting Aider using ${var.ai_provider} provider and model: ${var.ai_model}" + tmux new-session -d -s ${var.session_name} -c ${var.folder} "export ${local.env_var_name}=\"${var.ai_api_key}\"; aider --architect --yes-always ${local.model_flag} ${var.ai_model} --message \"${var.system_prompt}\"" echo "Tmux session '${var.session_name}' started. Access it by clicking the Aider button." fi else - if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]; then + if [ -n "${var.task_prompt}" ]; then echo "Running Aider with message in screen session..." if [ ! -f "$HOME/.screenrc" ]; then @@ -335,13 +418,12 @@ CONVENTIONS_EOF echo "acladd $(whoami)" >> "$HOME/.screenrc" fi + echo "Starting Aider using ${var.ai_provider} provider and model: ${var.ai_model}" screen -U -dmS ${var.session_name} bash -c " cd ${var.folder} export PATH=\"$HOME/bin:$HOME/.local/bin:$PATH\" - export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\" - export CODER_MCP_APP_STATUS_SLUG=\"aider\" - echo \"Starting Aider with app status slug: aider\" - aider --architect --yes-always --read CONVENTIONS.md --message \"Report each step to Coder. Your task: $CODER_MCP_AIDER_TASK_PROMPT\" + export ${local.env_var_name}=\"${var.ai_api_key}\" + aider --architect --yes-always ${local.model_flag} ${var.ai_model} --message \"${local.combined_prompt}\" /bin/bash " @@ -363,13 +445,12 @@ CONVENTIONS_EOF echo "acladd $(whoami)" >> "$HOME/.screenrc" fi + echo "Starting Aider using ${var.ai_provider} provider and model: ${var.ai_model}" screen -U -dmS ${var.session_name} bash -c " cd ${var.folder} export PATH=\"$HOME/bin:$HOME/.local/bin:$PATH\" - export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\" - export CODER_MCP_APP_STATUS_SLUG=\"aider\" - echo \"Starting Aider with app status slug: aider\" - aider --read CONVENTIONS.md + export ${local.env_var_name}=\"${var.ai_api_key}\" + aider --architect --yes-always ${local.model_flag} ${var.ai_model} --message \"${local.combined_prompt}\" /bin/bash " echo "Screen session '${var.session_name}' started. Access it by clicking the Aider button." @@ -393,32 +474,28 @@ resource "coder_app" "aider_cli" { export PATH="$HOME/bin:$HOME/.local/bin:$PATH" - export CODER_MCP_APP_STATUS_SLUG="aider" - export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 if [ "${var.use_tmux}" = "true" ]; then if tmux has-session -t ${var.session_name} 2>/dev/null; then echo "Attaching to existing Aider tmux session..." - tmux setenv -t ${var.session_name} CODER_MCP_APP_STATUS_SLUG "aider" tmux attach-session -t ${var.session_name} else echo "Starting new Aider tmux session..." - tmux new-session -s ${var.session_name} -c ${var.folder} "export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --read CONVENTIONS.md; exec bash" + tmux new-session -s ${var.session_name} -c ${var.folder} "export ${local.env_var_name}=\"${var.ai_api_key}\"; aider ${local.model_flag} ${var.ai_model} --message \"${local.combined_prompt}\"; exec bash" fi elif [ "${var.use_screen}" = "true" ]; then if ! screen -list | grep -q "${var.session_name}"; then echo "Error: No existing Aider session found. Please wait for the script to start it." exit 1 fi - export CODER_MCP_APP_STATUS_SLUG="aider" screen -xRR ${var.session_name} else cd "${var.folder}" echo "Starting Aider directly..." - export CODER_MCP_APP_STATUS_SLUG="aider" - aider --read CONVENTIONS.md + export ${local.env_var_name}="${var.ai_api_key}" + aider ${local.model_flag} ${var.ai_model} --message "${local.combined_prompt}" fi EOT order = var.order From 0a63eb5637390a23f9c4a9d8bb3d3e5ab5e8ed64 Mon Sep 17 00:00:00 2001 From: DevelopmentCats Date: Thu, 15 May 2025 13:31:46 +0000 Subject: [PATCH 5/7] docs(aider): prettier formatting --- registry/coder/modules/aider/README.md | 40 ++++++++++++++------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/registry/coder/modules/aider/README.md b/registry/coder/modules/aider/README.md index a0ca3b2..ff29303 100644 --- a/registry/coder/modules/aider/README.md +++ b/registry/coder/modules/aider/README.md @@ -44,7 +44,7 @@ module "aider" { | `icon` | The icon to use for the app | `string` | `"/icon/aider.svg"` | | `experiment_report_tasks` | Whether to enable task reporting | `bool` | `true` | | `system_prompt` | System prompt for instructing Aider on task reporting and behavior | `string` | See default in code | -| `task_prompt` | Task prompt to use with Aider | `string` | `""` | +| `task_prompt` | Task prompt to use with Aider | `string` | `""` | | `ai_provider` | AI provider to use with Aider (openai, anthropic, azure, etc.) | `string` | `"anthropic"` | | `ai_model` | AI model to use (can use Aider's built-in aliases like "sonnet", "4o") | `string` | `"sonnet"` | | `ai_api_key` | API key for the selected AI provider | `string` | `""` | @@ -98,7 +98,7 @@ module "aider" { agent_id = coder_agent.example.id use_tmux = true ai_provider = "openai" - ai_model = "4o" # Uses Aider's built-in alias for gpt-4o + ai_model = "4o" # Uses Aider's built-in alias for gpt-4o ai_api_key = var.openai_api_key } ``` @@ -113,14 +113,14 @@ variable "custom_api_key" { } module "aider" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" - version = "1.0.0" - agent_id = coder_agent.example.id - ai_provider = "custom" + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + ai_provider = "custom" custom_env_var_name = "MY_CUSTOM_API_KEY" - ai_model = "custom-model" - ai_api_key = var.custom_api_key + ai_model = "custom-model" + ai_api_key = var.custom_api_key } ``` @@ -287,16 +287,16 @@ Persistent sessions (screen/tmux) allow you to: Aider supports various providers and models, and this module integrates directly with Aider's built-in model aliases: -| Provider | Example Models/Aliases | Default Model | -| -------------- | ------------------------------------------- | ----------------- | -| **anthropic** | "sonnet" (Claude 3.7 Sonnet), "opus", "haiku" | "sonnet" | -| **openai** | "4o" (GPT-4o), "4" (GPT-4), "3.5-turbo" | "4o" | -| **azure** | Azure OpenAI models | "gpt-4" | -| **google** | "gemini" (Gemini Pro), "gemini-2.5-pro" | "gemini-2.5-pro" | -| **cohere** | "command-r-plus", etc. | "command-r-plus" | -| **mistral** | "mistral-large-latest" | "mistral-large-latest" | -| **ollama** | "llama3", etc. | "llama3" | -| **custom** | Any model name with custom ENV variable | - | +| Provider | Example Models/Aliases | Default Model | +| ------------- | --------------------------------------------- | ---------------------- | +| **anthropic** | "sonnet" (Claude 3.7 Sonnet), "opus", "haiku" | "sonnet" | +| **openai** | "4o" (GPT-4o), "4" (GPT-4), "3.5-turbo" | "4o" | +| **azure** | Azure OpenAI models | "gpt-4" | +| **google** | "gemini" (Gemini Pro), "gemini-2.5-pro" | "gemini-2.5-pro" | +| **cohere** | "command-r-plus", etc. | "command-r-plus" | +| **mistral** | "mistral-large-latest" | "mistral-large-latest" | +| **ollama** | "llama3", etc. | "llama3" | +| **custom** | Any model name with custom ENV variable | - | For a complete and up-to-date list of supported aliases and models, please refer to the [Aider LLM documentation](https://aider.chat/docs/llms.html) and the [Aider LLM Leaderboards](https://aider.chat/docs/leaderboards.html) which show performance comparisons across different models. @@ -311,3 +311,5 @@ If you encounter issues: For more information on using Aider, see the [Aider documentation](https://aider.chat/docs/). ``` + +``` From ab6bae86811f2ce92898afcbe84044a2bdcd58e0 Mon Sep 17 00:00:00 2001 From: M Atif Ali Date: Thu, 15 May 2025 19:19:49 +0500 Subject: [PATCH 6/7] Update registry/coder/modules/aider/README.md --- registry/coder/modules/aider/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/aider/README.md b/registry/coder/modules/aider/README.md index ff29303..39d22b7 100644 --- a/registry/coder/modules/aider/README.md +++ b/registry/coder/modules/aider/README.md @@ -13,7 +13,7 @@ Run [Aider](https://aider.chat) AI pair programming in your workspace. This modu ```tf module "aider" { - source = "registry.coder.com/modules/aider/coder" + source = "registry.coder.com/coder/aider/coder" version = "1.0.0" agent_id = coder_agent.example.id } From c4850051e9f9addc124a8fdaabf99a513a6ca5b7 Mon Sep 17 00:00:00 2001 From: M Atif Ali Date: Thu, 15 May 2025 19:30:24 +0500 Subject: [PATCH 7/7] Apply suggestions from code review --- registry/coder/modules/aider/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/aider/README.md b/registry/coder/modules/aider/README.md index 39d22b7..c1d8697 100644 --- a/registry/coder/modules/aider/README.md +++ b/registry/coder/modules/aider/README.md @@ -68,7 +68,7 @@ variable "anthropic_api_key" { module "aider" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" + source = "registry.coder.com/coder/aider/coder" version = "1.0.0" agent_id = coder_agent.example.id ai_api_key = var.anthropic_api_key @@ -93,7 +93,7 @@ variable "openai_api_key" { module "aider" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" + source = "registry.coder.com/coder/aider/coder" version = "1.0.0" agent_id = coder_agent.example.id use_tmux = true @@ -114,7 +114,7 @@ variable "custom_api_key" { module "aider" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" + source = "registry.coder.com/coder/aider/coder" version = "1.0.0" agent_id = coder_agent.example.id ai_provider = "custom" @@ -131,7 +131,7 @@ You can extend Aider's capabilities by adding custom extensions: ```tf module "aider" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" + source = "registry.coder.com/coder/aider/coder" version = "1.0.0" agent_id = coder_agent.example.id ai_api_key = var.anthropic_api_key @@ -210,7 +210,7 @@ data "coder_parameter" "ai_prompt" { module "aider" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/modules/aider/coder" + source = "registry.coder.com/coder/aider/coder" version = "1.0.0" agent_id = coder_agent.example.id ai_api_key = var.anthropic_api_key