Skip to content
Merged

Dev #2422

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
bc5b766
Upgrade to .NET 10 + ABP 10.3 + Mapperly migration
AndreGAot Apr 28, 2026
473d06c
Merge remote-tracking branch 'origin/dev' into upgrade-to-NET10
AndreGAot Apr 28, 2026
e6c8f71
Merge remote-tracking branch 'origin/dev' into upgrade-to-NET10
AndreGAot Apr 28, 2026
b033e1c
More .NET10 upgrade
AndreGAot Apr 29, 2026
c456495
Merge origin/dev into feature/AB#32683-net10-upgrade
AndreGAot Apr 30, 2026
7b37191
Clean up build warnings: 869 RMG020 + 156 NU1510 -> 0
AndreGAot Apr 30, 2026
e75e1a5
AB#32683 warnings and error fixes
AndreGAot May 1, 2026
7a49c1f
Merge remote-tracking branch 'origin/dev' into feature/AB#32683-net10…
AndreGAot May 1, 2026
809904d
AB#32683 fix issue with identity roles
AndreGAot May 1, 2026
f0c2658
AB#32683 address copilot feedback
AndreGAot May 1, 2026
3873546
AB#32683 js fixes
AndreGAot May 2, 2026
0ccbc87
AB#32683 more mapperly warning
AndreGAot May 4, 2026
0fe229c
AB#32683 update docker cli in dockerimage
AndreGAot May 4, 2026
e2aa494
AB#32683 fix warning and document updates
AndreGAot May 4, 2026
9012d68
AB#32683 add explicit update to account coding for mapper
AndreGAot May 4, 2026
73dce77
AB#32683 fixes to configurations section
AndreGAot May 4, 2026
631add4
AB#32683 comment out dev-certs
AndreGAot May 4, 2026
520ea20
AB#32683 fixes after merge
AndreGAot May 5, 2026
e8a23dd
AB#32683 add custom permission check and mapper updates
AndreGAot May 6, 2026
c1b950c
AB#32684: Register AmazonS3Client as singleton for reusability
aurelio-aot May 6, 2026
1accd3d
Merge remote-tracking branch 'origin/dev' into feature/AB#32683-net10…
AndreGAot May 6, 2026
1b7d26f
Merge remote-tracking branch 'origin/dev' into feature/AB#32683-net10…
AndreGAot May 6, 2026
bb7c7f6
AB#32452 remove prompt tools panel
jacobwillsmith May 7, 2026
e97cbc5
AB#32452 fix scoring queue proxy
jacobwillsmith May 7, 2026
b1051ad
Merge pull request #2410 from bcgov/feature/AB#32683-net10-upgrade
JamesPasta May 7, 2026
8af8b95
Merge pull request #2413 from bcgov/feature/AB#32452-delete-prompt-to…
JamesPasta May 7, 2026
e5f2a8b
Merge branch 'dev' into bugfix/AB#32684-Refactor-AmazonS3Client-Usage
aurelio-aot May 7, 2026
2e39540
AB#32451 fix queued scoring authorization
jacobwillsmith May 6, 2026
8d6b84e
AB#32451 restore chefs attachment selection behavior
jacobwillsmith May 7, 2026
e39a301
AB#32451 simplify chefs summary toggle
jacobwillsmith May 7, 2026
ec9b4ea
AB#32684: Fix sonarqube issues
aurelio-aot May 7, 2026
6185b87
Merge pull request #2406 from bcgov/bugfix/AB#32684-Refactor-AmazonS3…
aurelio-aot May 7, 2026
7724076
AB#32310 Support configurable AI execution modes for multi-step flows
jacobwillsmith Apr 30, 2026
971d83c
AB#32310 clarify AI execution modes
jacobwillsmith May 6, 2026
ec69f88
AB#32310 simplify scoring answer copy
jacobwillsmith May 6, 2026
662eea1
AB#32310 default AI execution to sequential
jacobwillsmith May 6, 2026
eaac541
AB#32310 keep attachment summaries sequential
jacobwillsmith May 7, 2026
7a95f7e
Merge pull request #2415 from bcgov/feature/AB#32310-support-ai-execu…
JamesPasta May 7, 2026
022cda6
Merge pull request #2414 from bcgov/feature/AB#32451-ai-generation-po…
JamesPasta May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

## Project Summary

Unity is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 9.1.3** with **.NET 9.0**, targeting **PostgreSQL 17**. The primary application code lives in `applications/Unity.GrantManager/`.
Unity is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 10.3** with **.NET 10.0**, targeting **PostgreSQL 17**. The primary application code lives in `applications/Unity.GrantManager/`.

