diff --git a/src/renderer/src/components/native-chat/NativeChatMonitoringStatus.tsx b/src/renderer/src/components/native-chat/NativeChatMonitoringStatus.tsx
index 4775417bd77..e63f4ab6271 100644
--- a/src/renderer/src/components/native-chat/NativeChatMonitoringStatus.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatMonitoringStatus.tsx
@@ -1,6 +1,5 @@
-import { AgentStateDot, agentStateLabel } from '@/components/AgentStateDot'
-
-const MONITORING_LABEL = agentStateLabel('monitoring')
+import { AgentStateDot } from '@/components/AgentStateDot'
+import { translate } from '@/i18n/i18n'
export function NativeChatMonitoringStatus({
monitoring
@@ -20,7 +19,9 @@ export function NativeChatMonitoringStatus({
- {MONITORING_LABEL}
+
+ {translate('components.native-chat.monitoringStatus.label', 'Monitoring background tasks')}
+
)
}
diff --git a/src/renderer/src/components/native-chat/use-native-chat-hook-status.ts b/src/renderer/src/components/native-chat/use-native-chat-hook-status.ts
index e2a7d87749a..12d84f4bc63 100644
--- a/src/renderer/src/components/native-chat/use-native-chat-hook-status.ts
+++ b/src/renderer/src/components/native-chat/use-native-chat-hook-status.ts
@@ -44,12 +44,11 @@ function resolveNativeChatHookStatus(
}
export function useNativeChatMonitoringStatus(paneKey: string): boolean {
- // Why: monitoring stays out of foreground lifecycle while remaining visible from the tab glyph's pane-status source.
- const agentStatusEpoch = useAppStore((store) => store.agentStatusEpoch)
- void agentStatusEpoch
- return useAppStore((store) =>
- resolveNativeChatMonitoringStatus(store.agentStatusByPaneKey[paneKey])
- )
+ return useAppStore((store) => {
+ // Why: epoch invalidates freshness; the primitive result avoids unrelated-pane rerenders.
+ void store.agentStatusEpoch
+ return resolveNativeChatMonitoringStatus(store.agentStatusByPaneKey[paneKey])
+ })
}
export function useNativeChatHookStatus(
diff --git a/src/renderer/src/components/native-chat/use-native-chat-monitoring-status.test.tsx b/src/renderer/src/components/native-chat/use-native-chat-monitoring-status.test.tsx
new file mode 100644
index 00000000000..4952072ad76
--- /dev/null
+++ b/src/renderer/src/components/native-chat/use-native-chat-monitoring-status.test.tsx
@@ -0,0 +1,66 @@
+// @vitest-environment happy-dom
+
+import '@testing-library/jest-dom/vitest'
+
+import { act, cleanup, render, screen } from '@testing-library/react'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import type { AgentStatusEntry } from '../../../../shared/agent-status-types'
+import { AGENT_STATUS_STALE_AFTER_MS } from '../../../../shared/agent-status-types'
+import { useAppStore } from '@/store'
+import { useNativeChatMonitoringStatus } from './use-native-chat-hook-status'
+
+const PANE_KEY = 'tab-1:11111111-1111-4111-8111-111111111111'
+
+function monitoringEntry(updatedAt: number): AgentStatusEntry {
+ return {
+ paneKey: PANE_KEY,
+ state: 'working',
+ workingMode: 'monitoring',
+ prompt: 'Monitor background tasks',
+ updatedAt,
+ stateStartedAt: updatedAt,
+ stateHistory: []
+ }
+}
+
+describe('useNativeChatMonitoringStatus', () => {
+ beforeEach(() => {
+ vi.useFakeTimers()
+ vi.setSystemTime(new Date('2026-09-04T12:00:00.000Z'))
+ useAppStore.setState({
+ agentStatusByPaneKey: { [PANE_KEY]: monitoringEntry(Date.now()) },
+ agentStatusEpoch: 0
+ })
+ })
+
+ afterEach(() => {
+ cleanup()
+ useAppStore.setState({ agentStatusByPaneKey: {}, agentStatusEpoch: 0 })
+ vi.useRealTimers()
+ })
+
+ it('rerenders at expiry without rerendering for an unrelated epoch', () => {
+ let renders = 0
+ function Probe(): React.JSX.Element {
+ renders += 1
+ const monitoring = useNativeChatMonitoringStatus(PANE_KEY)
+ return {monitoring ? 'monitoring' : 'idle'}
+ }
+
+ render()
+ expect(screen.getByText('monitoring')).toBeInTheDocument()
+ expect(renders).toBe(1)
+
+ act(() => {
+ useAppStore.setState((state) => ({ agentStatusEpoch: state.agentStatusEpoch + 1 }))
+ })
+ expect(renders).toBe(1)
+
+ vi.setSystemTime(Date.now() + AGENT_STATUS_STALE_AFTER_MS + 1)
+ act(() => {
+ useAppStore.setState((state) => ({ agentStatusEpoch: state.agentStatusEpoch + 1 }))
+ })
+ expect(screen.getByText('idle')).toBeInTheDocument()
+ expect(renders).toBe(2)
+ })
+})
diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json
index f2da58bffb3..d9fb5b898b0 100644
--- a/src/renderer/src/i18n/locales/en.json
+++ b/src/renderer/src/i18n/locales/en.json
@@ -17009,7 +17009,10 @@
},
"structuredSessionCloseFailed": "Could not close this Codex chat",
"structuredSessionLaunchFailed": "Could not open Codex chat",
- "structuredSessionCloseFailedDescription": "The terminal stayed open so the provider remains recoverable."
+ "structuredSessionCloseFailedDescription": "The terminal stayed open so the provider remains recoverable.",
+ "monitoringStatus": {
+ "label": "Monitoring background tasks"
+ }
},
"tab": {
"bar": {