| | | 1 | | // Copyright (c) NexusLabs. All rights reserved. |
| | | 2 | | // Licensed under the MIT License. |
| | | 3 | | |
| | | 4 | | using System.Collections.Immutable; |
| | | 5 | | using System.Threading; |
| | | 6 | | |
| | | 7 | | using Microsoft.CodeAnalysis; |
| | | 8 | | |
| | | 9 | | namespace NexusLabs.Needlr.AgentFramework.Generators; |
| | | 10 | | |
| | | 11 | | internal static class GraphDiscoveryHelper |
| | | 12 | | { |
| | | 13 | | public static ImmutableArray<GraphEdgeEntry> GetGraphEdgeEntries( |
| | | 14 | | GeneratorAttributeSyntaxContext context, |
| | | 15 | | CancellationToken cancellationToken) |
| | | 16 | | { |
| | 19 | 17 | | var typeSymbol = context.TargetSymbol as INamedTypeSymbol; |
| | 19 | 18 | | if (typeSymbol is null || !AgentDiscoveryHelper.IsAccessibleFromGeneratedCode(typeSymbol)) |
| | 0 | 19 | | return ImmutableArray<GraphEdgeEntry>.Empty; |
| | | 20 | | |
| | 19 | 21 | | var sourceTypeName = AgentDiscoveryHelper.GetFullyQualifiedName(typeSymbol); |
| | 19 | 22 | | var entries = ImmutableArray.CreateBuilder<GraphEdgeEntry>(); |
| | | 23 | | |
| | 84 | 24 | | foreach (var attr in context.Attributes) |
| | | 25 | | { |
| | 23 | 26 | | if (attr.ConstructorArguments.Length < 2) |
| | | 27 | | continue; |
| | | 28 | | |
| | 23 | 29 | | var graphName = attr.ConstructorArguments[0].Value as string; |
| | 23 | 30 | | if (string.IsNullOrWhiteSpace(graphName)) |
| | | 31 | | continue; |
| | | 32 | | |
| | 23 | 33 | | var typeArg = attr.ConstructorArguments[1]; |
| | 23 | 34 | | if (typeArg.Kind != TypedConstantKind.Type || typeArg.Value is not INamedTypeSymbol targetTypeSymbol) |
| | | 35 | | continue; |
| | | 36 | | |
| | 23 | 37 | | var targetTypeName = AgentDiscoveryHelper.GetFullyQualifiedName(targetTypeSymbol); |
| | | 38 | | |
| | 23 | 39 | | string? condition = null; |
| | 23 | 40 | | var isRequired = true; |
| | 23 | 41 | | int? nodeRoutingMode = null; |
| | | 42 | | |
| | 64 | 43 | | foreach (var named in attr.NamedArguments) |
| | | 44 | | { |
| | 9 | 45 | | if (named.Key == "Condition" && named.Value.Value is string conditionValue) |
| | | 46 | | { |
| | 6 | 47 | | condition = conditionValue; |
| | | 48 | | } |
| | 3 | 49 | | else if (named.Key == "IsRequired" && named.Value.Value is bool isReqValue) |
| | | 50 | | { |
| | 2 | 51 | | isRequired = isReqValue; |
| | | 52 | | } |
| | 1 | 53 | | else if (named.Key == "NodeRoutingMode" && named.Value.Value is int routeVal) |
| | | 54 | | { |
| | | 55 | | // Presence in NamedArguments means the user explicitly set it, |
| | | 56 | | // equivalent to HasNodeRoutingMode = true at runtime. |
| | 1 | 57 | | nodeRoutingMode = routeVal; |
| | | 58 | | } |
| | | 59 | | } |
| | | 60 | | |
| | 23 | 61 | | entries.Add(new GraphEdgeEntry( |
| | 23 | 62 | | sourceTypeName, |
| | 23 | 63 | | typeSymbol.Name, |
| | 23 | 64 | | graphName!, |
| | 23 | 65 | | targetTypeName, |
| | 23 | 66 | | condition, |
| | 23 | 67 | | isRequired, |
| | 23 | 68 | | nodeRoutingMode)); |
| | | 69 | | } |
| | | 70 | | |
| | 19 | 71 | | return entries.ToImmutable(); |
| | | 72 | | } |
| | | 73 | | |
| | | 74 | | public static ImmutableArray<GraphEntryPointEntry> GetGraphEntryPointEntries( |
| | | 75 | | GeneratorAttributeSyntaxContext context, |
| | | 76 | | CancellationToken cancellationToken) |
| | | 77 | | { |
| | 21 | 78 | | var typeSymbol = context.TargetSymbol as INamedTypeSymbol; |
| | 21 | 79 | | if (typeSymbol is null || !AgentDiscoveryHelper.IsAccessibleFromGeneratedCode(typeSymbol)) |
| | 0 | 80 | | return ImmutableArray<GraphEntryPointEntry>.Empty; |
| | | 81 | | |
| | 21 | 82 | | var agentTypeName = AgentDiscoveryHelper.GetFullyQualifiedName(typeSymbol); |
| | 21 | 83 | | var entries = ImmutableArray.CreateBuilder<GraphEntryPointEntry>(); |
| | | 84 | | |
| | 84 | 85 | | foreach (var attr in context.Attributes) |
| | | 86 | | { |
| | 21 | 87 | | if (attr.ConstructorArguments.Length < 1) |
| | | 88 | | continue; |
| | | 89 | | |
| | 21 | 90 | | var graphName = attr.ConstructorArguments[0].Value as string; |
| | 21 | 91 | | if (string.IsNullOrWhiteSpace(graphName)) |
| | | 92 | | continue; |
| | | 93 | | |
| | 21 | 94 | | var routingMode = 0; |
| | | 95 | | |
| | 42 | 96 | | foreach (var named in attr.NamedArguments) |
| | | 97 | | { |
| | 0 | 98 | | if (named.Key == "RoutingMode" && named.Value.Value is int routeVal) |
| | | 99 | | { |
| | 0 | 100 | | routingMode = routeVal; |
| | | 101 | | } |
| | | 102 | | } |
| | | 103 | | |
| | 21 | 104 | | entries.Add(new GraphEntryPointEntry( |
| | 21 | 105 | | agentTypeName, |
| | 21 | 106 | | typeSymbol.Name, |
| | 21 | 107 | | graphName!, |
| | 21 | 108 | | routingMode)); |
| | | 109 | | } |
| | | 110 | | |
| | 21 | 111 | | return entries.ToImmutable(); |
| | | 112 | | } |
| | | 113 | | |
| | | 114 | | public static ImmutableArray<GraphNodeEntry> GetGraphNodeEntries( |
| | | 115 | | GeneratorAttributeSyntaxContext context, |
| | | 116 | | CancellationToken cancellationToken) |
| | | 117 | | { |
| | 2 | 118 | | var typeSymbol = context.TargetSymbol as INamedTypeSymbol; |
| | 2 | 119 | | if (typeSymbol is null || !AgentDiscoveryHelper.IsAccessibleFromGeneratedCode(typeSymbol)) |
| | 0 | 120 | | return ImmutableArray<GraphNodeEntry>.Empty; |
| | | 121 | | |
| | 2 | 122 | | var agentTypeName = AgentDiscoveryHelper.GetFullyQualifiedName(typeSymbol); |
| | 2 | 123 | | var entries = ImmutableArray.CreateBuilder<GraphNodeEntry>(); |
| | | 124 | | |
| | 8 | 125 | | foreach (var attr in context.Attributes) |
| | | 126 | | { |
| | 2 | 127 | | if (attr.ConstructorArguments.Length < 1) |
| | | 128 | | continue; |
| | | 129 | | |
| | 2 | 130 | | var graphName = attr.ConstructorArguments[0].Value as string; |
| | 2 | 131 | | if (string.IsNullOrWhiteSpace(graphName)) |
| | | 132 | | continue; |
| | | 133 | | |
| | 2 | 134 | | var joinMode = 0; |
| | | 135 | | |
| | 8 | 136 | | foreach (var named in attr.NamedArguments) |
| | | 137 | | { |
| | 2 | 138 | | if (named.Key == "JoinMode" && named.Value.Value is int joinVal) |
| | | 139 | | { |
| | 2 | 140 | | joinMode = joinVal; |
| | | 141 | | } |
| | | 142 | | } |
| | | 143 | | |
| | 2 | 144 | | entries.Add(new GraphNodeEntry( |
| | 2 | 145 | | agentTypeName, |
| | 2 | 146 | | typeSymbol.Name, |
| | 2 | 147 | | graphName!, |
| | 2 | 148 | | joinMode)); |
| | | 149 | | } |
| | | 150 | | |
| | 2 | 151 | | return entries.ToImmutable(); |
| | | 152 | | } |
| | | 153 | | |
| | | 154 | | public static ImmutableArray<GraphReducerEntry> GetGraphReducerEntries( |
| | | 155 | | GeneratorAttributeSyntaxContext context, |
| | | 156 | | CancellationToken cancellationToken) |
| | | 157 | | { |
| | 3 | 158 | | var typeSymbol = context.TargetSymbol as INamedTypeSymbol; |
| | 3 | 159 | | if (typeSymbol is null || !AgentDiscoveryHelper.IsAccessibleFromGeneratedCode(typeSymbol)) |
| | 0 | 160 | | return ImmutableArray<GraphReducerEntry>.Empty; |
| | | 161 | | |
| | 3 | 162 | | var agentTypeName = AgentDiscoveryHelper.GetFullyQualifiedName(typeSymbol); |
| | 3 | 163 | | var entries = ImmutableArray.CreateBuilder<GraphReducerEntry>(); |
| | | 164 | | |
| | 12 | 165 | | foreach (var attr in context.Attributes) |
| | | 166 | | { |
| | 3 | 167 | | if (attr.ConstructorArguments.Length < 1) |
| | | 168 | | continue; |
| | | 169 | | |
| | 3 | 170 | | var graphName = attr.ConstructorArguments[0].Value as string; |
| | 3 | 171 | | if (string.IsNullOrWhiteSpace(graphName)) |
| | | 172 | | continue; |
| | | 173 | | |
| | 3 | 174 | | string reducerMethod = "Reduce"; |
| | | 175 | | |
| | 10 | 176 | | foreach (var named in attr.NamedArguments) |
| | | 177 | | { |
| | 2 | 178 | | if (named.Key == "ReducerMethod" && named.Value.Value is string methodVal |
| | 2 | 179 | | && !string.IsNullOrWhiteSpace(methodVal)) |
| | | 180 | | { |
| | 2 | 181 | | reducerMethod = methodVal; |
| | | 182 | | } |
| | | 183 | | } |
| | | 184 | | |
| | 3 | 185 | | entries.Add(new GraphReducerEntry( |
| | 3 | 186 | | agentTypeName, |
| | 3 | 187 | | typeSymbol.Name, |
| | 3 | 188 | | graphName!, |
| | 3 | 189 | | reducerMethod)); |
| | | 190 | | } |
| | | 191 | | |
| | 3 | 192 | | return entries.ToImmutable(); |
| | | 193 | | } |
| | | 194 | | } |