Documentation
¶
Overview ¶
Package exec provides a unified facade for tool execution in the toolexec ecosystem.
The exec package simplifies tool execution by combining discovery, execution, and result handling into a single, cohesive API. It integrates with tooldiscovery for tool registration and search, and with run for the underlying execution pipeline.
Overview ¶
Instead of working with multiple packages directly, users can create an Exec instance that handles the complete workflow:
- Tool registration via tooldiscovery's index
- Local handler management
- Tool search and discovery
- Single tool and chain execution
- Documentation retrieval
Basic Usage ¶
// Create discovery index and documentation store
idx := index.NewInMemoryIndex(index.IndexOptions{
Searcher: search.NewBM25Searcher(search.DefaultConfig()),
})
docs := tooldoc.NewInMemoryStore(tooldoc.StoreOptions{Index: idx})
// Register a tool
tool := model.Tool{
Tool: mcp.Tool{Name: "greet", Description: "Greets a user"},
Namespace: "demo",
}
idx.RegisterTool(tool, model.NewLocalBackend("greet-handler"))
// Create executor with local handler
executor, err := exec.New(exec.Options{
Index: idx,
Docs: docs,
LocalHandlers: map[string]exec.Handler{
"greet-handler": func(ctx context.Context, args map[string]any) (any, error) {
return fmt.Sprintf("Hello, %s!", args["name"]), nil
},
},
})
// Execute the tool
result, err := executor.RunTool(ctx, "demo:greet", map[string]any{"name": "World"})
Search and Execute ¶
The package supports a search-then-execute workflow:
results, _ := executor.SearchTools(ctx, "greeting tools", 5)
if len(results) > 0 {
result, _ := executor.RunTool(ctx, results[0].ID, args)
}
Chain Execution ¶
Execute multiple tools in sequence, optionally passing results between steps:
result, steps, err := executor.RunChain(ctx, []exec.Step{
{ToolID: "ns:tool1", Args: map[string]any{"x": 1}},
{ToolID: "ns:tool2", UsePrevious: true}, // receives tool1's result
})
Integration ¶
The exec package integrates with:
- github.com/jonwraymond/tooldiscovery/index for tool registration and lookup
- github.com/jonwraymond/tooldiscovery/tooldoc for tool documentation
- github.com/jonwraymond/toolexec/run for the underlying execution pipeline
- github.com/jonwraymond/toolfoundation/model for tool and backend types
Index ¶
- Constants
- Variables
- type CodeParams
- type CodeResult
- type Exec
- func (e *Exec) DocStore() tooldoc.Store
- func (e *Exec) GetToolDoc(ctx context.Context, toolID string, level tooldoc.DetailLevel) (tooldoc.ToolDoc, error)
- func (e *Exec) Index() index.Index
- func (e *Exec) RunChain(ctx context.Context, steps []Step) (Result, []StepResult, error)
- func (e *Exec) RunTool(ctx context.Context, toolID string, args map[string]any) (Result, error)
- func (e *Exec) SearchTools(ctx context.Context, query string, limit int) ([]ToolSummary, error)
- type Handler
- type Options
- type Result
- type Step
- type StepResult
- type ToolCall
- type ToolSummary
Examples ¶
Constants ¶
const ( DefaultMaxToolCalls = 100 DefaultLanguage = "go" DefaultTimeout = 30 * time.Second )
Default configuration values.
Variables ¶
var ( ErrIndexRequired = errors.New("exec: Index is required") ErrDocsRequired = errors.New("exec: Docs store is required") )
Errors returned by Options validation.
Functions ¶
This section is empty.
Types ¶
type CodeParams ¶
type CodeParams struct {
// Language specifies the programming language.
// If empty, Options.DefaultLanguage is used.
Language string
// Code is the source code to execute.
Code string
// Timeout overrides Options.DefaultTimeout for this execution.
// If zero, the default timeout is used.
Timeout time.Duration
// MaxToolCalls overrides Options.MaxToolCalls for this execution.
// If zero, the default limit is used.
MaxToolCalls int
// AllowedTools restricts which tools the code can call.
// If nil or empty, all registered tools are allowed.
AllowedTools []string
// Env provides environment variables for the execution.
Env map[string]string
}
CodeParams configures a code execution request.
type CodeResult ¶
type CodeResult struct {
// Value is the final return value from the code.
Value any
// ToolCalls contains information about each tool call made during execution.
ToolCalls []ToolCall
// Duration is the total execution time.
Duration time.Duration
// Stdout contains captured standard output.
Stdout string
// Stderr contains captured standard error.
Stderr string
// Error is non-nil if execution failed.
Error error
}
CodeResult represents the outcome of code execution with tool access.
type Exec ¶
type Exec struct {
// contains filtered or unexported fields
}
Exec is the unified facade for tool execution. It combines discovery, execution, and result handling into a single API.
func New ¶
New creates a new Exec instance with the given options.
Example ¶
package main
import (
"context"
"fmt"
"github.com/jonwraymond/tooldiscovery/index"
"github.com/jonwraymond/tooldiscovery/search"
"github.com/jonwraymond/tooldiscovery/tooldoc"
"github.com/jonwraymond/toolexec/exec"
)
func main() {
// Create discovery index and documentation store
idx := index.NewInMemoryIndex(index.IndexOptions{
Searcher: search.NewBM25Searcher(search.BM25Config{}),
})
docs := tooldoc.NewInMemoryStore(tooldoc.StoreOptions{Index: idx})
// Create executor with local handler
executor, err := exec.New(exec.Options{
Index: idx,
Docs: docs,
LocalHandlers: map[string]exec.Handler{
"greet-handler": func(ctx context.Context, args map[string]any) (any, error) {
name, _ := args["name"].(string)
return fmt.Sprintf("Hello, %s!", name), nil
},
},
})
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Executor created:", executor != nil)
}
Output: Executor created: true
func (*Exec) GetToolDoc ¶
func (e *Exec) GetToolDoc(ctx context.Context, toolID string, level tooldoc.DetailLevel) (tooldoc.ToolDoc, error)
GetToolDoc retrieves tool documentation at the specified detail level.
func (*Exec) Index ¶
Index returns the underlying tool index. This allows advanced usage patterns like direct tool registration.
func (*Exec) RunChain ¶
RunChain executes a sequence of tools. Returns the final result, a slice of step results, and any error.
Example ¶
package main
import (
"context"
"fmt"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/jonwraymond/tooldiscovery/index"
"github.com/jonwraymond/tooldiscovery/search"
"github.com/jonwraymond/tooldiscovery/tooldoc"
"github.com/jonwraymond/toolexec/exec"
"github.com/jonwraymond/toolfoundation/model"
)
func main() {
// Setup
idx := index.NewInMemoryIndex(index.IndexOptions{
Searcher: search.NewBM25Searcher(search.BM25Config{}),
})
docs := tooldoc.NewInMemoryStore(tooldoc.StoreOptions{Index: idx})
// Register an add tool
addTool := model.Tool{
Tool: mcp.Tool{
Name: "add",
Description: "Adds two numbers",
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"a": map[string]any{"type": "number"},
"b": map[string]any{"type": "number"},
},
},
},
Namespace: "math",
}
_ = idx.RegisterTool(addTool, model.NewLocalBackend("add-handler"))
// Create executor
executor, _ := exec.New(exec.Options{
Index: idx,
Docs: docs,
LocalHandlers: map[string]exec.Handler{
"add-handler": func(ctx context.Context, args map[string]any) (any, error) {
a, _ := args["a"].(float64)
b, _ := args["b"].(float64)
return a + b, nil
},
},
ValidateInput: false,
ValidateOutput: false,
})
// Execute a chain of operations
ctx := context.Background()
result, steps, err := executor.RunChain(ctx, []exec.Step{
{ToolID: "math:add", Args: map[string]any{"a": float64(5), "b": float64(3)}},
{ToolID: "math:add", Args: map[string]any{"a": float64(10), "b": float64(2)}},
})
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Steps completed:", len(steps))
fmt.Println("Final result:", result.Value)
}
Output: Steps completed: 2 Final result: 12
func (*Exec) RunTool ¶
RunTool executes a single tool by ID and returns the result.
Example ¶
package main
import (
"context"
"fmt"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/jonwraymond/tooldiscovery/index"
"github.com/jonwraymond/tooldiscovery/search"
"github.com/jonwraymond/tooldiscovery/tooldoc"
"github.com/jonwraymond/toolexec/exec"
"github.com/jonwraymond/toolfoundation/model"
)
func main() {
// Setup
idx := index.NewInMemoryIndex(index.IndexOptions{
Searcher: search.NewBM25Searcher(search.BM25Config{}),
})
docs := tooldoc.NewInMemoryStore(tooldoc.StoreOptions{Index: idx})
// Register a greeting tool
tool := model.Tool{
Tool: mcp.Tool{
Name: "greet",
Description: "Greets a user",
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"name": map[string]any{"type": "string"},
},
},
},
Namespace: "demo",
}
_ = idx.RegisterTool(tool, model.NewLocalBackend("greet-handler"))
// Create executor
executor, _ := exec.New(exec.Options{
Index: idx,
Docs: docs,
LocalHandlers: map[string]exec.Handler{
"greet-handler": func(ctx context.Context, args map[string]any) (any, error) {
name, _ := args["name"].(string)
return fmt.Sprintf("Hello, %s!", name), nil
},
},
ValidateInput: false,
ValidateOutput: false,
})
// Execute the tool
ctx := context.Background()
result, err := executor.RunTool(ctx, "demo:greet", map[string]any{"name": "World"})
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result.Value)
}
Output: Result: Hello, World!
func (*Exec) SearchTools ¶
SearchTools finds tools matching a query.
Example ¶
package main
import (
"context"
"fmt"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/jonwraymond/tooldiscovery/index"
"github.com/jonwraymond/tooldiscovery/tooldoc"
"github.com/jonwraymond/toolexec/exec"
"github.com/jonwraymond/toolfoundation/model"
)
func main() {
// Setup - use default lexical searcher for simplicity
idx := index.NewInMemoryIndex()
docs := tooldoc.NewInMemoryStore(tooldoc.StoreOptions{Index: idx})
// Register some tools (InputSchema is required)
tools := []model.Tool{
{
Tool: mcp.Tool{
Name: "greet",
Description: "Greets a user with a friendly message",
InputSchema: map[string]any{"type": "object"},
},
Namespace: "demo",
},
{
Tool: mcp.Tool{
Name: "farewell",
Description: "Says goodbye to a user",
InputSchema: map[string]any{"type": "object"},
},
Namespace: "demo",
},
}
for _, t := range tools {
_ = idx.RegisterTool(t, model.NewLocalBackend("handler"))
}
// Create executor
executor, _ := exec.New(exec.Options{
Index: idx,
Docs: docs,
})
// Search for greeting-related tools
ctx := context.Background()
results, err := executor.SearchTools(ctx, "greet", 5)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Found tools:", len(results))
if len(results) > 0 {
fmt.Println("Top result:", results[0].ID)
}
}
Output: Found tools: 1 Top result: demo:greet
type Handler ¶
Handler is the function signature for local tool handlers. It matches run.LocalHandler and local.HandlerFunc for compatibility.
type Options ¶
type Options struct {
// Index provides tool discovery and registration.
// Required.
Index index.Index
// Docs provides tool documentation.
// Required.
Docs tooldoc.Store
// LocalHandlers maps handler names to handler functions.
// These are used when a tool's backend is a local backend
// referencing the handler by name.
LocalHandlers map[string]Handler
// MCPExecutor executes MCP backend tools.
// Optional; if nil, MCP tools cannot be executed.
MCPExecutor run.MCPExecutor
// ProviderExecutor executes provider backend tools.
// Optional; if nil, provider tools cannot be executed.
ProviderExecutor run.ProviderExecutor
// SecurityProfile determines the runtime backend for code execution.
// Default: runtime.ProfileDev
SecurityProfile runtime.SecurityProfile
// EnableCodeExecution enables the code execution subsystem.
// Default: false (tool execution only)
EnableCodeExecution bool
// MaxToolCalls limits tool calls in code execution.
// Default: 100
MaxToolCalls int
// DefaultLanguage for code execution.
// Default: "go"
DefaultLanguage string
// DefaultTimeout for tool and code execution.
// Default: 30s
DefaultTimeout time.Duration
// ValidateInput enables input validation before execution.
// Default: true
ValidateInput bool
// ValidateOutput enables output validation after execution.
// Default: true
ValidateOutput bool
}
Options configures an Exec instance.
type Result ¶
type Result struct {
// Value is the return value from the tool.
Value any
// ToolID is the canonical ID of the executed tool.
ToolID string
// Duration is how long the tool took to execute.
Duration time.Duration
// Error is non-nil if the tool execution failed.
// This is set when the tool itself returns an error,
// not for resolution or validation errors (which are
// returned from RunTool directly).
Error error
}
Result represents the outcome of a single tool execution.
type Step ¶
type Step struct {
// ToolID is the canonical ID of the tool to execute.
ToolID string
// Args are the arguments to pass to the tool.
// If UsePrevious is true and Args is nil, the previous
// step's result is used as the argument map.
Args map[string]any
// UsePrevious indicates that this step should receive
// the previous step's result. If Args is also set,
// the previous result is merged into Args under the
// key "previous" (unless Args already has that key).
UsePrevious bool
// StopOnError determines whether chain execution should
// stop if this step fails. Default is true.
StopOnError *bool
}
Step defines a single step in a chain execution.
type StepResult ¶
type StepResult struct {
// StepIndex is the zero-based index of this step in the chain.
StepIndex int
// ToolID is the canonical ID of the executed tool.
ToolID string
// Args are the arguments passed to this step.
Args map[string]any
// Value is the return value from this step.
Value any
// Duration is how long this step took to execute.
Duration time.Duration
// Error is non-nil if this step failed.
Error error
// Skipped is true if this step was skipped due to a prior failure.
Skipped bool
}
StepResult represents the outcome of a single step in a chain execution.
func (StepResult) OK ¶
func (s StepResult) OK() bool
OK returns true if the step completed successfully.
type ToolCall ¶
type ToolCall struct {
// ToolID is the canonical ID of the called tool.
ToolID string
// Args are the arguments passed to the tool.
Args map[string]any
// Result is the tool's return value.
Result any
// Duration is how long the tool call took.
Duration time.Duration
// Error is non-nil if the tool call failed.
Error error
}
ToolCall represents a tool invocation made during code execution.
type ToolSummary ¶
ToolSummary is an alias to index.Summary for search results.