Skip to content

Cut streaming render cost - #1101

Open
ecokayiza wants to merge 5 commits into
ChatGPTBox-dev:masterfrom
ecokayiza:feat/streaming-render-perf
Open

ecokayiza wants to merge 5 commits into
ChatGPTBox-dev:masterfrom
ecokayiza:feat/streaming-render-perf

Conversation

@ecokayiza

@ecokayiza ecokayiza commented Oct 3, 2026 •

Copy link
Copy Markdown

Splits part of #1084 into a focused PR, as requested there. Based on the latest master.

What this does

A streamed answer arrives as a series of cumulative snapshots and every snapshot re-rendered the whole answer, so a long reply re-parsed from the top on each chunk. Two independent fixes to that:

1. Coalesce streamed chunks (answer-buffer.mjs). A burst renders once per animation frame instead of once per chunk, and the newest text is always flushed before the answer is finalized. Buffered frames are dropped when the card unmounts, is cleared, or starts a new question, so a stale frame cannot resurrect an old answer. The buffer falls back to a timer where the host has no animation frames (jsdom and other headless renderers), which is what lets upstream's lifecycle tests keep working.

2. Narrow syntax auto-detection (highlight-options.mjs). detect: true compiles every registered grammar the first time it runs; restricting the scan to a common-language subset keeps auto-detection and drops that first-use cost. Explicitly labelled blocks are unaffected.

Measured on a 394-character answer delivered as 19 chunks of 20 characters:

  • First code block on a cold page: ~132 ms before, ~4 ms after.
  • A burst: 48.6 ms of CPU over 19 renders before, 11.0 ms over 6 after.
  • A slow stream (60 ms per chunk): 48.6 ms before, 29.6 ms after.

Addresses #265.

Tests

  • tests/unit/components/answer-buffer.test.mjs — the buffer contract against a fake frame clock, plus the frame-scheduler fallback.
  • tests/unit/components/highlight-options.test.mjs — the detection subset only narrows auto-detection, labelled blocks unaffected.
  • tests/unit/components/conversation-card-lifecycle.test.mjs (existing) — still green, which is what exercises the timer fallback.

Validation

  • npm test — 1101 passing.
  • npm run lint — clean.
  • npm run build — all four variants build; expected artifacts present in build/chromium/.

Validation skipped: manual browser testing — no browser automation is available here. A smoke test would stream a long answer with a code block and check that it renders smoothly without a first-block stall.

Review in cubic

Summary by CodeRabbit

  • Improvements
    • Streamed answers now update in smoother, frame-paced batches. Pending text appears when a response completes, errors, or the connection drops, and is discarded when a new question starts, a response is retried, the conversation or session is reset, or the view closes.
    • Markdown code blocks now support automatic highlighting for a selected set of languages. Explicitly labelled languages outside that set are also highlighted, while unknown labels remain readable as plain text.

A streamed answer arrives as a series of cumulative snapshots and every
snapshot re-rendered the whole answer, so a long reply re-parsed from the top
on each chunk. Coalesce the chunks into one render per animation frame
(`answer-buffer.mjs`) and always flush the newest text before the answer is
finalized. Buffered frames are dropped when the card unmounts, is cleared, or
starts a new question, so a stale frame cannot resurrect an old answer. The
buffer falls back to a timer where the host has no animation frames (jsdom and
other headless renderers), which keeps the lifecycle tests working.

Syntax auto-detection is limited to a common-language subset in
`highlight-options.mjs`. `detect: true` compiles every registered grammar on
first use; narrowing the scan keeps auto-detection and drops that cost.
Explicitly labelled blocks are unaffected.

Measured on a 394-character answer delivered as 19 chunks of 20 characters:

- First code block on a cold page: ~132 ms before, ~4 ms after.
- A burst: 48.6 ms of CPU over 19 renders before, 11.0 ms over 6 after.
- A slow stream (60 ms per chunk): 48.6 ms before, 29.6 ms after.
Copilot AI balanced review requested due to automatic review settings October 3, 2026 10:04

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps greptile-apps 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (1)
AGENTS.md — auto-discovered

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8deca3a5-58f4-4a07-8940-abcffcb4fc61
📥 Commits

Reviewing files that changed from the base of the PR and between 7d73b32 and e3f81bf.

