Skip to content

Commit 9b2524a

Browse files
Merge pull request #171 from Deep-Blue-2013/master
Add IContentGeneratingHook.
2 parents 60a2131 + 8531d8a commit 9b2524a

File tree

25 files changed

+391
-141
lines changed

25 files changed

+391
-141
lines changed

docs/architecture/hooks.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,40 @@
55
## Agent Hook
66
`IAgentHook`
77
```csharp
8+
// Triggered when agent is loading.
89
bool OnAgentLoading(ref string id);
910
bool OnInstructionLoaded(string template, Dictionary<string, object> dict);
1011
bool OnFunctionsLoaded(List<FunctionDef> functions);
1112
bool OnSamplesLoaded(ref string samples);
12-
Agent OnAgentLoaded();
13+
14+
// Triggered when agent is loaded completely.
15+
void OnAgentLoaded(Agent agent);
1316
```
1417
More information about agent hook please go to [Agent Hook](../agent/hook.md).
1518

1619
## Conversation Hook
1720
`IConversationHook`
1821
```csharp
22+
// Triggered once for every new conversation.
23+
Task OnConversationInitialized(Conversation conversation);
1924
Task OnDialogsLoaded(List<RoleDialogModel> dialogs);
20-
Task BeforeCompletion();
25+
Task OnMessageReceived(RoleDialogModel message);
26+
27+
// Triggered before LLM calls function.
2128
Task OnFunctionExecuting(RoleDialogModel message);
29+
30+
// Triggered when the function calling completed.
2231
Task OnFunctionExecuted(RoleDialogModel message);
23-
Task AfterCompletion(RoleDialogModel message);
32+
Task OnResponseGenerated(RoleDialogModel message);
33+
34+
// LLM detected the current task is completed.
35+
Task CurrentTaskEnding(RoleDialogModel conversation);
2436

2537
// LLM detected the user's intention to end the conversation
2638
Task ConversationEnding(RoleDialogModel conversation);
39+
40+
// LLM can't handle user's request or user requests human being to involve.
41+
Task HumanInterventionNeeded(RoleDialogModel conversation);
2742
```
2843
More information about conversation hook please go to [Conversation Hook](../conversation/hook.md).
2944

src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ public interface IAgentHook
88
void SetAget(Agent agent);
99

1010
/// <summary>
11-
/// Triggered before loading, you can change the returned id to switch agent.
11+
/// Triggered when agent is loading.
12+
/// Return different agent for redirection purpose.
1213
/// </summary>
1314
/// <param name="id">Agent Id</param>
1415
/// <returns></returns>
1516
bool OnAgentLoading(ref string id);
1617

17-
1818
bool OnInstructionLoaded(string template, Dictionary<string, object> dict);
1919

2020
bool OnFunctionsLoaded(List<FunctionDef> functions);

src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,23 @@ public virtual Task OnStateChanged(string name, string preValue, string currentV
3636
return Task.CompletedTask;
3737
}
3838

39-
public virtual Task BeforeCompletion(RoleDialogModel message)
39+
public virtual Task OnDialogsLoaded(List<RoleDialogModel> dialogs)
40+
{
41+
_dialogs = dialogs;
42+
return Task.CompletedTask;
43+
}
44+
45+
public virtual Task ConversationEnding(RoleDialogModel message)
46+
{
47+
return Task.CompletedTask;
48+
}
49+
50+
public virtual Task CurrentTaskEnding(RoleDialogModel conversation)
51+
{
52+
return Task.CompletedTask;
53+
}
54+
55+
public virtual Task HumanInterventionNeeded(RoleDialogModel conversation)
4056
{
4157
return Task.CompletedTask;
4258
}
@@ -51,18 +67,17 @@ public virtual Task OnFunctionExecuted(RoleDialogModel message)
5167
return Task.CompletedTask;
5268
}
5369

54-
public virtual Task AfterCompletion(RoleDialogModel message)
70+
public virtual Task OnMessageReceived(RoleDialogModel message)
5571
{
5672
return Task.CompletedTask;
5773
}
5874

