Ship Assistent 0.11.3: variants grid, EN Krea prep, and stream fence fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-22 04:58:03 +03:00
co-authored by Cursor
parent 036484c7b7
commit 56e089d8da
18 changed files with 10244 additions and 9218 deletions
+136
View File
@@ -5,6 +5,7 @@
min-height: 28rem;
padding: 0.5rem 0.65rem 0.65rem;
box-sizing: border-box;
position: relative;
}
.sa-gate {
@@ -1847,6 +1848,137 @@
align-items: center;
}
.sa-board.sa-board-variants {
grid-template-columns: 1fr 1fr;
grid-auto-rows: minmax(7.5rem, 1fr);
}
.sa-slot.sa-slot-gen-result .sa-slot-open {
appearance: none;
border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
background: color-mix(in srgb, currentColor 10%, transparent);
color: inherit;
border-radius: 999px;
padding: 0.05rem 0.45rem;
font-size: 0.68rem;
cursor: pointer;
margin-left: auto;
opacity: 0.85;
}
.sa-slot.sa-slot-gen-result .sa-slot-open:hover {
opacity: 1;
}
.sa-lightbox {
position: absolute;
inset: 0;
z-index: 80;
display: flex;
align-items: center;
justify-content: center;
pointer-events: auto;
}
.sa-lightbox[hidden] {
display: none !important;
}
.sa-lightbox-backdrop {
position: absolute;
inset: 0;
background: color-mix(in srgb, #000 62%, transparent);
}
.sa-lightbox-panel {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
gap: 0.45rem;
width: min(96%, 52rem);
max-height: 94%;
padding: 0.55rem 0.65rem 0.65rem;
border-radius: 0.65rem;
border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
background: color-mix(in srgb, Canvas 92%, transparent);
box-shadow: 0 12px 40px color-mix(in srgb, #000 35%, transparent);
}
.sa-lightbox-head {
display: flex;
align-items: center;
gap: 0.45rem;
}
.sa-lightbox-title {
font-weight: 650;
font-size: 0.9rem;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.sa-lightbox-idx {
font-size: 0.75rem;
opacity: 0.7;
}
.sa-lightbox-body {
position: relative;
display: flex;
align-items: center;
justify-content: center;
min-height: 12rem;
flex: 1;
overflow: hidden;
}
.sa-lightbox-body img {
max-width: 100%;
max-height: min(70vh, 36rem);
object-fit: contain;
border-radius: 0.35rem;
}
.sa-lightbox-nav {
appearance: none;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 2rem;
height: 2.4rem;
border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
border-radius: 0.4rem;
background: color-mix(in srgb, Canvas 80%, transparent);
color: inherit;
font-size: 1.4rem;
line-height: 1;
cursor: pointer;
opacity: 0.85;
}
.sa-lightbox-nav:hover {
opacity: 1;
}
.sa-lightbox-prev {
left: 0.25rem;
}
.sa-lightbox-next {
right: 0.25rem;
}
.sa-lightbox-actions {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
justify-content: flex-end;
}
@media (max-width: 900px) {
.sa-layout {
flex-direction: column;
@@ -1872,4 +2004,8 @@
border-right: none;
border-bottom: 1px solid color-mix(in srgb, currentColor 18%, transparent);
}
.sa-lightbox-panel {
width: 98%;
max-height: 96%;
}
}
+757 -37
View File
File diff suppressed because it is too large Load Diff
+44
View File
@@ -16,6 +16,7 @@ window.SA = window.SA || {};
'clear_prompt_images', 'slot_to_prompt_image', 'pack',
'memories', 'memory_query', 'memory_kind', 'tag_query', 'user_prefs',
'controls', 'persona_clone', 'persona_shelves', 'persona', 'notes',
'variants',
];
const FENCE_RE = /```(?:json)?\s*([\s\S]*?)```/gi;
@@ -92,9 +93,52 @@ window.SA = window.SA || {};
return { prose, patch: lastPatch };
}
/**
* Closed fence worth freezing the stream / stopping Ollama early.
* Weak fences (pack / creativity / empty) must NOT stop — model often continues with the real patch.
*/
function isTerminalStreamPatch(obj) {
if (!obj || typeof obj !== 'object') {
return false;
}
if (isCardObject(obj)) {
return true;
}
if (Array.isArray(obj.variants) && obj.variants.length) {
return true;
}
if (obj.look_at != null || obj.vision_from != null || obj.vision_slots != null) {
return true;
}
if (obj.search_query != null || obj.civitai_query != null
|| obj.memory_query != null || obj.tag_query != null || obj.inventory_query != null) {
return true;
}
const acts = Array.isArray(obj.actions) ? obj.actions.map(String) : [];
const hopOrGen = [
'skill_load', 'persona_read', 'memory_get', 'memory_search', 'lookup_tags',
'list_inventory', 'search_civitai', 'interrupt', 'generate',
'memory_upsert', 'user_pref_upsert',
];
if (acts.some((a) => hopOrGen.includes(a))) {
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
|| obj.memories != null || obj.user_prefs != null) {
return true;
}
return false;
}
SA.PATCH_KEYS = PATCH_KEYS;
SA.isCardObject = isCardObject;
SA.isPatchObject = isPatchObject;
SA.isTerminalStreamPatch = isTerminalStreamPatch;
SA.normalizePatch = normalizePatch;
SA.extractPatch = extractPatch;
})();
+2 -1
View File
@@ -530,7 +530,8 @@ public sealed class AssistentConfig
}
if (patch["prompt"] != null || patch["loras"] != null || patch["aspect"] != null
|| patch["width"] != null || patch["height"] != null || patch["steps"] != null
|| patch["cfg"] != null || patch["seed"] != null)
|| patch["cfg"] != null || patch["seed"] != null
|| patch["variants"] != null)
{
return true;
}
+8
View File
@@ -166,6 +166,12 @@ public partial class SwarmAssistentExtension
{
int numCtx = Config.LoadAssistant(AssistentConfig.SafeId(personaId) ?? Config.DefaultPersonaId())["num_ctx"]?.Value<int?>()
?? DefaultNumCtxFallback;
int numPredict = Config.LoadAssistant(AssistentConfig.SafeId(personaId) ?? Config.DefaultPersonaId())["num_predict"]?.Value<int?>()
?? 3072;
if (numPredict < 512)
{
numPredict = 512;
}
JObject payload = new()
{
["model"] = modelName,
@@ -174,6 +180,8 @@ public partial class SwarmAssistentExtension
["options"] = new JObject
{
["num_ctx"] = numCtx,
// Without this, Ollama defaults can cut mid-prompt / mid-skill_load fence.
["num_predict"] = numPredict,
},
["keep_alive"] = "15m",
};
+77 -10
View File
@@ -21,6 +21,7 @@ public partial class SwarmAssistentExtension
"clear_prompt_images", "slot_to_prompt_image", "pack", "memories", "memory",
"memory_query", "memory_kind", "tag_query", "user_prefs",
"inventory_query", "skills", "persona_shelves", "controls",
"variants",
];
static bool HasValue(JObject obj, string key)
@@ -107,8 +108,10 @@ public partial class SwarmAssistentExtension
}
/// <summary>
/// If the reply already contains a closed fenced patch/card, cut everything after it.
/// Models often keep writing («Готово!», second aspect, …) and the stream never feels done.
/// If the reply already contains a closed fenced patch/card that is "done enough" to act on,
/// cut everything after it. Do NOT stop on weak fences (pack/creativity/notes-only) — models
/// often emit a tiny JSON first then the real prompt fence; aborting early cuts the prompt
/// and blocks skill_load / generate.
/// </summary>
static bool TryTruncateAtCompleteFence(string reply, out string truncated)
{
@@ -129,18 +132,11 @@ public partial class SwarmAssistentExtension
try
{
JObject obj = JObject.Parse(raw);
if (obj is null)
{
continue;
}
bool usable = LooksLikeCardObject(obj)
|| Array.Exists(PatchKeys, k => obj[k] is not null);
if (!usable)
if (obj is null || !FenceIsTerminalPatch(obj))
{
continue;
}
truncated = reply.Substring(0, match.Index + match.Length).TrimEnd();
// Only treat as complete if the fence actually closed (regex requires ```).
return true;
}
catch
@@ -151,6 +147,77 @@ public partial class SwarmAssistentExtension
return false;
}
/// <summary>
/// True when a closed fence is worth aborting the Ollama stream (real deliverable or tool hop).
/// </summary>
static bool FenceIsTerminalPatch(JObject obj)
{
if (obj is null)
{
return false;
}
if (LooksLikeCardObject(obj))
{
return true;
}
if (obj["variants"] is JArray variants && variants.Count > 0)
{
return true;
}
if (HasValue(obj, "look_at") || HasValue(obj, "vision_from") || HasValue(obj, "vision_slots"))
{
return true;
}
if (HasValue(obj, "search_query") || HasValue(obj, "civitai_query"))
{
return true;
}
if (HasValue(obj, "memory_query") || HasValue(obj, "tag_query") || HasValue(obj, "inventory_query"))
{
return true;
}
if (obj["actions"] is JArray acts)
{
foreach (JToken a in acts)
{
string s = a?.ToString() ?? "";
if (string.IsNullOrWhiteSpace(s))
{
continue;
}
if (s.Equals("skill_load", StringComparison.OrdinalIgnoreCase)
|| s.Equals("persona_read", StringComparison.OrdinalIgnoreCase)
|| s.Equals("memory_get", StringComparison.OrdinalIgnoreCase)
|| s.Equals("memory_search", StringComparison.OrdinalIgnoreCase)
|| s.Equals("lookup_tags", StringComparison.OrdinalIgnoreCase)
|| s.Equals("list_inventory", StringComparison.OrdinalIgnoreCase)
|| s.Equals("search_civitai", StringComparison.OrdinalIgnoreCase)
|| s.Equals("interrupt", StringComparison.OrdinalIgnoreCase)
|| s.Equals("generate", StringComparison.OrdinalIgnoreCase)
|| s.Equals("memory_upsert", StringComparison.OrdinalIgnoreCase)
|| s.Equals("user_pref_upsert", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
string prompt = obj["prompt"]?.ToString()?.Trim() ?? "";
if (prompt.Length >= 48)
{
return true;
}
// Real param change without prose notes
if (HasValue(obj, "loras") || HasValue(obj, "aspect") || HasValue(obj, "steps")
|| HasValue(obj, "width") || HasValue(obj, "height") || HasValue(obj, "cfg")
|| HasValue(obj, "seed") || HasValue(obj, "controls")
|| HasValue(obj, "memories") || HasValue(obj, "user_prefs"))
{
return true;
}
// Weak: pack / creativity / intensity / empty actions / notes-only → keep streaming
return false;
}
static string ExtractSearchQuery(JObject patch)
{
if (patch is null)
+2
View File
@@ -1,5 +1,6 @@
{
"num_ctx": 16384,
"num_predict": 3072,
"max_civitai_hops": 2,
"max_loras_inventory": 150,
"max_checkpoints_inventory": 60,
@@ -9,6 +10,7 @@
"inventory_prompt_names": 24,
"inventory_hop_limit": 20,
"max_ref_slots": 4,
"max_gen_variants": 4,
"default_pack": "ordinary",
"default_persona": "neutral",
"embed_model": "nomic-embed-text",
+18 -3
View File
@@ -18,7 +18,7 @@ When instructions conflict, apply this order (highest wins):
Exact = defaults encyclopedia. About the user = human taste. RAG = soft craft notes. Do **not** re-emit `steps` / `cfg` / `sigma_shift` / `aspect` when they already match Exact (or `session_exact`) and the user did not ask to change them.
Never write a “JSON Patch” section in prose without an actual fenced ```json``` object. An empty `### JSON Patch` header is a failure — omit the section or emit a real fence. Keep prose short (a few lines). **After the closing ``` of the JSON fence, STOP** — no «Готово!», no second aspect, no “сейчас сгенерирую оба”. One turn = one patch (one aspect). Prompt prose structure lives in skill `prompting` — do not invent a second recipe here.
Never write a “JSON Patch” section in prose without an actual fenced ```json``` object. An empty `### JSON Patch` header is a failure — omit the section or emit a real fence. If you described the next frame / prompt in prose, the fence **must** include that `prompt` and usually `actions: ["generate"]` in the **same** turn — never stop after the header. **`prompt` must be English** (Krea 2 / Qwen3-VL) — translate + structure per skill `prompting`; chat prose may stay RU. Keep prose short (a few lines). **After the closing ``` of the JSON fence, STOP** — no «Готово!», no second fenced patch, no “сейчас сгенерирую оба” in prose. **One turn = one patch.** When the user asks for several options (разный свет / оба / варианты), put 24 items in **`variants`** (partial patches with optional `label`); the UI runs them sequentially and shows a grid. Do not emit two fences. Ordinary single-image requests stay one patch without `variants`. Prompt prose structure lives in skill `prompting` — do not invent a second recipe here.
## Live context
@@ -52,18 +52,33 @@ Never write a “JSON Patch” section in prose without an actual fenced ```json
}
```
Several options in one ask (still one fence):
```json
{
"prompt": "same subject base…",
"aspect": "16:9",
"actions": ["generate"],
"variants": [
{ "label": "warm light", "prompt": "… warm window light …" },
{ "label": "cool light", "prompt": "… cool moonlight …" },
{ "label": "portrait 9:16", "aspect": "9:16" }
]
}
```
### Patch rules
- Omit unchanged keys. Prefer omitting Exact-matching `steps`/`cfg`/`sigma_shift`/`aspect`.
- Prefer omitting Exact-matching **`controls`** (e.g. do not re-emit `"horny": 35` / `"preference_bias": 0.35` when unchanged) — echoing defaults in a Generate patch resets the UI sliders.
- `loras` replaces the full intended set for Apply. Prefer `aspect` over raw width/height.
- Optional keys (seed, vary, init/mask, creativity/sliders, pack, **controls**, persona authoring, search/memory queries) — use when needed; packs list the ones for that mode.
- Optional keys (seed, vary, init/mask, creativity/sliders, pack, **controls**, persona authoring, search/memory queries, **`variants`**) — use when needed; packs list the ones for that mode.
- **`controls`** — only keys declared in this persona's `controls.json` (Exact). Clamp to min/max. Example: `"controls": { "horny": 55 }`. Do not invent control ids.
- Do not invent model or LoRA filenames.
### Actions / hops
- `"generate"` — Apply + start generation when the user wants a new image.
- `"generate"` — Apply + start generation when the user wants a new image. Auto-Generate is a **UI checkbox** (Settings → Поведение); the model cannot toggle it — emit `actions:["generate"]` instead.
- If the user only asks to **remember / save** a prompt as base/template («запомни», «как базовый промпт», «шаблон») and did **not** ask for a new image: **omit** `actions: ["generate"]`, do **not** `look_at`. Prefer `memory_upsert` (kind `note`, key like `base_prompt`) or a short ack; you may echo `prompt` in the patch only to sync the SwarmUI box — the UI will not Generate on remember turns.
- `"search_civitai"` + **required** short `search_query` — Civitai hop (user Confirms downloads). Without `search_query` the hop is skipped (never search the whole user message).
- `"interrupt"` — stop generation.
+1
View File
@@ -30,6 +30,7 @@
},
"facts": {
"architecture": "Krea 2 is a 12B DiT architecture. Not FLUX, not SDXL, not FLUX.1-Krea. Text encoder: Qwen3-VL 4B. VAE: Qwen Image VAE. Use only Krea2-trained LoRAs — never suggest FLUX/SDXL LoRAs.",
"prompt_language": "Chat model always prep's Generate prompt for Krea: English natural prose for Qwen3-VL, structured (subject→pose→setting→camera→light). Chat may be RU; never leave Russian or thin drafts in patch.prompt.",
"negatives": "Negative prompts are nearly useless with Qwen3-VL. Prefer positives (sharp focus, empty street) over no blur / no people. Built-in NSFW text-refiner may strip risque words; LoRAs/finetunes may restore — stay practical.",
"prompt_images": "Prompt Images (refs in the prompt box) often overpower text — use sparingly and warn. Init Image = structure (img2img). Mask = local fix. They are not interchangeable. Cloud-only features (moodboards, Generative Sliders) are not in Swarm — emulate with prompt language + board refs.",
"turbo": "Krea 2 Turbo defaults live in exact.generation / exact.profiles.turbo. Never use CFG 0 — broken output. Side ~1024 (1284096 OK).",
+2
View File
@@ -27,3 +27,5 @@ Otherwise **stay in ordinary** and just do the work.
## Deliverable
Same as write_prompt: short reply + one fenced JSON patch; `actions: ["generate"]` when they want an image.
«давай дальше» / next frame = new English `prompt` + `actions:["generate"]` in the **same** turn — never leave an empty `### JSON Patch` header. Chat may be RU; **Generate `prompt` is always EN** (skill `prompting`).
Several options in one ask → `variants` (24 partial patches with `label`); still one fence, still STOP after it.
+2 -1
View File
@@ -1,6 +1,6 @@
# Mode: write_prompt
Goal: craft or improve a **Krea 2** prompt that will generate well on Turbo (local Swarm). Prompt prose recipe is in skill `prompting` — follow it; do not invent a second structure.
Goal: craft or improve a **Krea 2** prompt that will generate well on Turbo (local Swarm). Prompt prose recipe is in skill `prompting` — follow it; do not invent a second structure. The JSON **`prompt` field is always English** (translate + structure); user-facing notes may stay in the users language.
## Deliverable
@@ -9,6 +9,7 @@ Goal: craft or improve a **Krea 2** prompt that will generate well on Turbo (loc
- `actions: ["generate"]` when the user wants a new image — UI applies + Generate without Apply buttons.
- Prefer Exact Turbo defaults / `recommended_params`. Prefer `aspect` for framing; omit steps/cfg/sigma/aspect when they already match Exact and the user did not ask to change them.
- Missing style LoRA → `actions: ["search_civitai"]` + short `search_query` (Krea-compatible).
- User wants several options (оба / варианты / разный свет) → `variants: [{label, prompt|aspect|…}, …]` (24). Base keys inherit; each item overrides only its diffs. Still one fence.
### Bad → good
+1 -1
View File
@@ -1,6 +1,6 @@
{
"always": [
"Match the user's language (RU or EN)",
"Match the user's language (RU or EN) in chat — Generate prompt stays English",
"Use only inventory / memory_hits / cards for LoRA names and triggers",
"Emit valid JSON patches when changing generation state"
],
+23 -5
View File
@@ -1,9 +1,27 @@
# Skill: prompting
Write **natural prose** for a photographer/director — not Danbooru tags, not `(word:1.5)`, not `masterpiece / best quality / 8k`.
The **chat model** prepares the Generate-box text for **Krea 2** (Qwen3-VL). Do this prep as fully as you can in the same turn (or the dedicated prep hop). Chat with the user may be RU/EN; the JSON **`prompt` is always English**.
Order (front-load importance): **subject → pose/action → setting → materials → camera/framing → lighting → medium/mood**.
## Hard rules (Krea / Qwen3-VL)
- Short user ideas: expand. Finished Krea-style paragraphs: keep wording; only fix anti-patterns.
- Put LoRA trigger phrases near the subject they affect.
- Prefer positives over negatives.
1. **`prompt` language = English only** — never put Russian into the JSON `prompt`. Translate the idea, then structure it.
2. **Natural photographer/director prose** — not Danbooru tag soup, not `(word:1.5)`, not `masterpiece / best quality / 8k`.
3. **Order (front-load):**
**subject → pose/action → body/wardrobe → setting → materials/textures → camera/framing → lighting → medium/mood**.
4. Put **LoRA trigger phrases** (exact English spelling) near the subject they affect.
5. Prefer **positives** over negatives (Qwen negatives are weak).
6. Short ideas: expand into a full Krea paragraph. Thin or RU drafts: rewrite before Generate — do not hand Krea a half-ready line.
## Prep checklist (before `actions:["generate"]`)
- English only in `prompt`
- Subject and action clear in the first sentence
- Wardrobe / body / setting concrete
- Camera + lighting present
- One coherent scene; NSFW stated in plain English if needed
- Triggers placed next to what they modify
## Deliverable
User-facing prose: short, in the users language.
JSON `prompt`: English, structured as above — ready for Swarm Generate / Krea 2.
+2 -2
View File
@@ -1,6 +1,6 @@
{
"welcome_html": "<div class=\"sa-welcome-title\">Assistent · Krea 2</div><ul><li><strong>Generate</strong> слева — живой просмотр. В чат сам не уходит.</li><li><strong>Refs</strong> — референсы на отдельной вкладке: drop / paste / Снимок gen.</li><li>Галочка vision на окне — отправить кадр модели.</li><li>Чипсы aspect / seed / Vary / Turbo·RAW. В чате: <code>/help</code>.</li><li>Кнопки патча только у последнего предложения.</li></ul>Напиши, что сгенерировать — или кинь референс и попроси правку.",
"help_text": "Slash-команды (без LLM):\n/help — этот список\n/new — новый чат\n/history — список чатов\n/debug — сводка UI/Exact\n/debug ask · /why — сводка + короткий ответ модели\n/gen — Generate сейчас\n/look generate|refN — прикрепить окно к vision\n/init /mask /clear — Init / Mask / Clear Init\n/interrupt — остановить генерацию\n/aspect 16:9 — размер из таблицы 1K\n/seed lock|random — зафиксировать или рандомизировать seed\n/vary — новый seed, тот же промпт\n/pack write|ordinary|critique|compose|params|inpaint|describe|card|persona\n/persona new — интервью: клон текущей личности (overlay)\n/persona clone <id> — клон с указанной\n/persona save — записать согласованный черновик\n/civitai <query> — поиск LoRA (Confirm в чате)\n/inventory — rescan моделей + обновить список LoRA\n\nЧипсы над полем ввода делают то же для aspect / seed / vary / Turbo·RAW.\nПри старте всегда новый чат; смена чата восстанавливает параметры.\nOverlay-личности удаляет только кнопка ✕ рядом с селектом (не модель).",
"welcome_html": "<div class=\"sa-welcome-title\">Assistent · Krea 2</div><ul><li><strong>Generate</strong> слева — живой просмотр. Несколько вариантов → сетка + клик для просмотра.</li><li><strong>Refs</strong> — референсы на отдельной вкладке: drop / paste / Снимок gen.</li><li>Галочка vision на окне — отправить кадр модели.</li><li>Чипсы aspect / seed / Vary / Turbo·RAW. В чате: <code>/help</code>.</li><li>Кнопки патча только у последнего предложения.</li></ul>Напиши, что сгенерировать — или кинь референс и попроси правку.",
"help_text": "Slash-команды (без LLM):\n/help — этот список\n/new — новый чат\n/history — список чатов\n/debug — сводка UI/Exact\n/debug ask · /why — сводка + короткий ответ модели\n/gen — Generate сейчас\n/look generate|refN — прикрепить окно к vision\n/init /mask /clear — Init / Mask / Clear Init\n/interrupt — остановить генерацию\n/aspect 16:9 — размер из таблицы 1K\n/seed lock|random — зафиксировать или рандомизировать seed\n/vary — новый seed, тот же промпт\n/pack write|ordinary|critique|compose|params|inpaint|describe|card|persona\n/persona new — интервью: клон текущей личности (overlay)\n/persona clone <id> — клон с указанной\n/persona save — записать согласованный черновик\n/civitai <query> — поиск LoRA (Confirm в чате)\n/inventory — rescan моделей + обновить список LoRA\n\nНесколько вариантов в одном запросе («оба», разный свет) → патч с variants[] → сетка на Generate, клик / Открыть / Enter — просмотр.\nЧипсы над полем ввода делают то же для aspect / seed / vary / Turbo·RAW.\nПри старте всегда новый чат; смена чата восстанавливает параметры.\nOverlay-личности удаляет только кнопка ✕ рядом с селектом (не модель).",
"chips": [
{ "label": "1:1", "action": "aspect", "value": "1:1", "title": "1024×1024" },
{ "label": "4:5", "action": "aspect", "value": "4:5", "title": "928×1152" },
+2 -1
View File
@@ -6,9 +6,10 @@
"detailed Krea prose"
],
"process": [
"translate idea → English Krea prose before Generate",
"subject → pose → clothes/hair → setting → camera → light → mood",
"front-load what matters",
"natural prose, not tag soup"
"natural EN prose, not tag soup"
],
"defaults": [
"photoreal / film unless user asks anime/hentai",
+1 -1
View File
@@ -2,7 +2,7 @@
"always": [
"You are Leonid; the user is not Leonid — never greet/address them as Леонид/Leonid unless About the user says their name is that",
"If asked your name, say you are Leonid (assistant)",
"Match user language (RU/EN)",
"Match user language (RU/EN) in chat; Generate patch prompt is always English for Krea",
"Craft first: triggers, aspect, Turbo — horny never replaces technique",
"Scale appearance/outfits by controls.preference_bias (1…1)",
"Scale sexual tone + roleplay fetishes by controls.horny (0…100)",
+11 -1
View File
@@ -2,6 +2,16 @@
SwarmUI extension for **collaborative Krea 2** prompting via **Ollama**: chat + board (Generate | Refs tabs), LoRA chips, **persona presets** (`Config/personas/`), **About the user** prefs + craft vector memory, model cards with Civitai fetch, img2img/inpaint, slash commands, auto Generate.
**Version 0.11.3** — Stream no longer aborts on weak JSON fences (so prompts/skill_load can finish); `num_predict` 3072. Builds on 0.11.2 Krea prep.
**Version 0.11.2** — Before Krea Generate, chat model maximally preps the prompt (EN + structure); skip prep hop only if already Krea-ready English. Builds on 0.11.1.
**Version 0.11.1** — Krea Generate `prompt` must be English (skill `prompting` + Exact + client rewrite hop if Cyrillic leaks). Builds on 0.11.0 variants.
**Version 0.11.0** — Пакет вариантов: JSON `variants[]` (2–4) → последовательные Generate → сетка на вкладке Generate + lightbox. Builds on 0.10.22 empty-patch fix.
**Version 0.10.22** — Empty `### JSON Patch` no longer dead-ends: synthesize prompt from prose / retry; «давай дальше» counts as Generate. Builds on 0.10.21 spinner fix.
**Version 0.10.21** — Board Generate spinner clears when Swarm finishes (`num_live_gens`), not only when the image URL string changes. Builds on 0.10.20 remember-without-gen.
**Version 0.10.20** — «Запомни / базовый промпт» no longer triggers Auto-Generate or auto look_at (even if the model sneaks `actions:["generate"]`). Builds on 0.10.19 slider echo fix.
@@ -12,7 +22,7 @@ SwarmUI extension for **collaborative Krea 2** prompting via **Ollama**: chat +
## Layout
- **Left — Board tabs:** **Generate** (full-height live view) | **Refs** (reference grid + badge `N · vision M`); **Посмотри результат** attaches the finished frame and asks for a verdict
- **Left — Board tabs:** **Generate** (live view, or a **variant grid** when the model emits `variants[]`) | **Refs** (reference grid + badge `N · vision M`); click a variant to select / open lightbox; **Посмотри результат** attaches the selected finished frame and asks for a verdict
- **Splitter:** drag to resize panes
- **Right:** Chat | Cards | Settings; persona / pack / Ollama chat model; **Ollama health** badge
- **Chips / slash:** loaded from `Config/_base/ui.json` (persona can override)
+1 -1
View File
@@ -36,7 +36,7 @@ public partial class SwarmAssistentExtension : Extension
ExtensionAuthor = "mrleo1nid";
Description = "Collaborative Krea 2 assistant: Ollama chat, persona presets, vector memory, model cards, Generate loop.";
License = "MIT";
Version = "0.10.21";
Version = "0.11.3";
Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory"];
}