(
workspaceId: WorkspaceId,
streamInfo: WorkspaceStreamInfo,
emptyStreamRecoveryAttempts: number
)
| 2361 | } |
| 2362 | |
| 2363 | private async retryEmptyStreamBeforeFailure( |
| 2364 | workspaceId: WorkspaceId, |
| 2365 | streamInfo: WorkspaceStreamInfo, |
| 2366 | emptyStreamRecoveryAttempts: number |
| 2367 | ): Promise<boolean> { |
| 2368 | if (emptyStreamRecoveryAttempts >= MAX_EMPTY_STREAM_RECOVERY_ATTEMPTS) { |
| 2369 | return false; |
| 2370 | } |
| 2371 | |
| 2372 | if (streamInfo.abortController.signal.aborted || streamInfo.softInterrupt.pending) { |
| 2373 | return false; |
| 2374 | } |
| 2375 | |
| 2376 | if (streamInfo.parts.length > 0) { |
| 2377 | return false; |
| 2378 | } |
| 2379 | |
| 2380 | const workspaceLog = this.getWorkspaceLogger(workspaceId, streamInfo); |
| 2381 | workspaceLog.warn("Retrying stream after empty-output completion", { |
| 2382 | messageId: streamInfo.messageId, |
| 2383 | model: streamInfo.model, |
| 2384 | nextAttempt: emptyStreamRecoveryAttempts + 1, |
| 2385 | maxAttempts: MAX_EMPTY_STREAM_RECOVERY_ATTEMPTS, |
| 2386 | previousResponseId: this.getOpenAIPreviousResponseId(streamInfo.request.providerOptions), |
| 2387 | }); |
| 2388 | |
| 2389 | streamInfo.didRetryAfterEmptyOutput = true; |
| 2390 | await this.resetStreamStateForRetry(workspaceId, streamInfo, { |
| 2391 | preserveUsage: true, |
| 2392 | workspaceLog, |
| 2393 | }); |
| 2394 | streamInfo.currentStepStartIndex = 0; |
| 2395 | streamInfo.streamResult = this.createStreamResult( |
| 2396 | streamInfo.request, |
| 2397 | streamInfo.abortController, |
| 2398 | streamInfo.stepTracker |
| 2399 | ); |
| 2400 | return true; |
| 2401 | } |
| 2402 | |
| 2403 | /** |
| 2404 | * Processes a stream with guaranteed cleanup, regardless of success or failure |
no test coverage detected