Skip to content

Capítulo 8 — Búsqueda por rutas de archivo

Commit: 43f213aAdd support for searching in file paths (birbbit/Hristijan Bogoevski, 10 febrero 2024)

¿Qué se construyó?

Este es el PR más grande del proyecto de la comunidad. Hristijan Bogoevski (birbbit) agregó soporte para buscar en una lista específica de archivos en lugar de un directorio completo.

También refactorizó el código para separar responsabilidades en funciones más pequeñas.

El nuevo parámetro file_paths

python
# ANTES: solo podías buscar en un directorio
search("función de pagos", path="./src")

# AHORA: también en una lista específica de archivos
search("función de pagos", file_paths=["./src/payments.py", "./src/orders.py"])

Esto es crucial para Open Interpreter: el agente puede seleccionar los archivos más relevantes del proyecto y pedirle a aifs que busque solo en esos.

La lógica de decidir dónde guardar el índice

python
def search(query, path=None, file_paths=None, max_results=5, ...):
    if path is None:
        # Mode: lista de archivos específicos
        common_prefix = os.path.commonprefix(file_paths)
        if not common_prefix.endswith("/"):
            common_prefix = os.path.dirname(common_prefix)
        path_to_index = os.path.join(common_prefix, "_.aifs")
    else:
        # Mode: directorio completo
        path_to_index = os.path.join(path, "_.aifs")

Cuando se usa file_paths, el índice se guarda en el directorio más cercano común a todos los archivos.

Ejemplo:

file_paths = [
    "/proyecto/src/payments.py",
    "/proyecto/src/orders.py",
    "/proyecto/tests/test_payments.py"
]

common_prefix = "/proyecto"  # el prefijo común
path_to_index = "/proyecto/_.aifs"

La nueva función index_files()

python
def index_files(file_paths, existingIndex=None, indexPath="", python_docstrings_only=False):
    if existingIndex is None:
        existingIndex = {}
    index = existingIndex
    deletedFiles = handle_deleted_files(index)
    modifiedFiles = handle_modified_files(index, python_docstrings_only)
    writeToIndex = len(deletedFiles) > 0 or len(modifiedFiles) > 0
    
    for file_path in file_paths:
        if file_path not in index or file_path in modifiedFiles:
            file_index = index_file(file_path, python_docstrings_only)
            if file_index:
                index[file_path] = file_index
    
    save_index(writeToIndex, index, indexPath)
    return index

La diferencia con index_directory(): en lugar de hacer os.walk() para descubrir archivos, itera sobre la lista explícita.

Refactoring: funciones más pequeñas

birbbit también extrajo funciones helper:

python
def handle_deleted_files(index: dict) -> List[str]:
    """updates the index to remove deleted files. returns deleted files"""
    deletedFiles = []
    for file_path, _ in index.items():
        if not os.path.isfile(file_path):
            deletedFiles.append(file_path)
    for file_path in deletedFiles:
        index.pop(file_path, None)
    return deletedFiles

def handle_modified_files(index: dict, python_docstrings_only: bool) -> List[str]:
    modifiedFiles = []
    for file_path, file_index in index.items():
        if os.path.getmtime(file_path) != file_index["last_modified"]:
            new_file_index = index_file(file_path, python_docstrings_only)
            index[file_path] = new_file_index
            modifiedFiles.append(file_path)
    return modifiedFiles

def save_index(writeToIndex, index, indexPath):
    if writeToIndex:
        with open(indexPath, "w") as f:
            json.dump(index, f)

Estas funciones se reutilizan tanto en index_files() como en index_directory().

Un bug que se coló

python
# BUG: usa 'and' en lugar de 'or' — nunca excluye nada
if file_path.endswith("_index.aifs") and file_path.endswith(".DS_Store") and file_path.endswith("_.aifs"):
    continue

# CORRECCIÓN esperada:
if file_path.endswith("_index.aifs") or file_path.endswith(".DS_Store") or file_path.endswith("_.aifs"):
    continue

Un archivo no puede terminar en _index.aifs Y .DS_Store al mismo tiempo, así que la condición nunca se cumple. Los archivos de índice se terminan incluyendo en la búsqueda. Este bug no fue detectado en este commit.

Lección del capítulo

La API de una librería debe crecer con los casos de uso reales de sus usuarios. El parámetro file_paths surgió de una necesidad concreta: Open Interpreter necesitaba buscar en archivos específicos, no en directorios completos.


Siguiente: Cap 09 — Contribuciones de la comunidad

Libro generado por El Profe 🧑‍🏫