优化消息里的读/写工具代码样式
This commit is contained in:
@@ -633,42 +633,71 @@ impl ClaudeParser {
|
|||||||
})
|
})
|
||||||
.map(|s| s.to_string());
|
.map(|s| s.to_string());
|
||||||
|
|
||||||
// For read tools, structurize with start_line from tool_input.offset
|
// Don't structurize here — `structurize_read_tool_output`
|
||||||
let output_preview =
|
// will handle Read tool output uniformly after grouping.
|
||||||
if tool_name == "read" || tool_name == "Read" {
|
let output_preview = output_text;
|
||||||
let start_line = value
|
|
||||||
.get("tool_input")
|
// Find the matching ToolUse by tool_name (reverse scan so the
|
||||||
.and_then(|i| i.get("offset"))
|
// most recent match wins), then fall back to the last ToolUse
|
||||||
.and_then(|o| o.as_u64())
|
// without a paired ToolResult yet.
|
||||||
.map(|o| o + 1)
|
let existing_result_ids: std::collections::HashSet<String> = messages
|
||||||
.unwrap_or(1);
|
.iter()
|
||||||
output_text.map(|text| {
|
.rev()
|
||||||
serde_json::json!({
|
.find(|m| matches!(m.role, MessageRole::Assistant))
|
||||||
"start_line": start_line,
|
.map(|m| {
|
||||||
"content": text
|
m.content
|
||||||
})
|
.iter()
|
||||||
.to_string()
|
.filter_map(|b| {
|
||||||
})
|
if let ContentBlock::ToolResult {
|
||||||
} else {
|
tool_use_id: Some(ref id),
|
||||||
output_text
|
..
|
||||||
};
|
} = b
|
||||||
|
{
|
||||||
|
Some(id.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
// Find matching ToolUse in the last assistant message and use its ID
|
|
||||||
let matching_id = messages
|
let matching_id = messages
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find(|m| matches!(m.role, MessageRole::Assistant))
|
.find(|m| matches!(m.role, MessageRole::Assistant))
|
||||||
.and_then(|m| {
|
.and_then(|m| {
|
||||||
|
// First: try to find an unpaired ToolUse with the same tool_name
|
||||||
|
let by_name = m.content.iter().rev().find_map(|b| {
|
||||||
|
if let ContentBlock::ToolUse {
|
||||||
|
tool_use_id: Some(ref id),
|
||||||
|
tool_name: ref tn,
|
||||||
|
..
|
||||||
|
} = b
|
||||||
|
{
|
||||||
|
if tn == tool_name
|
||||||
|
&& !existing_result_ids.contains(id)
|
||||||
|
{
|
||||||
|
return Some(id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
if by_name.is_some() {
|
||||||
|
return by_name;
|
||||||
|
}
|
||||||
|
// Fallback: last unpaired ToolUse regardless of name
|
||||||
m.content.iter().rev().find_map(|b| {
|
m.content.iter().rev().find_map(|b| {
|
||||||
if let ContentBlock::ToolUse {
|
if let ContentBlock::ToolUse {
|
||||||
tool_use_id: Some(ref id),
|
tool_use_id: Some(ref id),
|
||||||
..
|
..
|
||||||
} = b
|
} = b
|
||||||
{
|
{
|
||||||
Some(id.clone())
|
if !existing_result_ids.contains(id) {
|
||||||
} else {
|
return Some(id.clone());
|
||||||
None
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -517,7 +517,7 @@ export function UnifiedDiffPreview({
|
|||||||
{files.map((file) => (
|
{files.map((file) => (
|
||||||
<section
|
<section
|
||||||
key={file.key}
|
key={file.key}
|
||||||
className="flex max-h-[480px] flex-col rounded-lg border border-border bg-background"
|
className="flex max-h-[420px] flex-col rounded-lg border border-border bg-background"
|
||||||
>
|
>
|
||||||
<header className="flex shrink-0 items-center gap-2 border-b border-border bg-muted/40 px-3 py-2 text-[11px]">
|
<header className="flex shrink-0 items-center gap-2 border-b border-border bg-muted/40 px-3 py-2 text-[11px]">
|
||||||
<span className="shrink-0 rounded border border-border bg-background px-1.5 py-0.5 text-[10px] text-muted-foreground">
|
<span className="shrink-0 rounded border border-border bg-background px-1.5 py-0.5 text-[10px] text-muted-foreground">
|
||||||
|
|||||||
@@ -1321,7 +1321,7 @@ function FileToolInput({
|
|||||||
}, [isRead, output, content, newSource])
|
}, [isRead, output, content, newSource])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="flex max-h-[480px] flex-col rounded-lg border border-border bg-background">
|
<section className="flex max-h-[420px] flex-col rounded-lg border border-border bg-background">
|
||||||
<header className="flex shrink-0 items-center gap-2 border-b border-border bg-muted/40 px-3 py-2 text-[11px]">
|
<header className="flex shrink-0 items-center gap-2 border-b border-border bg-muted/40 px-3 py-2 text-[11px]">
|
||||||
<span className="shrink-0 rounded border border-border bg-background px-1.5 py-0.5 text-[10px] text-muted-foreground">
|
<span className="shrink-0 rounded border border-border bg-background px-1.5 py-0.5 text-[10px] text-muted-foreground">
|
||||||
{isRead ? "READ" : "WRITE"}
|
{isRead ? "READ" : "WRITE"}
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "يتم عرض نهاية المخرجات أثناء البث لتحسين الأداء.",
|
"showingTailOutput": "يتم عرض نهاية المخرجات أثناء البث لتحسين الأداء.",
|
||||||
"result": "النتيجة",
|
"result": "النتيجة",
|
||||||
"unknown": "غير معروف",
|
"unknown": "غير معروف",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "تم اقتطاع الإدخال — قد يكون الفرق غير مكتمل.",
|
||||||
"replaceAll": "استبدال الكل",
|
"replaceAll": "استبدال الكل",
|
||||||
"filesCount": "الملفات: {count}",
|
"filesCount": "الملفات: {count}",
|
||||||
"update": "تحديث",
|
"update": "تحديث",
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "Zur besseren Performance wird während des Streamings nur die Endausgabe angezeigt.",
|
"showingTailOutput": "Zur besseren Performance wird während des Streamings nur die Endausgabe angezeigt.",
|
||||||
"result": "Ergebnis",
|
"result": "Ergebnis",
|
||||||
"unknown": "unbekannt",
|
"unknown": "unbekannt",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "Eingabe wurde gekürzt — Diff ist möglicherweise unvollständig.",
|
||||||
"replaceAll": "ALLES ERSETZEN",
|
"replaceAll": "ALLES ERSETZEN",
|
||||||
"filesCount": "Dateien: {count}",
|
"filesCount": "Dateien: {count}",
|
||||||
"update": "aktualisieren",
|
"update": "aktualisieren",
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "Mostrando la salida final durante el streaming para mejorar el rendimiento.",
|
"showingTailOutput": "Mostrando la salida final durante el streaming para mejorar el rendimiento.",
|
||||||
"result": "Resultado",
|
"result": "Resultado",
|
||||||
"unknown": "desconocido",
|
"unknown": "desconocido",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "La entrada fue truncada — el diff puede estar incompleto.",
|
||||||
"replaceAll": "REEMPLAZAR TODO",
|
"replaceAll": "REEMPLAZAR TODO",
|
||||||
"filesCount": "Archivos: {count}",
|
"filesCount": "Archivos: {count}",
|
||||||
"update": "actualizar",
|
"update": "actualizar",
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "Affichage de la fin de la sortie pendant le streaming pour de meilleures performances.",
|
"showingTailOutput": "Affichage de la fin de la sortie pendant le streaming pour de meilleures performances.",
|
||||||
"result": "Résultat",
|
"result": "Résultat",
|
||||||
"unknown": "inconnu",
|
"unknown": "inconnu",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "L'entrée a été tronquée — le diff peut être incomplet.",
|
||||||
"replaceAll": "TOUT REMPLACER",
|
"replaceAll": "TOUT REMPLACER",
|
||||||
"filesCount": "Fichiers : {count}",
|
"filesCount": "Fichiers : {count}",
|
||||||
"update": "mettre à jour",
|
"update": "mettre à jour",
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "パフォーマンスのため、ストリーミング中は末尾出力を表示しています。",
|
"showingTailOutput": "パフォーマンスのため、ストリーミング中は末尾出力を表示しています。",
|
||||||
"result": "結果",
|
"result": "結果",
|
||||||
"unknown": "不明",
|
"unknown": "不明",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "入力が切り詰められました — diff が不完全な可能性があります。",
|
||||||
"replaceAll": "すべて置換",
|
"replaceAll": "すべて置換",
|
||||||
"filesCount": "ファイル: {count}",
|
"filesCount": "ファイル: {count}",
|
||||||
"update": "更新",
|
"update": "更新",
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "성능을 위해 스트리밍 중에는 출력의 끝부분만 표시합니다.",
|
"showingTailOutput": "성능을 위해 스트리밍 중에는 출력의 끝부분만 표시합니다.",
|
||||||
"result": "결과",
|
"result": "결과",
|
||||||
"unknown": "알 수 없음",
|
"unknown": "알 수 없음",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "입력이 잘렸습니다 — diff가 불완전할 수 있습니다.",
|
||||||
"replaceAll": "모두 바꾸기",
|
"replaceAll": "모두 바꾸기",
|
||||||
"filesCount": "파일: {count}",
|
"filesCount": "파일: {count}",
|
||||||
"update": "업데이트",
|
"update": "업데이트",
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "Mostrando a saída final durante o streaming para melhor desempenho.",
|
"showingTailOutput": "Mostrando a saída final durante o streaming para melhor desempenho.",
|
||||||
"result": "Resultado",
|
"result": "Resultado",
|
||||||
"unknown": "desconhecido",
|
"unknown": "desconhecido",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "A entrada foi truncada — o diff pode estar incompleto.",
|
||||||
"replaceAll": "SUBSTITUIR TUDO",
|
"replaceAll": "SUBSTITUIR TUDO",
|
||||||
"filesCount": "Arquivos: {count}",
|
"filesCount": "Arquivos: {count}",
|
||||||
"update": "atualizar",
|
"update": "atualizar",
|
||||||
|
|||||||
@@ -1485,7 +1485,7 @@
|
|||||||
"showingTailOutput": "為確保效能,串流輸出時僅顯示尾端內容。",
|
"showingTailOutput": "為確保效能,串流輸出時僅顯示尾端內容。",
|
||||||
"result": "結果",
|
"result": "結果",
|
||||||
"unknown": "未知",
|
"unknown": "未知",
|
||||||
"inputTruncated": "Input was truncated — diff may be incomplete.",
|
"inputTruncated": "輸入已截斷,diff 可能不完整。",
|
||||||
"replaceAll": "全部替換",
|
"replaceAll": "全部替換",
|
||||||
"filesCount": "檔案:{count}",
|
"filesCount": "檔案:{count}",
|
||||||
"update": "更新",
|
"update": "更新",
|
||||||
|
|||||||
Reference in New Issue
Block a user