You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Think: public accessor for the admitted turn's request id and trigger #2218
We run a Think subclass (@cloudflare/think 0.17.0, agents 0.22.0) as a per-tenant site manager. Turns arrive from several doors at once: the WebSocket chat, an email channel, alarm-driven proactive turns, and runTurn calls from our own tools. Per-turn state (which channel is speaking, which actor, the trace collector, attachments) has to be keyed by the turn that is actually running, because a channel body can be waiting on the queue while a WebSocket chat turn runs ahead of it.
The one identity every hook and tool call inside a turn shares is the request id the TurnQueue is running. Today we reach it, and two neighbours, through private fields:
this._turnQueue.activeRequestId. Think declares private _turnQueue; the TurnQueue class from agents/chat exposes activeRequestId publicly (set before the admitted body, cleared in its finally), but the queue instance itself is private.
this._turnQueue.enqueue(name, fn), to serialise our own post-publish work behind the chat turn (the detached-delivery pattern, inside keepAliveWhile).
this._cf_sealMemoryLimitedRecovery() (protected), to seal a still-live recovery incident when our own alarm strike counter trips.
A fourth value we cannot reach at all: the admitted turn's trigger (ws-chat, rpc, programmatic, agent-tool, auto-continuation, ...). It lives in the module-private admittedTurnContextAsyncLocalStorage in think.js and is not exposed on TurnContext, on activeTurnMetadata (empty on dashboard WebSocket turns), or on any hook argument. We need it to tell "the chat door's turn is running" from "our channel body's turn is running" when the two race.
We have wrapped all of these in one adapter module with a version pin that fails our typecheck on a bump, so nothing here is urgent for us. It would be better for everyone if the reads were public.
Ask
A public, documented accessor on Think (or Agent) for the admitted turn, something like:
readable from beforeTurn, prepareStep, tool execute and onChatResponse, and undefined outside any turn. Exporting TurnTrigger from @cloudflare/think would help too. A public way to enqueue work behind the current turn (enqueueTurn(name, fn) or similar) would remove the second private read.
+1 from our conversation submission/Stop integration. Rechecked source on 2026-09-15 in Think 0.18.0 (release 5f7ad7e4edac2ec8dd1d6a31758f251cb52373fa) and main a7b29135acf127cdf4a44114652970d0a22300de.
activeTurnMetadata still delegates to _turnMetadataFromMessages, which reads the latest user message's turnMetadata, rather than an immutable identity owned by the admitted turn or interaction.
Our use case includes approval A answered after a later user message B has been persisted. Latest-user metadata then identifies B; it is not proof of A's origin. We reconstruct approval ownership from the preceding user message and explicitly settle pre-Stop approvals. Existing supersession repair may prevent stale execution, so this is not a claim that we reproduced an approval safety bypass in 0.18.0. The missing public contract is interaction-owned provenance independent of that internal repair.
Please include originating request/submission identity and server-owned turn metadata for approval/tool-result continuations, preserved across eviction, alongside the admitted turn correlator. This would let a durable work-epoch fence use the actual origin instead of transcript position. Validation here is source/API inspection; our current application pins are Think 0.17.0 / agents 0.22.0 / ai-chat 0.11.0.
Also related: #2127. An accessor for the currently admitted turn should distinguish that turn from the originating interaction when a continuation resumes older work.
Activity
ternarybits commentedon Sep 15, 2026
+1 from our conversation submission/Stop integration. Rechecked source on 2026-09-15 in Think 0.18.0 (release
5f7ad7e4edac2ec8dd1d6a31758f251cb52373fa) and maina7b29135acf127cdf4a44114652970d0a22300de.activeTurnMetadatastill delegates to_turnMetadataFromMessages, which reads the latest user message'sturnMetadata, rather than an immutable identity owned by the admitted turn or interaction.Our use case includes approval A answered after a later user message B has been persisted. Latest-user metadata then identifies B; it is not proof of A's origin. We reconstruct approval ownership from the preceding user message and explicitly settle pre-Stop approvals. Existing supersession repair may prevent stale execution, so this is not a claim that we reproduced an approval safety bypass in 0.18.0. The missing public contract is interaction-owned provenance independent of that internal repair.
Please include originating request/submission identity and server-owned turn metadata for approval/tool-result continuations, preserved across eviction, alongside the admitted turn correlator. This would let a durable work-epoch fence use the actual origin instead of transcript position. Validation here is source/API inspection; our current application pins are Think 0.17.0 / agents 0.22.0 / ai-chat 0.11.0.
Also related: #2127. An accessor for the currently admitted turn should distinguish that turn from the originating interaction when a continuation resumes older work.
feat(think): expose the running turn's identity to hooks and tools (#…