Ship Assistent 0.14.1: Exact generate params and cheap park/warm.
Client always merges Exact turbo|raw steps/cfg/sigma before Generate so sparse LLM omissions and leftover SD 20/7 cannot stick; Ollama park/warm skip no-op /api/ps round-trips when the chat model is already unloaded or resident. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+73
-3
@@ -10,7 +10,9 @@ namespace Mrleo1nid.SwarmAssistent;
|
||||
|
||||
/// <summary>VRAM handover between Ollama and the image backend: park the chat model before
|
||||
/// Generate, warm it again once the user is back in the chat. Embed / memory models are never
|
||||
/// parked — they are tiny and reloading them stalls every retrieve.</summary>
|
||||
/// parked — they are tiny and reloading them stalls every retrieve.
|
||||
/// Warm is a no-op when Ollama already has the chat model resident (/api/ps) so post-Generate
|
||||
/// reload is cheap when Krea did not evict VL.</summary>
|
||||
public partial class SwarmAssistentExtension
|
||||
{
|
||||
const string WarmKeepAlive = "15m";
|
||||
@@ -28,6 +30,18 @@ public partial class SwarmAssistentExtension
|
||||
{
|
||||
return new JObject { ["success"] = true, ["parked"] = false, ["skipped"] = "memory model — never parked" };
|
||||
}
|
||||
// Already unloaded — skip the keep_alive:0 round-trip.
|
||||
if (!await IsOllamaModelResident(root, name))
|
||||
{
|
||||
return new JObject
|
||||
{
|
||||
["success"] = true,
|
||||
["parked"] = false,
|
||||
["skipped"] = "not_resident",
|
||||
["model"] = name,
|
||||
["base_url"] = root,
|
||||
};
|
||||
}
|
||||
JObject generate = new()
|
||||
{
|
||||
["model"] = name,
|
||||
@@ -56,7 +70,8 @@ public partial class SwarmAssistentExtension
|
||||
return new JObject { ["success"] = true, ["parked"] = true, ["model"] = name, ["base_url"] = root };
|
||||
}
|
||||
|
||||
/// <summary>Single-token chat so the model is resident again by the time the user types.</summary>
|
||||
/// <summary>Single-token chat so the model is resident again by the time the user types.
|
||||
/// Skips the load when /api/ps already lists the model (avoids ~20–30s no-op warm).</summary>
|
||||
public async Task<JObject> AssistentWarmLlm(Session session, string baseUrl, string model)
|
||||
{
|
||||
string root = NormalizeBaseUrl(baseUrl);
|
||||
@@ -69,6 +84,17 @@ public partial class SwarmAssistentExtension
|
||||
{
|
||||
return new JObject { ["success"] = true, ["warmed"] = false, ["skipped"] = "memory model" };
|
||||
}
|
||||
if (await IsOllamaModelResident(root, name))
|
||||
{
|
||||
return new JObject
|
||||
{
|
||||
["success"] = true,
|
||||
["warmed"] = true,
|
||||
["skipped"] = "already_resident",
|
||||
["model"] = name,
|
||||
["keep_alive"] = WarmKeepAlive,
|
||||
};
|
||||
}
|
||||
int numCtx = CfgInt("num_ctx", DefaultNumCtxFallback);
|
||||
JObject payload = new()
|
||||
{
|
||||
@@ -101,6 +127,50 @@ public partial class SwarmAssistentExtension
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>True when Ollama /api/ps lists <paramref name="model"/> (or a matching tag).</summary>
|
||||
async Task<bool> IsOllamaModelResident(string root, string model)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(root) || string.IsNullOrWhiteSpace(model))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
using HttpResponseMessage resp = await HttpClient.GetAsync($"{root}/api/ps");
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string body = await resp.Content.ReadAsStringAsync();
|
||||
JObject parsed = JObject.Parse(body);
|
||||
JArray models = parsed["models"] as JArray ?? [];
|
||||
foreach (JToken m in models)
|
||||
{
|
||||
string name = m["name"]?.ToString() ?? m["model"]?.ToString() ?? "";
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (string.Equals(name, model, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Tags may differ by :latest vs bare name.
|
||||
if (name.StartsWith(model + ":", StringComparison.OrdinalIgnoreCase)
|
||||
|| model.StartsWith(name + ":", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logs.Debug($"IsOllamaModelResident: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static async Task<(bool ok, string body)> PostOllamaJson(string root, string route, JObject payload)
|
||||
{
|
||||
try
|
||||
@@ -108,7 +178,7 @@ public partial class SwarmAssistentExtension
|
||||
using StringContent content = new(payload.ToString(Newtonsoft.Json.Formatting.None), Encoding.UTF8, "application/json");
|
||||
using HttpResponseMessage resp = await HttpClient.PostAsync($"{root}{route}", content);
|
||||
string body = await resp.Content.ReadAsStringAsync();
|
||||
return (resp.IsSuccessStatusCode, resp.IsSuccessStatusCode ? body : $"HTTP {(int)resp.StatusCode}: {body}");
|
||||
return (resp.IsSuccessStatusCode, body);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user