Skip to content

.NET: feat(dotnet): Add LocalCodeAct package for local Python execution#6105

Open
eavanvalkenburg wants to merge 15 commits into
microsoft:mainfrom
eavanvalkenburg:feature/local-codeact-dotnet
Open

.NET: feat(dotnet): Add LocalCodeAct package for local Python execution#6105
eavanvalkenburg wants to merge 15 commits into
microsoft:mainfrom
eavanvalkenburg:feature/local-codeact-dotnet

Conversation

@eavanvalkenburg
Copy link
Copy Markdown
Member

@eavanvalkenburg eavanvalkenburg commented May 27, 2026

Motivation and Context

Microsoft Foundry hosted agents are already container-isolated, but agent code today has no way to let an LLM author and run Python in-process inside that sandbox. This PR adds a CodeAct provider for .NET that complements the existing Hyperlight and Monty providers with an in-process Python subprocess option, intended for hosts that have already established their own isolation boundary (Foundry hosted agents, Container Apps, dedicated VMs).

This is the .NET counterpart of the Python agent-framework-local-codeact package (PR #6091); both packages share the same Python validator/runner scripts so behavior stays aligned across languages.

Description

Adds a new Microsoft.Agents.AI.LocalCodeAct package plus a unit-test project and two samples.

Package (dotnet/src/Microsoft.Agents.AI.LocalCodeAct):

  • LocalCodeActProviderAIContextProvider that injects an execute_code AIFunction and per-run system instructions describing host tools and mounts.
  • LocalCodeActProviderOptions — approval mode, host tools, file mounts, execution limits, environment, Python executable/runner overrides, and allow/block-list overrides for imports/builtins.
  • LocalExecuteCodeFunction (via Internal/ExecuteCodeFunction) — the execute_code tool surface invoked by the model.
  • Internal/ProcessBridge — JSON-lines IPC between host and Python subprocess (request framing, tool callbacks, response parsing, timeouts).
  • Internal/CodeExecutor — orchestrates validation → subprocess execution → captured-file collection.
  • Internal/CodeValidator — invokes the embedded Python validator via stdin JSON and converts errors to CodeValidationException.
  • Internal/FileMountHelper — normalizes mount paths, snapshots writable mounts before execution, and captures new/modified files after.
  • Internal/InstructionBuilder — renders system instructions that document the tool surface, mounts, and policy.
  • FileMount, ProcessExecutionLimits, LocalCodeActProviderOptions, CodeValidationException — public types.
  • Resources/runner.py, Resources/validator.py — embedded Python scripts kept in sync with the Python package; the validator script is identical apart from a _main() stdin entrypoint used by the .NET host.

Tests (dotnet/tests/Microsoft.Agents.AI.LocalCodeAct.UnitTests):
18 tests covering option validation, instruction-builder output, file-mount normalization, capture limits, provider wiring, and end-to-end Python subprocess integration (LocalExecuteCodeFunctionIntegrationTests).

Samples:

  • dotnet/samples/GettingStarted/AgentProviders/LocalCodeAct — minimal getting-started console sample.
  • dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-LocalCodeAct — Foundry hosted-agent sample with Compute and FetchData tools (mirrors the Python foundry_hosted_agent sample and the existing Hosted-LocalTools layout). Includes Program.cs, HostedLocalCodeAct.csproj, agent.yaml, agent.manifest.yaml, Dockerfile + Dockerfile.contributor (install Python 3 and set LOCAL_CODEACT_PYTHON=python3), .env.example, and a README with the standard run/curl flow.

Validation policy:

  • AST allow-list for imports and builtins (replaceable per call).
  • os.* attribute allow-list of {environ, path} only; every other os.<attr> is rejected. Override via the validator's allowed_os_attrs JSON field.
  • Captured files only come from read-write mounts; the capture helpers skip symlinks and hardlinks and verify that every entry's resolved path stays under the mount root, so a virtual mount path cannot be redirected (via symlink, hardlink, junction, or ..) to data outside its host directory.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? No

Related: companion Python PR #6091.

Copilot AI review requested due to automatic review settings May 27, 2026 08:52
@moonbox3 moonbox3 added documentation Improvements or additions to documentation .NET labels May 27, 2026
@github-actions github-actions Bot changed the title feat(dotnet): Add LocalCodeAct package for local Python execution .NET: feat(dotnet): Add LocalCodeAct package for local Python execution May 27, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 4 | Confidence: 91%

✓ Correctness

This PR has several critical correctness bugs: (1) ProcessBridge deserializes JSON to Dictionary<string, object?> which yields JsonElement values, then uses as Dictionary<string, object?> and Convert.ToInt32() casts that always fail, silently discarding subprocess results and crashing tool calls; (2) LocalCodeActProvider overides a non-existent ProvideContextAsync method instead of the actual base class method ProvideAIContextAsync(InvokingContext, CancellationToken) with incompatible signature and return type; (3) The runner script path is incorrectly passed as the validator script path to CodeValidator; (4) validator.py has no __main__ entry point, so AST validation always passes without actually validating.

✓ Security Reliability

The PR introduces a local Python code execution package with critical security and reliability issues: (1) the runnerScript parameter is incorrectly passed to CodeValidator as the validatorScript, which means if a custom runner script is configured alongside validation lists, the validation step will execute the code instead of validating it; (2) the CodeValidator subprocess has no timeout, creating a potential hang/DoS vector; (3) the _call_tool in runner.py uses id(kwargs) as call_id which can produce 64-bit integers that would overflow when the .NET side uses Convert.ToInt32.

✓ Test Coverage

The test suite covers only construction, metadata, and default values for 3 of the 5 production classes. There are no tests for the core behavior: LocalCodeActProvider.ProvideContextAsync (tool injection and disposal guard), LocalExecuteCodeFunction.InvokeCoreAsync (argument validation, post-dispose exception), CodeValidator.ValidateAsync, or ProcessBridge.RunAsync. The PR rationale acknowledges 'Full execution tests require Python installed and will be added in follow-up,' but several behavioral tests are achievable without Python (e.g., ProvideContextAsync output, InvokeCoreAsync missing 'code' argument, ObjectDisposedException after dispose, CodeValidator construction). Given this is marked as having 'remaining work' for additional tests, these are suggestions rather than blocking issues.

✗ Design Approach

The overall package shape matches the intended CodeAct surface, but I found three design-level blockers in the execution path: the default runner path cannot launch the bundled runner, successful subprocess results are silently discarded when parsed back into .NET, and the default constructor bypasses AST validation even though the package README documents validation as the default behavior.

Flagged Issues

  • ProcessBridge.cs:46 — the default path invokes python -m agent_framework_local_codeact._runner, but the runner is only shipped as an embedded .NET resource with no extraction logic (unlike CodeValidator which extracts its embedded script). Default construction always fails with ModuleNotFoundError.
  • ProcessBridge.cs:128-151 — JsonSerializer.Deserialize<Dictionary<string, object?>> materializes nested JSON as boxed JsonElement values. The as Dictionary<string, object?> cast always returns null, silently discarding all subprocess stdout/stderr/output on every successful execution.
  • LocalExecuteCodeFunction.cs:71-80 — CodeValidator is only instantiated when custom allow/block lists are supplied, contradicting README.md:91 which documents validation as the default behavior. The default constructor path runs unvalidated Python.

Automated review by eavanvalkenburg's agents

Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/LocalExecuteCodeFunction.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/CodeValidator.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/LocalExecuteCodeFunction.cs Outdated
Copy link
Copy Markdown
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

Adds a new .NET package (Microsoft.Agents.AI.LocalCodeAct) intended to run LLM-generated Python in a local subprocess with JSON-lines IPC, plus unit tests and a sample showing basic wiring.

Changes:

  • Introduces a new LocalCodeAct implementation (provider + execute_code function) with embedded Python runner/validator resources.
  • Adds initial unit test project covering basic construction/metadata/defaults.
  • Adds a new sample project and README documentation for usage and configuration.

Reviewed changes

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

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/Microsoft.Agents.AI.LocalCodeAct.csproj New packable project; embeds Resources/*.py and exposes internals to tests.
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Parent-side subprocess IPC bridge + tool dispatch (currently has critical JSON/type and runner-resolution issues).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/CodeValidator.cs .NET wrapper intended to run embedded Python AST validator (currently mismatched with validator script behavior).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/LocalExecuteCodeFunction.cs execute_code tool implementation (currently mismatched with repo’s AIFunction API and validation wiring).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/LocalCodeActProvider.cs AIContextProvider integration (currently overrides a non-existent method in this repo).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessExecutionLimits.cs Resource limit record (timeout/stdout/stderr/file size limits).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/FileMount.cs File mount type definitions (host path + logical mount path + mode).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ExecutionMode.cs ExecutionMode enum (Subprocess-only).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/Resources/runner.py Embedded Python child runner implementing JSON-lines protocol + tool calls.
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/Resources/validator.py Embedded AST validator (currently missing CLI/stdio protocol entrypoint).
dotnet/src/Microsoft.Agents.AI.LocalCodeAct/README.md Package documentation and examples (currently diverges from actual API/behavior).
dotnet/tests/Microsoft.Agents.AI.LocalCodeAct.UnitTests/Microsoft.Agents.AI.LocalCodeAct.UnitTests.csproj New unit test project referencing the new package.
dotnet/tests/Microsoft.Agents.AI.LocalCodeAct.UnitTests/LocalExecuteCodeFunctionTests.cs Basic tests for construction/metadata/disposal (currently missing using System;).
dotnet/tests/Microsoft.Agents.AI.LocalCodeAct.UnitTests/ProcessExecutionLimitsTests.cs Tests for default/custom limit values.
dotnet/tests/Microsoft.Agents.AI.LocalCodeAct.UnitTests/FileMountTests.cs Tests for FileMount defaults/customization.
dotnet/samples/LocalCodeAct/LocalCodeAct.csproj New sample project referencing LocalCodeAct + core agent project.
dotnet/samples/LocalCodeAct/Program.cs Sample demonstrating provider/function instantiation (currently missing using System / System.Threading.Tasks).
dotnet/samples/LocalCodeAct/README.md Sample README with safety guidance and run instructions.

Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/LocalCodeActProvider.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/LocalExecuteCodeFunction.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/ProcessBridge.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/LocalCodeActProvider.cs
Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/CodeValidator.cs Outdated
Comment thread dotnet/samples/LocalCodeAct/Program.cs Outdated
@eavanvalkenburg
Copy link
Copy Markdown
Member Author

File Mount Support and Integration Tests Added

Commit: fad8409

New Features

  1. FileMountHelper.cs (310 lines)

    • NormalizeMountPath() - POSIX path normalization with validation
    • ResolveExistingDirectory() - directory existence verification
    • IterRealFiles() - recursive file walking (skips symlinks)
    • SnapshotWritableMounts() - pre-execution file state capture
    • CaptureWrittenFiles() - post-execution file diff and content extraction
    • Media type detection for common file extensions
  2. Updated LocalExecuteCodeFunction

    • Added fileMounts parameter
    • Snapshots writable mounts before execution
    • Captures written files after execution
    • Returns captured files as AIContent in results
  3. Updated LocalCodeActProvider

    • Added fileMounts parameter pass-through
  4. IntegrationTests.cs (10 test cases)

    • ✅ Execute simple code and return result
    • ✅ Execute code with timeout (throws exception)
    • ✅ Execute code with invalid syntax (returns error)
    • ✅ Execute code with blocked import (validation fails)
    • ✅ Execute code with blocked builtin (validation fails)
    • ✅ Execute code with custom allowed imports
    • ✅ Execute code with file mounts (read from /input, write to /output, capture files)
    • ✅ Execute code with stdout capture
    • ✅ Provider injects tool into context

Implementation Parity

All features from Python agent-framework-local-codeact are now implemented in .NET:

  • ✅ AST validation with custom allow/block lists
  • ✅ Subprocess execution with JSON-lines IPC
  • ✅ Process execution limits (timeout, stdout/stderr caps, result size)
  • ✅ File mount support (read-only, read-write, overlay)
  • ✅ File capture with per-mount and total limits
  • ✅ Symlink-safe file walking
  • ✅ Tool injection and CodeAct instructions
  • ✅ Comprehensive integration tests

Note: Tests are marked to skip when Python is not available, allowing the package to build and basic tests to pass even without Python installed.

eavanvalkenburg added a commit to eavanvalkenburg/agent-framework that referenced this pull request May 27, 2026
Complete rewrite that follows the Hyperlight package conventions
(see Microsoft.Agents.AI.Hyperlight) and addresses all 24 review
comments on PR microsoft#6105:

Architectural fixes:
* LocalCodeActProvider now uses options-class constructor pattern
  matching HyperlightCodeActProvider.
* Override of ProvideAIContextAsync uses the correct
  (InvokingContext, CancellationToken) signature returning
  ValueTask<AIContext>.
* ExecuteCodeFunction follows the AIFunction Name/Description/JsonSchema
  property pattern with InvokeCoreAsync override.
* Provider exposes AddTools/GetTools/RemoveTools/ClearTools and
  AddFileMounts/GetFileMounts/RemoveFileMounts/ClearFileMounts CRUD
  methods, with snapshot-at-invocation semantics under a lock.

Runtime/security fixes:
* Subprocess IPC uses JsonObject/JsonNode end-to-end (no
  Dictionary<string, object?> casts that broke under JsonElement
  deserialization).
* Validator runs in its own subprocess with a dedicated timeout
  (ProcessExecutionLimits.ValidationTimeoutSeconds), never reuses
  the runner script.
* Validation enabled by default; can be opt-ed out via
  ValidationEnabled = false.
* validator.py has a __main__ entrypoint that reads JSON from
  stdin and exits with structured errors.
* validator.py is now compatible with Python 3.9+ (Match nodes
  added conditionally).
* call_id parsed as long to match Python id(kwargs) range.

Other:
* README rewritten with valid C# syntax (options-class, FileMount
  constructor) and accurate descriptions of validator and file
  capture behavior.
* Added integration tests that exercise the real subprocess and
  validator (skipped gracefully when python3 is not on PATH).
* All 18 tests pass (15 unit + 3 integration) across net8/net9/net10.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eavanvalkenburg eavanvalkenburg force-pushed the feature/local-codeact-dotnet branch from 99ff847 to fca0bbc Compare May 27, 2026 14:08
eavanvalkenburg added a commit to eavanvalkenburg/agent-framework that referenced this pull request May 27, 2026
Complete rewrite that follows the Hyperlight package conventions
(see Microsoft.Agents.AI.Hyperlight) and addresses all 24 review
comments on PR microsoft#6105:

Architectural fixes:
* LocalCodeActProvider now uses options-class constructor pattern
  matching HyperlightCodeActProvider.
* Override of ProvideAIContextAsync uses the correct
  (InvokingContext, CancellationToken) signature returning
  ValueTask<AIContext>.
* ExecuteCodeFunction follows the AIFunction Name/Description/JsonSchema
  property pattern with InvokeCoreAsync override.
* Provider exposes AddTools/GetTools/RemoveTools/ClearTools and
  AddFileMounts/GetFileMounts/RemoveFileMounts/ClearFileMounts CRUD
  methods, with snapshot-at-invocation semantics under a lock.

Runtime/security fixes:
* Subprocess IPC uses JsonObject/JsonNode end-to-end (no
  Dictionary<string, object?> casts that broke under JsonElement
  deserialization).
* Validator runs in its own subprocess with a dedicated timeout
  (ProcessExecutionLimits.ValidationTimeoutSeconds), never reuses
  the runner script.
* Validation enabled by default; can be opt-ed out via
  ValidationEnabled = false.
* validator.py has a __main__ entrypoint that reads JSON from
  stdin and exits with structured errors.
* validator.py is now compatible with Python 3.9+ (Match nodes
  added conditionally).
* call_id parsed as long to match Python id(kwargs) range.

Other:
* README rewritten with valid C# syntax (options-class, FileMount
  constructor) and accurate descriptions of validator and file
  capture behavior.
* Added integration tests that exercise the real subprocess and
  validator (skipped gracefully when python3 is not on PATH).
* All 18 tests pass (15 unit + 3 integration) across net8/net9/net10.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
eavanvalkenburg and others added 9 commits May 28, 2026 09:37
Create Microsoft.Agents.AI.LocalCodeAct package with:
- Project file with embedded Python resources
- ExecutionMode enum (Subprocess only)
- ProcessExecutionLimits record
- FileMount record and FileMountMode enum
- README.md documentation
- Embedded Python runner and validator scripts

This is the .NET equivalent of the Python agent-framework-local-codeact
package. Next: Implement process bridge and tool integration.
Copy Python runner and validator scripts from the Python implementation
as embedded resources for the .NET package.
Implement CodeValidator.cs that:
- Extracts embedded Python validator script to temp file
- Invokes Python validator with JSON request
- Passes custom allow/block lists
- Throws CodeValidationException on failures
- Cleans up temp files

Uses the embedded Resources/validator.py for AST validation.
Implement LocalExecuteCodeFunction as AIFunction:
- Accepts Python executable path (required)
- Registers host tools for code to call
- Validates code via CodeValidator if custom lists provided
- Executes via ProcessBridge
- Converts result dict to ChatMessage list
- Builds dynamic description including available tools

Matches Python LocalExecuteCodeTool functionality.
Implement AIContextProvider that:
- Injects execute_code tool into context
- Adds CodeAct instructions
- Enforces single-provider-per-agent via StateKeys
- Wraps LocalExecuteCodeFunction lifecycle

Minimal provider implementation matching Python LocalCodeActProvider.
Add unit tests:
- LocalExecuteCodeFunctionTests (4 tests)
- ProcessExecutionLimitsTests (2 tests)
- FileMountTests (2 tests)

Add sample:
- LocalCodeAct/Program.cs - Demonstrates provider and function usage
- LocalCodeAct/README.md - Documentation and safety warnings

Tests verify basic construction, metadata, and disposal.
Sample shows provider creation, function setup, and configuration.

Note: Build requires .NET 10 SDK per global.json.
Add sample demonstrating:
- LocalCodeActProvider creation and configuration
- LocalExecuteCodeFunction direct usage
- Execution modes and file mount configuration
- Safety warnings and prerequisites

Includes project file and README with security guidance.
- Added FileMountHelper.cs for file mount normalization, snapshot, and capture
- Updated LocalExecuteCodeFunction to support file mounts parameter
- Added file snapshot before/after execution with capture logic
- Updated LocalCodeActProvider to pass file mounts through
- Created comprehensive IntegrationTests.cs with 10 test cases:
  - Simple code execution
  - Timeout handling
  - Syntax error handling
  - Blocked import validation
  - Blocked builtin validation
  - Custom allowed imports
  - File mount read/write with capture
  - Stdout capture
  - Provider tool injection

All features from Python implementation now ported to .NET.
Complete rewrite that follows the Hyperlight package conventions
(see Microsoft.Agents.AI.Hyperlight) and addresses all 24 review
comments on PR microsoft#6105:

Architectural fixes:
* LocalCodeActProvider now uses options-class constructor pattern
  matching HyperlightCodeActProvider.
* Override of ProvideAIContextAsync uses the correct
  (InvokingContext, CancellationToken) signature returning
  ValueTask<AIContext>.
* ExecuteCodeFunction follows the AIFunction Name/Description/JsonSchema
  property pattern with InvokeCoreAsync override.
* Provider exposes AddTools/GetTools/RemoveTools/ClearTools and
  AddFileMounts/GetFileMounts/RemoveFileMounts/ClearFileMounts CRUD
  methods, with snapshot-at-invocation semantics under a lock.

Runtime/security fixes:
* Subprocess IPC uses JsonObject/JsonNode end-to-end (no
  Dictionary<string, object?> casts that broke under JsonElement
  deserialization).
* Validator runs in its own subprocess with a dedicated timeout
  (ProcessExecutionLimits.ValidationTimeoutSeconds), never reuses
  the runner script.
* Validation enabled by default; can be opt-ed out via
  ValidationEnabled = false.
* validator.py has a __main__ entrypoint that reads JSON from
  stdin and exits with structured errors.
* validator.py is now compatible with Python 3.9+ (Match nodes
  added conditionally).
* call_id parsed as long to match Python id(kwargs) range.

Other:
* README rewritten with valid C# syntax (options-class, FileMount
  constructor) and accurate descriptions of validator and file
  capture behavior.
* Added integration tests that exercise the real subprocess and
  validator (skipped gracefully when python3 is not on PATH).
* All 18 tests pass (15 unit + 3 integration) across net8/net9/net10.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The embedded Python validator script used by the .NET LocalCodeAct
package now enforces the builtin allow-list, matching the latest
behavior of agent_framework_local_codeact._validator. Names that are
real Python builtins must appear in the allow-list, while unknown names
(user-defined functions, registered tools) remain allowed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirrors the Python foundry_hosted_agent.py sample for the local-codeact
package: registers compute and fetch_data as sandbox-only host tools on
LocalCodeActProvider so the model only sees execute_code and reaches them
via await call_tool(...). Includes the standard hosted-agent supporting
files (agent.yaml, agent.manifest.yaml, Dockerfile, Dockerfile.contributor,
.env.example, README.md) and installs python3 in the container images so
the embedded runner and validator can execute.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirror the Python package change: the embedded validator.py invoked by the
.NET ProcessBridge replaces the os.* deny-list with an allow-list of
{environ, path}. Add allowed_os_attrs parameter to validate_code and
_CodeValidator, and surface it via the stdin JSON request schema so the
.NET host can opt in to a broader allow-list when needed.

Default behavior tightens to match the documented contract: any os.*
attribute outside {environ, path} (for example os.listdir, os.open,
os.getcwd) is rejected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eavanvalkenburg eavanvalkenburg marked this pull request as ready for review May 28, 2026 09:07
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 2 | Confidence: 89%

✓ Test Coverage

The PR adds 18 tests covering constructor validation, property defaults, provider wiring, and 3 integration tests. However, several critical internal components have no unit-level test coverage: FileMountHelper's capture-limit enforcement paths (3 separate branches), ProcessBridge's tool-call error handling (unknown tool, missing name, tool exception), CodeValidator's timeout and error extraction logic, and the various code-parameter type conversions in InvokeCoreAsync. The integration tests require Python on PATH and will be skipped in environments without it, meaning CI may have zero coverage of actual execution paths.

✗ Design Approach

LocalCodeActProviderOptions and the package README both say that omitting Environment yields a minimal, non-inherited environment, but ProcessBridge returns early on the null path and therefore inherits the full parent process environment instead.

Flagged Issues

  • ProcessBridge inherits the full parent environment when Environment is null (ProcessBridge.cs:110-112), contradicting the documented invariant in LocalCodeActProviderOptions and the README that the default is a minimal, non-inherited environment.

Automated review by eavanvalkenburg's agents

Comment thread dotnet/src/Microsoft.Agents.AI.LocalCodeAct/Resources/validator.py
- validator.py: enforce os.* allow-list on `from os import X` so names like
  `system`, `getcwd` cannot bypass the visit_Attribute restriction.
- ProcessBridge.ConfigureEnvironment: document that null Environment inherits
  the parent env (matching real behavior) and update the public
  LocalCodeActProviderOptions.Environment doc to describe the explicit
  empty-dictionary opt-in for a scrubbed environment.
- Tests:
  * FileMountHelperTests covers per-file, per-mount, and total
    capture-limit branches that return TextContent omissions.
  * Integration tests cover unknown-tool dispatch error, tool throwing
    exception, and CodeValidator timeout that kills the process and
    raises CodeValidationException.
- Sample: drop unused `Microsoft.Agents.AI.Foundry` using in
  Hosted-LocalCodeAct/Program.cs to satisfy IDE0005 check-format.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The dotnet/samples/LocalCodeAct/ scaffolding sample referenced APIs
that don't exist in the current package (`ExecutionMode`, FileMount
object-initializer syntax, the old LocalExecuteCodeFunction
constructor signature, function.Metadata.*), produced a long list of
check-format violations (CHARSET, IMPORTS, IDE0073 header, IDE0005
unused using, IDE1006 Async suffix, RCS1037 trailing whitespace), and
did not match any of the documented sample layouts.

The hosted-agent example at
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-LocalCodeAct
is the supported entry-point sample for this package.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add UTF-8 BOM to source files (CHARSET)
- Remove unused using directives (IDE0005)
- Simplify type names (IDE0001/IDE0002/IDE0090)
- Rename static field JsonOptions -> s_jsonOptions (IDE1006)
- Rename static field SyncRoot -> s_syncRoot (IDE1006)
- Add missing this. qualifications in ProcessBridge (IDE0009)
- Remove unused _options field from LocalCodeActProvider (IDE0052)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation .NET

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants