Documentation / SDK and API
Tools
Add your own tools to the agent, and control what it can use.
A tool is a function the model can call. Seshat ships with many (files, shell, search, web, tasks, notebooks, memory…). You add yours by implementing the Tool interface from github.com/KPO-Tech/seshat/pkg/tools, then registering it.
A custom tool
import "github.com/KPO-Tech/seshat/pkg/tools"
type Clock struct{}
func (Clock) Definition() tools.Definition {
return tools.Definition{
Name: "current_time",
Description: "Return the current UTC time.",
InputSchema: tools.FromMap(map[string]any{
"type": "object",
"properties": map[string]any{},
}),
IsReadOnly: true,
}
}
func (Clock) Call(ctx context.Context, in tools.CallInput, can tools.CanUseToolFn) (tools.CallResult, error) {
return tools.NewTextResult(time.Now().UTC().Format(time.RFC3339)), nil
}
func (Clock) Description(ctx context.Context) (string, error) {
return "Return the current UTC time.", nil
}
func (Clock) ValidateInput(ctx context.Context, in map[string]any) (map[string]any, error) {
return in, nil
}
func (Clock) CheckPermissions(ctx context.Context, in map[string]any, tc tools.ToolUseContext) tools.PermissionResult {
return tools.Passthrough(in) // let the global permission rules decide
}
func (Clock) IsConcurrencySafe(in map[string]any) bool { return true }
func (Clock) IsReadOnly(in map[string]any) bool { return true }
func (Clock) IsEnabled() bool { return true }
func (Clock) FormatResult(data any) string { return fmt.Sprint(data) }
func (Clock) BackfillInput(ctx context.Context, in map[string]any) map[string]any { return in }
Register it on the client, to make it available in every session, or on one session:
client.RegisterTool(Clock{}) // all sessions
session.RegisterTool(Clock{}) // this session only
You can also pass tools to a single Ask call: client.Ask(ctx, prompt, []sdk.Tool{Clock{}}).
Reporting errors
Return an error from Call only for a failure the runtime cannot recover from, such as a cancelled context. A problem the model should know about (bad input, file not found) goes back as a result built with tools.NewErrorResult(err), so the model sees it and can adapt.
Results
| Helper | Use |
|---|---|
tools.NewTextResult(text) | A plain text answer |
tools.NewJSONResult(data) | Structured data. Set .Content afterwards if you want a human-readable summary |
tools.NewErrorResult(err) | A failure the model should see |
Permissions
Each tool call goes through the permission pipeline before it runs. A tool can add its own rule in CheckPermissions, and returns tools.Passthrough when it has nothing to add. IsReadOnly and IsConcurrencySafe let the runtime run safe calls in parallel and treat read-only calls more leniently.
How approvals work, and the available modes, are described in Streaming, events and hooks.
Seeing what the agent has
names := client.ToolNames() // every tool name
surface, err := client.BuildToolSurface(ctx) // the tools as the model sees them
Tools from MCP servers
MCP servers add tools without any Go code. See Skills and MCP. You can change them while the client runs with client.ReloadMCPServers(ctx, servers).
Updated on 2026-10-07