Skip to content

Commit 906bf76

Browse files
authored
feat: show users when quota is breached (#687)
* feat: show users when quota is breached * fix: converts print function to use Report * fix: removes redundant ok * fix: lints and fmt
1 parent cf8889e commit 906bf76

File tree

4 files changed

+109
-20
lines changed

4 files changed

+109
-20
lines changed

crates/fig_api_client/src/clients/streaming_client.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,23 @@ impl StreamingClient {
119119
)
120120
.build()
121121
.expect("building conversation_state should not fail");
122+
let response = client
123+
.generate_assistant_response()
124+
.conversation_state(conversation_state)
125+
.send()
126+
.await;
122127

123-
Ok(SendMessageOutput::Codewhisperer(
124-
client
125-
.generate_assistant_response()
126-
.conversation_state(conversation_state)
127-
.send()
128-
.await?,
129-
))
128+
match response {
129+
Ok(resp) => Ok(SendMessageOutput::Codewhisperer(resp)),
130+
Err(e) => {
131+
let is_quota_breach = e.raw_response().is_some_and(|resp| resp.status().as_u16() == 429);
132+
if is_quota_breach {
133+
Err(Error::QuotaBreach("quota has reached its limit"))
134+
} else {
135+
Err(e.into())
136+
}
137+
},
138+
}
130139
},
131140
inner::Inner::QDeveloper(client) => {
132141
let conversation_state_builder = amzn_qdeveloper_streaming_client::types::ConversationState::builder()

crates/fig_api_client/src/error.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ pub enum Error {
4444
#[error("{}", SdkErrorDisplay(.0))]
4545
QDeveloperChatResponseStream(#[from] SdkError<QDeveloperChatResponseStreamError, RawMessage>),
4646

47+
// quota breach
48+
#[error("quota has reached its limit")]
49+
QuotaBreach(&'static str),
50+
4751
#[error(transparent)]
4852
SmithyBuild(#[from] aws_smithy_types::error::operation::BuildError),
4953

@@ -66,7 +70,8 @@ impl Error {
6670
Error::CodewhispererChatResponseStream(_)
6771
| Error::QDeveloperChatResponseStream(_)
6872
| Error::SmithyBuild(_)
69-
| Error::UnsupportedConsolas(_) => false,
73+
| Error::UnsupportedConsolas(_)
74+
| Error::QuotaBreach(_) => false,
7075
}
7176
}
7277

@@ -82,7 +87,8 @@ impl Error {
8287
Error::CodewhispererChatResponseStream(_)
8388
| Error::QDeveloperChatResponseStream(_)
8489
| Error::SmithyBuild(_)
85-
| Error::UnsupportedConsolas(_) => false,
90+
| Error::UnsupportedConsolas(_)
91+
| Error::QuotaBreach(_) => false,
8692
}
8793
}
8894
}

crates/q_cli/src/cli/chat/error.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use thiserror::Error;
2+
3+
#[derive(Debug, Error)]
4+
pub enum PromptAndSendError {
5+
FigClientError(fig_api_client::Error),
6+
IO(std::io::Error),
7+
Report(eyre::Report),
8+
}
9+
10+
impl std::fmt::Display for PromptAndSendError {
11+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12+
match self {
13+
PromptAndSendError::FigClientError(err) => err.fmt(f),
14+
PromptAndSendError::IO(err) => err.fmt(f),
15+
PromptAndSendError::Report(err) => err.fmt(f),
16+
}
17+
}
18+
}
19+
20+
impl From<fig_api_client::Error> for PromptAndSendError {
21+
fn from(value: fig_api_client::Error) -> Self {
22+
PromptAndSendError::FigClientError(value)
23+
}
24+
}
25+
26+
impl From<std::io::Error> for PromptAndSendError {
27+
fn from(value: std::io::Error) -> Self {
28+
PromptAndSendError::IO(value)
29+
}
30+
}
31+
32+
impl From<eyre::Report> for PromptAndSendError {
33+
fn from(value: eyre::Report) -> Self {
34+
PromptAndSendError::Report(value)
35+
}
36+
}

crates/q_cli/src/cli/chat/mod.rs

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod conversation_state;
2+
mod error;
23
mod input_source;
34
mod parse;
45
mod parser;
@@ -28,6 +29,7 @@ use crossterm::{
2829
style,
2930
terminal,
3031
};
32+
use error::PromptAndSendError;
3133
use eyre::{
3234
Result,
3335
bail,
@@ -147,6 +149,29 @@ fn load_tools() -> Result<ToolConfiguration> {
147149
})
148150
}
149151

