Ship Assistent 0.13.1: compile 0.13.0 so the SwarmUI tab loads.

Add missing WebSocket/HttpClient usings, stop using static on Config/FilePath helpers, and copy Microsoft.Data.Sqlite next to the extension dll.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-22 15:14:31 +03:00
co-authored by Cursor
parent 474a674a35
commit d29436c944
10 changed files with 32 additions and 13 deletions
-1
View File
@@ -729,7 +729,6 @@ public partial class SwarmAssistentExtension
ctx.Remove("enabled_loras"); // alias of selected_loras — do not double-feed ctx.Remove("enabled_loras"); // alias of selected_loras — do not double-feed
try try
{ {
string pid = AssistentConfig.SafeId(ctx["persona"]?.ToString()) ?? Config?.DefaultPersonaId() ?? "neutral";
JObject asst = Config?.LoadAssistant(pid) ?? new JObject(); JObject asst = Config?.LoadAssistant(pid) ?? new JObject();
double weight = asst["user_prefs_weight"]?.Value<double?>() ?? 1.0; double weight = asst["user_prefs_weight"]?.Value<double?>() ?? 1.0;
int maxPrefs = asst["user_prefs_max"]?.Value<int?>() ?? 16; int maxPrefs = asst["user_prefs_max"]?.Value<int?>() ?? 16;
+3 -3
View File
@@ -137,7 +137,7 @@ public partial class SwarmAssistentExtension
string cacheKey = $"hf:{datasetId}"; string cacheKey = $"hf:{datasetId}";
if (useCache) if (useCache)
{ {
JObject cached = Memory.GetKvObject(KvHfDatasetCache)?[cacheKey] as JObject; JObject cached = Memory.GetKvObject(AssistentMemory.KvHfDatasetCache)?[cacheKey] as JObject;
if (cached is not null && cached["checked_at"]?.Value<long?>() > DateTimeOffset.UtcNow.AddHours(-6).ToUnixTimeMilliseconds()) if (cached is not null && cached["checked_at"]?.Value<long?>() > DateTimeOffset.UtcNow.AddHours(-6).ToUnixTimeMilliseconds())
{ {
return cached; return cached;
@@ -302,9 +302,9 @@ public partial class SwarmAssistentExtension
result["checked_at"] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); result["checked_at"] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
try try
{ {
JObject bag = Memory.GetKvObject(KvHfDatasetCache) ?? new JObject(); JObject bag = Memory.GetKvObject(AssistentMemory.KvHfDatasetCache) ?? new JObject();
bag[cacheKey] = result; bag[cacheKey] = result;
Memory.SetKvObject(KvHfDatasetCache, bag); Memory.SetKvObject(AssistentMemory.KvHfDatasetCache, bag);
} }
catch (Exception ex) catch (Exception ex)
{ {
+1 -1
View File
@@ -275,7 +275,7 @@ public sealed partial class AssistentMemory
cmd.Parameters.AddWithValue("$base", (object)job["base_model"]?.ToString() ?? DBNull.Value); cmd.Parameters.AddWithValue("$base", (object)job["base_model"]?.ToString() ?? DBNull.Value);
cmd.Parameters.AddWithValue("$out", (object)job["output_name"]?.ToString() ?? DBNull.Value); cmd.Parameters.AddWithValue("$out", (object)job["output_name"]?.ToString() ?? DBNull.Value);
cmd.Parameters.AddWithValue("$log", (object)job["log_path"]?.ToString() ?? DBNull.Value); cmd.Parameters.AddWithValue("$log", (object)job["log_path"]?.ToString() ?? DBNull.Value);
cmd.Parameters.AddWithValue("$prog", (object)job["progress"]?.ToString(Newtonsoft.Json.Formatting.None) ?? job["progress_json"]?.ToString() ?? DBNull.Value); cmd.Parameters.AddWithValue("$prog", (object)(job["progress"]?.ToString(Newtonsoft.Json.Formatting.None) ?? job["progress_json"]?.ToString()) ?? DBNull.Value);
cmd.Parameters.AddWithValue("$c", job["created_at"]?.Value<long?>() ?? job["createdAt"]?.Value<long?>() ?? now); cmd.Parameters.AddWithValue("$c", job["created_at"]?.Value<long?>() ?? job["createdAt"]?.Value<long?>() ?? now);
cmd.Parameters.AddWithValue("$u", now); cmd.Parameters.AddWithValue("$u", now);
cmd.Parameters.AddWithValue("$f", (object)(job["finished_at"]?.Value<long?>() ?? job["finishedAt"]?.Value<long?>()) ?? DBNull.Value); cmd.Parameters.AddWithValue("$f", (object)(job["finished_at"]?.Value<long?>() ?? job["finishedAt"]?.Value<long?>()) ?? DBNull.Value);
+2 -2
View File
@@ -10,7 +10,7 @@ public partial class SwarmAssistentExtension
{ {
static readonly Regex JsonFenceRe = new(@"```(?:json)?\s*([\s\S]*?)```", RegexOptions.IgnoreCase | RegexOptions.Compiled); static readonly Regex JsonFenceRe = new(@"```(?:json)?\s*([\s\S]*?)```", RegexOptions.IgnoreCase | RegexOptions.Compiled);
static string[] PatchKeys => _patchKeys ??= Config?.LoadPatchKeys() ?? []; string[] PatchKeys => _patchKeys ??= Config?.LoadPatchKeys() ?? [];
static string[] _patchKeys; static string[] _patchKeys;
@@ -68,7 +68,7 @@ public partial class SwarmAssistentExtension
&& (HasValue(obj, "triggers") || HasValue(obj, "when") || HasValue(obj, "prompt_hint") || HasValue(obj, "notes")); && (HasValue(obj, "triggers") || HasValue(obj, "when") || HasValue(obj, "prompt_hint") || HasValue(obj, "notes"));
} }
static JObject TryParsePatch(string reply) JObject TryParsePatch(string reply)
{ {
if (string.IsNullOrWhiteSpace(reply)) if (string.IsNullOrWhiteSpace(reply))
{ {
+3 -3
View File
@@ -11,7 +11,7 @@ namespace Mrleo1nid.SwarmAssistent;
/// <summary>Link training dataset samples to the live agent as retrievable &quot;heard&quot; examples.</summary> /// <summary>Link training dataset samples to the live agent as retrievable &quot;heard&quot; examples.</summary>
public partial class SwarmAssistentExtension public partial class SwarmAssistentExtension
{ {
static string MemoryEmbedForTraining(string personaId = null) string MemoryEmbedForTraining(string personaId = null)
{ {
string pid = AssistentConfig.SafeId(personaId) ?? Config.DefaultPersonaId(); string pid = AssistentConfig.SafeId(personaId) ?? Config.DefaultPersonaId();
return Config.LoadSettings()["embed_model"]?.ToString() return Config.LoadSettings()["embed_model"]?.ToString()
@@ -19,7 +19,7 @@ public partial class SwarmAssistentExtension
?? "nomic-embed-text"; ?? "nomic-embed-text";
} }
static string MemoryBaseForTraining(JObject raw = null) string MemoryBaseForTraining(JObject raw = null)
=> MemoryBaseUrl(raw?["base_url"]?.ToString()); => MemoryBaseUrl(raw?["base_url"]?.ToString());
public async Task<JObject> AssistentGetDatasetAgentSettings(Session session) public async Task<JObject> AssistentGetDatasetAgentSettings(Session session)
@@ -96,7 +96,7 @@ public partial class SwarmAssistentExtension
string persona = raw?["persona"]?.ToString(); string persona = raw?["persona"]?.ToString();
string status = approvedOnly ? "approved" : "all"; string status = approvedOnly ? "approved" : "all";
List<JObject> samples = Memory.ListTrainSamples(status, persona, null, 2000); List<JObject> samples = Memory.ListTrainSamples(status, persona, null, 2000);
string baseUrl = MemoryBaseForTraining(raw); string baseUrl = MemoryBaseForTraining(raw);
int linked = 0; int linked = 0;
int skipped = 0; int skipped = 0;
List<string> errors = []; List<string> errors = [];
+1
View File
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
+3 -1
View File
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
@@ -156,7 +158,7 @@ public partial class SwarmAssistentExtension
return sb.ToString().Trim(); return sb.ToString().Trim();
} }
static string BuildRunnerCommand(JObject runner, string configPath, string logPath, string workDir) string BuildRunnerCommand(JObject runner, string configPath, string logPath, string workDir)
{ {
string python = runner["python"]?.ToString()?.Trim(); string python = runner["python"]?.ToString()?.Trim();
if (string.IsNullOrWhiteSpace(python)) if (string.IsNullOrWhiteSpace(python))
+2
View File
@@ -4,6 +4,8 @@ SwarmUI extension for **collaborative Krea 2** prompting via **Ollama**: chat +
**Turn model:** one user message is one *turn*. A turn may fan out into nested LLM *hops* — Krea prompt prep, empty-patch retry, vision, auto-critique. Hops share one `HOP_BUDGET`, never re-read the user's text (their prompt is client-authored), and pass the busy gate that blocks new user sends. What a reply does to generation state is decided once, in `resolveTurnIntent`: the model's `actions:["generate"]` / `look_at` win, RU intent heuristics only back it up when the model forgets, and an explicit «запомни, не генерируй» vetoes both. **Turn model:** one user message is one *turn*. A turn may fan out into nested LLM *hops* — Krea prompt prep, empty-patch retry, vision, auto-critique. Hops share one `HOP_BUDGET`, never re-read the user's text (their prompt is client-authored), and pass the busy gate that blocks new user sends. What a reply does to generation state is decided once, in `resolveTurnIntent`: the model's `actions:["generate"]` / `look_at` win, RU intent heuristics only back it up when the model forgets, and an explicit «запомни, не генерируй» vetoes both.
**Version 0.13.1** — Сборка 0.13.0: `using` для `WebSocket`/`HttpClient`, instance-методы с `Config`/`FilePath`, Sqlite dll рядом с extension (иначе вкладка не грузится / API пустые).
**Version 0.13.0****Реальный QLoRA-пайплайн**: `train_qlora.py` (TRL SFTTrainer + PEFT), HF-датасеты с маппингом (preset fiction title/tags→text), `max_samples`, полный post-train: safetensors → GGUF (`convert_lora_to_gguf.py`) → `ollama create` с `FROM ollama_base` + `ADAPTER`. Раннер: `builtin` + `custom`. Зависимости: `scripts/requirements-train.txt`. **Version 0.13.0****Реальный QLoRA-пайплайн**: `train_qlora.py` (TRL SFTTrainer + PEFT), HF-датасеты с маппингом (preset fiction title/tags→text), `max_samples`, полный post-train: safetensors → GGUF (`convert_lora_to_gguf.py`) → `ollama create` с `FROM ollama_base` + `ADAPTER`. Раннер: `builtin` + `custom`. Зависимости: `scripts/requirements-train.txt`.
**Version 0.12.1****Услышанное → агент**: одобренные примеры датасета сразу попадают в vector memory (`kind=heard`) и в контекст чата как `heard_examples` (без QLoRA). На вкладке «Датасет»: авто-подключение при одобрении, синхронизация всех, per-sample 🔗. Агент может запросить `heard_search`. Настройки: `training-agent.json`. **Version 0.12.1****Услышанное → агент**: одобренные примеры датасета сразу попадают в vector memory (`kind=heard`) и в контекст чата как `heard_examples` (без QLoRA). На вкладке «Датасет»: авто-подключение при одобрении, синхронизация всех, per-sample 🔗. Агент может запросить `heard_search`. Настройки: `training-agent.json`.
+2 -2
View File
@@ -33,7 +33,7 @@ public partial 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.13.0"; Version = "0.13.1";
Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory", "training", "heard", "qlora"]; Tags = ["tabs", "ui", "llm", "ollama", "krea", "inpaint", "memory", "training", "heard", "qlora"];
} }
@@ -104,7 +104,7 @@ public partial class SwarmAssistentExtension : Extension
API.RegisterAPICall(AssistentLinkTrainSampleToAgent, true, PermUse); API.RegisterAPICall(AssistentLinkTrainSampleToAgent, true, PermUse);
API.RegisterAPICall(AssistentUnlinkTrainSampleFromAgent, true, PermUse); API.RegisterAPICall(AssistentUnlinkTrainSampleFromAgent, true, PermUse);
API.RegisterAPICall(AssistentSyncDatasetToAgent, true, PermUse); API.RegisterAPICall(AssistentSyncDatasetToAgent, true, PermUse);
Logs.Init("Swarm Assistent extension loaded (0.13.0 real QLoRA pipeline)"); Logs.Init("Swarm Assistent extension loaded (0.13.1 QLoRA pipeline)");
} }
int CfgInt(string key, int fallback) int CfgInt(string key, int fallback)
+15
View File
@@ -6,4 +6,19 @@
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.11" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.11" />
</ItemGroup> </ItemGroup>
<Import Project="../../SwarmUI.extension.props" /> <Import Project="../../SwarmUI.extension.props" />
<!-- Must come after the import: SwarmUI.extension.props disables it, but the Sqlite
assemblies have to sit next to the extension dll for SwarmExtensionLoadContext
to resolve them as private deps. -->
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<!-- Everything else in the lock file is already loaded by the SwarmUI host. -->
<Target Name="ShipOnlySqlitePrivateDeps" AfterTargets="ResolveReferences">
<ItemGroup>
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)"
Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != 'Microsoft.Data.Sqlite'
AND '%(ReferenceCopyLocalPaths.NuGetPackageId)' != 'Microsoft.Data.Sqlite.Core'
AND !$([System.String]::Copy('%(ReferenceCopyLocalPaths.NuGetPackageId)').StartsWith('SQLitePCLRaw'))" />
</ItemGroup>
</Target>
</Project> </Project>