Skip to content

refactor(chat): run recovery continuations on Tasks - #2194

Merged
mattzcarey merged 22 commits into
mainfrom
feat/replatform-chat-recovery-on-tasks
Sep 2, 2026
Merged

refactor(chat): run recovery continuations on Tasks#2194
mattzcarey merged 22 commits into
mainfrom
feat/replatform-chat-recovery-on-tasks

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Base

Rebased onto main after #2190 merged. The rebase also incorporates #2191's Tasks write optimizations and #2192's deterministic Durable Object test helpers.

Why this changed

Root AI Chat and Think recovery still used Scheduler rows even though Tasks had become the durable replay primitive. Moving recovery onto Tasks exposed a broader alarm-lifetime issue: a job can return at a bounded handoff so Lifecycle can continue its due batch while the promise it started is still running. A memory reset from that promise still belongs to the alarm that started it, but it no longer reaches the alarm's call stack unless Lifecycle retains that relationship.

This is an alarm-domain concern, not Task or Scheduler policy.

Final architecture

Lifecycle owns bounded alarm work

  • Lifecycle pre-arms its existing deadman alarm before driving due jobs.
  • trackAlarmWork(promise) lets a bounded job handoff register the work it started with the current alarm.
  • Lifecycle continues driving the due batch, runs the host alarm hook, then joins the dynamically growing registered-work batch before classifying the alarm.
  • Every registered promise settling without a memory reset makes the alarm clean and clears prior strikes.
  • Any registered promise reporting a memory reset enters the existing alarm breaker once for the whole batch, using the job that registered it as the executing context.
  • Physical alarm re-arms requested while the batch is running are coalesced until the batch settles, so they cannot overwrite the pre-armed deadman.

Tasks is only an adapter to that boundary

  • Task wakes use one JobDriver attempt because ReplayStep owns their durable retry policy.
  • When Tasks reaches its five-second dispatch handoff, it registers the still-running attempt with Lifecycle and returns the run's authoritative wake outcome.
  • Tasks still updates authoritative run rows on breaker backoff/sealing, preventing startup reconciliation from resurrecting contained work.
  • Framework recovery definitions remain internal; there is no public grouping or recovery flag.
  • retain: false removes completed, failed, and cancelled runs, journals, wakes, and idempotency keys.

Chat recovery uses Tasks without losing Scheduler compatibility

  • Root AI Chat and Think recovery attempts are chained __cf_internal_chat_recovery Task runs.
  • Initial attempts deduplicate by incident; delayed retries use durable Task sleeps.
  • _chatRecoveryContinue and _chatRecoveryRetry return at model handoff, preserving queue liveness.
  • At that handoff AI Chat and Think register the model promise with Lifecycle. This applies identically whether the callback arrived through a Task or the temporary Scheduler compatibility transport.
  • Pre-handoff failures remain owned by the current Task/Scheduler execution; only post-handoff platform failures enqueue one replacement attempt.
  • Think startup recovery detects active Task runs through tasks.list().

Upgrade and breaker correctness

  • Existing cf_agents_jobs tables are upgraded idempotently with recovery_loop before any query references it.
  • Existing Task wake rows are reconciled to the one-attempt JobDriver policy.
  • Condemned-isolate errors escape step.do immediately.
  • Connection-loss failures use ReplayStep's durable retry budget and remain unsettled after exhaustion.
  • Recovery-loop wakes still back off and seal as a group; unrelated jobs remain untouched.

What we found during review

The first downstream approach used Task-specific late-OOM and clean-settlement marker jobs. It handled one detached Task, but it made Tasks responsible for alarm policy and failed when several promises belonged to the same alarm: one clean Task could clear strikes before a sibling reported OOM. It also left Scheduler-originated recovery as a separate case.

The final version removes those Task marker jobs and moves promise retention and group classification into Lifecycle. Tasks, Scheduler-driven chat recovery, and future alarm-backed capabilities now use one small core boundary instead of reimplementing breaker behavior downstream.

Compatibility and release

  • Existing pending _chatRecoveryContinue / _chatRecoveryRetry Scheduler rows still dispatch through the retained methods and drain normally.
  • Routed dynamic agents temporarily keep the root-owned Scheduler transport until Tasks supports routed child wakes. The refactor(lifecycle): dissolve alarm memory-limit policy into the jobs domain #2190 sealing bridge protects that path.
  • AI Chat and Think require agents >=0.23.0, the pending changesets release batch containing the shared runtime support.

Verification

Current head: 56e4635f.

  • Changed files formatted with Oxfmt.
  • git diff --check passes.
  • GitHub CI and Devin review are running for the current head.

Regression coverage in the branch includes:

  • existing job-table schema upgrade and repeated startup
  • final-step platform failure deferring after one Task wake dispatch
  • queued and warm Task attempts remaining in the alarm breaker after handoff
  • all-clean registered alarm work clearing stale strikes
  • concurrent clean and OOM work producing one alarm-level breaker outcome
  • Task run-row backoff surviving startup reconciliation
  • sealing at the strike budget and non-retained terminal cleanup
  • pre-handoff ownership versus post-handoff replacement for both chat callbacks
  • root AI Chat and Think recovery using Tasks rather than Scheduler rows
  • legacy and routed Scheduler recovery compatibility

Devin Review

@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cb6dff7

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

This PR includes changesets to release 4 packages
Name Type
agents Minor
@cloudflare/ai-chat 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

devin-ai-integration[bot]

This comment was marked as resolved.

@pkg-pr-new

pkg-pr-new Bot commented Sep 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

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

@cloudflare/ai-chat

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

@cloudflare/codemode

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

hono-agents

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

@cloudflare/shell

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

@cloudflare/think

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

@cloudflare/voice

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

@cloudflare/worker-bundler

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

commit: cb6dff7

Base automatically changed from chore/alarm-memory-limit-domain-boundaries to main September 1, 2026 14:44
Two confirmed gaps (pinned red-first in memory-limit.test.ts):

1. The driver's in-process dispatch retry converted a memory-limit reset
   into a silent success — the retry found the half-claimed run not due,
   returned void, and the wake was deleted without the breaker ever
   engaging. Memory-limit resets now defer to the alarm boundary like
   code-update resets: the isolate is condemned either way.

2. The run row outlives the breaker's queue-row policy: startup
   reconciliation re-derives due-now wakes from it, resurrecting a doomed
   run through backoff and past sealing. MemoryLimitContext now carries
   the striking job's identity, and Tasks applies the breaker to the run
   itself — demoted to the backoff wake on a strike (claim stripped so
   reconcile honors the deadline), terminally failed (task:failed,
   TaskMemoryLimitSealed) when the breaker seals. Generic for every
   definition: the striking run is the one that exhausted memory.

Claude-Session: https://claude.ai/code/session_011QZUJztM1rMTsHEC7mbcbz
devin-ai-integration[bot]

This comment was marked as resolved.

Replace root-agent recovery schedule rows with chained runs of the reserved
__cf_internal_chat_recovery Task definition shared by AI Chat and Think.
Initial attempts deduplicate by incident, delayed retries use step.sleep, and
the existing bounded callback methods still detach at model handoff. Legacy
and routed dynamic-agent schedules remain as compatibility shims.

Make Tasks breaker-safe for recovery definitions: condemned-isolate failures
escape journal retries, flagged framework definitions carry queue membership,
and onMemoryLimit aligns or seals their authoritative run rows so startup
cannot resurrect purged work. Think's submission sweep now inspects Tasks
rather than Scheduler rows.

AI Chat and Think require agents >=0.23.1, the release containing the shared
definition and internal enqueue aperture.
Apply retain: false through one terminal cleanup path shared by completed,
failed, and cancelled runs. A memory-limit seal now emits task:failed, removes
the run and journal, cancels its wake, and releases its idempotency key.

Make the breaker regression tolerate only the intentional workerd isolate
reset and use per-attempt Durable Object names so Vitest retries cannot collide
with durable rows from the failed attempt.
Preserve #2192's exact atomic helper shape while checking the Task transport
through a separate same-RPC method. Align chat peer ranges with the pending
changesets release batch, which publishes this work in agents 0.23.0.
@mattzcarey
mattzcarey force-pushed the feat/replatform-chat-recovery-on-tasks branch from 0dbc1a3 to 310dfce Compare September 1, 2026 15:02
devin-ai-integration[bot]

This comment was marked as resolved.

Upgrade existing Lifecycle job tables before reading the recovery-loop flag.
Let Task wakes defer after one JobDriver attempt because ReplayStep owns their
durable retry budget, including reconciliation of older wake rows.

Keep pre-handoff chat failures on the current Task or schedule, and enqueue a
replacement only after the bounded callback has handed off to the model turn.
devin-ai-integration[bot]

This comment was marked as resolved.

When bounded Task dispatch returns before an attempt, preserve a durable
late-memory-limit marker if that detached attempt later OOMs. The next alarm
rethrows the canonical signal inside JobDriver so existing strike, backoff,
and sealing policy remains authoritative.

Mark detached job outcomes so their alarm is not treated as a clean breaker
cycle, preserve marker wakes through startup reconciliation, and cover queued
and warm attempts plus marker cleanup.
devin-ai-integration[bot]

This comment was marked as resolved.

When work previously detached from an alarm settles without a memory reset,
enqueue one no-op Task wake. That wake restores any authoritative run deadline
and gives the existing JobDriver a clean alarm boundary to clear stale strikes.
Late OOMs keep using the existing late-memory-limit marker.
devin-ai-integration[bot]

This comment was marked as resolved.

Keep Lifecycle's deadman alarm armed while it joins promises registered at
bounded job handoffs. Classify the whole dynamically growing alarm batch once:
all clean work clears prior strikes, while any memory reset enters the existing
breaker once with its captured executing job.

Tasks now only registers attempts at its five-second handoff, and AI Chat and
Think register post-handoff model work so Task and Scheduler transports share
the same breaker. Remove the Task-specific late marker jobs and their state.
…g the alarm

Lifecycle: `trackAlarmWork` no longer holds the alarm invocation open or
coalesces physical re-arms. Handed-off work is classified when it settles:
a memory reset records a strike against the job that handed it off, one
strike per reset however many flows observe it, and strikes clear only
once no handed-off work is outstanding and the last of it settled clean.
Attribution follows the dispatch's async context and alarms in flight are
counted, so overlapping invocations (tests drive alarm() by hand while the
pool auto-fires the physical alarm) stay correct.

Tasks: drop the per-definition recoveryLoop grouping and its composition
root plumbing (setTaskRecoveryLoopDefinitionResolver,
Agent._recoveryLoopTaskDefinitions, the recoveryLoop option on
_registerInternalTaskDefinition). onMemoryLimit acts only on the run whose
wake struck, stripping the claim and pushing the deadline so the reclaim
still sees an interrupted attempt. onJob hands off one canonical promise
per attempt, #syncWake skips same-values pushes, and runAttached actually
attaches instead of racing the warm start.

Chat: both hosts run the bounded recovery callbacks through the shared
dispatchChatRecoveryToHandoff and register the recovery Task with hooks
keyed by callback name.

Design docs, changeset, stale Scheduler/recovery-engine comments and tests
updated; new tests pin one-strike-per-reset and the startup re-arm.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

