Ship Assistent 0.10.13: ordinary pack, senior chat default, aspect/critique fixes, prose UI.
Default pack is Обычный; prefer default_chat/senior Ollama tag; client-apply same-but-aspect; leave critique pack after hops; render Critique as Критика instead of raw ### markdown. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+118
-59
@@ -18,19 +18,31 @@ public partial class SwarmAssistentExtension
|
||||
const int MaxCivitaiHopsFallback = 2;
|
||||
const int MaxToolHopsFallback = 4;
|
||||
|
||||
List<JObject> BuildOllamaMessages(string packName, bool includeBase, string contextJson, JArray userMessages, string extraSystem = null, string personaId = null, IEnumerable<string> skillIds = null)
|
||||
(List<JObject> messages, JObject systemLayers) BuildOllamaMessages(string packName, bool includeBase, string contextJson, JArray userMessages, string extraSystem = null, string personaId = null, IEnumerable<string> skillIds = null)
|
||||
{
|
||||
List<JObject> ollamaMessages = [];
|
||||
StringBuilder system = new();
|
||||
JObject layers = new();
|
||||
string pid = AssistentConfig.SafeId(personaId) ?? Config.DefaultPersonaId();
|
||||
|
||||
void AddLayer(string name, string block)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(block))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (system.Length > 0)
|
||||
{
|
||||
system.AppendLine();
|
||||
}
|
||||
int before = system.Length;
|
||||
system.AppendLine(block.TrimEnd());
|
||||
layers[name] = system.Length - before;
|
||||
}
|
||||
|
||||
if (includeBase)
|
||||
{
|
||||
string core = Config.LoadCorePrompt(pid);
|
||||
if (!string.IsNullOrWhiteSpace(core))
|
||||
{
|
||||
system.AppendLine(core);
|
||||
}
|
||||
AddLayer("core", Config.LoadCorePrompt(pid));
|
||||
}
|
||||
|
||||
if (Memory is not null)
|
||||
@@ -40,12 +52,7 @@ public partial class SwarmAssistentExtension
|
||||
JObject asst = Config.LoadAssistant(pid);
|
||||
double weight = asst["user_prefs_weight"]?.Value<double?>() ?? 1.0;
|
||||
int maxPrefs = asst["user_prefs_max"]?.Value<int?>() ?? 16;
|
||||
string about = Memory.FormatUserPrefsBlock(pid, weight, maxPrefs);
|
||||
if (!string.IsNullOrWhiteSpace(about))
|
||||
{
|
||||
system.AppendLine();
|
||||
system.AppendLine(about);
|
||||
}
|
||||
AddLayer("prefs", Memory.FormatUserPrefsBlock(pid, weight, maxPrefs));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -54,56 +61,55 @@ public partial class SwarmAssistentExtension
|
||||
}
|
||||
|
||||
JObject exact = Config.LoadExactForPrompt(pid);
|
||||
if (exact is not null && exact.Count > 0 && LiveContextHasSize(contextJson))
|
||||
{
|
||||
exact.Remove("aspect_table");
|
||||
}
|
||||
if (exact is not null && exact.Count > 0)
|
||||
{
|
||||
system.AppendLine();
|
||||
system.AppendLine("## Exact memory (canonical KV defaults — prefer over RAG for numbers)");
|
||||
system.AppendLine("```json");
|
||||
system.AppendLine(exact.ToString(Newtonsoft.Json.Formatting.None));
|
||||
system.AppendLine("```");
|
||||
AddLayer("exact",
|
||||
"## Exact memory (canonical KV defaults — prefer over RAG for numbers)\n```json\n"
|
||||
+ exact.ToString(Newtonsoft.Json.Formatting.None) + "\n```");
|
||||
}
|
||||
|
||||
StringBuilder skillsBlock = new();
|
||||
foreach (string skillId in skillIds ?? Config.ResolveEnabledSkills(pid, null))
|
||||
{
|
||||
string skillText = Config.LoadSkillPrompt(pid, skillId);
|
||||
if (!string.IsNullOrWhiteSpace(skillText))
|
||||
{
|
||||
system.AppendLine();
|
||||
system.AppendLine($"## Skill: {skillId}");
|
||||
system.AppendLine(skillText);
|
||||
if (skillsBlock.Length > 0)
|
||||
{
|
||||
skillsBlock.AppendLine();
|
||||
}
|
||||
skillsBlock.AppendLine($"## Skill: {skillId}");
|
||||
skillsBlock.AppendLine(skillText.TrimEnd());
|
||||
}
|
||||
}
|
||||
AddLayer("skills", skillsBlock.ToString());
|
||||
|
||||
string identity = Config.RenderIdentityBlock(pid);
|
||||
if (!string.IsNullOrWhiteSpace(identity))
|
||||
{
|
||||
system.AppendLine();
|
||||
system.AppendLine(identity);
|
||||
}
|
||||
AddLayer("identity", Config.RenderIdentityBlock(pid));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(packName))
|
||||
{
|
||||
string situational = Config.LoadPackPrompt(pid, packName);
|
||||
if (!string.IsNullOrWhiteSpace(situational))
|
||||
{
|
||||
system.AppendLine();
|
||||
system.AppendLine($"## Active mode: {packName}");
|
||||
system.AppendLine(situational);
|
||||
AddLayer("pack", $"## Active mode: {packName}\n{situational.TrimEnd()}");
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(contextJson))
|
||||
{
|
||||
system.AppendLine();
|
||||
system.AppendLine("## Live SwarmUI context (JSON — trust this over guesses)");
|
||||
system.AppendLine("```json");
|
||||
system.AppendLine(contextJson);
|
||||
system.AppendLine("```");
|
||||
AddLayer("live",
|
||||
"## Live SwarmUI context (JSON — trust this over guesses)\n```json\n"
|
||||
+ contextJson + "\n```");
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(extraSystem))
|
||||
{
|
||||
system.AppendLine();
|
||||
system.AppendLine(extraSystem);
|
||||
AddLayer("extra", extraSystem);
|
||||
}
|
||||
|
||||
layers["total"] = system.Length;
|
||||
if (system.Length > 0)
|
||||
{
|
||||
ollamaMessages.Add(new JObject
|
||||
@@ -129,10 +135,10 @@ public partial class SwarmAssistentExtension
|
||||
}
|
||||
ollamaMessages.Add(copy);
|
||||
}
|
||||
return ollamaMessages;
|
||||
return (ollamaMessages, layers);
|
||||
}
|
||||
|
||||
async Task<(string reply, JObject raw, JArray civitaiResults, int systemChars)> RunChatWithHops(
|
||||
async Task<(string reply, JObject raw, JArray civitaiResults, int systemChars, JObject systemLayers)> RunChatWithHops(
|
||||
Session session,
|
||||
string root,
|
||||
string modelName,
|
||||
@@ -177,16 +183,10 @@ public partial class SwarmAssistentExtension
|
||||
|
||||
string enrichedContext = InjectMemoryHits(contextJson, hits);
|
||||
enrichedContext = EnrichPersonaContext(enrichedContext, pid, packName);
|
||||
List<JObject> messages = BuildOllamaMessages(packName, includeBase, enrichedContext, userMessages, personaId: pid, skillIds: skills);
|
||||
int systemChars = 0;
|
||||
foreach (JObject m in messages)
|
||||
{
|
||||
if (string.Equals(m["role"]?.ToString(), "system", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
systemChars = m["content"]?.ToString()?.Length ?? 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
(List<JObject> messages, JObject systemLayers) = BuildOllamaMessages(packName, includeBase, enrichedContext, userMessages, personaId: pid, skillIds: skills);
|
||||
int systemChars = systemLayers["total"]?.Value<int?>()
|
||||
?? messages.FirstOrDefault(m => string.Equals(m["role"]?.ToString(), "system", StringComparison.OrdinalIgnoreCase))?["content"]?.ToString()?.Length
|
||||
?? 0;
|
||||
JArray civitaiResults = [];
|
||||
string reply = "";
|
||||
JObject lastRaw = null;
|
||||
@@ -229,7 +229,7 @@ public partial class SwarmAssistentExtension
|
||||
messages.Add(new JObject { ["role"] = "assistant", ["content"] = assistantContent });
|
||||
messages.Add(new JObject { ["role"] = "user", ["content"] = follow });
|
||||
}
|
||||
return (reply, lastRaw, civitaiResults, systemChars);
|
||||
return (reply, lastRaw, civitaiResults, systemChars, systemLayers);
|
||||
}
|
||||
|
||||
static string BuildRetrieveQuery(JArray userMessages, string contextJson, string packName = null)
|
||||
@@ -249,7 +249,18 @@ public partial class SwarmAssistentExtension
|
||||
{
|
||||
sb.Append(ckpt).Append(' ');
|
||||
}
|
||||
if (ctx["enabled_loras"] is JArray en)
|
||||
if (ctx["selected_loras"] is JArray selLoras)
|
||||
{
|
||||
foreach (JToken t in selLoras.Take(12))
|
||||
{
|
||||
string n = t?["name"]?.ToString() ?? t?.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(n))
|
||||
{
|
||||
sb.Append(n).Append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctx["enabled_loras"] is JArray en)
|
||||
{
|
||||
foreach (JToken t in en.Take(12))
|
||||
{
|
||||
@@ -587,6 +598,10 @@ public partial class SwarmAssistentExtension
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (IsExactPointerHit(ho))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
JObject copy = (JObject)ho.DeepClone();
|
||||
string text = copy["text"]?.ToString() ?? "";
|
||||
if (text.Length > hitChars)
|
||||
@@ -598,6 +613,7 @@ public partial class SwarmAssistentExtension
|
||||
}
|
||||
ctx["memory_hits"] = clippedHits;
|
||||
ctx.Remove("taste_profile");
|
||||
ctx.Remove("enabled_loras"); // alias of selected_loras — do not double-feed
|
||||
try
|
||||
{
|
||||
string pid = AssistentConfig.SafeId(ctx["persona"]?.ToString()) ?? Config?.DefaultPersonaId() ?? "neutral";
|
||||
@@ -623,6 +639,49 @@ public partial class SwarmAssistentExtension
|
||||
return ctx.ToString(Newtonsoft.Json.Formatting.None);
|
||||
}
|
||||
|
||||
static bool LiveContextHasSize(string contextJson)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contextJson))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
JObject ctx = JObject.Parse(contextJson);
|
||||
int? w = ctx["width"]?.Value<int?>();
|
||||
int? h = ctx["height"]?.Value<int?>();
|
||||
return w is > 0 && h is > 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Drop RAG rows that only point at Exact (legacy krea_facts seed / "see Exact memory…").</summary>
|
||||
static bool IsExactPointerHit(JObject ho)
|
||||
{
|
||||
if (ho is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string key = (ho["key"]?.ToString() ?? "").Trim().ToLowerInvariant();
|
||||
if (key.StartsWith("krea2_", StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
string text = (ho["text"]?.ToString() ?? "").ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return text.Contains("live in exact memory", StringComparison.Ordinal)
|
||||
|| text.Contains("see exact memory", StringComparison.Ordinal)
|
||||
|| text.Contains("prefer exact kv", StringComparison.Ordinal)
|
||||
|| text.Contains("exact.facts.", StringComparison.Ordinal)
|
||||
|| text.Contains("exact memory profiles.", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
void SlimAvailableLorasInContext(JObject ctx, JArray hits)
|
||||
{
|
||||
if (ctx["available_loras"] is not JArray allLoras || allLoras.Count == 0)
|
||||
@@ -851,17 +910,17 @@ public partial class SwarmAssistentExtension
|
||||
}
|
||||
}
|
||||
JArray catalog = [];
|
||||
foreach (var p in Config.ListPersonaCatalog())
|
||||
{
|
||||
catalog.Add(new JObject
|
||||
{
|
||||
["id"] = p.id,
|
||||
["title"] = p.title,
|
||||
});
|
||||
}
|
||||
ctx["personas"] = catalog;
|
||||
if (authorPack)
|
||||
{
|
||||
foreach (var p in Config.ListPersonaCatalog())
|
||||
{
|
||||
catalog.Add(new JObject
|
||||
{
|
||||
["id"] = p.id,
|
||||
["title"] = p.title,
|
||||
});
|
||||
}
|
||||
ctx["personas"] = catalog;
|
||||
JObject shelves = Config.LoadIdentityParts(pid);
|
||||
shelves.Remove("extra");
|
||||
ctx["persona_shelves"] = shelves;
|
||||
|
||||
Reference in New Issue
Block a user