story-kit: merge 141_story_improve_server_logging_with_timestamps_and_error_visibility
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use crate::agents::{close_bug_to_archive, move_story_to_archived, move_story_to_merge, move_story_to_qa};
|
||||
use crate::config::ProjectConfig;
|
||||
use crate::log_buffer;
|
||||
use crate::slog_warn;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::settings::get_editor_command_from_store;
|
||||
use crate::http::workflow::{
|
||||
@@ -757,6 +758,10 @@ fn handle_tools_list(id: Option<Value>) -> JsonRpcResponse {
|
||||
"filter": {
|
||||
"type": "string",
|
||||
"description": "Optional substring filter (e.g. 'watcher', 'mcp', 'permission')"
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"description": "Filter by severity level: ERROR, WARN, or INFO. Returns only entries at that level."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -848,13 +853,16 @@ async fn handle_tools_call(
|
||||
"content": [{ "type": "text", "text": content }]
|
||||
}),
|
||||
),
|
||||
Err(msg) => JsonRpcResponse::success(
|
||||
id,
|
||||
json!({
|
||||
"content": [{ "type": "text", "text": msg }],
|
||||
"isError": true
|
||||
}),
|
||||
),
|
||||
Err(msg) => {
|
||||
slog_warn!("[mcp] Tool call failed: tool={tool_name} error={msg}");
|
||||
JsonRpcResponse::success(
|
||||
id,
|
||||
json!({
|
||||
"content": [{ "type": "text", "text": msg }],
|
||||
"isError": true
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1577,12 +1585,15 @@ fn tool_get_server_logs(args: &Value) -> Result<String, String> {
|
||||
.map(|n| n.min(1000) as usize)
|
||||
.unwrap_or(100);
|
||||
let filter = args.get("filter").and_then(|v| v.as_str());
|
||||
let severity = args
|
||||
.get("severity")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(log_buffer::LogLevel::from_str_ci);
|
||||
|
||||
// Fetch extra buffer entries to account for multi-line entries within each
|
||||
let fetch = lines_count.saturating_mul(4).min(4000);
|
||||
let recent = log_buffer::global().get_recent(fetch, filter);
|
||||
// Flatten buffer entries into individual lines, then take the last lines_count
|
||||
let all_lines: Vec<&str> = recent.iter().flat_map(|s| s.lines()).collect();
|
||||
let recent = log_buffer::global().get_recent(lines_count, filter, severity.as_ref());
|
||||
let joined = recent.join("\n");
|
||||
// Clamp to lines_count actual lines in case any entry contains embedded newlines.
|
||||
let all_lines: Vec<&str> = joined.lines().collect();
|
||||
let start = all_lines.len().saturating_sub(lines_count);
|
||||
Ok(all_lines[start..].join("\n"))
|
||||
}
|
||||
@@ -1620,12 +1631,17 @@ async fn tool_prompt_permission(args: &Value, ctx: &AppContext) -> Result<String
|
||||
response_rx,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| format!("Permission request for '{tool_name}' timed out after 5 minutes"))?
|
||||
.map_err(|_| {
|
||||
let msg = format!("Permission request for '{tool_name}' timed out after 5 minutes");
|
||||
slog_warn!("[permission] {msg}");
|
||||
msg
|
||||
})?
|
||||
.map_err(|_| "Permission response channel closed unexpectedly".to_string())?;
|
||||
|
||||
if approved {
|
||||
Ok(json!({"behavior": "allow"}).to_string())
|
||||
} else {
|
||||
slog_warn!("[permission] User denied permission for '{tool_name}'");
|
||||
Ok(json!({
|
||||
"behavior": "deny",
|
||||
"message": format!("User denied permission for '{tool_name}'")
|
||||
|
||||
Reference in New Issue
Block a user