@@ -263,6 +263,66 @@ describe('knowledge base Copilot operations', () => {
263263 )
264264 } )
265265
266+ it . each ( [
267+ [ 'an empty array' , [ ] ] ,
268+ [ 'null' , null ] ,
269+ [ 'only blank entries' , [ { tagName : ' ' , tagValue : ' ' } ] ] ,
270+ ] ) ( 'applies other document updates when documentTags contains %s' , async ( _label , tags ) => {
271+ mockCheckDocumentWriteAccess . mockResolvedValue ( { hasAccess : true } as never )
272+ mockUpdateDocument . mockResolvedValue ( { } as never )
273+
274+ const result = await knowledgeBaseServerTool . execute (
275+ {
276+ operation : 'update_document' ,
277+ args : {
278+ knowledgeBaseId : 'knowledge-base-1' ,
279+ documentId : 'document-1' ,
280+ filename : 'renamed.txt' ,
281+ enabled : false ,
282+ documentTags : tags ,
283+ } ,
284+ } ,
285+ { userId : 'user-1' , workspaceId : 'workspace-paid' }
286+ )
287+
288+ expect ( result ) . toMatchObject ( {
289+ success : true ,
290+ data : {
291+ documentId : 'document-1' ,
292+ filename : 'renamed.txt' ,
293+ enabled : false ,
294+ } ,
295+ } )
296+ expect ( mockGetDocumentTagDefinitions ) . not . toHaveBeenCalled ( )
297+ expect ( mockUpdateDocument ) . toHaveBeenCalledWith (
298+ 'document-1' ,
299+ { filename : 'renamed.txt' , enabled : false } ,
300+ expect . any ( String )
301+ )
302+ } )
303+
304+ it ( 'rejects update_document when empty documentTags is the only supplied update' , async ( ) => {
305+ mockCheckDocumentWriteAccess . mockResolvedValue ( { hasAccess : true } as never )
306+
307+ const result = await knowledgeBaseServerTool . execute (
308+ {
309+ operation : 'update_document' ,
310+ args : {
311+ knowledgeBaseId : 'knowledge-base-1' ,
312+ documentId : 'document-1' ,
313+ documentTags : [ ] ,
314+ } ,
315+ } ,
316+ { userId : 'user-1' , workspaceId : 'workspace-paid' }
317+ )
318+
319+ expect ( result ) . toEqual ( {
320+ success : false ,
321+ message : 'At least one of filename, enabled, or documentTags is required for update_document' ,
322+ } )
323+ expect ( mockUpdateDocument ) . not . toHaveBeenCalled ( )
324+ } )
325+
266326 it ( 'applies tag filters to semantic queries' , async ( ) => {
267327 mockCheckKnowledgeBaseAccess . mockResolvedValue ( { hasAccess : true } as never )
268328 mockGetKnowledgeBaseById . mockResolvedValue ( {
@@ -333,6 +393,54 @@ describe('knowledge base Copilot operations', () => {
333393 expect ( mockHandleVectorOnlySearch ) . not . toHaveBeenCalled ( )
334394 } )
335395
396+ it . each ( [
397+ [ 'an empty array' , [ ] ] ,
398+ [ 'null' , null ] ,
399+ [ 'only blank entries' , [ { tagName : ' ' , tagValue : ' ' } ] ] ,
400+ ] ) ( 'uses vector-only search when tagFilters contains %s' , async ( _label , filters ) => {
401+ mockCheckKnowledgeBaseAccess . mockResolvedValue ( { hasAccess : true } as never )
402+ mockGetKnowledgeBaseById . mockResolvedValue ( {
403+ id : 'knowledge-base-1' ,
404+ name : 'User Memory' ,
405+ workspaceId : 'workspace-paid' ,
406+ embeddingModel : 'text-embedding-3-small' ,
407+ } as never )
408+ mockCheckAttributedUsageLimits . mockResolvedValue ( { isExceeded : false } as never )
409+ mockGenerateSearchEmbedding . mockResolvedValue ( {
410+ embedding : [ 0.1 , 0.2 ] ,
411+ isBYOK : false ,
412+ } as never )
413+ mockGetQueryStrategy . mockReturnValue ( { distanceThreshold : 1 } as never )
414+ mockHandleVectorOnlySearch . mockResolvedValue ( [ ] )
415+ mockRecordSearchEmbeddingUsage . mockResolvedValue ( undefined )
416+
417+ const result = await knowledgeBaseServerTool . execute (
418+ {
419+ operation : 'query' ,
420+ args : {
421+ knowledgeBaseId : 'knowledge-base-1' ,
422+ query : 'memory' ,
423+ tagFilters : filters ,
424+ } ,
425+ } ,
426+ {
427+ userId : 'external-admin' ,
428+ workspaceId : 'workspace-paid' ,
429+ billingAttribution : BILLING_ATTRIBUTION ,
430+ }
431+ )
432+
433+ expect ( result . success ) . toBe ( true )
434+ expect ( mockGetDocumentTagDefinitions ) . not . toHaveBeenCalled ( )
435+ expect ( mockHandleTagAndVectorSearch ) . not . toHaveBeenCalled ( )
436+ expect ( mockHandleVectorOnlySearch ) . toHaveBeenCalledWith ( {
437+ knowledgeBaseIds : [ 'knowledge-base-1' ] ,
438+ topK : 5 ,
439+ queryVector : JSON . stringify ( [ 0.1 , 0.2 ] ) ,
440+ distanceThreshold : 1 ,
441+ } )
442+ } )
443+
336444 it ( 'wraps tag definitions in an object-shaped result payload' , async ( ) => {
337445 mockCheckKnowledgeBaseAccess . mockResolvedValue ( { hasAccess : true } as never )
338446 mockGetDocumentTagDefinitions . mockResolvedValue ( [
0 commit comments