MCPcopy Create free account
hub / github.com/claude-code-best/claude-code / handleMessageFromStream

Function handleMessageFromStream

src/utils/messages.ts:3285–3483  ·  view source on GitHub ↗
(
  message:
    | Message
    | TombstoneMessage
    | StreamEvent
    | RequestStartEvent
    | ToolUseSummaryMessage,
  onMessage: (message: Message) => void,
  onUpdateLength: (newContent: string) => void,
  onSetStreamMode: (mode: SpinnerMode) => void,
  onStreamingToolUses: (
    f: (streamingToolUse: StreamingToolUse[]) => StreamingToolUse[],
  ) => void,
  onTombstone?: (message: Message) => void,
  onStreamingThinking?: (
    f: (current: StreamingThinking | null) => StreamingThinking | null,
  ) => void,
  onApiMetrics?: (metrics: { ttftMs: number }) => void,
  onStreamingText?: (f: (current: string | null) => string | null) => void,
)

Source from the content-addressed store, hash-verified

3283 * Handles messages from a stream, updating response length for deltas and appending completed messages
3284 */
3285export function handleMessageFromStream(
3286 message:
3287 | Message
3288 | TombstoneMessage
3289 | StreamEvent
3290 | RequestStartEvent
3291 | ToolUseSummaryMessage,
3292 onMessage: (message: Message) => void,
3293 onUpdateLength: (newContent: string) => void,
3294 onSetStreamMode: (mode: SpinnerMode) => void,
3295 onStreamingToolUses: (
3296 f: (streamingToolUse: StreamingToolUse[]) => StreamingToolUse[],
3297 ) => void,
3298 onTombstone?: (message: Message) => void,
3299 onStreamingThinking?: (
3300 f: (current: StreamingThinking | null) => StreamingThinking | null,
3301 ) => void,
3302 onApiMetrics?: (metrics: { ttftMs: number }) => void,
3303 onStreamingText?: (f: (current: string | null) => string | null) => void,
3304): void {
3305 if (
3306 message.type !== 'stream_event' &&
3307 message.type !== 'stream_request_start'
3308 ) {
3309 // Handle tombstone messages - remove the targeted message instead of adding
3310 if (message.type === 'tombstone') {
3311 onTombstone?.(message.message as unknown as Message)
3312 return
3313 }
3314 // Tool use summary messages are SDK-only, ignore them in stream handling
3315 if (message.type === 'tool_use_summary') {
3316 return
3317 }
3318 // Capture complete thinking blocks for real-time display in transcript mode
3319 if (message.type === 'assistant') {
3320 const assistMsg = message as Message
3321 const contentArr = Array.isArray(assistMsg.message?.content)
3322 ? assistMsg.message.content
3323 : []
3324 const thinkingBlock = contentArr.find(
3325 block => typeof block !== 'string' && block.type === 'thinking',
3326 )
3327 if (
3328 thinkingBlock &&
3329 typeof thinkingBlock !== 'string' &&
3330 thinkingBlock.type === 'thinking'
3331 ) {
3332 const tb = thinkingBlock as ThinkingBlock
3333 onStreamingThinking?.(() => ({
3334 thinking: tb.thinking,
3335 isStreaming: false,
3336 streamingEndedAt: Date.now(),
3337 }))
3338 }
3339 }
3340 // Clear streaming text NOW so the render can switch displayedMessages
3341 // from deferredMessages to messages in the same batch, making the
3342 // transition from streaming text → final message atomic (no gap, no duplication).

Callers 3

execAgentHookFunction · 0.85
REPLFunction · 0.85
useRemoteSessionFunction · 0.85

Calls 3

isConnectorTextBlockFunction · 0.85
nowMethod · 0.80
onMessageFunction · 0.50

Tested by

no test coverage detected