Skip to content

feat(gemini): gemini cleanup and refactor #300

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
18d0917
chore: cleanup gemini script and docs
DevelopmentCats Aug 5, 2025
40d4d3f
feat(gemini): add YOLO mode for auto-approving tool calls and update …
DevelopmentCats Aug 5, 2025
ce41f0c
chore(gemini): clean up install and start scripts by removing unneces…
DevelopmentCats Aug 5, 2025
4fcc003
fix(gemini): update test expectation for API key usage message and bu…
DevelopmentCats Aug 5, 2025
370e73d
refactor(gemini): improve parameter persistence and argument handling
DevelopmentCats Aug 5, 2025
9b44262
refactor(gemini): reorganize agentapi module configuration and enhanc…
DevelopmentCats Aug 5, 2025
00647fd
refactor(gemini): enhance task prompt handling and streamline start s…
DevelopmentCats Aug 5, 2025
5dab7a5
refactor(gemini): remove hardcoded port configuration and simplify ag…
DevelopmentCats Aug 5, 2025
0f91c17
fix(gemini): fix agentapi versions
DevelopmentCats Aug 5, 2025
6d8db8d
refactor(gemini): enable interactive mode for Gemini CLI when a task …
DevelopmentCats Aug 5, 2025
f1ecaac
refactor(gemini): update GEMINI_ARGS to use --prompt-interactive for …
DevelopmentCats Aug 5, 2025
86f7b8a
chore(gemini): replace gemini-mock.sh with inline mock content in set…
DevelopmentCats Aug 6, 2025
c0d7605
chore(gemini): update version to 1.1.0 in README.md for minor version…
DevelopmentCats Aug 6, 2025
f7c25f6
docs(gemini): update link to Gemini CLI documentation
DevelopmentCats Aug 6, 2025
7d21009
chore: remove whitespace from env
DevelopmentCats Aug 6, 2025
2d25a04
Merge branch 'main' into cat/gemini-cleanup
DevelopmentCats Aug 6, 2025
29c82c0
feat(gemini): add folder parameter to module configuration and change…
DevelopmentCats Aug 6, 2025
3889862
Merge branch 'main' into cat/gemini-cleanup
DevelopmentCats Aug 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 100 additions & 37 deletions registry/coder-labs/modules/gemini/README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
---
display_name: Gemini CLI
description: Run Gemini CLI in your workspace for AI pair programming
icon: ../../../../.icons/gemini.svg
description: Run Gemini CLI in your workspace with AgentAPI integration
verified: true
tags: [agent, gemini, ai, google, tasks]
---

# Gemini CLI

