feat(desktop): run tool backend post-setup installs from the GUI (#40559)
Complete the desktop app's tool-backend configuration so it fully
mirrors `hermes tools`. The toolset config panel already did
enable/disable, provider selection, and API-key save/reveal/clear — the
one remaining gap was post-setup install hooks, which previously just
told the user to run the CLI.
Now a provider that declares a post_setup hook (browser Chromium,
Camofox, cua-driver, KittenTTS/Piper, ddgs, Spotify, Langfuse, xAI)
renders a 'Run setup' button that spawns the install via the
`POST /api/tools/toolsets/{name}/post-setup` endpoint and tails the
log inline, feeding the desktop activity rail — mirroring
command-center's runSystemAction poll loop. On completion the panel
refreshes so a now-installed backend reports itself ready.
- hermes.ts: runToolsetPostSetup(name, key) -> profile-scoped POST.
- toolset-config-panel.tsx: PostSetupRunner sub-component (Run setup
button + inline live log + activity-rail upsert + unmount guard),
replacing the CLI-only placeholder.
- i18n: replace the orphaned `toolsets.postSetup` (CLI redirect) string
with proper post-setup UI keys (hint / run / running / starting /
complete / error / failed) across en, ja, zh, zh-hant + types.
- test: post-setup run+poll+log-tail coverage; mock additions for
runToolsetPostSetup/getActionStatus/activity store.
Works against local AND remote backends: all calls route through the
desktop's single `hermes:api` IPC handler to connection.baseUrl, so a
connected remote configures the remote host's tools (keys -> remote
.env, install runs on the remote). Relies on the post-setup endpoint +
'hermes tools post-setup' CLI shipped in #40418.
Verification: tsc -b clean (all 5 locales), eslint clean (the lone
exhaustive-deps warning is pre-existing on origin/main), vitest 4/5
(new post-setup test passes; the failing 'saves an API key' test fails
identically on origin/main — pre-existing EnvVarActionsMenu drift).
This commit is contained in:
@@ -542,8 +542,16 @@ export const en: Translations = {
|
||||
ready: 'Ready',
|
||||
nousIncluded: 'Included with a Nous subscription — sign in to Nous Portal to activate.',
|
||||
noApiKeyRequired: 'No API key required.',
|
||||
postSetup: step =>
|
||||
`This provider needs an extra setup step (${step}). Run it from the CLI with hermes tools for now.`
|
||||
postSetupHint: step =>
|
||||
`This backend needs a one-time install (${step}). Runs on this machine — may take a few minutes.`,
|
||||
postSetupRun: 'Run setup',
|
||||
postSetupRunning: 'Installing…',
|
||||
postSetupStarting: 'Starting…',
|
||||
postSetupCompleteTitle: 'Setup complete',
|
||||
postSetupCompleteMessage: step => `${step} installed.`,
|
||||
postSetupErrorTitle: 'Setup finished with errors',
|
||||
postSetupErrorMessage: step => `Check the ${step} log.`,
|
||||
postSetupFailed: step => `Failed to run ${step} setup`
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -637,8 +637,16 @@ export const ja = defineLocale({
|
||||
ready: '準備完了',
|
||||
nousIncluded: 'Nous サブスクリプションに含まれています。有効にするには Nous Portal にサインインしてください。',
|
||||
noApiKeyRequired: 'API キーは不要です。',
|
||||
postSetup: step =>
|
||||
`このプロバイダーは追加のセットアップ手順 (${step}) が必要です。今は CLI で hermes tools を実行してください。`
|
||||
postSetupHint: step =>
|
||||
`このバックエンドは一度だけインストールが必要です (${step})。このマシン上で実行され、数分かかる場合があります。`,
|
||||
postSetupRun: 'セットアップを実行',
|
||||
postSetupRunning: 'インストール中…',
|
||||
postSetupStarting: '開始中…',
|
||||
postSetupCompleteTitle: 'セットアップ完了',
|
||||
postSetupCompleteMessage: step => `${step} をインストールしました。`,
|
||||
postSetupErrorTitle: 'セットアップはエラーで終了しました',
|
||||
postSetupErrorMessage: step => `${step} のログを確認してください。`,
|
||||
postSetupFailed: step => `${step} のセットアップの実行に失敗しました`
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -450,7 +450,15 @@ export interface Translations {
|
||||
ready: string
|
||||
nousIncluded: string
|
||||
noApiKeyRequired: string
|
||||
postSetup: (step: string) => string
|
||||
postSetupHint: (step: string) => string
|
||||
postSetupRun: string
|
||||
postSetupRunning: string
|
||||
postSetupStarting: string
|
||||
postSetupCompleteTitle: string
|
||||
postSetupCompleteMessage: (step: string) => string
|
||||
postSetupErrorTitle: string
|
||||
postSetupErrorMessage: (step: string) => string
|
||||
postSetupFailed: (step: string) => string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -621,7 +621,15 @@ export const zhHant = defineLocale({
|
||||
ready: '就緒',
|
||||
nousIncluded: '包含在 Nous 訂閱中;登入 Nous Portal 即可啟用。',
|
||||
noApiKeyRequired: '不需要 API 金鑰。',
|
||||
postSetup: step => `此提供方需要額外設定步驟 (${step})。暫時請在 CLI 中執行 hermes tools。`
|
||||
postSetupHint: step => `此後端需要一次性安裝 (${step})。將在此機器上執行,可能需要幾分鐘。`,
|
||||
postSetupRun: '執行設定',
|
||||
postSetupRunning: '安裝中…',
|
||||
postSetupStarting: '啟動中…',
|
||||
postSetupCompleteTitle: '設定完成',
|
||||
postSetupCompleteMessage: step => `已安裝 ${step}。`,
|
||||
postSetupErrorTitle: '設定完成但有錯誤',
|
||||
postSetupErrorMessage: step => `請檢查 ${step} 日誌。`,
|
||||
postSetupFailed: step => `執行 ${step} 設定失敗`
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -696,7 +696,15 @@ export const zh: Translations = {
|
||||
ready: '就绪',
|
||||
nousIncluded: '包含在 Nous 订阅中;登录 Nous Portal 即可激活。',
|
||||
noApiKeyRequired: '不需要 API 密钥。',
|
||||
postSetup: step => `此提供方需要额外设置步骤 (${step})。暂时请在 CLI 中运行 hermes tools。`
|
||||
postSetupHint: step => `此后端需要一次性安装 (${step})。将在此机器上执行,可能需要几分钟。`,
|
||||
postSetupRun: '运行设置',
|
||||
postSetupRunning: '安装中…',
|
||||
postSetupStarting: '启动中…',
|
||||
postSetupCompleteTitle: '设置完成',
|
||||
postSetupCompleteMessage: step => `已安装 ${step}。`,
|
||||
postSetupErrorTitle: '设置完成但有错误',
|
||||
postSetupErrorMessage: step => `请检查 ${step} 日志。`,
|
||||
postSetupFailed: step => `运行 ${step} 设置失败`
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user