Skip to content

Commit 8961c7a

Browse files
authored
Merge pull request #910 from hchen2020/master
add welcome for realtime
2 parents 051df93 + e3036ef commit 8961c7a

File tree

6 files changed

+61
-15
lines changed

6 files changed

+61
-15
lines changed

src/Infrastructure/BotSharp.Abstraction/MLTasks/IRealTimeCompletion.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ Task Connect(RealtimeHubConnection conn,
2626
Task<RealtimeSession> CreateSession(Agent agent, List<RoleDialogModel> conversations);
2727
Task UpdateSession(RealtimeHubConnection conn);
2828
Task InsertConversationItem(RoleDialogModel message);
29+
Task RemoveConversationItem(string itemId);
2930
Task TriggerModelInference(string? instructions = null);
31+
Task CancelModelResponse();
3032
Task<List<RoleDialogModel>> OnResponsedDone(RealtimeHubConnection conn, string response);
3133
Task<RoleDialogModel> OnConversationItemCreated(RealtimeHubConnection conn, string response);
3234
}

src/Infrastructure/BotSharp.Core/Realtime/RealtimeHub.cs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using BotSharp.Abstraction.Realtime.Models;
44
using BotSharp.Abstraction.MLTasks;
55
using BotSharp.Abstraction.Conversations.Enums;
6+
using BotSharp.Abstraction.Routing.Models;
67

78
namespace BotSharp.Core.Realtime;
89

@@ -97,7 +98,7 @@ await completer.Connect(conn,
9798

9899
if (dialogs.LastOrDefault()?.Role == AgentRole.Assistant)
99100
{
100-
// await completer.TriggerModelInference($"Rephase your last response:\r\n{dialogs.LastOrDefault()?.Content}");
101+
await completer.TriggerModelInference($"Rephase your last response:\r\n{dialogs.LastOrDefault()?.Content}");
101102
}
102103
else
103104
{
@@ -127,19 +128,32 @@ await completer.Connect(conn,
127128
{
128129
await routing.InvokeFunction(message.FunctionName, message);
129130
message.Role = AgentRole.Function;
130-
if (message.FunctionName == "route_to_agent" ||
131-
message.FunctionName == "util-routing-fallback_to_router")
131+
132+
if (message.FunctionName == "route_to_agent")
132133
{
133-
var routedAgentId = routing.Context.GetCurrentAgentId();
134-
if (conn.CurrentAgentId != routedAgentId)
135-
{
136-
conn.CurrentAgentId = routedAgentId;
137-
await completer.UpdateSession(conn);
138-
}
134+
var inst = JsonSerializer.Deserialize<RoutingArgs>(message.FunctionArgs ?? "{}");
135+
message.Content = $"Connected to agent of {inst.AgentName}";
136+
conn.CurrentAgentId = routing.Context.GetCurrentAgentId();
137+
138+
await completer.UpdateSession(conn);
139+
await completer.InsertConversationItem(message);
140+
await completer.TriggerModelInference($"Continue to proceed user request in {inst.AgentName}.");
139141
}
142+
else if (message.FunctionName == "util-routing-fallback_to_router")
143+
{
144+
var inst = JsonSerializer.Deserialize<FallbackArgs>(message.FunctionArgs ?? "{}");
145+
message.Content = $"Returned to Router due to {inst.Reason}";
146+
conn.CurrentAgentId = routing.Context.GetCurrentAgentId();
140147

141-
await completer.InsertConversationItem(message);
142-
await completer.TriggerModelInference("Reply based on the function's output.");
148+
await completer.UpdateSession(conn);
149+
await completer.InsertConversationItem(message);
150+
await completer.TriggerModelInference("Reply user request.");
151+
}
152+
else
153+
{
154+
await completer.InsertConversationItem(message);
155+
await completer.TriggerModelInference("Reply based on the function's output.");
156+
}
143157
}
144158
else
145159
{

src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/route_to_agent.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@
2626
"description": "Required parameters of next action agent"
2727
}
2828
},
29-
"required": [ "next_action_agent", "user_goal_agent", "args" ]
29+
"required": [ "next_action_agent", "user_goal_agent", "next_action_reason", "args" ]
3030
}
3131
}

src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instructions/instruction.liquid

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ Follow these steps to handle user request:
55
2. Determine which agent is suitable to handle this conversation. Try to minimize the routing of human service.
66
3. Extract and populate agent required arguments, think carefully, leave it as blank object if user didn't provide the specific arguments.
77
4. You must include all required args for the selected agent, but you must not make up any parameters when there is no exact value provided, those parameters must set value as null if not declared.
8+
{% if routing_mode != 'lazy' %}
89
5. Response must be in JSON format.
10+
{% endif %}
911

1012
{% if routing_requirements and routing_requirements != empty %}
1113
[REQUIREMENTS]

src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-routing-fallback_to_router.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@
1313
"description": "User question or statement."
1414
}
1515
},
16-
"required": [ "user_question" ]
16+
"required": [ "fallback_reason" ]
1717
}
1818
}

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,23 @@ await SendEventToModel(new
102102
});
103103
}
104104

105+
public async Task CancelModelResponse()
106+
{
107+
await SendEventToModel(new
108+
{
109+
type = "response.cancel"
110+
});
111+
}
112+
113+
public async Task RemoveConversationItem(string itemId)
114+
{
115+
await SendEventToModel(new
116+
{
117+
type = "conversation.item.delete",
118+
item_id = itemId
119+
});
120+
}
121+
105122
private async Task ReceiveMessage(RealtimeHubConnection conn,
106123
Action<string> onModelAudioDeltaReceived,
107124
Action onModelAudioResponseDone,
@@ -169,7 +186,6 @@ private async Task ReceiveMessage(RealtimeHubConnection conn,
169186
else if (response.Type == "response.done")
170187
{
171188
_logger.LogInformation($"{response.Type}: {receivedText}");
172-
await Task.Delay(1000);
173189
var messages = await OnResponsedDone(conn, receivedText);
174190
onModelResponseDone(messages);
175191
}
@@ -296,7 +312,13 @@ public async Task UpdateSession(RealtimeHubConnection conn)
296312
ToolChoice = "auto",
297313
Tools = functions,
298314
Modalities = [ "text", "audio" ],
299-
Temperature = Math.Max(options.Temperature ?? 0f, 0.6f)
315+
Temperature = Math.Max(options.Temperature ?? 0f, 0.6f),
316+
MaxResponseOutputTokens = 512,
317+
TurnDetection = new RealtimeSessionTurnDetection
318+
{
319+
Threshold = 0.8f,
320+
SilenceDuration = 800
321+
}
300322
}
301323
};
302324

@@ -565,6 +587,11 @@ public async Task<List<RoleDialogModel>> OnResponsedDone(RealtimeHubConnection c
565587
var outputs = new List<RoleDialogModel>();
566588

567589
var data = JsonSerializer.Deserialize<ResponseDone>(response).Body;
590+
if (data.Status != "completed")
591+
{
592+
return [];
593+
}
594+
568595
foreach (var output in data.Outputs)
569596
{
570597
if (output.Type == "function_call")
@@ -575,6 +602,7 @@ public async Task<List<RoleDialogModel>> OnResponsedDone(RealtimeHubConnection c
575602
FunctionName = output.Name,
576603
FunctionArgs = output.Arguments,
577604
ToolCallId = output.CallId,
605+
MessageId = output.Id,
578606
MessageType = MessageTypeName.FunctionCall
579607
});
580608
}

0 commit comments

Comments
 (0)