mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-07 05:32:47 +08:00
feat: optimize model management UI with waterfall fallback editor
This commit is contained in:
791
pnpm-lock.yaml
generated
Normal file
791
pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,791 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@tauri-apps/api':
|
||||
specifier: ^2.5.0
|
||||
version: 2.10.1
|
||||
'@tauri-apps/plugin-autostart':
|
||||
specifier: ^2.5.1
|
||||
version: 2.5.1
|
||||
'@tauri-apps/plugin-shell':
|
||||
specifier: ^2.2.1
|
||||
version: 2.3.5
|
||||
devDependencies:
|
||||
'@tauri-apps/cli':
|
||||
specifier: ^2.5.0
|
||||
version: 2.10.1
|
||||
vite:
|
||||
specifier: ^6.4.2
|
||||
version: 6.4.2
|
||||
|
||||
packages:
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.60.1':
|
||||
resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.60.1':
|
||||
resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.60.1':
|
||||
resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.60.1':
|
||||
resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.60.1':
|
||||
resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.60.1':
|
||||
resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.60.1':
|
||||
resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.60.1':
|
||||
resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.60.1':
|
||||
resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.60.1':
|
||||
resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.60.1':
|
||||
resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.60.1':
|
||||
resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.60.1':
|
||||
resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.60.1':
|
||||
resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.60.1':
|
||||
resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.60.1':
|
||||
resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.60.1':
|
||||
resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.60.1':
|
||||
resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.60.1':
|
||||
resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.60.1':
|
||||
resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.60.1':
|
||||
resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.60.1':
|
||||
resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.60.1':
|
||||
resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.60.1':
|
||||
resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.60.1':
|
||||
resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/api@2.10.1':
|
||||
resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==}
|
||||
|
||||
'@tauri-apps/cli-darwin-arm64@2.10.1':
|
||||
resolution: {integrity: sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@tauri-apps/cli-darwin-x64@2.10.1':
|
||||
resolution: {integrity: sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf@2.10.1':
|
||||
resolution: {integrity: sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-gnu@2.10.1':
|
||||
resolution: {integrity: sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-musl@2.10.1':
|
||||
resolution: {integrity: sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tauri-apps/cli-linux-riscv64-gnu@2.10.1':
|
||||
resolution: {integrity: sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@tauri-apps/cli-linux-x64-gnu@2.10.1':
|
||||
resolution: {integrity: sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tauri-apps/cli-linux-x64-musl@2.10.1':
|
||||
resolution: {integrity: sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tauri-apps/cli-win32-arm64-msvc@2.10.1':
|
||||
resolution: {integrity: sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/cli-win32-ia32-msvc@2.10.1':
|
||||
resolution: {integrity: sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/cli-win32-x64-msvc@2.10.1':
|
||||
resolution: {integrity: sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/cli@2.10.1':
|
||||
resolution: {integrity: sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==}
|
||||
engines: {node: '>= 10'}
|
||||
hasBin: true
|
||||
|
||||
'@tauri-apps/plugin-autostart@2.5.1':
|
||||
resolution: {integrity: sha512-zS/xx7yzveCcotkA+8TqkI2lysmG2wvQXv2HGAVExITmnFfHAdj1arGsbbfs3o6EktRHf6l34pJxc3YGG2mg7w==}
|
||||
|
||||
'@tauri-apps/plugin-shell@2.3.5':
|
||||
resolution: {integrity: sha512-jewtULhiQ7lI7+owCKAjc8tYLJr92U16bPOeAa472LHJdgaibLP83NcfAF2e+wkEcA53FxKQAZ7byDzs2eeizg==}
|
||||
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
esbuild@0.25.12:
|
||||
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
fdir@6.5.0:
|
||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
picomatch: ^3 || ^4
|
||||
peerDependenciesMeta:
|
||||
picomatch:
|
||||
optional: true
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
picomatch@4.0.4:
|
||||
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postcss@8.5.10:
|
||||
resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
rollup@4.60.1:
|
||||
resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
tinyglobby@0.2.16:
|
||||
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
vite@6.4.2:
|
||||
resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==}
|
||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
|
||||
jiti: '>=1.21.0'
|
||||
less: '*'
|
||||
lightningcss: ^1.21.0
|
||||
sass: '*'
|
||||
sass-embedded: '*'
|
||||
stylus: '*'
|
||||
sugarss: '*'
|
||||
terser: ^5.16.0
|
||||
tsx: ^4.8.1
|
||||
yaml: ^2.4.2
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
jiti:
|
||||
optional: true
|
||||
less:
|
||||
optional: true
|
||||
lightningcss:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
sass-embedded:
|
||||
optional: true
|
||||
stylus:
|
||||
optional: true
|
||||
sugarss:
|
||||
optional: true
|
||||
terser:
|
||||
optional: true
|
||||
tsx:
|
||||
optional: true
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.60.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/api@2.10.1': {}
|
||||
|
||||
'@tauri-apps/cli-darwin-arm64@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-darwin-x64@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-gnu@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-musl@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-riscv64-gnu@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-x64-gnu@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-linux-x64-musl@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-win32-arm64-msvc@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-win32-ia32-msvc@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli-win32-x64-msvc@2.10.1':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/cli@2.10.1':
|
||||
optionalDependencies:
|
||||
'@tauri-apps/cli-darwin-arm64': 2.10.1
|
||||
'@tauri-apps/cli-darwin-x64': 2.10.1
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf': 2.10.1
|
||||
'@tauri-apps/cli-linux-arm64-gnu': 2.10.1
|
||||
'@tauri-apps/cli-linux-arm64-musl': 2.10.1
|
||||
'@tauri-apps/cli-linux-riscv64-gnu': 2.10.1
|
||||
'@tauri-apps/cli-linux-x64-gnu': 2.10.1
|
||||
'@tauri-apps/cli-linux-x64-musl': 2.10.1
|
||||
'@tauri-apps/cli-win32-arm64-msvc': 2.10.1
|
||||
'@tauri-apps/cli-win32-ia32-msvc': 2.10.1
|
||||
'@tauri-apps/cli-win32-x64-msvc': 2.10.1
|
||||
|
||||
'@tauri-apps/plugin-autostart@2.5.1':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.10.1
|
||||
|
||||
'@tauri-apps/plugin-shell@2.3.5':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.10.1
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
esbuild@0.25.12:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.25.12
|
||||
'@esbuild/android-arm': 0.25.12
|
||||
'@esbuild/android-arm64': 0.25.12
|
||||
'@esbuild/android-x64': 0.25.12
|
||||
'@esbuild/darwin-arm64': 0.25.12
|
||||
'@esbuild/darwin-x64': 0.25.12
|
||||
'@esbuild/freebsd-arm64': 0.25.12
|
||||
'@esbuild/freebsd-x64': 0.25.12
|
||||
'@esbuild/linux-arm': 0.25.12
|
||||
'@esbuild/linux-arm64': 0.25.12
|
||||
'@esbuild/linux-ia32': 0.25.12
|
||||
'@esbuild/linux-loong64': 0.25.12
|
||||
'@esbuild/linux-mips64el': 0.25.12
|
||||
'@esbuild/linux-ppc64': 0.25.12
|
||||
'@esbuild/linux-riscv64': 0.25.12
|
||||
'@esbuild/linux-s390x': 0.25.12
|
||||
'@esbuild/linux-x64': 0.25.12
|
||||
'@esbuild/netbsd-arm64': 0.25.12
|
||||
'@esbuild/netbsd-x64': 0.25.12
|
||||
'@esbuild/openbsd-arm64': 0.25.12
|
||||
'@esbuild/openbsd-x64': 0.25.12
|
||||
'@esbuild/openharmony-arm64': 0.25.12
|
||||
'@esbuild/sunos-x64': 0.25.12
|
||||
'@esbuild/win32-arm64': 0.25.12
|
||||
'@esbuild/win32-ia32': 0.25.12
|
||||
'@esbuild/win32-x64': 0.25.12
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.4):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.4
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@4.0.4: {}
|
||||
|
||||
postcss@8.5.10:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
rollup@4.60.1:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.60.1
|
||||
'@rollup/rollup-android-arm64': 4.60.1
|
||||
'@rollup/rollup-darwin-arm64': 4.60.1
|
||||
'@rollup/rollup-darwin-x64': 4.60.1
|
||||
'@rollup/rollup-freebsd-arm64': 4.60.1
|
||||
'@rollup/rollup-freebsd-x64': 4.60.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.60.1
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.60.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.60.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.60.1
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.60.1
|
||||
'@rollup/rollup-linux-loong64-musl': 4.60.1
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.60.1
|
||||
'@rollup/rollup-linux-ppc64-musl': 4.60.1
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.60.1
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.60.1
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.60.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.60.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.60.1
|
||||
'@rollup/rollup-openbsd-x64': 4.60.1
|
||||
'@rollup/rollup-openharmony-arm64': 4.60.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.60.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.60.1
|
||||
'@rollup/rollup-win32-x64-gnu': 4.60.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.60.1
|
||||
fsevents: 2.3.3
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
tinyglobby@0.2.16:
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
|
||||
vite@6.4.2:
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
postcss: 8.5.10
|
||||
rollup: 4.60.1
|
||||
tinyglobby: 0.2.16
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
2606
src-tauri/gen/schemas/linux-schema.json
Normal file
2606
src-tauri/gen/schemas/linux-schema.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -436,6 +436,7 @@
|
||||
"fallbackModels": "备选模型:",
|
||||
"fallbackNone": "无",
|
||||
"fallbackHint": "主模型不可用时,系统会自动切换到备选模型",
|
||||
"configure": "配置",
|
||||
"primaryAutoSwitch": "主模型已自动切换为 {model}",
|
||||
"noProvider": "暂无服务商,点击「+ 添加服务商」开始配置",
|
||||
"noModel": "暂无模型,点击「+ 模型」添加",
|
||||
|
||||
@@ -58,7 +58,7 @@ export async function render() {
|
||||
`
|
||||
|
||||
const state = { config: null, search: '', undoStack: [] }
|
||||
// 非阻塞:先返回 DOM,后台加载数据
|
||||
// 非阻塞:先返回 DOM,后台加载数据
|
||||
loadConfig(page, state)
|
||||
bindTopActions(page, state)
|
||||
|
||||
@@ -75,12 +75,12 @@ async function loadConfig(page, state) {
|
||||
const listEl = page.querySelector('#providers-list')
|
||||
try {
|
||||
state.config = await api.readOpenclawConfig()
|
||||
// 自动修复现有配置中的 baseUrl(如 Ollama 缺少 /v1),一次性迁移
|
||||
// 自动修复现有配置中的 baseUrl(如 Ollama 缺少 /v1),一次性迁移
|
||||
const before = JSON.stringify(state.config?.models?.providers || {})
|
||||
normalizeProviderUrls(state.config)
|
||||
const after = JSON.stringify(state.config?.models?.providers || {})
|
||||
if (before !== after) {
|
||||
console.log('[models] 自动修复了服务商 baseUrl,正在保存...')
|
||||
console.log('[models] 自动修复了服务商 baseUrl,正在保存...')
|
||||
await api.writeOpenclawConfig(state.config)
|
||||
toast(t('models.autoFixUrl'), 'info')
|
||||
}
|
||||
@@ -116,25 +116,273 @@ function getApiTypeLabel(apiType) {
|
||||
function renderDefaultBar(page, state) {
|
||||
const bar = page.querySelector('#default-model-bar')
|
||||
const primary = getCurrentPrimary(state.config)
|
||||
const allModels = collectAllModels(state.config)
|
||||
const fallbacks = allModels.filter(m => m.full !== primary).map(m => m.full)
|
||||
|
||||
const fallbacks = state.config?.agents?.defaults?.model?.fallbacks || []
|
||||
const collapsed = !state.showFallbackEditor
|
||||
const chevron = collapsed ? '▸' : '▾'
|
||||
|
||||
bar.innerHTML = `
|
||||
<div class="config-section" style="margin-bottom:var(--space-lg)">
|
||||
<div class="config-section-title">${t('models.currentConfig')}</div>
|
||||
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap">
|
||||
<div>
|
||||
<span style="font-size:var(--font-size-sm);color:var(--text-tertiary)">${t('models.primaryModelLabel')}</span>
|
||||
<span style="font-family:var(--font-mono);font-size:var(--font-size-sm);color:${primary ? 'var(--success)' : 'var(--error)'}">${primary || t('models.notConfigured')}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style="font-size:var(--font-size-sm);color:var(--text-tertiary)">${t('models.fallbackModels')}</span>
|
||||
<span style="font-size:var(--font-size-sm);color:var(--text-secondary)">${fallbacks.length ? fallbacks.join(', ') : t('models.fallbackNone')}</span>
|
||||
<div class="config-section" style="margin-bottom:var(--space-lg); transition: all 0.3s ease;">
|
||||
<div class="config-section-title" id="system-model-title" style="display:flex; justify-content:space-between; align-items:center; cursor:pointer; user-select:none;">
|
||||
<div style="display:flex; align-items:center; gap:8px">
|
||||
<span style="display:inline-block;width:16px;font-size:12px;color:var(--text-tertiary)">${chevron}</span>
|
||||
<span>系统主/备模型</span>
|
||||
<div style="display:flex; gap:8px; margin-left: 12px; align-items: baseline;">
|
||||
<span style="color:var(--success); font-family:var(--font-mono); font-size: 0.9em; font-weight: 500;">${primary || '未配置'}</span>
|
||||
<span style="font-size: 11px; color: var(--text-tertiary); font-weight: normal;">${fallbacks.length} 个备选</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-hint" style="margin-top:6px">${t('models.fallbackHint')}</div>
|
||||
|
||||
<div id="fallback-waterfall-container" style="display:${state.showFallbackEditor ? 'block' : 'none'}; margin-top: 16px; border-top: 1px dashed var(--border-color); padding-top: 16px;">
|
||||
${renderFallbackWaterfall(state)}
|
||||
</div>
|
||||
|
||||
${collapsed ? '' : `<div class="form-hint" style="margin-top:8px">${t('models.fallbackHint')}</div>`}
|
||||
</div>
|
||||
`
|
||||
|
||||
// 绑定标题点击折叠/展开
|
||||
bar.querySelector('#system-model-title').onclick = () => {
|
||||
state.showFallbackEditor = !state.showFallbackEditor
|
||||
renderDefaultBar(page, state)
|
||||
}
|
||||
|
||||
if (state.showFallbackEditor) {
|
||||
bindWaterfallActions(page, state)
|
||||
}
|
||||
}
|
||||
|
||||
function renderFallbackWaterfall(state) {
|
||||
const primary = getCurrentPrimary(state.config)
|
||||
const allModels = collectAllModels(state.config)
|
||||
const currentFallbacks = state.config?.agents?.defaults?.model?.fallbacks || []
|
||||
|
||||
// 分组候选模型
|
||||
const providers = state.config?.models?.providers || {}
|
||||
const candidatesByProvider = {}
|
||||
Object.keys(providers).forEach(pKey => {
|
||||
const pModels = providers[pKey].models || []
|
||||
const filtered = pModels.map(m => typeof m === 'string' ? m : m.id)
|
||||
.filter(mId => {
|
||||
const full = `${pKey}/${mId}`
|
||||
return full !== primary && !currentFallbacks.includes(full)
|
||||
})
|
||||
if (filtered.length > 0) {
|
||||
candidatesByProvider[pKey] = filtered
|
||||
}
|
||||
})
|
||||
|
||||
if (!state._fallback_candidates_collapsed) state._fallback_candidates_collapsed = {}
|
||||
|
||||
return `
|
||||
<div class="fallback-editor-panel" style="background: var(--bg-secondary); padding: 12px; border-radius: var(--radius-md);">
|
||||
<div style="margin-bottom: 12px; font-size: 11px; color: var(--text-secondary); background: var(--bg-info-subtle); padding: 6px 10px; border-radius: 4px; border-left: 3px solid var(--primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
||||
<strong>💡 最佳实践:</strong> 建议备选模型保持在 <strong>2-3 款</strong> 并分布在不同服务商,以平衡可用性与延迟。
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1.2fr; gap: 24px;">
|
||||
<div>
|
||||
<div style="font-size: var(--font-size-xs); font-weight: bold; margin-bottom: 8px; color: var(--text-tertiary);">当前生效链 (支持拖拽排序)</div>
|
||||
<div id="active-fallback-list" style="display: flex; flex-direction: column; gap: 4px; min-height: 50px;">
|
||||
${currentFallbacks.map((f, i) => `
|
||||
<div class="fallback-chain-item" data-id="${f}" style="display: flex; align-items: center; justify-content: space-between; background: var(--bg-primary); padding: 6px 10px; border-radius: 4px; border: 1px solid var(--border-color);">
|
||||
<div style="display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1;">
|
||||
<span class="fallback-drag-handle" style="color:var(--text-tertiary);cursor:grab;user-select:none;font-size:14px;padding:2px; flex-shrink: 0;">⋮⋮</span>
|
||||
<span style="font-family: var(--font-mono); font-size: var(--font-size-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${i + 1}. ${f}</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 4px; flex-shrink: 0;">
|
||||
<button class="btn btn-xs btn-secondary btn-set-primary-from-fb" data-id="${f}" style="padding: 1px 4px; font-size: 10px;">设为主用</button>
|
||||
<button class="btn-icon btn-remove-fb" data-id="${f}" title="移除">${icon('x', 12)}</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
${currentFallbacks.length === 0 ? `<div style="font-size: 12px; color: var(--text-tertiary); text-align: center; padding: 20px; border: 1px dashed var(--border-color); border-radius: 4px;">尚未选择备选模型</div>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div style="font-size: var(--font-size-xs); font-weight: bold; margin-bottom: 8px; color: var(--text-tertiary);">可用候选池 (按服务商分组)</div>
|
||||
<div id="candidate-model-pool" style="display: flex; flex-direction: column; gap: 6px; max-height: 300px; overflow-y: auto; padding-right: 4px;">
|
||||
${Object.keys(candidatesByProvider).length === 0 ? `<div style="font-size: 12px; color: var(--text-tertiary); text-align: center; padding: 20px;">无可用候选模型</div>` :
|
||||
Object.keys(candidatesByProvider).map(pKey => {
|
||||
const collapsed = !!state._fallback_candidates_collapsed[pKey]
|
||||
const mIds = candidatesByProvider[pKey]
|
||||
return `
|
||||
<div class="candidate-provider-group" data-provider="${pKey}">
|
||||
<div class="candidate-provider-header" style="display: flex; align-items: center; gap: 6px; padding: 4px 8px; background: var(--bg-tertiary); border-radius: 4px; cursor: pointer; font-size: 11px; font-weight: bold; color: var(--text-secondary);">
|
||||
<span class="chevron">${collapsed ? '▸' : '▾'}</span>
|
||||
<span>${pKey}</span>
|
||||
<span style="margin-left: auto; color: var(--text-tertiary); font-weight: normal;">${mIds.length}</span>
|
||||
</div>
|
||||
<div class="candidate-provider-list" style="display: ${collapsed ? 'none' : 'flex'}; flex-direction: column; gap: 4px; padding: 4px 0 4px 12px;">
|
||||
${mIds.map(mId => `
|
||||
<div class="candidate-item" style="display: flex; align-items: center; justify-content: space-between; background: var(--bg-primary); padding: 4px 8px; border-radius: 4px; border: 1px solid var(--border-color); opacity: 0.9;">
|
||||
<span style="font-family: var(--font-mono); font-size: 11px; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${mId}</span>
|
||||
<button class="btn btn-xs btn-primary btn-add-fb" data-full="${pKey}/${mId}" style="padding: 1px 6px; font-size: 10px;">加入</button>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}).join('')
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 16px; display: flex; justify-content: flex-end; gap: 8px;">
|
||||
<button class="btn btn-sm btn-secondary" id="btn-cancel-fallback">取消</button>
|
||||
<button class="btn btn-sm btn-primary" id="btn-save-fallback">保存并应用</button>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
function bindWaterfallActions(page, state) {
|
||||
const container = page.querySelector('#fallback-waterfall-container')
|
||||
|
||||
// 移除
|
||||
container.querySelectorAll('.btn-remove-fb').forEach(btn => {
|
||||
btn.onclick = () => {
|
||||
const id = btn.dataset.id
|
||||
const fallbacks = state.config.agents.defaults.model.fallbacks || []
|
||||
state.config.agents.defaults.model.fallbacks = fallbacks.filter(f => f !== id)
|
||||
renderDefaultBar(page, state)
|
||||
}
|
||||
})
|
||||
|
||||
// 设为主用 (从备选链中提升)
|
||||
container.querySelectorAll('.btn-set-primary-from-fb').forEach(btn => {
|
||||
btn.onclick = () => {
|
||||
const full = btn.dataset.id
|
||||
const oldPrimary = getCurrentPrimary(state.config)
|
||||
const fallbacks = state.config.agents.defaults.model.fallbacks || []
|
||||
|
||||
pushUndo(state)
|
||||
// 1. 设置新主模型
|
||||
setPrimary(state, full)
|
||||
// 2. 将旧主模型放入备选链(原位置或末尾)
|
||||
const newFallbacks = fallbacks.filter(f => f !== full)
|
||||
if (oldPrimary) newFallbacks.push(oldPrimary)
|
||||
state.config.agents.defaults.model.fallbacks = newFallbacks
|
||||
|
||||
renderDefaultBar(page, state)
|
||||
toast(`已将 ${full} 设为主模型`, 'success')
|
||||
}
|
||||
})
|
||||
|
||||
// 加入
|
||||
container.querySelectorAll('.btn-add-fb').forEach(btn => {
|
||||
btn.onclick = () => {
|
||||
const full = btn.dataset.full
|
||||
if (!state.config.agents.defaults.model.fallbacks) state.config.agents.defaults.model.fallbacks = []
|
||||
state.config.agents.defaults.model.fallbacks.push(full)
|
||||
renderDefaultBar(page, state)
|
||||
}
|
||||
})
|
||||
|
||||
// 折叠候选服务商
|
||||
container.querySelectorAll('.candidate-provider-header').forEach(header => {
|
||||
header.onclick = () => {
|
||||
const group = header.closest('.candidate-provider-group')
|
||||
const pKey = group.dataset.provider
|
||||
state._fallback_candidates_collapsed[pKey] = !state._fallback_candidates_collapsed[pKey]
|
||||
renderDefaultBar(page, state)
|
||||
}
|
||||
})
|
||||
|
||||
// 拖拽排序逻辑 (适配当前列表)
|
||||
const chainContainer = container.querySelector('#active-fallback-list')
|
||||
if (chainContainer && state.config.agents.defaults.model.fallbacks?.length > 1) {
|
||||
let dragged = null
|
||||
let placeholder = null
|
||||
let startY = 0
|
||||
|
||||
chainContainer.addEventListener('pointerdown', e => {
|
||||
const handle = e.target.closest('.fallback-drag-handle')
|
||||
if (!handle) return
|
||||
const item = handle.closest('.fallback-chain-item')
|
||||
if (!item) return
|
||||
|
||||
e.preventDefault()
|
||||
dragged = item
|
||||
startY = e.clientY
|
||||
|
||||
placeholder = document.createElement('div')
|
||||
placeholder.style.cssText = `height:${item.offsetHeight}px;border:1px dashed var(--primary);border-radius:4px;margin-bottom:4px;background:var(--bg-tertiary)`
|
||||
item.after(placeholder)
|
||||
|
||||
const rect = item.getBoundingClientRect()
|
||||
item.style.position = 'fixed'
|
||||
item.style.left = rect.left + 'px'
|
||||
item.style.top = rect.top + 'px'
|
||||
item.style.width = rect.width + 'px'
|
||||
item.style.zIndex = '10000'
|
||||
item.style.opacity = '0.9'
|
||||
item.style.pointerEvents = 'none'
|
||||
item.setPointerCapture(e.pointerId)
|
||||
})
|
||||
|
||||
chainContainer.addEventListener('pointermove', e => {
|
||||
if (!dragged || !placeholder) return
|
||||
e.preventDefault()
|
||||
|
||||
const dy = e.clientY - startY
|
||||
itemMove(dragged, dy)
|
||||
startY = e.clientY
|
||||
|
||||
const siblings = [...chainContainer.querySelectorAll('.fallback-chain-item:not([style*="position: fixed"])')]
|
||||
for (const sibling of siblings) {
|
||||
const rect = sibling.getBoundingClientRect()
|
||||
if (e.clientY < rect.top + rect.height / 2) {
|
||||
sibling.before(placeholder)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (siblings.length) siblings[siblings.length - 1].after(placeholder)
|
||||
})
|
||||
|
||||
function itemMove(el, dy) {
|
||||
const top = parseFloat(el.style.top)
|
||||
el.style.top = (top + dy) + 'px'
|
||||
}
|
||||
|
||||
chainContainer.addEventListener('pointerup', e => {
|
||||
if (!dragged || !placeholder) return
|
||||
|
||||
dragged.style.position = ''
|
||||
dragged.style.left = ''
|
||||
dragged.style.top = ''
|
||||
dragged.style.width = ''
|
||||
dragged.style.zIndex = ''
|
||||
dragged.style.opacity = ''
|
||||
dragged.style.pointerEvents = ''
|
||||
|
||||
placeholder.before(dragged)
|
||||
placeholder.remove()
|
||||
|
||||
// 更新顺序
|
||||
const newOrderIds = [...chainContainer.querySelectorAll('.fallback-chain-item')].map(el => el.dataset.id)
|
||||
state.config.agents.defaults.model.fallbacks = newOrderIds
|
||||
|
||||
dragged = null
|
||||
placeholder = null
|
||||
renderDefaultBar(page, state) // 刷新索引数字
|
||||
})
|
||||
}
|
||||
|
||||
// 取消
|
||||
container.querySelector('#btn-cancel-fallback').onclick = async () => {
|
||||
state.showFallbackEditor = false
|
||||
loadConfig(page, state)
|
||||
}
|
||||
|
||||
// 保存
|
||||
container.querySelector('#btn-save-fallback').onclick = async () => {
|
||||
state.showFallbackEditor = false
|
||||
await doAutoSave(state)
|
||||
renderDefaultBar(page, state)
|
||||
}
|
||||
}
|
||||
|
||||
// 排序模型列表
|
||||
@@ -189,7 +437,7 @@ function sortModels(models, sortBy) {
|
||||
return sorted
|
||||
}
|
||||
|
||||
// 渲染服务商列表(渲染完后直接绑定事件)
|
||||
// 渲染服务商列表(渲染完后直接绑定事件)
|
||||
function renderProviders(page, state) {
|
||||
const listEl = page.querySelector('#providers-list')
|
||||
const providers = state.config?.models?.providers || {}
|
||||
@@ -262,11 +510,11 @@ function renderProviders(page, state) {
|
||||
`
|
||||
}).join('')
|
||||
|
||||
// innerHTML 完成后,直接给每个按钮绑定 onclick
|
||||
// innerHTML 完成后,直接给每个按钮绑定 onclick
|
||||
bindProviderButtons(listEl, page, state)
|
||||
}
|
||||
|
||||
// 渲染模型卡片(支持搜索高亮和批量选择 checkbox)
|
||||
// 渲染模型卡片(支持搜索高亮和批量选择 checkbox)
|
||||
function renderModelCards(providerKey, models, primary, search) {
|
||||
if (!models.length) {
|
||||
return `<div style="color:var(--text-tertiary);font-size:var(--font-size-sm);padding:8px 0">${t('models.noModel')}</div>`
|
||||
@@ -281,7 +529,7 @@ function renderModelCards(providerKey, models, primary, search) {
|
||||
const meta = []
|
||||
if (name !== id) meta.push(name)
|
||||
if (m.contextWindow) meta.push((m.contextWindow / 1000) + 'K ' + t('models.context'))
|
||||
// 测试状态标签:成功显示耗时,失败显示不可用
|
||||
// 测试状态标签:成功显示耗时,失败显示不可用
|
||||
let latencyTag = ''
|
||||
if (m.testStatus === 'fail') {
|
||||
latencyTag = `<span style="font-size:var(--font-size-xs);padding:1px 6px;border-radius:var(--radius-sm);background:var(--error-muted, #fee2e2);color:var(--error)" title="${(m.testError || '').replace(/"/g, '"')}">${t('models.unavailable')}</span>`
|
||||
@@ -334,7 +582,7 @@ function findModelIdx(provider, modelId) {
|
||||
|
||||
// ===== 自动保存 + 撤销机制 =====
|
||||
|
||||
// 保存快照到撤销栈(变更前调用)
|
||||
// 保存快照到撤销栈(变更前调用)
|
||||
function pushUndo(state) {
|
||||
state.undoStack.push(JSON.parse(JSON.stringify(state.config)))
|
||||
if (state.undoStack.length > 20) state.undoStack.shift()
|
||||
@@ -351,7 +599,7 @@ async function undo(page, state) {
|
||||
toast(t('models.undone'), 'info')
|
||||
}
|
||||
|
||||
// 自动保存(防抖 300ms)
|
||||
// 自动保存(防抖 300ms)
|
||||
let _saveTimer = null
|
||||
let _batchTestAbort = null // 批量测试终止控制器
|
||||
|
||||
@@ -365,7 +613,7 @@ function autoSave(state) {
|
||||
_saveTimer = setTimeout(() => doAutoSave(state), 300)
|
||||
}
|
||||
|
||||
/** 已知的 API 类型错误→正确映射,自动修复用户手动编辑或旧版本配置 */
|
||||
/** 已知的 API 类型错误→正确映射,自动修复用户手动编辑或旧版本配置 */
|
||||
const API_TYPE_FIXES = {
|
||||
'google-gemini': 'google-generative-ai',
|
||||
'gemini': 'google-generative-ai',
|
||||
@@ -376,7 +624,7 @@ const API_TYPE_FIXES = {
|
||||
}
|
||||
const VALID_API_TYPES = new Set(API_TYPES.map(t => t.value))
|
||||
|
||||
/** 保存前规范化所有服务商的 baseUrl 和 API 类型,确保 Gateway 能正确调用 */
|
||||
/** 保存前规范化所有服务商的 baseUrl 和 API 类型,确保 Gateway 能正确调用 */
|
||||
function normalizeProviderUrls(config) {
|
||||
const providers = config?.models?.providers
|
||||
if (!providers) return
|
||||
@@ -387,14 +635,14 @@ function normalizeProviderUrls(config) {
|
||||
if (API_TYPE_FIXES[lower]) {
|
||||
p.api = API_TYPE_FIXES[lower]
|
||||
} else if (!VALID_API_TYPES.has(lower)) {
|
||||
console.warn(`[models] 未知 API 类型「${p.api}」,自动修正为 openai-completions`)
|
||||
console.warn(`[models] 未知 API 类型「${p.api}」,自动修正为 openai-completions`)
|
||||
p.api = 'openai-completions'
|
||||
}
|
||||
}
|
||||
|
||||
if (!p.baseUrl) continue
|
||||
let url = p.baseUrl.replace(/\/+$/, '')
|
||||
// 去掉尾部的已知端点路径(用户可能粘贴了完整 URL)
|
||||
// 去掉尾部的已知端点路径(用户可能粘贴了完整 URL)
|
||||
for (const suffix of ['/api/chat', '/api/generate', '/api/tags', '/api', '/chat/completions', '/completions', '/responses', '/messages', '/models']) {
|
||||
if (url.endsWith(suffix)) { url = url.slice(0, -suffix.length); break }
|
||||
}
|
||||
@@ -403,15 +651,15 @@ function normalizeProviderUrls(config) {
|
||||
if (apiType === 'anthropic-messages') {
|
||||
if (!url.endsWith('/v1')) url += '/v1'
|
||||
} else if (apiType !== 'google-generative-ai' && apiType !== 'ollama') {
|
||||
// Ollama OpenAI 兼容模式端口检测:11434 默认需要加 /v1(ollama 原生 API 不需要)
|
||||
// Ollama OpenAI 兼容模式端口检测:11434 默认需要加 /v1(ollama 原生 API 不需要)
|
||||
if (/:11434$/.test(url) && !url.endsWith('/v1')) url += '/v1'
|
||||
// 不再强制追加 /v1,尊重用户填写的 URL(火山引擎等第三方用 /v3 等路径)
|
||||
// 不再强制追加 /v1,尊重用户填写的 URL(火山引擎等第三方用 /v3 等路径)
|
||||
}
|
||||
p.baseUrl = url
|
||||
}
|
||||
}
|
||||
|
||||
// 仅保存配置,不重启 Gateway(用于测试结果等元数据持久化)
|
||||
// 仅保存配置,不重启 Gateway(用于测试结果等元数据持久化)
|
||||
async function saveConfigOnly(state) {
|
||||
try {
|
||||
const primary = getCurrentPrimary(state.config)
|
||||
@@ -430,7 +678,7 @@ async function doAutoSave(state) {
|
||||
normalizeProviderUrls(state.config)
|
||||
await api.writeOpenclawConfig(state.config)
|
||||
|
||||
// 重启 Gateway 使配置生效(Gateway 不支持 SIGHUP 热重载)
|
||||
// 重启 Gateway 使配置生效(Gateway 不支持 SIGHUP 热重载)
|
||||
toast(t('models.configSavedRestarting'), 'info')
|
||||
try {
|
||||
await api.restartGateway()
|
||||
@@ -466,7 +714,7 @@ function updateUndoBtn(page, state) {
|
||||
btn.textContent = n ? t('models.undoN', { n }) : t('models.undo')
|
||||
}
|
||||
|
||||
// 渲染完成后,直接给每个 [data-action] 按钮绑定 onclick
|
||||
// 渲染完成后,直接给每个 [data-action] 按钮绑定 onclick
|
||||
function bindProviderButtons(listEl, page, state) {
|
||||
// 绑定排序下拉框
|
||||
listEl.querySelectorAll('select[data-action="sort-models"]').forEach(select => {
|
||||
@@ -484,7 +732,7 @@ function bindProviderButtons(listEl, page, state) {
|
||||
// 将排序固化到底层数据并保存
|
||||
pushUndo(state)
|
||||
provider.models = sortModels(provider.models, val)
|
||||
// 恢复下拉框显示 "默认顺序",因为新顺序已经变成了默认顺序
|
||||
// 恢复下拉框显示 "默认顺序",因为新顺序已经变成了默认顺序
|
||||
state.sortBy = 'default'
|
||||
renderProviders(page, state)
|
||||
autoSave(state)
|
||||
@@ -493,7 +741,7 @@ function bindProviderButtons(listEl, page, state) {
|
||||
}
|
||||
})
|
||||
|
||||
// 绑定拖拽排序(Pointer 事件实现,兼容 Tauri WebView2/WKWebView)
|
||||
// 绑定拖拽排序(Pointer 事件实现,兼容 Tauri WebView2/WKWebView)
|
||||
listEl.querySelectorAll('.provider-models').forEach(container => {
|
||||
let dragged = null
|
||||
let placeholder = null
|
||||
@@ -609,7 +857,7 @@ function bindProviderButtons(listEl, page, state) {
|
||||
if (!provider) return
|
||||
const card = btn.closest('.model-card')
|
||||
|
||||
// checkbox 改变时不需要阻止冒泡,由 handleAction 内部处理
|
||||
// checkbox 改变时不需要阻止冒泡,由 handleAction 内部处理
|
||||
if (btn.type === 'checkbox') {
|
||||
btn.onchange = (e) => {
|
||||
handleAction(action, btn, card, section, providerKey, provider, page, state)
|
||||
@@ -697,7 +945,7 @@ async function handleAction(action, btn, card, section, providerKey, provider, p
|
||||
}
|
||||
}
|
||||
|
||||
// 设置主模型(仅修改 state,不写入文件)
|
||||
// 设置主模型(仅修改 state,不写入文件)
|
||||
function setPrimary(state, full) {
|
||||
if (!state.config.agents) state.config.agents = {}
|
||||
if (!state.config.agents.defaults) state.config.agents.defaults = {}
|
||||
@@ -705,13 +953,13 @@ function setPrimary(state, full) {
|
||||
state.config.agents.defaults.model.primary = full
|
||||
}
|
||||
|
||||
// 应用默认模型:primary + 其余自动成为备选
|
||||
// 确保 primary 指向的模型仍然存在,不存在则自动切到第一个可用模型
|
||||
// 应用默认模型:primary + 其余自动成为备选
|
||||
// 确保 primary 指向的模型仍然存在,不存在则自动切到第一个可用模型
|
||||
function ensureValidPrimary(state) {
|
||||
const primary = getCurrentPrimary(state.config)
|
||||
const allModels = collectAllModels(state.config)
|
||||
if (allModels.length === 0) {
|
||||
// 所有模型都没了,清空 primary
|
||||
// 所有模型都没了,清空 primary
|
||||
if (state.config.agents?.defaults?.model) {
|
||||
state.config.agents.defaults.model.primary = ''
|
||||
}
|
||||
@@ -719,7 +967,7 @@ function ensureValidPrimary(state) {
|
||||
}
|
||||
const exists = allModels.some(m => m.full === primary)
|
||||
if (!exists) {
|
||||
// primary 指向已删除的模型,自动切到第一个
|
||||
// primary 指向已删除的模型,自动切到第一个
|
||||
const newPrimary = allModels[0].full
|
||||
setPrimary(state, newPrimary)
|
||||
toast(t('models.primaryAutoSwitch', { model: newPrimary }), 'info')
|
||||
@@ -734,8 +982,8 @@ function applyDefaultModel(state) {
|
||||
if (!defaults.model) defaults.model = {}
|
||||
defaults.model.primary = primary
|
||||
|
||||
// fallbacks / models 仅在为空时初始化(首次安装友好),不再每次保存都覆盖
|
||||
// 避免用户精心维护的精简 fallback 链被重写,且随模型增多不断膨胀 (fixes #190)
|
||||
// fallbacks / models 仅在为空时初始化(首次安装友好),不再每次保存都覆盖
|
||||
// 避免用户精心维护的精简 fallback 链被重写,且随模型增多不断膨胀 (fixes #190)
|
||||
if (!defaults.model.fallbacks || defaults.model.fallbacks.length === 0) {
|
||||
const allModels = collectAllModels(state.config)
|
||||
defaults.model.fallbacks = allModels.filter(m => m.full !== primary).map(m => m.full)
|
||||
@@ -748,9 +996,9 @@ function applyDefaultModel(state) {
|
||||
defaults.models = modelsMap
|
||||
}
|
||||
|
||||
// 注意:不再强制同步到各 agent 的 model.primary
|
||||
// 子 Agent 的模型覆盖是 OpenClaw 正常功能(用户可通过对话为不同 Agent 设置不同模型)
|
||||
// 强制覆盖会导致 #142:重开 ClawPanel 后子 Agent 模型配置被重置
|
||||
// 注意:不再强制同步到各 agent 的 model.primary
|
||||
// 子 Agent 的模型覆盖是 OpenClaw 正常功能(用户可通过对话为不同 Agent 设置不同模型)
|
||||
// 强制覆盖会导致 #142:重开 ClawPanel 后子 Agent 模型配置被重置
|
||||
}
|
||||
|
||||
// 顶部按钮事件
|
||||
@@ -758,7 +1006,7 @@ function bindTopActions(page, state) {
|
||||
page.querySelector('#btn-add-provider').onclick = () => addProvider(page, state)
|
||||
page.querySelector('#btn-undo').onclick = () => undo(page, state)
|
||||
|
||||
// 晴辰云:获取模型列表 → 弹窗让用户选择要添加的模型
|
||||
// 晴辰云:获取模型列表 → 弹窗让用户选择要添加的模型
|
||||
page.querySelector('#btn-qtcool-oneclick').onclick = async () => {
|
||||
if (!state.config) { toast(t('models.configNotReady'), 'warning'); return }
|
||||
|
||||
@@ -873,7 +1121,7 @@ function bindTopActions(page, state) {
|
||||
}
|
||||
}
|
||||
|
||||
// 添加服务商(带预设快捷选择)
|
||||
// 添加服务商(带预设快捷选择)
|
||||
function addProvider(page, state) {
|
||||
// 构建预设按钮 HTML
|
||||
const presetsHtml = PROVIDER_PRESETS.filter(p => !p.hidden).map(p =>
|
||||
@@ -933,7 +1181,7 @@ function addProvider(page, state) {
|
||||
// 高亮选中的预设
|
||||
overlay.querySelectorAll('.preset-btn').forEach(b => b.style.opacity = '0.5')
|
||||
btn.style.opacity = '1'
|
||||
// 显示服务商详情(官网、描述)
|
||||
// 显示服务商详情(官网、描述)
|
||||
const detailEl = overlay.querySelector('#preset-detail')
|
||||
if (detailEl) {
|
||||
if (preset.desc || preset.site) {
|
||||
@@ -1003,7 +1251,7 @@ function editProvider(page, state, providerKey) {
|
||||
})
|
||||
}
|
||||
|
||||
// 添加模型(带预设快捷选择)
|
||||
// 添加模型(带预设快捷选择)
|
||||
function addModel(page, state, providerKey) {
|
||||
const presets = MODEL_PRESETS[providerKey] || []
|
||||
const existingIds = (state.config.models.providers[providerKey].models || [])
|
||||
@@ -1020,7 +1268,7 @@ function addModel(page, state, providerKey) {
|
||||
]
|
||||
|
||||
if (available.length) {
|
||||
// 有预设可用,构建自定义弹窗
|
||||
// 有预设可用,构建自定义弹窗
|
||||
const overlay = document.createElement('div')
|
||||
overlay.className = 'modal-overlay'
|
||||
|
||||
@@ -1058,7 +1306,7 @@ function addModel(page, state, providerKey) {
|
||||
autoSave(state)
|
||||
})
|
||||
|
||||
// 预设按钮:点击直接添加
|
||||
// 预设按钮:点击直接添加
|
||||
overlay.querySelectorAll('.preset-btn').forEach(btn => {
|
||||
btn.onclick = () => {
|
||||
const preset = available.find(p => p.id === btn.dataset.mid)
|
||||
@@ -1075,7 +1323,7 @@ function addModel(page, state, providerKey) {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 无预设,直接弹普通 modal
|
||||
// 无预设,直接弹普通 modal
|
||||
showModal({
|
||||
title: t('models.addModelTitle', { provider: providerKey }),
|
||||
fields,
|
||||
@@ -1091,7 +1339,7 @@ function addModel(page, state, providerKey) {
|
||||
}
|
||||
}
|
||||
|
||||
// 构建表单字段 HTML(用于自定义弹窗)
|
||||
// 构建表单字段 HTML(用于自定义弹窗)
|
||||
function buildFieldsHtml(fields) {
|
||||
return fields.map(f => {
|
||||
if (f.type === 'checkbox') {
|
||||
@@ -1198,9 +1446,9 @@ async function handleBatchDelete(section, page, state, providerKey) {
|
||||
toast(t('models.batchDeleted', { count: ids.length }), 'info')
|
||||
}
|
||||
|
||||
// 批量测试:勾选的模型,没勾选则测试全部(记录耗时和状态)
|
||||
// 批量测试:勾选的模型,没勾选则测试全部(记录耗时和状态)
|
||||
async function handleBatchTest(section, state, providerKey) {
|
||||
// 如果正在测试,点击则终止
|
||||
// 如果正在测试,点击则终止
|
||||
if (_batchTestAbort) {
|
||||
_batchTestAbort.abort = true
|
||||
toast(t('models.stoppingBatchTest'), 'warning')
|
||||
@@ -1269,7 +1517,7 @@ async function handleBatchTest(section, state, providerKey) {
|
||||
|
||||
// 恢复按钮
|
||||
_batchTestAbort = null
|
||||
// 重新查找按钮(renderProviders 后 DOM 已更新)
|
||||
// 重新查找按钮(renderProviders 后 DOM 已更新)
|
||||
const newSection = page?.querySelector(`[data-provider="${providerKey}"]`)
|
||||
const newBtn = newSection?.querySelector('[data-action="batch-test"]')
|
||||
if (newBtn) {
|
||||
@@ -1382,7 +1630,7 @@ async function fetchRemoteModels(btn, page, state, providerKey) {
|
||||
}
|
||||
}
|
||||
|
||||
// 测试模型连通性(记录耗时和状态)
|
||||
// 测试模型连通性(记录耗时和状态)
|
||||
async function testModel(btn, state, providerKey, idx) {
|
||||
const provider = state.config.models.providers[providerKey]
|
||||
const model = provider.models[idx]
|
||||
@@ -1403,13 +1651,13 @@ async function testModel(btn, state, providerKey, idx) {
|
||||
model.testStatus = 'ok'
|
||||
delete model.testError
|
||||
}
|
||||
// 包含 ⚠ 的是非致命错误(429 等),拆分显示
|
||||
// 包含 ⚠ 的是非致命错误(429 等),拆分显示
|
||||
if (reply.startsWith('⚠')) {
|
||||
const lines = reply.split('\n')
|
||||
const summary = lines[0]
|
||||
const detail = lines.slice(1).join('\n').trim()
|
||||
if (detail) {
|
||||
const detailHtml = detail.replace(/</g, '<').replace(/(https?:\/\/[^\s,,。;))'"&]+)/g, '<a href="$1" target="_blank" style="color:var(--primary);text-decoration:underline">$1</a>')
|
||||
const detailHtml = detail.replace(/</g, '<').replace(/(https?:\/\/[^\s,,。;))'"&]+)/g, '<a href="$1" target="_blank" style="color:var(--primary);text-decoration:underline">$1</a>')
|
||||
toast(`<strong>${modelId}</strong> ${summary.replace(/</g, '<')}<br><span style="font-size:11px;line-height:1.5;word-break:break-all">${detailHtml}</span>`, 'warning', { duration: 10000, html: true })
|
||||
} else {
|
||||
toast(`${modelId} ${summary}`, 'warning', { duration: 6000 })
|
||||
@@ -1435,7 +1683,7 @@ async function testModel(btn, state, providerKey, idx) {
|
||||
renderProviders(page, state)
|
||||
renderDefaultBar(page, state)
|
||||
}
|
||||
// 持久化测试结果(仅保存,不重启 Gateway)
|
||||
// 持久化测试结果(仅保存,不重启 Gateway)
|
||||
saveConfigOnly(state)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user