68 lines
2.7 KiB
C#
68 lines
2.7 KiB
C#
using System.Text.Json.Nodes;
|
|
using backend.Conversations;
|
|
using backend.Data;
|
|
using backend.Realtime;
|
|
using backend.Tools;
|
|
using FluentAssertions;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Xunit;
|
|
|
|
namespace backend.tests;
|
|
|
|
public class RealtimeSessionToolsTests(ApiFactory factory) : IClassFixture<ApiFactory>
|
|
{
|
|
private readonly ApiFactory _factory = factory;
|
|
|
|
[Fact]
|
|
public async Task Get_current_time_call_returns_function_call_output_and_persists_tool_turn()
|
|
{
|
|
using var scope = _factory.Services.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
var log = scope.ServiceProvider.GetRequiredService<ConversationLog>();
|
|
var reg = new ToolRegistry(new ITool[] { new GetCurrentTimeTool() });
|
|
var upstream = new ScriptedRealtimeUpstream();
|
|
var sink = new RecordingSink();
|
|
var cfg = new RealtimeSettings("m", "v", "p", 30, new HashSet<string> { "get_current_time" });
|
|
var session = new RealtimeSession(Guid.NewGuid(), upstream, sink, log, reg, cfg,
|
|
new FakeDeviceChannel(), NullLogger.Instance);
|
|
|
|
upstream.Push(new JsonObject { ["type"] = "session.updated" });
|
|
var cts = new CancellationTokenSource();
|
|
var run = session.RunAsync(cts.Token);
|
|
await sink.WaitForAsync("session_started", TimeSpan.FromSeconds(2));
|
|
|
|
upstream.Push(new JsonObject
|
|
{
|
|
["type"] = "response.function_call_arguments.done",
|
|
["call_id"] = "call_abc",
|
|
["name"] = "get_current_time",
|
|
["arguments"] = "{}",
|
|
});
|
|
upstream.Push(new JsonObject { ["type"] = "response.done" });
|
|
|
|
var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(2);
|
|
while (DateTime.UtcNow < deadline && !upstream.Sent.Any(e =>
|
|
(string?)e["type"] == "conversation.item.create"))
|
|
{
|
|
await Task.Delay(20);
|
|
}
|
|
|
|
var item = upstream.Sent.First(e => (string?)e["type"] == "conversation.item.create");
|
|
((string?)item["item"]!["type"]).Should().Be("function_call_output");
|
|
((string?)item["item"]!["call_id"]).Should().Be("call_abc");
|
|
((string?)item["item"]!["output"]).Should().Contain("\"now\"");
|
|
|
|
upstream.Sent.Should().Contain(e => (string?)e["type"] == "response.create");
|
|
|
|
var convoId = session.ConversationId!.Value;
|
|
var toolTurn = await db.Turns.FirstAsync(t =>
|
|
t.ConversationId == convoId && t.Role == TurnRole.Tool);
|
|
toolTurn.ToolName.Should().Be("get_current_time");
|
|
toolTurn.ToolResultJson.Should().Contain("\"now\"");
|
|
|
|
cts.Cancel();
|
|
await run;
|
|
}
|
|
}
|