Skip to content

Commit 9a52674

Browse files
committed
merge qv2
2 parents e9ebd06 + 13feeaa commit 9a52674

File tree

7 files changed

+264
-98
lines changed

7 files changed

+264
-98
lines changed

crates/chat-cli/src/api_client/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ impl ApiClient {
382382
conversation_id,
383383
user_input_message,
384384
history,
385+
agent_continuation_id,
385386
} = conversation;
386387

387388
let model_id_opt: Option<String> = user_input_message.model_id.clone();
@@ -400,6 +401,8 @@ impl ApiClient {
400401
.map(|v| v.into_iter().map(|i| i.try_into()).collect::<Result<Vec<_>, _>>())
401402
.transpose()?,
402403
)
404+
.set_agent_continuation_id(agent_continuation_id)
405+
.agent_task_type(amzn_codewhisperer_streaming_client::types::AgentTaskType::Vibe)
403406
.build()
404407
.expect("building conversation should not fail");
405408

@@ -744,6 +747,7 @@ mod tests {
744747
model_id: Some("model".to_owned()),
745748
},
746749
history: None,
750+
agent_continuation_id: None,
747751
})
748752
.await
749753
.unwrap();

crates/chat-cli/src/api_client/model.rs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub struct ConversationState {
9797
pub conversation_id: Option<String>,
9898
pub user_input_message: UserInputMessage,
9999
pub history: Option<Vec<ChatMessage>>,
100+
pub agent_continuation_id: Option<String>,
100101
}
101102

102103
#[derive(Debug, Clone)]
@@ -542,7 +543,7 @@ impl TryFrom<AssistantResponseMessage> for amzn_qdeveloper_streaming_client::typ
542543
}
543544

544545
#[non_exhaustive]
545-
#[derive(Debug, Clone, PartialEq, Eq)]
546+
#[derive(Debug, Clone, PartialEq)]
546547
pub enum ChatResponseStream {
547548
AssistantResponseEvent {
548549
content: String,
@@ -563,6 +564,16 @@ pub enum ChatResponseStream {
563564
conversation_id: Option<String>,
564565
utterance_id: Option<String>,
565566
},
567+
MetadataEvent {
568+
total_tokens: Option<i32>,
569+
uncached_input_tokens: Option<i32>,
570+
output_tokens: Option<i32>,
571+
cache_read_input_tokens: Option<i32>,
572+
cache_write_input_tokens: Option<i32>,
573+
},
574+
MeteringEvent {
575+
usage: Option<f64>,
576+
},
566577
SupplementaryWebLinksEvent(()),
567578
ToolUseEvent {
568579
tool_use_id: String,
@@ -609,6 +620,18 @@ impl From<amzn_codewhisperer_streaming_client::types::ChatResponseStream> for Ch
609620
conversation_id,
610621
utterance_id,
611622
},
623+
amzn_codewhisperer_streaming_client::types::ChatResponseStream::MetadataEvent(
624+
amzn_codewhisperer_streaming_client::types::MetadataEvent { token_usage, .. },
625+
) => ChatResponseStream::MetadataEvent {
626+
total_tokens: token_usage.as_ref().map(|t| t.total_tokens),
627+
uncached_input_tokens: token_usage.as_ref().map(|t| t.uncached_input_tokens),
628+
output_tokens: token_usage.as_ref().map(|t| t.output_tokens),
629+
cache_read_input_tokens: token_usage.as_ref().and_then(|t| t.cache_read_input_tokens),
630+
cache_write_input_tokens: token_usage.as_ref().and_then(|t| t.cache_write_input_tokens),
631+
},
632+
amzn_codewhisperer_streaming_client::types::ChatResponseStream::MeteringEvent(
633+
amzn_codewhisperer_streaming_client::types::MeteringEvent { usage, .. },
634+
) => ChatResponseStream::MeteringEvent { usage },
612635
amzn_codewhisperer_streaming_client::types::ChatResponseStream::ToolUseEvent(
613636
amzn_codewhisperer_streaming_client::types::ToolUseEvent {
614637
tool_use_id,
@@ -626,7 +649,7 @@ impl From<amzn_codewhisperer_streaming_client::types::ChatResponseStream> for Ch
626649
amzn_codewhisperer_streaming_client::types::ChatResponseStream::SupplementaryWebLinksEvent(_) => {
627650
ChatResponseStream::SupplementaryWebLinksEvent(())
628651
},
629-
_ => ChatResponseStream::Unknown,
652+
_other => ChatResponseStream::Unknown,
630653
}
631654
}
632655
}
@@ -665,6 +688,18 @@ impl From<amzn_qdeveloper_streaming_client::types::ChatResponseStream> for ChatR
665688
conversation_id,
666689
utterance_id,
667690
},
691+
amzn_qdeveloper_streaming_client::types::ChatResponseStream::MetadataEvent(
692+
amzn_qdeveloper_streaming_client::types::MetadataEvent { token_usage, .. },
693+
) => ChatResponseStream::MetadataEvent {
694+
total_tokens: token_usage.as_ref().map(|t| t.total_tokens),
695+
uncached_input_tokens: token_usage.as_ref().map(|t| t.uncached_input_tokens),
696+
output_tokens: token_usage.as_ref().map(|t| t.output_tokens),
697+
cache_read_input_tokens: token_usage.as_ref().and_then(|t| t.cache_read_input_tokens),
698+
cache_write_input_tokens: token_usage.as_ref().and_then(|t| t.cache_write_input_tokens),
699+
},
700+
amzn_qdeveloper_streaming_client::types::ChatResponseStream::MeteringEvent(
701+
amzn_qdeveloper_streaming_client::types::MeteringEvent { usage, .. },
702+
) => ChatResponseStream::MeteringEvent { usage },
668703
amzn_qdeveloper_streaming_client::types::ChatResponseStream::ToolUseEvent(
669704
amzn_qdeveloper_streaming_client::types::ToolUseEvent {
670705
tool_use_id,
@@ -682,7 +717,7 @@ impl From<amzn_qdeveloper_streaming_client::types::ChatResponseStream> for ChatR
682717
amzn_qdeveloper_streaming_client::types::ChatResponseStream::SupplementaryWebLinksEvent(_) => {
683718
ChatResponseStream::SupplementaryWebLinksEvent(())
684719
},
685-
_ => ChatResponseStream::Unknown,
720+
_other => ChatResponseStream::Unknown,
686721
}
687722
}
688723
}
@@ -870,7 +905,8 @@ impl From<UserInputMessage> for amzn_codewhisperer_streaming_client::types::User
870905
.set_user_input_message_context(value.user_input_message_context.map(Into::into))
871906
.set_user_intent(value.user_intent.map(Into::into))
872907
.set_model_id(value.model_id)
873-
.origin(amzn_codewhisperer_streaming_client::types::Origin::Cli)
908+
//TODO: Setup new origin.
909+
.origin(amzn_codewhisperer_streaming_client::types::Origin::AiEditor)
874910
.build()
875911
.expect("Failed to build UserInputMessage")
876912
}
@@ -884,7 +920,8 @@ impl From<UserInputMessage> for amzn_qdeveloper_streaming_client::types::UserInp
884920
.set_user_input_message_context(value.user_input_message_context.map(Into::into))
885921
.set_user_intent(value.user_intent.map(Into::into))
886922
.set_model_id(value.model_id)
887-
.origin(amzn_qdeveloper_streaming_client::types::Origin::Cli)
923+
//TODO: Setup new origin.
924+
.origin(amzn_qdeveloper_streaming_client::types::Origin::AiEditor)
888925
.build()
889926
.expect("Failed to build UserInputMessage")
890927
}

