mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
move formats/anthropic
This commit is contained in:
Generated
+1
@@ -4773,6 +4773,7 @@ dependencies = [
|
||||
"async-stream",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"env-lock",
|
||||
"futures",
|
||||
"once_cell",
|
||||
"regex",
|
||||
|
||||
@@ -30,6 +30,7 @@ utoipa = { workspace = true, features = ["chrono"] }
|
||||
uuid = { workspace = true, features = ["v4", "std"] }
|
||||
|
||||
[dev-dependencies]
|
||||
env-lock = { workspace = true }
|
||||
test-case = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
pub mod anthropic;
|
||||
pub mod openai;
|
||||
|
||||
+60
-82
@@ -1,11 +1,11 @@
|
||||
use crate::conversation::message::{Message, MessageContent};
|
||||
use crate::conversation::token_usage::{ProviderUsage, Usage};
|
||||
use crate::errors::ProviderError;
|
||||
use crate::images::{convert_image, ImageFormat};
|
||||
use crate::mcp_utils::extract_text_from_resource;
|
||||
use crate::model::ModelConfig;
|
||||
use crate::models::ModelConfigParams;
|
||||
use crate::thinking::ThinkingEffort;
|
||||
use anyhow::{anyhow, Result};
|
||||
use goose_providers::conversation::token_usage::{ProviderUsage, Usage};
|
||||
use goose_providers::errors::ProviderError;
|
||||
use goose_providers::images::{convert_image, ImageFormat};
|
||||
use goose_providers::thinking::ThinkingEffort;
|
||||
use rmcp::model::{object, CallToolRequestParams, ErrorCode, ErrorData, JsonObject, Role, Tool};
|
||||
use rmcp::object as json_object;
|
||||
use serde_json::{json, Value};
|
||||
@@ -45,46 +45,19 @@ pub struct AnthropicFormatOptions {
|
||||
pub preserve_thinking_context: bool,
|
||||
}
|
||||
|
||||
impl AnthropicFormatOptions {
|
||||
fn for_model(self, model_config: &ModelConfig) -> Self {
|
||||
let preserve_thinking_context = model_config
|
||||
.get_config_param::<bool>(
|
||||
"preserve_thinking_context",
|
||||
"ANTHROPIC_PRESERVE_THINKING_CONTEXT",
|
||||
)
|
||||
.unwrap_or(self.preserve_thinking_context);
|
||||
let preserve_unsigned_thinking = model_config
|
||||
.get_config_param::<bool>(
|
||||
"preserve_unsigned_thinking",
|
||||
"ANTHROPIC_PRESERVE_UNSIGNED_THINKING",
|
||||
)
|
||||
.unwrap_or(self.preserve_unsigned_thinking)
|
||||
|| preserve_thinking_context;
|
||||
|
||||
Self {
|
||||
preserve_unsigned_thinking,
|
||||
preserve_thinking_context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supports_adaptive_thinking(model_name: &str) -> bool {
|
||||
let lower = model_name.to_lowercase();
|
||||
lower.contains("claude-opus-4-6") || lower.contains("claude-sonnet-4-6")
|
||||
}
|
||||
|
||||
pub fn thinking_type(model_config: &ModelConfig) -> ThinkingType {
|
||||
pub fn thinking_type(model_config: &ModelConfigParams) -> ThinkingType {
|
||||
let model_lower = model_config.model_name.to_lowercase();
|
||||
if !model_lower.contains("claude") {
|
||||
return ThinkingType::Disabled;
|
||||
}
|
||||
|
||||
let is_adaptive_model = supports_adaptive_thinking(&model_config.model_name);
|
||||
let effort = model_config.thinking_effort();
|
||||
|
||||
if effort.is_none() && legacy_thinking_budget_tokens().is_some() {
|
||||
return ThinkingType::Enabled;
|
||||
}
|
||||
let effort = model_config.thinking_effort;
|
||||
|
||||
match effort.unwrap_or(ThinkingEffort::Off) {
|
||||
ThinkingEffort::Off => ThinkingType::Disabled,
|
||||
@@ -507,13 +480,11 @@ pub fn get_usage(data: &Value) -> Result<Usage> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn thinking_effort(model_config: &ModelConfig) -> ThinkingEffort {
|
||||
model_config
|
||||
.thinking_effort()
|
||||
.unwrap_or(ThinkingEffort::High)
|
||||
pub fn thinking_effort(model_config: &ModelConfigParams) -> ThinkingEffort {
|
||||
model_config.thinking_effort.unwrap_or(ThinkingEffort::High)
|
||||
}
|
||||
|
||||
pub fn thinking_budget_tokens(model_config: &ModelConfig) -> i32 {
|
||||
pub fn thinking_budget_tokens(model_config: &ModelConfigParams) -> i32 {
|
||||
if let Some(request_param) = model_config
|
||||
.request_params
|
||||
.as_ref()
|
||||
@@ -523,13 +494,7 @@ pub fn thinking_budget_tokens(model_config: &ModelConfig) -> i32 {
|
||||
return request_param.max(1024);
|
||||
}
|
||||
|
||||
if let Some(budget) = legacy_thinking_budget_tokens() {
|
||||
return budget;
|
||||
}
|
||||
|
||||
let effort = model_config
|
||||
.thinking_effort()
|
||||
.unwrap_or(ThinkingEffort::High);
|
||||
let effort = model_config.thinking_effort.unwrap_or(ThinkingEffort::High);
|
||||
match effort {
|
||||
ThinkingEffort::Off => 1024,
|
||||
ThinkingEffort::Low => 4000,
|
||||
@@ -539,19 +504,9 @@ pub fn thinking_budget_tokens(model_config: &ModelConfig) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn legacy_thinking_budget_tokens() -> Option<i32> {
|
||||
let config = crate::config::Config::global();
|
||||
for key in ["ANTHROPIC_THINKING_BUDGET", "CLAUDE_THINKING_BUDGET"] {
|
||||
if let Ok(budget) = config.get_param::<i32>(key) {
|
||||
return Some(budget.max(1024));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn apply_thinking_config(
|
||||
payload: &mut Value,
|
||||
model_config: &ModelConfig,
|
||||
model_config: &ModelConfigParams,
|
||||
max_tokens: i32,
|
||||
options: AnthropicFormatOptions,
|
||||
) {
|
||||
@@ -598,7 +553,7 @@ fn apply_thinking_config(
|
||||
|
||||
/// Create a complete request payload for Anthropic's API
|
||||
pub fn create_request(
|
||||
model_config: &ModelConfig,
|
||||
model_config: &ModelConfigParams,
|
||||
system: &str,
|
||||
messages: &[Message],
|
||||
tools: &[Tool],
|
||||
@@ -613,13 +568,12 @@ pub fn create_request(
|
||||
}
|
||||
|
||||
pub fn create_request_with_options(
|
||||
model_config: &ModelConfig,
|
||||
model_config: &ModelConfigParams,
|
||||
system: &str,
|
||||
messages: &[Message],
|
||||
tools: &[Tool],
|
||||
options: AnthropicFormatOptions,
|
||||
) -> Result<Value> {
|
||||
let options = options.for_model(model_config);
|
||||
let anthropic_messages = format_messages_with_options(messages, options);
|
||||
let tool_specs = format_tools(tools);
|
||||
let system_spec = format_system(system);
|
||||
@@ -921,9 +875,10 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::conversation::message::Message;
|
||||
use crate::model::ModelConfig;
|
||||
use crate::models::ModelConfigParams;
|
||||
use rmcp::object;
|
||||
use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn test_parse_text_response() -> Result<()> {
|
||||
@@ -1186,12 +1141,12 @@ mod tests {
|
||||
fn test_create_request_adaptive_thinking_for_46_models() -> Result<()> {
|
||||
let _guard = env_lock::lock_env([("GOOSE_THINKING_EFFORT", None::<&str>)]);
|
||||
|
||||
let mut params = std::collections::HashMap::new();
|
||||
let mut params = HashMap::new();
|
||||
params.insert("thinking_effort".to_string(), json!("high"));
|
||||
|
||||
let mut config = cfg("claude-opus-4-6");
|
||||
config.max_tokens = Some(4096);
|
||||
config.request_params = Some(params);
|
||||
config.request_params = Some(¶ms);
|
||||
let messages = vec![Message::user().with_text("Hello")];
|
||||
let payload = create_request(&config, "system", &messages, &[])?;
|
||||
|
||||
@@ -1209,7 +1164,8 @@ mod tests {
|
||||
("ANTHROPIC_PRESERVE_THINKING_CONTEXT", None::<&str>),
|
||||
]);
|
||||
|
||||
let mut config = cfg_with_effort("claude-3-7-sonnet-20250219", "high");
|
||||
let params = effort_params("high");
|
||||
let mut config = cfg_with_params("claude-3-7-sonnet-20250219", ¶ms);
|
||||
config.max_tokens = Some(4096);
|
||||
|
||||
let messages = vec![Message::user().with_text("Hello")];
|
||||
@@ -1230,7 +1186,8 @@ mod tests {
|
||||
("ANTHROPIC_PRESERVE_THINKING_CONTEXT", None::<&str>),
|
||||
]);
|
||||
|
||||
let config = cfg_with_effort("claude-sonnet-4-20250514", "off");
|
||||
let params = effort_params("off");
|
||||
let config = cfg_with_params("claude-sonnet-4-20250514", ¶ms);
|
||||
let messages = vec![Message::user().with_text("Hello")];
|
||||
let payload = create_request(&config, "system", &messages, &[])?;
|
||||
|
||||
@@ -1297,7 +1254,7 @@ mod tests {
|
||||
params.insert("preserve_thinking_context".to_string(), json!(true));
|
||||
|
||||
let mut config = cfg("glm-4.7");
|
||||
config.request_params = Some(params);
|
||||
config.request_params = Some(¶ms);
|
||||
let messages = vec![
|
||||
Message::assistant().with_content(MessageContent::thinking("internal", "")),
|
||||
Message::user().with_text("Continue"),
|
||||
@@ -1490,18 +1447,25 @@ mod tests {
|
||||
assert_eq!(input, &json!({}));
|
||||
}
|
||||
|
||||
fn cfg(name: &str) -> ModelConfig {
|
||||
ModelConfig {
|
||||
model_name: name.to_string(),
|
||||
fn cfg<'a>(name: &'a str) -> ModelConfigParams<'a> {
|
||||
ModelConfigParams {
|
||||
model_name: name,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn cfg_with_effort(name: &str, effort: &str) -> ModelConfig {
|
||||
fn effort_params(effort: &str) -> HashMap<String, Value> {
|
||||
let mut params = std::collections::HashMap::new();
|
||||
params.insert("thinking_effort".to_string(), json!(effort));
|
||||
ModelConfig {
|
||||
model_name: name.to_string(),
|
||||
params
|
||||
}
|
||||
|
||||
fn cfg_with_params<'a>(
|
||||
name: &'a str,
|
||||
params: &'a HashMap<String, Value>,
|
||||
) -> ModelConfigParams<'a> {
|
||||
ModelConfigParams {
|
||||
model_name: name,
|
||||
request_params: Some(params),
|
||||
..Default::default()
|
||||
}
|
||||
@@ -1512,22 +1476,28 @@ mod tests {
|
||||
let _guard = env_lock::lock_env([("GOOSE_THINKING_EFFORT", None::<&str>)]);
|
||||
// Adaptive model with effort → adaptive
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("claude-opus-4-6", "high")),
|
||||
thinking_type(&cfg_with_params("claude-opus-4-6", &effort_params("high"))),
|
||||
ThinkingType::Adaptive
|
||||
);
|
||||
// Adaptive model with off → disabled
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("claude-opus-4-6", "off")),
|
||||
thinking_type(&cfg_with_params("claude-opus-4-6", &effort_params("off"))),
|
||||
ThinkingType::Disabled
|
||||
);
|
||||
// Non-adaptive Claude with effort → enabled
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("claude-3-7-sonnet-20250219", "high")),
|
||||
thinking_type(&cfg_with_params(
|
||||
"claude-3-7-sonnet-20250219",
|
||||
&effort_params("high")
|
||||
)),
|
||||
ThinkingType::Enabled
|
||||
);
|
||||
// Non-adaptive Claude with off → disabled
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("claude-3-7-sonnet-20250219", "off")),
|
||||
thinking_type(&cfg_with_params(
|
||||
"claude-3-7-sonnet-20250219",
|
||||
&effort_params("off")
|
||||
)),
|
||||
ThinkingType::Disabled
|
||||
);
|
||||
}
|
||||
@@ -1539,18 +1509,23 @@ mod tests {
|
||||
("ANTHROPIC_THINKING_BUDGET", Some("8192")),
|
||||
("CLAUDE_THINKING_BUDGET", None::<&str>),
|
||||
]);
|
||||
let config = cfg_with_effort("claude-3-7-sonnet-20250219", "high");
|
||||
assert_eq!(thinking_budget_tokens(&config), 8192);
|
||||
assert_eq!(
|
||||
thinking_budget_tokens(&cfg_with_params(
|
||||
"claude-3-7-sonnet-20250219",
|
||||
&effort_params("high")
|
||||
)),
|
||||
8192
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_thinking_type_non_claude_always_disabled() {
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("gpt-4o", "off")),
|
||||
thinking_type(&cfg_with_params("gpt-4o", &effort_params("off"))),
|
||||
ThinkingType::Disabled
|
||||
);
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("gpt-4o", "high")),
|
||||
thinking_type(&cfg_with_params("gpt-4o", &effort_params("high"))),
|
||||
ThinkingType::Disabled
|
||||
);
|
||||
}
|
||||
@@ -1558,11 +1533,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_thinking_type_off_means_disabled() {
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("claude-opus-4-6", "off")),
|
||||
thinking_type(&cfg_with_params("claude-opus-4-6", &effort_params("off"))),
|
||||
ThinkingType::Disabled
|
||||
);
|
||||
assert_eq!(
|
||||
thinking_type(&cfg_with_effort("claude-3-7-sonnet-20250219", "off")),
|
||||
thinking_type(&cfg_with_params(
|
||||
"claude-3-7-sonnet-20250219",
|
||||
&effort_params("off")
|
||||
)),
|
||||
ThinkingType::Disabled
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,9 @@ use serde_json::Value;
|
||||
|
||||
use crate::thinking::ThinkingEffort;
|
||||
|
||||
const DEFAULT_MAX_OUTPUT_TOKENS: i32 = 8192;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ModelConfigParams<'a> {
|
||||
pub model_name: &'a str,
|
||||
pub thinking_effort: Option<ThinkingEffort>,
|
||||
@@ -11,3 +14,9 @@ pub struct ModelConfigParams<'a> {
|
||||
pub max_tokens: Option<i32>,
|
||||
pub request_params: Option<&'a HashMap<String, Value>>,
|
||||
}
|
||||
|
||||
impl ModelConfigParams<'_> {
|
||||
pub fn max_output_tokens(&'_ self) -> i32 {
|
||||
self.max_tokens.unwrap_or(DEFAULT_MAX_OUTPUT_TOKENS)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use goose_providers::formats::openai::{extract_reasoning_effort, is_openai_responses_model};
|
||||
use goose_providers::models::ModelConfigParams;
|
||||
use goose_providers::thinking::ThinkingEffort;
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::de::Deserializer;
|
||||
@@ -494,6 +495,16 @@ impl ModelConfig {
|
||||
ModelConfig::new(model_name)
|
||||
.unwrap_or_else(|_| panic!("Failed to create model config for {}", model_name))
|
||||
}
|
||||
|
||||
pub fn as_config_params<'a>(&'a self) -> ModelConfigParams<'a> {
|
||||
ModelConfigParams {
|
||||
model_name: self.model_name.as_str(),
|
||||
thinking_effort: self.thinking_effort(),
|
||||
temperature: self.temperature,
|
||||
max_tokens: self.max_tokens,
|
||||
request_params: self.request_params.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -11,10 +11,6 @@ use tokio_util::io::StreamReader;
|
||||
|
||||
use super::api_client::{ApiClient, AuthMethod};
|
||||
use super::base::{ConfigKey, MessageStream, ModelInfo, Provider, ProviderDef, ProviderMetadata};
|
||||
use super::formats::anthropic::{
|
||||
create_request_with_options, response_to_streaming_message, thinking_type,
|
||||
AnthropicFormatOptions, ThinkingType,
|
||||
};
|
||||
use super::inventory::{config_secret_value, serialize_string_map, InventoryIdentityInput};
|
||||
use super::openai_compatible::handle_status;
|
||||
use super::openai_compatible::map_http_error_to_provider_error;
|
||||
@@ -24,6 +20,9 @@ use crate::conversation::message::Message;
|
||||
use crate::model::ModelConfig;
|
||||
use crate::providers::utils::RequestLog;
|
||||
use futures::future::BoxFuture;
|
||||
use goose_providers::formats::anthropic::{
|
||||
create_request_with_options, response_to_streaming_message, AnthropicFormatOptions,
|
||||
};
|
||||
use rmcp::model::Tool;
|
||||
|
||||
const ANTHROPIC_PROVIDER_NAME: &str = "anthropic";
|
||||
@@ -177,19 +176,6 @@ impl AnthropicProvider {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_conditional_headers(&self) -> Vec<(&str, &str)> {
|
||||
let mut headers = Vec::new();
|
||||
|
||||
if self.model.model_name.starts_with("claude-3-7-sonnet-") {
|
||||
if thinking_type(&self.model) == ThinkingType::Enabled {
|
||||
headers.push(("anthropic-beta", "output-128k-2025-02-19"));
|
||||
}
|
||||
headers.push(("anthropic-beta", "token-efficient-tools-2025-02-19"));
|
||||
}
|
||||
|
||||
headers
|
||||
}
|
||||
|
||||
async fn fetch_models_from_api(&self) -> Result<Vec<String>, ProviderError> {
|
||||
let response = self.api_client.request(None, "v1/models").api_get().await?;
|
||||
|
||||
@@ -226,6 +212,27 @@ impl AnthropicProvider {
|
||||
models.sort();
|
||||
Ok(models)
|
||||
}
|
||||
|
||||
fn format_options(&self, model_config: &ModelConfig) -> AnthropicFormatOptions {
|
||||
let preserve_thinking_context = model_config
|
||||
.get_config_param::<bool>(
|
||||
"preserve_thinking_context",
|
||||
"ANTHROPIC_PRESERVE_THINKING_CONTEXT",
|
||||
)
|
||||
.unwrap_or(self.format_options.preserve_thinking_context);
|
||||
let preserve_unsigned_thinking = model_config
|
||||
.get_config_param::<bool>(
|
||||
"preserve_unsigned_thinking",
|
||||
"ANTHROPIC_PRESERVE_UNSIGNED_THINKING",
|
||||
)
|
||||
.unwrap_or(self.format_options.preserve_unsigned_thinking)
|
||||
|| preserve_thinking_context;
|
||||
|
||||
AnthropicFormatOptions {
|
||||
preserve_unsigned_thinking,
|
||||
preserve_thinking_context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProviderDef for AnthropicProvider {
|
||||
@@ -342,26 +349,22 @@ impl Provider for AnthropicProvider {
|
||||
tools: &[Tool],
|
||||
) -> Result<MessageStream, ProviderError> {
|
||||
let mut payload = create_request_with_options(
|
||||
model_config,
|
||||
&model_config.as_config_params(),
|
||||
system,
|
||||
messages,
|
||||
tools,
|
||||
self.format_options,
|
||||
self.format_options(model_config),
|
||||
)?;
|
||||
payload
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.insert("stream".to_string(), Value::Bool(true));
|
||||
|
||||
let conditional_headers = self.get_conditional_headers();
|
||||
let mut log = RequestLog::start(model_config, &payload)?;
|
||||
|
||||
let response = self
|
||||
.with_retry(|| async {
|
||||
let mut request = self.api_client.request(Some(session_id), "v1/messages");
|
||||
for (key, value) in &conditional_headers {
|
||||
request = request.header(key, value)?;
|
||||
}
|
||||
let request = self.api_client.request(Some(session_id), "v1/messages");
|
||||
let resp = request.response_post(&payload).await?;
|
||||
handle_status(resp).await
|
||||
})
|
||||
|
||||
@@ -20,7 +20,7 @@ use super::base::{
|
||||
DEFAULT_PROVIDER_TIMEOUT_SECS,
|
||||
};
|
||||
use super::databricks_auth::{DatabricksAuth, DatabricksAuthProvider};
|
||||
use super::formats::{anthropic, openai_responses};
|
||||
use super::formats::openai_responses;
|
||||
use super::openai_compatible::{handle_status, stream_openai_compat, stream_responses_compat};
|
||||
use super::retry::ProviderRetry;
|
||||
use super::utils::RequestLog;
|
||||
@@ -32,6 +32,7 @@ use crate::providers::retry::{
|
||||
DEFAULT_MAX_RETRIES, DEFAULT_MAX_RETRY_INTERVAL_MS,
|
||||
};
|
||||
use goose_providers::errors::ProviderError;
|
||||
use goose_providers::formats::anthropic;
|
||||
use rmcp::model::Tool;
|
||||
|
||||
const DATABRICKS_V2_PROVIDER_NAME: &str = "databricks_v2";
|
||||
@@ -296,7 +297,8 @@ impl DatabricksV2Provider {
|
||||
messages: &[Message],
|
||||
tools: &[Tool],
|
||||
) -> Result<MessageStream, ProviderError> {
|
||||
let mut payload = anthropic::create_request(model_config, system, messages, tools)?;
|
||||
let mut payload =
|
||||
anthropic::create_request(&model_config.as_config_params(), system, messages, tools)?;
|
||||
payload["stream"] = Value::Bool(true);
|
||||
let mut log = RequestLog::start(model_config, &payload)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::conversation::message::{Message, MessageContent};
|
||||
use crate::model::ModelConfig;
|
||||
use crate::providers::formats::anthropic::{
|
||||
use goose_providers::formats::anthropic::{
|
||||
thinking_budget_tokens, thinking_effort, thinking_type, ThinkingType,
|
||||
};
|
||||
|
||||
@@ -246,12 +246,12 @@ fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec<Data
|
||||
fn apply_claude_thinking_config(payload: &mut Value, model_config: &ModelConfig) {
|
||||
let obj = payload.as_object_mut().unwrap();
|
||||
|
||||
match thinking_type(model_config) {
|
||||
match thinking_type(&model_config.as_config_params()) {
|
||||
ThinkingType::Adaptive => {
|
||||
obj.insert("thinking".to_string(), json!({ "type": "adaptive" }));
|
||||
obj.insert(
|
||||
"output_config".to_string(),
|
||||
json!({ "effort": thinking_effort(model_config).to_string() }),
|
||||
json!({ "effort": thinking_effort(&model_config.as_config_params()).to_string() }),
|
||||
);
|
||||
obj.insert(
|
||||
"max_completion_tokens".to_string(),
|
||||
@@ -259,7 +259,7 @@ fn apply_claude_thinking_config(payload: &mut Value, model_config: &ModelConfig)
|
||||
);
|
||||
}
|
||||
ThinkingType::Enabled => {
|
||||
let budget_tokens = thinking_budget_tokens(model_config);
|
||||
let budget_tokens = thinking_budget_tokens(&model_config.as_config_params());
|
||||
let max_tokens = model_config.max_output_tokens() + budget_tokens;
|
||||
obj.insert("max_tokens".to_string(), json!(max_tokens));
|
||||
obj.insert(
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use super::{anthropic, google};
|
||||
use super::google;
|
||||
use crate::conversation::message::Message;
|
||||
use crate::model::ModelConfig;
|
||||
use anyhow::{Context, Result};
|
||||
use goose_providers::conversation::token_usage::{ProviderUsage, Usage};
|
||||
use goose_providers::formats::anthropic;
|
||||
use rmcp::model::Tool;
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -220,7 +221,8 @@ fn create_anthropic_request(
|
||||
messages: &[Message],
|
||||
tools: &[Tool],
|
||||
) -> Result<Value> {
|
||||
let mut request = anthropic::create_request(model_config, system, messages, tools)?;
|
||||
let mut request =
|
||||
anthropic::create_request(&model_config.as_config_params(), system, messages, tools)?;
|
||||
|
||||
let obj = request
|
||||
.as_object_mut()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod anthropic;
|
||||
#[cfg(feature = "aws-providers")]
|
||||
pub mod bedrock;
|
||||
pub mod databricks;
|
||||
|
||||
@@ -20,7 +20,6 @@ use super::base::{
|
||||
ConfigKey, MessageStream, Provider, ProviderDef, ProviderMetadata,
|
||||
DEFAULT_PROVIDER_TIMEOUT_SECS,
|
||||
};
|
||||
use super::formats::anthropic::{create_request, response_to_streaming_message};
|
||||
use super::oauth_device_flow::{
|
||||
refresh_device_flow_token, run_device_flow, DeviceFlowConfig, DeviceFlowTokens, RequestEncoding,
|
||||
};
|
||||
@@ -31,6 +30,7 @@ use crate::conversation::message::Message;
|
||||
use crate::model::ModelConfig;
|
||||
use futures::future::BoxFuture;
|
||||
use goose_providers::errors::ProviderError;
|
||||
use goose_providers::formats::anthropic::{create_request, response_to_streaming_message};
|
||||
use rmcp::model::Tool;
|
||||
|
||||
const KIMI_CODE_PROVIDER_NAME: &str = "kimi_code";
|
||||
@@ -393,7 +393,7 @@ impl Provider for KimiCodeProvider {
|
||||
messages: &[Message],
|
||||
tools: &[Tool],
|
||||
) -> Result<MessageStream, ProviderError> {
|
||||
let mut payload = create_request(model_config, system, messages, tools)
|
||||
let mut payload = create_request(&model_config.as_config_params(), system, messages, tools)
|
||||
.map_err(|e| ProviderError::RequestFailed(e.to_string()))?;
|
||||
payload
|
||||
.as_object_mut()
|
||||
|
||||
Reference in New Issue
Block a user