📒 Files selected for processing (3)
  • src/components/ConversationCard/index.jsx
  • src/components/MarkdownRender/highlight-options.mjs
  • tests/unit/components/conversation-card-lifecycle.test.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/MarkdownRender/highlight-options.mjs

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Conversation cards now buffer streamed answers and schedule updates through animation frames or timers. They flush or discard pending text at specified lifecycle events. Both Markdown renderers use shared highlighting options, with tests covering answer buffering and language highlighting.

Changes

Streamed Answer Buffering

Layer / File(s) Summary
Frame scheduler and answer buffer
src/components/ConversationCard/answer-buffer.mjs, tests/unit/components/answer-buffer.test.mjs
The scheduler uses animation-frame functions when available and a timer fallback otherwise. The buffer renders the latest pending answer once per scheduled frame and supports immediate flush and discard. Tests cover scheduling, flushing, and discarding.
Conversation card streaming and lifecycle
src/components/ConversationCard/index.jsx, tests/setup/conversation-card-lifecycle-loader-hooks.mjs, tests/unit/components/conversation-card-lifecycle.test.mjs
Conversation cards buffer streamed messages. They flush pending content on completion, error, and transport disconnect. They discard pending content on unmount, retry, conversation clear, new-question submission, and session initialization. Lifecycle tests cover buffering, completion, question changes, and disconnects.

Markdown Highlighting

Layer / File(s) Summary
Shared highlighting configuration and renderer use
src/components/MarkdownRender/highlight-options.mjs, src/components/MarkdownRender/markdown.jsx, src/components/MarkdownRender/markdown-without-katex.jsx, tests/unit/components/highlight-options.test.mjs
Both Markdown renderers use shared rehypeHighlight options. Tests cover detected languages, explicitly labelled languages outside the detection subset, and unknown labels.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant ConversationCard
  participant AnswerBuffer
  participant FrameScheduler
  ConversationCard->>AnswerBuffer: Push streamed answer
  AnswerBuffer->>FrameScheduler: Schedule render callback
  FrameScheduler-->>AnswerBuffer: Invoke callback
  AnswerBuffer->>ConversationCard: Render latest pending answer
Loading

Suggested reviewers: peterdavehello

Merge Risk: ⚪ Minimal · up to e3f81

The change batches streamed answer rendering and shares the Markdown highlighting options. No concrete merge-blocking issue was identified, and the reported tests, lint, and build pass.

Security Architecture Review

Security architecture risk: 🔵 Low · up to e3f81

The changes remain within conversation rendering and card-owned transport cleanup. No new privileges or external entrypoints were identified. Remaining uncertainty concerns callback timing during unmount and provider-specific interruption behavior, rather than a demonstrated security regression.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed scheduling state is confined to an individual conversation card. Provider-supplied text continues toward the existing Markdown renderer; the buffer does not acquire credentials, dispatch provider requests, or introduce a cross-card data route.

Trust Boundaries and Controls

  • observed — Foreground callbacks carry their captured request identity and reject disconnected or disposed transports. After asynchronous credential retrieval, the card checks disposal, disconnection, and request identity before starting the provider.

Resilience and Maintainability Implications

  • observed — Disconnect invokes the provider’s abort controller, and explicit foreground stop finalizes through the card’s completion handler. Buffer cancellation occurs in passive cleanup, separately from layout-time transport disposal; the inspected tests do not establish every production interleaving between those operations.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 9 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: reducing render cost by batching streamed answer updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Reduce streaming answer render and syntax-detection costs

✨ Enhancement 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Coalesce streamed answer snapshots per frame while preserving the latest text at completion.
• Limit syntax auto-detection to common languages to reduce cold code-block rendering cost.
• Test buffer lifecycle, scheduler fallback, and highlighting behavior.
Diagram

graph TD
  Stream["Answer stream"] --> Card["Conversation card"] --> Buffer["Answer buffer"] --> Markdown["Markdown renderers"] --> View["Rendered answer"]
  Options["Highlight options"] --> Markdown
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Incremental Markdown rendering
  • ➕ Could avoid re-parsing unchanged text even during slow streams.
  • ➖ Substantially more complex around incomplete Markdown and changing code blocks.
  • ➖ Would not independently remove the cold auto-detection cost.

Recommendation: Keep the focused frame buffer and shared highlighting subset. They address burst renders and cold grammar compilation without the parsing and correctness risks of incremental rendering.

Files changed (7) +330 / -24

Enhancement (5) +129 / -24
answer-buffer.mjsAdd a frame-coalesced answer buffer +71/-0

Add a frame-coalesced answer buffer

• Keeps only the newest pending snapshot, with flush and discard operations for completion and lifecycle transitions. Uses animation frames where available and a timer otherwise.

src/components/ConversationCard/answer-buffer.mjs

index.jsxBuffer streamed answers in the conversation card +20/-1

Buffer streamed answers in the conversation card

• Queues answer snapshots instead of rendering every chunk, flushes pending text on completion or error, and discards it on unmount, retry, deletion, or a new question.

src/components/ConversationCard/index.jsx

highlight-options.mjsDefine shared, narrower syntax detection +34/-0

Define shared, narrower syntax detection

• Limits automatic language detection to common grammars while retaining highlighting for explicitly labelled blocks and existing missing-language behavior.

src/components/MarkdownRender/highlight-options.mjs

markdown-without-katex.jsxUse shared highlighting options without KaTeX +2/-11

Use shared highlighting options without KaTeX

• Replaces inline rehype-highlight settings with the shared options, applying the narrower auto-detection subset.

src/components/MarkdownRender/markdown-without-katex.jsx

markdown.jsxUse shared highlighting options with KaTeX +2/-12

Use shared highlighting options with KaTeX

• Replaces inline rehype-highlight settings with the shared options while retaining the existing KaTeX and Markdown plugins.

src/components/MarkdownRender/markdown.jsx

Tests (2) +201 / -0
answer-buffer.test.mjsTest answer coalescing and scheduler behavior +139/-0

Test answer coalescing and scheduler behavior

• Covers latest-snapshot rendering, subsequent frames, flush and discard behavior, native animation frames, and the timer fallback.

tests/unit/components/answer-buffer.test.mjs

highlight-options.test.mjsTest narrowed detection without losing labelled highlighting +62/-0

Test narrowed detection without losing labelled highlighting

• Checks auto-detection within the subset, highlighting for a labelled language outside it, and safe handling of unknown labels.

tests/unit/components/highlight-options.test.mjs

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 7 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread src/components/ConversationCard/index.jsx
Comment thread src/components/ConversationCard/answer-buffer.mjs
Comment thread tests/unit/components/answer-buffer.test.mjs

@pullfrog pullfrog 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.

ℹ️ No critical issues — two low-stakes notes below.

Reviewed changes

  • Streamed-chunk coalescing — new src/components/ConversationCard/answer-buffer.mjs buffers cumulative answer snapshots and renders at most once per animation frame, with a setTimeout(…, 16) fallback when the host lacks requestAnimationFrame (jsdom/headless). ConversationCard flushes before done/error, discards on retry/clear/new-question/unmount, and stays stateless via updateAnswer's functional updater.
  • Narrowed syntax auto-detection — new src/components/MarkdownRender/highlight-options.mjs adds a 19-language subset to rehype-highlight; both markdown.jsx and markdown-without-katex.jsx share it. Labelled blocks are unaffected.
  • Tests — answer-buffer.test.mjs pins push/flush/discard and both scheduler paths; highlight-options.test.mjs covers the detection subset plus labelled and unknown languages.

ℹ️ Auto-detection no longer covers several common unlabelled languages

The new subset deliberately narrows highlightAuto, but the excluded set includes widely used grammars: diff, shell, markdown, ini, makefile, scss, graphql, r, perl, lua, objectivec, vbnet, wasm, less, arduino, and php-template. Unlabelled code in those languages (e.g. an assistant reply with a bare diff block) will now render unhighlighted. Explicitly fenced blocks are unaffected — verified against rehype-highlight@6.0.0/lib/index.js, where labelled blocks dispatch to lowlight.highlight(lang, …) and only unlabelled blocks call lowlight.highlightAuto(…, { subset }). Likely intended, but flagging it as a user-visible change beyond the render-cost goal.

ℹ️ Nitpicks

  • src/components/ConversationCard/index.jsx:189 resets partialAnswerRef/retryRecordRef in the props.question effect without the answerBufferRef.current.discard() that the other three reset sites now call. Not reachable with the current callers (a card is mounted fresh per question), but the asymmetry is easy to align.
  • The new flush-on-done/error and discard-on-retry wiring has no integration coverage — conversation-card-lifecycle.test.mjs never drives the port listener with answer/done, so the wiring is exercised only by the isolated buffer unit test.

