refactor: improve type safety in document extraction and UI components

- Introduced Zod schemas for type-safe parsing of mentioned document information in chat messages.
- Updated the extractMentionedDocuments function to utilize the new schemas for better validation.
- Made the 'alt' property optional in image-related components for improved flexibility and fallback handling.
This commit is contained in:
Anish Sarkar 2025-12-26 00:18:47 +05:30
parent bea18960a4
commit 9bc3f193c3
3 changed files with 29 additions and 15 deletions

View file

@ -10,6 +10,7 @@ import { useAtomValue, useSetAtom } from "jotai";
import { useParams } from "next/navigation";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { z } from "zod";
import {
type MentionedDocumentInfo,
mentionedDocumentIdsAtom,
@ -55,20 +56,33 @@ function extractThinkingSteps(content: unknown): ThinkingStep[] {
}
/**
* Extract mentioned documents from message content
* Zod schema for mentioned document info (for type-safe parsing)
*/
const MentionedDocumentInfoSchema = z.object({
id: z.number(),
title: z.string(),
document_type: z.string(),
});
const MentionedDocumentsPartSchema = z.object({
type: z.literal("mentioned-documents"),
documents: z.array(MentionedDocumentInfoSchema),
});
/**
* Extract mentioned documents from message content (type-safe with Zod)
*/
function extractMentionedDocuments(content: unknown): MentionedDocumentInfo[] {
if (!Array.isArray(content)) return [];
const docsPart = content.find(
(part: unknown) =>
typeof part === "object" &&
part !== null &&
"type" in part &&
(part as { type: string }).type === "mentioned-documents"
) as { type: "mentioned-documents"; documents: MentionedDocumentInfo[] } | undefined;
for (const part of content) {
const result = MentionedDocumentsPartSchema.safeParse(part);
if (result.success) {
return result.data.documents;
}
}
return docsPart?.documents || [];
return [];
}
/**

View file

@ -23,7 +23,7 @@ interface DisplayImageResult {
id: string;
assetId: string;
src: string;
alt?: string; // Made optional - parseSerializableImage provides fallback
alt?: string; // Made optional - parseSerializableImage provides fallback
title?: string;
description?: string;
domain?: string;

View file

@ -24,7 +24,7 @@ const SerializableImageSchema = z.object({
id: z.string(),
assetId: z.string(),
src: z.string(),
alt: z.string().nullish(), // Made optional - will use fallback if missing
alt: z.string().nullish(), // Made optional - will use fallback if missing
title: z.string().nullish(),
description: z.string().nullish(),
href: z.string().nullish(),
@ -48,7 +48,7 @@ export interface ImageProps {
id: string;
assetId: string;
src: string;
alt?: string; // Optional with default fallback
alt?: string; // Optional with default fallback
title?: string;
description?: string;
href?: string;
@ -69,10 +69,10 @@ export function parseSerializableImage(result: unknown): SerializableImage & { a
if (!parsed.success) {
console.warn("Invalid image data:", parsed.error.issues);
// Try to extract basic info and return a fallback object
const obj = (result && typeof result === "object" ? result : {}) as Record<string, unknown>;
// If we have at least id, assetId, and src, we can still render the image
if (
typeof obj.id === "string" &&
@ -92,7 +92,7 @@ export function parseSerializableImage(result: unknown): SerializableImage & { a
source: undefined,
};
}
throw new Error(`Invalid image: ${parsed.error.issues.map((i) => i.message).join(", ")}`);
}