microsoft / microsoft/agent-framework

.NET: [Bug]: CodeAct/Hyperlight: host tool parameter names/schema are never surfaced to the model, calling contract must be hand-written into the tool [Description]

Open
#8,125 3 comments 0 reactions 1 assignee Claimed by @eavanvalkenburg View on GitHub
.NET reproduced skills
Dominant language
Python
Stars
13.6k
Forks
2.3k
Avg merge
2d 45m
Merged PRs (30d)
358

Description

### Description

When host tools are registered on `HyperlightCodeActProviderOptions.Tools`, the model reaches them via `call_tool("name", { ... })` inside `execute_code`. But the instructions injected for execute_code include only each tool's name and description, never its parameter names or JSON schema. As a result, the model cannot know what argument names to pass unless the developer manually encodes the calling contract inside the tool's [Description]. When the contract is omitted, `call_tool` fails at runtime with a "missing required parameter" error.

This differs from normal function/MCP tool calling, where the full parameter schema (names + per-parameter descriptions) is sent to the model.

Repro (.NET, Microsoft.Agents.AI.Hyperlight 1.15.0-preview.260722.1)
```
public static class InventoryTools
{
[Description("Gets the stock level (units on hand) of a spare part.")]
public static int GetStock(string partNumber) => partNumber switch
{
"BRG-4410" => 12, "SEAL-220" => 3, "FLT-901" => 47, _ => 0
};

[Description("Gets the unit price in EUR of a spare part.")]
public static decimal GetPrice(string partNumber) => partNumber switch
{
"BRG-4410" => 89.50m, "SEAL-220" => 14.25m, "FLT-901" => 6.80m, _ => 0m
};
}

var options = HyperlightCodeActProviderOptions.CreateForJavaScript();
options.Tools =
[
AIFunctionFactory.Create(InventoryTools.GetStock, "get_stock"),
AIFunctionFactory.Create(InventoryTools.GetPrice, "get_price"),
];

using var codeFunction = new HyperlightExecuteCodeFunction(options);
Console.WriteLine(codeFunction.BuildInstructions()); // inspect what the model sees
```

The generated execute_code description lists the tools like this. note there is no parameter information at all.

```
The following host tools are available inside the sandbox via `call_tool("", **kwargs)`:
- `get_stock`: Gets the stock level (units on hand) of a spare part.
- `get_price`: Gets the unit price in EUR of a spare part.
```

Running a prompt that needs these tools then fails, because the model can't guess the parameter name.
`tool 'get_stock': The arguments dictionary is missing a value for the required parameter 'partNumber'.`

Workaround — bake the calling contract into the description:

```
[Description("""
Gets the stock level (units on hand) of a spare part.
Call as: call_tool("get_stock", { partNumber: "BRG-4410" })
""")]
```

With this, the model emits the correct argument name and the calls succeed.

### Code Sample

```markdown
public static class InventoryTools
{
// NOTE: no calling contract in the description -> model cannot learn the param name
[Description("Gets the stock level (units on hand) of a spare part.")]
public static int GetStock(string partNumber) => partNumber switch
{
"BRG-4410" => 12, "SEAL-220" => 3, "FLT-901" => 47, _ => 0
};

[Description("Gets the unit price in EUR of a spare part.")]
public static decimal GetPrice(string partNumber) => partNumber switch
{
"BRG-4410" => 89.50m, "SEAL-220" => 14.25m, "FLT-901" => 6.80m, _ => 0m
};
}

var options = HyperlightCodeActProviderOptions.CreateForJavaScript();
options.Tools =
[
AIFunctionFactory.Create(InventoryTools.GetStock, "get_stock"),
AIFunctionFactory.Create(InventoryTools.GetPrice, "get_price"),
];

// Inspect exactly what the model is told about the tools:
using var codeFunction = new HyperlightExecuteCodeFunction(options);
Console.WriteLine(codeFunction.BuildInstructions());
// -> lists get_stock / get_price with NAME + DESCRIPTION only. No parameter info.

// Running a prompt that needs these tools then fails (see Error Messages).
```

### Error Messages / Stack Traces

```markdown
tool 'get_stock': The arguments dictionary is missing a value for the required parameter 'partNumber'. (Parameter 'arguments')
```

### Package Versions

Microsoft.Agents.AI: 1.15.0 Microsoft.Agents.AI.OpenAI: 1.15.0 Microsoft.Agents.AI.Hyperlight: 1.15.0-preview.260722.1

### .NET Version

.NET 10.0

### Additional Context

Suspected root cause (from decompiling the shipped `1.15.0-preview.260722.1` DLL): `InstructionBuilder.BuildExecuteCodeDescription`, in its foreach (var tool in tools) loop, appears to append only `tool.Name` and `tool.Description` per tool — I don't see `tool.JsonSchema` read anywhere in the method. If that's correct, parameter-level [Description] attributes are dropped entirely, leaving the tool-level description as the only channel that reaches the model.

There also seems to be no fallback schema channel: `HyperlightExecuteCodeFunction.JsonSchema` returns a hardcoded static declaring only execute_code's own code parameter.

```
{ "type": "object", "properties": { "code": { "type": "string" } }, "required": ["code"] }

```
so nothing structured about the host tools' parameters would reach the model. Please correct me if I'm misreading the decompiled source.

What the model actually receives from BuildInstructions().

```
The following host tools are available inside the sandbox via `call_tool("", **kwargs)`:
- `get_stock`: Gets the stock level (units on hand) of a spare part.
- `get_price`: Gets the unit price in EUR of a spare part.

```
Workaround: encode the calling contract in the description, e.g. Call as:` call_tool("get_stock", { partNumber: "BRG-4410" })`. With this present, the model emits the right argument name and calls succeed.

Minor doc note: the [Hyperlight docs](https://learn.microsoft.com/en-us/agent-framework/integrations/by-component/context-providers/hyperlight) limitation #6 mentions "Tool descriptions, parameter annotations, and return shapes matter more here…", which I initially read as parameter annotations being passed to the model. If the behavior above is correct, that line might be worth a small clarification. The samples all happen to use a single self-evident parameter, so this case doesn't surface in them.

Is the schema is left out deliberately for prompt-size reasons or anything else. Then I'm happy to prepare a focused fix with test coverage serializing each host tool's parameter schema into the `execute_code` listing if the maintainers are comfortable with that. Please let me know whether this can be assigned to me.

Related: this came out of feedback on [my article](https://medium.com/@epcm18/codeact-hyperlight-sandboxed-code-execution-in-the-microsoft-agent-framework-9dbbeeb3aeb9); a maintainer asked me to file it. See also Discussion #5328.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.