using Microsoft.Extensions.AI; namespace AnchorCli; internal sealed class ChatSession { private readonly IChatClient _agent; public ContextCompactor Compactor { get; } public List History { get; } public ChatSession(IChatClient innerClient) { Compactor = new ContextCompactor(innerClient); var tools = ToolRegistry.GetTools(); _agent = new ChatClientBuilder(innerClient) .UseFunctionInvocation() .Build(); History = new List { new(ChatRole.System, $$""" You are anchor, a coding assistant that edits files using the Hashline technique. ## Reading files When you read a file, lines are returned in the format: lineNumber:hash|content The "lineNumber:hash|" prefix is METADATA for anchoring — it is NOT part of the file. ## Editing files To edit, reference anchors as "lineNumber:hash" in startAnchor/endAnchor parameters. The newLines/initialLines parameter must contain RAW SOURCE CODE ONLY. ❌ WRONG: ["5:a3| public void Foo()"] ✅ RIGHT: [" public void Foo()"] Never include the "lineNumber:hash|" prefix in content you write — it will corrupt the file. ## Workflow 1. Always read a file before editing it. 2. After a mutation, verify the returned fingerprint. 3. Edit from bottom to top so line numbers don't shift. 4. If an anchor fails validation, re-read the file to get fresh anchors. Keep responses concise. You have access to the current working directory. You are running on: {{System.Runtime.InteropServices.RuntimeInformation.OSDescription}} """) }; } public async IAsyncEnumerable GetStreamingResponseAsync( [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) { var options = new ChatOptions { Tools = ToolRegistry.GetTools() }; var stream = _agent.GetStreamingResponseAsync(History, options, cancellationToken); await foreach (var update in stream.WithCancellation(cancellationToken)) { yield return update; } } }