Compare commits

...

2 Commits

Author SHA1 Message Date
Vikhyath Mondreti
e94d74a541 fix tests 2026-01-25 18:29:56 -08:00
Vikhyath Mondreti
974f3b9eff fix(kb): workspace id required for creation 2026-01-25 14:40:25 -08:00
6 changed files with 35 additions and 11 deletions

View File

@@ -16,6 +16,10 @@ mockKnowledgeSchemas()
mockDrizzleOrm() mockDrizzleOrm()
mockConsoleLogger() mockConsoleLogger()
vi.mock('@/lib/workspaces/permissions/utils', () => ({
getUserEntityPermissions: vi.fn().mockResolvedValue({ role: 'owner' }),
}))
describe('Knowledge Base API Route', () => { describe('Knowledge Base API Route', () => {
const mockAuth$ = mockAuth() const mockAuth$ = mockAuth()
@@ -86,6 +90,7 @@ describe('Knowledge Base API Route', () => {
const validKnowledgeBaseData = { const validKnowledgeBaseData = {
name: 'Test Knowledge Base', name: 'Test Knowledge Base',
description: 'Test description', description: 'Test description',
workspaceId: 'test-workspace-id',
chunkingConfig: { chunkingConfig: {
maxSize: 1024, maxSize: 1024,
minSize: 100, minSize: 100,
@@ -133,11 +138,25 @@ describe('Knowledge Base API Route', () => {
expect(data.details).toBeDefined() expect(data.details).toBeDefined()
}) })
it('should require workspaceId', async () => {
mockAuth$.mockAuthenticatedUser()
const req = createMockRequest('POST', { name: 'Test KB' })
const { POST } = await import('@/app/api/knowledge/route')
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(400)
expect(data.error).toBe('Invalid request data')
expect(data.details).toBeDefined()
})
it('should validate chunking config constraints', async () => { it('should validate chunking config constraints', async () => {
mockAuth$.mockAuthenticatedUser() mockAuth$.mockAuthenticatedUser()
const invalidData = { const invalidData = {
name: 'Test KB', name: 'Test KB',
workspaceId: 'test-workspace-id',
chunkingConfig: { chunkingConfig: {
maxSize: 100, // 100 tokens = 400 characters maxSize: 100, // 100 tokens = 400 characters
minSize: 500, // Invalid: minSize (500 chars) > maxSize (400 chars) minSize: 500, // Invalid: minSize (500 chars) > maxSize (400 chars)
@@ -157,7 +176,7 @@ describe('Knowledge Base API Route', () => {
it('should use default values for optional fields', async () => { it('should use default values for optional fields', async () => {
mockAuth$.mockAuthenticatedUser() mockAuth$.mockAuthenticatedUser()
const minimalData = { name: 'Test KB' } const minimalData = { name: 'Test KB', workspaceId: 'test-workspace-id' }
const req = createMockRequest('POST', minimalData) const req = createMockRequest('POST', minimalData)
const { POST } = await import('@/app/api/knowledge/route') const { POST } = await import('@/app/api/knowledge/route')
const response = await POST(req) const response = await POST(req)

View File

@@ -19,7 +19,7 @@ const logger = createLogger('KnowledgeBaseAPI')
const CreateKnowledgeBaseSchema = z.object({ const CreateKnowledgeBaseSchema = z.object({
name: z.string().min(1, 'Name is required'), name: z.string().min(1, 'Name is required'),
description: z.string().optional(), description: z.string().optional(),
workspaceId: z.string().optional(), workspaceId: z.string().min(1, 'Workspace ID is required'),
embeddingModel: z.literal('text-embedding-3-small').default('text-embedding-3-small'), embeddingModel: z.literal('text-embedding-3-small').default('text-embedding-3-small'),
embeddingDimension: z.literal(1536).default(1536), embeddingDimension: z.literal(1536).default(1536),
chunkingConfig: z chunkingConfig: z

View File

@@ -37,6 +37,13 @@ export const knowledgeBaseServerTool: BaseServerTool<KnowledgeBaseArgs, Knowledg
} }
} }
if (!args.workspaceId) {
return {
success: false,
message: 'Workspace ID is required for creating a knowledge base',
}
}
const requestId = crypto.randomUUID().slice(0, 8) const requestId = crypto.randomUUID().slice(0, 8)
const newKnowledgeBase = await createKnowledgeBase( const newKnowledgeBase = await createKnowledgeBase(
{ {

View File

@@ -79,7 +79,7 @@ export const KnowledgeBaseArgsSchema = z.object({
name: z.string().optional(), name: z.string().optional(),
/** Description of the knowledge base (optional for create) */ /** Description of the knowledge base (optional for create) */
description: z.string().optional(), description: z.string().optional(),
/** Workspace ID to associate with (optional for create/list) */ /** Workspace ID to associate with (required for create, optional for list) */
workspaceId: z.string().optional(), workspaceId: z.string().optional(),
/** Knowledge base ID (required for get, query) */ /** Knowledge base ID (required for get, query) */
knowledgeBaseId: z.string().optional(), knowledgeBaseId: z.string().optional(),

View File

@@ -86,18 +86,16 @@ export async function createKnowledgeBase(
const kbId = randomUUID() const kbId = randomUUID()
const now = new Date() const now = new Date()
if (data.workspaceId) { const hasPermission = await getUserEntityPermissions(data.userId, 'workspace', data.workspaceId)
const hasPermission = await getUserEntityPermissions(data.userId, 'workspace', data.workspaceId) if (hasPermission === null) {
if (hasPermission === null) { throw new Error('User does not have permission to create knowledge bases in this workspace')
throw new Error('User does not have permission to create knowledge bases in this workspace')
}
} }
const newKnowledgeBase = { const newKnowledgeBase = {
id: kbId, id: kbId,
name: data.name, name: data.name,
description: data.description ?? null, description: data.description ?? null,
workspaceId: data.workspaceId ?? null, workspaceId: data.workspaceId,
userId: data.userId, userId: data.userId,
tokenCount: 0, tokenCount: 0,
embeddingModel: data.embeddingModel, embeddingModel: data.embeddingModel,
@@ -122,7 +120,7 @@ export async function createKnowledgeBase(
chunkingConfig: data.chunkingConfig, chunkingConfig: data.chunkingConfig,
createdAt: now, createdAt: now,
updatedAt: now, updatedAt: now,
workspaceId: data.workspaceId ?? null, workspaceId: data.workspaceId,
docCount: 0, docCount: 0,
} }
} }

View File

@@ -32,7 +32,7 @@ export interface KnowledgeBaseWithCounts {
export interface CreateKnowledgeBaseData { export interface CreateKnowledgeBaseData {
name: string name: string
description?: string description?: string
workspaceId?: string workspaceId: string
embeddingModel: 'text-embedding-3-small' embeddingModel: 'text-embedding-3-small'
embeddingDimension: 1536 embeddingDimension: 1536
chunkingConfig: ChunkingConfig chunkingConfig: ChunkingConfig