Pullfrog  | Fix it ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

The detection subset was meant to avoid compiling every grammar on first
use, but it dropped languages that show up unlabelled in answers. A
`diff` block rendered as `css`, `lua` as `sql`, `ini` as `csharp`, and
`markdown` and `perl` as `bash`.

Use lowlight's registered set minus the entries that only mislead
detection: `shell` (a `bash` alias), `plaintext`/`python-repl`/
`php-template` (not useful for detection), and `arduino`/`objectivec`/
`vbnet`/`wasm` (rare in answers, and they win ambiguous `c`, `cpp`, `ini`
and `sql` matches away). Keep lowlight's registration order, because
`highlightAuto` settles equal-relevance candidates by subset order.

On the sampled answers detection now matches or beats the full set while
still compiling well under half the grammars.
The `props.question` effect reset the partial answer but left the answer
buffer alone, so a frame queued by the previous answer could render after
the new question started. `FloatingToolbar` and `DecisionCard` reuse the
card for a new question, so the path is reachable.

Also cover the wiring the unit tests missed: a burst stays buffered until
completion flushes it, switching the question drops the previous answer,
and the scheduler's timer fallback cancels a pending frame.
Copilot AI balanced review requested due to automatic review settings October 3, 2026 10:35

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps greptile-apps 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@ecokayiza

Copy link
Copy Markdown
Author

Followed up on the review findings, in two commits on top of a3af35a.

1. Auto-detection keeps the common languages — 815a075

The subset was dropping more than it looked: an unlabelled diff block rendered as css, lua as sql, ini as csharp, and markdown/perl as bash. The subset is now lowlight's registered set minus the entries that only mislead detection:

  • shell — a bash alias
  • plaintext, python-repl, php-template — not useful for detection
  • arduino, objectivec, vbnet, wasm — rare in answers, and they win ambiguous c, cpp, ini and sql matches

It stays in lowlight's registration order because highlightAuto settles equal-relevance candidates by subset order. Over 31 sampled unlabelled snippets: 20/31 correct, versus 17/31 for the full registered set and 14/31 for the original subset (measured with the pinned lowlight 2.9.0). Tests now pin diff, markdown and lua.

2. Buffered frames are dropped on a question switch — f2fae2f

Good catch — FloatingToolbar and DecisionCard reuse the card for a new question, so the props.question effect now calls discard() like the other reset paths.

3. Coverage for the wiring — in f2fae2f

  • a burst stays buffered until completion flushes it (fails without the flush() on done)
  • switching the question drops the previous answer (fails without the new discard())
  • the scheduler's timer fallback cancels a pending frame

4. rAF on hidden pages — left as is. done, error and the stop path all flush synchronously, so the only remaining case is a port disconnect while the tab is hidden. Worth a follow-up if it ever shows up, but I did not want to add a second timer path for it.

Validation: npm test 1105 passing, npm run lint clean, npm run build all four variants with the expected build/chromium/ artifacts. Manual browser smoke testing is still skipped (no browser automation available here).

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

Re-reviewed the two commits added since the prior pullfrog review at a3af35a. Both directly address the low-stakes notes from that review, and no new issues surfaced.

  • Discard buffered frames when the question switches — the props.question effect in ConversationCard/index.jsx now calls answerBufferRef.current.discard(), aligning the last reset site with the retry, clear, new-question, and unmount paths.
  • Restore common languages to the auto-detection subset — highlight-options.mjs scans 29 grammars again, adding back diff, graphql, ini, less, lua, makefile, markdown, perl, r, and scss. Only shell, plaintext, python-repl, php-template, arduino, objectivec, vbnet, and wasm stay excluded, each with a documented rationale.
  • Integration coverage for the buffer wiring — conversation-card-lifecycle.test.mjs now drives the port listener, asserting a burst stays buffered until done flushes it and that switching questions drops a stale buffered answer. answer-buffer.test.mjs adds a timer-fallback cancellation case, and the highlight test adds exact auto-detection assertions for diff, markdown, and lua.

