package knowledge import "fmt" // Structured errors, per §10: a code, never a bare string, and user-facing text // derived at the surface rather than raised from here. // // The codes matter more than they look. "the embedding provider is down" and // "this deployment has no embedding credential" are the same sentence to a // user and completely different to an operator — one is a page, the other is a // configuration task nobody has done. Flattening them into a single failure // makes that distinction unanswerable from a log. type Error struct { Code string `json:"code"` Message string `json:"message"` Cause error `json:"-"` } func (e *Error) Error() string { if e.Cause != nil { return fmt.Sprintf("%s: %s: %v", e.Code, e.Message, e.Cause) } return fmt.Sprintf("%s: %s", e.Code, e.Message) } func (e *Error) Unwrap() error { return e.Cause } const ( // ErrNoPrincipal is retrieval called without a caller. §5: there is no // overload without a principal, and this is what enforces it at run time // for a caller that assembled the struct by hand. ErrNoPrincipal = "knowledge.no_principal" // ErrNoSources is retrieval called without naming a corpus. An agent reads // the sources its spec declares; an empty list is not "all of them". ErrNoSources = "knowledge.no_sources" // ErrNoAudience is an ingest whose document reaches nobody. §5. ErrNoAudience = "knowledge.no_audience" // ErrNotConfigured is a missing embedding credential, or the stand-in // embedder refusing to run in production. ErrNotConfigured = "knowledge.not_configured" // ErrEmbedUnavailable is a provider that is reachable-in-principle and // failing now: a timeout, a 429, a 503. Retryable. ErrEmbedUnavailable = "knowledge.embed_unavailable" // ErrEmbedFailed is a provider answering something this code cannot use. // Not retryable — the same request will fail the same way. ErrEmbedFailed = "knowledge.embed_failed" // ErrModelMismatch is a corpus embedded with one model being searched with // another. Refused rather than served: vectors from two models are not // comparable, and the failure mode is confident nonsense. ErrModelMismatch = "knowledge.model_mismatch" // ErrIngestFailed and ErrRetrieveFailed are the database saying no. ErrIngestFailed = "knowledge.ingest_failed" ErrRetrieveFailed = "knowledge.retrieve_failed" ) // Retryable reports whether the same call might succeed later. func (e *Error) Retryable() bool { return e.Code == ErrEmbedUnavailable }