Skip to content

perf(think,sessions): stop re-reading the transcript during a turn - #2219

Open
mattzcarey wants to merge 1 commit into
mainfrom
perf/think-transcript-reads
Open

perf(think,sessions): stop re-reading the transcript during a turn#2219
mattzcarey wants to merge 1 commit into
mainfrom
perf/think-transcript-reads

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

What

Think stops reading the transcript during a turn.

A long Think turn used to read the whole persisted history 2 + T times, where T is the number of tool updates in the turn (client results, approvals, cross-message results from approved server tools, execution outcomes). Each read walks the sized path query (several billed rows per message for the byte subqueries) and then hydrates every row. With a 400-message transcript and 20 tool updates that is on the order of 10k billed row reads for a turn whose stream log writes about 30 rows.

Four changes, all on the read side. Nothing about what is durable, or when, moves.

  1. A tool update resolves its one target row from memory. _applyToolUpdateToMessages no longer calls session.getHistory(). _resolveToolCallOwner asks the in-flight accumulator first (a row under its id exists only when stall recovery persisted a partial), then the live cache for the owner's id, and reads that row alone. The apply is still a first-write-wins read-modify-write of the stored form, so Tool part state regresses during client tool round-trip; continuation starts but emits no output #1404 replays still write nothing and _scheduleAutoContinuation 50ms timer fires before all parallel client-tool results arrive → MissingToolResultsError #1649 mid-stream results still reach both the accumulator and the row. Storage is scanned only when the cache does not cover the active path (a windowed hydration or a failed boot hydration), and then newest first, stopping at the owner.

  2. A chat request reconciles against the cache. _reconcileAndPersistIncoming uses this.messages as the server transcript when the cache covers the path, skips echoed messages whose stored form is already what the server holds (the client posts its whole transcript every request; each echoed message used to cost Sessions an existence read plus a full-row compare), and no longer re-reads the path after the writes. The change feed already patched the cache for every write. A windowed cache keeps the old reads.

  3. Media eviction is gated from memory and armed by appends. Every cache refresh used to arm a pass whose first act is a content-free scan of the whole stored path. The gate now runs on each linear append (the event that ages older messages) and schedules a pass only when an aged cached message still carries an inline payload (hasEvictableMedia), or, when aged rows are not all in memory, once per distinct stored size.

  4. Two per-call costs become per-isolate. think_config writes of an unchanged request body or client-tool schemas are skipped, and the agent-tool child-run DDL (two CREATE IF NOT EXISTS plus three ALTER attempts that throw and are swallowed) runs once per isolate instead of before every milestone, progress snapshot and child-run read.

Sessions gains the read shape Think needs: session.history({ newestFirst: true }) streams the active path leaf → root by following parent pointers, paying one row per message the consumer takes. Compaction overlays are honored without planning them up front: an overlay that applies ends at a row the walk reaches before anything it covers, so the walk stays row-by-row until it lands on a compaction's end, then plans the remaining prefix by id and streams it overlay-collapsed in eight-row windows. A lookup that stops in the messages after the last compaction never pays for that.

Sessions also reports two writes the change feed used to hide: import (one per row importMessage() actually writes) and compaction (an overlay stored through addCompaction()). Think marks its cache stale on import and refreshes on compaction, so a host cache can no longer claim to cover a path that changed underneath it. compact() still reports compact.

Two guards keep the cache honest over a long-lived isolate. Appends are charged against the hydration budget measured at the last refresh, and once they would carry the cache past it the cache stops claiming to cover the path, so the next boundary re-reads and re-windows (#1710). And the eviction gate treats compaction overlays like a windowed hydration: rows collapsed under an overlay are not in the cache, so a compacted session gets one content-free pass per distinct stored size rather than none.

Measured

Billed rows, real Durable Object SQLite, pinned in tests.

Operation Before After
Find a tool call's owner three messages from the leaf, 200-message path (Sessions bench) 1801 rows read (getHistory) < 12 rows read (history({ newestFirst }))
One client tool result applied, 12-message vs 160-message transcript (Think) grows with the transcript identical, < 20 rows read
Turn start with the client echoing 12 vs 160 messages plus one new user message (Think) grows with the transcript identical, < 10 rows read, 1 row written

The Think numbers come from a rowsRead/rowsWritten counter on the test agent's ctx.storage.sql.exec, the same accounting the streams and sessions benches use.

Not in this PR

  • The recovery progress counter still does a KV get + put per credited chunk (two per tool call, one per text/reasoning segment start, one per 5 s of deltas). Deriving it from the stream log's tail, or crediting on flush, changes a persisted contract shared with @cloudflare/ai-chat and belongs in its own change.
  • compactAfter re-derives the token estimate over the whole content-free path on every inserted append (Sessions). A running total kept alongside the leaf cache would remove it.
  • On a wake recovery the orphaned stream's chunks are read in full up to three times across getPartialStreamText, persistOrphanedStream and the give-up path.
  • The _annotateActionApprovalChunk per-chunk SELECT only fires for paused durable actions and is left alone.

Tests

  • agents sessions suites (69): newest-first ordering, overlays, early exit, branch leaf; import and compaction change events; the storage-ops bench pins the owner lookup under 12 rows against a full read over 1000, with and without a compacted prefix, and bounds a lookup that has to enter the overlay.
  • @cloudflare/think suites: client-tools (new rows-read tests for tool update and turn start), hydration-budget (tool result for a row outside the window still lands via the storage fallback), media-eviction (hasEvictableMedia; a linear append schedules the pass with no cache refresh), plus the full Think workers project and the @cloudflare/ai-chat workers project.
  • npm run typecheck, oxfmt --check ., oxlint clean.

Devin Review

A long Think turn read the whole persisted history 2 + T times: once to
reconcile the client's transcript, once to refresh the cache after
persisting it, and once per tool update (client result, approval,
cross-message result, execution outcome) to find the one message that
owns the call. Each read pays the sized path query and hydrates every
row, so the billed reads grew with transcript length times tool count.

Think now resolves a tool update's owner from the in-flight accumulator
and the live cache and reads that row alone; a chat request reconciles
against the cache, skips echoed messages whose stored form is unchanged,
and does not re-read the path after its writes. Storage is walked only
when the cache does not cover the active path, and then newest first,
stopping at the owner. The cache re-windows itself once appends carry it
past the hydration budget and marks itself stale on Sessions `import`
and `compaction` events. Media eviction is gated from memory on each
linear append instead of a stored-path scan after every cache refresh;
unchanged think_config rewrites and the per-call agent-tool DDL are
skipped.

Sessions gains `history({ newestFirst: true })`, a leaf-to-root walk
over parent pointers that pays one row per message the consumer takes
and plans compaction overlays only once it reaches a compacted span, and
reports `import` and `compaction` writes on the change feed.

Pinned on real DO SQLite: the owner lookup on a 200-message path reads
under 12 rows against 1801 for a full read; a Think tool update and a
turn start bill the same rows on a 12-message and a 160-message
transcript.
@changeset-bot

changeset-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 160c147

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
agents Patch
@cloudflare/think Patch
@cloudflare/agent-think Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@agent-think

agent-think Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

🟡 agents import sizes

Measured 267 runtime imports as minified bundles. The primary size is gzip; raw minified size is included for diagnosis. An existing import growing by more than 10% is marked red. This report is informational.

Red Yellow Green Unchanged New Removed
0 2 0 263 2 0

Compared 94485788 with 160c1473. Open workflow run.

Changed imports (4)
Status Import Base gzip Head gzip Delta
🟡 agents/sessions#Sessions 9.0 KiB 9.4 KiB +418 B (+4.56%)
🟡 agents/sessions#Session 2.0 KiB 2.0 KiB +22 B (+1.07%)
agents/sessions#COMPACTION_PREFIX 147 B
agents/sessions#isCompactionMessage 177 B
All 267 current runtime imports
Status Import Gzip Raw minified
agents#__DO_NOT_USE_WILL_BREAK__agentContext 258.6 KiB 1130.0 KiB
agents#__DO_NOT_USE_WILL_BREAK__withInvocationScope 258.6 KiB 1130.0 KiB
agents#Agent 258.6 KiB 1130.0 KiB
agents#AGENT_TOOL_MILESTONE_PART 258.6 KiB 1130.0 KiB
agents#AGENT_TOOL_PROGRESS_PART 258.6 KiB 1130.0 KiB
agents#buildAgentPath 259.1 KiB 1132.3 KiB
agents#buildAgentUrl 259.3 KiB 1132.7 KiB
agents#callable 258.6 KiB 1130.1 KiB
agents#camelCaseToKebabCase 258.6 KiB 1130.0 KiB
agents#createHeaderBasedEmailResolver 258.8 KiB 1130.4 KiB
agents#DEFAULT_AGENT_STATIC_OPTIONS 258.6 KiB 1130.0 KiB
agents#DurableObjectOAuthClientProvider 258.6 KiB 1130.0 KiB
agents#getAgentByName 258.6 KiB 1130.0 KiB
agents#getCurrentAgent 258.6 KiB 1130.0 KiB
agents#getSubAgentByName 258.9 KiB 1130.7 KiB
agents#isDurableObjectCodeUpdateReset 258.6 KiB 1130.0 KiB
agents#isDurableObjectMemoryLimitReset 258.6 KiB 1130.0 KiB
agents#isDurableObjectStorageReset 258.6 KiB 1130.1 KiB
agents#isPlatformTransientError 258.6 KiB 1130.0 KiB
agents#MCP_SERVER_ID_MAX_LENGTH 258.6 KiB 1130.0 KiB
agents#MessageType 258.8 KiB 1130.3 KiB
agents#normalizeServerId 258.6 KiB 1130.0 KiB
agents#parseSubAgentPath 258.6 KiB 1130.0 KiB
agents#routeAgentEmail 258.9 KiB 1130.7 KiB
agents#routeAgentRequest 259.2 KiB 1131.9 KiB
agents#routeSubAgentRequest 258.8 KiB 1130.6 KiB
agents#SqlError 258.6 KiB 1130.0 KiB
agents#StreamingResponse 258.6 KiB 1130.0 KiB
agents#SUB_PREFIX 258.6 KiB 1130.0 KiB
agents#unstable_callable 258.7 KiB 1130.2 KiB
agents/agent-tools#agentTool 112.5 KiB 538.2 KiB
agents/browser#BrowserConnector 50.5 KiB 176.6 KiB
agents/browser#browserContent 36.3 KiB 127.4 KiB
agents/browser#browserExtract 36.3 KiB 127.4 KiB
agents/browser#browserLinks 36.3 KiB 127.4 KiB
agents/browser#browserMarkdown 36.3 KiB 127.4 KiB
agents/browser#browserPdf 36.3 KiB 127.3 KiB
agents/browser#BrowserRenderingError 36.0 KiB 126.7 KiB
agents/browser#browserScrape 36.3 KiB 127.4 KiB
agents/browser#browserScreenshot 36.3 KiB 127.3 KiB
agents/browser#browserSnapshot 36.3 KiB 127.4 KiB
agents/browser#CdpSession 37.2 KiB 129.8 KiB
agents/browser#CodemodeRuntime 39.6 KiB 139.0 KiB
agents/browser#connectBrowser 37.8 KiB 131.4 KiB
agents/browser#connectBrowserSession 37.5 KiB 130.4 KiB
agents/browser#connectUrl 37.6 KiB 130.5 KiB
agents/browser#createBrowserSession 36.3 KiB 127.5 KiB
agents/browser#DEFAULT_EXEC_SWEEP_IDLE_MS 36.0 KiB 126.6 KiB
agents/browser#DEFAULT_SWEEP_IDLE_MS 36.0 KiB 126.6 KiB
agents/browser#deleteBrowserSession 36.1 KiB 126.9 KiB
agents/browser#DurableBrowserSessionStore 36.4 KiB 127.6 KiB
agents/browser#getBrowserRecording 36.2 KiB 127.1 KiB
agents/browser#listBrowserTargets 36.1 KiB 126.9 KiB
agents/browser#loadCdpSpec 36.6 KiB 128.3 KiB
agents/browser#runQuickAction 36.0 KiB 126.6 KiB
agents/browser/ai#createBrowserRuntime 146.0 KiB 630.3 KiB
agents/browser/ai#createBrowserTools 146.0 KiB 630.3 KiB
agents/browser/ai#createQuickActionTools 122.5 KiB 554.3 KiB
agents/browser/tanstack-ai#createBrowserTools 161.7 KiB 699.2 KiB
agents/chat#AbortRegistry 2.5 KiB 8.9 KiB
agents/chat#AGENT_TOOL_STREAM_PROGRESS_BUMP_THROTTLE_MS 2.3 KiB 8.2 KiB
agents/chat#AgentToolProgressEmitter 2.7 KiB 9.5 KiB
agents/chat#AgentToolStreamProgressThrottle 2.4 KiB 8.3 KiB
agents/chat#aiSdkRecoveryCodec 2.3 KiB 8.2 KiB
agents/chat#applyAgentToolEvent 3.2 KiB 11.0 KiB
agents/chat#applyChunkToParts 2.3 KiB 8.2 KiB
agents/chat#applyToolUpdate 2.4 KiB 8.4 KiB
agents/chat#AutoContinuationController 2.3 KiB 8.2 KiB
agents/chat#awaitWithDeadline 2.4 KiB 8.4 KiB
agents/chat#broadcastTransition 3.2 KiB 11.4 KiB
agents/chat#buildChatRecoveringFrame 2.4 KiB 8.4 KiB
agents/chat#buildInClauseStrings 2.4 KiB 8.4 KiB
agents/chat#bumpChatRecoveryProgress 2.4 KiB 8.3 KiB
agents/chat#byteLength 2.5 KiB 8.4 KiB
agents/chat#CHAT_LAST_TERMINAL_KEY 2.3 KiB 8.2 KiB
agents/chat#CHAT_MESSAGE_TYPES 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERING_FLAG_TTL_MS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERING_KEY 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_ALARM_DEBOUNCE_MS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_INCIDENT_KEY_PREFIX 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_INCIDENT_TTL_MS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_PROGRESS_KEY 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_STABLE_RETRY_DELAY_SECONDS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_TASK_NAME 2.3 KiB 8.2 KiB
agents/chat#CHAT_STREAM_PROGRESS_CREDIT_THROTTLE_MS 2.3 KiB 8.2 KiB
agents/chat#ChatRecoveryEngine 4.4 KiB 15.3 KiB
agents/chat#chatRecoveryTaskRunOptions 2.4 KiB 8.6 KiB
agents/chat#ChatStreamStalledError 2.4 KiB 8.3 KiB
agents/chat#classifyAgentToolChildRecovery 2.4 KiB 8.5 KiB
agents/chat#clearChatTerminal 2.3 KiB 8.3 KiB
agents/chat#clientResolvableToolNames 2.3 KiB 8.3 KiB
agents/chat#ContinuationState 2.7 KiB 9.8 KiB
agents/chat#createAgentToolEventState 2.3 KiB 8.3 KiB
agents/chat#createChatFiberSnapshot 2.5 KiB 8.6 KiB
agents/chat#createChatRecoveryTaskDefinition 2.6 KiB 9.0 KiB
agents/chat#createChatStreams 6.3 KiB 21.7 KiB
agents/chat#createChatTurnTaskDefinition 2.7 KiB 8.9 KiB
agents/chat#createToolsFromClientSchemas 114.3 KiB 545.4 KiB
agents/chat#crossMessageToolResultUpdate 2.4 KiB 8.6 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_MAX_OOM_RETRIES 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_MAX_WORK 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_NO_PROGRESS_TIMEOUT_MS 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_STABLE_TIMEOUT_MS 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_TERMINAL_MESSAGE 2.4 KiB 8.3 KiB
agents/chat#dispatchChatRecoveryToHandoff 3.0 KiB 9.9 KiB
agents/chat#drainInteractionApplies 2.3 KiB 8.3 KiB
agents/chat#enforceRowSizeLimit 3.5 KiB 11.2 KiB
agents/chat#hasIncompleteToolBatch 2.4 KiB 8.6 KiB
agents/chat#interceptAgentToolBroadcast 2.5 KiB 8.7 KiB
agents/chat#isPlatformFailure 2.6 KiB 8.9 KiB
agents/chat#isReplayChunk 2.4 KiB 8.7 KiB
agents/chat#iterateWithStallWatchdog 2.6 KiB 8.8 KiB
agents/chat#KV_DELETE_MAX_KEYS 2.3 KiB 8.2 KiB
agents/chat#listActiveChatRecoveryIncidents 2.4 KiB 8.4 KiB
agents/chat#MAX_BOUND_PARAMS 2.3 KiB 8.2 KiB
agents/chat#MessageType 2.4 KiB 9.0 KiB
agents/chat#normalizeToolInput 2.3 KiB 8.2 KiB
agents/chat#parseProtocolMessage 2.5 KiB 9.0 KiB
agents/chat#partAwaitsClientInteraction 2.4 KiB 8.6 KiB
agents/chat#pausedExecutionUpdate 2.4 KiB 8.4 KiB
agents/chat#pendingChatTerminal 2.3 KiB 8.3 KiB
agents/chat#persistReconstructedOrphan 3.1 KiB 11.0 KiB
agents/chat#PreStreamTurns 2.6 KiB 9.3 KiB
agents/chat#readChatRecoveryProgress 2.3 KiB 8.3 KiB
agents/chat#reconcileMessages 2.8 KiB 9.6 KiB
agents/chat#reconcileOrphanPartial 2.4 KiB 8.5 KiB
agents/chat#recordChatTerminal 2.4 KiB 8.3 KiB
agents/chat#repairInterruptedToolParts 2.6 KiB 9.1 KiB
agents/chat#resolveChatRecoveryConfig 2.6 KiB 8.9 KiB
agents/chat#resolveToolMergeId 2.4 KiB 8.5 KiB
agents/chat#ResumableStream 4.6 KiB 15.6 KiB
agents/chat#ResumeHandshake 3.0 KiB 10.4 KiB
agents/chat#ROW_MAX_BYTES 2.3 KiB 8.2 KiB
agents/chat#runChatRecoveryExhaustion 2.6 KiB 8.9 KiB
agents/chat#sanitizeMessage 2.5 KiB 8.8 KiB
agents/chat#sendIfOpen 2.4 KiB 8.4 KiB
agents/chat#setChatRecovering 2.5 KiB 8.5 KiB
agents/chat#shouldCreditStreamProgress 2.4 KiB 8.3 KiB
agents/chat#STREAM_RESUME_NONE_REASONS 2.3 KiB 8.2 KiB
agents/chat#StreamAccumulator 2.9 KiB 10.7 KiB
agents/chat#StreamProgressCreditThrottle 2.4 KiB 8.3 KiB
agents/chat#SubmitConcurrencyController 2.9 KiB 10.3 KiB
agents/chat#sweepStaleChatRecoveryIncidents 2.4 KiB 8.5 KiB
agents/chat#TextSegmentJoiner 2.7 KiB 9.2 KiB
agents/chat#TIMED_OUT 2.3 KiB 8.2 KiB
agents/chat#toolApprovalUpdate 2.4 KiB 8.5 KiB
agents/chat#toolPartHasSettledResult 2.3 KiB 8.4 KiB
agents/chat#toolResultUpdate 2.4 KiB 8.5 KiB
agents/chat#truncateOlderMessages 3.2 KiB 10.4 KiB
agents/chat#TurnQueue 2.6 KiB 9.2 KiB
agents/chat#unwrapChatFiberSnapshot 2.4 KiB 8.5 KiB
agents/chat#wrapChatFiberSnapshot 2.3 KiB 8.2 KiB
agents/chat-sdk#ChatSdkStateAdapter 261.0 KiB 1141.6 KiB
agents/chat-sdk#ChatSdkStateAgent 260.4 KiB 1139.1 KiB
agents/chat-sdk#createChatSdkState 261.0 KiB 1141.6 KiB
agents/chat-sdk#defaultKeyShard 258.8 KiB 1130.2 KiB
agents/chat-sdk#defaultThreadShard 258.7 KiB 1130.1 KiB
agents/chat/react#detectToolsRequiringConfirmation 3.3 KiB 8.3 KiB
agents/chat/react#extractClientToolSchemas 3.2 KiB 8.3 KiB
agents/chat/react#getAgentMessages 3.4 KiB 8.6 KiB
agents/chat/react#getToolApproval 3.1 KiB 8.0 KiB
agents/chat/react#getToolCallId 3.1 KiB 8.0 KiB
agents/chat/react#getToolInput 3.1 KiB 8.0 KiB
agents/chat/react#getToolOutput 3.1 KiB 8.0 KiB
agents/chat/react#getToolPartState 3.2 KiB 8.2 KiB
agents/chat/react#useAgentChat 132.9 KiB 609.7 KiB
agents/chat/react#WebSocketChatTransport 5.7 KiB 17.1 KiB
agents/chat/transport#WebSocketChatTransport 2.8 KiB 9.2 KiB
agents/client#AgentClient 5.7 KiB 16.6 KiB
agents/client#AgentConnectionError 582 B 993 B
agents/client#agentFetch 4.2 KiB 12.3 KiB
agents/client#createStubProxy 638 B 1.0 KiB
agents/client#DEFAULT_CALL_TIMEOUT_MS 473 B 770 B
agents/client#isTerminalCloseEvent 509 B 822 B
agents/context#AgentContextProvider 412 B 792 B
agents/context#AgentSearchProvider 640 B 1.3 KiB
agents/context#ContextBlocks 87.4 KiB 429.7 KiB
agents/email#createAddressBasedEmailResolver 193 B 227 B
agents/email#createCatchAllEmailResolver 110 B 97 B
agents/email#createHeaderBasedEmailResolver 334 B 492 B
agents/email#createSecureReplyEmailResolver 718 B 1.3 KiB
agents/email#DEFAULT_MAX_AGE_SECONDS 56 B 39 B
agents/email#isAutoReplyEmail 201 B 249 B
agents/email#signAgentHeaders 424 B 812 B
agents/experimental/webmcp#registerWebMcp 85.2 KiB 295.8 KiB
agents/lifecycle#getCurrentAgent 376 B 798 B
agents/lifecycle#Lifecycle 8.3 KiB 25.8 KiB
agents/lifecycle#LifecycleCapability 484 B 975 B
agents/mcp#createLegacyMcpHandler 375.9 KiB 1572.2 KiB
agents/mcp#createMcpHandler 388.2 KiB 1617.4 KiB
agents/mcp#DurableObjectEventStore 342.5 KiB 1430.7 KiB
agents/mcp#ElicitRequestSchema 342.5 KiB 1430.7 KiB
agents/mcp#experimental_createMcpHandler 376.1 KiB 1572.5 KiB
agents/mcp#getMcpAuthContext 342.5 KiB 1430.8 KiB
agents/mcp#MCP_SERVER_ID_MAX_LENGTH 342.5 KiB 1430.7 KiB
agents/mcp#McpAgent 342.5 KiB 1430.7 KiB
agents/mcp#normalizeServerId 342.5 KiB 1430.7 KiB
agents/mcp#RPC_DO_PREFIX 342.5 KiB 1430.7 KiB
agents/mcp#RPCClientTransport 342.5 KiB 1430.7 KiB
agents/mcp#RPCServerTransport 342.5 KiB 1430.7 KiB
agents/mcp#SSEEdgeClientTransport 342.6 KiB 1431.0 KiB
agents/mcp#StreamableHTTPEdgeClientTransport 342.6 KiB 1431.0 KiB
agents/mcp#WorkerTransport 345.8 KiB 1447.6 KiB
agents/mcp/client#getNamespacedData 62.9 KiB 240.0 KiB
agents/mcp/client#MCP_SERVER_ID_MAX_LENGTH 62.9 KiB 239.9 KiB
agents/mcp/client#MCPClientManager 158.6 KiB 702.6 KiB
agents/mcp/client#normalizeServerId 63.0 KiB 240.2 KiB
agents/mcp/do-oauth-client-provider#DurableObjectOAuthClientProvider 2.1 KiB 6.6 KiB
agents/mcp/server#createMcpHandler 80.5 KiB 307.2 KiB
agents/mcp/server#getMcpAuthContext 64.0 KiB 245.5 KiB
agents/observability#channels 259 B 549 B
agents/observability#genericObservability 470 B 1.2 KiB
agents/observability#subscribe 324 B 668 B
agents/observability/ai#wrapAISDK 8.8 KiB 30.5 KiB
agents/react#_testUtils 3.8 KiB 9.5 KiB
agents/react#useAgent 10.8 KiB 31.1 KiB
agents/react#useAgentToolEvents 5.6 KiB 16.8 KiB
agents/routing#getAgentByName 795 B 1.7 KiB
agents/routing#routeAgentRequest 1.6 KiB 3.6 KiB
agents/routing#RoutedAgents 2.4 KiB 6.2 KiB
agents/schedule#getSchedulePrompt 85.8 KiB 424.7 KiB
agents/schedule#scheduleSchema 85.3 KiB 423.6 KiB
agents/schedule#unstable_getSchedulePrompt 85.9 KiB 424.9 KiB
agents/schedule#unstable_scheduleSchema 85.3 KiB 423.6 KiB
agents/schedules#Scheduler 6.8 KiB 22.0 KiB
agents/schedules/parser#getSchedulePrompt 85.8 KiB 424.7 KiB
agents/schedules/parser#scheduleSchema 85.3 KiB 423.6 KiB
agents/sessions#COMPACTION_PREFIX 147 B 160 B
agents/sessions#createCompactFunction 1.7 KiB 4.0 KiB
agents/sessions#isCompactionMessage 177 B 200 B
🟡 agents/sessions#Session 2.0 KiB 6.2 KiB
🟡 agents/sessions#Sessions 9.4 KiB 33.6 KiB
agents/skills#fromManifest 309.8 KiB 1084.0 KiB
agents/skills#parseSkillFrontmatter 328.4 KiB 1146.2 KiB
agents/skills#parseSkillMarkdown 328.6 KiB 1146.5 KiB
agents/skills#r2 330.2 KiB 1150.4 KiB
agents/skills#runner 369.0 KiB 1297.8 KiB
agents/skills#SkillRegistry 416.4 KiB 1581.7 KiB
agents/skills/compile#compileSkillScript 15.4 KiB 43.4 KiB
agents/skills/compile#isCompilableSkillScript 15.4 KiB 43.3 KiB
agents/streams#DEFAULT_MAX_CHUNK_BYTES 94 B 96 B
agents/streams#sseResponse 855 B 1.6 KiB
agents/streams#StreamClosedError 175 B 212 B
agents/streams#StreamNotFoundError 215 B 276 B
agents/streams#Streams 4.1 KiB 13.5 KiB
agents/streams#StreamSerializationError 171 B 201 B
agents/tasks#DuplicateTaskStepError 328 B 463 B
agents/tasks#MAX_SERIALIZED_BYTES 190 B 232 B
agents/tasks#MissingTaskDefinitionError 358 B 536 B
agents/tasks#NonRetryableError 238 B 308 B
agents/tasks#TaskReplayDivergedError 341 B 483 B
agents/tasks#Tasks 8.9 KiB 31.8 KiB
agents/tasks#TaskSerializationError 258 B 339 B
agents/types#MessageType 211 B 365 B
agents/vite#default 353.8 KiB 1356.1 KiB
agents/websockets#CALLABLES_RPC_QUERY 12.4 KiB 43.3 KiB
agents/websockets#CALLABLES_RPC_VALUE 12.4 KiB 43.3 KiB
agents/websockets#callablesFromDecorated 12.7 KiB 44.3 KiB
agents/websockets#callablesRpcUrl 12.5 KiB 43.5 KiB
agents/websockets#isCallablesRpcUpgrade 12.4 KiB 43.4 KiB
agents/websockets#WebSockets 17.7 KiB 62.2 KiB
agents/workflows#AgentWorkflow 260.0 KiB 1134.8 KiB
agents/workflows#WorkflowRejectedError 258.7 KiB 1130.2 KiB
agents/x402#normalizeNetwork 14.7 KiB 61.1 KiB
agents/x402#withX402 23.0 KiB 89.2 KiB
agents/x402#withX402Client 104.1 KiB 346.5 KiB

Reported by agent-think[bot].

@devin-ai-integration devin-ai-integration 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.

Devin Review found 2 potential issues.

Devin Review

Comment on lines +3734 to +3739
this._cachedBytesSinceSync += JSON.stringify(message).length;
if (
this._lastHydration.totalContentBytes + this._cachedBytesSinceSync >
budget
) {
this._cacheCoversActivePath = false;

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.

🔴 Hydration budget misses cache growth

Large updates never reach _cachedBytesSinceSync, while non-ASCII appends count UTF-16 units instead of stored bytes. _cacheCoversActivePath can stay true beyond hydrationByteBudget, so later turns skip re-windowing and retain excess history.

Prompt for agents
Fix Think's post-hydration cache growth accounting in packages/think/src/think.ts. The current _noteCachedGrowth path only runs for linear appends and adds JSON.stringify(message).length, which is UTF-16 code units rather than the UTF-8/storage-sized units used by hydrationByteBudget. Updates can also enlarge cached messages without affecting the accounting. Track byte deltas for every cache mutation that can grow the cached transcript, using the same byte semantics as Sessions where possible, and mark _cacheCoversActivePath false once the refreshed total plus subsequent growth exceeds the budget. Preserve the optimization that avoids unnecessary full transcript reads.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +3536 to +3542
if (this._agedRowsHiddenFromCache()) {
if (
this._lastHydration !== null &&
this._mediaEvictionFruitlessAtBytes ===
this._lastHydration.totalContentBytes
) {
return;

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.

🟡 Media eviction stays suppressed after appends

After a fruitless compacted or windowed pass, appends leave _lastHydration.totalContentBytes unchanged. The stale equality suppresses later passes, so newly aged media remains inline until another refresh occurs.

Prompt for agents
Make the fruitless media-eviction gate reflect storage changes after the last hydration. In packages/think/src/think.ts, _mediaEvictionFruitlessAtBytes is compared against _lastHydration.totalContentBytes, but linear append events do not update that hydration snapshot. On compacted or windowed caches, a fruitless pass can therefore suppress all later append-triggered passes. Invalidate or advance the fruitless marker whenever a durable mutation changes candidate rows or total stored bytes, while retaining the no-repeat-scan optimization for genuinely unchanged storage.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@pkg-pr-new

pkg-pr-new Bot commented Sep 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2219

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2219

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2219

hono-agents

npm i https://pkg.pr.new/hono-agents@2219

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2219

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2219

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2219

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2219

commit: 160c147

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.

1 participant