lock surface: restore redacted chat on unlock + announce replies
Redacted messages stayed '[content hidden until unlock]' forever — nothing restored them on unlock. Redaction now records the message and unlock restores content from rawContent. Turns finishing while locked are also redacted and surfaced. New LockAgentCard shows a one-line preview of replies that landed during the lock window on the lock glance, like a notification; body stays hidden until unlock. sessiond auth: getpwuid_r buffer is u8 with a c_char cast so it compiles on aarch64 (c_char = u8 there) and x86 (c_char = i8).
This commit is contained in:
parent
dc9fe900ec
commit
e10efbbd56
6 changed files with 160 additions and 9 deletions
|
|
@ -131,20 +131,71 @@ Singleton {
|
|||
// raw content is preserved in the message's rawContent so it can be
|
||||
// shown again after unlock (the message stays in history), but the
|
||||
// displayed content is cleared.
|
||||
//
|
||||
// The redaction is reversible: every message whose content we replaced
|
||||
// with the placeholder is recorded in `redactedOnLock`, and on unlock
|
||||
// its content is restored from `rawContent` (the streaming message too,
|
||||
// if it is still in flight). A finished message redacted at lock then
|
||||
// surfaced on the lock screen counts as "delivered" and is restored
|
||||
// normally on unlock; one that never surfaced stays for the chat to
|
||||
// replay once unlocked.
|
||||
property var redactedOnLock: []
|
||||
|
||||
function _redactMessage(msg) {
|
||||
if (!msg || msg.content.length === 0) return;
|
||||
if (msg.content === Translation.tr("[content hidden until unlock]")) return;
|
||||
msg.rawContent = msg.content;
|
||||
msg.content = Translation.tr("[content hidden until unlock]");
|
||||
if (!root.redactedOnLock.includes(msg)) {
|
||||
root.redactedOnLock = [...root.redactedOnLock, msg];
|
||||
}
|
||||
root.redactedMessagesChanged();
|
||||
}
|
||||
|
||||
function _restoreRedacted() {
|
||||
if (root.redactedOnLock.length === 0) return;
|
||||
for (const msg of root.redactedOnLock) {
|
||||
if (msg && msg.rawContent && msg.rawContent.length > 0) {
|
||||
msg.content = msg.rawContent;
|
||||
}
|
||||
}
|
||||
root.redactedOnLock = [];
|
||||
root.redactedMessagesChanged();
|
||||
}
|
||||
|
||||
// Messages redacted while locked, newest first, for the lock surface to
|
||||
// surface as ambient notifications. Strips to a one-line preview — the
|
||||
// lock screen shows "the agent replied", not the personal-tier body.
|
||||
function redactedPreviews() {
|
||||
return root.redactedOnLock
|
||||
.filter(m => m && m.rawContent && m.rawContent.length > 0 && m.role === "assistant")
|
||||
.map(m => {
|
||||
const firstLine = m.rawContent.split("\n").find(l => l.trim().length > 0) || "";
|
||||
return firstLine.slice(0, 80);
|
||||
})
|
||||
.reverse();
|
||||
}
|
||||
|
||||
signal redactedMessagesChanged()
|
||||
|
||||
Connections {
|
||||
target: GlobalStates
|
||||
function onScreenLockedChanged() {
|
||||
if (!GlobalStates.screenLocked) return;
|
||||
if (!root.streamingMessage) return;
|
||||
// Lock fired mid-stream. Redact the displayed content.
|
||||
// rawContent preserves the actual response for post-unlock.
|
||||
if (root.streamingMessage.content.length > 0) {
|
||||
root.streamingMessage.content = Translation.tr("[content hidden until unlock]");
|
||||
console.log("[ai] lock fired during stream — redacted personal output");
|
||||
if (GlobalStates.screenLocked) {
|
||||
// Lock fired mid-stream — redact the in-flight content.
|
||||
if (root.streamingMessage) {
|
||||
root._redactMessage(root.streamingMessage);
|
||||
console.log("[ai] lock fired during stream — redacted personal output");
|
||||
}
|
||||
} else {
|
||||
// Unlock: restore every message we hid, so the chat shows
|
||||
// what actually came back rather than lingering placeholders.
|
||||
root._restoreRedacted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ── Streaming message shaping ────────────────────────────────────────
|
||||
property AiMessageData streamingMessage
|
||||
property bool inThinkBlock: false
|
||||
|
|
@ -171,6 +222,12 @@ Singleton {
|
|||
}
|
||||
root.streamingMessage.thinking = false;
|
||||
root.streamingMessage.done = true;
|
||||
// If the turn finished while the session is locked, the finished
|
||||
// assistant message is personal-tier output the user hasn't seen —
|
||||
// redact it for the chat view and let the lock surface announce it.
|
||||
if (GlobalStates.screenLocked && root.streamingMessage.content.length > 0) {
|
||||
root._redactMessage(root.streamingMessage);
|
||||
}
|
||||
if (root.postResponseHook) {
|
||||
root.postResponseHook();
|
||||
root.postResponseHook = null;
|
||||
|
|
|
|||
Loading…
Reference in a new issue