Adds a read-only get_effective_run_config(taskId) tool that reports the model/max-turns/effort/permission-mode/agent-path/system-prompt/skills a task will actually run with, each tagged with its source (task/list/ preset/global), plus max-turns' raw requested value and clamp status. Extracted the model/max-turns/agent-path resolution out of TaskRunner.ResolveConfigAsync into EffectiveRunConfigResolver so the run path and the new reporting tool share one codepath instead of risking drift, per docs/explore-notes/worker-task-pipeline.md's max-turns trap.
54 lines
2.9 KiB
C#
54 lines
2.9 KiB
C#
using ClaudeDo.Data.Models;
|
|
|
|
namespace ClaudeDo.Worker.Runner;
|
|
|
|
/// <summary>The task/list/preset/global resolution <see cref="TaskRunner"/> actually runs with,
|
|
/// plus where each value came from — so a caller can tell a genuine default from an override
|
|
/// without re-deriving the resolution order itself.</summary>
|
|
public sealed record EffectiveRunConfig(
|
|
string Model, string ModelSource,
|
|
int MaxTurns, string MaxTurnsSource, int RequestedMaxTurns, bool MaxTurnsClamped,
|
|
string Effort,
|
|
string? AgentPath, string? AgentPathSource,
|
|
string PermissionMode,
|
|
bool SystemPromptSet, IReadOnlyList<string> SystemPromptSources);
|
|
|
|
/// <summary>Single source of truth for "which value wins" — shared by <see cref="TaskRunner"/>'s
|
|
/// actual run path and any read-only reporting of the same resolution (e.g. the
|
|
/// <c>get_effective_run_config</c> MCP tool), so the two can never drift apart.</summary>
|
|
public static class EffectiveRunConfigResolver
|
|
{
|
|
public static EffectiveRunConfig Resolve(
|
|
TaskEntity task, ListConfigEntity? listConfig, AppSettingsEntity global,
|
|
string? systemFile, string? improvementPrompt)
|
|
{
|
|
var model = task.Model ?? listConfig?.Model ?? global.DefaultModel;
|
|
var modelSource = task.Model is not null ? "task" : listConfig?.Model is not null ? "list" : "global";
|
|
|
|
var preset = ModelPresets.For(global.ModelPresets, model, global.DefaultMaxTurns);
|
|
|
|
var requestedMaxTurns = task.MaxTurns ?? listConfig?.MaxTurns ?? preset.MaxTurns;
|
|
var maxTurnsSource = task.MaxTurns is not null ? "task" : listConfig?.MaxTurns is not null ? "list" : "preset";
|
|
// ResolveMaxTurns is declared int? but always returns a value (Math.Min of non-null inputs).
|
|
var maxTurns = TaskRunner.ResolveMaxTurns(task.MaxTurns, listConfig?.MaxTurns, preset.MaxTurns, global.MaxTurnsCeiling)!.Value;
|
|
|
|
var agentPath = task.AgentPath ?? listConfig?.AgentPath;
|
|
var agentPathSource = task.AgentPath is not null ? "task" : listConfig?.AgentPath is not null ? "list" : null;
|
|
|
|
var systemPromptSources = new List<string>();
|
|
if (!string.IsNullOrWhiteSpace(systemFile)) systemPromptSources.Add("systemFile");
|
|
if (!string.IsNullOrWhiteSpace(improvementPrompt)) systemPromptSources.Add("improvementPrompt");
|
|
if (!string.IsNullOrWhiteSpace(global.DefaultClaudeInstructions)) systemPromptSources.Add("global");
|
|
if (!string.IsNullOrWhiteSpace(listConfig?.SystemPrompt)) systemPromptSources.Add("list");
|
|
if (!string.IsNullOrWhiteSpace(task.SystemPrompt)) systemPromptSources.Add("task");
|
|
|
|
return new EffectiveRunConfig(
|
|
model, modelSource,
|
|
maxTurns, maxTurnsSource, requestedMaxTurns, maxTurns < requestedMaxTurns,
|
|
preset.Effort,
|
|
agentPath, agentPathSource,
|
|
global.DefaultPermissionMode,
|
|
systemPromptSources.Count > 0, systemPromptSources);
|
|
}
|
|
}
|