fix(tui): keep stream cadence responsive while typing
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import type { ScrollBoxHandle } from '@hermes/ink'
|
import type { ScrollBoxHandle } from '@hermes/ink'
|
||||||
|
|
||||||
import type { SelectionApi } from './interfaces.js'
|
import type { SelectionApi } from './interfaces.js'
|
||||||
import { markScrolling } from './interactionMode.js'
|
|
||||||
|
|
||||||
export interface SelectionSnap {
|
export interface SelectionSnap {
|
||||||
anchor?: { row: number } | null
|
anchor?: { row: number } | null
|
||||||
@@ -30,8 +29,6 @@ export function scrollWithSelectionBy(delta: number, { scrollRef, selection }: S
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
markScrolling()
|
|
||||||
|
|
||||||
const sel = selection.getState() as null | SelectionSnap
|
const sel = selection.getState() as null | SelectionSnap
|
||||||
const top = s.getViewportTop()
|
const top = s.getViewportTop()
|
||||||
const bottom = top + viewport - 1
|
const bottom = top + viewport - 1
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {
|
|||||||
REASONING_PULSE_MS,
|
REASONING_PULSE_MS,
|
||||||
STREAM_BATCH_MS,
|
STREAM_BATCH_MS,
|
||||||
STREAM_IDLE_BATCH_MS,
|
STREAM_IDLE_BATCH_MS,
|
||||||
STREAM_SCROLLING_BATCH_MS,
|
|
||||||
STREAM_TYPING_BATCH_MS
|
STREAM_TYPING_BATCH_MS
|
||||||
} from '../config/timing.js'
|
} from '../config/timing.js'
|
||||||
import type { SessionInterruptResponse, SubagentEventPayload } from '../gatewayTypes.js'
|
import type { SessionInterruptResponse, SubagentEventPayload } from '../gatewayTypes.js'
|
||||||
@@ -16,7 +15,6 @@ import {
|
|||||||
} from '../lib/text.js'
|
} from '../lib/text.js'
|
||||||
import type { ActiveTool, ActivityItem, Msg, SubagentProgress } from '../types.js'
|
import type { ActiveTool, ActivityItem, Msg, SubagentProgress } from '../types.js'
|
||||||
|
|
||||||
import { getInteractionMode } from './interactionMode.js'
|
|
||||||
import { resetFlowOverlays } from './overlayStore.js'
|
import { resetFlowOverlays } from './overlayStore.js'
|
||||||
import { pushSnapshot } from './spawnHistoryStore.js'
|
import { pushSnapshot } from './spawnHistoryStore.js'
|
||||||
import { getTurnState, patchTurnState, resetTurnState } from './turnStore.js'
|
import { getTurnState, patchTurnState, resetTurnState } from './turnStore.js'
|
||||||
@@ -504,15 +502,12 @@ class TurnController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const interaction = getInteractionMode()
|
|
||||||
const delay = interaction === 'scrolling' ? STREAM_SCROLLING_BATCH_MS : interaction === 'typing' ? STREAM_TYPING_BATCH_MS : this.streamDelay
|
|
||||||
|
|
||||||
this.streamTimer = setTimeout(() => {
|
this.streamTimer = setTimeout(() => {
|
||||||
this.streamTimer = null
|
this.streamTimer = null
|
||||||
const raw = this.bufRef.trimStart()
|
const raw = this.bufRef.trimStart()
|
||||||
const visible = hasReasoningTag(raw) ? splitReasoning(raw).text : raw
|
const visible = hasReasoningTag(raw) ? splitReasoning(raw).text : raw
|
||||||
patchTurnState({ streaming: visible })
|
patchTurnState({ streaming: visible })
|
||||||
}, delay)
|
}, this.streamDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
startMessage() {
|
startMessage() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { type MutableRefObject, useCallback, useEffect, useRef } from 'react'
|
import { type MutableRefObject, useCallback, useEffect, useRef } from 'react'
|
||||||
|
|
||||||
|
import { TYPING_IDLE_MS } from '../config/timing.js'
|
||||||
import { attachedImageNotice } from '../domain/messages.js'
|
import { attachedImageNotice } from '../domain/messages.js'
|
||||||
import { looksLikeSlashCommand } from '../domain/slash.js'
|
import { looksLikeSlashCommand } from '../domain/slash.js'
|
||||||
import type { GatewayClient } from '../gatewayClient.js'
|
import type { GatewayClient } from '../gatewayClient.js'
|
||||||
@@ -10,7 +11,6 @@ import { PASTE_SNIPPET_RE } from '../protocol/paste.js'
|
|||||||
import type { Msg } from '../types.js'
|
import type { Msg } from '../types.js'
|
||||||
|
|
||||||
import type { ComposerActions, ComposerRefs, ComposerState, PasteSnippet } from './interfaces.js'
|
import type { ComposerActions, ComposerRefs, ComposerState, PasteSnippet } from './interfaces.js'
|
||||||
import { markTyping } from './interactionMode.js'
|
|
||||||
import { turnController } from './turnController.js'
|
import { turnController } from './turnController.js'
|
||||||
import { getUiState, patchUiState } from './uiStore.js'
|
import { getUiState, patchUiState } from './uiStore.js'
|
||||||
|
|
||||||
@@ -48,13 +48,28 @@ export function useSubmission(opts: UseSubmissionOptions) {
|
|||||||
} = opts
|
} = opts
|
||||||
|
|
||||||
const lastEmptyAt = useRef(0)
|
const lastEmptyAt = useRef(0)
|
||||||
|
const typingIdleTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (composerState.input || composerState.inputBuf.length) {
|
if (composerState.input || composerState.inputBuf.length) {
|
||||||
markTyping()
|
|
||||||
if (getUiState().busy) {
|
if (getUiState().busy) {
|
||||||
turnController.boostStreamingForTyping()
|
turnController.boostStreamingForTyping()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typingIdleTimer.current) {
|
||||||
|
clearTimeout(typingIdleTimer.current)
|
||||||
|
}
|
||||||
|
|
||||||
|
typingIdleTimer.current = setTimeout(() => {
|
||||||
|
typingIdleTimer.current = null
|
||||||
|
turnController.relaxStreaming()
|
||||||
|
}, TYPING_IDLE_MS)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (typingIdleTimer.current) {
|
||||||
|
clearTimeout(typingIdleTimer.current)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [composerState.input, composerState.inputBuf])
|
}, [composerState.input, composerState.inputBuf])
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
export const STREAM_BATCH_MS = 16
|
export const STREAM_BATCH_MS = 16
|
||||||
export const STREAM_IDLE_BATCH_MS = 16
|
export const STREAM_IDLE_BATCH_MS = 16
|
||||||
export const STREAM_SCROLLING_BATCH_MS = 250
|
export const STREAM_TYPING_BATCH_MS = 80
|
||||||
export const STREAM_TYPING_BATCH_MS = 120
|
|
||||||
export const TYPING_IDLE_MS = 250
|
export const TYPING_IDLE_MS = 250
|
||||||
export const SCROLLING_IDLE_MS = 450
|
export const SCROLLING_IDLE_MS = 450
|
||||||
export const REASONING_PULSE_MS = 700
|
export const REASONING_PULSE_MS = 700
|
||||||
|
|||||||
Reference in New Issue
Block a user