Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9268307
first pass
katzdave Jan 20, 2026
ed68894
lots of improvements
katzdave Jan 21, 2026
a5e807e
another big wave
katzdave Jan 21, 2026
f327622
Test fix
katzdave Jan 21, 2026
56dd2a5
:fix cost v1
katzdave Jan 21, 2026
4c8b08b
Merge branch 'main' of github.com:block/goose into dkatz/canonical-pr…
katzdave Jan 21, 2026
a8d202c
actuall fix cost now
katzdave Jan 21, 2026
2c19b24
some docs fixes
katzdave Jan 22, 2026
078566b
fix cost display
katzdave Jan 22, 2026
87ce2eb
add recommeded to diff
katzdave Jan 22, 2026
248e69c
normalization fix for openrouter + regen
katzdave Jan 22, 2026
cc848de
fix databricks model support
katzdave Jan 22, 2026
4500c26
get rid of deduping logic
katzdave Jan 22, 2026
d93c35d
fmt
katzdave Jan 22, 2026
b2b50bc
Merge branch 'main' of github.com:block/goose into dkatz/canonical-pr…
katzdave Jan 22, 2026
ca1a514
fix build/tests and rm lots of comments
katzdave Jan 22, 2026
edbe3ed
fmt
katzdave Jan 22, 2026
03c3f5b
copilot suggestions
katzdave Jan 22, 2026
88a7ec5
fmt
katzdave Jan 22, 2026
582d9cd
merge
katzdave Jan 23, 2026
6cf36f3
Merge branch 'main' of github.com:block/goose into dkatz/canonical-pr…
katzdave Jan 26, 2026
c9efc8f
Merge branch 'main' of github.com:block/goose into dkatz/canonical-pr…
katzdave Jan 27, 2026
dd41da5
Fix fetch_supported_models signature to match trait
katzdave Jan 27, 2026
f0d40cd
rebuild canonical
katzdave Jan 27, 2026
dc25cb3
fmt
katzdave Jan 27, 2026
c2f6376
review comments
katzdave Jan 29, 2026
ddffc7e
fmt
katzdave Jan 29, 2026
323f8ea
regen openapi
katzdave Jan 29, 2026
2a9837f
fix xai
katzdave Jan 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/goose-cli/src/session/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,8 +871,8 @@ fn estimate_cost_usd(
) -> Option<f64> {
let canonical_model = maybe_get_canonical_model(provider, model)?;

let input_cost_per_token = canonical_model.pricing.prompt?;
let output_cost_per_token = canonical_model.pricing.completion?;
let input_cost_per_token = canonical_model.cost.input? / 1_000_000.0;
let output_cost_per_token = canonical_model.cost.output? / 1_000_000.0;

let input_cost = input_cost_per_token * input_tokens as f64;
let output_cost = output_cost_per_token * output_tokens as f64;
Expand Down
14 changes: 7 additions & 7 deletions crates/goose-server/src/routes/config_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,17 +505,17 @@ pub async fn get_pricing(

let mut pricing_data = Vec::new();

if let (Some(input_cost), Some(output_cost)) = (
canonical_model.pricing.prompt,
canonical_model.pricing.completion,
) {
if let (Some(input_cost), Some(output_cost)) =
(canonical_model.cost.input, canonical_model.cost.output)
{
pricing_data.push(PricingData {
provider: query.provider.clone(),
model: query.model.clone(),
input_token_cost: input_cost,
output_token_cost: output_cost,
// Canonical model costs are per million tokens, convert to per-token
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needing this comment suggests that we need to refactor this more either at the beginning or at the end - let's have one unit we pass around

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My followup pr deletes the pricing API and replaces it with a full canonical model fetch (or at least just the fields the client needs, but gives us a place to layer on more). will keep as cost / mtokens until we render.

input_token_cost: input_cost / 1_000_000.0,
output_token_cost: output_cost / 1_000_000.0,
currency: "$".to_string(),
context_length: Some(canonical_model.context_length as u32),
context_length: Some(canonical_model.limit.context as u32),
});
}

Expand Down
43 changes: 34 additions & 9 deletions crates/goose/src/providers/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ pub struct ModelInfo {
pub name: String,
/// The maximum context length this model supports
pub context_limit: usize,
/// Cost per token for input (optional)
/// Cost per token for input in USD (optional)
pub input_token_cost: Option<f64>,
/// Cost per token for output (optional)
/// Cost per token for output in USD (optional)
pub output_token_cost: Option<f64>,
/// Currency for the costs (default: "$")
pub currency: Option<String>,
Expand Down Expand Up @@ -456,15 +456,40 @@ pub trait Provider: Send + Sync {

let provider_name = self.get_name();

let recommended_models: Vec<String> = all_models
// Get all text-capable models with their release dates
let mut models_with_dates: Vec<(String, Option<String>)> = all_models
.iter()
.filter(|model| {
map_to_canonical_model(provider_name, model, registry)
.and_then(|canonical_id| registry.get(&canonical_id))
.map(|m| m.input_modalities.contains(&"text".to_string()))
.unwrap_or(false)
.filter_map(|model| {
let canonical_id = map_to_canonical_model(provider_name, model, registry)?;

let (provider, model_name) = canonical_id.split_once('/')?;
let canonical_model = registry.get(provider, model_name)?;

if !canonical_model
.modalities
.input
.contains(&crate::providers::canonical::Modality::Text)
{
return None;
}

let release_date = canonical_model.release_date.clone();

Some((model.clone(), release_date))
})
.cloned()
.collect();

// Sort by release date (most recent first), then alphabetically for models without dates
models_with_dates.sort_by(|a, b| match (&a.1, &b.1) {
(Some(date_a), Some(date_b)) => date_b.cmp(date_a),
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => a.0.cmp(&b.0),
});
Comment on lines +483 to +488
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sorting logic has an issue. When comparing models with release dates, date_b.cmp(date_a) will sort lexicographically, not chronologically. Since dates are in "YYYY-MM-DD" format, this works correctly (newer dates sort first), but it would be clearer to add a comment explaining this relies on ISO 8601 date format.

Copilot uses AI. Check for mistakes.

let recommended_models: Vec<String> = models_with_dates
.into_iter()
.map(|(name, _)| name)
.collect();

if recommended_models.is_empty() {
Expand Down
Loading
Loading