Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8ed8310
Update package versions in `Directory.Build.props` and `Directory.Pac…
sfmskywalker Dec 10, 2025
c9253c9
Initial plan
Copilot Dec 11, 2025
5bbd847
Add Microsoft Agent Framework integration with code-first support
Copilot Dec 11, 2025
7e699df
Add comprehensive documentation and examples for Agent Framework feat…
Copilot Dec 11, 2025
163a17f
Add unit tests and fix null reference issues in ConfigurationKernelCo…
Copilot Dec 11, 2025
e03d1bf
Address code review feedback - improve error handling and remove unus…
Copilot Dec 11, 2025
1d616cb
Add migration guide for Agent Framework features
Copilot Dec 11, 2025
fb4f4eb
Refactor package versioning and temporarily comment out scoped activi…
sfmskywalker Dec 12, 2025
5409790
Add `Elsa.Agents.Tests` project and refactor `TestWorkflowDefinition`…
sfmskywalker Dec 12, 2025
b0705a7
Remove legacy KernelFactory and implement improved Agent Framework su…
sfmskywalker Dec 12, 2025
814cf6d
Remove SK-based agent workflows and introduce code-first agents
sfmskywalker Dec 12, 2025
d86dbd7
Refactor agent activities and improve dependency injection
sfmskywalker Dec 13, 2025
97a3299
Refactor agent workflow infrastructure to simplify providers.
sfmskywalker Dec 13, 2025
5089bc1
Refactor agents framework and replace deprecated agent implementation
sfmskywalker Dec 13, 2025
0269fae
Replace "plugins" with "skills" throughout agents framework
sfmskywalker Dec 13, 2025
b020eb8
Remove legacy API key and service management functionality.
sfmskywalker Dec 13, 2025
89f3e1b
Remove ApiKeyDefinition and ServiceDefinition tables.
sfmskywalker Dec 13, 2025
add31db
Add Azure OpenAI integration to Elsa Agents
sfmskywalker Dec 13, 2025
b4d7a24
Refactor agent activity providers and registry to improve naming cons…
sfmskywalker Dec 14, 2025
fe8d3a1
Improve naming consistency in documentation for agent activity provid…
sfmskywalker Dec 14, 2025
b8521cf
Refactor runAsynchronously logic and remove TaskActivityAttribute
sfmskywalker Dec 14, 2025
5db7bfb
Introduce `IAgentFactory` and `IAgentInvoker` interfaces to decouple …
sfmskywalker Dec 14, 2025
4725ce5
Refactor agents framework to unify configuration and improve invocati…
sfmskywalker Dec 14, 2025
f4c7864
Remove obsolete agent test suite and update solution references.
sfmskywalker Dec 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>

<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<NoWarn>$(NoWarn);CS0162;CS1591</NoWarn>
<!-- IL trimming warnings -->
<NoWarn>$(NoWarn);IL2026;IL2046;IL2057;IL2067;IL2070;IL2072;IL2075;IL2087;IL2091</NoWarn>
</PropertyGroup>

<PropertyGroup Label="PackageVersions">
<ElsaVersion>3.6.0-preview.4036</ElsaVersion>
<ElsaStudioVersion>3.6.0-preview.1297</ElsaStudioVersion>
</PropertyGroup>

</Project>
152 changes: 79 additions & 73 deletions Directory.Packages.props

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Elsa.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "data", "data", "{6D2A4421-A
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Data.Csv", "src\modules\data\Elsa.Data.Csv\Elsa.Data.Csv.csproj", "{015646EB-EC33-4ADF-8417-B9D1A6B7CF06}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "agents", "agents", "{60A25F2D-634D-438A-87EA-F204677978BE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -751,6 +753,7 @@ Global
{BEB35A25-5A80-4B56-A1EC-F005288CD11C} = {AAD61D93-7C78-42C4-9F37-2564D127A668}
{6D2A4421-A388-4BEE-BB11-D0FC32A80A10} = {30CF0330-4B09-4784-B499-46BED303810B}
{015646EB-EC33-4ADF-8417-B9D1A6B7CF06} = {6D2A4421-A388-4BEE-BB11-D0FC32A80A10}
{60A25F2D-634D-438A-87EA-F204677978BE} = {3DDE6F89-531C-47F8-9CD7-7A4E6984FA48}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {11A771DA-B728-445E-8A88-AE1C84C3B3A6}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.ComponentModel;
using System.Dynamic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Elsa.Expressions.Helpers;
using Elsa.Agents.Activities.ActivityProviders;
using Elsa.Workflows;
using Elsa.Workflows.Models;
using static Elsa.Agents.Activities.Extensions.ResponseHelpers;

namespace Elsa.Agents.Activities;

/// <summary>
/// An activity that executes a function of a skilled agent. This is an internal activity that is used by <see cref="CodeFirstAgentActivityProvider"/>.
/// </summary>
[Browsable(false)]
public class CodeFirstAgentActivity : CodeActivity
{
private static JsonSerializerOptions? _serializerOptions;

[JsonIgnore] internal string AgentName { get; set; } = null!;

/// <inheritdoc />
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
var cancellationToken = context.CancellationToken;
var activityDescriptor = context.ActivityDescriptor;
var inputDescriptors = activityDescriptor.Inputs;
var functionInput = new Dictionary<string, object?>();

foreach (var inputDescriptor in inputDescriptors)
{
var input = (Input?)inputDescriptor.ValueGetter(this);
var inputValue = input != null ? context.Get(input.MemoryBlockReference()) : null;

if (inputValue is ExpandoObject expandoObject)
inputValue = expandoObject.ConvertTo<string>();

functionInput[inputDescriptor.Name] = inputValue;
}

// Resolve the agent via the unified abstraction.
var agentResolver = context.GetRequiredService<IAgentResolver>();
var agent = await agentResolver.ResolveAsync(AgentName, cancellationToken);
var agentType = agent.GetType();
var agentPropertyLookup = agentType.GetProperties().ToDictionary(x => x.Name, x => x);

// Copy activity input descriptor values into the agent public properties:
foreach (var inputDescriptor in inputDescriptors)
{
var input = (Input?)inputDescriptor.ValueGetter(this);
var inputValue = input != null ? context.Get(input.MemoryBlockReference()) : null;
agentPropertyLookup[inputDescriptor.Name].SetValue(agent, inputValue);
}

var agentExecutionContext = new AgentExecutionContext { CancellationToken = context.CancellationToken };
var agentExecutionResponse = await agent.RunAsync(agentExecutionContext);
var responseText = StripCodeFences(agentExecutionResponse.Text);
var isJsonResponse = IsJsonResponse(responseText);
var outputType = context.ActivityDescriptor.Outputs.Single().Type;

// If the target type is object and the response is in JSON format, we want it to be deserialized into an ExpandoObject for dynamic field access.
if (outputType == typeof(object) && isJsonResponse)
outputType = typeof(ExpandoObject);

var outputValue = isJsonResponse ? responseText.ConvertTo(outputType) : responseText;
var outputDescriptor = activityDescriptor.Outputs.Single();
var output = (Output?)outputDescriptor.ValueGetter(this);
context.Set(output, outputValue, "Output");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using Elsa.Agents;
using Elsa.Expressions.Helpers;
using Elsa.Extensions;
using Elsa.Agents.Activities.ActivityProviders;
using Elsa.Workflows;
using Elsa.Workflows.Models;
using Elsa.Workflows.Serialization.Converters;
using static Elsa.Agents.Activities.Extensions.ResponseHelpers;

namespace Elsa.Agents.Activities;

/// <summary>
/// An activity that executes a function of a skilled agent. This is an internal activity that is used by <see cref="AgentActivityProvider"/>.
/// An activity that executes a function of a skilled agent. This is an internal activity that is used by <see cref="ConfigurationAgentActivityProvider"/>.
/// </summary>
[Browsable(false)]
public class AgentActivity : CodeActivity
public class ConfiguredAgentActivity : CodeActivity
{
private static JsonSerializerOptions? _serializerOptions;

Expand All @@ -44,30 +44,31 @@ protected override async ValueTask ExecuteAsync(ActivityExecutionContext context
var inputValue = input != null ? context.Get(input.MemoryBlockReference()) : null;

if (inputValue is ExpandoObject expandoObject)
{
inputValue = expandoObject.ConvertTo<string>();
}

functionInput[inputDescriptor.Name] = inputValue;
}

var agentInvoker = context.GetRequiredService<AgentInvoker>();
var result = await agentInvoker.InvokeAgentAsync(AgentName, functionInput, context.CancellationToken);
var json = result.ChatMessageContent.Content?.Trim();

if (string.IsNullOrWhiteSpace(json))
throw new InvalidOperationException("The message content is empty or null.");

var agentInvoker = context.GetRequiredService<IAgentInvoker>();
var request = new InvokeAgentRequest
{
AgentName = AgentName,
Input = functionInput,
CancellationToken = context.CancellationToken
};
var agentExecutionResponse = await agentInvoker.InvokeAsync(request);
var responseText = StripCodeFences(agentExecutionResponse.ChatMessageContent.Content!);
var isJsonResponse = IsJsonResponse(responseText);
var outputType = context.ActivityDescriptor.Outputs.Single().Type;

// If the target type is object, we want the JSON to be deserialized into an ExpandoObject for dynamic field access.
if (outputType == typeof(object))
// If the target type is object and the response is in JSON format, we want it to be deserialized into an ExpandoObject for dynamic field access.
if (outputType == typeof(object) && isJsonResponse)
outputType = typeof(ExpandoObject);

var converterOptions = new ObjectConverterOptions(SerializerOptions);
var outputValue = json.ConvertTo(outputType, converterOptions);
var outputValue = isJsonResponse ? responseText.ConvertTo(outputType, converterOptions) : responseText;
var outputDescriptor = activityDescriptor.Outputs.Single();
var output = (Output)outputDescriptor.ValueGetter(this);
context.Set(output, outputValue);
var output = (Output?)outputDescriptor.ValueGetter(this);
context.Set(output, outputValue, "Output");
}
}

This file was deleted.

Loading
Loading