Dev builds (go run / untagged) report cli_version="dev" which is not a
valid semver string. Both frontend and server-side version checks treated
this as "missing" and blocked the Quick Create flow entirely.
Since dev builds are built from HEAD and are always at least as new as
any released version, "dev" should always pass the gate.
Fixed in both:
- packages/core/runtimes/cli-version.ts (frontend pre-check)
- server/pkg/agent/version.go (server trust boundary)
* fix(quick-create): bound dialog height + scroll editor when content overflows
Pasting a screenshot into the agent-create prompt expanded the editor
unbounded, which dragged DialogContent past the viewport since the agent
mode className had no max-height. Manual mode was unaffected because
manualDialogContentClass pins `!h-96`.
- Cap agent-mode DialogContent at `!max-h-[80vh]` (width stays
`!max-w-xl`); short prompts still render compact, tall content stops
at 80% of the viewport.
- Switch the editor wrapper to `flex-1 min-h-[140px] overflow-y-auto`
so it absorbs the remaining vertical space inside the now-bounded
DialogContent and scrolls internally instead of pushing the dialog.
* feat(quick-create): gate on daemon CLI version with pre-check + server enforcement
The agent-create flow depends on multica CLI behavior introduced in
v0.2.20 (URL attachment handling, no-retry semantics on
`multica issue create` failure — see PR #1851 / MUL-1496). Older
daemons either double-create issues on partial CLI failures or
mishandle pasted screenshot URLs. Per J's review on MUL-1496, gate
the flow at two layers — frontend pre-check for fast feedback,
server re-check as the trust boundary, both fail-closed on
missing/unparsable versions.
Server:
- New MinQuickCreateCLIVersion + CheckMinCLIVersion helper in
pkg/agent (with sentinel errors for missing vs too-old).
- QuickCreateIssue handler reads runtime metadata.cli_version and
returns a stable 422 { code: "daemon_version_unsupported",
current_version, min_version, runtime_id } before enqueuing.
- The check runs after the existing online + ownership validation,
so all rejections surface uniformly through the modal's existing
error path.
Frontend:
- New @multica/core/runtimes/cli-version with the min version
constant, parser, and runtime-metadata reader (tiny semver, no
new lib dep).
- AgentCreatePanel resolves the selected agent's runtime, runs the
same check, shows an inline amber notice below the agent picker
when missing/too old, and disables the Create button.
- Submit handler also catches the server's 422 (defensive race —
runtime can re-register between pre-check and submit) and
surfaces the same wording in the error row.
Switching to manual create remains a clean escape hatch — manual
mode doesn't talk to a daemon at all, so an outdated CLI doesn't
block the user from filing the issue.
* feat(agent-status): add workspace live-tasks endpoint and TaskFailureReason type
Lays the API + type contract for the front-end agent presence cache:
- New `GET /api/active-tasks` returns active (queued/dispatched/running)
tasks plus failed tasks within the last 2 minutes for the current
workspace. The 2-minute window powers a UI-side auto-clearing "Failed"
agent state without back-end pollers.
- `agent_task_queue` has no workspace_id column, so the query JOINs agent;
`SELECT atq.*` keeps `failure_reason` (migration 055) on the wire.
- Adds `TaskFailureReason` to `AgentTask` so the UI can map the 5 backend
classifiers (agent_error / timeout / runtime_offline / runtime_recovery
/ manual) to copy without parsing free-text errors.
- New `api.getActiveTasksForWorkspace()` client method; workspace is
resolved server-side from the X-Workspace-Slug header (no path param,
matching /api/agents and /api/runtimes conventions).
Includes the joint engineering plan and designer brief that scope the
broader Agent / Runtime status redesign — Phase 0 is this contract plus
the front-end derivation layer landing in the next commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(agent-status): derive presence/health states with WS sync and desktop IPC bridge
Adds the front-end derivation layer that turns raw server data into the
user-facing 5-state agent / 4-state runtime enums. UI files are
deliberately untouched in this commit — derivation lives behind hooks
(useAgentPresence, useRuntimeHealth) that any component can call with
zero additional network traffic.
Architecture:
- Derivation is pure functions in packages/core/{agents,runtimes}; the
back-end stays free of UI translation. Agents algorithm: runtime
offline > recent failed (2-min window) > running > queued > available.
Runtimes algorithm: status + last_seen_at -> online / recently_lost /
offline / about_to_gc.
- A single workspace-wide active-tasks query backs all per-agent
presence reads, eliminating N+1 across hover cards, list rows, and
pickers. 30-second tick re-renders the hooks so the failed window
expires even when no underlying data changes.
- WS task lifecycle events (dispatch / completed / failed / cancelled)
invalidate active-tasks via the prefix dispatcher. completed/failed
were removed from specificEvents so they go through both the prefix
invalidate and the existing chat ws.on() handlers. Reconnect refetch
picks up active-tasks too.
- Desktop bridges window.daemonAPI.onStatusChange directly into the
runtimes cache via setQueryData, giving the local daemon sub-second
feedback (vs. 75s server sweep). Bridge is wsId-bound so workspace
switches automatically rebind the subscription; daemon_id matching
covers the same-daemon-multiple-providers case.
24 derivation unit tests cover all branches plus null/empty/boundary
inputs (FAILED_WINDOW_MS edges, null last_seen_at, missing
completed_at). Full core suite: 112 tests passing. Typecheck green
across all 8 workspace packages.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(agent-status): redesign agent runtime status as two orthogonal dimensions
Splits the conflated 5-state agent presence into two independent axes:
- AgentAvailability (3-state): online / unstable / offline — drives the
dot indicator everywhere a dot appears. Pure runtime reachability;
never sticky-red because of a past task outcome.
- LastTaskState (5-state): running / completed / failed / cancelled /
idle — surfaced as text + icon on focused surfaces (hover card,
agent detail page, agents list, runtime detail). Never colours the dot.
Major changes:
* Domain layer: AgentPresence union → AgentAvailability + LastTaskState.
derive-presence split into deriveAgentAvailability + deriveLastTaskState
+ deriveAgentPresenceDetail orchestrator. Tests reorganised into three
groups (availability invariants, last-task invariants, composition).
* Visual config: presenceConfig (5 entries) → availabilityConfig (3) +
taskStateConfig (5). availabilityOrder + lastTaskOrder for filter chips.
* Workspace-level presence prefetch: new useWorkspacePresencePrefetch
hook + WorkspacePresencePrefetch mount component, wired into
DashboardLayout (web) and WorkspaceRouteLayout (desktop). Hover cards
render synchronously with no skeleton flash on first hover.
* ActorAvatar hover: flipped default — disableHoverCard removed,
enableHoverCard added (default false). Opt-in at ~14 decision-moment
surfaces; pickers / decoration sub-chips stay plain. Status dot
decoupled (showStatusDot prop) so picker rows can show presence
without nesting popovers.
* Hover cards: AgentProfileCard simplified — availability dot only,
Detail link top-right (logs live on the detail page). New
MemberProfileCard mirrors the structure: name + role + email +
top-2 owned agents (sorted by 30d run count) with click-through to
agent detail.
* Agents list: split Status into two columns — availability (3-color
dot + label) and Last run (task icon + label, optional running
counts). Two independent filter chip groups (Status + Last run);
combination acts as intersection ("online + failed" finds broken-
but-alive agents).
* Other UI surfaces (issue list/board/detail, comments, autopilots,
projects, runtimes, mention autocomplete, subscribers picker)
updated to the new dot semantics; status dot now strictly 3-color.
Server changes accompany the client redesign — workspace-wide
agent-task-snapshot endpoint, runtime usage queries, etc. — to feed
the derive layer with the data it needs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(agent-detail): drop last-task chip from detail header + inspector
The Recent work section on the agent detail page already shows the same
data (with task titles, timestamps, error context) — surfacing
"Completed" / "Failed" / etc. up in the header was redundant chrome.
Detail surfaces now show only the 3-state availability dot.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(tables): handle narrow viewports across agents / skills / runtimes
Three table layouts were squeezing content into adjacent cells at
intermediate widths. Each fix is small and targeted:
* runtime-list: the Runtime cell's base name had `shrink-0`, so it
refused to truncate when its grid column was narrowed under width
pressure — the name visually overflowed into the Health column
("ClaudeOnline" etc). Removed shrink-0, added truncate. The Health
column was also a fixed 9.5rem reservation for the worst-case
"Recently lost · 2m 14s ago" copy; switched to minmax(0,1fr) so it
competes fairly with Runtime.
* skills-page: had a single grid template with no responsive
breakpoints — all 6 columns were rendered at any width and got
visually jammed below md. Added a <md template that drops Source +
Updated; the row markup hides those cells via `hidden md:block` /
`md:contents`.
* agent-list-item: the new Last run column was reserved at minmax(8rem,
max-content); on narrow md viewports the 8rem floor pushed the row
past available width. Changed to minmax(0,max-content) so the cell
shrinks under pressure (its content already truncates).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(agent-card): hover-only Detail + add Runtime row + breathing room
Three small polish tweaks to the agent hover card:
- Detail link gets `mr-1` + fades in only on card hover (group-hover).
It was visually flush against the popover edge and competing for
attention; now it stays out of the way during a quick glance and
surfaces only when the user is dwelling on the card.
- Runtime row is back, in the meta block (cloud/local icon + runtime
name). The earlier removal was over-aggressive — knowing where an
agent runs is part of "who is this agent". The wifi badge stays
dropped because the availability dot in the header already conveys
reachability.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(runtime): wifi-style health icon (4-state) for runtime list + agent card
Replaces the 6px coloured dot with a wifi-shape icon that carries both
state (Wifi vs WifiOff) and severity (success/warning/muted/destructive).
Mapping:
- online → Wifi (success)
- recently_lost → WifiHigh (warning) — transient hiccup, fewer bars
- offline → WifiOff (muted) — long unreachable
- about_to_gc → WifiOff (destructive) — sweeper coming soon
Used in two places:
- Runtime list: replaces HealthDot in the dedicated leading-icon column.
Bumped the column from 0.5rem (dot-sized) to 0.875rem (icon-sized).
- Agent profile card RuntimeRow: derives runtime health from runtime +
clock (matching the 4-state semantics) and renders HealthIcon next
to the runtime name. Cloud runtimes always read as online. The
duplicate signal with the header availability dot is intentional —
it confirms WHICH runtime is the one currently in the dot's state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a first-class `model` field on agents so users can pick the LLM model from the create / settings UI instead of editing `custom_env` / `custom_args`. Each provider's dropdown is populated from the live CLI when possible (`opencode models`, `pi --list-models`, `openclaw agents list --json`, `cursor-agent --list-models`, hermes ACP `session/new` → `SessionModelState`), with a static catalog for providers that don't enumerate.
Daemon resolves the runtime model as `agent.model → MULTICA_<PROVIDER>_MODEL → ""` — empty passes through so each backend's CLI picks its own default, avoiding static-guess drift.
Per-provider honouring:
- Claude / Codex / OpenCode / Cursor / Gemini / Pi / Copilot — CLI `--model` / thread payload.
- OpenClaw — `opts.Model` is mapped to `--agent <name>` (the CLI rejects `--model`).
- Hermes — `session/set_model` ACP RPC; stderr is sniffed for provider-level errors so HTTP 4xx from the configured LLM surfaces instead of "empty output"; explicit-model failures mark the task `failed`.
Supporting changes: migration 050 adds `agent.model`; daemon ↔ server heartbeat piggyback carries a model-discovery request; new REST endpoints under `/api/runtimes/{id}/models`; `multica agent create --model` / `update --model`; shared `ModelDropdown` in `packages/views/agents` (searchable, creatable, provider-grouped, default-badge, runtime-supported gate).
Desktop-launched daemons have their CLI binary overwritten by the Desktop
app on every launch, so any in-app update is reset. The detail panel already
renders 'Managed by Desktop' and hides the Update button when
metadata.launched_by === 'desktop', but the sidebar red dot
(useMyRuntimesNeedUpdate) and the list arrow (useUpdatableRuntimeIds) still
flagged them because runtimeNeedsUpdate() only considered mode/owner/version.
Short-circuit runtimeNeedsUpdate() on launched_by === 'desktop' so all three
surfaces (sidebar dot, list arrow, detail panel) agree and defer CLI
upgrades to the Desktop auto-updater.
Co-authored-by: CC-Girl <cc-girl@multica.ai>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
useMyRuntimesNeedUpdate and useUpdatableRuntimeIds now take wsId as an
argument so they work safely outside WorkspaceIdProvider (e.g. in sidebar).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(runtime): proactive CLI update notifications with per-user filtering
- Add latestCliVersionOptions query (GitHub Releases API, 10-min TanStack cache)
- Add useMyRuntimesNeedUpdate / useUpdatableRuntimeIds hooks using owner_id
- Show red dot on sidebar Runtimes item when user's runtimes need updates
- Show update arrow icon alongside status dot in runtime list items
* fix(core): add runtimes/hooks to package.json exports