Skip to main content

knowledge-base-management

Guide for working with the Knowledge Base system in DEVS. Use this when asked to add knowledge management features, file handling, or document processing.

معلومات المصدر

المستودع
codename-co/devs
آخر نشاط في المصدر
١٦ يناير ٢٠٢٦ في ٢٣:٢٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥٣
التفرعات
٢

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
knowledge-base-management
description
Guide for working with the Knowledge Base system in DEVS. Use this when asked to add knowledge management features, file handling, or document processing.
# Knowledge Base Management for DEVS The Knowledge Base system allows users to store and manage files, documents, and other knowledge items that agents can reference during conversations. ## Core Concepts ### KnowledgeItem Interface ```typescript interface KnowledgeItem { id: string name: string type: 'file' | 'folder' fileType?: 'document' | 'image' | 'text' content?: string // Text content or base64 for files contentHash?: string // SHA-256 hash for deduplication mimeType?: string size?: number path: string // Virtual path in knowledge base parentId?: string // Parent folder ID lastModified: Date createdAt: Date tags?: string[] description?: string syncSource?: 'manual' | 'filesystem_api' | 'connector' fileSystemHandle?: string // For File System API sync watchId?: string lastSyncCheck?: Date } ``` ## File Type Detection Supported file types in `src/lib/knowledge-utils.ts`: ```typescript const TEXT_EXTENSIONS = [ '.txt', '.md', '.js', '.ts', '.jsx', '.tsx', '.css', '.html', '.xml', '.csv', '.yaml', '.yml', '.log', ] const IMAGE_EXTENSIONS = [ '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', '.ico', '.tiff', '.tif', ] const DOCUMENT_EXTENSIONS = [ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.rtf', '.epub', ] function getFileType( filename: string, ): 'text' | 'image' | 'document' | 'unknown' { const ext = filename.toLowerCase().split('.').pop() if (TEXT_EXTENSIONS.includes(`.${ext}`)) return 'text' if (IMAGE_EXTENSIONS.includes(`.${ext}`)) return 'image' if (DOCUMENT_EXTENSIONS.includes(`.${ext}`)) return 'document' return 'unknown' } ``` ## Database Operations ```typescript import { db } from '@/lib/db' // Create knowledge item async function createKnowledgeItem( item: Omit<KnowledgeItem, 'id'>, ): Promise<string> { const id = crypto.randomUUID() await db.knowledge.add({ ...item, id }) return id } // Get items by path async function getItemsByPath(path: string): Promise<KnowledgeItem[]> { return db.knowledge.where('path').startsWith(path).toArray() } // Get folder contents async function getFolderContents(folderId?: string): Promise<KnowledgeItem[]> { if (folderId) { return db.knowledge.where('parentId').equals(folderId).toArray() } return db.knowledge.filter((item) => !item.parentId).toArray() } // Search by content hash (deduplication) async function findDuplicate( contentHash: string, ): Promise<KnowledgeItem | undefined> { return db.knowledge.where('contentHash').equals(contentHash).first() } ``` ## Content Hashing for Deduplication ```typescript async function generateContentHash( content: string | ArrayBuffer, ): Promise<string> { const data = typeof content === 'string' ? new TextEncoder().encode(content) : new Uint8Array(content) const hashBuffer = await crypto.subtle.digest('SHA-256', data) const hashArray = Array.from(new Uint8Array(hashBuffer)) return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('') } ``` ## File Upload Handling ```typescript async function handleFileUpload( file: File, parentId?: string, ): Promise<KnowledgeItem> { const content = await readFileContent(file) const contentHash = await generateContentHash(content) // Check for duplicates const existing = await findDuplicate(contentHash) if (existing) { toast.info('File already exists in knowledge base') return existing } const item: KnowledgeItem = { id: crypto.randomUUID(), name: file.name, type: 'file', fileType: getFileType(file.name), content: typeof content === 'string' ? content : btoa(content), contentHash, mimeType: file.type, size: file.size, path: parentId ? `${getPath(parentId)}/${file.name}` : `/${file.name}`, parentId, lastModified: new Date(file.lastModified), createdAt: new Date(), syncSource: 'manual', } await db.knowledge.add(item) return item } async function readFileContent(file: File): Promise<string | ArrayBuffer> { return new Promise((resolve, reject) => { const reader = new FileReader() if (file.type.startsWith('text/') || getFileType(file.name) === 'text') { reader.onload = () => resolve(reader.result as string) reader.onerror = reject reader.readAsText(file) } else { reader.onload = () => resolve(reader.result as ArrayBuffer) reader.onerror = reject reader.readAsArrayBuffer(file) } }) } ``` ## Folder Watching (File System API) ```typescript import { db } from '@/lib/db' async function watchFolder(handle: FileSystemDirectoryHandle): Promise<void> { // Request permission const permission = await handle.requestPermission({ mode: 'read' }) if (permission !== 'granted') { throw new Error('Permission denied') } // Scan and sync folder await syncFolder(handle, undefined) // Store handle for persistence await db.knowledge.add({ id: crypto.randomUUID(), name: handle.name, type: 'folder', path: `/${handle.name}`, createdAt: new Date(), lastModified: new Date(), syncSource: 'filesystem_api', fileSystemHandle: handle.name, }) } async function syncFolder( handle: FileSystemDirectoryHandle, parentId?: string, ): Promise<void> { for await (const entry of handle.values()) { if (entry.kind === 'file') { const file = await entry.getFile() await handleFileUpload(file, parentId) } else if (entry.kind === 'directory') { // Create folder and recurse const folderId = await createFolder(entry.name, parentId) await syncFolder(entry, folderId) } } } ``` ## Context Injection for Agents When agents need knowledge context: ```typescript import { db } from '@/lib/db' async function getRelevantKnowledge( query: string, agentId: string, ): Promise<KnowledgeItem[]> { // Get agent's assigned knowledge items const agentKnowledge = await getAgentKnowledge(agentId) // Search for relevant items const searchTerms = query.toLowerCase().split(' ') return agentKnowledge.filter((item) => { const searchText = `${item.name} ${item.description || ''} ${item.tags?.join(' ') || ''}`.toLowerCase() return searchTerms.some((term) => searchText.includes(term)) }) } function formatKnowledgeForContext(items: KnowledgeItem[]): string { return items .map((item) => { return `## ${item.name} ${item.description || ''} ${item.content || '[Binary content]'} ---` }) .join('\n\n') } ``` ## Document Processing For processing different document types: ```typescript // src/lib/document-processor.ts export async function processDocument(item: KnowledgeItem): Promise<string> { switch (item.fileType) { case 'text': return item.content || '' case 'document': return await extractTextFromDocument(item) case 'image': // Could use OCR or image description return `[Image: ${item.name}]` default: return `[Unsupported file type: ${item.mimeType}]` } } ``` ## Component Integration ```tsx import { useCallback, useState } from 'react' import { Button, Card, Progress } from '@heroui/react' import { Icon } from '@/components/Icon' import { toast } from '@/lib/toast' function KnowledgeUploader() { const [isUploading, setIsUploading] = useState(false) const [progress, setProgress] = useState(0) const handleDrop = useCallback(async (e: React.DragEvent) => { e.preventDefault() const files = Array.from(e.dataTransfer.files) setIsUploading(true) setProgress(0) for (let i = 0; i < files.length; i++) { await handleFileUpload(files[i]) setProgress(((i + 1) / files.length) * 100) } setIsUploading(false) toast.success(`Uploaded ${files.length} files`) }, []) return ( <Card onDrop={handleDrop} onDragOver={(e) => e.preventDefault()} className="border-dashed border-2 p-8 text-center" > <Icon name="Upload" size={48} className="mx-auto mb-4" /> <p>Drop files here to upload</p> {isUploading && <Progress value={progress} className="mt-4" />} </Card> ) } ``` ## Testing ```typescript import { describe, it, expect, beforeEach, vi } from 'vitest' import { db } from '@/lib/db' vi.mock('@/lib/db') describe('Knowledge Base', () => { beforeEach(() => { vi.clearAllMocks() }) it('should detect file types correctly', () => { expect(getFileType('document.md')).toBe('text') expect(getFileType('image.png')).toBe('image') expect(getFileType('file.pdf')).toBe('document') expect(getFileType('data.bin')).toBe('unknown') }) it('should generate consistent content hashes', async () => { const content = 'test content' const hash1 = await generateContentHash(content) const hash2 = await generateContentHash(content) expect(hash1).toBe(hash2) }) it('should detect duplicates', async () => { const hash = 'abc123' vi.mocked(db.knowledge.where).mockReturnValue({ equals: vi.fn().mockReturnValue({ first: vi.fn().mockResolvedValue({ id: 'existing' }), }), } as any) const result = await findDuplicate(hash) expect(result).toEqual({ id: 'existing' }) }) }) ```
عرض على GitHub