Adding logging when we crash in bedrock, adding open AI request translator changes and AI page settings cleanup

This commit is contained in:
Ryan Ward
2026-07-08 15:19:51 -05:00
parent bc83792d7a
commit 40bd86f662
11 changed files with 686 additions and 287 deletions
+9
View File
@@ -268,6 +268,15 @@ impl BedrockClient {
);
}
}
super::crash_log::log_crash(
"BedrockApiError",
&msg,
&effective_model_id,
messages.len(),
None,
);
if msg.contains("AccessDenied") || msg.contains("access denied") {
BedrockError::AccessDenied(msg)
} else if msg.contains("ThrottlingException") || msg.contains("throttl") {
+95
View File
@@ -0,0 +1,95 @@
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
use chrono::Local;
const CRASH_LOG_DIR: &str = "crash-logs";
const MAX_CRASH_LOGS: usize = 20;
fn crash_log_dir() -> Option<PathBuf> {
galaxy_core::paths::galaxy_home_config_dir().map(|dir| dir.join(CRASH_LOG_DIR))
}
pub fn log_crash(
error_type: &str,
error_message: &str,
model_id: &str,
message_count: usize,
context_tokens: Option<u32>,
) {
let Some(dir) = crash_log_dir() else {
log::warn!("[crash-log] Could not determine crash log directory");
return;
};
if let Err(e) = fs::create_dir_all(&dir) {
log::warn!("[crash-log] Failed to create crash log directory: {e}");
return;
}
rotate_logs(&dir);
let timestamp = Local::now();
let filename = format!("crash_{}.log", timestamp.format("%Y%m%d_%H%M%S"));
let path = dir.join(&filename);
let content = format!(
"=== Galaxy Crash Log ===\n\
Timestamp: {}\n\
Error Type: {}\n\
Model: {}\n\
Message Count: {}\n\
Context Tokens: {}\n\
\n\
Error Details:\n\
{}\n\
========================\n",
timestamp.format("%Y-%m-%d %H:%M:%S %Z"),
error_type,
model_id,
message_count,
context_tokens
.map(|t| t.to_string())
.unwrap_or_else(|| "unknown".to_string()),
error_message,
);
match OpenOptions::new().create(true).write(true).open(&path) {
Ok(mut file) => {
if let Err(e) = file.write_all(content.as_bytes()) {
log::warn!("[crash-log] Failed to write crash log: {e}");
} else {
log::info!("[crash-log] Wrote crash log to {}", path.display());
}
}
Err(e) => {
log::warn!("[crash-log] Failed to open crash log file: {e}");
}
}
}
fn rotate_logs(dir: &std::path::Path) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
let mut logs: Vec<PathBuf> = entries
.filter_map(|e| e.ok())
.map(|e| e.path())
.filter(|p| {
p.file_name()
.and_then(|n| n.to_str())
.is_some_and(|n| n.starts_with("crash_") && n.ends_with(".log"))
})
.collect();
logs.sort();
while logs.len() >= MAX_CRASH_LOGS {
if let Some(oldest) = logs.first() {
let _ = fs::remove_file(oldest);
logs.remove(0);
}
}
}
+1
View File
@@ -1,5 +1,6 @@
pub mod client;
pub mod convert;
pub mod crash_log;
pub mod diagnostic;
pub mod external_config;
pub mod models;
+35
View File
@@ -1562,6 +1562,41 @@ fn extract_tool_result_content(result: &api::request::input::ToolCallResult) ->
None => ("Agent completed.".to_string(), false),
}
}
api::request::input::tool_call_result::Result::AskUserQuestion(ask_result) => {
match &ask_result.result {
Some(api::ask_user_question_result::Result::Success(success)) => {
let answers_text: Vec<String> = success
.answers
.iter()
.map(|item| {
let answer_str = match &item.answer {
Some(api::ask_user_question_result::answer_item::Answer::MultipleChoice(mc)) => {
let mut parts = mc.selected_options.clone();
if !mc.other_text.is_empty() {
parts.push(mc.other_text.clone());
}
parts.join(", ")
}
Some(api::ask_user_question_result::answer_item::Answer::Skipped(_)) => {
"Skipped".to_string()
}
None => "No answer provided".to_string(),
};
if item.question_id.is_empty() {
answer_str
} else {
format!("{}: {}", item.question_id, answer_str)
}
})
.collect();
(format!("User's answers:\n{}", answers_text.join("\n")), false)
}
Some(api::ask_user_question_result::Result::Error(error)) => {
(format!("User question error: {}", error.message), true)
}
None => ("User did not answer.".to_string(), true),
}
}
_ => ("Tool completed successfully.".to_string(), false),
}
} else {
@@ -397,6 +397,13 @@ pub fn bedrock_stream_to_response_events(
);
}
}
super::crash_log::log_crash(
"BedrockStreamError",
&format!("{e}"),
&model_id,
event_count as usize,
Some(input_tokens as u32),
);
if !buffered_text.is_empty() {
let msg_id = current_text_message_id
.clone()