Ship Assistent 0.11.9: esbuild bundle and patch-keys manifest.
Replace split Assets JS with a built bundle and aligned C#/config so SwarmUI loads one script and patch apply stays consistent; drop legacy terse persona and memory seed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+47
-99
@@ -29,6 +29,10 @@ public sealed class AssistentConfig
|
||||
public static string SafeId(string id)
|
||||
{
|
||||
string s = (id ?? "").Replace('\\', '/').AfterLast('/').Replace("..", "").Trim();
|
||||
if (string.Equals(s, "terse", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
s = "aggressive";
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(s) || !Regex.IsMatch(s, @"^[A-Za-z0-9][A-Za-z0-9_\-]{0,63}$"))
|
||||
{
|
||||
return null;
|
||||
@@ -122,21 +126,29 @@ public sealed class AssistentConfig
|
||||
}
|
||||
}
|
||||
|
||||
public JArray TryReadJsonArray(string path)
|
||||
public string[] LoadPatchKeys()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
||||
string path = ResolveUnder(_bundledRoot, "_base/patch-keys.json");
|
||||
JObject doc = TryReadJson(path);
|
||||
if (doc?["keys"] is JArray arr && arr.Count > 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return JArray.Parse(File.ReadAllText(path, Encoding.UTF8));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logs.Debug($"AssistentConfig json-array {path}: {ex.Message}");
|
||||
return null;
|
||||
return arr.Select(t => t?.ToString()).Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
|
||||
}
|
||||
// Fallback if bundled json missing
|
||||
return
|
||||
[
|
||||
"prompt", "negative", "loras", "width", "height", "steps", "cfg", "seed", "sigma_shift", "sampler", "scheduler",
|
||||
"actions", "search_query", "civitai_query",
|
||||
"use_init_image", "clear_init_image", "init_creativity", "denoise",
|
||||
"use_mask_image", "clear_mask_image", "mask_blur", "mask_grow",
|
||||
"look_at", "vision_from", "vision_slots", "slot_to_init", "slot_to_mask",
|
||||
"snapshot_generate", "select_slot", "aspect", "images", "batch", "vary", "lock_seed",
|
||||
"creativity", "intensity", "complexity", "movement",
|
||||
"clear_prompt_images", "slot_to_prompt_image", "pack", "memories", "memory",
|
||||
"memory_query", "memory_kind", "tag_query", "user_prefs",
|
||||
"inventory_query", "skills", "persona_shelves", "persona_clone", "persona", "controls",
|
||||
"variants",
|
||||
];
|
||||
}
|
||||
|
||||
public string TryReadText(string path)
|
||||
@@ -272,33 +284,6 @@ public sealed class AssistentConfig
|
||||
byId[id] = (cur.title, cur.accent, PersonaSource(id));
|
||||
}
|
||||
|
||||
// Legacy personas.json titles
|
||||
string overlayJson = Path.Combine(_overlayRoot, "personas.json");
|
||||
JObject legacy = TryReadJson(overlayJson);
|
||||
if (legacy?["personas"] is JArray arr)
|
||||
{
|
||||
foreach (JToken t in arr)
|
||||
{
|
||||
if (t is not JObject po)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string id = SafeId(po["id"]?.ToString());
|
||||
if (id is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (byId.TryGetValue(id, out var cur))
|
||||
{
|
||||
byId[id] = (po["title"]?.ToString() ?? cur.title, cur.accent, cur.source);
|
||||
}
|
||||
else
|
||||
{
|
||||
byId[id] = (po["title"]?.ToString() ?? id, "#8b949e", "legacy");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return byId.OrderBy(kv => kv.Key, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(kv => (kv.Key, kv.Value.title, kv.Value.accent, kv.Value.source))
|
||||
.ToList();
|
||||
@@ -308,13 +293,6 @@ public sealed class AssistentConfig
|
||||
{
|
||||
JObject assistant = MergeJsonLayers("assistant.json", LayerRoots("neutral"));
|
||||
string def = SafeId(assistant["default_persona"]?.ToString()) ?? "neutral";
|
||||
string overlayJson = Path.Combine(_overlayRoot, "personas.json");
|
||||
JObject legacy = TryReadJson(overlayJson);
|
||||
string fromLegacy = SafeId(legacy?["default"]?.ToString());
|
||||
if (fromLegacy is not null)
|
||||
{
|
||||
def = fromLegacy;
|
||||
}
|
||||
var catalog = ListPersonaCatalog();
|
||||
if (catalog.All(p => !string.Equals(p.id, def, StringComparison.OrdinalIgnoreCase)) && catalog.Count > 0)
|
||||
{
|
||||
@@ -410,17 +388,20 @@ public sealed class AssistentConfig
|
||||
/// <summary>Clamp and merge control values into overlay exact.json (controls key only).</summary>
|
||||
public JObject SaveControlValues(string personaId, JObject values)
|
||||
{
|
||||
string id = SafeId(personaId) ?? "neutral";
|
||||
JObject schema = LoadControlsSchema(id);
|
||||
string dir = Path.Combine(_overlayRoot, "personas", id);
|
||||
Directory.CreateDirectory(dir);
|
||||
string path = Path.Combine(dir, "exact.json");
|
||||
JObject existing = TryReadJson(path) ?? new JObject();
|
||||
JObject prev = existing["controls"] as JObject ?? new JObject();
|
||||
JObject clamped = ClampControls(schema, values ?? new JObject());
|
||||
existing["controls"] = DeepMerge(prev, clamped);
|
||||
File.WriteAllText(path, existing.ToString(Newtonsoft.Json.Formatting.Indented) + "\n", Encoding.UTF8);
|
||||
return LoadControlValues(id);
|
||||
lock (_lock)
|
||||
{
|
||||
string id = SafeId(personaId) ?? "neutral";
|
||||
JObject schema = LoadControlsSchema(id);
|
||||
string dir = Path.Combine(_overlayRoot, "personas", id);
|
||||
Directory.CreateDirectory(dir);
|
||||
string path = Path.Combine(dir, "exact.json");
|
||||
JObject existing = TryReadJson(path) ?? new JObject();
|
||||
JObject prev = existing["controls"] as JObject ?? new JObject();
|
||||
JObject clamped = ClampControls(schema, values ?? new JObject());
|
||||
existing["controls"] = DeepMerge(prev, clamped);
|
||||
File.WriteAllText(path, existing.ToString(Newtonsoft.Json.Formatting.Indented) + "\n", Encoding.UTF8);
|
||||
return LoadControlValues(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static JObject ClampControls(JObject schema, JObject values)
|
||||
@@ -727,11 +708,6 @@ public sealed class AssistentConfig
|
||||
{
|
||||
string id = SafeId(personaId) ?? throw new ArgumentException("invalid persona id");
|
||||
if (IsBundledPersona(id) && !allowBundledShadow && !IsOverlayPersona(id))
|
||||
{
|
||||
// v1: do not shadow-write bundled; require clone to a new overlay id.
|
||||
throw new InvalidOperationException($"cannot write bundled persona '{id}' — clone to a new overlay id");
|
||||
}
|
||||
if (IsBundledPersona(id) && !IsOverlayPersona(id))
|
||||
{
|
||||
throw new InvalidOperationException($"cannot write bundled persona '{id}' — clone to a new overlay id");
|
||||
}
|
||||
@@ -1099,39 +1075,6 @@ public sealed class AssistentConfig
|
||||
}
|
||||
string extra = MergeTextLayers("extra.md", roots);
|
||||
|
||||
// Legacy personas.json: only when no overlay persona folder exists for this id.
|
||||
string overlayPersonaDir = Path.Combine(_overlayRoot, "personas", id);
|
||||
bool hasOverlayFolder = Directory.Exists(overlayPersonaDir)
|
||||
&& (File.Exists(Path.Combine(overlayPersonaDir, "persona.json"))
|
||||
|| File.Exists(Path.Combine(overlayPersonaDir, "extra.md")));
|
||||
if (!hasOverlayFolder)
|
||||
{
|
||||
string overlayJson = Path.Combine(_overlayRoot, "personas.json");
|
||||
JObject legacy = TryReadJson(overlayJson);
|
||||
if (legacy?["personas"] is JArray arr)
|
||||
{
|
||||
foreach (JToken t in arr)
|
||||
{
|
||||
if (t is JObject po && string.Equals(SafeId(po["id"]?.ToString()), id, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
JObject persona = shelves["persona"] as JObject ?? new JObject();
|
||||
string title = po["title"]?.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(title))
|
||||
{
|
||||
persona["title"] = title;
|
||||
}
|
||||
shelves["persona"] = persona;
|
||||
string prompt = po["prompt"]?.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(prompt))
|
||||
{
|
||||
extra = string.IsNullOrWhiteSpace(extra) ? prompt : extra + "\n\n" + prompt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shelves["extra"] = extra ?? "";
|
||||
return shelves;
|
||||
}
|
||||
@@ -1428,9 +1371,13 @@ public sealed class AssistentConfig
|
||||
|
||||
public void SaveSettings(JObject settings)
|
||||
{
|
||||
Directory.CreateDirectory(_overlayRoot);
|
||||
string path = Path.Combine(_overlayRoot, "settings.json");
|
||||
File.WriteAllText(path, (settings ?? new JObject()).ToString(Newtonsoft.Json.Formatting.Indented), Encoding.UTF8);
|
||||
lock (_lock)
|
||||
{
|
||||
Directory.CreateDirectory(_overlayRoot);
|
||||
string path = Path.Combine(_overlayRoot, "settings.json");
|
||||
JObject merged = DeepMerge(LoadSettings(), settings ?? new JObject());
|
||||
File.WriteAllText(path, merged.ToString(Newtonsoft.Json.Formatting.Indented), Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
public JObject LoadOllamaRoles()
|
||||
@@ -1471,7 +1418,7 @@ public sealed class AssistentConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clientSkills is not null && clientSkills.Count > 0)
|
||||
if (clientSkills is not null)
|
||||
{
|
||||
enabled.Clear();
|
||||
foreach (JToken t in clientSkills)
|
||||
@@ -1534,6 +1481,7 @@ public sealed class AssistentConfig
|
||||
["identity"] = identity,
|
||||
["identity_summary"] = RenderIdentityBlock(id, includeAllShelves: true),
|
||||
["enabled_skills"] = new JArray(ResolveEnabledSkills(id, null)),
|
||||
["patch_keys"] = new JArray(LoadPatchKeys()),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user