diff --git a/src/AgentOs.Modules.Pipeline/Agents/AgentsOptions.cs b/src/AgentOs.Modules.Pipeline/Agents/AgentsOptions.cs index bbd977f..fb810b1 100644 --- a/src/AgentOs.Modules.Pipeline/Agents/AgentsOptions.cs +++ b/src/AgentOs.Modules.Pipeline/Agents/AgentsOptions.cs @@ -84,13 +84,7 @@ public bool IsValid() => AgentRoles.All.All(r => For(r.Key) is { } a && a.MaxTokens > 0); /// Every configured agent, for cross-cutting checks (startup validation). - public IEnumerable All() - { - foreach (var role in AgentRoles.All) - { - if (For(role.Key) is { } options) { yield return options; } - } - } + public IEnumerable All() => AgentRoles.All.Select(role => For(role.Key)).OfType(); } /// Configuration for a single agent. diff --git a/src/AgentOs.Modules.Pipeline/Agents/TicketFlowDefinition.cs b/src/AgentOs.Modules.Pipeline/Agents/TicketFlowDefinition.cs index 5e9c4e4..a45bdfd 100644 --- a/src/AgentOs.Modules.Pipeline/Agents/TicketFlowDefinition.cs +++ b/src/AgentOs.Modules.Pipeline/Agents/TicketFlowDefinition.cs @@ -363,13 +363,9 @@ public static IReadOnlyList Validate(TicketFlowDefinition? de } // Edges: known steps; pass = one next step each (none after Merge, none into Code); fail = back to Code only. - foreach (var e in definition.Edges) - { - if (!byId.ContainsKey(e.From) || !byId.ContainsKey(e.To)) - { - problems.Add(new(null, $"An edge points at a step that doesn't exist ({e.From} → {e.To}).")); - } - } + problems.AddRange(definition.Edges + .Where(e => !byId.ContainsKey(e.From) || !byId.ContainsKey(e.To)) + .Select(e => new TicketFlowProblem(null, $"An edge points at a step that doesn't exist ({e.From} → {e.To})."))); var edges = definition.Edges.Where(e => byId.ContainsKey(e.From) && byId.ContainsKey(e.To)).ToList(); var pass = edges.Where(e => e.When == TicketFlowEdgeWhen.Pass).ToList(); var fail = edges.Where(e => e.When == TicketFlowEdgeWhen.Fail).ToList(); diff --git a/src/AgentOs.Web/Components/Pages/AgentProfilesApp.razor b/src/AgentOs.Web/Components/Pages/AgentProfilesApp.razor index afa7d62..905f227 100644 --- a/src/AgentOs.Web/Components/Pages/AgentProfilesApp.razor +++ b/src/AgentOs.Web/Components/Pages/AgentProfilesApp.razor @@ -231,11 +231,10 @@ else { foreach (var field in RoleFields.Where(f => byKey.GetValueOrDefault(AgentSettings.Key(role, f))?.Source is null or SettingSource.Default)) { - if (await Legacy.ReadAsync(role, field, _tenantId) is { } old) - { - row.Loaded[field] = old; - row.Legacy = true; - } + var old = await Legacy.ReadAsync(role, field, _tenantId); + if (old is null) { continue; } + row.Loaded[field] = old; + row.Legacy = true; } } row.Provider = row.Loaded.GetValueOrDefault(ProviderField, string.Empty); diff --git a/src/AgentOs.Web/Services/BoardTasks/BoardTaskService.cs b/src/AgentOs.Web/Services/BoardTasks/BoardTaskService.cs index 322a62b..bd35822 100644 --- a/src/AgentOs.Web/Services/BoardTasks/BoardTaskService.cs +++ b/src/AgentOs.Web/Services/BoardTasks/BoardTaskService.cs @@ -552,7 +552,7 @@ await sessRepo.UpdateRepoRunResultAsync(tenantId, outcome.SessionRepoId, "Failed // It used to mark the repo Failed and drop the pull request link: Autopilot lost track of the open PR // and started the ticket over on a new branch (VNChess #95 / PR #97, 2026-10-24). var stood = children.FirstOrDefault(c => c.Id == outcome.SessionRepoId); - if (FailedFollowUpKeepsItsChange(change is not null, stood?.Status, stood?.PrUrl) && stood is not null) + if (stood is not null && FailedFollowUpKeepsItsChange(change is not null, stood.Status, stood.PrUrl)) { await sessRepo.UpdateRepoRunResultAsync(tenantId, stood.Id, stood.Status, stood.BranchName, stood.PrUrl, "The last fix attempt failed: " + (outcome.Error ?? "Agent failed.")).ConfigureAwait(false); diff --git a/tests/AgentOs.E2E.Tests/AgentOsUi/TicketFlowTests.cs b/tests/AgentOs.E2E.Tests/AgentOsUi/TicketFlowTests.cs index eb7a593..b362cd0 100644 --- a/tests/AgentOs.E2E.Tests/AgentOsUi/TicketFlowTests.cs +++ b/tests/AgentOs.E2E.Tests/AgentOsUi/TicketFlowTests.cs @@ -63,11 +63,10 @@ private static async Task EnsureDefaultAsync(ILocator win) var changed = false; foreach (var step in new[] { "review", "test" }) { - if (await Card(win, step).GetAttributeAsync("class") is { } css && css.Contains("run-skipped", StringComparison.Ordinal)) - { - await SetRunsAsync(win, step, on: true); - changed = true; - } + var css = await Card(win, step).GetAttributeAsync("class"); + if (css is null || !css.Contains("run-skipped", StringComparison.Ordinal)) { continue; } + await SetRunsAsync(win, step, on: true); + changed = true; } if (changed) { diff --git a/tests/AgentOs.Tests/Agents/AgentRegistryGuardTests.cs b/tests/AgentOs.Tests/Agents/AgentRegistryGuardTests.cs index 69cc0e9..16a4d8f 100644 --- a/tests/AgentOs.Tests/Agents/AgentRegistryGuardTests.cs +++ b/tests/AgentOs.Tests/Agents/AgentRegistryGuardTests.cs @@ -75,15 +75,14 @@ BinaryExpressionSyntax b when b.IsKind(SyntaxKind.AddExpression) => HardCoded(b. _ => false, }; - foreach (var call in root.DescendantNodes().OfType()) + foreach (var (call, provider) in root.DescendantNodes().OfType() + .Where(c => c.Expression is MemberAccessExpressionSyntax { Name.Identifier.ValueText: "Create" }) + .Select(c => (Call: c, Provider: c.ArgumentList.Arguments.FirstOrDefault())) + .Where(x => x.Provider is { } p + && p.NameColon is null or { Name.Identifier.ValueText: "providerName" } + && HardCoded(p.Expression))) { - if (call.Expression is MemberAccessExpressionSyntax { Name.Identifier.ValueText: "Create" } - && call.ArgumentList.Arguments is [var provider, ..] - && provider.NameColon is null or { Name.Identifier.ValueText: "providerName" } - && HardCoded(provider.Expression)) - { - yield return $"line {Line(call)}: ILlmClientFactory.Create({provider.Expression})"; - } + yield return $"line {Line(call)}: ILlmClientFactory.Create({provider!.Expression})"; } foreach (var creation in root.DescendantNodes().OfType()) diff --git a/tests/AgentOs.Tests/Web/TicketFlowDefinitionTests.cs b/tests/AgentOs.Tests/Web/TicketFlowDefinitionTests.cs index 57ddcec..9409ad9 100644 --- a/tests/AgentOs.Tests/Web/TicketFlowDefinitionTests.cs +++ b/tests/AgentOs.Tests/Web/TicketFlowDefinitionTests.cs @@ -229,9 +229,8 @@ public void Plan_WithoutAGate_IsUnsafe() [Fact] public void EveryStepKind_IsRegistered_WithRolesFromTheAgentRegistry() { - foreach (var kind in System.Enum.GetValues()) + foreach (var info in System.Enum.GetValues().Select(TicketStepKinds.Of)) { - var info = TicketStepKinds.Of(kind); info.Roles.ShouldAllBe(r => AgentRoles.Find(r) != null); } TicketStepKinds.Of(TicketStepKind.Code).DefaultRole.ShouldBe(AgentRoles.IssueWork);