Documentation
¶
Overview ¶
Package llm talks to an OpenAI-compatible chat completions endpoint, and fences the untrusted text Hecate would put in a prompt.
Everything Hecate knows about a stuck promotion is attacker-influenced: Flux condition messages, git commit messages, pull request titles, image tags, a step's captured output. Any of it can contain text written to be read as an instruction. The fencing here is not a hardening pass to be done later — it is the reason this package exists rather than callers assembling prompts themselves.
One client, no provider interface. Ollama, llama.cpp, vLLM, LM Studio and the hosted vendors all speak /v1/chat/completions, so "pluggable" is a base URL, a model name and an optional key. If something genuinely does not fit, that is the day to write a second implementation.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Diagnose ¶
Diagnose asks a model to explain, in prose, a Gate that Hecate has already analysed.
It is given the finished Explanation rather than the raw resources, and that is the important part: the deterministic analysis has already decided what is blocking and what would fix it, so the model's job is to say it readably. It is not being asked what is wrong, because a model that concluded something different from the code would be reporting a second opinion nobody asked for.
The Explanation's own fields are Hecate's, but the strings inside them are not: a step message carries whatever a git host or a Flux controller said, so the whole thing goes inside the fence.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an OpenAI-compatible chat completions client.
type Config ¶
type Config struct {
// BaseURL is the API root — http://localhost:11434/v1 for Ollama,
// https://api.openai.com/v1 for OpenAI. The /chat/completions path is
// appended.
BaseURL string
// Model is the model name the endpoint knows.
Model string
// APIKey is optional: local runtimes do not want one.
APIKey string
// Timeout bounds a single completion. Zero uses 60s, which is generous
// because a local model on CPU is slow and a diagnosis is not on anyone's
// critical path.
Timeout time.Duration
}
Config is what it takes to reach a model.
func FromEnv ¶
func FromEnv() Config
FromEnv reads the standard variables, so Hecate drops into a setup that already has a model configured.
HECATE_LLM_* wins over OPENAI_* so a machine can point Hecate at a local model without disturbing whatever else uses the OpenAI variables.
func (Config) Configured ¶
Configured reports whether there is enough to talk to a model.
Hecate must work with no model at all: diagnosis is an assist, never a dependency, so every caller asks this rather than treating its absence as an error.
type Fence ¶
type Fence struct {
// contains filtered or unexported fields
}
Fence wraps untrusted content in delimiters the content cannot forge.
The delimiter carries a per-call token, and any occurrence of that token is stripped from the content first. A fixed delimiter is guessable: text that contained the closing marker would end the fence early and the rest would be read as trusted prompt, which is the whole attack.
func NewFence ¶
NewFence returns a fence whose delimiters are unguessable for this prompt.
The token is derived from the caller rather than randomly, so a prompt is reproducible for a given input — which matters for testing, and for anyone trying to work out what the model was actually shown.
type Prompt ¶
type Prompt struct {
// Task is the trusted instruction: what to do with the data.
Task string
// Blocks are already-fenced untrusted sections, from Fence.Wrap.
Blocks []string
}
Prompt assembles a system and user message from trusted instructions and fenced untrusted data.