init code template in instruct service

This commit is contained in:
Jicheng Lu 2025-09-30 15:03:06 -05:00
parent 2770c4fe22
commit 2e0069d4e5
9 changed files with 91 additions and 35 deletions

View file

@ -6,5 +6,5 @@ public interface ICodeInterpretService
{ {
string Provider { get; } string Provider { get; }
Task<CodeInterpretResult> RunCode(string code, List<KeyValue>? arguments = null, CodeInterpretOptions? options = null); Task<CodeInterpretResult> RunCode(string code, IEnumerable<KeyValue>? arguments = null, CodeInterpretOptions? options = null);
} }

View file

@ -7,13 +7,16 @@ public interface IInstructService
/// <summary> /// <summary>
/// Execute completion by using specified instruction or template /// Execute completion by using specified instruction or template
/// </summary> /// </summary>
/// <param name="agentId">Agent (static agent)</param> /// <param name="agentId"></param>
/// <param name="message">Additional message provided by user</param> /// <param name="message"></param>
/// <param name="templateName">Template name</param> /// <param name="instruction"></param>
/// <param name="instruction">System prompt</param> /// <param name="llmTemplateName"></param>
/// <param name="files"></param>
/// <param name="codeOptions"></param>
/// <returns></returns> /// <returns></returns>
Task<InstructResult> Execute(string agentId, RoleDialogModel message, Task<InstructResult> Execute(string agentId, RoleDialogModel message,
string? templateName = null, string? instruction = null, IEnumerable<InstructFileModel>? files = null); string? instruction = null, string? llmTemplateName = null,
IEnumerable<InstructFileModel>? files = null, CodeInstructOptions? codeOptions = null);
/// <summary> /// <summary>
/// A generic way to execute completion by using specified instruction or template /// A generic way to execute completion by using specified instruction or template

View file

@ -0,0 +1,7 @@
namespace BotSharp.Abstraction.Instructs.Models;
public class CodeInstructOptions
{
public string? CodeTemplateName { get; set; }
public string? CodeInterpretProvider { get; set; }
}

View file

@ -6,7 +6,8 @@ public class InstructResult : ITrackableMessage
public string MessageId { get; set; } public string MessageId { get; set; }
public string Text { get; set; } = string.Empty; public string Text { get; set; } = string.Empty;
public object? Data { get; set; } public object? Data { get; set; }
[JsonPropertyName("template")] [JsonPropertyName("template")]
public string? Template{ get; set; } public string? Template { get; set; }
public Dictionary<string, string>? States { get; set; } = new(); public Dictionary<string, string>? States { get; set; } = new();
} }

View file

@ -8,6 +8,17 @@ public class KeyValue
[JsonPropertyName("value")] [JsonPropertyName("value")]
public string? Value { get; set; } public string? Value { get; set; }
public KeyValue()
{
}
public KeyValue(string key, string? value)
{
Key = key;
Value = value;
}
public override string ToString() public override string ToString()
{ {
return $"Key: {Key}, Value: {Value}"; return $"Key: {Key}, Value: {Value}";

View file

@ -1,36 +1,67 @@
using BotSharp.Abstraction.CodeInterpreter;
using BotSharp.Abstraction.Instructs; using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models; using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.MLTasks; using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Models;
namespace BotSharp.Core.Instructs; namespace BotSharp.Core.Instructs;
public partial class InstructService public partial class InstructService
{ {
public async Task<InstructResult> Execute(string agentId, RoleDialogModel message, public async Task<InstructResult> Execute(
string? templateName = null, string? instruction = null, IEnumerable<InstructFileModel>? files = null) string agentId,
RoleDialogModel message,
string? instruction = null,
string? llmTemplateName = null,
IEnumerable<InstructFileModel>? files = null,
CodeInstructOptions? codeOptions = null)
{ {
var agentService = _services.GetRequiredService<IAgentService>(); var agentService = _services.GetRequiredService<IAgentService>();
Agent agent = await agentService.LoadAgent(agentId); Agent agent = await agentService.LoadAgent(agentId);
var response = new InstructResult
{
MessageId = message.MessageId,
Template = codeOptions?.CodeTemplateName ?? llmTemplateName
};
if (agent == null) if (agent == null)
{ {
return new InstructResult response.Text = $"Agent (id: {agentId}) does not exist!";
{ return response;
MessageId = message.MessageId,
Text = $"Agent (id: {agentId}) does not exist!"
};
} }
if (agent.Disabled) if (agent.Disabled)
{ {
var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent."; var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent.";
return new InstructResult response.Text = content;
{ return response;
MessageId = message.MessageId,
Text = content
};
} }
// Run code template
if (!string.IsNullOrWhiteSpace(codeOptions?.CodeTemplateName))
{
var codeInterpreter = _services.GetServices<ICodeInterpretService>()
.FirstOrDefault(x => x.Provider.IsEqualTo(codeOptions?.CodeInterpretProvider.IfNullOrEmptyAs("python-interpreter")));
if (codeInterpreter == null)
{
var error = "No code interpreter found.";
_logger.LogError(error);
response.Text = error;
}
else
{
var state = _services.GetRequiredService<IConversationStateService>();
var arguments = state.GetStates().Select(x => new KeyValue(x.Key, x.Value));
var result = await codeInterpreter.RunCode("", arguments);
response.Text = result?.Result?.ToString();
}
return response;
}
// Trigger before completion hooks // Trigger before completion hooks
var hooks = _services.GetHooks<IInstructHook>(agentId); var hooks = _services.GetHooks<IInstructHook>(agentId);
foreach (var hook in hooks) foreach (var hook in hooks)
@ -52,19 +83,13 @@ public partial class InstructService
var model = string.Empty; var model = string.Empty;
// Render prompt // Render prompt
var prompt = string.IsNullOrEmpty(templateName) ? var prompt = string.IsNullOrEmpty(llmTemplateName) ?
agentService.RenderInstruction(agent) : agentService.RenderInstruction(agent) :
agentService.RenderTemplate(agent, templateName); agentService.RenderTemplate(agent, llmTemplateName);
var completer = CompletionProvider.GetCompletion(_services, var completer = CompletionProvider.GetCompletion(_services,
agentConfig: agent.LlmConfig); agentConfig: agent.LlmConfig);
var response = new InstructResult
{
MessageId = message.MessageId,
Template = templateName,
};
if (completer is ITextCompletion textCompleter) if (completer is ITextCompletion textCompleter)
{ {
instruction = null; instruction = null;
@ -111,7 +136,7 @@ public partial class InstructService
AgentId = agentId, AgentId = agentId,
Provider = provider, Provider = provider,
Model = model, Model = model,
TemplateName = templateName, TemplateName = llmTemplateName,
UserMessage = prompt, UserMessage = prompt,
SystemInstruction = instruction, SystemInstruction = instruction,
CompletionText = response.Text CompletionText = response.Text

View file

@ -36,9 +36,10 @@ public class InstructModeController : ControllerBase
var instructor = _services.GetRequiredService<IInstructService>(); var instructor = _services.GetRequiredService<IInstructService>();
var result = await instructor.Execute(agentId, var result = await instructor.Execute(agentId,
new RoleDialogModel(AgentRole.User, input.Text), new RoleDialogModel(AgentRole.User, input.Text),
templateName: input.Template,
instruction: input.Instruction, instruction: input.Instruction,
files: input.Files); llmTemplateName: input.Template,
files: input.Files,
codeOptions: input.CodeOptions);
result.States = state.GetStates(); result.States = state.GetStates();

View file

@ -1,3 +1,5 @@
using BotSharp.Abstraction.Instructs.Models;
namespace BotSharp.OpenAPI.ViewModels.Instructs; namespace BotSharp.OpenAPI.ViewModels.Instructs;
public class InstructMessageModel : IncomingMessageModel public class InstructMessageModel : IncomingMessageModel
@ -9,6 +11,7 @@ public class InstructMessageModel : IncomingMessageModel
public override string Channel { get; set; } = ConversationChannel.OpenAPI; public override string Channel { get; set; } = ConversationChannel.OpenAPI;
public string? Template { get; set; } public string? Template { get; set; }
public List<InstructFileModel> Files { get; set; } = []; public List<InstructFileModel> Files { get; set; } = [];
public CodeInstructOptions? CodeOptions { get; set; }
} }

View file

@ -20,7 +20,8 @@ public class PyInterpretService : ICodeInterpretService
public string Provider => "python-interpreter"; public string Provider => "python-interpreter";
public async Task<CodeInterpretResult> RunCode(string code, List<KeyValue>? arguments = null, CodeInterpretOptions? options = null) public async Task<CodeInterpretResult> RunCode(string code,
IEnumerable<KeyValue>? arguments = null, CodeInterpretOptions? options = null)
{ {
try try
{ {
@ -45,14 +46,18 @@ public class PyInterpretService : ICodeInterpretService
// Set arguments // Set arguments
if (!arguments.IsNullOrEmpty()) if (!arguments.IsNullOrEmpty())
{ {
sys.argv = new PyList(); var list = new PyList();
sys.argv.Append("code.py"); list.Append(new PyString("code.py"));
foreach (var arg in arguments) foreach (var arg in arguments)
{ {
sys.argv.Append($"--{arg.Key}"); if (!string.IsNullOrWhiteSpace(arg.Key) && !string.IsNullOrWhiteSpace(arg.Value))
sys.argv.Append($"{arg.Value}"); {
list.Append(new PyString($"--{arg.Key}"));
list.Append(new PyString($"{arg.Value}"));
}
} }
sys.argv = list;
} }
// Execute Python script // Execute Python script