using System.Collections.Concurrent; using System.Text.Json; using ClawdDotNet.Core.Tools; namespace ClawdDotNet.Core.Tests.Infrastructure; /// /// Konfigurierbares Tool für Engine-Tests: liefert feste Ergebnisse, kann verzögern /// (um Nebenläufigkeit zu provozieren) oder werfen. /// internal sealed class FakeTool : IAgentTool { private readonly Func> _handler; public string Name { get; } public string Description => $"Test-Tool {Name}"; public JsonElement InputSchema { get; } = JsonDocument.Parse(""" { "type": "object", "properties": { "action": { "type": "string" } } } """).RootElement.Clone(); /// Jeder Aufruf wird mitgeschrieben — inklusive der aufrufenden Agent-Id. public ConcurrentBag Invocations { get; } = new(); private FakeTool(string name, Func> handler) { Name = name; _handler = handler; } public static FakeTool Returning(string result, string name = "TestTool") => new(name, (_, _, _) => Task.FromResult(ToolResult.Ok(result))); /// Verzögert die Ausführung — vergrößert das Zeitfenster für Races. public static FakeTool Slow(TimeSpan delay, string result = "ok", string name = "TestTool") => new(name, async (_, _, ct) => { await Task.Delay(delay, ct); return ToolResult.Ok(result); }); public static FakeTool Throwing(Exception ex, string name = "TestTool") => new(name, (_, _, _) => throw ex); public Task ExecuteAsync(JsonElement input, AgentToolContext context, CancellationToken ct) { Invocations.Add(context.AgentId); return _handler(input, context, ct); } } internal sealed class InMemoryStateStore : ClawdDotNet.Core.State.IStateStore { private readonly ConcurrentDictionary _values = new(); public Task GetAsync(string key, CancellationToken ct) => Task.FromResult(_values.GetValueOrDefault(key)); public Task SetAsync(string key, string value, CancellationToken ct) { _values[key] = value; return Task.CompletedTask; } public Task DeleteAsync(string key, CancellationToken ct) { _values.TryRemove(key, out _); return Task.CompletedTask; } }