runtime: emit metering events via public seam

This commit is contained in:
github-ops
2026-05-15 14:12:59 +00:00
parent 280ea99628
commit 42312ff76f
10 changed files with 270 additions and 19 deletions
@@ -1,5 +1,7 @@
use std::collections::BTreeMap;
use crank_core::{AgentId, InvocationSource, WorkspaceId};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ResponseCacheScope {
pub workspace_key: String,
@@ -11,6 +13,14 @@ pub struct RuntimeRequestContext {
pub request_id: String,
pub correlation_id: String,
pub response_cache_scope: Option<ResponseCacheScope>,
pub metering_context: Option<MeteringContext>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MeteringContext {
pub workspace_id: WorkspaceId,
pub agent_id: Option<AgentId>,
pub source: InvocationSource,
}
impl RuntimeRequestContext {
@@ -19,6 +29,7 @@ impl RuntimeRequestContext {
request_id: request_id.into(),
correlation_id: correlation_id.into(),
response_cache_scope: None,
metering_context: None,
}
}
@@ -49,6 +60,24 @@ impl RuntimeRequestContext {
pub fn response_cache_scope(&self) -> Option<&ResponseCacheScope> {
self.response_cache_scope.as_ref()
}
pub fn with_metering_context(
mut self,
workspace_id: WorkspaceId,
agent_id: Option<AgentId>,
source: InvocationSource,
) -> Self {
self.metering_context = Some(MeteringContext {
workspace_id,
agent_id,
source,
});
self
}
pub fn metering_context(&self) -> Option<&MeteringContext> {
self.metering_context.as_ref()
}
}
impl From<ResponseCacheScope> for crank_core::ResponseCacheScope {
@@ -75,12 +104,35 @@ impl From<&RuntimeRequestContext> for crank_core::RuntimeRequestContext {
request_id: value.request_id.clone(),
correlation_id: value.correlation_id.clone(),
response_cache_scope: value.response_cache_scope.as_ref().map(Into::into),
metering_context: value.metering_context.as_ref().map(Into::into),
}
}
}
impl From<MeteringContext> for crank_core::MeteringContext {
fn from(value: MeteringContext) -> Self {
Self {
workspace_id: value.workspace_id,
agent_id: value.agent_id,
source: value.source,
}
}
}
impl From<&MeteringContext> for crank_core::MeteringContext {
fn from(value: &MeteringContext) -> Self {
Self {
workspace_id: value.workspace_id.clone(),
agent_id: value.agent_id.clone(),
source: value.source,
}
}
}
#[cfg(test)]
mod tests {
use crank_core::{InvocationSource, WorkspaceId};
use super::RuntimeRequestContext;
#[test]
@@ -101,4 +153,18 @@ mod tests {
assert_eq!(scope.workspace_key, "ws_01");
assert_eq!(scope.agent_key, "agent_01");
}
#[test]
fn attaches_metering_context() {
let context = RuntimeRequestContext::from_request_id("req_123").with_metering_context(
WorkspaceId::new("ws_01"),
None,
InvocationSource::AdminTestRun,
);
let metering = context.metering_context().unwrap();
assert_eq!(metering.workspace_id, WorkspaceId::new("ws_01"));
assert_eq!(metering.agent_id, None);
assert_eq!(metering.source, InvocationSource::AdminTestRun);
}
}