fix(core): broadcast channel output for runs without inbound request context#18553
fix(core): broadcast channel output for runs without inbound request context#18553CalebBarnes wants to merge 1 commit into
Conversation
…context ChatChannelOutputProcessor previously only rendered to the channel when AgentChannels stashed a render context on requestContext during an inbound platform webhook. Heartbeat, Studio, and custom-UI/user-code runs on a channel-backed thread therefore never posted back. Bind the owning AgentChannels into the processor and add a fallback: when no inbound render context exists, reconstruct it from the run's threadId via buildRenderContextForThread, which reads the thread's persisted channel coordinates and delegates to the same _buildRenderContext used by the inbound paths. The resolved context (or null for non-channel threads) is cached on state so it is built once per run. Co-Authored-By: Mastra Code (anthropic/claude-opus-4-8) <noreply@mastra.ai>
🦋 Changeset detectedLatest commit: 7e6ca73 The changes in this PR will be included in the next version bump. This PR includes changesets to release 22 packages
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 |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
Superseded by #18630, which collapses this two-PR stack into a single self-contained PR. Instead of threading new identity fields through the whole processor surface (old #18552), #18630 reads the run's threadId from the framework-populated |
What this ships
Agent runs on a channel-backed thread (Slack, Discord, etc.) now post their output back to the channel even when the run did not start from an inbound platform message. Heartbeat-triggered runs, Studio runs, and custom-UI / user-code runs against a channel thread previously produced no channel output at all — they were silently dropped.
Why
ChatChannelOutputProcessoronly rendered to the channel whenAgentChannelsstashed a render context onrequestContextduring an inbound webhook (processChatMessage, approve/decline). Any run that did not originate from a platform message had no such context, so the processor early-returned and nothing reached the channel. Channel delivery was effectively coupled to the inbound request path.How
ChatChannelOutputProcessoris now bound to its owningAgentChannelsat construction.threadId(provided by the processor-identity work) via a newAgentChannels.buildRenderContextForThread(threadId). That method reads the thread's persisted channel coordinates (channel_platform,channel_externalThreadId), materializes the live channel thread handle, and delegates to the same_buildRenderContextthe inbound paths use — so both paths produce an identical render context (single source of truth).requestContextpath is unchanged and still takes precedence (fast path).null) is cached onstateso it is built once per run, not per chunk.Nothing new is persisted: every non-serializable field (adapter, closures, logger) is rebuilt live from the bound
AgentChannels.Stacking
Stacked on #18552 (processor context identity), which threads
threadIdto the output processor. This PR targets that branch and stays a draft until #18552 merges.Test plan
pnpm build:corepnpm --filter ./packages/core check(typecheck clean)pnpm --filter ./packages/core test -- src/channels/— all 238 channels tests pass, including 5 new fallback tests inoutput-processor.test.ts:requestContextkeythreadIdis providedrequestContextrender context over the fallback (no regression)