// keenableToolDescription follows the upstream Python tool's description,
// trimmed for the chat model. The "no API key required" line is the
// differentiator from Tavily/DuckDuckGo/SearXNG.
constkeenableToolDescription=`Keenable is a web search API built for AI agents. It returns fresh, relevant web results for a query and works without an API key by default (keyless free tier). When searching:
- Use a focused query of the most important terms (and synonyms).
- Optionally restrict to a single site/domain.`
// keenableParams is the JSON shape the model sends into InvokableRun.
// site is an optional single-domain filter. mode is "pro" (default,
// deeper) or "realtime" (requires a server-configured key). top_n caps
// how many results we keep from the upstream `results` array.
typekeenableParamsstruct{
Querystring`json:"query"`
Sitestring`json:"site"`
Modestring`json:"mode"`
TopNint`json:"top_n"`
}
// keenableRequestBody is the JSON body POSTed to the Keenable search
// endpoint. Mirrors the upstream Python tool — query, mode, and an
// optional site filter.
typekeenableRequestBodystruct{
Querystring`json:"query"`
Modestring`json:"mode"`
Sitestring`json:"site,omitempty"`
}
// keenableResult mirrors one element of the upstream `results` array.
// The Python tool's _retrieve_chunks reads `title`, `url`, `description`,
// so we model those fields and pass everything else through verbatim
// when serializing to the model.
typekeenableResultstruct{
Titlestring`json:"title"`
URLstring`json:"url"`
Descriptionstring`json:"description"`
}
// keenableResponse is the envelope returned by Keenable. We only model
// the fields we care about; the upstream API has more, but they are
// ignored.
typekeenableResponsestruct{
Results[]keenableResult`json:"results"`
}
// keenableEnvelope is the shape the model actually sees, identical to
// the Python tool's output convention.
typekeenableEnvelopestruct{
Results[]keenableResult`json:"results"`
Errorstring`json:"_ERROR,omitempty"`
}
// KeenableTool is the Keenable web search tool. It POSTs a search
// request to the public keyless endpoint by default and to the keyed
// endpoint (with X-API-Key) when an API key is provided. The upstream
// `results` array is returned as JSON.
typeKeenableToolstruct{
helper*HTTPHelper
apiKeystring
// envBaseURL resolves the Keenable API base URL from the
// KEENABLE_API_URL env var (HTTPS enforced). Exposed as a
// function so tests can inject a fake without mutating process
// state — matches the envKey pattern used by TavilyTool.
envBaseURLfunc()string
}
// NewKeenableTool returns a KeenableTool using the default HTTPHelper
// and the KEENABLE_API_URL env var for base-URL resolution.
funcNewKeenableTool()*KeenableTool{
returnNewKeenableToolWith(NewHTTPHelper())
}
// NewKeenableToolWithAPIKey returns a KeenableTool that uses a
// server-provided API key instead of model-visible runtime args.