8000 agentapi and ai task support · coder/registry@33489fc · GitHub
[go: up one dir, main page]

Skip to content

Commit 33489fc

Browse files
committed
agentapi and ai task support
1 parent da67cd3 commit 33489fc

File tree

1 file changed

+158
-25
lines changed
  • registry/coder/modules/claude-code

1 file changed

+158
-25
lines changed

registry/coder/modules/claude-code/main.tf

Lines changed: 158 additions & 25 deletions
< F987 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ terraform {
44
required_providers {
55
coder = {
66
source = "coder/coder"
7-
version = ">= 2.5"
7+
version = ">= 2.7"
88
}
99
}
1010
}
@@ -96,9 +96,75 @@ variable "experiment_tmux_session_save_interval" {
9696
default = "15"
9797
}
9898

99+
variable "install_agentapi" {
100+
type = bool
101+
description = "Whether to install AgentAPI."
102+
default = true
103+
}
104+
105+
variable "agentapi_version" {
106+
type = string
107+
description = "The version of AgentAPI to install."
108+
default = "v0.2.2"
109+
}
110+
99111
locals {
100-
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
101-
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
112+
# we have to trim the slash because otherwise coder exp mcp will
113+
# set up an invalid claude config
114+
workdir = trimsuffix(var.folder, "/")
115+
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
116+
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
117+
agentapi_start_command = <<-EOT
118+
#!/bin/bash
119+
set -e
120+
121+
# if the first argument is not empty, start claude with the prompt
122+
if [ -n "$1" ]; then
123+
prompt="$(cat ~/.claude-code-prompt)"
124+
cp ~/.claude-code-prompt /tmp/claude-code-prompt
125+
else
126+
rm -f /tmp/claude-code-prompt
127+
fi
128+
129+
# We need to check if there's a session to use --continue. If there's no session,
130+
# using this flag would cause claude to exit with an error.
131+
# warning: this is a hack and will break if claude changes the format of the .claude.json file.
132+
# Also, this solution is not ideal: a user has to quit claude in order for the session id to appear
133+
# in .claude.json. If they just restart the workspace, the session id will not be available.
134+
continue_flag=""
135+
if grep -q '"lastSessionId":' ~/.claude.json; then
136+
echo "Found a Claude Code session to continue."
137+
continue_flag="--continue"
138+
else
139+
echo "No Claude Code session to continue."
140+
fi
141+
142+
# use low width to fit in the tasks UI sidebar. height is adjusted so that width x height ~= 80x1000 characters
143+
# visible in the terminal screen by default.
144+
prompt_subshell='"$(cat /tmp/claude-code-prompt)"'
145+
agentapi server --term-width 67 --term-height 1190 -- bash -c "claude $continue_flag --dangerously-skip-permissions $prompt_subshell"
146+
EOT
147+
agentapi_wait_for_start_command = <<-EOT
148+
#!/bin/bash
149+
set -o errexit
150+
set -o pipefail
151+
152+
echo "Waiting for agentapi server to start on port 3284..."
153+
for i in $(seq 1 15); do
154+
if lsof -i :3284 | grep -q 'LISTEN'; then
155+
echo "agentapi server started on port 3284."
156+
break
157+
fi
158+
echo "Waiting... ($i/15)"
159+
sleep 1
160+
done
161+
if ! lsof -i :3284 | grep -q 'LISTEN'; then
162+
echo "Error: agentapi server did not start on port 3284 after 15 seconds."
163+
exit 1
164+
fi
165+
EOT
166+
agentapi_start_command_base64 = base64encode(local.agentapi_start_command)
167+
agentapi_wait_for_start_command_base64 = base64encode(local.agentapi_wait_for_start_command)
102168
}
103169

