#42178 dropped every session-scoped gateway event that arrived without an explicit session_id, to stop background activity attaching to the focused chat. But the gateway already stamps background sessions with their own id, so an unscoped message/reasoning/tool/prompt event can only be the focused turn's own output. Dropping those swallowed the live answer — it reappeared only after a transcript refetch (manual refresh). Narrow the guard to subagent.* (the only genuinely background/async family); everything else falls back to the active session as before.
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
import type { StatusbarMenuItem } from '@/app/shell/statusbar-controls'
|
|
|
|
const LOG_TAIL = 5
|
|
|
|
interface RpcEventLike {
|
|
payload?: unknown
|
|
type?: string
|
|
}
|
|
|
|
function asRecord(payload: unknown): Record<string, unknown> {
|
|
return payload && typeof payload === 'object' ? (payload as Record<string, unknown>) : {}
|
|
}
|
|
|
|
/**
|
|
* Whether an unscoped event (no `session_id`) must be dropped rather than
|
|
* attributed to the focused chat.
|
|
*
|
|
* Only `subagent.*` qualifies: it describes background/async work that must
|
|
* never attach to whichever chat happens to be focused. Every other scoped
|
|
* event — message/reasoning/thinking/tool/status/prompt — is, when unscoped,
|
|
* the active turn's own output. The gateway always stamps a *background*
|
|
* session's events with that session's id, so a missing id can only mean "the
|
|
* focused turn". #42178 dropped those too, which silently swallowed the live
|
|
* answer; it then reappeared only after a transcript refetch (manual refresh).
|
|
*/
|
|
export function gatewayEventRequiresSessionId(eventType: string | undefined): boolean {
|
|
return eventType?.startsWith('subagent.') ?? false
|
|
}
|
|
|
|
export function gatewayEventCompletedFileDiff(event: RpcEventLike): boolean {
|
|
if (event.type !== 'tool.complete') {
|
|
return false
|
|
}
|
|
|
|
const diff = asRecord(event.payload).inline_diff
|
|
|
|
return typeof diff === 'string' && diff.trim().length > 0
|
|
}
|
|
|
|
export function buildGatewayLogItems(lines: readonly string[]): readonly StatusbarMenuItem[] {
|
|
if (lines.length === 0) {
|
|
return [
|
|
{
|
|
className: 'text-muted-foreground',
|
|
disabled: true,
|
|
id: 'gateway-log-empty',
|
|
label: 'No recent gateway log lines'
|
|
}
|
|
]
|
|
}
|
|
|
|
return lines.slice(-LOG_TAIL).map((line, index) => ({
|
|
className: 'font-mono text-[0.68rem] text-muted-foreground',
|
|
disabled: true,
|
|
id: `gateway-log:${index}`,
|
|
label: line.trim().slice(0, 120) || '(blank log line)'
|
|
}))
|
|
}
|