**Key stack:** .NET 9 · ABP 9.1.3 · EF Core 9.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · AutoMapper · Cypress (E2E)
**Key stack:** .NET 10 · ABP 10.3 · EF Core 10.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · Mapperly · Cypress (E2E)

## Repository Structure

Expand All @@ -21,7 +21,7 @@ documentation/ ← Technical docs
## Key Conventions

- **ABP Framework** modular monolith with DDD layered architecture
- **AutoMapper** for DTO mapping (not Mapperly)
- **Mapperly** for DTO mapping (not AutoMapper)
- **Razor Pages** UI with custom ABP theme (Unity.Theme.UX2)
- Multi-tenant architecture with separate host/tenant database contexts
- `dev` → `test` → `main` branch promotion flow
Expand All @@ -39,6 +39,6 @@ All PRs must pass `dotnet build` and `dotnet test` before merge. The CI runs all

## Do NOT

- Use Mapperly patterns — this project uses AutoMapper
- Use AutoMapper patterns — this project uses Mapperly
- Create repositories for child entities — only aggregate roots get repositories
- Put business logic in application services — use domain entities/services
2 changes: 1 addition & 1 deletion applications/Unity.GrantManager/.github/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ Pick the agent that matches your workflow stage and provide:
2. Target module(s) and files.
3. Constraints (tenant scope, security, deadline, non-functional requirements).

Each agent enforces ABP layering, AutoMapper usage, localization, and test conventions from repository instructions and skills.
Each agent enforces ABP layering, Mapperly usage, localization, and test conventions from repository instructions and skills.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: application-service-designer
description: Designs application contracts, DTOs, authorization, and AutoMapper mapping plans.
description: Designs application contracts, DTOs, authorization, and Mapperly mapping plans.
---

# ABP Application Service Designer Agent
Expand All @@ -22,7 +22,7 @@ Produce ABP-compliant service contracts and implementation plans using DTO-first
1. Propose or update `I*AppService` method signatures.
2. Define DTOs per method intent (create, update, get, list).
3. Identify authorization requirements and permission constants.
4. Define AutoMapper profile changes.
4. Define Mapperly mapper changes.
5. Define validation and business-exception boundaries.

## Output Format
Expand All @@ -40,4 +40,4 @@ Produce ABP-compliant service contracts and implementation plans using DTO-first
- Follow `.github/instructions/csharp.instructions.md`.
- Methods must be async and end with `Async`.
- Accept/return DTOs only, never entities.
- Use AutoMapper with `ObjectMapper.Map<>()`, never Mapperly.
- Use Mapperly with `ObjectMapper.Map<>()`, never AutoMapper. Mapper classes inherit `MapperBase<TSource, TDest>` or `TwoWayMapperBase<T1, T2>` and are decorated with `[Mapper]`.
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,5 @@ Rules:

- Enforce module dependency direction from `.github/skills/unity-module-structure/SKILL.md`.
- Enforce ABP app/domain rules from `.github/instructions/csharp.instructions.md`.
- Do not use Mapperly. Use AutoMapper.
- Do not use AutoMapper. Use Mapperly (`[Mapper]` attribute, `MapperBase<TSource, TDest>`).
- Do not place business rules in controllers or app services.
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ Evaluate if a branch is ready for PR against ABP architecture, policy, and CI ex
- Follow `.github/copilot-instructions.md`.
- Require `dotnet build Unity.GrantManager.sln --no-restore` and `dotnet test Unity.GrantManager.sln --no-build` readiness.
- Enforce ABP module layering rules from `.github/skills/unity-module-structure/SKILL.md`.
- Enforce AutoMapper, localization, and permissions conventions.
- Enforce Mapperly, localization, and permissions conventions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ For each changed file in the PR:

### Step 3: ABP Architecture
- Layer boundaries (Domain → Application → Web)
- Repository/DTO/AutoMapper conventions
- Repository/DTO/Mapperly conventions
- Permissions and localization keys
- EF migrations (if schema changes)

Expand Down Expand Up @@ -131,7 +131,7 @@ When invoked:
- ✅ Build/tests pass (backend unit tests)
-**Cypress E2E tests pass** (frontend integration tests)
- ✅ ABP conventions followed
-AutoMapper/localization/permissions configured
-Mapperly/localization/permissions configured

## Tool Usage

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ formatter.format(amount); // Returns formatted currency string
3. Create migration
4. Create DTOs in `*.Application.Contracts`
5. Create application service in `*.Application`
6. Add AutoMapper mappings
6. Add Mapperly mappings
7. Define permissions
8. Create MVC controller and views

