Tim O'Farrellandopenhands 048e390419 feat(automations): add logs modal to activity log items (#600)
* feat(automations): add logs modal to activity log items

Each AutomationRun now surfaces its bash command output via a small
terminal-icon button placed to the left of the run status badge in the
activity log. Clicking the icon opens a modal that fetches the
BashCommand event and all paginated BashOutput events for the run.

- Add bash_command_id to AutomationRun type (and mock data).
- New BashService.getCommandLogs(): cloud-aware reader for bash events
  that routes through callCloudProxy on cloud backends (runtime URL +
  session-api-key auth) and through BashClient directly on local
  backends. Pages through BashOutput events sorted by timestamp.
- New useBashCommandLogs hook: hydrates the run's conversation to
  resolve runtime URL + session API key, then drives the BashService
  query. Surfaces resolution states (loading, conversation missing,
  sandbox gone) so the modal can render meaningful empty states.
- New RunLogsModal: renders interleaved stdout/stderr from the command
  with stderr highlighted, exit code, and explicit messaging when the
  command is missing or the sandbox is no longer alive.
- Activity-log-item gets a logs button that stopPropagation +
  preventDefault on the wrapping conversation link.
- i18n: 8 new AUTOMATIONS$DETAIL$LOGS_* keys across all 15 languages.
- Tests: BashService cloud/local routing + ActivityLogItem button
  behaviour.

Co-authored-by: openhands <openhands@all-hands.dev>

* feat(automations): split logs modal into Output/Error tabs

Address review feedback on the run logs modal:

* Rename the modal title from "Run logs" to "Logs".
* Make the modal actually fire the bash-events search request:
  - In local mode, the agent-server hosts events under a single root,
    so the search query no longer waits for the per-conversation URL
    to resolve before firing. The conversation lookup still runs (so
    session-api-key and per-conversation URL are honoured when
    present), but it no longer gates the fetch.
  - In cloud mode the behaviour is unchanged — runtime endpoints
    require the conversation_url for the cloud-proxy hostOverride.
* Replace the interleaved stdout/stderr pre-block with two tabs:
  Output (stdout, default) and Error (stderr). The body of each tab
  is the chronological concatenation (by timestamp + order) of the
  matching field across every BashOutput event for the command.
* Simplify BashService — drop the extra BashCommand fetch; only the
  BashOutput search (`kind__eq=BashOutput, command_id__eq=<id>`) is
  needed for the rendered view. Note that the agent-server API uses
  `command_id__eq` (not `bash_command_id__eq`) — see the python
  bash_router for the canonical filter name.

i18n: add LOGS_TAB_OUTPUT, LOGS_TAB_ERROR, LOGS_EMPTY across all 15
locales; retranslate LOGS_TITLE to "Logs".

Tests:
* New run-logs-modal.test.tsx covers tab defaults, stdout/stderr
  concatenation (with reverse-order inputs to verify the sort),
  loading state, and Escape-to-close.
* bash-service.test.ts rewritten for the new listOutputs API and a
  cloud-without-conversation-url error path.

Co-authored-by: openhands <openhands@all-hands.dev>

* feat(automations): tolerate paused/missing/unreachable sandboxes in run logs modal

Cloud sandboxes can be in non-RUNNING states (paused, starting,
deleted, errored) and even RUNNING sandboxes can transiently fail at
the network layer. Previously the modal would either show a stuck
'Loading logs...' spinner or dump a raw axios error string. Now each
known-bad state is mapped to a stable `SandboxIssue` code with its
own localized empty-state message.

Behaviour:

* Pre-flight: when `sandbox_status` is MISSING, PAUSED, STARTING, or
  ERROR — or the conversation has no runtime URL at all — the bash
  query is **disabled** (no doomed request is fired). The modal
  renders the matching message instead of a spinner.
* Post-flight: when the request does fire and fails with a 404 or
  5xx response, or a network-level error (no response), the failure
  is classified as `unreachable` and the modal renders the
  'sandbox unreachable' message instead of the raw error. 401/403
  are *not* collapsed — those are auth bugs we want to surface.
* Local backends are unchanged: no sandbox lifecycle, so
  `sandboxIssue` is always null and errors flow through as-is.

API changes:

* `useBashCommandLogs` exposes a `sandboxIssue` discriminated union
  ("missing" | "paused" | "starting" | "errored" | "unreachable")
  instead of the old `hasNoRuntime` boolean. When an issue is set
  the hook clears `error` so the modal doesn't render both an empty
  state AND a raw axios string for the same failure.
* The modal switches over the issue codes via a centralized
  `SANDBOX_ISSUE_I18N` map.

