optimize ConversationHub · SciSharp/BotSharp@2103a20 · GitHub
Skip to content

Commit 2103a20

Browse files
committed
optimize ConversationHub
1 parent fa88e9d commit 2103a20

6 files changed

Lines changed: 58 additions & 58 deletions

File tree

‎src/Infrastructure/BotSharp.Core/Demo/Functions/GetFunEventsFn.cs‎

Lines changed: 2 additions & 2 deletions

‎src/Infrastructure/BotSharp.Core/Demo/Functions/GetWeatherFn.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public async Task<bool> Execute(RoleDialogModel message)
2828

2929
await Task.Delay(1000);
3030

31-
_services.PushIndication(message, $"Start querying weather data in {args?.City}");
31+
_services.GetHub().PushIndication(message, $"Start querying weather data in {args?.City}");
3232

3333
await Task.Delay(1500);
3434

@@ -43,7 +43,7 @@ public async Task<bool> Execute(RoleDialogModel message)
4343
});
4444
#endif
4545

46-
_services.PushIndication(message, $"Still working on it... Hold on, {args?.City}");
46+
_services.GetHub().PushIndication(message, $"Still working on it... Hold on, {args?.City}");
4747

4848
await Task.Delay(1500);
4949

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
namespace BotSharp.Core.MessageHub;
2+
3+
/// <summary>
4+
/// Pushing events into one conversation. The id is captured when the hub is taken, on the thread
5+
/// that asked for it -- a reporter running on a transport's own thread can keep this and push
6+
/// without resolving a scoped service again. Don't hold one past the conversation it was taken for.
7+
/// </summary>
8+
public sealed class ConversationHub
9+
{
10+
private readonly MessageHub<HubObserveData<RoleDialogModel>> _hub;
11+
12+
internal ConversationHub(MessageHub<HubObserveData<RoleDialogModel>> hub, string? conversationId)
13+
{
14+
_hub = hub;
15+
ConversationId = conversationId;
16+
}
17+
18+
/// <summary>Where every push goes; null when taken outside a conversation.</summary>
19+
public string? ConversationId { get; }
20+
21+
/// <summary>
22+
/// Raise the "working on it" line in chat. <paramref name="message"/> is pushed as-is and its
23+
/// <c>Indication</c> overwritten, so clone it when the original is still in use by a call in flight.
24+
/// </summary>
25+
public void PushIndication(RoleDialogModel message, string? indication)
26+
{
27+
// Nothing to announce, or no one to announce it to: subscribers match on RefId.
28+
if (string.IsNullOrWhiteSpace(indication) || string.IsNullOrWhiteSpace(ConversationId))
29+
{
30+
return;
31+
}
32+
33+
message.Indication = indication;
34+
35+
_hub.Push(new()
36+
{
37+
EventName = ChatEvent.OnIndicationReceived,
38+
Data = message,
39+
RefId = ConversationId
40+
});
41+
}
42+
}
Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,14 @@
11
namespace BotSharp.Core.MessageHub;
22

3-
/// <summary>
4-
/// Raising the "working on it" line in chat.
5-
/// </summary>
63
public static class MessageHubExtensions
74
{
85
/// <summary>
9-
/// Announce <paramref name="indication"/> in the conversation this call is running in.
10-
/// <paramref name="message"/> is pushed as-is and its <c>Indication</c> overwritten, so clone it
11-
/// when the original is still in use by a call in flight.
6+
/// The hub bound to the conversation this call is running in.
127
/// </summary>
13-
public static void PushIndication(this IServiceProvider services, RoleDialogModel message, string? indication)
8+
public static ConversationHub GetHub(this IServiceProvider services)
149
{
1510
var conv = services.GetRequiredService<IConversationService>();
1611
var hub = services.GetRequiredService<MessageHub<HubObserveData<RoleDialogModel>>>();
17-
hub.PushIndication(message, indication, conv.ConversationId);
18-
}
19-
20-
/// <summary>
21-
/// The same, for callers already holding both -- a thread where resolving a scoped service to
22-
/// ask for the conversation id would be a race.
23-
/// </summary>
24-
public static void PushIndication(
25-
this MessageHub<HubObserveData<RoleDialogModel>> hub,
26-
RoleDialogModel message,
27-
string? indication,
28-
string? conversationId)
29-
{
30-
// Nothing to announce, or no one to announce it to: subscribers match on RefId.
31-
if (string.IsNullOrWhiteSpace(indication) || string.IsNullOrWhiteSpace(conversationId))
32-
{
33-
return;
34-
}
35-
36-
message.Indication = indication;
37-
38-
hub.Push(new()
39-
{
40-
EventName = ChatEvent.OnIndicationReceived,
41-
Data = message,
42-
RefId = conversationId
43-
});
12+
return new ConversationHub(hub, conv.ConversationId);
4413
}
4514
}

