ethagent 3.3.3 → 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 -259
  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,327 +0,0 @@
1
- import { defaultModelFor, type EthagentConfig, type ProviderId } from '../storage/config.js'
2
- import { getKey } from '../storage/secrets.js'
3
- import { loadLocalHfModels } from './huggingface.js'
4
- import { hasOpenAIOAuthCredentials } from '../auth/openaiOAuth/credentials.js'
5
- import { providerDisplayName } from './providerDisplay.js'
6
-
7
- const OPENAI_OAUTH_MODEL_IDS = ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.3-codex', 'gpt-5.2'] as const
8
-
9
- export const OPENAI_OAUTH_DEFAULT_MODEL = 'gpt-5.4'
10
-
11
- export function isOpenAIOAuthAllowedModel(model: string): boolean {
12
- return (OPENAI_OAUTH_MODEL_IDS as readonly string[]).includes(model)
13
- }
14
-
15
- export type ModelCatalogSource = 'installed' | 'discovered' | 'fallback'
16
-
17
- export type ModelCatalogEntry = {
18
- provider: ProviderId
19
- id: string
20
- label: string
21
- description?: string
22
- source: ModelCatalogSource
23
- }
24
-
25
- export type ModelCatalogResult = {
26
- provider: ProviderId
27
- entries: ModelCatalogEntry[]
28
- status: 'ok' | 'fallback'
29
- error?: string
30
- }
31
-
32
- type DiscoverDeps = {
33
- fetchImpl?: typeof fetch
34
- loadKey?: (provider: ProviderId) => Promise<string | null>
35
- listHfLocal?: () => Promise<Array<{ id: string; displayName: string }>>
36
- now?: () => number
37
- }
38
-
39
- const OPENAI_DEFAULT_BASE_URL = 'https://api.openai.com/v1'
40
- const ANTHROPIC_VERSION = '2023-06-01'
41
- const CACHE_TTL_MS = 60_000
42
-
43
- type CacheValue = {
44
- expiresAt: number
45
- entries: ModelCatalogEntry[]
46
- }
47
-
48
- const cache = new Map<string, CacheValue>()
49
-
50
- export function openAIBaseUrlFor(config: Pick<EthagentConfig, 'provider' | 'baseUrl'>): string {
51
- return config.provider === 'openai' && config.baseUrl
52
- ? config.baseUrl
53
- : OPENAI_DEFAULT_BASE_URL
54
- }
55
-
56
- export function clearModelCatalogCache(): void {
57
- cache.clear()
58
- }
59
-
60
- export async function discoverProviderModels(
61
- config: EthagentConfig,
62
- deps: DiscoverDeps = {},
63
- ): Promise<ModelCatalogResult> {
64
- const provider = config.provider
65
- if (provider === 'llamacpp') {
66
- try {
67
- const installed = await (deps.listHfLocal ?? (() => loadLocalHfModels()))()
68
- return {
69
- provider,
70
- status: 'ok',
71
- entries: dedupeEntries(installed.map(model => ({
72
- provider,
73
- id: model.id,
74
- label: model.displayName,
75
- source: 'installed' as const,
76
- }))),
77
- }
78
- } catch (err: unknown) {
79
- return fallbackResult(config, (err as Error).message)
80
- }
81
- }
82
-
83
- const loadKey = deps.loadKey ?? getKey
84
- const apiKey = await loadKey(provider)
85
- if (!apiKey) {
86
- if (provider === 'openai' && await hasOpenAIOAuthCredentials()) {
87
- return openAIOAuthCatalog()
88
- }
89
- return fallbackResult(config, `missing ${providerDisplayName(provider)} API key`)
90
- }
91
-
92
- const baseUrl = provider === 'openai' ? openAIBaseUrlFor(config) : ''
93
- const key = cacheKey(provider, baseUrl, true)
94
- const now = deps.now?.() ?? Date.now()
95
- const cached = cache.get(key)
96
- if (cached && cached.expiresAt > now) {
97
- return { provider, status: 'ok', entries: cached.entries }
98
- }
99
-
100
- try {
101
- const fetchImpl = deps.fetchImpl ?? fetch
102
- const entries =
103
- provider === 'openai'
104
- ? await discoverOpenAIModels(fetchImpl, provider, baseUrl, apiKey, isDefaultOpenAIBaseUrl(baseUrl))
105
- : provider === 'anthropic'
106
- ? await discoverAnthropicModels(fetchImpl, apiKey)
107
- : await discoverGeminiModels(fetchImpl, apiKey)
108
- const deduped = dedupeEntries(entries)
109
- cache.set(key, { expiresAt: now + CACHE_TTL_MS, entries: deduped })
110
- return { provider, status: 'ok', entries: deduped }
111
- } catch (err: unknown) {
112
- return fallbackResult(config, (err as Error).message)
113
- }
114
- }
115
-
116
- function openAIOAuthCatalog(): ModelCatalogResult {
117
- return {
118
- provider: 'openai',
119
- status: 'ok',
120
- entries: OPENAI_OAUTH_MODEL_IDS.map(id => ({
121
- provider: 'openai' as ProviderId,
122
- id,
123
- label: id,
124
- source: 'discovered' as const,
125
- })),
126
- }
127
- }
128
-
129
- function fallbackResult(config: EthagentConfig, error?: string): ModelCatalogResult {
130
- const provider = config.provider
131
- return {
132
- provider,
133
- status: 'fallback',
134
- error,
135
- entries: dedupeEntries([
136
- {
137
- provider,
138
- id: config.model,
139
- label: config.model,
140
- source: 'fallback',
141
- },
142
- {
143
- provider,
144
- id: defaultModelFor(provider),
145
- label: defaultModelFor(provider),
146
- source: 'fallback',
147
- },
148
- ]),
149
- }
150
- }
151
-
152
- const OPENAI_CHAT_PREFIXES = ['gpt-', 'chatgpt-', 'o1', 'o3', 'o4']
153
- const OPENAI_NON_CHAT_PATTERNS: RegExp[] = [
154
- /-instruct(?:$|-)/,
155
- /-realtime(?:$|-)/,
156
- /-audio(?:$|-)/,
157
- /-transcribe(?:$|-)/,
158
- /-tts(?:$|-)/,
159
- /-search-preview(?:$|-)/,
160
- /-image(?:$|-)/,
161
- ]
162
- const OPENAI_NON_CHAT_FAMILIES = [
163
- 'text-embedding-',
164
- 'text-similarity-',
165
- 'text-search-',
166
- 'whisper-',
167
- 'tts-',
168
- 'dall-e-',
169
- 'gpt-image-',
170
- 'omni-moderation-',
171
- 'text-moderation-',
172
- 'babbage-',
173
- 'davinci-',
174
- 'computer-use-',
175
- ]
176
- const OPENAI_NON_CHAT_EXACT = new Set(['davinci', 'babbage', 'ada', 'curie'])
177
-
178
- function isChatCapableOpenAIModel(id: string): boolean {
179
- if (OPENAI_NON_CHAT_EXACT.has(id)) return false
180
- if (OPENAI_NON_CHAT_FAMILIES.some(prefix => id.startsWith(prefix))) return false
181
- if (OPENAI_NON_CHAT_PATTERNS.some(re => re.test(id))) return false
182
- return OPENAI_CHAT_PREFIXES.some(prefix => id.startsWith(prefix))
183
- }
184
-
185
- function isDefaultOpenAIBaseUrl(baseUrl: string): boolean {
186
- return baseUrl.replace(/\/+$/, '') === OPENAI_DEFAULT_BASE_URL
187
- }
188
-
189
- async function discoverOpenAIModels(
190
- fetchImpl: typeof fetch,
191
- provider: ProviderId,
192
- baseUrl: string,
193
- apiKey: string,
194
- applyChatFilter: boolean,
195
- ): Promise<ModelCatalogEntry[]> {
196
- const urls = openAIModelUrls(baseUrl)
197
- let lastError: Error | undefined
198
- for (const url of urls) {
199
- try {
200
- const response = await fetchImpl(url, {
201
- method: 'GET',
202
- headers: {
203
- Authorization: `Bearer ${apiKey}`,
204
- Accept: 'application/json',
205
- },
206
- })
207
- if (!response.ok) {
208
- lastError = new Error(`HTTP ${response.status}`)
209
- continue
210
- }
211
- const data = await response.json() as { data?: Array<{ id?: unknown }> }
212
- return (data.data ?? [])
213
- .filter(item => typeof item.id === 'string' && item.id.length > 0)
214
- .filter(item => !applyChatFilter || isChatCapableOpenAIModel(item.id as string))
215
- .map(item => ({
216
- provider,
217
- id: item.id as string,
218
- label: item.id as string,
219
- source: 'discovered' as const,
220
- }))
221
- } catch (err: unknown) {
222
- lastError = err as Error
223
- }
224
- }
225
- throw lastError ?? new Error('no OpenAI model endpoint responded')
226
- }
227
-
228
- function openAIModelUrls(baseUrl: string): string[] {
229
- const normalized = baseUrl.replace(/\/+$/, '')
230
- const fallback = normalized.endsWith('/v1')
231
- ? `${normalized.slice(0, -3)}/models`
232
- : `${normalized}/v1/models`
233
- return dedupeStrings([`${normalized}/models`, fallback])
234
- }
235
-
236
- async function discoverAnthropicModels(
237
- fetchImpl: typeof fetch,
238
- apiKey: string,
239
- ): Promise<ModelCatalogEntry[]> {
240
- const response = await fetchImpl('https://api.anthropic.com/v1/models', {
241
- method: 'GET',
242
- headers: {
243
- 'x-api-key': apiKey,
244
- 'anthropic-version': ANTHROPIC_VERSION,
245
- Accept: 'application/json',
246
- },
247
- })
248
- if (!response.ok) throw new Error(`HTTP ${response.status}`)
249
- const data = await response.json() as { data?: Array<{ id?: unknown; display_name?: unknown }> }
250
- return (data.data ?? [])
251
- .filter(item => typeof item.id === 'string' && item.id.length > 0)
252
- .map(item => ({
253
- provider: 'anthropic',
254
- id: item.id as string,
255
- label: typeof item.display_name === 'string' && item.display_name.length > 0
256
- ? item.display_name
257
- : item.id as string,
258
- source: 'discovered' as const,
259
- }))
260
- }
261
-
262
- async function discoverGeminiModels(
263
- fetchImpl: typeof fetch,
264
- apiKey: string,
265
- ): Promise<ModelCatalogEntry[]> {
266
- const response = await fetchImpl(
267
- 'https://generativelanguage.googleapis.com/v1beta/models',
268
- {
269
- method: 'GET',
270
- headers: {
271
- Accept: 'application/json',
272
- 'x-goog-api-key': apiKey.trim(),
273
- },
274
- },
275
- )
276
- if (!response.ok) throw new Error(`HTTP ${response.status}`)
277
- const data = await response.json() as {
278
- models?: Array<{
279
- name?: unknown
280
- displayName?: unknown
281
- description?: unknown
282
- supportedGenerationMethods?: unknown
283
- }>
284
- }
285
- return (data.models ?? [])
286
- .filter(item => typeof item.name === 'string' && item.name.length > 0)
287
- .filter(item => Array.isArray(item.supportedGenerationMethods)
288
- && item.supportedGenerationMethods.includes('generateContent'))
289
- .map(item => {
290
- const id = (item.name as string).replace(/^models\//, '')
291
- return {
292
- provider: 'gemini' as const,
293
- id,
294
- label: typeof item.displayName === 'string' && item.displayName.length > 0
295
- ? item.displayName
296
- : id,
297
- description: typeof item.description === 'string' ? item.description : undefined,
298
- source: 'discovered' as const,
299
- }
300
- })
301
- }
302
-
303
- function cacheKey(provider: ProviderId, baseUrl: string, hasKey: boolean): string {
304
- return `${provider}\0${baseUrl}\0${hasKey ? 'key' : 'no-key'}`
305
- }
306
-
307
- function dedupeEntries(entries: ModelCatalogEntry[]): ModelCatalogEntry[] {
308
- const seen = new Set<string>()
309
- const out: ModelCatalogEntry[] = []
310
- for (const entry of entries) {
311
- if (seen.has(entry.id)) continue
312
- seen.add(entry.id)
313
- out.push(entry)
314
- }
315
- return out
316
- }
317
-
318
- function dedupeStrings(values: string[]): string[] {
319
- const seen = new Set<string>()
320
- const out: string[] = []
321
- for (const value of values) {
322
- if (seen.has(value)) continue
323
- seen.add(value)
324
- out.push(value)
325
- }
326
- return out
327
- }