Automatisierungsvorschlaege nur mit n8n-Anbindung (#726)
An instance without n8n has no use for workflow proposals. New instance
setting automation.enabled ("this instance works with n8n"), off by default:
- off: automation_find/automation_propose refuse, no candidates are put to
agents, and the escalation tool does not mention proposals at all;
- the switch sits in the settings card for external MCP servers; the
approvals view says proposals are off instead of standing empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
184a507e3d
commit
a17ac2957f
@@ -9,6 +9,16 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ClawdDotNet.Core.Automation;
|
||||
|
||||
/// <summary>
|
||||
/// #726: Whether the instance works with n8n. Off by default: an instance without n8n has no
|
||||
/// use for workflow proposals, and every proposal and candidate costs runs and attention.
|
||||
/// </summary>
|
||||
public sealed class AutomationSettings
|
||||
{
|
||||
[System.Text.Json.Serialization.JsonPropertyName("enabled")]
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>What the replaced tasks cost over the measured days — taken from the receipts, not estimated.</summary>
|
||||
public sealed record MeasuredSavings(int Days, int Runs, decimal CostUsd, long Tokens)
|
||||
{
|
||||
@@ -32,6 +42,9 @@ public sealed record AutomationOutcome(bool Ok, string Message, long? Id = null)
|
||||
|
||||
public interface IAutomationProposals
|
||||
{
|
||||
/// <summary>Whether the instance works with n8n — without it, nothing is proposed.</summary>
|
||||
bool Enabled { get; }
|
||||
|
||||
Task<IReadOnlyList<AutomationProposal>> FindAsync(string subject, CancellationToken ct);
|
||||
|
||||
Task<AutomationOutcome> ProposeAsync(AutomationRequest request, CancellationToken ct);
|
||||
@@ -57,8 +70,13 @@ public sealed class AutomationProposals(
|
||||
ITaskRepository tasks,
|
||||
TaskboardService? board,
|
||||
ILogger logger,
|
||||
Func<AutomationSettings>? settings = null,
|
||||
TimeProvider? clock = null) : IAutomationProposals, IAsyncDisposable
|
||||
{
|
||||
public bool Enabled => settings?.Invoke().Enabled ?? true;
|
||||
|
||||
public const string DisabledMessage = "This instance does not work with n8n — workflow proposals are switched off.";
|
||||
|
||||
public const int MaxOpenPerAgent = 3;
|
||||
public const int MeasureDays = 28;
|
||||
|
||||
@@ -85,6 +103,8 @@ public sealed class AutomationProposals(
|
||||
|
||||
public async Task<AutomationOutcome> ProposeAsync(AutomationRequest r, CancellationToken ct)
|
||||
{
|
||||
if (!Enabled)
|
||||
return new(false, DisabledMessage);
|
||||
if (string.IsNullOrWhiteSpace(r.Purpose) || string.IsNullOrWhiteSpace(r.Trigger))
|
||||
return new(false, "'purpose' and 'trigger' are required — what it is for, and what starts it.");
|
||||
if (r.TaskIds.Count == 0)
|
||||
@@ -236,7 +256,7 @@ public sealed class AutomationProposals(
|
||||
/// </summary>
|
||||
public async Task<IReadOnlyList<string>> FindCandidatesAsync(CancellationToken ct)
|
||||
{
|
||||
if (board is null)
|
||||
if (board is null || !Enabled)
|
||||
return [];
|
||||
var since = Now.AddDays(-CandidateDays);
|
||||
var proposals = await ListAsync(null, 1000, ct);
|
||||
|
||||
@@ -159,6 +159,10 @@ public sealed class InstanceConfig
|
||||
[JsonPropertyName("fileHistory")]
|
||||
public Files.FileHistorySettings FileHistory { get; set; } = new();
|
||||
|
||||
/// <summary>#726: Whether this instance works with n8n — only then do agents propose workflows. Off by default.</summary>
|
||||
[JsonPropertyName("automation")]
|
||||
public Automation.AutomationSettings Automation { get; set; } = new();
|
||||
|
||||
/// <summary>#197: External MCP servers whose tools the agents may use — set up by a human only.</summary>
|
||||
[JsonPropertyName("mcpServers")]
|
||||
public List<Mcp.McpServerConfig> McpServers { get; set; } = new();
|
||||
|
||||
Reference in New Issue
Block a user