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 $unchanged = [IO.File]::ReadAllText($readmePath).Contains('The greet function returns') if ($previewResult.tool -ne 'propose_file_change' -or $previewResult.proposal.path -ne 'README.md' -or -not $unchanged) { throw 'The live agent did not return a README.md diff preview while preserving the file.' } [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 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 } }