Expand Down
14 changes: 7 additions & 7 deletions applications/Unity.GrantManager/.github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

## Project Overview

Unity Grant Manager is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 9.1.3** with **.NET 9.0**, targeting **PostgreSQL 17**. The UI uses **Razor Pages** with a custom ABP theme (Unity.Theme.UX2). The architecture follows ABP's **Domain-Driven Design (DDD)** layered module pattern.
Unity Grant Manager is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 10.3** with **.NET 10.0**, targeting **PostgreSQL 17**. The UI uses **Razor Pages** with a custom ABP theme (Unity.Theme.UX2). The architecture follows ABP's **Domain-Driven Design (DDD)** layered module pattern.

**Key stack:** .NET 9 · ABP 9.1.3 · EF Core 9.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · AutoMapper · Cypress (E2E)
**Key stack:** .NET 10 · ABP 10.3 · EF Core 10.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · Mapperly · Cypress (E2E)

## Repository Layout

Expand All @@ -20,7 +20,7 @@ NuGet.Config ← NuGet package sources
docker-compose.yml ← Docker dev environment
src/
Unity.GrantManager.Web/ ← Razor Pages web app (entry point)
Unity.GrantManager.Application/ ← App services, AutoMapper profiles
Unity.GrantManager.Application/ ← App services, Mapperly mappers
Unity.GrantManager.Application.Contracts/ ← DTOs, interfaces
Unity.GrantManager.Domain/ ← Entities, repositories, domain services
Unity.GrantManager.Domain.Shared/ ← Enums, constants, localization (en.json)
Expand Down Expand Up @@ -93,7 +93,7 @@ Every PR triggers branch-specific GitHub Actions workflows (in the repo root `.g

1. **Validate source branch** — PRs to `dev` must come from `feature/*`, `hotfix/*`, `bugfix/*`, `test`, or `main`. PRs to `main` must come from `test` or `hotfix/*` only.
2. **Discover test projects** — Finds all `*Tests.csproj` files automatically.
3. **Run tests in parallel matrix** — Each test project runs independently with `dotnet test` using .NET 9.0.x.
3. **Run tests in parallel matrix** — Each test project runs independently with `dotnet test` using .NET 10.0.x.
4. **Aggregate results** — Posts pass/fail badge as PR comment.

Always ensure `dotnet build` and `dotnet test` pass before submitting changes.
Expand Down Expand Up @@ -135,8 +135,8 @@ Preferred code-usage boundaries (guidance for new code):
- All methods `async`, end with `Async`.
- Accept/return **DTOs only**, never entities. Define DTOs in `*.Application.Contracts`.
- Make all public methods `virtual` for extensibility.
- This project uses **AutoMapper** (not Mapperly). Mapping profiles are `*AutoMapperProfile.cs` inheriting `Profile`.
- `ObjectMapper.Map<>()` is used for DTO mapping, not Mapperly partials.
- This project uses **Mapperly** (not AutoMapper). Mapper classes are `*MapperlyProfile.cs` decorated with `[Mapper]` and inheriting `MapperBase<TSource, TDest>` or `TwoWayMapperBase<T1, T2>`.
- `ObjectMapper.Map<>()` is used for DTO mapping at call sites; Mapperly generates the implementation via source generation.

### EF Core

Expand Down Expand Up @@ -178,7 +178,7 @@ Use the ABP workflow agents in `.github/agents/` to accelerate planning, develop

- `feature-planner`: Convert a feature request or bug into a layered ABP implementation plan.
- `ddd-modeler`: Design or review aggregates, invariants, repositories, and domain managers.
- `application-service-designer`: Define app service contracts, DTOs, authorization, and AutoMapper changes.
- `application-service-designer`: Define app service contracts, DTOs, authorization, and Mapperly mapper changes.
- `efcore-migration-planner`: Plan host vs tenant EF Core model updates and migration steps safely.
- `permissions-localization-auditor`: Audit diffs for permission coverage, localization keys, and hardcoded text.
- `test-strategy`: Build risk-based unit/integration test plans for ABP features.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ These properties are pre-injected in `ApplicationService`, `DomainService`, and
| `CurrentUser` | Access authenticated user (Id, Name, Email, Roles) |
| `CurrentTenant` | Access current tenant context (Id, Name) |
| `L` / `L["Key"]` | Localization shortcut |
| `ObjectMapper` | AutoMapper-based mapping |
| `ObjectMapper` | Mapperly-based mapping |
| `Logger` | Structured logging via `ILogger<T>` |
| `AuthorizationService` | Programmatic authorization checks |
| `UnitOfWorkManager` | Manual unit-of-work control |
Expand Down Expand Up @@ -57,8 +57,8 @@ These properties are pre-injected in `ApplicationService`, `DomainService`, and
- All methods `async`, name ends with `Async`.
- Accept/return DTOs only, never entities. Define DTOs in `*.Application.Contracts`.
- Make all public methods `virtual`.
- Use **AutoMapper** (`ObjectMapper.Map<>()`) for DTO mapping. Do NOT use Mapperly.
- Mapping profiles: `*AutoMapperProfile.cs` inheriting `Profile`.
- Use **Mapperly** (`ObjectMapper.Map<>()`) for DTO mapping. Do NOT use AutoMapper.
- Mapper classes: `*MapperlyProfile.cs` decorated with `[Mapper]`, inheriting `MapperBase<TSource, TDest>` or `TwoWayMapperBase<T1, T2>`.

## Code Style

Expand All @@ -85,8 +85,8 @@ These properties are pre-injected in `ApplicationService`, `DomainService`, and
## DTOs vs Entities

- Application services MUST accept and return DTOs only, never entities
- Use `ObjectMapper` (AutoMapper) to map between entities and DTOs
- Define mapping profiles in `*AutoMapperProfile` class in Application project
- Use `ObjectMapper` (Mapperly) to map between entities and DTOs
- Define mappers in `*MapperlyProfile` class in Application project

## Authorization

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,35 @@ public interface IGrantAppService : IApplicationService
- Do NOT use web types (`IFormFile`, `Stream`) — accept `byte[]` from controllers.
- Do NOT call other app services in the same module. Use domain services or repositories.

## Object Mapping (AutoMapper)
## Object Mapping (Mapperly)

This project uses **AutoMapper** (not Mapperly). Mapping profiles are defined as:
This project uses **Mapperly** (not AutoMapper). Mapper classes are defined using `Riok.Mapperly.Abstractions` and `Volo.Abp.Mapperly`:

```csharp
public class GrantManagerApplicationAutoMapperProfile : Profile
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;

[Mapper]
public partial class GrantToGrantDtoMapper : MapperBase<Grant, GrantDto>
{
public override partial GrantDto Map(Grant source);
public override partial void Map(Grant source, GrantDto destination);
}

// For bidirectional mapping:
[Mapper]
public partial class ZoneGroupDefinitionMapper : TwoWayMapperBase<ZoneGroupDefinition, ZoneGroupDefinitionDto>
{
public GrantManagerApplicationAutoMapperProfile()
{
CreateMap<Grant, GrantDto>();
CreateMap<CreateGrantDto, Grant>();
}
public override partial ZoneGroupDefinitionDto Map(ZoneGroupDefinition source);
public override partial void Map(ZoneGroupDefinition source, ZoneGroupDefinitionDto destination);
public override partial ZoneGroupDefinition ReverseMap(ZoneGroupDefinitionDto source);
public override partial void ReverseMap(ZoneGroupDefinitionDto source, ZoneGroupDefinition destination);
}
```

- Profile files follow `*AutoMapperProfile.cs` naming.
- Each Application and Web project has its own profile.
- Use `ObjectMapper.Map<TSource, TDest>(source)` in app services.
- Mapper files follow `*MapperlyProfile.cs` naming; each Application and Web project has its own file.
- Use `[MapperIgnoreTarget(nameof(...))]` to skip properties, `[MapProperty]` to rename, and `[MapPropertyFromSource]` for custom resolver methods.
- Call sites still use `ObjectMapper.Map<TSource, TDest>(source)` — Mapperly provides the source-generated implementation.

## Error Handling

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Unity.{ModuleName}/
Unity.{ModuleName}.Domain.Shared/ ← Enums, constants, localization, ETOs
Unity.{ModuleName}.Domain/ ← Entities, repository interfaces, domain services
Unity.{ModuleName}.Application.Contracts/ ← DTOs, app service interfaces
Unity.{ModuleName}.Application/ ← App service implementations, AutoMapper profiles
Unity.{ModuleName}.Application/ ← App service implementations, Mapperly mappers
Unity.{ModuleName}.EntityFrameworkCore/ ← DbContext, migrations (if module has own DB tables)
Unity.{ModuleName}.HttpApi/ ← REST controllers
Unity.{ModuleName}.HttpApi.Client/ ← Remote client proxies
Expand Down
4 changes: 2 additions & 2 deletions applications/Unity.GrantManager/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

<PropertyGroup>
<!-- Suppress NU1701 warnings for Microsoft.Extensions.Compliance.Abstractions -->
<!-- This package works correctly with .NET 9.0 despite targeting older frameworks -->
<!-- This package works correctly with .NET 10.0 despite targeting older frameworks -->
<!-- Suppress MSB3277 warnings for EntityFrameworkCore.Relational version conflicts -->
<!-- These conflicts don't cause runtime issues in this solution -->
<NoWarn>$(NoWarn);NU1701;MSB3277</NoWarn>
</PropertyGroup>

<ItemGroup>
<!-- Explicitly reference compatible version to avoid transitive dependency warnings -->
<PackageReference Include="Microsoft.Extensions.Compliance.Abstractions" Version="9.5.0" />
<PackageReference Include="Microsoft.Extensions.Compliance.Abstractions" Version="10.1.0" />

</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>Unity.AI</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="9.0.5" />
<PackageReference Include="Volo.Abp.Authorization" Version="9.1.3" />
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="9.1.3" />
<PackageReference Include="Volo.Abp.Features" Version="9.1.3" />
<PackageReference Include="Volo.Abp.SettingManagement.Application.Contracts" Version="9.1.3" />
<PackageReference Include="Volo.Abp.Authorization" Version="10.3.0" />
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="10.3.0" />
<PackageReference Include="Volo.Abp.Features" Version="10.3.0" />
<PackageReference Include="Volo.Abp.SettingManagement.Application.Contracts" Version="10.3.0" />
<ProjectReference Include="..\Unity.AI.Domain.Shared\Unity.AI.Shared.csproj" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Unity.AI.Operations;

/// <summary>
/// Execution strategy for multi-step AI flows that iterate over many work items
/// (e.g. multiple attachments, multiple scoresheet sections).
/// </summary>
public enum AIExecutionMode
{
/// <summary>One item at a time, in order. Default; preserves legacy behavior.</summary>
Sequential,

/// <summary>All items started concurrently and awaited together.</summary>
Parallel,

/// <summary>All items sent through one batch operation.</summary>
Batch
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.Extensions.Configuration;
using Unity.AI.Prompts;
using Volo.Abp.DependencyInjection;

namespace Unity.AI.Operations;

/// <summary>
/// Resolves the configured <see cref="AIExecutionMode"/> for an AI operation.
/// Configuration keys (all optional, default = Sequential):
/// Azure:Operations:{operationName}:ExecutionMode - "Sequential" | "Parallel" | "Batch" (case-insensitive)
/// Azure:Operations:Defaults:ExecutionMode - default when operation override is absent
/// </summary>
public class AIExecutionModeResolver(IConfiguration configuration) : ITransientDependency
{
public const string AttachmentSummaryOperation = AIPromptTypes.AttachmentSummary;
public const string ApplicationScoringOperation = AIPromptTypes.ApplicationScoring;

public AIExecutionMode ResolveMode(string operationName)
{
var configured = configuration[$"Azure:Operations:{operationName}:ExecutionMode"];
if (string.IsNullOrWhiteSpace(configured))
{
configured = configuration["Azure:Operations:Defaults:ExecutionMode"];
}

return configured?.Trim().ToLowerInvariant() switch
{
"parallel" => AIExecutionMode.Parallel,
"batch" => AIExecutionMode.Batch,
_ => AIExecutionMode.Sequential
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Unity.AI.Operations;

/// <summary>
/// Runs an async operation across a collection of items using a configurable execution mode.
/// Stateless and intentionally tiny: callers resolve mode and provide item/batch work.
/// </summary>
public static class AIExecutionStrategy
{
public static async Task<List<TResult>> RunAsync<T, TResult>(
IReadOnlyCollection<T> items,
AIExecutionMode mode,
Func<T, Task<TResult>> operation,
Func<IReadOnlyCollection<T>, Task<List<TResult>>> batchOperation)
{
ArgumentNullException.ThrowIfNull(items);
ArgumentNullException.ThrowIfNull(operation);
ArgumentNullException.ThrowIfNull(batchOperation);

if (items.Count == 0)
{
return [];
}

switch (mode)
{
case AIExecutionMode.Parallel:
return [.. await Task.WhenAll(items.Select(operation))];

case AIExecutionMode.Batch:
return await batchOperation(items);

default:
var sequential = new List<TResult>(items.Count);
foreach (var item in items)
{
sequential.Add(await operation(item));
}
return sequential;
}
}
}
Loading
Loading