agents

package
v1.4.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SearchAPIToolsDescription = "" /* 325-byte string literal not displayed */
	SearchAPIToolsInputSchema = `` /* 207-byte string literal not displayed */
)

SearchAPIToolsDescription / SearchAPIToolsInputSchema define the meta-tool as shown to the LLM. The runner adds this tool to a run only when the agent has been granted at least one endpoint-tool.

View Source
const FindAppPageDescription = "" /* 451-byte string literal not displayed */

FindAppPageDescription is what the model reads when deciding to call the tool. It states the one thing the agent cannot work out on its own — that link keys come from here rather than from a guessed URL — because the failure this tool exists to prevent is a confidently invented path.

View Source
const FindAppPageInputSchema = `` /* 206-byte string literal not displayed */

FindAppPageInputSchema is the tool's parameter schema as shown to the model.

View Source
const FindAppPageSlug = "find_app_page"

FindAppPageSlug is the meta-tool a chat agent uses to find the app pages it can link to. Like search_api_tools it is a runtime capability the runner injects rather than a tool a merchant grants: linking a page is part of how a chat reply is written, and every existing agent would otherwise be stuck describing menu paths.

View Source
const SearchAPIToolsSlug = "search_api_tools"

SearchAPIToolsSlug is the meta-tool agents use to discover endpoint-tools on demand (progressive disclosure), instead of having all of them injected up front.

Variables

View Source
var BuiltinTools = []BuiltinToolDescriptor{
	{
		Slug:        constants.ToolCreateArtifact,
		DisplayName: "Create Artifact",
		Description: "Create an artifact such as a report, document, or data export.",
		InputSchema: `{"type":"object","properties":{"artifact_type":{"type":"string","description":"Type of artifact (e.g., report, document, csv)"},"name":{"type":"string","description":"Artifact name"},"content":{"type":"string","description":"Artifact content"},"mime_type":{"type":"string","description":"MIME type of the content (e.g., text/plain, text/csv, application/json)"}},"required":["artifact_type","name","content","mime_type"]}`,
		Group:       builtinGroupGeneral,
	},
	{
		Slug:        constants.ToolReadDoc,
		DisplayName: "Read Doc",
		Description: "Read the content of an OpenMRP documentation page. " +
			"To find the right page, first fetch https://docs.openmrp.ai/llms.txt which lists all available pages with descriptions. " +
			"Then call this tool again with the URL of the page you want to read.",
		InputSchema: `{"type":"object","properties":{"url":{"type":"string","description":"The full URL of the documentation page to read (must be from docs.openmrp.ai). Start with https://docs.openmrp.ai/llms.txt to discover available pages."}},"required":["url"]}`,
		Group:       builtinGroupKnowledge,
	},
	{
		Slug:        constants.ToolFetchUrl,
		DisplayName: "Fetch URL",
		Description: "Fetch the content of a public URL. Returns the response body as text. Only HTTPS URLs are allowed. " +
			"When fetching a website for the first time, check if the site has an /llms.txt file (e.g. https://example.com/llms.txt). " +
			"This file follows the llms.txt standard and lists markdown-formatted URLs optimized for LLM consumption. " +
			"If llms.txt exists and contains relevant URLs, prefer fetching those markdown URLs instead of the raw HTML pages. " +
			"Also look for llms-full.txt for comprehensive content. Skip the llms.txt check for direct links to files, APIs, or non-website URLs.",
		InputSchema: `{"type":"object","properties":{"url":{"type":"string","description":"The HTTPS URL to fetch"}},"required":["url"]}`,
		Group:       builtinGroupKnowledge,
	},
	{
		Slug:        constants.ToolSendEmail,
		DisplayName: "Send Email",
		Description: "Send an email reply to the customer through the conversation's bound inbox. The reply goes to whoever last emailed this thread, threaded correctly. This is an externally-visible action. Only the subject, body, and optional cc are needed — the recipient is determined by the conversation.",
		InputSchema: `{"type":"object","properties":{"cc":{"type":"array","items":{"type":"string"},"description":"Optional cc addresses"},"subject":{"type":"string","description":"Email subject"},"body":{"type":"string","description":"Email body (plain text)"}},"required":["subject","body"]}`,
		Group:       builtinGroupGeneral,
		Mutating:    true,
	},
	{
		Slug:        constants.ToolDraftReply,
		DisplayName: "Draft Reply",
		Description: "Propose a reply to the external party on a case — whoever the case corresponds with (a customer, supplier, or other contact reachable over the case's inbox). The draft is held for a human teammate to review, edit, and approve before it is sent — it is NOT sent by this tool. Use it for BOTH channels: if the case is bridged to an email inbox the approved draft is sent as an email reply (set the optional subject); otherwise it is sent as an in-app portal message. The channel is chosen automatically from the case, so you do not need a separate email tool. Provide just the reply body (and, for an email case, an optional subject); you do not need — and will not be given — a conversation ID. Use this to answer the person on the other end; write the message exactly as it should be sent to them.",
		InputSchema: `{"type":"object","properties":{"body":{"type":"string","description":"The outbound reply text, written exactly as it should be sent to the recipient."},"subject":{"type":"string","description":"Optional email subject; used only when the case is email-bridged, ignored otherwise."}},"required":["body"]}`,
		Group:       builtinGroupGeneral,
	},
}

