Skip to content

Commit c2dc2b1

Browse files
committed
tests and fixes
1 parent cdc2090 commit c2dc2b1

30 files changed

Lines changed: 973 additions & 83 deletions

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ Ask first:
387387

388388
### Likes
389389

390+
- Keep regression coverage tied to real operator flows: when agent creation changes, tests should cover creating an agent, choosing a valid provider model, and sending at least one message through the resulting session path.
390391
- Follow the canonical MCAF tutorial when bootstrapping or upgrading the agent workflow.
391392
- Commit cohesive code-change batches promptly while debugging, especially before switching focus or starting long verification runs, so the branch state stays inspectable and pushable.
392393
- After opening or updating a PR, create a fresh working branch before continuing with the next slice of work so follow-up changes do not pile onto the already-reviewed branch.

DotPilot.Core/AgentBuilder/Services/AgentPromptDraftGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ private async ValueTask<ProviderStatusDescriptor> ResolvePreferredProviderAsync(
111111
AgentProviderStatus.Disabled,
112112
"Provider is disabled for local agent creation.",
113113
AgentSessionDefaults.GetDefaultModel(AgentProviderKind.Debug),
114+
[AgentSessionDefaults.GetDefaultModel(AgentProviderKind.Debug)],
114115
AgentSessionDefaults.GetDefaultModel(AgentProviderKind.Debug),
115116
false,
116117
false,

DotPilot.Core/ChatSessions/Commands/CreateSessionCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using ManagedCode.Communication.Commands;
21
using DotPilot.Core.ControlPlaneDomain;
2+
using ManagedCode.Communication.Commands;
33

44
namespace DotPilot.Core.ChatSessions.Commands;
55

DotPilot.Core/ChatSessions/Commands/SendSessionMessageCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Globalization;
2-
using ManagedCode.Communication.Commands;
32
using DotPilot.Core.ControlPlaneDomain;
3+
using ManagedCode.Communication.Commands;
44

55
namespace DotPilot.Core.ChatSessions.Commands;
66

DotPilot.Core/ChatSessions/Contracts/AgentSessionContracts.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public sealed record ProviderStatusDescriptor(
1919
AgentProviderStatus Status,
2020
string StatusSummary,
2121
string SuggestedModelName,
22+
IReadOnlyList<string> SupportedModelNames,
2223
string? InstalledVersion,
2324
bool IsEnabled,
2425
bool CanCreateAgents,

DotPilot.Core/ChatSessions/Execution/AgentSessionService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,11 @@ public async ValueTask<Result<AgentProfileSummary>> CreateAgentAsync(
157157
{
158158
Id = Guid.CreateVersion7(),
159159
Name = agentName,
160+
Role = AgentProfileSchemaDefaults.DefaultRole,
160161
ProviderKind = (int)command.ProviderKind,
161162
ModelName = modelName,
162163
SystemPrompt = systemPrompt,
164+
CapabilitiesJson = AgentProfileSchemaDefaults.EmptyCapabilitiesJson,
163165
CreatedAt = createdAt,
164166
};
165167

@@ -719,6 +721,7 @@ private async Task EnsureInitializedAsync(CancellationToken cancellationToken)
719721
AgentSessionServiceLog.InitializationStarted(logger);
720722
await using var dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
721723
await dbContext.Database.EnsureCreatedAsync(cancellationToken);
724+
await AgentProfileSchemaCompatibilityEnsurer.EnsureAsync(dbContext, cancellationToken);
722725
await EnsureDefaultProviderAndAgentAsync(dbContext, cancellationToken);
723726
_initialized = true;
724727
AgentSessionServiceLog.InitializationCompleted(logger);
@@ -776,9 +779,11 @@ record => record.ProviderKind == (int)AgentProviderKind.Debug,
776779
{
777780
Id = Guid.CreateVersion7(),
778781
Name = AgentSessionDefaults.SystemAgentName,
782+
Role = AgentProfileSchemaDefaults.DefaultRole,
779783
ProviderKind = (int)providerKind,
780784
ModelName = AgentSessionDefaults.GetDefaultModel(providerKind),
781785
SystemPrompt = AgentSessionDefaults.SystemAgentPrompt,
786+
CapabilitiesJson = AgentProfileSchemaDefaults.EmptyCapabilitiesJson,
782787
CreatedAt = timeProvider.GetUtcNow(),
783788
};
784789

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace DotPilot.Core.ChatSessions;
2+
3+
internal static class AgentProfileSchemaDefaults
4+
{
5+
// Legacy SQLite stores still require these columns even though the current UI no longer edits them.
6+
public const int DefaultRole = 4;
7+
8+
public const string EmptyCapabilitiesJson = "[]";
9+
}

DotPilot.Core/ChatSessions/Persistence/Models/LocalAgentSessionRecords.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ internal sealed class AgentProfileRecord
66

77
public string Name { get; set; } = string.Empty;
88

9+
public int Role { get; set; }
10+
911
public int ProviderKind { get; set; }
1012

1113
public string ModelName { get; set; } = string.Empty;
1214

1315
public string SystemPrompt { get; set; } = string.Empty;
1416

17+
public string CapabilitiesJson { get; set; } = AgentProfileSchemaDefaults.EmptyCapabilitiesJson;
18+
1519
public DateTimeOffset CreatedAt { get; set; }
1620
}
1721

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System.Data;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace DotPilot.Core.ChatSessions;
5+
6+
internal static class AgentProfileSchemaCompatibilityEnsurer
7+
{
8+
private const string AgentProfilesTableName = "AgentProfiles";
9+
private const string RoleColumnName = "Role";
10+
private const string CapabilitiesJsonColumnName = "CapabilitiesJson";
11+
12+
public static async Task EnsureAsync(LocalAgentSessionDbContext dbContext, CancellationToken cancellationToken)
13+
{
14+
ArgumentNullException.ThrowIfNull(dbContext);
15+
16+
if (!dbContext.Database.IsSqlite())
17+
{
18+
return;
19+
}
20+
21+
var existingColumns = await ReadColumnNamesAsync(dbContext, cancellationToken);
22+
if (!existingColumns.Contains(RoleColumnName, StringComparer.OrdinalIgnoreCase))
23+
{
24+
await dbContext.Database.ExecuteSqlRawAsync(
25+
$"""
26+
ALTER TABLE "{AgentProfilesTableName}"
27+
ADD COLUMN "{RoleColumnName}" INTEGER NOT NULL DEFAULT {AgentProfileSchemaDefaults.DefaultRole};
28+
""",
29+
cancellationToken);
30+
}
31+
32+
if (!existingColumns.Contains(CapabilitiesJsonColumnName, StringComparer.OrdinalIgnoreCase))
33+
{
34+
await dbContext.Database.ExecuteSqlRawAsync(
35+
$"""
36+
ALTER TABLE "{AgentProfilesTableName}"
37+
ADD COLUMN "{CapabilitiesJsonColumnName}" TEXT NOT NULL DEFAULT '{AgentProfileSchemaDefaults.EmptyCapabilitiesJson}';
38+
""",
39+
cancellationToken);
40+
}
41+
}
42+
43+
private static async Task<HashSet<string>> ReadColumnNamesAsync(
44+
LocalAgentSessionDbContext dbContext,
45+
CancellationToken cancellationToken)
46+
{
47+
var connection = dbContext.Database.GetDbConnection();
48+
var shouldCloseConnection = connection.State != ConnectionState.Open;
49+
if (shouldCloseConnection)
50+
{
51+
await connection.OpenAsync(cancellationToken);
52+
}
53+
54+
try
55+
{
56+
await using var command = connection.CreateCommand();
57+
command.CommandText = $"""PRAGMA table_info("{AgentProfilesTableName}")""";
58+
59+
HashSet<string> columns = new(StringComparer.OrdinalIgnoreCase);
60+
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
61+
var nameOrdinal = reader.GetOrdinal("name");
62+
while (await reader.ReadAsync(cancellationToken))
63+
{
64+
columns.Add(reader.GetString(nameOrdinal));
65+
}
66+
67+
return columns;
68+
}
69+
finally
70+
{
71+
if (shouldCloseConnection)
72+
{
73+
await connection.CloseAsync();
74+
}
75+
}
76+
}
77+
}

DotPilot.Core/ChatSessions/Persistence/Storage/LocalAgentSessionDbContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
1919
{
2020
entity.HasKey(record => record.Id);
2121
entity.Property(record => record.Name).IsRequired();
22+
entity.Property(record => record.Role)
23+
.HasDefaultValue(AgentProfileSchemaDefaults.DefaultRole);
2224
entity.Property(record => record.ModelName).IsRequired();
2325
entity.Property(record => record.SystemPrompt).IsRequired();
26+
entity.Property(record => record.CapabilitiesJson)
27+
.HasDefaultValue(AgentProfileSchemaDefaults.EmptyCapabilitiesJson)
28+
.IsRequired();
2429
});
2530

2631
modelBuilder.Entity<SessionRecord>(entity =>

0 commit comments

Comments
 (0)