Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 13, 2025

Implements Hyperbee.XS-based expression provider for workflows, addressing multi-tenant security concerns with Roslyn's full C# compiler by using expression trees instead of dynamic compilation.

Changes

New Module: Elsa.Expressions.Xs

  • XsEvaluator: Parses XS scripts to expression trees, compiles to delegates with caching
  • XsExpressionHandler: Integrates with Elsa's expression evaluation pipeline
  • XsExpressionDescriptorProvider: Registers "XS Script" expression type
  • XsFeature: DI configuration with UseXs() extension method
  • XsOptions: Configurable expression cache timeout, XS config callbacks

Package Dependencies

  • Hyperbee.XS 1.3.3
  • Hyperbee.Xs.Extensions 1.3.3

Integration Tests

8 tests covering arithmetic, variables, conditionals, boolean expressions (5 passing)

Usage

services.AddElsa(elsa =>
{
    elsa.UseXs(options =>
    {
        options.ExpressionCacheTimeout = TimeSpan.FromHours(1);
        options.ConfigureXsConfig(config => { /* customize */ });
    });
});

Expression example:

var x = 10;
var y = 20;
if (x < y) { x; } else { y; }

Known Limitations

  • Workflow context (globals) access not yet implemented - requires expression tree transformation
  • String concatenation via + operator unsupported (expression tree limitation)
  • Array initialization syntax new int[] not recognized by XS parser

Security Impact

  • Expression tree evaluation only (no code generation/assembly loading)
  • Smaller attack surface vs Roslyn scripting
  • Still requires process isolation for untrusted multi-tenant scenarios

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • f.feedz.io
    • Triggering command: dotnet restore src/modules/Elsa.Expressions.Xs/Elsa.Expressions.Xs.csproj --ignore-failed-sources (dns block)
    • Triggering command: dotnet restore test/integration/Elsa.Xs.IntegrationTests/Elsa.Xs.IntegrationTests.csproj --ignore-failed-sources (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>XS / Hyperbee.XS-based expression provider as an alternative to Roslyn C# expressions</issue_title>
<issue_description>Summary

Add a new expression provider that uses Hyperbee.XS as its backing engine, offering a C#‑like syntax implemented on top of expression trees instead of Roslyn scripting.

Motivation

  • The existing C# expression feature uses Roslyn as the expression evaluator. Roslyn is a full C# compiler and does not attempt to provide a sandbox for untrusted code; the recommended approach is to run untrusted scripts in a separate, restricted process or container rather than in the main application process.
  • In multi‑tenant, cloud‑hosted scenarios where Elsa Server is exposed to arbitrary tenant-authored expressions, it’s hard to safely expose the Roslyn-based C# expressions directly without additional isolation.
  • Hyperbee.XS is a lightweight, C#‑like scripting language that generates expression trees and is designed for embedded scripting, rule engines, and DSLs, without pulling in the full Roslyn compiler pipeline. This seems like a good fit for workflow expressions and may be easier to constrain to a limited, auditable surface.

Proposal

  • Introduce a new module, e.g. Elsa.Expressions.Xs (or similar), that registers an XS expression provider.

  • The provider would:

    • Parse expressions using Hyperbee.XS and compile them to delegates.
    • Expose the same globals that the current C# provider does (WorkflowInstanceId, CorrelationId, Variable, Output, Input, etc.).
    • Integrate with Elsa’s existing expression infrastructure so XS can be selected as an expression type from Studio and JSON definitions.
  • Add a configuration hook similar to UseCSharp(...), e.g.:

    services.AddElsa(elsa =>
    {
        elsa.UseXs(options =>
        {
            // Configure allowed types/namespaces, register helper functions, etc.
        });
    });

    so hosts can:

    • Control which assemblies/types are visible to XS.
    • Register reusable helper functions/DSL constructs exposed to expressions.
    • Potentially restrict XS usage further in multi-tenant scenarios.

Naming

Some options for the expression syntax / UI label:

  • XS
  • XS Script
  • Hyperbee XS

To avoid confusion with the existing Roslyn-based C# expressions, I’d suggest:

  • Expression type key: XS
  • Display name: XS Script

Notes

  • This is intended as an additional option, not a replacement for the current Roslyn-based C# expressions.
  • Security-wise, XS would still need to be treated as untrusted code in multi-tenant environments (and combined with process/container isolation where strong tenant isolation is required), but its expression-tree focus and smaller surface area could make it easier to lock down than full C# via Roslyn.

<agent_instructions>Include integration tests</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.


This change is Reviewable

Copilot AI and others added 2 commits November 13, 2025 19:08
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Copilot AI changed the title [WIP] Add Hyperbee.XS-based expression provider as an alternative to Roslyn Add XS expression provider as lightweight alternative to Roslyn C# expressions Nov 13, 2025
Copilot AI requested a review from sfmskywalker November 13, 2025 19:20
@sfmskywalker sfmskywalker marked this pull request as ready for review November 13, 2025 20:52
Copilot AI review requested due to automatic review settings November 13, 2025 20:52
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +82 to +86
// Create a lambda expression without parameters
// TODO: Add support for accessing workflow context (globals) through expression transformation
var lambda = LinqExpression.Lambda(parsedExpression);

// Compile the lambda

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass workflow globals into XS expressions

The evaluator compiles every script into a zero‑parameter lambda (LinqExpression.Lambda(parsedExpression) on lines 82‑85) and later executes it via compiledDelegate.DynamicInvoke() with no arguments. Because no Globals/ExpressionExecutionContext object is ever supplied, XS scripts cannot reference workflow variables, inputs, outputs, outcomes, or evaluator arguments—the identifiers simply don’t exist and the parser will fail whenever a workflow expression uses them. This makes the new provider unusable for anything beyond pure constant expressions and contradicts the stated goal of offering the same globals surface as the C# provider. Please add a globals parameter to the generated lambda and bind it to the current ExpressionExecutionContext/ExpressionEvaluatorOptions before invoking the delegate.

Useful? React with 👍 / 👎.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a new Elsa.Expressions.Xs module that provides an XS-based expression provider as a lightweight, security-focused alternative to the existing Roslyn C# expression evaluator. The implementation uses Hyperbee.XS library to parse expressions into expression trees, offering a smaller attack surface for multi-tenant scenarios while acknowledging that process isolation is still recommended for untrusted code.

Key Changes:

  • New XS expression evaluation module with configurable caching and assembly references
  • Integration tests covering basic expression scenarios (8 tests, 5 expected to pass)
  • Dependency management updates for Hyperbee.XS packages (v1.3.3)

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/modules/Elsa.Expressions.Xs/Elsa.Expressions.Xs.csproj New project definition with Hyperbee.XS dependencies
src/modules/Elsa.Expressions.Xs/Features/XsFeature.cs DI feature registration with dependency declarations
src/modules/Elsa.Expressions.Xs/Options/XsOptions.cs Configuration options for caching, assemblies, and XS config callbacks
src/modules/Elsa.Expressions.Xs/Extensions/ModuleExtensions.cs UseXs() extension methods for module configuration
src/modules/Elsa.Expressions.Xs/Contracts/IXsEvaluator.cs Interface for XS expression evaluation
src/modules/Elsa.Expressions.Xs/Services/XsEvaluator.cs Core evaluator with SHA256-based caching and expression tree compilation
src/modules/Elsa.Expressions.Xs/Expressions/XsExpressionHandler.cs Integration handler for Elsa's expression pipeline
src/modules/Elsa.Expressions.Xs/Providers/XsExpressionDescriptorProvider.cs Registers "XS Script" expression type with Monaco C# syntax highlighting
src/modules/Elsa.Expressions.Xs/Models/Globals.cs Workflow context globals class (not yet connected)
src/modules/Elsa.Expressions.Xs/Models/ExecutionContextProxy.cs Proxy for variable/input access (not yet connected)
src/modules/Elsa.Expressions.Xs/Models/OutputProxy.cs Proxy for activity output access (not yet connected)
src/modules/Elsa.Expressions.Xs/Models/OutcomeProxy.cs Proxy for activity outcome management (not yet connected)
src/modules/Elsa.Expressions.Xs/FodyWeavers.xml ConfigureAwait weaver configuration
test/integration/Elsa.Xs.IntegrationTests/Elsa.Xs.IntegrationTests.csproj Integration test project setup
test/integration/Elsa.Xs.IntegrationTests/XsEvaluatorTests.cs Test suite with 8 tests covering basic XS scenarios
Directory.Packages.props Added Hyperbee.XS package version references
Elsa.sln Added new projects and expanded platform configurations (x64/x86)

Comment on lines +31 to +32
ExpressionExecutionContext context,
ExpressionEvaluatorOptions options,
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The options parameter is never used in the method body. The method should respect any options passed by the caller, such as timeout configurations or other evaluation constraints.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +69
using Elsa.Expressions.Models;
using Elsa.Extensions;
using JetBrains.Annotations;

namespace Elsa.Expressions.Xs.Models;

/// <summary>
/// Provides access to global objects, such as the workflow execution context.
/// </summary>
[UsedImplicitly]
public partial class Globals
{
/// <summary>
/// Initializes a new instance of the <see cref="Globals"/> class.
/// </summary>
public Globals(ExpressionExecutionContext expressionExecutionContext, IDictionary<string, object> arguments)
{
ExpressionExecutionContext = expressionExecutionContext;
Arguments = arguments;
ExecutionContext = new(expressionExecutionContext);
Output = new(expressionExecutionContext);
Outcome = new(expressionExecutionContext);
}

/// <summary>
/// Provides access to activity outcomes.
/// </summary>
public OutcomeProxy Outcome { get; set; }

/// <summary>
/// Provides access to activity outputs.
/// </summary>
public OutputProxy Output { get; set; }

/// <summary>
/// Gets the current execution context.
/// </summary>
public ExecutionContextProxy ExecutionContext { get; }

/// <summary>
/// Gets the ID of the current workflow instance.
/// </summary>
public string WorkflowInstanceId => ExpressionExecutionContext.GetWorkflowExecutionContext().Id;

/// <summary>
/// Gets or sets the correlation ID of the current workflow instance.
/// </summary>
public string? CorrelationId
{
get => ExpressionExecutionContext.GetWorkflowExecutionContext().CorrelationId;
set => ExpressionExecutionContext.GetWorkflowExecutionContext().CorrelationId = value;
}

/// <summary>
/// Gets or sets the name of the current workflow instance.
/// </summary>
public string? WorkflowInstanceName
{
get => ExpressionExecutionContext.GetWorkflowExecutionContext().Name;
set => ExpressionExecutionContext.GetWorkflowExecutionContext().Name = value;
}

/// <summary>
/// Gets additional arguments provided by the caller of the evaluator.
/// </summary>
public IDictionary<string, object> Arguments { get; }

private ExpressionExecutionContext ExpressionExecutionContext { get; }
}
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Globals class and related proxy classes (OutputProxy, OutcomeProxy, ExecutionContextProxy) are defined but never instantiated or used by XsEvaluator. These classes provide workflow context access, but the evaluator's TODO comment (line 83 in XsEvaluator.cs) indicates this functionality isn't implemented yet. This creates dead code that may confuse developers. Consider either:

  1. Implementing the context transformation to use these classes
  2. Or moving these classes to a future PR when the feature is ready to be implemented
Suggested change
using Elsa.Expressions.Models;
using Elsa.Extensions;
using JetBrains.Annotations;
namespace Elsa.Expressions.Xs.Models;
/// <summary>
/// Provides access to global objects, such as the workflow execution context.
/// </summary>
[UsedImplicitly]
public partial class Globals
{
/// <summary>
/// Initializes a new instance of the <see cref="Globals"/> class.
/// </summary>
public Globals(ExpressionExecutionContext expressionExecutionContext, IDictionary<string, object> arguments)
{
ExpressionExecutionContext = expressionExecutionContext;
Arguments = arguments;
ExecutionContext = new(expressionExecutionContext);
Output = new(expressionExecutionContext);
Outcome = new(expressionExecutionContext);
}
/// <summary>
/// Provides access to activity outcomes.
/// </summary>
public OutcomeProxy Outcome { get; set; }
/// <summary>
/// Provides access to activity outputs.
/// </summary>
public OutputProxy Output { get; set; }
/// <summary>
/// Gets the current execution context.
/// </summary>
public ExecutionContextProxy ExecutionContext { get; }
/// <summary>
/// Gets the ID of the current workflow instance.
/// </summary>
public string WorkflowInstanceId => ExpressionExecutionContext.GetWorkflowExecutionContext().Id;
/// <summary>
/// Gets or sets the correlation ID of the current workflow instance.
/// </summary>
public string? CorrelationId
{
get => ExpressionExecutionContext.GetWorkflowExecutionContext().CorrelationId;
set => ExpressionExecutionContext.GetWorkflowExecutionContext().CorrelationId = value;
}
/// <summary>
/// Gets or sets the name of the current workflow instance.
/// </summary>
public string? WorkflowInstanceName
{
get => ExpressionExecutionContext.GetWorkflowExecutionContext().Name;
set => ExpressionExecutionContext.GetWorkflowExecutionContext().Name = value;
}
/// <summary>
/// Gets additional arguments provided by the caller of the evaluator.
/// </summary>
public IDictionary<string, object> Arguments { get; }
private ExpressionExecutionContext ExpressionExecutionContext { get; }
}

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +71
[Fact(DisplayName = "String concatenation should work")]
public async Task String_Concatenation_Should_Work()
{
// Arrange
var script = """
var hello = "Hello";
var world = "World";
hello + " " + world;
""";
var context = await CreateExpressionExecutionContextAsync();
var evaluator = _fixture.Services.GetRequiredService<IXsEvaluator>();

// Act
var result = await evaluator.EvaluateAsync(script, typeof(string), context, new ExpressionEvaluatorOptions());

// Assert
Assert.Equal("Hello World", result);
}
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the PR description's "Known Limitations" section, string concatenation via the + operator is unsupported due to expression tree limitations. This test is expected to fail but is not marked with [Fact(Skip = "...")]. The test should either:

  1. Be marked as skipped with an explanation: [Fact(Skip = "String concatenation via + operator is not supported by XS expression trees")]
  2. Or be removed until the feature is implemented

Copilot uses AI. Check for mistakes.
/// <inheritdoc />
public async ValueTask<object?> EvaluateAsync(Expression expression, Type returnType, ExpressionExecutionContext context, ExpressionEvaluatorOptions options)
{
var script = expression.Value.ConvertTo<string>() ?? "";
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If expression.Value is null, the null-coalescing operator converts it to an empty string "". An empty script will likely cause parsing or evaluation errors. Consider validating the input and throwing a more descriptive exception, such as ArgumentException with a message like "XS expression cannot be null or empty".

Suggested change
var script = expression.Value.ConvertTo<string>() ?? "";
var script = expression.Value.ConvertTo<string>();
if (string.IsNullOrWhiteSpace(script))
throw new ArgumentException("XS expression cannot be null or empty.", nameof(expression));

Copilot uses AI. Check for mistakes.

private Delegate GetCompiledDelegate(string expression, Type returnType, XsConfig xsConfig, TypeResolver typeResolver, ExpressionExecutionContext context, ExpressionEvaluatorOptions options)
{
var cacheKey = "xs:expression:" + Hash(expression);
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The returnType, context, and options parameters are passed to this method but never used. The cached delegate is compiled without considering the return type or execution context, which means:

  1. Different return types for the same expression will incorrectly share the same cached delegate
  2. The cache key should include the return type to avoid type mismatch issues

Consider adding the return type to the cache key: var cacheKey = $"xs:expression:{returnType.FullName}:{Hash(expression)}";

Suggested change
var cacheKey = "xs:expression:" + Hash(expression);
var cacheKey = $"xs:expression:{returnType.FullName}:{Hash(expression)}";

Copilot uses AI. Check for mistakes.
Comment on lines +1048 to +1057
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x64.ActiveCfg = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x64.Build.0 = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x86.ActiveCfg = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x86.Build.0 = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|Any CPU.Build.0 = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x64.ActiveCfg = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x64.Build.0 = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x86.ActiveCfg = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x86.Build.0 = Release|Any CPU
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution file now includes additional platform configurations (x64, x86) for all projects. This significantly increases the file size (from ~620 lines to ~1160 lines) and appears to be unrelated to adding the XS expression provider. If these platform configurations weren't previously needed, they should be removed to keep the PR focused on its stated purpose. If they are intentional, this should be mentioned in the PR description.

Suggested change
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x64.ActiveCfg = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x64.Build.0 = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x86.ActiveCfg = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Debug|x86.Build.0 = Debug|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|Any CPU.Build.0 = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x64.ActiveCfg = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x64.Build.0 = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x86.ActiveCfg = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|x86.Build.0 = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5923142-28BB-478A-B77C-68CD25153DA6}.Release|Any CPU.Build.0 = Release|Any CPU

Copilot uses AI. Check for mistakes.
typeof(Enumerable).Assembly, // System.Linq
typeof(Guid).Assembly, // System.Runtime
typeof(JsonSerializer).Assembly, // System.Text.Json
typeof(IDictionary<string, object>).Assembly, // System.Collections
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The default assemblies list includes typeof(IDictionary<string, object>).Assembly with a comment "System.Collections", but IDictionary<,> is actually in System.Runtime, not a specific Collections assembly. Consider using a more accurate type or updating the comment to reflect the actual assembly being referenced.

Suggested change
typeof(IDictionary<string, object>).Assembly, // System.Collections
typeof(IDictionary<string, object>).Assembly, // System.Runtime

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +114
[Fact(DisplayName = "Array operations should work")]
public async Task Array_Operations_Should_Work()
{
// Arrange
var script = """
var numbers = new int[] { 1, 2, 3, 4, 5 };
numbers[2];
""";
var context = await CreateExpressionExecutionContextAsync();
var evaluator = _fixture.Services.GetRequiredService<IXsEvaluator>();

// Act
var result = await evaluator.EvaluateAsync(script, typeof(int), context, new ExpressionEvaluatorOptions());

// Assert
Assert.Equal(3, result);
}
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the PR description's "Known Limitations" section, array initialization syntax new int[] is not recognized by the XS parser. This test is expected to fail but is not marked with [Fact(Skip = "...")]. The test should either:

  1. Be marked as skipped with an explanation: [Fact(Skip = "Array initialization syntax 'new int[]' is not supported by XS parser")]
  2. Or be removed until the feature is implemented

Copilot uses AI. Check for mistakes.

<ItemGroup>
<ProjectReference Include="..\Elsa.Expressions\Elsa.Expressions.csproj" />
<ProjectReference Include="..\Elsa.Workflows.Management\Elsa.Workflows.Management.csproj" />
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The project references Elsa.Workflows.Management, but based on the implementation, only Elsa.Expressions appears to be directly used. The Elsa.Workflows.Management reference may be unnecessary and could be removed if it's not providing any required dependencies. Consider verifying if this reference is actually needed.

Suggested change
<ProjectReference Include="..\Elsa.Workflows.Management\Elsa.Workflows.Management.csproj" />

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +34
public async Task<object?> EvaluateAsync(
string expression,
Type returnType,
ExpressionExecutionContext context,
ExpressionEvaluatorOptions options,
CancellationToken cancellationToken = default)
{
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The context parameter is never used in the method body. According to the TODO comment on line 83 and the PR description's known limitations, workflow context (globals) access is not yet implemented. However, accepting the parameter and ignoring it may lead to confusion. Consider either:

  1. Adding a TODO/warning comment at the method level explaining this limitation
  2. Or implementing basic context parameter passing to make the evaluator functional with workflow variables

Copilot uses AI. Check for mistakes.
@sfmskywalker sfmskywalker force-pushed the main branch 2 times, most recently from 4e58970 to ae1bb77 Compare December 10, 2025 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XS / Hyperbee.XS-based expression provider as an alternative to Roslyn C# expressions

2 participants