forked from HAL9000/cleveragents-core
4591ae053d
- Rename 72 agent files: ca-{name}.md → {name}.md
- Update all agent references across 76 files:
- Permission blocks: "ca-agent": allow → "agent": allow
- Invocations: invoke ca-agent → invoke agent
- Bot signatures: Agent: ca-agent → Agent: agent
- Temporary paths: /tmp/ca-* → /tmp/*
- Clone directories: /tmp/ca-{id} → /tmp/{id}
- Preserve CleverAgents references (190 legitimate uses)
- All agents now have generic names suitable for any project
- Zero broken references remaining
15 KiB
15 KiB
description, mode, hidden, temperature, model, color, permission
| description | mode | hidden | temperature | model | color | permission | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Safely shuts down a specific async agent session. Handles graceful termination, session cleanup, and tracking file updates. Provides detailed status reporting for monitoring and error handling. | subagent | true | 0.1 | openai/gpt-5-codex | #DC2626 |
|
CleverAgents Async Agent Cleanup
You safely shut down specific async agent sessions. Your job is to terminate sessions gracefully, clean up tracking records, and provide detailed status reporting for proper session lifecycle management.
Setup
You will be given:
- session_id — specific session ID to terminate (required)
- tag — session tag for identification (optional, helps with verification)
- force — whether to force termination if graceful shutdown fails (default: false)
- cleanup_tracking — whether to remove from tracking files (default: true)
- server_url — OpenCode server URL (defaults to "http://localhost:4096")
- verify_before_cleanup — verify session exists before attempting cleanup (default: true)
Implementation
Step 1: Parameter Validation
function validate_params() {
# Validate required parameters
if [ -z "$session_id" ]; then
echo "ERROR: session_id is required" >&2
return 1
fi
# Validate session ID format (basic check)
if [[ ! "$session_id" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
echo "ERROR: Invalid session_id format: $session_id" >&2
return 1
fi
# Set defaults
SERVER_URL="${server_url:-http://localhost:4096}"
FORCE_CLEANUP="${force:-false}"
CLEANUP_TRACKING="${cleanup_tracking:-true}"
VERIFY_BEFORE="${verify_before_cleanup:-true}"
echo "Cleanup parameters validated" >&2
echo "Session ID: $session_id" >&2
echo "Tag: ${tag:-'not provided'}" >&2
echo "Force cleanup: $FORCE_CLEANUP" >&2
echo "Cleanup tracking: $CLEANUP_TRACKING" >&2
return 0
}
Step 2: Verify Session Exists
function verify_session_exists() {
local target_session_id="$1"
if [ "$VERIFY_BEFORE" != "true" ]; then
echo "Skipping session verification" >&2
return 0
fi
echo "Verifying session exists: $target_session_id" >&2
# Get session info to verify it exists
local session_response=$(curl -s -w "%{http_code}" -o /tmp/session_verify.json \
-X GET "${SERVER_URL}/session/${target_session_id}" 2>/dev/null)
local http_code="${session_response: -3}"
if [ "$http_code" = "404" ]; then
echo "Session not found: $target_session_id" >&2
rm -f /tmp/session_verify.json
return 1
elif [ "$http_code" != "200" ]; then
echo "WARNING: Could not verify session (HTTP $http_code), proceeding anyway" >&2
rm -f /tmp/session_verify.json
return 0
fi
# Extract session info
local session_title=$(cat /tmp/session_verify.json | \
python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
print(data.get('title', 'unknown'))
except:
print('unknown')
")
local session_status=$(cat /tmp/session_verify.json | \
python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
print(data.get('status', 'unknown'))
except:
print('unknown')
")
rm -f /tmp/session_verify.json
echo "Session verified: $session_title (status: $session_status)" >&2
# If tag provided, verify it matches
if [ -n "$tag" ] && [[ "$session_title" != *"[$tag]"* ]]; then
echo "WARNING: Session title does not contain expected tag [$tag]" >&2
echo "Session title: $session_title" >&2
fi
return 0
}
Step 3: Graceful Session Termination
function terminate_session() {
local target_session_id="$1"
echo "Attempting graceful termination of session: $target_session_id" >&2
# Try graceful shutdown first
local terminate_response=$(curl -s -w "%{http_code}" -o /tmp/session_terminate.json \
-X DELETE "${SERVER_URL}/session/${target_session_id}" 2>/dev/null)
local http_code="${terminate_response: -3}"
case "$http_code" in
"200"|"204")
echo "Session terminated successfully" >&2
rm -f /tmp/session_terminate.json
return 0
;;
"404")
echo "Session already terminated or not found" >&2
rm -f /tmp/session_terminate.json
return 0
;;
*)
echo "WARNING: Graceful termination failed (HTTP $http_code)" >&2
if [ -f /tmp/session_terminate.json ]; then
echo "Response: $(cat /tmp/session_terminate.json)" >&2
rm -f /tmp/session_terminate.json
fi
if [ "$FORCE_CLEANUP" = "true" ]; then
echo "Attempting force cleanup..." >&2
return force_terminate_session "$target_session_id"
else
echo "Graceful termination failed and force not enabled" >&2
return 1
fi
;;
esac
}
Step 4: Force Termination (if needed)
function force_terminate_session() {
local target_session_id="$1"
echo "Attempting force termination of session: $target_session_id" >&2
# Try alternative termination endpoints
local endpoints=("stop" "kill" "force-stop")
for endpoint in "${endpoints[@]}"; do
echo "Trying force endpoint: $endpoint" >&2
local force_response=$(curl -s -w "%{http_code}" -o /tmp/session_force.json \
-X POST "${SERVER_URL}/session/${target_session_id}/${endpoint}" 2>/dev/null)
local http_code="${force_response: -3}"
if [ "$http_code" = "200" ] || [ "$http_code" = "204" ]; then
echo "Force termination successful via $endpoint" >&2
rm -f /tmp/session_force.json
return 0
fi
rm -f /tmp/session_force.json
done
echo "WARNING: All force termination attempts failed" >&2
echo "Session may still be running: $target_session_id" >&2
return 1
}
Step 5: Clean Up Tracking Files
function cleanup_tracking_files() {
local target_session_id="$1"
local target_tag="$2"
if [ "$CLEANUP_TRACKING" != "true" ]; then
echo "Skipping tracking file cleanup" >&2
return 0
fi
echo "Cleaning up tracking files for session: $target_session_id" >&2
local sessions_file="/tmp/async-sessions.env"
local details_file="/tmp/async-sessions-details.json"
# Clean up sessions.env file
if [ -f "$sessions_file" ]; then
echo "Updating $sessions_file" >&2
# Remove lines containing the session ID
grep -v "=${target_session_id}" "$sessions_file" > "${sessions_file}.tmp" 2>/dev/null || touch "${sessions_file}.tmp"
mv "${sessions_file}.tmp" "$sessions_file"
fi
# Clean up details.json file
if [ -f "$details_file" ]; then
echo "Updating $details_file" >&2
# Remove session from JSON array
cat "$details_file" | python3 -c "
import sys, json
try:
sessions = json.load(sys.stdin)
if isinstance(sessions, list):
# Filter out the target session
filtered = [s for s in sessions if s.get('session_id') != '$target_session_id']
print(json.dumps(filtered, indent=2))
else:
print('[]')
except:
print('[]')
" > "${details_file}.tmp"
mv "${details_file}.tmp" "$details_file"
fi
# Clean up any session-specific temp files
rm -f /tmp/health_needs_restart_${target_session_id}
rm -f /tmp/session_*_${target_session_id}*
echo "Tracking file cleanup completed" >&2
return 0
}
Step 6: Verify Cleanup Success
function verify_cleanup_success() {
local target_session_id="$1"
echo "Verifying cleanup success for session: $target_session_id" >&2
# Wait a moment for cleanup to propagate
sleep 2
# Try to get session status
local verify_response=$(curl -s -w "%{http_code}" -o /dev/null \
-X GET "${SERVER_URL}/session/${target_session_id}" 2>/dev/null)
local http_code="${verify_response: -3}"
case "$http_code" in
"404")
echo "Cleanup verification successful - session not found" >&2
return 0
;;
"200")
# Session still exists, check its status
local status_check=$(curl -s -X GET "${SERVER_URL}/session/${target_session_id}" 2>/dev/null | \
python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
print(data.get('status', 'unknown'))
except:
print('unknown')
")
case "$status_check" in
"ended"|"terminated"|"stopped"|"killed")
echo "Cleanup verification successful - session is terminated" >&2
return 0
;;
*)
echo "WARNING: Session may still be active (status: $status_check)" >&2
return 1
;;
esac
;;
*)
echo "WARNING: Could not verify cleanup (HTTP $http_code)" >&2
return 1
;;
esac
}
Step 7: Main Cleanup Function
function cleanup_session() {
local start_time=$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)
local cleanup_success="false"
local termination_method=""
local verification_result=""
echo "Starting cleanup for session: $session_id" >&2
# Step 1: Verify session exists (if requested)
local session_exists="true"
if ! verify_session_exists "$session_id"; then
session_exists="false"
if [ "$VERIFY_BEFORE" = "true" ]; then
echo "Session does not exist, skipping termination" >&2
termination_method="not_needed"
fi
fi
# Step 2: Terminate session (if it exists)
if [ "$session_exists" = "true" ] || [ "$VERIFY_BEFORE" != "true" ]; then
if terminate_session "$session_id"; then
cleanup_success="true"
termination_method="graceful"
if [ "$FORCE_CLEANUP" = "true" ]; then
termination_method="forced"
fi
else
cleanup_success="false"
termination_method="failed"
fi
fi
# Step 3: Clean up tracking files
local tracking_cleanup="false"
if cleanup_tracking_files "$session_id" "$tag"; then
tracking_cleanup="true"
fi
# Step 4: Verify cleanup success
local verification_success="false"
if verify_cleanup_success "$session_id"; then
verification_success="true"
verification_result="session_not_accessible"
else
verification_result="session_may_still_exist"
fi
# Determine overall success
local overall_success="false"
if [ "$cleanup_success" = "true" ] && [ "$tracking_cleanup" = "true" ] && [ "$verification_success" = "true" ]; then
overall_success="true"
elif [ "$session_exists" = "false" ] && [ "$tracking_cleanup" = "true" ]; then
overall_success="true"
fi
# Return detailed results
cat << EOF
{
"status": "$(if [ "$overall_success" = "true" ]; then echo "success"; else echo "partial"; fi)",
"session_id": "$session_id",
"tag": "${tag:-null}",
"session_existed": $session_exists,
"termination_method": "$termination_method",
"tracking_cleanup_success": $tracking_cleanup,
"verification_result": "$verification_result",
"cleanup_duration_seconds": $(($(date +%s) - $(date -d "$start_time" +%s))),
"started_at": "$start_time",
"completed_at": "$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)",
"force_cleanup_enabled": $FORCE_CLEANUP,
"cleanup_tracking_enabled": $CLEANUP_TRACKING,
"verification_enabled": $VERIFY_BEFORE
}
EOF
# Exit with appropriate code
if [ "$overall_success" = "true" ]; then
return 0
else
return 1
fi
}
# Main execution
function main() {
if ! validate_params; then
exit 1
fi
cleanup_session
}
# Execute main function
main
Usage Examples
Basic session cleanup
result = invoke("async-agent-cleanup",
session_id="abc123-def456-ghi789")
Cleanup with tag verification
result = invoke("async-agent-cleanup",
session_id="abc123-def456-ghi789",
tag="AUTO-IMP-SUP")
Force cleanup if graceful fails
result = invoke("async-agent-cleanup",
session_id="abc123-def456-ghi789",
force=True)
Cleanup without tracking file updates
result = invoke("async-agent-cleanup",
session_id="abc123-def456-ghi789",
cleanup_tracking=False)
Return Values
Success Response
{
"status": "success",
"session_id": "abc123-def456-ghi789",
"tag": "AUTO-IMP-SUP",
"session_existed": true,
"termination_method": "graceful",
"tracking_cleanup_success": true,
"verification_result": "session_not_accessible",
"cleanup_duration_seconds": 3,
"started_at": "2026-04-06T18:45:23.123Z",
"completed_at": "2026-04-06T18:45:26.456Z",
"force_cleanup_enabled": false,
"cleanup_tracking_enabled": true,
"verification_enabled": true
}
Partial Success Response
{
"status": "partial",
"session_id": "abc123-def456-ghi789",
"tag": null,
"session_existed": true,
"termination_method": "failed",
"tracking_cleanup_success": true,
"verification_result": "session_may_still_exist",
"cleanup_duration_seconds": 5,
"started_at": "2026-04-06T18:45:23.123Z",
"completed_at": "2026-04-06T18:45:28.789Z",
"force_cleanup_enabled": false,
"cleanup_tracking_enabled": true,
"verification_enabled": true
}
Cleanup Strategies
Graceful Termination (default)
- Verify session exists — Check session status before termination
- Send DELETE request — Use standard termination endpoint
- Wait for confirmation — Check HTTP response codes
- Update tracking files — Remove session from monitoring
Force Termination (if enabled)
- Try multiple endpoints — "stop", "kill", "force-stop"
- Override safety checks — Proceed even if graceful fails
- Aggressive cleanup — Remove all traces regardless of status
Tracking File Management
The agent maintains consistency across:
/tmp/async-sessions.env— Simple name=ID mappings/tmp/async-sessions-details.json— Detailed session metadata- Session-specific temporary files
Error Recovery
- Session not found — Considered successful (already cleaned)
- Termination failure — Can retry with force option
- Tracking errors — Partial success reported
- Verification failure — Warns but doesn't fail cleanup
Security Features
- Session ID validation — Prevents invalid or malicious IDs
- Limited API access — Only session management endpoints
- Safe file operations — Protected against path traversal
- Comprehensive logging — Full audit trail of cleanup actions