Download src/state/teammateViewHelpers.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 4.4 kB
-
https://huggingface.co/chenbhao/codev/resolve/main/src/state/teammateViewHelpers.ts
- Command line
-
hf download hf://chenbhao/codev/src/state/teammateViewHelpers.ts
-
curl -L -o teammateViewHelpers.ts https://huggingface.co/chenbhao/codev/resolve/main/src/state/teammateViewHelpers.ts
4.4 kB
| import { logEvent } from '../services/analytics/index.js' | |
| import { isTerminalTaskStatus } from '../Task.js' | |
| import type { LocalAgentTaskState } from '../tasks/LocalAgentTask/LocalAgentTask.js' | |
| // Inlined from framework.ts — importing creates a cycle through | |
| // BackgroundTasksDialog. Keep in sync with PANEL_GRACE_MS there. | |
| const PANEL_GRACE_MS = 30_000 | |
| import type { AppState } from './AppState.js' | |
| // Inline type check instead of importing isLocalAgentTask — breaks the | |
| // teammateViewHelpers → LocalAgentTask runtime edge that creates a cycle | |
| // through BackgroundTasksDialog. | |
| function isLocalAgent(task: unknown): task is LocalAgentTaskState { | |
| return ( | |
| typeof task === 'object' && | |
| task !== null && | |
| 'type' in task && | |
| task.type === 'local_agent' | |
| ) | |
| } | |
| /** | |
| * Return the task released back to stub form: retain dropped, messages | |
| * cleared, evictAfter set if terminal. Shared by exitTeammateView and | |
| * the switch-away path in enterTeammateView. | |
| */ | |
| function release(task: LocalAgentTaskState): LocalAgentTaskState { | |
| return { | |
| ...task, | |
| retain: false, | |
| messages: undefined, | |
| diskLoaded: false, | |
| evictAfter: isTerminalTaskStatus(task.status) | |
| ? Date.now() + PANEL_GRACE_MS | |
| : undefined, | |
| } | |
| } | |
| /** | |
| * Transitions the UI to view a teammate's transcript. | |
| * Sets viewingAgentTaskId and, for local_agent, retain: true (blocks eviction, | |
| * enables stream-append, triggers disk bootstrap) and clears evictAfter. | |
| * If switching from another agent, releases the previous one back to stub. | |
| */ | |
| export function enterTeammateView( | |
| taskId: string, | |
| setAppState: (updater: (prev: AppState) => AppState) => void, | |
| ): void { | |
| logEvent('tengu_transcript_view_enter', {}) | |
| setAppState(prev => { | |
| const task = prev.tasks[taskId] | |
| const prevId = prev.viewingAgentTaskId | |
| const prevTask = prevId !== undefined ? prev.tasks[prevId] : undefined | |
| const switching = | |
| prevId !== undefined && | |
| prevId !== taskId && | |
| isLocalAgent(prevTask) && | |
| prevTask.retain | |
| const needsRetain = | |
| isLocalAgent(task) && (!task.retain || task.evictAfter !== undefined) | |
| const needsView = | |
| prev.viewingAgentTaskId !== taskId || | |
| prev.viewSelectionMode !== 'viewing-agent' | |
| if (!needsRetain && !needsView && !switching) return prev | |
| let tasks = prev.tasks | |
| if (switching || needsRetain) { | |
| tasks = { ...prev.tasks } | |
| if (switching) tasks[prevId] = release(prevTask) | |
| if (needsRetain) { | |
| tasks[taskId] = { ...task, retain: true, evictAfter: undefined } | |
| } | |
| } | |
| return { | |
| ...prev, | |
| viewingAgentTaskId: taskId, | |
| viewSelectionMode: 'viewing-agent', | |
| tasks, | |
| } | |
| }) | |
| } | |
| /** | |
| * Exit teammate transcript view and return to leader's view. | |
| * Drops retain and clears messages back to stub form; if terminal, | |
| * schedules eviction via evictAfter so the row lingers briefly. | |
| */ | |
| export function exitTeammateView( | |
| setAppState: (updater: (prev: AppState) => AppState) => void, | |
| ): void { | |
| logEvent('tengu_transcript_view_exit', {}) | |
| setAppState(prev => { | |
| const id = prev.viewingAgentTaskId | |
| const cleared = { | |
| ...prev, | |
| viewingAgentTaskId: undefined, | |
| viewSelectionMode: 'none' as const, | |
| } | |
| if (id === undefined) { | |
| return prev.viewSelectionMode === 'none' ? prev : cleared | |
| } | |
| const task = prev.tasks[id] | |
| if (!isLocalAgent(task) || !task.retain) return cleared | |
| return { | |
| ...cleared, | |
| tasks: { ...prev.tasks, [id]: release(task) }, | |
| } | |
| }) | |
| } | |
| /** | |
| * Context-sensitive x: running → abort, terminal → dismiss. | |
| * Dismiss sets evictAfter=0 so the filter hides immediately. | |
| * If viewing the dismissed agent, also exits to leader. | |
| */ | |
| export function stopOrDismissAgent( | |
| taskId: string, | |
| setAppState: (updater: (prev: AppState) => AppState) => void, | |
| ): void { | |
| setAppState(prev => { | |
| const task = prev.tasks[taskId] | |
| if (!isLocalAgent(task)) return prev | |
| if (task.status === 'running') { | |
| task.abortController?.abort() | |
| return prev | |
| } | |
| if (task.evictAfter === 0) return prev | |
| const viewingThis = prev.viewingAgentTaskId === taskId | |
| return { | |
| ...prev, | |
| tasks: { | |
| ...prev.tasks, | |
| [taskId]: { ...release(task), evictAfter: 0 }, | |
| }, | |
| ...(viewingThis && { | |
| viewingAgentTaskId: undefined, | |
| viewSelectionMode: 'none', | |
| }), | |
| } | |
| }) | |
| } | |