Documentation
¶
Overview ¶
Package httpreq exposes a single model-callable HTTP-request tool. It wraps go-resty as the transport and enforces host, method, redirect, timeout, and response-size policy at one client boundary.
The allowlist is mandatory — there is no "allow all" mode. Callers MUST enumerate the hosts the LLM is permitted to reach. An interrupted response remains an error. Received status, headers, and body bytes are preserved as core/tool.CallError evidence, not a complete tool result. Body and header values use content.Content; UTF-8 text is readable and binary data, partial characters, and HTTP obs-text remain lossless.
Index ¶
Examples ¶
Constants ¶
const ( DefaultTimeout = 30 * time.Second DefaultMaxResponseBytes = int64(256 * 1024) MaxRequestTimeout = 2 * time.Minute )
Exported defaults keep constructor behavior visible and overridable.
Variables ¶
var ( ErrNilClient = errors.New("httpreq: client must not be nil") ErrNilRequest = errors.New("httpreq: request must not be nil") ErrMissingAllowedHosts = errors.New("httpreq: allowed hosts must not be empty; configure an explicit network allowlist") ErrInvalidClientConfig = errors.New("httpreq: client configuration is invalid") ErrInvalidHostPattern = errors.New("httpreq: host pattern is invalid") ErrEmptyURL = errors.New("httpreq: url must not be empty") ErrInvalidURL = errors.New("httpreq: url must be an absolute http(s) URL") ErrInvalidMethod = errors.New("httpreq: method must be GET, HEAD, POST, PUT, PATCH, or DELETE") ErrInvalidRequestTimeout = errors.New("httpreq: timeout_ms must be between 1 and 120000 when set") ErrHostNotAllowed = errors.New("httpreq: host is not allowed by client policy") ErrHostHeaderOverride = errors.New("httpreq: model-supplied Host header overrides are prohibited") ErrMethodNotAllowed = errors.New("httpreq: method is not allowed by client policy") ErrRedirectLimitReached = errors.New("httpreq: redirect limit reached") )
Functions ¶
This section is empty.
Types ¶
type Allowlist ¶
type Allowlist struct {
// contains filtered or unexported fields
}
Allowlist is a compiled host policy. Exact and leading-wildcard patterns share the same case, trailing-dot, IP, and IDNA normalization as request hosts. The zero value allows nothing.
func NewAllowlist ¶
NewAllowlist compiles host patterns once so every request is matched against normalized forms rather than raw strings. Comparing hosts textually is what lets case, a trailing dot, or an IDNA variant slip past a filter that looks correct.
Example ¶
package main
import (
"fmt"
"github.com/Tangerg/scope/tools/httpreq"
)
func main() {
allowlist, err := httpreq.NewAllowlist([]string{"api.example.com", "*.services.example.com"})
if err != nil {
panic(err)
}
fmt.Println(
allowlist.Allows("API.EXAMPLE.COM"),
allowlist.Allows("search.services.example.com"),
allowlist.Allows("example.net"),
)
}
Output: true true false
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client executes requests through an immutable network and resource policy.
func NewClient ¶
func NewClient(config ClientConfig) (*Client, error)
NewClient fails closed: without an allowlist there is no host a model- supplied URL may reach. The alternative — an empty allowlist meaning unrestricted — turns a forgotten configuration line into an open proxy.
func (*Client) Do ¶
Do applies the frozen host, method, timeout, redirect, and response-size policy before returning a model-facing response. If body reading or closure fails, the response retains the received status, headers, and admitted body prefix as evidence alongside the error. It is not a completed response, and the error does not establish whether a request with side effects committed at the server.
type ClientConfig ¶
type ClientConfig struct {
// AllowedHosts accepts exact hosts and one leading wildcard, such as
// "api.example.com" or "*.example.com". A wildcard does not match its root.
AllowedHosts []string
// AllowedMethods defaults to GET and HEAD. Comparison is case-insensitive.
AllowedMethods []Method
// DefaultHeaders are added unless [Request.Headers] overrides them.
DefaultHeaders map[string]string
// MaxResponseBytes selects [DefaultMaxResponseBytes] at zero.
MaxResponseBytes int64
// DefaultTimeout selects [DefaultTimeout] at zero.
DefaultTimeout time.Duration
// HTTPClient supplies caller-owned transport, cookie jar, proxy, and TLS
// settings. NewClient clones the value before installing redirect policy.
HTTPClient *http.Client
}
ClientConfig defines the network authority and resource bounds frozen into a Client. AllowedHosts is mandatory because the zero policy denies network access rather than silently opening it.
func (ClientConfig) Validate ¶
func (c ClientConfig) Validate() error
type Method ¶
type Method string
Method is an HTTP method exposed by the tool contract.
const ( MethodGET Method = http.MethodGet MethodHEAD Method = http.MethodHead MethodPOST Method = http.MethodPost MethodPUT Method = http.MethodPut MethodPATCH Method = http.MethodPatch MethodDELETE Method = http.MethodDelete )
Methods are an allowlist rather than a pass-through, because the tool decides what a model may do to a remote host. An unlisted method is refused before the request is built.
type Request ¶
type Request struct {
URL string `json:"url" jsonschema:"minLength=1" jsonschema_description:"Absolute http(s) URL. Host must match the configured allowlist."`
Method Method `` /* 229-byte string literal not displayed */
Headers map[string]string `` /* 197-byte string literal not displayed */
Query map[string]string `json:"query,omitempty" jsonschema_description:"Optional query parameters appended to the URL."`
Body string `` /* 143-byte string literal not displayed */
TimeoutMS int `` /* 177-byte string literal not displayed */
}
Request is the model-facing argument shape, and its struct tags are the contract the model actually sees. The schema is derived from this type so the description a model reads and the fields the tool decodes cannot drift apart.
type Response ¶
type Response struct {
Status int `json:"status"`
Headers map[string][]content.Content `json:"headers,omitempty"`
Body content.Content `json:"body"`
Truncated bool `json:"truncated,omitzero"`
// Duration includes transport execution, body reading, and body closure.
Duration string `json:"duration"`
}
Response is the model-facing result. Body and header values preserve bytes; UTF-8 remains readable text and other bytes use explicit base64 on the wire. Alongside an error from Client.Do it contains incomplete observations only; Truncated reports the configured size cap, not successful body completion.
type Tool ¶
type Tool struct {
// contains filtered or unexported fields
}
Tool adapts a configured Client to the tool contract. It takes a concrete client rather than an interface because the allowlist, method restrictions, and timeouts are the point of this tool; a substitutable transport would let a caller bypass them.
func NewTool ¶
NewTool rejects a nil client so a tool cannot be advertised to a model before the restrictions that make it safe exist.
func (*Tool) Call ¶
func (t *Tool) Call(ctx context.Context, invocation toolcontract.Invocation) (chat.ToolOutput, error)
func (*Tool) Definition ¶
func (t *Tool) Definition() chat.ToolDefinition
func (*Tool) Unwrap ¶ added in v0.19.0
func (t *Tool) Unwrap() toolcontract.Tool