Entscheidungsinstanz an der Spitze: Mensch, Agent oder Mensch zuerst mit Frist (#690)
- cases.top in instance.json: Human | Agent | HumanFirst, agentId, humanFirstHours - TopRole: der entscheidende Agent steht in keiner Einheit, liest keine Fremdinhalte und hat nur Taskboard, Escalation, Memory, FileRW, AgentComm; geprueft beim Setzen, bei jeder Zustellung und vor jeder Entscheidung - CaseDesk: was bisher an der Spitze beim Menschen landete, geht nach Einstellung an den Agenten; Tagesdeckel und Frist gehen weiter an den Menschen. handle verwehrt, forward geht an den Menschen. Mensch zuerst: Uebergabe nach Ablauf, eigene Frist. Der Mensch kann einen Fall des Agenten selbst entscheiden. - Beschluesse des Agenten: ByTopAgent, zum Lesen vorgelegt; jeder Beschluss laesst sich mit Begruendung zuruecknehmen und bindet dann niemanden mehr - Briefing fuer den Agenten an der Spitze, auch ohne Einheiten - OrgAdministration.SetTop mit Audit; Werkzeugsperre und Verschiebesperre - WebUI Vorgaenge: Reiter Spitze, Lesen/Zuruecknehmen, Zaehler; i18n en/de - Tests: TopRoleTests (15), OrgAdministrationTests (+2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e22edb418a
commit
e8964e3c74
@@ -0,0 +1,64 @@
|
||||
using ClawdDotNet.Core.Config;
|
||||
using ClawdDotNet.Core.Organisation;
|
||||
|
||||
namespace ClawdDotNet.Core.Cases;
|
||||
|
||||
/// <summary>
|
||||
/// #690: The deciding instance at the top of the tree (Organisation-Konzept, section 6).
|
||||
///
|
||||
/// <para><b>A role, not a person.</b> A human, an agent, or the human first with the agent
|
||||
/// behind — otherwise the kit would fix one picture of a company.</para>
|
||||
///
|
||||
/// <para><b>What a deciding agent may not do matters more than what it may.</b> It decides
|
||||
/// questions and does not carry them out; it has no tool with an effect outside; it does not
|
||||
/// change the structure. Otherwise the top of the organisation is its largest hole — a model
|
||||
/// with full power and nobody opposite. So it holds only the tools of <see cref="AllowedTools"/>
|
||||
/// and stands outside the units; an agent that does not fit is not given a case — the human is.</para>
|
||||
///
|
||||
/// <para><b>It makes the organisation faster, not more right.</b> Its data comes from the same
|
||||
/// instance, with the same possible errors. Every decision it takes is therefore presented to
|
||||
/// the human to read (<see cref="Decision.ByTopAgent"/>), and the deadline holds for it too.</para>
|
||||
/// </summary>
|
||||
public static class TopRole
|
||||
{
|
||||
/// <summary>
|
||||
/// What a deciding agent may hold: tasks for the units that carry a decision out, its own
|
||||
/// case tool, memory, files inside the instance, and talking to agents. Nothing with an
|
||||
/// effect outside (Mail, Telegram, social media, FTP, APIs), nothing that reads foreign
|
||||
/// content into the top, no database, nothing that creates or edits agents.
|
||||
/// </summary>
|
||||
public static readonly IReadOnlySet<string> AllowedTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"Taskboard", CaseDesk.ToolName, "Memory", "FileRW", "AgentComm"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Why this agent cannot take the top, or <c>null</c>. Checked when it is set and again
|
||||
/// every time a case would go to it — the configuration may have changed in between.
|
||||
/// </summary>
|
||||
public static string? Unfit(AgentConfig? agent, string agentId)
|
||||
{
|
||||
if (agent is null)
|
||||
return $"There is no agent '{agentId}'.";
|
||||
if (!string.IsNullOrWhiteSpace(agent.UnitId))
|
||||
return $"'{agent.AgentId}' belongs to a unit. The deciding agent stands above all units, not in one — " +
|
||||
"move it to the top level first.";
|
||||
if (agent.TreatAsForeignReader)
|
||||
return $"'{agent.AgentId}' is set to read content from outside. Whoever decides for the whole instance must not.";
|
||||
var beyond = agent.Tools.Keys.Where(t => !AllowedTools.Contains(t)).OrderBy(t => t, StringComparer.OrdinalIgnoreCase).ToList();
|
||||
if (beyond.Count > 0)
|
||||
return $"'{agent.AgentId}' holds tools a deciding agent may not have: {string.Join(", ", beyond)}. " +
|
||||
$"It decides, it does not carry out — allowed are {string.Join(", ", AllowedTools.Order(StringComparer.OrdinalIgnoreCase))}.";
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>The deciding agent, if the settings name one and it fits; otherwise <c>null</c> and why.</summary>
|
||||
public static (AgentConfig? Agent, string? Problem) Resolve(TopSettings top, OrgChart? org)
|
||||
{
|
||||
if (!top.UsesAgent)
|
||||
return (null, null);
|
||||
var agent = org?.Agent(top.AgentId!.Trim());
|
||||
var problem = Unfit(agent, top.AgentId!.Trim());
|
||||
return problem is null ? (agent, null) : (null, problem);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user