Documentation
¶
Overview ¶
Package costs provides a pluggable cost translation layer for ark. It follows the same registration pattern as internal/agent/providers and internal/agent/queue: implementations register via RegisterCostProvider and are selected by name via NewCostProvider.
The default provider ("static") uses hardcoded pricing tables for Anthropic and OpenAI models. Unknown models (e.g. local Ollama) return zero cost rather than an error, so they are tracked as free rather than causing reconcile failures.
Index ¶
- func Backends() []string
- func PeriodWindowStart(period string) time.Time
- func RegisterCostProvider(name string, f Factory)
- func RegisterSpendStore(scheme string, f SpendStoreFactory)
- func SpendStoreBackends() []string
- func SumStepCosts(steps []StepCost) float64
- func TruncateToPeriod(t time.Time, p Period) time.Time
- type BudgetDecision
- type BudgetInput
- type BudgetPolicy
- type BudgetStatus
- type ConfigMapCostProvider
- type CostProvider
- type Factory
- type NoopSpendStore
- type Period
- type RollupEntry
- type SpendEntry
- type SpendScope
- type SpendStore
- type SpendStoreFactory
- type StandardBudgetPolicy
- type StaticCostProvider
- type StepCost
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Backends ¶
func Backends() []string
Backends returns the sorted names of all registered CostProvider implementations.
func PeriodWindowStart ¶
PeriodWindowStart returns the start of the current budget window for the given period string. Accepts "daily"/"day", "weekly"/"week", "monthly"/"month".
func RegisterCostProvider ¶
RegisterCostProvider makes a CostProvider available under the given name. Typically called from an init() function in the implementation package.
func RegisterSpendStore ¶
func RegisterSpendStore(scheme string, f SpendStoreFactory)
RegisterSpendStore registers a SpendStore factory under a scheme name. Call from an init() function so blank-importing the package activates it.
func SpendStoreBackends ¶
func SpendStoreBackends() []string
SpendStoreBackends returns the sorted names of all registered schemes.
func SumStepCosts ¶
SumStepCosts returns the total cost in USD across all steps that have a CostUSD set. Used by flow/phase.go to accumulate run-level cost.
Types ¶
type BudgetDecision ¶
type BudgetDecision struct {
// Status is the outcome: OK, Warning, or Exceeded.
Status BudgetStatus
// SpentUSD is the total spend for the period.
SpentUSD float64
// LimitUSD is the configured limit.
LimitUSD float64
// PctUsed is SpentUSD / LimitUSD expressed as a value from 0 to 100+.
PctUsed float64
// Message is a human-readable summary.
Message string
}
BudgetDecision is the result of a budget policy evaluation.
type BudgetInput ¶
type BudgetInput struct {
// Selector mirrors ArkBudgetSelector fields.
Namespace string
Team string
// Period is "daily", "weekly", or "monthly".
Period string
// Limit is the maximum spend for the period.
Limit float64
// WarnAt is the warn threshold as a percentage (0–100).
WarnAt int
}
BudgetInput contains everything needed to evaluate a budget, without importing the API types (avoids import cycles).
type BudgetPolicy ¶
type BudgetPolicy interface {
// Evaluate returns a decision based on current SpendStore data.
// store and scope are provided by the caller; the policy calls store.Total.
Evaluate(ctx context.Context, input BudgetInput, store SpendStore) (BudgetDecision, error)
}
BudgetPolicy evaluates current spend against a budget limit.
func DefaultBudgetPolicy ¶
func DefaultBudgetPolicy() BudgetPolicy
DefaultBudgetPolicy returns the standard built-in policy.
type BudgetStatus ¶
type BudgetStatus string
BudgetStatus mirrors arkonisv1alpha1.BudgetStatus to avoid an import cycle.
const ( BudgetOK BudgetStatus = "OK" BudgetWarning BudgetStatus = "Warning" BudgetExceeded BudgetStatus = "Exceeded" )
type ConfigMapCostProvider ¶
type ConfigMapCostProvider struct {
// contains filtered or unexported fields
}
ConfigMapCostProvider reads pricing from a flat key→value map loaded from a Kubernetes ConfigMap. The operator loads this once at startup via NewConfigMapCostProvider and watches the ConfigMap for changes; call Reload(data) whenever the ConfigMap's Data field changes.
ConfigMap format (each key is a model name prefix):
claude-opus-4: "15.00/75.00" # input_per_1m/output_per_1m USD my-custom-model: "0.50/1.00" local-model: "0.00/0.00"
func NewConfigMapCostProvider ¶
func NewConfigMapCostProvider(data map[string]string, fallback CostProvider) (*ConfigMapCostProvider, error)
NewConfigMapCostProvider creates a provider pre-loaded with the given ConfigMap data map. Pass the static provider as fallback so unknown models still get a reasonable cost rather than $0.
func (*ConfigMapCostProvider) Cost ¶
func (p *ConfigMapCostProvider) Cost(model string, inputTokens, outputTokens int64) float64
Cost returns the dollar cost for the given model and token counts. Uses longest-prefix match against the loaded ConfigMap entries. Falls back to the fallback provider if no prefix matches.
func (*ConfigMapCostProvider) Currency ¶
func (p *ConfigMapCostProvider) Currency() string
func (*ConfigMapCostProvider) Reload ¶
func (p *ConfigMapCostProvider) Reload(data map[string]string) error
Reload replaces the pricing table with fresh data from a ConfigMap. Call this whenever the ConfigMap's Data field is updated (via a Watch event). Thread-safe; the provider continues serving requests during the reload.
type CostProvider ¶
type CostProvider interface {
// Cost returns the dollar cost for the given model and token counts.
// Returns 0.0 for unknown models rather than an error.
Cost(model string, inputTokens, outputTokens int64) float64
// Currency returns the ISO 4217 currency code (e.g. "USD").
Currency() string
}
CostProvider translates token usage into a dollar cost for a given model.
func Default ¶
func Default() CostProvider
Default returns the static cost provider. Convenience wrapper for callers that don't need configurability — zero cost on unknown models, no error path.
func NewCostProvider ¶
func NewCostProvider(name string) (CostProvider, error)
NewCostProvider returns the named CostProvider, or the "static" default when name is empty. Returns an error only if the name is non-empty and unknown.
type NoopSpendStore ¶
type NoopSpendStore struct{}
NoopSpendStore silently discards all writes. Useful for deployments that only want cost-per-run tracking (Phase 1) without full spend history.
func (NoopSpendStore) Record ¶
func (NoopSpendStore) Record(_ context.Context, _ SpendEntry) error
func (NoopSpendStore) Rollup ¶
func (NoopSpendStore) Rollup(_ context.Context, _ SpendScope, _ Period, _ time.Time) ([]RollupEntry, error)
func (NoopSpendStore) Total ¶
func (NoopSpendStore) Total(_ context.Context, _ SpendScope, _ time.Time) (float64, error)
type RollupEntry ¶
type RollupEntry struct {
Date time.Time // start of the bucket (truncated to Period)
Namespace string
Team string
Model string
TotalCostUSD float64
InputTokens int64
OutputTokens int64
RunCount int64
}
RollupEntry is one time-bucket of aggregated spend.
type SpendEntry ¶
type SpendEntry struct {
Timestamp time.Time
Namespace string
Team string
RunName string
StepName string
Model string
InputTokens int64
OutputTokens int64
CostUSD float64
}
SpendEntry records the cost of a single pipeline step.
type SpendScope ¶
type SpendScope struct {
Namespace string // empty = all namespaces
Team string // empty = all teams
Model string // empty = all models
}
SpendScope filters queries to a subset of entries. Empty strings mean "all values".
type SpendStore ¶
type SpendStore interface {
// Record saves one step's spend. Called after each step succeeds.
Record(ctx context.Context, entry SpendEntry) error
// Rollup returns spend aggregated into period buckets for a scope.
Rollup(ctx context.Context, scope SpendScope, period Period, since time.Time) ([]RollupEntry, error)
// Total returns the sum of CostUSD for a scope since the given time.
// Used by BudgetPolicy to compare against a spend limit.
Total(ctx context.Context, scope SpendScope, since time.Time) (float64, error)
}
SpendStore records and queries historical pipeline spend. All writes are best-effort; implementations should log errors but must not return errors that would fail the reconcile loop.
func NewSpendStore ¶
func NewSpendStore(url string) (SpendStore, error)
NewSpendStore returns a SpendStore for the given URL. The URL scheme selects the backend (e.g. "redis://localhost:6379"). Returns a NoopSpendStore when url is empty.
type SpendStoreFactory ¶
type SpendStoreFactory func(url string) (SpendStore, error)
SpendStoreFactory constructs a SpendStore from a connection URL. The URL scheme selects the backend (e.g. "redis://...").
type StandardBudgetPolicy ¶
type StandardBudgetPolicy struct{}
StandardBudgetPolicy is the built-in budget policy. It calls SpendStore.Total for the current period window and compares it against the limit.
func (*StandardBudgetPolicy) Evaluate ¶
func (p *StandardBudgetPolicy) Evaluate(ctx context.Context, input BudgetInput, store SpendStore) (BudgetDecision, error)
Evaluate checks current spend for the period and returns OK / Warning / Exceeded.
type StaticCostProvider ¶
type StaticCostProvider struct{}
StaticCostProvider uses the hardcoded pricing table above. Unknown models return 0.0 (treated as free).
func (*StaticCostProvider) Cost ¶
func (p *StaticCostProvider) Cost(model string, inputTokens, outputTokens int64) float64
func (*StaticCostProvider) Currency ¶
func (p *StaticCostProvider) Currency() string
Directories
¶
| Path | Synopsis |
|---|---|
|
Package memstore provides an in-memory SpendStore for local development, ark run, and unit tests.
|
Package memstore provides an in-memory SpendStore for local development, ark run, and unit tests. |
|
Package redisstore registers a Redis-backed SpendStore.
|
Package redisstore registers a Redis-backed SpendStore. |