refactor: update knowledge document types and API client interfaces

- Refactored types in `Knowledge/types.ts` to introduce new interfaces for document handling.
- Added `KnowledgeDocItem`, `KnowledgeDocsListResponse`, `KnowledgeDocsUploadInput`, `KnowledgeDocsUploadResponse`, and `KnowledgeDocsDeleteResponse` for better structure and clarity.
- Updated `KnowledgeDocsApiClient` interface to include methods for listing, uploading, and deleting documents.

fix: replace deprecated icons in AccountSettingsPanel and SettingMenu

- Replaced `CheckCircleIcon` with `CheckCircle` from `lucide-react` in `AccountSettingsPanel.tsx`.
- Updated `SettingMenu.tsx` to use `Settings` and `User` from `lucide-react` instead of custom icons.

test: add tests for knowledge docs routes and KnowledgePage

- Created `knowledge-docs-routes.test.ts` to test API routes for listing, uploading, and deleting knowledge documents.
- Added `knowledge-page.test.tsx` to test the rendering and functionality of the KnowledgePage component, including document loading and deletion.
This commit is contained in:
duanshuwen
2026-04-19 09:40:07 +08:00
parent 92ec3189bc
commit 5cc9b86e1f
20 changed files with 1752 additions and 1159 deletions

View File

@@ -9,6 +9,7 @@ import { handleChannelRoutes } from './routes/channels';
import { handleCronRoutes } from './routes/cron';
import { handleFileRoutes } from './routes/files';
import { handleGatewayRoutes } from './routes/gateway';
import { handleKnowledgeRoutes } from './routes/knowledge';
import { handleModelRoutes } from './routes/models';
import { handleProviderRoutes } from './routes/providers';
import { handleSessionRoutes } from './routes/sessions';
@@ -25,6 +26,7 @@ const routeHandlers: RouteHandler[] = [
handleModelRoutes,
handleCronRoutes,
handleGatewayRoutes,
handleKnowledgeRoutes,
handleFileRoutes,
handleSessionRoutes,
];

View File

@@ -0,0 +1,86 @@
import type { HostApiContext } from '../context';
import type { NormalizedHostApiRequest } from '../route-utils';
import { fail, ok, parseJsonBody } from '../route-utils';
import {
deleteKnowledgeDoc,
listKnowledgeDocs,
uploadKnowledgeDoc,
isSafeKnowledgeDocName,
} from '../../utils/knowledge-docs';
function getDeleteTarget(request: NormalizedHostApiRequest): string | null {
const fromQuery = request.url.searchParams.get('name')?.trim() || '';
if (fromQuery) return fromQuery;
const body = request.body && typeof request.body === 'string'
? parseJsonBody<{ fileName?: string; name?: string }>(request.body)
: (request.body as { fileName?: string; name?: string } | null);
const candidate = String(body?.fileName || body?.name || '').trim();
return candidate || null;
}
export async function handleKnowledgeRoutes(
request: NormalizedHostApiRequest,
_ctx: HostApiContext,
) {
const { pathname, method } = request;
if (pathname === '/api/knowledge/docs' && method === 'GET') {
try {
return ok({
success: true,
files: await listKnowledgeDocs(),
});
} catch (error) {
return fail(500, error instanceof Error ? error.message : String(error));
}
}
if (pathname === '/api/knowledge/docs' && method === 'POST') {
try {
const body = parseJsonBody<{ base64?: string; fileName?: string }>(request.body);
const fileName = String(body?.fileName || '').trim();
const base64 = String(body?.base64 || '').trim();
if (!fileName) {
return fail(400, 'fileName is required');
}
if (!base64) {
return fail(400, 'base64 is required');
}
if (!isSafeKnowledgeDocName(fileName)) {
return fail(400, 'Invalid file name');
}
return ok({
success: true,
file: await uploadKnowledgeDoc({ fileName, base64 }),
});
} catch (error) {
return fail(500, error instanceof Error ? error.message : String(error));
}
}
if (method === 'DELETE' && (pathname === '/api/knowledge/docs' || pathname.startsWith('/api/knowledge/docs/'))) {
try {
const fileName = pathname.startsWith('/api/knowledge/docs/')
? decodeURIComponent(pathname.slice('/api/knowledge/docs/'.length))
: getDeleteTarget(request);
if (!fileName) {
return fail(400, 'fileName is required');
}
if (!isSafeKnowledgeDocName(fileName)) {
return fail(400, 'Invalid file name');
}
await deleteKnowledgeDoc(fileName);
return ok({ success: true });
} catch (error) {
return fail(500, error instanceof Error ? error.message : String(error));
}
}
return null;
}