Surface host model runtime capability skew

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-06-12 22:08:01 -07:00
co-authored by Orca
parent e85d09ca15
commit 76a446c50e
4 changed files with 112 additions and 4 deletions
@@ -98,7 +98,7 @@ Done means: settings pages no longer imply one global provider/account when the
- [~] Audit caches keyed by repo id, path, owner/repo, or active runtime and add host/source identity where needed.
- [~] Ensure request ownership is explicit for provider fetches, provider mutations, file-system calls, git calls, terminal calls, and automation runs.
- [~] Add capability negotiation for remote servers so new clients can degrade gracefully with older servers.
- [~] Add version-skew UX for unsupported source-context or host-context APIs.
- [x] Add version-skew UX for unsupported source-context or host-context APIs.
- [x] Ensure SSH hosts and remote servers expose comparable availability/health states to the UI.
- [x] Keep future cloud VM support as a host capability model, not a separate user-facing mental model.
@@ -246,3 +246,4 @@ Done means: reviewers and future agents can understand the vision, implementatio
- [x] 2026-06-12: Preserved explicit automation run-host context in CLI project selectors: `orca automations create/edit --project/--host` and `--project-host-setup` now send `WorkspaceRunContext` alongside the legacy repo selector, so scheduled runs retain logical project, host, setup, repo, and path identity. Verified with focused CLI regressions (108 tests), targeted oxlint, full `pnpm run typecheck`, and `git diff --check`.
- [x] 2026-06-12: Added an advanced automation CLI source selector via `--source-context <json|null>` for create/edit, normalizing the shared `TaskSourceContext` shape before RPC and allowing edit callers to clear the source context with `null`; verified with focused CLI regressions (111 tests), targeted oxlint, full `pnpm run typecheck`, and `git diff --check`.
- [x] 2026-06-12: Added a reusable Tasks source availability notice and wired unavailable source-host/account states into the Tasks source chrome, so disconnected/auth-needed/blocked hosts show an inline status, fully unavailable sources disable their icon, and partial multi-host failures remain selectable with warning copy; verified with focused source-summary tests, targeted oxlint, and full `pnpm run typecheck`.
- [x] 2026-06-12: Added explicit remote-runtime Host model capability names for project setup, task source context, and workspace run context, then surfaced a Settings saved-server summary that says whether Host model support is ready, unknown, or requires a server update for specific missing capabilities; verified with focused RuntimeEnvironmentsPane tests, targeted oxlint, and full `pnpm run typecheck`.
@@ -1,13 +1,17 @@
import { describe, expect, it } from 'vitest'
import {
MIN_COMPATIBLE_RUNTIME_SERVER_VERSION,
RUNTIME_PROTOCOL_VERSION
PROJECT_HOST_SETUP_RUNTIME_CAPABILITY,
RUNTIME_PROTOCOL_VERSION,
TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY,
WORKSPACE_RUN_CONTEXT_RUNTIME_CAPABILITY
} from '../../../../shared/protocol-version'
import {
evaluateHostDetails,
getActiveServerModeDescription,
getHostDetailsDescription,
getHostDetailsSummary,
getHostModelCapabilitySummary,
getRuntimeCapabilitiesSummary,
type RuntimeHostDetails
} from './RuntimeEnvironmentsPane'
@@ -129,6 +133,47 @@ describe('RuntimeEnvironmentsPane host details', () => {
).toBe('runtime.environments.v1, browser.screencast.v1, terminal.multiplex.v1 +1')
})
it('summarizes Host model capability support for version-skewed servers', () => {
expect(
getHostModelCapabilitySummary({
runtimeId: 'runtime',
rendererGraphEpoch: 1,
graphStatus: 'ready',
authoritativeWindowId: 1,
liveTabCount: 0,
liveLeafCount: 0
})
).toBe('Host model support: checking server capabilities')
expect(
getHostModelCapabilitySummary({
runtimeId: 'runtime',
rendererGraphEpoch: 1,
graphStatus: 'ready',
authoritativeWindowId: 1,
liveTabCount: 0,
liveLeafCount: 0,
capabilities: [
PROJECT_HOST_SETUP_RUNTIME_CAPABILITY,
TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY,
WORKSPACE_RUN_CONTEXT_RUNTIME_CAPABILITY
]
})
).toBe('Host model support: ready')
expect(
getHostModelCapabilitySummary({
runtimeId: 'runtime',
rendererGraphEpoch: 1,
graphStatus: 'ready',
authoritativeWindowId: 1,
liveTabCount: 0,
liveLeafCount: 0,
capabilities: [PROJECT_HOST_SETUP_RUNTIME_CAPABILITY]
})
).toBe('Host model support: update server for task source context, workspace run context')
})
it('explains that selecting a saved server is the explicit default Host mode', () => {
expect(getActiveServerModeDescription(true)).toContain('default Host')
expect(getActiveServerModeDescription(true)).toContain('browser/mobile handoff')
@@ -15,7 +15,10 @@ import {
} from '../../../../shared/protocol-compat'
import {
MIN_COMPATIBLE_RUNTIME_SERVER_VERSION,
RUNTIME_PROTOCOL_VERSION
PROJECT_HOST_SETUP_RUNTIME_CAPABILITY,
RUNTIME_PROTOCOL_VERSION,
TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY,
WORKSPACE_RUN_CONTEXT_RUNTIME_CAPABILITY
} from '../../../../shared/protocol-version'
import { Button } from '../ui/button'
import { Input } from '../ui/input'
@@ -110,6 +113,60 @@ export function getRuntimeCapabilitiesSummary(status: RuntimeStatus | null | und
return hiddenCount > 0 ? `${visibleCapabilities} +${hiddenCount}` : visibleCapabilities
}
export function getHostModelCapabilitySummary(
status: RuntimeStatus | null | undefined
): string | null {
if (!status) {
return null
}
const capabilities = status.capabilities
if (!capabilities) {
return translate(
'auto.components.settings.RuntimeEnvironmentsPane.hostModelCapabilityUnknown',
'Host model support: checking server capabilities'
)
}
const missing = [
PROJECT_HOST_SETUP_RUNTIME_CAPABILITY,
TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY,
WORKSPACE_RUN_CONTEXT_RUNTIME_CAPABILITY
].filter((capability) => !capabilities.includes(capability))
if (missing.length === 0) {
return translate(
'auto.components.settings.RuntimeEnvironmentsPane.hostModelCapabilitySupported',
'Host model support: ready'
)
}
const missingLabels = missing.map(getHostModelCapabilityLabel)
return translate(
'auto.components.settings.RuntimeEnvironmentsPane.hostModelCapabilityMissing',
'Host model support: update server for {{value0}}',
{ value0: missingLabels.join(', ') }
)
}
function getHostModelCapabilityLabel(capability: string): string {
switch (capability) {
case PROJECT_HOST_SETUP_RUNTIME_CAPABILITY:
return translate(
'auto.components.settings.RuntimeEnvironmentsPane.hostModelCapabilityProjectSetup',
'project setup'
)
case TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY:
return translate(
'auto.components.settings.RuntimeEnvironmentsPane.hostModelCapabilityTaskSourceContext',
'task source context'
)
case WORKSPACE_RUN_CONTEXT_RUNTIME_CAPABILITY:
return translate(
'auto.components.settings.RuntimeEnvironmentsPane.hostModelCapabilityWorkspaceRunContext',
'workspace run context'
)
default:
return capability
}
}
export function getActiveServerModeDescription(allowLocalRuntime: boolean): string {
return allowLocalRuntime
? translate(
@@ -715,6 +772,7 @@ export function RuntimeEnvironmentsPane({
}
)}
</span>
<span>{getHostModelCapabilitySummary(details.runtimeStatus)}</span>
</>
) : detailsDescription ? (
<span className="truncate text-destructive">{detailsDescription}</span>
+5 -1
View File
@@ -22,6 +22,8 @@ export const MIN_COMPATIBLE_RUNTIME_CLIENT_VERSION = 2
export const MIN_COMPATIBLE_RUNTIME_SERVER_VERSION = 2
export const PROJECT_HOST_SETUP_RUNTIME_CAPABILITY = 'project-host-setup.v1' as const
export const TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY = 'task-source-context.v1' as const
export const WORKSPACE_RUN_CONTEXT_RUNTIME_CAPABILITY = 'workspace-run-context.v1' as const
export const RUNTIME_CAPABILITIES = [
'runtime.status.compat.v1',
@@ -31,7 +33,9 @@ export const RUNTIME_CAPABILITIES = [
'terminal.multiplex.v1',
'workspace-ports.v1',
'mobile.tasks.v1',
PROJECT_HOST_SETUP_RUNTIME_CAPABILITY
PROJECT_HOST_SETUP_RUNTIME_CAPABILITY,
TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY,
WORKSPACE_RUN_CONTEXT_RUNTIME_CAPABILITY
] as const
export type RuntimeCapability = (typeof RUNTIME_CAPABILITIES)[number] | (string & {})