blob: 40ef7ebf968e84e0896e36a1e25e838026dfa168 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use super::Selection;
use super::Wire;
use maka_agent_ports::provider::Error;
use serde_json::Value;
/// An explicit reply budget is capped by capacity, before subtracting a fixed
/// Anthropic thinking budget. Other OpenAI routes have no implicit reply cap.
pub(super) fn resolve(
connection: &Selection<'_>,
wire: Wire,
options: &Value,
) -> Result<Option<u64>, Error> {
let requested = connection
.overrides
.and_then(|value| value.max_output_tokens);
if requested.is_none()
&& wire != Wire::AnthropicMessages
&& !(connection.provider == "kimi-coding-plan" && wire == Wire::OpenaiChatCompletions)
{
return Ok(None);
}
let limit = connection.model.max_output_tokens;
let limit = match (requested, limit) {
(Some(requested), Some(capacity)) => Some(requested.min(capacity)),
(requested, capacity) => requested.or(capacity),
};
limit
.map(|limit| {
if wire == Wire::AnthropicMessages {
subtract_budget(limit, options)
} else {
Ok(limit)
}
})
.transpose()
}
fn subtract_budget(limit: u64, options: &Value) -> Result<u64, Error> {
let thinking = &options["anthropic"]["thinking"];
let fixed = if thinking["type"] == "enabled" {
thinking["budgetTokens"].as_u64().unwrap_or(0)
} else {
0
};
limit
.checked_sub(fixed)
.filter(|limit| *limit > 0)
.ok_or(Error::InsufficientOutputBudget)
}