agentapi and ai task support
This commit is contained in:
parent
da67cd3b36
commit
6c3c2f067d
@ -4,7 +4,7 @@ terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.5"
|
||||
version = ">= 2.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,9 +96,75 @@ variable "experiment_tmux_session_save_interval" {
|
||||
default = "15"
|
||||
}
|
||||
|
||||
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.2.2"
|
||||
}
|
||||
|
||||
locals {
|
||||
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) : ""
|
||||
# we have to trim the slash because otherwise coder exp mcp will
|
||||
# set up an invalid claude config
|
||||
workdir = trimsuffix(var.folder, "/")
|
||||
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) : ""
|
||||
agentapi_start_command = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# if the first argument is not empty, start claude with the prompt
|
||||
if [ -n "$1" ]; then
|
||||
prompt="$(cat ~/.claude-code-prompt)"
|
||||
cp ~/.claude-code-prompt /tmp/claude-code-prompt
|
||||
else
|
||||
rm -f /tmp/claude-code-prompt
|
||||
fi
|
||||
|
||||
# We need to check if there's a session to use --continue. If there's no session,
|
||||
# using this flag would cause claude to exit with an error.
|
||||
# warning: this is a hack and will break if claude changes the format of the .claude.json file.
|
||||
# Also, this solution is not ideal: a user has to quit claude in order for the session id to appear
|
||||
# in .claude.json. If they just restart the workspace, the session id will not be available.
|
||||
continue_flag=""
|
||||
if grep -q '"lastSessionId":' ~/.claude.json; then
|
||||
echo "Found a Claude Code session to continue."
|
||||
continue_flag="--continue"
|
||||
else
|
||||
echo "No Claude Code session to continue."
|
||||
fi
|
||||
|
||||
# use low width to fit in the tasks UI sidebar. height is adjusted so that width x height ~= 80x1000 characters
|
||||
# visible in the terminal screen by default.
|
||||
prompt_subshell='"$(cat /tmp/claude-code-prompt)"'
|
||||
agentapi server --term-width 67 --term-height 1190 -- bash -c "claude $continue_flag --dangerously-skip-permissions $prompt_subshell"
|
||||
EOT
|
||||
agentapi_wait_for_start_command = <<-EOT
|
||||
#!/bin/bash
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
echo "Waiting for agentapi server to start on port 3284..."
|
||||
for i in $(seq 1 15); do
|
||||
if lsof -i :3284 | grep -q 'LISTEN'; then
|
||||
echo "agentapi server started on port 3284."
|
||||
break
|
||||
fi
|
||||
echo "Waiting... ($i/15)"
|
||||
sleep 1
|
||||
done
|
||||
if ! lsof -i :3284 | grep -q 'LISTEN'; then
|
||||
echo "Error: agentapi server did not start on port 3284 after 15 seconds."
|
||||
exit 1
|
||||
fi
|
||||
EOT
|
||||
agentapi_start_command_base64 = base64encode(local.agentapi_start_command)
|
||||
agentapi_wait_for_start_command_base64 = base64encode(local.agentapi_wait_for_start_command)
|
||||
}
|
||||
|
||||
# Install and Initialize Claude Code
|
||||
@ -132,12 +198,12 @@ resource "coder_script" "claude_code" {
|
||||
fi
|
||||
}
|
||||
|
||||
if [ ! -d "${var.folder}" ]; then
|
||||
echo "Warning: The specified folder '${var.folder}' does not exist."
|
||||
if [ ! -d "${local.workdir}" ]; then
|
||||
echo "Warning: The specified folder '${local.workdir}' does not exist."
|
||||
echo "Creating the folder..."
|
||||
# The folder must exist before tmux is started or else claude will start
|
||||
# in the home directory.
|
||||
mkdir -p "${var.folder}"
|
||||
mkdir -p "${local.workdir}"
|
||||
echo "Folder created successfully."
|
||||
fi
|
||||
if [ -n "${local.encoded_pre_install_script}" ]; then
|
||||
@ -176,9 +242,38 @@ resource "coder_script" "claude_code" {
|
||||
npm install -g @anthropic-ai/claude-code@${var.claude_code_version}
|
||||
fi
|
||||
|
||||
# Install AgentAPI if enabled
|
||||
if [ "${var.install_agentapi}" = "true" ]; then
|
||||
echo "Installing AgentAPI..."
|
||||
arch=$(uname -m)
|
||||
if [ "$arch" = "x86_64" ]; then
|
||||
binary_name="agentapi-linux-amd64"
|
||||
elif [ "$arch" = "aarch64" ]; then
|
||||
binary_name="agentapi-linux-arm64"
|
||||
else
|
||||
echo "Error: Unsupported architecture: $arch"
|
||||
exit 1
|
||||
fi
|
||||
wget "https://github.com/coder/agentapi/releases/download/${var.agentapi_version}/$binary_name"
|
||||
chmod +x "$binary_name"
|
||||
sudo mv "$binary_name" /usr/local/bin/agentapi
|
||||
fi
|
||||
if ! command_exists agentapi; then
|
||||
echo "Error: AgentAPI is not installed. Please enable install_agentapi or install it manually."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# save the prompt for the agentapi start command
|
||||
echo -n "$CODER_MCP_CLAUDE_TASK_PROMPT" > ~/.claude-code-prompt
|
||||
|
||||
echo -n "${local.agentapi_start_command_base64}" | base64 -d > ~/.agentapi-start-command
|
||||
chmod +x ~/.agentapi-start-command
|
||||
echo -n "${local.agentapi_wait_for_start_command_base64}" | base64 -d > ~/.agentapi-wait-for-start-command
|
||||
chmod +x ~/.agentapi-wait-for-start-command
|
||||
|
||||
if [ "${var.experiment_report_tasks}" = "true" ]; then
|
||||
echo "Configuring Claude Code to report tasks via Coder MCP..."
|
||||
coder exp mcp configure claude-code ${var.folder}
|
||||
coder exp mcp configure claude-code ${local.workdir} --ai-agentapi-url http://localhost:3284
|
||||
fi
|
||||
|
||||
if [ -n "${local.encoded_post_install_script}" ]; then
|
||||
@ -257,17 +352,16 @@ EOF
|
||||
export LANG=en_US.UTF-8
|
||||
export LC_ALL=en_US.UTF-8
|
||||
|
||||
tmux new-session -d -s agentapi-cc -c ${local.workdir} '~/.agentapi-start-command true; exec bash'
|
||||
~/.agentapi-wait-for-start-command
|
||||
|
||||
if [ "${var.experiment_tmux_session_persistence}" = "true" ]; then
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
if ! tmux has-session -t claude-code 2>/dev/null; then
|
||||
# Only create a new session if one doesn't exist
|
||||
tmux new-session -d -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
|
||||
fi
|
||||
else
|
||||
if ! tmux has-session -t claude-code 2>/dev/null; then
|
||||
tmux new-session -d -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
|
||||
fi
|
||||
if ! tmux has-session -t claude-code 2>/dev/null; then
|
||||
# Only create a new session if one doesn't exist
|
||||
tmux new-session -d -s claude-code -c ${local.workdir} "agentapi attach; exec bash"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -297,9 +391,17 @@ EOF
|
||||
export LANG=en_US.UTF-8
|
||||
export LC_ALL=en_US.UTF-8
|
||||
|
||||
screen -U -dmS agentapi-cc bash -c '
|
||||
cd ${local.workdir}
|
||||
# setting the first argument will make claude use the prompt
|
||||
~/.agentapi-start-command true
|
||||
exec bash
|
||||
'
|
||||
~/.agentapi-wait-for-start-command
|
||||
|
||||
screen -U -dmS claude-code bash -c '
|
||||
cd ${var.folder}
|
||||
claude --dangerously-skip-permissions "$CODER_MCP_CLAUDE_TASK_PROMPT" | tee -a "$HOME/.claude-code.log"
|
||||
cd ${local.workdir}
|
||||
agentapi attach
|
||||
exec bash
|
||||
'
|
||||
else
|
||||
@ -312,6 +414,21 @@ EOF
|
||||
run_on_start = true
|
||||
}
|
||||
|
||||
resource "coder_app" "claude_code_web" {
|
||||
# use a short slug to mitigate https://github.com/coder/coder/issues/15178
|
||||
slug = "ccw"
|
||||
display_name = "Claude Code Web"
|
||||
agent_id = var.agent_id
|
||||
url = "http://localhost:3284/"
|
||||
icon = var.icon
|
||||
subdomain = true
|
||||
healthcheck {
|
||||
url = "http://localhost:3284/status"
|
||||
interval = 5
|
||||
threshold = 3
|
||||
}
|
||||
}
|
||||
|
||||
resource "coder_app" "claude_code" {
|
||||
slug = "claude-code"
|
||||
display_name = "Claude Code"
|
||||
@ -324,31 +441,47 @@ resource "coder_app" "claude_code" {
|
||||
export LC_ALL=en_US.UTF-8
|
||||
|
||||
if [ "${var.experiment_use_tmux}" = "true" ]; then
|
||||
if ! tmux has-session -t agentapi-cc 2>/dev/null; then
|
||||
# start agentapi without claude using the prompt (no argument)
|
||||
tmux new-session -d -s agentapi-cc -c ${local.workdir} '~/.agentapi-start-command; exec bash'
|
||||
~/.agentapi-wait-for-start-command
|
||||
fi
|
||||
|
||||
if tmux has-session -t claude-code 2>/dev/null; then
|
||||
echo "Attaching to existing Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
|
||||
# If Claude isn't running in the session, start it without the prompt
|
||||
if ! tmux list-panes -t claude-code -F '#{pane_current_command}' | grep -q "claude"; then
|
||||
tmux send-keys -t claude-code "cd ${var.folder} && claude -c --dangerously-skip-permissions" C-m
|
||||
fi
|
||||
tmux attach-session -t claude-code
|
||||
else
|
||||
echo "Starting a new Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
|
||||
tmux new-session -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions | tee -a \"$HOME/.claude-code.log\"; exec bash"
|
||||
tmux new-session -s claude-code -c ${local.workdir} "agentapi attach; exec bash"
|
||||
fi
|
||||
elif [ "${var.experiment_use_screen}" = "true" ]; then
|
||||
if ! screen -list | grep -q "agentapi-cc"; then
|
||||
screen -S agentapi-cc bash -c '
|
||||
cd ${local.workdir}
|
||||
# start agentapi without claude using the prompt (no argument)
|
||||
~/.agentapi-start-command
|
||||
exec bash
|
||||
'
|
||||
fi
|
||||
if screen -list | grep -q "claude-code"; then
|
||||
echo "Attaching to existing Claude Code screen session." | tee -a "$HOME/.claude-code.log"
|
||||
screen -xRR claude-code
|
||||
else
|
||||
echo "Starting a new Claude Code screen session." | tee -a "$HOME/.claude-code.log"
|
||||
screen -S claude-code bash -c 'claude --dangerously-skip-permissions | tee -a "$HOME/.claude-code.log"; exec bash'
|
||||
screen -S claude-code bash -c 'agentapi attach; exec bash'
|
||||
fi
|
||||
else
|
||||
cd ${var.folder}
|
||||
claude
|
||||
cd ${local.workdir}
|
||||
agentapi attach
|
||||
fi
|
||||
EOT
|
||||
icon = var.icon
|
||||
order = var.order
|
||||
group = var.group
|
||||
}
|
||||
|
||||
resource "coder_ai_task" "claude_code" {
|
||||
sidebar_app {
|
||||
id = coder_app.claude_code_web.id
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user