Spaces:
Runtime error
Runtime error
File size: 4,084 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 | // src/app/(dashboard)/dashboard/playground/hooks/useStructuredOutput.ts
"use client";
import { useState, useCallback } from "react";
import { StructuredOutputSchema } from "@/shared/schemas/playground";
export interface StructuredOutputSchemaInput {
name: string;
schema: Record<string, unknown>;
strict?: boolean;
}
export interface UseStructuredOutputState {
enabled: boolean;
schema: StructuredOutputSchemaInput | null;
error: string | null;
}
export interface ValidateResponseResult {
valid: boolean;
error?: string;
}
export interface UseStructuredOutput extends UseStructuredOutputState {
setEnabled: (enabled: boolean) => void;
/**
* Set and validate the JSON schema via Zod StructuredOutputSchema.
* Clears error on success; sets error on validation failure.
*/
setSchema: (s: StructuredOutputSchemaInput) => void;
/**
* Validate a response body against the current schema.
* - First tries JSON.parse if content is a string.
* - Then checks that the parsed value is a non-null object (basic shape validation).
* Returns { valid: true } on success; { valid: false, error } on failure.
*/
validateResponse: (content: unknown) => ValidateResponseResult;
}
/**
* Hook for the Structured Output (JSON mode) toggle in the Build tab.
* Manages toggle state + JSON schema + client-side response validation.
*/
export function useStructuredOutput(): UseStructuredOutput {
const [enabled, setEnabledState] = useState(false);
const [schema, setSchemaState] = useState<StructuredOutputSchemaInput | null>(null);
const [error, setError] = useState<string | null>(null);
const setEnabled = useCallback((value: boolean): void => {
setEnabledState(value);
}, []);
const setSchema = useCallback((s: StructuredOutputSchemaInput): void => {
// Validate via StructuredOutputSchema (wraps the input as if it were a full response_format object).
const parsed = StructuredOutputSchema.safeParse({
type: "json_schema",
json_schema: s,
});
if (!parsed.success) {
const message = parsed.error.issues.map((i) => i.message).join("; ");
setError(message);
return;
}
setSchemaState(s);
setError(null);
}, []);
const validateResponse = useCallback(
(content: unknown): ValidateResponseResult => {
if (schema == null) {
return { valid: false, error: "No schema set" };
}
// Step 1: parse JSON if the content is a string.
let parsed: unknown = content;
if (typeof content === "string") {
try {
parsed = JSON.parse(content);
} catch {
return { valid: false, error: "Response is not valid JSON" };
}
}
// Step 2: basic shape validation — must be a non-null object.
// Full JSON Schema validation would require ajv (not present in this project).
// We do a structural check: verify it's an object, and for each key in the
// schema's `properties` (if present), check that the key exists in the response.
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
return { valid: false, error: "Response is not a JSON object" };
}
const responseObj = parsed as Record<string, unknown>;
const schemaObj = schema.schema;
// If the schema has a "properties" field, validate that required keys are present.
const properties = schemaObj["properties"];
if (properties != null && typeof properties === "object" && !Array.isArray(properties)) {
const required = schemaObj["required"];
if (Array.isArray(required)) {
for (const key of required) {
if (typeof key === "string" && !(key in responseObj)) {
return {
valid: false,
error: `Response is missing required field: "${key}"`,
};
}
}
}
}
return { valid: true };
},
[schema],
);
return {
enabled,
schema,
error,
setEnabled,
setSchema,
validateResponse,
};
}
|