@@ -30,7 +30,10 @@ use std::io::{
30
30
} ;
31
31
use std:: process:: ExitCode ;
32
32
use std:: sync:: Arc ;
33
- use std:: time:: Duration ;
33
+ use std:: time:: {
34
+ Duration ,
35
+ Instant ,
36
+ } ;
34
37
35
38
use amzn_codewhisperer_client:: types:: SubscriptionStatus ;
36
39
use clap:: {
@@ -138,6 +141,7 @@ use crate::database::settings::Setting;
138
141
use crate :: mcp_client:: Prompt ;
139
142
use crate :: os:: Os ;
140
143
use crate :: telemetry:: core:: {
144
+ AgentConfigInitArgs ,
141
145
ChatAddedMessageParams ,
142
146
ChatConversationType ,
143
147
MessageMetaTag ,
@@ -240,11 +244,26 @@ impl ChatArgs {
240
244
) ?;
241
245
}
242
246
247
+ let conversation_id = uuid:: Uuid :: new_v4 ( ) . to_string ( ) ;
248
+ info ! ( ?conversation_id, "Generated new conversation id" ) ;
249
+
243
250
let agents = {
244
251
let skip_migration = self . no_interactive ;
245
- let mut agents = Agents :: load ( os, self . agent . as_deref ( ) , skip_migration, & mut stderr) . await ;
252
+ let ( mut agents, md ) = Agents :: load ( os, self . agent . as_deref ( ) , skip_migration, & mut stderr) . await ;
246
253
agents. trust_all_tools = self . trust_all_tools ;
247
254
255
+ os. telemetry
256
+ . send_agent_config_init ( & os. database , conversation_id. clone ( ) , AgentConfigInitArgs {
257
+ agents_loaded_count : md. load_count as i64 ,
258
+ agents_loaded_failed_count : md. load_failed_count as i64 ,
259
+ legacy_profile_migration_executed : md. migration_performed ,
260
+ legacy_profile_migrated_count : md. migrated_count as i64 ,
261
+ launched_agent : md. launched_agent ,
262
+ } )
263
+ . await
264
+ . map_err ( |err| error ! ( ?err, "failed to send agent config init telemetry" ) )
265
+ . ok ( ) ;
266
+
248
267
if agents
249
268
. get_active ( )
250
269
. is_some_and ( |a| !a. mcp_servers . mcp_servers . is_empty ( ) )
@@ -287,8 +306,6 @@ impl ChatArgs {
287
306
None
288
307
} ;
289
308
290
- let conversation_id = uuid:: Uuid :: new_v4 ( ) . to_string ( ) ;
291
- info ! ( ?conversation_id, "Generated new conversation id" ) ;
292
309
let ( prompt_request_sender, prompt_request_receiver) = std:: sync:: mpsc:: channel :: < Option < String > > ( ) ;
293
310
let ( prompt_response_sender, prompt_response_receiver) = std:: sync:: mpsc:: channel :: < Vec < String > > ( ) ;
294
311
let mut tool_manager = ToolManagerBuilder :: default ( )
@@ -495,10 +512,17 @@ pub struct ChatSession {
495
512
spinner : Option < Spinner > ,
496
513
/// [ConversationState].
497
514
conversation : ConversationState ,
515
+ /// Tool uses requested by the model that are actively being handled.
498
516
tool_uses : Vec < QueuedTool > ,
517
+ /// An index into [Self::tool_uses] to represent the current tool use being handled.
518
+ pending_tool_index : Option < usize > ,
519
+ /// The time immediately after having received valid tool uses from the model.
520
+ ///
521
+ /// Used to track the time taken from initially prompting the user to tool execute
522
+ /// completion.
523
+ tool_turn_start_time : Option < Instant > ,
499
524
/// [RequestMetadata] about the ongoing operation.
500
525
user_turn_request_metadata : Vec < RequestMetadata > ,
501
- pending_tool_index : Option < usize > ,
502
526
/// Telemetry events to be sent as part of the conversation. The HashMap key is tool_use_id.
503
527
tool_use_telemetry_events : HashMap < String , ToolUseEventBuilder > ,
504
528
/// State used to keep track of tool use relation
@@ -622,6 +646,7 @@ impl ChatSession {
622
646
tool_uses : vec ! [ ] ,
623
647
user_turn_request_metadata : vec ! [ ] ,
624
648
pending_tool_index : None ,
649
+ tool_turn_start_time : None ,
625
650
tool_use_telemetry_events : HashMap :: new ( ) ,
626
651
tool_use_status : ToolUseStatus :: Idle ,
627
652
failed_request_ids : Vec :: new ( ) ,
@@ -978,6 +1003,7 @@ impl ChatSession {
978
1003
self . conversation . enforce_conversation_invariants ( ) ;
979
1004
self . conversation . reset_next_user_message ( ) ;
980
1005
self . pending_tool_index = None ;
1006
+ self . tool_turn_start_time = None ;
981
1007
self . reset_user_turn ( ) ;
982
1008
983
1009
self . inner = Some ( ChatState :: PromptUser {
@@ -1806,6 +1832,9 @@ impl ChatSession {
1806
1832
1807
1833
if allowed {
1808
1834
tool. accepted = true ;
1835
+ self . tool_use_telemetry_events
1836
+ . entry ( tool. id . clone ( ) )
1837
+ . and_modify ( |ev| ev. is_trusted = true ) ;
1809
1838
continue ;
1810
1839
}
1811
1840
@@ -1821,10 +1850,12 @@ impl ChatSession {
1821
1850
let mut image_blocks: Vec < RichImageBlock > = Vec :: new ( ) ;
1822
1851
1823
1852
for tool in & self . tool_uses {
1853
+ let tool_start = std:: time:: Instant :: now ( ) ;
1824
1854
let mut tool_telemetry = self . tool_use_telemetry_events . entry ( tool. id . clone ( ) ) ;
1825
- tool_telemetry = tool_telemetry. and_modify ( |ev| ev. is_accepted = true ) ;
1855
+ tool_telemetry = tool_telemetry. and_modify ( |ev| {
1856
+ ev. is_accepted = true ;
1857
+ } ) ;
1826
1858
1827
- let tool_start = std:: time:: Instant :: now ( ) ;
1828
1859
let invoke_result = tool. tool . invoke ( os, & mut self . stdout ) . await ;
1829
1860
1830
1861
if self . spinner . is_some ( ) {
@@ -1837,12 +1868,18 @@ impl ChatSession {
1837
1868
}
1838
1869
execute ! ( self . stdout, style:: Print ( "\n " ) ) ?;
1839
1870
1840
- let tool_time = std:: time:: Instant :: now ( ) . duration_since ( tool_start) ;
1871
+ let tool_end_time = Instant :: now ( ) ;
1872
+ let tool_time = tool_end_time. duration_since ( tool_start) ;
1873
+ tool_telemetry = tool_telemetry. and_modify ( |ev| {
1874
+ ev. execution_duration = Some ( tool_time) ;
1875
+ ev. turn_duration = self . tool_turn_start_time . map ( |t| tool_end_time. duration_since ( t) ) ;
1876
+ } ) ;
1841
1877
if let Tool :: Custom ( ct) = & tool. tool {
1842
1878
tool_telemetry = tool_telemetry. and_modify ( |ev| {
1879
+ ev. is_custom_tool = true ;
1880
+ // legacy fields previously implemented for only MCP tools
1843
1881
ev. custom_tool_call_latency = Some ( tool_time. as_secs ( ) as usize ) ;
1844
1882
ev. input_token_size = Some ( ct. get_input_token_size ( ) ) ;
1845
- ev. is_custom_tool = true ;
1846
1883
} ) ;
1847
1884
}
1848
1885
let tool_time = format ! ( "{}.{}" , tool_time. as_secs( ) , tool_time. subsec_millis( ) ) ;
@@ -2232,6 +2269,7 @@ impl ChatSession {
2232
2269
} else {
2233
2270
self . tool_uses . clear ( ) ;
2234
2271
self . pending_tool_index = None ;
2272
+ self . tool_turn_start_time = None ;
2235
2273
2236
2274
self . send_chat_telemetry ( os, TelemetryResult :: Succeeded , None , None , None , true )
2237
2275
. await ;
@@ -2342,6 +2380,7 @@ impl ChatSession {
2342
2380
2343
2381
self . tool_uses = queued_tools;
2344
2382
self . pending_tool_index = Some ( 0 ) ;
2383
+ self . tool_turn_start_time = Some ( Instant :: now ( ) ) ;
2345
2384
Ok ( ChatState :: ExecuteTools )
2346
2385
}
2347
2386
@@ -2353,6 +2392,7 @@ impl ChatSession {
2353
2392
self . conversation . enforce_conversation_invariants ( ) ;
2354
2393
self . conversation . reset_next_user_message ( ) ;
2355
2394
self . pending_tool_index = None ;
2395
+ self . tool_turn_start_time = None ;
2356
2396
return Ok ( ChatState :: PromptUser {
2357
2397
skip_printing_tools : false ,
2358
2398
} ) ;
0 commit comments