diff --git a/Cargo.toml b/Cargo.toml
index 592903db..0bc08b32 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,6 +22,7 @@ unstable = [
"unstable_session_list",
"unstable_session_model",
"unstable_session_resume",
+ "unstable_session_usage",
]
unstable_cancel_request = []
unstable_session_config_options = []
@@ -30,6 +31,7 @@ unstable_session_info_update = []
unstable_session_list = []
unstable_session_model = []
unstable_session_resume = []
+unstable_session_usage = []
[[bin]]
name = "generate"
diff --git a/docs/protocol/draft/schema.mdx b/docs/protocol/draft/schema.mdx
index a90cfec6..440a6d99 100644
--- a/docs/protocol/draft/schema.mdx
+++ b/docs/protocol/draft/schema.mdx
@@ -612,6 +612,14 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte
StopReason} required>
Indicates why the agent stopped processing the turn.
+Usage | null>} >
+ **UNSTABLE**
+
+This capability is not part of the spec yet, and may be removed or changed at any point.
+
+Token usage for this turn (optional).
+
+
### session/resume
@@ -1955,6 +1963,25 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte
A single item of content
+## Cost
+
+**UNSTABLE**
+
+This capability is not part of the spec yet, and may be removed or changed at any point.
+
+Cost information for a session.
+
+**Type:** Object
+
+**Properties:**
+
+
+ Total cumulative cost for session.
+
+
+ ISO 4217 currency code (e.g., "USD", "EUR").
+
+
## CurrentModeUpdate
The current mode of the session has changed
@@ -3687,6 +3714,44 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte
+
+**UNSTABLE**
+
+This capability is not part of the spec yet, and may be removed or changed at any point.
+
+Context window and cost update for the session.
+
+
+
+
+ The _meta property is reserved by ACP to allow clients and agents to attach additional
+metadata to their interactions. Implementations MUST NOT make assumptions about values at
+these keys.
+
+See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
+
+
+Cost | null>} >
+ Cumulative session cost (optional).
+
+
+
+
+ Total context window size in tokens.
+
+ - Minimum: `0`
+
+
+
+ Tokens currently in context.
+
+ - Minimum: `0`
+
+
+
+
+
+
## StopReason
Reasons why an agent stops processing a prompt turn.
@@ -4131,3 +4196,88 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte
A hint to display when the input hasn't been provided yet
+
+## Usage
+
+**UNSTABLE**
+
+This capability is not part of the spec yet, and may be removed or changed at any point.
+
+Token usage information for a prompt turn.
+
+**Type:** Object
+
+**Properties:**
+
+
+ Total cache read tokens.
+
+ - Minimum: `0`
+
+
+
+ Total cache write tokens.
+
+ - Minimum: `0`
+
+
+
+ Total input tokens across all turns.
+
+ - Minimum: `0`
+
+
+
+ Total output tokens across all turns.
+
+ - Minimum: `0`
+
+
+
+ Total thought/reasoning tokens
+
+ - Minimum: `0`
+
+
+
+ Sum of all token types across session.
+
+ - Minimum: `0`
+
+
+
+## UsageUpdate
+
+**UNSTABLE**
+
+This capability is not part of the spec yet, and may be removed or changed at any point.
+
+Context window and cost update for a session.
+
+**Type:** Object
+
+**Properties:**
+
+
+ The _meta property is reserved by ACP to allow clients and agents to attach additional
+metadata to their interactions. Implementations MUST NOT make assumptions about values at
+these keys.
+
+See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
+
+
+Cost | null>} >
+ Cumulative session cost (optional).
+
+
+ Total context window size in tokens.
+
+ - Minimum: `0`
+
+
+
+ Tokens currently in context.
+
+ - Minimum: `0`
+
+
diff --git a/docs/rfds/session-usage.mdx b/docs/rfds/session-usage.mdx
index bf56bdfc..c8df37a1 100644
--- a/docs/rfds/session-usage.mdx
+++ b/docs/rfds/session-usage.mdx
@@ -92,7 +92,7 @@ Add a `usage` field to `PromptResponse` for token consumption tracking:
- `total_tokens` (number, required) - Sum of all token types across session
- `input_tokens` (number, required) - Total input tokens across all turns
- `output_tokens` (number, required) - Total output tokens across all turns
-- `thought_tokens` (number, optional) - Total thought/reasoning tokens (for o1/o3 models)
+- `thought_tokens` (number, optional) - Total thought/reasoning tokens
- `cached_read_tokens` (number, optional) - Total cache read tokens
- `cached_write_tokens` (number, optional) - Total cache write tokens
diff --git a/schema/schema.unstable.json b/schema/schema.unstable.json
index c7e8534c..f1fe59d8 100644
--- a/schema/schema.unstable.json
+++ b/schema/schema.unstable.json
@@ -1013,6 +1013,22 @@
"required": ["content"],
"type": "object"
},
+ "Cost": {
+ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCost information for a session.",
+ "properties": {
+ "amount": {
+ "description": "Total cumulative cost for session.",
+ "format": "double",
+ "type": "number"
+ },
+ "currency": {
+ "description": "ISO 4217 currency code (e.g., \"USD\", \"EUR\").",
+ "type": "string"
+ }
+ },
+ "required": ["amount", "currency"],
+ "type": "object"
+ },
"CreateTerminalRequest": {
"description": "Request to create a new terminal and execute a command.",
"properties": {
@@ -2224,6 +2240,17 @@
}
],
"description": "Indicates why the agent stopped processing the turn."
+ },
+ "usage": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/Usage"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nToken usage for this turn (optional)."
}
},
"required": ["stopReason"],
@@ -3191,6 +3218,22 @@
},
"required": ["sessionUpdate"],
"type": "object"
+ },
+ {
+ "allOf": [
+ {
+ "$ref": "#/$defs/UsageUpdate"
+ }
+ ],
+ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nContext window and cost update for the session.",
+ "properties": {
+ "sessionUpdate": {
+ "const": "usage_update",
+ "type": "string"
+ }
+ },
+ "required": ["sessionUpdate"],
+ "type": "object"
}
]
},
@@ -3813,6 +3856,84 @@
"required": ["hint"],
"type": "object"
},
+ "Usage": {
+ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nToken usage information for a prompt turn.",
+ "properties": {
+ "cachedReadTokens": {
+ "description": "Total cache read tokens.",
+ "format": "uint64",
+ "minimum": 0,
+ "type": ["integer", "null"]
+ },
+ "cachedWriteTokens": {
+ "description": "Total cache write tokens.",
+ "format": "uint64",
+ "minimum": 0,
+ "type": ["integer", "null"]
+ },
+ "inputTokens": {
+ "description": "Total input tokens across all turns.",
+ "format": "uint64",
+ "minimum": 0,
+ "type": "integer"
+ },
+ "outputTokens": {
+ "description": "Total output tokens across all turns.",
+ "format": "uint64",
+ "minimum": 0,
+ "type": "integer"
+ },
+ "thoughtTokens": {
+ "description": "Total thought/reasoning tokens",
+ "format": "uint64",
+ "minimum": 0,
+ "type": ["integer", "null"]
+ },
+ "totalTokens": {
+ "description": "Sum of all token types across session.",
+ "format": "uint64",
+ "minimum": 0,
+ "type": "integer"
+ }
+ },
+ "required": ["totalTokens", "inputTokens", "outputTokens"],
+ "type": "object"
+ },
+ "UsageUpdate": {
+ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nContext window and cost update for a session.",
+ "properties": {
+ "_meta": {
+ "additionalProperties": true,
+ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)",
+ "type": ["object", "null"]
+ },
+ "cost": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/Cost"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Cumulative session cost (optional)."
+ },
+ "size": {
+ "description": "Total context window size in tokens.",
+ "format": "uint64",
+ "minimum": 0,
+ "type": "integer"
+ },
+ "used": {
+ "description": "Tokens currently in context.",
+ "format": "uint64",
+ "minimum": 0,
+ "type": "integer"
+ }
+ },
+ "required": ["used", "size"],
+ "type": "object"
+ },
"WaitForTerminalExitRequest": {
"description": "Request to wait for a terminal command to exit.",
"properties": {
diff --git a/src/agent.rs b/src/agent.rs
index 6f5e5627..f3477d1e 100644
--- a/src/agent.rs
+++ b/src/agent.rs
@@ -2118,6 +2118,14 @@ impl PromptRequest {
pub struct PromptResponse {
/// Indicates why the agent stopped processing the turn.
pub stop_reason: StopReason,
+ /// **UNSTABLE**
+ ///
+ /// This capability is not part of the spec yet, and may be removed or changed at any point.
+ ///
+ /// Token usage for this turn (optional).
+ #[cfg(feature = "unstable_session_usage")]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub usage: Option,
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
/// these keys.
@@ -2132,10 +2140,24 @@ impl PromptResponse {
pub fn new(stop_reason: StopReason) -> Self {
Self {
stop_reason,
+ #[cfg(feature = "unstable_session_usage")]
+ usage: None,
meta: None,
}
}
+ /// **UNSTABLE**
+ ///
+ /// This capability is not part of the spec yet, and may be removed or changed at any point.
+ ///
+ /// Token usage for this turn.
+ #[cfg(feature = "unstable_session_usage")]
+ #[must_use]
+ pub fn usage(mut self, usage: impl IntoOption) -> Self {
+ self.usage = usage.into_option();
+ self
+ }
+
/// The _meta property is reserved by ACP to allow clients and agents to attach additional
/// metadata to their interactions. Implementations MUST NOT make assumptions about values at
/// these keys.
@@ -2175,6 +2197,69 @@ pub enum StopReason {
Cancelled,
}
+/// **UNSTABLE**
+///
+/// This capability is not part of the spec yet, and may be removed or changed at any point.
+///
+/// Token usage information for a prompt turn.
+#[cfg(feature = "unstable_session_usage")]
+#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+#[non_exhaustive]
+pub struct Usage {
+ /// Sum of all token types across session.
+ pub total_tokens: u64,
+ /// Total input tokens across all turns.
+ pub input_tokens: u64,
+ /// Total output tokens across all turns.
+ pub output_tokens: u64,
+ /// Total thought/reasoning tokens
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub thought_tokens: Option,
+ /// Total cache read tokens.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub cached_read_tokens: Option,
+ /// Total cache write tokens.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub cached_write_tokens: Option,
+}
+
+#[cfg(feature = "unstable_session_usage")]
+impl Usage {
+ #[must_use]
+ pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
+ Self {
+ total_tokens,
+ input_tokens,
+ output_tokens,
+ thought_tokens: None,
+ cached_read_tokens: None,
+ cached_write_tokens: None,
+ }
+ }
+
+ /// Total thought/reasoning tokens
+ #[must_use]
+ pub fn thought_tokens(mut self, thought_tokens: impl IntoOption) -> Self {
+ self.thought_tokens = thought_tokens.into_option();
+ self
+ }
+
+ /// Total cache read tokens.
+ #[must_use]
+ pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption) -> Self {
+ self.cached_read_tokens = cached_read_tokens.into_option();
+ self
+ }
+
+ /// Total cache write tokens.
+ #[must_use]
+ pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption) -> Self {
+ self.cached_write_tokens = cached_write_tokens.into_option();
+ self
+ }
+}
+
// Model
/// **UNSTABLE**
diff --git a/src/client.rs b/src/client.rs
index 94cf5644..2a6119b3 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -104,6 +104,13 @@ pub enum SessionUpdate {
#[cfg(feature = "unstable_session_info_update")]
/// Session metadata has been updated (title, timestamps, custom metadata)
SessionInfoUpdate(SessionInfoUpdate),
+ /// **UNSTABLE**
+ ///
+ /// This capability is not part of the spec yet, and may be removed or changed at any point.
+ ///
+ /// Context window and cost update for the session.
+ #[cfg(feature = "unstable_session_usage")]
+ UsageUpdate(UsageUpdate),
}
/// The current mode of the session has changed
@@ -245,6 +252,90 @@ impl SessionInfoUpdate {
}
}
+/// **UNSTABLE**
+///
+/// This capability is not part of the spec yet, and may be removed or changed at any point.
+///
+/// Context window and cost update for a session.
+#[cfg(feature = "unstable_session_usage")]
+#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
+#[serde(rename_all = "camelCase")]
+#[non_exhaustive]
+pub struct UsageUpdate {
+ /// Tokens currently in context.
+ pub used: u64,
+ /// Total context window size in tokens.
+ pub size: u64,
+ /// Cumulative session cost (optional).
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub cost: Option,
+ /// The _meta property is reserved by ACP to allow clients and agents to attach additional
+ /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
+ /// these keys.
+ ///
+ /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
+ #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
+ pub meta: Option,
+}
+
+#[cfg(feature = "unstable_session_usage")]
+impl UsageUpdate {
+ #[must_use]
+ pub fn new(used: u64, size: u64) -> Self {
+ Self {
+ used,
+ size,
+ cost: None,
+ meta: None,
+ }
+ }
+
+ /// Cumulative session cost (optional).
+ #[must_use]
+ pub fn cost(mut self, cost: impl IntoOption) -> Self {
+ self.cost = cost.into_option();
+ self
+ }
+
+ /// The _meta property is reserved by ACP to allow clients and agents to attach additional
+ /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
+ /// these keys.
+ ///
+ /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
+ #[must_use]
+ pub fn meta(mut self, meta: impl IntoOption) -> Self {
+ self.meta = meta.into_option();
+ self
+ }
+}
+
+/// **UNSTABLE**
+///
+/// This capability is not part of the spec yet, and may be removed or changed at any point.
+///
+/// Cost information for a session.
+#[cfg(feature = "unstable_session_usage")]
+#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
+#[serde(rename_all = "camelCase")]
+#[non_exhaustive]
+pub struct Cost {
+ /// Total cumulative cost for session.
+ pub amount: f64,
+ /// ISO 4217 currency code (e.g., "USD", "EUR").
+ pub currency: String,
+}
+
+#[cfg(feature = "unstable_session_usage")]
+impl Cost {
+ #[must_use]
+ pub fn new(amount: f64, currency: impl Into) -> Self {
+ Self {
+ amount,
+ currency: currency.into(),
+ }
+ }
+}
+
/// A streamed item of content
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "camelCase")]