feat: Add typed stuff

This commit is contained in:
2025-09-04 15:13:07 +02:00
parent 18769c134d
commit 900ed70162
13 changed files with 251 additions and 118 deletions

View File

@@ -89,9 +89,11 @@ export interface TokenUsage {
/**
* Response from an AI completion request
*/
export interface CompletionResponse {
/** Generated content */
content: string;
export interface CompletionResponse<T = string> {
/** Generated content, either as a string or a typed object */
content: T;
/** Raw response from the provider, if content is a typed object */
rawContent?: string;
/** Model used for generation */
model: string;
/** Token usage statistics */
@@ -220,55 +222,71 @@ export function createResponseType<T = any>(
export function generateResponseTypePrompt(responseType: ResponseType): string {
const { typeDefinition, description, example, strictJson } = responseType;
let prompt = `You must respond with a JSON object that matches the following TypeScript type definition:\n\n`;
prompt += `Type Definition:\n\`\`\`typescript\n${typeDefinition}\n\`\`\`\n\n`;
prompt += `Description: ${description}\n\n`;
let prompt = `You are an AI assistant that must respond with a JSON object. The JSON object must strictly adhere to the following TypeScript type definition:
`;
prompt += `Type Definition:
typescript
${typeDefinition}

`;
prompt += `Description: ${description}
`;
if (example) {
prompt += `Example:\n\`\`\`json\n${JSON.stringify(example, null, 2)}\n\`\`\`\n\n`;
prompt += `Example of the expected JSON output:
json
${JSON.stringify(example, null, 2)}

`;
}
if (strictJson) {
prompt += `IMPORTANT: Your response must be valid JSON only. Do not include any text before or after the JSON object. Do not use markdown formatting.`;
prompt += `IMPORTANT: Your entire response must be a single, valid JSON object that conforms to the type definition above. Do not include any additional text, explanations, or markdown formatting before or after the JSON object.`;
} else {
prompt += `Your response should follow the structure defined above.`;
prompt += `Your response should contain a JSON object that follows the structure defined above.`;
}
return prompt;
}
/**
* Validates that a response matches the expected type structure
* Parses and validates that a response matches the expected type structure
*
* @param response - The response content to validate
* @param responseType - The expected response type
* @returns Object with validation result and parsed data
* @returns The parsed and validated data object
* @throws {AIProviderError} If parsing or validation fails
*/
export function validateResponseType<T = any>(
export function parseAndValidateResponseType<T = any>(
response: string,
responseType: ResponseType<T>
): { isValid: boolean; data?: T; error?: string } {
): T {
try {
// Parse JSON response
// Attempt to parse the JSON response
const parsed = JSON.parse(response);
// Basic validation - in a real implementation, you might want to use
// a schema validation library like zod or ajv for more thorough validation
// Basic validation: ensure it's a non-null object.
// For more robust validation, a library like Zod or Ajv could be used
// based on the typeDefinition, but that's beyond the current scope.
if (typeof parsed !== 'object' || parsed === null) {
return {
isValid: false,
error: 'Response must be a JSON object'
};
throw new Error('Response must be a JSON object');
}
return {
isValid: true,
data: parsed as T
};
// Here you could add more sophisticated validation if needed, e.g.,
// checking keys against the responseType.typeDefinition
return parsed as T;
} catch (error) {
return {
isValid: false,
error: `Invalid JSON: ${(error as Error).message}`
};
// Wrap parsing/validation errors in a standardized AIProviderError
throw new AIProviderError(
`Failed to parse or validate structured response: ${(error as Error).message}`,
AIErrorType.INVALID_REQUEST,
undefined,
error as Error
);
}
}