BuiltinTools is the catalog of built-in agent tools. Regenerating is unnecessary — edit this slice directly. Each Slug must have a handler registered in RegisterTools (register.go).

View Source
var EndpointTools = []EndpointToolDescriptor{}/* 304 elements not displayed */

EndpointTools is the generated catalog of api-gateway endpoints exposed as agent tools (endpoints flagged AgentTool=true). Regenerate with `make generate` or `make gen-agent-tools`.

Functions

func AllowedToolGroups

func AllowedToolGroups(allowed map[string]bool) []string

AllowedToolGroups returns the distinct display groups of the endpoint-tools in the allowed set, sorted, so an agent can be told in plain language what domains it can act on.

func HandleCreateArtifact

func HandleCreateArtifact(_ context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)

func HandleDraftReply

func HandleDraftReply(ctx context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)

HandleDraftReply proposes a reply to the case's external party as a real status=draft message held for human approval. Works on any case regardless of who it's with (customer, supplier, other contact) — the channel is resolved server-side (email if bridged, else a portal message) and the draft surfaces in the reply-drafts bar for a human to edit/approve/send. The conversation is fixed by the run, so the agent supplies only the content and never needs (or is given) a conversation id.

func HandleFetchURL

func HandleFetchURL(_ context.Context, input json.RawMessage, _ *domain.HandlerRunContext) (string, error)

func HandleFindAppPage

func HandleFindAppPage(_ context.Context, input json.RawMessage, _ *domain.HandlerRunContext) (string, error)

HandleFindAppPage answers a page lookup with the exact markdown links to write.

The result gives the agent finished link text rather than parts to assemble, because assembling is where it went wrong before: it would reason its way to a plausible `/dashboard/...` URL that the chat renderer has no way to resolve. For a page whose detail view shows a kind of record, the record-link form is included too, since an agent that has just looked up (say) a contracted price usually wants to link that record and not the list it lives on.

func HandleReadDoc

func HandleReadDoc(_ context.Context, input json.RawMessage, _ *domain.HandlerRunContext) (string, error)

func HandleSearchAPITools

func HandleSearchAPITools(_ context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)

HandleSearchAPITools searches the agent's granted endpoint-tools and records the matches as revealed so the runner makes them callable.

func HandleSendEmail

func HandleSendEmail(ctx context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)

HandleSendEmail sends an email reply through the conversation's bound inbox. The tool is gated by human review (see send_email's RequireReview wiring), so by the time this handler runs the send has been approved.

func RegisterEndpointTools

func RegisterEndpointTools(registry *ToolHandlerRegistry)

RegisterEndpointTools registers a handler for every generated endpoint-tool plus the search_api_tools meta-tool. Each endpoint handler maps the LLM's flat input object onto an HTTP call into the api-gateway via the run's GatewayClient.

func RegisterTools

func RegisterTools(registry *ToolHandlerRegistry)

func RevealedSlugsForQueries

func RevealedSlugsForQueries(queries []string, allowed map[string]bool) map[string]bool

