Verbesserung für Tests von Prompts #80

Merged
Lars merged 2 commits from develop into main 2026-04-12 11:58:07 +02:00
2 changed files with 165 additions and 52 deletions
Showing only changes of commit 08c9cccdcc - Show all commits

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useRef } from 'react'
import { useState, useEffect, useRef, useLayoutEffect } from 'react'
import { api } from '../utils/api'
import { X, Plus, Trash2, MoveUp, MoveDown, Code } from 'lucide-react'
import PlaceholderPicker from './PlaceholderPicker'
@ -66,6 +66,53 @@ function sanitizeDebugForPanel(dbg, resultType) {
return o
}
/** Langer Inhalt: zunächst auf maxRem eingeklappt, „Mehr/Weniger anzeigen“ */
function ExpandableCollapsible({ children, contentKey, maxRem = 28 }) {
const [expanded, setExpanded] = useState(false)
const wrapRef = useRef(null)
const [showToggle, setShowToggle] = useState(false)
useEffect(() => {
setExpanded(false)
}, [contentKey])
useLayoutEffect(() => {
const el = wrapRef.current
if (!el) return
if (expanded) {
setShowToggle(true)
return
}
setShowToggle(el.scrollHeight > el.clientHeight + 2)
}, [contentKey, expanded])
return (
<div>
<div
ref={wrapRef}
style={{
maxHeight: expanded ? 'none' : `${maxRem}rem`,
overflow: expanded ? 'visible' : 'hidden'
}}
>
{children}
</div>
{showToggle && (
<div style={{ marginTop: 10, textAlign: 'center' }}>
<button
type="button"
className="btn btn-secondary"
style={{ fontSize: 12, padding: '6px 14px' }}
onClick={() => setExpanded((e) => !e)}
>
{expanded ? 'Weniger anzeigen' : 'Mehr anzeigen'}
</button>
</div>
)}
</div>
)
}
function renderTestOutput(testResult) {
if (!testResult) return null
if (testResult.error) {
@ -89,7 +136,7 @@ function renderTestOutput(testResult) {
return <span style={{ color: 'var(--text3)' }}>Keine Ausgabe</span>
}
const proseBox = (content) => (
const proseBox = (content, contentKey) => (
<div
style={{
padding: 16,
@ -102,7 +149,11 @@ function renderTestOutput(testResult) {
textAlign: 'left'
}}
>
{content}
{contentKey != null ? (
<ExpandableCollapsible contentKey={contentKey}>{content}</ExpandableCollapsible>
) : (
content
)}
</div>
)
@ -123,23 +174,27 @@ function renderTestOutput(testResult) {
{key}
</div>
{typeof val === 'string' ? (
proseBox(<Markdown text={val} />)
proseBox(
<Markdown text={val} />,
`pipe-${key}-${val.length}-${val.slice(0, 120)}`
)
) : (
<pre
style={{
margin: 0,
padding: 12,
background: 'var(--bg)',
borderRadius: 8,
border: '1px solid var(--border)',
fontSize: 12,
overflow: 'auto',
maxHeight: 360,
textAlign: 'left'
}}
>
{JSON.stringify(val, null, 2)}
</pre>
<ExpandableCollapsible contentKey={`pipe-json-${key}-${JSON.stringify(val).slice(0, 200)}`} maxRem={22}>
<pre
style={{
margin: 0,
padding: 12,
background: 'var(--bg)',
borderRadius: 8,
border: '1px solid var(--border)',
fontSize: 12,
overflow: 'auto',
textAlign: 'left'
}}
>
{JSON.stringify(val, null, 2)}
</pre>
</ExpandableCollapsible>
)}
</div>
))}
@ -151,47 +206,54 @@ function renderTestOutput(testResult) {
if (fmt === 'json') {
try {
const parsed = JSON.parse(out)
const jsonStr = JSON.stringify(parsed, null, 2)
return (
<pre
style={{
margin: 0,
padding: 12,
background: 'var(--bg)',
borderRadius: 8,
border: '1px solid var(--border)',
fontSize: 12,
overflow: 'auto',
maxHeight: 480,
textAlign: 'left'
}}
>
{JSON.stringify(parsed, null, 2)}
</pre>
<ExpandableCollapsible contentKey={`json-out-${jsonStr.length}-${jsonStr.slice(0, 80)}`} maxRem={26}>
<pre
style={{
margin: 0,
padding: 12,
background: 'var(--bg)',
borderRadius: 8,
border: '1px solid var(--border)',
fontSize: 12,
overflow: 'auto',
textAlign: 'left'
}}
>
{jsonStr}
</pre>
</ExpandableCollapsible>
)
} catch {
return proseBox(<pre style={{ margin: 0, whiteSpace: 'pre-wrap' }}>{out}</pre>)
return proseBox(
<pre style={{ margin: 0, whiteSpace: 'pre-wrap' }}>{out}</pre>,
`json-fail-${out.length}-${out.slice(0, 80)}`
)
}
}
return proseBox(<Markdown text={out} />)
return proseBox(<Markdown text={out} />, `text-out-${out.length}-${out.slice(0, 120)}`)
}
if (typeof out === 'object') {
const jsonStr = JSON.stringify(out, null, 2)
return (
<pre
style={{
margin: 0,
padding: 12,
background: 'var(--bg)',
borderRadius: 8,
border: '1px solid var(--border)',
fontSize: 12,
overflow: 'auto',
maxHeight: 480,
textAlign: 'left'
}}
>
{JSON.stringify(out, null, 2)}
</pre>
<ExpandableCollapsible contentKey={`obj-out-${jsonStr.length}-${jsonStr.slice(0, 120)}`} maxRem={26}>
<pre
style={{
margin: 0,
padding: 12,
background: 'var(--bg)',
borderRadius: 8,
border: '1px solid var(--border)',
fontSize: 12,
overflow: 'auto',
textAlign: 'left'
}}
>
{jsonStr}
</pre>
</ExpandableCollapsible>
)
}

View File

@ -1,5 +1,5 @@
// Lightweight Markdown renderer handles the subset used by the AI:
// ## Headings, **bold**, bullet lists, numbered lists, line breaks
// ## Headings, **bold**, bullet lists, numbered lists, fenced ``` code ```, line breaks
export default function Markdown({ text }) {
if (!text) return null
@ -7,6 +7,19 @@ export default function Markdown({ text }) {
const lines = text.split('\n')
const elements = []
let i = 0
let blockId = 0
const codeBlockStyle = {
margin: '10px 0',
padding: 12,
background: 'var(--surface2)',
borderRadius: 8,
border: '1px solid var(--border)',
overflow: 'auto',
fontSize: 12,
lineHeight: 1.5,
fontFamily: 'ui-monospace, Consolas, monospace'
}
const parseLine = (line) => {
// Parse inline **bold** and *italic*
@ -39,6 +52,44 @@ export default function Markdown({ text }) {
while (i < lines.length) {
const line = lines[i]
// Fenced code block: ``` or ```lang
const trimmedStart = line.trimStart()
if (trimmedStart.startsWith('```')) {
const lang = trimmedStart.slice(3).trim() || null
i++
const codeLines = []
while (i < lines.length) {
if (lines[i].trim().startsWith('```')) {
i++
break
}
codeLines.push(lines[i])
i++
}
const code = codeLines.join('\n')
elements.push(
<div key={`code-${blockId++}`} style={{ margin: '10px 0' }}>
{lang && (
<div
style={{
fontSize: 10,
color: 'var(--text3)',
marginBottom: 6,
fontFamily: 'ui-monospace, monospace',
letterSpacing: 0.02
}}
>
{lang}
</div>
)}
<pre style={codeBlockStyle}>
<code style={{ color: 'var(--text1)', whiteSpace: 'pre', display: 'block' }}>{code}</code>
</pre>
</div>
)
continue
}
// Skip empty lines (add spacing)
if (line.trim() === '') {
elements.push(<div key={i} style={{ height: 8 }} />)