blob: b6212419b1de078d759946d4c5d0fc0633cf2167 [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.
*/
//! Root-authorized accounting reads; all data comes from physical EventLog facts.
use maka_agent_facts::accounting::Activity;
use maka_agent_facts::accounting::Group;
use maka_agent_facts::accounting::ModelSummary;
use maka_agent_facts::accounting::ModelTotals;
use maka_agent_facts::accounting::Pending;
use maka_agent_facts::accounting::ProviderSummary;
use maka_agent_facts::accounting::Selection;
use maka_agent_facts::accounting::ToolSummary;
use maka_agent_facts::accounting::ToolTotals;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Clone, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[schemars(rename = "SettingsUsageRange")]
pub struct Range {
#[schemars(range(min = 0, max = 9_007_199_254_740_991u64))]
pub from: f64,
#[schemars(range(min = 0, max = 9_007_199_254_740_991u64))]
pub to: f64,
#[serde(deserialize_with = "Option::deserialize")]
#[schemars(with = "maka_plugin_core::wire_schema::RequiredNullable<String>")]
pub session_id: Option<String>,
#[serde(deserialize_with = "Option::deserialize")]
#[schemars(with = "maka_plugin_core::wire_schema::RequiredNullable<u64>")]
pub through: Option<u64>,
}
impl From<Range> for maka_event_log::usage::Query {
fn from(value: Range) -> Self {
Self {
from: value.from,
to: value.to,
session_id: value.session_id,
through: value.through,
}
}
}
#[derive(Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
#[schemars(rename = "SettingsUsageRead")]
pub struct Read {
pub range: Range,
pub selection: Selection,
#[schemars(range(max = 9_007_199_254_740_991u64))]
pub offset: u64,
}
#[derive(Serialize, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[schemars(rename = "SettingsUsagePage")]
pub struct Page {
pub through: u64,
#[schemars(length(max = 32))]
pub attempts: Vec<Activity>,
pub total: u64,
pub next_offset: Option<u64>,
}
#[derive(Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
#[schemars(rename = "SettingsUsageSummaryRead")]
pub struct SummaryRead {
pub range: Range,
pub group: Group,
#[schemars(range(max = 9_007_199_254_740_991u64))]
pub offset: u64,
}
#[derive(Serialize, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[schemars(rename = "SettingsUsageTotals")]
pub struct Totals {
pub models: ModelTotals,
pub tools: ToolTotals,
pub pending: Pending,
#[schemars(length(max = 32))]
pub by_provider: Vec<ProviderSummary>,
#[schemars(length(max = 32))]
pub by_model: Vec<ModelSummary>,
#[schemars(length(max = 32))]
pub by_tool: Vec<ToolSummary>,
}
#[derive(Serialize, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[schemars(rename = "SettingsUsageSummary")]
pub struct Report {
pub through: u64,
pub summary: Totals,
pub next_offset: Option<u64>,
}
#[derive(Serialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
#[schemars(rename = "SettingsPricingResult")]
pub enum PricingResult {
Updated {
result: maka_agent_facts::pricing::Updated,
},
Rejected,
}
pub(crate) async fn page(log: &maka_event_log::EventLog, input: Value) -> Result<Value, String> {
let input: Read = serde_json::from_value(input).map_err(|_| "settings_input_invalid")?;
let page = log
.usage_activity(input.range.into(), input.selection, input.offset, 32)
.await
.map_err(|_| "settings_usage_unavailable")?;
super::connections::encode(Page {
through: page.through,
attempts: page.attempts,
total: page.total,
next_offset: page.next_offset,
})
}
pub(crate) async fn summary(log: &maka_event_log::EventLog, input: Value) -> Result<Value, String> {
let input: SummaryRead = serde_json::from_value(input).map_err(|_| "settings_input_invalid")?;
let report = log
.usage_summary_page(input.range.into(), input.group, input.offset)
.await
.map_err(|_| "settings_usage_unavailable")?;
let summary = report.summary;
super::connections::encode(Report {
through: report.through,
next_offset: report.next_offset,
summary: Totals {
models: summary.models,
tools: summary.tools,
pending: summary.pending,
by_provider: summary.by_provider,
by_model: summary.by_model,
by_tool: summary.by_tool,
},
})
}
pub(crate) async fn prices(
store: &maka_config::ConfigurationStore,
input: Value,
) -> Result<Value, String> {
let input = serde_json::from_value(input).map_err(|_| "settings_input_invalid")?;
super::connections::encode(
store
.query_pricing(input)
.await
.map_err(|_| "settings_prices_unavailable")?,
)
}
pub(crate) async fn update_price(
store: &maka_config::ConfigurationStore,
input: Value,
) -> Result<Value, String> {
let Ok(input) = serde_json::from_value(input) else {
return super::connections::encode(PricingResult::Rejected);
};
let result = match store.update_pricing(input).await {
Ok(result) => PricingResult::Updated { result },
Err(maka_config::ConfigError::Invalid(_)) => PricingResult::Rejected,
Err(_) => return Err("settings_effect_unknown".into()),
};
super::connections::encode(result)
}