Skip to content

Commit 4736732

Browse files
committed
fix: address PR 84 review comments
1 parent e3faff0 commit 4736732

File tree

11 files changed

+248
-91
lines changed

11 files changed

+248
-91
lines changed

DotPilot.Core/ChatSessions/Commands/CreateAgentProfileCommand.cs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,34 @@ namespace DotPilot.Core.ChatSessions.Commands;
44

55
public sealed class CreateAgentProfileCommand : Command<CreateAgentProfileCommand.Payload>
66
{
7-
private readonly Payload _payload;
7+
private readonly Payload payload;
88

99
public CreateAgentProfileCommand(
1010
string name,
1111
AgentProviderKind providerKind,
1212
string modelName,
1313
string systemPrompt,
1414
string description = "")
15-
: base(
16-
Guid.CreateVersion7(),
17-
nameof(CreateAgentProfileCommand),
18-
new Payload(name, providerKind, modelName, systemPrompt, description))
15+
: this(new Payload(name, providerKind, modelName, systemPrompt, description))
1916
{
20-
_payload = new Payload(name, providerKind, modelName, systemPrompt, description);
21-
Value = _payload;
2217
}
2318

24-
public string Name => _payload.Name;
19+
private CreateAgentProfileCommand(Payload payload)
20+
: base(Guid.CreateVersion7(), nameof(CreateAgentProfileCommand), payload)
21+
{
22+
this.payload = payload;
23+
Value = payload;
24+
}
25+
26+
public string Name => payload.Name;
2527

26-
public AgentProviderKind ProviderKind => _payload.ProviderKind;
28+
public AgentProviderKind ProviderKind => payload.ProviderKind;
2729

28-
public string ModelName => _payload.ModelName;
30+
public string ModelName => payload.ModelName;
2931

30-
public string SystemPrompt => _payload.SystemPrompt;
32+
public string SystemPrompt => payload.SystemPrompt;
3133

32-
public string Description => _payload.Description;
34+
public string Description => payload.Description;
3335

3436
[GenerateSerializer]
3537
public sealed record Payload(

DotPilot.Core/ChatSessions/Commands/CreateSessionCommand.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@ namespace DotPilot.Core.ChatSessions.Commands;
55

66
public sealed class CreateSessionCommand : Command<CreateSessionCommand.Payload>
77
{
8-
private readonly Payload _payload;
8+
private readonly Payload payload;
99

1010
public CreateSessionCommand(
1111
string title,
1212
AgentProfileId agentProfileId)
13-
: base(
14-
Guid.CreateVersion7(),
15-
nameof(CreateSessionCommand),
16-
new Payload(title, agentProfileId))
13+
: this(new Payload(title, agentProfileId))
1714
{
18-
_payload = new Payload(title, agentProfileId);
19-
Value = _payload;
2015
}
2116

22-
public string Title => _payload.Title;
17+
private CreateSessionCommand(Payload payload)
18+
: base(Guid.CreateVersion7(), nameof(CreateSessionCommand), payload)
19+
{
20+
this.payload = payload;
21+
Value = payload;
22+
}
23+
24+
public string Title => payload.Title;
2325

24-
public AgentProfileId AgentProfileId => _payload.AgentProfileId;
26+
public AgentProfileId AgentProfileId => payload.AgentProfileId;
2527

2628
[GenerateSerializer]
2729
public sealed record Payload(

DotPilot.Core/ChatSessions/Commands/SendSessionMessageCommand.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,26 @@ namespace DotPilot.Core.ChatSessions.Commands;
66

77
public sealed class SendSessionMessageCommand : Command<SendSessionMessageCommand.Payload>
88
{
9-
private readonly Payload _payload;
9+
private readonly Payload payload;
1010

1111
public SendSessionMessageCommand(
1212
SessionId sessionId,
1313
string message)
14-
: base(
15-
Guid.CreateVersion7(),
16-
nameof(SendSessionMessageCommand),
17-
new Payload(sessionId, message))
14+
: this(new Payload(sessionId, message))
1815
{
19-
_payload = new Payload(sessionId, message);
20-
Value = _payload;
21-
base.SessionId = sessionId.Value.ToString("N", CultureInfo.InvariantCulture);
2216
}
2317

24-
public new SessionId SessionId => _payload.SessionId;
18+
private SendSessionMessageCommand(Payload payload)
19+
: base(Guid.CreateVersion7(), nameof(SendSessionMessageCommand), payload)
20+
{
21+
this.payload = payload;
22+
Value = payload;
23+
base.SessionId = payload.SessionId.Value.ToString("N", CultureInfo.InvariantCulture);
24+
}
25+
26+
public new SessionId SessionId => payload.SessionId;
2527

26-
public string Message => _payload.Message;
28+
public string Message => payload.Message;
2729

2830
[GenerateSerializer]
2931
public sealed record Payload(

DotPilot.Core/ChatSessions/Commands/UpdateAgentProfileCommand.cs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace DotPilot.Core.ChatSessions.Commands;
55

66
public sealed class UpdateAgentProfileCommand : Command<UpdateAgentProfileCommand.Payload>
77
{
8-
private readonly Payload _payload;
8+
private readonly Payload payload;
99

1010
public UpdateAgentProfileCommand(
1111
AgentProfileId agentId,
@@ -14,26 +14,28 @@ public UpdateAgentProfileCommand(
1414
string modelName,
1515
string systemPrompt,
1616
string description = "")
17-
: base(
18-
Guid.CreateVersion7(),
19-
nameof(UpdateAgentProfileCommand),
20-
new Payload(agentId, name, providerKind, modelName, systemPrompt, description))
17+
: this(new Payload(agentId, name, providerKind, modelName, systemPrompt, description))
2118
{
22-
_payload = new Payload(agentId, name, providerKind, modelName, systemPrompt, description);
23-
Value = _payload;
2419
}
2520

26-
public AgentProfileId AgentId => _payload.AgentId;
21+
private UpdateAgentProfileCommand(Payload payload)
22+
: base(Guid.CreateVersion7(), nameof(UpdateAgentProfileCommand), payload)
23+
{
24+
this.payload = payload;
25+
Value = payload;
26+
}
27+
28+
public AgentProfileId AgentId => payload.AgentId;
2729

28-
public string Name => _payload.Name;
30+
public string Name => payload.Name;
2931

30-
public AgentProviderKind ProviderKind => _payload.ProviderKind;
32+
public AgentProviderKind ProviderKind => payload.ProviderKind;
3133

32-
public string ModelName => _payload.ModelName;
34+
public string ModelName => payload.ModelName;
3335

34-
public string SystemPrompt => _payload.SystemPrompt;
36+
public string SystemPrompt => payload.SystemPrompt;
3537

36-
public string Description => _payload.Description;
38+
public string Description => payload.Description;
3739

3840
[GenerateSerializer]
3941
public sealed record Payload(

DotPilot.Core/ChatSessions/Commands/UpdateProviderPreferenceCommand.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,25 @@ namespace DotPilot.Core.ChatSessions.Commands;
44

55
public sealed class UpdateProviderPreferenceCommand : Command<UpdateProviderPreferenceCommand.Payload>
66
{
7-
private readonly Payload _payload;
7+
private readonly Payload payload;
88

99
public UpdateProviderPreferenceCommand(
1010
AgentProviderKind providerKind,
1111
bool isEnabled)
12-
: base(
13-
Guid.CreateVersion7(),
14-
nameof(UpdateProviderPreferenceCommand),
15-
new Payload(providerKind, isEnabled))
12+
: this(new Payload(providerKind, isEnabled))
1613
{
17-
_payload = new Payload(providerKind, isEnabled);
18-
Value = _payload;
1914
}
2015

21-
public AgentProviderKind ProviderKind => _payload.ProviderKind;
16+
private UpdateProviderPreferenceCommand(Payload payload)
17+
: base(Guid.CreateVersion7(), nameof(UpdateProviderPreferenceCommand), payload)
18+
{
19+
this.payload = payload;
20+
Value = payload;
21+
}
22+
23+
public AgentProviderKind ProviderKind => payload.ProviderKind;
2224

23-
public bool IsEnabled => _payload.IsEnabled;
25+
public bool IsEnabled => payload.IsEnabled;
2426

2527
[GenerateSerializer]
2628
public sealed record Payload(

DotPilot.Core/ChatSessions/Execution/SessionActivityMonitor.cs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,34 +81,45 @@ private void EndActivity(ActivityLease lease)
8181

8282
private SessionActivitySnapshot UpdateSnapshotUnsafe()
8383
{
84+
if (_leases.Count == 0)
85+
{
86+
_current = EmptySnapshot;
87+
return _current;
88+
}
89+
8490
var activeSessions = GetActiveSessionsUnsafe();
85-
_current = _leases.Count == 0
86-
? EmptySnapshot
87-
: CreateSnapshot(activeSessions);
91+
_current = CreateSnapshot(activeSessions, _leases[^1].Descriptor);
8892
return _current;
8993
}
9094

91-
private IReadOnlyList<SessionActivityDescriptor> GetActiveSessionsUnsafe()
95+
private List<SessionActivityDescriptor> GetActiveSessionsUnsafe()
9296
{
9397
if (_leases.Count == 0)
9498
{
9599
return [];
96100
}
97101

98-
var descriptors = new Dictionary<SessionId, SessionActivityDescriptor>();
99-
for (var index = 0; index < _leases.Count; index++)
102+
HashSet<SessionId> seen = [];
103+
List<SessionActivityDescriptor> descriptors = [];
104+
for (var index = _leases.Count - 1; index >= 0; index--)
100105
{
101106
var descriptor = _leases[index].Descriptor;
102-
descriptors.Remove(descriptor.SessionId);
103-
descriptors[descriptor.SessionId] = descriptor;
107+
if (!seen.Add(descriptor.SessionId))
108+
{
109+
continue;
110+
}
111+
112+
descriptors.Add(descriptor);
104113
}
105114

106-
return [.. descriptors.Values];
115+
descriptors.Reverse();
116+
return descriptors;
107117
}
108118

109-
private static SessionActivitySnapshot CreateSnapshot(IReadOnlyList<SessionActivityDescriptor> activeSessions)
119+
private static SessionActivitySnapshot CreateSnapshot(
120+
List<SessionActivityDescriptor> activeSessions,
121+
SessionActivityDescriptor latestSession)
110122
{
111-
var latestSession = activeSessions[^1];
112123
return new SessionActivitySnapshot(
113124
true,
114125
activeSessions.Count,

DotPilot.Core/Providers/Services/AgentProviderStatusSnapshotReader.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,24 @@ public static async Task<IReadOnlyList<ProviderStatusProbeResult>> BuildAsync(
3030
.ToDictionaryAsync(
3131
preference => (AgentProviderKind)preference.ProviderKind,
3232
cancellationToken);
33+
var profiles = AgentSessionProviderCatalog.All;
3334

3435
return await Task.Run(
35-
() => AgentSessionProviderCatalog.All
36-
.Select(profile => BuildProviderStatus(profile, GetProviderPreference(profile.Kind, preferences)))
37-
.ToArray(),
38-
cancellationToken);
36+
async () =>
37+
{
38+
List<ProviderStatusProbeResult> results = new(profiles.Count);
39+
foreach (var profile in profiles)
40+
{
41+
cancellationToken.ThrowIfCancellationRequested();
42+
results.Add(await BuildProviderStatusAsync(
43+
profile,
44+
GetProviderPreference(profile.Kind, preferences),
45+
cancellationToken).ConfigureAwait(false));
46+
}
47+
48+
return (IReadOnlyList<ProviderStatusProbeResult>)results;
49+
},
50+
cancellationToken).ConfigureAwait(false);
3951
}
4052

4153
private static ProviderPreferenceRecord GetProviderPreference(
@@ -52,9 +64,10 @@ private static ProviderPreferenceRecord GetProviderPreference(
5264
};
5365
}
5466

55-
private static ProviderStatusProbeResult BuildProviderStatus(
67+
private static async ValueTask<ProviderStatusProbeResult> BuildProviderStatusAsync(
5668
AgentSessionProviderProfile profile,
57-
ProviderPreferenceRecord preference)
69+
ProviderPreferenceRecord preference,
70+
CancellationToken cancellationToken)
5871
{
5972
var providerId = AgentSessionDeterministicIdentity.CreateProviderId(profile.CommandName);
6073
var actions = new List<ProviderActionDescriptor>();
@@ -95,7 +108,7 @@ private static ProviderStatusProbeResult BuildProviderStatus(
95108
installedVersion = AgentSessionCommandProbe.ReadVersion(executablePath, ["--version"]);
96109
actions.Add(new ProviderActionDescriptor("Open CLI", "CLI detected on PATH.", $"{profile.CommandName} --version"));
97110

98-
var metadata = ResolveMetadata(profile, executablePath);
111+
var metadata = await ResolveMetadataAsync(profile, executablePath, cancellationToken).ConfigureAwait(false);
99112
installedVersion = ResolveInstalledVersion(
100113
installedVersion,
101114
metadata.InstalledVersion,
@@ -150,15 +163,19 @@ private static ProviderStatusProbeResult BuildProviderStatus(
150163
executablePath);
151164
}
152165

153-
private static ProviderCliMetadataSnapshot ResolveMetadata(
166+
private static async ValueTask<ProviderCliMetadataSnapshot> ResolveMetadataAsync(
154167
AgentSessionProviderProfile profile,
155-
string executablePath)
168+
string executablePath,
169+
CancellationToken cancellationToken)
156170
{
157171
return profile.Kind switch
158172
{
159173
AgentProviderKind.Codex => CreateCodexSnapshot(CodexCliMetadataReader.TryRead(executablePath)),
160174
AgentProviderKind.ClaudeCode => ClaudeCodeCliMetadataReader.TryRead(executablePath, profile),
161-
AgentProviderKind.GitHubCopilot => CopilotCliMetadataReader.TryRead(executablePath, profile),
175+
AgentProviderKind.GitHubCopilot => await CopilotCliMetadataReader.TryReadAsync(
176+
executablePath,
177+
profile,
178+
cancellationToken).ConfigureAwait(false),
162179
_ => new ProviderCliMetadataSnapshot(null, null, []),
163180
};
164181
}

DotPilot.Core/Providers/Services/CopilotCliMetadataReader.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@ internal static class CopilotCliMetadataReader
1010
private const string EnabledPolicyState = "enabled";
1111
private const string ModelSettingHeader = "`model`:";
1212

13-
public static ProviderCliMetadataSnapshot TryRead(string executablePath, AgentSessionProviderProfile profile)
13+
public static async ValueTask<ProviderCliMetadataSnapshot> TryReadAsync(
14+
string executablePath,
15+
AgentSessionProviderProfile profile,
16+
CancellationToken cancellationToken)
1417
{
1518
ArgumentException.ThrowIfNullOrWhiteSpace(executablePath);
1619
ArgumentNullException.ThrowIfNull(profile);
1720

1821
var configuredModel = ReadConfiguredModel();
1922
try
2023
{
21-
return ReadViaSdkAsync(executablePath, configuredModel).AsTask().GetAwaiter().GetResult();
24+
return await ReadViaSdkAsync(executablePath, configuredModel, cancellationToken).ConfigureAwait(false);
2225
}
2326
catch
2427
{
@@ -31,7 +34,8 @@ public static ProviderCliMetadataSnapshot TryRead(string executablePath, AgentSe
3134

3235
private static async ValueTask<ProviderCliMetadataSnapshot> ReadViaSdkAsync(
3336
string executablePath,
34-
string? configuredModel)
37+
string? configuredModel,
38+
CancellationToken cancellationToken)
3539
{
3640
await using var client = new CopilotClient(new CopilotClientOptions
3741
{
@@ -40,9 +44,9 @@ private static async ValueTask<ProviderCliMetadataSnapshot> ReadViaSdkAsync(
4044
UseStdio = true,
4145
});
4246

43-
await client.StartAsync(CancellationToken.None);
44-
var status = await client.GetStatusAsync(CancellationToken.None);
45-
var models = await client.ListModelsAsync(CancellationToken.None);
47+
await client.StartAsync(cancellationToken).ConfigureAwait(false);
48+
var status = await client.GetStatusAsync(cancellationToken).ConfigureAwait(false);
49+
var models = await client.ListModelsAsync(cancellationToken).ConfigureAwait(false);
4650

4751
return new ProviderCliMetadataSnapshot(
4852
status.Version,

0 commit comments

Comments
 (0)