Skip to content

perf(site): fix compiler memoization gap in AgentDetailInput#23683

Merged
mafredri merged 1 commit intomainfrom
mafredri/perf-agentdetailinput-compiler-memoization
Mar 26, 2026
Merged

perf(site): fix compiler memoization gap in AgentDetailInput#23683
mafredri merged 1 commit intomainfrom
mafredri/perf-agentdetailinput-compiler-memoization

Conversation

@mafredri
Copy link
Copy Markdown
Member

@mafredri mafredri commented Mar 26, 2026

Why

In AgentDetailInput, the React Compiler failed to memoize the messages
derivation chain (orderedMessageIDs.map().filter() and
getLatestContextUsage(messages)). Two source patterns prevented the
compiler from grouping them into a single cache guard:

  1. A useDashboard() hook call between the messages computation and its
    consumer (getLatestContextUsage). Hooks must be called unconditionally,
    so the compiler cannot wrap non-hook computations in a conditional guard
    when a hook sits between them.

  2. An IIFE around the context usage logic, which the compiler lowers into a
    bb0: block with break, fragmenting the dependency chain.

The identical pattern in AgentDetailTimeline (same file) compiled
correctly because its derivation chain has no hook calls or IIFEs between
steps.

Fix

Replace the IIFE with a ternary and reorder the non-hook computation
(rawUsage, latestContextUsage) before the useDashboard() call. This
lets the compiler group the entire chain into one cache guard keyed on
messagesByID and orderedMessageIDs.

Proof

Cache guard simulation test in chatHelpers.test.ts measures guard miss
counts across 10 renders with stable message data:

Guard strategy Misses (10 renders)
Before (no guard on messages chain) 10/10
After (guard on messagesByID + orderedMessageIDs) 0/10

The test first proves the precondition: getLatestContextUsage always
returns a fresh object reference even when values are identical. Without the
compiler guard, every render produces a new rawUsage ref, which cascades
into a new latestContextUsage, which misses the 34-dep AgentChatInput
JSX guard.

Compiled output confirms the guard structure:

// AFTER: messages + getLatestContextUsage inside guard
if ($[0] !== messagesByID || $[1] !== orderedMessageIDs) {
    const messages = orderedMessageIDs.map(t3).filter(isChatMessage);
    t2 = getLatestContextUsage(messages);
}
// latestContextUsage spread in separate guard
if ($[5] !== compressionThreshold || $[6] !== rawUsage) {
    t3 = rawUsage ? { ...rawUsage, compressionThreshold } : rawUsage;
}

🤖 This PR was created with the help of Coder Agents, and will be reviewed by a human. 🏂🏻

@mafredri mafredri force-pushed the mafredri/perf-agentdetailinput-compiler-memoization branch 2 times, most recently from 6c278bf to 2c71222 Compare March 26, 2026 17:42
@mafredri mafredri marked this pull request as ready for review March 26, 2026 18:04
Copy link
Copy Markdown
Contributor

@DanielleMaywood DanielleMaywood left a comment

Choose a reason for hiding this comment

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

I don't think we need to merge the test

The React Compiler failed to memoize the messages derivation
chain because a useDashboard() hook call sat between the
messages computation and its consumer (getLatestContextUsage).
An IIFE around the context usage logic also fragmented the
dependency chain.

Replacing the IIFE with a ternary and reordering the non-hook
computation before the hook call lets the compiler group
messages + getLatestContextUsage into a single cache guard
keyed on messagesByID and orderedMessageIDs.
@mafredri mafredri force-pushed the mafredri/perf-agentdetailinput-compiler-memoization branch from 2c71222 to 6c27fb2 Compare March 26, 2026 18:21
@mafredri mafredri enabled auto-merge (squash) March 26, 2026 18:23
@mafredri mafredri merged commit 94e5de2 into main Mar 26, 2026
26 of 27 checks passed
@mafredri mafredri deleted the mafredri/perf-agentdetailinput-compiler-memoization branch March 26, 2026 18:30
@github-actions github-actions bot locked and limited conversation to collaborators Mar 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants