commit
330bbc33d7
|
|
@ -1,13 +1,10 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Hooks;
|
||||
|
||||
namespace BotSharp.Abstraction.Agents;
|
||||
|
||||
public interface IAgentHook
|
||||
public interface IAgentHook : IHookBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Agent Id
|
||||
/// </summary>
|
||||
string SelfId { get; }
|
||||
Agent Agent { get; }
|
||||
void SetAgent(Agent agent);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
|
||||
namespace BotSharp.Abstraction.Conversations;
|
||||
|
||||
public interface IConversationHook
|
||||
public interface IConversationHook : IHookBase
|
||||
{
|
||||
int Priority { get; }
|
||||
Agent Agent { get; }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
|
||||
namespace BotSharp.Abstraction.Crontab;
|
||||
|
||||
public interface ICrontabHook
|
||||
public interface ICrontabHook : IHookBase
|
||||
{
|
||||
string[]? Triggers
|
||||
=> null;
|
||||
|
|
|
|||
17
src/Infrastructure/BotSharp.Abstraction/Hooks/IHookBase.cs
Normal file
17
src/Infrastructure/BotSharp.Abstraction/Hooks/IHookBase.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BotSharp.Abstraction.Hooks
|
||||
{
|
||||
public interface IHookBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Agent Id
|
||||
/// </summary>
|
||||
string SelfId => string.Empty;
|
||||
bool IsMatch(string id) => string.IsNullOrEmpty(SelfId) || SelfId == id;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
using BotSharp.Abstraction.Instructs.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Instructs;
|
||||
|
||||
public interface IInstructHook
|
||||
public interface IInstructHook : IHookBase
|
||||
{
|
||||
string SelfId { get; }
|
||||
Task BeforeCompletion(Agent agent, RoleDialogModel message);
|
||||
Task AfterCompletion(Agent agent, InstructResult result);
|
||||
Task OnResponseGenerated(InstructResponseModel response);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Hooks;
|
||||
|
||||
namespace BotSharp.Abstraction.Loggers;
|
||||
|
||||
/// <summary>
|
||||
/// Model content generating hook, it can be used for logging, metrics and tracing.
|
||||
/// </summary>
|
||||
public interface IContentGeneratingHook
|
||||
public interface IContentGeneratingHook : IHookBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Before content generating.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
|
||||
namespace BotSharp.Abstraction.Planning;
|
||||
|
||||
public interface IPlanningHook
|
||||
public interface IPlanningHook : IHookBase
|
||||
{
|
||||
Task<string> GetSummaryAdditionalRequirements(string planner, RoleDialogModel message)
|
||||
=> Task.FromResult(string.Empty);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
|
||||
namespace BotSharp.Abstraction.Realtime;
|
||||
|
||||
public interface IRealtimeHook
|
||||
public interface IRealtimeHook : IHookBase
|
||||
{
|
||||
Task OnModelReady(Agent agent, IRealTimeCompletion completer);
|
||||
string[] OnModelTranscriptPrompt(Agent agent);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Hooks;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing;
|
||||
|
||||
public interface IRoutingHook
|
||||
public interface IRoutingHook : IHookBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Routing instruction is received from Router
|
||||
|
|
|
|||
|
|
@ -125,6 +125,6 @@ public class CrontabService : ICrontabService, ITaskFeeder
|
|||
await hook.OnCronTriggered(item);
|
||||
await hook.OnTaskExecuted(item);
|
||||
}
|
||||
});
|
||||
}, item.AgentId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ public class RealtimeHub : IRealtimeHub
|
|||
// Not TriggerModelInference, waiting for user utter.
|
||||
var instruction = await _completer.UpdateSession(_conn, isInit: true);
|
||||
var data = _conn.OnModelReady();
|
||||
await HookEmitter.Emit<IRealtimeHook>(_services, async hook => await hook.OnModelReady(agent, _completer));
|
||||
await HookEmitter.Emit<IRealtimeHook>(_services, async hook => await hook.OnModelReady(agent, _completer),
|
||||
agent.Id);
|
||||
await (init?.Invoke(data) ?? Task.CompletedTask);
|
||||
},
|
||||
onModelAudioDeltaReceived: async (audioDeltaData, itemId) =>
|
||||
|
|
@ -92,7 +93,8 @@ public class RealtimeHub : IRealtimeHub
|
|||
if (message.FunctionName == "route_to_agent")
|
||||
{
|
||||
var instruction = JsonSerializer.Deserialize<FunctionCallFromLlm>(message.FunctionArgs, BotSharpOptions.defaultJsonOptions);
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnRoutingInstructionReceived(instruction, message));
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnRoutingInstructionReceived(instruction, message),
|
||||
agent.Id);
|
||||
}
|
||||
|
||||
await routing.InvokeFunction(message.FunctionName, message);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using BotSharp.Abstraction.Infrastructures;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
|
@ -10,29 +11,12 @@ public partial class AgentService
|
|||
// [SharpCache(10, perInstanceCache: true)]
|
||||
public async Task<Agent> LoadAgent(string id, bool loadUtility = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString()) return null;
|
||||
|
||||
var hooks = _services.GetServices<IAgentHook>();
|
||||
|
||||
// Before agent is loaded.
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hook.OnAgentLoading(ref id);
|
||||
}
|
||||
HookEmitter.Emit<IAgentHook>(_services, hook => hook.OnAgentLoading(ref id), id);
|
||||
|
||||
var agent = await GetAgent(id);
|
||||
if (agent == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (agent == null) return null;
|
||||
|
||||
await InheritAgent(agent);
|
||||
OverrideInstructionByChannel(agent);
|
||||
|
|
@ -43,13 +27,7 @@ public partial class AgentService
|
|||
PopulateState(agent.TemplateDict);
|
||||
|
||||
// After agent is loaded
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
HookEmitter.Emit<IAgentHook>(_services, hook => {
|
||||
hook.SetAgent(agent);
|
||||
|
||||
if (!string.IsNullOrEmpty(agent.Instruction))
|
||||
|
|
@ -72,13 +50,14 @@ public partial class AgentService
|
|||
hook.OnAgentUtilityLoaded(agent);
|
||||
}
|
||||
|
||||
if(!agent.McpTools.IsNullOrEmpty())
|
||||
if (!agent.McpTools.IsNullOrEmpty())
|
||||
{
|
||||
hook.OnAgentMcpToolLoaded(agent);
|
||||
}
|
||||
|
||||
|
||||
hook.OnAgentLoaded(agent);
|
||||
}
|
||||
|
||||
}, id);
|
||||
|
||||
_logger.LogInformation($"Loaded agent {agent}.");
|
||||
|
||||
|
|
|
|||
|
|
@ -132,9 +132,8 @@ public partial class AgentService
|
|||
agent.TemplateDict[TemplateRenderConstant.RENDER_AGENT] = agent;
|
||||
var content = render.Render(template, agent.TemplateDict);
|
||||
|
||||
HookEmitter.Emit<IContentGeneratingHook>(_services, async hook =>
|
||||
await hook.OnRenderingTemplate(agent, templateName, content)
|
||||
).Wait();
|
||||
HookEmitter.Emit<IContentGeneratingHook>(_services, async hook => await hook.OnRenderingTemplate(agent, templateName, content),
|
||||
agent.Id).Wait();
|
||||
|
||||
return content;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,16 +158,14 @@ public partial class ConversationService
|
|||
// Emit conversation ending hook
|
||||
if (response.Instruction.ConversationEnd)
|
||||
{
|
||||
await HookEmitter.Emit<IConversationHook>(_services, async hook =>
|
||||
await hook.OnConversationEnding(response)
|
||||
);
|
||||
await HookEmitter.Emit<IConversationHook>(_services, async hook => await hook.OnConversationEnding(response),
|
||||
response.CurrentAgentId);
|
||||
response.FunctionName = "conversation_end";
|
||||
}
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IConversationHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(response)
|
||||
);
|
||||
await HookEmitter.Emit<IConversationHook>(_services, async hook => await hook.OnResponseGenerated(response),
|
||||
response.CurrentAgentId);
|
||||
|
||||
await onResponseReceived(response);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using BotSharp.Abstraction.Instructs.Models;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using System.IO;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
|
||||
namespace BotSharp.Core.Files.Services;
|
||||
|
||||
|
|
@ -24,14 +25,7 @@ public partial class FileInstructService
|
|||
}
|
||||
});
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = innerAgentId,
|
||||
|
|
@ -41,8 +35,7 @@ public partial class FileInstructService
|
|||
UserMessage = text,
|
||||
SystemInstruction = instruction,
|
||||
CompletionText = message.Content
|
||||
});
|
||||
}
|
||||
}), innerAgentId);
|
||||
|
||||
return message.Content;
|
||||
}
|
||||
|
|
@ -59,14 +52,7 @@ public partial class FileInstructService
|
|||
Instruction = instruction
|
||||
}, new RoleDialogModel(AgentRole.User, instruction ?? text));
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = innerAgentId,
|
||||
|
|
@ -76,8 +62,7 @@ public partial class FileInstructService
|
|||
UserMessage = text,
|
||||
SystemInstruction = instruction,
|
||||
CompletionText = message.Content
|
||||
});
|
||||
}
|
||||
}), innerAgentId);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
|
@ -104,14 +89,7 @@ public partial class FileInstructService
|
|||
|
||||
stream.Close();
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = innerAgentId,
|
||||
|
|
@ -119,8 +97,7 @@ public partial class FileInstructService
|
|||
Model = completion.Model,
|
||||
UserMessage = string.Empty,
|
||||
CompletionText = message.Content
|
||||
});
|
||||
}
|
||||
}), innerAgentId);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
|
@ -149,14 +126,7 @@ public partial class FileInstructService
|
|||
|
||||
stream.Close();
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = innerAgentId,
|
||||
|
|
@ -166,8 +136,7 @@ public partial class FileInstructService
|
|||
UserMessage = text,
|
||||
SystemInstruction = instruction,
|
||||
CompletionText = message.Content
|
||||
});
|
||||
}
|
||||
}), innerAgentId);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
|
@ -205,14 +174,7 @@ public partial class FileInstructService
|
|||
imageStream.Close();
|
||||
maskStream.Close();
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = innerAgentId,
|
||||
|
|
@ -222,8 +184,7 @@ public partial class FileInstructService
|
|||
UserMessage = text,
|
||||
SystemInstruction = instruction,
|
||||
CompletionText = message.Content
|
||||
});
|
||||
}
|
||||
}), innerAgentId);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using BotSharp.Abstraction.Files.Converters;
|
||||
using BotSharp.Abstraction.Instructs.Models;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
|
||||
namespace BotSharp.Core.Files.Services;
|
||||
|
||||
|
|
@ -42,14 +43,7 @@ public partial class FileInstructService
|
|||
}
|
||||
});
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = innerAgentId,
|
||||
|
|
@ -59,8 +53,7 @@ public partial class FileInstructService
|
|||
UserMessage = text,
|
||||
SystemInstruction = instruction,
|
||||
CompletionText = message.Content
|
||||
});
|
||||
}
|
||||
}), innerAgentId);
|
||||
|
||||
return message.Content;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
|
||||
namespace BotSharp.Core.Infrastructures;
|
||||
|
||||
public static class HookEmitter
|
||||
{
|
||||
public static HookEmittedResult Emit<T>(IServiceProvider services, Action<T> action, HookEmitOption<T>? option = null)
|
||||
public static HookEmittedResult Emit<T>(IServiceProvider services, Action<T> action, string agentId, HookEmitOption<T>? option = null) where T : IHookBase
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<T>>();
|
||||
var result = new HookEmittedResult();
|
||||
var hooks = services.GetServices<T>();
|
||||
var hooks = services.GetServices<T>().Where(p => p.IsMatch(agentId));
|
||||
option = option ?? new();
|
||||
|
||||
foreach (var hook in hooks)
|
||||
|
|
@ -35,11 +36,11 @@ public static class HookEmitter
|
|||
return result;
|
||||
}
|
||||
|
||||
public static async Task<HookEmittedResult> Emit<T>(IServiceProvider services, Func<T, Task> action, HookEmitOption<T>? option = null)
|
||||
public static async Task<HookEmittedResult> Emit<T>(IServiceProvider services, Func<T, Task> action, string agentId, HookEmitOption<T>? option = null) where T : IHookBase
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<T>>();
|
||||
var result = new HookEmittedResult();
|
||||
var hooks = services.GetServices<T>();
|
||||
var hooks = services.GetServices<T>().Where(p => p.IsMatch(agentId));
|
||||
option = option ?? new();
|
||||
|
||||
foreach (var hook in hooks)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Functions;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Instructs.Models;
|
||||
|
||||
|
|
@ -60,14 +61,7 @@ public class ExecuteTemplateFn : IFunctionCallback
|
|||
new(AgentRole.User, text)
|
||||
});
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = agent.Id,
|
||||
|
|
@ -76,8 +70,7 @@ public class ExecuteTemplateFn : IFunctionCallback
|
|||
Model = completion.Model,
|
||||
UserMessage = text,
|
||||
CompletionText = response.Content
|
||||
});
|
||||
}
|
||||
}), agent.Id);
|
||||
|
||||
return response.Content;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,14 +23,9 @@ public partial class InstructService
|
|||
}
|
||||
|
||||
// Trigger before completion hooks
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
var hooks = _services.GetServices<IInstructHook>().Where(p => p.IsMatch(agentId));
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await hook.BeforeCompletion(agent, message);
|
||||
|
||||
// Interrupted by hook
|
||||
|
|
@ -99,11 +94,6 @@ public partial class InstructService
|
|||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await hook.AfterCompletion(agent, response);
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@ public class InstructExecutor : IExecutor
|
|||
{
|
||||
inst.OriginalAgent = goalAgent;
|
||||
// Emit hook
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnRoutingInstructionRevised(inst, message)
|
||||
);
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnRoutingInstructionRevised(inst, message),
|
||||
message.CurrentAgentId);
|
||||
}
|
||||
|
||||
message.FunctionArgs = JsonSerializer.Serialize(inst);
|
||||
|
|
|
|||
|
|
@ -99,9 +99,8 @@ public class RoutingContext : IRoutingContext
|
|||
var preAgentId = _stack.Count == 0 ? agentId : _stack.Peek();
|
||||
_stack.Push(agentId);
|
||||
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnAgentEnqueued(agentId, preAgentId, reason: reason)
|
||||
).Wait();
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnAgentEnqueued(agentId, preAgentId, reason: reason),
|
||||
agentId).Wait();
|
||||
|
||||
UpdateLazyRoutingAgent(updateLazyRouting);
|
||||
}
|
||||
|
|
@ -120,9 +119,8 @@ public class RoutingContext : IRoutingContext
|
|||
var agentId = _stack.Pop();
|
||||
var currentAgentId = GetCurrentAgentId();
|
||||
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason)
|
||||
).Wait();
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason),
|
||||
agentId).Wait();
|
||||
|
||||
if (string.IsNullOrEmpty(currentAgentId))
|
||||
{
|
||||
|
|
@ -203,9 +201,8 @@ public class RoutingContext : IRoutingContext
|
|||
_stack.Pop();
|
||||
_stack.Push(agentId);
|
||||
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason)
|
||||
).Wait();
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason),
|
||||
agentId).Wait();
|
||||
}
|
||||
|
||||
UpdateLazyRoutingAgent(updateLazyRouting);
|
||||
|
|
@ -220,9 +217,8 @@ public class RoutingContext : IRoutingContext
|
|||
|
||||
var agentId = GetCurrentAgentId();
|
||||
_stack.Clear();
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnAgentQueueEmptied(agentId, reason: reason)
|
||||
).Wait();
|
||||
HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnAgentQueueEmptied(agentId, reason: reason),
|
||||
agentId).Wait();
|
||||
}
|
||||
|
||||
public void SetMessageId(string conversationId, string messageId)
|
||||
|
|
|
|||
|
|
@ -51,9 +51,8 @@ public partial class RoutingService
|
|||
int loopCount = 1;
|
||||
while (true)
|
||||
{
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnRoutingInstructionReceived(inst, message)
|
||||
);
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnRoutingInstructionReceived(inst, message),
|
||||
agent.Id);
|
||||
|
||||
// Save states
|
||||
states.SaveStateByArgs(inst.Arguments);
|
||||
|
|
|
|||
|
|
@ -345,7 +345,8 @@ public class ConversationController : ControllerBase
|
|||
};
|
||||
|
||||
await HookEmitter.Emit<IConversationHook>(_services, async hook =>
|
||||
await hook.OnNotificationGenerated(inputMsg)
|
||||
await hook.OnNotificationGenerated(inputMsg),
|
||||
routing.Context.GetCurrentAgentId()
|
||||
);
|
||||
|
||||
return response;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Files.Utilities;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Instructs.Models;
|
||||
using BotSharp.Core.Infrastructures;
|
||||
|
|
@ -58,14 +59,7 @@ public class InstructModeController : ControllerBase
|
|||
var textCompletion = CompletionProvider.GetTextCompletion(_services);
|
||||
var response = await textCompletion.GetCompletion(input.Text, agentId, Guid.NewGuid().ToString());
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = agentId,
|
||||
|
|
@ -74,8 +68,8 @@ public class InstructModeController : ControllerBase
|
|||
TemplateName = input.Template,
|
||||
UserMessage = input.Text,
|
||||
CompletionText = response
|
||||
});
|
||||
}
|
||||
}), agentId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
@ -103,14 +97,7 @@ public class InstructModeController : ControllerBase
|
|||
}
|
||||
});
|
||||
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
|
||||
await hook.OnResponseGenerated(new InstructResponseModel
|
||||
{
|
||||
AgentId = agentId,
|
||||
|
|
@ -120,8 +107,8 @@ public class InstructModeController : ControllerBase
|
|||
UserMessage = input.Text,
|
||||
SystemInstruction = message.RenderedInstruction,
|
||||
CompletionText = message.Content
|
||||
});
|
||||
}
|
||||
}), agentId);
|
||||
|
||||
return message.Content;
|
||||
}
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ public class GoogleRealTimeProvider : IRealTimeCompletion
|
|||
config.ResponseModalities = new List<Modality>([Modality.AUDIO]);
|
||||
|
||||
var words = new List<string>();
|
||||
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
|
||||
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)), agent.Id);
|
||||
|
||||
var realtimeModelSettings = _services.GetRequiredService<RealtimeModelSettings>();
|
||||
|
||||
|
|
@ -278,7 +278,7 @@ public class GoogleRealTimeProvider : IRealTimeCompletion
|
|||
}).ToArray();
|
||||
|
||||
await HookEmitter.Emit<IContentGeneratingHook>(_services,
|
||||
async hook => { await hook.OnSessionUpdated(agent, prompt, functions, isInit); });
|
||||
async hook => { await hook.OnSessionUpdated(agent, prompt, functions, isInit); }, agent.Id);
|
||||
|
||||
if (_settings.Gemini.UseGoogleSearch)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
|||
if (realtimeModelSettings.InputAudioTranscribe)
|
||||
{
|
||||
var words = new List<string>();
|
||||
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
|
||||
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)), agent.Id);
|
||||
|
||||
sessionUpdate.session.InputAudioTranscription = new InputAudioTranscription
|
||||
{
|
||||
|
|
@ -332,7 +332,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
|||
await HookEmitter.Emit<IContentGeneratingHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnSessionUpdated(agent, instruction, functions, isInit);
|
||||
});
|
||||
}, agent.Id);
|
||||
|
||||
await SendEventToModel(sessionUpdate);
|
||||
await Task.Delay(300);
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class SqlGenerationFn : IFunctionCallback
|
|||
{
|
||||
var requirement = await x.GetSummaryAdditionalRequirements(nameof(SqlGenerationPlanner), message);
|
||||
additionalRequirements.Add(requirement);
|
||||
});
|
||||
}, message.CurrentAgentId);
|
||||
|
||||
var globalKnowledges = new List<string>();
|
||||
foreach (var hook in knowledgeHooks)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ public class SqlReviewFn : IFunctionCallback
|
|||
if (args != null && !args.IsSqlTemplate && args.ContainsSqlStatements)
|
||||
{
|
||||
await HookEmitter.Emit<IPlanningHook>(_services, async hook =>
|
||||
await hook.OnSourceCodeGenerated(nameof(SqlGenerationPlanner), message, "sql")
|
||||
await hook.OnSourceCodeGenerated(nameof(SqlGenerationPlanner), message, "sql"),
|
||||
message.CurrentAgentId
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ public class SummaryPlanFn : IFunctionCallback
|
|||
message.Content = summary.Content;
|
||||
|
||||
await HookEmitter.Emit<IPlanningHook>(_services, async hook =>
|
||||
await hook.OnPlanningCompleted(nameof(TwoStageTaskPlanner), message)
|
||||
await hook.OnPlanningCompleted(nameof(TwoStageTaskPlanner), message),
|
||||
message.CurrentAgentId
|
||||
);
|
||||
|
||||
return true;
|
||||
|
|
@ -88,7 +89,7 @@ public class SummaryPlanFn : IFunctionCallback
|
|||
{
|
||||
var requirement = await x.GetSummaryAdditionalRequirements(nameof(TwoStageTaskPlanner), message);
|
||||
additionalRequirements.Add(requirement);
|
||||
});
|
||||
}, message.CurrentAgentId);
|
||||
|
||||
var globalKnowledges = new List<string>();
|
||||
foreach (var hook in knowledgeHooks)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class SqlDriverPlanningHook : IPlanningHook
|
|||
await HookEmitter.Emit<ISqlDriverHook>(_services, async (hook) =>
|
||||
{
|
||||
await hook.SqlGenerated(msg);
|
||||
});
|
||||
}, msg.CurrentAgentId);
|
||||
|
||||
var settings = _services.GetRequiredService<SqlDriverSetting>();
|
||||
if (!settings.ExecuteSqlSelectAutonomous)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
|
||||
namespace BotSharp.Plugin.SqlDriver.Interfaces;
|
||||
|
||||
public interface ISqlDriverHook
|
||||
public interface ISqlDriverHook : IHookBase
|
||||
{
|
||||
// Get database type
|
||||
string GetDatabaseType(RoleDialogModel message);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public class TwilioInboundController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnSessionCreating(request, instruction);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
var (agent, conversationId) = await InitConversation(request);
|
||||
request.ConversationId = conversationId.Id;
|
||||
|
|
@ -67,12 +67,8 @@ public class TwilioInboundController : TwilioController
|
|||
{
|
||||
response = new VoiceResponse();
|
||||
|
||||
var emitOptions = new HookEmitOption<ITwilioCallStatusHook>
|
||||
{
|
||||
ShouldExecute = hook => hook.IsMatch(request)
|
||||
};
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async hook => await hook.OnVoicemailStarting(request), emitOptions);
|
||||
async hook => await hook.OnVoicemailStarting(request), request.AgentId);
|
||||
|
||||
var url = twilio.GetSpeechPath(request.ConversationId, "voicemail.mp3");
|
||||
response.Play(new Uri(url));
|
||||
|
|
@ -123,7 +119,7 @@ public class TwilioInboundController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnSessionCreated(request);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
return TwiML(response);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,13 +33,8 @@ public class TwilioOutboundController : TwilioController
|
|||
if (twilio.MachineDetected(request))
|
||||
{
|
||||
response = new VoiceResponse();
|
||||
|
||||
var emitOptions = new HookEmitOption<ITwilioCallStatusHook>
|
||||
{
|
||||
ShouldExecute = hook => hook.IsMatch(request)
|
||||
};
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async hook => await hook.OnVoicemailStarting(request), emitOptions);
|
||||
async hook => await hook.OnVoicemailStarting(request), request.AgentId);
|
||||
|
||||
var url = twilio.GetSpeechPath(request.ConversationId, "voicemail.mp3");
|
||||
response.Play(new Uri(url));
|
||||
|
|
|
|||
|
|
@ -37,11 +37,7 @@ public class TwilioRecordController : TwilioController
|
|||
convService.SaveStates();
|
||||
|
||||
// recording completed
|
||||
var emitOptions = new HookEmitOption<ITwilioCallStatusHook>
|
||||
{
|
||||
ShouldExecute = hook => hook.IsMatch(request)
|
||||
};
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, x => x.OnRecordingCompleted(request), emitOptions);
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, x => x.OnRecordingCompleted(request), request.AgentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ public class TwilioTranscribeController : TwilioController
|
|||
|
||||
// transcription completed
|
||||
transcript.Language = request.LanguageCode;
|
||||
await HookEmitter.Emit<IRealtimeHook>(_services, async x => await x.OnTranscribeCompleted(message, transcript));
|
||||
await HookEmitter.Emit<IRealtimeHook>(_services, async x => await x.OnTranscribeCompleted(message, transcript),
|
||||
request.AgentId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnSessionCreating(request, instruction);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
if (string.IsNullOrWhiteSpace(request.Intent))
|
||||
|
|
@ -98,7 +98,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnSessionCreated(request);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
return TwiML(response);
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnReceivedUserMessage(request);
|
||||
});
|
||||
}, request.AgentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -161,7 +161,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnAgentHangUp(request);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
response = twilio.HangUp(string.Empty);
|
||||
}
|
||||
|
|
@ -185,7 +185,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnWaitingUserResponse(request, instruction);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
response = twilio.ReturnInstructions(instruction);
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ public class TwilioVoiceController : TwilioController
|
|||
{
|
||||
request.AIResponseErrorMessage = $"AI response timeout: AIResponseWaitTime greater than {request.AIResponseWaitTime}, please check internal error log!";
|
||||
await hook.OnAgentHangUp(request);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
response = twilio.HangUp($"twilio/error.mp3");
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnAgentTransferring(request, _settings);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
response = twilio.DialCsrAgent($"twilio/voice/speeches/{request.ConversationId}/{reply.SpeechFileName}");
|
||||
}
|
||||
|
|
@ -249,7 +249,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnAgentHangUp(request);
|
||||
});
|
||||
}, request.AgentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -274,7 +274,7 @@ public class TwilioVoiceController : TwilioController
|
|||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnAgentResponsing(request, instruction);
|
||||
});
|
||||
}, request.AgentId);
|
||||
|
||||
response = twilio.ReturnInstructions(instruction);
|
||||
}
|
||||
|
|
@ -343,41 +343,35 @@ public class TwilioVoiceController : TwilioController
|
|||
{
|
||||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
|
||||
// Define the options with the predicate
|
||||
var emitOptions = new HookEmitOption<ITwilioCallStatusHook>
|
||||
{
|
||||
ShouldExecute = hook => hook.IsMatch(request)
|
||||
};
|
||||
|
||||
switch (request.CallStatus)
|
||||
{
|
||||
case "completed":
|
||||
if (twilio.MachineDetected(request))
|
||||
{
|
||||
// voicemail
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnVoicemailLeft(request), emitOptions);
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnVoicemailLeft(request), request.AgentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// phone call completed
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnUserDisconnected(request), emitOptions);
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnUserDisconnected(request), request.AgentId);
|
||||
}
|
||||
break;
|
||||
|
||||
case "busy":
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallBusyStatus(request), emitOptions);
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallBusyStatus(request), request.AgentId);
|
||||
break;
|
||||
|
||||
case "no-answer":
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallNoAnswerStatus(request), emitOptions);
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallNoAnswerStatus(request), request.AgentId);
|
||||
break;
|
||||
|
||||
case "canceled":
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallCanceledStatus(request), emitOptions);
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallCanceledStatus(request), request.AgentId);
|
||||
break;
|
||||
|
||||
case "failed":
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallFailedStatus(request), emitOptions);
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallFailedStatus(request), request.AgentId);
|
||||
break;
|
||||
default:
|
||||
_logger.LogError($"Unknown call status: {request.CallStatus}, {request.CallSid}");
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
using BotSharp.Plugin.Twilio.Models;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace BotSharp.Plugin.Twilio.Interfaces;
|
||||
|
||||
public interface ITwilioCallStatusHook
|
||||
public interface ITwilioCallStatusHook : IHookBase
|
||||
{
|
||||
bool IsMatch(ConversationalVoiceRequest request) => true;
|
||||
Task OnVoicemailLeft(ConversationalVoiceRequest request) => Task.CompletedTask;
|
||||
Task OnUserDisconnected(ConversationalVoiceRequest request) => Task.CompletedTask;
|
||||
Task OnRecordingCompleted(ConversationalVoiceRequest request) => Task.CompletedTask;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
using BotSharp.Abstraction.Realtime.Models;
|
||||
using BotSharp.Plugin.Twilio.Models;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace BotSharp.Plugin.Twilio.Interfaces;
|
||||
|
||||
public interface ITwilioSessionHook
|
||||
public interface ITwilioSessionHook : IHookBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Before session creating
|
||||
|
|
|
|||
|
|
@ -157,7 +157,8 @@ public class TwilioMessageQueueService : BackgroundService
|
|||
var agentService = sp.GetRequiredService<IAgentService>();
|
||||
var agent = agentService.GetAgent(agentId).Result;
|
||||
var extraWords = new List<string>();
|
||||
HookEmitter.Emit<IRealtimeHook>(sp, hook => extraWords.AddRange(hook.OnModelTranscriptPrompt(agent)));
|
||||
HookEmitter.Emit<IRealtimeHook>(sp, hook => extraWords.AddRange(hook.OnModelTranscriptPrompt(agent)),
|
||||
agentId);
|
||||
|
||||
var phrases = reply.Content.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
int capcity = 100;
|
||||
|
|
|
|||
|
|
@ -235,7 +235,8 @@ public class TwilioService
|
|||
if (_settings.TranscribeEnabled)
|
||||
{
|
||||
var words = new List<string>();
|
||||
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
|
||||
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)),
|
||||
agent.Id);
|
||||
var hints = string.Join(", ", words);
|
||||
var start = new Start();
|
||||
start.Transcription(
|
||||
|
|
@ -323,10 +324,8 @@ public class TwilioService
|
|||
ActionOnEmptyResult = true
|
||||
};
|
||||
|
||||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnWaitingAgentResponse(request, instruction);
|
||||
});
|
||||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook => await hook.OnWaitingAgentResponse(request, instruction),
|
||||
request.AgentId);
|
||||
|
||||
response = ReturnInstructions(instruction);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue