140 lines
5.5 KiB
PowerShell
140 lines
5.5 KiB
PowerShell
param(
|
|
[string]$ApiBaseUrl = 'http://127.0.0.1:8000'
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$ApiBaseUrl = $ApiBaseUrl.TrimEnd('/')
|
|
$testRoot = Join-Path ([IO.Path]::GetTempPath()) ('sovereignai-agent-smoke-' + [guid]::NewGuid().ToString('N'))
|
|
$readmePath = Join-Path $testRoot 'README.md'
|
|
$sourcePath = Join-Path $testRoot 'src/hello.py'
|
|
$token = $null
|
|
$registered = $false
|
|
|
|
try {
|
|
$health = Invoke-RestMethod -Uri "$ApiBaseUrl/health" -TimeoutSec 10
|
|
if ($health.status -ne 'ok') {
|
|
throw "The API is not healthy: $($health.status)"
|
|
}
|
|
|
|
$null = New-Item -ItemType Directory -Path (Split-Path -Parent $sourcePath) -Force
|
|
Set-Content -LiteralPath $readmePath -Encoding utf8 -Value "# Agent workspace smoke test`n`nThe greet function returns a greeting containing the provided name.`n"
|
|
Set-Content -LiteralPath $sourcePath -Encoding utf8 -Value "def greet(name):`n return f'Hello, {name}!'`n"
|
|
|
|
$session = Invoke-RestMethod -Method Post -Uri "$ApiBaseUrl/v1/auth/local-session" -TimeoutSec 10
|
|
$token = $session.access_token
|
|
$headers = @{ Authorization = "Bearer $token" }
|
|
$projectBody = @{ workspace_path = $testRoot } | ConvertTo-Json
|
|
|
|
$registeredProject = Invoke-RestMethod `
|
|
-Method Post `
|
|
-Uri "$ApiBaseUrl/v1/agent/projects" `
|
|
-Headers $headers `
|
|
-ContentType 'application/json' `
|
|
-Body $projectBody `
|
|
-TimeoutSec 10
|
|
$registered = $true
|
|
|
|
$listed = Invoke-RestMethod `
|
|
-Method Post `
|
|
-Uri "$ApiBaseUrl/v1/agent/workspace/files" `
|
|
-Headers $headers `
|
|
-ContentType 'application/json' `
|
|
-Body $projectBody `
|
|
-TimeoutSec 10
|
|
if ($listed.files -notcontains 'src/hello.py') {
|
|
throw 'The registered project file list did not contain src/hello.py.'
|
|
}
|
|
|
|
$readRequest = @{
|
|
task = 'اشرح بإيجاز ماذا تفعل الدالة greet في الملف المحدد، واستشهد بمساره.'
|
|
workspace_path = $testRoot
|
|
workspace_files = @('src/hello.py')
|
|
skill_id = 'code_explain'
|
|
} | ConvertTo-Json -Depth 5
|
|
$readResult = Invoke-RestMethod `
|
|
-Method Post `
|
|
-Uri "$ApiBaseUrl/v1/agent/run" `
|
|
-Headers $headers `
|
|
-ContentType 'application/json' `
|
|
-Body $readRequest `
|
|
-TimeoutSec 240
|
|
if ($readResult.files -notcontains 'src/hello.py' -or $readResult.result -notmatch 'greet') {
|
|
throw 'The live agent response did not cite and explain src/hello.py.'
|
|
}
|
|
|
|
$previewRequest = @{
|
|
task = 'نفّذ تعديلًا صريحًا داخل المشروع: حدّث README.md بإضافة سطر عربي يشرح أن الدالة greet ترجع تحية تتضمن الاسم. استخدم أداة propose_file_change لإنشاء معاينة diff فقط. لا تطبق التغيير.'
|
|
workspace_path = $testRoot
|
|
workspace_files = @('README.md')
|
|
skill_id = 'code_review'
|
|
} | ConvertTo-Json -Depth 5
|
|
$previewResult = Invoke-RestMethod `
|
|
-Method Post `
|
|
-Uri "$ApiBaseUrl/v1/agent/run" `
|
|
-Headers $headers `
|
|
-ContentType 'application/json' `
|
|
-Body $previewRequest `
|
|
-TimeoutSec 240
|
|
$previewDiff = [string]$previewResult.proposal.diff
|
|
$unchanged = [IO.File]::ReadAllText($readmePath).Contains('The greet function returns')
|
|
if ($previewResult.tool -ne 'propose_file_change') {
|
|
throw "The live model selected '$($previewResult.tool)' instead of propose_file_change."
|
|
}
|
|
if ($previewResult.proposal.path -ne 'README.md') {
|
|
throw 'The live proposal targeted a different file than README.md.'
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($previewDiff)) {
|
|
throw 'The live proposal did not include diff text.'
|
|
}
|
|
if ($previewDiff -notmatch '(?m)^\+[^+]') {
|
|
throw 'The live proposal diff did not contain an added line.'
|
|
}
|
|
if (-not $unchanged) {
|
|
throw 'The smoke test changed README.md before explicit approval.'
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
status = 'passed'
|
|
model = $readResult.model
|
|
registered_project = $registeredProject.name
|
|
listed_files = @($listed.files)
|
|
read_citations = @($readResult.files)
|
|
preview_tool = $previewResult.tool
|
|
preview_path = $previewResult.proposal.path
|
|
preview_operation = $previewResult.proposal.operation
|
|
preview_diff_lines = @($previewDiff -split "`n").Count
|
|
file_unchanged_without_user_approval = $unchanged
|
|
} | ConvertTo-Json -Depth 5
|
|
}
|
|
finally {
|
|
if ($registered -and $token) {
|
|
try {
|
|
Invoke-RestMethod `
|
|
-Method Delete `
|
|
-Uri "$ApiBaseUrl/v1/agent/projects" `
|
|
-Headers @{ Authorization = "Bearer $token" } `
|
|
-ContentType 'application/json' `
|
|
-Body (@{ workspace_path = $testRoot } | ConvertTo-Json) `
|
|
-TimeoutSec 10 | Out-Null
|
|
}
|
|
catch {
|
|
Write-Warning 'Could not remove the temporary project registration.'
|
|
}
|
|
}
|
|
if ($token) {
|
|
try {
|
|
Invoke-RestMethod `
|
|
-Method Post `
|
|
-Uri "$ApiBaseUrl/v1/auth/logout" `
|
|
-Headers @{ Authorization = "Bearer $token" } `
|
|
-TimeoutSec 10 | Out-Null
|
|
}
|
|
catch {
|
|
Write-Warning 'Could not revoke the temporary local session.'
|
|
}
|
|
}
|
|
if (Test-Path -LiteralPath $testRoot) {
|
|
Remove-Item -LiteralPath $testRoot -Recurse -Force
|
|
}
|
|
}
|