optimize AgentHook,IInstructHook

This commit is contained in:
nick.yi 2025-05-15 10:48:08 +08:00
parent 6fa8950f79
commit b748ce3d9f
8 changed files with 68 additions and 121 deletions

View file

@ -9,6 +9,8 @@ public interface IAgentHook
/// </summary>
string SelfId { get; }
Agent Agent { get; }
bool IsMatch(string id) => string.IsNullOrEmpty(SelfId) || SelfId == id;
void SetAgent(Agent agent);
/// <summary>

View file

@ -5,6 +5,7 @@ namespace BotSharp.Abstraction.Instructs;
public interface IInstructHook
{
string SelfId { get; }
bool IsMatch(string id) => string.IsNullOrEmpty(SelfId) || SelfId == id;
Task BeforeCompletion(Agent agent, RoleDialogModel message);
Task AfterCompletion(Agent agent, InstructResult result);
Task OnResponseGenerated(InstructResponseModel response);

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Infrastructures;
using BotSharp.Abstraction.Routing.Models;
using System.Collections.Concurrent;
@ -10,29 +11,16 @@ 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())
if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString()) return null;
var emitOptions = new HookEmitOption<IAgentHook>
{
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);
}
ShouldExecute = hook => hook.IsMatch(id)
};
HookEmitter.Emit<IAgentHook>(_services, hook => hook.OnAgentLoading(ref id), emitOptions);
var agent = await GetAgent(id);
if (agent == null)
{
return null;
}
if (agent == null) return null;
await InheritAgent(agent);
OverrideInstructionByChannel(agent);
@ -43,13 +31,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 +54,14 @@ public partial class AgentService
hook.OnAgentUtilityLoaded(agent);
}
if(!agent.McpTools.IsNullOrEmpty())
if (!agent.McpTools.IsNullOrEmpty())
{
hook.OnAgentMcpToolLoaded(agent);
}
hook.OnAgentLoaded(agent);
}
}, emitOptions);
_logger.LogInformation($"Loaded agent {agent}.");

View file

@ -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,11 @@ public partial class FileInstructService
}
});
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(innerAgentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@ -41,8 +39,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
});
}
}), emitOptions);
return message.Content;
}
@ -59,14 +56,11 @@ public partial class FileInstructService
Instruction = instruction
}, new RoleDialogModel(AgentRole.User, instruction ?? text));
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(innerAgentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@ -76,8 +70,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
});
}
}), emitOptions);
return message;
}
@ -104,14 +97,11 @@ public partial class FileInstructService
stream.Close();
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(innerAgentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@ -119,8 +109,7 @@ public partial class FileInstructService
Model = completion.Model,
UserMessage = string.Empty,
CompletionText = message.Content
});
}
}), emitOptions);
return message;
}
@ -150,13 +139,11 @@ public partial class FileInstructService
stream.Close();
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(innerAgentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@ -166,8 +153,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
});
}
}), emitOptions);
return message;
}
@ -205,14 +191,11 @@ public partial class FileInstructService
imageStream.Close();
maskStream.Close();
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(innerAgentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@ -222,8 +205,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
});
}
}), emitOptions);
return message;
}

View file

@ -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,11 @@ public partial class FileInstructService
}
});
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(innerAgentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@ -59,8 +57,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
});
}
}), emitOptions);
return message.Content;
}

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Functions;
using BotSharp.Abstraction.Infrastructures;
using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models;
@ -60,14 +61,11 @@ public class ExecuteTemplateFn : IFunctionCallback
new(AgentRole.User, text)
});
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(agent.Id)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agent.Id,
@ -76,8 +74,7 @@ public class ExecuteTemplateFn : IFunctionCallback
Model = completion.Model,
UserMessage = text,
CompletionText = response.Content
});
}
}), emitOptions);
return response.Content;
}

View file

@ -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
{

View file

@ -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,11 @@ 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)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(agentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agentId,
@ -74,8 +72,8 @@ public class InstructModeController : ControllerBase
TemplateName = input.Template,
UserMessage = input.Text,
CompletionText = response
});
}
}), emitOptions);
return response;
}
@ -103,14 +101,11 @@ public class InstructModeController : ControllerBase
}
});
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
var emitOptions = new HookEmitOption<IInstructHook>
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
ShouldExecute = hook => hook.IsMatch(agentId)
};
await HookEmitter.Emit<IInstructHook>(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agentId,
@ -120,8 +115,8 @@ public class InstructModeController : ControllerBase
UserMessage = input.Text,
SystemInstruction = message.RenderedInstruction,
CompletionText = message.Content
});
}
}), emitOptions);
return message.Content;
}
#endregion