Documentation
¶
Index ¶
- Constants
- Variables
- func AllowedToolGroups(allowed map[string]bool) []string
- func HandleCreateArtifact(_ context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)
- func HandleDraftReply(ctx context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)
- func HandleFetchURL(_ context.Context, input json.RawMessage, _ *domain.HandlerRunContext) (string, error)
- func HandleFindAppPage(_ context.Context, input json.RawMessage, _ *domain.HandlerRunContext) (string, error)
- func HandleReadDoc(_ context.Context, input json.RawMessage, _ *domain.HandlerRunContext) (string, error)
- func HandleSearchAPITools(_ context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)
- func HandleSendEmail(ctx context.Context, input json.RawMessage, runCtx *domain.HandlerRunContext) (string, error)
- func RegisterEndpointTools(registry *ToolHandlerRegistry)
- func RegisterTools(registry *ToolHandlerRegistry)
- func RevealedSlugsForQueries(queries []string, allowed map[string]bool) map[string]bool
- type ActionPreview
- type BuiltinToolDescriptor
- type BuiltinToolGroup
- type EndpointToolDescriptor
- type EndpointToolParam
- type EndpointToolParamLocation
- type PreviewField
- type PreviewResource
- type ToolHandlerRegistry
Constants ¶
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.
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.
const FindAppPageInputSchema = `` /* 206-byte string literal not displayed */
FindAppPageInputSchema is the tool's parameter schema as shown to the model.
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.
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 ¶
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).
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 ¶
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 ¶
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 ¶
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 (r *ToolHandlerRegistry) Get(slug string) (domain.ToolHandlerFunc, bool)
func (*ToolHandlerRegistry) Register ¶
func (r *ToolHandlerRegistry) Register(slug string, fn domain.ToolHandlerFunc)