I verified the subset ordering claim against lowlight@2.9.0's common registration order (the 29 names are a subsequence in the same order) and confirmed the three touched suites pass locally (node --test, 30 passing).

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

A stream can end without a `done`/`error` message: an extension reload, a
background crash or a dropped port. The buffered chunk then waited for the
next animation frame, which never runs on a hidden page, so the card kept a
stale answer until the tab became visible.

Flush before reconnecting so the newest chunk renders synchronously either
way. A lifecycle test drops the port mid-stream and asserts the chunk is
rendered before the replacement Port is used.
Copilot AI balanced review requested due to automatic review settings October 3, 2026 10:39

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps greptile-apps 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

Re-reviewed the single commit added since the prior pullfrog review at f2fae2f (one source file plus one test).

  • Flush the answer buffer when the transport drops — ConversationCard/index.jsx's portListener now calls answerBufferRef.current.flush() before reconnecting, so the newest buffered chunk renders synchronously even on a hidden page where animation frames are paused. It runs after the existing replacedPortRef/disposedRef guards, so clear-conversation, port supersession, and unmount still discard rather than resurrect a stale buffer.
  • Integration coverage for the dropped-transport path — the lifecycle suite's new test drives a chunk through the port, asserts it stays buffered, then triggers a remote disconnect and asserts the chunk rendered synchronously and a replacement port was created. Verified it fails (17/18) with the flush removed and passes (18/18) with it; the full conversation-card-lifecycle.test.mjs run is 18/18.

This directly addresses the earlier non-Pullfrog concern that a stream ending via onDisconnect (no done/error) left the newest chunk pending until the next animation frame.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread src/components/ConversationCard/index.jsx Outdated
Comment thread src/components/MarkdownRender/highlight-options.mjs Outdated
A runtime Port that drops mid-generation is replaced, but a foreground
generation (Bing web) streams through its own transport and only uses this Port
as a keepalive. Flushing the buffer and calling setIsReady(true) here finalized
that answer early and unlocked sending while chunks were still arriving, so
guard both behind "no foreground generation is in flight".

The highlight subset note also described `shell` as a `bash` alias; it is the
Shell Session console-prompt grammar, and `bash` only aliases `sh`/`zsh`.
Copilot AI balanced review requested due to automatic review settings October 3, 2026 16:10

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps greptile-apps 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 3 files (changes from recent commits).

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread tests/unit/components/conversation-card-lifecycle.test.mjs

@pullfrog pullfrog 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.

ℹ️ No critical issues — one minor comment-accuracy suggestion inline.

Reviewed changes

Re-reviewed the single commit added since the prior pullfrog review at 7d73b32.

  • Keepalive Port drop no longer unlocks sending during a foreground generation — portListener now gates answerBufferRef.current.flush() and setIsReady(true) on foregroundPortsRef.current.size === 0, so a keepalive Port drop while a Bing-web foreground stream is in flight neither renders an intermediate partial nor re-enables the input. The fakePort is added at generation start and removed in finally, so the guard tracks "foreground generation in flight" exactly; background mode keeps an empty set and behaves as before, and the foreground stream's own done/error still flush and unlock.
  • Corrected the shell auto-detection rationale — the comment now identifies shell as the Shell Session console-prompt grammar rather than a bash alias, addressing the earlier inaccuracy.
  • Integration coverage — new lifecycle test asserts sending stays locked when the keepalive Port drops mid-foreground-generation, which fails against the pre-e3f81bf unconditional setIsReady(true).

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/components/MarkdownRender/highlight-options.mjs
@ecokayiza

Copy link
Copy Markdown
Author

Review follow-up complete.

  • Every review thread is replied to and resolved (7/7).
  • Two late findings verified as non-issues, replied inline:
    • conversation-card-lifecycle P3: npm run pretty:check passes, and re-running Prettier with the repo config reproduces the file byte-for-byte, so it keeps that line as written.
    • highlight-options alias nit: package-lock.json resolves highlight.js to 11.11.2, where bash.aliases === ['sh','zsh']; the ['sh'] list only applies to 11.8.0, so the comment is accurate as written.
  • Local validation on e3f81bfe: npm test 1107 pass / 0 fail, npm run lint clean, npm run build green (4 variants + zips).

CI note: the format-lint and pr-tests workflow runs show action_required - on a fork PR they wait for maintainer approval - so the check list stays pending until approved.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants