Skip to content

.NET: Allow custom argument marshaling for skill scripts#6498

Open
SergeyMenshykh wants to merge 2 commits into
microsoft:mainfrom
SergeyMenshykh:sergeymenshykh/issue-6020-argument-marshaler
Open

.NET: Allow custom argument marshaling for skill scripts#6498
SergeyMenshykh wants to merge 2 commits into
microsoft:mainfrom
SergeyMenshykh:sergeymenshykh/issue-6020-argument-marshaler

Conversation

@SergeyMenshykh

@SergeyMenshykh SergeyMenshykh commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

vLLM and some other OpenAI-compatible backends send tool-call arguments as a JSON string (e.g. "{\"query\":\"hello\"}") instead of a JSON object. Skill scripts only accept a JSON object, so these calls fail with an InvalidOperationException.

This PR lets callers plug in their own argument conversion logic.

Changes

  • Adds an optional Func<JsonElement?, AIFunctionArguments>? argumentMarshaler that controls how raw JSON arguments are converted before the script delegate runs.
  • It can be supplied at three levels:
    • AgentInlineSkillScript constructor - per script.
    • AgentInlineSkill constructor - applies to all scripts added via AddScript.
    • AgentClassSkill<T> constructor - applies to discovered scripts and those created via CreateScript.
  • When omitted, the existing behavior is unchanged: arguments must be a JSON object (or null), otherwise an InvalidOperationException is thrown.

Closes #6020

Add an optional Func<JsonElement?, AIFunctionArguments> argument marshaler to inline and class-based skills so callers can customize how raw JSON tool-call arguments are converted into AIFunctionArguments before delegate invocation. This enables handling backends (e.g. vLLM) that send tool-call arguments as a JSON string instead of a JSON object. The marshaler can be supplied at the script, inline-skill, or class-skill level; when omitted, the existing strict JSON-object behavior is preserved unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 configurable argument marshaling for .NET skill scripts so callers can handle OpenAI-compatible backends (e.g., vLLM) that emit tool-call arguments as a JSON string instead of a JSON object, while preserving the existing strict default behavior.

Changes:

  • Added an optional Func<JsonElement?, AIFunctionArguments>? argumentMarshaler that converts raw JSON arguments into AIFunctionArguments before invoking the script delegate.
  • Plumbed the marshaler through AgentInlineSkillScript, AgentInlineSkill (skill-level default), and AgentClassSkill<T> (applies to discovered/programmatic scripts).
  • Added unit tests covering default behavior vs. custom string-parsing marshaler behavior and precedence rules.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/SkillScriptArgumentMarshalerTests.cs Adds tests validating default strict object-only marshaling and custom marshaler support (including vLLM-like string-wrapped JSON).
dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillScript.cs Adds a per-script marshaler hook and uses it in RunAsync prior to AIFunction invocation.
dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs Adds a skill-level default marshaler and wires it into scripts added via AddScript.
dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs Adds a skill-level marshaler for class-based skills and passes it to discovered/programmatic scripts.
Comments suppressed due to low confidence (1)

dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs:124

  • AgentClassSkill is a public base class; replacing the protected parameterless constructor with a single ctor that takes an (optional) parameter is a binary-breaking change for already-compiled derived skills (they will look for base .ctor() and fail at runtime). Keep a true parameterless ctor and add a new overload that accepts argumentMarshaler.
    protected AgentClassSkill(Func<JsonElement?, AIFunctionArguments>? argumentMarshaler = null)
    {
        this._argumentMarshaler = argumentMarshaler;
        this._resources = new Lazy<IReadOnlyList<AgentSkillResource>?>(this.DiscoverResources);
        this._scripts = new Lazy<IReadOnlyList<AgentSkillScript>?>(this.DiscoverScripts);
        this._content = new Lazy<string>(() => AgentInlineSkillContentBuilder.Build(
            this.Frontmatter.Name,
            this.Frontmatter.Description,
            this.Instructions,
            this.Scripts));
    }

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 5 | Confidence: 92% | Result: All clear

Reviewed: Correctness, Security Reliability, Test Coverage, Failure Modes, Design Approach


Automated review by SergeyMenshykh's agents

@SergeyMenshykh SergeyMenshykh self-assigned this Jun 12, 2026
@SergeyMenshykh SergeyMenshykh moved this to In Review in Agent Framework Jun 12, 2026
@SergeyMenshykh SergeyMenshykh marked this pull request as ready for review June 12, 2026 11:35

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 5 | Confidence: 91% | Result: All clear

Reviewed: Correctness, Security Reliability, Test Coverage, Failure Modes, Design Approach


Automated review by SergeyMenshykh's agents

@SergeyMenshykh SergeyMenshykh disabled auto-merge June 12, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: Arguments valueKind is String instead of Object when calling AgentInlineSkillScript via functionCall

5 participants