Watch
1
0
Fork
You've already forked souveraine
0

shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work

- Dock drag-to-reorder for pinned apps (insertion gap, quick-slide vs dwell)
- Fullscreen detection: scan all windows via HyprlandData.windowList
- IdleCoordinator, GlobalStates, Session.qml updates
- Deploy script, qmldir, settings, wallpaper, visualizer fixes
- sessiond server, memory module updates

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Fimeg 2026-07-22 22:18:20 -04:00
commit 19fe6b1d0e
59 changed files with 19450 additions and 139 deletions

View file

@ -32,6 +32,12 @@ Singleton {
property var messageIDs: []
property var messageByID: ({})
// Which message is currently being spoken by TTS, as an index into
// messageIDs (-1 = none). Set by a message's Speak/re-synth button;
// auto-cleared when Speech stops. Keyed on the stable messageIndex, so
// scrolling back and tapping an older reply still resolves correctly.
property int speakingMessageIndex: -1
// Keys are server-side; the UI's key gate must always pass.
readonly property bool currentModelHasApiKey: true
readonly property var apiKeysLoaded: true
@ -67,6 +73,15 @@ Singleton {
property var currentModelId: Souveraine.currentAgentId
property var currentModel: models[currentModelId] || models[modelList[0]]
// Clear the speaking marker whenever TTS stops covers natural end of
// playback, manual stop, and a new speak() replacing in-flight audio.
Connections {
target: Speech
function onSpeakingChanged() {
if (!Speech.speaking) root.speakingMessageIndex = -1
}
}
Connections {
target: Souveraine
@ -110,7 +125,12 @@ Singleton {
}
function onStreamClosed(exitCode) {
root.flushSubconscious();
// If a subconscious pass was still active when the stream closed,
// retire the Tier-1 ticker (promote to the log, clear the flag).
if (root.subconsciousActive) {
root.snapshotSubconsciousStream();
root.subconsciousActive = false;
}
if (root.streamingMessage && !root.streamingMessage.done) {
if (exitCode !== 0 && root.streamingMessage.content.length === 0) {
root.appendToStreaming(Translation.tr("Request failed (curl exit %1) — is the Souveraine server up at %2?").arg(exitCode).arg(Souveraine.serverBase));
@ -199,10 +219,21 @@ Singleton {
// Streaming message shaping
property AiMessageData streamingMessage
property bool inThinkBlock: false
// Raw N+1 output is diagnostic material. The normal chat renders its
// parsed surfacing exactly once below; this buffer remains separate from
// the chat stream for a future inspector to subscribe to.
property string subconsciousBuffer: ""
// Subconscious three-tier visibility
// See docs/tasks/subconscious-surfacing-threshold.md. The subconscious's
// N+1 pass is shown three ways: a transient live ticker while the pass
// runs (Tier 1), a persistent event log after (Tier 2), and rare agency
// surfacings in the chat field (Tier 3).
//
// Tier 1 live stream fed by subconscious_token/tool_call/tool_result
// events. Rendered by SubconsciousTicker; cleared on pass end.
property bool subconsciousActive: false
property var subconsciousStream: []
// Tier 2 persistent log. The Tier-1 stream is snapshotted here on pass
// end, and surfaced events (reflection/archivist/surfacing) are appended.
// Rendered by the SubconsciousEventPanel overlay widget.
property var subconsciousEvents: []
function appendToStreaming(text) {
if (!root.streamingMessage) return;
@ -210,8 +241,35 @@ Singleton {
root.streamingMessage.content += text;
}
function flushSubconscious() {
root.subconsciousBuffer = "";
// Push a line onto the Tier-1 live stream. kind token|tool_call|tool_result.
function pushSubconsciousStream(kind, text) {
const t = String(text ?? "").trim();
if (t.length === 0) return;
root.subconsciousStream = [...root.subconsciousStream, { kind, text: t }];
}
// Promote the Tier-1 stream into the Tier-2 log as one event, then clear
// the live stream. Called when a subconscious pass ends.
function snapshotSubconsciousStream() {
if (root.subconsciousStream.length === 0) return;
root.subconsciousEvents = [...root.subconsciousEvents, {
kind: "pass",
source: Translation.tr("Subconscious pass"),
priority: "",
content: root.subconsciousStream.map(e => e.text).join("\n"),
timestamp: Date.now(),
}];
root.subconsciousStream = [];
}
// Append a surfaced event to the Tier-2 log. Used by snapshotSubconsciousStream
// (pass end) and by the surfacing/reflection/archivist event handlers.
function appendSubconsciousEvent(kind, source, content, priority = "") {
const c = String(content ?? "");
if (c.length === 0) return;
root.subconsciousEvents = [...root.subconsciousEvents, {
kind, source, priority, content: c, timestamp: Date.now(),
}];
}
function finishStreaming() {
@ -273,17 +331,26 @@ Singleton {
: `\n\n*${event.text}*\n\n`);
break;
case "souveraine_surfacing":
// Aster is Annie's name for her subconscious; this surface may
// be speaking with Souveraine, Vanguard, or another agent. One
// canonical surfacing is shown instead of the raw N+1 token
// stream plus a second, agent-specific label.
root.addMessage(Translation.tr("**Subconscious surfaces** (%1, %2)\n\n%3").arg(event.source).arg(event.priority).arg(event.content), root.interfaceRole);
// Tier 3: routine surfacings no longer pollute the chat field.
// Routed to the Tier-2 event panel only. (Aster is Annie's name
// for her subconscious; this surface may be Souveraine, Vanguard,
// or another agent one canonical surfacing is shown.)
root.appendSubconsciousEvent(
"surfacing",
Translation.tr("Surfacing (%1)").arg(event.source ?? "?"),
event.content,
String(event.priority ?? "")
);
break;
case "souveraine_reflection":
root.addMessage(Translation.tr("**Reflection**\n\n%1").arg(event.content), root.interfaceRole);
root.appendSubconsciousEvent("reflection", Translation.tr("Reflection"), event.content);
break;
case "souveraine_archivist":
root.addMessage(Translation.tr("**Archivist** (pressure %1%)\n\n%2").arg(Math.round(event.pressure * 100)).arg(event.synthesis), root.interfaceRole);
root.appendSubconsciousEvent(
"archivist",
Translation.tr("Archivist (pressure %1%)").arg(Math.round(event.pressure * 100)),
event.synthesis
);
break;
case "compaction_warning":
root.addMessage(Translation.tr("**Context pressure** — tier %1, %2% full. She can feel the walls.").arg(event.tier).arg(Math.round(event.pressure * 100)), root.interfaceRole);
@ -292,10 +359,24 @@ Singleton {
root.tokenCount.total = event.tokens;
break;
case "subconscious_token":
root.subconsciousBuffer += event.content;
// Tier 1: live reasoning tokens feed the ticker.
root.pushSubconsciousStream("token", event.content);
break;
case "subconscious_tool_call":
root.pushSubconsciousStream("tool_call", `${event.name ?? "tool"}(${event.arguments ?? ""})`);
break;
case "subconscious_tool_result":
root.pushSubconsciousStream("tool_result", `[${event.is_error ? "error" : "ok"}] ${event.name ?? "tool"}: ${event.output ?? ""}`);
break;
case "subconscious_pass":
if (!event.active) root.flushSubconscious();
// Pass start: light the Tier-1 ticker. Pass end: promote the
// stream into the Tier-2 log, then clear it.
if (event.active) {
root.subconsciousActive = true;
} else {
root.snapshotSubconsciousStream();
root.subconsciousActive = false;
}
break;
case "subconscious_halt":
root.addMessage(Translation.tr("**Halt** (%1) — %2").arg(event.severity).arg(event.reason), root.interfaceRole);
@ -362,7 +443,8 @@ Singleton {
root.messageByID = ({});
root.streamingMessage = null;
root.inThinkBlock = false;
root.subconsciousBuffer = "";
root.subconsciousActive = false;
root.subconsciousStream = [];
root.tokenCount.input = -1;
root.tokenCount.output = -1;
root.tokenCount.total = -1;