Watch
1
0
Fork
You've already forked souveraine
0

quickshell: resume agent conversations from server

This commit is contained in:
Fimeg 2026-07-12 16:31:55 -04:00
commit 6e21c50dcc
9 changed files with 338 additions and 127 deletions

View file

@ -84,13 +84,21 @@ Singleton {
});
root.models = map;
root.modelList = Object.keys(map);
// Restore persisted agent choice if it exists server-side
// Restore the selected agent, then derive its latest conversation
// from the server. No per-agent conversation map lives in the UI.
const persisted = Persistent.states?.ai?.model ?? "";
if (persisted.length > 0 && Souveraine.agents[persisted]) {
Souveraine.selectAgent(persisted);
} else if (Souveraine.currentAgentId.length > 0) {
Souveraine.selectAgent(Souveraine.currentAgentId);
}
}
function onConversationResumed(agentId, conversationId, messages) {
if (agentId !== Souveraine.currentAgentId) return;
root.restoreServerConversation(messages);
}
function onServerUnreachable() {
root.addMessage(
Translation.tr("Souveraine server unreachable at %1\n\nStart it with:\n```bash\nsouveraine server\n```").arg(Souveraine.serverBase),
@ -261,6 +269,38 @@ Singleton {
Souveraine.newConversation();
}
// Render the server's canonical transcript after /agent or /resume.
// This replaces ii's old local snapshot behaviour: the next send remains
// on the same live Souveraine conversation rather than silently forking.
function restoreServerConversation(messages) {
root.messageIDs = [];
root.messageByID = ({});
root.streamingMessage = null;
root.inThinkBlock = false;
root.subconsciousBuffer = "";
root.tokenCount.input = -1;
root.tokenCount.output = -1;
root.tokenCount.total = -1;
messages.forEach(message => {
const content = (message.blocks ?? []).map(block => {
switch (block.type) {
case "text": return block.text ?? "";
case "reasoning": return `<think>\n${block.reasoning ?? ""}\n</think>`;
case "tool_use": return `sensor: ${block.name ?? "?"}(${block.input ?? ""})`;
case "tool_result": return `[${block.tool_name ?? "tool"}] ${block.output ?? ""}`;
case "image": return "[image]";
default: return "";
}
}).filter(Boolean).join("\n");
if (content.length === 0) return;
const role = message.role === "user"
? "user"
: message.role === "assistant" ? "assistant" : root.interfaceRole;
root.addMessage(content, role);
});
}
function sendUserMessage(message) {
if (message.length === 0) return;
root.addMessage(message, "user");
@ -301,9 +341,18 @@ Singleton {
modelId = match;
}
if (setPersistentState) Persistent.states.ai.model = modelId;
Souveraine.selectAgent(modelId);
if (!Souveraine.selectAgent(modelId)) {
if (feedback) root.addMessage(Translation.tr("Finish or cancel the current turn before switching agents."), root.interfaceRole);
return;
}
root.currentModel = models[modelId];
if (feedback) root.addMessage(Translation.tr("Agent set to %1").arg(models[modelId].name), root.interfaceRole);
if (feedback) root.addMessage(Translation.tr("Switched to %1 — resuming her latest conversation.").arg(models[modelId].name), root.interfaceRole);
}
function resumeConversation() {
if (!Souveraine.resumeLatestConversation()) {
root.addMessage(Translation.tr("Finish or cancel the current turn before resuming."), root.interfaceRole);
}
}
// Souveraine-owned settings: advice instead of local state