Adopt the mic-check CLAUDE.md and .editorconfig house standards
Ported both files from wamplerj/mic-check and retargeted them to this project's
stack, then brought the code into line with the rules rather than watering the
rules down to fit the code.
.editorconfig — C# rules carried over verbatim, with four changes:
- Added root = true and a [*] section (utf-8, space indent, final newline,
trim trailing whitespace). Without root the file inherits from any parent
.editorconfig above the checkout.
- end_of_line lf rather than crlf. Every file here is LF and there is no
.gitattributes to normalise on checkout, so crlf would rewrite the tree on
first save.
- csharp_style_namespace_declarations file_scoped, was block_scoped. The source
file sets file_scoped under [*.{cs,vb}] and block_scoped under [*.cs]; the
C#-specific key wins, so the two disagreeing meant C# silently got
block_scoped. Every .cs file here is file-scoped.
- Added sections for the React client (ts/tsx/js 2-space, 100 cols), json/yaml,
css/html, markdown (trailing whitespace preserved — it is a line break there)
and MSBuild files.
Also dropped a duplicated dotnet_naming_style.pascal_case block that appeared
twice verbatim in the source.
CLAUDE.md — same structure and voice, retargeted: React not Vue, xUnit and
FluentAssertions not NUnit and jest, this repo's six projects, and the real
testing approach (in-memory SQLite via TestDatabase, model calls faked at the
IAgentModelClient seam). Added sections the standards did not cover: the
three-front-ends-one-API rule, PATCH semantics, and a note that build-and-tests
green is not the same as working, with the commands to actually run each piece.
Code brought into compliance:
- Removed sealed from five types (the standard says no sealed)
- NovelAgentToolset.ExecuteAsync returned a named tuple; it now returns an
AgentToolResult record (the standard says no tuples for return types)
- Added LangVersion latest to all six csproj files
None of the style rules produce build warnings — the IDE analyzers behind them
are off unless EnforceCodeStyleInBuild is set, and verified they stay silent
with it on too. 44 tests still pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S56bfZMGe1hnhpWP4CjjNw
This commit is contained in:
co-authored by
Claude Opus 5
parent
7678cc7275
commit
1852ceb2d1
@@ -1,9 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NovelSoftware.Infrastructure\NovelSoftware.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.10">
|
||||
@@ -11,12 +11,13 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.OpenApi" Version="2.11.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace NovelSoftware.Application.Agent;
|
||||
/// Small builder for the JSON Schema objects tool definitions need. Hand-writing these
|
||||
/// as string literals is where tool definitions usually rot, so build them structurally.
|
||||
/// </summary>
|
||||
public sealed class JsonSchemaBuilder
|
||||
public class JsonSchemaBuilder
|
||||
{
|
||||
private readonly JsonObject _properties = [];
|
||||
private readonly JsonArray _required = [];
|
||||
|
||||
@@ -101,14 +101,14 @@ public class NovelAgentService(
|
||||
var results = new List<AgentContentBlock>();
|
||||
foreach (var call in requestedTools)
|
||||
{
|
||||
var (result, isError) = await toolset.ExecuteAsync(call.Name, projectId, call.Input, ct);
|
||||
var outcome = await toolset.ExecuteAsync(call.Name, projectId, call.Input, ct);
|
||||
|
||||
logger.LogInformation(
|
||||
"Agent tool {Tool} on project {ProjectId} {Outcome}",
|
||||
call.Name, projectId, isError ? "failed" : "succeeded");
|
||||
call.Name, projectId, outcome.IsError ? "failed" : "succeeded");
|
||||
|
||||
toolCalls.Add(new ToolCallDto(call.Name, call.Input.ToString(), result));
|
||||
results.Add(new AgentToolResultBlock(call.Id, result, isError));
|
||||
toolCalls.Add(new ToolCallDto(call.Name, call.Input.ToString(), outcome.Content));
|
||||
results.Add(new AgentToolResultBlock(call.Id, outcome.Content, outcome.IsError));
|
||||
}
|
||||
|
||||
transcript.Add(AgentChatMessage.User([.. results]));
|
||||
|
||||
@@ -5,8 +5,11 @@ using NovelSoftware.Domain;
|
||||
|
||||
namespace NovelSoftware.Application.Agent;
|
||||
|
||||
/// <summary>The outcome of running a tool: what to hand back to the model, and whether it failed.</summary>
|
||||
public record AgentToolResult(string Content, bool IsError);
|
||||
|
||||
/// <summary>A tool the agent can call, bound to a handler that runs against the project's data.</summary>
|
||||
public sealed record AgentTool(
|
||||
public record AgentTool(
|
||||
string Name,
|
||||
string Description,
|
||||
JsonElement InputSchema,
|
||||
@@ -42,30 +45,30 @@ public class NovelAgentToolset(
|
||||
/// Runs a tool and serialises its result. Failures come back as text rather than
|
||||
/// exceptions so the model can read the message and correct itself.
|
||||
/// </summary>
|
||||
public async Task<(string Result, bool IsError)> ExecuteAsync(
|
||||
public async Task<AgentToolResult> ExecuteAsync(
|
||||
string name, Guid projectId, JsonElement input, CancellationToken ct = default)
|
||||
{
|
||||
if (!ByName.TryGetValue(name, out var tool))
|
||||
{
|
||||
return ($"No such tool: '{name}'.", true);
|
||||
return new AgentToolResult($"No such tool: '{name}'.", true);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await tool.Handler(projectId, input, ct);
|
||||
return (JsonSerializer.Serialize(result, SerializerOptions), false);
|
||||
return new AgentToolResult(JsonSerializer.Serialize(result, SerializerOptions), false);
|
||||
}
|
||||
catch (NotFoundException ex)
|
||||
{
|
||||
return (ex.Message, true);
|
||||
return new AgentToolResult(ex.Message, true);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return (ex.Message, true);
|
||||
return new AgentToolResult(ex.Message, true);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return (ex.Message, true);
|
||||
return new AgentToolResult(ex.Message, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace NovelSoftware.Infrastructure.Persistence;
|
||||
/// first" listing depends on. The domain only ever writes UtcNow, so normalising to UTC
|
||||
/// loses nothing.
|
||||
/// </summary>
|
||||
internal sealed class UtcTicksConverter()
|
||||
internal class UtcTicksConverter()
|
||||
: ValueConverter<DateTimeOffset, long>(
|
||||
value => value.UtcTicks,
|
||||
ticks => new DateTimeOffset(ticks, TimeSpan.Zero));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user