ompchamber 2.0.2 → 3.1.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.
- package/README.md +31 -11
- package/bunfig.toml +11 -0
- package/dist/client/index.html +16 -5
- package/dist/client/index.js +1393 -0
- package/dist/client/static/js/index-8t70jhyj.js +5149 -0
- package/dist/client/static/js/index-n4wkqj7t.css +1 -0
- package/index.html +54 -0
- package/package.json +9 -10
- package/public/apple-touch-icon.png +0 -0
- package/public/icon-192x192.png +0 -0
- package/public/icon.svg +60 -0
- package/public/manifest.webmanifest +38 -0
- package/src/cli/lib/commands/serve.js +9 -5
- package/src/cli/lib/runtime.js +18 -7
- package/src/client/components/common/code-editor/handler.test.ts +274 -0
- package/src/client/components/common/code-editor/handler.ts +175 -0
- package/src/client/components/common/code-editor/index.tsx +185 -220
- package/src/client/components/common/code-surface/index.tsx +109 -12
- package/src/client/components/common/lazy-panels.tsx +5 -1
- package/src/client/components/common/provider-icon/glyphs.ts +118 -0
- package/src/client/components/common/provider-icon/index.tsx +85 -0
- package/src/client/components/common/viewport.ts +5 -3
- package/src/client/components/layout/RightActivityBar.tsx +2 -1
- package/src/client/components/layout/desktop-layout/TopNavbar.tsx +21 -4
- package/src/client/components/layout/desktop-layout/WorkspacePanels.tsx +4 -0
- package/src/client/components/layout/desktop-layout/index.tsx +26 -4
- package/src/client/components/mobile/LayoutWrapper.tsx +16 -0
- package/src/client/components/mobile/RightSidebar.tsx +11 -4
- package/src/client/components/mobile/SessionSidebar.tsx +10 -0
- package/src/client/components/mobile/mobile-right-sidebar/FullEditor.tsx +0 -1
- package/src/client/components/mobile/mobile-session-sidebar/Item.tsx +16 -1
- package/src/client/components/mobile/mobile-session-sidebar/List.tsx +3 -0
- package/src/client/components/settings/categories/ProviderSettings.tsx +45 -4
- package/src/client/components/settings/categories/UsageSettings.tsx +22 -7
- package/src/client/components/settings/categories/provider-settings/AddModelModal.tsx +322 -0
- package/src/client/components/settings/categories/provider-settings/AddProviderModal.tsx +152 -56
- package/src/client/components/settings/categories/provider-settings/AuthSection.tsx +52 -1
- package/src/client/components/settings/categories/provider-settings/DeleteProviderModal.tsx +133 -0
- package/src/client/components/settings/categories/provider-settings/DialectFields.tsx +136 -0
- package/src/client/components/settings/categories/provider-settings/EffortLadder.tsx +89 -0
- package/src/client/components/settings/categories/provider-settings/Header.tsx +2 -2
- package/src/client/components/settings/categories/provider-settings/LoginModal.tsx +2 -2
- package/src/client/components/settings/categories/provider-settings/ModelsList.tsx +22 -2
- package/src/client/components/settings/categories/provider-settings/PresetPicker.tsx +82 -0
- package/src/client/components/settings/categories/provider-settings/PriceFields.tsx +107 -0
- package/src/client/components/settings/categories/provider-settings/ReconnectModal.tsx +43 -22
- package/src/client/components/settings/categories/provider-settings/SidebarList.tsx +2 -2
- package/src/client/components/settings/categories/usage-settings/LimitsSection.tsx +115 -0
- package/src/client/components/settings/categories/usage-settings/ProviderCard.tsx +19 -26
- package/src/client/components/settings/categories/usage-settings/ProviderDetail.tsx +29 -22
- package/src/client/components/settings/categories/usage-settings/SidebarList.tsx +60 -48
- package/src/client/components/settings/categories/usage-settings/format.ts +36 -0
- package/src/client/components/settings/categories/usage-settings/providers.ts +52 -28
- package/src/client/components/workspace/browser-panel/AddressBar.tsx +1 -10
- package/src/client/components/workspace/browser-panel/Screencast.tsx +4 -5
- package/src/client/components/workspace/browser-panel/index.tsx +6 -6
- package/src/client/components/workspace/browser-toolbar/index.tsx +22 -12
- package/src/client/components/workspace/chat-timeline/AiMessageFooter.tsx +1 -1
- package/src/client/components/workspace/chat-timeline/GeneratingIndicator.tsx +1 -1
- package/src/client/components/workspace/chat-timeline/ToolCallCard.tsx +1 -1
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Todo.tsx +1 -1
- package/src/client/components/workspace/diff-panel/Toolbar.tsx +71 -38
- package/src/client/components/workspace/diff-panel/index.tsx +139 -53
- package/src/client/components/workspace/editor/CommandPalette.test.ts +242 -0
- package/src/client/components/workspace/editor/CommandPalette.tsx +138 -0
- package/src/client/components/workspace/editor/FindWidget.test.ts +261 -0
- package/src/client/components/workspace/editor/FindWidget.tsx +219 -0
- package/src/client/components/workspace/editor/Tabs.tsx +2 -2
- package/src/client/components/workspace/editor/Toolbar.tsx +129 -26
- package/src/client/components/workspace/editor/index.tsx +180 -62
- package/src/client/components/workspace/file-explorer/Modals.tsx +79 -2
- package/src/client/components/workspace/file-explorer/TreeItem.tsx +43 -113
- package/src/client/components/workspace/model-dropdown/Item.tsx +13 -23
- package/src/client/components/workspace/model-dropdown/Panel.tsx +1 -1
- package/src/client/components/workspace/model-dropdown/Section.tsx +13 -4
- package/src/client/components/workspace/model-dropdown/index.tsx +7 -3
- package/src/client/components/workspace/todo-panel/PhaseGroup.tsx +76 -0
- package/src/client/components/workspace/todo-panel/Row.tsx +69 -0
- package/src/client/components/workspace/todo-panel/index.tsx +161 -0
- package/src/client/components/workspace/usage-panel/ProviderSelect.tsx +10 -5
- package/src/client/components/workspace/usage-panel/index.tsx +36 -18
- package/src/client/data/samples/dialogue-session.ts +1 -1
- package/src/client/data/samples/sample-tools/other.ts +1 -1
- package/src/client/data/settings/provider.ts +141 -9
- package/src/client/hooks/editor/find-harness.test-util.ts +170 -0
- package/src/client/hooks/editor/scroll-container.test.ts +102 -0
- package/src/client/hooks/editor/scroll-container.ts +26 -0
- package/src/client/hooks/editor/use-code-window.ts +2 -20
- package/src/client/hooks/editor/use-editor-find-write.test.ts +170 -0
- package/src/client/hooks/editor/use-editor-find.test.ts +118 -0
- package/src/client/hooks/editor/use-editor-find.ts +321 -0
- package/src/client/hooks/editor/use-editor-history.test.ts +216 -0
- package/src/client/hooks/editor/use-editor-history.ts +134 -0
- package/src/client/hooks/editor/use-file-editor.ts +24 -27
- package/src/client/hooks/editor/use-occurrences.test.ts +236 -0
- package/src/client/hooks/editor/use-occurrences.ts +98 -0
- package/src/client/hooks/models/use-provider-names.ts +1 -1
- package/src/client/hooks/settings/providers/actions.ts +337 -0
- package/src/client/hooks/settings/providers/api.ts +69 -0
- package/src/client/hooks/settings/providers/index.ts +138 -0
- package/src/client/hooks/settings/providers/messages.ts +77 -0
- package/src/client/hooks/settings/useUsageReport.ts +8 -3
- package/src/client/hooks/ui/theme.ts +3 -3
- package/src/client/hooks/workspace/file-tabs.ts +62 -11
- package/src/client/hooks/workspace/file-tree-actions.test.ts +348 -0
- package/src/client/hooks/workspace/file-tree-actions.ts +250 -0
- package/src/client/hooks/workspace/session-todos.ts +102 -0
- package/src/client/stubs/elkjs.ts +6 -1
- package/src/client/tailwind.css +30 -0
- package/src/server/index.ts +20 -2
- package/src/server/lib/assets/font-css.server.ts +86 -0
- package/src/server/lib/assets/fonts.server.ts +117 -0
- package/src/server/lib/bundler/css.ts +116 -0
- package/src/server/lib/lifecycle/shell-route.ts +17 -0
- package/src/server/lib/models/provider-listing.server.ts +257 -0
- package/src/server/lib/models/provider-registry.server.test.ts +122 -0
- package/src/server/lib/models/provider-registry.server.ts +76 -25
- package/src/server/lib/omp/config/models-config.ts +11 -0
- package/src/server/lib/omp/config/models-validation.test.ts +137 -0
- package/src/server/lib/omp/config/models-validation.ts +111 -2
- package/src/server/lib/omp/config/provider-seeds.test.ts +167 -0
- package/src/server/lib/omp/config/provider-seeds.ts +176 -0
- package/src/server/lib/omp/config/providers.ts +94 -100
- package/src/server/lib/omp/core/auth-credentials.ts +45 -0
- package/src/server/lib/omp/session/todos.ts +100 -0
- package/src/server/lib/omp/session/{usage.ts → usage/aggregate.ts} +1 -118
- package/src/server/lib/omp/session/usage/shaping.ts +130 -0
- package/src/server/lib/usage/deepseek.ts +4 -5
- package/src/server/lib/usage/kenari.ts +7 -6
- package/src/server/lib/usage/omp-usage.server.test.ts +126 -0
- package/src/server/lib/usage/omp-usage.server.ts +194 -0
- package/src/server/lib/usage/provider-key.ts +81 -3
- package/src/server/lib/usage/providers.server.test.ts +47 -0
- package/src/server/lib/usage/providers.server.ts +208 -0
- package/src/server/lib/usage/vendor-balance.server.test.ts +104 -0
- package/src/server/lib/usage/vendor-balance.server.ts +284 -0
- package/src/server/plugins/shell.server.ts +56 -0
- package/src/server/plugins/ssr.ts +24 -36
- package/src/server/plugins/static.test.ts +26 -29
- package/src/server/plugins/static.ts +40 -19
- package/src/server/routes/fs/action-create.test.ts +90 -0
- package/src/server/routes/fs/action.ts +23 -0
- package/src/server/routes/omp/index.ts +2 -0
- package/src/server/routes/omp/session-todos.ts +80 -0
- package/src/server/routes/settings/index.ts +2 -0
- package/src/server/routes/settings/provider-model.ts +107 -0
- package/src/server/routes/settings/provider-models.ts +65 -202
- package/src/server/routes/settings/providers.ts +22 -7
- package/src/server/routes/settings/usage.ts +125 -45
- package/src/server/routes/telemetry/tokens.ts +2 -1
- package/src/shared/lib/chat/{todo-parser.ts → todo/parser.ts} +17 -0
- package/src/shared/lib/chat/todo/progress.ts +97 -0
- package/src/shared/lib/chat/todo/snapshot.test.ts +156 -0
- package/src/shared/lib/chat/todo/snapshot.ts +215 -0
- package/src/shared/lib/code/editor/commands.test.ts +155 -0
- package/src/shared/lib/code/editor/commands.ts +260 -0
- package/src/shared/lib/code/editor/edits.test.ts +100 -0
- package/src/shared/lib/code/editor/edits.ts +122 -0
- package/src/shared/lib/code/editor/find-status.test.ts +50 -0
- package/src/shared/lib/code/editor/find-status.ts +36 -0
- package/src/shared/lib/code/editor/find.test.ts +203 -0
- package/src/shared/lib/code/editor/find.ts +224 -0
- package/src/{client/components/common/code-editor → shared/lib/code/editor}/history.test.ts +1 -1
- package/src/shared/lib/code/editor/keymap.test.ts +109 -0
- package/src/shared/lib/code/editor/keymap.ts +151 -0
- package/src/shared/lib/code/editor/layers.test.ts +77 -0
- package/src/shared/lib/code/editor/layers.ts +67 -0
- package/src/shared/lib/code/editor/line-edits.test.ts +131 -0
- package/src/shared/lib/code/editor/line-edits.ts +159 -0
- package/src/shared/lib/code/editor/lines.test.ts +81 -0
- package/src/shared/lib/code/editor/lines.ts +83 -0
- package/src/shared/lib/code/editor/marks.test.ts +86 -0
- package/src/shared/lib/code/editor/marks.ts +106 -0
- package/src/shared/lib/code/editor/occurrences.test.ts +117 -0
- package/src/shared/lib/code/editor/occurrences.ts +111 -0
- package/src/shared/lib/code/editor/palette.test.ts +91 -0
- package/src/shared/lib/code/editor/palette.ts +92 -0
- package/src/shared/lib/code/editor/reset-css.test.ts +35 -0
- package/src/shared/lib/code/editor/reset-css.ts +32 -0
- package/src/shared/lib/code/editor/text-commands.test.ts +178 -0
- package/src/shared/lib/code/editor/text-commands.ts +154 -0
- package/src/shared/lib/code/syntax-highlight.test.ts +75 -0
- package/src/shared/lib/code/syntax-highlight.ts +29 -17
- package/src/shared/lib/code/windowed-highlight.ts +52 -1
- package/src/shared/lib/fs/diff-parser.test.ts +116 -0
- package/src/shared/lib/fs/diff-parser.ts +86 -33
- package/src/shared/lib/models/{provider-connection.ts → provider/connection.ts} +37 -0
- package/src/shared/lib/models/provider/dialect.ts +179 -0
- package/src/shared/lib/models/provider/glyph.test.ts +116 -0
- package/src/shared/lib/models/provider/glyph.ts +200 -0
- package/src/shared/lib/models/{provider-models.ts → provider/models.ts} +91 -6
- package/src/shared/lib/models/provider/presets.test.ts +172 -0
- package/src/shared/lib/models/provider/presets.ts +83 -0
- package/src/shared/lib/ui/key-binding.test.ts +115 -0
- package/src/shared/lib/ui/key-binding.ts +143 -0
- package/src/shared/lib/util/platform.test.ts +87 -0
- package/src/shared/lib/util/platform.ts +30 -0
- package/src/shared/lib/workspace/file-tab-id.ts +29 -0
- package/src/shared/lib/workspace/keymap.test.ts +82 -0
- package/src/shared/lib/workspace/keymap.ts +30 -0
- package/src/shared/lib/workspace/refresh-cadence.ts +9 -0
- package/src/shared/lib/workspace/right-panels.ts +8 -0
- package/src/shared/lib/workspace/session-state/store.ts +0 -1
- package/src/shared/types/index.ts +1 -0
- package/src/shared/types/settings/provider.ts +81 -0
- package/src/shared/types/settings/usage.ts +88 -14
- package/src/shared/types/todo.ts +108 -0
- package/tsconfig.json +3 -1
- package/dist/client/static/css/index.5f630421b7.css +0 -2
- package/dist/client/static/font/KaTeX_AMS-Regular.a79f1c3119.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Bold.ec17d13264.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Regular.55fac25845.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Bold.d42a5579b0.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Regular.d3c882a649.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-Bold.c3fb5ac22f.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-BoldItalic.6f2bb1dff2.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-Italic.8916142bec.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-Regular.0462f03bdf.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Math-BoldItalic.572d331f69.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Math-Italic.f28c23acad.woff2 +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Bold.8c5b5494b6.woff2 +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Italic.3b1e59b3ba.woff2 +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Regular.ba21ed5f84.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Script-Regular.03e9641d6f.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Size1-Regular.eae34984b3.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Size2-Regular.5916a24fa3.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Size4-Regular.10d95fd3a2.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Typewriter-Regular.a8709e3622.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-400-normal.2655b10c55.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-500-normal.92a991f204.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-600-normal.43788eb7f1.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-700-normal.2667215d33.woff2 +0 -0
- package/dist/client/static/js/77.0d81c74cf0.js +0 -139
- package/dist/client/static/js/77.0d81c74cf0.js.LICENSE.txt +0 -8
- package/dist/client/static/js/async/0.8e59f2eb5b.js +0 -1
- package/dist/client/static/js/async/0k.5852e6b4fa.js +0 -1
- package/dist/client/static/js/async/0w.9ed36d5860.js +0 -1
- package/dist/client/static/js/async/1.f387c12b63.js +0 -1
- package/dist/client/static/js/async/12.d091f91c99.js +0 -1
- package/dist/client/static/js/async/13.8f810a8a6c.js +0 -1
- package/dist/client/static/js/async/19.6fe909d55a.js +0 -160
- package/dist/client/static/js/async/1b.23f1141a38.js +0 -1
- package/dist/client/static/js/async/1k.973e8e21fc.js +0 -2
- package/dist/client/static/js/async/1k.973e8e21fc.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/1p.0d5cddda96.js +0 -1
- package/dist/client/static/js/async/2.b589f1733b.js +0 -1
- package/dist/client/static/js/async/2v.96165101de.js +0 -1
- package/dist/client/static/js/async/3.0cacc08423.js +0 -1
- package/dist/client/static/js/async/37.b28b2f61cd.js +0 -1
- package/dist/client/static/js/async/3d.5085fb913f.js +0 -1
- package/dist/client/static/js/async/3j.357c80ff38.js +0 -2
- package/dist/client/static/js/async/3j.357c80ff38.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/3p.bcf32a0983.js +0 -1
- package/dist/client/static/js/async/3r.3a69e98ee0.js +0 -64
- package/dist/client/static/js/async/3u.1228460e2a.js +0 -1
- package/dist/client/static/js/async/3y.3530b824ad.js +0 -198
- package/dist/client/static/js/async/3y.3530b824ad.js.LICENSE.txt +0 -5
- package/dist/client/static/js/async/4.9442eeb472.js +0 -1
- package/dist/client/static/js/async/4e.678285ca55.js +0 -1
- package/dist/client/static/js/async/4k.33a0c7eeb4.js +0 -1
- package/dist/client/static/js/async/4m.928a1dde85.js +0 -31
- package/dist/client/static/js/async/4m.928a1dde85.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/4q.aad20dab25.js +0 -1
- package/dist/client/static/js/async/5.ebaf8b89cc.js +0 -36
- package/dist/client/static/js/async/51.95bcae98af.js +0 -2
- package/dist/client/static/js/async/51.95bcae98af.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/5b.d88304bc13.js +0 -1
- package/dist/client/static/js/async/5j.d6407c4248.js +0 -287
- package/dist/client/static/js/async/5o.88316d4460.js +0 -62
- package/dist/client/static/js/async/6.f034c9b528.js +0 -1
- package/dist/client/static/js/async/66.5dfa29f957.js +0 -93
- package/dist/client/static/js/async/6o.5b1a06a382.js +0 -1
- package/dist/client/static/js/async/7.e4a9288dd0.js +0 -1
- package/dist/client/static/js/async/73.308dff4da8.js +0 -1
- package/dist/client/static/js/async/7e.a1cc9bfd88.js +0 -1
- package/dist/client/static/js/async/7g.a7814350c3.js +0 -1
- package/dist/client/static/js/async/7l.fadbbc0583.js +0 -1
- package/dist/client/static/js/async/8.5067439d8c.js +0 -1
- package/dist/client/static/js/async/8j.ea110663fb.js +0 -1
- package/dist/client/static/js/async/a.bce4542392.js +0 -1
- package/dist/client/static/js/async/aa.65d3852576.js +0 -1
- package/dist/client/static/js/async/ar.9303e5f2e8.js +0 -2
- package/dist/client/static/js/async/ar.9303e5f2e8.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/az.d656062b0f.js +0 -1
- package/dist/client/static/js/async/b.b4f6f06515.js +0 -1
- package/dist/client/static/js/async/bi.09688ba75c.js +0 -1
- package/dist/client/static/js/async/bq.586bc738d1.js +0 -1
- package/dist/client/static/js/async/c.797d933882.js +0 -1
- package/dist/client/static/js/async/c0.0af1e640d3.js +0 -24
- package/dist/client/static/js/async/ca.8a52cfd447.js +0 -1
- package/dist/client/static/js/async/cf.d34fff5d67.js +0 -1
- package/dist/client/static/js/async/ct.b74928f7a3.js +0 -1
- package/dist/client/static/js/async/cx.3cb0242a3a.js +0 -226
- package/dist/client/static/js/async/d.a5fc8fe1b3.js +0 -1
- package/dist/client/static/js/async/da.f62c70f6c8.js +0 -1
- package/dist/client/static/js/async/dp.1725d6432c.js +0 -1
- package/dist/client/static/js/async/e.93214d622b.js +0 -79
- package/dist/client/static/js/async/f.ab50467719.js +0 -19
- package/dist/client/static/js/async/f.ab50467719.js.LICENSE.txt +0 -12
- package/dist/client/static/js/async/f7.46971e9d6d.js +0 -2
- package/dist/client/static/js/async/f7.46971e9d6d.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/f8.bbf0dbae70.js +0 -1
- package/dist/client/static/js/async/g.cb81980498.js +0 -2
- package/dist/client/static/js/async/g.cb81980498.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/h.4e790471e4.js +0 -27
- package/dist/client/static/js/async/h1.393f066d09.js +0 -1
- package/dist/client/static/js/async/h3.216e9798ab.js +0 -148
- package/dist/client/static/js/async/hd.0da931b622.js +0 -1
- package/dist/client/static/js/async/hk.ba7fb04d41.js +0 -1
- package/dist/client/static/js/async/hn.b645041e00.js +0 -1
- package/dist/client/static/js/async/ho.475a5e1ae4.js +0 -1
- package/dist/client/static/js/async/hp.e9fe2e395a.js +0 -2
- package/dist/client/static/js/async/hp.e9fe2e395a.js.LICENSE.txt +0 -17
- package/dist/client/static/js/async/hs.e7c59d8090.js +0 -41
- package/dist/client/static/js/async/i.7c148e8440.js +0 -1
- package/dist/client/static/js/async/id.573df20f29.js +0 -1
- package/dist/client/static/js/async/j.ab925882d8.js +0 -1
- package/dist/client/static/js/async/jd.63886a1f09.js +0 -1
- package/dist/client/static/js/async/jg.d86ebd4013.js +0 -86
- package/dist/client/static/js/async/jl.874d352278.js +0 -1
- package/dist/client/static/js/async/jll.11313b455a.js +0 -1
- package/dist/client/static/js/async/js.67182759ef.js +0 -1
- package/dist/client/static/js/async/jsc.23b70d6f40.js +0 -1
- package/dist/client/static/js/async/jse.334588ff5d.js +0 -1
- package/dist/client/static/js/async/jz.72eb929106.js +0 -77
- package/dist/client/static/js/async/k.3210286401.js +0 -217
- package/dist/client/static/js/async/ka.c1990ecaa3.js +0 -115
- package/dist/client/static/js/async/katex-vendor.de6a87c308.js +0 -1
- package/dist/client/static/js/async/ku.29c8a59d0c.js +0 -1
- package/dist/client/static/js/async/ky.8dab1dade0.js +0 -1
- package/dist/client/static/js/async/l.12dd34e1be.js +0 -1
- package/dist/client/static/js/async/l9.949710adaf.js +0 -83
- package/dist/client/static/js/async/l9.949710adaf.js.LICENSE.txt +0 -13
- package/dist/client/static/js/async/ls.9d9a01026c.js +0 -104
- package/dist/client/static/js/async/m.eb2e6752e2.js +0 -28
- package/dist/client/static/js/async/m.eb2e6752e2.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/m3.d2b05f9604.js +0 -2
- package/dist/client/static/js/async/m3.d2b05f9604.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/ma.2c261b04dd.js +0 -2
- package/dist/client/static/js/async/ma.2c261b04dd.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/me.8ace414f80.js +0 -23
- package/dist/client/static/js/async/ms.98960af4eb.js +0 -67
- package/dist/client/static/js/async/ms.98960af4eb.js.LICENSE.txt +0 -12
- package/dist/client/static/js/async/mt.0352e976d8.js +0 -1
- package/dist/client/static/js/async/n.a9f1c51701.js +0 -1
- package/dist/client/static/js/async/na.a36cd532d6.js +0 -1
- package/dist/client/static/js/async/nk.fc7e58325e.js +0 -1
- package/dist/client/static/js/async/o.36353dfb88.js +0 -1
- package/dist/client/static/js/async/oc.b73042e8bd.js +0 -8
- package/dist/client/static/js/async/og.8eb577893a.js +0 -193
- package/dist/client/static/js/async/p.48ecfcd14e.js +0 -1
- package/dist/client/static/js/async/px.fc6877924b.js +0 -1
- package/dist/client/static/js/async/q.22588845a9.js +0 -21
- package/dist/client/static/js/async/q.22588845a9.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/q5.97dc1481b6.js +0 -286
- package/dist/client/static/js/async/qs.2a9ddb3c72.js +0 -1
- package/dist/client/static/js/async/r.51010ad87c.js +0 -1
- package/dist/client/static/js/async/rd.cb6bf495bb.js +0 -2
- package/dist/client/static/js/async/rd.cb6bf495bb.js.LICENSE.txt +0 -4
- package/dist/client/static/js/async/s.0f395cdda5.js +0 -94
- package/dist/client/static/js/async/t.4dca0e2ba8.js +0 -1
- package/dist/client/static/js/async/t9.d44f57d518.js +0 -1
- package/dist/client/static/js/async/ta.973534bbec.js +0 -1
- package/dist/client/static/js/async/tr.e878658140.js +0 -309
- package/dist/client/static/js/async/u.0871ac5b22.js +0 -1
- package/dist/client/static/js/async/ud.3065bfee31.js +0 -2
- package/dist/client/static/js/async/ud.3065bfee31.js.LICENSE.txt +0 -4
- package/dist/client/static/js/async/up.ea990da0ff.js +0 -32
- package/dist/client/static/js/async/uw.8890abbabc.js +0 -1
- package/dist/client/static/js/async/v.7d28d3c241.js +0 -34
- package/dist/client/static/js/async/vp.9b13bf8610.js +0 -1
- package/dist/client/static/js/async/vt.42416b707d.js +0 -1
- package/dist/client/static/js/async/w.08ac210f60.js +0 -1
- package/dist/client/static/js/async/wt.ad92393a90.js +0 -1
- package/dist/client/static/js/async/x.563f72ca6b.js +0 -1
- package/dist/client/static/js/async/x0.475516418f.js +0 -1
- package/dist/client/static/js/async/x1.da8687159b.js +0 -90
- package/dist/client/static/js/async/xe.da8dcc2015.js +0 -2
- package/dist/client/static/js/async/xe.da8dcc2015.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/xl.a3c562a58c.js +0 -1
- package/dist/client/static/js/async/xn.6510c0abe2.js +0 -2
- package/dist/client/static/js/async/xn.6510c0abe2.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/xn1.83a7784fe1.js +0 -10
- package/dist/client/static/js/async/xn1.83a7784fe1.js.LICENSE.txt +0 -11
- package/dist/client/static/js/async/xnl.feb0021e50.js +0 -2
- package/dist/client/static/js/async/xnl.feb0021e50.js.LICENSE.txt +0 -12
- package/dist/client/static/js/async/y.1a9ed7a5d8.js +0 -1
- package/dist/client/static/js/async/y6.43c57defe4.js +0 -1
- package/dist/client/static/js/async/yb.8c1342401d.js +0 -1
- package/dist/client/static/js/async/ybq.4491f2f2dc.js +0 -1
- package/dist/client/static/js/async/yg.35bebd6d0c.js +0 -149
- package/dist/client/static/js/async/yq.917ddd7ba2.js +0 -1
- package/dist/client/static/js/async/ys.00687cf82d.js +0 -38
- package/dist/client/static/js/async/yv.d99d829136.js +0 -1
- package/dist/client/static/js/async/z.56f61a4374.js +0 -1
- package/dist/client/static/js/async/zi.5fdb07b86a.js +0 -24
- package/dist/client/static/js/async/zj.654f37e8ff.js +0 -1
- package/dist/client/static/js/async/zn.966d6f1cc6.js +0 -1
- package/dist/client/static/js/async/zo.26213b40c0.js +0 -1
- package/dist/client/static/js/async/zx.e9f4105e00.js +0 -1
- package/dist/client/static/js/index.e6a257402a.js +0 -38
- package/dist/client/static/js/index.e6a257402a.js.LICENSE.txt +0 -4
- package/dist/client/static/js/markdown-vendor.71e43278b3.js +0 -144
- package/dist/client/static/js/shiki-vendor.cb8452ddcd.js +0 -1
- package/src/client/components/settings/categories/provider-settings/Icons.tsx +0 -35
- package/src/client/hooks/settings/providers.ts +0 -326
- package/src/server/plugins/dev-assets.ts +0 -49
- package/src/shared/lib/code/editor-utils.ts +0 -16
- package/src/shared/lib/models/provider-presets.ts +0 -29
- /package/dist/client/{apple-touch-icon.png → static/apple-touch-icon-dskx5sr3.png} +0 -0
- /package/dist/client/{icon-192x192.png → static/icon-192x192-6gn5cr2f.png} +0 -0
- /package/dist/client/{icon.svg → static/icon-d07z9dtz.svg} +0 -0
- /package/dist/client/{manifest.webmanifest → static/manifest-bnyy75kt.webmanifest} +0 -0
- /package/{dist/client → public}/icon-512x512.png +0 -0
- /package/{dist/client → public}/icon-maskable-512x512.png +0 -0
- /package/{dist/client → public}/sw.js +0 -0
- /package/src/{client/components/common/code-editor → shared/lib/code/editor}/history.ts +0 -0
- /package/src/shared/lib/models/{provider-cleanup.ts → provider/cleanup.ts} +0 -0
- /package/src/shared/lib/models/{provider-label.ts → provider/label.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from 'preact/hooks';
|
|
2
|
-
import { AlertCircle, Ban, Check, Info } from 'lucide-preact';
|
|
2
|
+
import { AlertCircle, Ban, Check, Info, Trash2 } from 'lucide-preact';
|
|
3
3
|
import type { ProviderItem } from '@/shared/types';
|
|
4
4
|
|
|
5
5
|
interface ProviderAuthSectionProps {
|
|
@@ -8,6 +8,8 @@ interface ProviderAuthSectionProps {
|
|
|
8
8
|
onToggleDisconnect: () => void;
|
|
9
9
|
/** Adds/removes the provider in omp's config.yml `disabledProviders`. */
|
|
10
10
|
onToggleDisabled: () => void;
|
|
11
|
+
/** Opens the delete confirmation for a provider registered in models.yml. */
|
|
12
|
+
onDelete: () => void;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export function ProviderAuthSection({
|
|
@@ -15,6 +17,7 @@ export function ProviderAuthSection({
|
|
|
15
17
|
onOpenReconnectModal,
|
|
16
18
|
onToggleDisconnect,
|
|
17
19
|
onToggleDisabled,
|
|
20
|
+
onDelete,
|
|
18
21
|
}: ProviderAuthSectionProps) {
|
|
19
22
|
const [showInfoTooltip, setShowInfoTooltip] = useState(false);
|
|
20
23
|
const isConnected = provider.status === 'connected';
|
|
@@ -82,6 +85,22 @@ export function ProviderAuthSection({
|
|
|
82
85
|
>
|
|
83
86
|
{isConnected ? 'reconnect' : 'connect'}
|
|
84
87
|
</button>
|
|
88
|
+
|
|
89
|
+
{/* Delete only exists for a provider that HAS a models.yml entry:
|
|
90
|
+
there is nothing in the file to remove otherwise, and the button
|
|
91
|
+
would promise an action it cannot perform. A login provider's
|
|
92
|
+
credential is never touched by this. */}
|
|
93
|
+
{provider.inModelsYml && (
|
|
94
|
+
<button
|
|
95
|
+
type="button"
|
|
96
|
+
onClick={onDelete}
|
|
97
|
+
title="Remove this provider's models.yml entry"
|
|
98
|
+
className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-error/10 hover:bg-error/20 text-error text-xs font-medium transition-colors cursor-pointer border border-error/30"
|
|
99
|
+
>
|
|
100
|
+
<Trash2 size={12} />
|
|
101
|
+
<span>delete</span>
|
|
102
|
+
</button>
|
|
103
|
+
)}
|
|
85
104
|
</div>
|
|
86
105
|
</div>
|
|
87
106
|
</div>
|
|
@@ -113,6 +132,38 @@ export function ProviderAuthSection({
|
|
|
113
132
|
</span>
|
|
114
133
|
)}
|
|
115
134
|
</div>
|
|
135
|
+
|
|
136
|
+
{/* Dialect: the wire api and auth mode omp will use. A provider whose
|
|
137
|
+
endpoint is right but whose dialect is wrong fails on every request,
|
|
138
|
+
so it belongs next to the connection status rather than in a log. */}
|
|
139
|
+
{(provider.api || provider.auth || provider.discovery) && (
|
|
140
|
+
<div className="flex flex-wrap items-center gap-1.5 pt-0.5">
|
|
141
|
+
{provider.api && (
|
|
142
|
+
<span
|
|
143
|
+
className="px-1.5 py-0.5 rounded border border-ink/15 text-[10px] font-mono text-ink/70"
|
|
144
|
+
title="Wire API omp uses for this provider"
|
|
145
|
+
>
|
|
146
|
+
{provider.api}
|
|
147
|
+
</span>
|
|
148
|
+
)}
|
|
149
|
+
{provider.auth && provider.auth !== 'apiKey' && (
|
|
150
|
+
<span
|
|
151
|
+
className="px-1.5 py-0.5 rounded border border-ink/15 text-[10px] font-mono text-ink/70"
|
|
152
|
+
title="Auth mode from models.yml"
|
|
153
|
+
>
|
|
154
|
+
auth: {provider.auth}
|
|
155
|
+
</span>
|
|
156
|
+
)}
|
|
157
|
+
{provider.discovery && (
|
|
158
|
+
<span
|
|
159
|
+
className="px-1.5 py-0.5 rounded border border-ink/15 text-[10px] font-mono text-ink/70"
|
|
160
|
+
title="omp lists this provider's models live"
|
|
161
|
+
>
|
|
162
|
+
discovery: {provider.discovery}
|
|
163
|
+
</span>
|
|
164
|
+
)}
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
116
167
|
</div>
|
|
117
168
|
|
|
118
169
|
<div className="border-b border-ink/10" />
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { useEffect } from 'preact/hooks';
|
|
2
|
+
import { AlertTriangle, Loader2, Trash2 } from 'lucide-preact';
|
|
3
|
+
import type { ProviderItem } from '@/shared/types';
|
|
4
|
+
import { ProviderIcon } from '@/client/components/common/provider-icon';
|
|
5
|
+
|
|
6
|
+
interface DeleteProviderModalProps {
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
provider: ProviderItem | null;
|
|
9
|
+
/** True while the delete request is in flight. */
|
|
10
|
+
isDeleting: boolean;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
onConfirm: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Confirmation for deleting a provider registered in `models.yml`.
|
|
17
|
+
*
|
|
18
|
+
* The dialog names what actually disappears — the file entry, its model list,
|
|
19
|
+
* and the endpoint/credential stored on it — because the action is not
|
|
20
|
+
* reversible from the UI: the endpoint and API key are only ever shown masked,
|
|
21
|
+
* so a deleted provider has to be reconfigured from scratch.
|
|
22
|
+
*
|
|
23
|
+
* It also says what is NOT touched. A provider omp ships (a login provider, or
|
|
24
|
+
* a bundled catalog entry) keeps its own configuration; only the `models.yml`
|
|
25
|
+
* override goes, and that distinction is the difference between "I can add this
|
|
26
|
+
* back" and "I just deleted my Anthropic login".
|
|
27
|
+
*/
|
|
28
|
+
export function DeleteProviderModal({
|
|
29
|
+
isOpen,
|
|
30
|
+
provider,
|
|
31
|
+
isDeleting,
|
|
32
|
+
onClose,
|
|
33
|
+
onConfirm,
|
|
34
|
+
}: DeleteProviderModalProps) {
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
// No dismissing mid-delete: the modal resolves itself on success, and an
|
|
37
|
+
// early close would let a second delete be queued against a stale list.
|
|
38
|
+
const handler = (e: globalThis.KeyboardEvent) => {
|
|
39
|
+
if (e.key !== 'Escape' || isDeleting) return;
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
onClose();
|
|
42
|
+
};
|
|
43
|
+
window.addEventListener('keydown', handler);
|
|
44
|
+
return () => window.removeEventListener('keydown', handler);
|
|
45
|
+
}, [onClose, isDeleting]);
|
|
46
|
+
|
|
47
|
+
if (!isOpen || !provider) return null;
|
|
48
|
+
|
|
49
|
+
const modelCount = provider.models.length;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
className="fixed inset-0 z-[70] flex items-center justify-center bg-ink/40 backdrop-blur-[2px] p-4"
|
|
54
|
+
onClick={isDeleting ? undefined : onClose}
|
|
55
|
+
role="dialog"
|
|
56
|
+
aria-modal="true"
|
|
57
|
+
aria-label="Confirm provider deletion"
|
|
58
|
+
>
|
|
59
|
+
<div
|
|
60
|
+
className="bg-paper border border-ink/20 rounded-xl shadow-2xl w-[min(94vw,460px)] overflow-hidden text-ink"
|
|
61
|
+
onClick={(e) => e.stopPropagation()}
|
|
62
|
+
>
|
|
63
|
+
<div className="flex items-center gap-3 px-5 py-4 border-b border-ink/10">
|
|
64
|
+
<Trash2 size={16} className="text-error shrink-0" />
|
|
65
|
+
<div className="min-w-0">
|
|
66
|
+
<h2 className="text-sm font-semibold text-ink">Delete provider?</h2>
|
|
67
|
+
<p className="text-[11px] text-ink/50 truncate">
|
|
68
|
+
<span className="font-mono">{provider.slug}</span>
|
|
69
|
+
</p>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div className="px-5 py-4 space-y-3">
|
|
74
|
+
<div className="flex items-center gap-2.5 px-3 py-2.5 rounded-lg bg-ink/5 border border-ink/10">
|
|
75
|
+
<ProviderIcon icon={provider.icon} slug={provider.slug} name={provider.name} size={18} />
|
|
76
|
+
<span className="text-xs font-medium text-ink truncate">{provider.name}</span>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<ul className="text-[11.5px] leading-relaxed text-ink/70 space-y-1.5">
|
|
80
|
+
<li>
|
|
81
|
+
Its entry is removed from{' '}
|
|
82
|
+
<span className="font-mono text-ink">~/.omp/agent/models.yml</span>
|
|
83
|
+
{modelCount > 0
|
|
84
|
+
? `, along with its ${modelCount} registered model${modelCount === 1 ? '' : 's'}.`
|
|
85
|
+
: '.'}
|
|
86
|
+
</li>
|
|
87
|
+
<li>The endpoint and API key stored on that entry are removed with it — they are shown masked here, so you would need to enter them again.</li>
|
|
88
|
+
{provider.credentialSource === 'omp-auth' && (
|
|
89
|
+
<li className="text-ink/60">
|
|
90
|
+
Your omp login for <span className="font-mono">{provider.slug}</span> is NOT touched — only the models.yml
|
|
91
|
+
entry above. The provider stays available through that login.
|
|
92
|
+
</li>
|
|
93
|
+
)}
|
|
94
|
+
</ul>
|
|
95
|
+
|
|
96
|
+
<div className="flex items-start gap-2 px-3 py-2 rounded-md border border-error/30 bg-error/5 text-[11px] text-ink/75">
|
|
97
|
+
<AlertTriangle size={13} className="mt-0.5 shrink-0 text-error" />
|
|
98
|
+
<span>This cannot be undone from the UI. Re-adding the provider starts from an empty endpoint and key.</span>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div className="flex items-center justify-end gap-2 px-5 py-3.5 border-t border-ink/10">
|
|
103
|
+
<button
|
|
104
|
+
type="button"
|
|
105
|
+
onClick={onClose}
|
|
106
|
+
disabled={isDeleting}
|
|
107
|
+
className="px-3.5 py-1.5 rounded-md border border-ink/20 text-xs font-medium text-ink hover:bg-ink/5 transition-colors cursor-pointer disabled:opacity-50"
|
|
108
|
+
>
|
|
109
|
+
Cancel
|
|
110
|
+
</button>
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
onClick={onConfirm}
|
|
114
|
+
disabled={isDeleting}
|
|
115
|
+
className="px-3.5 py-1.5 rounded-md bg-error text-canvas text-xs font-medium hover:opacity-90 transition-opacity cursor-pointer disabled:opacity-50 flex items-center gap-1.5"
|
|
116
|
+
>
|
|
117
|
+
{isDeleting ? (
|
|
118
|
+
<>
|
|
119
|
+
<Loader2 size={13} className="animate-spin" />
|
|
120
|
+
<span>Deleting...</span>
|
|
121
|
+
</>
|
|
122
|
+
) : (
|
|
123
|
+
<>
|
|
124
|
+
<Trash2 size={13} />
|
|
125
|
+
<span>Delete provider</span>
|
|
126
|
+
</>
|
|
127
|
+
)}
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
OmpProviderApi,
|
|
3
|
+
ProviderAuthMode,
|
|
4
|
+
ProviderDiscoveryType,
|
|
5
|
+
ProviderModelSource,
|
|
6
|
+
} from '@/shared/types/settings/provider';
|
|
7
|
+
import {
|
|
8
|
+
PROVIDER_APIS,
|
|
9
|
+
PROVIDER_API_LABELS,
|
|
10
|
+
PROVIDER_AUTH_MODES,
|
|
11
|
+
PROVIDER_DISCOVERY_TYPES,
|
|
12
|
+
} from '@/shared/lib/models/provider/dialect';
|
|
13
|
+
|
|
14
|
+
interface DialectFieldsProps {
|
|
15
|
+
api: OmpProviderApi;
|
|
16
|
+
onApiChange: (api: OmpProviderApi) => void;
|
|
17
|
+
auth: ProviderAuthMode;
|
|
18
|
+
onAuthChange: (auth: ProviderAuthMode) => void;
|
|
19
|
+
source: ProviderModelSource;
|
|
20
|
+
onSourceChange: (source: ProviderModelSource) => void;
|
|
21
|
+
discovery: ProviderDiscoveryType;
|
|
22
|
+
onDiscoveryChange: (discovery: ProviderDiscoveryType) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const SOURCE_OPTIONS: ReadonlyArray<{ value: ProviderModelSource; label: string; hint: string }> = [
|
|
26
|
+
{ value: 'fetch', label: 'Fetch now', hint: 'List the endpoint here and write the ids into models.yml' },
|
|
27
|
+
{ value: 'discovery', label: 'Let omp discover', hint: 'omp lists the models live on every run' },
|
|
28
|
+
{ value: 'override', label: 'Endpoint only', hint: 'Keep omp’s own model list, change only the URL' },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const fieldClass = 'w-full text-xs py-2 px-3 rounded-lg border border-ink/20 hover:border-ink/40 '
|
|
32
|
+
+ 'bg-paper focus:outline-none focus:border-ink text-ink transition-colors cursor-pointer';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The provider DIALECT controls: wire API, auth mode, and where the model list
|
|
36
|
+
* comes from.
|
|
37
|
+
*
|
|
38
|
+
* These three are the `models.yml` fields that decide whether a provider works
|
|
39
|
+
* at all, and each one is a decision the chamber cannot make for the user:
|
|
40
|
+
*
|
|
41
|
+
* - An Anthropic-shaped proxy reached with a Bearer header authorises nothing,
|
|
42
|
+
* and omp rejects an unknown `api` by disabling every custom provider in the
|
|
43
|
+
* file — so the dialect is picked from omp's own list, never guessed into it.
|
|
44
|
+
* - `auth: none` is what makes a local server keyless; without it omp demands a
|
|
45
|
+
* key and the provider is reported as unconfigured.
|
|
46
|
+
* - A provider omp can discover should not also receive a snapshot of ids, or
|
|
47
|
+
* the two lists drift as soon as the endpoint adds a model.
|
|
48
|
+
*/
|
|
49
|
+
export function DialectFields({
|
|
50
|
+
api,
|
|
51
|
+
onApiChange,
|
|
52
|
+
auth,
|
|
53
|
+
onAuthChange,
|
|
54
|
+
source,
|
|
55
|
+
onSourceChange,
|
|
56
|
+
discovery,
|
|
57
|
+
onDiscoveryChange,
|
|
58
|
+
}: DialectFieldsProps) {
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
<div className="grid grid-cols-2 gap-3">
|
|
62
|
+
<div>
|
|
63
|
+
<label className="block text-xs font-semibold text-ink mb-1">Wire API</label>
|
|
64
|
+
<select
|
|
65
|
+
value={api}
|
|
66
|
+
onChange={(e) => onApiChange(e.currentTarget.value as OmpProviderApi)}
|
|
67
|
+
className={fieldClass}
|
|
68
|
+
>
|
|
69
|
+
{PROVIDER_APIS.map((value) => (
|
|
70
|
+
<option key={value} value={value}>{value}</option>
|
|
71
|
+
))}
|
|
72
|
+
</select>
|
|
73
|
+
</div>
|
|
74
|
+
<div>
|
|
75
|
+
<label className="block text-xs font-semibold text-ink mb-1">Auth</label>
|
|
76
|
+
<select
|
|
77
|
+
value={auth}
|
|
78
|
+
onChange={(e) => onAuthChange(e.currentTarget.value as ProviderAuthMode)}
|
|
79
|
+
className={fieldClass}
|
|
80
|
+
>
|
|
81
|
+
{PROVIDER_AUTH_MODES.map((mode) => (
|
|
82
|
+
<option key={mode.value} value={mode.value}>{mode.label}</option>
|
|
83
|
+
))}
|
|
84
|
+
</select>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<p className="text-[10px] text-ink/40 leading-relaxed -mt-1">
|
|
88
|
+
{PROVIDER_API_LABELS[api]} · {PROVIDER_AUTH_MODES.find((m) => m.value === auth)?.hint}
|
|
89
|
+
</p>
|
|
90
|
+
|
|
91
|
+
<div>
|
|
92
|
+
<label className="block text-xs font-semibold text-ink mb-1">Model source</label>
|
|
93
|
+
<div className="grid grid-cols-3 gap-2">
|
|
94
|
+
{SOURCE_OPTIONS.map((option) => {
|
|
95
|
+
const isSelected = source === option.value;
|
|
96
|
+
return (
|
|
97
|
+
<button
|
|
98
|
+
key={option.value}
|
|
99
|
+
type="button"
|
|
100
|
+
onClick={() => onSourceChange(option.value)}
|
|
101
|
+
className={`px-2 py-1.5 rounded-lg border text-[11px] transition-colors cursor-pointer ${
|
|
102
|
+
isSelected
|
|
103
|
+
? 'border-ink/50 bg-ink/5 font-semibold text-ink'
|
|
104
|
+
: 'border-ink/15 hover:border-ink/30 text-ink/70'
|
|
105
|
+
}`}
|
|
106
|
+
>
|
|
107
|
+
{option.label}
|
|
108
|
+
</button>
|
|
109
|
+
);
|
|
110
|
+
})}
|
|
111
|
+
</div>
|
|
112
|
+
<p className="text-[10px] text-ink/40 mt-1 leading-relaxed">
|
|
113
|
+
{SOURCE_OPTIONS.find((option) => option.value === source)?.hint}
|
|
114
|
+
</p>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
{source === 'discovery' && (
|
|
118
|
+
<div>
|
|
119
|
+
<label className="block text-xs font-semibold text-ink mb-1">Discovery protocol</label>
|
|
120
|
+
<select
|
|
121
|
+
value={discovery}
|
|
122
|
+
onChange={(e) => onDiscoveryChange(e.currentTarget.value as ProviderDiscoveryType)}
|
|
123
|
+
className={fieldClass}
|
|
124
|
+
>
|
|
125
|
+
{PROVIDER_DISCOVERY_TYPES.map((type) => (
|
|
126
|
+
<option key={type.value} value={type.value}>{type.label}</option>
|
|
127
|
+
))}
|
|
128
|
+
</select>
|
|
129
|
+
<p className="text-[10px] text-ink/40 mt-1">
|
|
130
|
+
{PROVIDER_DISCOVERY_TYPES.find((type) => type.value === discovery)?.hint}
|
|
131
|
+
</p>
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
134
|
+
</>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Check } from 'lucide-preact';
|
|
2
|
+
import { PROVIDER_THINKING_EFFORTS, type ProviderThinkingEffort } from '@/shared/lib/models/provider/dialect';
|
|
3
|
+
|
|
4
|
+
interface EffortLadderProps {
|
|
5
|
+
/** Selected levels, in any order; the component renders them in omp's order. */
|
|
6
|
+
selected: ProviderThinkingEffort[];
|
|
7
|
+
onToggle: (effort: ProviderThinkingEffort) => void;
|
|
8
|
+
onSelectAll: () => void;
|
|
9
|
+
onClear: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The reasoning ladder a model accepts, as checkboxes.
|
|
14
|
+
*
|
|
15
|
+
* omp reads this as `thinking.efforts` and refuses to start a level that is not
|
|
16
|
+
* on the list, so the control is a capability declaration rather than a
|
|
17
|
+
* preference: ticking `low` and `high` means the model may be asked for those
|
|
18
|
+
* two and nothing else. `off` is deliberately not offered — omp's `EffortSchema`
|
|
19
|
+
* rejects it, and turning thinking off is a per-turn choice the chat composer
|
|
20
|
+
* already owns.
|
|
21
|
+
*
|
|
22
|
+
* An EMPTY selection is a valid and distinct state: it means "do not declare a
|
|
23
|
+
* ladder", which leaves omp on its own default for the model. That is why the
|
|
24
|
+
* hint changes with the selection instead of always describing a ladder.
|
|
25
|
+
*/
|
|
26
|
+
export function EffortLadder({ selected, onToggle, onSelectAll, onClear }: EffortLadderProps) {
|
|
27
|
+
const isAll = selected.length === PROVIDER_THINKING_EFFORTS.length;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div>
|
|
31
|
+
<div className="flex items-center justify-between mb-1.5">
|
|
32
|
+
<label className="block text-xs font-semibold text-ink">Reasoning levels</label>
|
|
33
|
+
<div className="flex items-center gap-2 text-[10px]">
|
|
34
|
+
<button
|
|
35
|
+
type="button"
|
|
36
|
+
onClick={onSelectAll}
|
|
37
|
+
disabled={isAll}
|
|
38
|
+
className="text-ink/50 hover:text-ink transition-colors cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
|
|
39
|
+
>
|
|
40
|
+
all
|
|
41
|
+
</button>
|
|
42
|
+
<span className="text-ink/20">·</span>
|
|
43
|
+
<button
|
|
44
|
+
type="button"
|
|
45
|
+
onClick={onClear}
|
|
46
|
+
disabled={selected.length === 0}
|
|
47
|
+
className="text-ink/50 hover:text-ink transition-colors cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
|
|
48
|
+
>
|
|
49
|
+
none
|
|
50
|
+
</button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div className="grid grid-cols-3 gap-2">
|
|
55
|
+
{PROVIDER_THINKING_EFFORTS.map((effort) => {
|
|
56
|
+
const isOn = selected.includes(effort);
|
|
57
|
+
return (
|
|
58
|
+
<button
|
|
59
|
+
key={effort}
|
|
60
|
+
type="button"
|
|
61
|
+
onClick={() => onToggle(effort)}
|
|
62
|
+
aria-pressed={isOn}
|
|
63
|
+
className={`flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border text-left text-[11px] transition-colors cursor-pointer ${
|
|
64
|
+
isOn
|
|
65
|
+
? 'border-ink/50 bg-ink/5 font-semibold text-ink'
|
|
66
|
+
: 'border-ink/15 hover:border-ink/30 text-ink/70'
|
|
67
|
+
}`}
|
|
68
|
+
>
|
|
69
|
+
<span
|
|
70
|
+
className={`w-3 h-3 rounded-[3px] border flex items-center justify-center shrink-0 ${
|
|
71
|
+
isOn ? 'border-ink bg-ink text-canvas' : 'border-ink/30'
|
|
72
|
+
}`}
|
|
73
|
+
>
|
|
74
|
+
{isOn && <Check size={9} strokeWidth={3} />}
|
|
75
|
+
</span>
|
|
76
|
+
<span className="truncate">{effort}</span>
|
|
77
|
+
</button>
|
|
78
|
+
);
|
|
79
|
+
})}
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<p className="text-[10px] text-ink/40 mt-1">
|
|
83
|
+
{selected.length === 0
|
|
84
|
+
? 'No ladder declared — omp keeps its own default levels for this model.'
|
|
85
|
+
: `Only these levels will be offered: ${PROVIDER_THINKING_EFFORTS.filter((e) => selected.includes(e)).join(', ')}.`}
|
|
86
|
+
</p>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ProviderItem } from '@/shared/types';
|
|
2
|
-
import { ProviderIcon } from '@/client/components/
|
|
2
|
+
import { ProviderIcon } from '@/client/components/common/provider-icon';
|
|
3
3
|
|
|
4
4
|
interface ProviderHeaderProps {
|
|
5
5
|
provider: ProviderItem;
|
|
@@ -9,7 +9,7 @@ export function ProviderHeader({ provider }: ProviderHeaderProps) {
|
|
|
9
9
|
return (
|
|
10
10
|
<div className="flex flex-col gap-1 pb-4">
|
|
11
11
|
<div className="flex items-center gap-2.5">
|
|
12
|
-
<ProviderIcon icon={provider.icon} size={22} />
|
|
12
|
+
<ProviderIcon icon={provider.icon} slug={provider.slug} name={provider.name} size={22} />
|
|
13
13
|
<h2 className="text-xl font-bold tracking-tight text-ink">
|
|
14
14
|
{provider.name}
|
|
15
15
|
</h2>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
2
2
|
import { AlertCircle, CheckCircle2, Globe, Key, Loader2 } from 'lucide-preact';
|
|
3
3
|
import type { ProviderItem } from '@/shared/types';
|
|
4
|
-
import { ProviderIcon } from '@/client/components/
|
|
4
|
+
import { ProviderIcon } from '@/client/components/common/provider-icon';
|
|
5
5
|
import { Modal } from '@/client/components/common/Modal';
|
|
6
6
|
|
|
7
7
|
interface LoginModalProps {
|
|
@@ -132,7 +132,7 @@ export function LoginModal({ isOpen, provider, onClose, onAuthenticated }: Login
|
|
|
132
132
|
onClose={onClose}
|
|
133
133
|
header={
|
|
134
134
|
<div className="flex items-center gap-2.5">
|
|
135
|
-
<ProviderIcon icon={provider.icon} size={18} />
|
|
135
|
+
<ProviderIcon icon={provider.icon} slug={provider.slug} name={provider.name} size={18} />
|
|
136
136
|
<div>
|
|
137
137
|
<h3 className="text-sm font-semibold text-ink">Sign in to {provider.name}</h3>
|
|
138
138
|
<p className="text-[11px] text-ink/50 font-mono">{provider.slug}</p>
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { useState } from 'preact/hooks';
|
|
2
|
-
import { Eye, EyeOff, Image as ImageIcon, RefreshCw, Search, Settings2, SlidersHorizontal } from 'lucide-preact';
|
|
2
|
+
import { Eye, EyeOff, Image as ImageIcon, Plus, RefreshCw, Search, Settings2, SlidersHorizontal } from 'lucide-preact';
|
|
3
3
|
import type { ProviderModel } from '@/shared/types';
|
|
4
4
|
import { formatContextWindow } from '@/shared/lib/code/format';
|
|
5
5
|
import { formatPrice } from '@/shared/lib/format/number';
|
|
6
6
|
|
|
7
7
|
interface ProviderModelsListProps {
|
|
8
8
|
models: ProviderModel[];
|
|
9
|
+
/** Why the list is empty, when it legitimately is — never a generic excuse. */
|
|
10
|
+
emptyReason?: string;
|
|
9
11
|
onToggleModelVisibility: (modelId: string) => void;
|
|
10
12
|
onHideAll: () => void;
|
|
11
13
|
onShowAll: () => void;
|
|
12
14
|
onFetchModels: () => Promise<void>;
|
|
15
|
+
/** Opens the manual "Add Model" dialog. */
|
|
16
|
+
onAddModel: () => void;
|
|
13
17
|
canFetchModels: boolean;
|
|
14
18
|
isFetchingModels: boolean;
|
|
15
19
|
onOpenModelConfig: (model: ProviderModel) => void;
|
|
@@ -18,10 +22,12 @@ interface ProviderModelsListProps {
|
|
|
18
22
|
|
|
19
23
|
export function ProviderModelsList({
|
|
20
24
|
models,
|
|
25
|
+
emptyReason,
|
|
21
26
|
onToggleModelVisibility,
|
|
22
27
|
onHideAll,
|
|
23
28
|
onShowAll,
|
|
24
29
|
onFetchModels,
|
|
30
|
+
onAddModel,
|
|
25
31
|
canFetchModels,
|
|
26
32
|
isFetchingModels,
|
|
27
33
|
onOpenModelConfig,
|
|
@@ -52,6 +58,18 @@ export function ProviderModelsList({
|
|
|
52
58
|
<RefreshCw size={12} className={isFetchingModels ? 'animate-spin' : ''} />
|
|
53
59
|
<span>{isFetchingModels ? 'fetching...' : 'fetch models'}</span>
|
|
54
60
|
</button>
|
|
61
|
+
{/* Manual registration, for the ids no listing endpoint reports:
|
|
62
|
+
a gateway model its /models omits, an Azure deployment name, a
|
|
63
|
+
provider with no listing route at all (Bedrock, Vertex). */}
|
|
64
|
+
<button
|
|
65
|
+
type="button"
|
|
66
|
+
onClick={onAddModel}
|
|
67
|
+
title="Register a model by hand"
|
|
68
|
+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded bg-ink/5 hover:bg-ink/10 text-[11px] font-medium text-ink/80 hover:text-ink transition-colors cursor-pointer border border-ink/10"
|
|
69
|
+
>
|
|
70
|
+
<Plus size={12} />
|
|
71
|
+
<span>add model</span>
|
|
72
|
+
</button>
|
|
55
73
|
<button
|
|
56
74
|
type="button"
|
|
57
75
|
onClick={onHideAll}
|
|
@@ -94,7 +112,9 @@ export function ProviderModelsList({
|
|
|
94
112
|
<div className="space-y-1 pt-1">
|
|
95
113
|
{filteredModels.length === 0 ? (
|
|
96
114
|
<div className="py-8 text-center text-xs text-ink/40">
|
|
97
|
-
|
|
115
|
+
{searchQuery
|
|
116
|
+
? `No models found matching "${searchQuery}"`
|
|
117
|
+
: emptyReason || 'No models registered for this provider yet.'}
|
|
98
118
|
</div>
|
|
99
119
|
) : (
|
|
100
120
|
filteredModels.map((model) => (
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { useState } from 'preact/hooks';
|
|
2
|
+
import { Check, ChevronDown } from 'lucide-preact';
|
|
3
|
+
import type { PresetProviderOption } from '@/shared/types/settings/provider';
|
|
4
|
+
import { groupProviderPresets } from '@/shared/lib/models/provider/presets';
|
|
5
|
+
import { ProviderIcon } from '@/client/components/common/provider-icon';
|
|
6
|
+
|
|
7
|
+
interface PresetPickerProps {
|
|
8
|
+
presets: PresetProviderOption[];
|
|
9
|
+
selectedPresetId: string;
|
|
10
|
+
onSelectPreset: (preset: PresetProviderOption) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The provider picker, grouped by kind.
|
|
15
|
+
*
|
|
16
|
+
* Groups matter because the presets are not interchangeable: a local engine is
|
|
17
|
+
* keyless and discovered by omp, a gateway is fetched and written into
|
|
18
|
+
* models.yml, and an "Other dialects" entry exists precisely because the
|
|
19
|
+
* endpoint is NOT OpenAI-shaped. Listing them in one flat grid made a keyless
|
|
20
|
+
* Ollama row look like a hosted API that would ask for a key.
|
|
21
|
+
*/
|
|
22
|
+
export function PresetPicker({ presets, selectedPresetId, onSelectPreset }: PresetPickerProps) {
|
|
23
|
+
const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});
|
|
24
|
+
const groups = groupProviderPresets(presets);
|
|
25
|
+
|
|
26
|
+
if (presets.length === 0) {
|
|
27
|
+
return (
|
|
28
|
+
<p className="px-2 py-3 text-xs text-ink/50">
|
|
29
|
+
Every known provider is already configured.
|
|
30
|
+
</p>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className="max-h-52 scrollbar-overlay-container scrollbar-overlay-static pr-1 space-y-2">
|
|
36
|
+
{groups.map((entry) => {
|
|
37
|
+
const isCollapsed = collapsed[entry.group] === true;
|
|
38
|
+
return (
|
|
39
|
+
<div key={entry.group}>
|
|
40
|
+
<button
|
|
41
|
+
type="button"
|
|
42
|
+
onClick={() => setCollapsed((prev) => ({ ...prev, [entry.group]: !isCollapsed }))}
|
|
43
|
+
className="w-full flex items-center gap-1.5 px-0.5 py-1 text-[10px] font-semibold tracking-wider text-ink/50 uppercase hover:text-ink/80 transition-colors cursor-pointer"
|
|
44
|
+
>
|
|
45
|
+
<ChevronDown
|
|
46
|
+
size={11}
|
|
47
|
+
className={`transition-transform ${isCollapsed ? '-rotate-90' : ''}`}
|
|
48
|
+
/>
|
|
49
|
+
<span>{entry.group}</span>
|
|
50
|
+
<span className="text-ink/30 normal-case tracking-normal">{entry.options.length}</span>
|
|
51
|
+
</button>
|
|
52
|
+
|
|
53
|
+
{!isCollapsed && (
|
|
54
|
+
<div className="grid grid-cols-2 gap-2 pt-1">
|
|
55
|
+
{entry.options.map((preset) => {
|
|
56
|
+
const isSelected = preset.id === selectedPresetId;
|
|
57
|
+
return (
|
|
58
|
+
<button
|
|
59
|
+
key={preset.id}
|
|
60
|
+
type="button"
|
|
61
|
+
onClick={() => onSelectPreset(preset)}
|
|
62
|
+
title={preset.defaultUrl}
|
|
63
|
+
className={`flex items-center gap-2 p-2 rounded-lg border text-left text-xs transition-colors cursor-pointer ${
|
|
64
|
+
isSelected
|
|
65
|
+
? 'border-ink/50 bg-ink/5 font-semibold text-ink shadow-2xs'
|
|
66
|
+
: 'border-ink/15 hover:border-ink/30 text-ink/70'
|
|
67
|
+
}`}
|
|
68
|
+
>
|
|
69
|
+
<ProviderIcon icon={preset.icon} slug={preset.slug} name={preset.name} size={14} />
|
|
70
|
+
<span className="truncate flex-1">{preset.name}</span>
|
|
71
|
+
{isSelected && <Check size={12} className="shrink-0 text-ink" />}
|
|
72
|
+
</button>
|
|
73
|
+
);
|
|
74
|
+
})}
|
|
75
|
+
</div>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
})}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|