‎src/Infrastructure/BotSharp.Core/Routing/Executor/MCPToolExecutor.cs‎

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,12 @@ public Task<string> GetIndicatorAsync(RoleDialogModel message)
8787
/// </summary>
8888
private sealed class ToolProgressIndicator : IProgress<ProgressNotificationValue>
8989
{
90-
private readonly MessageHub<HubObserveData<RoleDialogModel>> _hub;
91-
private readonly string _conversationId;
90+
private readonly ConversationHub _hub;
9291
private readonly RoleDialogModel _message;
9392

94-
private ToolProgressIndicator(
95-
MessageHub<HubObserveData<RoleDialogModel>> hub,
96-
string conversationId,
97-
RoleDialogModel message)
93+
private ToolProgressIndicator(ConversationHub hub, RoleDialogModel message)
9894
{
9995
_hub = hub;
100-
_conversationId = conversationId;
10196
_message = message;
10297
}
10398

@@ -106,22 +101,16 @@ private ToolProgressIndicator(
106101
/// tool invoked outside one, from a task or a test. Null is the right answer there rather
107102
/// than a reporter that drops everything: it also tells the server not to bother sending.
108103
/// <para>
109-
/// The conversation id is read HERE, on the thread that starts the call, and captured.
110-
/// <see cref="Report"/> runs on whichever thread the MCP transport is reading on, and
111-
/// resolving a scoped service from there to ask again would be a race for a value that
104+
/// The hub is taken HERE, on the thread that starts the call, so it carries the conversation
105+
/// id with it. <see cref="Report"/> runs on whichever thread the MCP transport is reading on,
106+
/// and resolving a scoped service from there to ask again would be a race for a value that
112107
/// cannot change during the call.
113108
/// </para>
114109
/// </summary>
115110
public static ToolProgressIndicator? For(IServiceProvider services, RoleDialogModel message)
116111
{
117-
var conversationId = services.GetRequiredService<IConversationService>().ConversationId;
118-
if (string.IsNullOrWhiteSpace(conversationId))
119-
{
120-
return null;
121-
}
122-
123-
var hub = services.GetRequiredService<MessageHub<HubObserveData<RoleDialogModel>>>();
124-
return new ToolProgressIndicator(hub, conversationId, message);
112+
var hub = services.GetHub();
113+
return string.IsNullOrWhiteSpace(hub.ConversationId) ? null : new ToolProgressIndicator(hub, message);
125114
}
126115

127116
/// <summary>
@@ -145,7 +134,7 @@ public void Report(ProgressNotificationValue value)
145134

146135
// Cloned: this is pushed to observers that read it, and the function's own message is
147136
// still being used by the call in flight. Its indication is not ours to overwrite.
148-
_hub.PushIndication(RoleDialogModel.From(_message), value.Message, _conversationId);
137+
_hub.PushIndication(RoleDialogModel.From(_message), value.Message);
149138
}
150139
}
151140

‎src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs‎

Lines changed: 1 addition & 1 deletion

0 commit comments

Comments
 (0)