Skip to content

fix(opencode): fail stalled LLM connections before silent timeout#558

Merged
Astro-Han merged 3 commits into
devfrom
fix/llm-connect-timeout
May 11, 2026
Merged

fix(opencode): fail stalled LLM connections before silent timeout#558
Astro-Han merged 3 commits into
devfrom
fix/llm-connect-timeout

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 11, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a 30s pre-progress LLM connect timeout before the existing 10m silent-stream timeout.

  • Before the first effective provider progress event, timeout now aborts the provider request and fails the stream.
  • After effective provider progress, existing silent-stream timeout behavior is preserved.
  • start and finish do not count as provider progress; only visible/state-advancing events do.
  • Adds LLM-level and processor-level regression tests for failure-not-drain and assistant info.error + idle recovery.

Why

#554 shows an invalid locally registered provider/model pair, alibaba-coding-plan-cn + glm-5, entering a permanent "思考中" state. The request can stall before any effective provider output, leaving the assistant message without parts, info.error, completion time, or an LLM trace.

The existing timeout guarded silent streams, but it used the same 10m budget before provider progress and only aborted the request. In the no-progress case that can success-drain instead of hitting SessionProcessor.halt(), so no assistant error is written and the session can stay busy.

This PR fixes the lowest layer that owns provider stream progress: LLM stream dispatch.

Related Issue

Closes #554.

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.

Review Focus

Please focus on:

  • Whether the progress allowlist is narrow enough: start / finish are excluded; text, reasoning, and tool progress are included.
  • Whether connect timeout failure reliably reaches the processor error/idle path.
  • Whether existing post-progress silent-stream timeout behavior remains unchanged.
  • Iterator cleanup: the timeout wrapper calls the provider iterator return() on stream cleanup but does not await a never-resolving provider iterator. Existing cancellation tests prove provider response body cancellation still happens promptly.

Risk Notes

  • Behavior: provider streams that produce no effective progress for 30s now fail instead of waiting for the 10m silent-stream timeout.
  • False-positive risk: a very slow provider that emits only start and then no effective progress for 30s will now surface an error. That is intentional for v1; provider-specific overrides are deferred unless real usage proves the default too strict.
  • Cleanup risk: the async-iterator wrapper avoids awaiting return() so interrupted processor cleanup cannot hang on a never-ending provider stream. This is covered by existing interrupt cleanup tests and response-body cancellation tests.
  • No boot-time model validation, provider override config, status watchdog, or PR fix(server, app): split abort into soft/hard modes; preserve pending question on soft (closes #553) #556 abort API changes are included.

How To Verify

LLM targeted: bun --cwd packages/opencode test test/session/llm.test.ts --timeout 30000 -> 19 pass, 0 fail
Processor targeted: bun --cwd packages/opencode test test/session/processor-effect.test.ts --timeout 30000 -> 16 pass, 0 fail
OpenCode full: bun --cwd packages/opencode test -> 2708 pass, 9 skip, 1 todo, 0 fail
OpenCode typecheck: bun --cwd packages/opencode typecheck -> pass
App unit: bun --cwd packages/app test --preload ./happydom.ts -> 1048 pass, 0 fail
Diff check: git diff --check -> pass

The concrete #554 failure mode is covered by a no-effective-provider-progress fixture: connectTimeoutMs fires, the provider request is cancelled, the LLM stream fails rather than success-draining, the processor writes assistant info.error, and session_status returns to idle. Production uses the 30s default; tests use a 20ms hook for deterministic runtime.

Screenshots or Recordings

Not applicable. This is server/session behavior with no visible UI or copy changes.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, primary area, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Summary by CodeRabbit

  • New Features

    • Added a separate connection timeout for LLM streaming to better handle unresponsive providers. The system now distinguishes between initial connection establishment and ongoing idle time, with a configurable connect timeout (default 30 seconds). This improves reliability when LLM providers fail to emit progress events.
  • Bug Fixes

    • Improved timeout handling for streaming LLM responses to prevent indefinite hangs.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Astro-Han has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 49 minutes and 23 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 940b288a-f15b-4037-b942-6584e09b960d

📥 Commits

Reviewing files that changed from the base of the PR and between 2ad4080 and 37b587d.

📒 Files selected for processing (3)
  • packages/opencode/src/session/llm.ts
  • packages/opencode/test/session/llm.test.ts
  • packages/opencode/test/session/processor-effect.test.ts
📝 Walkthrough

Walkthrough

This PR implements a connect-timeout watchdog for LLM streaming to prevent indefinite stuck states when providers are misconfigured or reject model combinations. It introduces a 30-second connect timeout that fires if no provider progress events arrive, while preserving the existing stream-idle timeout for cases where progress has already begun. The change includes new timeout constants, type extensions, event classification logic, iterator wrappers, expanded test mocks, and comprehensive unit and integration tests.

Changes

Connect-Timeout Watchdog for LLM Streaming

Layer / File(s) Summary
Timeout Configuration & Types
packages/opencode/src/session/llm.ts
Introduces CONNECT_STREAM_TIMEOUT_MS constant (30 s) and adds optional connectTimeoutMs?: number field to exported StreamInput type.
Timeout Control Flow
packages/opencode/src/session/llm.ts
Reworks timeout lifecycle to track provider-progress state and manage two phases: connect timeout (pre-progress, aborts on fire) and stream timeout (post-progress). Resets timeout per event based on progress classification.
Stream Wrapper & Event Classification
packages/opencode/src/session/llm.ts
Wraps fullStream iterator with failOnTimeout to race events against timeout-failure promises. Adds isProviderProgressEvent helper to classify stream events as progress (text, reasoning, tool, error) vs. non-progress (start only).
Test Mock Helpers
packages/opencode/test/session/llm.test.ts
Adds streamStartOnly() and streamProgressThenSilent() mock functions to simulate stalled providers after start or brief progress.
Unit Tests – Timeout Semantics
packages/opencode/test/session/llm.test.ts
Updates "silent stream timeout" test with new mock and connectTimeoutMs: 1_000; adds tests asserting connect-timeout failure, start-only events don't reset connect timer; updates "question blocker" test to expect failure with connectTimeoutMs.
Integration Test – SessionProcessor
packages/opencode/test/session/processor-effect.test.ts
Adds live test verifying low connectTimeoutMs with hanging LLM results in "stop" return, error on assistant message, error events published, and session idle.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

P1, upstream

Poem

🐰 A timeout's tick, a guardian's call,
Prevents the stuck, the endless hall,
When messages drift with nary a sound,
Connect awaits—then freedom's found!
✨ No more "thinking," just clear resolve. 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(opencode): fail stalled LLM connections before silent timeout' clearly and concisely describes the main change: adding an earlier timeout for stalled connections before the silent-stream timeout kicks in.
Description check ✅ Passed The PR description is comprehensive and follows the template well, covering summary, motivation, linked issue, review focus, risk notes, and verification steps with concrete test results.
Linked Issues check ✅ Passed The PR successfully implements the primary objective from #554: a 30s connect-timeout watchdog that fires if no provider progress arrives, causing the stream to fail rather than drain, enabling assistant error writing and session idle recovery.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the connect-timeout feature: LLM stream timeout logic, StreamInput configuration, and corresponding test coverage. No unrelated refactors, dependencies, or generated files are introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/llm-connect-timeout

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Astro-Han Astro-Han added bug Something isn't working P2 Medium priority app Application behavior and product flows harness Model harness, prompts, tool descriptions, and session mechanics labels May 11, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a dedicated connection timeout for LLM streams, distinct from the existing silent stream timeout. It adds a connectTimeoutMs configuration option and updates the streaming logic to track provider progress, applying the connection timeout until the first progress event is received. The implementation includes a new failOnTimeout utility to wrap async iterables and race them against timeout signals. Testing coverage is expanded with new cases for connection timeout failures and session status transitions. One review comment identifies a potential unhandled promise rejection when racing the stream iterator against the timeout, suggesting a catch handler for the iterator's next promise.

Comment thread packages/opencode/src/session/llm.ts Outdated

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opus second-pass review (product layer / three questions / five locks)

Conclusion: approve

Implementation stays inside the GPT-X-locked D shape: connect-phase timeout split from silent-stream timeout, allowlist-gated provider progress flag, force-failure path via failOnTimeout wrapper hitting processor.halt(). No drift into boot validation, no status reconcile watchdog, no churn on session.abort from PR #556.

Three questions

Could this be even less? 293 lines across llm.ts + 2 test files. Core change is ~70 lines (constant + state + failOnTimeout + isProviderProgressEvent); the rest is targeted tests. Promise.race(iterator.next(), timeoutFailure) plus double timeoutError() sync-check after the race is necessary to plug the race window between setTimeout firing and the next iterator pull resolving — cannot shrink without losing correctness. Check.

Is what remains good enough?

  • CONNECT_STREAM_TIMEOUT_MS = 30_000 default; connectTimeoutMs?: number is a test-only hook (not surfaced via config), matches GPT-X "no provider override in v1" red line.
  • isProviderProgressEvent allowlist excludes start and finish per GPT-X-tightened spec. Includes text-*, reasoning-*, tool-input-*, tool-call, tool-result, tool-error — only events that prove the provider is actually producing content/state.
  • failConnectTimeout() writes timeoutError, rejects the timeoutFailure promise, then calls ctrl.abort(). The failOnTimeout wrapper double-checks timeoutError() before AND after the Promise.race to plug the window where setTimeout fires concurrent with iterator.next() resolving. Stream throws → Effect.runDrain returns failure → processor.halt() triggers → assistant info.error written → session status flips to idle.
  • After first valid progress event, providerProgressed = true flips currentTimeoutMs() to streamTimeoutMs. Existing silent-stream timeout path (10min default) preserved.
  • Re-arm semantics during hasAwaitingQuestion preserved via the existing arm() re-entry — pending-question soft cancel from PR #556 is not broken.

Check.

Is it reassuring? Five-lock acceptance traced against tests:

  1. connect timeout produces stream failure not success drain — explicit test asserting Exit.isFailure(exit)).toBe(true) plus responseCanceled + requestAborted both fire. This is the lock GPT-X put hardest weight on; the test name is locked to the semantic to keep future maintainers honest.
  2. Processor writes info.error + flips status idle — covered by processor-effect.test.ts additions (+65 LOC). I did not deep-read those but the test names need to assert this chain explicitly; please confirm in engineering final.
  3. First progress event disarms connect timeout — covered indirectly by silent stream timeout cancels provider response body promptly rewritten to use waitProgressThenSilentStreamingRequest fixture: provider emits text-delta first, then goes silent, only streamTimeoutMs (20ms) fires, exit stays success.
  4. Awaiting question pauses connect timeout, fires failure after answer — covered by the reworked does not count awaiting question blockers as silent provider timeout test: connect timeout suspended for 90ms while awaiting, request not aborted; after answer, connect timeout fires and exit is failure. PR #556 soft-cancel pending-question semantic preserved.
  5. Live repro of alibaba-coding-plan-cn + glm-5 — flagged for manual verification in PR body. Not asserted in CI.

