- PUT /api/agents/{id} und /texts: Stammdaten, Grenzen, Budget, Identity/Soul/
Systemprompt (L6/L7); "Jetzt ausfuehren" in der Agentenansicht (L9)
- Lizenzschluessel ueber die Weboberflaeche (L1): erst vom Lizenzserver
bestaetigt, dann gespeichert; hebt die Sperre ohne Neustart auf
- GET/PUT /api/settings: Instanz- und Anwendungseinstellungen inkl.
OpenRouter-Key (L3/L4/L5), Geheimnisse nur schreibend
- GET/PUT /api/verwaltung/settings: Deploymentcenter und Update-Kanal des Managers
- Einstellungsseite zeigt echte Werte statt fester Texte
- NonInteractiveLicensePrompt verwies auf --license-set-key, den es nie gab
- Sprachpakete werden bei jedem Lauf geprueft (LanguagePackTests)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
102 lines
3.9 KiB
C#
102 lines
3.9 KiB
C#
using ClawdDotNet.App.Services;
|
|
using ClawdDotNet.Core.Config;
|
|
using Shouldly;
|
|
|
|
namespace ClawdDotNet.App.Tests.Services;
|
|
|
|
/// <summary>
|
|
/// #764: Editing an agent from the WebUI — what the desktop agent page did directly on the
|
|
/// configuration objects, now one checked call.
|
|
/// </summary>
|
|
public sealed class AgentUpdateTests
|
|
{
|
|
[Fact]
|
|
public void Changes_survive_a_restart_including_identity_and_soul()
|
|
{
|
|
// Identity and Soul live in their own files; written only into AgentSettings.json they
|
|
// would be overwritten by the next load.
|
|
using var host = new TestHost();
|
|
host.Host.AgentAdmin.Add(new NewAgent("scout", "Scout", "old-model")).Ok.ShouldBeTrue();
|
|
|
|
var result = host.Host.AgentAdmin.Update("scout", new AgentUpdate(
|
|
DisplayName: "Scout II", Model: "new-model", SystemPrompt: "Be brief.",
|
|
Identity: "# Identity: changed", Soul: "# Soul: changed", PromptCaching: "OFF",
|
|
MaxSteps: 42, DailyTokens: 12_345, DailyCostUsd: 1.5m, WhenExhausted: "catchupOnce"));
|
|
|
|
result.Ok.ShouldBeTrue(result.Message);
|
|
|
|
var reloaded = host.Host.Directories
|
|
.LoadInstanceConfig(host.Host.InstancePath).Agents
|
|
.Single(a => a.AgentId == "scout");
|
|
|
|
reloaded.DisplayName.ShouldBe("Scout II");
|
|
reloaded.Model.ShouldBe("new-model");
|
|
reloaded.SystemPrompt.ShouldBe("Be brief.");
|
|
reloaded.Identity.ShouldBe("# Identity: changed");
|
|
reloaded.Soul.ShouldBe("# Soul: changed");
|
|
reloaded.PromptCaching.ShouldBe("off");
|
|
reloaded.LoopGuard.MaxSteps.ShouldBe(42);
|
|
reloaded.Budget.DailyTokens.ShouldBe(12_345);
|
|
reloaded.Budget.DailyCostUsd.ShouldBe(1.5m);
|
|
reloaded.Budget.WhenExhausted.ShouldBe("catchUpOnce");
|
|
}
|
|
|
|
[Fact]
|
|
public void Fields_left_out_keep_their_value()
|
|
{
|
|
using var host = new TestHost();
|
|
host.Host.AgentAdmin.Add(new NewAgent("scout", "Scout", "model", "Watches the market")).Ok.ShouldBeTrue();
|
|
host.Host.AgentAdmin.Update("scout", new AgentUpdate(Identity: "keep me")).Ok.ShouldBeTrue();
|
|
|
|
host.Host.AgentAdmin.Update("scout", new AgentUpdate(Model: "other")).Ok.ShouldBeTrue();
|
|
|
|
var agent = host.Host.AgentAdmin.Find("scout")!;
|
|
agent.Model.ShouldBe("other");
|
|
agent.Description.ShouldBe("Watches the market");
|
|
agent.Identity.ShouldBe("keep me");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("display")]
|
|
[InlineData("caching")]
|
|
[InlineData("exhausted")]
|
|
[InlineData("steps")]
|
|
[InlineData("budget")]
|
|
public void One_bad_value_changes_nothing(string bad)
|
|
{
|
|
using var host = new TestHost(TestHost.Agent("scout", "Scout"));
|
|
var update = bad switch
|
|
{
|
|
"display" => new AgentUpdate(Model: "new-model", DisplayName: " "),
|
|
"caching" => new AgentUpdate(Model: "new-model", PromptCaching: "sometimes"),
|
|
"exhausted" => new AgentUpdate(Model: "new-model", WhenExhausted: "panic"),
|
|
"steps" => new AgentUpdate(Model: "new-model", MaxSteps: 0),
|
|
_ => new AgentUpdate(Model: "new-model", DailyCostUsd: -1m)
|
|
};
|
|
|
|
host.Host.AgentAdmin.Update("scout", update).Ok.ShouldBeFalse();
|
|
|
|
host.Host.AgentAdmin.Find("scout")!.Model.ShouldBe("anthropic/claude-sonnet-4-5");
|
|
host.Changes.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void An_unknown_agent_is_refused()
|
|
{
|
|
using var host = new TestHost();
|
|
|
|
host.Host.AgentAdmin.Update("ghost", new AgentUpdate(Model: "x")).Ok.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void A_change_is_announced()
|
|
{
|
|
// Without the event the other views (and a second browser) would keep the old values.
|
|
using var host = new TestHost(TestHost.Agent("scout"));
|
|
|
|
host.Host.AgentAdmin.Update("scout", new AgentUpdate(Model: "x")).Ok.ShouldBeTrue();
|
|
|
|
host.Changes.ShouldHaveSingleItem().Kind.ShouldBe(InstanceChangeKind.Agents);
|
|
}
|
|
}
|