59-
public virtual Task OnDialogsLoaded(List<RoleDialogModel> dialogs)
75+
public virtual Task OnResponseGenerated(RoleDialogModel message)
6076
{
61-
_dialogs = dialogs;
6277
return Task.CompletedTask;
6378
}
6479

65-
public virtual Task ConversationEnding(RoleDialogModel message)
80+
public virtual Task OnConversationInitialized(Conversation conversation)
6681
{
6782
return Task.CompletedTask;
6883
}

src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@ public interface IConversationHook
44
{
55
int Priority { get; }
66
Agent Agent { get; }
7+
List<RoleDialogModel> Dialogs { get; }
78
IConversationHook SetAgent(Agent agent);
89

910
Conversation Conversation { get; }
1011
IConversationHook SetConversation(Conversation conversation);
1112

12-
List<RoleDialogModel> Dialogs { get; }
1313
/// <summary>
14-
/// Triggered when dialog history is loaded
14+
/// Triggered once for every new conversation.
15+
/// </summary>
16+
/// <param name="conversation"></param>
17+
/// <returns></returns>
18+
Task OnConversationInitialized(Conversation conversation);
19+
20+
/// <summary>
21+
/// Triggered when dialog history is loaded.
1522
/// </summary>
1623
/// <param name="dialogs"></param>
1724
/// <returns></returns>
@@ -20,10 +27,43 @@ public interface IConversationHook
2027
Task OnStateLoaded(ConversationState state);
2128
Task OnStateChanged(string name, string preValue, string currentValue);
2229

23-
Task BeforeCompletion(RoleDialogModel message);
30+
Task OnMessageReceived(RoleDialogModel message);
31+
32+
/// <summary>
33+
/// Triggered before LLM calls function.
34+
/// </summary>
35+
/// <param name="message"></param>
36+
/// <returns></returns>
2437
Task OnFunctionExecuting(RoleDialogModel message);
38+
39+
/// <summary>
40+
/// Triggered when the function calling completed.
41+
/// </summary>
42+
/// <param name="message"></param>
43+
/// <returns></returns>
2544
Task OnFunctionExecuted(RoleDialogModel message);
26-
Task AfterCompletion(RoleDialogModel message);
2745

46+
Task OnResponseGenerated(RoleDialogModel message);
47+
48+
/// <summary>
49+
/// LLM detected the current task is completed.
50+
/// It's useful for the situation of multiple tasks in the same conversation.
51+
/// </summary>
52+
/// <param name="conversation"></param>
53+
/// <returns></returns>
54+
Task CurrentTaskEnding(RoleDialogModel conversation);
55+
56+
/// <summary>
57+
/// LLM detected the whole conversation is going to be end.
58+
/// </summary>
59+
/// <param name="conversation"></param>
60+
/// <returns></returns>
2861
Task ConversationEnding(RoleDialogModel conversation);
62+
63+
/// <summary>
64+
/// LLM can't handle user's request or user requests human being to involve.
65+
/// </summary>
66+
/// <param name="conversation"></param>
67+
/// <returns></returns>
68+
Task HumanInterventionNeeded(RoleDialogModel conversation);
2969
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace BotSharp.Abstraction.MLTasks;
2+
3+
/// <summary>
4+
/// Model content generating hook, it can be used for logging, metrics and tracing.
5+
/// </summary>
6+
public interface IContentGeneratingHook
7+
{
8+
/// <summary>
9+
/// Before content generating.
10+
/// </summary>
11+
/// <returns></returns>
12+
Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations) => Task.CompletedTask;
13+
14+
/// <summary>
15+
/// After content generated.
16+
/// </summary>
17+
/// <returns></returns>
18+
Task AfterGenerated(RoleDialogModel message, TokenStatsModel tokenStats) => Task.CompletedTask;
19+
}

