Ship Assistent 0.12.1: training tab, dataset pipeline, and heard RAG.
Restructure UI with app-level tabs and chat history drawer; add dataset curation, HF import, Modelfile/QLoRA hooks, and link approved samples to the agent immediately via heard vector memory without waiting for fine-tuning. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -185,6 +185,7 @@ public partial class SwarmAssistentExtension
|
||||
{
|
||||
AssistentMemory.RetrieveOptions opt = MemoryRetrieveOptions(pid);
|
||||
hits = await Memory.RetrieveAsync(root, retrieveQuery, opt.TopK, embed, Config.PersonaExtendsChain(pid), opt);
|
||||
hits = FilterHeardHitsIfDisabled(hits);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -192,7 +193,7 @@ public partial class SwarmAssistentExtension
|
||||
}
|
||||
}
|
||||
|
||||
string enrichedContext = InjectMemoryHits(contextJson, hits);
|
||||
string enrichedContext = InjectMemoryHits(contextJson, hits, pid);
|
||||
if (!slimDebug)
|
||||
{
|
||||
enrichedContext = EnrichPersonaContext(enrichedContext, pid, packName);
|
||||
@@ -338,24 +339,51 @@ public partial class SwarmAssistentExtension
|
||||
AssistentMemory.RetrieveOptions MemoryRetrieveOptions(string pid)
|
||||
{
|
||||
JObject a = Config.LoadAssistant(pid) ?? new JObject();
|
||||
JObject agent = Config.LoadTrainingAgent();
|
||||
AssistentMemory.RetrieveOptions opt = new()
|
||||
{
|
||||
TopK = a["memory_top_k"]?.Value<int?>() ?? 8,
|
||||
MinScore = a["memory_min_score"]?.Value<float?>() ?? 0.32f,
|
||||
ApplyQuotas = true,
|
||||
};
|
||||
if (a["memory_quotas"] is JObject quotas)
|
||||
Dictionary<string, int> quotas = AssistentMemory.CopyDefaultQuotas();
|
||||
if (a["memory_quotas"] is JObject qOverrides)
|
||||
{
|
||||
Dictionary<string, int> d = new(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (JProperty p in quotas.Properties())
|
||||
foreach (JProperty p in qOverrides.Properties())
|
||||
{
|
||||
d[p.Name] = p.Value?.Value<int?>() ?? 2;
|
||||
quotas[p.Name] = p.Value?.Value<int?>() ?? 2;
|
||||
}
|
||||
opt.Quotas = d;
|
||||
}
|
||||
if (agent["enabled"]?.Value<bool?>() != false)
|
||||
{
|
||||
quotas["heard"] = agent["heard_quota"]?.Value<int?>() ?? 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
quotas.Remove("heard");
|
||||
}
|
||||
opt.Quotas = quotas;
|
||||
return opt;
|
||||
}
|
||||
|
||||
JArray FilterHeardHitsIfDisabled(JArray hits)
|
||||
{
|
||||
if (Config.LoadTrainingAgent()["enabled"]?.Value<bool?>() != false)
|
||||
{
|
||||
return hits;
|
||||
}
|
||||
JArray filtered = [];
|
||||
foreach (JToken t in hits ?? [])
|
||||
{
|
||||
if (t is JObject ho && string.Equals(ho["kind"]?.ToString(), AssistentMemory.HeardKind, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
filtered.Add(t);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
async Task<(string follow, JArray civitai)> RunToolHop(
|
||||
Session session,
|
||||
string root,
|
||||
@@ -413,6 +441,38 @@ public partial class SwarmAssistentExtension
|
||||
+ rows.ToString(Newtonsoft.Json.Formatting.None) + "\n```",
|
||||
null);
|
||||
}
|
||||
if (tool == "heard_search")
|
||||
{
|
||||
if (Config.LoadTrainingAgent()["enabled"]?.Value<bool?>() == false)
|
||||
{
|
||||
return ("heard_search disabled in training-agent settings.", null);
|
||||
}
|
||||
string q = patch["memory_query"]?.ToString()?.Trim()
|
||||
?? patch["search_query"]?.ToString()?.Trim()
|
||||
?? ExtractMemoryQuery(patch);
|
||||
if (string.IsNullOrWhiteSpace(q) || !hopDone.Add("heard:" + q))
|
||||
{
|
||||
return (null, null);
|
||||
}
|
||||
int topK = Config.LoadTrainingAgent()["heard_quota"]?.Value<int?>() ?? 3;
|
||||
JArray rows = await Memory.SearchAsync(root, q, AssistentMemory.HeardKind, topK, embed, chain);
|
||||
JArray examples = [];
|
||||
foreach (JToken t in rows)
|
||||
{
|
||||
if (t is JObject ho)
|
||||
{
|
||||
JObject ex = Memory.BuildHeardExampleFromHit(ho, chain);
|
||||
if (ex is not null)
|
||||
{
|
||||
examples.Add(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
"heard_search — curated dialogue examples the assistant learned (style/reference, not hard rules). Use tone and structure; omit heard_search unless you need more examples.\n```json\n"
|
||||
+ examples.ToString(Newtonsoft.Json.Formatting.None) + "\n```",
|
||||
null);
|
||||
}
|
||||
if (tool == "lookup_tags")
|
||||
{
|
||||
string q = ExtractTagQuery(patch);
|
||||
@@ -599,7 +659,7 @@ public partial class SwarmAssistentExtension
|
||||
return outRows;
|
||||
}
|
||||
|
||||
string InjectMemoryHits(string contextJson, JArray hits, JObject exact = null)
|
||||
string InjectMemoryHits(string contextJson, JArray hits, string personaId = null)
|
||||
{
|
||||
JObject ctx;
|
||||
try
|
||||
@@ -614,7 +674,7 @@ public partial class SwarmAssistentExtension
|
||||
int hitChars = 240;
|
||||
try
|
||||
{
|
||||
string pidHit = AssistentConfig.SafeId(ctx["persona"]?.ToString()) ?? Config?.DefaultPersonaId() ?? "neutral";
|
||||
string pidHit = AssistentConfig.SafeId(ctx["persona"]?.ToString()) ?? personaId ?? Config?.DefaultPersonaId() ?? "neutral";
|
||||
hitChars = Config?.LoadAssistant(pidHit)?["memory_hit_chars"]?.Value<int?>() ?? 240;
|
||||
}
|
||||
catch
|
||||
@@ -623,7 +683,11 @@ public partial class SwarmAssistentExtension
|
||||
}
|
||||
hitChars = Math.Max(80, Math.Min(hitChars, 800));
|
||||
|
||||
string pid = AssistentConfig.SafeId(ctx["persona"]?.ToString()) ?? personaId ?? Config?.DefaultPersonaId() ?? "neutral";
|
||||
IEnumerable<string> chain = Config?.PersonaExtendsChain(pid) ?? [];
|
||||
|
||||
JArray clippedHits = [];
|
||||
JArray heardExamples = [];
|
||||
foreach (JToken t in hits ?? [])
|
||||
{
|
||||
if (t is not JObject ho)
|
||||
@@ -634,6 +698,15 @@ public partial class SwarmAssistentExtension
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (string.Equals(ho["kind"]?.ToString(), AssistentMemory.HeardKind, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
JObject ex = Memory?.BuildHeardExampleFromHit(ho, chain);
|
||||
if (ex is not null)
|
||||
{
|
||||
heardExamples.Add(ex);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
JObject copy = (JObject)ho.DeepClone();
|
||||
string text = copy["text"]?.ToString() ?? "";
|
||||
if (text.Length > hitChars)
|
||||
@@ -644,6 +717,14 @@ public partial class SwarmAssistentExtension
|
||||
clippedHits.Add(copy);
|
||||
}
|
||||
ctx["memory_hits"] = clippedHits;
|
||||
if (heardExamples.Count > 0)
|
||||
{
|
||||
ctx["heard_examples"] = heardExamples;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.Remove("heard_examples");
|
||||
}
|
||||
ctx.Remove("taste_profile");
|
||||
ctx.Remove("enabled_loras"); // alias of selected_loras — do not double-feed
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user