Skip to content

add welcome for realtime #910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 1, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ Task Connect(RealtimeHubConnection conn,
Task<RealtimeSession> CreateSession(Agent agent, List<RoleDialogModel> conversations);
Task UpdateSession(RealtimeHubConnection conn);
Task InsertConversationItem(RoleDialogModel message);
Task RemoveConversationItem(string itemId);
Task TriggerModelInference(string? instructions = null);
Task CancelModelResponse();
Task<List<RoleDialogModel>> OnResponsedDone(RealtimeHubConnection conn, string response);
Task<RoleDialogModel> OnConversationItemCreated(RealtimeHubConnection conn, string response);
}
36 changes: 25 additions & 11 deletions src/Infrastructure/BotSharp.Core/Realtime/RealtimeHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using BotSharp.Abstraction.Realtime.Models;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Conversations.Enums;
using BotSharp.Abstraction.Routing.Models;

namespace BotSharp.Core.Realtime;

Expand Down Expand Up @@ -97,7 +98,7 @@ await completer.Connect(conn,

if (dialogs.LastOrDefault()?.Role == AgentRole.Assistant)
{
// await completer.TriggerModelInference($"Rephase your last response:\r\n{dialogs.LastOrDefault()?.Content}");
await completer.TriggerModelInference($"Rephase your last response:\r\n{dialogs.LastOrDefault()?.Content}");
}
else
{
Expand Down Expand Up @@ -127,19 +128,32 @@ await completer.Connect(conn,
{
await routing.InvokeFunction(message.FunctionName, message);
message.Role = AgentRole.Function;
if (message.FunctionName == "route_to_agent" ||
message.FunctionName == "util-routing-fallback_to_router")

if (message.FunctionName == "route_to_agent")
{
var routedAgentId = routing.Context.GetCurrentAgentId();
if (conn.CurrentAgentId != routedAgentId)
{
conn.CurrentAgentId = routedAgentId;
await completer.UpdateSession(conn);
}
var inst = JsonSerializer.Deserialize<RoutingArgs>(message.FunctionArgs ?? "{}");
message.Content = $"Connected to agent of {inst.AgentName}";
conn.CurrentAgentId = routing.Context.GetCurrentAgentId();

await completer.UpdateSession(conn);
await completer.InsertConversationItem(message);
await completer.TriggerModelInference($"Continue to proceed user request in {inst.AgentName}.");
}
else if (message.FunctionName == "util-routing-fallback_to_router")
{
var inst = JsonSerializer.Deserialize<FallbackArgs>(message.FunctionArgs ?? "{}");
message.Content = $"Returned to Router due to {inst.Reason}";
conn.CurrentAgentId = routing.Context.GetCurrentAgentId();

await completer.InsertConversationItem(message);
await completer.TriggerModelInference("Reply based on the function's output.");
await completer.UpdateSession(conn);
await completer.InsertConversationItem(message);
await completer.TriggerModelInference("Reply user request.");
}
else
{
await completer.InsertConversationItem(message);
await completer.TriggerModelInference("Reply based on the function's output.");
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
"description": "Required parameters of next action agent"
}
},
"required": [ "next_action_agent", "user_goal_agent", "args" ]
"required": [ "next_action_agent", "user_goal_agent", "next_action_reason", "args" ]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ Follow these steps to handle user request:
2. Determine which agent is suitable to handle this conversation. Try to minimize the routing of human service.
3. Extract and populate agent required arguments, think carefully, leave it as blank object if user didn't provide the specific arguments.
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.
{% if routing_mode != 'lazy' %}
5. Response must be in JSON format.
{% endif %}

{% if routing_requirements and routing_requirements != empty %}
[REQUIREMENTS]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"description": "User question or statement."
}
},
"required": [ "user_question" ]
"required": [ "fallback_reason" ]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,23 @@ await SendEventToModel(new
});
}

public async Task CancelModelResponse()
{
await SendEventToModel(new
{
type = "response.cancel"
});
}

public async Task RemoveConversationItem(string itemId)
{
await SendEventToModel(new
{
type = "conversation.item.delete",
item_id = itemId
});
}

private async Task ReceiveMessage(RealtimeHubConnection conn,
Action<string> onModelAudioDeltaReceived,
Action onModelAudioResponseDone,
Expand Down Expand Up @@ -169,7 +186,6 @@ private async Task ReceiveMessage(RealtimeHubConnection conn,
else if (response.Type == "response.done")
{
_logger.LogInformation($"{response.Type}: {receivedText}");
await Task.Delay(1000);
var messages = await OnResponsedDone(conn, receivedText);
onModelResponseDone(messages);
}
Expand Down Expand Up @@ -296,7 +312,13 @@ public async Task UpdateSession(RealtimeHubConnection conn)
ToolChoice = "auto",
Tools = functions,
Modalities = [ "text", "audio" ],
Temperature = Math.Max(options.Temperature ?? 0f, 0.6f)
Temperature = Math.Max(options.Temperature ?? 0f, 0.6f),
MaxResponseOutputTokens = 512,
TurnDetection = new RealtimeSessionTurnDetection
{
Threshold = 0.8f,
SilenceDuration = 800
}
}
};

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

var data = JsonSerializer.Deserialize<ResponseDone>(response).Body;
if (data.Status != "completed")
{
return [];
}

foreach (var output in data.Outputs)
{
if (output.Type == "function_call")
Expand All @@ -575,6 +602,7 @@ public async Task<List<RoleDialogModel>> OnResponsedDone(RealtimeHubConnection c
FunctionName = output.Name,
FunctionArgs = output.Arguments,
ToolCallId = output.CallId,
MessageId = output.Id,
MessageType = MessageTypeName.FunctionCall
});
}
Expand Down
Loading