crates/chat-cli/src/cli/chat/context.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -379,14 +379,12 @@ async fn process_path(
379379
async fn add_file_to_context(os: &Os, path: &Path, context_files: &mut Vec<(String, String)>) -> Result<()> {
380380
let filename = path.to_string_lossy().to_string();
381381
let content = os.fs.read_to_string(path).await?;
382-
382+
383383
// Check if this is a steering file that needs front matter filtering
384-
if filename.contains(".kiro/steering") && filename.ends_with(".md") {
385-
if !should_include_steering_file(&content)? {
386-
return Ok(());
387-
}
384+
if filename.contains(".kiro/steering") && filename.ends_with(".md") && !should_include_steering_file(&content)? {
385+
return Ok(());
388386
}
389-
387+
390388
context_files.push((filename, content));
391389
Ok(())
392390
}
@@ -403,30 +401,30 @@ fn should_include_steering_file(content: &str) -> Result<bool> {
403401
// No front matter - include the file
404402
return Ok(true);
405403
}
406-
404+
407405
// Find the end of the front matter
408406
let lines: Vec<&str> = content.lines().collect();
409407
let mut end_index = None;
410-
408+
411409
for (i, line) in lines.iter().enumerate().skip(1) {
412410
if line.trim() == "---" {
413411
end_index = Some(i);
414412
break;
415413
}
416414
}
417-
415+
418416
let end_index = match end_index {
419417
Some(idx) => idx,
420418
None => {
421419
// Malformed front matter - include the file
422420
return Ok(true);
423-
}
421+
},
424422
};
425-
423+
426424
// Extract and parse the front matter
427425
let front_matter_lines = &lines[1..end_index];
428426
let front_matter_yaml = front_matter_lines.join("\n");
429-
427+
430428
match serde_yaml::from_str::<FrontMatter>(&front_matter_yaml) {
431429
Ok(front_matter) => {
432430
match front_matter.inclusion.as_deref() {
@@ -436,11 +434,11 @@ fn should_include_steering_file(content: &str) -> Result<bool> {
436434
None => Ok(true), // No inclusion field - include
437435
Some(_) => Ok(true), // Unknown inclusion value - include
438436
}
439-
}
437+
},
440438
Err(_) => {
441439
// Failed to parse front matter - include the file
442440
Ok(true)
443-
}
441+
},
444442
}
445443
}
446444

crates/chat-cli/src/cli/chat/conversation.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,57 @@ pub struct McpServerInfo {
102102
pub config: CustomToolConfig,
103103
}
104104

