1use chio_core::receipt::{FinancialBudgetAuthorityReceiptMetadata, SettlementStatus};
2use serde::{Deserialize, Serialize};
3
4pub const MAX_COST_ATTRIBUTION_LIMIT: usize = 200;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(rename_all = "camelCase")]
10pub struct CostAttributionQuery {
11 #[serde(default, skip_serializing_if = "Option::is_none")]
12 pub capability_id: Option<String>,
13 #[serde(default, skip_serializing_if = "Option::is_none")]
14 pub agent_subject: Option<String>,
15 #[serde(default, skip_serializing_if = "Option::is_none")]
16 pub tool_server: Option<String>,
17 #[serde(default, skip_serializing_if = "Option::is_none")]
18 pub tool_name: Option<String>,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub since: Option<u64>,
21 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub until: Option<u64>,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub limit: Option<usize>,
25}
26
27impl Default for CostAttributionQuery {
28 fn default() -> Self {
29 Self {
30 capability_id: None,
31 agent_subject: None,
32 tool_server: None,
33 tool_name: None,
34 since: None,
35 until: None,
36 limit: Some(100),
37 }
38 }
39}
40
41#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
42#[serde(rename_all = "camelCase")]
43pub struct CostAttributionSummary {
44 pub matching_receipts: u64,
45 pub returned_receipts: u64,
46 pub total_cost_charged: u64,
47 pub total_attempted_cost: u64,
48 pub max_delegation_depth: u64,
49 pub distinct_root_subjects: u64,
50 pub distinct_leaf_subjects: u64,
51 pub lineage_gap_count: u64,
52 pub truncated: bool,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
56#[serde(rename_all = "camelCase")]
57pub struct CostAttributionChainHop {
58 pub capability_id: String,
59 pub subject_key: String,
60 pub issuer_key: String,
61 pub delegation_depth: u64,
62 #[serde(default, skip_serializing_if = "Option::is_none")]
63 pub parent_capability_id: Option<String>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
67#[serde(rename_all = "camelCase")]
68pub struct RootCostAttributionRow {
69 pub root_subject_key: String,
70 pub receipt_count: u64,
71 pub total_cost_charged: u64,
72 pub total_attempted_cost: u64,
73 pub distinct_leaf_subjects: u64,
74 pub max_delegation_depth: u64,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
78#[serde(rename_all = "camelCase")]
79pub struct LeafCostAttributionRow {
80 pub root_subject_key: String,
81 pub leaf_subject_key: String,
82 pub receipt_count: u64,
83 pub total_cost_charged: u64,
84 pub total_attempted_cost: u64,
85 pub max_delegation_depth: u64,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
89#[serde(rename_all = "camelCase")]
90pub struct CostAttributionReceiptRow {
91 pub seq: u64,
92 pub receipt_id: String,
93 pub timestamp: u64,
94 pub capability_id: String,
95 pub tool_server: String,
96 pub tool_name: String,
97 pub decision_kind: String,
98 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub root_subject_key: Option<String>,
100 #[serde(default, skip_serializing_if = "Option::is_none")]
101 pub leaf_subject_key: Option<String>,
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub grant_index: Option<u32>,
104 pub delegation_depth: u64,
105 pub cost_charged: u64,
106 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub attempted_cost: Option<u64>,
108 pub currency: String,
109 #[serde(default, skip_serializing_if = "Option::is_none")]
110 pub budget_total: Option<u64>,
111 #[serde(default, skip_serializing_if = "Option::is_none")]
112 pub budget_remaining: Option<u64>,
113 #[serde(default, skip_serializing_if = "Option::is_none")]
114 pub settlement_status: Option<SettlementStatus>,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
116 pub payment_reference: Option<String>,
117 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub budget_authority: Option<FinancialBudgetAuthorityReceiptMetadata>,
119 pub lineage_complete: bool,
120 pub chain: Vec<CostAttributionChainHop>,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
124#[serde(rename_all = "camelCase")]
125pub struct CostAttributionReport {
126 pub summary: CostAttributionSummary,
127 pub by_root: Vec<RootCostAttributionRow>,
128 pub by_leaf: Vec<LeafCostAttributionRow>,
129 pub receipts: Vec<CostAttributionReceiptRow>,
130}