(raw)
| 219 | }); |
| 220 | |
| 221 | const processFrame = async (raw) => { |
| 222 | if (closed) return; |
| 223 | |
| 224 | if (typeof raw !== "string") { |
| 225 | emitErrorEvent(ws, "invalid_frame_type", "Only text WebSocket frames are supported"); |
| 226 | requestClose(1003, "binary_not_supported"); |
| 227 | return; |
| 228 | } |
| 229 | |
| 230 | let frame; |
| 231 | try { |
| 232 | frame = JSON.parse(raw); |
| 233 | } catch (err) { |
| 234 | emitErrorEvent( |
| 235 | ws, |
| 236 | "invalid_json", |
| 237 | `Invalid JSON frame: ${err && err.message ? err.message : "parse error"}` |
| 238 | ); |
| 239 | return; |
| 240 | } |
| 241 | |
| 242 | if (!frame || typeof frame !== "object") { |
| 243 | emitErrorEvent(ws, "invalid_frame", "Frame must be a JSON object"); |
| 244 | return; |
| 245 | } |
| 246 | |
| 247 | if (frame.type !== "response.create") { |
| 248 | emitErrorEvent( |
| 249 | ws, |
| 250 | "unsupported_event_type", |
| 251 | `Only type=response.create is supported; received: ${frame.type ?? "(missing)"}` |
| 252 | ); |
| 253 | return; |
| 254 | } |
| 255 | |
| 256 | const { type: _type, ...rawBody } = frame; |
| 257 | const body = { ...rawBody }; |
| 258 | // body.model wins over query; only fill from query when body lacks a model |
| 259 | // (LiteLLM/other compat). Drop transport-only fields. |
| 260 | if (queryModel && (body.model === undefined || body.model === null || body.model === "")) { |
| 261 | body.model = queryModel; |
| 262 | } |
| 263 | |
| 264 | log("info", "ws_request_started", { |
| 265 | model: typeof body.model === "string" ? body.model : null, |
| 266 | payloadBytes: Buffer.byteLength(raw, "utf8"), |
| 267 | hasPreviousResponseId: typeof body.previous_response_id === "string", |
| 268 | }); |
| 269 | |
| 270 | await forwardToInternalHttp( |
| 271 | ws, |
| 272 | req, |
| 273 | body, |
| 274 | responsesWsSessionId, |
| 275 | (clientReq) => { |
| 276 | currentInternalReq = clientReq; |
| 277 | }, |
| 278 | requestClose |
no test coverage detected