152+
fn print_error<W: Write>(
153+
output: &mut W,
154+
prepend_msg: &str,
155+
report: Option<eyre::Report>,
156+
) -> Result<(), std::io::Error> {
157+
queue!(
158+
output,
159+
style::SetAttribute(Attribute::Bold),
160+
style::SetForegroundColor(Color::Red),
161+
)?;
162+
if let Some(report) = report {
163+
queue!(output, style::Print(format!("{}: {:?}\n", prepend_msg, report)),)?;
164+
} else {
165+
queue!(output, style::Print(prepend_msg), style::Print("\n"))?;
166+
}
167+
queue!(
168+
output,
169+
style::SetForegroundColor(Color::Reset),
170+
style::SetAttribute(Attribute::Reset),
171+
)?;
172+
output.flush()
173+
}
174+
150175
/// Required fields for initializing a new chat session.
151176
struct ChatArgs<'o, W> {
152177
/// The [Write] destination for printing conversation text.
@@ -250,15 +275,26 @@ Hi, I'm <g>Amazon Q</g>. Ask me anything.
250275
cursor::Show
251276
)?;
252277
}
253-
execute!(
254-
self.output,
255-
style::SetAttribute(Attribute::Bold),
256-
style::SetForegroundColor(Color::Red),
257-
style::Print(format!("Amazon Q is having trouble responding right now: {:?}\n", e)),
258-
style::Print("Please try again later.\n\n"),
259-
style::SetForegroundColor(Color::Reset),
260-
style::SetAttribute(Attribute::Reset),
261-
)?;
278+
match e {
279+
PromptAndSendError::FigClientError(err) => {
280+
if let fig_api_client::Error::QuotaBreach(msg) = err {
281+
print_error(self.output, msg, None)?;
282+
} else {
283+
print_error(
284+
self.output,
285+
"Amazon Q is having trouble responding right now",
286+
Some(err.into()),
287+
)?;
288+
}
289+
},
290+
_ => {
291+
print_error(
292+
self.output,
293+
"Amazon Q is having trouble responding right now",
294+
Some(e.into()),
295+
)?;
296+
},
297+
}
262298
if self.conversation_state.next_message.is_none() {
263299
self.conversation_state.history.pop_back();
264300
}
@@ -445,7 +481,7 @@ Hi, I'm <g>Amazon Q</g>. Ask me anything.
445481
&mut self,
446482
sigint_recver: &mut tokio::sync::mpsc::Receiver<()>,
447483
should_terminate: &Arc<AtomicBool>,
448-
) -> Result<Option<SendMessageOutput>> {
484+
) -> Result<Option<SendMessageOutput>, error::PromptAndSendError> {
449485
loop {
450486
// Tool uses that need to be executed.
451487
let mut queued_tools: Vec<(String, Tool)> = Vec::new();
@@ -548,7 +584,9 @@ Hi, I'm <g>Amazon Q</g>. Ask me anything.
548584
self.tool_use_recursions += 1;
549585
let terminal_width = self.terminal_width();
550586
if self.tool_use_recursions > MAX_TOOL_USE_RECURSIONS {
551-
bail!("Exceeded max tool use recursion limit: {}", MAX_TOOL_USE_RECURSIONS);
587+
return Err(
588+
eyre::eyre!("Exceeded max tool use recursion limit: {}", MAX_TOOL_USE_RECURSIONS).into(),
589+
);
552590
}
553591

554592
for (i, (_, tool)) in queued_tools.iter().enumerate() {

0 commit comments

Comments
 (0)