| 522 | } |
| 523 | |
| 524 | fn classify_error_kind<T: ProvideErrorMetadata, R>( |
| 525 | status_code: Option<u16>, |
| 526 | body: &[u8], |
| 527 | model_id_opt: Option<&str>, |
| 528 | sdk_error: &error::SdkError<T, R>, |
| 529 | ) -> ConverseStreamErrorKind { |
| 530 | let contains = |haystack: &[u8], needle: &[u8]| haystack.windows(needle.len()).any(|v| v == needle); |
| 531 | |
| 532 | let is_throttling = status_code.is_some_and(|status| status == 429); |
| 533 | let is_context_window_overflow = contains(body, b"Input is too long."); |
| 534 | let is_model_unavailable = contains(body, b"INSUFFICIENT_MODEL_CAPACITY") |
| 535 | // Legacy error response fallback |
| 536 | || (model_id_opt.is_some() |
| 537 | && status_code.is_some_and(|status| status == 500) |
| 538 | && contains( |
| 539 | body, |
| 540 | b"Encountered unexpectedly high load when processing the request, please try again.", |
| 541 | )); |
| 542 | let is_monthly_limit_err = contains(body, b"MONTHLY_REQUEST_COUNT"); |
| 543 | |
| 544 | if is_context_window_overflow { |
| 545 | return ConverseStreamErrorKind::ContextWindowOverflow; |
| 546 | } |
| 547 | |
| 548 | // Both ModelOverloadedError and Throttling return 429, |
| 549 | // so check is_model_unavailable first. |
| 550 | if is_model_unavailable { |
| 551 | return ConverseStreamErrorKind::ModelOverloadedError; |
| 552 | } |
| 553 | |
| 554 | if is_throttling { |
| 555 | return ConverseStreamErrorKind::Throttling; |
| 556 | } |
| 557 | |
| 558 | if is_monthly_limit_err { |
| 559 | return ConverseStreamErrorKind::MonthlyLimitReached; |
| 560 | } |
| 561 | |
| 562 | ConverseStreamErrorKind::Unknown { |
| 563 | // do not change - we currently use sdk_error_code for mapping from an arbitrary sdk error |
| 564 | // to a reason code. |
| 565 | reason_code: error::sdk_error_code(sdk_error), |
| 566 | } |
| 567 | } |
| 568 | |
| 569 | fn timeout_config(database: &Database) -> TimeoutConfig { |
| 570 | let timeout = database |