| | | 1 | | namespace NexusLabs.Needlr.AgentFramework; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// Declares a directed edge from the decorated agent to the specified target |
| | | 5 | | /// agent type within a named graph workflow. Apply multiple times for fan-out |
| | | 6 | | /// (multiple outgoing edges from one agent). |
| | | 7 | | /// </summary> |
| | | 8 | | /// <remarks> |
| | | 9 | | /// <para> |
| | | 10 | | /// Edge placement follows the same convention as <see cref="AgentHandoffsToAttribute"/>: |
| | | 11 | | /// the attribute is placed on the <em>source</em> agent and references the target. |
| | | 12 | | /// </para> |
| | | 13 | | /// <para> |
| | | 14 | | /// When <see cref="Condition"/> is set, the edge is conditional. In |
| | | 15 | | /// <see cref="GraphRoutingMode.Deterministic"/> mode, the condition string |
| | | 16 | | /// names a predicate method on the agent class. In |
| | | 17 | | /// <see cref="GraphRoutingMode.LlmChoice"/> mode, the condition string |
| | | 18 | | /// becomes a tool description for LLM-based routing. |
| | | 19 | | /// </para> |
| | | 20 | | /// </remarks> |
| | | 21 | | /// <example> |
| | | 22 | | /// <code> |
| | | 23 | | /// [NeedlrAiAgent(Instructions = "Analyze the request.")] |
| | | 24 | | /// [AgentGraphEntry("Research")] |
| | | 25 | | /// [AgentGraphEdge("Research", typeof(WebAgent), Condition = "NeedsWebData")] |
| | | 26 | | /// [AgentGraphEdge("Research", typeof(SummaryAgent))] |
| | | 27 | | /// public class AnalyzerAgent { } |
| | | 28 | | /// </code> |
| | | 29 | | /// </example> |
| | | 30 | | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] |
| | | 31 | | public sealed class AgentGraphEdgeAttribute : Attribute |
| | | 32 | | { |
| | | 33 | | /// <summary> |
| | | 34 | | /// Initializes a new <see cref="AgentGraphEdgeAttribute"/>. |
| | | 35 | | /// </summary> |
| | | 36 | | /// <param name="graphName">The name of the graph this edge belongs to.</param> |
| | | 37 | | /// <param name="targetAgentType">The downstream agent type.</param> |
| | 61836 | 38 | | public AgentGraphEdgeAttribute(string graphName, Type targetAgentType) |
| | | 39 | | { |
| | 61836 | 40 | | ArgumentException.ThrowIfNullOrWhiteSpace(graphName); |
| | 61835 | 41 | | ArgumentNullException.ThrowIfNull(targetAgentType); |
| | 61834 | 42 | | GraphName = graphName; |
| | 61834 | 43 | | TargetAgentType = targetAgentType; |
| | 61834 | 44 | | } |
| | | 45 | | |
| | | 46 | | /// <summary>Gets the graph name this edge belongs to.</summary> |
| | 4321 | 47 | | public string GraphName { get; } |
| | | 48 | | |
| | | 49 | | /// <summary>Gets the downstream agent type.</summary> |
| | 258 | 50 | | public Type TargetAgentType { get; } |
| | | 51 | | |
| | | 52 | | /// <summary> |
| | | 53 | | /// Gets or sets the optional routing condition. Interpretation depends on |
| | | 54 | | /// the graph's <see cref="GraphRoutingMode"/>. When <see langword="null"/>, |
| | | 55 | | /// the edge is unconditional. |
| | | 56 | | /// </summary> |
| | 14584 | 57 | | public string? Condition { get; set; } |
| | | 58 | | |
| | | 59 | | /// <summary> |
| | | 60 | | /// Gets or sets whether this edge's target is required for graph success. |
| | | 61 | | /// When <see langword="true"/> (default), a failure in the target node |
| | | 62 | | /// fails the entire graph. When <see langword="false"/>, the branch is |
| | | 63 | | /// marked degraded but parallel branches continue. |
| | | 64 | | /// </summary> |
| | 69550 | 65 | | public bool IsRequired { get; set; } = true; |
| | | 66 | | |
| | | 67 | | /// <summary> |
| | | 68 | | /// Gets or sets a per-node routing mode override for the source node of this |
| | | 69 | | /// edge. When set on any edge from a given source node, this overrides the |
| | | 70 | | /// graph-wide <see cref="AgentGraphEntryAttribute.RoutingMode"/> for that |
| | | 71 | | /// node's outgoing edges. Only needs to be set on one edge per source node |
| | | 72 | | /// (the generator reads the first non-null value). |
| | | 73 | | /// Use <see cref="HasNodeRoutingMode"/> to check if a value was explicitly set. |
| | | 74 | | /// </summary> |
| | | 75 | | public GraphRoutingMode NodeRoutingMode |
| | | 76 | | { |
| | 2 | 77 | | get => _nodeRoutingMode; |
| | | 78 | | set |
| | | 79 | | { |
| | 688 | 80 | | _nodeRoutingMode = value; |
| | 688 | 81 | | HasNodeRoutingMode = true; |
| | 688 | 82 | | } |
| | | 83 | | } |
| | | 84 | | |
| | | 85 | | /// <summary> |
| | | 86 | | /// Gets whether <see cref="NodeRoutingMode"/> was explicitly set on this edge. |
| | | 87 | | /// When <see langword="false"/>, the graph-wide routing mode is used. |
| | | 88 | | /// </summary> |
| | 845 | 89 | | public bool HasNodeRoutingMode { get; private set; } |
| | | 90 | | |
| | | 91 | | private GraphRoutingMode _nodeRoutingMode; |
| | | 92 | | } |