Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/OpenClaw.Tests/FakeNacosRouterMcpTools.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Text.Json;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
Expand All @@ -22,7 +23,7 @@ public sealed class NacosRouterFixtureState
public HashSet<string> SucceedUseServers { get; } = new(StringComparer.Ordinal);

// Issue #233: timestamps of every use_tool call, for backoff assertions.
public List<DateTimeOffset> UseTimestamps { get; } = [];
public List<long> UseTimestamps { get; } = [];
}

// Parameters and prose envelopes follow the pinned upstream Python Router.
Expand Down Expand Up @@ -58,7 +59,7 @@ public string Add(string mcp_server_name)
[McpServerTool(Name = "use_tool"), Description("Proxy an installed tool.")]
public CallToolResult Use(string mcp_server_name, string mcp_tool_name, string @params)
{
state.UseTimestamps.Add(DateTimeOffset.UtcNow);
state.UseTimestamps.Add(Stopwatch.GetTimestamp());
state.Calls.Add("use:" + mcp_server_name + ":" + mcp_tool_name);
var serverOk = mcp_server_name == "weather-mcp" || state.SucceedUseServers.Contains(mcp_server_name);
var invalid = !serverOk || mcp_tool_name != "get_weather";
Expand Down
14 changes: 10 additions & 4 deletions src/OpenClaw.Tests/NacosRouterIntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Reflection;
using System.Text.Json;
using Microsoft.AspNetCore.Builder;
Expand Down Expand Up @@ -296,10 +297,15 @@ public async Task DynamicSlot_UseToolFailureRetries_ThenFallsBack(bool maf)
Assert.Equal(new[] { "search", "add:weather-mcp", "use:weather-mcp:get_weather", "use:weather-mcp:get_weather", "use:weather-mcp:get_weather" }, state.Calls);
var timestamps = state.UseTimestamps;
Assert.Equal(3, timestamps.Count);
Assert.True((timestamps[1] - timestamps[0]).TotalMilliseconds >= 100,
$"expected >= 100 ms backoff between attempts 1 and 2, got {(timestamps[1] - timestamps[0]).TotalMilliseconds:0} ms");
Assert.True((timestamps[2] - timestamps[1]).TotalMilliseconds >= 100,
$"expected >= 100 ms backoff between attempts 2 and 3, got {(timestamps[2] - timestamps[1]).TotalMilliseconds:0} ms");
const double configuredBackoffMilliseconds = 100;
const double timerToleranceMilliseconds = 10;
for (var attempt = 1; attempt < timestamps.Count; attempt++)
{
var elapsed = Stopwatch.GetElapsedTime(timestamps[attempt - 1], timestamps[attempt]).TotalMilliseconds;
Assert.True(elapsed >= configuredBackoffMilliseconds - timerToleranceMilliseconds,
$"expected approximately {configuredBackoffMilliseconds:0} ms backoff between attempts {attempt} and {attempt + 1}, " +
$"allowing {timerToleranceMilliseconds:0} ms timer tolerance; got {elapsed:0.000} ms");
}
var run = Assert.Single(session.MetaRunHistory);
var query = Assert.Single(run.StepResults, step => step.Id == "query");
Assert.Equal("capability_execution_failed", query.FailureCode);
Expand Down
Loading