aps-agent/scripts/run-pi-real-workbook-e2e.ps1

160 lines
5.6 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<#
.SYNOPSIS
Run the explicitly opted-in real Pi CLI / real LLM / real workbook E2E.
.DESCRIPTION
Loads only the LLM_* values needed by the product runner, points every APS
persistence path at a fresh temporary artifact root, and invokes the opt-in
pytest module. It never starts or connects to the live 8000/5173 services.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$SourcePath,
[string]$ArtifactRoot,
[string]$Python,
[string]$PiCli,
[string]$NodeBin,
[int]$PiTimeoutSec = 300
)
$ErrorActionPreference = 'Stop'
$RepoRoot = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..')).Path
if ([string]::IsNullOrWhiteSpace($ArtifactRoot)) {
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$ArtifactRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("aps-pi-real-e2e-" + $stamp)
}
$ArtifactRoot = [System.IO.Path]::GetFullPath($ArtifactRoot)
New-Item -ItemType Directory -Path $ArtifactRoot -Force | Out-Null
$ResolvedSource = (Resolve-Path -LiteralPath $SourcePath).Path
if (-not (Test-Path -LiteralPath $ResolvedSource -PathType Leaf)) {
throw "SourcePath must be a file: $ResolvedSource"
}
if ([string]::IsNullOrWhiteSpace($Python)) {
$venvPython = Join-Path $RepoRoot '.venv\Scripts\python.exe'
if (Test-Path -LiteralPath $venvPython -PathType Leaf) {
$Python = $venvPython
} else {
$Python = (Get-Command python -ErrorAction Stop).Source
}
}
if (-not (Test-Path -LiteralPath $Python -PathType Leaf)) {
throw "Python executable not found: $Python"
}
if ([string]::IsNullOrWhiteSpace($PiCli)) {
$PiCli = Join-Path $RepoRoot 'poc\pi-fallback\runtime\node_modules\@mariozechner\pi-coding-agent\dist\cli.js'
}
if (-not (Test-Path -LiteralPath $PiCli -PathType Leaf)) {
throw "Real Pi CLI not found: $PiCli"
}
if ([string]::IsNullOrWhiteSpace($NodeBin)) {
if (-not [string]::IsNullOrWhiteSpace($env:APS_FALLBACK_NODE)) {
$NodeBin = $env:APS_FALLBACK_NODE
} else {
$NodeBin = (Get-Command node -ErrorAction Stop).Source
}
}
if (-not (Test-Path -LiteralPath $NodeBin -PathType Leaf)) {
$resolvedNode = Get-Command $NodeBin -ErrorAction SilentlyContinue
if ($null -eq $resolvedNode) {
throw "Node executable not found: $NodeBin"
}
$NodeBin = $resolvedNode.Source
}
function Read-DotEnvValue {
param([string]$Path, [string]$Name)
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
return $null
}
$pattern = '^\s*(?:export\s+)?' + [regex]::Escape($Name) + '\s*=\s*(.*)$'
foreach ($line in [System.IO.File]::ReadAllLines($Path)) {
if ($line -match $pattern) {
$value = $Matches[1].Trim()
if ($value.Length -ge 2) {
$first = $value.Substring(0, 1)
$last = $value.Substring($value.Length - 1, 1)
if (($first -eq '"' -and $last -eq '"') -or ($first -eq "'" -and $last -eq "'")) {
$value = $value.Substring(1, $value.Length - 2)
}
}
return $value
}
}
return $null
}
$DotEnv = Join-Path $RepoRoot '.env'
foreach ($name in @('LLM_PROVIDER', 'LLM_API_KEY', 'LLM_BASE_URL', 'LLM_MODEL')) {
if ([string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable($name))) {
$value = Read-DotEnvValue -Path $DotEnv -Name $name
if (-not [string]::IsNullOrWhiteSpace($value)) {
[Environment]::SetEnvironmentVariable($name, $value, 'Process')
}
}
}
if ([string]::IsNullOrWhiteSpace($env:LLM_BASE_URL) -or [string]::IsNullOrWhiteSpace($env:LLM_API_KEY)) {
throw "LLM_BASE_URL and LLM_API_KEY are required; fill the whitelisted values in .env or the caller environment."
}
$env:ROUND87_SOURCE = $ResolvedSource
$env:ROUND87_REQUIRED = '1'
$env:APS_REAL_PI_E2E = '1'
$env:APS_REAL_PI_E2E_ARTIFACT_DIR = $ArtifactRoot
$env:APS_FALLBACK_PI_CLI = $PiCli
$env:APS_FALLBACK_NODE = $NodeBin
$env:APS_FALLBACK_TIMEOUT_SEC = [string]$PiTimeoutSec
$env:APS_FALLBACK_EXEC_TIMEOUT_SEC = [string]$PiTimeoutSec
$PytestArgs = @(
'-m', 'pytest',
'tests\e2e\test_pi_real_workbook_e2e.py',
'-q', '-s', '--tb=short', '-p', 'no:cacheprovider'
)
$Reproduce = '.\scripts\run-pi-real-workbook-e2e.ps1 -SourcePath "$env:ROUND87_SOURCE" -ArtifactRoot "' + $ArtifactRoot + '"'
Write-Host "[real-pi-e2e] repo: $RepoRoot"
Write-Host "[real-pi-e2e] artifacts: $ArtifactRoot"
Write-Host "[real-pi-e2e] source: $ResolvedSource"
Write-Host "[real-pi-e2e] pi cli: $PiCli"
Write-Host "[real-pi-e2e] llm configured: $([bool]$env:LLM_API_KEY) provider=$($env:LLM_PROVIDER) model=$($env:LLM_MODEL)"
Write-Host "[real-pi-e2e] live services: not used; in-process TestClient only"
Push-Location -LiteralPath $RepoRoot
try {
& $Python $PytestArgs
$ExitCode = $LASTEXITCODE
} finally {
Pop-Location
}
if ($ExitCode -ne 0) {
Write-Host "[real-pi-e2e] FAILED exit=$ExitCode"
Write-Host "[real-pi-e2e] artifacts preserved: $ArtifactRoot"
Write-Host "[real-pi-e2e] reproduce: $Reproduce"
exit $ExitCode
}
Write-Host "[real-pi-e2e] PASSED"
# 运行时目录(Pi 会话 / 临时工作目录)可能在断言结束后被回收:
# 汇总查找必须是尽力而为,否则会把已通过的验收误报成脚本失败。
$Summary = $null
try {
$Summary = Get-ChildItem -LiteralPath $ArtifactRoot -Recurse -Filter 'latest-summary.json' -File `
-ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
} catch {
$Summary = $null
}
if ($null -ne $Summary) {
Write-Host "[real-pi-e2e] evidence summary: $($Summary.FullName)"
} else {
Write-Host '[real-pi-e2e] evidence summary: <not found; inspect the artifact root>'
}