Run [Gemini CLI](https://ai.google.dev/gemini-api/docs/cli) in your workspace to access Google's Gemini AI models, and custom pre/post install scripts. This module integrates with [AgentAPI](https://github.com/coder/agentapi) for Coder Tasks compatibility.
Run [Gemini CLI](https://github.com/google-gemini/gemini-cli) in your workspace to access Google's Gemini AI models for interactive coding assistance and automated task execution.

```tf
module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
gemini_api_key = var.gemini_api_key
gemini_model = "gemini-2.5-pro"
install_gemini = true
gemini_version = "latest"
agentapi_version = "latest"
source = "registry.coder.com/coder-labs/gemini/coder"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
```

## Features

- **Interactive AI Assistance**: Run Gemini CLI directly in your terminal for coding help
- **Automated Task Execution**: Execute coding tasks automatically via AgentAPI integration
- **Multiple AI Models**: Support for Gemini 2.5 Pro, Flash, and other Google AI models
- **API Key Integration**: Seamless authentication with Gemini API
- **MCP Server Integration**: Built-in Coder MCP server for task reporting
- **Persistent Sessions**: Maintain context across workspace sessions

## Prerequisites

- You must add the [Coder Login](https://registry.coder.com/modules/coder-login/coder) module to your template
- Node.js and npm will be installed automatically if not present
- The [Coder Login](https://registry.coder.com/modules/coder/coder-login) module is required

## Usage Example
## Examples

- Example 1:
### Basic setup

```tf
variable "gemini_api_key" {
Expand All @@ -40,39 +45,97 @@ variable "gemini_api_key" {
}

module "gemini" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/gemini/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
gemini_api_key = var.gemini_api_key # we recommend providing this parameter inorder to have a smoother experience (i.e. no google sign-in)
gemini_model = "gemini-2.5-flash"
install_gemini = true
gemini_version = "latest"
gemini_instruction_prompt = "Start every response with `Gemini says:`"
source = "registry.coder.com/coder-labs/gemini/coder"
version = "1.1.0"
agent_id = coder_agent.example.id
gemini_api_key = var.gemini_api_key
folder = "/home/coder/project"
}
```

## How it Works
This basic setup will:

- Install Gemini CLI in the workspace
- Configure authentication with your API key
- Set Gemini to run in `/home/coder/project` directory
- Enable interactive use from the terminal
- Set up MCP server integration for task reporting

### Automated task execution (Experimental)

> This functionality is in early access 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/ai-coder)

```tf
variable "gemini_api_key" {
type = string
description = "Gemini API key"
sensitive = true
}

module "coder-login" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/coder-login/coder"
version = "~> 1.0"
agent_id = coder_agent.example.id
}

- **Install**: The module installs Gemini CLI using npm (installs Node.js via NVM if needed)
- **Instruction Prompt**: If `GEMINI_INSTRUCTION_PROMPT` and `GEMINI_START_DIRECTORY` are set, creates the directory (if needed) and writes the prompt to `GEMINI.md`
- **Start**: Launches Gemini CLI in the specified directory, wrapped by AgentAPI
- **Environment**: Sets `GEMINI_API_KEY`, `GOOGLE_GENAI_USE_VERTEXAI`, `GEMINI_MODEL` for the CLI (if variables provided)
data "coder_parameter" "ai_prompt" {
type = "string"
name = "AI Prompt"
default = ""
description = "Task prompt for automated Gemini execution"
mutable = true
}

module "gemini" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/gemini/coder"
version = "1.1.0"
agent_id = coder_agent.example.id
gemini_api_key = var.gemini_api_key
gemini_model = "gemini-2.5-flash"
folder = "/home/coder/project"
task_prompt = data.coder_parameter.ai_prompt.value
enable_yolo_mode = true # Auto-approve all tool calls for automation
gemini_system_prompt = <<-EOT
You are a helpful coding assistant. Always explain your code changes clearly.
YOU MUST REPORT ALL TASKS TO CODER.
EOT
}
```

> [!WARNING]
> YOLO mode automatically approves all tool calls without user confirmation. The agent has access to your machine's file system and terminal. Only enable in trusted, isolated environments.

### Using Vertex AI (Enterprise)

For enterprise users who prefer Google's Vertex AI platform:

```tf
module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder"
version = "1.1.0"
agent_id = coder_agent.example.id
gemini_api_key = var.gemini_api_key
folder = "/home/coder/project"
use_vertexai = true
}
```

## Troubleshooting

- If Gemini CLI is not found, ensure `install_gemini = true` and your API key is valid
- Node.js and npm are installed automatically if missing (using NVM)
- Check logs in `/home/coder/.gemini-module/` for install/start output
- We highly recommend using the `gemini_api_key` variable, this also ensures smooth tasks running without needing to sign in to Google.
- If Gemini CLI is not found, ensure your API key is valid (`install_gemini` defaults to `true`)
- Check logs in `~/.gemini-module/` for install/start output
- Use the `gemini_api_key` variable to avoid requiring Google sign-in

> [!IMPORTANT]
> To use tasks with Gemini CLI, ensure you have the `gemini_api_key` variable set, and **you pass the `AI Prompt` Parameter**.
> By default we inject the "theme": "Default" and "selectedAuthType": "gemini-api-key" to your ~/.gemini/settings.json along with the coder mcp server.
> In `gemini_instruction_prompt` and `AI Prompt` text we recommend using (\`\`) backticks instead of quotes to avoid escaping issues. Eg: gemini_instruction_prompt = "Start every response with \`Gemini says:\` "
The module creates log files in the workspace's `~/.gemini-module` directory for debugging purposes.

## References

- [Gemini CLI Documentation](https://ai.google.dev/gemini-api/docs/cli)
- [Gemini CLI Documentation](https://github.com/google-gemini/gemini-cli/blob/main/docs/index.md)
- [AgentAPI Documentation](https://github.com/coder/agentapi)
- [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents)
- [Coder AI Agents Guide](https://coder.com/docs/ai-coder)
35 changes: 31 additions & 4 deletions registry/coder-labs/modules/gemini/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
} from "bun:test";
import { execContainer, readFileContainer, runTerraformInit } from "~test";
import {
loadTestFile,
writeExecutable,
setup as setupUtil,
execModuleScript,
Expand Down Expand Up @@ -54,10 +53,24 @@ const setup = async (props?: SetupProps): Promise<{ id: string }> => {
agentapiMockScript: props?.agentapiMockScript,
});
if (!props?.skipGeminiMock) {
const geminiMockContent = `#!/bin/bash

if [[ "$1" == "--version" ]]; then
echo "HELLO: $(bash -c env)"
echo "gemini version v2.5.0"
exit 0
fi

set -e

while true; do
echo "$(date) - gemini-mock"
sleep 15
done`;
await writeExecutable({
containerId: id,
filePath: "/usr/bin/gemini",
content: await loadTestFile(import.meta.dir, "gemini-mock.sh"),
content: geminiMockContent,
});
}
return { id };
Expand All @@ -70,7 +83,7 @@ describe("gemini", async () => {
await runTerraformInit(import.meta.dir);
});

test("happy-path", async () => {
test("agent-api", async () => {
const { id } = await setup();
await execModuleScript(id);
await expectAgentAPIStarted(id);
Expand Down Expand Up @@ -117,7 +130,7 @@ describe("gemini", async () => {
await execModuleScript(id);

const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log");
expect(resp).toContain("gemini_api_key provided !");
expect(resp).toContain("Using direct Gemini API with API key");
});

test("use-vertexai", async () => {
Expand Down Expand Up @@ -197,6 +210,20 @@ describe("gemini", async () => {
expect(resp).toContain(prompt);
});

test("task-prompt", async () => {
const taskPrompt = "Create a simple Hello World function";
const { id } = await setup({
moduleVariables: {
task_prompt: taskPrompt,
},
});
await execModuleScript(id, {
GEMINI_TASK_PROMPT: taskPrompt,
});
const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log");
expect(resp).toContain("Running automated task:");
});

test("start-without-prompt", async () => {
const { id } = await setup();
await execModuleScript(id);
Expand Down
61 changes: 36 additions & 25 deletions registry/coder-labs/modules/gemini/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ variable "use_vertexai" {

variable "install_agentapi" {
type = bool
description = "Whether to install AgentAPI."
description = "Whether to install AgentAPI for web UI and task automation."
default = true
}

variable "agentapi_version" {
type = string
description = "The version of AgentAPI to install."
default = "v0.3.0"
default = "v0.2.3"
}

variable "gemini_model" {
Expand All @@ -102,12 +102,10 @@ variable "post_install_script" {
default = null
}

data "coder_parameter" "ai_prompt" {
type = "string"
name = "AI Prompt"
variable "task_prompt" {
type = string
description = "Task prompt for automated Gemini execution"
default = ""
description = "Initial prompt for the Gemini CLI"
mutable = true
}

variable "additional_extensions" {
Expand All @@ -122,12 +120,24 @@ variable "gemini_system_prompt" {
default = ""
}

variable "enable_yolo_mode" {
type = bool
description = "Enable YOLO mode to automatically approve all tool calls without user confirmation. Use with caution."
default = false
}

resource "coder_env" "gemini_api_key" {
agent_id = var.agent_id
name = "GEMINI_API_KEY"
value = var.gemini_api_key
}

resource "coder_env" "google_api_key" {
agent_id = var.agent_id
name = "GOOGLE_API_KEY"
value = var.gemini_api_key
}

resource "coder_env" "gemini_use_vertex_ai" {
agent_id = var.agent_id
name = "GOOGLE_GENAI_USE_VERTEXAI"
Expand Down Expand Up @@ -166,7 +176,7 @@ EOT

module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "1.0.0"
version = "1.0.2"

agent_id = var.agent_id
web_app_slug = local.app_slug
Expand All @@ -181,22 +191,7 @@ module "agentapi" {
agentapi_version = var.agentapi_version
pre_install_script = var.pre_install_script
post_install_script = var.post_install_script
start_script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail

echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
chmod +x /tmp/start.sh
GEMINI_API_KEY='${var.gemini_api_key}' \
GOOGLE_GENAI_USE_VERTEXAI='${var.use_vertexai}' \
GEMINI_MODEL='${var.gemini_model}' \
GEMINI_START_DIRECTORY='${var.folder}' \
GEMINI_TASK_PROMPT='${base64encode(data.coder_parameter.ai_prompt.value)}' \
/tmp/start.sh
EOT

install_script = <<-EOT
install_script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail
Expand All @@ -209,7 +204,23 @@ module "agentapi" {
BASE_EXTENSIONS='${base64encode(replace(local.base_extensions, "'", "'\\''"))}' \
ADDITIONAL_EXTENSIONS='${base64encode(replace(var.additional_extensions != null ? var.additional_extensions : "", "'", "'\\''"))}' \
GEMINI_START_DIRECTORY='${var.folder}' \
GEMINI_INSTRUCTION_PROMPT='${base64encode(var.gemini_system_prompt)}' \
GEMINI_SYSTEM_PROMPT='${base64encode(var.gemini_system_prompt)}' \
/tmp/install.sh
EOT
start_script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail

echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
chmod +x /tmp/start.sh
GEMINI_API_KEY='${var.gemini_api_key}' \
GOOGLE_API_KEY='${var.gemini_api_key}' \
GOOGLE_GENAI_USE_VERTEXAI='${var.use_vertexai}' \
GEMINI_YOLO_MODE='${var.enable_yolo_mode}' \
GEMINI_MODEL='${var.gemini_model}' \
GEMINI_START_DIRECTORY='${var.folder}' \
GEMINI_TASK_PROMPT='${var.task_prompt}' \
/tmp/start.sh
EOT
}
Loading