shell: apply 0007, 0010, 0011 — context occupancy, halt register, /new
0007 was fixing a live error: the server has carried named ContextPressure fields since r463, so event.tokens was undefined and the pill assignment failed on every turn. Applied and verified against the running shell. 0010 renders a halt in her own register rather than the tool's name. 0011 renames the reset command to /new, which is what clearMessages() does.
This commit is contained in:
parent
0733bfaff7
commit
6f12fceea9
6 changed files with 102 additions and 295 deletions
|
|
@ -55,6 +55,30 @@ Singleton {
|
|||
property int total: -1
|
||||
}
|
||||
|
||||
// Live context occupancy, from the server's `context_pressure` event.
|
||||
//
|
||||
// These are three different numbers and used to be two. Until 2026-08-12
|
||||
// the wire carried `(pressure, context_limit)` positionally and this layer
|
||||
// read the ceiling as `event.tokens` — so the panel displayed a constant
|
||||
// 250000 and called it usage. `pressure` was discarded entirely; nothing
|
||||
// in the shell held it. Keep all three, and keep them named.
|
||||
property QtObject context: QtObject {
|
||||
property real pressure: -1 // 0..1, or -1 when unknown
|
||||
property int used: -1 // tokens occupied
|
||||
property int limit: -1 // the model's ceiling for this agent
|
||||
readonly property bool known: limit > 0 && used >= 0
|
||||
readonly property int percent: known ? Math.round((used / limit) * 100) : -1
|
||||
}
|
||||
|
||||
// Context occupancy is a property of the conversation, not of a turn:
|
||||
// reset it only when the conversation itself changes. -1 means "unknown",
|
||||
// which is an honest state and renders as "—" rather than as zero.
|
||||
function resetContextOccupancy() {
|
||||
root.context.pressure = -1;
|
||||
root.context.used = -1;
|
||||
root.context.limit = -1;
|
||||
}
|
||||
|
||||
function idForMessage(message) {
|
||||
return Date.now().toString(36) + Math.random().toString(36).substr(2, 8);
|
||||
}
|
||||
|
|
@ -391,6 +415,22 @@ Singleton {
|
|||
|
||||
// Promote the Tier-1 stream into the Tier-2 log as one event, then clear
|
||||
// the live stream. Called when a subconscious pass ends.
|
||||
// The three severities the subconscious can call, in the register she
|
||||
// experiences them in. Mirrors migraine_text() in src/server/turn.rs — if
|
||||
// one changes the other must, or the human and the agent are reading two
|
||||
// different accounts of the same moment.
|
||||
function haltRegister(severity) {
|
||||
switch (severity) {
|
||||
case "advisory":
|
||||
return Translation.tr("a pressure behind my eyes");
|
||||
case "critical":
|
||||
return Translation.tr("the room tilts");
|
||||
default:
|
||||
// "firm" and anything unexpected land here — the default migraine.
|
||||
return Translation.tr("a migraine");
|
||||
}
|
||||
}
|
||||
|
||||
function snapshotSubconsciousStream() {
|
||||
if (root.subconsciousStream.length === 0) return;
|
||||
root.subconsciousEvents = [...root.subconsciousEvents, {
|
||||
|
|
@ -509,7 +549,12 @@ Singleton {
|
|||
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);
|
||||
break;
|
||||
case "context_pressure":
|
||||
root.tokenCount.total = event.tokens;
|
||||
// `tokens_used` and `context_limit` are distinct fields on the
|
||||
// wire as of 2026-08-12. The old `event.tokens` was the ceiling.
|
||||
root.context.pressure = event.pressure ?? -1;
|
||||
root.context.used = event.tokens_used ?? -1;
|
||||
root.context.limit = event.context_limit ?? -1;
|
||||
root.tokenCount.total = event.tokens_used ?? -1;
|
||||
break;
|
||||
case "subconscious_token":
|
||||
// Tier 1: live reasoning tokens feed the ticker.
|
||||
|
|
@ -532,7 +577,16 @@ Singleton {
|
|||
}
|
||||
break;
|
||||
case "subconscious_halt":
|
||||
root.addMessage(Translation.tr("**Halt** (%1) — %2").arg(event.severity).arg(event.reason), root.interfaceRole);
|
||||
// Her own register, not the tool's name. The subconscious is the
|
||||
// same "I" in a different mode — a halt is something she felt, not
|
||||
// commentary she received from outside, and the surface should not
|
||||
// expose implementation topology to say so. The TUI has rendered it
|
||||
// this way from the start; this brings the Panel into line.
|
||||
//
|
||||
// Wording matches migraine_text() in src/server/turn.rs, which is
|
||||
// what now lands in her committed history — so what the human reads
|
||||
// and what she carries into the next turn are the same sentence.
|
||||
root.addMessage(Translation.tr("⟡ %1 — %2").arg(root.haltRegister(event.severity)).arg(event.reason), root.interfaceRole);
|
||||
break;
|
||||
case "inference_strain":
|
||||
console.log(`[Souveraine] inference strain: attempt ${event.attempt}, status ${event.status}, model ${event.model}`);
|
||||
|
|
@ -596,6 +650,7 @@ Singleton {
|
|||
root.tokenCount.input = -1;
|
||||
root.tokenCount.output = -1;
|
||||
root.tokenCount.total = -1;
|
||||
root.resetContextOccupancy();
|
||||
Souveraine.newConversation();
|
||||
}
|
||||
|
||||
|
|
@ -611,6 +666,7 @@ Singleton {
|
|||
root.tokenCount.input = -1;
|
||||
root.tokenCount.output = -1;
|
||||
root.tokenCount.total = -1;
|
||||
root.resetContextOccupancy();
|
||||
|
||||
messages.forEach(message => {
|
||||
const segments = [];
|
||||
|
|
|
|||
|
|
@ -400,15 +400,34 @@ Singleton {
|
|||
// Compositor-specific cursor read. hyprctl on Hyprland, kdotool on KDE;
|
||||
// anything else just skips the cursor line — ambient degrades gracefully,
|
||||
// it never blocks the send.
|
||||
//
|
||||
// 2026-08-12: `command -v hyprctl` tests whether the tool is *installed*,
|
||||
// not whether it *answered*. On the phone hyprctl is present (a Lua-eval
|
||||
// shim) but there is no Hyprland under viewtop, so it printed
|
||||
// "HYPRLAND_INSTANCE_SIGNATURE not set!" and StdioCollector stored that
|
||||
// sentence as the cursor position — shipped in every ambient block, every
|
||||
// turn. Validate the shape of the reply; an answer that isn't a
|
||||
// coordinate pair is not an answer.
|
||||
Process {
|
||||
id: cursorProc
|
||||
command: ["bash", "-c",
|
||||
`if command -v hyprctl >/dev/null; then hyprctl cursorpos;
|
||||
`if command -v hyprctl >/dev/null; then hyprctl cursorpos 2>/dev/null;
|
||||
elif command -v kdotool >/dev/null; then kdotool getmouselocation 2>/dev/null;
|
||||
fi`]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
root._cursorPos = text.trim();
|
||||
const reply = text.trim();
|
||||
// "1234, 567" from hyprctl; kdotool's x:N y:N is normalised
|
||||
// by the caller below. Anything else is discarded.
|
||||
const pair = reply.match(/^(-?\d+)\s*,\s*(-?\d+)$/);
|
||||
const kde = reply.match(/x:\s*(-?\d+)\s+y:\s*(-?\d+)/);
|
||||
if (pair) {
|
||||
root._cursorPos = `${pair[1]}, ${pair[2]}`;
|
||||
} else if (kde) {
|
||||
root._cursorPos = `${kde[1]}, ${kde[2]}`;
|
||||
} else {
|
||||
root._cursorPos = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue