@kritchoff/agent-browser 0.9.44 → 0.9.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docker-compose.sdk.yml +1 -0
- package/package.json +1 -1
- package/sdk.sh +36 -90
- package/start.sh +25 -37
package/docker-compose.sdk.yml
CHANGED
package/package.json
CHANGED
package/sdk.sh
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Agent Browser SDK Wrapper
|
|
3
3
|
#
|
|
4
4
|
# A user-friendly entry point for AI Agents to interact with the Android Browser Environment.
|
|
5
|
-
# Handles "
|
|
5
|
+
# Handles "Hyper-Speed Snapshot" logic for instant startups.
|
|
6
6
|
#
|
|
7
7
|
# Usage:
|
|
8
8
|
# ./sdk.sh start - Start the environment (Cold boot 1st time, Warm boot after)
|
|
@@ -13,14 +13,13 @@
|
|
|
13
13
|
|
|
14
14
|
set -e
|
|
15
15
|
|
|
16
|
-
# Set high timeouts for large image downloads
|
|
17
|
-
# This helps prevent 'TLS handshake timeout' on slow connections
|
|
16
|
+
# Set high timeouts for large image downloads
|
|
18
17
|
export COMPOSE_HTTP_TIMEOUT=900
|
|
19
18
|
export DOCKER_CLIENT_TIMEOUT=900
|
|
20
19
|
|
|
21
20
|
SDK_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
21
|
CACHE_DIR="$SDK_ROOT/cache"
|
|
23
|
-
|
|
22
|
+
SNAPSHOT_DIR="$CACHE_DIR/snapshots/quickboot"
|
|
24
23
|
|
|
25
24
|
# Default to production/local build unless --dist is used
|
|
26
25
|
COMPOSE_FILE="$SDK_ROOT/docker-compose.prod.yml"
|
|
@@ -46,7 +45,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
46
45
|
done
|
|
47
46
|
|
|
48
47
|
# Ensure cache dir exists
|
|
49
|
-
mkdir -p "$CACHE_DIR"
|
|
48
|
+
mkdir -p "$CACHE_DIR/snapshots"
|
|
50
49
|
|
|
51
50
|
log_info() { echo -e "${BLUE}[SDK]${NC} $1"; }
|
|
52
51
|
log_success() { echo -e "${GREEN}[SDK]${NC} $1"; }
|
|
@@ -54,12 +53,11 @@ log_warn() { echo -e "${YELLOW}[SDK]${NC} $1"; }
|
|
|
54
53
|
log_error() { echo -e "${RED}[SDK]${NC} $1"; }
|
|
55
54
|
|
|
56
55
|
pull_images_with_retry() {
|
|
57
|
-
# Only pull if we are using the distribution compose file (which uses images)
|
|
58
56
|
if [[ "$COMPOSE_FILE" != *"docker-compose.sdk.yml" ]]; then
|
|
59
57
|
return 0
|
|
60
58
|
fi
|
|
61
59
|
|
|
62
|
-
local max_retries=
|
|
60
|
+
local max_retries=10
|
|
63
61
|
local count=0
|
|
64
62
|
|
|
65
63
|
log_info "Please wait while we get things ready..."
|
|
@@ -70,8 +68,8 @@ pull_images_with_retry() {
|
|
|
70
68
|
fi
|
|
71
69
|
|
|
72
70
|
count=$((count + 1))
|
|
73
|
-
log_warn "Download failed/interrupted. Retrying ($count/$max_retries)..."
|
|
74
|
-
sleep
|
|
71
|
+
log_warn "Download failed/interrupted. Retrying ($count/$max_retries) in 10s..."
|
|
72
|
+
sleep 10
|
|
75
73
|
done
|
|
76
74
|
|
|
77
75
|
log_error "Failed to download images after $max_retries attempts. Please check your internet connection."
|
|
@@ -80,97 +78,49 @@ pull_images_with_retry() {
|
|
|
80
78
|
|
|
81
79
|
cmd_start() {
|
|
82
80
|
log_info "Initializing Agent Environment (using $COMPOSE_FILE)..."
|
|
83
|
-
|
|
84
|
-
# Export COMPOSE_FILE so start.sh (which might call docker compose) uses it
|
|
85
|
-
# Note: start.sh needs to be updated to respect COMPOSE_FILE if it doesn't already
|
|
86
81
|
export COMPOSE_FILE="$COMPOSE_FILE"
|
|
87
|
-
|
|
88
|
-
# Ensure images are present (Production robustness)
|
|
89
82
|
pull_images_with_retry
|
|
90
83
|
|
|
91
|
-
# --- ALWAYS CLEAN UP PREVIOUS STATE ---
|
|
92
|
-
# This prevents network namespace corruption and port binding failures on warm boots
|
|
93
84
|
log_info "Cleaning up previous container state..."
|
|
94
85
|
docker compose -f "$COMPOSE_FILE" down -v --remove-orphans >/dev/null 2>&1 || true
|
|
95
86
|
|
|
96
|
-
if [ -
|
|
87
|
+
if [ -d "$SNAPSHOT_DIR" ]; then
|
|
97
88
|
# === WARM START ===
|
|
98
|
-
log_success "Found cached baseline snapshot. Performing WARM BOOT..."
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"$SDK_ROOT/start.sh" --snapshot "$SNAPSHOT_FILE"
|
|
113
|
-
fi
|
|
114
|
-
else
|
|
115
|
-
# === COLD START & FREEZE ===
|
|
116
|
-
log_warn "No baseline found. Performing FIRST RUN SETUP (Cold Boot)..."
|
|
117
|
-
log_warn "This will take ~60-90 seconds, but only once."
|
|
118
|
-
|
|
119
|
-
# Start in background to wait for it
|
|
120
|
-
"$SDK_ROOT/start.sh" &
|
|
121
|
-
START_PID=$!
|
|
122
|
-
wait $START_PID
|
|
123
|
-
|
|
124
|
-
# Check if start was successful
|
|
125
|
-
if [ $? -ne 0 ]; then
|
|
126
|
-
log_error "Startup failed."
|
|
127
|
-
exit 1
|
|
128
|
-
fi
|
|
89
|
+
log_success "Found cached baseline snapshot. Performing HYPER-SPEED WARM BOOT..."
|
|
90
|
+
export EMULATOR_SNAPSHOT_NAME="quickboot"
|
|
91
|
+
"$SDK_ROOT/start.sh"
|
|
92
|
+
else
|
|
93
|
+
# === COLD START & FREEZE ===
|
|
94
|
+
log_warn "No baseline found. Performing FIRST RUN SETUP (Cold Boot)..."
|
|
95
|
+
log_warn "This will take ~60-90 seconds, but only once."
|
|
96
|
+
|
|
97
|
+
export EMULATOR_SNAPSHOT_NAME=""
|
|
98
|
+
|
|
99
|
+
"$SDK_ROOT/start.sh" &
|
|
100
|
+
START_PID=$!
|
|
101
|
+
wait $START_PID
|
|
129
102
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
log_error "Error: Android container not found."
|
|
138
|
-
exit 1
|
|
139
|
-
fi
|
|
103
|
+
if [ $? -ne 0 ]; then
|
|
104
|
+
log_error "Startup failed."
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
cd "$SDK_ROOT"
|
|
109
|
+
CONTAINER=$(docker compose ps -q android-service)
|
|
140
110
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
log_info "Waiting for ports to release..."
|
|
148
|
-
sleep 5
|
|
149
|
-
|
|
150
|
-
"$SDK_ROOT/start.sh"
|
|
151
|
-
|
|
152
|
-
# Re-fetch container ID after restart
|
|
153
|
-
CONTAINER=$(docker compose ps -q android-service)
|
|
154
|
-
fi
|
|
155
|
-
|
|
156
|
-
# 1. Save snapshot inside emulator
|
|
111
|
+
if [ -z "$CONTAINER" ]; then
|
|
112
|
+
log_error "Error: Android container not found."
|
|
113
|
+
exit 1
|
|
114
|
+
fi
|
|
115
|
+
|
|
157
116
|
log_info "Saving emulator state (quickboot)..."
|
|
158
117
|
if docker exec "$CONTAINER" adb emu avd snapshot save quickboot; then
|
|
159
|
-
log_success "Snapshot saved
|
|
118
|
+
log_success "Snapshot saved to host volume."
|
|
119
|
+
log_success "Setup Complete! Future runs will launch instantly."
|
|
160
120
|
else
|
|
161
121
|
log_error "Failed to save snapshot inside emulator."
|
|
162
122
|
exit 1
|
|
163
123
|
fi
|
|
164
|
-
|
|
165
|
-
# 2. Export to host
|
|
166
|
-
log_info "Exporting to cache..."
|
|
167
|
-
if "$SDK_ROOT/scripts/snapshot_manager.sh" export quickboot "$SNAPSHOT_FILE"; then
|
|
168
|
-
log_success "Snapshot exported to $SNAPSHOT_FILE"
|
|
169
|
-
log_success "Setup Complete! Future runs will launch in ~20 seconds."
|
|
170
|
-
else
|
|
171
|
-
log_error "Failed to export snapshot."
|
|
172
|
-
# Don't exit, environment is still running
|
|
173
|
-
fi
|
|
174
124
|
fi
|
|
175
125
|
}
|
|
176
126
|
|
|
@@ -195,17 +145,13 @@ cmd_reset() {
|
|
|
195
145
|
}
|
|
196
146
|
|
|
197
147
|
cmd_agent() {
|
|
198
|
-
# Forward commands to the native agent binary or script
|
|
199
|
-
# Assuming 'agent' binary is in $SDK_ROOT/agent or bin/agent-browser
|
|
200
148
|
if [ -f "$SDK_ROOT/agent" ]; then
|
|
201
149
|
"$SDK_ROOT/agent" "$@"
|
|
202
150
|
else
|
|
203
|
-
# Fallback to bin/agent-browser.js if binary not built/linked
|
|
204
151
|
node "$SDK_ROOT/bin/agent-browser.js" "$@"
|
|
205
152
|
fi
|
|
206
153
|
}
|
|
207
154
|
|
|
208
|
-
# Main Dispatch
|
|
209
155
|
case "$1" in
|
|
210
156
|
start)
|
|
211
157
|
cmd_start
|
|
@@ -224,7 +170,7 @@ case "$1" in
|
|
|
224
170
|
cmd_agent "$@"
|
|
225
171
|
;;
|
|
226
172
|
*)
|
|
227
|
-
echo "Usage: $0 {start|stop|reset|agent}"
|
|
173
|
+
echo "Usage: $0 {start|stop|clean|reset|agent}"
|
|
228
174
|
exit 1
|
|
229
175
|
;;
|
|
230
176
|
esac
|
package/start.sh
CHANGED
|
@@ -54,38 +54,6 @@ docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" up -d --build --rem
|
|
|
54
54
|
ANDROID_CONTAINER=$(docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" ps -q android-service)
|
|
55
55
|
AGENT_CONTAINER=$(docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" ps -q agent-service)
|
|
56
56
|
|
|
57
|
-
# 2b. Import Snapshot (if requested)
|
|
58
|
-
if [ -n "$SNAPSHOT_PATH" ]; then
|
|
59
|
-
echo -e "\n${YELLOW}[2.5/4] Importing Snapshot: $SNAPSHOT_PATH...${NC}"
|
|
60
|
-
|
|
61
|
-
# Wait for container to be responsive
|
|
62
|
-
echo -n " Waiting for container to be ready for import... "
|
|
63
|
-
until docker exec "$ANDROID_CONTAINER" echo "ready" &>/dev/null; do
|
|
64
|
-
sleep 1
|
|
65
|
-
done
|
|
66
|
-
echo -e "${GREEN}OK${NC}"
|
|
67
|
-
|
|
68
|
-
# Import
|
|
69
|
-
if "$SCRIPT_DIR/scripts/snapshot_manager.sh" import "$SNAPSHOT_PATH" "w8rl_imported"; then
|
|
70
|
-
echo -e "${GREEN} Snapshot imported successfully.${NC}"
|
|
71
|
-
|
|
72
|
-
# Configure emulator to load this snapshot
|
|
73
|
-
# We set the env var in the container for the next boot
|
|
74
|
-
# (This assumes the entrypoint script respects EMULATOR_SNAPSHOT_NAME)
|
|
75
|
-
# For now, we'll rely on the default behavior or standard AVD loading
|
|
76
|
-
|
|
77
|
-
echo " Restarting services to load snapshot..."
|
|
78
|
-
docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" restart android-service agent-service
|
|
79
|
-
|
|
80
|
-
# Update container IDs after restart
|
|
81
|
-
ANDROID_CONTAINER=$(docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" ps -q android-service)
|
|
82
|
-
AGENT_CONTAINER=$(docker compose -f "${COMPOSE_FILE:-docker-compose.prod.yml}" ps -q agent-service)
|
|
83
|
-
else
|
|
84
|
-
echo -e "${RED}Error: Failed to import snapshot.${NC}"
|
|
85
|
-
exit 1
|
|
86
|
-
fi
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
57
|
# 3. Wait for Readiness
|
|
90
58
|
echo -e "\n${YELLOW}[3/4] Waiting for Initialization...${NC}"
|
|
91
59
|
|
|
@@ -96,17 +64,37 @@ wait_for_log() {
|
|
|
96
64
|
|
|
97
65
|
echo -n " Waiting for $label... "
|
|
98
66
|
until docker logs "$container" 2>&1 | grep -q "$pattern"; do
|
|
99
|
-
sleep
|
|
67
|
+
sleep 1 # Faster polling
|
|
100
68
|
done
|
|
101
69
|
echo -e "${GREEN}Done!${NC}"
|
|
102
70
|
}
|
|
103
71
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
wait_for_log "$ANDROID_CONTAINER" "
|
|
107
|
-
|
|
72
|
+
if [ -z "$SNAPSHOT_PATH" ] && [ -z "$EMULATOR_SNAPSHOT_NAME" ]; then
|
|
73
|
+
# --- COLD BOOT PATH (Wait for everything) ---
|
|
74
|
+
wait_for_log "$ANDROID_CONTAINER" "Emulator boot complete" "Android Emulator Boot"
|
|
75
|
+
wait_for_log "$ANDROID_CONTAINER" "APK installation complete" "WootzApp Installation"
|
|
76
|
+
wait_for_log "$ANDROID_CONTAINER" "CDP Bridge ready" "CDP Bridge"
|
|
77
|
+
else
|
|
78
|
+
# --- WARM BOOT PATH (Hyper-Speed) ---
|
|
79
|
+
# We skip Boot and APK installation because they are inside the snapshot.
|
|
80
|
+
# We only wait for the Daemon to reconnect to the resumed emulator.
|
|
81
|
+
echo -e "${GREEN} Snapshot detected. Skipping OS boot and APK install waits.${NC}"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# We always wait for the Daemon because it's the final bridge to the SDK
|
|
108
85
|
wait_for_log "$AGENT_CONTAINER" "Daemon listening on TCP" "Agent Daemon Connection"
|
|
109
86
|
|
|
87
|
+
# 3.5 Network Rehydration (Warm Boot Only)
|
|
88
|
+
if [ -n "$SNAPSHOT_PATH" ]; then
|
|
89
|
+
echo " Rehydrating Android network connection..."
|
|
90
|
+
# Toggle airplane mode to force DHCP lease renewal
|
|
91
|
+
docker exec "$ANDROID_CONTAINER" adb shell cmd connectivity airplane-mode enable
|
|
92
|
+
sleep 2
|
|
93
|
+
docker exec "$ANDROID_CONTAINER" adb shell cmd connectivity airplane-mode disable
|
|
94
|
+
# Wait for internet to come back
|
|
95
|
+
sleep 3
|
|
96
|
+
fi
|
|
97
|
+
|
|
110
98
|
# 4. Success
|
|
111
99
|
echo -e "\n${GREEN}[4/4] Environment Ready!${NC}"
|
|
112
100
|
echo -e "${BLUE}=================================================${NC}"
|