105+
#[derive(Debug, Clone, Serialize, Deserialize)]
106+
pub struct UserTurnMetadata {
107+
continuation_id: String,
108+
/// [RequestMetadata] about the ongoing operation.
109+
requests: Vec<RequestMetadata>,
110+
}
111+
112+
impl Default for UserTurnMetadata {
113+
fn default() -> Self {
114+
Self::new()
115+
}
116+
}
117+
118+
/// Enum used to store metadata about user turns
119+
impl UserTurnMetadata {
120+
pub fn new() -> Self {
121+
Self {
122+
continuation_id: uuid::Uuid::new_v4().to_string(),
123+
requests: vec![],
124+
}
125+
}
126+
127+
pub fn continuation_id(&self) -> &str {
128+
&self.continuation_id
129+
}
130+
131+
pub fn add_request(&mut self, request: RequestMetadata) {
132+
self.requests.push(request);
133+
}
134+
135+
pub fn first_request(&self) -> Option<RequestMetadata> {
136+
self.requests.first().cloned()
137+
}
138+
139+
pub fn last_request(&self) -> Option<RequestMetadata> {
140+
self.requests.last().cloned()
141+
}
142+
143+
pub fn iter(&self) -> impl Iterator<Item = &RequestMetadata> {
144+
self.requests.iter()
145+
}
146+
147+
pub fn first(&self) -> Option<&RequestMetadata> {
148+
self.requests.first()
149+
}
150+
151+
pub fn last(&self) -> Option<&RequestMetadata> {
152+
self.requests.last()
153+
}
154+
}
155+
105156
/// Tracks state related to an ongoing conversation.
106157
#[derive(Debug, Clone, Serialize, Deserialize)]
107158
pub struct ConversationState {
@@ -149,6 +200,9 @@ pub struct ConversationState {
149200
/// Tangent mode checkpoint - stores main conversation when in tangent mode
150201
#[serde(default, skip_serializing_if = "Option::is_none")]
151202
tangent_state: Option<ConversationCheckpoint>,
203+
/// Metadata about the ongoing user turn operation
204+
#[serde(default)]
205+
pub user_turn_metadata: UserTurnMetadata,
152206
}
153207

154208
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -212,6 +266,7 @@ impl ConversationState {
212266
checkpoint_manager: None,
213267
mcp_enabled,
214268
tangent_state: None,
269+
user_turn_metadata: UserTurnMetadata::new(),
215270
}
216271
}
217272

@@ -378,6 +433,10 @@ impl ConversationState {
378433
self.next_message = None;
379434
}
380435

436+
pub fn current_continuation_id(&self) -> &str {
437+
self.user_turn_metadata.continuation_id()
438+
}
439+
381440
pub async fn set_next_user_message(&mut self, input: String) {
382441
debug_assert!(self.next_message.is_none(), "next_message should not exist");
383442
if let Some(next_message) = self.next_message.as_ref() {
@@ -614,6 +673,7 @@ impl ConversationState {
614673
dropped_context_files,
615674
tools: &self.tools,
616675
model_id: self.model_info.as_ref().map(|m| m.model_id.as_str()),
676+
continuation_id: Some(self.user_turn_metadata.continuation_id()),
617677
})
618678
}
619679

@@ -719,6 +779,7 @@ impl ConversationState {
719779
.unwrap_or(UserMessage::new_prompt(summary_content, None)) // should not happen
720780
.into_user_input_message(self.model_info.as_ref().map(|m| m.model_id.clone()), &tools),
721781
history: Some(flatten_history(history.iter())),
782+
agent_continuation_id: Some(self.user_turn_metadata.continuation_id().to_string()),
722783
})
723784
}
724785

@@ -777,6 +838,7 @@ Return only the JSON configuration, no additional text.",
777838
conversation_id: Some(self.conversation_id.clone()),
778839
user_input_message: generation_message.into_user_input_message(self.model.clone(), &tools),
779840
history: Some(flatten_history(history.iter())),
841+
agent_continuation_id: Some(self.user_turn_metadata.continuation_id().to_string()),
780842
})
781843
}
782844

@@ -992,6 +1054,7 @@ pub struct BackendConversationStateImpl<'a, T, U> {
9921054
pub dropped_context_files: Vec<(String, String)>,
9931055
pub tools: &'a HashMap<ToolOrigin, Vec<Tool>>,
9941056
pub model_id: Option<&'a str>,
1057+
pub continuation_id: Option<&'a str>,
9951058
}
9961059

9971060
impl BackendConversationStateImpl<'_, std::collections::vec_deque::Iter<'_, HistoryEntry>, Option<Vec<HistoryEntry>>> {
@@ -1007,6 +1070,7 @@ impl BackendConversationStateImpl<'_, std::collections::vec_deque::Iter<'_, Hist
10071070
conversation_id: Some(self.conversation_id.to_string()),
10081071
user_input_message,
10091072
history: Some(history),
1073+
agent_continuation_id: self.continuation_id.map(str::to_string),
10101074
})
10111075
}
10121076

0 commit comments

Comments
 (0)