AgentMesh Documentation

Give agents reliable capabilities

Build function tools, wrap sub-agents, or ship production retrievers with consistent validation and observability.

Tools let models trigger deterministic side effects—API calls, computations, retrieval queries, or even other agents—while respecting schema validation and observability. Everything lives under tool/ and works with the shared core.Tool contract, while tool/retrieval adds convenience helpers for search-style capabilities.

Examples assume am := github.com/hupe1980/agentmesh and core := github.com/hupe1980/agentmesh/core.


Function tools

tool.NewFuncTool and tool.NewFuncToolFromType wrap pure Go functions with JSON Schema validation. They are perfect when you want quick utility functions or lightweight integrations.

  • When to use: simple RPC-like operations, deterministic calculations, thin wrappers over internal services.
  • Behavior:
    • Validates incoming JSON arguments against your schema before calling the function
    • Normalizes errors to tool.Error codes (VALIDATION_ERROR, EXECUTION_ERROR)
    • Runs safely in parallel; no shared mutable state
type SumArgs struct {
  A float64 `json:"a"`
  B float64 `json:"b"`
}

sumTool, _ := tool.NewFuncToolFromType("calculate_sum", "Add two numbers", SumArgs{}, func(ctx context.Context, tc core.ToolContext, args SumArgs) (any, error) {
  return args.A + args.B, nil
})

planner, _ := am.NewModelAgent("planner", llm, func(o *am.ModelAgentOptions) {
  o.Tools = []core.Tool{sumTool}
})

Prefer handwritten schemas? NewFuncTool accepts a map[string]any schema instead of deriving it from a struct.


Toolsets

Registering dozens of tools up front can overwhelm the prompt. Implement core.Toolset to load tools on demand based on the current context, or reuse the built-in adapters (for example, MCP).

  • When to use: dynamic connectors, per-user tool catalogs, or rate-limited APIs.
  • Behavior:
    • Toolsets decide at call time which tools to expose via ListTools
    • Works alongside inline tools; the executor merges duplicates by name
    • Often paired with caching or feature flags to keep prompts trim
type DocsToolset struct{}

func (DocsToolset) ListTools(ctx context.Context, ro core.ReadonlyContext) ([]core.Tool, error) {
  // e.g., only surface tools relevant to the active workspace
  return []core.Tool{sumTool, searchDocsTool}, nil
}

researcher, _ := am.NewModelAgent("researcher", llm, func(o *am.ModelAgentOptions) {
  o.Toolsets = []core.Toolset{DocsToolset{}}
})

MCP toolset

The tool/mcp adapter lets you connect to external MCP servers and expose their declared tools to your agents. It handles session pooling, schema conversion, and remote execution over stdio or HTTP transports.

  • When to use: integrate hosted tool providers, share capabilities with other MCP-compliant runtimes, or proxy heavy operations out of process.
  • Behavior:
    • Discovers remote tools at runtime via ListTools
    • Reuses pooled sessions keyed by auth headers for efficiency
    • Supports stdio (command), streamable HTTP, and SSE transports out of the box
import mcptool "github.com/hupe1980/agentmesh/tool/mcp"

factory := mcptool.NewStdioSessionFactory("mcp-server", []string{"serve"})
mcpToolset := mcptool.NewToolset(factory, func(o *mcptool.ToolsetOptions) {
  o.NamePrefix = "remote"
})
defer mcpToolset.Close()

planner, _ := am.NewModelAgent("planner", llm, func(o *am.ModelAgentOptions) {
  o.Toolsets = append(o.Toolsets, mcpToolset)
})

Need to authenticate over HTTP instead? Swap in mcptool.NewStreamableSessionFactory or mcptool.NewSSESessionFactory with custom headers. The adapter forwards ToolContext metadata so nested tool calls can still access artifacts and plugins.


AgentTool

tool.NewAgentTool turns an existing agent into a tool, allowing higher-level planners to delegate entire flows. It spins up a nested runner with isolated artifacts and state.

  • When to use: hierarchical planners, reusable sub-agents, fallback escalation paths.
  • Behavior:
    • Shares the caller’s plugin manager and artifact store via ToolContext
    • Streams events back into the parent run; final text becomes the tool response
    • Works with any core.Agent (model-based or purely functional)
summarizer := am.NewSequentialAgent("summarizer", []core.Agent{writer, editor})
summarizerTool := tool.NewAgentTool(summarizer)

