Skip to content

feat: Sourcegraph Amp module #257

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 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .icons/sourcegraph-amp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions registry/harsh9485/modules/sourcegraph_amp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---

display\_name: Sourcegraph AMP
icon: ../../../../.icons/sourcegraph-amp.svg
description: Run Sourcegraph AMP CLI in your workspace with AgentAPI integration
verified: true
tags: \[agent, sourcegraph, amp, ai, tasks]
---

# Sourcegraph AMP CLI

Run [Sourcegraph AMP CLI](https://sourcegraph.com/amp) in your workspace to access Sourcegraph's AI-powered code search and analysis tools, with AgentAPI integration for seamless Coder Tasks support.

```tf
module "sourcegraph_amp" {
source = "registry.coder.com/harsh9485/sourcegraph-amp/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
sourcegraph_amp_api_key = var.sourcegraph_amp_api_key
install_sourcegraph-amp = true
agentapi_version = "latest"
}
```

## Prerequisites

* Include the [Coder Login](https://registry.coder.com/modules/coder-login/coder) module in your template
* Node.js and npm are automatically installed (via NVM) if not already available

## Usage Example

```tf
variable "sourcegraph_amp_api_key" {
type = string
description = "Sourcegraph AMP API key"
sensitive = true
}

module "sourcegraph_amp" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/harsh9485/sourcegraph-amp/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
sourcegraph_amp_api_key = var.sourcegraph_amp_api_key # recommended for authenticated usage
install_sourcegraph-amp = true
}
```

## How it Works

* **Install**: Installs Sourcegraph AMP CLI using npm (installs Node.js via NVM if required)
* **Start**: Launches AMP CLI in the specified directory, wrapped with AgentAPI to enable tasks and AI interactions
* **Environment Variables**: Sets `SOURCEGRAPH_AMP_API_KEY` and `SOURCEGRAPH_AMP_START_DIRECTORY` for the CLI execution

## Troubleshooting

* If `amp` is not found, ensure `install_sourcegraph-amp = true` and your API key is valid
* Logs are written under `/home/coder/.sourcegraph-amp-module/` (`install.log`, `agentapi-start.log`) for debugging
* If AgentAPI fails to start, verify that your container has network access and executable permissions for the scripts

> \[!IMPORTANT]
> For using **Coder Tasks** with Sourcegraph AMP, make sure to pass the `AI Prompt` parameter and set `sourcegraph_amp_api_key`.
> This ensures task reporting and status updates work seamlessly.

## References

* [Sourcegraph AMP Documentation](https://sourcegraph.com/amp)
* [AgentAPI Documentation](https://github.com/coder/agentapi)
* [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents)
126 changes: 126 additions & 0 deletions registry/harsh9485/modules/sourcegraph_amp/main.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
test,
afterEach,
describe,
setDefaultTimeout,
beforeAll,
expect,
} from "bun:test";
import { execContainer, readFileContainer, runTerraformInit } from "~test";
import {
loadTestFile,
writeExecutable,
setup as setupUtil,
execModuleScript,
expectAgentAPIStarted,
} from "../../../coder/modules/agentapi/test-util";

let cleanupFunctions: (() => Promise<void>)[] = [];
const registerCleanup = (cleanup: () => Promise<void>) => {
cleanupFunctions.push(cleanup);
};
afterEach(async () => {
const cleanupFnsCopy = cleanupFunctions.slice().reverse();
cleanupFunctions = [];
for (const cleanup of cleanupFnsCopy) {
try {
await cleanup();
} catch (error) {
console.error("Error during cleanup:", error);
}
}
});

interface SetupProps {
skipAgentAPIMock?: boolean;
skipAmpMock?: boolean;
moduleVariables?: Record<string, string>;
agentapiMockScript?: string;
}

const setup = async (props?: SetupProps): Promise<{ id: string }> => {
const projectDir = "/home/coder/project";
const { id } = await setupUtil({
moduleDir: import.meta.dir,
moduleVariables: {
install_sourcegraph_amp: props?.skipAmpMock ? "true" : "false",
install_agentapi: props?.skipAgentAPIMock ? "true" : "false",
sourcegraph_amp_model: "test-model",
...props?.moduleVariables,
},
registerCleanup,
projectDir,
skipAgentAPIMock: props?.skipAgentAPIMock,
agentapiMockScript: props?.agentapiMockScript,
});

// Place the AMP mock CLI binary inside the container
if (!props?.skipAmpMock) {
await writeExecutable({
containerId: id,
filePath: "/usr/bin/amp",
content: await loadTestFile(`${import.meta.dir}`, "amp-mock.sh"),
});
}

return { id };
};

setDefaultTimeout(60 * 1000 * 8);

describe("Sourcegraph AMP Module", async () => {
beforeAll(async () => {
await runTerraformInit(import.meta.dir);
});

test("happy-path", async () => {
const { id } = await setup();
await execModuleScript(id);
await expectAgentAPIStarted(id);
});

test("sourcegraph-amp-api-key", async () => {
const apiKey = "test-api-key-123";
const { id } = await setup({
moduleVariables: {
sourcegraph_amp_api_key: apiKey,
},
});
await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.sourcegraph-amp-module/agentapi-start.log");
expect(resp).toContain("AMP version: AMP CLI mock version v1.0.0");
});

test("custom-folder", async () => {
const folder = "/tmp/sourcegraph-amp-test";
const { id } = await setup({
moduleVariables: {
folder,
},
});
await execModuleScript(id);
const resp = await readFileContainer(id, "/home/coder/.sourcegraph-amp-module/install.log");
expect(resp).toContain(folder);
});

test("pre-post-install-scripts", async () => {
const { id } = await setup({
moduleVariables: {
pre_install_script: "#!/bin/bash\necho 'pre-install-script'",
post_install_script: "#!/bin/bash\necho 'post-install-script'",
},
});
await execModuleScript(id);
const preLog = await readFileContainer(id, "/home/coder/.sourcegraph-amp-module/pre_install.log");
expect(preLog).toContain("pre-install-script");
const postLog = await readFileContainer(id, "/home/coder/.sourcegraph-amp-module/post_install.log");
expect(postLog).toContain("post-install-script");
});

test("amp-not-installed", async () => {
const { id } = await setup({ skipAmpMock: true });
await execModuleScript(id);
const log = await readFileContainer(id, "/home/coder/.sourcegraph-amp-module/install.log");
expect(log).toContain("Error");
});
});
160 changes: 160 additions & 0 deletions registry/harsh9485/modules/sourcegraph_amp/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
terraform {
required_version = ">= 1.0"

required_providers {
coder = {
source = "coder/coder"
version = ">= 2.7"
}
}
}

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 "group" {
type = string
description = "The name of a group that this app belongs to."
default = null
}

variable "icon" {
type = string
description = "The icon to use for the app."
default = "/icon/sourcegraph-amp.svg"
}

variable "folder" {
type = string
description = "The folder to run sourcegraph-amp in."
default = "/home/coder"
}

variable "install_sourcegraph-amp" {
type = bool
description = "Whether to install sourcegraph-amp."
default = true
}

variable "sourcegraph-amp_api_key" {
type = string
description = "sourcegraph-amp API Key"
default = ""
}

resource "coder_env" "sourcegraph-amp_api_key" {
agent_id = var.agent_id
name = "SOURCEGRAPH_AMP_API_KEY"
value = var.sourcegraph-amp_api_key
}

variable "install_agentapi" {
type = bool
description = "Whether to install AgentAPI."
default = true
}

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

variable "pre_install_script" {
type = string
description = "Custom script to run before installing sourcegraph-amp"
default = null
}

variable "post_install_script" {
type = string
description = "Custom script to run after installing sourcegraph-amp."
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: ${local.app_slug}
CODER_MCP_AI_AGENTAPI_URL: http://localhost:3284
name: Coder
timeout: 3000
type: stdio
developer:
display_name: Developer
enabled: true
name: developer
timeout: 300
type: builtin
EOT

app_slug = "sourcegraph-amp"
install_script = file("${path.module}/scripts/install.sh")
start_script = file("${path.module}/scripts/start.sh")
module_dir_name = ".sourcegraph-amp-module"
}

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

agent_id = var.agent_id
web_app_slug = local.app_slug
web_app_order = var.order
web_app_group = var.group
web_app_icon = var.icon
web_app_display_name = "Sourcegraph Amp"
cli_app_slug = "${local.app_slug}-cli"
cli_app_display_name = "Sourcegraph Amp CLI"
module_dir_name = local.module_dir_name
install_agentapi = var.install_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
SOURCEGRAPH_AMP_API_KEY='${var.sourcegraph-amp_api_key}' \
SOURCEGRAPH_AMP_START_DIRECTORY='${var.folder}' \
/tmp/start.sh
EOT

install_script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail

echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
chmod +x /tmp/install.sh
ARG_INSTALL_SOURCEGRAPH_AMP='${var.install_sourcegraph-amp}' \
SOURCEGRAPH_AMP_START_DIRECTORY='${var.folder}' \
BASE_EXTENSIONS='${replace(local.base_extensions, "'", "'\\''")}' \
/tmp/install.sh
EOT
}


Loading