answer

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package answer turns a question into a grounded answer, or into an honest refusal to answer.

Declining is a first-class outcome rather than an error path. Calibration against the curated corpus showed that a retrieval score cannot separate a question the corpus answers from one whose subject it merely covers: the bands overlap, and excluding every unanswerable question would cost 40% of the answerable ones. BM25 measures term overlap, not whether a passage answers anything.

So the judgement lives here, and it is made against the retrieved passages. A component that can only produce answers produces one for every question, including the questions whose correct answer is that we do not know — and those answers arrive carrying a real citation to a page that does not say it, which is worse than silence.

Index

Constants

View Source
const DefaultLimit = 8

DefaultLimit is how many passages are retrieved for one question.

View Source
const PassageDelimiter = "-----BEGIN PASSAGE-----"

PassageDelimiter fences retrieved content in the prompt.

Passage text is untrusted: it comes from public repositories anyone may open a merge request against, and in later phases the question arrives from a public Discord channel. Delimiting is what keeps content from reading as instruction — it does not make injection impossible, but it makes the boundary explicit and it is the part a prompt can actually enforce.

Variables

View Source
var (
	// ErrUngrounded means the composer returned prose citing nothing. Whatever
	// it says is not supported by anything retrieved.
	ErrUngrounded = errors.New("answer: no passage was cited")

	// ErrFabricatedCitation means a citation pointed outside the retrieved set.
	ErrFabricatedCitation = errors.New("answer: cited a passage that was not retrieved")
)

Reasons an answer was refused after the composer produced one.

Functions

func ResponseSchema

func ResponseSchema() *jsonschema.Schema

ResponseSchema is the structured-output schema the composer expects.

Reflected from composeReply through chat.GenerateSchema rather than written by hand. The hand-written map worked against claude-local, which marshals whatever it is given, and was silently mangled by the Anthropic provider — that provider reads a *jsonschema.Schema for its properties and required fields, and treats any other value as the properties map itself. Reflecting the struct keeps the schema and the type it decodes into from drifting apart as well.

Returns the concrete *jsonschema.Schema rather than any. chat.Config.Bind types the field concretely from v0.9.0, so the interface return now needs a type assertion at every call site — and the whole reason this exists is that handing that field the wrong shape fails silently rather than loudly.

func SystemPrompt

func SystemPrompt() string

SystemPrompt is the instruction the composer relies on, exported so a caller constructing the client can set it.

Types

type Answer

type Answer struct {
	// Text is the prose, empty when declining.
	Text string

	// Cites indexes the passages the answer is grounded in, as positions in the
	// slice the composer was given.
	Cites []int

	// Declined marks a judgement that the passages do not answer the question.
	Declined bool

	// DeclineReason says why, in terms a person can read.
	DeclineReason string
}

Answer is what a Composer produces.

type ChatComposer

type ChatComposer struct {
	// contains filtered or unexported fields
}

ChatComposer composes answers through a chat provider.

func NewComposer

func NewComposer(client chat.ChatClient) *ChatComposer

NewComposer builds a composer over a chat client.

func (*ChatComposer) Compose

func (c *ChatComposer) Compose(
	ctx context.Context, question string, results []index.Result,
) (Answer, error)

Compose asks the model to answer from the passages, or to decline.

type Citation

type Citation struct {
	URL         string
	HeadingPath string
	SourcePath  string
	RepoPath    string
	CommitSHA   string
}

Citation is a resolved reference to the passage supporting an answer.

type Composer

type Composer interface {
	Compose(ctx context.Context, question string, results []index.Result) (Answer, error)
}

Composer turns a question and its retrieved passages into an answer, or declines.

The contract is deliberately able to say no. Sufficiency is judged against the passages rather than against the question or the model's own knowledge: an answer that cannot be grounded in what was retrieved must not be returned however plausible it is.

type Option

type Option func(*Service)

Option configures a Service.

func WithLimit

func WithLimit(n int) Option

WithLimit sets how many passages are retrieved.

func WithScoreFloor

func WithScoreFloor(f float64) Option

WithScoreFloor discards passages scoring below f before composing.

A floor discards noise. It is deliberately not the gate: calibration showed no score separates answerable questions from unanswerable ones, so a floor set high enough to exclude the latter takes 40% of the former with it.

type Response

type Response struct {
	Text      string
	Citations []Citation

	// Declined is true when the corpus did not answer. It is an outcome, not a
	// failure: a declined question is a knowledge gap, which is the product's
	// highest-value output.
	Declined      bool
	DeclineReason string

	// Cause carries why an answer was refused after being produced, when it was
	// refused here rather than declined by the composer.
	Cause error

	// Retrieved is what the question found, for reporting and for measuring
	// retrieval independently of composition.
	Retrieved []index.Result
}

Response is the outcome of asking a question.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service answers questions from the index.

func New

func New(r index.Retriever, c Composer, opts ...Option) *Service

New builds an answering service.

func (*Service) Ask

func (s *Service) Ask(ctx context.Context, question string) (Response, error)

Ask answers a question, or declines.

An error means something broke — the index was unreachable, the provider failed. It never means "we do not know", which is a Response with Declined set. Conflating them would lose the distinction between a knowledge gap and an incident, and the gap backlog depends on it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL