zzet--gortex
a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
100 行
3.0 KiB
Go
100 行
3.0 KiB
Go
package anthropic
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/zzet/gortex/internal/llm"
|
|
)
|
|
|
|
// Option configures optional Anthropic behaviours on a Provider at
|
|
// construction. Provider.New takes a variadic list of these, so the
|
|
// base signature (a RemoteConfig) stays unchanged.
|
|
type Option func(*Provider)
|
|
|
|
// WithPromptCaching enables Anthropic prompt caching with the given TTL
|
|
// ("5m" or "1h"; "5m" is assumed when empty). When enabled, the system
|
|
// prompt and the structured-output tool are marked as cache
|
|
// breakpoints. A false `enabled` is a no-op.
|
|
func WithPromptCaching(enabled bool, ttl string) Option {
|
|
return func(p *Provider) {
|
|
if !enabled {
|
|
return
|
|
}
|
|
p.caching = true
|
|
p.cacheTTL = strings.TrimSpace(ttl)
|
|
}
|
|
}
|
|
|
|
// WithThinking configures extended thinking. mode is off / auto / manual
|
|
// / adaptive; budget is the manual-mode token budget; display is the
|
|
// adaptive-mode visibility ("summarized" / "omitted"). An empty or "off"
|
|
// mode is a no-op.
|
|
func WithThinking(mode string, budget int, display string) Option {
|
|
return func(p *Provider) {
|
|
p.thinkingMode = strings.ToLower(strings.TrimSpace(mode))
|
|
p.thinkingBudget = budget
|
|
p.thinkingDisplay = strings.TrimSpace(display)
|
|
}
|
|
}
|
|
|
|
// defaultThinkingBudget is the manual-mode budget used when thinking is
|
|
// enabled without an explicit one. The Anthropic minimum is 1024.
|
|
const defaultThinkingBudget = 4096
|
|
|
|
// cacheControl builds the ephemeral cache_control marker honouring the
|
|
// configured TTL.
|
|
func (p *Provider) cacheControl() map[string]any {
|
|
cc := map[string]any{"type": "ephemeral"}
|
|
if p.cacheTTL != "" {
|
|
cc["ttl"] = p.cacheTTL
|
|
}
|
|
return cc
|
|
}
|
|
|
|
// thinkingConfig returns the `thinking` request object and the minimum
|
|
// max_tokens the request must carry for it, or (nil, 0) when thinking
|
|
// is off or not applicable.
|
|
//
|
|
// Extended thinking is incompatible with a forced tool_choice, so it is
|
|
// only ever applied to freeform requests — the structured-output passes
|
|
// (which pin tool_choice to the respond tool) run without it. The
|
|
// resolved mode is gated by model capability: "auto" picks adaptive on a
|
|
// capable model, else manual; an explicit "adaptive" on an incapable
|
|
// model degrades to manual rather than erroring.
|
|
func (p *Provider) thinkingConfig(shape llm.JSONShape) (map[string]any, int) {
|
|
if shape != llm.ShapeFreeform {
|
|
return nil, 0
|
|
}
|
|
mode := p.thinkingMode
|
|
switch mode {
|
|
case "", "off":
|
|
return nil, 0
|
|
case "auto":
|
|
if supportsAdaptiveThinking(p.model) {
|
|
mode = "adaptive"
|
|
} else {
|
|
mode = "manual"
|
|
}
|
|
}
|
|
|
|
if mode == "adaptive" && supportsAdaptiveThinking(p.model) {
|
|
cfg := map[string]any{"type": "adaptive"}
|
|
if p.thinkingDisplay != "" {
|
|
cfg["display"] = p.thinkingDisplay
|
|
}
|
|
// Adaptive thinking still needs headroom in max_tokens.
|
|
return cfg, 4096
|
|
}
|
|
|
|
// manual (also the fallback for adaptive on an incapable model)
|
|
budget := p.thinkingBudget
|
|
if budget <= 0 {
|
|
budget = defaultThinkingBudget
|
|
}
|
|
if budget < 1024 {
|
|
budget = 1024
|
|
}
|
|
// max_tokens must exceed the thinking budget.
|
|
return map[string]any{"type": "enabled", "budget_tokens": budget}, budget + 1024
|
|
}
|