@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.
@@ -19,6 +19,7 @@ services:
19
19
  - /dev/kvm:/dev/kvm
20
20
  volumes:
21
21
  - avd-data:/root/.android
22
+ - ./cache/snapshots:/root/.android/avd/Pixel_6_API_34.avd/snapshots
22
23
  healthcheck:
23
24
  test: ["CMD", "curl", "-f", "http://localhost:9224/json/version"]
24
25
  interval: 10s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kritchoff/agent-browser",
3
- "version": "0.9.44",
3
+ "version": "0.9.47",
4
4
  "description": "Headless browser automation CLI for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
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 "Lazy Snapshot" logic for instant startups.
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 (Production robustness)
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
- SNAPSHOT_FILE="$CACHE_DIR/baseline.tar.gz"
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=5
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 5
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 [ -f "$SNAPSHOT_FILE" ]; then
87
+ if [ -d "$SNAPSHOT_DIR" ]; then
97
88
  # === WARM START ===
98
- log_success "Found cached baseline snapshot. Performing WARM BOOT..."
99
- "$SDK_ROOT/start.sh" --snapshot "$SNAPSHOT_FILE"
100
-
101
- # Verify port mapping for warm start too
102
- cd "$SDK_ROOT"
103
- AGENT_CONT=$(docker compose ps -q agent-service)
104
- if [ -n "$AGENT_CONT" ] && ! docker port "$AGENT_CONT" 3000 >/dev/null 2>&1; then
105
- log_warn "Port 3000 (Host 32001) is not mapped! Container config is stale."
106
- log_info "Forcing full restart to apply network settings..."
107
- docker compose -f "$COMPOSE_FILE" down -v --remove-orphans
108
-
109
- log_info "Waiting for ports to release..."
110
- sleep 5
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
- # We need to find the container ID to send the adb command
131
- # We use docker compose to find it reliably
132
- cd "$SDK_ROOT"
133
- CONTAINER=$(docker compose ps -q android-service)
134
- AGENT_CONT=$(docker compose ps -q agent-service)
135
-
136
- if [ -z "$CONTAINER" ]; then
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
- # SELF-HEAL: Verify port 3000 is actually mapped
142
- if ! docker port "$AGENT_CONT" 3000 >/dev/null 2>&1; then
143
- log_warn "Port 3000 (Host 32001) is not mapped! Container config is stale."
144
- log_info "Forcing full restart to apply network settings..."
145
- docker compose -f "$COMPOSE_FILE" down -v --remove-orphans
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 inside emulator."
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 2
67
+ sleep 1 # Faster polling
100
68
  done
101
69
  echo -e "${GREEN}Done!${NC}"
102
70
  }
103
71
 
104
- wait_for_log "$ANDROID_CONTAINER" "Emulator boot complete" "Android Emulator Boot"
105
- wait_for_log "$ANDROID_CONTAINER" "APK installation complete" "WootzApp Installation"
106
- wait_for_log "$ANDROID_CONTAINER" "CDP Bridge ready" "CDP Bridge"
107
- # Daemon logs "Daemon listening on TCP 0.0.0.0:3000" in direct mode
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}"