Findings

P3-1 (rename request, not blocking): The test does not count awaiting question blockers as silent provider timeout no longer matches its current behavior. The first half still asserts that awaiting-question re-arm prevents fire, but the second half now asserts that connect timeout DOES fire (as failure) after the answer is sent. Suggest renaming to connect timeout pauses during awaiting question and fires failure after answer once this PR lands, or splitting into two tests. Not a blocker — behavior is correct, name is the artifact lag.

P3-2 (style nit, not blocking): failOnTimeout wrapper's return() method calls void iterator.return?.().catch(() => {}) without awaiting. This is intentional to avoid hanging on a provider iterator that never resolves cleanup. Worth a one-line code comment noting the design intent: "abort signal is the real cancellation path; iterator.return() is best-effort protocol courtesy that we do not block on."

P3-3 (Gemini bot finding, defer to GPT-X engineering final): Gemini left an unresolved review thread suggesting void nextPromise.catch(() => {}) before the Promise.race to suppress unhandled-rejection warnings when the late AbortError lands after the timeout has already rejected. I think this is a legitimate small improvement (Node will log unhandled rejection warnings even when behavior is correct); GPT-X should weigh whether to fix in this PR or defer.

Approve

Pending GPT-X engineering final pass and Gemini thread resolution.

@Astro-Han Astro-Han force-pushed the fix/llm-connect-timeout branch from 67f8033 to 3614914 Compare May 11, 2026 12:50

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Engineering review: one P2 issue before I can pass this.

  • P2 packages/opencode/src/session/llm.ts:501: resetTimeout(event) currently clears and re-arms the timer for every fullStream event, even when isProviderProgressEvent(event) is false and providerProgressed is still false. That means start, finish, or any future unallowlisted housekeeping event can keep extending the connect timeout without any effective provider progress, which weakens the #554 contract and contradicts the explicit allowlist decision that start/finish do not count as progress.

    Suggested shape: before providerProgressed is true, ignore non-progress events for timer-reset purposes; after the first allowlisted progress event, continue resetting on every event to preserve the existing silent-stream timeout semantics.

    const progressed = isProviderProgressEvent(event)
    if (!providerProgressed && !progressed) return
    if (progressed) providerProgressed = true
    if (timeout) clearTimeout(timeout)
    arm()

    Please add a regression test showing a start-only or otherwise non-progress-only stream still fails on connectTimeoutMs without extending the timer.

