Compare commits
14 Commits
main
...
35C4n0r/ch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88ddf343ba | ||
|
|
aa6c429a3c | ||
|
|
f73c20a50a | ||
|
|
90fe6a50a0 | ||
|
|
70f4d625b8 | ||
|
|
c70954191e | ||
|
|
2d8699b465 | ||
|
|
9e827d526e | ||
|
|
236c1ccd02 | ||
|
|
496c29dda7 | ||
|
|
d6b490ecb2 | ||
|
|
b5e79685e6 | ||
|
|
45d3d8ee19 | ||
|
|
c61c6fdb26 |
@ -13,12 +13,15 @@ Run [GitHub Copilot CLI](https://docs.github.com/copilot/concepts/agents/about-c
|
|||||||
```tf
|
```tf
|
||||||
module "copilot" {
|
module "copilot" {
|
||||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
workdir = "/home/coder/projects"
|
workdir = "/home/coder/projects"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> **Security Notice**: This module runs Copilot with `--allow-all` by default, which enables all permissions (equivalent to `--allow-all-tools --allow-all-paths --allow-all-urls`). This bypasses permission prompts and allows Copilot unrestricted access to tools, file paths, and URLs. Use this module _only_ in trusted environments.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> This example assumes you have [Coder external authentication](https://coder.com/docs/admin/external-auth) configured with `id = "github"`. If not, you can provide a direct token using the `github_token` variable or provide the correct external authentication id for GitHub by setting `external_auth_id = "my-github"`.
|
> This example assumes you have [Coder external authentication](https://coder.com/docs/admin/external-auth) configured with `id = "github"`. If not, you can provide a direct token using the `github_token` variable or provide the correct external authentication id for GitHub by setting `external_auth_id = "my-github"`.
|
||||||
|
|
||||||
@ -51,7 +54,7 @@ data "coder_parameter" "ai_prompt" {
|
|||||||
|
|
||||||
module "copilot" {
|
module "copilot" {
|
||||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
workdir = "/home/coder/projects"
|
workdir = "/home/coder/projects"
|
||||||
|
|
||||||
@ -71,7 +74,7 @@ Customize tool permissions, MCP servers, and Copilot settings:
|
|||||||
```tf
|
```tf
|
||||||
module "copilot" {
|
module "copilot" {
|
||||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
workdir = "/home/coder/projects"
|
workdir = "/home/coder/projects"
|
||||||
|
|
||||||
@ -215,6 +218,19 @@ By default, the module resumes the latest Copilot session when the workspace res
|
|||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Session resumption requires persistent storage for the home directory or workspace volume. Without persistent storage, sessions will not resume across workspace restarts.
|
> Session resumption requires persistent storage for the home directory or workspace volume. Without persistent storage, sessions will not resume across workspace restarts.
|
||||||
|
|
||||||
|
## State Persistence
|
||||||
|
|
||||||
|
AgentAPI can save and restore its conversation state to disk across workspace restarts. This complements `resume_session` (which resumes the Copilot CLI session) by also preserving the AgentAPI-level context. Enabled by default, requires agentapi >= v0.12.0 (older versions skip it with a warning).
|
||||||
|
|
||||||
|
To disable:
|
||||||
|
|
||||||
|
```tf
|
||||||
|
module "copilot" {
|
||||||
|
# ... other config
|
||||||
|
enable_state_persistence = false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
If you encounter any issues, check the log files in the `~/.copilot-module` directory within your workspace for detailed information.
|
If you encounter any issues, check the log files in the `~/.copilot-module` directory within your workspace for detailed information.
|
||||||
|
|||||||
@ -347,3 +347,32 @@ run "aibridge_proxy_with_copilot_config" {
|
|||||||
error_message = "copilot_model environment variable should be set alongside proxy"
|
error_message = "copilot_model environment variable should be set alongside proxy"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run "enable_state_persistence_default" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "test-agent"
|
||||||
|
workdir = "/home/coder"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = var.enable_state_persistence == true
|
||||||
|
error_message = "enable_state_persistence should default to true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "disable_state_persistence" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "test-agent"
|
||||||
|
workdir = "/home/coder"
|
||||||
|
enable_state_persistence = false
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = var.enable_state_persistence == false
|
||||||
|
error_message = "enable_state_persistence should be false when explicitly disabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -119,6 +119,12 @@ variable "subdomain" {
|
|||||||
default = false
|
default = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "enable_state_persistence" {
|
||||||
|
type = bool
|
||||||
|
description = "Enable AgentAPI conversation state persistence across restarts."
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
variable "order" {
|
variable "order" {
|
||||||
type = number
|
type = number
|
||||||
description = "The order determines the position of app in the UI presentation."
|
description = "The order determines the position of app in the UI presentation."
|
||||||
@ -155,6 +161,12 @@ variable "cli_app_display_name" {
|
|||||||
default = "Copilot"
|
default = "Copilot"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "allow_all" {
|
||||||
|
type = bool
|
||||||
|
description = "Allow all tools without prompting (equivalent to --allow-all)."
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
variable "resume_session" {
|
variable "resume_session" {
|
||||||
type = bool
|
type = bool
|
||||||
description = "Whether to automatically resume the latest Copilot session on workspace restart."
|
description = "Whether to automatically resume the latest Copilot session on workspace restart."
|
||||||
@ -271,25 +283,26 @@ resource "coder_env" "github_token" {
|
|||||||
|
|
||||||
module "agentapi" {
|
module "agentapi" {
|
||||||
source = "registry.coder.com/coder/agentapi/coder"
|
source = "registry.coder.com/coder/agentapi/coder"
|
||||||
version = "2.0.0"
|
version = "2.2.0"
|
||||||
|
|
||||||
agent_id = var.agent_id
|
agent_id = var.agent_id
|
||||||
folder = local.workdir
|
folder = local.workdir
|
||||||
web_app_slug = local.app_slug
|
web_app_slug = local.app_slug
|
||||||
web_app_order = var.order
|
web_app_order = var.order
|
||||||
web_app_group = var.group
|
web_app_group = var.group
|
||||||
web_app_icon = var.icon
|
web_app_icon = var.icon
|
||||||
web_app_display_name = var.web_app_display_name
|
web_app_display_name = var.web_app_display_name
|
||||||
cli_app = var.cli_app
|
cli_app = var.cli_app
|
||||||
cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null
|
cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null
|
||||||
cli_app_icon = var.cli_app ? var.icon : null
|
cli_app_icon = var.cli_app ? var.icon : null
|
||||||
cli_app_display_name = var.cli_app ? var.cli_app_display_name : null
|
cli_app_display_name = var.cli_app ? var.cli_app_display_name : null
|
||||||
agentapi_subdomain = var.subdomain
|
agentapi_subdomain = var.subdomain
|
||||||
module_dir_name = local.module_dir_name
|
module_dir_name = local.module_dir_name
|
||||||
install_agentapi = var.install_agentapi
|
install_agentapi = var.install_agentapi
|
||||||
agentapi_version = var.agentapi_version
|
agentapi_version = var.agentapi_version
|
||||||
pre_install_script = var.pre_install_script
|
enable_state_persistence = var.enable_state_persistence
|
||||||
post_install_script = var.post_install_script
|
pre_install_script = var.pre_install_script
|
||||||
|
post_install_script = var.post_install_script
|
||||||
|
|
||||||
start_script = <<-EOT
|
start_script = <<-EOT
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
@ -299,6 +312,7 @@ module "agentapi" {
|
|||||||
chmod +x /tmp/start.sh
|
chmod +x /tmp/start.sh
|
||||||
|
|
||||||
ARG_WORKDIR='${local.workdir}' \
|
ARG_WORKDIR='${local.workdir}' \
|
||||||
|
ARG_ALLOW_ALL='${var.allow_all}' \
|
||||||
ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
|
ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
|
||||||
ARG_SYSTEM_PROMPT='${base64encode(local.final_system_prompt)}' \
|
ARG_SYSTEM_PROMPT='${base64encode(local.final_system_prompt)}' \
|
||||||
ARG_COPILOT_MODEL='${var.copilot_model}' \
|
ARG_COPILOT_MODEL='${var.copilot_model}' \
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [ -f "$HOME/.bashrc" ]; then
|
|
||||||
source "$HOME"/.bashrc
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
|
||||||
command_exists() {
|
command_exists() {
|
||||||
command -v "$1" > /dev/null 2>&1
|
command -v "$1" > /dev/null 2>&1
|
||||||
}
|
}
|
||||||
@ -19,34 +17,13 @@ ARG_EXTERNAL_AUTH_ID=${ARG_EXTERNAL_AUTH_ID:-github}
|
|||||||
ARG_COPILOT_VERSION=${ARG_COPILOT_VERSION:-0.0.334}
|
ARG_COPILOT_VERSION=${ARG_COPILOT_VERSION:-0.0.334}
|
||||||
ARG_COPILOT_MODEL=${ARG_COPILOT_MODEL:-claude-sonnet-4.5}
|
ARG_COPILOT_MODEL=${ARG_COPILOT_MODEL:-claude-sonnet-4.5}
|
||||||
|
|
||||||
validate_prerequisites() {
|
|
||||||
if ! command_exists node; then
|
|
||||||
echo "ERROR: Node.js not found. Copilot requires Node.js v22+."
|
|
||||||
echo "Install with: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command_exists npm; then
|
|
||||||
echo "ERROR: npm not found. Copilot requires npm v10+."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
node_version=$(node --version | sed 's/v//' | cut -d. -f1)
|
|
||||||
if [ "$node_version" -lt 22 ]; then
|
|
||||||
echo "WARNING: Node.js v$node_version detected. Copilot requires v22+."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_copilot() {
|
install_copilot() {
|
||||||
if ! command_exists copilot; then
|
if ! command_exists copilot; then
|
||||||
echo "Installing GitHub Copilot CLI (version: ${ARG_COPILOT_VERSION})..."
|
echo "Installing GitHub Copilot CLI (version: ${ARG_COPILOT_VERSION})..."
|
||||||
if [ "$ARG_COPILOT_VERSION" = "latest" ]; then
|
curl -fsSL https://gh.io/copilot-install | VERSION="${ARG_COPILOT_VERSION}" bash
|
||||||
npm install -g @github/copilot
|
|
||||||
else
|
|
||||||
npm install -g "@github/copilot@${ARG_COPILOT_VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command_exists copilot; then
|
if ! command_exists copilot; then
|
||||||
|
echo "PATH after installation: $PATH"
|
||||||
echo "ERROR: Failed to install Copilot"
|
echo "ERROR: Failed to install Copilot"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -95,7 +72,7 @@ setup_copilot_configurations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setup_copilot_config() {
|
setup_copilot_config() {
|
||||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME}"
|
||||||
local copilot_config_dir="$XDG_CONFIG_HOME/.copilot"
|
local copilot_config_dir="$XDG_CONFIG_HOME/.copilot"
|
||||||
local copilot_config_file="$copilot_config_dir/config.json"
|
local copilot_config_file="$copilot_config_dir/config.json"
|
||||||
local mcp_config_file="$copilot_config_dir/mcp-config.json"
|
local mcp_config_file="$copilot_config_dir/mcp-config.json"
|
||||||
@ -190,27 +167,15 @@ add_custom_mcp_servers() {
|
|||||||
local updated_config
|
local updated_config
|
||||||
updated_config=$(jq --argjson custom "$custom_servers" '.mcpServers += $custom' "$mcp_config_file")
|
updated_config=$(jq --argjson custom "$custom_servers" '.mcpServers += $custom' "$mcp_config_file")
|
||||||
echo "$updated_config" > "$mcp_config_file"
|
echo "$updated_config" > "$mcp_config_file"
|
||||||
elif command_exists node; then
|
|
||||||
node -e "
|
|
||||||
const fs = require('fs');
|
|
||||||
const existing = JSON.parse(fs.readFileSync('$mcp_config_file', 'utf8'));
|
|
||||||
const input = JSON.parse(\`$ARG_MCP_CONFIG\`);
|
|
||||||
const custom = input.mcpServers || {};
|
|
||||||
existing.mcpServers = {...existing.mcpServers, ...custom};
|
|
||||||
fs.writeFileSync('$mcp_config_file', JSON.stringify(existing, null, 2));
|
|
||||||
"
|
|
||||||
else
|
else
|
||||||
echo "WARNING: jq and node not available, cannot merge custom MCP servers"
|
echo "WARNING: jq not available, cannot merge custom MCP servers"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_copilot_model() {
|
configure_copilot_model() {
|
||||||
if [ -n "$ARG_COPILOT_MODEL" ] && [ "$ARG_COPILOT_MODEL" != "claude-sonnet-4.5" ]; then
|
if [[ -n "${ARG_COPILOT_MODEL}" ]]; then
|
||||||
echo "Setting Copilot model to: $ARG_COPILOT_MODEL"
|
echo "Setting Copilot model to: ${ARG_COPILOT_MODEL}"
|
||||||
copilot config model "$ARG_COPILOT_MODEL" || {
|
export COPILOT_MODEL="${ARG_COPILOT_MODEL}"
|
||||||
echo "WARNING: Failed to set model via copilot config, will use environment variable fallback"
|
|
||||||
export COPILOT_MODEL="$ARG_COPILOT_MODEL"
|
|
||||||
}
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +192,6 @@ configure_coder_integration() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_prerequisites
|
|
||||||
install_copilot
|
install_copilot
|
||||||
check_github_authentication
|
check_github_authentication
|
||||||
setup_copilot_configurations
|
setup_copilot_configurations
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [ -f "$HOME/.bashrc" ]; then
|
|
||||||
source "$HOME"/.bashrc
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
export PATH="$HOME/.local/bin:$PATH"
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
@ -13,6 +9,7 @@ command_exists() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"}
|
ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"}
|
||||||
|
ARG_ALLOW_ALL=${ARG_ALLOW_ALL:-true}
|
||||||
ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d 2> /dev/null || echo "")
|
ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d 2> /dev/null || echo "")
|
||||||
ARG_SYSTEM_PROMPT=$(echo -n "${ARG_SYSTEM_PROMPT:-}" | base64 -d 2> /dev/null || echo "")
|
ARG_SYSTEM_PROMPT=$(echo -n "${ARG_SYSTEM_PROMPT:-}" | base64 -d 2> /dev/null || echo "")
|
||||||
ARG_COPILOT_MODEL=${ARG_COPILOT_MODEL:-}
|
ARG_COPILOT_MODEL=${ARG_COPILOT_MODEL:-}
|
||||||
@ -28,7 +25,7 @@ ARG_AIBRIDGE_PROXY_CERT_PATH=${ARG_AIBRIDGE_PROXY_CERT_PATH:-}
|
|||||||
|
|
||||||
validate_copilot_installation() {
|
validate_copilot_installation() {
|
||||||
if ! command_exists copilot; then
|
if ! command_exists copilot; then
|
||||||
echo "ERROR: Copilot not installed. Run: npm install -g @github/copilot"
|
echo "ERROR: Copilot not installed or not in PATH. Please ensure Copilot CLI is installed and accessible."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -73,6 +70,20 @@ build_copilot_args() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$ARG_ALLOW_ALL" = "true" ]; then
|
||||||
|
COPILOT_ARGS+=(--allow-all)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_existing_session; then
|
||||||
|
COPILOT_ARGS+=(--continue)
|
||||||
|
else
|
||||||
|
local initial_prompt
|
||||||
|
initial_prompt=$(build_initial_prompt)
|
||||||
|
if [[ -n "${initial_prompt}" ]]; then
|
||||||
|
COPILOT_ARGS+=(-i "${initial_prompt}")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
check_existing_session() {
|
check_existing_session() {
|
||||||
@ -169,35 +180,11 @@ start_agentapi() {
|
|||||||
|
|
||||||
build_copilot_args
|
build_copilot_args
|
||||||
|
|
||||||
if check_existing_session; then
|
if [ ${#COPILOT_ARGS[@]} -gt 0 ]; then
|
||||||
echo "Continuing latest Copilot session..."
|
echo "Copilot arguments: ${COPILOT_ARGS[*]}"
|
||||||
if [ ${#COPILOT_ARGS[@]} -gt 0 ]; then
|
agentapi server --type copilot --term-width 67 --term-height 1190 -- copilot "${COPILOT_ARGS[@]}"
|
||||||
echo "Copilot arguments: ${COPILOT_ARGS[*]}"
|
|
||||||
agentapi server --type copilot --term-width 120 --term-height 40 -- copilot --continue "${COPILOT_ARGS[@]}"
|
|
||||||
else
|
|
||||||
agentapi server --type copilot --term-width 120 --term-height 40 -- copilot --continue
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
echo "Starting new Copilot session..."
|
agentapi server --type copilot --term-width 67 --term-height 1190 -- copilot
|
||||||
local initial_prompt
|
|
||||||
initial_prompt=$(build_initial_prompt)
|
|
||||||
|
|
||||||
if [ -n "$initial_prompt" ]; then
|
|
||||||
echo "Using initial prompt with system context"
|
|
||||||
if [ ${#COPILOT_ARGS[@]} -gt 0 ]; then
|
|
||||||
echo "Copilot arguments: ${COPILOT_ARGS[*]}"
|
|
||||||
agentapi server -I="$initial_prompt" --type copilot --term-width 120 --term-height 40 -- copilot "${COPILOT_ARGS[@]}"
|
|
||||||
else
|
|
||||||
agentapi server -I="$initial_prompt" --type copilot --term-width 120 --term-height 40 -- copilot
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ ${#COPILOT_ARGS[@]} -gt 0 ]; then
|
|
||||||
echo "Copilot arguments: ${COPILOT_ARGS[*]}"
|
|
||||||
agentapi server --type copilot --term-width 120 --term-height 40 -- copilot "${COPILOT_ARGS[@]}"
|
|
||||||
else
|
|
||||||
agentapi server --type copilot --term-width 120 --term-height 40 -- copilot
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user