Skip to content

Commit eb898fd

Browse files
authored
Merge pull request #80 from managedcode/codex/issue-24-embedded-orleans-host
Implement embedded Orleans localhost host
2 parents dd4b891 + 52745b0 commit eb898fd

37 files changed

+1084
-28
lines changed

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This file defines how AI agents work in this solution.
2323
- `DotPilot`
2424
- `DotPilot.Core`
2525
- `DotPilot.Runtime`
26+
- `DotPilot.Runtime.Host`
2627
- `DotPilot.ReleaseTool`
2728
- `DotPilot.Tests`
2829
- `DotPilot.UITests`
@@ -152,7 +153,9 @@ For this app:
152153
- architecture work must keep a vertical-slice shape: each feature owns its contracts, orchestration, and tests behind clear boundaries instead of growing a shared horizontal service layer
153154
- keep the Uno app project presentation-only; domain, runtime host, orchestration, integrations, and persistence code must live in separate class-library projects so UI composition does not mix with feature implementation
154155
- structure both `DotPilot.Tests` and `DotPilot.UITests` by vertical slice and explicit harness boundaries; do not keep test files in one flat project-root pile
156+
- the first embedded Orleans host cut must use `UseLocalhostClustering` plus in-memory grain storage and reminders; do not introduce remote clustering or external durable stores until a later backlog item explicitly requires them
155157
- GitHub is the backlog, not the product: use issues and PRs only to drive task scope and traceability, and never copy GitHub issue text, labels, workflow language, or tracker metadata into production code, runtime snapshots, or user-facing UI
158+
- never claim an epic is complete until its current GitHub scope is verified against the live issue graph; check which issues are real children versus issues that merely depend on the epic or belong to a different parent epic
156159
- Desktop responsiveness is a product requirement: avoid synchronous probe, filesystem, network, or process work on UI-facing construction and navigation paths so the app stays fast and immediately reactive
157160
- Do not invent a repo-specific product framing such as "workbench" unless the active issue or feature spec explicitly uses it; implement the app features described in the backlog instead of turning internal implementation language into the product narrative
158161
- GitHub Actions workflows must use descriptive names and filenames that reflect their purpose; do not use a generic `ci.yml` catch-all because build validation and release automation are separate operator flows
@@ -366,6 +369,7 @@ Ask first:
366369
- Installing stale, non-canonical, or non-`mcaf-*` skills into the repo-local agent skill directory.
367370
- Moving root governance out of the repository root.
368371
- Mixing multiple `.NET` test frameworks in the active solution without a documented migration plan.
372+
- Creating auxiliary `git worktree` directories for normal PR follow-up when straightforward branch switching in the main checkout is enough.
369373
- Running build, test, or verification commands for file-only structural reorganizations when the user explicitly asked for folder cleanup without behavior changes.
370374
- Adding fallback paths or alternate harnesses that only make failures disappear in tests while the primary product path remains broken.
371375
- Switching desktop Uno pages into stacked or mobile-style responsive layouts during resize work unless the user explicitly asks for a different composition; desktop pages must stay desktop-first and protect geometry through sizing constraints instead.

Directory.Packages.props

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
<PackageVersion Include="coverlet.collector" Version="8.0.0" />
1313
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
1414
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
15+
<PackageVersion Include="Microsoft.Orleans.Core.Abstractions" Version="10.0.1" />
16+
<PackageVersion Include="Microsoft.Orleans.Persistence.Memory" Version="10.0.1" />
17+
<PackageVersion Include="Microsoft.Orleans.Reminders" Version="10.0.1" />
18+
<PackageVersion Include="Microsoft.Orleans.Server" Version="10.0.1" />
1519
<PackageVersion Include="NUnit" Version="4.5.1" />
1620
<PackageVersion Include="NUnit3TestAdapter" Version="6.1.0" />
1721
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.1" />

DotPilot.Core/DotPilot.Core.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@
66
<NoWarn>$(NoWarn);CS1591</NoWarn>
77
</PropertyGroup>
88

9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" />
11+
</ItemGroup>
12+
913
</Project>

DotPilot.Core/Features/ControlPlaneDomain/ControlPlaneIdentifiers.cs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,77 +2,96 @@
22

33
namespace DotPilot.Core.Features.ControlPlaneDomain;
44

5-
public readonly record struct WorkspaceId(Guid Value)
5+
[GenerateSerializer]
6+
public readonly record struct WorkspaceId([property: Id(0)] Guid Value)
67
{
78
public static WorkspaceId New() => new(ControlPlaneIdentifier.NewValue());
89

910
public override string ToString() => ControlPlaneIdentifier.Format(Value);
1011
}
1112

12-
public readonly record struct AgentProfileId(Guid Value)
13+
[GenerateSerializer]
14+
public readonly record struct AgentProfileId([property: Id(0)] Guid Value)
1315
{
1416
public static AgentProfileId New() => new(ControlPlaneIdentifier.NewValue());
1517

1618
public override string ToString() => ControlPlaneIdentifier.Format(Value);
1719
}
1820

19-
public readonly record struct SessionId(Guid Value)
21+
[GenerateSerializer]
22+
public readonly record struct SessionId([property: Id(0)] Guid Value)
2023
{
2124
public static SessionId New() => new(ControlPlaneIdentifier.NewValue());
2225

2326
public override string ToString() => ControlPlaneIdentifier.Format(Value);
2427
}
2528

26-
public readonly record struct FleetId(Guid Value)
29+
[GenerateSerializer]
30+
public readonly record struct FleetId([property: Id(0)] Guid Value)
2731
{
2832
public static FleetId New() => new(ControlPlaneIdentifier.NewValue());
2933

3034
public override string ToString() => ControlPlaneIdentifier.Format(Value);
3135
}
3236

33-
public readonly record struct ProviderId(Guid Value)
37+
[GenerateSerializer]
38+
public readonly record struct PolicyId([property: Id(0)] Guid Value)
39+
{
40+
public static PolicyId New() => new(ControlPlaneIdentifier.NewValue());
41+
42+
public override string ToString() => ControlPlaneIdentifier.Format(Value);
43+
}
44+
45+
[GenerateSerializer]
46+
public readonly record struct ProviderId([property: Id(0)] Guid Value)
3447
{
3548
public static ProviderId New() => new(ControlPlaneIdentifier.NewValue());
3649

3750
public override string ToString() => ControlPlaneIdentifier.Format(Value);
3851
}
3952

40-
public readonly record struct ModelRuntimeId(Guid Value)
53+
[GenerateSerializer]
54+
public readonly record struct ModelRuntimeId([property: Id(0)] Guid Value)
4155
{
4256
public static ModelRuntimeId New() => new(ControlPlaneIdentifier.NewValue());
4357

4458
public override string ToString() => ControlPlaneIdentifier.Format(Value);
4559
}
4660

47-
public readonly record struct ToolCapabilityId(Guid Value)
61+
[GenerateSerializer]
62+
public readonly record struct ToolCapabilityId([property: Id(0)] Guid Value)
4863
{
4964
public static ToolCapabilityId New() => new(ControlPlaneIdentifier.NewValue());
5065

5166
public override string ToString() => ControlPlaneIdentifier.Format(Value);
5267
}
5368

54-
public readonly record struct ApprovalId(Guid Value)
69+
[GenerateSerializer]
70+
public readonly record struct ApprovalId([property: Id(0)] Guid Value)
5571
{
5672
public static ApprovalId New() => new(ControlPlaneIdentifier.NewValue());
5773

5874
public override string ToString() => ControlPlaneIdentifier.Format(Value);
5975
}
6076

61-
public readonly record struct ArtifactId(Guid Value)
77+
[GenerateSerializer]
78+
public readonly record struct ArtifactId([property: Id(0)] Guid Value)
6279
{
6380
public static ArtifactId New() => new(ControlPlaneIdentifier.NewValue());
6481

6582
public override string ToString() => ControlPlaneIdentifier.Format(Value);
6683
}
6784

68-
public readonly record struct TelemetryRecordId(Guid Value)
85+
[GenerateSerializer]
86+
public readonly record struct TelemetryRecordId([property: Id(0)] Guid Value)
6987
{
7088
public static TelemetryRecordId New() => new(ControlPlaneIdentifier.NewValue());
7189

7290
public override string ToString() => ControlPlaneIdentifier.Format(Value);
7391
}
7492

75-
public readonly record struct EvaluationId(Guid Value)
93+
[GenerateSerializer]
94+
public readonly record struct EvaluationId([property: Id(0)] Guid Value)
7695
{
7796
public static EvaluationId New() => new(ControlPlaneIdentifier.NewValue());
7897

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,58 @@
11
namespace DotPilot.Core.Features.ControlPlaneDomain;
22

3+
[GenerateSerializer]
34
public sealed record WorkspaceDescriptor
45
{
6+
[Id(0)]
57
public WorkspaceId Id { get; init; }
68

9+
[Id(1)]
710
public string Name { get; init; } = string.Empty;
811

12+
[Id(2)]
913
public string RootPath { get; init; } = string.Empty;
1014

15+
[Id(3)]
1116
public string BranchName { get; init; } = string.Empty;
1217
}
1318

19+
[GenerateSerializer]
1420
public sealed record AgentProfileDescriptor
1521
{
22+
[Id(0)]
1623
public AgentProfileId Id { get; init; }
1724

25+
[Id(1)]
1826
public string Name { get; init; } = string.Empty;
1927

28+
[Id(2)]
2029
public AgentRoleKind Role { get; init; }
2130

31+
[Id(3)]
2232
public ProviderId? ProviderId { get; init; }
2333

34+
[Id(4)]
2435
public ModelRuntimeId? ModelRuntimeId { get; init; }
2536

26-
public IReadOnlyList<ToolCapabilityId> ToolCapabilityIds { get; init; } = [];
37+
[Id(5)]
38+
public ToolCapabilityId[] ToolCapabilityIds { get; init; } = [];
2739

28-
public IReadOnlyList<string> Tags { get; init; } = [];
40+
[Id(6)]
41+
public string[] Tags { get; init; } = [];
2942
}
3043

44+
[GenerateSerializer]
3145
public sealed record FleetDescriptor
3246
{
47+
[Id(0)]
3348
public FleetId Id { get; init; }
3449

50+
[Id(1)]
3551
public string Name { get; init; } = string.Empty;
3652

53+
[Id(2)]
3754
public FleetExecutionMode ExecutionMode { get; init; } = FleetExecutionMode.SingleAgent;
3855

39-
public IReadOnlyList<AgentProfileId> AgentProfileIds { get; init; } = [];
56+
[Id(3)]
57+
public AgentProfileId[] AgentProfileIds { get; init; } = [];
4058
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace DotPilot.Core.Features.ControlPlaneDomain;
2+
3+
[GenerateSerializer]
4+
public sealed record PolicyDescriptor
5+
{
6+
[Id(0)]
7+
public PolicyId Id { get; init; }
8+
9+
[Id(1)]
10+
public string Name { get; init; } = string.Empty;
11+
12+
[Id(2)]
13+
public ApprovalState DefaultApprovalState { get; init; } = ApprovalState.NotRequired;
14+
15+
[Id(3)]
16+
public bool AllowsNetworkAccess { get; init; }
17+
18+
[Id(4)]
19+
public bool AllowsFileSystemWrites { get; init; }
20+
21+
[Id(5)]
22+
public ApprovalScope[] ProtectedScopes { get; init; } = [];
23+
}
Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,73 @@
11
namespace DotPilot.Core.Features.ControlPlaneDomain;
22

3+
[GenerateSerializer]
34
public sealed record ToolCapabilityDescriptor
45
{
6+
[Id(0)]
57
public ToolCapabilityId Id { get; init; }
68

9+
[Id(1)]
710
public string Name { get; init; } = string.Empty;
811

12+
[Id(2)]
913
public string DisplayName { get; init; } = string.Empty;
1014

15+
[Id(3)]
1116
public ToolCapabilityKind Kind { get; init; }
1217

18+
[Id(4)]
1319
public bool RequiresApproval { get; init; }
1420

21+
[Id(5)]
1522
public bool IsEnabledByDefault { get; init; }
1623

17-
public IReadOnlyList<string> Tags { get; init; } = [];
24+
[Id(6)]
25+
public string[] Tags { get; init; } = [];
1826
}
1927

28+
[GenerateSerializer]
2029
public sealed record ProviderDescriptor
2130
{
31+
[Id(0)]
2232
public ProviderId Id { get; init; }
2333

34+
[Id(1)]
2435
public string DisplayName { get; init; } = string.Empty;
2536

37+
[Id(2)]
2638
public string CommandName { get; init; } = string.Empty;
2739

40+
[Id(3)]
2841
public ProviderConnectionStatus Status { get; init; } = ProviderConnectionStatus.Unavailable;
2942

43+
[Id(4)]
3044
public string StatusSummary { get; init; } = string.Empty;
3145

46+
[Id(5)]
3247
public bool RequiresExternalToolchain { get; init; }
3348

34-
public IReadOnlyList<ToolCapabilityId> SupportedToolIds { get; init; } = [];
49+
[Id(6)]
50+
public ToolCapabilityId[] SupportedToolIds { get; init; } = [];
3551
}
3652

53+
[GenerateSerializer]
3754
public sealed record ModelRuntimeDescriptor
3855
{
56+
[Id(0)]
3957
public ModelRuntimeId Id { get; init; }
4058

59+
[Id(1)]
4160
public string DisplayName { get; init; } = string.Empty;
4261

62+
[Id(2)]
4363
public string EngineName { get; init; } = string.Empty;
4464

65+
[Id(3)]
4566
public RuntimeKind RuntimeKind { get; init; }
4667

68+
[Id(4)]
4769
public ProviderConnectionStatus Status { get; init; } = ProviderConnectionStatus.Unavailable;
4870

49-
public IReadOnlyList<string> SupportedModelFamilies { get; init; } = [];
71+
[Id(5)]
72+
public string[] SupportedModelFamilies { get; init; } = [];
5073
}

0 commit comments

Comments
 (0)