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]
- 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
Assessment
This issue has not been assessed yet.