Skip to content
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Provider-specific request/response handling moved out of the generic chat completions codec into per-provider codecs.
- Remove google from active providers.

## 0.1.4 - 2026-10-4

### Added
Expand Down
6 changes: 3 additions & 3 deletions crates/agent/src/agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,13 @@ impl Agent {
Ok(())
}

pub async fn set_provider_order(&self, provider_order: Vec<String>) -> Result<(), AgentError> {
pub async fn set_extensions(&self, extensions: llm::Extensions) -> Result<(), AgentError> {
let mut model = self.model.try_lock().map_err(|_| {
AgentError::Model(providers::ModelError::Llm(llm::LlmError::Configuration(
"agent is busy: cannot change provider order mid-run".into(),
"agent is busy: cannot change request extensions mid-run".into(),
)))
})?;
model.set_provider_order(provider_order);
model.set_extensions(extensions);
Ok(())
}
}
7 changes: 5 additions & 2 deletions crates/agent/src/agent/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,13 @@ pub(super) async fn summarize(
messages.push(Message::user(instruction));

let options = RequestOptions::default();
let extensions = llm::Extensions::default();
let mut stream_resp = model
.stream(CompletionInput {
messages: &messages,
tools: &[],
options: &options,
extensions: &extensions,
})
.await?;

Expand Down Expand Up @@ -217,9 +219,9 @@ pub(super) async fn stream_round(
.collect();

let messages = build_messages(context);
let mut extensions = llm::Extensions::default();
extensions.insert(llm::SessionId(session_id));
let options = RequestOptions {
prompt_cache_key: Some(session_id.clone()),
session_id: Some(session_id),
cache_control: Some(PromptCacheControl::one_hour()),
..RequestOptions::default()
};
Expand All @@ -229,6 +231,7 @@ pub(super) async fn stream_round(
messages: &messages,
tools: &tools,
options: &options,
extensions: &extensions,
})
.await?;

Expand Down
15 changes: 15 additions & 0 deletions crates/alan/src/core/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::core::store::JsonStore;
const SETTINGS_KEY: &str = "settings";
use anyhow::Context as _;
use llm::ReasoningEffort;
use providers::OpenRouterOptions;
use std::collections::BTreeMap;
use std::path::PathBuf;

Expand Down Expand Up @@ -146,6 +147,20 @@ impl Settings {
pub fn provider_order(&self, model: &str) -> Vec<String> {
self.provider_orders.get(model).cloned().unwrap_or_default()
}

/// Provider-specific request options for `model`, keyed by provider.
/// Only OpenRouter exposes settings today; the order is routed to its
/// codec via request extensions.
pub fn extensions(&self, model: &str) -> llm::Extensions {
let mut extensions = llm::Extensions::default();
let order = self.provider_order(model);
if !order.is_empty() {
extensions.insert(OpenRouterOptions {
provider_order: order,
});
}
extensions
}
}

/// Apply a PatchSettings to mutate only specified fields.
Expand Down
7 changes: 4 additions & 3 deletions crates/alan/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use agent::{Agent, SessionManager, ToolPermissionManager, default_tools};
use alan_tui::Runtime;
use llm::ReasoningEffort;
use providers::{
FileCredentialStore, GoogleProvider, LocalProvider, ModelOptions, OpenRouterProvider, Provider,
FileCredentialStore, LocalProvider, ModelOptions, OpenRouterProvider, Provider,
ProviderRegistry, ZaiProvider, bind_model,
};
use std::path::PathBuf;
Expand Down Expand Up @@ -151,7 +151,8 @@ fn build_providers(
) -> anyhow::Result<Vec<Arc<dyn Provider>>> {
Ok(vec![
Arc::new(ZaiProvider::from_store(Arc::clone(credential_store)).build()?),
Arc::new(GoogleProvider::from_store(Arc::clone(credential_store)).build()?),
// until there really exists some evidence that this is needed, we can add back
// Arc::new(GoogleProvider::from_store(Arc::clone(credential_store)).build()?),
Arc::new(OpenRouterProvider::from_store(Arc::clone(credential_store)).build()?),
Arc::clone(local_provider) as Arc<dyn Provider>,
])
Expand Down Expand Up @@ -197,7 +198,7 @@ fn select_model(
ModelOptions {
server_tools,
reasoning_effort: settings.reasoning.unwrap_or_default(),
provider_order: settings.provider_order(&model_id),
extensions: settings.extensions(&model_id),
},
)?)
}
Expand Down
12 changes: 8 additions & 4 deletions crates/alan/src/views/components/chat_view/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::root::AlanAction;
use alan_tui::TaskError;
use alan_tui::context::Context;
use providers::{
Model, ModelInfo, ModelOptions, Provider, ProviderId, ProviderRegistry, bind_local_model,
bind_model,
Model, ModelInfo, ModelOptions, OpenRouterOptions, Provider, ProviderId, ProviderRegistry,
bind_local_model, bind_model,
};
use std::sync::Arc;

Expand Down Expand Up @@ -63,7 +63,7 @@ pub(crate) fn open_models_picker(view: &mut ChatView, cx: &mut Context<'_, ChatV
let settings = settings::get_settings()
.await
.map_err(|e| TaskError(e.into()))?;
options.provider_order = settings.provider_order(&model_info.id);
options.extensions = settings.extensions(&model_info.id);

let model = bind_model_info(&providers, &model_info, options)?;
let name = model_info.name.clone();
Expand Down Expand Up @@ -124,8 +124,12 @@ pub(crate) fn apply_model_provider(
cx.spawn(
async move {
let model_id = agent.info().await.id;
let mut extensions = agent.model_options().await.extensions;
extensions.insert(OpenRouterOptions {
provider_order: provider_order.clone(),
});
agent
.set_provider_order(provider_order.clone())
.set_extensions(extensions)
.await
.map_err(|error| TaskError(Box::new(error)))?;

Expand Down
2 changes: 1 addition & 1 deletion crates/alan/src/views/components/chat_view/profiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ fn apply_profile(
async move {
let mut options = agent.model_options().await;
let settings = settings::get_settings().await.map_err(super::to_task)?;
options.provider_order = settings.provider_order(&profile.model);
options.extensions = settings.extensions(&profile.model);
options.reasoning_effort = profile.reasoning;
options.server_tools = server_tools_for_provider(
&providers,
Expand Down
Loading
Loading