Skip to content

Commit bc40dee

Browse files
committed
tool call done; to do session restart
1 parent 04eafed commit bc40dee

11 files changed

Lines changed: 59 additions & 34 deletions

File tree

src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ public async Task OnFunctionExecuted(RoleDialogModel message)
4242
var routing = _services.GetRequiredService<IRoutingService>();
4343

4444
message.Role = AgentRole.Function;
45-
//message.Role = AgentRole.Assistant;
4645

4746
if (message.FunctionName == "route_to_agent")
4847
{
@@ -66,21 +65,24 @@ public async Task OnFunctionExecuted(RoleDialogModel message)
6665
else
6766
{
6867
// Update session for changed states
69-
var instruction = await hub.Completer.UpdateSession(hub.HubConn);
68+
69+
// TO DO
70+
//var instruction = await hub.Completer.UpdateSession(hub.HubConn);
7071
await hub.Completer.InsertConversationItem(message);
7172

7273
if (string.IsNullOrEmpty(message.Content))
7374
{
7475
return;
7576
}
76-
else if (message.StopCompletion)
77-
{
78-
await hub.Completer.TriggerModelInference($"Say to user: \"{message.Content}\"");
79-
}
80-
else
81-
{
82-
await hub.Completer.TriggerModelInference(instruction);
83-
}
77+
78+
//if (message.StopCompletion)
79+
//{
80+
// await hub.Completer.TriggerModelInference($"Say to user: \"{message.Content}\"");
81+
//}
82+
//else
83+
//{
84+
// await hub.Completer.TriggerModelInference();
85+
//}
8486
}
8587
}
8688
}

src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public void RegisterDI(IServiceCollection services, IConfiguration config)
4141
return settingService.Bind<GoogleApiSettings>("GoogleApi");
4242
});
4343

44+
services.AddScoped<ConversationHookProvider>();
4445
services.AddScoped<IConversationStorage, ConversationStorage>();
4546
services.AddScoped<IConversationService, ConversationService>();
4647
services.AddScoped<IConversationProgressService, ConversationProgressService>();

src/Infrastructure/BotSharp.Core/Session/LlmRealtimeSession.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ public async Task DisconnectAsync()
106106

107107
public void Dispose()
108108
{
109+
_clientEventSemaphore?.Dispose();
109110
_webSocket?.Dispose();
110111
}
111112
}

src/Infrastructure/BotSharp.Core/Statistics/Services/BotSharpStatsService.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using BotSharp.Abstraction.Infrastructures;
21
using BotSharp.Abstraction.Statistics.Settings;
32

43
namespace BotSharp.Core.Statistics.Services;

src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ public void RegisterDI(IServiceCollection services, IConfiguration config)
2424
services.AddScoped<IConversationHook, ChatHubConversationHook>();
2525
services.AddScoped<IConversationHook, StreamingLogHook>();
2626
services.AddScoped<IConversationHook, WelcomeHook>();
27-
services.AddScoped<ConversationHookProvider>();
2827
services.AddScoped<IRoutingHook, StreamingLogHook>();
2928
services.AddScoped<IContentGeneratingHook, StreamingLogHook>();
3029
services.AddScoped<ICrontabHook, ChatHubCrontabHook>();

src/Plugins/BotSharp.Plugin.GoogleAI/Models/Realtime/RealtimeGenerateContentSetup.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ internal class RealtimeGenerateContentSetup
2121

2222
[JsonPropertyName("outputAudioTranscription")]
2323
public AudioTranscriptionConfig? OutputAudioTranscription { get; set; }
24+
25+
[JsonPropertyName("sessionResumption")]
26+
public SessionResumptionConfig? SessionResumption { get; set; }
2427
}
2528

26-
internal class AudioTranscriptionConfig { }
29+
internal class AudioTranscriptionConfig { }
30+
31+
internal class SessionResumptionConfig
32+
{
33+
[JsonPropertyName("handle")]
34+
public string? Handle { get; set; }
35+
}