RevealedSlugsForQueries replays a run's earlier search_api_tools queries against the supplied grant and returns the union of endpoint-tool slugs they surface. search_api_tools' reveals live only on the per-turn run context, so the runner uses this on resume to restore, from the recorded queries, the set an earlier turn made callable — without it a follow-up message that calls an already-discovered tool is denied until the model re-searches. Scoping the replay to the live grant re-checks permission for free: a query that previously surfaced a since-revoked tool no longer returns it, so the tool stays hidden and the execution guard still denies it.

Types

type ActionPreview

type ActionPreview struct {
	// Operation is the kind of change, for the reviewer's mental model: create, update, delete, action (a named operation like `issue` or `close`) or read.
	Operation string `json:"operation"`
	// Title names the operation the way the API does (the endpoint's display name, e.g. "Update Customer Price").
	Title string `json:"title"`
	// Resource identifies what is being changed. Absent on a create, which has no target yet.
	Resource *PreviewResource `json:"resource,omitempty"`
	// Fields are the values the call sets, in schema order, each with its current value where one could be read.
	Fields []PreviewField `json:"fields"`
	// Identifiers are the path parameters that select the target rather than change it, so the reviewer sees what was addressed without them cluttering the change list.
	Identifiers []PreviewField `json:"identifiers,omitempty"`
	Method      string         `json:"method"`
	Path        string         `json:"path"`
	// BeforeState reports whether current values were readable. False means the rows carry only new values — the reviewer must not read "no current value" as "this field is empty today".
	BeforeState bool `json:"before_state"`
	// Truncated is set when the call sets more fields than the preview carries.
	Truncated bool `json:"truncated,omitempty"`
}

ActionPreview is a reviewable description of what a blocked tool call will do, built when the run pauses and carried on the pause step so both the chat approval card and the run console can render it without re-deriving anything.

It exists because the raw tool input is not reviewable: `{"id":"acpr_x","unit_price":"11.00"}` says nothing about which price is being changed, what it is today, or that the other three fields are staying put. Approving an agent's write is a decision, and a decision needs the before as much as the after — so this resolves the target record and reads its current state, and every field the call sets is presented as current → new.

func BuildActionPreview

func BuildActionPreview(ctx context.Context, slug string, rawInput json.RawMessage, runCtx *domain.HandlerRunContext) *ActionPreview

BuildActionPreview describes a tool call the run is about to pause on.

Never fails: a preview is a review aid, so anything unresolvable (an unparseable schema, an unreadable target) degrades to a thinner preview rather than blocking the pause. Returns nil for a tool with no catalog descriptor (a built-in tool, which has no endpoint to describe) or input that isn't a JSON object — the approval UI falls back to showing the raw input there.

type BuiltinToolDescriptor

type BuiltinToolDescriptor struct {
	Slug                constants.Tool
	DisplayName         string
	Description         string
	InputSchema         string
	Group               BuiltinToolGroup
	RequiredPermissions []string
	// Mutating reports whether invoking this tool takes an externally-visible or otherwise irreversible action (e.g. send_email puts mail in front of a customer). Mutating built-in tools default to requiring human review and that gate cannot be turned off per-agent — the run pauses in awaiting_approval whenever the agent calls one. Read-only tools and tools that only stage something for a human to approve (e.g. draft_reply) are non-mutating.
	Mutating bool
}

BuiltinToolDescriptor describes one built-in agent tool: the runtime fields the LLM needs (Description, InputSchema) plus the metadata the tool-selection UI shows (DisplayName, Group, RequiredPermissions). Category is always "built_in".

func LookupBuiltinTool

func LookupBuiltinTool(slug string) (BuiltinToolDescriptor, bool)

LookupBuiltinTool returns the catalog descriptor for a slug.

type BuiltinToolGroup

type BuiltinToolGroup struct {
	ID        string
	Name      string
	Slug      string
	Icon      string
	SortOrder int32
}

BuiltinToolGroup is the display grouping for the tool-selection UI. These mirror the groups that used to be seeded into tool_group.

func BuiltinToolGroups

func BuiltinToolGroups() []BuiltinToolGroup

BuiltinToolGroups returns the distinct display groups referenced by BuiltinTools, in catalog order.

type EndpointToolDescriptor

