@@ -217,6 +217,111 @@ func TestBleveIndex_SearchTokenization(t *testing.T) {
217217 }
218218}
219219
220+ func TestBleveIndex_SearchUnderscoreSegments (t * testing.T ) {
221+ idx , err := NewBleveIndex (t .TempDir (), zap .NewNop ())
222+ require .NoError (t , err )
223+ defer idx .Close ()
224+
225+ require .NoError (t , idx .BatchIndex ([]* config.ToolMetadata {
226+ {
227+ Name : "work_start_task_attachment_upload" ,
228+ ServerName : "fixture" ,
229+ Description : "Create a signed request for a local file." ,
230+ ParamsJSON : `{"type":"object","properties":{}}` ,
231+ Hash : "target" ,
232+ },
233+ {
234+ Name : "network_upload_attachment" ,
235+ ServerName : "fixture" ,
236+ Description : "Create a signed request for a remote file." ,
237+ ParamsJSON : `{"type":"object","properties":{}}` ,
238+ Hash : "substring-decoy" ,
239+ },
240+ }))
241+
242+ t .Run ("matches non-contiguous segments in any order" , func (t * testing.T ) {
243+ for _ , query := range []string {
244+ "work_upload_attachment" ,
245+ "attachment_work_upload" ,
246+ "work_start_task_attachment_upload" ,
247+ } {
248+ results , err := idx .SearchTools (query , 10 )
249+ require .NoError (t , err )
250+ require .NotEmpty (t , results , query )
251+ assert .Equal (t , "fixture:work_start_task_attachment_upload" , results [0 ].Tool .Name , query )
252+ }
253+ })
254+
255+ t .Run ("requires segment boundaries and every query segment" , func (t * testing.T ) {
256+ for _ , query := range []string {"network_work_upload_attachment" , "work_missing_attachment" } {
257+ results , err := idx .SearchTools (query , 10 )
258+ require .NoError (t , err )
259+ assert .Empty (t , results , query )
260+ }
261+ })
262+
263+ t .Run ("preserves a legacy prefix match ahead of an added segment match" , func (t * testing.T ) {
264+ prefixIdx , err := NewBleveIndex (t .TempDir (), zap .NewNop ())
265+ require .NoError (t , err )
266+ defer prefixIdx .Close ()
267+
268+ require .NoError (t , prefixIdx .BatchIndex ([]* config.ToolMetadata {
269+ {
270+ Name : "work_upload_attachment_preview" ,
271+ ServerName : "fixture" ,
272+ Description : "Preview an attachment upload for a Work task." ,
273+ Hash : "legacy-prefix" ,
274+ },
275+ {
276+ Name : "work_start_task_attachment_upload" ,
277+ ServerName : "fixture" ,
278+ Description : "Create a signed request for a local file." ,
279+ Hash : "segment-match" ,
280+ },
281+ }))
282+
283+ results , err := prefixIdx .SearchTools ("work_upload_attachment" , 10 )
284+ require .NoError (t , err )
285+ require .Len (t , results , 2 )
286+ assert .Equal (t , "fixture:work_upload_attachment_preview" , results [0 ].Tool .Name )
287+ assert .Equal (t , "fixture:work_start_task_attachment_upload" , results [1 ].Tool .Name )
288+ })
289+ }
290+
291+ func TestFieldsContainExactToolName (t * testing.T ) {
292+ tests := []struct {
293+ name string
294+ fields map [string ]interface {}
295+ query string
296+ want bool
297+ }{
298+ {
299+ name : "tool name" ,
300+ fields : map [string ]interface {}{"tool_name" : "work_upload_attachment" , "full_tool_name" : "fixture:work_upload_attachment" },
301+ query : "work_upload_attachment" ,
302+ want : true ,
303+ },
304+ {
305+ name : "full tool name" ,
306+ fields : map [string ]interface {}{"tool_name" : "work_upload_attachment" , "full_tool_name" : "fixture:work_upload_attachment" },
307+ query : "fixture:work_upload_attachment" ,
308+ want : true ,
309+ },
310+ {
311+ name : "no exact name" ,
312+ fields : map [string ]interface {}{"tool_name" : "work_start_task_attachment_upload" , "full_tool_name" : "fixture:work_start_task_attachment_upload" },
313+ query : "work_upload_attachment" ,
314+ want : false ,
315+ },
316+ }
317+
318+ for _ , tt := range tests {
319+ t .Run (tt .name , func (t * testing.T ) {
320+ assert .Equal (t , tt .want , fieldsContainExactToolName (tt .fields , tt .query ))
321+ })
322+ }
323+ }
324+
220325func TestBleveIndex_FieldMapping (t * testing.T ) {
221326 // Test that all fields are properly indexed and searchable
222327 tool := & config.ToolMetadata {
0 commit comments