using ClawdDotNet.Core.Config; using ClawdDotNet.Core.Organisation; namespace ClawdDotNet.Core.Cases; /// /// #690: The deciding instance at the top of the tree (Organisation-Konzept, section 6). /// /// A role, not a person. A human, an agent, or the human first with the agent /// behind — otherwise the kit would fix one picture of a company. /// /// What a deciding agent may not do matters more than what it may. 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 /// and stands outside the units; an agent that does not fit is not given a case — the human is. /// /// It makes the organisation faster, not more right. Its data comes from the same /// instance, with the same possible errors. Every decision it takes is therefore presented to /// the human to read (), and the deadline holds for it too. /// public static class TopRole { /// /// 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. /// public static readonly IReadOnlySet AllowedTools = new HashSet(StringComparer.OrdinalIgnoreCase) { "Taskboard", CaseDesk.ToolName, "Memory", "FileRW", "AgentComm" }; /// /// Why this agent cannot take the top, or null. Checked when it is set and again /// every time a case would go to it — the configuration may have changed in between. /// 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; } /// The deciding agent, if the settings name one and it fits; otherwise null and why. 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); } }