104170
# Install and Initialize Claude Code
@@ -132,12 +198,12 @@ resource "coder_script" "claude_code" {
132198
fi
133199
}
134200
135-
if [ ! -d "${var.folder}" ]; then
136-
echo "Warning: The specified folder '${var.folder}' does not exist."
201+
if [ ! -d "${local.workdir}" ]; then
202+
echo "Warning: The specified folder '${local.workdir}' does not exist."
137203
echo "Creating the folder..."
138204
# The folder must exist before tmux is started or else claude will start
139205
# in the home directory.
140-
mkdir -p "${var.folder}"
206+
mkdir -p "${local.workdir}"
141207
echo "Folder created successfully."
142208
fi
143209
if [ -n "${local.encoded_pre_install_script}" ]; then
@@ -176,9 +242,38 @@ resource "coder_script" "claude_code" {
176242
npm install -g @anthropic-ai/claude-code@${var.claude_code_version}
177243
fi
178244
245+
# Install AgentAPI if enabled
246+
if [ "${var.install_agentapi}" = "true" ]; then
247+
echo "Installing AgentAPI..."
248+
arch=$(uname -m)
249+
if [ "$arch" = "x86_64" ]; then
250+
binary_name="agentapi-linux-amd64"
251+
elif [ "$arch" = "aarch64" ]; then
252+
binary_name="agentapi-linux-arm64"
253+
else
254+
echo "Error: Unsupported architecture: $arch"
255+
exit 1
256+
fi
257+
wget "https://github.com/coder/agentapi/releases/download/${var.agentapi_version}/$binary_name"
258+
chmod +x "$binary_name"
259+
sudo mv "$binary_name" /usr/local/bin/agentapi
260+
fi
261+
if ! command_exists agentapi; then
262+
echo "Error: AgentAPI is not installed. Please enable install_agentapi or install it manually."
263+
exit 1
264+
fi
265+
266+
# save the prompt for the agentapi start command
267+
echo -n "$CODER_MCP_CLAUDE_TASK_PROMPT" > ~/.claude-code-prompt
268+
269+
echo -n "${local.agentapi_start_command_base64}" | base64 -d > ~/.agentapi-start-command
270+
chmod +x ~/.agentapi-start-command
271+
echo -n "${local.agentapi_wait_for_start_command_base64}" | base64 -d > ~/.agentapi-wait-for-start-command
272+
chmod +x ~/.agentapi-wait-for-start-command
273+
179274
if [ "${var.experiment_report_tasks}" = "true" ]; then
180275
echo "Configuring Claude Code to report tasks via Coder MCP..."
181-
coder exp mcp configure claude-code ${var.folder}
276+
coder exp mcp configure claude-code ${local.workdir} --ai-agentapi-url http://localhost:3284
182277
fi
183278
184279
if [ -n "${local.encoded_post_install_script}" ]; then
@@ -257,17 +352,16 @@ EOF
257352
export LANG=en_US.UTF-8
258353
export LC_ALL=en_US.UTF-8
259354
355+
tmux new-session -d -s agentapi-cc -c ${local.workdir} '~/.agentapi-start-command true; exec bash'
356+
~/.agentapi-wait-for-start-command
357+
260358
if [ "${var.experiment_tmux_session_persistence}" = "true" ]; then
261359
sleep 3
360+
fi
262361
263-
if ! tmux has-session -t claude-code 2>/dev/null; then
264-
# Only create a new session if one doesn't exist
265-
tmux new-session -d -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
266-
fi
267-
else
268-
if ! tmux has-session -t claude-code 2>/dev/null; then
269-
tmux new-session -d -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
270-
fi
362+
if ! tmux has-session -t claude-code 2>/dev/null; then
363+
# Only create a new session if one doesn't exist
364+
tmux new-session -d -s claude-code -c ${local.workdir} "agentapi attach; exec bash"
271365
fi
272366
fi
273367
@@ -297,9 +391,17 @@ EOF
297391
export LANG=en_US.UTF-8
298392
export LC_ALL=en_US.UTF-8
299393
394+
screen -U -dmS agentapi-cc bash -c '
395+
cd ${local.workdir}
396+
# setting the first argument will make claude use the prompt
397+
~/.agentapi-start-command true
398+
exec bash
399+
'
400+
~/.agentapi-wait-for-start-command
401+
300402
screen -U -dmS claude-code bash -c '
301-
cd ${var.folder}
302-
claude --dangerously-skip-permissions "$CODER_MCP_CLAUDE_TASK_PROMPT" | tee -a "$HOME/.claude-code.log"
403+
cd ${local.workdir}
404+
agentapi attach
303405
exec bash
304406
'
305407
else
@@ -312,6 +414,21 @@ EOF
312414
run_on_start = true
313415
}
314416

