@@ -3004,14 +3004,29 @@ def cmd_logs(args):
30043004 return 0
30053005
30063006
3007- def upload_startup_script_to_datastore (script_path : str , file_path : str ) -> bool :
3007+ # Minimal startup script for Azure ML compute instances.
3008+ # Previously lived at vendor/WindowsAgentArena/scripts/azure_files/compute-instance-startup.sh
3009+ COMPUTE_INSTANCE_STARTUP_SH = """\
3010+ #!/bin/bash
3011+
3012+ # Minimal startup script - completes quickly to avoid Azure ML timeout
3013+ # The actual work (Docker pull, Windows boot) happens in the job itself
3014+
3015+ echo "$(date): Compute instance startup script - minimal version"
3016+
3017+ # Just exit successfully - the job will handle Docker setup
3018+ exit 0
3019+ """
3020+
3021+
3022+ def upload_startup_script_to_datastore (script_content : str , file_path : str ) -> bool :
30083023 """Upload startup script to Azure ML workspace code file share.
30093024
30103025 Azure ML mounts the 'code-*' file share at:
30113026 /mnt/batch/tasks/shared/LS_root/mounts/clusters/<instance>/code/
30123027
30133028 Args:
3014- script_path: Local path to the startup script
3029+ script_content: Content of the startup script
30153030 file_path: Destination path in file share (e.g., 'Users/openadapt/compute-instance-startup.sh')
30163031
30173032 Returns:
@@ -3145,28 +3160,35 @@ def upload_startup_script_to_datastore(script_path: str, file_path: str) -> bool
31453160 )
31463161 # Ignore errors - directory may already exist
31473162
3148- # Upload the script to file share
3149- log ("AZURE-ML" , f"Uploading { script_path } to { file_path } ..." )
3150- result = subprocess .run (
3151- [
3152- "az" ,
3153- "storage" ,
3154- "file" ,
3155- "upload" ,
3156- "--account-name" ,
3157- storage_account ,
3158- "--account-key" ,
3159- storage_key ,
3160- "--share-name" ,
3161- code_share ,
3162- "--source" ,
3163- script_path ,
3164- "--path" ,
3165- file_path ,
3166- ],
3167- capture_output = True ,
3168- text = True ,
3169- )
3163+ # Write content to a temp file for az storage upload
3164+ with tempfile .NamedTemporaryFile (mode = "w" , suffix = ".sh" , delete = False ) as tmp :
3165+ tmp .write (script_content )
3166+ tmp_path = tmp .name
3167+
3168+ try :
3169+ log ("AZURE-ML" , f"Uploading startup script to { file_path } ..." )
3170+ result = subprocess .run (
3171+ [
3172+ "az" ,
3173+ "storage" ,
3174+ "file" ,
3175+ "upload" ,
3176+ "--account-name" ,
3177+ storage_account ,
3178+ "--account-key" ,
3179+ storage_key ,
3180+ "--share-name" ,
3181+ code_share ,
3182+ "--source" ,
3183+ tmp_path ,
3184+ "--path" ,
3185+ file_path ,
3186+ ],
3187+ capture_output = True ,
3188+ text = True ,
3189+ )
3190+ finally :
3191+ os .unlink (tmp_path )
31703192
31713193 if result .returncode != 0 :
31723194 log ("AZURE-ML" , f"ERROR: Failed to upload: { result .stderr } " )
@@ -3354,9 +3376,11 @@ def upload_golden_image_to_blob(source_path: str) -> bool:
33543376 if not source_dir .exists ():
33553377 log ("AZURE-ML" , f"ERROR: Source directory not found: { source_dir } " )
33563378 log ("AZURE-ML" , "" )
3357- log ("AZURE-ML" , "You need to prepare the golden image first:" )
3358- log ("AZURE-ML" , " cd vendor/WindowsAgentArena" )
3359- log ("AZURE-ML" , " ./scripts/run.sh --prepare-image true" )
3379+ log ("AZURE-ML" , "You need to prepare the golden image first." )
3380+ log (
3381+ "AZURE-ML" ,
3382+ "See https://github.com/microsoft/WindowsAgentArena for setup instructions." ,
3383+ )
33603384 return False
33613385
33623386 # Check for required files (only data.img is truly required, OVMF files come from Docker image)
@@ -4634,74 +4658,22 @@ class CreateArgs:
46344658 if skip_benchmark :
46354659 log ("AUTO" , " Skipping benchmark (--skip-benchmark specified)" )
46364660 else :
4637- # Ensure startup script is uploaded
4638- waa_scripts = (
4639- Path (__file__ ).parent .parent .parent
4640- / "vendor"
4641- / "WindowsAgentArena"
4642- / "scripts"
4643- )
4644- startup_script_local = (
4645- waa_scripts / "azure_files" / "compute-instance-startup.sh"
4646- )
4661+ # Upload embedded startup script
46474662 startup_script_datastore_path = "Users/openadapt/compute-instance-startup.sh"
4648-
4649- if startup_script_local .exists ():
4650- log ("AUTO" , " Ensuring startup script is uploaded..." )
4651- success = upload_startup_script_to_datastore (
4652- str (startup_script_local ), startup_script_datastore_path
4653- )
4654- if not success :
4655- log ("AUTO" , " WARNING: Failed to upload startup script" )
4656- # Continue anyway - it might already be there
4657-
4658- # Update config.json
4659- config_path = waa_scripts .parent / "config.json"
4660- config = {
4661- "OPENAI_API_KEY" : settings .openai_api_key ,
4662- "AZURE_SUBSCRIPTION_ID" : settings .azure_subscription_id ,
4663- "AZURE_ML_RESOURCE_GROUP" : settings .azure_ml_resource_group ,
4664- "AZURE_ML_WORKSPACE_NAME" : settings .azure_ml_workspace_name ,
4665- }
4666- with open (config_path , "w" ) as f :
4667- json .dump (config , f , indent = 4 )
4668- log ("AUTO" , f" Updated { config_path } " )
4669-
4670- # Build run_azure.py command
4671- exp_name = (
4672- getattr (args , "exp_name" , None ) or f"e{ datetime .now ().strftime ('%m%d%H%M' )} "
4663+ log ("AUTO" , " Ensuring startup script is uploaded..." )
4664+ success = upload_startup_script_to_datastore (
4665+ COMPUTE_INSTANCE_STARTUP_SH , startup_script_datastore_path
46734666 )
4674- docker_image = getattr (args , "image" , None ) or "windowsarena/winarena:latest"
4675- model = getattr (args , "model" , None ) or "gpt-4o-mini"
4676- agent = getattr (args , "agent" , None ) or "navi"
4677-
4678- cmd = [
4679- "python" ,
4680- str (waa_scripts / "run_azure.py" ),
4681- "--docker_img_name" ,
4682- docker_image ,
4683- "--num_workers" ,
4684- str (num_workers ),
4685- "--exp_name" ,
4686- exp_name ,
4687- "--model_name" ,
4688- model ,
4689- "--agent" ,
4690- agent ,
4691- "--ci_startup_script_path" ,
4692- startup_script_datastore_path ,
4693- ]
4694-
4695- log ("AUTO" , f" Running: { ' ' .join (cmd )} " )
4696- log ("AUTO" , f" Workers: { num_workers } , Model: { model } " )
4697- log ("AUTO" , "" )
4698-
4699- # Run the command
4700- result = subprocess .run (cmd , cwd = waa_scripts )
4667+ if not success :
4668+ log ("AUTO" , " WARNING: Failed to upload startup script" )
4669+ # Continue anyway - it might already be there
47014670
4702- if result .returncode != 0 :
4703- log ("AUTO" , " ERROR: run_azure.py failed" )
4704- return 1
4671+ log (
4672+ "AUTO" ,
4673+ " ERROR: run-azure-ml-auto requires vendor/WindowsAgentArena submodule "
4674+ "(removed). Use pool-create + pool-run instead." ,
4675+ )
4676+ return 1
47054677
47064678 # =========================================================================
47074679 # Complete
@@ -4733,7 +4705,6 @@ def cmd_run_azure_ml(args):
47334705 Uses --setup to upload the required startup script to Azure datastore.
47344706 """
47354707 init_logging ()
4736- start_time = time .time ()
47374708
47384709 from openadapt_ml .config import settings
47394710
@@ -4769,17 +4740,7 @@ def cmd_run_azure_ml(args):
47694740 )
47704741 return 1
47714742
4772- # Paths
4773- waa_scripts = (
4774- Path (__file__ ).parent .parent .parent / "vendor" / "WindowsAgentArena" / "scripts"
4775- )
4776- if not waa_scripts .exists ():
4777- log ("AZURE-ML" , f"ERROR: WAA scripts not found at { waa_scripts } " )
4778- return 1
4779-
4780- # Startup script configuration
4781- startup_script_local = waa_scripts / "azure_files" / "compute-instance-startup.sh"
4782- # Use custom path or default to Users/openadapt/...
4743+ # Startup script datastore path
47834744 startup_script_datastore_path = (
47844745 getattr (args , "ci_startup_script_path" , None )
47854746 or "Users/openadapt/compute-instance-startup.sh"
@@ -4792,14 +4753,8 @@ def cmd_run_azure_ml(args):
47924753 "=== SETUP MODE: Uploading startup script to Azure ML datastore ===" ,
47934754 )
47944755
4795- if not startup_script_local .exists ():
4796- log (
4797- "AZURE-ML" , f"ERROR: Startup script not found at { startup_script_local } "
4798- )
4799- return 1
4800-
48014756 success = upload_startup_script_to_datastore (
4802- str ( startup_script_local ) , startup_script_datastore_path
4757+ COMPUTE_INSTANCE_STARTUP_SH , startup_script_datastore_path
48034758 )
48044759
48054760 if success :
@@ -4861,7 +4816,7 @@ def cmd_run_azure_ml(args):
48614816 log ("AZURE-ML" , "To upload golden image:" )
48624817 log (
48634818 "AZURE-ML" ,
4864- " 1. Prepare locally: cd vendor/ WindowsAgentArena && ./scripts/run.sh --prepare-image true" ,
4819+ " 1. Prepare locally: clone WindowsAgentArena and run ./scripts/run.sh --prepare-image true" ,
48654820 )
48664821 log (
48674822 "AZURE-ML" ,
@@ -4882,11 +4837,11 @@ def cmd_run_azure_ml(args):
48824837 if getattr (args , "upload_image" , False ):
48834838 log ("AZURE-ML" , "=== UPLOAD IMAGE: Uploading golden image to blob storage ===" )
48844839
4885- # Determine source path
4886- default_source = (
4887- waa_scripts . parent / "src" / "win-arena-container" / "vm" / "storage"
4888- )
4889- source_path = getattr ( args , "image_source" , None ) or str ( default_source )
4840+ # Determine source path (--image-source required since submodule was removed)
4841+ source_path = getattr ( args , "image_source" , None )
4842+ if not source_path :
4843+ log ( "AZURE-ML" , "ERROR: --image-source is required (no default path)" )
4844+ return 1
48904845
48914846 success = upload_golden_image_to_blob (source_path )
48924847 if success :
@@ -4954,59 +4909,20 @@ def cmd_run_azure_ml(args):
49544909 teardown_azure_ml_resources (confirm = confirm , keep_image = keep_image )
49554910 return 0
49564911
4957- # Update config.json with our settings
4958- config_path = waa_scripts .parent / "config.json"
4959- config = {
4960- "OPENAI_API_KEY" : settings .openai_api_key ,
4961- "AZURE_SUBSCRIPTION_ID" : settings .azure_subscription_id ,
4962- "AZURE_ML_RESOURCE_GROUP" : settings .azure_ml_resource_group ,
4963- "AZURE_ML_WORKSPACE_NAME" : settings .azure_ml_workspace_name ,
4964- }
4965- with open (config_path , "w" ) as f :
4966- json .dump (config , f , indent = 4 )
4967- log ("AZURE-ML" , f"Updated { config_path } " )
4968-
4969- # Build run_azure.py command
4970- num_workers = getattr (args , "workers" , None ) or 1
4971- # Keep exp_name short - compute instance name is "w{worker_id}Exp{exp_name}" and max 24 chars
4972- exp_name = (
4973- getattr (args , "exp_name" , None ) or f"e{ datetime .now ().strftime ('%m%d%H%M' )} "
4974- )
4975- docker_image = getattr (args , "image" , None ) or "windowsarena/winarena:latest"
4976- model = getattr (args , "model" , None ) or "gpt-4o-mini"
4977- agent = getattr (args , "agent" , None ) or "navi"
4978-
4979- cmd = [
4980- "python" ,
4981- str (waa_scripts / "run_azure.py" ),
4982- "--docker_img_name" ,
4983- docker_image ,
4984- "--num_workers" ,
4985- str (num_workers ),
4986- "--exp_name" ,
4987- exp_name ,
4988- "--model_name" ,
4989- model ,
4990- "--agent" ,
4991- agent ,
4992- "--ci_startup_script_path" ,
4993- startup_script_datastore_path ,
4994- ]
4995-
4996- log ("AZURE-ML" , f"Running: { ' ' .join (cmd )} " )
4997- log ("AZURE-ML" , f"Workers: { num_workers } , Model: { model } , Image: { docker_image } " )
4998- log ("AZURE-ML" , f"Startup script: { startup_script_datastore_path } " )
4999-
5000- # Run the command
5001- result = subprocess .run (cmd , cwd = waa_scripts )
5002-
5003- elapsed = time .time () - start_time
5004- if result .returncode != 0 :
5005- log ("AZURE-ML" , f"ERROR: run_azure.py failed after { elapsed :.1f} s" )
5006- return 1
5007-
5008- log ("AZURE-ML" , f"Completed in { elapsed :.1f} s" )
5009- return 0
4912+ # Direct benchmark execution via run_azure.py is no longer available
4913+ # (vendor/WindowsAgentArena submodule was removed). Use pool commands instead.
4914+ log (
4915+ "AZURE-ML" , "ERROR: Direct Azure ML benchmark execution is no longer available."
4916+ )
4917+ log ("AZURE-ML" , "The vendor/WindowsAgentArena submodule has been removed." )
4918+ log ("AZURE-ML" , "" )
4919+ log ("AZURE-ML" , "Use pool-based execution instead:" )
4920+ log (
4921+ "AZURE-ML" ,
4922+ " uv run python -m openadapt_ml.benchmarks.cli pool-create --workers N" ,
4923+ )
4924+ log ("AZURE-ML" , " uv run python -m openadapt_ml.benchmarks.cli pool-run --tasks N" )
4925+ return 1
50104926
50114927
50124928def get_azure_ml_dedicated_quota (subscription_id : str , location : str ) -> dict :
@@ -7956,7 +7872,7 @@ def main():
79567872 )
79577873 p_azure_ml .add_argument (
79587874 "--image-source" ,
7959- help = "Custom source path for golden image upload (default: vendor/WindowsAgentArena/src/win-arena-container/vm/storage )" ,
7875+ help = "Source path for golden image upload (required for --upload-image )" ,
79607876 )
79617877 p_azure_ml .add_argument (
79627878 "--upload-placeholder" ,
0 commit comments