({
agent,
subAgents,
workspace,
template,
onUpdateAgent,
initialMetadata,
})
| 137 | Boolean(script?.exit_code || (script?.status && script.status !== "ok")); |
| 138 | |
| 139 | export const AgentRow: FC<AgentRowProps> = ({ |
| 140 | agent, |
| 141 | subAgents, |
| 142 | workspace, |
| 143 | template, |
| 144 | onUpdateAgent, |
| 145 | initialMetadata, |
| 146 | }) => { |
| 147 | const { browser_only, workspace_external_agent } = useFeatureVisibility(); |
| 148 | const appSections = organizeAgentApps(agent.apps); |
| 149 | const hasAppsToDisplay = |
| 150 | !browser_only || appSections.some((it) => it.apps.length > 0); |
| 151 | const isExternalAgent = workspace.latest_build.has_external_agent; |
| 152 | const shouldDisplayAgentApps = |
| 153 | (agent.status === "connected" && hasAppsToDisplay) || |
| 154 | (agent.status === "connecting" && !isExternalAgent); |
| 155 | const hasVSCodeApp = |
| 156 | agent.display_apps.includes("vscode") || |
| 157 | agent.display_apps.includes("vscode_insiders"); |
| 158 | const showVSCode = hasVSCodeApp && !browser_only; |
| 159 | |
| 160 | const hasStartupFeatures = Boolean(agent.logs_length); |
| 161 | const runningScriptsCount = agent.scripts.filter( |
| 162 | (s) => s.run_on_start && !s.status, |
| 163 | ).length; |
| 164 | const healthIssues = getAgentHealthIssues(agent); |
| 165 | const hasAgentIssues = healthIssues.length > 0; |
| 166 | const hasWarningIssues = healthIssues.some((i) => i.severity === "warning"); |
| 167 | const { proxy } = useProxy(); |
| 168 | const [showLogs, setShowLogs] = useState( |
| 169 | (["starting", "start_timeout"].includes(agent.lifecycle_state) || |
| 170 | hasAgentIssues) && |
| 171 | hasStartupFeatures, |
| 172 | ); |
| 173 | const agentLogs = useAgentLogs({ agentId: agent.id, enabled: showLogs }); |
| 174 | const logListRef = useRef<List>(null); |
| 175 | const logListDivRef = useRef<HTMLDivElement>(null); |
| 176 | const [bottomOfLogs, setBottomOfLogs] = useState(true); |
| 177 | |
| 178 | useEffect(() => { |
| 179 | setShowLogs( |
| 180 | (agent.lifecycle_state !== "ready" || hasAgentIssues) && |
| 181 | hasStartupFeatures, |
| 182 | ); |
| 183 | }, [agent.lifecycle_state, hasAgentIssues, hasStartupFeatures]); |
| 184 | |
| 185 | // This is a layout effect to remove flicker when we're scrolling to the bottom. |
| 186 | // biome-ignore lint/correctness/useExhaustiveDependencies: consider refactoring |
| 187 | useLayoutEffect(() => { |
| 188 | // If we're currently watching the bottom, we always want to stay at the bottom. |
| 189 | if (bottomOfLogs && logListRef.current) { |
| 190 | logListRef.current.scrollToItem(agentLogs.length - 1, "end"); |
| 191 | } |
| 192 | }, [showLogs, agentLogs, bottomOfLogs]); |
| 193 | |
| 194 | // This is a bit of a hack on the react-window API to get the scroll position. |
| 195 | // If we're scrolled to the bottom, we want to keep the list scrolled to the bottom. |
| 196 | // This makes it feel similar to a terminal that auto-scrolls downwards! |
nothing calls this directly
no test coverage detected