Fix broken chat: slim Exact prompt and restore JSON discipline.
Stop duplicating Exact into live context, tighten preview URL matching, force write_prompt on "поправь", and gate critique behind vision + a real JSON fence. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+10
-10
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Swarm Assistent — Krea 2 collaborative chat (Ollama via Swarm API).
|
* Swarm Assistent — Krea 2 collaborative chat (Ollama via Swarm API).
|
||||||
* v0.7.1: Exact KV memory; block SwarmUI ViewSpecial/model-card previews from Generate+vision.
|
* v0.7.2: Slim Exact in prompt; no Exact blob in live ctx; tighter preview filter; critique requires vision+JSON.
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
const LS_BASE = 'swarm_assistent_base_url';
|
const LS_BASE = 'swarm_assistent_base_url';
|
||||||
@@ -1681,10 +1681,10 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.exact = state.exact || state.config?.exact || null;
|
|
||||||
ctx.session_exact = state.sessionExact && Object.keys(state.sessionExact).length
|
ctx.session_exact = state.sessionExact && Object.keys(state.sessionExact).length
|
||||||
? { ...state.sessionExact }
|
? { ...state.sessionExact }
|
||||||
: {};
|
: {};
|
||||||
|
// Exact KV is already in the system prompt — do not duplicate the full blob into live context.
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
@@ -2088,6 +2088,9 @@
|
|||||||
if (!t.trim()) {
|
if (!t.trim()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (/\b(поправь|исправь|перепиши|улучши|fix\s+it|make\s+it\s+better|rewrite)\b/i.test(t)) {
|
||||||
|
return 'write_prompt';
|
||||||
|
}
|
||||||
if (/\b(опиши\s+реф|опиши\s+изображ|prompt\s+from\s+image|describe\s+(this|the|ref|image)|reverse\s*prompt)\b/i.test(t)
|
if (/\b(опиши\s+реф|опиши\s+изображ|prompt\s+from\s+image|describe\s+(this|the|ref|image)|reverse\s*prompt)\b/i.test(t)
|
||||||
|| /опиши\s+(этот|эту|картинк|референс)/i.test(t)) {
|
|| /опиши\s+(этот|эту|картинк|референс)/i.test(t)) {
|
||||||
return 'describe_ref';
|
return 'describe_ref';
|
||||||
@@ -2846,17 +2849,14 @@
|
|||||||
if (!s) {
|
if (!s) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// SwarmUI checkpoint/LoRA cards: ViewSpecial/*, View/Models/*, *.preview.*, PLACEHOLDER.
|
// Only SwarmUI checkpoint/LoRA card routes — not bare "/models/" (matches Civitai page URLs).
|
||||||
if (s.includes('.preview.')
|
return s.includes('.preview.')
|
||||||
|| s.includes('placeholder')
|
|| s.includes('placeholder')
|
||||||
|| s.includes('/viewspecial/')
|
|| s.includes('/viewspecial/')
|
||||||
|| s.includes('viewspecial/')
|
|| s.includes('viewspecial/')
|
||||||
|| s.includes('/models/')
|
|| s.includes('/view/models/')
|
||||||
|| s.includes('view/models/')
|
|| /\/view\/models\//.test(s)
|
||||||
|| /[?&](?:path|file)=[^&]*\.preview\./i.test(s)) {
|
|| /[?&](?:path|file)=[^&]*\.preview\./i.test(s);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findCurrentGenerateSrc({ allowPreview = false } = {}) {
|
function findCurrentGenerateSrc({ allowPreview = false } = {}) {
|
||||||
|
|||||||
@@ -315,6 +315,46 @@ public sealed class AssistentConfig
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Exact KV for the system prompt: params tables only (facts stay short / in RAG).</summary>
|
||||||
|
public JObject LoadExactForPrompt(string personaId)
|
||||||
|
{
|
||||||
|
JObject full = LoadExact(personaId);
|
||||||
|
if (full is null || full.Count == 0)
|
||||||
|
{
|
||||||
|
return full ?? new JObject();
|
||||||
|
}
|
||||||
|
JObject slim = new();
|
||||||
|
foreach (string key in new[] { "generation", "profiles", "aspect_table" })
|
||||||
|
{
|
||||||
|
if (full[key] is not null)
|
||||||
|
{
|
||||||
|
slim[key] = full[key].DeepClone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (full["facts"] is JObject facts)
|
||||||
|
{
|
||||||
|
// Keep short pointers only — long prose bloats 7B context and kills JSON discipline.
|
||||||
|
JObject shortFacts = new();
|
||||||
|
foreach (JProperty prop in facts.Properties())
|
||||||
|
{
|
||||||
|
string text = prop.Value?.ToString() ?? "";
|
||||||
|
if (text.Length <= 160)
|
||||||
|
{
|
||||||
|
shortFacts[prop.Name] = text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shortFacts[prop.Name] = text.Substring(0, 157) + "…";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shortFacts.Count > 0)
|
||||||
|
{
|
||||||
|
slim["facts"] = shortFacts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slim;
|
||||||
|
}
|
||||||
|
|
||||||
public JObject LoadAssistant(string personaId) => MergeJsonLayers("assistant.json", LayerRoots(personaId));
|
public JObject LoadAssistant(string personaId) => MergeJsonLayers("assistant.json", LayerRoots(personaId));
|
||||||
|
|
||||||
public JObject LoadUi(string personaId) => MergeJsonLayers("ui.json", LayerRoots(personaId));
|
public JObject LoadUi(string personaId) => MergeJsonLayers("ui.json", LayerRoots(personaId));
|
||||||
|
|||||||
@@ -16,14 +16,17 @@ When instructions conflict, apply this order (highest wins):
|
|||||||
|
|
||||||
Exact = encyclopedia of defaults. RAG = soft 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.
|
Exact = encyclopedia of defaults. RAG = soft 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. If you propose UI changes, the fence is mandatory. Keep the prose short (a few lines) — do not paste long critique templates.
|
||||||
|
|
||||||
## Live context
|
## Live context
|
||||||
|
|
||||||
A JSON block named "Live SwarmUI context" is attached. Treat it as ground truth — refreshed every chat turn:
|
A JSON block named "Live SwarmUI context" is attached. Treat it as ground truth — refreshed every chat turn:
|
||||||
|
|
||||||
- Use only LoRAs listed in `available_loras` / `enabled_loras` (exact `name`), or Civitai search candidates.
|
- Use only LoRAs listed in `available_loras` / `enabled_loras` (exact `name`), or Civitai search candidates.
|
||||||
- Prefer listed `trigger_phrase` / `triggers` — **never invent** trigger words.
|
- Prefer listed `trigger_phrase` / `triggers` — **never invent** trigger words.
|
||||||
- `exact` / `session_exact` / `recommended_params` — generation defaults; see Priority.
|
- `session_exact` / `recommended_params` — session overrides and defaults (Exact KV is in the system block above).
|
||||||
- `memory_hits` are retrieved notes (LoRA tips, pitfalls). Trust them over guesses, but **not** over exact or the user.
|
- `memory_hits` are retrieved notes (LoRA tips, pitfalls). Trust them over guesses, but **not** over Exact or the user.
|
||||||
|
- `has_vision_image` — if false, do not invent what the image looks like; emit `look_at` first when you need to see it.
|
||||||
- `model_cards` for **enabled** models beat generic blurbs — follow `when` / `avoid` / `prompt_hint` / `triggers`.
|
- `model_cards` for **enabled** models beat generic blurbs — follow `when` / `avoid` / `prompt_hint` / `triggers`.
|
||||||
- `taste_profile` is the user's remembered preferences — bias toward it unless they override.
|
- `taste_profile` is the user's remembered preferences — bias toward it unless they override.
|
||||||
- Prefer `krea_likely` / Krea architecture entries; ignore FLUX/SDXL LoRAs.
|
- Prefer `krea_likely` / Krea architecture entries; ignore FLUX/SDXL LoRAs.
|
||||||
|
|||||||
@@ -1,28 +1,20 @@
|
|||||||
# Mode: critique_image
|
# Mode: critique_image
|
||||||
|
|
||||||
Goal: look at the attached / requested board image(s) and improve the next generation for **Krea 2**.
|
Goal: look at the attached board image(s) and improve the next **Krea 2** generation.
|
||||||
|
|
||||||
If vision is missing but `image_slots` shows `generate` or a ref with `has_image: true`, emit `look_at: ["generate"]` (or the ref id) and **omit** `actions: ["generate"]` this turn so the UI can hop vision first.
|
## Vision gate (mandatory)
|
||||||
|
|
||||||
## Critique checklist
|
- If `has_vision_image` is false: emit **only** a one-line note + JSON with `look_at: ["generate"]` (or the ref id). Do **not** write a critique checklist. Do **not** invent defects.
|
||||||
|
- If vision is present: short critique, then a real fenced JSON patch.
|
||||||
|
|
||||||
- Subject, composition, lighting — what works / what fails.
|
## Critique (keep short)
|
||||||
- **Anatomy** (hands, limbs, face).
|
|
||||||
- **Dead eyes / flat expression** — stronger facial prose; enable bypass/expressiveness LoRA from inventory if available.
|
|
||||||
- **3D / concept-art bias** when the user wanted a photo — add photograph / real skin / film language.
|
|
||||||
- **Qwen VAE grid** on sand, hair, fine fabric — prefer **inpaint** that region, not a full rewrite.
|
|
||||||
- **Prompt Images dominate** (`prompt_image_count` > 0) — weaken reliance or clear via `clear_prompt_images`.
|
|
||||||
- Aspect too tight/wide — set `aspect` or width/height.
|
|
||||||
- Missing / wrong LoRA triggers or weights.
|
|
||||||
|
|
||||||
## Fix strategy
|
Bullet the real issues you see (anatomy, eyes, lighting, aspect, LoRA triggers). Do not paste a generic template of pitfalls you did not observe.
|
||||||
|
|
||||||
- **Local defect** (hands, face, object): inpaint (`use_init_image` + mask). No mask → ask to paint / pack `inpaint_edit`.
|
|
||||||
- **Global restyle:** img2img with `init_creativity` ≈ 0.4–0.6.
|
|
||||||
- **From-scratch rewrite:** only when composition is wrong.
|
|
||||||
|
|
||||||
## Deliverable
|
## Deliverable
|
||||||
|
|
||||||
- Short critique in the user's language.
|
1. 2–6 short lines in the user's language.
|
||||||
- JSON patch with improved `prompt` and any `loras` / size / init tweaks.
|
2. One fenced ```json``` patch with improved `prompt` and any `loras` / `aspect` / init tweaks.
|
||||||
- `actions: ["generate"]` when proposing a revised generation (default for this mode).
|
3. `actions: ["generate"]` when proposing a revised generation.
|
||||||
|
|
||||||
|
Never describe a patch in prose without the fenced JSON object.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
SwarmUI extension for **collaborative Krea 2** prompting via **Ollama**: chat + board (Generate | Refs tabs), LoRA chips, **persona presets** (`Config/personas/`), **vector memory**, model cards with Civitai fetch, img2img/inpaint, slash commands, auto Generate.
|
SwarmUI extension for **collaborative Krea 2** prompting via **Ollama**: chat + board (Generate | Refs tabs), LoRA chips, **persona presets** (`Config/personas/`), **vector memory**, model cards with Civitai fetch, img2img/inpaint, slash commands, auto Generate.
|
||||||
|
|
||||||
**Version 0.7.1** — Exact KV memory + persona overlays; block SwarmUI `ViewSpecial`/model-card previews from Generate + vision.
|
**Version 0.7.2** — Exact KV (slim in prompt); block `ViewSpecial` model-card previews; critique requires vision + real JSON fence.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class SwarmAssistentExtension : Extension
|
|||||||
ExtensionAuthor = "mrleo1nid";
|
ExtensionAuthor = "mrleo1nid";
|
||||||
Description = "Collaborative Krea 2 assistant: Ollama chat, persona presets, vector memory, model cards, Generate loop.";
|
Description = "Collaborative Krea 2 assistant: Ollama chat, persona presets, vector memory, model cards, Generate loop.";
|
||||||
License = "MIT";
|
License = "MIT";
|
||||||
Version = "0.7.1";
|
Version = "0.7.2";
|
||||||
Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory"];
|
Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1347,11 +1347,11 @@ public class SwarmAssistentExtension : Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JObject exact = Config.LoadExact(pid);
|
JObject exact = Config.LoadExactForPrompt(pid);
|
||||||
if (exact is not null && exact.Count > 0)
|
if (exact is not null && exact.Count > 0)
|
||||||
{
|
{
|
||||||
system.AppendLine();
|
system.AppendLine();
|
||||||
system.AppendLine("## Exact memory (canonical KV — always trust over RAG guesses)");
|
system.AppendLine("## Exact memory (canonical KV defaults — prefer over RAG for numbers)");
|
||||||
system.AppendLine("```json");
|
system.AppendLine("```json");
|
||||||
system.AppendLine(exact.ToString(Newtonsoft.Json.Formatting.None));
|
system.AppendLine(exact.ToString(Newtonsoft.Json.Formatting.None));
|
||||||
system.AppendLine("```");
|
system.AppendLine("```");
|
||||||
@@ -1574,7 +1574,7 @@ public class SwarmAssistentExtension : Extension
|
|||||||
Logs.Debug($"Assistent memory retrieve: {ex.Message}");
|
Logs.Debug($"Assistent memory retrieve: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
string enrichedContext = InjectMemoryHits(contextJson, hits, Config.LoadExact(pid));
|
string enrichedContext = InjectMemoryHits(contextJson, hits);
|
||||||
List<JObject> messages = BuildOllamaMessages(packName, includeBase, enrichedContext, userMessages, personaId: pid, skillIds: skills);
|
List<JObject> messages = BuildOllamaMessages(packName, includeBase, enrichedContext, userMessages, personaId: pid, skillIds: skills);
|
||||||
JArray civitaiResults = [];
|
JArray civitaiResults = [];
|
||||||
string reply = "";
|
string reply = "";
|
||||||
@@ -1681,29 +1681,12 @@ public class SwarmAssistentExtension : Extension
|
|||||||
ctx = new JObject { ["_raw_context"] = contextJson };
|
ctx = new JObject { ["_raw_context"] = contextJson };
|
||||||
}
|
}
|
||||||
ctx["memory_hits"] = hits ?? new JArray();
|
ctx["memory_hits"] = hits ?? new JArray();
|
||||||
if (exact is not null && exact.Count > 0 && ctx["exact"] is null)
|
// Never re-inject full Exact into live context (already in system prompt).
|
||||||
{
|
ctx.Remove("exact");
|
||||||
ctx["exact"] = exact;
|
|
||||||
}
|
|
||||||
if (ctx["session_exact"] is null)
|
if (ctx["session_exact"] is null)
|
||||||
{
|
{
|
||||||
ctx["session_exact"] = new JObject();
|
ctx["session_exact"] = new JObject();
|
||||||
}
|
}
|
||||||
if (ctx["recommended_params"] is null && exact?["generation"] is JObject gen)
|
|
||||||
{
|
|
||||||
JObject rec = new();
|
|
||||||
foreach (string key in new[] { "steps", "cfg", "sigma_shift", "aspect", "images" })
|
|
||||||
{
|
|
||||||
if (gen[key] is not null)
|
|
||||||
{
|
|
||||||
rec[key] = gen[key].DeepClone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rec.Count > 0)
|
|
||||||
{
|
|
||||||
ctx["recommended_params"] = rec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Slim inventory for LLM: keep enabled + current, drop full dump if present
|
// Slim inventory for LLM: keep enabled + current, drop full dump if present
|
||||||
if (ctx["available_loras"] is JArray allLoras && allLoras.Count > 24)
|
if (ctx["available_loras"] is JArray allLoras && allLoras.Count > 24)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user