A React Native app for the ultimate thinking partner.

refactor(ui): convert tool call arguments to YAML format and remove result left border

- Replace JSON formatting with YAML for better readability
- Add jsonToYaml() converter with proper indentation and type handling
- Use YAML literal block style (|) for multiline strings
- Smart quoting for strings with special characters
- Remove left border from Result section for cleaner appearance

+62 -16
+62 -16
src/components/ToolCallItem.tsx
··· 78 78 const displayNames = useMemo(() => getToolDisplayName(toolName, callText, hasResult), [toolName, callText, hasResult]); 79 79 const displayText = hasResult ? displayNames.past : displayNames.present; 80 80 81 + // Convert JSON arguments to YAML format for better readability 82 + const jsonToYaml = (obj: any, indent = 0): string => { 83 + const spaces = ' '.repeat(indent); 84 + 85 + if (obj === null) return 'null'; 86 + if (obj === undefined) return 'undefined'; 87 + if (typeof obj === 'boolean') return obj.toString(); 88 + if (typeof obj === 'number') return obj.toString(); 89 + 90 + // String handling - use literal block style for multiline strings 91 + if (typeof obj === 'string') { 92 + if (obj.includes('\n')) { 93 + // Multiline string - use literal block style 94 + const lines = obj.split('\n'); 95 + return '|\n' + lines.map(line => spaces + ' ' + line).join('\n'); 96 + } 97 + // Single line string - quote if contains special characters 98 + if (obj.match(/[:#{}[\],&*!|>'"@`-]/) || obj.trim() !== obj) { 99 + return `"${obj.replace(/"/g, '\\"')}"`; 100 + } 101 + return obj; 102 + } 103 + 104 + // Array handling 105 + if (Array.isArray(obj)) { 106 + if (obj.length === 0) return '[]'; 107 + return '\n' + obj.map(item => 108 + spaces + '- ' + jsonToYaml(item, indent + 1).replace(/^\s+/, '') 109 + ).join('\n'); 110 + } 111 + 112 + // Object handling 113 + if (typeof obj === 'object') { 114 + const entries = Object.entries(obj); 115 + if (entries.length === 0) return '{}'; 116 + return '\n' + entries.map(([key, value]) => { 117 + const yamlValue = jsonToYaml(value, indent + 1); 118 + // If value starts with newline, it's multiline 119 + if (yamlValue.startsWith('\n') || yamlValue.startsWith('|')) { 120 + return `${spaces}${key}: ${yamlValue}`; 121 + } 122 + return `${spaces}${key}: ${yamlValue}`; 123 + }).join('\n'); 124 + } 125 + 126 + return String(obj); 127 + }; 128 + 81 129 // Try to parse a "name({json})" or "name(k=v, ...)" shape into 82 130 // a nicer multiline representation for readability. 83 131 const prettyCallText = useMemo(() => { ··· 89 137 90 138 const looksJsonLike = (s: string) => s.startsWith('{') || s.startsWith('['); 91 139 92 - const toPrettyJson = (s: string): string | null => { 93 - try { return JSON.stringify(JSON.parse(s), null, 2); } catch { return null; } 140 + const toYaml = (s: string): string | null => { 141 + try { 142 + const parsed = JSON.parse(s); 143 + return jsonToYaml(parsed, 1).trim(); 144 + } catch { 145 + return null; 146 + } 94 147 }; 95 148 96 - const fromKvToPrettyJson = (s: string): string | null => { 97 - // Best-effort conversion of "k=v, x=1" into JSON 149 + const fromKvToYaml = (s: string): string | null => { 150 + // Best-effort conversion of "k=v, x=1" into YAML 98 151 try { 99 - // Wrap in braces and quote keys. Avoid touching quoted strings by a light heuristic: 100 - // this will work for our formatted args that already JSON.stringify values. 152 + // Wrap in braces and quote keys 101 153 const replaced = s.replace(/([A-Za-z_][A-Za-z0-9_]*)\s*=/g, '"$1": '); 102 154 const wrapped = `{ ${replaced} }`; 103 - return toPrettyJson(wrapped); 155 + return toYaml(wrapped); 104 156 } catch { 105 157 return null; 106 158 } ··· 108 160 109 161 const argsPretty = 110 162 looksJsonLike(inside) 111 - ? (toPrettyJson(inside) ?? inside) 112 - : (fromKvToPrettyJson(inside) ?? inside); 163 + ? (toYaml(inside) ?? inside) 164 + : (fromKvToYaml(inside) ?? inside); 113 165 114 166 // If we couldn't improve it, just return the raw text 115 167 if (argsPretty === raw) return raw; 116 168 117 169 // Compose a friendly multiline signature 118 - const indented = argsPretty 119 - .split('\n') 120 - .map((line) => ` ${line}`) 121 - .join('\n'); 122 - return `${fn}(\n${indented}\n)`; 170 + return `${fn}(\n${argsPretty}\n)`; 123 171 }, [callText]); 124 172 125 173 const formattedResult = useMemo(() => { ··· 237 285 flexDirection: 'row', 238 286 alignItems: 'center', 239 287 gap: 6, 240 - borderLeftWidth: 1, 241 288 borderRightWidth: 1, 242 289 paddingVertical: 8, 243 290 paddingHorizontal: 10, ··· 254 301 resultBox: { 255 302 borderBottomLeftRadius: 10, 256 303 borderBottomRightRadius: 10, 257 - borderLeftWidth: 1, 258 304 borderRightWidth: 1, 259 305 borderBottomWidth: 1, 260 306 paddingVertical: 10,