-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvllm-text-smoke.ps1
More file actions
267 lines (240 loc) · 7.14 KB
/
Copy pathvllm-text-smoke.ps1
File metadata and controls
267 lines (240 loc) · 7.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# End-to-end text smoke against a running vLLM OpenAI-compatible server and lipstd.
# Default base URL is localhost:8000/v1; override -VllmBaseUrl for other hosts/ports
# (for example WSL CPU vLLM on http://127.0.0.1:18000/v1; see docs/dogfood-local.md).
param(
[string]$Model = "",
[string]$VllmBaseUrl = "http://localhost:8000/v1",
[string]$VllmApiKey = "vllm",
[string]$ProxyAddress = "",
[string]$ExpectedResponsePattern = "",
[switch]$SkipDirectVllmPreflight,
[int]$StartupTimeoutSeconds = 30,
[int]$RequestTimeoutSeconds = 120
)
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot
$tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) ("lip-vllm-smoke-" + [System.Guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $tmpDir | Out-Null
$configPath = Join-Path $tmpDir "config.yaml"
$stdoutPath = Join-Path $tmpDir "lipstd.stdout.log"
$stderrPath = Join-Path $tmpDir "lipstd.stderr.log"
function Get-VllmServerRoot {
$serverRoot = $VllmBaseUrl.TrimEnd("/")
if ($serverRoot.EndsWith("/v1")) {
$serverRoot = $serverRoot.Substring(0, $serverRoot.Length - 3)
}
return $serverRoot.TrimEnd("/")
}
function Test-VllmHealth {
$healthURL = (Get-VllmServerRoot) + "/health"
$resp = Invoke-WebRequest -Method Get -Uri $healthURL -TimeoutSec 10
if ($resp.StatusCode -ne 200) {
throw "vLLM health check failed at $healthURL with status $($resp.StatusCode)"
}
}
function New-FreeLoopbackAddress {
$listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Parse("127.0.0.1"), 0)
$listener.Start()
try {
$port = $listener.LocalEndpoint.Port
} finally {
$listener.Stop()
}
return "127.0.0.1:$port"
}
function Read-FirstVllmModel {
$modelsURL = ($VllmBaseUrl.TrimEnd("/")) + "/models"
$models = Invoke-RestMethod -Method Get -Uri $modelsURL -TimeoutSec 10
if (-not $models.data -or $models.data.Count -eq 0) {
throw "vLLM returned no models from $modelsURL"
}
return [string]$models.data[0].id
}
function Invoke-TextChat {
param(
[string]$Uri,
[string]$RequestModel,
[hashtable]$Headers = @{}
)
$body = @{
model = $RequestModel
stream = $false
max_tokens = 64
messages = @(
@{ role = "user"; content = "Respond with exactly: LIP VLLM TEXT SMOKE OK" }
)
} | ConvertTo-Json -Depth 8
return Invoke-RestMethod -Method Post -Uri $Uri -Headers $Headers -ContentType "application/json" -Body $body -TimeoutSec $RequestTimeoutSeconds
}
function Wait-ProxyReady {
$deadline = (Get-Date).AddSeconds($StartupTimeoutSeconds)
$healthURL = "http://$ProxyAddress/healthz"
while ((Get-Date) -lt $deadline) {
if ($script:proc -and $script:proc.HasExited) {
throw "proxy exited before becoming healthy with code $($script:proc.ExitCode)"
}
try {
$resp = Invoke-WebRequest -Method Get -Uri $healthURL -TimeoutSec 2
if ($resp.StatusCode -eq 200) {
return
}
} catch {
Start-Sleep -Milliseconds 250
}
}
throw "proxy did not become healthy at $healthURL within ${StartupTimeoutSeconds}s"
}
if ([string]::IsNullOrWhiteSpace($ProxyAddress)) {
$ProxyAddress = New-FreeLoopbackAddress
}
Write-Host "vllm base url: $VllmBaseUrl"
$vllmHeaders = @{
"Authorization" = "Bearer $VllmApiKey"
}
if (-not $SkipDirectVllmPreflight) {
try {
Test-VllmHealth
Write-Host "vllm health preflight: PASS"
} catch {
throw "vLLM health preflight failed: $($_.Exception.Message)"
}
}
if ([string]::IsNullOrWhiteSpace($Model)) {
$Model = Read-FirstVllmModel
}
if (-not $SkipDirectVllmPreflight) {
try {
$direct = Invoke-TextChat -Uri (($VllmBaseUrl.TrimEnd("/")) + "/chat/completions") -RequestModel $Model -Headers $vllmHeaders
$directText = [string]$direct.choices[0].message.content
if ([string]::IsNullOrWhiteSpace($directText)) {
throw "direct vLLM returned an empty assistant message"
}
Write-Host "vllm direct text preflight: PASS"
} catch {
throw "direct vLLM text preflight failed for model '$Model': $($_.Exception.Message)"
}
}
$defaultRoute = "vllm:$Model"
$proxyRequestModel = "vllm:$Model"
$config = @"
server:
address: "$ProxyAddress"
read_header_timeout: 10s
read_timeout: 60s
write_timeout: 180s
idle_timeout: 60s
routing:
max_attempts: 1
default_route: "$defaultRoute"
continuity:
in_memory: true
store: memory
logging:
level: info
format: text
diagnostics:
enabled: true
health_path: "/healthz"
hooks:
tool_reactor_error_policy: fail_open
plugins:
frontends:
- id: openai-responses
enabled: true
config: {}
- id: openai-legacy
enabled: true
config: {}
- id: anthropic
enabled: true
config: {}
- id: gemini
enabled: true
config: {}
backends:
- id: openai-responses
enabled: false
config: {}
- id: openai-legacy
enabled: false
config: {}
- id: anthropic
enabled: false
config: {}
- id: gemini
enabled: false
config: {}
- id: bedrock
enabled: false
config: {}
- id: acp
enabled: false
config: {}
- id: openrouter
enabled: false
config: {}
- id: nvidia
enabled: false
config: {}
- id: ollama
enabled: false
config: {}
- id: ollama-cloud
enabled: false
config: {}
- id: lmstudio
enabled: false
config: {}
- id: vllm
enabled: true
config:
base_url: "$VllmBaseUrl"
api_key: "$VllmApiKey"
discovery:
catalog: true
timeout: 10s
features:
- id: submit-noop
enabled: true
config: {}
- id: parts-noop
enabled: true
config: {}
- id: tool-reactor-noop
enabled: true
config: {}
"@
Set-Content -LiteralPath $configPath -Value $config -Encoding UTF8
$script:proc = $null
$ok = $false
try {
$script:proc = Start-Process -FilePath "go" -ArgumentList @("run", "./cmd/lipstd", "--config", $configPath, "serve") -WorkingDirectory $root -NoNewWindow -PassThru -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath
Wait-ProxyReady
$headers = @{
"Authorization" = "Bearer smoke"
}
$resp = Invoke-TextChat -Uri "http://$ProxyAddress/v1/chat/completions" -RequestModel $proxyRequestModel -Headers $headers
$text = [string]$resp.choices[0].message.content
if ([string]::IsNullOrWhiteSpace($text)) {
throw "proxy returned an empty assistant message"
}
if (-not [string]::IsNullOrWhiteSpace($ExpectedResponsePattern) -and $text -notmatch $ExpectedResponsePattern) {
throw "unexpected assistant response: $text"
}
Write-Host "vllm-text-smoke: PASS"
Write-Host "model: $Model"
Write-Host "response: $text"
$ok = $true
} finally {
if ($script:proc -and -not $script:proc.HasExited) {
Stop-Process -Id $script:proc.Id -Force
$script:proc.WaitForExit(5000) | Out-Null
}
if (-not $ok -and $script:proc -and $script:proc.ExitCode -ne 0 -and $null -ne $script:proc.ExitCode) {
Write-Host "lipstd stdout: $stdoutPath"
Write-Host "lipstd stderr: $stderrPath"
}
if ($ok -and (Test-Path -LiteralPath $tmpDir)) {
Remove-Item -LiteralPath $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
}
}