From 830548984a063ab53fd6d3debc23936a5706aecf Mon Sep 17 00:00:00 2001 From: changliuchang777 <1551617642@qq.com> Date: Sun, 5 Jul 2026 23:44:44 +0800 Subject: [PATCH 1/3] feat: add response diff utility --- src/utils/diff.ts | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/utils/diff.ts diff --git a/src/utils/diff.ts b/src/utils/diff.ts new file mode 100644 index 0000000..45a8a97 --- /dev/null +++ b/src/utils/diff.ts @@ -0,0 +1,57 @@ +export type DiffLineType = 'same' | 'added' | 'removed'; + +export type DiffLine = { + type: DiffLineType; + text: string; +}; + +function formatJsonLines(value: unknown) { + return JSON.stringify(value ?? {}, null, 2).split('\n'); +} + +export function buildJsonDiff(before: unknown, after: unknown): DiffLine[] { + const previous = formatJsonLines(before); + const next = formatJsonLines(after); + const lengths = Array.from({ length: previous.length + 1 }, () => + Array(next.length + 1).fill(0) + ); + + for (let i = previous.length - 1; i >= 0; i -= 1) { + for (let j = next.length - 1; j >= 0; j -= 1) { + lengths[i][j] = + previous[i] === next[j] + ? lengths[i + 1][j + 1] + 1 + : Math.max(lengths[i + 1][j], lengths[i][j + 1]); + } + } + + const diff: DiffLine[] = []; + let i = 0; + let j = 0; + + while (i < previous.length && j < next.length) { + if (previous[i] === next[j]) { + diff.push({ type: 'same', text: previous[i] }); + i += 1; + j += 1; + } else if (lengths[i + 1][j] >= lengths[i][j + 1]) { + diff.push({ type: 'removed', text: previous[i] }); + i += 1; + } else { + diff.push({ type: 'added', text: next[j] }); + j += 1; + } + } + + while (i < previous.length) { + diff.push({ type: 'removed', text: previous[i] }); + i += 1; + } + + while (j < next.length) { + diff.push({ type: 'added', text: next[j] }); + j += 1; + } + + return diff; +} From c254a0256869b6676f607b38d9da29d739b62cc0 Mon Sep 17 00:00:00 2001 From: changliuchang777 <1551617642@qq.com> Date: Sun, 5 Jul 2026 23:44:59 +0800 Subject: [PATCH 2/3] feat: show response diff in call history --- src/components/CallHistoryRow.tsx | 34 ++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/components/CallHistoryRow.tsx b/src/components/CallHistoryRow.tsx index 523fb87..a6de951 100644 --- a/src/components/CallHistoryRow.tsx +++ b/src/components/CallHistoryRow.tsx @@ -1,6 +1,6 @@ -import { useState } from 'react'; import { CheckCircle, XCircle } from 'lucide-react'; import { formatPrice } from '../utils/format'; +import { buildJsonDiff } from '../utils/diff'; export type CallRecord = { id: string; @@ -11,6 +11,7 @@ export type CallRecord = { cost: number; request?: unknown; response?: unknown; + compareResponse?: unknown; }; type Props = { @@ -55,6 +56,34 @@ function StatusIcon({ status }: { status: 'success' | 'error' }) { ); } +function ResponseDiff({ before, after }: { before: unknown; after: unknown }) { + const lines = buildJsonDiff(before, after); + + return ( +
+ {lines.map((line, index) => {
+ const prefix =
+ line.type === 'added' ? '+ ' : line.type === 'removed' ? '- ' : ' ';
+
+ return (
+
+ {prefix}
+ {line.text}
+ {'\n'}
+
+ );
+ })}
+
+ {JSON.stringify(call.response ?? {}, null, 2)}
+ {call.compareResponse !== undefined && (
+