src/Plugins/BotSharp.Plugin.GoogleAI/Models/Realtime/RealtimeServerResponse.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ internal class RealtimeServerResponse
1515

1616
[JsonPropertyName("toolCall")]
1717
public RealtimeToolCall? ToolCall { get; set; }
18+
19+
[JsonPropertyName("sessionResumptionUpdate")]
20+
public RealtimeSessionResumptionUpdate? SessionResumptionUpdate { get; set; }
1821
}
1922

2023

@@ -91,4 +94,13 @@ internal class RealtimeFunctionCall
9194

9295
[JsonPropertyName("args")]
9396
public JsonNode? Args { get; set; }
97+
}
98+
99+
internal class RealtimeSessionResumptionUpdate
100+
{
101+
[JsonPropertyName("newHandle")]
102+
public string? NewHandle { get; set; }
103+
104+
[JsonPropertyName("resumable")]
105+
public bool? Resumable { get; set; }
94106
}

src/Plugins/BotSharp.Plugin.GoogleAI/Models/Realtime/RealtimeTranscriptionResponse.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public void Collect(string text)
2828
_contentStream.Position = 0;
2929
}
3030

31-
public string GetString()
31+
public string GetText()
3232
{
3333
if (_contentStream.Length == 0)
3434
{

src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Realtime/RealTimeCompletionProvider.cs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ private async Task ReceiveMessage(
113113
continue;
114114
}
115115

116-
Console.WriteLine($"Received text: {receivedText}");
117116
try
118117
{
119118
var response = JsonSerializer.Deserialize<RealtimeServerResponse>(receivedText, _jsonOptions);
@@ -126,10 +125,15 @@ private async Task ReceiveMessage(
126125
{
127126
_logger.LogInformation($"Session setup completed.");
128127
}
128+
else if (response.SessionResumptionUpdate != null)
129+
{
130+
_logger.LogInformation($"Session resumption update => New handle: {response.SessionResumptionUpdate.NewHandle}, Resumable: {response.SessionResumptionUpdate.Resumable}");
131+
}
129132
else if (response.ToolCall != null && !response.ToolCall.FunctionCalls.IsNullOrEmpty())
130133
{
131-
var functionCall = response.ToolCall.FunctionCalls.First();
132-
_logger.LogInformation($"Tool call received {functionCall.Name}({functionCall.Args?.ToJsonString(_jsonOptions) ?? string.Empty}).");
134+
var functionCall = response.ToolCall.FunctionCalls!.First();
135+
136+
_logger.LogInformation($"Tool call received: {functionCall.Name}({functionCall.Args?.ToJsonString(_jsonOptions) ?? string.Empty}).");
133137

134138
if (functionCall != null)
135139
{
@@ -154,7 +158,7 @@ private async Task ReceiveMessage(
154158
_logger.LogInformation($"Model audio delta received.");
155159

156160
// Handle input transcription
157-
var inputTranscription = inputStream.GetString();
161+
var inputTranscription = inputStream.GetText();
158162
if (!string.IsNullOrEmpty(inputTranscription))
159163
{
160164
var message = OnUserAudioTranscriptionCompleted(conn, inputTranscription);
@@ -182,7 +186,8 @@ private async Task ReceiveMessage(
182186
{
183187
_logger.LogInformation($"Model turn completed.");
184188

185-
var outputTranscription = outputStream.GetString();
189+
// Handle output transcription
190+
var outputTranscription = outputStream.GetText();
186191
if (!string.IsNullOrEmpty(outputTranscription))
187192
{
188193
var messages = await OnResponseDone(conn, outputTranscription, response.UsageMetaData);
@@ -237,13 +242,13 @@ await SendEventToModel(new BidiClientPayload
237242

238243
public async Task TriggerModelInference(string? instructions = null)
239244
{
240-
var content = new Content("Please respond to me.", AgentRole.User);
245+
var content = new Content(instructions ?? "Please respond to user.", AgentRole.User);
241246

242247
await SendEventToModel(new BidiClientPayload
243248
{
244249
ClientContent = new()
245250
{
246-
Turns = null,
251+
Turns = [content],
247252
TurnComplete = true
248253
}
249254
});
@@ -269,9 +274,10 @@ public async Task SendEventToModel(object message)
269274
public async Task<string> UpdateSession(RealtimeHubConnection conn, bool isInit = false)
270275
{
271276
var convService = _services.GetRequiredService<IConversationService>();
272-
var conv = await convService.GetConversation(conn.ConversationId);
273-
274277
var agentService = _services.GetRequiredService<IAgentService>();
278+
var realtimeSetting = _services.GetRequiredService<RealtimeModelSettings>();
279+
280+
var conv = await convService.GetConversation(conn.ConversationId);
275281
var agent = await agentService.LoadAgent(conn.CurrentAgentId);
276282

277283
var (prompt, request) = PrepareOptions(agent, []);
@@ -285,10 +291,8 @@ public async Task<string> UpdateSession(RealtimeHubConnection conn, bool isInit
285291
var words = new List<string>();
286292
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
287293

288-
var realtimeModelSettings = _services.GetRequiredService<RealtimeModelSettings>();
289-
290-
config.Temperature = Math.Max(realtimeModelSettings.Temperature, 0.6f);
291-
config.MaxOutputTokens = realtimeModelSettings.MaxResponseOutputTokens;
294+
config.Temperature = Math.Max(realtimeSetting.Temperature, 0.6f);
295+
config.MaxOutputTokens = realtimeSetting.MaxResponseOutputTokens;
292296
}
293297

294298
var functions = request.Tools?.SelectMany(s => s.FunctionDeclarations).Select(x =>
@@ -316,7 +320,6 @@ await HookEmitter.Emit<IContentGeneratingHook>(_services,
316320
});
317321
}
318322

319-
var realtimeSetting = _services.GetRequiredService<RealtimeModelSettings>();
320323
await SendEventToModel(new RealtimeClientPayload
321324
{
322325
Setup = new RealtimeGenerateContentSetup()
@@ -326,7 +329,8 @@ await SendEventToModel(new RealtimeClientPayload
326329
SystemInstruction = request.SystemInstruction,
327330
Tools = request.Tools?.ToArray(),
328331
InputAudioTranscription = realtimeSetting.InputAudioTranscribe ? new() : null,
329-
OutputAudioTranscription = realtimeSetting.InputAudioTranscribe ? new() : null
332+
OutputAudioTranscription = realtimeSetting.InputAudioTranscribe ? new() : null,
333+
SessionResumption = new()
330334
}
331335
});
332336

@@ -339,6 +343,7 @@ public async Task InsertConversationItem(RoleDialogModel message)
339343
{
340344
var function = new FunctionResponse()
341345
{
346+
Id = message.ToolCallId,
342347
Name = message.FunctionName ?? string.Empty,
343348
Response = new JsonObject()
344349
{

src/Plugins/BotSharp.Plugin.OpenAI/Providers/Realtime/RealTimeCompletionProvider.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ await _session.ConnectAsync(
6565
cancellationToken: CancellationToken.None);
6666

6767
_ = ReceiveMessage(
68-
_services,
68+
realtimeSettings,
6969
conn,
7070
onModelReady,
7171
onModelAudioDeltaReceived,
@@ -144,7 +144,7 @@ await SendEventToModel(new
144144
}
145145

146146
private async Task ReceiveMessage(
147-
IServiceProvider services,
147+
RealtimeModelSettings realtimeSettings,
148148
RealtimeHubConnection conn,
149149
Func<Task> onModelReady,
150150
Func<string, string, Task> onModelAudioDeltaReceived,
@@ -156,7 +156,6 @@ private async Task ReceiveMessage(
156156
Func<Task> onInterruptionDetected)
157157
{
158158
DateTime? startTime = null;
159-
var realtimeSettings = _services.GetRequiredService<RealtimeModelSettings>();
160159

161160
await foreach (ChatSessionUpdate update in _session.ReceiveUpdatesAsync(CancellationToken.None))
162161
{

0 commit comments

Comments
 (0)