|
|
@@ -19,7 +19,7 @@ interface ExpressionInputProps {
|
|
|
className?: string
|
|
|
}
|
|
|
|
|
|
-type ContentKind = 'plain' | 'json' | 'broken-json' | 'markdown'
|
|
|
+type ContentKind = 'plain' | 'json' | 'templated-json' | 'broken-json' | 'markdown'
|
|
|
|
|
|
// What someone typed into a field says what it is. A prompt, a JSON body and a
|
|
|
// note are all "string" to the schema, so the shape of the text is the only
|
|
|
@@ -34,7 +34,20 @@ function detectContentKind(value: string): ContentKind {
|
|
|
JSON.parse(text)
|
|
|
return 'json'
|
|
|
} catch {
|
|
|
- return 'broken-json'
|
|
|
+ // A graph or request body written for this system holds placeholders
|
|
|
+ // where values will go, and a placeholder standing in for a number is not
|
|
|
+ // JSON until it is filled in. That is the field working as intended, not
|
|
|
+ // a mistake, so it is only called broken if it still fails once the
|
|
|
+ // placeholders are given a value.
|
|
|
+ const filled = text
|
|
|
+ .replace(/<<[^>]*>>/g, '0')
|
|
|
+ .replace(/\{\{[^}]*\}\}/g, '0')
|
|
|
+ try {
|
|
|
+ JSON.parse(filled)
|
|
|
+ return 'templated-json'
|
|
|
+ } catch {
|
|
|
+ return 'broken-json'
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -59,6 +72,10 @@ const KIND_LABELS: Record<ContentKind, { label: string; className: string } | nu
|
|
|
label: 'JSON',
|
|
|
className: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
|
|
|
},
|
|
|
+ 'templated-json': {
|
|
|
+ label: 'JSON with placeholders',
|
|
|
+ className: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
|
|
|
+ },
|
|
|
'broken-json': {
|
|
|
label: 'JSON with a syntax error',
|
|
|
className: 'bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300',
|
|
|
@@ -261,7 +278,7 @@ export function ExpressionInput({
|
|
|
|
|
|
const kind = detectContentKind(value || '')
|
|
|
const kindLabel = KIND_LABELS[kind]
|
|
|
- const isCode = kind === 'json' || kind === 'broken-json'
|
|
|
+ const isCode = kind === 'json' || kind === 'templated-json' || kind === 'broken-json'
|
|
|
|
|
|
// The field is always a textarea so it can grow with what is typed into it
|
|
|
// without swapping the element under the cursor, which would lose focus and
|
|
|
@@ -378,6 +395,11 @@ export function ExpressionInput({
|
|
|
Format
|
|
|
</button>
|
|
|
)}
|
|
|
+ {kind === 'templated-json' && (
|
|
|
+ <span className="text-gray-500 dark:text-gray-400">
|
|
|
+ Valid once the placeholders are filled in
|
|
|
+ </span>
|
|
|
+ )}
|
|
|
{kind === 'broken-json' && (
|
|
|
<span className="text-gray-500 dark:text-gray-400">
|
|
|
Starts and ends like JSON but does not parse - check quotes and commas
|