The info.error + idle processor test is on the right layer, Gemini P3-3 is addressed, and the non-awaited return() cleanup is now documented. I will re-check after this timer-reset edge is patched.

@Astro-Han Astro-Han force-pushed the fix/llm-connect-timeout branch from 3614914 to 6295698 Compare May 11, 2026 12:59

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Engineering review pass for 6295698b5.

The previous P2 is addressed: connect-phase non-progress events no longer reset the connect timer, while post-progress events still reset the existing silent-stream timeout. The new start-only regression covers the important edge case.

Verified locally:

  • bun --cwd packages/opencode test test/session/llm.test.ts -t "timeout" --timeout 30000: 4 pass
  • bun --cwd packages/opencode test test/session/processor-effect.test.ts -t "connect timeout writes assistant info.error and flips session_status idle" --timeout 10000: 1 pass
  • bun --cwd packages/opencode typecheck: pass
  • git diff --check: pass

No unresolved review threads found. CI is still running on the latest SHA, so keep waiting for the required checks before merge. Non-blocking closeout note: the PR body verification counts should be refreshed for the added regression test (llm.test.ts now has 19 tests and the full opencode run reported 2708 pass).

Approve in body: the implementation now matches the #554 boundary and does not expand into boot validation, provider overrides, status watchdogs, or the #556 abort API.

@Astro-Han Astro-Han force-pushed the fix/llm-connect-timeout branch from 6295698 to 2ad4080 Compare May 11, 2026 13:10
@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Engineering review pass for the rewritten history at 2ad40808f.

Commit granularity now matches the PawWork rule: PR branch commits are review-sized and independently explainable, while dev can still use squash merge.

Commit review:

  • f89725343 fix(opencode): fail stalled llm connections before silent timeout: core implementation plus the minimal LLM failure-not-success-drain regression. Single fix intent.
  • b29832c22 test(opencode): cover llm connect timeout edge cases: LLM phase-boundary coverage for post-progress silent-stream behavior, start-only non-progress events, and awaiting-question re-arm. Single test-expansion intent.
  • 2ad40808f test(opencode): cover processor recovery after connect timeout: processor-level info.error + session_status idle recovery coverage. Single cross-layer regression intent.

Per-commit verification I reran by checkout:

  • f89725343: bun --cwd packages/opencode typecheck pass; bun --cwd packages/opencode test test/session/llm.test.ts -t "connect timeout produces stream failure not success drain" --timeout 30000 pass.
  • b29832c22: bun --cwd packages/opencode typecheck pass; bun --cwd packages/opencode test test/session/llm.test.ts -t "timeout" --timeout 30000 pass.
  • 2ad40808f: bun --cwd packages/opencode typecheck pass; bun --cwd packages/opencode test test/session/processor-effect.test.ts -t "connect timeout writes assistant info.error and flips session_status idle" --timeout 10000 pass; bun --cwd packages/opencode test test/session/llm.test.ts -t "timeout" --timeout 30000 pass.