src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task<bool> SendMessage(string agentId,
3232
hook.SetAgent(agent)
3333
.SetConversation(conversation);
3434

35-
await hook.BeforeCompletion(incoming);
35+
await hook.OnMessageReceived(incoming);
3636

3737
// Interrupted by hook
3838
if (incoming.StopCompletion)
@@ -79,14 +79,6 @@ private async Task<Conversation> GetConversationRecord(string agentId)
7979

8080
private async Task HandleAssistantMessage(RoleDialogModel message, Func<RoleDialogModel, Task> onMessageReceived)
8181
{
82-
var hooks = _services.GetServices<IConversationHook>().ToList();
83-
84-
// After chat completion hook
85-
foreach (var hook in hooks)
86-
{
87-
await hook.AfterCompletion(message);
88-
}
89-
9082
var routingSetting = _services.GetRequiredService<RoutingSettings>();
9183
var agentName = routingSetting.RouterId == message.CurrentAgentId ?
9284
"Router" :
@@ -101,6 +93,12 @@ private async Task HandleAssistantMessage(RoleDialogModel message, Func<RoleDial
10193
_logger.LogInformation(text);
10294
#endif
10395

96+
var hooks = _services.GetServices<IConversationHook>().ToList();
97+
foreach (var hook in hooks)
98+
{
99+
await hook.OnResponseGenerated(message);
100+
}
101+
104102
await onMessageReceived(message);
105103

106104
// Add to dialog history

src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using BotSharp.Abstraction.Conversations.Models;
12
using BotSharp.Abstraction.Repositories;
23

34
namespace BotSharp.Core.Conversations.Services;
@@ -64,6 +65,13 @@ public async Task<Conversation> NewConversation(Conversation sess)
6465
record.Title = "New Conversation";
6566

6667
db.CreateNewConversation(record);
68+
69+
var hooks = _services.GetServices<IConversationHook>().ToList();
70+
foreach (var hook in hooks)
71+
{
72+
await hook.OnConversationInitialized(record);
73+
}
74+
6775
return record;
6876
}
6977

src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallF
3232

3333
foreach (var hook in hooks)
3434
{
35-
await hook.OnFunctionExecuting(result);
35+
await hook.ConversationEnding(result);
3636
}
3737

3838
return result;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using BotSharp.Abstraction.Functions.Models;
2+
using BotSharp.Abstraction.Routing;
3+
using BotSharp.Abstraction.Routing.Settings;
4+
5+
namespace BotSharp.Core.Routing.Handlers;
6+
7+
public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandler
8+
{
9+
public string Name => "human_intervention_needed";
10+
11+
public string Description => "Reach out to a real human or customer representative.";
12+
13+
private readonly RoutingSettings _settings;
14+
15+
public HumanInterventionNeededHandler(IServiceProvider services, ILogger<HumanInterventionNeededHandler> logger, RoutingSettings settings)
16+
: base(services, logger, settings)
17+
{
18+
_settings = settings;
19+
}
20+
21+
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
22+
{
23+
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
24+
{
25+
CurrentAgentId = _settings.RouterId,
26+
FunctionName = inst.Function,
27+
ExecutionData = inst
28+
};
29+
30+
var hooks = _services.GetServices<IConversationHook>()
31+
.OrderBy(x => x.Priority)
32+
.ToList();
33+
34+
foreach (var hook in hooks)
35+
{
36+
await hook.HumanInterventionNeeded(result);
37+
}
38+
39+
return result;
40+
}
41+
}

src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,24 @@ public TaskEndRoutingHandler(IServiceProvider services, ILogger<TaskEndRoutingHa
2323
{
2424
}
2525

26-
public Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
26+
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
2727
{
28-
throw new NotImplementedException();
28+
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
29+
{
30+
CurrentAgentId = _settings.RouterId,
31+
FunctionName = inst.Function,
32+
ExecutionData = inst
33+
};
34+
35+
var hooks = _services.GetServices<IConversationHook>()
36+
.OrderBy(x => x.Priority)
37+
.ToList();
38+
39+
foreach (var hook in hooks)
40+
{
41+
await hook.CurrentTaskEnding(result);
42+
}
43+
44+
return result;
2945
}
3046
}

0 commit comments

Comments
 (0)