diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-23 17:09:58 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-23 17:09:58 +0200 |
| commit | e7de6f62f438acfa723961000c558b4d9f9da35f (patch) | |
| tree | 16fece6b35aedc628ede244367b7af38621f278b /desktop/modules | |
| parent | 4f133813fd0f677d5a4f9cac496bd3d3738cd276 (diff) | |
| download | quickshell-e7de6f62f438acfa723961000c558b4d9f9da35f.tar.gz quickshell-e7de6f62f438acfa723961000c558b4d9f9da35f.zip | |
assistant settings: a Cloud section, and Prefer for cloud models
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/modules')
| -rw-r--r-- | desktop/modules/assistant/AssistantPage.qml | 185 |
1 files changed, 182 insertions, 3 deletions
diff --git a/desktop/modules/assistant/AssistantPage.qml b/desktop/modules/assistant/AssistantPage.qml index e088241..5878b3b 100644 --- a/desktop/modules/assistant/AssistantPage.qml +++ b/desktop/modules/assistant/AssistantPage.qml @@ -166,9 +166,9 @@ Column { Small { width: page.width wrapMode: Text.Wrap - text: "The assistant answers with whichever model llama-server has loaded. Opening it loads " - + "the preferred model if another one is in. Load swaps a model in now, for every client, " - + "without changing the preference." + text: "Each chat uses the model picked in the canvas header, else the preferred one. " + + "Opening the canvas loads that model if it is a local one and another is in. " + + "Load swaps a model in now, for every client, without changing the preference." } Small { @@ -231,6 +231,50 @@ Column { } } + // The saved cloud models: Prefer only, there is nothing to load. + Repeater { + model: page.asst.savedClouds.flatMap(c => c.models.map(m => c.name + ":" + m)) + + delegate: Rectangle { + id: cloudRow + required property string modelData + readonly property bool preferred: Prefs.assistantModel === modelData + objectName: "model:" + modelData + width: page.width + height: 40 + radius: 8 + color: Qt.alpha(Theme.surface, 0.35) + + // nf-fa-cloud, present in Inconsolata Nerd Font. + Text { + id: cloudIcon + anchors { left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter } + text: "" + color: Theme.subtext + font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 4 } + } + Text { + id: cloudName + anchors { left: cloudIcon.right; leftMargin: 8; verticalCenter: parent.verticalCenter } + text: cloudRow.modelData + color: Theme.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } + } + Small { + anchors { left: cloudName.right; leftMargin: 10; verticalCenter: parent.verticalCenter } + visible: cloudRow.preferred + text: "preferred" + color: Theme.accent + } + Button { + anchors { right: parent.right; rightMargin: 6; verticalCenter: parent.verticalCenter } + text: cloudRow.preferred ? "Preferred" : "Prefer" + enabled: !cloudRow.preferred + onClicked: Prefs.setAssistantModel(cloudRow.modelData) + } + } + } + Small { width: page.width visible: page.asst.modelError !== "" @@ -368,6 +412,141 @@ Column { // --- env --- + // --- cloud --- + + Heading { text: "Cloud" } + + Small { + width: page.width + wrapMode: Text.Wrap + text: "Providers with an OpenAI-compatible API, offered in the canvas's model menu. A cloud " + + "chat is sent its history, attachments and the results of the tools marked " + + "cloud = true; voice is still transcribed here. The key command prints the API key: " + + "the assistant runs it at startup and on Fetch, which saves this page first." + } + + Small { + width: page.width + visible: page.asst.clouds === null + wrapMode: Text.Wrap + text: "config.toml has a [[cloud]] table this page cannot read; edit it by hand." + color: Theme.red + } + + Repeater { + model: page.asst.clouds === null ? 0 : page.asst.cloudCount + + delegate: Rectangle { + id: prov + required property int index + readonly property var c: page.asst.clouds?.[index] ?? { name: "", url: "", key_cmd: "", models: [] } + readonly property var got: page.asst.fetched[prov.c.name] + objectName: "cloud:" + index + width: page.width + height: provCol.implicitHeight + 20 + radius: 8 + color: Qt.alpha(Theme.surface, 0.35) + + Column { + id: provCol + anchors { left: parent.left; right: parent.right; top: parent.top; margins: 10 } + spacing: 6 + + Labelled { + width: provCol.width + label: "Name" + Field { + anchors.fill: parent + value: prov.c.name + placeholder: "openrouter" + onEdited: t => page.asst.editCloud(prov.index, { name: t.trim() }) + } + } + Labelled { + width: provCol.width + label: "URL" + Field { + anchors.fill: parent + value: prov.c.url + placeholder: "https://openrouter.ai/api/v1" + onEdited: t => page.asst.editCloud(prov.index, { url: t.trim() }) + } + } + Labelled { + width: provCol.width + label: "Key command" + Field { + anchors.fill: parent + value: prov.c.key_cmd + placeholder: "pass show llm/openrouter" + onEdited: t => page.asst.editCloud(prov.index, { key_cmd: t.trim() }) + } + } + Row { + spacing: 6 + Button { + text: page.asst.fetching === prov.c.name ? "Fetching…" : "Fetch models" + enabled: page.asst.fetching === "" && page.asst.valid && prov.c.name !== "" + onClicked: page.asst.fetchModels(prov.c.name) + } + Button { + text: "Remove" + danger: true + onClicked: page.asst.removeCloud(prov.index) + } + } + Small { + width: provCol.width + visible: typeof prov.got === "string" + wrapMode: Text.Wrap + text: typeof prov.got === "string" ? prov.got : "" + color: Theme.red + } + // The fetched ids and any kept from before, each switched + // into models or out of it. + Repeater { + model: Array.isArray(prov.got) + ? [...new Set(prov.got.concat(prov.c.models))].sort() : prov.c.models + + delegate: Item { + id: idRow + required property string modelData + width: provCol.width + height: 28 + Switch { + id: idOn + anchors { left: parent.left; verticalCenter: parent.verticalCenter } + checked: prov.c.models.includes(idRow.modelData) + onToggled: on => page.asst.editCloud(prov.index, { models: on + ? prov.c.models.concat([idRow.modelData]) + : prov.c.models.filter(m => m !== idRow.modelData) }) + } + Text { + anchors { left: idOn.right; leftMargin: 10; verticalCenter: parent.verticalCenter } + text: idRow.modelData + color: Theme.text + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 } + } + } + } + } + } + } + + Small { + width: page.width + visible: page.asst.cloudError !== "" + wrapMode: Text.Wrap + text: page.asst.cloudError + color: Theme.red + } + + Button { + text: "Add provider" + enabled: page.asst.clouds !== null + onClicked: page.asst.editCloud(page.asst.cloudCount, {}) + } + Heading { text: "Tool environment" } Small { width: page.width |
