Add OpenRouter chat provider; fix Windows load errors (0.17.0).

- OpenRouter as an alternative chat provider: server-side API key
  (settings.json or OPENROUTER_API_KEY), model list with vision marks and
  filter, SSE streaming, images as data URLs. Memory embeddings stay on Ollama;
  park/warm LLM are no-ops for the remote provider.
- AssistentSaveKnowledgeAttach: JArray param is not supported by SwarmUI API
  reflection and aborted registration of every later API call; use string[].
- SQLite bootstrap: preload native e_sqlite3 for the current OS/arch
  (win/osx/linux) and resolve DllImport to it.
- settings.json: shared-read + atomic write with retry to avoid Windows
  sharing violations.
- csproj: fix MSB4012 in the native SQLite copy target.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nid
2026-09-17 06:18:47 +03:00
co-authored by Claude Opus 5
parent f2b92e96ca
commit d67f5e396e
13 changed files with 740 additions and 56 deletions
+30 -2
View File
@@ -117,7 +117,10 @@ public sealed class AssistentConfig
}
try
{
return JObject.Parse(File.ReadAllText(path, Encoding.UTF8));
// Share read/write/delete: Windows otherwise fails a concurrent SaveSettings with a sharing violation.
using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
using StreamReader reader = new(fs, Encoding.UTF8);
return JObject.Parse(reader.ReadToEnd());
}
catch (Exception ex)
{
@@ -1671,7 +1674,32 @@ public sealed class AssistentConfig
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);
WriteFileAtomic(path, merged.ToString(Newtonsoft.Json.Formatting.Indented));
}
}
/// <summary>Temp file + rename, retried briefly: readers never see a half-written file and a
/// transient lock (antivirus, editor, parallel read) does not fail the API call.</summary>
static void WriteFileAtomic(string path, string text)
{
string tmp = $"{path}.{Guid.NewGuid():N}.tmp";
File.WriteAllText(tmp, text, Encoding.UTF8);
for (int attempt = 0; ; attempt++)
{
try
{
File.Move(tmp, path, overwrite: true);
return;
}
catch (IOException) when (attempt < 10)
{
System.Threading.Thread.Sleep(25 * (attempt + 1));
}
catch
{
try { File.Delete(tmp); } catch { }
throw;
}
}
}