i18n: replace the single `LOGS_SANDBOX_GONE` key with five specific
keys (one per sandbox issue) across all 15 locales.

Tests:

* New `__tests__/hooks/query/use-bash-command-logs.test.tsx`
  exhaustively covers each sandbox_status, the no-runtime-URL case,
  conversationMissing, the happy path, 404/5xx → unreachable
  classification, the network-error case, and the explicit
  401/403-passes-through case.
* `run-logs-modal.test.tsx` extended with a parameterized case
  covering all five issue codes; verifies the empty-state message is
  rendered and the tab body is suppressed.

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-18 18:22:26 +00:00
2026-04-24 17:33:22 -04:00

agent-canvas

Warning

This project is in alpha phase. It may be vibecoded, untested, or out of date. Learn more.

OpenHands is a platform for orchestrating coding agents across different environments. You can:

  • ⌨️ prompt agents manually
  • 🕐 run agents on a schedule
  • ⚡ trigger agents automatically — e.g. from Slack, GitHub, or Datadog.

Agents can run anywhere:

  • 🧑‍💻 on your laptop
  • 🖥️ on a remote virtual machine
  • ☁️ in our hosted cloud
  • 🏢 or inside your company’s infrastructure

The same Agent Canvas frontend can swap between each of these environments, so you can see everything in one place.

OpenHands works with any agent harness (e.g. Claude Code, Codex) or connect directly to an LLM (e.g. Anthropic, OpenAI, Gemini, Mistral, Minimax, Kimi).

If you have questions or feedback, please open a GitHub issue or join the #proj-agent-canvas channel in Slack

Screenshot 2026-05-11 at 10 13 19 AM

Quickstart

Direct Install

You can install OpenHands to run agents on any machine: on your laptop, on a dedicated computer like a Mac Mini, or on a server in the cloud.

The most powerful way to run OpenHands is on a server in the cloud. This allows your agents to continue running even when your laptop is shut, and makes it easier to trigger your agents through third-party services like Slack, GitHub, and Datadog. See SELF_HOSTING.md for details, especially with respect to security hardening.

Notably, you can run the backend in multiple different environments, and switch between them from the same Agent Canvas frontend. E.g. you can share an Agent Server with your team for agents doing code review and dependency updates, then have your personal agents running on your laptop.

Warning

This runs the agent-server directly on the machine you're installing on--the agent will have full access to your filesystem!

Prerequisites:

  • Node.js 22.12.x or later
  • npm
  • uv (for running the agent server via uvx)
git clone https://github.com/OpenHands/agent-canvas.git
cd agent-canvas
npm install
npm run dev:dangerously-dockerless

Access the UI at http://localhost:8000. You can add additional backends directly from the UI.

With Docker Sandbox

If you're running on your laptop, you likely want to sandbox OpenHands to limit the agent's access to your system.

Watch the video on how to run this on Mac or Windows.

Prerequisites:

  • Node.js 22.12.x or later
  • npm
  • Docker

Set $PROJECTS_PATH to the directory on your machine where your projects live (e.g. /path/to/your/projects). The agent server will mount this directory so the agent can read and edit your code.

export PROJECTS_PATH=/path/to/your/projects
git clone https://github.com/OpenHands/agent-canvas.git
cd agent-canvas
npm install
npm run dev:docker

Windows PowerShell workaround: if npm run dev:docker starts the backend but http://localhost:8000 shows Bad Gateway and the logs include a Vite error like 'C:\\Program' is not recognized, start the same stack directly with Node instead. Replace the path below with your projects folder, and do not include any prompt characters or a trailing > in the value.

$env:PROJECTS_PATH = "/path/to/your/projects"
node --env-file-if-exists=.env .\scripts\dev-docker.mjs

Access the UI at http://localhost:8000.

Architecture

Agent Canvas is powered by the OpenHands Agent Server, a REST API for running multiple agents on a single machine. Each Agent Server runs on a single host/port; the Agent Canvas can connect to multiple Agent Servers and easily flip between them.

You can run an Agent Server anywhere:

  • Directly on your laptop (be careful!)
  • Inside a Docker container
  • On a dedicated machine like a Mac Mini
  • On a virtual machine in the cloud
  • Inside a Kubernetes Pod
  • Inside OpenHands Cloud (our commercial offering)

The Agent Server is often paired with an Automation Server, which lets you set up agents that run on a schedule or in response to events.

image

More documentation

For contributor and developer workflows, including frontend-only mode, mock mode, environment variables, and build/test commands, see DEVELOPMENT.md.

S
Languages
TypeScript 93.7%
JavaScript 4.7%
Python 0.9%
Shell 0.3%
CSS 0.2%
Other 0.1%