type EndpointToolDescriptor struct {
	Slug          string
	DisplayName   string
	Description   string
	Method        string
	RouteTemplate string
	// InputSchema is the self-contained JSON Schema shown to the LLM.
	InputSchema string
	Params      []EndpointToolParam
	// RequiredPermissions are the "<domain>:<action>" permissions this operation needs (from the endpoint's declaration). Surfaced in the tool-selection UI.
	RequiredPermissions []string
	// RequiredRoleType, when non-empty, is the role type the caller must have (e.g. "admin"). Surfaced in the tool-selection UI.
	RequiredRoleType string
	// Group is the display group for the tool-selection UI (e.g. "Customers").
	Group string
	// ReadOnly mirrors the endpoint's own declaration that it computes an answer without changing anything despite not being a GET (a quote, a preview, an analytics query). Generated from the endpoint, never inferred here.
	ReadOnly bool
}

EndpointToolDescriptor is the generated description of an api-gateway endpoint exposed as an agent tool. The catalog of these (EndpointTools) is code-generated from endpoints that are public or flagged AgentTool=true; see `make gen-agent-tools`. These tools are offered to every agent in addition to its explicitly-linked hand-crafted tools — adding one needs no database migration, only a regenerate.

func LookupEndpointTool

func LookupEndpointTool(slug string) (EndpointToolDescriptor, bool)

LookupEndpointTool returns the catalog descriptor for a slug.

func SearchEndpointTools

func SearchEndpointTools(query string, allowed map[string]bool, limit int) []EndpointToolDescriptor

SearchEndpointTools returns up to limit catalog tools matching query, restricted to the allowed set. Matching is simple term overlap against each tool's slug and description.

func (EndpointToolDescriptor) Mutating

func (d EndpointToolDescriptor) Mutating() bool

Mutating reports whether invoking this tool changes server state.

The method is the default answer, because a POST or PUT that writes nothing is the exception rather than the rule — but it is only the default. Quotes, previews and analytics take a request body and so cannot be GETs, and reporting those as mutating puts them in front of a merchant deciding which tools an agent may run unsupervised, next to the ones that actually create orders. The endpoint says which it is; this reads that.

type EndpointToolParam

type EndpointToolParam struct {
	Name  string
	In    EndpointToolParamLocation
	Array bool
}

EndpointToolParam describes one input field of a generated endpoint-tool and where it belongs in the outgoing request.

type EndpointToolParamLocation

type EndpointToolParamLocation string

EndpointToolParamLocation identifies where a tool input value goes when building the gateway HTTP request.

const (
	EndpointToolParamPath  EndpointToolParamLocation = "path"
	EndpointToolParamQuery EndpointToolParamLocation = "query"
	EndpointToolParamBody  EndpointToolParamLocation = "body"
)

type PreviewField

type PreviewField struct {
	// Key is the dotted input path (`freight.carrier_id`), kept so a reviewer can tie a row back to the API field.
	Key string `json:"key"`
	// Label is the field's human name, including its parent group ("Freight › Carrier").
	Label string `json:"label"`
	// After is the value the call sets, and Before the value it replaces (absent when unread or unset).
	After  any `json:"after"`
	Before any `json:"before,omitempty"`
	// Changed is false when the call sets a field to the value it already holds — worth showing, but not as a change.
	Changed bool `json:"changed"`
	// Format hints at rendering (`decimal`, `date`, `date-time`, `id`, `enum`, `bool`).
	Format string `json:"format,omitempty"`
	// Description is the field's API documentation, for a reviewer who needs to know what the field means.
	Description string `json:"description,omitempty"`
}

PreviewField is one value a call sets, paired with the value it replaces.

type PreviewResource

type PreviewResource struct {
	Object string `json:"object,omitempty"`
	ID     string `json:"id,omitempty"`
	// Label is the record's human name or number, read from the record itself.
	Label string `json:"label,omitempty"`
	// Linkable reports whether the frontend has a detail page for this object type.
	Linkable bool `json:"linkable"`
}

PreviewResource identifies the record an action targets, in the same shape the frontend's resource-link registry consumes — so the preview header can link straight to the record.

type ToolHandlerRegistry

type ToolHandlerRegistry struct {
	// contains filtered or unexported fields
}

ToolHandlerRegistry maps tool slugs to their handler functions.

func NewToolHandlerRegistry

func NewToolHandlerRegistry() *ToolHandlerRegistry

func (*ToolHandlerRegistry) Get

func (*ToolHandlerRegistry) Register

func (r *ToolHandlerRegistry) Register(slug string, fn domain.ToolHandlerFunc)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL