@@ -1905,6 +1905,151 @@ def test_google_maps_grounding_invoke_direct(backend_config: dict) -> None:
19051905 assert "grounding_metadata" in response_with_location .response_metadata
19061906
19071907
1908+ def test_file_search_tool_binding (backend_config : dict ) -> None :
1909+ """Test that file_search tool can be bound to a model.
1910+
1911+ This test verifies the tool binding mechanics work correctly.
1912+ Note: Actually using file_search requires a pre-configured file search store.
1913+ """
1914+ model = ChatGoogleGenerativeAI (model = _MODEL , ** backend_config )
1915+
1916+ # Test binding with empty dict (valid but won't work without store names)
1917+ model_with_file_search = model .bind_tools ([{"file_search" : {}}])
1918+ assert model_with_file_search is not None
1919+
1920+ # Test binding with explicit parameters
1921+ model_with_params = model .bind_tools (
1922+ [
1923+ {
1924+ "file_search" : {
1925+ "top_k" : 5 ,
1926+ }
1927+ }
1928+ ]
1929+ )
1930+ assert model_with_params is not None
1931+
1932+
1933+ @pytest .mark .extended
1934+ def test_file_search_tool (backend_config : dict ) -> None :
1935+ """Test file_search tool with a configured file search store.
1936+
1937+ This test requires a pre-configured file search store with indexed content.
1938+ Set the FILE_SEARCH_STORE_NAME environment variable to run this test.
1939+
1940+ Example store name format: `fileSearchStores/my-file-search-store-123`
1941+
1942+ To run:
1943+ FILE_SEARCH_STORE_NAME=fileSearchStores/your-store pytest --extended
1944+ """
1945+ store_name = os .environ .get ("FILE_SEARCH_STORE_NAME" )
1946+ if not store_name :
1947+ pytest .skip (
1948+ "File search test requires FILE_SEARCH_STORE_NAME env var to be set"
1949+ )
1950+
1951+ model = ChatGoogleGenerativeAI (model = _MODEL , ** backend_config )
1952+ model_with_file_search = model .bind_tools (
1953+ [
1954+ {
1955+ "file_search" : {
1956+ "file_search_store_names" : [store_name ],
1957+ "top_k" : 5 ,
1958+ }
1959+ }
1960+ ]
1961+ )
1962+
1963+ # Query the file search store
1964+ response = model_with_file_search .invoke (
1965+ "What information do you have about the documents in the store?"
1966+ )
1967+
1968+ assert isinstance (response , AIMessage )
1969+ assert response .content is not None
1970+
1971+ # File search should populate grounding metadata when results are found
1972+ if "grounding_metadata" in response .response_metadata :
1973+ grounding = response .response_metadata ["grounding_metadata" ]
1974+ # Verify grounding structure exists (may or may not have chunks depending on
1975+ # store content)
1976+ assert isinstance (grounding , dict )
1977+
1978+
1979+ @pytest .mark .extended
1980+ def test_file_search_tool_with_metadata_filter (backend_config : dict ) -> None :
1981+ """Test file_search tool with metadata filtering.
1982+
1983+ This test requires a pre-configured file search store with indexed content
1984+ and metadata.
1985+ Set the FILE_SEARCH_STORE_NAME environment variable to run this test.
1986+
1987+ To run:
1988+ FILE_SEARCH_STORE_NAME=fileSearchStores/your-store pytest --extended
1989+ """
1990+ store_name = os .environ .get ("FILE_SEARCH_STORE_NAME" )
1991+ if not store_name :
1992+ pytest .skip (
1993+ "File search test requires FILE_SEARCH_STORE_NAME env var to be set"
1994+ )
1995+
1996+ model = ChatGoogleGenerativeAI (model = _MODEL , ** backend_config )
1997+
1998+ # Test with metadata filter (AIP-160 filter syntax)
1999+ # Example filter: category = "technical" AND year >= 2024
2000+ model_with_filter = model .bind_tools (
2001+ [
2002+ {
2003+ "file_search" : {
2004+ "file_search_store_names" : [store_name ],
2005+ "top_k" : 3 ,
2006+ "metadata_filter" : 'category = "general"' ,
2007+ }
2008+ }
2009+ ]
2010+ )
2011+
2012+ response = model_with_filter .invoke ("Summarize the filtered documents." )
2013+
2014+ assert isinstance (response , AIMessage )
2015+ assert response .content is not None
2016+
2017+
2018+ @pytest .mark .extended
2019+ def test_file_search_invoke_direct (backend_config : dict ) -> None :
2020+ """Test passing file_search tool directly to invoke without binding.
2021+
2022+ This test requires a pre-configured file search store.
2023+ Set the FILE_SEARCH_STORE_NAME environment variable to run this test.
2024+
2025+ To run:
2026+ FILE_SEARCH_STORE_NAME=fileSearchStores/your-store pytest --extended
2027+ """
2028+ store_name = os .environ .get ("FILE_SEARCH_STORE_NAME" )
2029+ if not store_name :
2030+ pytest .skip (
2031+ "File search test requires FILE_SEARCH_STORE_NAME env var to be set"
2032+ )
2033+
2034+ model = ChatGoogleGenerativeAI (model = _MODEL , ** backend_config )
2035+
2036+ # Pass file_search tool directly to invoke
2037+ response = model .invoke (
2038+ "What documents are available?" ,
2039+ tools = [
2040+ {
2041+ "file_search" : {
2042+ "file_search_store_names" : [store_name ],
2043+ "top_k" : 5 ,
2044+ }
2045+ }
2046+ ],
2047+ )
2048+
2049+ assert isinstance (response , AIMessage )
2050+ assert response .content is not None
2051+
2052+
19082053def _check_code_execution_output (message : AIMessage , output_version : str ) -> None :
19092054 if output_version == "v0" :
19102055 blocks = [block for block in message .content if isinstance (block , dict )]
0 commit comments