Also checked git diff --check dev...HEAD: pass, and review threads remain resolved.

Non-blocking nit: the awaiting-question LLM test name still says "silent provider timeout" even though the behavior now covers connect timeout pausing during an awaiting question and firing after answer. The behavior is correct and this does not block merge.

CI is still running on the latest SHA, so wait for required checks before merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/opencode/src/session/llm.ts (1)

456-458: ⚡ Quick win

Suppress potential unhandled-rejection on timeoutFailure.

timeoutFailure is constructed at acquire time, but its rejection handler is only attached later when Promise.race([nextPromise, request.timeoutFailure]) runs inside next(). If failConnectTimeout resolves the rejection before the first next() is called (e.g., a very small connectTimeoutMs in tests, or a tight timing window between yielded events), Node may report an unhandled rejection warning and could terminate the process in stricter runtimes.

Attach a no-op catch at construction to make the promise always observed; the next() consumer still gets the rejection via Promise.race.

🛡️ Proposed fix
                 const timeoutFailure = new Promise<never>((_, reject) => {
                   rejectTimeout = reject
                 })
+                // Ensure the rejection is always observed even if no `next()` is in flight
+                // when the connect timeout fires (e.g., tight test timings).
+                void timeoutFailure.catch(() => {})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/session/llm.ts` around lines 456 - 458, The
timeoutFailure Promise created alongside rejectTimeout can reject before any
consumer attaches handlers (in next()), causing unhandled-rejection warnings;
update the construction of timeoutFailure (and the place that assigns
rejectTimeout) to attach a no-op catch handler (e.g., timeoutFailure.catch(() =>
{})) immediately after creation so rejections are always observed while still
allowing next() to race on request.timeoutFailure and receive the rejection;
locate the timeoutFailure and rejectTimeout variables in the acquire/create
block and add the catch there, leaving next(), failConnectTimeout, and
Promise.race logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/opencode/src/session/llm.ts`:
- Around line 456-458: The timeoutFailure Promise created alongside
rejectTimeout can reject before any consumer attaches handlers (in next()),
causing unhandled-rejection warnings; update the construction of timeoutFailure
(and the place that assigns rejectTimeout) to attach a no-op catch handler
(e.g., timeoutFailure.catch(() => {})) immediately after creation so rejections
are always observed while still allowing next() to race on
request.timeoutFailure and receive the rejection; locate the timeoutFailure and
rejectTimeout variables in the acquire/create block and add the catch there,
leaving next(), failConnectTimeout, and Promise.race logic unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 883c7d2b-f380-41b7-a8c9-f31eb6601bf1

📥 Commits

Reviewing files that changed from the base of the PR and between dc1e9b8 and 2ad4080.

📒 Files selected for processing (3)
  • packages/opencode/src/session/llm.ts
  • packages/opencode/test/session/llm.test.ts
  • packages/opencode/test/session/processor-effect.test.ts

@Astro-Han Astro-Han force-pushed the fix/llm-connect-timeout branch from 2ad4080 to 8c8b285 Compare May 11, 2026 13:18
@Astro-Han Astro-Han force-pushed the fix/llm-connect-timeout branch from 8c8b285 to 37b587d Compare May 11, 2026 13:23

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Engineering re-check pass for 37b587daa after the CodeRabbit nitpick fix.

Confirmed the no-op catch was fixuped into commit 1 and preserves the original timeout promise for Promise.race([nextPromise, request.timeoutFailure]); it only observes early rejection warnings. The earlier nextPromise.catch(() => {}) remains in place. Commit 2 also now has the corrected awaiting-question test name.

Verified locally:

  • On commit a4cd01b50: bun --cwd packages/opencode typecheck pass; bun --cwd packages/opencode test test/session/llm.test.ts -t "connect timeout produces stream failure not success drain" --timeout 30000 pass.
  • On PR HEAD 37b587daa: bun --cwd packages/opencode test test/session/llm.test.ts --timeout 30000: 19 pass; git diff --check dev...HEAD: pass; worktree clean.

No engineering blockers from GPT-X. Wait for CI to finish before merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows bug Something isn't working harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Stuck '思考中' state when provider/model is misconfigured (no connect timeout)

1 participant