Merge claudedo/123b0241b5e94b69bfa592fde89c51aa

This commit is contained in:
mika kuns
2026-08-05 22:44:47 +02:00
9 changed files with 383 additions and 20 deletions
+66 -1
View File
@@ -1,7 +1,10 @@
using System.ComponentModel;
using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Runner;
using Microsoft.EntityFrameworkCore;
using ModelContextProtocol.Server;
namespace ClaudeDo.Worker.External;
@@ -11,18 +14,36 @@ public sealed record TaskConfigResult(bool Found, TaskConfigDto? Config);
public sealed record SetListConfigResult(bool Ok, string ListId, TaskConfigDto? Config);
public sealed record SetTaskConfigResult(bool Ok, string TaskId, TaskConfigDto? Config);
public sealed record EffectiveModelDto(string Value, string Source);
public sealed record EffectiveMaxTurnsDto(int Effective, string Source, int Requested, bool Clamped);
public sealed record EffectiveAgentPathDto(string? Value, string? Source);
public sealed record EffectiveSystemPromptDto(bool Set, IReadOnlyList<string> Sources);
public sealed record EffectiveRunConfigDto(
string TaskId,
EffectiveModelDto Model,
EffectiveMaxTurnsDto MaxTurns,
string Effort,
string PermissionMode,
EffectiveAgentPathDto AgentPath,
EffectiveSystemPromptDto SystemPrompt,
IReadOnlyList<string> SkillNames);
[McpServerToolType]
public sealed class ConfigMcpTools
{
private readonly ListRepository _lists;
private readonly TaskRepository _tasks;
private readonly HubBroadcaster _broadcaster;
private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
public ConfigMcpTools(ListRepository lists, TaskRepository tasks, HubBroadcaster broadcaster)
public ConfigMcpTools(
ListRepository lists, TaskRepository tasks, HubBroadcaster broadcaster,
IDbContextFactory<ClaudeDoDbContext> dbFactory)
{
_lists = lists;
_tasks = tasks;
_broadcaster = broadcaster;
_dbFactory = dbFactory;
}
[McpServerTool, Description("Get a list's default config (model, system prompt, agent path). Returns { found: false, config: null } if no config is set.")]
@@ -97,4 +118,48 @@ public sealed class ConfigMcpTools
return new TaskConfigResult(false, null);
return new TaskConfigResult(true, new TaskConfigDto(task.Model, task.SystemPrompt, task.AgentPath, task.MaxTurns));
}
[McpServerTool, Description(
"Get the config a task will ACTUALLY run with — model, max turns, effort, permission mode, agent path, " +
"whether a system prompt is set, and skill names — with each field's source (task/list/preset/global). " +
"Uses the exact same resolution TaskRunner runs with, so this never drifts from get_app_settings/" +
"get_task_config's raw, possibly-unused values. maxTurns also reports the raw requested value and " +
"whether it was clamped to the global ceiling. Read-only, no side effects.")]
public async Task<EffectiveRunConfigDto> GetEffectiveRunConfig(string taskId, CancellationToken cancellationToken)
{
var task = await _tasks.GetByIdAsync(taskId, cancellationToken)
?? throw new InvalidOperationException($"Task {taskId} not found.");
var listConfig = await _lists.GetConfigAsync(task.ListId, cancellationToken);
AppSettingsEntity global;
using (var ctx = await _dbFactory.CreateDbContextAsync(cancellationToken))
global = await new AppSettingsRepository(ctx).GetAsync(cancellationToken);
var systemFile = PromptFiles.ReadOrDefault(PromptKind.System);
var isImprovementChild = task.ParentTaskId is not null && task.CreatedBy == task.ParentTaskId;
var improvementPrompt = isImprovementChild ? PromptFiles.ReadOrDefault(PromptKind.ImprovementChild) : null;
var effective = EffectiveRunConfigResolver.Resolve(task, listConfig, global, systemFile, improvementPrompt);
var requestedSkills = TaskRunner.UnionSkillNames(task.SessionSkills, listConfig?.SessionSkills, global.SessionSkills);
var skillNames = requestedSkills;
if (requestedSkills.Count > 0)
{
List<SessionSkillEntity> installed;
using (var ctx = await _dbFactory.CreateDbContextAsync(cancellationToken))
installed = (await new SessionSkillRepository(ctx).ListAsync(cancellationToken)).ToList();
var installedNames = installed.Select(s => s.Name).ToHashSet(StringComparer.Ordinal);
skillNames = TaskRunner.FilterToInstalled(requestedSkills, installedNames);
}
return new EffectiveRunConfigDto(
taskId,
new EffectiveModelDto(effective.Model, effective.ModelSource),
new EffectiveMaxTurnsDto(effective.MaxTurns, effective.MaxTurnsSource, effective.RequestedMaxTurns, effective.MaxTurnsClamped),
effective.Effort,
effective.PermissionMode,
new EffectiveAgentPathDto(effective.AgentPath, effective.AgentPathSource),
new EffectiveSystemPromptDto(effective.SystemPromptSet, effective.SystemPromptSources),
skillNames);
}
}