Skip to content

fix(web): harden session diffs handling and support local asset override#19266

Open
codeg-dev wants to merge 4 commits intoanomalyco:devfrom
codeg-dev:fix/surrogate-json-escape
Open

fix(web): harden session diffs handling and support local asset override#19266
codeg-dev wants to merge 4 commits intoanomalyco:devfrom
codeg-dev:fix/surrogate-json-escape

Conversation

@codeg-dev
Copy link
Copy Markdown

@codeg-dev codeg-dev commented Mar 26, 2026

Issue for this PR

Closes #19268

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

This PR fixes a web crash where session review paths called .map() on non-array diff payloads (summary.diffs, session_diff).

It adds Array.isArray normalization at all UI entrypoints that consume diffs, and adds an optional server-side local asset override (OPENCODE_APP_DIST) so operators can serve patched web bundles when CDN chunks are stale.

How did you verify your code works?

  • bun turbo typecheck
  • bun test test/provider/sanitize-surrogates.test.ts (packages/opencode)
  • bun run build (packages/opencode)
  • LSP diagnostics clean for packages/opencode/src/server/server.ts
  • Live deployment validation on codeg-fob: served index-DSTRUJlB.js and session-CDIAwBxQ.js with Array.isArray guards present

Screenshots / recordings

N/A

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@codeg-dev codeg-dev requested a review from adamdotdevin as a code owner March 26, 2026 10:04
@github-actions github-actions bot added needs:compliance This means the issue will auto-close after 2 hours. needs:issue labels Mar 26, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search, I found one related PR:

PR #19221: fix(app): guard diffs with Array.isArray to prevent .map crash

Why it's related: This PR addresses the same core issue - protecting against crashes when .map() is called on diffs that might not be arrays. While PR #19266 (current PR) appears to be a more comprehensive fix that also includes the asset override feature, PR #19221 tackles the same defensive diff handling problem.

I also found PR #19261 (fix: add defensive checks for undefined values in diff handling) which may be tangentially related to the diffs handling aspect.

@github-actions github-actions bot removed needs:compliance This means the issue will auto-close after 2 hours. needs:issue labels Mar 26, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@codeg-dev
Copy link
Copy Markdown
Author

Code review

Found 1 issue:

  1. In OPENCODE_APP_DIST mode, non-file SPA routes (for example /session/<id>) fall through to CDN proxy instead of local index.html fallback. This keeps a hidden dependency on app.opencode.ai and breaks fully-local recovery behavior when CDN is unavailable.
    const appDist = process.env.OPENCODE_APP_DIST
    if (appDist) {
    const filePath = path === "/" || path === "" ? "/index.html" : path
    const localFile = Bun.file(appDist + filePath)
    const exists = await localFile.exists()
    if (exists) {
    const content = await localFile.arrayBuffer()
    const mimeType = (() => {
    if (filePath.endsWith(".js")) return "text/javascript;charset=UTF-8"
    if (filePath.endsWith(".css")) return "text/css;charset=UTF-8"
    if (filePath.endsWith(".html")) return "text/html;charset=UTF-8"
    if (filePath.endsWith(".svg")) return "image/svg+xml"
    if (filePath.endsWith(".png")) return "image/png"
    if (filePath.endsWith(".ico")) return "image/x-icon"
    if (filePath.endsWith(".json")) return "application/json"
    if (filePath.endsWith(".woff2")) return "font/woff2"
    if (filePath.endsWith(".woff")) return "font/woff"
    if (filePath.endsWith(".aac")) return "audio/aac"
    return "application/octet-stream"
    })()
    const headers: Record<string, string> = {
    "Content-Type": mimeType,
    "Content-Security-Policy":
    "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:",
    }
    if (filePath === "/index.html") {
    headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
    } else if (filePath.startsWith("/assets/")) {
    headers["Cache-Control"] = "max-age=31536000, public, immutable"
    }
    return new Response(content, { headers })
    }
    }
    const response = await proxy(`https://app.opencode.ai${path}`, {
    ...c.req,

🤖 Generated with OpenCode

…gling tool_use blocks

When a retryable error (rate limit, timeout) occurs mid-stream while tool calls
are in pending/running state, the previous continue statement skipped the cleanup
at the end of the while loop. This left tool parts in pending/running state in the
DB. On the next request, these orphaned parts could produce tool_use blocks without
corresponding tool_result blocks, causing Anthropic API error:
'tool_use ids were found without tool_result blocks immediately after'.

Fix: run tool cleanup before the continue so pending/running parts are converted
to error state even on retry. The retry will generate new tool call IDs, so old
stale parts must be marked as error to maintain valid tool_use/tool_result pairing.

Ref: upstream issues anomalyco#16749, anomalyco#10616
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web mode crash when session diffs payload is non-array

1 participant