Ship Assistent 0.15.2: apply closed generate patches immediately, recover stalled streams, and skip repeat greetings when a chat already has replies.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+262
-122
@@ -43,6 +43,7 @@
|
||||
"actions",
|
||||
"generate",
|
||||
"ask",
|
||||
"checkpoint",
|
||||
"use_init_image",
|
||||
"clear_init_image",
|
||||
"init_creativity",
|
||||
@@ -85,6 +86,20 @@
|
||||
function has(obj, key) {
|
||||
return obj[key] !== void 0 && obj[key] !== null;
|
||||
}
|
||||
function generateFlagOn(obj) {
|
||||
if (!obj || typeof obj !== "object") {
|
||||
return false;
|
||||
}
|
||||
const g = obj.generate;
|
||||
if (g === true || g === 1) {
|
||||
return true;
|
||||
}
|
||||
if (typeof g === "string" && /^(true|1|yes|on)$/i.test(g.trim())) {
|
||||
return true;
|
||||
}
|
||||
const acts = Array.isArray(obj.actions) ? obj.actions.map(String) : [];
|
||||
return acts.includes("generate");
|
||||
}
|
||||
function isPatchObject2(obj) {
|
||||
if (!obj || typeof obj !== "object") {
|
||||
return false;
|
||||
@@ -96,7 +111,7 @@
|
||||
return patch;
|
||||
}
|
||||
const acts = Array.isArray(patch.actions) ? patch.actions.map(String) : [];
|
||||
if (patch.generate === true || acts.includes("generate")) {
|
||||
if (generateFlagOn(patch) || acts.includes("generate")) {
|
||||
patch.generate = true;
|
||||
}
|
||||
if (typeof patch.ask === "string") {
|
||||
@@ -114,31 +129,63 @@
|
||||
}
|
||||
return patch;
|
||||
}
|
||||
function tryParsePatchJson(raw) {
|
||||
try {
|
||||
const obj = JSON.parse(String(raw || "").trim());
|
||||
if (isPatchObject2(obj)) {
|
||||
return normalizePatch(obj);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function extractPatch(text) {
|
||||
if (!text) {
|
||||
return { prose: text || "", patch: null };
|
||||
}
|
||||
const re = new RegExp(FENCE_RE.source, "gi");
|
||||
let match;
|
||||
let lastPatch = null;
|
||||
let prose = text;
|
||||
let lastAny = null;
|
||||
let lastAnyIndex = -1;
|
||||
let lastAnyLen = 0;
|
||||
let lastTerminal = null;
|
||||
let lastTermIndex = -1;
|
||||
let lastTermLen = 0;
|
||||
while ((match = re.exec(text)) !== null) {
|
||||
try {
|
||||
const obj = JSON.parse(match[1].trim());
|
||||
if (isPatchObject2(obj)) {
|
||||
lastPatch = normalizePatch(obj);
|
||||
prose = (text.slice(0, match.index) + text.slice(match.index + match[0].length)).trim();
|
||||
}
|
||||
} catch (e) {
|
||||
const parsed = tryParsePatchJson(match[1]);
|
||||
if (!parsed) {
|
||||
continue;
|
||||
}
|
||||
lastAny = parsed;
|
||||
lastAnyIndex = match.index;
|
||||
lastAnyLen = match[0].length;
|
||||
if (isTerminalStreamPatch(parsed)) {
|
||||
lastTerminal = parsed;
|
||||
lastTermIndex = match.index;
|
||||
lastTermLen = match[0].length;
|
||||
}
|
||||
}
|
||||
return { prose, patch: lastPatch };
|
||||
const chosen = lastTerminal || lastAny;
|
||||
if (chosen) {
|
||||
const idx = lastTerminal ? lastTermIndex : lastAnyIndex;
|
||||
const len = lastTerminal ? lastTermLen : lastAnyLen;
|
||||
const prose = (text.slice(0, idx) + text.slice(idx + len)).trim();
|
||||
return { prose, patch: chosen };
|
||||
}
|
||||
const brace = text.lastIndexOf("{");
|
||||
if (brace >= 0) {
|
||||
const parsed = tryParsePatchJson(text.slice(brace));
|
||||
if (parsed) {
|
||||
return { prose: text.slice(0, brace).trim(), patch: parsed };
|
||||
}
|
||||
}
|
||||
return { prose: text, patch: null };
|
||||
}
|
||||
function isTerminalStreamPatch(obj) {
|
||||
if (!obj || typeof obj !== "object") {
|
||||
return false;
|
||||
}
|
||||
if (obj.generate === true) {
|
||||
if (generateFlagOn(obj)) {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(obj.ask) && obj.ask.length) {
|
||||
@@ -153,14 +200,10 @@
|
||||
if (obj.look_at != null || obj.vision_from != null || obj.vision_slots != null) {
|
||||
return true;
|
||||
}
|
||||
const acts = Array.isArray(obj.actions) ? obj.actions.map(String) : [];
|
||||
if (acts.includes("generate")) {
|
||||
return true;
|
||||
}
|
||||
if (String(obj.prompt || "").trim().length >= 48) {
|
||||
return true;
|
||||
}
|
||||
if (obj.loras != null || obj.aspect != null || obj.steps != null || obj.width != null || obj.height != null || obj.cfg != null || obj.seed != null || obj.controls != null) {
|
||||
if (obj.loras != null || obj.aspect != null || obj.steps != null || obj.width != null || obj.height != null || obj.cfg != null || obj.seed != null || obj.controls != null || obj.checkpoint != null || obj.negative != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -172,6 +215,7 @@
|
||||
SA2.isTerminalStreamPatch = isTerminalStreamPatch;
|
||||
SA2.normalizePatch = normalizePatch;
|
||||
SA2.extractPatch = extractPatch;
|
||||
SA2.generateFlagOn = generateFlagOn;
|
||||
}
|
||||
|
||||
// src/persist.js
|
||||
@@ -375,7 +419,9 @@
|
||||
}
|
||||
const delta = { ...raw };
|
||||
const acts = Array.isArray(delta.actions) ? delta.actions.map(String) : [];
|
||||
if (delta.generate === true || acts.includes("generate")) {
|
||||
const g = delta.generate;
|
||||
const generateOn = g === true || g === 1 || typeof g === "string" && /^(true|1|yes|on)$/i.test(g.trim()) || acts.includes("generate");
|
||||
if (generateOn) {
|
||||
delta.generate = true;
|
||||
}
|
||||
if (typeof delta.ask === "string") {
|
||||
@@ -392,7 +438,8 @@
|
||||
if (!patch || typeof patch !== "object") {
|
||||
return false;
|
||||
}
|
||||
if (patch.generate === true) {
|
||||
const n = normalizeDelta(patch);
|
||||
if (n?.generate === true) {
|
||||
return true;
|
||||
}
|
||||
const acts = Array.isArray(patch.actions) ? patch.actions.map(String) : [];
|
||||
@@ -631,10 +678,12 @@
|
||||
session_exact: extras.sessionExact || null
|
||||
};
|
||||
}
|
||||
function resolveTurnIntent(patch, userText, { vetoFn } = {}) {
|
||||
function resolveTurnIntent(patch, userText, { vetoFn, askGenerateFn, fromAutoCritique } = {}) {
|
||||
const delta = normalizeDelta(patch) || {};
|
||||
const vetoed = typeof vetoFn === "function" ? !!vetoFn(userText) : false;
|
||||
const generate = !vetoed && patchWantsGenerate(delta);
|
||||
const modelAsked = patchWantsGenerate(delta);
|
||||
const userAsked = typeof askGenerateFn === "function" && !!askGenerateFn(userText) && !!(modelAsked || String(delta.prompt || "").trim());
|
||||
const generate = !vetoed && !fromAutoCritique && (modelAsked || userAsked);
|
||||
const hasLook = delta.look_at != null || delta.vision_from != null || delta.vision_slots != null;
|
||||
const look = !!(hasLook && !generate && !vetoed);
|
||||
const ask = patchAskList(delta);
|
||||
@@ -884,7 +933,7 @@
|
||||
scrollToBottom,
|
||||
hideEmpty
|
||||
} = opts;
|
||||
let card2 = null;
|
||||
let card = null;
|
||||
let listEl = null;
|
||||
let titleEl = null;
|
||||
let steps = [];
|
||||
@@ -894,16 +943,16 @@
|
||||
if (!box) {
|
||||
return null;
|
||||
}
|
||||
if (card2 && card2.isConnected) {
|
||||
return card2;
|
||||
if (card && card.isConnected) {
|
||||
return card;
|
||||
}
|
||||
if (typeof hideEmpty === "function") {
|
||||
hideEmpty();
|
||||
}
|
||||
card2 = document.createElement("div");
|
||||
card2.className = "sa-activity sa-activity-live";
|
||||
card2.setAttribute("role", "status");
|
||||
card2.setAttribute("aria-live", "polite");
|
||||
card = document.createElement("div");
|
||||
card.className = "sa-activity sa-activity-live";
|
||||
card.setAttribute("role", "status");
|
||||
card.setAttribute("aria-live", "polite");
|
||||
const head = document.createElement("button");
|
||||
head.type = "button";
|
||||
head.className = "sa-activity-head";
|
||||
@@ -923,18 +972,18 @@
|
||||
head.appendChild(chev);
|
||||
head.addEventListener("click", () => {
|
||||
open = !open;
|
||||
card2.classList.toggle("sa-activity-collapsed", !open);
|
||||
card.classList.toggle("sa-activity-collapsed", !open);
|
||||
head.setAttribute("aria-expanded", open ? "true" : "false");
|
||||
});
|
||||
listEl = document.createElement("div");
|
||||
listEl.className = "sa-activity-steps";
|
||||
card2.appendChild(head);
|
||||
card2.appendChild(listEl);
|
||||
box.appendChild(card2);
|
||||
card.appendChild(head);
|
||||
card.appendChild(listEl);
|
||||
box.appendChild(card);
|
||||
if (typeof scrollToBottom === "function") {
|
||||
scrollToBottom();
|
||||
}
|
||||
return card2;
|
||||
return card;
|
||||
}
|
||||
function renderStep(step) {
|
||||
const row = document.createElement("div");
|
||||
@@ -970,15 +1019,15 @@
|
||||
if (titleEl) {
|
||||
titleEl.textContent = running ? running.label : last?.label || "Assistent";
|
||||
}
|
||||
card2.classList.toggle("sa-activity-live", steps.some((s) => s.status === "running"));
|
||||
card2.classList.toggle("sa-activity-done", steps.length > 0 && steps.every((s) => s.status === "done" || s.status === "skip"));
|
||||
card.classList.toggle("sa-activity-live", steps.some((s) => s.status === "running"));
|
||||
card.classList.toggle("sa-activity-done", steps.length > 0 && steps.every((s) => s.status === "done" || s.status === "skip"));
|
||||
if (typeof scrollToBottom === "function") {
|
||||
scrollToBottom();
|
||||
}
|
||||
}
|
||||
function begin(title) {
|
||||
steps = [];
|
||||
card2 = null;
|
||||
card = null;
|
||||
listEl = null;
|
||||
titleEl = null;
|
||||
open = true;
|
||||
@@ -1021,9 +1070,9 @@
|
||||
titleEl.textContent = summary;
|
||||
}
|
||||
paint();
|
||||
if (card2) {
|
||||
card2.classList.remove("sa-activity-live");
|
||||
card2.classList.add("sa-activity-done");
|
||||
if (card) {
|
||||
card.classList.remove("sa-activity-live");
|
||||
card.classList.add("sa-activity-done");
|
||||
}
|
||||
}
|
||||
function noteModelCommands(patch) {
|
||||
@@ -1242,8 +1291,8 @@
|
||||
\u041D\u0430\u043F\u0438\u0448\u0438, \u0447\u0442\u043E \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u2014 \u0438\u043B\u0438 \u043A\u0438\u043D\u044C \u0440\u0435\u0444\u0435\u0440\u0435\u043D\u0441 \u0438 \u043F\u043E\u043F\u0440\u043E\u0441\u0438 \u043F\u0440\u0430\u0432\u043A\u0443.`;
|
||||
let HELP_TEXT = `Slash-\u043A\u043E\u043C\u0430\u043D\u0434\u044B (\u0431\u0435\u0437 LLM):
|
||||
/help \u2014 \u044D\u0442\u043E\u0442 \u0441\u043F\u0438\u0441\u043E\u043A
|
||||
/new \u2014 \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442 (\u0442\u0435\u043A\u0443\u0449\u0438\u0439 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u0441\u044F \u0432 \u0418\u0441\u0442\u043E\u0440\u0438\u044E)
|
||||
/history \u2014 \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u0447\u0430\u0442\u043E\u0432
|
||||
/new \u2014 \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442 (\u0442\u0435\u043A\u0443\u0449\u0438\u0439 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u0441\u044F \u0432 \u0441\u043F\u0438\u0441\u043A\u0435)
|
||||
/history \u2014 \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0438\u043B\u0438 \u0441\u043A\u0440\u044B\u0442\u044C \u043F\u0430\u043D\u0435\u043B\u044C \u0447\u0430\u0442\u043E\u0432
|
||||
/compress \u2014 \u0441\u0436\u0430\u0442\u044C \u0441\u0442\u0430\u0440\u044B\u0435 \u0445\u043E\u0434\u044B \u0432 \u0441\u0430\u043C\u043C\u0430\u0440\u0438
|
||||
/debug \u2014 \u0441\u0432\u043E\u0434\u043A\u0430 UI/Exact (\u0431\u0435\u0437 LLM)
|
||||
/debug ask \u2014 \u0442\u043E \u0436\u0435 + \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0439 \u043E\u0442\u0432\u0435\u0442 \u043C\u043E\u0434\u0435\u043B\u0438
|
||||
@@ -1259,11 +1308,11 @@
|
||||
/inventory \u2014 rescan \u043C\u043E\u0434\u0435\u043B\u0435\u0439 + \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A LoRA
|
||||
|
||||
\u0427\u0438\u043F\u0441\u044B \u043D\u0430\u0434 \u043F\u043E\u043B\u0435\u043C \u0432\u0432\u043E\u0434\u0430 \u0434\u0435\u043B\u0430\u044E\u0442 \u0442\u043E \u0436\u0435 \u0434\u043B\u044F aspect / seed / vary / Turbo\xB7RAW.
|
||||
\u041F\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442; \u0441\u043C\u0435\u043D\u0430 \u0447\u0430\u0442\u0430 \u0432 \u0418\u0441\u0442\u043E\u0440\u0438\u0438 \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B.`;
|
||||
\u041F\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442; \u0441\u043C\u0435\u043D\u0430 \u0447\u0430\u0442\u0430 \u0432 \u043F\u0430\u043D\u0435\u043B\u0438 \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B.`;
|
||||
let SLASH_COMMANDS = [
|
||||
{ cmd: "/help", hint: "\u0441\u043F\u0438\u0441\u043E\u043A \u043A\u043E\u043C\u0430\u043D\u0434" },
|
||||
{ cmd: "/new", hint: "\u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442" },
|
||||
{ cmd: "/history", hint: "\u0438\u0441\u0442\u043E\u0440\u0438\u044F \u0447\u0430\u0442\u043E\u0432" },
|
||||
{ cmd: "/history", hint: "\u043F\u0430\u043D\u0435\u043B\u044C \u0447\u0430\u0442\u043E\u0432" },
|
||||
{ cmd: "/compress", hint: "\u0441\u0436\u0430\u0442\u044C \u0441\u0442\u0430\u0440\u044B\u0435 \u0445\u043E\u0434\u044B" },
|
||||
{ cmd: "/debug", hint: "\u0441\u0432\u043E\u0434\u043A\u0430 \xB7 ask = \u0441 LLM" },
|
||||
{ cmd: "/why", hint: "debug + \u043F\u043E\u044F\u0441\u043D\u0435\u043D\u0438\u0435 LLM" },
|
||||
@@ -2143,9 +2192,16 @@ ${patch.prompt}`;
|
||||
function mergePromptEnRewrite(effective) {
|
||||
const base = state.pendingPromptEnMerge;
|
||||
state.pendingPromptEnMerge = null;
|
||||
if (!base || !effective) {
|
||||
if (!base) {
|
||||
return effective;
|
||||
}
|
||||
if (!effective) {
|
||||
return {
|
||||
...base,
|
||||
generate: true,
|
||||
actions: Array.isArray(base.actions) && base.actions.length ? base.actions : ["generate"]
|
||||
};
|
||||
}
|
||||
return {
|
||||
...base,
|
||||
...effective,
|
||||
@@ -2184,6 +2240,21 @@ ${patch.prompt}`;
|
||||
}
|
||||
return /(?:^|[^а-яёa-z0-9_])(посмотри|смотри|глянь)\s+(на\s+)?(результат|картинк[а-яё]*|изображен[а-яё]*|кадр|ген|реф)/i.test(t);
|
||||
}
|
||||
function userAsksGenerate(text) {
|
||||
if (window.SA && typeof SA.userAsksGenerate === "function") {
|
||||
return SA.userAsksGenerate(text);
|
||||
}
|
||||
const t = String(text || "").trim();
|
||||
if (!t || userAsksNoGenerate(t)) {
|
||||
return false;
|
||||
}
|
||||
if (/\b(generat(e|ion)|draw|render|make\s+(an?\s+)?image|run\s+generate)\b/i.test(t)) {
|
||||
return true;
|
||||
}
|
||||
return cyrTokenRe(
|
||||
"\u0441\u0433\u0435\u043D\u0435\u0440[\u0430-\u044F\u0451]*|\u043D\u0430\u0440\u0438\u0441\u0443\u0439|\u043D\u0430\u0440\u0438\u0441\u0443\u0439\u0442\u0435|\u0437\u0430\u043F\u0443\u0441\u0442\u0438\\s+\u0433\u0435\u043D\u0435\u0440[\u0430-\u044F\u0451]*|\u0441\u0434\u0435\u043B\u0430\u0439\\s+(\u043A\u0430\u0434\u0440|\u043A\u0430\u0440\u0442\u0438\u043D\u043A[\u0430-\u044F\u0451]*|\u0438\u0437\u043E\u0431\u0440\u0430\u0436[\u0430-\u044F\u0451]*)"
|
||||
).test(t);
|
||||
}
|
||||
function packWantsVision(pack) {
|
||||
const p = String(pack || "");
|
||||
return p === "critique_image" || p === "describe_ref" || p === "compose_scene" || p === "inpaint_edit";
|
||||
@@ -2191,11 +2262,16 @@ ${patch.prompt}`;
|
||||
function resolveTurnIntent2(patch, userText, opts = {}) {
|
||||
const S = window.SA && window.SA.session;
|
||||
if (S && typeof S.resolveTurnIntent === "function") {
|
||||
return S.resolveTurnIntent(patch, userText, { vetoFn: userAsksNoGenerate });
|
||||
return S.resolveTurnIntent(patch, userText, {
|
||||
vetoFn: userAsksNoGenerate,
|
||||
askGenerateFn: userAsksGenerate,
|
||||
fromAutoCritique: !!opts.fromAutoCritique
|
||||
});
|
||||
}
|
||||
const vetoed = !isMachineTurn(opts) && userAsksNoGenerate(userText);
|
||||
const modelAsked = !!(patch && (patch.generate === true || Array.isArray(patch.actions) && patch.actions.map(String).includes("generate")));
|
||||
const generate = !vetoed && !opts.fromAutoCritique && modelAsked;
|
||||
const modelAsked = !!(patch && (patch.generate === true || patch.generate === 1 || typeof patch.generate === "string" && /^(true|1|yes|on)$/i.test(patch.generate) || Array.isArray(patch.actions) && patch.actions.map(String).includes("generate")));
|
||||
const userAsked = !isMachineTurn(opts) && userAsksGenerate(userText) && !!(modelAsked || String(patch?.prompt || "").trim());
|
||||
const generate = !vetoed && !opts.fromAutoCritique && (modelAsked || userAsked);
|
||||
const hasLook = !!patch && (patch.look_at != null || patch.vision_from != null || patch.vision_slots != null);
|
||||
const look = !!(hasLook && !vetoed && !generate);
|
||||
const ask = Array.isArray(patch?.ask) ? patch.ask.map(String) : typeof patch?.ask === "string" && patch.ask ? [patch.ask] : [];
|
||||
@@ -3364,6 +3440,7 @@ ${patch.prompt}`;
|
||||
genBtn.textContent = "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C";
|
||||
genBtn.addEventListener("click", async () => {
|
||||
if (isGenerateUnavailable()) {
|
||||
setStatus("Generate \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u2014 \u043F\u043E\u0434\u043E\u0436\u0434\u0438 \u0438\u043B\u0438 \u043D\u0430\u0436\u043C\u0438 \u0421\u0442\u043E\u043F");
|
||||
return;
|
||||
}
|
||||
startBusyUi("silent_gen");
|
||||
@@ -4161,7 +4238,7 @@ ${patch.prompt}`;
|
||||
const empty = document.createElement("div");
|
||||
empty.className = "sa-chat-empty";
|
||||
empty.id = "sa_chat_empty";
|
||||
empty.innerHTML = emptyHint || '<div class="sa-chat-empty-title">\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442</div><div class="sa-chat-empty-hint">\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B Generate \u043E\u0441\u0442\u0430\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u0441\u0435\u0439\u0447\u0430\u0441.<br><strong>+</strong> \u2014 \u0435\u0449\u0451 \u043E\u0434\u0438\u043D \u0447\u0430\u0442 \xB7 <strong>\u0418\u0441\u0442\u043E\u0440\u0438\u044F</strong> \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u043A \u043F\u0440\u043E\u0448\u043B\u043E\u043C\u0443 (\u0441 \u0435\u0433\u043E \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438).</div>';
|
||||
empty.innerHTML = emptyHint || '<div class="sa-chat-empty-title">\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442</div><div class="sa-chat-empty-hint">\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B Generate \u043E\u0441\u0442\u0430\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u0441\u0435\u0439\u0447\u0430\u0441.<br><strong>+</strong> \u2014 \u0435\u0449\u0451 \u043E\u0434\u0438\u043D \u0447\u0430\u0442 \xB7 \u043A\u043D\u043E\u043F\u043A\u0430 \u043F\u0430\u043D\u0435\u043B\u0438 \u0441\u043B\u0435\u0432\u0430 \u2014 \u043F\u0440\u043E\u0448\u043B\u044B\u0435 \u0434\u0438\u0430\u043B\u043E\u0433\u0438.</div>';
|
||||
box.appendChild(empty);
|
||||
}
|
||||
function renderHistoryIntoUi(messages) {
|
||||
@@ -4222,19 +4299,34 @@ ${patch.prompt}`;
|
||||
}
|
||||
const chat = findChat(state.activeChatId);
|
||||
el.textContent = chat?.title || "\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442";
|
||||
el.title = (chat?.title || "\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442") + " \u2014 \u043A\u043B\u0438\u043A: \u0418\u0441\u0442\u043E\u0440\u0438\u044F";
|
||||
el.title = chat?.title || "\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442";
|
||||
}
|
||||
function chatHasTranscript(c) {
|
||||
return (c?.messages || []).length > 0 || (c?.messages_count || 0) > 0;
|
||||
}
|
||||
function savedChatsCount() {
|
||||
return (state.chats || []).filter((c) => (c.messages || []).length > 0).length;
|
||||
return (state.chats || []).filter(chatHasTranscript).length;
|
||||
}
|
||||
function isBlankActiveChat() {
|
||||
if ((state.history || []).length) {
|
||||
return false;
|
||||
}
|
||||
const chat = findChat(state.activeChatId);
|
||||
return !chat || !chatHasTranscript(chat);
|
||||
}
|
||||
function syncHistoryBadge() {
|
||||
const btn = $2("sa_btn_chats");
|
||||
if (!btn) {
|
||||
return;
|
||||
const countEl = $2("sa_chats_count");
|
||||
const n = (state.chats || []).filter(chatHasTranscript).length;
|
||||
const open = !!state.chatsPanelOpen;
|
||||
if (btn) {
|
||||
btn.title = open ? n ? `\u0421\u043A\u0440\u044B\u0442\u044C \u0447\u0430\u0442\u044B (${n})` : "\u0421\u043A\u0440\u044B\u0442\u044C \u0447\u0430\u0442\u044B" : n ? `\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0447\u0430\u0442\u044B (${n})` : "\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0447\u0430\u0442\u044B";
|
||||
btn.setAttribute("aria-label", btn.title);
|
||||
}
|
||||
if (countEl) {
|
||||
countEl.hidden = n < 1;
|
||||
countEl.textContent = n > 99 ? "99+" : String(n);
|
||||
}
|
||||
const n = savedChatsCount();
|
||||
btn.textContent = n > 0 ? `\u0418\u0441\u0442\u043E\u0440\u0438\u044F (${n})` : "\u0418\u0441\u0442\u043E\u0440\u0438\u044F";
|
||||
btn.title = n > 0 ? `\u0421\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0445 \u0447\u0430\u0442\u043E\u0432: ${n}. \u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B.` : "\u0418\u0441\u0442\u043E\u0440\u0438\u044F \u0447\u0430\u0442\u043E\u0432 (\u043F\u043E\u043A\u0430 \u043F\u0443\u0441\u0442\u043E)";
|
||||
}
|
||||
function formatChatWhen(ts) {
|
||||
if (!ts) {
|
||||
@@ -4304,7 +4396,7 @@ ${patch.prompt}`;
|
||||
root.innerHTML = "";
|
||||
syncHistoryBadge();
|
||||
const q = (state.chatsQuery || "").trim().toLowerCase();
|
||||
let chats = (state.chats || []).slice().sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)).filter((c) => (c.messages || []).length > 0 || (c.messages_count || 0) > 0);
|
||||
let chats = (state.chats || []).slice().sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)).filter((c) => c.id === state.activeChatId || chatHasTranscript(c));
|
||||
if (q) {
|
||||
const local = chats.filter((c) => chatMatchesQuery(c, q));
|
||||
const seen = new Set(local.map((c) => c.id));
|
||||
@@ -4342,6 +4434,7 @@ ${patch.prompt}`;
|
||||
btn?.classList.toggle("sa-sessions-toggle-active", state.chatsPanelOpen);
|
||||
root?.classList.toggle("sa-drawer-open", state.chatsPanelOpen);
|
||||
localStorage.setItem(LS_CHATS_DRAWER, state.chatsPanelOpen ? "1" : "0");
|
||||
syncHistoryBadge();
|
||||
if (state.chatsPanelOpen) {
|
||||
saveActiveChatToStore();
|
||||
const search = $2("sa_chats_search");
|
||||
@@ -4353,13 +4446,17 @@ ${patch.prompt}`;
|
||||
}
|
||||
saveUiStateToDisk();
|
||||
}
|
||||
async function startNewChat({ saveCurrent = true, force = false } = {}) {
|
||||
if (!force && (state.busy || state.generating)) {
|
||||
setStatus("\u0417\u0430\u043D\u044F\u0442\u043E \u2014 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u043A\u043E\u043D\u0446\u0430 \u043E\u0442\u0432\u0435\u0442\u0430 \u0438\u043B\u0438 \u0421\u0442\u043E\u043F");
|
||||
async function startNewChat({ saveCurrent = true, force = false, openDrawer = false } = {}) {
|
||||
if (!force && isBlankActiveChat()) {
|
||||
setStatus("\u0423\u0436\u0435 \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442");
|
||||
if (openDrawer) {
|
||||
setChatsPanelOpen(true);
|
||||
}
|
||||
$2("sa_input")?.focus();
|
||||
return;
|
||||
}
|
||||
if (force) {
|
||||
abortInFlightWork({ status: "" });
|
||||
if (state.busy || state.generating) {
|
||||
abortInFlightWork({ status: "", interruptSwarm: !!state.generating });
|
||||
}
|
||||
if (saveCurrent) {
|
||||
saveActiveChatToStore({ dropEmpty: true });
|
||||
@@ -4401,6 +4498,12 @@ ${patch.prompt}`;
|
||||
updateCtxChip();
|
||||
setStatus("\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442 \u2014 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B Generate \u043A\u0430\u043A \u0441\u0435\u0439\u0447\u0430\u0441");
|
||||
maybeWelcome();
|
||||
if (openDrawer) {
|
||||
setChatsPanelOpen(true);
|
||||
}
|
||||
if (openDrawer || !force) {
|
||||
$2("sa_input")?.focus();
|
||||
}
|
||||
}
|
||||
async function switchToChat(id) {
|
||||
if (!id || id === state.activeChatId) {
|
||||
@@ -4540,7 +4643,7 @@ ${patch.prompt}`;
|
||||
syncBuildGenButton();
|
||||
clearPersistedHistory();
|
||||
resetContextMemory({ persist: false });
|
||||
resetMessagesUi('<div class="sa-chat-empty-title">\u0427\u0430\u0442 \u043E\u0447\u0438\u0449\u0435\u043D</div><div class="sa-chat-empty-hint">\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0441\u0431\u0440\u043E\u0448\u0435\u043D\u044B. \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B Generate \u043D\u0430 \u043C\u0435\u0441\u0442\u0435. <strong>+</strong> \u2014 \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442 \u0432 \u0418\u0441\u0442\u043E\u0440\u0438\u044E, <strong>\u0418\u0441\u0442\u043E\u0440\u0438\u044F</strong> \u2014 \u043F\u0440\u043E\u0448\u043B\u044B\u0435 \u0434\u0438\u0430\u043B\u043E\u0433\u0438.</div>');
|
||||
resetMessagesUi('<div class="sa-chat-empty-title">\u0427\u0430\u0442 \u043E\u0447\u0438\u0449\u0435\u043D</div><div class="sa-chat-empty-hint">\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0441\u0431\u0440\u043E\u0448\u0435\u043D\u044B. \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B Generate \u043D\u0430 \u043C\u0435\u0441\u0442\u0435. <strong>+</strong> \u2014 \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442, \u043A\u043D\u043E\u043F\u043A\u0430 \u043F\u0430\u043D\u0435\u043B\u0438 \u0441\u043B\u0435\u0432\u0430 \u2014 \u043F\u0440\u043E\u0448\u043B\u044B\u0435 \u0434\u0438\u0430\u043B\u043E\u0433\u0438.</div>');
|
||||
setStatus("\u0427\u0430\u0442 \u043E\u0447\u0438\u0449\u0435\u043D");
|
||||
updateSessionLabel();
|
||||
syncHistoryBadge();
|
||||
@@ -5577,7 +5680,7 @@ ${patch.prompt}`;
|
||||
if (!state.gotDelta || !state.busy || state.generating || state.turnSettled) {
|
||||
return;
|
||||
}
|
||||
const waitMs = state.streamFenceDone ? 4e3 : 15e3;
|
||||
const waitMs = state.streamFenceDone ? 800 : state.gotDelta ? 2200 : 15e3;
|
||||
if (Date.now() - (state.lastDeltaAt || 0) < waitMs) {
|
||||
return;
|
||||
}
|
||||
@@ -6159,23 +6262,30 @@ ${patch.prompt}`;
|
||||
state.streamFenceDone = false;
|
||||
return div;
|
||||
}
|
||||
function parseTerminalPatchObject(raw) {
|
||||
try {
|
||||
const obj = JSON.parse(String(raw || "").trim());
|
||||
const terminal = window.SA && typeof SA.isTerminalStreamPatch === "function" ? SA.isTerminalStreamPatch(obj) : typeof isPatchObject === "function" && isPatchObject(obj);
|
||||
return terminal ? obj : null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function streamHasClosedPatchFence(text) {
|
||||
const t = String(text || "");
|
||||
if (!/```[\s\S]*```/.test(t)) {
|
||||
return false;
|
||||
}
|
||||
const re = /```(?:json)?\s*([\s\S]*?)```/gi;
|
||||
let match;
|
||||
while ((match = re.exec(t)) !== null) {
|
||||
try {
|
||||
const obj = JSON.parse(match[1].trim());
|
||||
const terminal = window.SA && typeof SA.isTerminalStreamPatch === "function" ? SA.isTerminalStreamPatch(obj) : typeof isPatchObject === "function" && isPatchObject(obj);
|
||||
if (terminal) {
|
||||
if (/```[\s\S]*```/.test(t)) {
|
||||
const re = /```(?:json)?\s*([\s\S]*?)```/gi;
|
||||
let match;
|
||||
while ((match = re.exec(t)) !== null) {
|
||||
if (parseTerminalPatchObject(match[1])) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
const brace = t.lastIndexOf("{");
|
||||
if (brace >= 0 && parseTerminalPatchObject(t.slice(brace))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function trimToClosedPatchFence(text) {
|
||||
@@ -6184,16 +6294,18 @@ ${patch.prompt}`;
|
||||
let match;
|
||||
let lastEnd = -1;
|
||||
while ((match = re.exec(t)) !== null) {
|
||||
try {
|
||||
const obj = JSON.parse(match[1].trim());
|
||||
const terminal = window.SA && typeof SA.isTerminalStreamPatch === "function" ? SA.isTerminalStreamPatch(obj) : typeof isPatchObject === "function" && isPatchObject(obj);
|
||||
if (terminal) {
|
||||
lastEnd = match.index + match[0].length;
|
||||
}
|
||||
} catch (e) {
|
||||
if (parseTerminalPatchObject(match[1])) {
|
||||
lastEnd = match.index + match[0].length;
|
||||
}
|
||||
}
|
||||
return lastEnd > 0 ? t.slice(0, lastEnd).trimEnd() : t;
|
||||
if (lastEnd > 0) {
|
||||
return t.slice(0, lastEnd).trimEnd();
|
||||
}
|
||||
const brace = t.lastIndexOf("{");
|
||||
if (brace >= 0 && parseTerminalPatchObject(t.slice(brace))) {
|
||||
return t.trimEnd();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
function appendStreamDelta(delta) {
|
||||
if (state.streamFenceDone) {
|
||||
@@ -6218,6 +6330,18 @@ ${patch.prompt}`;
|
||||
if (streamHasClosedPatchFence(state.streamText)) {
|
||||
state.streamText = trimToClosedPatchFence(state.streamText);
|
||||
state.streamFenceDone = true;
|
||||
setAssistantBody(state.streamEl, state.streamText, { live: true });
|
||||
scrollMessagesToBottom();
|
||||
const fn = state.onClosedTerminalFence;
|
||||
state.onClosedTerminalFence = null;
|
||||
if (typeof fn === "function") {
|
||||
try {
|
||||
fn(state.streamText);
|
||||
} catch (e) {
|
||||
console.warn("Assistent closed-fence finalize", e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
setAssistantBody(state.streamEl, state.streamText, { live: true });
|
||||
scrollMessagesToBottom();
|
||||
@@ -6242,16 +6366,9 @@ ${patch.prompt}`;
|
||||
const { prose, patch } = extractPatch2(fullReply);
|
||||
setAssistantBody(el, prose || fullReply || "");
|
||||
el.querySelectorAll(".sa-patch, .sa-civitai-list").forEach((n) => n.remove());
|
||||
if (patch && !(card && !patch.prompt && !patch.actions && !patch.loras)) {
|
||||
if (patch) {
|
||||
const silent = !!(meta && meta.silentPatch) || !!state.pendingSilentGen;
|
||||
mountPatchBlock(el, patch, { silent });
|
||||
} else if (card) {
|
||||
const wrap = document.createElement("div");
|
||||
wrap.className = "sa-patch sa-card-json-preview";
|
||||
const pre = document.createElement("pre");
|
||||
pre.textContent = JSON.stringify(card, null, 2);
|
||||
wrap.appendChild(pre);
|
||||
el.appendChild(wrap);
|
||||
}
|
||||
if (!(meta && meta.historical)) {
|
||||
mountCurateButtons(el, meta);
|
||||
@@ -7387,8 +7504,6 @@ ${data.ui.help_extra}`.trim();
|
||||
const n = state.inventory.loras.length;
|
||||
const ck = state.inventory.checkpoints.length;
|
||||
setStatus(`Inventory: ${n} LoRAs, ${ck} ckpts${rescan ? " (rescanned)" : ""}`);
|
||||
if (state.view === "cards") {
|
||||
}
|
||||
if (done) {
|
||||
done(state.inventory);
|
||||
}
|
||||
@@ -8314,7 +8429,7 @@ ${summary || "(\u043F\u0443\u0441\u0442\u043E)"}`;
|
||||
}
|
||||
const extracted = typeof extractPatch2 === "function" ? extractPatch2(reply) : { patch: null };
|
||||
let effective = extracted && extracted.patch ? extracted.patch : null;
|
||||
if (opts.fromPromptEnRetry && effective && typeof mergePromptEnRewrite === "function") {
|
||||
if (opts.fromPromptEnRetry && typeof mergePromptEnRewrite === "function" && (effective || state.pendingPromptEnMerge)) {
|
||||
effective = mergePromptEnRewrite(effective);
|
||||
}
|
||||
const S = window.SA && window.SA.session;
|
||||
@@ -8322,11 +8437,12 @@ ${summary || "(\u043F\u0443\u0441\u0442\u043E)"}`;
|
||||
if (effective && act && typeof act.noteModelCommands === "function") {
|
||||
act.noteModelCommands(effective);
|
||||
}
|
||||
const promptChanged = !!(effective && String(effective.prompt || "").trim());
|
||||
if (effective && S) {
|
||||
state.chatSession = S.mergeDelta(state.chatSession || S.emptySession(), effective);
|
||||
activityDone("delta", {
|
||||
kind: "delta",
|
||||
label: "\u041E\u0431\u043D\u043E\u0432\u0438\u043B \u0441\u0435\u0441\u0441\u0438\u044E",
|
||||
label: promptChanged ? "\u041F\u0440\u043E\u043C\u043F\u0442 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D" : "\u041E\u0431\u043D\u043E\u0432\u0438\u043B \u0441\u0435\u0441\u0441\u0438\u044E",
|
||||
detail: Object.keys(effective).filter((k) => effective[k] != null && !["actions", "notes"].includes(k)).slice(0, 10).join(", ")
|
||||
});
|
||||
try {
|
||||
@@ -8342,7 +8458,10 @@ ${summary || "(\u043F\u0443\u0441\u0442\u043E)"}`;
|
||||
if (Array.isArray(effective?.actions) && effective.actions.map(String).includes("interrupt")) {
|
||||
if (typeof doInterruptNow === "function") doInterruptNow();
|
||||
}
|
||||
const intent = resolveTurnIntent2(effective, opts.userText || "", opts);
|
||||
let intent = resolveTurnIntent2(effective, opts.userText || "", opts);
|
||||
if (opts.userWantsGenerate && effective && !intent.vetoed && !fromAutoCritique) {
|
||||
intent = { ...intent, generate: true };
|
||||
}
|
||||
if (effective) {
|
||||
if (intent.generate) {
|
||||
const acts = Array.isArray(effective.actions) ? effective.actions.map(String) : [];
|
||||
@@ -8450,6 +8569,10 @@ ${summary || "(\u043F\u0443\u0441\u0442\u043E)"}`;
|
||||
if (S && effective) state.chatSession = S.mergeDelta(state.chatSession || S.emptySession(), effective);
|
||||
await pushSessionToSwarm(state.chatSession);
|
||||
if (typeof syncLiveParamsBar === "function") syncLiveParamsBar();
|
||||
if (typeof appendSystemNote === "function") {
|
||||
appendSystemNote(promptChanged ? "\u041F\u0440\u043E\u043C\u043F\u0442 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D \xB7 Generate" : "\u0417\u0430\u043F\u0443\u0441\u043A\u0430\u044E Generate");
|
||||
}
|
||||
setStatus(promptChanged ? "\u041F\u0440\u043E\u043C\u043F\u0442 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D \xB7 Generate" : "Generate");
|
||||
const srcOut = await runGenerateFromPatch(
|
||||
{ ...effective || {}, actions: ["generate"], generate: true },
|
||||
{ force: true, fromSession: true }
|
||||
@@ -8459,12 +8582,20 @@ ${summary || "(\u043F\u0443\u0441\u0442\u043E)"}`;
|
||||
if (typeof maybeAutoCritique === "function") await maybeAutoCritique(srcOut);
|
||||
if (typeof maybeAutoVisionLook === "function") await maybeAutoVisionLook(srcOut);
|
||||
}
|
||||
} else if (effective && $2("sa_auto_apply")?.checked) {
|
||||
} else if (effective) {
|
||||
if (S) state.chatSession = S.mergeDelta(state.chatSession || S.emptySession(), effective);
|
||||
await pushSessionToSwarm(state.chatSession);
|
||||
if (typeof syncLiveParamsBar === "function") syncLiveParamsBar();
|
||||
if (promptChanged || $2("sa_auto_apply")?.checked) {
|
||||
await pushSessionToSwarm(state.chatSession);
|
||||
if (typeof syncLiveParamsBar === "function") syncLiveParamsBar();
|
||||
if (promptChanged && typeof appendSystemNote === "function") {
|
||||
appendSystemNote("\u041F\u0440\u043E\u043C\u043F\u0442 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D");
|
||||
}
|
||||
if (promptChanged) {
|
||||
setStatus("\u041F\u0440\u043E\u043C\u043F\u0442 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D");
|
||||
}
|
||||
}
|
||||
if (!state.generating && typeof stopBusyUi === "function") {
|
||||
stopBusyUi(intent.vetoed ? "\u0417\u0430\u043F\u043E\u043C\u043D\u0438\u043B \xB7 \u0431\u0435\u0437 Generate" : "");
|
||||
stopBusyUi(intent.vetoed ? "\u0417\u0430\u043F\u043E\u043C\u043D\u0438\u043B \xB7 \u0431\u0435\u0437 Generate" : promptChanged ? "\u041F\u0440\u043E\u043C\u043F\u0442 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D" : "");
|
||||
}
|
||||
}
|
||||
state.pendingSilentGen = false;
|
||||
@@ -8628,12 +8759,12 @@ ${summary || "(\u043F\u0443\u0441\u0442\u043E)"}`;
|
||||
return true;
|
||||
}
|
||||
if (cmd === "new" || cmd === "newchat") {
|
||||
await startNewChat({ saveCurrent: true });
|
||||
await startNewChat({ saveCurrent: true, openDrawer: true });
|
||||
return true;
|
||||
}
|
||||
if (cmd === "history" || cmd === "chats" || cmd === "sessions") {
|
||||
setChatsPanelOpen(true);
|
||||
setStatus("/history");
|
||||
setChatsPanelOpen(!state.chatsPanelOpen);
|
||||
setStatus(state.chatsPanelOpen ? "/history" : "\u0427\u0430\u0442\u044B \u0441\u043A\u0440\u044B\u0442\u044B");
|
||||
return true;
|
||||
}
|
||||
if (cmd === "compress" || cmd === "compact" || cmd === "\u0441\u0436\u0430\u0442\u044C") {
|
||||
@@ -9036,6 +9167,8 @@ ${HELP_TEXT}`);
|
||||
startBusyUi(state.expectColdLoad ? "loading" : "thinking");
|
||||
}
|
||||
const context = collectLiveContext();
|
||||
context.prior_assistant_turns = (state.history || []).filter((m) => m && m.role === "assistant" && !m.systemish).length;
|
||||
context.do_not_greet = context.prior_assistant_turns > 0;
|
||||
context.has_vision_image = visionReadySlots().length > 0;
|
||||
context.images_in_request = !!(images && images.length);
|
||||
context.attached_slot_ids = attachableSlots().map((s) => s.id);
|
||||
@@ -9074,6 +9207,7 @@ ${HELP_TEXT}`);
|
||||
return;
|
||||
}
|
||||
state.turnSettled = true;
|
||||
state.onClosedTerminalFence = null;
|
||||
clearStreamStall();
|
||||
if (meta.system_chars != null) {
|
||||
state.lastSystemChars = Number(meta.system_chars) || 0;
|
||||
@@ -9128,6 +9262,7 @@ ${HELP_TEXT}`);
|
||||
return;
|
||||
}
|
||||
state.turnSettled = true;
|
||||
state.onClosedTerminalFence = null;
|
||||
clearStreamStall();
|
||||
state.busy = false;
|
||||
setInterruptVisible(state.generating);
|
||||
@@ -9144,14 +9279,19 @@ ${HELP_TEXT}`);
|
||||
};
|
||||
if (typeof makeWSRequest === "function") {
|
||||
beginStreamMessage(msgMeta);
|
||||
armStreamStall(chatEpoch, (reply) => {
|
||||
const settleStreamReply = (reply) => {
|
||||
if (state.turnSettled || chatEpoch !== state.chatEpoch) {
|
||||
return;
|
||||
}
|
||||
const raw = String(reply || state.streamText || "").trim() || (state.streamEl?.querySelector(".sa-msg-body")?.textContent || "");
|
||||
if (state.streamEl) {
|
||||
finalizeStreamMessage(reply, []);
|
||||
finalizeStreamMessage(raw, []);
|
||||
}
|
||||
finishOk(reply, [], {});
|
||||
finishOk(raw, [], {});
|
||||
};
|
||||
state.onClosedTerminalFence = (text2) => settleStreamReply(text2);
|
||||
armStreamStall(chatEpoch, (reply) => {
|
||||
settleStreamReply(reply);
|
||||
});
|
||||
makeWSRequest(
|
||||
"AssistentChatWS",
|
||||
@@ -9184,12 +9324,13 @@ ${HELP_TEXT}`);
|
||||
if (data.delta) {
|
||||
appendStreamDelta(data.delta);
|
||||
}
|
||||
if (data.done || data.reply != null) {
|
||||
if (data.done || typeof data.reply === "string" && data.reply.length > 0 && !data.delta) {
|
||||
if (state.turnSettled) {
|
||||
return;
|
||||
}
|
||||
const reply = data.reply || state.streamEl?.querySelector(".sa-msg-body")?.textContent || "";
|
||||
const reply = String(state.streamText || data.reply || "").trim() || state.streamEl?.querySelector(".sa-msg-body")?.textContent || "";
|
||||
const civitai = data.civitai_results || [];
|
||||
state.onClosedTerminalFence = null;
|
||||
if (state.streamEl) {
|
||||
finalizeStreamMessage(reply, civitai);
|
||||
}
|
||||
@@ -9454,7 +9595,14 @@ ${HELP_TEXT}`);
|
||||
wireSplitter();
|
||||
registerSendButton();
|
||||
wireSlashInput();
|
||||
$2("sa_btn_new_chat")?.addEventListener("click", () => startNewChat({ saveCurrent: true }));
|
||||
$2("sa_btn_new_chat")?.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
startNewChat({ saveCurrent: true, openDrawer: true });
|
||||
});
|
||||
$2("sa_btn_new_chat_bar")?.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
startNewChat({ saveCurrent: true, openDrawer: true });
|
||||
});
|
||||
$2("sa_ctx_chip")?.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
toggleCtxPanel();
|
||||
@@ -9489,16 +9637,6 @@ ${HELP_TEXT}`);
|
||||
setChatsPanelOpen(!state.chatsPanelOpen);
|
||||
});
|
||||
$2("sa_btn_chats_close")?.addEventListener("click", () => setChatsPanelOpen(false));
|
||||
$2("sa_session_label")?.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
setChatsPanelOpen(!state.chatsPanelOpen);
|
||||
});
|
||||
$2("sa_session_label")?.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
setChatsPanelOpen(!state.chatsPanelOpen);
|
||||
}
|
||||
});
|
||||
$2("sa_chats_panel")?.addEventListener("click", (e) => e.stopPropagation());
|
||||
$2("sa_chats_list")?.addEventListener("click", (e) => {
|
||||
const row = e.target.closest(".sa-chat-row");
|
||||
@@ -9513,9 +9651,7 @@ ${HELP_TEXT}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (e.target.closest("[data-open]")) {
|
||||
switchToChat(id);
|
||||
}
|
||||
switchToChat(id);
|
||||
});
|
||||
let chatsSearchTimer = null;
|
||||
$2("sa_chats_search")?.addEventListener("input", () => {
|
||||
@@ -9753,7 +9889,11 @@ ${HELP_TEXT}`);
|
||||
});
|
||||
$2("sa_chips")?.addEventListener("click", async (e) => {
|
||||
const btn = e.target.closest(".sa-chip");
|
||||
if (!btn || state.busy || state.generating) {
|
||||
if (!btn) {
|
||||
return;
|
||||
}
|
||||
if (state.busy || state.generating) {
|
||||
setStatus("\u0417\u0430\u043D\u044F\u0442\u043E \u2014 \u043F\u043E\u0434\u043E\u0436\u0434\u0438 \u0438\u043B\u0438 \u043D\u0430\u0436\u043C\u0438 \u0421\u0442\u043E\u043F");
|
||||
return;
|
||||
}
|
||||
const aspect = btn.getAttribute("data-aspect");
|
||||
|
||||
Reference in New Issue
Block a user