Spaces:
Runtime error
Runtime error
File size: 4,942 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | "use client";
// src/app/(dashboard)/dashboard/playground/components/StructuredOutputEditor.tsx
import { useState } from "react";
import { useStructuredOutput } from "../hooks/useStructuredOutput";
import type { StructuredOutputSchemaInput } from "../hooks/useStructuredOutput";
interface StructuredOutputEditorProps {
structuredOutput: ReturnType<typeof useStructuredOutput>;
}
const DEFAULT_SCHEMA: StructuredOutputSchemaInput = {
name: "my_schema",
schema: {
type: "object",
properties: {
result: { type: "string" },
},
required: ["result"],
},
strict: true,
};
/**
* StructuredOutputEditor — toggle JSON mode on/off + edit JSON schema.
*
* When enabled, the Build tab sends response_format: { type: "json_schema", json_schema: {...} }.
* Schema validation is client-side via Zod StructuredOutputSchema (D9).
*/
export default function StructuredOutputEditor({ structuredOutput }: StructuredOutputEditorProps) {
const { enabled, schema, error, setEnabled, setSchema } = structuredOutput;
const [schemaRaw, setSchemaRaw] = useState(
JSON.stringify(schema ?? DEFAULT_SCHEMA, null, 2),
);
const [nameField, setNameField] = useState(schema?.name ?? "my_schema");
const [parseError, setParseError] = useState<string | null>(null);
function handleValidate() {
let parsed: unknown;
try {
parsed = JSON.parse(schemaRaw);
} catch {
setParseError("Invalid JSON");
return;
}
setParseError(null);
// The parsed JSON should be the inner schema object (not the full response_format wrapper)
const input: StructuredOutputSchemaInput = {
name: nameField.trim() || "my_schema",
schema: parsed as Record<string, unknown>,
strict: true,
};
setSchema(input);
}
return (
<div className="flex flex-col gap-3">
{/* Toggle */}
<div className="flex items-center justify-between">
<div className="flex flex-col gap-0.5">
<span className="text-xs font-medium text-text-main">JSON mode</span>
<span className="text-[11px] text-text-muted">
Forces response_format: json_schema
</span>
</div>
<button
role="switch"
aria-checked={enabled}
onClick={() => setEnabled(!enabled)}
className={`relative inline-flex w-10 h-5 rounded-full transition-colors ${
enabled ? "bg-primary" : "bg-text-muted/30"
}`}
aria-label={enabled ? "Disable JSON mode" : "Enable JSON mode"}
>
<span
className={`absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white shadow transition-transform ${
enabled ? "translate-x-5" : "translate-x-0"
}`}
/>
</button>
</div>
{/* Schema editor (shown only when enabled) */}
{enabled && (
<div className="flex flex-col gap-2 border border-border rounded-lg p-3 bg-surface">
{/* Schema name */}
<div className="flex flex-col gap-1">
<label className="text-[10px] text-text-muted uppercase tracking-wider">
Schema name
</label>
<input
type="text"
value={nameField}
onChange={(e) => setNameField(e.target.value)}
placeholder="my_schema"
className="text-xs bg-bg-alt border border-border rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary text-text-main"
/>
</div>
{/* Schema JSON textarea */}
<div className="flex flex-col gap-1">
<label className="text-[10px] text-text-muted uppercase tracking-wider">
JSON schema
</label>
<textarea
value={schemaRaw}
onChange={(e) => setSchemaRaw(e.target.value)}
rows={8}
className="text-xs font-mono bg-bg-alt border border-border rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary text-text-main resize-y"
aria-label="JSON schema editor"
/>
</div>
{/* Errors */}
{(parseError ?? error) && (
<p className="text-xs text-destructive">
{parseError ?? error}
</p>
)}
{/* Status — show when schema is set and no errors */}
{schema != null && !parseError && !error && (
<p className="text-xs text-green-600 dark:text-green-400">
✓ Schema validated
</p>
)}
{/* Validate button */}
<button
onClick={handleValidate}
className="text-xs px-3 py-1.5 rounded border border-border text-text-muted hover:text-text-main hover:bg-black/5 dark:hover:bg-white/5 transition-colors self-start"
>
Validate schema
</button>
</div>
)}
</div>
);
}
|