From 892f876dd2401a6ccc1756f5a92f6e4ab2a7592a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 06:21:07 +0000 Subject: [PATCH] [dotnet-port-api] Port shelltool metadata overrides Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/dotnet-go-sdk-feature-comparison.md | 4 ++-- tool/shelltool/localshell.go | 28 +++++++++++++++++++++--- tool/shelltool/shelltool_test.go | 14 ++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/docs/dotnet-go-sdk-feature-comparison.md b/docs/dotnet-go-sdk-feature-comparison.md index 22f52a52..bc62232b 100644 --- a/docs/dotnet-go-sdk-feature-comparison.md +++ b/docs/dotnet-go-sdk-feature-comparison.md @@ -37,7 +37,7 @@ Within overlapping features, the main misalignments are API shape and ecosystem | Message/content model | `ChatMessage`, `AIContent`, text/data/error/function call/function result/hosted file/vector store/reasoning/code interpreter and durable state wrappers. | `message.Message`, `Content`, text/data/error/function call/function result/hosted file/vector store/reasoning/URI/usage/approval/code interpreter content. | Aligned | Type names and serialization are not interchangeable. Go has its own content model rather than using MEAI. | | Annotations/citations | MEAI annotation/content support through `AIContent`. | `message.Annotation`, citation annotations, annotated text spans. | Aligned | No direct binary compatibility; mapping is provider-specific. | | Function tools | `AIFunction`, `AITool`, function tools, plugins, dynamic function tools, tool argument matching in evals. | `tool.Tool`, `tool.FuncTool`, `functool.New`, typed input/output schemas, and a plugin-style grouping sample. | Partial | Go has typed function tools and plugin-style tool grouping, but no first-class plugin abstraction or dynamic tool sample equivalent to .NET steps 12 and 20. | -| Shell tool and environment context | `Microsoft.Agents.AI.Tools.Shell`: `LocalShellExecutor`, `ShellPolicy` (allow/deny-list), `ShellResult`, stateless and persistent shell execution modes, approval-in-the-loop gate, head-tail output truncation, `ShellEnvironmentProvider`, `ShellEnvironmentSnapshot`, shell-family instructions, common CLI probing. | `tool/shelltool.NewLocal`, `shelltool.LocalConfig` (mode, timeout, max output, policy, acknowledge unsafe), `shelltool.Policy`, `shelltool.Result.FormatForModel`, `shelltool.Executor`, `shelltool.NewEnvironmentProvider`, `EnvironmentProviderConfig`, `ShellEnvironmentSnapshot`, `DefaultShellEnvironmentInstructions`. | Aligned | Go mirrors the .NET design for local execution, policy allow/deny-list, approval-required by default, stateless/persistent modes, output truncation, environment snapshot probing, cached first-probe behavior, refresh, current snapshot access, shell-family prompt instructions, invalid/duplicate probe handling, stderr version fallback, caller cancellation, and probe timeout handling. Docker shell executor not ported (Go has no equivalent `DockerShellExecutor`). Go represents tool-version nullability with `ToolVersion{Found bool}` rather than nullable strings. | +| Shell tool and environment context | `Microsoft.Agents.AI.Tools.Shell`: `LocalShellExecutor`, `ShellPolicy` (allow/deny-list), `ShellResult`, stateless and persistent shell execution modes, approval-in-the-loop gate, configurable tool name/description, head-tail output truncation, `ShellEnvironmentProvider`, `ShellEnvironmentSnapshot`, shell-family instructions, common CLI probing. | `tool/shelltool.NewLocal`, `shelltool.LocalConfig` (name, description, mode, timeout, max output, policy, acknowledge unsafe), `shelltool.Policy`, `shelltool.Result.FormatForModel`, `shelltool.Executor`, `shelltool.NewEnvironmentProvider`, `EnvironmentProviderConfig`, `ShellEnvironmentSnapshot`, `DefaultShellEnvironmentInstructions`. | Aligned | Go mirrors the .NET design for local execution, policy allow/deny-list, approval-required by default, configurable tool name/description, stateless/persistent modes, output truncation, environment snapshot probing, cached first-probe behavior, refresh, current snapshot access, shell-family prompt instructions, invalid/duplicate probe handling, stderr version fallback, caller cancellation, and probe timeout handling. Docker shell executor not ported (Go has no equivalent `DockerShellExecutor`). Go represents tool-version nullability with `ToolVersion{Found bool}` rather than nullable strings. | | Tool auto-calling | Provider/tool-call loop, tool approval agent, and message injection during the function loop (`EnableMessageInjection` / `MessageInjectingChatClient`). | `agent/harness/toolautocall`, default provider middleware unless disabled. Message injection supported via `Config.EnableMessageInjection` and `toolautocall.MessageInjectorFromContext(ctx)`. | Aligned | Go implements auto-call as explicit middleware; .NET uses agent/tool abstractions and provider adapters. | | Tool approval | Tool approval request/response content, tool approval agent and builder extensions, auto-approval rules (heuristics). | `message.ToolApprovalRequestContent`, `message.ToolApprovalResponseContent`, `tool.ApprovalRequiredFunc`, `agent/harness/toolautocall` approval flow, `agent/harness/toolapproval` middleware for standing-rule and auto-approval-rule approval management, AGUI HITL sample. | Aligned | API shape differs: .NET uses a `ToolApprovalAgent` delegating-agent wrapper with `ToolApprovalAgentOptions`; Go uses idiomatic middleware (`toolapproval.New(toolapproval.Config{AutoApprovalRules: ...})`). Standing approval rules, queued-request batching, `AlwaysApprove*` response content, and auto-approval rules (heuristics) are now present in both SDKs. | | Hosted/server-side tools | Foundry/OpenAI samples for code interpreter, file search, web search, OpenAPI, Bing custom search, SharePoint, Microsoft Fabric, memory search, Toolbox, hosted MCP. | `tool/hostedtool` declarations for web search, file search, code interpreter, MCP server; Foundry-first samples cover code interpreter, web search, MCP client tools, and local MCP tools; OpenAI Responses hosted-tool coverage remains provider-specific. | Partial | Go has declaration types and initial Foundry/OpenAI Responses hosted-tool coverage, but fewer service-specific Foundry hosted tool integrations and no Foundry toolbox lifecycle sample. | @@ -202,7 +202,7 @@ The following Go packages and sample groups were present and accounted for in th | `tool/agenttool` | Agent as function tool. | | `tool/hostedtool` | Hosted web search, file search, code interpreter, MCP server declarations. | | `tool/mcptool` | MCP tool bridge and MCP server/client helpers. | -| `tool/shelltool` | Local shell command execution tool with policy allow/deny-list, approval gate, output truncation, raw executor interface, shell environment provider, environment snapshots, shell-family instructions, and common CLI version probing. | +| `tool/shelltool` | Local shell command execution tool with configurable tool metadata, policy allow/deny-list, approval gate, output truncation, raw executor interface, shell environment provider, environment snapshots, shell-family instructions, and common CLI version probing. | | `workflow` | Workflow graph builder, executor bindings, edge model, events, protocol, request ports, state context. | | `workflow/checkpoint` | In-memory checkpoint manager, JSON checkpoint manager, file-system JSON store, and public custom store interface. | | `workflow/inproc` | In-process run/streaming/resume/checkpoint execution environments. | diff --git a/tool/shelltool/localshell.go b/tool/shelltool/localshell.go index 200021bd..276f9e8c 100644 --- a/tool/shelltool/localshell.go +++ b/tool/shelltool/localshell.go @@ -34,6 +34,14 @@ const defaultMaxOutputBytes = 64 * 1024 // LocalConfig configures the shell tool returned by [NewLocal]. type LocalConfig struct { + // Name overrides the tool identifier exposed to the model. When empty, + // [NewLocal] uses the default name "run_shell". + Name string + + // Description overrides the model-facing tool description. When empty, + // [NewLocal] derives a default description from the local shell settings. + Description string + // Shell is an optional override for the shell binary path. When empty, // the AGENT_FRAMEWORK_SHELL environment variable is consulted; if that is // also unset, the OS default is used (/bin/bash on POSIX, pwsh/cmd on @@ -145,12 +153,12 @@ type Local struct { exec *localShellExecutor } -// Name returns the tool identifier (run_shell). -func (t *Local) Name() string { return "run_shell" } +// Name returns the tool identifier. +func (t *Local) Name() string { return t.exec.opts.toolName() } // Description returns the model-facing description of the shell tool. func (t *Local) Description() string { - return t.exec.opts.defaultDescription() + return t.exec.opts.toolDescription() } // Schema returns the JSON schema for the tool's command argument. @@ -535,6 +543,20 @@ func (o LocalConfig) resolvedShell() (resolvedShell, error) { return resolvedShell{binary: binary, kind: classifyShellKind(binary)}, nil } +func (o LocalConfig) toolName() string { + if strings.TrimSpace(o.Name) != "" { + return o.Name + } + return "run_shell" +} + +func (o LocalConfig) toolDescription() string { + if strings.TrimSpace(o.Description) != "" { + return o.Description + } + return o.defaultDescription() +} + func (o LocalConfig) defaultDescription() string { shell, err := o.resolvedShell() if err != nil { diff --git a/tool/shelltool/shelltool_test.go b/tool/shelltool/shelltool_test.go index c72753b9..f8381982 100644 --- a/tool/shelltool/shelltool_test.go +++ b/tool/shelltool/shelltool_test.go @@ -806,6 +806,20 @@ func TestNewLocal_descriptionContainsShellGuidance(t *testing.T) { } } +func TestNewLocal_customNameAndDescription(t *testing.T) { + ft := newLocal(t, shelltool.LocalConfig{ + AcknowledgeUnsafe: true, + Name: "custom_shell", + Description: "Run a custom command.", + }) + if ft.Name() != "custom_shell" { + t.Errorf("expected custom name, got %q", ft.Name()) + } + if ft.Description() != "Run a custom command." { + t.Errorf("expected custom description, got %q", ft.Description()) + } +} + func TestNewLocal_persistentCmdErrors(t *testing.T) { _, err := shelltool.NewLocal(shelltool.LocalConfig{ AcknowledgeUnsafe: true,