Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This file defines how AI agents work in this solution.
- `DotPilot`
- `DotPilot.Core`
- `DotPilot.Runtime`
- `DotPilot.Runtime.Host`
- `DotPilot.ReleaseTool`
- `DotPilot.Tests`
- `DotPilot.UITests`
Expand Down Expand Up @@ -152,6 +153,7 @@ For this app:
- 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
- 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
- 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
- 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
- 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
- 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
- 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
Expand Down
4 changes: 4 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<PackageVersion Include="coverlet.collector" Version="8.0.0" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageVersion Include="Microsoft.Orleans.Core.Abstractions" Version="10.0.1" />
<PackageVersion Include="Microsoft.Orleans.Persistence.Memory" Version="10.0.1" />
<PackageVersion Include="Microsoft.Orleans.Reminders" Version="10.0.1" />
<PackageVersion Include="Microsoft.Orleans.Server" Version="10.0.1" />
<PackageVersion Include="NUnit" Version="4.5.1" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.1" />
Expand Down
4 changes: 4 additions & 0 deletions DotPilot.Core/DotPilot.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,96 @@

namespace DotPilot.Core.Features.ControlPlaneDomain;

public readonly record struct WorkspaceId(Guid Value)
[GenerateSerializer]
public readonly record struct WorkspaceId([property: Id(0)] Guid Value)
{
public static WorkspaceId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct AgentProfileId(Guid Value)
[GenerateSerializer]
public readonly record struct AgentProfileId([property: Id(0)] Guid Value)
{
public static AgentProfileId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct SessionId(Guid Value)
[GenerateSerializer]
public readonly record struct SessionId([property: Id(0)] Guid Value)
{
public static SessionId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct FleetId(Guid Value)
[GenerateSerializer]
public readonly record struct FleetId([property: Id(0)] Guid Value)
{
public static FleetId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct ProviderId(Guid Value)
[GenerateSerializer]
public readonly record struct PolicyId([property: Id(0)] Guid Value)
{
public static PolicyId New() => new(ControlPlaneIdentifier.NewValue());

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

[GenerateSerializer]
public readonly record struct ProviderId([property: Id(0)] Guid Value)
{
public static ProviderId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct ModelRuntimeId(Guid Value)
[GenerateSerializer]
public readonly record struct ModelRuntimeId([property: Id(0)] Guid Value)
{
public static ModelRuntimeId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct ToolCapabilityId(Guid Value)
[GenerateSerializer]
public readonly record struct ToolCapabilityId([property: Id(0)] Guid Value)
{
public static ToolCapabilityId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct ApprovalId(Guid Value)
[GenerateSerializer]
public readonly record struct ApprovalId([property: Id(0)] Guid Value)
{
public static ApprovalId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct ArtifactId(Guid Value)
[GenerateSerializer]
public readonly record struct ArtifactId([property: Id(0)] Guid Value)
{
public static ArtifactId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct TelemetryRecordId(Guid Value)
[GenerateSerializer]
public readonly record struct TelemetryRecordId([property: Id(0)] Guid Value)
{
public static TelemetryRecordId New() => new(ControlPlaneIdentifier.NewValue());

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

public readonly record struct EvaluationId(Guid Value)
[GenerateSerializer]
public readonly record struct EvaluationId([property: Id(0)] Guid Value)
{
public static EvaluationId New() => new(ControlPlaneIdentifier.NewValue());

Expand Down
24 changes: 21 additions & 3 deletions DotPilot.Core/Features/ControlPlaneDomain/ParticipantContracts.cs
Original file line number Diff line number Diff line change
@@ -1,40 +1,58 @@
namespace DotPilot.Core.Features.ControlPlaneDomain;

[GenerateSerializer]
public sealed record WorkspaceDescriptor
{
[Id(0)]
public WorkspaceId Id { get; init; }

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

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

[Id(3)]
public string BranchName { get; init; } = string.Empty;
}

[GenerateSerializer]
public sealed record AgentProfileDescriptor
{
[Id(0)]
public AgentProfileId Id { get; init; }

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

[Id(2)]
public AgentRoleKind Role { get; init; }

[Id(3)]
public ProviderId? ProviderId { get; init; }

[Id(4)]
public ModelRuntimeId? ModelRuntimeId { get; init; }

public IReadOnlyList<ToolCapabilityId> ToolCapabilityIds { get; init; } = [];
[Id(5)]
public ToolCapabilityId[] ToolCapabilityIds { get; init; } = [];

public IReadOnlyList<string> Tags { get; init; } = [];
[Id(6)]
public string[] Tags { get; init; } = [];
}

[GenerateSerializer]
public sealed record FleetDescriptor
{
[Id(0)]
public FleetId Id { get; init; }

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

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

public IReadOnlyList<AgentProfileId> AgentProfileIds { get; init; } = [];
[Id(3)]
public AgentProfileId[] AgentProfileIds { get; init; } = [];
}
23 changes: 23 additions & 0 deletions DotPilot.Core/Features/ControlPlaneDomain/PolicyContracts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace DotPilot.Core.Features.ControlPlaneDomain;

[GenerateSerializer]
public sealed record PolicyDescriptor
{
[Id(0)]
public PolicyId Id { get; init; }

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

[Id(2)]
public ApprovalState DefaultApprovalState { get; init; } = ApprovalState.NotRequired;

[Id(3)]
public bool AllowsNetworkAccess { get; init; }

[Id(4)]
public bool AllowsFileSystemWrites { get; init; }

[Id(5)]
public ApprovalScope[] ProtectedScopes { get; init; } = [];
}
Original file line number Diff line number Diff line change
@@ -1,50 +1,73 @@
namespace DotPilot.Core.Features.ControlPlaneDomain;

[GenerateSerializer]
public sealed record ToolCapabilityDescriptor
{
[Id(0)]
public ToolCapabilityId Id { get; init; }

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

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

[Id(3)]
public ToolCapabilityKind Kind { get; init; }

[Id(4)]
public bool RequiresApproval { get; init; }

[Id(5)]
public bool IsEnabledByDefault { get; init; }

public IReadOnlyList<string> Tags { get; init; } = [];
[Id(6)]
public string[] Tags { get; init; } = [];
}

[GenerateSerializer]
public sealed record ProviderDescriptor
{
[Id(0)]
public ProviderId Id { get; init; }

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

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

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

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

[Id(5)]
public bool RequiresExternalToolchain { get; init; }

public IReadOnlyList<ToolCapabilityId> SupportedToolIds { get; init; } = [];
[Id(6)]
public ToolCapabilityId[] SupportedToolIds { get; init; } = [];
}

[GenerateSerializer]
public sealed record ModelRuntimeDescriptor
{
[Id(0)]
public ModelRuntimeId Id { get; init; }

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

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

[Id(3)]
public RuntimeKind RuntimeKind { get; init; }

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

public IReadOnlyList<string> SupportedModelFamilies { get; init; } = [];
[Id(5)]
public string[] SupportedModelFamilies { get; init; } = [];
}
Loading