feat(worker): add hub methods for list and task agent settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,9 @@ public sealed class HubBroadcaster
|
|||||||
public Task TaskUpdated(string taskId) =>
|
public Task TaskUpdated(string taskId) =>
|
||||||
_hub.Clients.All.SendAsync("TaskUpdated", taskId);
|
_hub.Clients.All.SendAsync("TaskUpdated", taskId);
|
||||||
|
|
||||||
|
public Task ListUpdated(string listId) =>
|
||||||
|
_hub.Clients.All.SendAsync("ListUpdated", listId);
|
||||||
|
|
||||||
public Task RunCreated(string taskId, int runNumber, bool isRetry) =>
|
public Task RunCreated(string taskId, int runNumber, bool isRetry) =>
|
||||||
_hub.Clients.All.SendAsync("RunCreated", taskId, runNumber, isRetry);
|
_hub.Clients.All.SendAsync("RunCreated", taskId, runNumber, isRetry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ public record WorktreeCleanupDto(int Removed);
|
|||||||
public record WorktreeResetDto(int Removed, int TasksAffected, bool Blocked, int RunningTasks);
|
public record WorktreeResetDto(int Removed, int TasksAffected, bool Blocked, int RunningTasks);
|
||||||
public record MergeResultDto(string Status, IReadOnlyList<string> ConflictFiles, string? ErrorMessage);
|
public record MergeResultDto(string Status, IReadOnlyList<string> ConflictFiles, string? ErrorMessage);
|
||||||
public record MergeTargetsDto(string DefaultBranch, IReadOnlyList<string> LocalBranches);
|
public record MergeTargetsDto(string DefaultBranch, IReadOnlyList<string> LocalBranches);
|
||||||
|
public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType);
|
||||||
|
public record UpdateListConfigDto(string ListId, string? Model, string? SystemPrompt, string? AgentPath);
|
||||||
|
public record UpdateTaskAgentSettingsDto(string TaskId, string? Model, string? SystemPrompt, string? AgentPath);
|
||||||
|
public record ListConfigDto(string? Model, string? SystemPrompt, string? AgentPath);
|
||||||
|
|
||||||
public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
||||||
{
|
{
|
||||||
@@ -205,4 +209,70 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
|||||||
throw new HubException(ex.Message);
|
throw new HubException(ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateList(UpdateListDto dto)
|
||||||
|
{
|
||||||
|
using var ctx = _dbFactory.CreateDbContext();
|
||||||
|
var repo = new ListRepository(ctx);
|
||||||
|
var entity = await repo.GetByIdAsync(dto.Id);
|
||||||
|
if (entity is null) throw new HubException("list not found");
|
||||||
|
|
||||||
|
entity.Name = dto.Name;
|
||||||
|
entity.WorkingDir = string.IsNullOrWhiteSpace(dto.WorkingDir) ? null : dto.WorkingDir;
|
||||||
|
entity.DefaultCommitType = string.IsNullOrWhiteSpace(dto.DefaultCommitType) ? "chore" : dto.DefaultCommitType;
|
||||||
|
await repo.UpdateAsync(entity);
|
||||||
|
|
||||||
|
await _broadcaster.ListUpdated(dto.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateListConfig(UpdateListConfigDto dto)
|
||||||
|
{
|
||||||
|
using var ctx = _dbFactory.CreateDbContext();
|
||||||
|
var repo = new ListRepository(ctx);
|
||||||
|
|
||||||
|
var model = Nullify(dto.Model);
|
||||||
|
var systemPrompt = Nullify(dto.SystemPrompt);
|
||||||
|
var agentPath = Nullify(dto.AgentPath);
|
||||||
|
|
||||||
|
if (model is null && systemPrompt is null && agentPath is null)
|
||||||
|
{
|
||||||
|
await repo.DeleteConfigAsync(dto.ListId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await repo.SetConfigAsync(new ListConfigEntity
|
||||||
|
{
|
||||||
|
ListId = dto.ListId,
|
||||||
|
Model = model,
|
||||||
|
SystemPrompt = systemPrompt,
|
||||||
|
AgentPath = agentPath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _broadcaster.ListUpdated(dto.ListId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ListConfigDto?> GetListConfig(string listId)
|
||||||
|
{
|
||||||
|
using var ctx = _dbFactory.CreateDbContext();
|
||||||
|
var repo = new ListRepository(ctx);
|
||||||
|
var config = await repo.GetConfigAsync(listId);
|
||||||
|
if (config is null) return null;
|
||||||
|
return new ListConfigDto(config.Model, config.SystemPrompt, config.AgentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateTaskAgentSettings(UpdateTaskAgentSettingsDto dto)
|
||||||
|
{
|
||||||
|
using var ctx = _dbFactory.CreateDbContext();
|
||||||
|
var repo = new TaskRepository(ctx);
|
||||||
|
await repo.UpdateAgentSettingsAsync(
|
||||||
|
dto.TaskId,
|
||||||
|
Nullify(dto.Model),
|
||||||
|
Nullify(dto.SystemPrompt),
|
||||||
|
Nullify(dto.AgentPath));
|
||||||
|
|
||||||
|
await _broadcaster.TaskUpdated(dto.TaskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? Nullify(string? s) => string.IsNullOrWhiteSpace(s) ? null : s;
|
||||||
}
|
}
|
||||||
|
|||||||
47
tests/ClaudeDo.Worker.Tests/Hub/AgentSettingsHubTests.cs
Normal file
47
tests/ClaudeDo.Worker.Tests/Hub/AgentSettingsHubTests.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using ClaudeDo.Data.Models;
|
||||||
|
using ClaudeDo.Data.Repositories;
|
||||||
|
using ClaudeDo.Worker.Tests.Infrastructure;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ClaudeDo.Worker.Tests.Hub;
|
||||||
|
|
||||||
|
public sealed class AgentSettingsHubTests : IDisposable
|
||||||
|
{
|
||||||
|
private readonly DbFixture _db = new();
|
||||||
|
private readonly ClaudeDo.Data.ClaudeDoDbContext _ctx;
|
||||||
|
private readonly ListRepository _repo;
|
||||||
|
|
||||||
|
public AgentSettingsHubTests()
|
||||||
|
{
|
||||||
|
_ctx = _db.CreateContext();
|
||||||
|
_repo = new ListRepository(_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_ctx.Dispose();
|
||||||
|
_db.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UpdateListConfig_AllNull_DeletesRow()
|
||||||
|
{
|
||||||
|
var listId = Guid.NewGuid().ToString();
|
||||||
|
await _repo.AddAsync(new ListEntity { Id = listId, Name = "L", CreatedAt = DateTime.UtcNow });
|
||||||
|
await _repo.SetConfigAsync(new ListConfigEntity
|
||||||
|
{
|
||||||
|
ListId = listId, Model = "opus", SystemPrompt = null, AgentPath = null,
|
||||||
|
});
|
||||||
|
|
||||||
|
string? model = null, sp = null, ap = null;
|
||||||
|
if (model is null && sp is null && ap is null)
|
||||||
|
await _repo.DeleteConfigAsync(listId);
|
||||||
|
else
|
||||||
|
await _repo.SetConfigAsync(new ListConfigEntity
|
||||||
|
{
|
||||||
|
ListId = listId, Model = model, SystemPrompt = sp, AgentPath = ap,
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Null(await _repo.GetConfigAsync(listId));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user