(threadId)
| 393 | } |
| 394 | |
| 395 | const resumeActiveRunForThread = async (threadId) => { |
| 396 | if (!threadId) return |
| 397 | const ts = getThreadState(threadId) |
| 398 | if (!ts) return |
| 399 | |
| 400 | if (ts.runStreamAbortController) { |
| 401 | if (!ts.activeRunId) return |
| 402 | try { |
| 403 | const runRes = await agentApi.getAgentRun(ts.activeRunId) |
| 404 | const run = runRes?.run |
| 405 | if (run?.status === RUN_INTERRUPTED_STATUS) { |
| 406 | stopRunStreamSubscription(threadId) |
| 407 | const snapshot = loadActiveRunSnapshot(threadId) |
| 408 | if (hasPendingInterruptForRun(ts, run.id)) { |
| 409 | await preserveInterruptedRun(threadId, run, snapshot) |
| 410 | } else { |
| 411 | resetOnGoingConv(threadId) |
| 412 | await startRunStream(threadId, run.id, '0-0') |
| 413 | } |
| 414 | } else if (run && RUN_TERMINAL_STATUSES.has(run.status)) { |
| 415 | stopRunStreamSubscription(threadId) |
| 416 | ts.activeRunId = null |
| 417 | ts.isStreaming = false |
| 418 | ts.replyLoadingVisible = false |
| 419 | ts.pendingRequestId = null |
| 420 | clearPendingInterruptForRun(threadId, run.id) |
| 421 | clearActiveRunSnapshot(threadId) |
| 422 | notifyTerminalDetected(threadId, run.id, new Set([threadId])) |
| 423 | } |
| 424 | } catch (e) { |
| 425 | console.warn('Failed to refresh active run while stream is open:', threadId, e) |
| 426 | } |
| 427 | return |
| 428 | } |
| 429 | |
| 430 | const snapshot = loadActiveRunSnapshot(threadId) |
| 431 | if (snapshot?.run_id) { |
| 432 | if (Date.now() - Number(snapshot.created_at || 0) > ACTIVE_RUN_STORAGE_TTL_MS) { |
| 433 | clearActiveRunSnapshot(threadId) |
| 434 | } else { |
| 435 | try { |
| 436 | const runRes = await agentApi.getAgentRun(snapshot.run_id) |
| 437 | const run = runRes?.run |
| 438 | if (run?.status === RUN_INTERRUPTED_STATUS) { |
| 439 | // 仅当本地仍持有该中断时才据快照恢复;否则不能仅凭快照重放旧中断 |
| 440 | // (可能已被回复),交由下方 active_run 做权威判定。 |
| 441 | if (hasPendingInterruptForRun(ts, run.id)) { |
| 442 | await preserveInterruptedRun(threadId, run, snapshot) |
| 443 | return |
| 444 | } |
| 445 | } else if (run && !RUN_TERMINAL_STATUSES.has(run.status)) { |
| 446 | const afterSeq = resolveRunResumeAfterSeq({ |
| 447 | snapshot, |
| 448 | threadState: ts |
| 449 | }) |
| 450 | if (afterSeq === '0-0') { |
| 451 | resetOnGoingConv(threadId) |
| 452 | } |
nothing calls this directly
no test coverage detected