ethagent 3.3.4 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/.claude-plugin/marketplace.json +11 -0
  2. package/.claude-plugin/plugin.json +35 -0
  3. package/LICENSE +1 -1
  4. package/README.md +64 -104
  5. package/commands/ethagent.md +40 -0
  6. package/package.json +16 -16
  7. package/src/app/keybindings/KeybindingProvider.tsx +1 -6
  8. package/src/app/keybindings/types.ts +1 -6
  9. package/src/cli/ResetConfirmView.tsx +54 -53
  10. package/src/cli/demo.ts +86 -0
  11. package/src/cli/hookIo.ts +45 -0
  12. package/src/cli/main.tsx +94 -123
  13. package/src/cli/memoryGuard.ts +49 -0
  14. package/src/cli/reset.ts +28 -70
  15. package/src/cli/sessionStart.ts +33 -0
  16. package/src/cli/status.ts +46 -0
  17. package/src/cli/sync.ts +167 -0
  18. package/src/cli/syncAdapters/claude-code.ts +86 -0
  19. package/src/cli/syncAdapters/codex.ts +66 -0
  20. package/src/cli/syncAdapters/index.ts +45 -0
  21. package/src/cli/syncAdapters/managedBlock.ts +175 -0
  22. package/src/cli/syncAdapters/shared.ts +63 -0
  23. package/src/identity/continuity/envelopeParse.ts +20 -1
  24. package/src/identity/continuity/publicSkills.ts +3 -1
  25. package/src/identity/continuity/skills/publicSkillsSync.ts +2 -1
  26. package/src/identity/continuity/skills/scaffold.ts +5 -2
  27. package/src/identity/continuity/snapshots.ts +12 -5
  28. package/src/identity/continuity/storage/defaults.ts +20 -19
  29. package/src/identity/continuity/storage/status.ts +1 -1
  30. package/src/identity/ens/ensLookup/constants.ts +1 -1
  31. package/src/identity/manager/IdentityManager.tsx +33 -0
  32. package/src/identity/{hub → manager}/OperationalRoutes.tsx +37 -18
  33. package/src/identity/{hub → manager}/Routes.tsx +48 -34
  34. package/src/identity/{hub → manager}/continuity/ContinuityDashboardScreen.tsx +9 -19
  35. package/src/identity/{hub → manager}/continuity/RebackupStorageScreen.tsx +3 -3
  36. package/src/identity/manager/continuity/RecoveryConfirmScreen.tsx +102 -0
  37. package/src/identity/{hub → manager}/continuity/SavePromptScreen.tsx +2 -3
  38. package/src/identity/{hub → manager}/continuity/completion.ts +1 -1
  39. package/src/identity/{hub → manager}/continuity/effects.ts +1 -1
  40. package/src/identity/{hub → manager}/continuity/skills/DeleteSkillConfirmScreen.tsx +2 -2
  41. package/src/identity/{hub → manager}/continuity/skills/NewSkillScreen.tsx +0 -5
  42. package/src/identity/{hub → manager}/continuity/skills/NewSkillVisibilityScreen.tsx +4 -4
  43. package/src/identity/{hub → manager}/continuity/skills/SkillActionsScreen.tsx +6 -22
  44. package/src/identity/{hub → manager}/continuity/skills/SkillsTreeScreen.tsx +5 -17
  45. package/src/identity/{hub → manager}/continuity/snapshot.ts +1 -1
  46. package/src/identity/{hub → manager}/continuity/vault.ts +1 -1
  47. package/src/identity/{hub → manager}/create/CreateFlow.tsx +59 -32
  48. package/src/identity/{hub → manager}/create/effects.ts +19 -10
  49. package/src/identity/manager/create/importScan.ts +122 -0
  50. package/src/identity/{hub → manager}/custody/CustodyEditFlow.tsx +17 -61
  51. package/src/identity/{hub → manager}/custody/actions.ts +1 -15
  52. package/src/identity/{hub → manager}/custody/routes.tsx +20 -40
  53. package/src/identity/{hub → manager}/custody/transactions.ts +1 -0
  54. package/src/identity/{hub → manager}/custody/types.ts +1 -2
  55. package/src/identity/{hub → manager}/custody/useCustodyEffects.ts +1 -1
  56. package/src/identity/{hub → manager}/ens/EnsEditAdvancedScreens.tsx +2 -2
  57. package/src/identity/{hub → manager}/ens/EnsEditMaintenanceScreens.tsx +12 -23
  58. package/src/identity/{hub → manager}/ens/EnsEditReviewScreens.tsx +18 -42
  59. package/src/identity/{hub → manager}/ens/EnsEditRunners.tsx +1 -1
  60. package/src/identity/{hub → manager}/ens/EnsEditShared.tsx +0 -2
  61. package/src/identity/{hub → manager}/ens/EnsEditSimpleScreens.tsx +10 -19
  62. package/src/identity/{hub → manager}/ens/EnsFlow.tsx +133 -41
  63. package/src/identity/{hub → manager}/ens/EnsOperatorWalletsScreen.tsx +14 -19
  64. package/src/identity/{hub → manager}/ens/editCopy.ts +1 -14
  65. package/src/identity/{hub → manager}/profile/EditProfileFlow.tsx +99 -66
  66. package/src/identity/{hub → manager}/profile/effects.ts +1 -3
  67. package/src/identity/{hub → manager}/profile/operatorSave.ts +1 -1
  68. package/src/identity/{hub → manager}/profile/state.ts +1 -1
  69. package/src/identity/{hub/identityHubReducer.ts → manager/reducer.ts} +25 -26
  70. package/src/identity/{hub → manager}/restore/RestoreFlow.tsx +16 -24
  71. package/src/identity/{hub → manager}/restore/apply.ts +1 -1
  72. package/src/identity/{hub → manager}/restore/auth.ts +1 -1
  73. package/src/identity/{hub → manager}/restore/discover.ts +1 -1
  74. package/src/identity/{hub → manager}/restore/fetch.ts +1 -1
  75. package/src/identity/{hub → manager}/restore/restoreAdmin.ts +1 -1
  76. package/src/identity/{hub → manager}/restore/useRestoreEffects.ts +2 -9
  77. package/src/identity/{hub → manager}/settings/StorageCredentialScreen.tsx +10 -25
  78. package/src/identity/{hub → manager}/shared/components/DetailsScreen.tsx +5 -7
  79. package/src/identity/{hub → manager}/shared/components/ErrorScreen.tsx +6 -10
  80. package/src/identity/{hub → manager}/shared/components/FlowTimeline.tsx +4 -3
  81. package/src/identity/{hub → manager}/shared/components/IdentitySummary.tsx +19 -59
  82. package/src/identity/manager/shared/components/LazyMenu.tsx +147 -0
  83. package/src/identity/manager/shared/components/MenuScreen.tsx +220 -0
  84. package/src/identity/manager/shared/components/OperationCompleteScreen.tsx +28 -0
  85. package/src/identity/{hub → manager}/shared/components/UnlinkedIdentityScreen.tsx +9 -10
  86. package/src/identity/{hub → manager}/shared/components/WalletApprovalScreen.tsx +1 -2
  87. package/src/identity/manager/shared/components/Wordmark.tsx +54 -0
  88. package/src/identity/{hub → manager}/shared/components/menuFlagsFromReconciliation.ts +39 -15
  89. package/src/identity/{hub → manager}/shared/effects/profilePrep.ts +1 -1
  90. package/src/identity/manager/shared/effects/types.ts +30 -0
  91. package/src/identity/{hub → manager}/shared/model/copy.ts +0 -4
  92. package/src/identity/{hub → manager}/shared/model/errors.ts +32 -3
  93. package/src/identity/{hub → manager}/shared/model/network.ts +2 -2
  94. package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/hook.ts +5 -0
  95. package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/run.ts +1 -1
  96. package/src/identity/{hub/shared/reconciliation/useAgentReconciliation.ts → manager/shared/reconciliation/index.ts} +6 -0
  97. package/src/identity/{hub → manager}/shared/utils.ts +6 -10
  98. package/src/identity/{hub → manager}/transfer/TokenTransferFlow.tsx +3 -3
  99. package/src/identity/{hub → manager}/transfer/TokenTransferScreens.tsx +4 -10
  100. package/src/identity/{hub → manager}/transfer/effects.ts +1 -1
  101. package/src/identity/{hub → manager}/types.ts +5 -6
  102. package/src/identity/{hub/useIdentityHubContinuity.ts → manager/useContinuity.ts} +59 -27
  103. package/src/identity/{hub/useIdentityHubController.ts → manager/useController.ts} +38 -35
  104. package/src/identity/{hub/useIdentityHubSideEffects.ts → manager/useSideEffects.ts} +40 -4
  105. package/src/identity/registry/erc8004/discovery.ts +3 -17
  106. package/src/identity/registry/erc8004/utils.ts +1 -1
  107. package/src/identity/storage/ipfs.ts +21 -1
  108. package/src/identity/wallet/browserWallet/html.ts +10 -2
  109. package/src/identity/wallet/browserWallet/http.ts +18 -0
  110. package/src/identity/wallet/browserWallet/requestServer.ts +5 -1
  111. package/src/identity/wallet/browserWallet/requests.ts +10 -28
  112. package/src/identity/wallet/browserWallet/session.ts +26 -33
  113. package/src/identity/wallet/browserWallet/validation.ts +14 -0
  114. package/src/identity/wallet/browserWallet/walletPageSource.ts +22 -40
  115. package/src/identity/wallet/page/boot.ts +43 -0
  116. package/src/identity/wallet/page/config.ts +59 -0
  117. package/src/identity/wallet/page/constants.ts +12 -0
  118. package/src/identity/wallet/page/copy.ts +47 -68
  119. package/src/identity/wallet/page/css.ts +638 -0
  120. package/src/identity/wallet/page/{errorView.ts → errors.ts} +5 -14
  121. package/src/identity/wallet/page/{controller.ts → flow.ts} +4 -71
  122. package/src/identity/wallet/page/markup.ts +44 -34
  123. package/src/identity/wallet/page/{walletProvider.ts → provider.ts} +0 -3
  124. package/src/identity/wallet/page/resize.ts +95 -0
  125. package/src/identity/wallet/page/state.ts +135 -8
  126. package/src/identity/wallet/page/timeline.ts +161 -0
  127. package/src/identity/wallet/page/view.ts +22 -302
  128. package/src/storage/config.ts +30 -80
  129. package/src/storage/reset.ts +31 -0
  130. package/src/storage/secrets.ts +1 -16
  131. package/src/ui/Select.tsx +27 -5
  132. package/src/ui/Spinner.tsx +16 -15
  133. package/src/ui/Surface.tsx +21 -17
  134. package/src/ui/TextArea.tsx +173 -0
  135. package/src/ui/TextInput.tsx +31 -133
  136. package/src/ui/theme.ts +22 -13
  137. package/src/utils/clipboard.ts +0 -140
  138. package/src/app/FirstRun.tsx +0 -577
  139. package/src/app/FirstRunTimeline.tsx +0 -51
  140. package/src/app/firstRunConfig.ts +0 -26
  141. package/src/app/hooks/useCancelRequest.ts +0 -22
  142. package/src/app/hooks/useDoublePress.ts +0 -46
  143. package/src/app/hooks/useExitOnCtrlC.ts +0 -36
  144. package/src/auth/openaiOAuth/credentials.ts +0 -47
  145. package/src/auth/openaiOAuth/crypto.ts +0 -23
  146. package/src/auth/openaiOAuth/index.ts +0 -238
  147. package/src/auth/openaiOAuth/landingPage.ts +0 -116
  148. package/src/auth/openaiOAuth/listener.ts +0 -151
  149. package/src/auth/openaiOAuth/refresh.ts +0 -70
  150. package/src/auth/openaiOAuth/shared.ts +0 -115
  151. package/src/chat/ChatBottomPane.tsx +0 -296
  152. package/src/chat/ChatScreen.tsx +0 -1685
  153. package/src/chat/ConversationStack.tsx +0 -56
  154. package/src/chat/MessageList.tsx +0 -638
  155. package/src/chat/SessionStatus.tsx +0 -53
  156. package/src/chat/chatEnvironment.ts +0 -16
  157. package/src/chat/chatScreenUtils.ts +0 -194
  158. package/src/chat/chatSessionState.ts +0 -146
  159. package/src/chat/chatTurnContext.ts +0 -50
  160. package/src/chat/chatTurnOrchestrator.ts +0 -603
  161. package/src/chat/chatTurnRows.ts +0 -64
  162. package/src/chat/commands.ts +0 -494
  163. package/src/chat/continuityEditReview.ts +0 -42
  164. package/src/chat/display/DiffView.tsx +0 -193
  165. package/src/chat/display/SyntaxText.tsx +0 -192
  166. package/src/chat/display/toolCallDisplay.ts +0 -103
  167. package/src/chat/display/toolResultDisplay.ts +0 -19
  168. package/src/chat/input/ChatInput.tsx +0 -625
  169. package/src/chat/input/chatInputHelpers.ts +0 -62
  170. package/src/chat/input/chatInputState.ts +0 -247
  171. package/src/chat/input/chatPaste.ts +0 -49
  172. package/src/chat/input/imageRefs.ts +0 -30
  173. package/src/chat/input/inputRendering.tsx +0 -93
  174. package/src/chat/input/textCursor.ts +0 -212
  175. package/src/chat/messageMarkdown.ts +0 -220
  176. package/src/chat/messageRows.ts +0 -43
  177. package/src/chat/planImplementation.ts +0 -62
  178. package/src/chat/slashCommandHandlers.ts +0 -122
  179. package/src/chat/slashCommandViews.ts +0 -120
  180. package/src/chat/transcript/TranscriptView.tsx +0 -184
  181. package/src/chat/transcript/transcriptViewport.ts +0 -295
  182. package/src/chat/views/ContextLimitView.tsx +0 -95
  183. package/src/chat/views/ContinuityEditReviewView.tsx +0 -50
  184. package/src/chat/views/CopyPicker.tsx +0 -50
  185. package/src/chat/views/PermissionPrompt.tsx +0 -156
  186. package/src/chat/views/PermissionsView.tsx +0 -165
  187. package/src/chat/views/PlanApprovalView.tsx +0 -91
  188. package/src/chat/views/ResumeView.tsx +0 -273
  189. package/src/chat/views/RewindView.tsx +0 -412
  190. package/src/cli/preview.tsx +0 -14
  191. package/src/cli/updateNotice.ts +0 -54
  192. package/src/identity/continuity/privateEdit/apply.ts +0 -170
  193. package/src/identity/continuity/privateEdit/diff.ts +0 -6
  194. package/src/identity/continuity/privateEdit/files.ts +0 -23
  195. package/src/identity/continuity/privateEdit/types.ts +0 -28
  196. package/src/identity/continuity/privateEdit.ts +0 -46
  197. package/src/identity/hub/IdentityHub.tsx +0 -14
  198. package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +0 -104
  199. package/src/identity/hub/ens/effects.ts +0 -218
  200. package/src/identity/hub/shared/components/MenuScreen.tsx +0 -241
  201. package/src/identity/hub/shared/effects/types.ts +0 -53
  202. package/src/identity/hub/shared/reconciliation/index.ts +0 -14
  203. package/src/identity/wallet/page/grainient.ts +0 -278
  204. package/src/identity/wallet/page/html.ts +0 -28
  205. package/src/identity/wallet/page/styles/base.ts +0 -260
  206. package/src/identity/wallet/page/styles/components.ts +0 -262
  207. package/src/identity/wallet/page/styles/index.ts +0 -5
  208. package/src/identity/wallet/page/styles/responsive.ts +0 -247
  209. package/src/identity/wallet/page.tsx +0 -38
  210. package/src/mcp/approvals.ts +0 -113
  211. package/src/mcp/config.ts +0 -235
  212. package/src/mcp/manager.ts +0 -482
  213. package/src/mcp/managerHelpers.ts +0 -70
  214. package/src/mcp/names.ts +0 -19
  215. package/src/mcp/output.ts +0 -96
  216. package/src/models/ModelPicker.tsx +0 -1009
  217. package/src/models/catalog.ts +0 -327
  218. package/src/models/huggingface.ts +0 -712
  219. package/src/models/huggingfaceStorage.ts +0 -136
  220. package/src/models/llamacpp.ts +0 -848
  221. package/src/models/llamacppCommands.ts +0 -44
  222. package/src/models/llamacppConfig.ts +0 -34
  223. package/src/models/llamacppDiscovery.ts +0 -176
  224. package/src/models/llamacppOutput.ts +0 -65
  225. package/src/models/llamacppPreflight.ts +0 -158
  226. package/src/models/modelDisplay.ts +0 -180
  227. package/src/models/modelPickerCatalogFlow.ts +0 -56
  228. package/src/models/modelPickerCredentials.ts +0 -166
  229. package/src/models/modelPickerData.ts +0 -41
  230. package/src/models/modelPickerDisplay.tsx +0 -132
  231. package/src/models/modelPickerHfFlow.ts +0 -192
  232. package/src/models/modelPickerLocalRunnerFlow.ts +0 -115
  233. package/src/models/modelPickerOptions.ts +0 -457
  234. package/src/models/modelPickerTypes.ts +0 -69
  235. package/src/models/modelPickerUninstallFlow.ts +0 -48
  236. package/src/models/modelPickerViewHelpers.ts +0 -174
  237. package/src/models/modelRecommendation.ts +0 -139
  238. package/src/models/providerDisplay.ts +0 -16
  239. package/src/models/runtimeDetection.ts +0 -81
  240. package/src/models/uncensoredCatalog.ts +0 -86
  241. package/src/providers/anthropic.ts +0 -290
  242. package/src/providers/contracts.ts +0 -71
  243. package/src/providers/errors.ts +0 -80
  244. package/src/providers/gemini.ts +0 -391
  245. package/src/providers/openai-chat.ts +0 -474
  246. package/src/providers/openai-responses-format.ts +0 -177
  247. package/src/providers/openai-responses.ts +0 -306
  248. package/src/providers/openaiChatWire.ts +0 -124
  249. package/src/providers/registry.ts +0 -120
  250. package/src/providers/retry.ts +0 -58
  251. package/src/providers/sse.ts +0 -93
  252. package/src/runtime/compaction.ts +0 -395
  253. package/src/runtime/cwd.ts +0 -43
  254. package/src/runtime/providerTurn.ts +0 -38
  255. package/src/runtime/sessionMode.ts +0 -55
  256. package/src/runtime/systemPrompt.ts +0 -213
  257. package/src/runtime/textToolParser.ts +0 -161
  258. package/src/runtime/toolClaimGuards.ts +0 -143
  259. package/src/runtime/toolExecution.ts +0 -304
  260. package/src/runtime/toolIntent.ts +0 -143
  261. package/src/runtime/turn.ts +0 -369
  262. package/src/runtime/turnNudges.ts +0 -223
  263. package/src/runtime/turnTypes.ts +0 -86
  264. package/src/storage/factoryReset.ts +0 -127
  265. package/src/storage/history.ts +0 -58
  266. package/src/storage/permissions.ts +0 -76
  267. package/src/storage/rewind.ts +0 -266
  268. package/src/storage/sessionExport.ts +0 -49
  269. package/src/storage/sessions.ts +0 -495
  270. package/src/tools/bashSafety.ts +0 -186
  271. package/src/tools/bashTool.ts +0 -140
  272. package/src/tools/changeDirectoryTool.ts +0 -213
  273. package/src/tools/contracts.ts +0 -192
  274. package/src/tools/deleteFileTool.ts +0 -116
  275. package/src/tools/editTool.ts +0 -165
  276. package/src/tools/editUtils.ts +0 -170
  277. package/src/tools/fileDiff.ts +0 -261
  278. package/src/tools/listDirectoryTool.ts +0 -55
  279. package/src/tools/listSkillFilesTool.ts +0 -77
  280. package/src/tools/listSkillsTool.ts +0 -68
  281. package/src/tools/mcpResourceTools.ts +0 -95
  282. package/src/tools/permissionRules.ts +0 -85
  283. package/src/tools/privateContinuityEditTool.ts +0 -187
  284. package/src/tools/privateContinuityReadTool.ts +0 -106
  285. package/src/tools/readSkillTool.ts +0 -107
  286. package/src/tools/readTool.ts +0 -85
  287. package/src/tools/registry.ts +0 -103
  288. package/src/tools/writeFileTool.ts +0 -167
  289. package/src/ui/BrandSplash.tsx +0 -133
  290. package/src/ui/terminalTitle.ts +0 -30
  291. package/src/utils/images.ts +0 -140
  292. package/src/utils/markdownSegments.ts +0 -51
  293. package/src/utils/messages.ts +0 -37
  294. package/src/utils/withRetry.ts +0 -324
  295. /package/src/identity/{hub → manager}/continuity/state.ts +0 -0
  296. /package/src/identity/{hub → manager}/custody/helpers.ts +0 -0
  297. /package/src/identity/{hub → manager}/custody/preflight.ts +0 -0
  298. /package/src/identity/{hub → manager}/custody/state.ts +0 -0
  299. /package/src/identity/{hub → manager}/custody/useCustodyFlow.tsx +0 -0
  300. /package/src/identity/{hub → manager}/ens/EnsEditFlow.tsx +0 -0
  301. /package/src/identity/{hub → manager}/ens/advancedEnsValidation.ts +0 -0
  302. /package/src/identity/{hub → manager}/ens/state.ts +0 -0
  303. /package/src/identity/{hub → manager}/ens/transactions.ts +0 -0
  304. /package/src/identity/{hub → manager}/ens/types.ts +0 -0
  305. /package/src/identity/{hub → manager}/profile/identity.ts +0 -0
  306. /package/src/identity/{hub → manager}/restore/envelopes.ts +0 -0
  307. /package/src/identity/{hub → manager}/restore/helpers.ts +0 -0
  308. /package/src/identity/{hub → manager}/restore/recovery.ts +0 -0
  309. /package/src/identity/{hub → manager}/restore/resolve.ts +0 -0
  310. /package/src/identity/{hub → manager}/shared/components/BusyScreen.tsx +0 -0
  311. /package/src/identity/{hub → manager}/shared/components/NetworkScreen.tsx +0 -0
  312. /package/src/identity/{hub → manager}/shared/components/PinataJwtInput.tsx +0 -0
  313. /package/src/identity/{hub → manager}/shared/effects/receipts.ts +0 -0
  314. /package/src/identity/{hub → manager}/shared/effects/sync.ts +0 -0
  315. /package/src/identity/{hub → manager}/shared/model/format.ts +0 -0
  316. /package/src/identity/{hub → manager}/shared/operatorWallets.ts +0 -0
  317. /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/ownership.ts +0 -0
  318. /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/types.ts +0 -0
  319. /package/src/identity/{hub → manager}/shared/reconciliation/walletSetup.ts +0 -0
  320. /package/src/identity/{hub → manager}/shared/txGuard.ts +0 -0
  321. /package/src/identity/{hub → manager}/transfer/progress.ts +0 -0
  322. /package/src/identity/{hub → manager}/transfer/state.ts +0 -0
