diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 604a52d729..8e4a612f42 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -2308,6 +2308,7 @@ "runtime": { "title": "Runtime", "how": "How it runs", + "native": "Native engine", "hosted": "Hosted", "daemon": "On a computer, via the daemon", "cli": "Single CLI", diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index c3c3e779c7..018df182c2 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -2299,6 +2299,7 @@ "runtime": { "title": "运行环境", "how": "运行方式", + "native": "原生引擎", "hosted": "托管运行", "daemon": "通过守护进程在电脑上运行", "cli": "单个 CLI", diff --git a/frontend/src/v2/__tests__/V2AgentRuntimeGrants.test.tsx b/frontend/src/v2/__tests__/V2AgentRuntimeGrants.test.tsx index a8ed9b9d6a..d3737680ed 100644 --- a/frontend/src/v2/__tests__/V2AgentRuntimeGrants.test.tsx +++ b/frontend/src/v2/__tests__/V2AgentRuntimeGrants.test.tsx @@ -49,9 +49,16 @@ test('runtime labels only recognize walked adapters and distinguish daemon from expect(describeRuntime({ runtimeType: 'webhook', host: 'byo', adapter: 'dsh' })).toEqual({ mode: 'cli', adapter: 'DeepSeek Harness' }); expect(describeRuntime({ runtimeType: 'wrapper', adapter: 'unwalked' })).toEqual({ mode: 'daemon', adapter: null }); expect(describeRuntime({ runtimeType: 'hosted' })).toEqual({ mode: 'hosted', adapter: null }); + expect(describeRuntime({ runtimeType: 'native', host: 'cloud' })).toEqual({ mode: 'native', adapter: null }); expect(describeRuntime({ runtimeType: 'webhook', host: 'byo' })).toEqual({ mode: 'unknown', adapter: null }); }); +test('shows the native engine for a native agent', async () => { + renderSection({ runtimeType: 'native' }); + expect(await screen.findByText('Native engine')).toBeInTheDocument(); + expect(screen.queryByText('Hosted')).not.toBeInTheDocument(); +}); + test('revoked Runtime row offers an active computer and moves in one request', async () => { axios.get.mockImplementation((url) => Promise.resolve({ data: url.includes('/agent-binding/placement') ? { boundMachineId: 'old', requestedMachineId: null, boundMachineRevoked: true, diff --git a/frontend/src/v2/components/V2AgentRuntimeGrants.tsx b/frontend/src/v2/components/V2AgentRuntimeGrants.tsx index b4d8c29ae5..1823161a5c 100644 --- a/frontend/src/v2/components/V2AgentRuntimeGrants.tsx +++ b/frontend/src/v2/components/V2AgentRuntimeGrants.tsx @@ -57,11 +57,12 @@ const WALKED_ADAPTERS: Record = { }; const DAEMON_SETUP_COMMAND = 'npm i -g @commonlyai/cli@latest && commonly login && commonly daemon register && commonly daemon install'; -export const describeRuntime = (runtime: Runtime): { mode: 'hosted' | 'daemon' | 'cli' | 'unknown'; adapter: string | null } => { +export const describeRuntime = (runtime: Runtime): { mode: 'native' | 'hosted' | 'daemon' | 'cli' | 'unknown'; adapter: string | null } => { const type = String(runtime.runtimeType || '').toLowerCase(); const adapterKey = String(runtime.adapter || type).toLowerCase(); const mode = type === 'wrapper' ? (runtime.managed === false ? 'cli' : 'daemon') - : type === 'hosted' || type === 'native' || type === 'internal' || runtime.host === 'cloud' ? 'hosted' + : type === 'native' ? 'native' + : type === 'hosted' || type === 'internal' || runtime.host === 'cloud' ? 'hosted' : runtime.host === 'byo' && WALKED_ADAPTERS[adapterKey] ? 'cli' : 'unknown'; return { mode, adapter: WALKED_ADAPTERS[adapterKey] || null }; }; @@ -142,6 +143,7 @@ const V2AgentRuntimeGrants: React.FC = ({ const details = useMemo(() => describeRuntime(runtime), [runtime]); const modeLabel = { + native: t('agentManage.runtime.native', { defaultValue: 'Native engine' }), hosted: t('agentManage.runtime.hosted', { defaultValue: 'Hosted' }), daemon: t('agentManage.runtime.daemon', { defaultValue: 'On a computer, via the daemon' }), cli: t('agentManage.runtime.cli', { defaultValue: 'Single CLI' }),