Documentation
¶
Index ¶
Constants ¶
const ( // LoadSkillToolName is the built-in tool the advertisement tells the model // to call. Callers append LoadSkillTool's output to their own tool list. LoadSkillToolName = "load_skill" )
Variables ¶
var ( ErrNoToolCalling = errors.New("backend did not return a tool call") ErrOutputLimit = errors.New("reply hit the output token limit") ErrIterationLimit = errors.New("tool loop hit the iteration limit") ErrResponseTooLarge = errors.New("response body exceeds the configured cap") ErrNotJSON = errors.New("reply is not JSON") ErrInvalidJSON = errors.New("reply is not valid JSON") )
Every failure a caller can act on is one of these, wrapped with %w so the detail travels without the caller matching on message text.
Functions ¶
func Advertise ¶
Advertise renders the skill catalogue for the system prompt. Output depends only on the set of skills, not on their input order. An empty set renders as the empty string so callers can concatenate unconditionally.
func DecodeJSONObject ¶
DecodeJSONObject parses assistant content as a single JSON object, tolerating inline reasoning, stray prose, and code fences around it. When several candidates parse, the longest wins: the real reply contains every object nested inside it, while the schema sketches that leaked reasoning tends to include ("the shape is {\"stories\": [...]}") are short. Taking the first parseable candidate instead returned those sketches as the reply. Returns ErrNotJSON when no object is present at all, ErrInvalidJSON when braces are present but nothing parses.
func StripReasoning ¶
StripReasoning removes leaked chain-of-thought from assistant content. Closed <think>...</think> blocks are dropped. Some serving templates consume the opening tag, leaving bare reasoning that ends in </think>: everything through the last closing tag is reasoning, not reply. An opening tag left without a closing one opens reasoning that never ends, so everything from it on is dropped too -- a run that stopped inside the model's thinking has no reply, and passing the thinking through as one is worse than returning nothing. The result is trimmed of surrounding space.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is one configured OpenAI-compatible endpoint. It is safe for concurrent use; the SDK client it wraps is immutable after construction.
func NewClient ¶
NewClient builds a client for baseURL. apiKey may be empty for endpoints that need no credential (Ollama and friends), in which case no Authorization header is sent -- including one inherited from the process environment.
func (*Client) ProbeToolCalling ¶
ProbeToolCalling reports whether model can call tools at all. Tool calling is a prerequisite, not a nice-to-have: the loop is built on it, so a model that only produces prose fails here rather than later on real work.
func (*Client) Run ¶
Run drives the tool loop until the model answers without calling a tool. Tool calls are executed sequentially in the order the model emitted them and their results are fed back as tool messages; a tool that fails yields "error: <msg>" rather than ending the run, because the model can recover from a bad argument and cannot recover from a dropped turn.
Every failure that came from the endpoint is opaque: the base URL and the key never appear in a returned error, so a caller that surfaces the error to a browser does not turn the endpoint into a reachability oracle.
type Option ¶
type Option func(*config)
Option configures a Client at construction time. Options never read the environment; every value reaching the wire is supplied by the caller.
func WithHTTPClient ¶
WithHTTPClient supplies the transport. The endpoint is caller-configured, so the SSRF guard, timeout and redirect policy belong to the caller's client.
func WithMaxResponseBytes ¶
WithMaxResponseBytes sets the cap on one decompressed response body. Must be positive; the default is 1 MiB.
func WithUserAgent ¶
WithUserAgent overrides the SDK's User-Agent header.
type RunRequest ¶
type RunRequest struct {
Model string
System string
Prompt string
Tools []Tool
MaxTokens int64
MaxIterations int
Temperature float64
}
RunRequest is one agent run. MaxTokens is required: leaving the budget to the upstream default is what truncates a reply mid-object.
type RunResult ¶
RunResult is a completed run: the final assistant text with inline reasoning removed, plus what it cost in rounds and tool invocations.
type Skill ¶
Skill is one markdown instruction file: YAML-ish frontmatter delimited by "---" lines carrying single-line name and description keys, then a body.
func LoadSkills ¶
LoadSkills reads every *.md file directly under dir; subdirectories are not walked. A file with no parseable frontmatter, no name, no description, or a name already claimed by an earlier file is an error naming every offender -- a broken skill file must fail loudly rather than vanish from the advertisement. Nothing is returned alongside such an error.
A missing dir is returned wrapped; callers that treat an absent user directory as "no skills" check errors.Is(err, fs.ErrNotExist).
The result is sorted by name so the advertisement is stable regardless of how the filesystem orders entries.
func MergeSkills ¶
MergeSkills layers overrides onto base by name -- an override replaces the base entry entirely, it is not merged field by field. The result is sorted by name and shares no backing array with either input.
type Tool ¶
type Tool struct {
Name string
Description string
InputSchema map[string]any
Run func(ctx context.Context, input json.RawMessage) (string, error)
}
Tool is one function the model may call. InputSchema is a JSON Schema object describing the arguments; Run receives the raw arguments the model produced, which are untrusted and may not match the schema.
func LoadSkillTool ¶
LoadSkillTool returns the built-in tool that hands a skill body to the model. The catalogue is snapshotted, so mutating the caller's slice afterwards does not change what the tool serves. A miss is an error whose message lists the available names; the run loop feeds tool errors back to the model, so the model can correct itself without the loop aborting.