Two correctness fixes from Devin Review, both against the previous
commit's job-driver.ts:

- Overlapping alarm() invocations attributed a memory-limit strike to
  whichever job a shared instance field (#executingRow) last pointed
  at, not the job that actually struck — the struck job could escape
  backoff/sealing while an unrelated one absorbed it. Replaced with an
  AttributedPlatformFailure carrying the row out of the throw itself,
  correct by construction regardless of overlap.

- The quiescence-clear check for the strike counter read stale
  snapshots of #alarmsInFlight/#outstandingAlarmWork depending on which
  of two transitions (an alarm ending, a handoff settling) ran first,
  so a strike recorded in the gap between checks could never clear.
  Fixed by having each transition re-check both counters fresh, with
  no yield point between the mutation and the check on either side.

Fixing the second issue introduced a regression caught by the full
suite: the quiescence check started running unconditionally in
runAlarm's finally, including right after a strike was just recorded,
immediately clearing what had just been set. Restored the
placement-based guard (only a clean pass triggers the check) that the
prior design relied on.

New regression test isolates the attribution fix from Tasks' own
active-attempt tracking, which independently and correctly re-tracks a
Task run an overlapping alarm re-dispatches and was masking the bug in
two earlier attempts at this test.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

Third correctness fix from Devin Review against job-driver.ts, following
the same shape as the two already fixed: a strike could be fully recorded
(durable counter written, isolate reset scheduled via setTimeout(0)), and
then a slower, unrelated clean handoff still outstanding at that moment
could settle in the gap before the reset actually lands, find the alarm
domain quiescent, and clear what was just recorded.

Fixed with #strikeRecordedThisIsolate: once any flow records a strike in
this isolate, no later settlement may clear the durable counter for the
rest of this isolate's life. The isolate always resets shortly after a
recorded strike, so the next genuinely clean cycle runs in a fresh
isolate with a fresh JobDriver and the flag back at its default — there
is no cross-isolate state to reset.

New regression test (oomBeforeCleanSibling) orders a run's own strike
distinctly before a separately tracked clean sibling; verified against
the pre-fix code that it exercises the intended scenario and passes
correctly with the fix. I could not force this specific narrow race
window (bounded by workerd's own near-instant setTimeout(0) teardown
scheduling) to reproducibly fail pre-fix within this test harness after
several timing attempts, so this is a positive regression guard rather
than a failing-then-passing proof like the other two fixes in this PR.
The fix itself is verified by direct code tracing, matching Devin's own
independent diagnosis of the same race.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB

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

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 1 new potential issue.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

// Set before the first await below: closes the window as tightly as
// possible against a still-outstanding clean sibling reaching quiescence
// and clearing what this event is about to record.
this.#strikeRecordedThisIsolate = true;

@devin-ai-integration devin-ai-integration Bot Sep 2, 2026

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.

🔴 Failed reset freezes breaker state

When strike finalization fails before scheduling a reset, #strikeRecordedThisIsolate remains true. Later memory failures reuse the old strike and never advance sealing.

Devin Review

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

Replaces the imperative _registerInternalTaskDefinition/_internalTaskDefinitions
mechanism on Agent (a Map populated via a protected method, five near-identical
one-line wrapper methods across AIChatAgent and Think just to call it) with a
plain `register(name, definition)` method directly on Tasks. Framework code
calls this.tasks.register(...) once per reserved name from its own
constructor; it throws if the name lacks the `__cf` prefix or is already
registered, so registration composes correctly no matter how many subclass
layers exist or what any of them do with their own taskDefinitions field —
it no longer depends on Agent's own field-override machinery at all.

Agent's constructor keeps setTaskDefinitionResolver, but its only remaining
job is bridging the end user's own overridable taskDefinitions field, which
genuinely cannot be read at Tasks-construction time (a further-downstream
subclass's field initializer runs only after every constructor up the chain
returns) — register() has no such problem since it's called eagerly from
each host's own constructor, after this.tasks already exists.

design/rfc-fibers.md updated to describe the new mechanism (an adversarial
review caught the stale reference to the old resolver-based path). New
tests cover register()'s own validation branches directly (missing __cf
prefix, empty name, duplicate registration, collision with a
constructor-declared definition, and that a registered definition is
reachable only through the internal aperture, never the public run()) —
the only real definitions that previously exercised it (chat turn, chat
recovery, messenger reply) never hit any of its failure paths.

No public API surface changes: docs/agents/tasks.md and the existing
changeset need no edits, matching every other __DO_NOT_USE_WILL_BREAK__-
style internal aperture on Tasks.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
@agent-think

agent-think Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🔴 agents import sizes

Measured 289 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
1 83 8 191 4 2

Compared 99e5e2ec with cb6dff71. Open workflow run.

Changed imports (98)
Status Import Base gzip Head gzip Delta
🔴 agents/tasks#Tasks 7.8 KiB 8.9 KiB +1.0 KiB (+13.21%)
🟡 agents/lifecycle#Lifecycle 7.9 KiB 8.3 KiB +388 B (+4.81%)
🟡 agents/lifecycle#getCurrentAgent 366 B 376 B +10 B (+2.73%)
🟡 agents/lifecycle#LifecycleCapability 472 B 484 B +12 B (+2.54%)
🟡 agents/tasks#DuplicateTaskStepError 326 B 328 B +2 B (+0.61%)
🟡 agents/tasks#NonRetryableError 237 B 238 B +1 B (+0.42%)
🟡 agents/chat-sdk#defaultKeyShard 257.7 KiB 258.8 KiB +1.1 KiB (+0.41%)
🟡 agents/chat-sdk#defaultThreadShard 257.6 KiB 258.7 KiB +1.1 KiB (+0.41%)
🟡 agents/workflows#WorkflowRejectedError 257.6 KiB 258.7 KiB +1.1 KiB (+0.41%)
🟡 agents#callable 257.6 KiB 258.6 KiB +1.1 KiB (+0.41%)
🟡 agents/workflows#AgentWorkflow 258.9 KiB 260.0 KiB +1.1 KiB (+0.41%)
🟡 agents#DurableObjectOAuthClientProvider 257.6 KiB 258.6 KiB +1.0 KiB (+0.41%)
🟡 agents#isDurableObjectCodeUpdateReset 257.6 KiB 258.6 KiB +1.0 KiB (+0.41%)
🟡 agents#getAgentByName 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#AGENT_TOOL_MILESTONE_PART 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#SqlError 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#parseSubAgentPath 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#camelCaseToKebabCase 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#__DO_NOT_USE_WILL_BREAK__withInvocationScope 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#isPlatformTransientError 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#__DO_NOT_USE_WILL_BREAK__agentContext 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#DEFAULT_AGENT_STATIC_OPTIONS 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#getCurrentAgent 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#AGENT_TOOL_PROGRESS_PART 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#createHeaderBasedEmailResolver 257.8 KiB 258.8 KiB +1.0 KiB (+0.4%)
🟡 agents#isDurableObjectMemoryLimitReset 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#SUB_PREFIX 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#routeSubAgentRequest 257.8 KiB 258.8 KiB +1.0 KiB (+0.4%)
🟡 agents#MCP_SERVER_ID_MAX_LENGTH 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#routeAgentEmail 257.9 KiB 258.9 KiB +1.0 KiB (+0.4%)
🟡 agents#normalizeServerId 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#unstable_callable 257.7 KiB 258.7 KiB +1.0 KiB (+0.4%)
🟡 agents#MessageType 257.7 KiB 258.8 KiB +1.0 KiB (+0.4%)
🟡 agents#StreamingResponse 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents#Agent 257.6 KiB 258.6 KiB +1.0 KiB (+0.4%)
🟡 agents/chat-sdk#ChatSdkStateAgent 259.3 KiB 260.4 KiB +1.0 KiB (+0.39%)
🟡 agents#getSubAgentByName 257.9 KiB 258.9 KiB +1.0 KiB (+0.39%)
🟡 agents#buildAgentPath 258.1 KiB 259.1 KiB +1.0 KiB (+0.39%)
🟡 agents#isDurableObjectStorageReset 257.6 KiB 258.6 KiB +1.0 KiB (+0.39%)
🟡 agents#buildAgentUrl 258.3 KiB 259.3 KiB +1.0 KiB (+0.39%)
🟡 agents/chat-sdk#createChatSdkState 260.0 KiB 261.0 KiB +1.0 KiB (+0.39%)
🟡 agents#routeAgentRequest 258.2 KiB 259.2 KiB +1023 B (+0.39%)
🟡 agents/chat-sdk#ChatSdkStateAdapter 260.0 KiB 261.0 KiB +1.0 KiB (+0.39%)
🟡 agents/mcp#RPCServerTransport 341.5 KiB 342.5 KiB +1021 B (+0.29%)
🟡 agents/mcp#normalizeServerId 341.5 KiB 342.5 KiB +1019 B (+0.29%)
🟡 agents/mcp#RPCClientTransport 341.5 KiB 342.5 KiB +1018 B (+0.29%)
🟡 agents/mcp#ElicitRequestSchema 341.5 KiB 342.5 KiB +998 B (+0.29%)
🟡 agents/mcp#createMcpHandler 387.1 KiB 388.2 KiB +1.1 KiB (+0.28%)
🟡 agents/mcp#getMcpAuthContext 341.5 KiB 342.5 KiB +991 B (+0.28%)
🟡 agents/mcp#StreamableHTTPEdgeClientTransport 341.6 KiB 342.6 KiB +987 B (+0.28%)
🟡 agents/mcp#McpAgent 341.5 KiB 342.5 KiB +985 B (+0.28%)
🟡 agents/mcp#RPC_DO_PREFIX 341.5 KiB 342.5 KiB +985 B (+0.28%)
🟡 agents/mcp#SSEEdgeClientTransport 341.6 KiB 342.6 KiB +975 B (+0.28%)
🟡 agents/mcp#DurableObjectEventStore 341.5 KiB 342.5 KiB +970 B (+0.28%)
🟡 agents/mcp#WorkerTransport 344.9 KiB 345.8 KiB +972 B (+0.28%)
🟡 agents/mcp#MCP_SERVER_ID_MAX_LENGTH 341.5 KiB 342.5 KiB +957 B (+0.27%)
🟡 agents/mcp#experimental_createMcpHandler 375.1 KiB 376.1 KiB +979 B (+0.25%)
🟡 agents/mcp#createLegacyMcpHandler 375.0 KiB 375.9 KiB +964 B (+0.25%)
🟡 agents/chat#classifyAgentToolChildRecovery 2.4 KiB 2.4 KiB +2 B (+0.08%)
🟡 agents/websockets#callablesFromDecorated 12.7 KiB 12.7 KiB +9 B (+0.07%)
🟡 agents/websockets#CALLABLES_RPC_VALUE 12.4 KiB 12.4 KiB +8 B (+0.06%)
🟡 agents/websockets#CALLABLES_RPC_QUERY 12.4 KiB 12.4 KiB +8 B (+0.06%)
🟡 agents/websockets#isCallablesRpcUpgrade 12.4 KiB 12.4 KiB +8 B (+0.06%)
🟡 agents/websockets#callablesRpcUrl 12.4 KiB 12.5 KiB +6 B (+0.05%)
🟡 agents/websockets#WebSockets 17.7 KiB 17.7 KiB +8 B (+0.04%)
🟡 agents/chat#CHAT_LAST_TERMINAL_KEY 2.3 KiB 2.3 KiB +1 B (+0.04%)
🟡 agents/chat#clearChatTerminal 2.3 KiB 2.3 KiB +1 B (+0.04%)
🟡 agents/chat#recordChatTerminal 2.3 KiB 2.3 KiB +1 B (+0.04%)
🟡 agents/chat#DEFAULT_CHAT_RECOVERY_TERMINAL_MESSAGE 2.3 KiB 2.3 KiB +1 B (+0.04%)
🟡 agents/chat#bumpChatRecoveryProgress 2.3 KiB 2.3 KiB +1 B (+0.04%)
🟡 agents/chat#buildChatRecoveringFrame 2.4 KiB 2.4 KiB +1 B (+0.04%)
🟡 agents/chat#listActiveChatRecoveryIncidents 2.4 KiB 2.4 KiB +1 B (+0.04%)
🟡 agents/chat#hasIncompleteToolBatch 2.4 KiB 2.4 KiB +1 B (+0.04%)
🟡 agents/chat#interceptAgentToolBroadcast 2.5 KiB 2.5 KiB +1 B (+0.04%)
🟡 agents/chat#AbortRegistry 2.5 KiB 2.5 KiB +1 B (+0.04%)
🟡 agents/chat#TurnQueue 2.6 KiB 2.6 KiB +1 B (+0.04%)
🟡 agents/chat#ContinuationState 2.6 KiB 2.6 KiB +1 B (+0.04%)
🟡 agents/chat#AgentToolProgressEmitter 2.6 KiB 2.6 KiB +1 B (+0.04%)
🟡 agents/chat#TextSegmentJoiner 2.7 KiB 2.7 KiB +1 B (+0.04%)
🟡 agents/chat#createChatStreams 5.5 KiB 5.5 KiB +2 B (+0.04%)
🟡 agents/chat#reconcileMessages 2.8 KiB 2.8 KiB +1 B (+0.04%)
🟡 agents/chat#StreamAccumulator 2.9 KiB 2.9 KiB +1 B (+0.03%)
🟡 agents/chat#ChatRecoveryEngine 4.4 KiB 4.4 KiB +1 B (+0.02%)
🟡 agents/chat#createToolsFromClientSchemas 114.3 KiB 114.3 KiB +6 B (+0.01%)
🟢 agents/schedules#Scheduler 7.0 KiB 6.8 KiB -212 B (-2.96%)
🟢 agents/tasks#MissingTaskDefinitionError 359 B 358 B -1 B (-0.28%)
🟢 agents/chat#cleanupStreamBuffers 2.3 KiB 2.3 KiB -1 B (-0.04%)
🟢 agents/chat#buildInClauseStrings 2.4 KiB 2.4 KiB -1 B (-0.04%)
🟢 agents/chat#MessageType 2.4 KiB 2.4 KiB -1 B (-0.04%)
🟢 agents/chat#PreStreamTurns 2.6 KiB 2.6 KiB -1 B (-0.04%)
🟢 agents/chat#createChatTurnTaskDefinition 2.6 KiB 2.6 KiB -1 B (-0.04%)
🟢 agents/chat#applyAgentToolEvent 3.2 KiB 3.2 KiB -1 B (-0.03%)
agents/chat#CHAT_RECOVERY_TASK_NAME 2.3 KiB
agents/chat#chatRecoveryTaskRunOptions 2.4 KiB
agents/chat#createChatRecoveryTaskDefinition 2.6 KiB
agents/chat#dispatchChatRecoveryToHandoff 3.0 KiB
🟢 agents/chat#chatRecoveryRedeferPolicy 2.3 KiB
🟢 agents/chat#chatRecoverySchedulePolicy 2.3 KiB
All 287 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.6 KiB 9.5 KiB
agents/chat#AgentToolStreamProgressThrottle 2.3 KiB 8.3 KiB
agents/chat#aiSdkRecoveryCodec 2.3 KiB 8.2 KiB
🟢 agents/chat#applyAgentToolEvent 3.2 KiB 10.9 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.1 KiB 11.4 KiB
🟡 agents/chat#buildChatRecoveringFrame 2.4 KiB 8.3 KiB
🟢 agents/chat#buildInClauseStrings 2.4 KiB 8.4 KiB
🟡 agents/chat#bumpChatRecoveryProgress 2.3 KiB 8.3 KiB
agents/chat#byteLength 2.3 KiB 8.2 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.2 KiB
agents/chat#chatRecoveryTaskRunOptions 2.4 KiB 8.5 KiB
agents/chat#ChatStreamStalledError 2.3 KiB 8.3 KiB
🟡 agents/chat#classifyAgentToolChildRecovery 2.4 KiB 8.5 KiB
🟢 agents/chat#cleanupStreamBuffers 2.3 KiB 8.2 KiB
🟡 agents/chat#clearChatTerminal 2.3 KiB 8.2 KiB
agents/chat#clientResolvableToolNames 2.3 KiB 8.3 KiB
🟡 agents/chat#ContinuationState 2.6 KiB 9.8 KiB
agents/chat#createAgentToolEventState 2.3 KiB 8.2 KiB
agents/chat#createChatFiberSnapshot 2.4 KiB 8.6 KiB
agents/chat#createChatRecoveryTaskDefinition 2.6 KiB 9.0 KiB
🟡 agents/chat#createChatStreams 5.5 KiB 19.3 KiB
🟢 agents/chat#createChatTurnTaskDefinition 2.6 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.3 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.4 KiB 11.0 KiB
🟡 agents/chat#hasIncompleteToolBatch 2.4 KiB 8.6 KiB
🟡 agents/chat#interceptAgentToolBroadcast 2.5 KiB 8.6 KiB
agents/chat#isPlatformFailure 2.6 KiB 8.9 KiB
agents/chat#isReplayChunk 2.4 KiB 8.6 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.5 KiB
agents/chat#pausedExecutionUpdate 2.4 KiB 8.4 KiB
agents/chat#pendingChatTerminal 2.3 KiB 8.3 KiB
agents/chat#persistReconstructedOrphan 3.0 KiB 11.0 KiB
🟢 agents/chat#PreStreamTurns 2.6 KiB 9.2 KiB
agents/chat#readChatRecoveryProgress 2.3 KiB 8.3 KiB
🟡 agents/chat#reconcileMessages 2.8 KiB 9.5 KiB
agents/chat#reconcileOrphanPartial 2.4 KiB 8.4 KiB
🟡 agents/chat#recordChatTerminal 2.3 KiB 8.3 KiB
agents/chat#repairInterruptedToolParts 2.6 KiB 9.1 KiB
agents/chat#resolveChatRecoveryConfig 2.5 KiB 8.9 KiB
agents/chat#resolveToolMergeId 2.4 KiB 8.5 KiB
agents/chat#ResumableStream 4.6 KiB 15.3 KiB
agents/chat#ResumeHandshake 2.9 KiB 10.4 KiB
agents/chat#ROW_MAX_BYTES 2.3 KiB 8.2 KiB
agents/chat#runChatRecoveryExhaustion 2.5 KiB 8.9 KiB
agents/chat#sanitizeMessage 2.5 KiB 9.0 KiB
agents/chat#sendIfOpen 2.4 KiB 8.3 KiB
agents/chat#setChatRecovering 2.4 KiB 8.5 KiB
agents/chat#shouldCreditStreamProgress 2.3 KiB 8.3 KiB
agents/chat#STREAM_CLEANUP_DELAY_SECONDS 2.3 KiB 8.2 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.3 KiB 8.3 KiB
agents/chat#SubmitConcurrencyController 2.9 KiB 10.2 KiB
agents/chat#sweepStaleChatRecoveryIncidents 2.4 KiB 8.4 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.3 KiB
agents/chat#toolResultUpdate 2.4 KiB 8.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/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/memory/session#AgentContextProvider 425 B 810 B
agents/experimental/memory/session#AgentSearchProvider 821 B 2.0 KiB
agents/experimental/memory/session#AgentSessionProvider 2.5 KiB 8.8 KiB
agents/experimental/memory/session#isSearchProvider 128 B 134 B
agents/experimental/memory/session#isSkillProvider 127 B 130 B
agents/experimental/memory/session#isWritableProvider 126 B 128 B
agents/experimental/memory/session#PostgresContextProvider 422 B 671 B
agents/experimental/memory/session#PostgresSearchProvider 630 B 1.1 KiB
agents/experimental/memory/session#PostgresSessionProvider 1.7 KiB 5.3 KiB
agents/experimental/memory/session#R2SkillProvider 436 B 791 B
agents/experimental/memory/session#Session 93.4 KiB 454.0 KiB
agents/experimental/memory/session#SessionManager 94.5 KiB 460.1 KiB
agents/experimental/memory/utils#alignBoundaryBackward 291 B 584 B
agents/experimental/memory/utils#alignBoundaryForward 275 B 539 B
agents/experimental/memory/utils#buildSummaryPrompt 867 B 2.0 KiB
agents/experimental/memory/utils#CHARS_PER_TOKEN 51 B 31 B
agents/experimental/memory/utils#COMPACTION_PREFIX 63 B 43 B
agents/experimental/memory/utils#computeSummaryBudget 363 B 634 B
agents/experimental/memory/utils#createCompactFunction 1.8 KiB 4.2 KiB
agents/experimental/memory/utils#estimateMessageTokens 336 B 567 B
agents/experimental/memory/utils#estimateStringTokens 142 B 145 B
agents/experimental/memory/utils#findTailCutByTokens 597 B 1.3 KiB
agents/experimental/memory/utils#isCompactionMessage 98 B 83 B
agents/experimental/memory/utils#sanitizeToolPairs 537 B 1.1 KiB
agents/experimental/memory/utils#TOKENS_PER_MESSAGE 51 B 31 B
agents/experimental/memory/utils#truncateOlderMessages 1022 B 2.2 KiB
agents/experimental/memory/utils#WORDS_TOKEN_MULTIPLIER 53 B 33 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/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 397.5 KiB 1513.3 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 83 B 81 B
agents/streams#sseResponse 843 B 1.6 KiB
agents/streams#StreamClosedError 161 B 197 B
agents/streams#StreamNotFoundError 201 B 261 B
agents/streams#Streams 3.4 KiB 11.1 KiB
agents/streams#StreamSerializationError 158 B 186 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.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 1 new potential issue.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment on lines +442 to +453
this.#store.write(
`UPDATE cf_agents_task_runs
SET generation = NULL,
next_at = CASE
WHEN next_at IS NULL OR next_at < ? THEN ?
ELSE next_at
END,
updated_at = ?
WHERE run_id = ?
AND state IN ('pending', 'waiting', 'running')`,
[context.nextTime, context.nextTime, now, runId]
);

