feat(llm): ReasoningEffort request option and ErrUnsupported sentinel
Groundwork for the provider phase: reasoning levels map to native knobs (OpenAI reasoning_effort, Ollama think); ErrUnsupported marks declared capability mismatches that chains advance past without health penalty. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -107,7 +107,7 @@ func chainDo[T any](ctx context.Context, c *chain, attempt func(context.Context,
|
|||||||
|
|
||||||
class := c.cfg.classify(err)
|
class := c.cfg.classify(err)
|
||||||
if class == llm.ClassPermanent {
|
if class == llm.ClassPermanent {
|
||||||
if errors.Is(err, llm.ErrModelNotFound) || c.cfg.AdvanceOnPermanent {
|
if errors.Is(err, llm.ErrModelNotFound) || errors.Is(err, llm.ErrUnsupported) || c.cfg.AdvanceOnPermanent {
|
||||||
// Not a health problem (or policy says keep going):
|
// Not a health problem (or policy says keep going):
|
||||||
// advance without penalizing the target.
|
// advance without penalizing the target.
|
||||||
failures = append(failures, fmt.Errorf("%s: %w", t.key, err))
|
failures = append(failures, fmt.Errorf("%s: %w", t.key, err))
|
||||||
|
|||||||
+8
-1
@@ -26,6 +26,13 @@ const (
|
|||||||
// condition. Chains advance past it without penalizing the target's health.
|
// condition. Chains advance past it without penalizing the target's health.
|
||||||
var ErrModelNotFound = errors.New("model not found")
|
var ErrModelNotFound = errors.New("model not found")
|
||||||
|
|
||||||
|
// ErrUnsupported marks a request the target cannot serve by declaration —
|
||||||
|
// e.g. images that cannot be normalized to its capabilities, or a feature
|
||||||
|
// (tools, structured output) it does not support. Permanent for the target,
|
||||||
|
// but chains advance past it without penalizing health: another element may
|
||||||
|
// well be able to serve the request.
|
||||||
|
var ErrUnsupported = errors.New("request unsupported by target")
|
||||||
|
|
||||||
// APIError is a structured provider error carrying enough context to
|
// APIError is a structured provider error carrying enough context to
|
||||||
// classify it and to debug it.
|
// classify it and to debug it.
|
||||||
type APIError struct {
|
type APIError struct {
|
||||||
@@ -96,7 +103,7 @@ func Classify(err error) ErrorClass {
|
|||||||
if errors.Is(err, context.DeadlineExceeded) {
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
return ClassTransient
|
return ClassTransient
|
||||||
}
|
}
|
||||||
if errors.Is(err, ErrModelNotFound) {
|
if errors.Is(err, ErrModelNotFound) || errors.Is(err, ErrUnsupported) {
|
||||||
return ClassPermanent
|
return ClassPermanent
|
||||||
}
|
}
|
||||||
if errors.Is(err, syscall.ECONNREFUSED) || errors.Is(err, syscall.ECONNRESET) {
|
if errors.Is(err, syscall.ECONNREFUSED) || errors.Is(err, syscall.ECONNRESET) {
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ type Request struct {
|
|||||||
|
|
||||||
// StopSequences halt generation when emitted.
|
// StopSequences halt generation when emitted.
|
||||||
StopSequences []string
|
StopSequences []string
|
||||||
|
|
||||||
|
// ReasoningEffort requests a reasoning/thinking level from models that
|
||||||
|
// support one: "low", "medium", or "high" (empty = provider default).
|
||||||
|
// Providers map it to their native knob (OpenAI reasoning_effort,
|
||||||
|
// Ollama think levels) and ignore it where no mapping exists.
|
||||||
|
ReasoningEffort string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option mutates a Request before it is sent. Options passed to Generate or
|
// Option mutates a Request before it is sent. Options passed to Generate or
|
||||||
@@ -88,6 +94,12 @@ func WithStopSequences(stops ...string) Option {
|
|||||||
return func(r *Request) { r.StopSequences = stops }
|
return func(r *Request) { r.StopSequences = stops }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithReasoningEffort requests a reasoning/thinking level ("low", "medium",
|
||||||
|
// "high") from models that support one.
|
||||||
|
func WithReasoningEffort(level string) Option {
|
||||||
|
return func(r *Request) { r.ReasoningEffort = level }
|
||||||
|
}
|
||||||
|
|
||||||
// Apply returns a copy of the request with all options applied. Providers
|
// Apply returns a copy of the request with all options applied. Providers
|
||||||
// and wrappers call this once at the top of Generate/Stream.
|
// and wrappers call this once at the top of Generate/Stream.
|
||||||
func (r Request) Apply(opts ...Option) Request {
|
func (r Request) Apply(opts ...Option) Request {
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ const (
|
|||||||
// ErrModelNotFound re-exports llm.ErrModelNotFound.
|
// ErrModelNotFound re-exports llm.ErrModelNotFound.
|
||||||
var ErrModelNotFound = llm.ErrModelNotFound
|
var ErrModelNotFound = llm.ErrModelNotFound
|
||||||
|
|
||||||
|
// ErrUnsupported re-exports llm.ErrUnsupported.
|
||||||
|
var ErrUnsupported = llm.ErrUnsupported
|
||||||
|
|
||||||
// Re-exported content and message constructors.
|
// Re-exported content and message constructors.
|
||||||
func Text(s string) Part { return llm.Text(s) }
|
func Text(s string) Part { return llm.Text(s) }
|
||||||
func Image(mime string, data []byte) Part { return llm.Image(mime, data) }
|
func Image(mime string, data []byte) Part { return llm.Image(mime, data) }
|
||||||
@@ -96,6 +99,7 @@ func WithTemperature(t float64) Option { return llm.WithTempera
|
|||||||
func WithTopP(p float64) Option { return llm.WithTopP(p) }
|
func WithTopP(p float64) Option { return llm.WithTopP(p) }
|
||||||
func WithMaxTokens(n int) Option { return llm.WithMaxTokens(n) }
|
func WithMaxTokens(n int) Option { return llm.WithMaxTokens(n) }
|
||||||
func WithStopSequences(stops ...string) Option { return llm.WithStopSequences(stops...) }
|
func WithStopSequences(stops ...string) Option { return llm.WithStopSequences(stops...) }
|
||||||
|
func WithReasoningEffort(level string) Option { return llm.WithReasoningEffort(level) }
|
||||||
|
|
||||||
// WithModelCapabilities re-exports llm.WithCapabilities for Provider.Model
|
// WithModelCapabilities re-exports llm.WithCapabilities for Provider.Model
|
||||||
// calls made through this package.
|
// calls made through this package.
|
||||||
|
|||||||
Reference in New Issue
Block a user