Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/dotnet-go-sdk-feature-comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
Expand Down Expand Up @@ -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. |
Expand Down
28 changes: 25 additions & 3 deletions tool/shelltool/localshell.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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"
}
Comment thread
michelle-clayton-work marked this conversation as resolved.

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 {
Expand Down
14 changes: 14 additions & 0 deletions tool/shelltool/shelltool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading