Help us shape the future of Go! Take the 2026 Go Developer Survey

tripadvice

package
v0.40.22 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package tripadvice wraps the operator-configured AI provider to generate plain-language observations about a Rivian trip plan: charging stop summary, arrival SoC commentary, adapter warnings, and drive-mode suggestions when the plan looks sub-optimal.

Structure mirrors internal/recap: side-effect-free buildPrompt, stateless Generate, structured JSON output the SPA renders as a card below the route table.

Index

Constants

View Source
const (
	BasisYourReceipts = "your_receipts"
	BasisYourSetting  = "your_setting"
	BasisObserved     = "observed"
)

Price bases for StopPrice.Basis.

View Source
const DefaultDCFCRateUSD = 0.46

DefaultDCFCRateUSD is the per-kWh fallback used in the rare case where the cost estimator runs without a route (pre-network-table API consumers, tests). The real per-stop pricing flows through the Networks table in networks.go.

Variables

This section is empty.

Functions

This section is empty.

Types

type Context

type Context struct {
	// DriveMode is the mode the user explicitly chose, or "" for
	// "let the planner pick". Included so the model can say "you
	// planned in Conserve mode" rather than treating it as a mystery.
	DriveMode   string
	StartingSoC float64
	HasAdapter  bool
	// Weather at the origin at departure time. nil when the operator
	// has not enabled the weather feature (recap.weather_enabled).
	Weather *weather.Snapshot
	// TirePressurebars holds [FL, FR, RL, RR] in bar from the live
	// vehicle state. Zero values mean unavailable for that corner.
	TirePressureBars [4]float64
	// PackKWh is the observed battery capacity in kWh from the vehicle
	// record. 0 means unknown.
	PackKWh float64
	// TirePlacardPSI is the user-configured door-jamb cold-fill
	// pressure from the vehicle profile. 0 means unconfigured; the
	// prompt then falls back to a generic "below placard" framing
	// instead of citing a specific number.
	TirePlacardPSI float64
	// HomePricePerKWh is the user's at-home charging cost in
	// HomeCurrency (typically USD). 0 means unconfigured — the cost
	// section degrades to a pure-DCFC estimate.
	HomePricePerKWh float64
	HomeCurrency    string
	// GasPricePerGallon × distance / ComparisonMPG drives the gas-
	// equivalent chip. Both must be > 0 for the chip to render.
	GasPricePerGallon float64
	ComparisonMPG     float64
	// DCFCNetworks is the user's edited price book from Settings.
	// Pass nil or empty to use the built-in defaults from dcfcrates.
	// Per-stop rates honour each row's MemberActive flag so the
	// estimate's user-totals match what the user has actually
	// signed up for.
	DCFCNetworks []dcfcrates.NetworkOverride
	// OwnRates is what the user actually paid per kWh at each network (slug), from
	// their own receipts, with how many sessions it rests on. The caller supplies
	// only figures that meet the minimum (receipts.PaidMinSessions) in this
	// context's currency. nil when the user has no receipts.
	OwnRates map[string]OwnRate
	// Now is the clock for the observed-price expiry; zero means time.Now().
	Now time.Time
}

Context bundles user-supplied labels and request parameters that would otherwise be unavailable in the plan response itself.

Privacy: what the model receives about places is limited to charger names, and locations rounded to weather.CoarseRound (0.1 deg, ~11 km). The typed origin/destination text (which may be a street address) is deliberately not part of Context, and no full-precision coordinate is ever written into the prompt.

type CostEstimate

type CostEstimate struct {
	Currency string `json:"currency"`
	// DCFCSpendLow and DCFCSpendHigh sum the priced stops' cost range. Equal when no
	// priced stop has a range; both 0 when no stop has a price (see PricedStops).
	DCFCSpendLow  float64 `json:"dcfc_spend_low"`
	DCFCSpendHigh float64 `json:"dcfc_spend_high"`
	// PricedStops and UnpricedStops count the DC fast stops with and without a price,
	// so the UI can say "partial: 2 of 3 stops priced".
	PricedStops   int `json:"priced_stops"`
	UnpricedStops int `json:"unpriced_stops"`
	// EstimateBasis is which sources fed the figure: "your_receipts", "your_setting",
	// "observed", "mixed" (more than one of them) or "none" (no stop priced). The UI
	// words the estimate from it ("estimate (typical observed price)" when observed or
	// mixed).
	EstimateBasis  string  `json:"estimate_basis"`
	HomeEquivalent float64 `json:"home_equivalent"`
	// GasEquivalent is what the same distance would cost in an ICE
	// vehicle at the user's configured gas price + MPG. Zero when
	// either input is unset.
	GasEquivalent     float64 `json:"gas_equivalent"`
	GasPricePerGallon float64 `json:"gas_price_per_gallon"`
	GasMPG            float64 `json:"gas_mpg"`
	// HomeRateUsed is the user's configured at-home rate, 0 when
	// unconfigured.
	HomeRateUsed float64 `json:"home_rate_used"`
	// Breakdown lists each DC fast stop. Empty when no DCFC stops
	// were on the route (all-from-home trip).
	Breakdown []CostStop `json:"breakdown,omitempty"`
}

CostEstimate is a deterministic, code-computed projection of trip cost. It is an ESTIMATE and says so: the dollar figures for the DC fast stops are a range (DCFCSpendLow to DCFCSpendHigh) over the stops that have a price, and a stop with none is counted in UnpricedStops, not given a made-up number. Where each stop's price comes from is on the stop (CostStop.Price.Basis), in order:

  1. the user's own receipts at that network (their paid $/kWh, at least 3 sessions);
  2. a rate the user set themselves in Settings (not the seeded default);
  3. the third-party observed price (dcfcrates.ObservedFor: its own table, source and month, hidden after 12 months);
  4. none: "price shown at the charger".

The built-in table's dated guest and member rates are never used for a dollar figure. HomeEquivalent and GasEquivalent are unchanged.

func EstimateRoute added in v0.18.85

func EstimateRoute(r *rivian.TripRoute, tc Context) CostEstimate

EstimateRoute projects DCFC spend + home-rate-equivalent for a single route. Exported so the /api/trips/plan handler can attach a cost to every route in the response without making the SPA round- trip through the AI advice endpoint just to see numbers.

type CostStop added in v0.18.83

type CostStop struct {
	NetworkSlug string  `json:"network_slug"`
	NetworkName string  `json:"network_name"`
	ChargerName string  `json:"charger_name"`
	EnergyKWh   float64 `json:"energy_kwh"`
	MemberPlan  string  `json:"member_plan,omitempty"`
	// Price is nil when there is none for this stop: "price shown at the charger".
	Price *StopPrice `json:"price"`
	// CostLow and CostHigh are EnergyKWh times the price range, nil with no price.
	CostLow  *float64 `json:"cost_low"`
	CostHigh *float64 `json:"cost_high"`
}

CostStop is one waypoint's contribution to the DC fast total.

type OwnRate added in v0.38.7

type OwnRate struct {
	PerKWh   float64
	Sessions int
}

OwnRate is the user's own paid price at a network.

type Parsed

type Parsed struct {
	Headline   string   `json:"headline"`
	Cost       []string `json:"cost"`
	Efficiency []string `json:"efficiency"`
	Weather    []string `json:"weather"`
	Vehicle    []string `json:"vehicle"`
}

Parsed is the structured JSON shape the model emits. Each list holds 1-3 short sentences; sections with nothing useful to say stay empty rather than emitting filler.

type Result

type Result struct {
	// Raw is the model's reply, stored and forwarded as-is.
	Raw          string
	Parsed       *Parsed
	Model        string
	InputTokens  int64
	OutputTokens int64
	// Cost is computed deterministically in Go (not by the LLM) so
	// the dollar figure is always accurate. The LLM gets the same
	// numbers in the prompt and writes the commentary around them.
	Cost CostEstimate
}

Result is what Generate returns to the handler.

func Generate

func Generate(ctx context.Context, a *ai.Analyzer, plan *rivian.TripPlan, tc Context) (Result, error)

Generate calls the AI provider with a compact trip-plan summary and returns structured advice. The context's deadline should be generous (30s+) — sit in the AI-bound route group, not the timed one.

type StopPrice added in v0.38.7

type StopPrice struct {
	Basis      string  `json:"basis"`
	PerKWhLow  float64 `json:"per_kwh_low"`
	PerKWhHigh float64 `json:"per_kwh_high"`
	// LowNote and HighNote say what each end of a range is (observed Tesla: with and
	// without the membership); empty when the ends are equal.
	LowNote  string `json:"low_note,omitempty"`
	HighNote string `json:"high_note,omitempty"`
	// Sessions is how many of the user's receipts a your_receipts figure rests on.
	Sessions int `json:"sessions,omitempty"`
	// Source, SourceURL and ObservedMonth name the third party behind an observed figure.
	Source        string `json:"source,omitempty"`
	SourceURL     string `json:"source_url,omitempty"`
	ObservedMonth string `json:"observed_month,omitempty"`
	// Label is the exact wording to show with the figure.
	Label string `json:"label"`
}

StopPrice is the price used for one stop and where it came from.

Jump to

Keyboard shortcuts

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