planner, _ := am.NewModelAgent("planner", llm, func(o *am.ModelAgentOptions) {
  o.Tools = append(o.Tools, summarizerTool)
})

LangChainGo tool

The tool/langchaingo adapter wraps any langchaingo tools.Tool so it can be used as an AgentMesh core.Tool without rewriting integrations. Try it with the built-in calculator from github.com/tmc/langchaingo/tools—the same one showcased in examples/langchaingo.

  • When to use: reuse existing LangChainGo tool implementations alongside native AgentMesh tools.
  • Behavior:
    • Mirrors name and description from the wrapped tool by default (override via options)
    • Presents a single string argument (__arg1) that is forwarded to the LangChainGo tool
    • Surfaces validation errors using tool.Error for consistent error handling
import (
  langchainTool "github.com/hupe1980/agentmesh/tool/langchaingo"
  lctools "github.com/tmc/langchaingo/tools"
)

calcTool := langchainTool.NewTool(&lctools.Calculator{})

planner, _ := am.NewModelAgent("planner", llm, func(o *am.ModelAgentOptions) {
  o.Tools = append(o.Tools, calcTool)
})

Need additional metadata or custom validation? Pass option functions to NewTool to override the generated name and description or wrap the result with your own schema enforcement.


Retrieval tools

The tool/retrieval helpers make it easy to expose search connectors as strongly typed tools and to compose multiple retrievers together.

Wrap retrievers as tools

retrieval.NewTool converts any retrieval.Retriever into a regular core.Tool that accepts a query string. Returned documents use the shared retrieval.Document shape (PageContent, Score, Metadata) so downstream agents receive consistent payloads.

retriever := retrieval.NewMergerRetriever([]retrieval.Retriever{bedrock, kendra})

searchTool := retrieval.NewTool(
  "knowledge_base_search",
  "Search the enterprise knowledge sources and return the top documents.",
  retriever,
)

planner, _ := am.NewModelAgent("planner", llm, func(o *am.ModelAgentOptions) {
  o.Tools = append(o.Tools, searchTool)
})

Merger retriever

retrieval.NewMergerRetriever fans out to multiple retrievers and merges their document lists. Use option functions to tune behavior:

  • WithMergerMaxParallel(n) bounds concurrent requests (default is 4; pass 0 to force sequential execution).
  • WithMergerStopOnFirstError(true) cancels remaining calls after the first failure (default is true); otherwise errors are aggregated via errors.Join and successful documents are still returned.
retriever := retrieval.NewMergerRetriever(
  []retrieval.Retriever{bedrock, kendra, langchain},
  retrieval.WithMergerMaxParallel(2),
  retrieval.WithMergerStopOnFirstError(false),
)

Documents preserve the order of the input retriever slice, and duplicate metadata is left untouched so you can attribute results to the right source.

Built-in connectors

AgentMesh ships ready-to-use retrievers that plug straight into the wrapper above:

  • tool/retrieval/amazonbedrock – call Amazon Bedrock Agent Runtime knowledge bases and translate their scores into retrieval.Document objects.
  • tool/retrieval/amazonkendra – query Amazon Kendra indexes with optional attribute filters and user context.
  • tool/retrieval/langchaingo – adapt any LangChainGo retriever or vector store into the AgentMesh interface.

Each package uses the same Options pattern (func(*Options)) for advanced tuning and includes unit tests demonstrating expected behavior. Mix and match them with MergerRetriever to build hybrid search stacks.


Tool execution

Under the hood, agents rely on tool.NewParallelToolExecutor(maxParallel) to execute function calls. It enforces concurrency limits, records metrics, emits trace spans, and protects against panics.

  • Max concurrency defaults to the batch size; configure it to bound resource usage.
  • Tool runs gain a core.ToolContext exposing session state, artifact helpers, and plugin hooks.
  • Errors are aggregated so the agent can decide whether to retry, escalate, or continue.
selector := flow.NewDefaultSelector(&flow.Executors{
  AgentExecutor: agent.DefaultAgentExecutor,
  ModelExecutor: model.DefaultModelExecutor,
  ToolExecutor:  tool.NewParallelToolExecutor(4),
})

planner, _ := am.NewModelAgent("planner", llm, func(o *am.ModelAgentOptions) {
  o.FlowSelector = selector
  o.Tools = []core.Tool{sumTool, summarizerTool}
})

Combine these building blocks to give agents actionable capabilities without sacrificing determinism or observability.