@@ -1,115 +0,0 @@
1
- import type {
2
- LlamaCppInstallProgress,
3
- LlamaCppInstallResult,
4
- LlamaCppStartResult,
5
- } from './llamacpp.js'
6
- import {
7
- installLlamaCppRunner,
8
- setLlamaCppServerPath,
9
- startLlamaCppServer,
10
- } from './llamacpp.js'
11
- import type { LocalHfModel } from './huggingface.js'
12
- import type { ModelPickerSelection, ModelPickerState as State } from './modelPickerTypes.js'
13
- import { loadHfPickerModels, probeLlamaCpp } from './modelPickerData.js'
14
- export function localRunnerStartFailureSubtitle(result: Extract<LlamaCppStartResult, { ok: false }>): string {
15
- switch (result.code) {
16
- case 'readiness-timeout':
17
- return 'the local runner is still loading or did not answer in time'
18
- case 'runner-exited':
19
- return 'the local runner closed before becoming ready'
20
- case 'spawn-failed':
21
- return 'the local runner could not be started'
22
- case 'different-model-running':
23
- return result.message
24
- case 'model-file-missing':
25
- return result.message
26
- case 'runner-not-installed':
27
- return 'this machine still needs a local runner'
28
- }
29
- }
30
-
31
- export async function startAndPickHfModel(
32
- model: LocalHfModel,
33
- state: Extract<State, { kind: 'list' | 'localCatalog' | 'hfDone' | 'mmprojOffer' | 'mmprojError' }>,
34
- setState: (s: State) => void,
35
- onPick: (sel: ModelPickerSelection) => void,
36
- ): Promise<void> {
37
- if (model.risk === 'high') {
38
- setState({ kind: 'hfError', data: state.data, message: 'blocked high-risk model; choose a model from a more credible source' })
39
- return
40
- }
41
- if (model.mmprojAvailable && !model.mmprojPath && state.kind !== 'mmprojOffer' && state.kind !== 'mmprojError') {
42
- setState({ kind: 'mmprojOffer', data: state.data, model })
43
- return
44
- }
45
- setState({ kind: 'localRunnerStarting', data: state.data, model, startedAt: Date.now() })
46
- const result = await startLlamaCppServer({
47
- modelPath: model.localPath,
48
- modelAlias: model.id,
49
- mmprojPath: model.mmprojPath,
50
- })
51
- const llamaCpp = await probeLlamaCpp()
52
- const data = { ...state.data, llamaCpp }
53
- if (!result.ok) {
54
- if (result.code === 'runner-not-installed') {
55
- setState({ kind: 'localRunnerSetup', data, model })
56
- return
57
- }
58
- setState({ kind: 'localRunnerStartFail', data, model, result })
59
- return
60
- }
61
- onPick({ kind: 'llamacpp', model: model.id, mmprojPath: model.mmprojPath })
62
- }
63
-
64
- export async function installRunnerAndStart(
65
- state: Extract<State, { kind: 'localRunnerSetup' }>,
66
- setState: (s: State) => void,
67
- onPick: (sel: ModelPickerSelection) => void,
68
- ): Promise<void> {
69
- await runRunnerSetup(state, setState, onPick, installLlamaCppRunner)
70
- }
71
-
72
- export async function runRunnerSetup(
73
- state: Extract<State, { kind: 'localRunnerSetup' }>,
74
- setState: (s: State) => void,
75
- onPick: (sel: ModelPickerSelection) => void,
76
- setup: (onProgress?: (progress: LlamaCppInstallProgress) => void) => Promise<LlamaCppInstallResult>,
77
- ): Promise<void> {
78
- const startedAt = Date.now()
79
- const initialProgress: LlamaCppInstallProgress = {
80
- phase: 'checking',
81
- label: 'preparing local runner...',
82
- progress: 0.04,
83
- }
84
- const updateProgress = (progress: LlamaCppInstallProgress): void => {
85
- setState({ kind: 'localRunnerInstalling', data: state.data, model: state.model, startedAt, progress })
86
- }
87
-
88
- setState({ kind: 'localRunnerInstalling', data: state.data, model: state.model, startedAt, progress: initialProgress })
89
- const result = await setup(updateProgress)
90
- if (!result.ok) {
91
- setState({ kind: 'localRunnerInstallFail', data: state.data, model: state.model, result })
92
- return
93
- }
94
- await startAndPickHfModel(state.model, { kind: 'hfDone', data: state.data, model: state.model }, setState, onPick)
95
- }
96
-
97
- export async function saveRunnerPathAndStart(
98
- state: Extract<State, { kind: 'localRunnerPathEntry' }>,
99
- value: string,
100
- setState: (s: State) => void,
101
- onPick: (sel: ModelPickerSelection) => void,
102
- ): Promise<void> {
103
- const runnerPath = value.trim().replace(/^"|"$/g, '')
104
- if (!runnerPath) {
105
- setState({ ...state, error: 'paste the full path to llama-server' })
106
- return
107
- }
108
- setState({ ...state, submitting: true, error: undefined })
109
- try {
110
- await setLlamaCppServerPath(runnerPath)
111
- await startAndPickHfModel(state.model, { kind: 'hfDone', data: state.data, model: state.model }, setState, onPick)
112
- } catch (err: unknown) {
113
- setState({ ...state, submitting: false, error: (err as Error).message })
114
- }
115
- }
@@ -1,457 +0,0 @@
1
- import { defaultModelFor, type ProviderId } from '../storage/config.js'
2
- import { type ModelCatalogEntry, type ModelCatalogResult } from './catalog.js'
3
- import type { HfRisk, HfTask } from './huggingface.js'
4
- import type { SpecSnapshot } from './runtimeDetection.js'
5
- import { contextWindowInfo } from '../runtime/compaction.js'
6
- import { type SelectOption } from '../ui/Select.js'
7
- import { formatLocalHfModelDisplayName, formatModelDisplayName } from './modelDisplay.js'
8
- import { localModelId, quantizationFromFilename } from './huggingface.js'
9
- import type { UncensoredCatalogEntry } from './uncensoredCatalog.js'
10
- import { cloudProviderDisplayName, providerDisplayName, type CloudProviderId } from './providerDisplay.js'
11
-
12
- export { cloudProviderDisplayName, providerDisplayName, type CloudProviderId }
13
-
14
- export const MODEL_PICKER_CLOUD_PROVIDERS: CloudProviderId[] = ['openai', 'anthropic', 'gemini']
15
- export const LOCAL_MODEL_LINK_HINT = 'Paste a GGUF link'
16
- export const LOCAL_MODEL_LINK_EXAMPLE = 'e.g. https://huggingface.co/Qwen/Qwen3-8B-GGUF'
17
-
18
- export type LocalHfPickerModel = {
19
- id: string
20
- displayName: string
21
- sizeBytes: number
22
- quantization?: string
23
- risk: HfRisk
24
- task: HfTask
25
- status: 'ready' | 'incomplete'
26
- mmprojPath?: string
27
- mmprojAvailable?: boolean
28
- mmprojSizeBytes?: number
29
- }
30
-
31
- export type CloudCredentialKind = 'apikey' | 'oauth'
32
-
33
- export type ModelPickerOptionsData = {
34
- llamaCpp: {
35
- binaryPresent: boolean
36
- serverUp: boolean
37
- error?: string
38
- }
39
- hfModels: LocalHfPickerModel[]
40
- machineSpec?: SpecSnapshot
41
- cloudKeys: Partial<Record<ProviderId, boolean>>
42
- cloudCatalogs: Partial<Record<ProviderId, ModelCatalogResult>>
43
- cloudCredentialKinds?: Partial<Record<ProviderId, CloudCredentialKind>>
44
- }
45
-
46
- export type ModelPickerContextFit = {
47
- usedTokens: number
48
- thresholdPercent?: number
49
- }
50
-
51
- export type ModelPickerOptionsContext = {
52
- currentProvider: ProviderId
53
- currentModel: string
54
- contextFit?: ModelPickerContextFit | null
55
- }
56
-
57
- const CURATED_CLOUD_MODEL_LIMIT = 3
58
- const PROVIDER_INDENT = 2
59
- const CHILD_INDENT = 4
60
-
61
- export function buildModelPickerOptions(
62
- data: ModelPickerOptionsData,
63
- context: ModelPickerOptionsContext,
64
- options_: { localOnly?: boolean } = {},
65
- ): SelectOption<string>[] {
66
- const localOnly = options_.localOnly === true
67
- const options: SelectOption<string>[] = []
68
-
69
- options.push(sectionOption('hdr:local', 'Local Models'))
70
- appendHfModelOptions(options, data, context, 'Added From Links', 46)
71
- options.push(groupOption('hdr:local:manage', 'Manage'))
72
- options.push(utilityOption('hf:download', 'Add Local Model File', LOCAL_MODEL_LINK_HINT))
73
- options.push(utilityOption('local:catalog', 'View Full Catalog', 'Curated local GGUF files'))
74
- if (data.hfModels.length > 0) {
75
- options.push(utilityOption('local:uninstall', 'Uninstall Downloaded GGUF'))
76
- }
77
-
78
- if (!localOnly) {
79
- options.push(sectionOption('hdr:cloud', 'Cloud'))
80
- for (const provider of MODEL_PICKER_CLOUD_PROVIDERS) {
81
- options.push(groupOption(`hdr:cloud:${provider}`, cloudProviderDisplayName(provider)))
82
- const keySet = data.cloudKeys[provider] === true
83
- if (!keySet) {
84
- if (provider === 'openai') {
85
- options.push(utilityOption('oauth:openai', 'Sign in with ChatGPT', 'Use your ChatGPT subscription'))
86
- }
87
- options.push(utilityOption(`key:set:${provider}`, 'Add API Key'))
88
- continue
89
- }
90
-
91
- const catalog = data.cloudCatalogs[provider]
92
- if (catalog?.status === 'fallback') {
93
- const reason = catalog.error ? ` · ${catalog.error}` : ''
94
- options.push(noticeOption(
95
- `hdr:cloud-fallback:${provider}`,
96
- `Catalog unavailable${reason} · showing configured model`,
97
- CHILD_INDENT,
98
- ))
99
- }
100
-
101
- const models = orderModelsForContextFit(provider, cloudPickerModels(provider, catalog, context), context.contextFit)
102
- if (models.length === 0) {
103
- options.push(noticeOption(`hdr:cloud-empty:${provider}`, 'No selectable models', CHILD_INDENT))
104
- }
105
- for (const model of models) {
106
- const active = context.currentProvider === provider && context.currentModel === model
107
- const displayName = formatModelDisplayName(provider, model, { maxLength: 58 })
108
- options.push(rowOption(
109
- `c:${provider}:${model}`,
110
- contextFitLabel(provider, model, `${displayName}${active ? ' *' : ''}`, context.contextFit),
111
- ))
112
- }
113
- options.push(groupOption(`hdr:cloud:${provider}:manage`, 'Manage'))
114
- options.push(utilityOption(`catalog:${provider}`, 'Full Catalog'))
115
- const manageLabel = provider === 'openai' && data.cloudCredentialKinds?.openai === 'oauth'
116
- ? 'Manage ChatGPT Sign-in'
117
- : 'Manage API Key'
118
- options.push(utilityOption(`key:manage:${provider}`, manageLabel))
119
- }
120
- }
121
-
122
- if (!localOnly) {
123
- options.push(sectionOption('hdr:exit', 'Exit'))
124
- options.push(utilityOption('cancel', 'Close Model Picker', 'Return to chat'))
125
- }
126
-
127
- return options
128
- }
129
-
130
- export function buildLocalModelCatalogOptions(
131
- data: ModelPickerOptionsData,
132
- context: ModelPickerOptionsContext,
133
- catalog: UncensoredCatalogEntry[] = [],
134
- ): SelectOption<string>[] {
135
- const options: SelectOption<string>[] = []
136
- options.push(sectionOption('hdr:local-catalog', 'View Full Catalog'))
137
- options.push(groupOption('hdr:uncensored:catalog', 'Curated Local GGUF Files'))
138
- if (catalog.length === 0) {
139
- options.push(noticeOption('hdr:uncensored-empty', 'Setup files unavailable; paste a GGUF link instead', CHILD_INDENT))
140
- } else {
141
- for (const entry of catalog) {
142
- const id = localModelId(entry.repo.repoId, entry.file.filename)
143
- const displayName = formatLocalHfModelDisplayName(id, {
144
- displayName: entry.file.filename.split('/').pop() ?? entry.file.filename,
145
- maxLength: 56,
146
- })
147
- const quant = quantLabel(entry.file.filename)
148
- options.push(rowOption(
149
- catalogOptionValue(entry.repo.repoId, entry.file.filename),
150
- displayName,
151
- undefined,
152
- modelMetadataSubtext(`${quant} · ${formatSize(entry.file.sizeBytes ?? 0)}`, [
153
- entry.recommended ? 'Recommended for this machine' : '',
154
- entry.installed ? 'Installed' : '',
155
- ]),
156
- ))
157
- }
158
- }
159
-
160
- appendHfModelOptions(options, data, context, 'Downloaded GGUF', 50)
161
- options.push(utilityOption('hf:download', 'Add Local Model File', LOCAL_MODEL_LINK_HINT))
162
-
163
- if (data.hfModels.length > 0) {
164
- options.push(utilityOption('local:uninstall', 'Uninstall Downloaded GGUF'))
165
- }
166
- options.push(sectionOption('hdr:navigation', 'Navigation'))
167
- options.push(utilityOption('back', 'Back To Picker', 'Return to model picker'))
168
- return options
169
- }
170
-
171
- function appendHfModelOptions(
172
- options: SelectOption<string>[],
173
- data: ModelPickerOptionsData,
174
- context: ModelPickerOptionsContext,
175
- groupLabel: string,
176
- maxLength: number,
177
- ): void {
178
- options.push(groupOption('hdr:local:hf', groupLabel))
179
- if (data.hfModels.length === 0) {
180
- options.push(noticeOption('hdr:hf-empty', 'No downloaded files', CHILD_INDENT))
181
- return
182
- }
183
-
184
- const models = orderModelsForContextFit(
185
- 'llamacpp',
186
- data.hfModels.map(model => model.id),
187
- context.contextFit,
188
- )
189
- const byId = new Map(data.hfModels.map(model => [model.id, model]))
190
- for (const id of models) {
191
- const model = byId.get(id)
192
- if (!model) continue
193
- const active = context.currentProvider === 'llamacpp' && id === context.currentModel
194
- const size = formatSize(model.sizeBytes)
195
- const displayName = formatLocalHfModelDisplayName(id, {
196
- displayName: model.displayName,
197
- maxLength,
198
- })
199
- const tags = ['Installed']
200
- if (model.mmprojPath) tags.push('Vision encoder loaded')
201
- options.push(rowOption(
202
- `hf:${id}`,
203
- contextFitLabel('llamacpp', id, `${active ? '* ' : ' '}${displayName}`, context.contextFit),
204
- undefined,
205
- modelMetadataSubtext(size, tags),
206
- ))
207
- if (model.mmprojAvailable && !model.mmprojPath) {
208
- const projectorSize = model.mmprojSizeBytes ? ` (+${formatSize(model.mmprojSizeBytes)})` : ''
209
- options.push(rowOption(
210
- `hfmmproj:${id}`,
211
- ` + Add Vision Encoder${projectorSize}`,
212
- 'Enable image input on this local model',
213
- ))
214
- }
215
- }
216
- }
217
-
218
- export function catalogOptionValue(repoId: string, filename: string): string {
219
- return `uc:${repoId}#${filename}`
220
- }
221
-
222
- export function cloudPickerModels(
223
- provider: CloudProviderId,
224
- catalog: ModelCatalogResult | undefined,
225
- _context: ModelPickerOptionsContext,
226
- ): string[] {
227
- const entries = catalog?.entries ?? []
228
- const discovered = catalog?.status === 'ok'
229
- ? curateDiscoveredCloudEntries(provider, entries).map(entry => entry.id)
230
- : entries.map(entry => entry.id)
231
- const models = dedupeStrings(discovered)
232
-
233
- if (catalog?.status !== 'ok' && entries.length === 0) {
234
- appendUnique(models, defaultModelFor(provider))
235
- }
236
-
237
- return models
238
- }
239
-
240
- export function curateDiscoveredCloudEntries(
241
- provider: CloudProviderId,
242
- entries: ModelCatalogEntry[],
243
- ): ModelCatalogEntry[] {
244
- const unique = dedupeEntries(entries)
245
- const eligible = unique.filter(entry => isCuratedModelCandidate(provider, entry.id))
246
- return rankEntriesByRecency(eligible).slice(0, CURATED_CLOUD_MODEL_LIMIT).map(item => item.entry)
247
- }
248
-
249
- export function orderModelsForContextFit(
250
- provider: ProviderId,
251
- models: string[],
252
- contextFit?: ModelPickerContextFit | null,
253
- ): string[] {
254
- if (!contextFit) return models
255
- return models
256
- .map((model, index) => ({ model, index, fit: modelContextFit(provider, model, contextFit) }))
257
- .sort((a, b) => {
258
- if (a.fit.fits !== b.fit.fits) return a.fit.fits ? -1 : 1
259
- return b.fit.windowTokens - a.fit.windowTokens || a.index - b.index
260
- })
261
- .map(item => item.model)
262
- }
263
-
264
- function contextFitLabel(
265
- provider: ProviderId,
266
- model: string,
267
- baseLabel: string,
268
- contextFit?: ModelPickerContextFit | null,
269
- ): string {
270
- if (!contextFit) return baseLabel
271
- const fit = modelContextFit(provider, model, contextFit)
272
- return `${baseLabel} ${formatContextWindow(fit.windowTokens)} ctx ${fit.percent}%`
273
- }
274
-
275
- function modelContextFit(provider: ProviderId, model: string, contextFit: ModelPickerContextFit): {
276
- fits: boolean
277
- percent: number
278
- windowTokens: number
279
- } {
280
- const windowTokens = contextWindowInfo(provider, model).tokens
281
- const percent = windowTokens > 0 ? Math.round((contextFit.usedTokens / windowTokens) * 100) : 0
282
- const threshold = contextFit.thresholdPercent ?? 90
283
- return { fits: percent < threshold, percent, windowTokens }
284
- }
285
-
286
- function quantLabel(filename: string): string {
287
- if (filename.toLowerCase().startsWith('mmproj-')) return 'Vision encoder'
288
- return quantizationFromFilename(filename) ?? 'GGUF'
289
- }
290
-
291
- function sectionOption(value: string, label: string): SelectOption<string> {
292
- return {
293
- value,
294
- label,
295
- disabled: true,
296
- role: 'section',
297
- bold: true,
298
- }
299
- }
300
-
301
- function groupOption(value: string, label: string): SelectOption<string> {
302
- return {
303
- value,
304
- label,
305
- disabled: true,
306
- role: 'group',
307
- bold: true,
308
- indent: PROVIDER_INDENT,
309
- }
310
- }
311
-
312
- function noticeOption(value: string, label: string, indent = 0): SelectOption<string> {
313
- return {
314
- value,
315
- label,
316
- disabled: true,
317
- role: 'notice',
318
- prefix: 'note',
319
- indent,
320
- }
321
- }
322
-
323
- function rowOption(value: string, label: string, hint?: string, subtext?: string): SelectOption<string> {
324
- return {
325
- value,
326
- label,
327
- subtext,
328
- hint,
329
- role: 'option',
330
- indent: CHILD_INDENT,
331
- }
332
- }
333
-
334
- function utilityOption(value: string, label: string, hint?: string): SelectOption<string> {
335
- return {
336
- value,
337
- label,
338
- hint,
339
- role: 'utility',
340
- indent: CHILD_INDENT,
341
- }
342
- }
343
-
344
- function formatSize(bytes: number): string {
345
- if (bytes <= 0) return ''
346
- const gb = bytes / 1e9
347
- if (gb >= 1) return `${gb.toFixed(1)} GB`
348
- return `${Math.round(bytes / 1e6)} MB`
349
- }
350
-
351
- function modelMetadataSubtext(size: string, indicators: string[]): string | undefined {
352
- return [size, ...indicators].filter(Boolean).join(' · ') || undefined
353
- }
354
-
355
- function formatContextWindow(tokens: number): string {
356
- if (tokens >= 1_000_000) {
357
- const millions = tokens / 1_000_000
358
- return Number.isInteger(millions) ? `${millions}m` : `${millions.toFixed(1)}m`
359
- }
360
- if (tokens >= 1000) return `${Math.round(tokens / 1000)}k`
361
- return String(tokens)
362
- }
363
-
364
- type RankedEntry = {
365
- entry: ModelCatalogEntry
366
- score: number
367
- index: number
368
- }
369
-
370
- function rankEntriesByRecency(entries: ModelCatalogEntry[]): RankedEntry[] {
371
- return entries
372
- .map((entry, index) => ({
373
- entry,
374
- index,
375
- score: recencyScore(entry.id),
376
- }))
377
- .sort((a, b) => b.score - a.score || a.index - b.index)
378
- }
379
-
380
- function recencyScore(id: string): number {
381
- return dateScore(id) || versionScore(id)
382
- }
383
-
384
- function dateScore(id: string): number {
385
- const iso = id.match(/(?:^|[-_])(\d{4})[-_](\d{2})[-_](\d{2})(?=$|[-_])/)
386
- if (iso) return Number(`${iso[1]}${iso[2]}${iso[3]}`)
387
- const compact = id.match(/(?:^|[-_])(\d{8})(?=$|[-_])/)
388
- if (compact) return Number(compact[1])
389
- const monthYear = id.match(/(?:^|[-_])(\d{1,2})[-_](\d{4})(?=$|[-_])/)
390
- if (monthYear) return Number(`${monthYear[2]}${monthYear[1]?.padStart(2, '0')}00`)
391
- return 0
392
- }
393
-
394
- function versionScore(id: string): number {
395
- const match = id.match(/(?:^|[-_])(\d+(?:[.-]\d+){0,3})(?=$|[-_])/)
396
- if (!match) return 0
397
- const version = match[1]
398
- if (!version) return 0
399
- return version
400
- .split(/[.-]/)
401
- .slice(0, 4)
402
- .reduce((score, part, index) => {
403
- const value = Number.parseInt(part, 10)
404
- if (!Number.isFinite(value)) return score
405
- return score + value * Math.pow(100, 3 - index)
406
- }, 0)
407
- }
408
-
409
- const CURATED_EXCLUDED_TOKENS = [
410
- 'alpha',
411
- 'beta',
412
- 'deep-research',
413
- 'dev',
414
- 'experimental',
415
- 'preview',
416
- 'test',
417
- ] as const
418
-
419
- function isCuratedModelCandidate(provider: CloudProviderId, id: string): boolean {
420
- const lower = id.toLowerCase()
421
- if (provider === 'gemini' && !lower.startsWith('gemini-')) return false
422
- return !CURATED_EXCLUDED_TOKENS.some(token => hasToken(lower, token))
423
- }
424
-
425
- function hasToken(id: string, token: string): boolean {
426
- return new RegExp(`(^|[-_.])${escapeRegExp(token)}($|[-_.])`).test(id)
427
- }
428
-
429
- function escapeRegExp(value: string): string {
430
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
431
- }
432
-
433
- function dedupeEntries(entries: ModelCatalogEntry[]): ModelCatalogEntry[] {
434
- const seen = new Set<string>()
435
- const out: ModelCatalogEntry[] = []
436
- for (const entry of entries) {
437
- if (seen.has(entry.id)) continue
438
- seen.add(entry.id)
439
- out.push(entry)
440
- }
441
- return out
442
- }
443
-
444
- function dedupeStrings(values: string[]): string[] {
445
- const seen = new Set<string>()
446
- const out: string[] = []
447
- for (const value of values) {
448
- if (seen.has(value)) continue
449
- seen.add(value)
450
- out.push(value)
451
- }
452
- return out
453
- }
454
-
455
- function appendUnique(values: string[], value: string): void {
456
- if (!values.includes(value)) values.push(value)
457
- }
@@ -1,69 +0,0 @@
1
- import type { EthagentConfig, ProviderId } from '../storage/config.js'
2
- import type {
3
- LlamaCppInstallProgress,
4
- LlamaCppInstallResult,
5
- LlamaCppStartResult,
6
- } from './llamacpp.js'
7
- import type {
8
- HfDownloadPlan,
9
- HfDownloadProgress,
10
- HuggingFaceRepoInfo,
11
- HuggingFaceSibling,
12
- LocalHfModel,
13
- } from './huggingface.js'
14
- import type {
15
- CloudProviderId,
16
- ModelPickerContextFit,
17
- ModelPickerOptionsData,
18
- } from './modelPickerOptions.js'
19
-
20
- export type ModelPickerSelection =
21
- | { kind: 'llamacpp'; model: string; mmprojPath?: string }
22
- | { kind: 'cloud'; provider: CloudProviderId; model: string; keyJustSet: boolean }
23
-
24
- export type ModelPickerProps = {
25
- currentConfig: EthagentConfig
26
- currentProvider: ProviderId
27
- currentModel: string
28
- contextFit?: ModelPickerContextFit | null
29
- featuredHfRepo?: string
30
- localOnly?: boolean
31
- onPick: (selection: ModelPickerSelection) => void
32
- onCancel: () => void
33
- }
34
-
35
- export type LoadedModelPickerData = ModelPickerOptionsData
36
- export type LocalUninstallTarget = { kind: 'hf'; id: string; displayName: string; sizeBytes: number }
37
-
38
- export type ModelPickerState =
39
- | { kind: 'loading' }
40
- | { kind: 'list'; data: LoadedModelPickerData }
41
- | { kind: 'localCatalogLoading'; data: LoadedModelPickerData }
42
- | { kind: 'localCatalog'; data: LoadedModelPickerData; catalog: import('./uncensoredCatalog.js').UncensoredCatalogEntry[] }
43
- | { kind: 'localCatalogError'; data: LoadedModelPickerData; message: string }
44
- | { kind: 'catalog'; provider: CloudProviderId; data: LoadedModelPickerData }
45
- | { kind: 'keyEntry'; provider: CloudProviderId; action: 'set' | 'edit'; data: LoadedModelPickerData; submitting: boolean; error?: string }
46
- | { kind: 'keyManage'; provider: CloudProviderId; data: LoadedModelPickerData; submitting: boolean; error?: string }
47
- | { kind: 'oauthManage'; data: LoadedModelPickerData; submitting: boolean; error?: string }
48
- | { kind: 'oauthLogin'; data: LoadedModelPickerData; phase: 'waiting' | 'exchanging' | 'error'; url?: string; message?: string }
49
- | { kind: 'hfInput'; data: LoadedModelPickerData; error?: string }
50
- | { kind: 'hfLoading'; data: LoadedModelPickerData; input: string }
51
- | { kind: 'hfFilePick'; data: LoadedModelPickerData; input: string; repo: HuggingFaceRepoInfo; files: HuggingFaceSibling[] }
52
- | { kind: 'hfReview'; data: LoadedModelPickerData; plan: HfDownloadPlan }
53
- | { kind: 'hfDownloading'; data: LoadedModelPickerData; plan: HfDownloadPlan; progress: HfDownloadProgress }
54
- | { kind: 'hfDone'; data: LoadedModelPickerData; model: LocalHfModel; alreadyInstalled?: boolean }
55
- | { kind: 'hfError'; data: LoadedModelPickerData; message: string; input?: string }
56
- | { kind: 'localUninstallPick'; data: LoadedModelPickerData }
57
- | { kind: 'localUninstallConfirm'; data: LoadedModelPickerData; target: LocalUninstallTarget }
58
- | { kind: 'localUninstalling'; data: LoadedModelPickerData; target: LocalUninstallTarget }
59
- | { kind: 'localUninstallDone'; data: LoadedModelPickerData; modelName: string }
60
- | { kind: 'localUninstallError'; data: LoadedModelPickerData; target: LocalUninstallTarget; message: string }
61
- | { kind: 'localRunnerSetup'; data: LoadedModelPickerData; model: LocalHfModel }
62
- | { kind: 'localRunnerInstalling'; data: LoadedModelPickerData; model: LocalHfModel; startedAt: number; progress: LlamaCppInstallProgress }
63
- | { kind: 'localRunnerInstallFail'; data: LoadedModelPickerData; model: LocalHfModel; result: Extract<LlamaCppInstallResult, { ok: false }> }
64
- | { kind: 'localRunnerPathEntry'; data: LoadedModelPickerData; model: LocalHfModel; submitting: boolean; error?: string }
65
- | { kind: 'localRunnerStarting'; data: LoadedModelPickerData; model: LocalHfModel; startedAt: number }
66
- | { kind: 'localRunnerStartFail'; data: LoadedModelPickerData; model: LocalHfModel; result: Extract<LlamaCppStartResult, { ok: false }> }
67
- | { kind: 'mmprojOffer'; data: LoadedModelPickerData; model: LocalHfModel }
68
- | { kind: 'mmprojDownloading'; data: LoadedModelPickerData; model: LocalHfModel; progress: HfDownloadProgress }
69
- | { kind: 'mmprojError'; data: LoadedModelPickerData; model: LocalHfModel; message: string }
@@ -1,48 +0,0 @@
1
- import type { ProviderId } from '../storage/config.js'
2
- import { uninstallLocalHfModel } from './huggingface.js'
3
- import { formatLocalHfModelDisplayName } from './modelDisplay.js'
4
- import type { LoadedModelPickerData as LoadedData, LocalUninstallTarget, ModelPickerState as State } from './modelPickerTypes.js'
5
- import { refreshLocalModelData } from './modelPickerData.js'
6
- export function localUninstallTargets(data: LoadedData): LocalUninstallTarget[] {
7
- return data.hfModels.map(model => ({
8
- kind: 'hf' as const,
9
- id: model.id,
10
- displayName: formatLocalHfModelDisplayName(model.id, {
11
- displayName: model.displayName,
12
- maxLength: 64,
13
- }),
14
- sizeBytes: model.sizeBytes,
15
- }))
16
- }
17
-
18
- export function isCurrentLocalUninstallTarget(
19
- target: LocalUninstallTarget,
20
- currentProvider: ProviderId,
21
- currentModel: string,
22
- ): boolean {
23
- return target.kind === 'hf' && currentProvider === 'llamacpp' && target.id === currentModel
24
- }
25
-
26
- export function localUninstallBoundaryCopy(_target: LocalUninstallTarget): string {
27
- return 'This removes only the downloaded GGUF file and metadata from this machine.'
28
- }
29
-
30
- export async function uninstallLocalModel(
31
- state: Extract<State, { kind: 'localUninstallConfirm' }>,
32
- setState: (s: State) => void,
33
- ): Promise<void> {
34
- setState({ kind: 'localUninstalling', data: state.data, target: state.target })
35
- const modelName = state.target.displayName
36
- try {
37
- await uninstallLocalHfModel(state.target.id)
38
- const data = await refreshLocalModelData(state.data)
39
- setState({ kind: 'localUninstallDone', data, modelName })
40
- } catch (err: unknown) {
41
- setState({
42
- kind: 'localUninstallError',
43
- data: state.data,
44
- target: state.target,
45
- message: (err as Error).message,
46
- })
47
- }
48
- }