From 914d718ebe5d7dcd58676ef54f4c1246268cb06f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 02:41:35 +0000 Subject: [PATCH] feat: emit agent usage metrics even when not in a git repo When running AI checkpoint outside a git repository, the AgentUsage metric event is now emitted before exiting. This ensures client metrics are still recorded for agent usage tracking regardless of whether the user is working in a git repo. Changes: - Make should_emit_agent_usage pub(crate) in checkpoint.rs - Add emit_no_repo_agent_metrics helper in git_ai_handlers.rs - Call it at both no-repo exit paths (no repos from files, no files) Co-Authored-By: Sasha Varlamov --- src/commands/checkpoint.rs | 4 ++-- src/commands/git_ai_handlers.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/commands/checkpoint.rs b/src/commands/checkpoint.rs index 3d7df0bd..9cf73cff 100644 --- a/src/commands/checkpoint.rs +++ b/src/commands/checkpoint.rs @@ -86,7 +86,7 @@ fn build_checkpoint_attrs( /// Persistent local rate limit keyed by prompt ID hash. #[cfg(not(any(test, feature = "test-support")))] -fn should_emit_agent_usage(agent_id: &AgentId) -> bool { +pub(crate) fn should_emit_agent_usage(agent_id: &AgentId) -> bool { let prompt_id = generate_short_hash(&agent_id.id, &agent_id.tool); let now_ts = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -107,7 +107,7 @@ fn should_emit_agent_usage(agent_id: &AgentId) -> bool { /// Always returns false in test mode — no metrics DB access needed. #[cfg(any(test, feature = "test-support"))] -fn should_emit_agent_usage(_agent_id: &AgentId) -> bool { +pub(crate) fn should_emit_agent_usage(_agent_id: &AgentId) -> bool { false } diff --git a/src/commands/git_ai_handlers.rs b/src/commands/git_ai_handlers.rs index 99c153e9..5d966216 100644 --- a/src/commands/git_ai_handlers.rs +++ b/src/commands/git_ai_handlers.rs @@ -1,3 +1,4 @@ +use crate::authorship::authorship_log_serialization::generate_short_hash; use crate::authorship::ignore::effective_ignore_patterns; use crate::authorship::internal_db::InternalDatabase; use crate::authorship::range_authorship; @@ -589,6 +590,7 @@ fn handle_checkpoint(args: &[String]) { "Failed to find any git repositories for the edited files. Orphaned files: {:?}", orphan_files ); + emit_no_repo_agent_metrics(agent_run_result.as_ref()); std::process::exit(0); } @@ -719,6 +721,7 @@ fn handle_checkpoint(args: &[String]) { eprintln!( "Failed to find repository: workspace root is not a git repository and no edited files provided" ); + emit_no_repo_agent_metrics(agent_run_result.as_ref()); std::process::exit(0); } @@ -1091,6 +1094,32 @@ fn handle_git_hooks(args: &[String]) { } } +fn emit_no_repo_agent_metrics(agent_run_result: Option<&AgentRunResult>) { + let Some(result) = agent_run_result else { + return; + }; + if result.checkpoint_kind == CheckpointKind::Human { + return; + } + + let agent_id = &result.agent_id; + if !commands::checkpoint::should_emit_agent_usage(agent_id) { + return; + } + + let prompt_id = generate_short_hash(&agent_id.id, &agent_id.tool); + let attrs = crate::metrics::EventAttributes::with_version(env!("CARGO_PKG_VERSION")) + .tool(&agent_id.tool) + .model(&agent_id.model) + .prompt_id(prompt_id) + .external_prompt_id(&agent_id.id); + + let values = crate::metrics::AgentUsageValues::new(); + crate::metrics::record(values, attrs); + + observability::spawn_background_flush(); +} + fn get_all_files_for_mock_ai(working_dir: &str) -> Vec { // Find the git repository let repo = match find_repository_in_path(working_dir) {