Fix remote training and model validation pipeline
This commit is contained in:
@@ -6,6 +6,7 @@ param(
|
||||
[int]$PollSeconds = 10,
|
||||
[int]$WatchdogMinutes = 5,
|
||||
[string]$RepoRoot = "",
|
||||
[string]$CredentialPath = "",
|
||||
[switch]$StartNow,
|
||||
[switch]$KeepLegacyRetrainer
|
||||
)
|
||||
@@ -15,105 +16,153 @@ $ErrorActionPreference = "Stop"
|
||||
if (-not $RepoRoot) {
|
||||
$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||
}
|
||||
$Agent = Join-Path $RepoRoot "tools\windows_training_agent.py"
|
||||
if (-not (Test-Path $Agent)) {
|
||||
throw "Windows training agent not found: $Agent"
|
||||
if (-not $CredentialPath) {
|
||||
$CredentialPath = Join-Path $env:LOCALAPPDATA "TradeBot\training-agent.token"
|
||||
}
|
||||
|
||||
function Resolve-Python {
|
||||
$venvPython = Join-Path $RepoRoot ".venv\Scripts\python.exe"
|
||||
if (Test-Path $venvPython) {
|
||||
return $venvPython
|
||||
}
|
||||
|
||||
$userPython = Join-Path $env:LOCALAPPDATA "Programs\TradeBotPython312\python.exe"
|
||||
if (Test-Path $userPython) {
|
||||
return $userPython
|
||||
}
|
||||
|
||||
foreach ($candidate in @("python.exe", "python")) {
|
||||
$command = Get-Command $candidate -ErrorAction SilentlyContinue
|
||||
if ($command) {
|
||||
return $command.Source
|
||||
}
|
||||
}
|
||||
throw "Python was not found. Create .venv or install Python 3.12."
|
||||
}
|
||||
|
||||
function Resolve-WindowlessPython {
|
||||
$python = Resolve-Python
|
||||
$pythonw = Join-Path (Split-Path -Parent $python) "pythonw.exe"
|
||||
if (Test-Path $pythonw) {
|
||||
return $pythonw
|
||||
}
|
||||
return $python
|
||||
$runner = Join-Path $RepoRoot "tools\run_windows_training_agent.ps1"
|
||||
if (-not (Test-Path -LiteralPath $runner)) {
|
||||
throw "Windows training agent runner not found: $runner"
|
||||
}
|
||||
|
||||
$credentialDirectory = Split-Path -Parent $CredentialPath
|
||||
New-Item -ItemType Directory -Path $credentialDirectory -Force | Out-Null
|
||||
if ($ApiAuth) {
|
||||
[Environment]::SetEnvironmentVariable("TRADEBOT_API_AUTH", $ApiAuth, "User")
|
||||
$env:TRADEBOT_API_AUTH = $ApiAuth
|
||||
$ApiAuth.Trim() |
|
||||
ConvertTo-SecureString -AsPlainText -Force |
|
||||
ConvertFrom-SecureString |
|
||||
Set-Content -LiteralPath $CredentialPath -Encoding UTF8
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $CredentialPath)) {
|
||||
throw "ApiAuth is required for the first installation."
|
||||
}
|
||||
|
||||
# Remove the legacy plaintext secret from the user environment. The new runner
|
||||
# decrypts the DPAPI-protected credential only inside the agent process tree.
|
||||
[Environment]::SetEnvironmentVariable("TRADEBOT_API_AUTH", $null, "User")
|
||||
Remove-Item Env:TRADEBOT_API_AUTH -ErrorAction SilentlyContinue
|
||||
[Environment]::SetEnvironmentVariable("TRADEBOT_API_BASE_URL", $ApiBaseUrl, "User")
|
||||
[Environment]::SetEnvironmentVariable("TRADEBOT_TRAINING_WORKER_NAME", $env:COMPUTERNAME, "User")
|
||||
$env:TRADEBOT_API_BASE_URL = $ApiBaseUrl
|
||||
$env:TRADEBOT_TRAINING_WORKER_NAME = $env:COMPUTERNAME
|
||||
|
||||
if (-not $KeepLegacyRetrainer) {
|
||||
foreach ($legacyName in @("TradeBot PyTorch Forecaster Retrainer", "TradeBot LSTM Retrainer")) {
|
||||
$legacyTask = Get-ScheduledTask -TaskName $legacyName -ErrorAction SilentlyContinue
|
||||
if ($legacyTask) {
|
||||
Unregister-ScheduledTask -TaskName $legacyName -Confirm:$false
|
||||
Write-Host "Removed legacy scheduled task '$legacyName'."
|
||||
try {
|
||||
$legacyTask = Get-ScheduledTask -TaskName $legacyName -ErrorAction SilentlyContinue
|
||||
if ($legacyTask) {
|
||||
Unregister-ScheduledTask -TaskName $legacyName -Confirm:$false
|
||||
Write-Host "Removed legacy scheduled task '$legacyName'."
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not remove legacy scheduled task '$legacyName': $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$python = Resolve-WindowlessPython
|
||||
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
||||
$arguments = @(
|
||||
"-u",
|
||||
"`"$Agent`"",
|
||||
"--repo-root", "`"$RepoRoot`"",
|
||||
"--api-base-url", "`"$ApiBaseUrl`"",
|
||||
"--poll-seconds", $PollSeconds.ToString()
|
||||
$principal = New-Object System.Security.Principal.WindowsPrincipal(
|
||||
[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
)
|
||||
$isAdministrator = $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
$powershell = (Get-Command powershell.exe -ErrorAction Stop).Source
|
||||
$runnerArguments = @(
|
||||
"-NoProfile",
|
||||
"-WindowStyle", "Hidden",
|
||||
"-ExecutionPolicy", "Bypass",
|
||||
"-File", "`"$runner`"",
|
||||
"-RepoRoot", "`"$RepoRoot`"",
|
||||
"-ApiBaseUrl", "`"$ApiBaseUrl`"",
|
||||
"-CredentialPath", "`"$CredentialPath`"",
|
||||
"-WorkerName", "`"$env:COMPUTERNAME`"",
|
||||
"-PollSeconds", $PollSeconds.ToString()
|
||||
) -join " "
|
||||
|
||||
$action = New-ScheduledTaskAction -Execute $python -Argument $arguments -WorkingDirectory $RepoRoot
|
||||
$trigger = @(
|
||||
New-ScheduledTaskTrigger -AtLogOn -User $currentUser
|
||||
New-ScheduledTaskTrigger -AtStartup
|
||||
New-ScheduledTaskTrigger `
|
||||
-Once `
|
||||
-At (Get-Date).AddMinutes(1) `
|
||||
-RepetitionInterval (New-TimeSpan -Minutes $WatchdogMinutes) `
|
||||
-RepetitionDuration (New-TimeSpan -Days 3650)
|
||||
)
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserId $currentUser `
|
||||
-LogonType Interactive `
|
||||
-RunLevel Limited
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-StartWhenAvailable `
|
||||
-MultipleInstances IgnoreNew `
|
||||
-AllowStartIfOnBatteries `
|
||||
-DontStopIfGoingOnBatteries `
|
||||
-RestartCount 999 `
|
||||
-RestartInterval (New-TimeSpan -Minutes 1) `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Days 30)
|
||||
$startupShortcut = Join-Path ([Environment]::GetFolderPath("Startup")) "$TaskName.lnk"
|
||||
$runKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"
|
||||
Remove-ItemProperty -Path $runKey -Name "TradeBotWindowsTrainingAgent" -ErrorAction SilentlyContinue
|
||||
|
||||
Register-ScheduledTask `
|
||||
-TaskName $TaskName `
|
||||
-Action $action `
|
||||
-Trigger $trigger `
|
||||
-Principal $principal `
|
||||
-Settings $settings `
|
||||
-Description "Keeps the TradeBot Windows training agent online and polls the public bot API for retrain jobs." `
|
||||
-Force | Out-Null
|
||||
$installMode = "startup shortcut"
|
||||
if ($isAdministrator) {
|
||||
if (Test-Path -LiteralPath $startupShortcut) {
|
||||
Remove-Item -LiteralPath $startupShortcut -Force
|
||||
}
|
||||
$action = New-ScheduledTaskAction -Execute $powershell -Argument $runnerArguments -WorkingDirectory $RepoRoot
|
||||
$trigger = @(
|
||||
New-ScheduledTaskTrigger -AtLogOn -User $currentUser
|
||||
New-ScheduledTaskTrigger -AtStartup
|
||||
New-ScheduledTaskTrigger `
|
||||
-Once `
|
||||
-At (Get-Date).AddMinutes(1) `
|
||||
-RepetitionInterval (New-TimeSpan -Minutes $WatchdogMinutes) `
|
||||
-RepetitionDuration (New-TimeSpan -Days 3650)
|
||||
)
|
||||
$taskPrincipal = New-ScheduledTaskPrincipal `
|
||||
-UserId $currentUser `
|
||||
-LogonType Interactive `
|
||||
-RunLevel Limited
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-StartWhenAvailable `
|
||||
-MultipleInstances IgnoreNew `
|
||||
-AllowStartIfOnBatteries `
|
||||
-DontStopIfGoingOnBatteries `
|
||||
-RestartCount 999 `
|
||||
-RestartInterval (New-TimeSpan -Minutes 1) `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Days 30)
|
||||
|
||||
if ($StartNow) {
|
||||
Start-ScheduledTask -TaskName $TaskName
|
||||
Register-ScheduledTask `
|
||||
-TaskName $TaskName `
|
||||
-Action $action `
|
||||
-Trigger $trigger `
|
||||
-Principal $taskPrincipal `
|
||||
-Settings $settings `
|
||||
-Description "Keeps the TradeBot Windows training agent online and polls the bot API for retrain jobs." `
|
||||
-Force | Out-Null
|
||||
$installMode = "scheduled task"
|
||||
}
|
||||
else {
|
||||
try {
|
||||
$existingTask = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
if ($existingTask) {
|
||||
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not remove an existing elevated task: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
$shell = New-Object -ComObject WScript.Shell
|
||||
$shortcut = $shell.CreateShortcut($startupShortcut)
|
||||
$shortcut.TargetPath = $powershell
|
||||
$shortcut.Arguments = $runnerArguments
|
||||
$shortcut.WorkingDirectory = $RepoRoot
|
||||
$shortcut.WindowStyle = 7
|
||||
$shortcut.Description = "TradeBot Windows Training Agent"
|
||||
$shortcut.Save()
|
||||
}
|
||||
|
||||
Write-Host "Registered scheduled task '$TaskName' for Windows startup, logon, and watchdog restarts."
|
||||
Get-CimInstance Win32_Process |
|
||||
Where-Object {
|
||||
$_.ProcessId -ne $PID -and
|
||||
$_.CommandLine -and
|
||||
($_.CommandLine -match [regex]::Escape("windows_training_agent.py") -or
|
||||
$_.CommandLine -match [regex]::Escape("run_windows_training_agent.ps1"))
|
||||
} |
|
||||
ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
if ($StartNow) {
|
||||
if ($installMode -eq "scheduled task") {
|
||||
Start-ScheduledTask -TaskName $TaskName
|
||||
}
|
||||
else {
|
||||
Start-Process `
|
||||
-FilePath $powershell `
|
||||
-ArgumentList $runnerArguments `
|
||||
-WorkingDirectory $RepoRoot `
|
||||
-WindowStyle Hidden | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Installed '$TaskName' using $installMode."
|
||||
Write-Host "Agent API: $ApiBaseUrl"
|
||||
Write-Host "Agent script: $Agent"
|
||||
Write-Host "Encrypted credential: $CredentialPath"
|
||||
Write-Host "Agent runner: $runner"
|
||||
|
||||
Reference in New Issue
Block a user