@devin-ai-integration devin-ai-integration Bot Sep 2, 2026

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.

🟡 Memory retries ignore breaker backoff

When a Task exceeds memory, onMemoryLimit preserves its later claim deadline. Recovery waits minutes or longer instead of the breaker's 30–90 seconds.

Devin Review

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

cf_agents_jobs (and its recovery_loop column) has never shipped in a
release — the whole table was introduced in this same unreleased branch
(#2175, then extended with recovery_loop in #2190/#2194). No deployed
Durable Object can have this table without the column already present:
CREATE TABLE IF NOT EXISTS already includes it in the same statement. The
pragma_table_info probe + ALTER TABLE fallback was defending against a
schema history that cannot exist yet.

Removes the dead branch, its regression test (which only proved the
migration path itself, not anything a real caller depends on), and the
two doc/changeset sentences describing it.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
…heduler bridge

Tasks now mirrors a routed sub-agent's run deadline to the root's job
queue while the run row and step journal stay put: only the root owns
the physical alarm, so only the wake needs to cross that boundary.
onRoute handles syncWake/dispatch/memoryLimit; a routed strike forwards
to the owning facet's own onAlarmMemoryLimit hook, the same bridge
Scheduler already used, since the facet's own Lifecycle never observes
the root's alarm directly.

AIChatAgent and Think's _enqueueChatRecovery now always uses Tasks,
removing the parentPath-gated Scheduler fallback and the now-dead
chatRecoverySchedulePolicy/chatRecoveryRedeferPolicy helpers.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

Fixes a typecheck failure in packages/ai-chat/src/tests/tsconfig.json
CI caught: the test-only OOM Task definition added in the routed-wake
work needed the child's own constructor to register it, which used
AgentContext without importing it.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

- onRoute's "dispatch" case awaited #executeRun directly, bypassing
  onJob's active-run claim refresh and its five-second dispatch
  budget. A routed run already active on the facet lost its wake when
  the root's mirror job settled with no reschedule, and a long-running
  routed handler blocked the root's whole alarm cycle. Extracted the
  shared bounded-dispatch logic into #dispatchRun, used by both onJob
  locally and onRoute's "dispatch" case, whose wake outcome now flows
  back as the RPC's own return value instead of being discarded.

- onMemoryLimit only forwarded a routed run's SEALED strike to its
  owning facet. A non-sealed strike backed off the root's mirror job
  but left the facet's own claim (generation, next_at) untouched;
  any facet startup before the backoff elapsed read that claim as an
  interrupted attempt and reconciled it due again now, resurrecting
  the run through the breaker. Forward every strike, sealed or not.

Verified the backoff fix is real: reverting to sealed-only forwarding
reproduces the failure (generation stays set) in the new
"backs off a routed facet's own claim" test. The active-run and
dispatch-budget fixes reuse #dispatchRun verbatim from the local path,
already covered by the existing local dispatch tests; a dedicated
routed-side regression test for the concurrent-active and >5s-budget
cases was not added given the cost of reliably constructing those
races across a real DO-RPC boundary in this harness.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

…ancel stale wakes on facet deletion

Two more Devin-flagged bugs in the routed-Tasks work:

- Routed tasks bypassed the memory breaker. A routed dispatch that
  exceeded the five-second budget called trackAlarmWork from inside
  onRoute on the facet, but that call only attaches to a live alarm
  invocation's AsyncLocalStorage scope — onRoute runs in response to
  an incoming RPC, not the facet's own alarm, so the call silently
  did nothing. Every redispatch of a routed run goes through this
  same path (root owns the physical alarm), so a routed run that
  regularly overran the budget could OOM repeatedly without the
  breaker ever seeing it.

  Moved the budget race to the root side instead: root now races its
  own await of the routed RPC call, and on budget keeps the
  still-pending call itself tracked via trackAlarmWork, which works
  because onJob runs inside root's own live alarm scope. The facet's
  onRoute dispatch handler no longer needs its own budget or tracking
  at all — it just fully awaits, since the call keeps running on the
  facet regardless of whether root is still waiting on it.

  Verified this is actually safe with a deployed repro (not simulated
  via ctx.abort(), which is deliberately deferred and wouldn't reject
  an in-flight caller): a callee DO whose isolate is killed by the
  platform's real memory-limit enforcement while mid-flight on an RPC
  call reliably rejects the caller's pending promise with the
  platform's own "exceeded its memory limit" text — exactly what the
  breaker already matches on. Confirmed across 3 trials against a
  real deployment, then deleted the repro worker.

  Added a regression test whose failure lands after root's own
  budget elapses (a real >5s delay, not a simulated abort) and
  confirmed it fails when reverted to the old (silently-inert)
  tracking call.

- Deleting a facet left its routed Task wake mirrored on the root
  forever, since only Scheduler's routed rows were cleaned up on
  facet-subtree deletion. Added the same
  __DO_NOT_USE_WILL_BREAK__cleanupRoutePrefix aperture to Tasks,
  mirroring Scheduler's, and wired it into the same cleanupPrefix
  call site.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

…; retry a failed post-handoff redefer

Two more Devin-flagged bugs from the latest routed-Tasks review pass:

- Once root started racing its own await of a routed dispatch (the
  RPC-tracking fix earlier today), a budget win now returns undefined
  as root's own job outcome. JobDriver deletes the mirror job on an
  undefined outcome — but only when the row is still marked "running"
  from that same dispatch. #executeRun now pushes the claim deadline
  via #syncWake immediately after claiming, before the handler runs:
  that push clears the row's in-flight marker (job-queue's own
  "newer durable intent wins" guard), so root's later stale undefined
  outcome no-ops against it instead of deleting a still-live claim. A
  hung or interrupted routed attempt keeps its alarm either way now,
  independent of whether this specific attempt happens to settle
  cleanly, fail, or never resolve at all.

- dispatchChatRecoveryToHandoff swallowed a failed post-handoff
  redefer entirely. The Task that dispatched it has already settled
  by the time redefer runs, so nothing else owned that incident —
  a transient failure to enqueue the replacement abandoned recovery
  silently. Wrapped it in a bounded retry (tryN, 3 attempts) and
  surface the final failure through the same onDetachedError channel
  an unowned detached failure already uses, rather than a bare
  swallowed catch.

Both verified non-vacuous: reverting each fix reproduces the exact
failure Devin described (the mirror job actually gets deleted; the
redefer failure is actually silent) in new regression tests, then
passes again restored. The claim-mirroring test uses a real 6.5s
delayed failure, not a simulated one.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

…duplicate runs

The redefer retry added last commit (tryN, 3 attempts) has its own bug:
Tasks acceptance can throw after already durably inserting the run row —
most likely on the wake-mirror push, not the insert itself — so a
rejected enqueue does not prove nothing was created. Retrying the same
unkeyed "redefer" enqueue (intentionally unkeyed for a genuinely new
attempt, per chatRecoveryTaskRunOptions) could create up to three
replacement runs for one incident instead of joining the first.

dispatchChatRecoveryToHandoff now generates one dedupe key per failure
and passes it to every retried redefer call; chatRecoveryTaskRunOptions
keys the run by it (runId) when supplied, so a retry after a partial
success joins that same row instead of duplicating it. Verified
non-vacuous: reverting chatRecoveryTaskRunOptions's use of the key
reproduces exactly the gap in the new "keys the run by dedupeKey" test.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
devin-ai-integration[bot]

This comment was marked as resolved.

…sting run

The dedupe fix from the last commit prevents a retried enqueue from
creating a duplicate run, but joining the existing row alone doesn't
help if that row's wake was never durably pushed in the first place.
#accept can throw after already inserting the run — most likely on the
wake-mirror #syncWake call itself, not the insert — so a retry that
finds the existing row and returns accepted:false was reporting success
against a run nothing would ever wake again.

The join branch now calls #syncWake before returning, for every caller
(runId or idempotencyKey match), not just chat recovery's retried
redefer — any Tasks caller retrying acceptance after a partial failure
benefits the same way. Cheap in the common case (#syncWake already
no-ops when the mirror already matches).

Verified non-vacuous: reverting the added #syncWake call and rerunning
the new "repairs a missing wake mirror" capability test reproduces the
gap exactly — the mirror job stays missing after the retry joins the
run.

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB
…imit bridge

Scheduler's routed memory-limit compatibility bridge existed to deliver
a sealed strike to a dynamic agent whose chat-recovery schedule row was
purged, back when routed chat recovery ran on Scheduler. Chat recovery
now always uses Tasks (this PR), which has its own routed memory-limit
bridge (setTaskRoutedMemoryLimitHandler), so this path carries no live
traffic. Removed setSchedulerRoutedMemoryLimitHandler, the WeakMap
backing it, the "memoryLimit" SchedulerRouteMessage variant, and
Scheduler's onMemoryLimit/onRoute handling of it, plus Agent's wiring.

Deliberately left in place: LEGACY_RECOVERY_LOOP_CALLBACKS' migration
of pre-existing legacy schedule rows (still needed regardless of
routing, so the local alarm breaker still counts them), and
MemoryLimitContext.purgedRecoveryLoopJobs itself (now unread by any
capability, but a generic hook a future routed capability with
purge-as-a-pack semantics could still use — Tasks backs off one run
at a time instead).

Full suites still pass (2012 agents, 661 ai-chat, 888 think).

Claude-Session: https://claude.ai/code/session_011DVPXpp9SyXM1ChxvkQCTB

@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 1 new potential issue.

4 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

* the owning capability and delete this bridge.
*/
async onMemoryLimit(context: MemoryLimitContext): Promise<void> {
if (!context.sealed) 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.

🟡 Legacy child recovery never terminalizes

When a migrated routed recovery schedule seals after repeated memory resets, missing onMemoryLimit routing leaves its child chat active. Users remain stuck in recovery.

Prompt for agents
Preserve terminal memory-limit delivery for routed Scheduler recovery rows that can survive an upgrade. Existing _chatRecoveryContinue and _chatRecoveryRetry rows remain in the root Lifecycle queue with owner_path and recoveryLoop set. If one seals the breaker, the root purges it, while the recovery incident lives on the dynamic-agent owner. Restore an equivalent routed sealing bridge across packages/agents/src/schedules/scheduler.ts and packages/agents/src/index.ts, or add a migration/drain mechanism that guarantees no routed legacy recovery row can still execute before removing the bridge.
Devin Review

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a known, deliberate tradeoff, not an oversight — flagged before removing the bridge and confirmed. You're right about the exact consequence: a legacy routed _chatRecoveryContinue/_chatRecoveryRetry row, if one still exists on a fleet that hasn't restarted since before this PR, purges silently on seal instead of notifying its owning facet, since Scheduler no longer forwards that strike.

Restoring the bridge or adding a formal drain guarantee is more machinery to keep a narrowing, already-legacy population correctly draining, for a scenario (a routed schedule row surviving from before Tasks took over routed chat recovery, AND that specific row hitting the breaker's seal threshold) that's already rare and only gets rarer. The call here was to accept it rather than carry the compatibility bridge indefinitely — leaving it not resolved so it's visible to reviewers rather than resolving it myself.

@mattzcarey
mattzcarey merged commit 6da4c44 into main Sep 2, 2026
18 checks passed
@mattzcarey
mattzcarey deleted the feat/replatform-chat-recovery-on-tasks branch September 2, 2026 18:16
@github-actions github-actions Bot mentioned this pull request Sep 2, 2026
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