diff --git a/docs/dotnet-go-sdk-feature-comparison.md b/docs/dotnet-go-sdk-feature-comparison.md index 97afef6b..04f87968 100644 --- a/docs/dotnet-go-sdk-feature-comparison.md +++ b/docs/dotnet-go-sdk-feature-comparison.md @@ -45,7 +45,7 @@ Intentional contract choices in this parity pass: | 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 selection supports auto, none, require-any, or one required function. | `tool.Tool`, `tool.FuncTool`, `functool.New`, typed input/output schemas, `ToolModeAuto`, `ToolModeNone`, `ToolModeRequired`, `RequireTool`, and a plugin-style grouping sample. | Partial | Core tool-selection semantics align. 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, concurrent invocation, tool approval agent, and the separate `MessageInjectingChatClient` decorator. | `agent/harness/toolautocall` is installed by supporting providers. Supplying `agent.Config.MessageInjector` enables the corresponding internal provider-call decorator; callers queue and inspect messages through that `agent.MessageInjector`. Auto-call supports concurrent invocation, approval-response binding, and approval-not-required call bypass. | Aligned | Go keeps auto-call in explicit middleware and uses an explicit injector, while preserving .NET's separate inner-decorator behavior. | | 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. Approval responses are rebound by request ID to session-snapshotted calls; unknown and duplicate responses are ignored, while safe sibling calls are executed and reinjected on the next turn. | 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. | @@ -214,7 +214,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 fabe1cea..1145872d 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. @@ -533,6 +541,20 @@ func (o LocalConfig) resolvedShell() (resolvedShell, error) { return resolvedShell{binary: binary, kind: classifyShellKind(binary)}, nil } +func (o LocalConfig) toolName() string { + if name := strings.TrimSpace(o.Name); name != "" { + return 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 0e892386..80d766c6 100644 --- a/tool/shelltool/shelltool_test.go +++ b/tool/shelltool/shelltool_test.go @@ -888,6 +888,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,