Compare commits

...

1 Commits

Author SHA1 Message Date
DevelopmentCats 1d589162d4 feat: initial commit session resumption 2025-10-22 17:04:11 -05:00
5 changed files with 266 additions and 12 deletions
+4
View File
@@ -30,6 +30,10 @@ module "goose" {
The `codercom/oss-dogfood:latest` container image can be used for testing on container-based workspaces.
### Session Resumption Behavior
By default, Goose automatically resumes workspace-specific sessions when your workspace restarts. Sessions are named `task-{workspace_name}`, ensuring each workspace maintains its own conversation history. If no session exists (first start), your task prompt will run normally. To disable this and always start fresh, set `continue = false`.
## Examples
### Run in the background and report tasks
+88
View File
@@ -291,4 +291,92 @@ describe("goose", async () => {
expect(agentapiMockOutput).toMatch(/AGENTAPI_CHAT_BASE_PATH=$/m);
});
});
describe("session management", async () => {
test("session-name-new", async () => {
const { id } = await setup({
agentapiMockScript: await loadTestFile(
import.meta.dir,
"agentapi-mock-print-args.js",
),
moduleVariables: {
session_name: "my-custom-session",
},
});
await execModuleScript(id);
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
expect(agentapiMockOutput).toContain("Session name: my-custom-session");
expect(agentapiMockOutput).toContain("Starting new named session: my-custom-session");
});
test("session-name-resume", async () => {
const { id } = await setup({
agentapiMockScript: await loadTestFile(
import.meta.dir,
"agentapi-mock-print-args.js",
),
moduleVariables: {
session_name: "existing-session",
},
});
await execContainer(id, [
"bash",
"-c",
dedent`
cat > /usr/bin/goose <<'EOF'
#!/bin/bash
if [ "$1" = "session" ] && [ "$2" = "list" ] && [ "$3" = "--format" ] && [ "$4" = "json" ]; then
echo '[{"id":"test123","name":"existing-session"}]'
else
echo "goose mock"
fi
EOF
chmod +x /usr/bin/goose
`,
]);
await execModuleScript(id);
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
expect(agentapiMockOutput).toContain("Resuming session by name: existing-session");
});
test("default-session-name", async () => {
const { id } = await setup({
agentapiMockScript: await loadTestFile(
import.meta.dir,
"agentapi-mock-print-args.js",
),
moduleVariables: {
continue: "true",
},
});
await execModuleScript(id);
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
expect(agentapiMockOutput).toContain("Session name: task-");
expect(agentapiMockOutput).toContain("Starting new session:");
});
test("continue-disabled", async () => {
const { id } = await setup({
agentapiMockScript: await loadTestFile(
import.meta.dir,
"agentapi-mock-print-args.js",
),
moduleVariables: {
continue: "false",
},
});
await execModuleScript(id);
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
expect(agentapiMockOutput).toContain("Continue disabled, starting fresh session");
});
});
});
+28 -3
View File
@@ -100,9 +100,22 @@ variable "additional_extensions" {
default = null
}
variable "session_name" {
type = string
description = "Name for the Goose session. If empty, uses 'task-{workspace_name}' for automatic workspace-specific session naming."
default = ""
}
variable "continue" {
type = bool
description = "Automatically continue existing sessions on workspace restart. When true, resumes session by name if it exists, otherwise starts new named session. When false, always starts fresh."
default = true
}
locals {
app_slug = "goose"
base_extensions = <<-EOT
app_slug = "goose"
default_session_name = "task-${data.coder_workspace.me.name}"
base_extensions = <<-EOT
coder:
args:
- exp
@@ -156,8 +169,20 @@ module "agentapi" {
agentapi_subdomain = var.subdomain
pre_install_script = var.pre_install_script
post_install_script = var.post_install_script
start_script = local.start_script
folder = local.folder
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
ARG_SESSION_NAME='${var.session_name}' \
ARG_DEFAULT_SESSION_NAME='${local.default_session_name}' \
ARG_CONTINUE='${var.continue}' \
/tmp/start.sh
EOT
install_script = <<-EOT
#!/bin/bash
set -o errexit
@@ -0,0 +1,105 @@
run "test_goose_basic" {
command = plan
variables {
agent_id = "test-agent-123"
goose_provider = "anthropic"
goose_model = "claude-3-5-sonnet-latest"
}
assert {
condition = var.goose_provider == "anthropic"
error_message = "Goose provider variable should be set correctly"
}
assert {
condition = var.goose_model == "claude-3-5-sonnet-latest"
error_message = "Goose model variable should be set correctly"
}
assert {
condition = var.install_goose == true
error_message = "Install goose should default to true"
}
assert {
condition = var.install_agentapi == true
error_message = "Install agentapi should default to true"
}
assert {
condition = var.continue == true
error_message = "Continue should default to true"
}
}
run "test_goose_with_session_name" {
command = plan
variables {
agent_id = "test-agent-456"
goose_provider = "anthropic"
goose_model = "claude-3-5-sonnet-latest"
session_name = "my-custom-session"
}
assert {
condition = var.session_name == "my-custom-session"
error_message = "Session name should be set to my-custom-session"
}
}
run "test_goose_continue_disabled" {
command = plan
variables {
agent_id = "test-agent-789"
goose_provider = "anthropic"
goose_model = "claude-3-5-sonnet-latest"
continue = false
}
assert {
condition = var.continue == false
error_message = "Continue should be set to false"
}
}
run "test_goose_default_session_name" {
command = plan
variables {
agent_id = "test-agent-101"
goose_provider = "anthropic"
goose_model = "claude-3-5-sonnet-latest"
}
assert {
condition = length(regexall("task-", local.default_session_name)) > 0
error_message = "Default session name should contain task- prefix"
}
}
run "test_goose_with_additional_extensions" {
command = plan
variables {
agent_id = "test-agent-202"
goose_provider = "anthropic"
goose_model = "claude-3-5-sonnet-latest"
additional_extensions = <<-EOT
custom-extension:
enabled: true
name: custom
timeout: 300
type: builtin
EOT
}
assert {
condition = var.additional_extensions != null
error_message = "Additional extensions should be set"
}
}
+41 -9
View File
@@ -16,19 +16,51 @@ else
exit 1
fi
# this must be kept up to date with main.tf
MODULE_DIR="$HOME/.goose-module"
mkdir -p "$MODULE_DIR"
if [ ! -z "$GOOSE_TASK_PROMPT" ]; then
echo "Starting with a prompt"
PROMPT="Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT"
PROMPT_FILE="$MODULE_DIR/prompt.txt"
echo -n "$PROMPT" > "$PROMPT_FILE"
GOOSE_ARGS=(run --interactive --instructions "$PROMPT_FILE")
ARG_SESSION_NAME=${ARG_SESSION_NAME:-}
ARG_DEFAULT_SESSION_NAME=${ARG_DEFAULT_SESSION_NAME:-}
ARG_CONTINUE=${ARG_CONTINUE:-true}
if [ -n "$ARG_SESSION_NAME" ]; then
SESSION_NAME="$ARG_SESSION_NAME"
else
echo "Starting without a prompt"
GOOSE_ARGS=()
SESSION_NAME="$ARG_DEFAULT_SESSION_NAME"
fi
echo "Session name: $SESSION_NAME"
session_name_exists() {
local name=$1
"$GOOSE_CMD" session list --format json 2>/dev/null | grep -q "\"name\":[[:space:]]*\"$name\""
}
if [ "$ARG_CONTINUE" = "true" ]; then
if session_name_exists "$SESSION_NAME"; then
echo "Resuming session: $SESSION_NAME"
GOOSE_ARGS=(session --resume --name "$SESSION_NAME")
else
echo "Starting new session: $SESSION_NAME"
if [ -n "$GOOSE_TASK_PROMPT" ]; then
PROMPT="Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT"
PROMPT_FILE="$MODULE_DIR/prompt.txt"
echo -n "$PROMPT" > "$PROMPT_FILE"
GOOSE_ARGS=(run --interactive --name "$SESSION_NAME" --instructions "$PROMPT_FILE")
else
GOOSE_ARGS=(session --name "$SESSION_NAME")
fi
fi
else
echo "Continue disabled, starting fresh session"
if [ -n "$GOOSE_TASK_PROMPT" ]; then
PROMPT="Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT"
PROMPT_FILE="$MODULE_DIR/prompt.txt"
echo -n "$PROMPT" > "$PROMPT_FILE"
GOOSE_ARGS=(run --interactive --instructions "$PROMPT_FILE")
else
GOOSE_ARGS=(session)
fi
fi
agentapi server --term-width 67 --term-height 1190 -- \