diff --git a/Cargo.lock b/Cargo.lock
index a7de0d5..be96ebf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -32,6 +32,8 @@ dependencies = [
"tokio-util",
"tower-cookies",
"tower-http 0.5.2",
+ "tracing",
+ "tracing-subscriber",
"uuid",
]
@@ -128,9 +130,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.103"
+version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "arbitrary"
@@ -140,9 +142,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
[[package]]
name = "arc-swap"
-version = "1.9.2"
+version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b"
+checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207"
dependencies = [
"rustversion",
]
@@ -161,9 +163,9 @@ dependencies = [
[[package]]
name = "arrayvec"
-version = "0.7.8"
+version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
+checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe"
[[package]]
name = "async-stream"
@@ -554,9 +556,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.66"
+version = "1.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996"
+checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -589,9 +591,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chacha20"
-version = "0.10.1"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81"
+checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
@@ -1422,9 +1424,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"r-efi 5.3.0",
"wasip2",
+ "wasm-bindgen",
]
[[package]]
@@ -1434,11 +1438,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [
"cfg-if",
- "js-sys",
"libc",
"r-efi 6.0.0",
"rand_core 0.10.1",
- "wasm-bindgen",
]
[[package]]
@@ -1602,9 +1604,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hybrid-array"
-version = "0.4.13"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c"
+checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da"
dependencies = [
"typenum",
]
@@ -1953,9 +1955,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.103"
+version = "0.3.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
+checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
dependencies = [
"cfg-if",
"futures-util",
@@ -1994,9 +1996,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
-version = "0.1.18"
+version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652"
+checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@@ -2246,12 +2248,14 @@ dependencies = [
[[package]]
name = "omniference"
-version = "0.2.1"
+version = "0.3.0"
+source = "git+https://github.com/Henrik-3/omniference.git?rev=fd69edd438430d68f9b81b5570033b12d33a4fd2#fd69edd438430d68f9b81b5570033b12d33a4fd2"
dependencies = [
"anyhow",
"async-stream",
"async-trait",
"axum 0.7.9",
+ "base64",
"bytes",
"dotenvy",
"futures",
@@ -2454,7 +2458,7 @@ dependencies = [
"hmac",
"md-5",
"memchr",
- "rand 0.10.2",
+ "rand 0.10.1",
"sha2 0.11.0",
"stringprep",
]
@@ -2611,15 +2615,14 @@ dependencies = [
[[package]]
name = "quinn-proto"
-version = "0.11.16"
+version = "0.11.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560"
+checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"
dependencies = [
"bytes",
- "getrandom 0.4.3",
+ "getrandom 0.3.4",
"lru-slab",
- "rand 0.10.2",
- "rand_pcg",
+ "rand 0.9.4",
"ring",
"rustc-hash",
"rustls",
@@ -2633,16 +2636,16 @@ dependencies = [
[[package]]
name = "quinn-udp"
-version = "0.5.15"
+version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694"
+checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
dependencies = [
"cfg_aliases",
"libc",
"once_cell",
"socket2",
"tracing",
- "windows-sys 0.61.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -2679,15 +2682,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
dependencies = [
"libc",
- "rand_chacha",
+ "rand_chacha 0.3.1",
"rand_core 0.6.4",
]
[[package]]
name = "rand"
-version = "0.10.2"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
+checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
dependencies = [
"chacha20",
"getrandom 0.4.3",
@@ -2704,6 +2717,16 @@ dependencies = [
"rand_core 0.6.4",
]
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
[[package]]
name = "rand_core"
version = "0.6.4"
@@ -2715,18 +2738,18 @@ dependencies = [
[[package]]
name = "rand_core"
-version = "0.10.1"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
[[package]]
-name = "rand_pcg"
-version = "0.10.2"
+name = "rand_core"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a"
-dependencies = [
- "rand_core 0.10.1",
-]
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rand_xoshiro"
@@ -2965,9 +2988,9 @@ checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]]
name = "rustc-hash"
-version = "2.1.3"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
+checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
[[package]]
name = "rustix"
@@ -3022,9 +3045,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.15.0"
+version = "1.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046"
+checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
dependencies = [
"web-time",
"zeroize",
@@ -3461,7 +3484,7 @@ dependencies = [
"log",
"md-5",
"memchr",
- "rand 0.10.2",
+ "rand 0.10.1",
"rust_decimal",
"serde",
"serde_json",
@@ -3688,9 +3711,9 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.53"
+version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
+checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327"
dependencies = [
"deranged",
"num-conv",
@@ -3708,9 +3731,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
[[package]]
name = "time-macros"
-version = "0.2.31"
+version = "0.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f"
+checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935"
dependencies = [
"num-conv",
"time-core",
@@ -4205,9 +4228,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "uuid"
-version = "1.23.4"
+version = "1.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53"
+checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7"
dependencies = [
"getrandom 0.4.3",
"js-sys",
@@ -4285,9 +4308,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
-version = "0.2.126"
+version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
+checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
dependencies = [
"cfg-if",
"once_cell",
@@ -4299,9 +4322,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.76"
+version = "0.4.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d"
+checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4309,9 +4332,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.126"
+version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
+checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -4319,9 +4342,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.126"
+version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
+checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -4332,9 +4355,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.126"
+version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
+checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
dependencies = [
"unicode-ident",
]
@@ -4718,9 +4741,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.103"
+version = "0.3.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
+checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -5219,3 +5242,7 @@ dependencies = [
"cc",
"pkg-config",
]
+
+[[patch.unused]]
+name = "omniference"
+version = "0.3.0"
diff --git a/Cargo.toml b/Cargo.toml
index 21166cd..e25fc3e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,7 +37,7 @@ reqwest = { version = "0.12", default-features = false, features = [
"multipart",
] }
tower-http = { version = "0.5", features = ["cors"] }
-omniference = "0.2"
+omniference = { git = "https://github.com/Henrik-3/omniference.git", rev = "fd69edd438430d68f9b81b5570033b12d33a4fd2" }
aes-gcm = "0.10"
rand = "0.8"
rust_decimal = { version = "1.39.0", features = ["db-postgres", "serde"] }
@@ -45,6 +45,8 @@ futures-util = "0.3.31"
async-stream = "0.3.6"
tokio-util = "0.7.17"
extism = "1"
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter"] }
sha2 = "0.10"
base64 = "0.22"
thiserror = "2"
diff --git a/frontend/components/AppSidebar.vue b/frontend/components/AppSidebar.vue
index 984d1bb..dc3c342 100644
--- a/frontend/components/AppSidebar.vue
+++ b/frontend/components/AppSidebar.vue
@@ -113,6 +113,7 @@ const store = useMainStore();
const chatStore = useChatStore();
const budgetStore = useBudgetStore();
const router = useRouter();
+const route = useRoute();
const showWorkspaceManager = ref(false);
@@ -122,6 +123,7 @@ const userInitials = computed(() => {
});
function goToSettings() {
+ store.settingsReturnPath = route.path.startsWith('/chats/') ? route.fullPath : '/';
router.push('/settings');
}
diff --git a/frontend/components/chat/MessageItem.vue b/frontend/components/chat/MessageItem.vue
index 69f87bf..40f29da 100644
--- a/frontend/components/chat/MessageItem.vue
+++ b/frontend/components/chat/MessageItem.vue
@@ -11,7 +11,7 @@
@@ -21,7 +21,7 @@
-
+
@@ -31,7 +31,53 @@
-
+
+
+
+
+
+ {{ store.getTranslation('chat.message_item.reasoning') }}
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
-
+
@@ -224,8 +270,8 @@ const attachedImages = computed(() => {
return [];
}
return props.message.content_parts
- .filter((part: any) => part.type === 'image' && part.image_id)
- .map((part: any) => ({
+ .filter(part => part.type === 'image')
+ .map(part => ({
image_id: part.image_id,
url: `/api/v1/images/${part.image_id}`,
}));
@@ -281,6 +327,55 @@ const renderedContent = computed(() => {
return renderComplete(props.message.content);
});
+const hasInterleavedParts = computed(() => {
+ if (isUser.value) return false;
+ const parts = props.message.content_parts;
+ return Array.isArray(parts) && parts.some(p => p.type === 'tool_call');
+});
+
+const partHtmlCache = new Map
();
+
+const orderedParts = computed(() => {
+ const parts = props.message.content_parts;
+ if (!Array.isArray(parts)) return [];
+ return parts.filter(part => part.type !== 'tool_result').map((part, index) => {
+ if (part.type === 'tool_call') {
+ const tool = props.message.tool_calls?.find(tc => tc.tool_call_id === part.id);
+ return {type: 'tool_call' as const, tool};
+ }
+ if (part.type === 'image') {
+ return {
+ type: 'image' as const,
+ imageId: part.image_id,
+ url: `/api/v1/images/${encodeURIComponent(part.image_id)}`,
+ };
+ }
+ if (part.type === 'reasoning') {
+ const text = part.text;
+ const cached = partHtmlCache.get(index);
+ const html = cached?.text === text && cached.streaming === isStreaming.value ? cached.html : isStreaming.value ? renderStreaming(text) : renderComplete(text);
+ partHtmlCache.set(index, {text, streaming: isStreaming.value, html});
+ return {type: 'reasoning' as const, html};
+ }
+ const text = part.text;
+ const cached = partHtmlCache.get(index);
+ const html = cached?.text === text && cached.streaming === isStreaming.value ? cached.html : isStreaming.value ? renderStreaming(text) : renderComplete(text);
+ partHtmlCache.set(index, {text, streaming: isStreaming.value, html});
+ return {type: 'text' as const, html};
+ });
+});
+
+const reasoningToggles = ref>({});
+
+function isReasoningOpen(idx: number): boolean {
+ if (idx in reasoningToggles.value) return reasoningToggles.value[idx];
+ return isStreaming.value && idx === orderedParts.value.length - 1;
+}
+
+function toggleReasoning(idx: number) {
+ reasoningToggles.value[idx] = !isReasoningOpen(idx);
+}
+
const renderedReasoning = computed(() => {
if (!props.message.reasoning_content) return '';
diff --git a/frontend/components/chat/ToolExecutionDisplay.vue b/frontend/components/chat/ToolExecutionDisplay.vue
index 1d407f8..f777255 100644
--- a/frontend/components/chat/ToolExecutionDisplay.vue
+++ b/frontend/components/chat/ToolExecutionDisplay.vue
@@ -131,6 +131,9 @@ function isValidImageProtocol(url: string): boolean {
const imageUrl = computed(() => {
if (!props.output) return null;
const out = typeof props.output === 'string' ? tryParseJson(props.output) : props.output;
+ if (out?.image_id && typeof out.image_id === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(out.image_id)) {
+ return `/api/v1/images/${encodeURIComponent(out.image_id)}`;
+ }
if (out?.image_url && isValidImageProtocol(out.image_url)) return out.image_url;
if (out?.image_reference && isValidImageProtocol(out.image_reference)) return out.image_reference;
if (out?.url && isImageUrl(out.url)) return out.url;
diff --git a/frontend/components/settings/DefaultModelPicker.vue b/frontend/components/settings/DefaultModelPicker.vue
index 3f1f5c7..a157cf9 100644
--- a/frontend/components/settings/DefaultModelPicker.vue
+++ b/frontend/components/settings/DefaultModelPicker.vue
@@ -3,7 +3,7 @@
@@ -131,17 +131,23 @@ import {Bot, ChevronDown, Check, Loader2, Search, X} from 'lucide-vue-next';
import {useMainStore} from '~/stores';
import {useModelPicker} from '~/composables/useModelPicker';
import {Popover, PopoverContent, PopoverTrigger} from '~/components/ui/popover';
-import type {ModelList} from '~/types/chat';
+import type {ModelList, PaginatedResponse} from '~/types/chat';
const props = withDefaults(defineProps<{
modelValue: string | null;
endpoint?: string;
+ providerEndpoint?: string;
+ selectedModelEndpoint?: string;
disabled?: boolean;
placeholder?: string;
+ valueMode?: 'model_id' | 'uuid';
}>(), {
endpoint: '/api/v1/models',
+ providerEndpoint: undefined,
+ selectedModelEndpoint: undefined,
disabled: false,
placeholder: undefined,
+ valueMode: 'model_id',
});
const emit = defineEmits<{
@@ -166,20 +172,42 @@ const {
onSearchInput: pickerOnSearch,
selectFilter: pickerSelectFilter,
init: pickerInit,
-} = useModelPicker({endpoint: props.endpoint});
+} = useModelPicker({endpoint: props.endpoint, providerEndpoint: props.providerEndpoint});
const scrollContainer = ref(null);
const sentinel = ref(null);
let observer: IntersectionObserver | null = null;
-
-const selectedModel = computed(() => {
- if (!props.modelValue) return null;
- return pickerModels.value.find(m => m.model_id === props.modelValue) ?? null;
-});
+const selectedModel = ref(null);
+
+watch(
+ () => props.modelValue,
+ async value => {
+ if (!value) {
+ selectedModel.value = null;
+ return;
+ }
+ const loaded = pickerModels.value.find(model => modelValueFor(model) === value);
+ if (loaded) {
+ selectedModel.value = loaded;
+ return;
+ }
+ try {
+ const {$customFetch} = useNuxtApp();
+ const model = props.valueMode === 'uuid' && props.selectedModelEndpoint
+ ? await $customFetch(`${props.selectedModelEndpoint}/${value}`)
+ : (await $customFetch>(props.endpoint, {params: {query: value, size: '50'}})).items.find(item => modelValueFor(item) === value) ?? null;
+ if (props.modelValue === value) selectedModel.value = model;
+ } catch {
+ if (props.modelValue === value) selectedModel.value = null;
+ }
+ },
+ {immediate: true},
+);
watch(isOpen, async open => {
if (open) {
await pickerInit();
+ if (props.modelValue) selectedModel.value = pickerModels.value.find(model => modelValueFor(model) === props.modelValue) ?? selectedModel.value;
setupObserver();
} else {
teardownObserver();
@@ -210,7 +238,11 @@ function teardownObserver() {
onUnmounted(teardownObserver);
function selectModel(model: ModelList | null) {
- emit('update:modelValue', model?.model_id ?? null);
+ emit('update:modelValue', model ? modelValueFor(model) : null);
isOpen.value = false;
}
+
+function modelValueFor(model: ModelList) {
+ return props.valueMode === 'uuid' ? model.id : model.model_id;
+}
diff --git a/frontend/composables/useModelPicker.ts b/frontend/composables/useModelPicker.ts
index 88082ca..7ec733e 100644
--- a/frontend/composables/useModelPicker.ts
+++ b/frontend/composables/useModelPicker.ts
@@ -2,9 +2,10 @@ import type {ModelList, PaginatedResponse, ProviderTab} from '~/types/chat';
export type ModelFilter = 'all' | 'favorites' | string;
-export function useModelPicker(options: {endpoint?: string} = {}) {
+export function useModelPicker(options: {endpoint?: string; providerEndpoint?: string} = {}) {
const {$customFetch} = useNuxtApp();
const endpoint = options.endpoint ?? '/api/v1/models';
+ const providerEndpoint = options.providerEndpoint ?? '/api/v1/providers';
const models = ref([]);
const providers = ref([]);
@@ -38,7 +39,7 @@ export function useModelPicker(options: {endpoint?: string} = {}) {
async function loadProviders() {
try {
- const res = await $customFetch('/api/v1/providers');
+ const res = await $customFetch(providerEndpoint);
providers.value = res ?? [];
} catch (e) {
console.error('Failed to fetch model providers:', e);
diff --git a/frontend/pages/settings.vue b/frontend/pages/settings.vue
index 171353d..b745485 100644
--- a/frontend/pages/settings.vue
+++ b/frontend/pages/settings.vue
@@ -77,7 +77,9 @@ const activeTab = computed(() => {
});
function goBack() {
- router.push('/');
+ const returnPath = store.settingsReturnPath;
+ store.settingsReturnPath = '/';
+ router.push(returnPath === '/' || returnPath.startsWith('/chats/') ? returnPath : '/');
}
onMounted(() => {
diff --git a/frontend/pages/settings/tools.vue b/frontend/pages/settings/tools.vue
index f38fb00..d01c4ee 100644
--- a/frontend/pages/settings/tools.vue
+++ b/frontend/pages/settings/tools.vue
@@ -239,6 +239,17 @@
+
+
+
+
{{ store.getTranslation('settings.tools.system_prompt_hint') }}
+
+
@@ -326,21 +337,36 @@