417+
resource "coder_app" "claude_code_web" {
418+
# use a short slug to mitigate https://github.com/coder/coder/issues/15178
419+
slug = "ccw"
420+
display_name = "Claude Code Web"
421+
agent_id = var.agent_id
422+
url = "http://localhost:3284/"
423+
icon = var.icon
424+
subdomain = true
425+
healthcheck {
426+
url = "http://localhost:3284/status"
427+
interval = 5
428+
threshold = 3
429+
}
430+
}
431+
315432
resource "coder_app" "claude_code" {
316433
slug = "claude-code"
317434
display_name = "Claude Code"
@@ -324,31 +441,47 @@ resource "coder_app" "claude_code" {
324441
export LC_ALL=en_US.UTF-8
325442
326443
if [ "${var.experiment_use_tmux}" = "true" ]; then
444+
if ! tmux has-session -t agentapi-cc 2>/dev/null; then
445+
# start agentapi without claude using the prompt (no argument)
446+
tmux new-session -d -s agentapi-cc -c ${local.workdir} '~/.agentapi-start-command; exec bash'
447+
~/.agentapi-wait-for-start-command
448+
fi
449+
327450
if tmux has-session -t claude-code 2>/dev/null; then
328451
echo "Attaching to existing Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
329-
# If Claude isn't running in the session, start it without the prompt
330-
if ! tmux list-panes -t claude-code -F '#{pane_current_command}' | grep -q "claude"; then
331-
tmux send-keys -t claude-code "cd ${var.folder} && claude -c --dangerously-skip-permissions" C-m
332-
fi
333452
tmux attach-session -t claude-code
334453
else
335454
echo "Starting a new Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
336-
tmux new-session -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions | tee -a \"$HOME/.claude-code.log\"; exec bash"
455+
tmux new-session -s claude-code -c ${local.workdir} "agentapi attach; exec bash"
337456
fi
338457
elif [ "${var.experiment_use_screen}" = "true" ]; then
458+
if ! screen -list | grep -q "agentapi-cc"; then
459+
screen -S agentapi-cc bash -c '
460+
cd ${local.workdir}
461+
# start agentapi without claude using the prompt (no argument)
462+
~/.agentapi-start-command
463+
exec bash
464+
'
465+
fi
339466
if screen -list | grep -q "claude-code"; then
340467
echo "Attaching to existing Claude Code screen session." | tee -a "$HOME/.claude-code.log"
341468
screen -xRR claude-code
342469
else
343470
echo "Starting a new Claude Code screen session." | tee -a "$HOME/.claude-code.log"
344-
screen -S claude-code bash -c 'claude --dangerously-skip-permissions | tee -a "$HOME/.claude-code.log"; exec bash'
471+
screen -S claude-code bash -c 'agentapi attach; exec bash'
345472
fi
346473
else
347-
cd ${var.folder}
348-
claude
474+
cd ${local.workdir}
475+
agentapi attach
349476
fi
350477
EOT
351478
icon = var.icon
352479
order = var.order
353480
group = var.group
354481
}
482+
483+
resource "coder_ai_task" "claude_code" {
484+
sidebar_app {
485+
id = coder_app.claude_code.id
486+
}
487+
}

0 commit comments

Comments
 (0)
0