Skip to content

fix: agent error reporting and handling #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- support for using proxies. Proxy authentication is not yet supported.

### Changed

- connections to the workspace are no longer established automatically after agent started with error.

## 0.1.5 - 2025-04-14

### Fixed
Expand Down
24 changes: 11 additions & 13 deletions src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,16 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) {
fun toRemoteEnvironmentState(context: CoderToolboxContext): CustomRemoteEnvironmentState {
return CustomRemoteEnvironmentState(
label,
getStateColor(context),
ready(), // reachable
color = getStateColor(context),
reachable = ready() || unhealthy(),
// TODO@JB: How does this work? Would like a spinner for pending states.
getStateIcon()
icon = getStateIcon()
)
}

private fun getStateColor(context: CoderToolboxContext): StateColor {
return if (ready()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Active)
else if (unhealthy()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Unhealthy)
else if (canStart()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Failed)
else if (pending()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Activating)
else if (this == DELETING) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Deleting)
Expand All @@ -78,7 +79,7 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) {
}

private fun getStateIcon(): EnvironmentStateIcons {
return if (ready()) EnvironmentStateIcons.Active
return if (ready() || unhealthy()) EnvironmentStateIcons.Active
else if (canStart()) EnvironmentStateIcons.Hibernated
else if (pending()) EnvironmentStateIcons.Connecting
else if (this == DELETING || this == DELETED) EnvironmentStateIcons.Offline
Expand All @@ -88,13 +89,10 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) {
/**
* Return true if the agent is in a connectable state.
*/
fun ready(): Boolean {
// It seems that the agent can get stuck in a `created` state if the
// workspace is updated and the agent is restarted (presumably because
// lifecycle scripts are not running again). This feels like either a
// Coder or template bug, but `coder ssh` and the VS Code plugin will
// still connect so do the same here to not be the odd one out.
return listOf(READY, START_ERROR, AGENT_STARTING_READY, START_TIMEOUT_READY, CREATED)
fun ready(): Boolean = this == READY

fun unhealthy(): Boolean {
return listOf(START_ERROR, START_TIMEOUT_READY)
.contains(this)
}

Expand All @@ -103,7 +101,7 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) {
*/
fun pending(): Boolean {
// See ready() for why `CREATED` is not in this list.
return listOf(CONNECTING, TIMEOUT, AGENT_STARTING, START_TIMEOUT, QUEUED, STARTING)
return listOf(CREATED, CONNECTING, TIMEOUT, AGENT_STARTING, START_TIMEOUT, QUEUED, STARTING)
.contains(this)
}

Expand All @@ -116,7 +114,7 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) {
/**
* Return true if the workspace can be stopped.
*/
fun canStop(): Boolean = ready() || pending()
fun canStop(): Boolean = ready() || pending() || unhealthy()

// We want to check that the workspace is `running`, the agent is
// `connected`, and the agent lifecycle state is `ready` to ensure the best
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ open class CoderProtocolHandler(
val status = WorkspaceAndAgentStatus.from(workspace, agent)

if (!status.ready()) {
context.logger.error("Agent ${agent.name} for workspace $workspaceName from $deploymentURL is not started")
context.showErrorPopup(MissingArgumentException("Can't handle URI because agent ${agent.name} for workspace $workspaceName from $deploymentURL is not started"))
context.logger.error("Agent ${agent.name} for workspace $workspaceName from $deploymentURL is not ready")
context.showErrorPopup(MissingArgumentException("Can't handle URI because agent ${agent.name} for workspace $workspaceName from $deploymentURL is not ready"))
return
}

Expand Down
Loading